逆向笔记--常用到的汇编知识点

函数调用与返回过程

call过程:
// 段内call通常进行两步操作
push 	ip
jmp 	addr
// 如果call的函数不是本段当中的地址
push	cs
push 	ip
jmp 	addr
ret过程:
ret实际上是一个伪指令,由编译器决定在编译时最终使用retn(return from near procedure)或者retf(return from far procedure),这实际上对应了call的两种方式

段内call不需要将段地址压栈,对应的retn只需要实现

pop ip

段间call需要将段地址压栈,因此对应的retf实现

pop ip
pop cs

堆栈设置

每一个函数都需要自己的堆栈,而call指令并没有为被调用函数设置堆栈,因此需要在子程序的开头设置堆栈

push ebp
mov ebp, esp
----------------------
// 子程序内容
----------------------
mov esp, ebp
pop ebp
ret

参数传递

//	主程序按从右向左的顺序将参数逐个压栈,最后一个参数先入栈。每一个参数压栈一次。
//	在子程序中,使用[EBP+X] 的方式来访问参数。X=8 代表第 1 个参数;X=12 代表第二个参数,依次类推
//	[ebp+4]保存ip的值,因为call会将当前ip压栈
push arg3
push arg2
push arg1
call func

GS安全编译

GS是针对栈的一种保护机制,具体的过程如下:

在函数调用发生时,会使用一个随机值(IDA中会标记为__security_cookie)来防止栈溢出
在这里插入图片描述
以上程序中重点需要关注这几句

mov eax, __security_cookie
xor eax, ebp
mov [ebp+var_4], eax
-------------------
mov ecx, [ebp+var_4]
xor exc, ebp
call ....

通俗的来讲就是首先对ebp和__security_cookie做异或,结果放在ebp-4的位置,也就是ebp下面的第一个位置,在函数ret之前,取出这个值和ebp再做一次异或,两次异或后的结果就会恢复为__security_cookie,只需要验证__security_cookie就知道是否发生了溢出

猜你喜欢

转载自blog.csdn.net/adventural/article/details/107937367