IDA Pro - 如何得到比較清楚的逆向虛擬碼
阿新 • • 發佈:2018-12-28
原文地址:Question about disassembler
簡介
這篇文章介紹瞭如何在不使用外掛的IDA Hex-Rays如何得到比較清晰的虛擬碼。IDA Hex-Rays功能很強大,只要你提供了足夠多的資訊,它就能產生十分簡單明瞭的程式碼。
下面我們以下面這個二進位制檔案為例:
為了方便我直接把exe檔案字尾改成jpg,下載下來把檔案字尾改回exe就行了
二進位制檔案下載地址:
步驟
開啟IDA Pro載入這個exe檔案,先按shitf + F5,新增vc32_14, vc32rtf, vc32ucrt這三個符號簽名檔案。
這個exe檔案的main函式不太好找,我們先定位到exe檔案的入口,按F5得到以下結果
signed int __usercall [email protected]<eax>(int [email protected]<ebp>, int [email protected]<esi>) { char v2; // bl int v4; // ST14_4 _DWORD *v5; // eax _DWORD *v6; // esi _DWORD *v7; // eax _DWORD *v8; // esi const char **v9; // edi int *v10; // esi const char **v11; // eax sub_4018B4(); if ( !(unsigned __int8)__scrt_initialize_crt(1) || (v2 = 0, *(_BYTE *)(a1 - 25) = 0, *(_DWORD *)(a1 - 4) = 0, *(_BYTE *)(a1 - 36) = sub_401631(), dword_41CC40 == 1) ) { __scrt_fastfail(7); goto LABEL_20; } if ( dword_41CC40 ) { v2 = 1; *(_BYTE *)(a1 - 25) = 1; } else { dword_41CC40 = 1; if ( _initterm_e(&unk_415140, &unk_415158) ) { *(_DWORD *)(a1 - 4) = -2; return 255; } _initterm(&unk_415134, &unk_41513C); dword_41CC40 = 2; } __scrt_release_startup_lock(*(_DWORD *)(a1 - 36)); v5 = (_DWORD *)sub_40196C(v4); v6 = v5; if ( *v5 ) { if ( (unsigned __int8)__scrt_is_nonwritable_in_current_image(v5) ) ((void (__thiscall *)(_DWORD, _DWORD, signed int, _DWORD))*v6)(*v6, 0, 2, 0); } v7 = (_DWORD *)sub_401972(); v8 = v7; if ( *v7 ) { if ( (unsigned __int8)__scrt_is_nonwritable_in_current_image(v7) ) _register_thread_local_exe_atexit_callback(*v8); } v9 = *(const char ***)sub_406ACE(); v10 = (int *)sub_406AC8(); v11 = (const char **)unknown_libname_31(); a2 = main(*v10, v9, v11); if ( !(unsigned __int8)sub_401A94() ) LABEL_20: exit(a2); if ( !v2 ) _cexit(); __scrt_uninitialize_crt(1, 0); *(_DWORD *)(a1 - 4) = -2; return a2; }
注意下面的程式碼
a2 = main(*v10, v9, v11);
if ( !(unsigned __int8)sub_401A94() )
LABEL_20:
exit(a2);
exit函式的引數應該就是主函式的返回值。
定位到到main函式
.text:00401390 mov esi, eax .text:00401392 call sub_406312 .text:00401392 .text:00401397 push eax ; envp .text:00401398 push edi ; argv .text:00401399 push dword ptr [esi] ; argc .text:0040139B call main
按F5,我們會得到以下程式碼
int __cdecl main(int argc, const char **argv, const char **envp)
{
HMODULE v3; // esi
CHAR v4; // al
int v5; // ecx
unsigned int v6; // esi
char v7; // bl
__int128 v9; // [esp+4h] [ebp-22Ch]
int v10; // [esp+14h] [ebp-21Ch]
int v11; // [esp+18h] [ebp-218h]
__int16 v12; // [esp+1Ch] [ebp-214h]
char v13; // [esp+1Eh] [ebp-212h]
int v14; // [esp+20h] [ebp-210h]
char v15; // [esp+24h] [ebp-20Ch]
CHAR Buffer[256]; // [esp+124h] [ebp-10Ch]
int v17; // [esp+224h] [ebp-Ch]
char v18; // [esp+228h] [ebp-8h]
v3 = GetModuleHandleA(0);
memset(Buffer, 0, 0xFFu);
memset(&v15, 0, 0xFFu);
if ( !LoadStringA(v3, 0x539u, Buffer, 255) )
return -1;
v4 = Buffer[0];
if ( Buffer[0] )
{
v5 = 0;
do
{
*((_BYTE *)&v14 + ++v5 + 3) = v4 ^ 0x30;
v4 = Buffer[v5];
}
while ( v4 );
}
memset(Buffer, 0, 0xFFu);
if ( !LoadStringA(v3, 0x29Au, Buffer, 255) )
return -1;
v17 = 0;
v18 = 0;
v14 = 5;
if ( RegGetValueA(-2147483647, &v15, Buffer, 0xFFFF, 0, &v17, &v14) )
return -1;
v6 = 0;
v9 = xmmword_4194E0;
v10 = 55858812;
v7 = 114;
v11 = 1157851502;
v12 = 20051;
v13 = 0;
do
{
sub_401010((const char *)&unk_4194D0, v7 ^ *((_BYTE *)&v17 + v6 % (v14 - 1)));
v7 = *((_BYTE *)&v9 + v6++ + 1);
}
while ( v7 );
return 0;
}
看起來確實很亂,但我們可以幫助反彙編器給出一個稍好一點的程式碼
首先我們有兩個memsets
memset(Buffer, 0, 0xFFu);
memset(&v15, 0, 0xFFu);