逆向工程-printf()函数与参数传递

#include

int main()

{

printf("a=%d; b=%d;c=%d",1,2,3);

return 0;

}

 

 

x86传递3个参数

$SG3830 DB 'a=%d;b=%d;c=%d',00h

...

push 3

push 2

push 1

push OFFSET $SG3830

call _printf

add esp,16

 

函数的参数以逆序存入栈里,第一个参数在最后入栈。

32位地址指针和int类型数据都占据32位/4字节空间。4个参数总共占16字节的存储空间

在调用函数之后,“ADD ESP,X”指令修正ESP寄存器中的栈指针。

 

如果某个程序连续地调用多个函数,且调用函数的指令之间不夹杂其他指令 ,那么编译器可能把释放参数存储空间的“ADD ESP,X”指令进行合并,一次性释放所有空间。

push a1

push a2

call ...

...

push a1

call ...

push a1

push a2

push a3

call ...

add esp,24

如下例:

push 3

call sub_100018B0

call sub_100019D0

call sub_10006A90

push 1

call sub_10006A90

add esp,8

 

cdecl调用约定的特征:被调用方函数不负责恢复ESP的状态;调用方函数负责还原参数所用的空间。

ADD ESP,10

ESP寄存器的值有变化,但是栈中的数据还在那里。因为程序没有把原有的栈的数据进行清零,所以保留在栈指针SP之上的参数值就成为了噪音或者脏数据。

 

GCC编译

main proc near

 

var_10 =dword ptr-10h

var_C =dword ptr-0Ch

var_8 =dword ptr-8

var_4 =dword ptr-4

push ebp

mov ebp,esp

and esp,0FFFFFFF0h

sub esp,10h

mov eax,offset aADBDCD;"a=%d;b=%d;c=%d"

mov [esp+10h+var_4],3

mov [esp+10h+var_8],2

mov [esp+10h+var_C],1

mov [esp+10h+var_10],eax

call _printf

mov eax,0

leave

retn

main endp

与MSVC生成 程序相比,GCC生成的程序仅在参数入栈的方式上有所区别。GCC没有使用PUSH/POP指令,而是直接对栈进行了操作。

 

ARM模式下传递3个参数

ARM系统在传递参数时,通常会进行拆分:把前4个参数传递给R0~R3寄存器,然后利用栈传递其余的参数。

 

32位ARM系统

非经优化的Keil+ARM模式

main

STMFD SP!,{R4,LR}

MOV R3,#3

MOV R2,#2

MOV R1,#1

ADR R0,aADBDCD; "a=%d;b=%d;c=%d"

BL __2printf

MOV R0,#0

LDMFD SP!,{R4,PC}

 

R0~R3寄存器依次负责传递参数。R0 寄存器置0,对应着return 0

 

你可能感兴趣的:(汇编语言)