二进制代码逆向——如何寻找main入口,先找mainCRTStartup,common_main,common_main_seh,invoke_main,main然后就是main函数
控制台应用程序的main函数入口
在OD中找到以上其他中的函数,然后跟着3个参数的CALL就是main
例:
———————————————————-
我在vs2022里编译一个程序,看下和c的区别,如下:
#include <stdio.h> int add(int x, int y) { return x + y; } int main(int argc, char* argv[]) { int (*sub)(int, int); int x = add(3, 4); printf("%d\n", x); return 0; }
反汇编的代码:
--- D:\source\test27\Conso\Conso\Conso.cpp -------------------------------------
Conso.exe!main(int, char * *):
001218A0 55 push ebp
001218A1 8B EC mov ebp,esp
001218A3 81 EC D8 00 00 00 sub esp,0D8h
001218A9 53 push ebx
001218AA 56 push esi
001218AB 57 push edi
001218AC 8D 7D E8 lea edi,[ebp-18h]
001218AF B9 06 00 00 00 mov ecx,6
001218B4 B8 CC CC CC CC mov eax,0CCCCCCCCh
001218B9 F3 AB rep stos dword ptr es:[edi]
001218BB B9 08 C0 12 00 mov ecx,offset _F4F12A98_Conso@cpp (012C008h)
001218C0 E8 56 FA FF FF call @__CheckForDebuggerJustMyCode@4 (012131Bh)
001218C5 6A 04 push 4
001218C7 6A 03 push 3
001218C9 E8 EE F9 FF FF call add (01212BCh)
001218CE 83 C4 08 add esp,8
001218D1 89 45 EC mov dword ptr [x],eax
001218D4 8B 45 EC mov eax,dword ptr [x]
001218D7 50 push eax
001218D8 68 30 7B 12 00 push offset string "%d\n" (0127B30h)
001218DD E8 EB F7 FF FF call _printf (01210CDh)
001218E2 83 C4 08 add esp,8
001218E5 33 C0 xor eax,eax
001218E7 5F pop edi
001218E8 5E pop esi
001218E9 5B pop ebx
001218EA 81 C4 D8 00 00 00 add esp,0D8h
001218F0 3B EC cmp ebp,esp
001218F2 E8 48 F9 FF FF call __RTC_CheckEsp (012123Fh)
001218F7 8B E5 mov esp,ebp
001218F9 5D pop ebp
001218FA C3 ret
看下调用stack:
--- D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl --------
Conso.exe!invoke_main(void):
001221B0 55 push ebp
001221B1 8B EC mov ebp,esp
001221B3 83 EC 0C sub esp,0Ch
001221B6 E8 D9 F0 FF FF call __get_initial_narrow_environment (0121294h)
001221BB 89 45 FC mov dword ptr [ebp-4],eax
001221BE E8 DB F0 FF FF call ___p___argv (012129Eh)
001221C3 8B 00 mov eax,dword ptr [eax]
001221C5 89 45 F8 mov dword ptr [ebp-8],eax
001221C8 E8 97 EE FF FF call ___p___argc (0121064h)
001221CD 8B 08 mov ecx,dword ptr [eax]
001221CF 89 4D F4 mov dword ptr [ebp-0Ch],ecx
001221D2 8B 55 FC mov edx,dword ptr [ebp-4]
001221D5 52 push edx
001221D6 8B 45 F8 mov eax,dword ptr [ebp-8]
001221D9 50 push eax
001221DA 8B 4D F4 mov ecx,dword ptr [ebp-0Ch]
001221DD 51 push ecx
001221DE E8 ED F0 FF FF call _main (01212D0h)
001221E3 83 C4 0C add esp,0Ch
001221E6 8B E5 mov esp,ebp
001221E8 5D pop ebp
001221E9 C3 ret
--- D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl --------
Conso.exe!__scrt_common_main_seh(void):
00121EE0 55 push ebp
00121EE1 8B EC mov ebp,esp
00121EE3 6A FE push 0FFFFFFFEh
00121EE5 68 88 91 12 00 push 129188h
00121EEA 68 50 3A 12 00 push offset _except_handler4 (0123A50h)
00121EEF 64 A1 00 00 00 00 mov eax,dword ptr fs:[00000000h]
00121EF5 50 push eax
00121EF6 83 C4 CC add esp,0FFFFFFCCh
00121EF9 53 push ebx
00121EFA 56 push esi
00121EFB 57 push edi
00121EFC A1 20 A0 12 00 mov eax,dword ptr [__security_cookie (012A020h)]
00121F01 31 45 F8 xor dword ptr [ebp-8],eax
00121F04 33 C5 xor eax,ebp
00121F06 50 push eax
00121F07 8D 45 F0 lea eax,[ebp-10h]
00121F0A 64 A3 00 00 00 00 mov dword ptr fs:[00000000h],eax
00121F10 89 65 E8 mov dword ptr [ebp-18h],esp
00121F13 6A 01 push 1
00121F15 E8 89 F3 FF FF call ___scrt_initialize_crt (01212A3h)
00121F1A 83 C4 04 add esp,4
00121F1D 0F B6 C0 movzx eax,al
00121F20 85 C0 test eax,eax
00121F22 75 07 jne __scrt_common_main_seh+4Bh (0121F2Bh)
00121F24 6A 07 push 7
00121F26 E8 A6 F2 FF FF call ___scrt_fastfail (01211D1h)
00121F2B C6 45 E7 00 mov byte ptr [has_cctor],0
00121F2F C7 45 FC 00 00 00 00 mov dword ptr [ebp-4],0
00121F36 E8 9F F3 FF FF call ___scrt_acquire_startup_lock (01212DAh)
00121F3B 88 45 E6 mov byte ptr [ebp-1Ah],al
00121F3E 83 3D 50 A1 12 00 01 cmp dword ptr [__scrt_current_native_startup_state (012A150h)],1
00121F45 75 09 jne __scrt_common_main_seh+70h (0121F50h)
00121F47 6A 07 push 7
00121F49 E8 83 F2 FF FF call ___scrt_fastfail (01211D1h)
00121F4E EB 61 jmp __scrt_common_main_seh+0D1h (0121FB1h)
00121F50 83 3D 50 A1 12 00 00 cmp dword ptr [__scrt_current_native_startup_state (012A150h)],0
00121F57 75 54 jne __scrt_common_main_seh+0CDh (0121FADh)
00121F59 C7 05 50 A1 12 00 01 00 00 00 mov dword ptr [__scrt_current_native_startup_state (012A150h)],1
00121F63 68 18 76 12 00 push offset __xi_z (0127618h)
00121F68 68 0C 73 12 00 push offset __xi_a (012730Ch)
00121F6D E8 01 F1 FF FF call __initterm_e (0121073h)
00121F72 83 C4 08 add esp,8
00121F75 85 C0 test eax,eax
00121F77 74 16 je __scrt_common_main_seh+0AFh (0121F8Fh)
00121F79 C7 45 C8 FF 00 00 00 mov dword ptr [ebp-38h],0FFh
00121F80 C7 45 FC FE FF FF FF mov dword ptr [ebp-4],0FFFFFFFEh
00121F87 8B 45 C8 mov eax,dword ptr [ebp-38h]
00121F8A E9 53 01 00 00 jmp $LN18+44h (01220E2h)
00121F8F 68 08 72 12 00 push offset __xc_z (0127208h)
00121F94 68 00 70 12 00 push offset __xc_a (0127000h)
00121F99 E8 BE F3 FF FF call __initterm (012135Ch)
00121F9E 83 C4 08 add esp,8
00121FA1 C7 05 50 A1 12 00 02 00 00 00 mov dword ptr [__scrt_current_native_startup_state (012A150h)],2
00121FAB EB 04 jmp __scrt_common_main_seh+0D1h (0121FB1h)
00121FAD C6 45 E7 01 mov byte ptr [has_cctor],1
00121FB1 0F B6 4D E6 movzx ecx,byte ptr [ebp-1Ah]
00121FB5 51 push ecx
00121FB6 E8 B2 F1 FF FF call ___scrt_release_startup_lock (012116Dh)
00121FBB 83 C4 04 add esp,4
00121FBE E8 88 F0 FF FF call ___scrt_get_dyn_tls_init_callback (012104Bh)
00121FC3 89 45 E0 mov dword ptr [ebp-20h],eax
00121FC6 8B 55 E0 mov edx,dword ptr [ebp-20h]
00121FC9 83 3A 00 cmp dword ptr [edx],0
00121FCC 74 33 je __scrt_common_main_seh+121h (0122001h)
00121FCE 8B 45 E0 mov eax,dword ptr [ebp-20h]
00121FD1 50 push eax
00121FD2 E8 4B F1 FF FF call ___scrt_is_nonwritable_in_current_image (0121122h)
00121FD7 83 C4 04 add esp,4
00121FDA 0F B6 C8 movzx ecx,al
00121FDD 85 C9 test ecx,ecx
00121FDF 74 20 je __scrt_common_main_seh+121h (0122001h)
00121FE1 8B 55 E0 mov edx,dword ptr [ebp-20h]
00121FE4 8B 02 mov eax,dword ptr [edx]
00121FE6 89 45 C4 mov dword ptr [ebp-3Ch],eax
00121FE9 6A 00 push 0
00121FEB 6A 02 push 2
00121FED 6A 00 push 0
00121FEF 8B 4D C4 mov ecx,dword ptr [ebp-3Ch]
00121FF2 89 4D D8 mov dword ptr [ebp-28h],ecx
00121FF5 8B 4D D8 mov ecx,dword ptr [ebp-28h]
00121FF8 FF 15 00 D0 12 00 call dword ptr [__guard_check_icall_fptr (012D000h)]
00121FFE FF 55 D8 call dword ptr [ebp-28h]
00122001 E8 31 F0 FF FF call ___scrt_get_dyn_tls_dtor_callback (0121037h)
00122006 89 45 DC mov dword ptr [ebp-24h],eax
00122009 8B 55 DC mov edx,dword ptr [ebp-24h]
0012200C 83 3A 00 cmp dword ptr [edx],0
0012200F 74 21 je __scrt_common_main_seh+152h (0122032h)
00122011 8B 45 DC mov eax,dword ptr [ebp-24h]
00122014 50 push eax
00122015 E8 08 F1 FF FF call ___scrt_is_nonwritable_in_current_image (0121122h)
0012201A 83 C4 04 add esp,4
0012201D 0F B6 C8 movzx ecx,al
00122020 85 C9 test ecx,ecx
00122022 74 0E je __scrt_common_main_seh+152h (0122032h)
00122024 8B 55 DC mov edx,dword ptr [ebp-24h]
00122027 8B 02 mov eax,dword ptr [edx]
00122029 50 push eax
0012202A E8 D0 F0 FF FF call __register_thread_local_exe_atexit_callback (01210FFh)
0012202F 83 C4 04 add esp,4
00122032 E8 79 01 00 00 call invoke_main (01221B0h)
00122037 89 45 D4 mov dword ptr [ebp-2Ch],eax
0012203A E8 AF F2 FF FF call ___scrt_is_managed_app (01212EEh)
0012203F 0F B6 C8 movzx ecx,al
00122042 85 C9 test ecx,ecx
00122044 75 09 jne __scrt_common_main_seh+16Fh (012204Fh)
00122046 8B 55 D4 mov edx,dword ptr [ebp-2Ch]
00122049 52 push edx
0012204A E8 AF F1 FF FF call _exit (01211FEh)
...
结合C++反汇编逆向分析这本书里提到的:
总结下来就是找mainCRTStartup,common_main,common_main_seh,invoke_main,main然后就是main函数了!
上面vs2022的代码,我们再来使用odb分析下:
打开ODB,一开始看到的是:
也就是odb一开始就是给你找到mainCRTStartup,然后进入:
就到了common_main,继续走进去:
就到了common_main_seh,这个代码比较多,我们直接找invoke_main,翻了大概1-2页的ODB汇编代码,看到invoke_main
跟进去,然后如下,终于看到了三个push的main函数了!!!
紫色行进入,就只最终的main函数了:
其他补充:
说的应该就是invoke_main了!
逆向CallingConvention.exe,还原为C代码,记录过程。该程序可以自己去生成一个:
#include <iostream> #include<Windows.h> #include<stdio.h> int functionC(int a, int b) { return a + b; } int functionB(int a,int b,int c) { return a + b + c; } int functionA(int a, int b, int c, int d, int e) { int x, y; x = functionB(a, b, c); y = functionC(a, b); return y = functionC(x, y); } int main() { int result = functionA(1, 3, 4, 6, 7); printf("结果是:%d\n", result); system("pause");
return 0; }
程序入口
main函数
通过Main函数识别出来程序大致框架如下:
函数3为编译器自动添加的堆栈平衡检查函数
void __fastcall func1(int a,int b,int c,int d,int e){
}
void __cdecl func2(int x,int y){
}
void main(int argc,char *argv[])
{
func1(1,3,4,6,7);
func2(m,n);
}
func1函数
从以上汇编代码识别出func1的框架如下:
void __fastcall func1(int a,int b,int c,int d,int e){
int x=1;
int y=3;
func3(x,y,c);
func4();
func4();
}
func3函数
func3函数大致框架如下:
int __cdecl func3(int x,int y,it z)
{
return x+y+z;
}
func1函数补充如下:
void __fastcall func1(int a,int b,int c,int d,int e){
int x=1;
int y=3;
int z=func3(x,y,c);
func4(x,y);
func4();
}
func4函数
func4的函数框架如下:
int cdecl func4(int x.int y)
{
return x+y;
}
func1函数补充如下:
void __fastcall func1(int a,int b,int c,int d,int e){
int x=1;
int y=3;
int z=func3(x,y,c);
int p=func4(x,y);
func4(p,z); //运算后eax=0C
}
到此,func1基本逆向完成,回到main函数,继续func2的逆向,如下:
func2函数==》注意:这个是printf函数的汇编!
进到func2函数内部,发现其应该是printf函数,那么回到main函数,继续完善,如下:
Main函数
int cdecl func4(int x,int y)
{
return x+y;
}
void __fastcall func1(int a,int b,int c,int d,int e){
int x=1;
int y=3;
int z=func3(x,y,c);
int p=func4(x,y);
func4(p,z); //运算后eax=0C
}
void main(int argc,char *argv[])
{
printf("%d",func1(1,3,4,6,7));
}
上面的答案有瑕疵,比如函数返回值啥的void错误:
完善后代码如下:
#include <iostream>
#include<Windows.h>
#include<stdio.h>
int functionC(int a, int b)
{
return a + b;
}
int functionB(int a,int b,int c)
{
return a + b + c;
}
int functionA(int a, int b, int c, int d, int e)
{
int x, y;
x = functionB(a, b, c);
y = functionC(a, b);
return y = functionC(x, y);
}
int main()
{
int result = functionA(1, 3, 4, 6, 7);
printf("结果是:%d\n", result);
system("pause");
}