Win逆向笔记1-空函数-带参函数-裸函数-调用约定

1.空函数

void fun()
{




}

反汇编

保护栈底
push        ebp
提升堆栈
mov         ebp,esp
sub         esp,40h
保护现场
push        ebx
push        esi
push        edi
填充缓冲区
lea         edi,[ebp-40h]
mov         ecx,10h
mov         eax,0CCCCCCCCh
rep stos    dword ptr [edi]

2.带参函数

两个数相加

int fun(int a,int b)
{
	return a + b;
}

反汇编

传参
push        4  
push        3  
调用函数求和函数
call        0E13C0h
外平栈 
add         esp,8 

保护栈底
push        ebp  
提升堆栈
mov         ebp,esp  
sub         esp,0C0h 
保护现场 
push        ebx  
push        esi  
push        edi 
填充缓冲区 
mov         edi,ebp  
xor         ecx,ecx  
mov         eax,0CCCCCCCCh  
rep stos    dword ptr es:[edi]  
mov         ecx,offset _EDC018E5_test1@cpp (0EC066h)  
call        @__CheckForDebuggerJustMyCode@4 (0E1320h)  
函数真正的功能在这里实现a+b然后放到cx
mov         eax,dword ptr [a]  
add         eax,dword ptr [b] 
恢复现场
pop         edi  
pop         esi  
pop         ebx
降低栈顶  
add         esp,0C0h  
堆栈平衡错误检查
cmp         ebp,esp  
call        __RTC_CheckEsp (0E1244h)  
恢复主调函数堆栈
mov         esp,ebp  
pop         ebp  
返回
ret  

三个数相加

int fun(int a,int b,int c)
{
	return a + b + c;
}

反汇编

传参
push        5  
push        4  
push        3  
调用求和函数
call        fun (0F213C5h)
外平栈  
add         esp,0Ch 



保护栈底
push        ebp 
提升堆栈 
mov         ebp,esp  
sub         esp,0C0h 
保护现场 
push        ebx  
push        esi  
push        edi 
填充缓冲区 
mov         edi,ebp  
xor         ecx,ecx  
mov         eax,0CCCCCCCCh  
rep stos    dword ptr es:[edi]  
mov         ecx,offset _EDC018E5_test1@cpp (0F2C066h)  
call        @__CheckForDebuggerJustMyCode@4 (0F21320h)  

函数真正的功能实现a+b+c放到eax
mov         eax,dword ptr [a]  
add         eax,dword ptr [b]  
add         eax,dword ptr [c]  

恢复现场
pop         edi  
pop         esi  
pop         ebx 
降低堆栈 
add         esp,0C0h 
堆栈平衡错误检查 
cmp         ebp,esp  
call        __RTC_CheckEsp (0F21244h)  
恢复堆栈
mov         esp,ebp  
pop         ebp  
返回
ret  

3.裸函数

直接执行裸函数会执行出错,因为编译器不会帮你做任何操作例如ret等

void __declspec(naked) fun()  
{

}

反汇编

不会自动生成反汇编代码,调用函数后跳到int3 停止函数执行

加上ret可以正常执行,因为可以正确返回

void __declspec(naked) fun()
{
	_asm {
		ret;
	}
}

无参数无返回值的函数框架

void __declspec(naked) fun()
{
	_asm {
		push ebp
		mov ebp,esp
		sub esp,0x40
		push ebx
		push esi
		push edi
		lea edi,dword ptr ds:[ebp-0x40]
		mov eax,0xCCCCCCCC
		mov ecx,0x10
		rep stosd

		pop edi
		pop esi
		pop ebx
		mov esp,ebp
		pop ebp

		ret
	}
}

有参数有返回值的函数框架

int __declspec(naked) fun(int x, int y)
{
	_asm {
		push ebp
		mov ebp,esp
		sub esp,0x40
		push ebx
		push esi
		push edi
		lea edi,dword ptr ds:[ebp-0x40]
		mov eax,0xCCCCCCCC
		mov ecx,0x10
		rep stosd

		mov eax, dword ptr ds : [ebp + 8]
		add eax, dword ptr ds : [ebp + 0xC]

		pop edi
		pop esi
		pop ebx
		mov esp,ebp
		pop ebp

		ret
	}
}

带局部变量的函数框架

int __declspec(naked) fun(int x, int y)
{
	_asm {
		push ebp
		mov ebp,esp
		sub esp,0x40
		push ebx
		push esi
		push edi
		lea edi,dword ptr ds:[ebp-0x40]
		mov eax,0xCCCCCCCC
		mov ecx,0x10
		rep stosd

		mov dword ptr ds : [ebp - 4] , 2
		mov dword ptr ds : [ebp - 8] , 3
		mov eax, dword ptr ds : [ebp + 8]
		add eax, dword ptr ds : [ebp + 0xC]

		pop edi
		pop esi
		pop ebx
		mov esp,ebp
		pop ebp

		ret
	}
}

4.调用约定

调用约定参数压栈顺序平衡堆栈
__cdecl从右至左入栈调用者清理栈
__stdcall从右至左入栈自身清理堆栈
__fastcallECX/EDX传送前两个自身清理堆栈
剩下:从右至左入栈

_cdecl

int __cdecl Plus(int a, int b)
{
	return a + b;
}

反汇编
    push        5  
    push        4  
    call        Plus (08813E8h)  
    add         esp,8  


如果不指定调用约定默认为_cdecl

不定参数的函数可以使用这种方式

_stdcall

int __stdcall Plus(int a, int b)
{
	return a + b;
}



push        5  
push        4  
call        Plus (0C513EDh) 

在函数内部平衡堆栈
不定参数的函数无法使用这种方式

ret         8  

__fastcall

int __fastcall Plus(int a, int b,int c)
{
	return a + b;
}


寄存器方式传参  (前两个参数用寄存器,后面的参数用push入栈) 
在函数内部平衡堆栈

mov         edx,5  
mov         ecx,4  
call        Plus (0BB13F2h)  

5.程序的真正入口

main 或WinMain 是“语法规定的用户入口”,而不是“应用程序入口”。应用程序入口通常是启动函数。

main 函数被调用前要调用的函数

GetVersion() 

_heap_init() 

GetCommandLineA() 

_crtGetEnvironmentStringsA() 

_setargv()

_setenvp()

_cinit()

main函数的参数

main(__argc, _argv, _get_initial_narrow_environment());

main函数的识别

3个参数,分别是命令行参数个数、命令行参数信息和环境变量信息,而且main函数是启动函数中唯一具有3个参数的函数。同 理,WinMain也是启动函数中唯一具有4个参数的函数。 main函数返回后需要调用exit函数,结束程序根据main函数调用 的特征,找到入口代码第一次调用exit函数处,离exit最近的且有 3个参数的函数通常就是main函数。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值