【QCTF】 Xman Reverse asong题目(That girl)
本帖最后由 zhukai055 于 2018-7-16 09:09 编辑REVERSE-ASONG:
0x01:
下载三个文件,分别是 asong linux程序 out输出that_girl 原文
0x02:开始分析asong
Sub_400AAA:
int __fastcall sub_400AAA(const char *a1, __int64a2)//入栈内容:字符串指针,处理后的字符串长度{int v2; // eax@3int result; // eax@4__int64 v4; // rcx@4__int64 v5; // @1char buf; // @2int fd; // @1__int64 v8; // @1 v8 = *MK_FP(__FS__, 40LL);fd = open(a1, 0, a2, a1);//打开that_girl文件while ( read(fd, &buf, 1uLL) == 1 )//按单字符读入,读入成功,即循环{ v2 =sub_400936((unsigned int)buf, &buf);//读取到的内容进入sub_400936函数++*(_DWORD *)(4LL * v2 + v5);//v5是密码对应表的首地址,A++; 密码表用A数组表示。 }result = close(fd);v4 = *MK_FP(__FS__, 40LL) ^ v8;return result;
}
-----------------------------------------------------------------------------------__int64 __fastcall sub_400936(char a1)//一个算法{__int64 result; // rax@1 result = (unsigned int)(a1 - 10);switch ( a1 ){ case 95: result = (unsigned int)(a1 - 49); break; case 10: result = (unsigned int)(a1 + 35); break; case 32: case 33: case 34: result = (unsigned int)(a1 + 10); break; case 39: result = (unsigned int)(a1 + 2); break; case 44: result = (unsigned int)(a1 - 4); break; case 46: result = (unsigned int)(a1 - 7); break; case 58: case 59: result = (unsigned int)(a1 - 21); break; case 63: result = (unsigned int)(a1 - 27); break; default: if ( a1 <= 47 || a1 > 57 ) { if ( a1 <= 64 || a1 > 90 ) { if ( a1 > 96 && a1 <= 122 ) result = (unsigned int)(a1 - 87); } else { result = (unsigned int)(a1 - 55); } } else { result = (unsigned int)(a1 - 48); } break;}return result;
}
-----------------------------------------------------------------------------------
__int64 __fastcall sub_400E54(const char *a1, __int64a2)//入栈内容:字符串指针,处理后的字符串长度{int i; // @1int v4; // @1char v5[56]; // @3__int64 v6; // @1 v6 = *MK_FP(__FS__, 40LL);v4 = strlen(a1);for ( i = 0; i < v4; ++i )v5[i] = *(_DWORD *)(4LL * (signed int)sub_400936(a1[i]) + a2);//v5= A)];
sub_400D33(v5);//调整数组内位置函数sub_400DB4((unsigned __int8 *)v5, v4);sub_400CC0(v5, "out", (unsigned int)v4);return *MK_FP(__FS__, 40LL) ^ v6;
}
-----------------------------------------------------------------------------------__int64 __fastcall sub_400D33(_BYTE *a1){__int64 result; // rax@4_BYTE v2[5]; // @1 v2[4] = 0;*(_DWORD *)v2 = *a1;while (dword_6020A0[*(signed int *)&v2[1]] ){ a1[*(signed int *)&v2[1]] = a1[dword_6020A0[*(signed int *)&v2[1]]];*(_DWORD *)&v2[1] =dword_6020A0[*(signed int *)&v2[1]];
}result = (unsigned __int8)v2[0];a1[*(signed int *)&v2[1]] = v2[0];return result;
}//dword_6020A0在汇编上显示的是,4 * v1+地址,就是说,在一个数组中取一个下标为4*v1的内容。
//读内存,发现 其中的二位数组,按照这个表来 决定着下一个位置如何更换。
其结果是这样更换。
整理成C++代码
void sub_400D33(int asdstr[]) { int v1 = 0; int v0 = 0; int newstr[39]; v1 = B[(4 * v1) / 16][(4 * v1) % 16]; while (v1) { newstr[v0] = asdstr[v1]; cout << v0 << "" << v1 << endl; v0 = v1; v1 = B[(4 * v1) / 16][(4 * v1) % 16]; } newstr[1] = asdstr[0]; }
-----------------------------------------------------------------------------------
继续看下个函数
unsigned __int8 *__fastcallsub_400DB4(unsigned __int8 *a1, int a2)//最后一个算法,内容为,这一位和下一位经过左移和右移再或一下得到最终结果。{unsigned __int8 *result; // rax@4char v3; // @1int i; // @1 v3 = *a1 >> 5;for ( i = 0; a2 - 1 > i; ++i ) a1[i] = 8 * a1[i] | (a1[i + 1] >> 5);result = &a1[i];*result = 8 * *result | v3;return result;} 打开out文件,我们已经知道最终结果为:ec 29 e3 41 e1 f7 aa 1d 29 ed 29 99 39 f3 b7 a9 e7 ac 2b b7 ab40 9f a9 31 35 2c 29 ef A8 3d 4b b0 e9 e1 68 7b 41
开始我们的逆向爆破:
1.爆破最后一个函数,
因为是或运算,所以得爆破前面一位和后面一位,才能确定中间的内容。最终得到的结果为。int key[] = { 61, 133, 60, 104, 60, 62, 245, 67,165, 61, 165, 51, 39, 62, 118, 245, 60, 245,133, 118, 245, 104, 19, 245, 38,38, 165, 133, 61, 245, 7, 169, 118, 29, 60, 45, 15, 104, 32 };这其中第一位没爆破出来,在可能的几个数字中一个一个试的。{29, 61, 93, 125, 157, 189, 221, 253 };2.根据换位表,反推原数组 我是手动填数字的没用算法。{ 133, 67, 104, 133, 245, 38, 60, 61, 39, 245, 51,104, 62, 60, 118, 38, 245, 118, 165, 245, 19, 165, 61, 245, 62, 165, 45, 61,245, 7, 60, 118, 29, 60, 15, 104, 133, 169 }; 3.爆破我们的字符串。
void sub_400E54baopo(){ int i; // @1 int v4; // @1 int v5[56]; // @3 __int64 v6; // @1 int ls; int DS[] = { 133, 67, 104, 133, 245, 38, 60, 61, 39, 245, 51, 104, 62, 60, 118, 38, 245, 118, 165, 245, 19, 165, 61, 245, 62, 165, 45, 61, 245, 7, 60, 118, 29, 60, 15, 104, 133, 169 }; v4 = 38; int adsad[] = { 29, 61, 93, 125, 157, 189, 221, 253 };//开始爆破的时候,不确定是哪个就一个一个试的。 for (int ia = 0; ia < 38; ia++) { for (i = 0; i < 360; i++) { ls = A[(4 * sub_400936(i))];//进入密码对应表。读取出结果。 if (ls == DS[ia]) { cout << (char)i << ""<<ia<<""<<endl; } } cout << endl; } }
爆破出来的结果发现,不区分大小写,都能通过。那就先来大写吧。THAT_GIRL_SAYING_NO_FOR_YOUR_VINDICATEQCTF{THAT_GIRL_SAYING_NO_FOR_YOUR_VINDICATE}4.用VS c++ 恢复全部源码后,填入字符串,运行。完全一致。Getflag,不区分大小写,都试了下。QCTF{THAT_GIRL_SAYING_NO_FOR_YOUR_VINDICATE}QCTF{that_girl_saying_no_for_your_vindicate}
天使3号 发表于 2018-7-16 09:15
QCTF 是TX出的比赛吗,楼主大佬
是xctf夏令营的 voyage1969 发表于 2018-7-22 00:16
CTF萌新前来学习(想问下楼主爆破是用python语言写的嘛)
都可以啊,我一般用c++ 因为翻译过来的 伪代码 稍微改改就可以放在 VSc++中用 QCTF 是TX出的比赛吗,楼主大佬 感谢分享谢谢大佬 随贴有经验常来常看看 一次0.5 跟贴有经验,常来,常看看 一次0.5 两次才一分 不错学习了逆向还得靠耐心 感谢大佬分享,学习了 大佬多少名? 进营了吧你去哪个营? 好复杂,半天没看懂