[Blog recommendations] How to obtain the C language function start address and return address
This blog post is from the Bkjia blog gmxydm blogger. If you have any questions, go to the blog page for an interactive discussion! Blog: http://5412097.blog.51cto.com/5402097/1641374
|
In the anti-plug-in system, the return address of the function is often checked to ensure that the return address of the function is within the specified range, so that the functions in the game program are not called by the plug-in. This check method involves a basic technical problem. How do I obtain the return address of the function?
For example, the first piece of code below:
- #include<stdio.h>
- int main()
- {
- getchar();
- return 0;
- }
For a very simple program, how do we obtain the start address and return address of the function? The start address is very easy to obtain, as shown below:
- #include<stdio.h>
- int main()
- {
- printf("%0x\n",main);
- getchar();
- return 0;
- }
So how can we get the return address of the function? This is relatively difficult. Let's first look at the result of the first code disassembly:
- #include<stdio.h>
- intmain()
- {
- 009919E0 push ebp
- 009919E1 mov ebp,esp
- 009919E3 sub esp,0C0h
- 009919E9 push ebx
- 009919EA push esi
- 009919EB push edi
- 009919EC lea edi,[ebp-0C0h]
- 009919F2 mov ecx,30h
- 009919F7 mov eax,0CCCCCCCCh
- 009919FC rep stos dword ptr es:[edi]
- getchar();
- 009919FE mov esi,esp
- 00991A00 call dword ptr [__imp__getchar (9982B0h)]
- 00991A06 cmp esi,esp
- 00991A08 call @ILT+295(__RTC_CheckEsp) (99112Ch)
- return 0;
- 00991A0D xor eax,eax
- }
- 00991A0F pop edi
- 00991A10 pop esi
- 00991A11 pop ebx
- 00991A12 add esp,0C0h
- 00991A18 cmp ebp,esp
- 00991A1A call @ILT+295(__RTC_CheckEsp) (99112Ch)
- 00991A1F mov esp,ebp
- 00991A21 pop ebp
- 00991A22 ret
At the beginning of the Code, save the content of ebp and write the content of ESP to EBP:
- 009919E0 push ebp
-
- 009919E1 mov ebp,esp
The Assembly command call will do two things. First, it will push the address of an instruction after the call command into the stack, jump to the call location of the call Command unconditionally, and start executing the subroutine.
The ret command corresponding to the call command starts to execute a command after the call command.
So how does the ret Command know the address of the next command of the call Command? Because the call Command has pushed this command into the stack, the ret command can find the address of a command after the call command.
Since the ret command can find the return address of the call, that is, the address of the next command of the call, we can also find it !!!
Before and during the execution of the main function, the stack distribution is as follows:
Through the above figures, we can clearly see that the return address of the main function is in [EBP + 4. Therefore, the code for getting the return address of the main function is as follows:
- #include<stdio.h>
- int main()
- {
- int re_addr;
- __asm
- {
- mov eax,dword ptr [ebp+4]
- mov re_addr,eax
- }
- printf("%0X\n",re_addr);
- getchar();
- return 0;
- }
The _ tmainCRTStartup () function calls the main function. The Calling assembly code is as follows:
Mainret = main (argc, argv, envp );
00B81926 mov eax, dword ptr [envp (0B87140h)]
00B8192B push eax
00B8192C mov ecx, dword ptr [argv (0B87144h)]
00B81932 push ecx
00B81933 mov edx, dword ptr [argc (0B8713Ch)]
00B81939 push edx
00B8193A call @ ILT + 300 (_ main) (0B81131h)
00B8193F add esp, 0Ch
00B81942 mov dword ptr [mainret (0B87154h)], eax
We can see that the address of a command after the call main command is 00B8193F, And the return address of the main command we get is as follows:
B8193F
The result is correct.
Similar to other functions, the following describes how to generate a function with a function return value, which is provided to you as follows:
- #include<stdio.h>
-
- int Get_return_addr()
- {
- int re_addr;
- __asm
- {
- mov eax,dword ptr [ebp]
- mov ebx,dword ptr [eax+4]
- mov re_addr,ebx
- }
- returnre_addr;
-
- }
-
- int main()
- {
- intre_addr=Get_return_addr();
- printf("%0X\n",re_addr);
- getchar();
- return 0;
- }
In the Get_return_add function, why are there several more Assembly commands? You can think for yourself.