获取函数返回值:
gcc提供了获取当前函数的返回地址的一个关键字:
void * __builtin_return_address(int nLevel);
nlevel 参数指获取哪个函数的返回值,0表示当前函数,1表示当前函数的调用者的函数,为2依次类推;
下面是vc6的实现:
__declspec (naked) void* __builtin_return_address (int iLevel)
{
__asm
{
push ebx;
mov eax, ebp;
mov ebx, DWORD PTR [esp + 8]; // iLevel
__Next:
test ebx, ebx;
je __break;
dec ebx;
mov eax, DWORD PTR [eax];
jmp __Next;
__break:
mov eax, DWORD PTR [eax + 4];
pop ebx;
ret;
}
}
用一个测试例子来试一下:
int sum(int a,int b)
{
void *add=__builtin_return_address(0);
return a+b;
}
int main(int argc, char* argv[])
{
int c=sum(1,4);
return 0;
}
这里取得是当前函数的返回地址;调试过程中用汇编展开:
32: int main(int argc, char* argv[])
33: {
004010A0 push ebp
004010A1 mov ebp,esp
004010A3 sub esp,44h
004010A6 push ebx
004010A7 push esi
004010A8 push edi
004010A9 lea edi,[ebp-44h]
004010AC mov ecx,11h
004010B1 mov eax,0CCCCCCCCh
004010B6 rep stos dword ptr [edi]
34:
35:
36: int c=sum(1,4);
004010B8 push 4
004010BA push 1
004010BC call @ILT+0(sum) (00401005)
004010C1 add esp,8
004010C4 mov dword ptr [ebp-4],eax
37:
38: return 0;
004010C7 xor eax,eax
39: }
我们看到,sum函数的返回地址应该是004010C1, 然后跟进sum函数,查看执行后add的地址发现恰恰是004010C1,说明模仿成功。
__declspec (naked)关键字说明:
naked
Microsoft Specific —>
__declspec( naked ) declarator
For functions declared with the naked attribute, the compiler generates code without prolog and epilog code. You can use this feature to write your own prolog/epilog code using inline assembler code. Naked functions are particularly useful in writing virtual device drivers.