📄 说明.txt
字号:
说明
~~~~~~~~~~~~~~~
本示例用于演示如何在BASM中使得“jmp proc”执行后返回到下一行。
尽管使“jmp proc”执行后返回到下一行的方法很多,但要实现如下
两个目标却是比较难于做到的:
1. 不破坏栈结构,使proc()与当前函数有相同的入口参数(stdcall)
2. 代码通用,不需要每次都计算地址
这样的需求可能出现在使用raw hook技术实现的API拦截上。
本例实现了满足上述需求。但它同时导致一个严重问题:由于修改了栈
上的返回地址,因此事实上当前的JmpCall()过程在执行完并返回(ret)
时,将取得一个非确定的地址值。
这在本例中的直接后果就是:代码未尾的"readln;"一行将无法执行到。
要避免这个问题,应该使用一个内存地址来暂存“当前的”返回地址,
并在“jmp proc”之后修正堆栈。例如:
______________________________________________________
var
temp : Pointer;
// ...
mov ebx, [esp] // 当前的返回地址
mov temp, ebx // 暂存到temp
DB $E8, $0, $0, $0, $0, $8F, $04, $24, $83, $04, $24, $0C
jmp proc
push temp // 重填当前例程的返回地址
@@ReturnHere:
______________________________________________________
更复杂的情况与例程的入口参数有关。由于除cdecl之外的调用约定都要求目前例
程在退出之前清除堆栈。因此上例在实用中更常见的用法会是:
______________________________________________________
// ...
// 1. 备份栈上的参数和返回地址(到堆)
DB $E8, $0, $0, $0, $0, $8F, $04, $24, $83, $04, $24, $0C
jmp proc
// 2. 从堆中恢复参数和返回地址(到栈)
@@ReturnHere:
______________________________________________________
这其实已经使前面所列的两个目标中“代码通用”变得无法实现。如果摒弃这些
需求,那么更常见的做法是:
______________________________________________________
// ...
// 1. 在栈上再分配同等大小的空间
// 2. 在栈上再制作一个入口参数块(内存复制)
call proc // call, 将返回到地址@@ReturnHere
@@ReturnHere:
______________________________________________________
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -