前一篇演示了在堆上分配空间,生成出可执行代码,并执行之。一般来说可执行代码都是在代码段里的,在堆上和在数据段里都的不是“正常编译”得到的代码。这次就来演示一下把代码放到数据段的例子吧~
代码如下。跟前一篇一样,把对应的机器码和汇编都写在注释里,方便理解。
#include <stdio.h>
typedef int (*puts_ptr)(const char*);
typedef void (*myfunc_ptr)(puts_ptr);
/*
void foo(puts_ptr p) {
p("greetings from generated code!");
}
*/
/* code as string in data section:
offset | bytes (in hex) | mnemonics
00 | 55 | push EBP
01 | 8BEC | mov EBP, ESP
03 | E8 00000000 | call next instruction
08 | 58 | pop EAX
09 | 83C0 0D | add EAX, 0D
12 | 50 | push EAX
13 | FF55 08 | call dword ptr [EBP + 8]
16 | 83C4 04 | add ESP, 04
19 | 5D | pop EBP
20 | C3 | ret
*/
int main() {
myfunc_ptr pMyfunc;
puts_ptr pPuts = &puts;
const char* code = "\x55\x8B\xEC\xE8\x00\x00\x00\x00"
"\x58\x83\xC0\x0D\x50\xFF\x55\x08"
"\x83\xC4\x04\x5D\xC3"
"greetings from generated code!";
pMyfunc = (myfunc_ptr)code;
pMyfunc(pPuts);
return 0;
}
可以看到,这个例子的关键就是源码里的字符串字面量——那堆奇怪的\xNN和后面接着的问候语。不要忘记C/C++里相邻的字符串字面量会被编译器合并为一个字符串常量。Windows上的
PE文件区分代码段(一般在.text section里)与数据段(一般在.data section和.rdata section;后者是只读数据段)里,而这个字符串字面量就会被安置在数据段中。
这个例子里放在数据段的代码的结构与前一篇放在堆上的代码基本一样,也是把代码与其需要的数据混在一起,前面是代码,字符串数据紧跟在代码后。
不同的是:前一篇生成的代码中第3条指令是一个push imm32,压入栈的是直接量;这个直接量是在生成代码时通过相对偏移量计算出来的。这个例子则使用了一个小trick来获取基地址,直接在代码中计算push的值,使用压入栈指令是push EAX。这个trick是以下的指令序列:
offset | bytes (in hex) | mnemonics
03 | E8 00000000 | call next instruction
08 | 58 | pop EAX
09 | 83C0 0D | add EAX, 0D
首先是一条call imm32指令,参数是0x00000000。这条指令的语义是:把下一条指令的地址作为返回地址压入栈,并且跳转到下一条指令的地址+0x00000000的位置。注意这条指令的32位直接量是2的补码,是带符号的。执行这条指令之后,我们就让CPU把call指令的下一条指令的地址压到了栈上,这样就可以知道“基地址”是多少了。
接下来是pop EAX,把刚才压到栈上的“返回地址”弹出来,赋值给EAX。
然后是add EAX, imm8。数一下指令的长度,可以知道要显示的字符串距离pop EAX指令的偏移量是13,也就是0x0D;所以把前面得到的“基地址”加上这个偏移量,就得到了要显示的字符串的起始地址。
后面的指令序列基本上就跟前一篇的一样了,不用多解释。
这种获取地址的trick在可重定位的代码(relocatable code)中很常见。例如编译器生成一个DLL的时候,它不知道实际运行的时候装载器会把DLL image装载到什么地址,所以里面跟地址相关的代码都得编译为基地址+偏移量的形式。基地址的获取经常就是用类似的trick来完成的。
前一篇提到了Windows Vista和Windows 7上的DEP,它对数据段的可执行性也有限制:数据段内存被认为是
不可执行的。所以这个例子在上述两种操作系统(和对应的Server版)里直接编译运行会出错。这些系统认为可执行代码就应该保存到代码段,所以上例中放在字符串中的代码也应该移到代码段中。
在堆上和数据段里放代码有什么意思呢?就像有些时候C的switch...case语句会被编译为基于表的跳转,而这个跳转表就夹杂在指令序列中一样,代码和数据其实没有明显的界限——冯·诺依曼体系结构的机器上,存储器既可以用于保存代码,也可以用于保存数据;代码就是数据,数据可以看作代码来执行。这篇和前一篇的demo只是演示了这一点而已。引申开来,有时候我们会希望根据运行时的某些特定条件来动态生成些效率较高的、特化的代码,而不是使用通用但效率较低的代码,这个时候就需要用到动态代码生成技术。生成的代码放在内存里,如果不能执行那就不好玩了。这两个demo演示了动态生成代码是可执行的。
下次再写咯……喝茶去~
分享到:
相关推荐
微信小程序demo:商城(源代码+截图)微信小程序demo:商城(源代码+截图)微信小程序demo:商城(源代码+截图)微信小程序demo:商城(源代码+截图)微信小程序demo:商城(源代码+截图)微信小程序demo:商城(源代码+截图)...
微信小程序demo:简易抽奖(源代码+截图)微信小程序demo:简易抽奖(源代码+截图)微信小程序demo:简易抽奖(源代码+截图)微信小程序demo:简易抽奖(源代码+截图)微信小程序demo:简易抽奖(源代码+截图)微信小程序demo...
android 串口测试demo 代码简单 无bug 完美运行 android 串口测试demo 代码简单 无bug 完美运行 android 串口测试demo 代码简单 无bug 完美运行 android 串口测试demo 代码简单 无bug 完美运行 android 串口测试demo...
微信小程序demo:商城分销系统(源代码+截图)微信小程序demo:商城分销系统(源代码+截图)微信小程序demo:商城分销系统(源代码+截图)微信小程序demo:商城分销系统(源代码+截图)微信小程序demo:商城分销系统(源代码+...
微信小程序demo:花店(源代码+截图)微信小程序demo:花店(源代码+截图)微信小程序demo:花店(源代码+截图)微信小程序demo:花店(源代码+截图)微信小程序demo:花店(源代码+截图)微信小程序demo:花店(源代码+截图)...
微信小程序demo组件:canvas股票分时图(源代码+截图)微信小程序demo组件:canvas股票分时图(源代码+截图)微信小程序demo组件:canvas股票分时图(源代码+截图)微信小程序demo组件:canvas股票分时图(源代码+截图)微信...
微信小程序demo:在线聊天功能(源代码+截图)微信小程序demo:在线聊天功能(源代码+截图)微信小程序demo:在线聊天功能(源代码+截图)微信小程序demo:在线聊天功能(源代码+截图)微信小程序demo:在线聊天功能(源代码+...
微信小程序demo:逗乐(源代码+截图)微信小程序demo:逗乐(源代码+截图)微信小程序demo:逗乐(源代码+截图)微信小程序demo:逗乐(源代码+截图)微信小程序demo:逗乐(源代码+截图)微信小程序demo:逗乐(源代码+截图)...
小程序源码 移动端小商城DEMO (商城demo源码) (代码源)小程序源码 移动端小商城DEMO (商城demo源码) (代码源)小程序源码 移动端小商城DEMO (商城demo源码) (代码源)小程序源码 移动端小商城DEMO (商城demo源码) ...
适用1028版本(源代码+截图)微信小程序demo:智能机器人;适用1028版本(源代码+截图)微信小程序demo:智能机器人;适用1028版本(源代码+截图)微信小程序demo:智能机器人;适用1028版本(源代码+截图)微信小程序demo:...
微信小程序学习demo:基础接口演示demo(源代码+截图)微信小程序学习demo:基础接口演示demo(源代码+截图)微信小程序学习demo:基础接口演示demo(源代码+截图)微信小程序学习demo:基础接口演示demo(源代码+截图)微信...
微信小程序服务端开发demo(源代码+截图)微信小程序服务端开发demo(源代码+截图)微信小程序服务端开发demo(源代码+截图)微信小程序服务端开发demo(源代码+截图)微信小程序服务端开发demo(源代码+截图)微信小程序...
微信小程序练习demo:练习demo(源代码+截图)微信小程序练习demo:练习demo(源代码+截图)微信小程序练习demo:练习demo(源代码+截图)微信小程序练习demo:练习demo(源代码+截图)微信小程序练习demo:练习demo(源代码+...
微信小程序demo:豆瓣(源代码+截图)微信小程序demo:豆瓣(源代码+截图)微信小程序demo:豆瓣(源代码+截图)微信小程序demo:豆瓣(源代码+截图)微信小程序demo:豆瓣(源代码+截图)微信小程序demo:豆瓣(源代码+截图)...
微信小程序demo:豆瓣电影:使用API(源代码+截图)微信小程序demo:豆瓣电影:使用API(源代码+截图)微信小程序demo:豆瓣电影:使用API(源代码+截图)微信小程序demo:豆瓣电影:使用API(源代码+截图)微信小程序demo:...
微信小程序学习demo:表单练习(源代码+截图)微信小程序学习demo:表单练习(源代码+截图)微信小程序学习demo:表单练习(源代码+截图)微信小程序学习demo:表单练习(源代码+截图)微信小程序学习demo:表单练习(源代码+...
微信小程序demo:归谷(源代码+截图)微信小程序demo:归谷(源代码+截图)微信小程序demo:归谷(源代码+截图)微信小程序demo:归谷(源代码+截图)微信小程序demo:归谷(源代码+截图)微信小程序demo:归谷(源代码+截图)...
微信小程序后台demo:基于springboot(源代码+截图)微信小程序后台demo:基于springboot(源代码+截图)微信小程序后台demo:基于springboot(源代码+截图)微信小程序后台demo:基于springboot(源代码+截图)微信小程序...
微信小程序demo:ihobby(源代码+截图)微信小程序demo:ihobby(源代码+截图)微信小程序demo:ihobby(源代码+截图)微信小程序demo:ihobby(源代码+截图)微信小程序demo:ihobby(源代码+截图)微信小程序demo:ihobby(源...
微信小程序demo:奔跑果果(源代码+截图)微信小程序demo:奔跑果果(源代码+截图)微信小程序demo:奔跑果果(源代码+截图)微信小程序demo:奔跑果果(源代码+截图)微信小程序demo:奔跑果果(源代码+截图)微信小程序demo...