初步研究了下一种有趣的技术: 能动态修改的代码。 把机器指令写到数组中,并且动态修改他。据称在某些场合能极大提高速度(譬如,无需传递参数,可以动态修改流程)。 偶今天用VC尝试了一下简单的ram函数,颇为有趣,虽然这个例子并未看到高效在哪里...
比如下面的程序定义了一个ram函数 addInt , 他将一个数加上另一个数(使用 IA-32指令集,即目前32位奔腾和AMD兼容机的指令集):
int main(){
static unsigned char addInt_fd[] = {
0x81, 0x05, //0000 add [<address>], <num>
0x00, 0x00, 0x00, 0x00, //0002 -<address>
0x00, 0x00, 0x00, 0x00, //0006 -<num> addInt_by
0xc3, //000a ret
};void* &addInt_address = *(void**)( addInt_fd + 0x02); // address of the num to add
long &addInt_num = *(long* )( addInt_fd + 0x06); // the constant to add to num
void (*addInt)() = (void (*)())((void*) addInt_fd ); // the func
int a = 874;
addInt_address = &a;
addInt_num = 5910000;addInt();
printf( "%d/n", a );
}
输出:
5910874
怎么做的呢? 首先讲一下用到的指令。 若有变量long a ,他的地址是 0x 004010ff。 我们要把它的内容增加 0xaabbccdd,最快速的指令是:
<格式> add dword ptr [ lhs ], rhs ; lhs 和 rhs 都是dword立即数
<指令> add dword ptr [ 0x004010ff ], 0xaabbccdd
<编码> 81 05 ff 10 40 00 dd cc bb aa
所以现在我定义一段内存 addInt_fd, 他的内容是半成品的 add 指令:
81 05 00 00 00 00 00 00 00 00
两个全0 的dword 是占位符。 现在我们可以在运行时把a 的地址写到 lhs 上,把需要增加的量写到 rhs 上,然后强行call 这个 addInt_fd 的地址。 最后加一个 ret 指令就可以返回,其编码是:
c3
为了方便调用和输入指令,我用两个引用指向需填参数的地址,并且用一个函数指针指向这段内存的首地址。这样就完成了。