探尋逝去的Atlantis文明
打開文件發現啥都沒有
運行殺毒軟件提示有代碼混淆器
OD掛上各種報錯,估計有反調
于是從頭分析,首先是兩個TlsCallback
TlsCallback_0中第一個函數sub_402B30動態獲取了ZwSetInformationThread設置當前線程的信息
v0 = GetModuleHandleA(&ModuleName); // Ntdll
v1 = GetProcAddress(v0, &ProcName); // ZwSetInformationThread
v2 = GetCurrentThread();
return ((int (__stdcall *)(HANDLE, signed int, _DWORD, _DWORD))v1)(v2, 17, 0, 0);// ThreadHideFromDebugger
百度一下可以輕松發現這個函數經常被用來反調試,第17個參數正好就是反調用的:
將其首字節改成0xc3,爆破掉即可
后一個函數sub_4028F0同樣也是動態獲取了4個函數的地址,將它們保存在了一個函數表中留待日后取用。其中一個是IsDebuggerPresent這樣的反調函數,另外三個則是VirtualAlloc、VirtualFree和Exit這種有用的函數,因此不可簡單Patch
再往后立即就調用了剛才的IsDebuggerPresent,判斷到直接Exit
這里Patch或者下斷過都行,小問題
TlsCallback_1里則是一個MessageBox,無關緊要
接著進入main主函數

那三個連續的函數不用在意,解密代碼很復雜,無需關心
sub_43180里是對Debug斷點的Hook
我們知道調試器下斷的原理是將某個地址的機器碼改為0xcc,使其觸發異常,從而被調試器捕捉中斷
這個Hook會將0xcc改為0xc3,直接ret,導致不僅調試器捕捉不到斷點,而且會直接令程序崩潰
這個函數里除了Hook沒有別的東西,直接Patch掉
sub_403010里才是重頭戲,通過memcpy將解密后的代碼送入開辟出的空間中,然后直接調用
幾個函數通過F8步過函數可以大致猜測出功能
關鍵在change_input和check兩個函數中
其實當把那幾個反調試通過以后就問題就不大了
動態調試跟進去,發現change_input中將Inputbase64后通過GlobalAddAtom將其加入了全局原子
再往后跟的幾個函數都格外的復雜,再加上代碼是動態解密的,每次都需要自己MakeCode再F5才能瀏覽一遍猜測是否需要詳細跟蹤
事實上在AddAtom之后雖然還有幾個函數調用了Input的指針,但它們都是釋放空間用的。
這個AddAtom添加了一個全局可用的字符串,必然在某處調用了GlobalGetAtomName
因此不妨稍微忽視一下其他函數,再往后跟
果不其然在v19,即check中捕捉到了GlobalGetAtomName的調用
該函數中生成了一個table,然后將table進行一頓操作后與Input逐字節異或,最后與另一個值進行比較—非常簡單粗暴常見的逆向套路了
可以通過dump將table得到,然后效仿操作與結果數組異或從而得到flag
但更簡單的方法當然是注意到這兩點:
異或的逆運算還是異或
將table進行一頓操作與input完全無關
因此將結果數組直接放入Input的地址中,等到比較的時候,該地址中就是我們需要input的值了
解base64輕松得到flag。
2018DDCTF-Writeup