测试文件 https://www.lanzous.com/ianojbc
如果运行程序提示缺少msvcr100d.dll文件 将此dll文件放程序的同一目录。 https://www.lanzous.com/iap3v6f
获取信息
32位文件存在upx壳代码分析
upx脱壳之后 打开主函数代码
int __thiscall main_0(void *this) HANDLE v2; // [esp D0h] [ebp-14h] HANDLE hObject; // [esp DCh] [ebp-8h] sub_4110FF(this); ::hObject CreateMutexW(0, 0, 0); j_strcpy(Dest, Source); hObject CreateThread(0, 0, StartAddress, 0, 0, 0); v2 CreateThread(0, 0, sub_41119F, 0, 0, 0); CloseHandle(hObject); CloseHandle(v2); while ( dword_418008 ! -1 ) sub_411190(); CloseHandle(::hObject); return 0;}
打开sub_4110FF
int sub_411BD0() printf( 1111111111111111111111111111111111111111111111111111111111111111111111111111111\\n *******************************************************************************\\n ************** ****************************************************\\n ************** ******** ********************* *************\\n ************** ********* ********************* ***************************\\n ************** ********* ********************* ***************************\\n ************** ********* ********************* ***************************\\n ************** ******* ********************** ***************************\\n ************** **** ************************* ***************************\\n ************** * *************************** **************\\n ************** *** ************************* ***************************\\n ************** ****** *********************** ***************************\\n ************** ******** ********************* ***************************\\n ************** ********** ******************* ***************************\\n ************** *********** ***************** *************\\n *******************************************************************************\\n 1111111111111111111111111111111111111111111111111111111111111111111111111111111\\n printf( input flag:\\n return scanf( %36s , Source);}
CreateThread函数起到创建新线程 调用函数执行用 值得注意的是这里使用了两次CreateThread 创建线程A,B。程序会执行完A之后 才会执行B B执行后再次执行A 这样交替执行。
第一处CreateThread
打开StartAddress函数
void __stdcall StartAddress_0(int a1) while ( 1 ) WaitForSingleObject(hObject, 0xFFFFFFFF); if ( dword_418008 -1 ) sub_41112C( Source, dword_418008); --dword_418008; Sleep(0x64u); ReleaseMutex(hObject);}
打开sub_41112C函数
出现堆栈指针不平衡
转到汇编代码 在option中开启stack pointer
在指针不平衡的上方 按下Alt K 修改栈指针为0
正常打开函数了
char *__cdecl sub_411940(int a1, int a2) char *result; // eax char v3; // [esp D3h] [ebp-5h] v3 *(_BYTE *)(a2 a1); if ( (v3 97 || v3 122) (v3 65 || v3 90) ) exit(0); if ( v3 97 || v3 122 ) result off_418000[0]; *(_BYTE *)(a2 a1) off_418000[0][*(char *)(a2 a1) - 38]; else result off_418000[0]; *(_BYTE *)(a2 a1) off_418000[0][*(char *)(a2 a1) - 96]; return result;}
这就是一个判断大小写字符 对字符进行表替换。off_418000[0]的值为QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbn
第二处CreateThread
void __stdcall sub_411B10(int a1) while ( 1 ) WaitForSingleObject(hObject, 0xFFFFFFFF); if ( dword_418008 -1 ) Sleep(0x64u); --dword_418008; ReleaseMutex(hObject);}
这里少了对我们输入字符的操作函数 就仅仅对dword_418008变量进行减1操作。
sub_411190函数
回到主函数最后有个sub_411190函数 打开
int sub_411880() int i; // [esp D0h] [ebp-8h] for ( i i i ) if ( Source[i] ! off_418004[i] ) exit(0); return printf( \\nflag{%s}\\n\\n , Dest);}
这里我们了解到输入字符串变换后的值为off_418004 即TOiZiZtOrYaToUwPnToBsOaOapsyS
dword_418008的起始值为0x1D 因此输入字符长度应该为30 在上面三个函数的分析 我们可以知道 程序通过对输入字符串前29个字符进行间隔的字符表替换 得到TOiZiZtOrYaToUwPnToBsOaOapsyS。
因为不知道哪个线程先执行 所以在写脚本时都试了下 应该是后面那个线程先执行。
# -*- coding:utf-8 -*-dec TOiZiZtOrYaToUwPnToBsOaOapsyS flag result QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm for i in range(len(dec)): if i % 2 0: flag dec[i] continue if(dec[i].isupper()): flag chr(result.find(dec[i]) 96) else: flag chr(result.find(dec[i]) 38)print ( flag{ flag } )
get flag
得到flag{ThisisthreadofwindowshahaIsES} 不过我们输入的是30个字符 这里flag里面只有29个字符 最后一个字符应该都可以 不过正确答案是E 大不了一个个试就行。
flag{ThisisthreadofwindowshahaIsESE}
本文链接: http://terhk.immuno-online.com/view-703812.html