exe调用某个函数时: int TestFun(int a, int b);
EBP+C: second parameter
EBP+8: first parameter
EBP+4: return address
EBP: previous EBP ===》 旧的ebp值(调用者的ebp)
EBP-4: local variable
EBP-8: local variable
内存地址的增长方向:
对于堆来讲,生长方向是向上的,也就是向着内存地址增加的方向;
对于栈来讲,它的生长方向是向下的,是向着内存地址减小的方向增长;
(1)cdcall 堆栈资源释放在函数执行外面,一般的c语言调用。 CALL XXX; ADD ESP, xxH
fun xxx(){
push eax
CALL XXX; //xxx(int) ==> cdcall;
ADD ESP,04H // 增加值由xxx函数,入栈参数个数确定;
}
(2)stdcall 在函数的里面释放堆栈,一般的windows API。 CALL XXX;
fun xxx(){
push ebp
mov ebp,esp
/// 插入新代码
...
/// 插入新代码 end;
mov ebp,esp
pop ebp
retn
}
(3) naked call。 进入函数时编译器会产生代码来保存ESI,EDI,EBX,EBP寄存器,退出函数时则产生代码恢复这些寄存器的内容。 (这些代码称作 prolog and epilog code,一般,ebp,esp的保存是必须的). 但是naked call不产生这样的代码。 ==> 维持堆栈平衡;
xxx函数使用naked call被调用时: 保持堆栈平衡;
fun xxx(){
__asm
{
push ebp
mov ebp,esp
}
... 代码;
}
例子:
__declspec(naked) void __stdcall My_MessageBox(HWND hWnd,LPCTSTR lpText,LPCTSTR lpCaption,UINT uType)
{// Jmpcode.addr=(DWORD)(My_MessageBox)-(DWORD)(MessageBoxA)-5;
__asm
{
PUSH EBP
MOV EBP,ESP
}
printf("取得参数 %x,%s,%s,%x\n",hWnd,lpText,lpCaption,uType);
__asm
{
mov ebx,old_MessageBoxA //讲MessageBoxA地址赋给EBX
add ebx,5 //EBX+5
jmp ebx
}
}
__asm 硬编码
{
_emit 0x8b
_emit 0xd4 // MOV EDX,ESP
_emit 0x0f
_emit 0x34 // SYSENTER
}
(4)取数据的方法:
A:基址 + 偏移地址;
B:函数取代; ==》 参数相同的函数; ==》 hook函数地址
C:函数增加; ==》 参数不同的函数;加入一个函数;==》 hook地址,增加函数(保持堆栈平衡),调用地址之后代码;
D:多个函数协同调用;
本文详细介绍了三种call调用约定:cdcall、stdcall和naked call的工作原理,特别是在函数hook时如何保持堆栈平衡。通过实例分析了各自的特点,如cdcall在函数外部释放堆栈,stdcall在函数内部释放,naked call则不生成保存和恢复寄存器的代码,要求手动维护堆栈平衡。
2321

被折叠的 条评论
为什么被折叠?



