天书夜读 第一章笔记

来源:互联网 发布:北京大学数学学院知乎 编辑:程序博客网 时间:2024/04/27 14:15

1.call的本质相当于push+jmp,ret的本质相当于pop+jmp,call和ret都要操作堆栈,而jmp只是单纯的跳转,不会对堆栈进行操作

2.lea 取得地址(第二个参数)后放入第一个参数中,也可用来赋值,如lea edi,[ebp-0cch],中括号是取得地址的内容,即取得ebp-0cch这个地址的内容,也就

相当于mov edi,ebp-0cch,但mov操作符不支持后一个参数的形式是寄存器减去一个数,而lea支持,所以可以用lea来代替

3.stos指令,将eax中的内容copy到一个目的地址指向的区域,另外还有stosb stosw指令,b和w指示了每次copy的大小,b即byte,w即word

看一段程式化的反汇编代码

这段代码是初始化堆栈和分配局部变量用的,往分配好的堆栈空间放入int3中断。

这里面用到了rep,stos指令,rep即重复执行ECX中的次数,直至为0,而rep stos dword ptr es:[edi],就是指用eax中的值初始化es:[edi]所指向的区域,dword ptr表明每次是四个字节,一共循环十次,而地址是往栈底方向还是往栈顶方向由标志寄存器的D位决定,d为0往栈底方向,d为1往栈顶方向。

4.跳转指令jmp 无条件跳转

jg:大于的时候跳转,前面通常有个cmp指令

jl:小于的时候跳转,前面通常有个cmp指令

jge:大于等于。。。。。

jle:小于等于。。。

5.函数调用规则:

(1)c语言调用规则(cdecl)

参数自右向左入栈,由调用者清除堆栈。所以生成的可执行文件较大

(2)winapi调用规则(_stdcall)

参数自右向左入栈,由被调用者清除堆栈。所以生成的可执行文件较小

5.函数调用的反汇编代码:

void myfunction(int a,int b)

{

push ebp ;保存ebp,并把esp放入ebp中,

mov ebp,esp                 ;此时,ebp和esp都是这次函数调用的时的栈顶

sub esp,0cch  ;把esp往上移动一个范围,等于在堆栈中放出一片新的

 ;空间用来存储局部变量

push ebx ;下面保存三个寄存器:ebx、esi、edi

push esi

push edi


lea edi,[ebp - 0cch]     ;本来是“mov edi,ebp-0cch”,但是mov不支持

;"-"操作,所以对ebp-0cch取内容,而lea把内容

;的地址,也就是ebp-0cch加载到edi中,目的是

;把保存的局部变量的区域(从ebp-0cch开始的区域)

;初始化成全部0cccccccch

mov ecx,33h

mov eax,0cccccccch

rep stos dword ptr [edi] ;写入0cch指令(中断)

int c = a+b

mov eax,dword ptr [a]

add eax,dword ptr [b]   ;其实这两条指令时 mov eax,[ebp+8],add eax,[ebp+0ch]

;参数是通过ebp从堆栈中取得的

mov dword ptr [c],eax

}

pop edi

pop esi

pop ebx

mov esp,ebp   ;恢复原来的ebp和esp,让上一个调用函数正常使用

pop ebp

ret


主程序中对这个函数的调用方式是:

mov eax,dword ptr [b] ;把b,a两个参数压入堆栈

push eax

mov ecx,dword ptr [a]

push ecx

call myFunction

add esp,8 ;恢复堆栈


至于以上代码中被调用函数为什么用[ebp+8]和[ebp+0ch]来取得参数,是因为,主程序在调用被调用函数的时候,先将两个参数(均为四个字节,32为cpu就为四个字节)

压入栈,call指令又会把主程序中的下一条指令地址压入栈,然后进入子程序后,又会将ebp压栈,所以找参数a要ebp+8,而参数b则ebp+0ch

原创粉丝点击