About the invocation of a compiled language function (i)

Source: Internet
Author: User

In the end, it is really a good thing to do, bad things do absolutely,

However, think about writing something that will help the memory, but also for the reference of others, so decided to take some time cursive this article

Previously in the blog post about the crack also slightly mentioned this problem, now go deep into it.


The narrow sense of compiling refers to the program language code to the CPU can execute the machine code, such as C + + (VC + +)

VB6 's main program is actually compiled, but most of it is similar to Java, generating intermediate code, which is interpreted as machine code by the virtual machine at runtime.

This is similar to scripting, except that the intermediate code is binary, not easy to understand, and the script is more intuitive

For. NET (vb,c#, etc.) is purely generated intermediate code (Microsoft Intermediate), so that these language generated programs can easily "decompile" and any language conversion

Generate intermediate code, which is also compiled in the broadest sense.


What we are going to talk about today is mainly in the narrow sense of compiling, and mainly with VC6 as an example, the details of the function call, I still pay more attention to the details

There are several commonly used function calls in VC:

1, _stdcall
2. __cdec (default)
3, __fastcall
4, thiscall (implicit)
5. Naked (bare function)

In fact, naked is not a calling convention, but a function modifier, which is compiler-oriented, which allows the programmer to freely control the stack of functions.

The compilation can be the same as all calls except ThisCall. Let's write a little demo to see how these functions are called separately.

Call.h #ifndef __call_h_#define __call_h_#if _msc_ver > 1000#pragma once#endif//_msc_ver > 1000//#ifdef __CP Lusplus//extern "C" {//#endifclass ccall{public:ccall (); ~ccall (); int call (int arg1, short arg2, char arg3, void *arg4);p R Otected:int m_var1;};/ /#ifdef __cplusplus//}//#endif #endif
For various purposes, I still write the function body outside the class:

Call.cpp. #include "call.h" Ccall::ccall () {m_var1 = 18;} Ccall::~ccall () {}int ccall::call (int arg1, short arg2, char arg3, void *arg4) {int Var1;short var2;char var3;int *p;var1 = Arg1;var2 = Arg2;var3 = Arg3;p = (int *) arg4;*p = M_var1;return 0;}
There are also portals and global functions:

Main.cpp #include <windows.h> #include "call.h" int g_var1;void fnvoid (int arg1, short arg2, char arg3) {int var1 ; short Var2;char var3;var1 = arg1;var2 = Arg2;var3 = Arg3;arg1 = -1;g_var1 = 111;return;} int fndefaultcall (int arg1, short arg2, char arg3, void *arg4) {int Var1;short var2;char var3;int *p;var1 = ARG1;VAR2 = arg 2;var3 = arg3;p = (int *) arg4;*p = 7;return 0;} int __stdcall Fnstandardcall (int arg1, short arg2, char arg3, void *arg4) {int Var1;short var2;char var3;int *p;var1 = arg1 ; var2 = Arg2;var3 = Arg3;p = (int *) arg4;*p = 11;return 0;} int __fastcall fnfastcall (int arg1, short arg2, char arg3, void *arg4) {int Var1;short var2;char var3;int *p;var1 = Arg1;va r2 = Arg2;var3 = Arg3;p = (int *) arg4;*p = 14;return 0;} __declspec (naked) int __cdecl fnnakedcall (int arg1, short arg2, char arg3, void *arg4) {//1. The value of all registers here is the same as before//2. Use variable names to refer to any What local variable is equivalent to referencing a key function variable or parameter//3. Must be responsible for the maintenance of registers, here functions as __CDECL__ASM{PUSHEBP; Prolog Beginmovebp, Espsubesp, 50hpushebxpushesipushedileaedi, [Ebp-50h]moVECX, 14hmoveax, 0CCCCCCCChrep stosdword ptr [edi]; Prolog end//var1 = Arg1;moveax, dword ptr [EBP + 8]; [ESP + 8]movdword ptr [ebp-4], eax;  [esp-4]//var2 = arg2;movcx, Word ptr [ebp + 0ch]mov word ptr [ebp-8], cx//var3 = ARG3;MOVDL, byte ptr [Ebp + 10h]movbyte ptr [ebp-0ch], dl//p = (int *) Arg4;moveax, DWORD ptr [Ebp + 14h]movdword ptr [ebp-10h], eax//*p = -1;mo v ecx, DWORD ptr [Ebp-10h]movdword ptr [ecx], 0ffffffffh//return 22;moveax, 16h; 0x16 = 22popedi; Epilog Beginpopesipopebxmovesp, EBPPOPEBP; Epilog end//return to caller function (does not use RET 10h) ret}}int main (int argc, char **argv) {Ccall *pcall;int var1;int R Et;fnvoid (1, 2, 3); ret = Fndefaultcall (4, 5, 6, &var1); ret = Fnstandardcall (8, 9, ten, &var1); ret = Fnfastcall (11, &AMP;VAR1);p call = new Ccall (), ret = Pcall->call (n, N, &var1);d elete pcall;//pcall = Null;ret = Fnna Kedcall (+, +, &var1); return 0;}

The following is a look at the call procedure under Debug, note that if VS.NET,VC is compiled, a DWORD is added before and after each variable to detect a buffer overflow

The first is to call the void function with no return value, which is __cdecl called by default:

:      fnvoid (1, 2, 3); 0040135D   push        30040135F   push        200401361   push        100401363   call        @ILT +5 (fnvoid) (0040100a) 00401368   add         esp,0ch121:
As you can see, the parameter is pressed from right to left onto the stack, then call function address, then add ESP, clean up the stack

Note:

The stack is extended from a high address to a low address, such as the first push before the ESP (stack top pointer) =0x0012ff04, then push 3 esp=0x0012ff00

And so on, push 2,ESP=0X0012FEFC; Push 1,esp=0x0012fef8

Next is the call instruction, which will return the address, which is the next instruction position (EIP, instruction pointer) pressed into the stack, such as

Call before eip=0x00401363 (next eip=0x00401368)

After call EIP=0X0040100A,ESP=0X0012FEF4

Then the call ends, and the last RET instruction of the __CDECL convention function pops the top of the stack to the EIP pointer

eip=0x00401368 Esp=0x0012fef8

Then add esp,0xc, here 0xc=12 that is 3 DWORD is the number of front push (pop to pop to a register, add directly modify the top position of the stack, reduce the stack size)

To this, the stack and EIP revert to the state before the call.


Then we go inside the function and see what it's doing in a shady activity:

7:void fnvoid (int arg1, short arg2, char arg3) 8: {00401140 push ebp00401141 mov ebp,esp00401143         Sub esp,4ch00401146 push ebx00401147 push esi00401148 push edi00401149 Lea        EDI,[EBP-4CH]0040114C mov ecx,13h00401151 mov eax,0cccccccch00401156 rep stos dword ptr [edi]9: int var1;10:short Var2;11:char var3;12:var1 = arg1;00401158 mov eax,dword ptr [ebp+8] 0040115B mov dword ptr [EBP-4],EAX13:VAR2 = arg2;0040115e mov cx,word ptr [ebp+0ch]00401162 m OV Word ptr [ebp-8],cx14:var3 = arg3;00401166 mov dl,byte ptr [ebp+10h]00401169 mov byt e ptr [ebp-0ch],dl15:16:arg1 = -1;0040116c mov dword ptr [EBP+8],0FFFFFFFFH17:G_VAR1 = 111;0040117         3 mov DWORD ptr [G_var1 (0042ae74)],6fh18:return;19:}0040117d pop edi0040117e Pop       esi0040117f Pop  ebx00401180 mov esp,ebp00401182 pop ebp00401183 ret---No source file--------------------------- -----------------------------------00401184 int 3
First EBP is a stack-bottom pointer, is a high address (higher than ESP), the stack of functions should be between ESP and EBP, should not read and write the stack memory above EBP

Note that it should not be possible that a buffer overflow attack used by hackers is to take advantage of this and they can execute arbitrary code when your program accidentally writes to these places

Including adding an administrator account, and so on, this is usually a function such as strcpy, such as Char sztext[256], but the source string exceeds 256 bytes

The push EBP is the value that holds the bottom of the stack, which is called before the

MOV EBP, esp assigns the stack top to the bottom of the stack, equivalent to the top of the stack before the call as the current stack, and then

Sub ESP, 4Ch stack top reduces 4c=76 (19 DWORD), which is equivalent to a stack size of 76 bytes, thus creating a stack used by the current function

Next

Push EBX the base register into the stack, the compiler is very mechanical, in fact, so far, do not need a base register, of course, do not need to stage its value, but the compiler is not a person, it does not matter

Then the push ESI and EDI are the original pointer and the target pointer of the string operation, knowing the assembly language, the boy began to batch processing

Lea Edi,[ebp-4ch] In fact, EBP-4CH is ESP is the top of the stack, the top address as the purpose (memory address is lower)

mov ecx,13h number 0x13=19, remember the 19 DWORD you just said?

MOV eax,0cccccccch, string operation value, 0xCCCCCCCC

Rep stos dword ptr [edi], the value to which EDI points to a DWORD write eax, that is, 0XCCCCCCCC, if ECX is nonzero, EDI increments one DWORD to continue writing

Know why the VC variable why the default value is always 0xCC, the local variables are stored on the stack, now the entire stack is this value

In fact, there is another use, wait for the function to return when we say.

Now the "Spring Tanaka Reunion" officially began,


var1 = arg1;

mov Eax,dword ptr [ebp+8]

mov DWORD ptr [Ebp-4],eax

EBP is the new stack-bottom pointer, which is the original stack top, called by the previous time, call will push the return address (the instruction address is not the return value address),

So now EBP is pointing to the return address? Note the start of the push EBP, which then presses into a DWORD, so this time EBP is pointing to the original EBP

Stack to the low address extension, then ebp+4 is the return address of the function, the order is reversed, ebp+8 is the last push-in parameter, that is, the first parameter!

Stack to the low address extension, then ebp-4 is the first local variable, someone asked why mov to EAX, and then from EAX to the first local variable? Dichun said: This is not many times

Yuan Fang said: "mov instruction two parameters can not be memory, that is, memory, this is why the register is called the reason, English register is registered meaning, is both a noun is also a verb


Figured out this, the back of the good understanding, but with low-word, low-byte to transfer it

Then we modify the value of the parameter, in fact, it is understood, because the call directly after the add esp,xx parameter discarded, and thus does not change anything, except the temporary discarded stack

Next is the assignment of global variables, an immediate number to the memory address of the global variable, or understand the

There is no return value single function, the function end return has no meaning, if the above return will generate a jmp instruction, jump here to


Finally, clean the scene, the first push of the last pop to restore their previous values, restore the original stack top value, pop restore the original stack

The last RET instruction, which we have said at the time of the function call, is what happens if the return address in the stack (the address that the restored stack top ESP points to) is modified.

For example, point to the address of the ShellExecute API, the parameter is cmd/c net user admin1 123456/add

This is left to everyone to think about it, remember just said 0xCC another use, if there is no RET at this time, execution to the back is 0xCC this machine code corresponds to an int 3 interrupt

In debug, such as Ollydebug will be inserted at the breakpoint at 0xCC, the debugger to continue to restore the original value of this byte before continuing to execute

So, inadvertently the buffer, often caused by the memory is forbidden to access, or interrupt, and some people are very sensitive to it, like a beautiful skirt is blown up,

Amitabha, Sin!


The article seems very long, I first int3, the following continue

About the invocation of a compiled language function (i)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.