昨天晚上回去后实在无聊睡不着,拿着身边的 Yeeloong 笔记本随便找点事干干,想到了 JIT 的原理,于是简单的验证了一下运行时动态生成指令并执行。
我先找了一下进程中哪个 VMA 是可以执行的,使用命令 cat /proc/self/maps 可以找到:
00400000-0040c000 r-xp 00000000 08:02 524311 /bin/cat 00418000-0041c000 rw-p 00008000 08:02 524311 /bin/cat 0041c000-00440000 rwxp 00000000 00:00 0 [heap] 2b9c8000-2b9ec000 r-xp 00000000 08:02 917518 /lib/ld-2.14.so 2b9f8000-2b9fc000 rw-p 00020000 08:02 917518 /lib/ld-2.14.so 2ba18000-2bb70000 r-xp 00000000 08:02 918040 /lib/libc-2.14.so 2bb70000-2bb7c000 ---p 00158000 08:02 918040 /lib/libc-2.14.so 2bb7c000-2bb80000 r--p 00154000 08:02 918040 /lib/libc-2.14.so 2bb80000-2bb84000 rw-p 00158000 08:02 918040 /lib/libc-2.14.so 2bb84000-2bb88000 rw-p 00000000 00:00 0 2bb88000-2bd88000 r--p 00000000 08:02 786854 /usr/lib/locale/locale-archive 7ff70000-7ff94000 rwxp 00000000 00:00 0 [stack] 7fff4000-7fff8000 r-xp 00000000 00:00 0 [vdso] |
从上面的结果中可以看到 heap 和 stack 两个 VMA 的权限属性都是 rwxp,意味着我可以向里面存入指令并执行。
我选择了在栈中存入两条指令,然后转过去执行。代码如下:
#include <stdio.h> int main(int argc, char *argv[]) { unsigned int insn[] = { 0x1000ffff, 0x00000000 }; __asm__ volatile ( "jr %0 \n\t" "nop \n\t" ::"r"(insn) ); return 0; } |
编译程序后,执行这个程序就会进入栈里的死循环了。
你可能会想到这个操作系统的 heap 和 stack 具有可执行权限是不安全的,我确认了一下 x86 里没有可执行权限的,那么当没有可执行权限又应该怎么办呢?我们下次再说。
Over!