之前已經知道了函數這個玩意在計算機中的本質,本身在棧中存放其實就是一個指針的方式,而指針指向的內容就是在內存中存放的機器碼。
解釋到這裡就已經很明顯了,函數其實並不是一定要在編譯期載入內存後靜態,也就是固定的方式運行的。
我們可以手動開闢內存,輸入機器碼,然後讓指針指向這塊內存。從而實現在運行時動態生成函數。
哦呼~想想就有點激動,這個邏輯其實就有點像動態語言,例如PHP,JAVA,Python的解釋器的工作方式。
而且這個方式可以不用在語言中編寫彙編,可以繞過某些平臺無法在C中編寫彙編的限制。
首先我們得獲取機器碼,我這裡直接通過反彙編直接獲取。
1//0x00005555555547a7 <+0>: 55 push rbp
2//0x00005555555547a8 <+1>: 48 89 e5 mov rbp,rsp
3//0x00005555555547ab <+4>: b8 01 00 00 00 mov eax,0x1
4//0x00005555555547b0 <+9>: 5d pop rbp
5//0x00005555555547b1 <+10>: c3 ret
6int ret() {
7 return 1;
8}
然後把這些機器碼寫進內存, 之後進行類型強轉之後,就可以直接運行。
1char ret_code[] = {
2 0x55,
3 0x48, 0x89, 0xe5,
4 0xb8, 0x10, 0x00, 0x00, 0x00,
5 0x5d,
6 0xc3
7 };
8
9 void *tmp = mmap(
10 NULL,
11 getpagesize(),
12 PROT_READ | PROT_WRITE | PROT_EXEC,
13 MAP_ANONYMOUS | MAP_PRIVATE,
14 -1,
15 0
16 );
17
18 memscp3(tmp, ret_code, sizeof(ret_code));
19
20 ret_p p = tmp;
21
22 int bbb = p();
23
24 printf("%d\n", bbb);