之前寫了一篇關於win平臺下,從內存執行二進制碼的文章,所以此文主要修改自那篇。
大家可能會很好奇,我們的任意程序,不就是在內存中執行的二進制機器碼嗎?
不,今天我要說的是,我們如何把實現指定功能的一段二進制機器碼,放到我們的程序中,然後在需要的時候,直接調用它。
當然,這段代碼也有其他用途,故而有了shell code的暱稱,參考百度百科:
https://baike.baidu.com/item/shellcode/4051847?fr=aladdin
思考:
我們需要解決以下問題
- 二進制代碼從哪裏來?
- c/c++中如何調用它?
這些問題,接下來,都會得到解決。
不過,我們先來看看效果。
一、執行二進制代碼效果
main.c:
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
typedef int(*AddFunc)(int, int);
int main()
{
// int add(int a, int b)函數64位系統下二進制碼
unsigned char add_binaryCode[] = {
0x55,
0x48, 0x89, 0xe5,
0x89, 0x7d, 0xfc,
0x89, 0x75, 0xf8,
0x8b, 0x55, 0xfc,
0x8b, 0x45, 0xf8,
0x01, 0xd0,
0x5d,
0xc3
};
// 申請EXECUTE屬性內存
void* execBuf = mmap(NULL, sizeof(add_binaryCode), PROT_WRITE | PROT_EXEC,MAP_ANON | MAP_PRIVATE, -1, 0);
// 拷貝二進制碼
memcpy(execBuf, add_binaryCode, sizeof(add_binaryCode));
// 執行二進制碼
AddFunc func = (AddFunc)execBuf;
int ret = func(1, 2);
printf("result:%d\n", ret);
// 釋放內存
munmap(execBuf, sizeof(add_binaryCode));
return 0;
}
Ubuntu環境64位下編譯執行
gcc main.c -o main.out
./main.out
add_binaryCode中裝的是add函數二進制碼,C函數形式如下:
int add(int a, int b)
{
return a + b;
}
我們不能在數組中執行二進制碼,這樣會報異常,故需要申請帶可執行屬性的內存,然後拷貝到其中,強轉類型後,調用此函數。
運行結果:
運行結果正確,且沒有報異常。
小結:
我們可以把邏輯代碼封裝爲函數,並轉換爲二進制碼,然後在c/c++中進行調用執行。
到此我們解決了,在c/c++中如何執行二進制碼的問題。
接下來,我們來解決二進制碼如何生成的問題。
二、二進制代碼的生成
個人認爲有2種方式生成二進制碼
1.純手寫十六進制機器碼
2.採用c/c++等高級語言編寫程序,編譯後,對其反彙編進而獲得十六進制機器碼
第一種,好比回到了紙帶打孔編程的石器時代,需要了解x86指令集及其對應機器碼,能力有限,直接放棄。
接下來,採用第二種方式,大概講下,怎麼通過自己寫的函數,去提取生成的二進制碼。
1. 編寫add測試函數
add.c:
int add(int a, int b)
{
return a + b;
}
2. 編譯,生成*.o文件
gcc -c add.c -o add.o
3. 提取add函數二進制碼
objdump -j .text -d add.o
每行":"後面的十六進制數字就是機器碼。如下:
故,我們把這些機器碼拷貝出來,放到數組中
unsigned char add_binaryCode[] = {
0x55,
0x48, 0x89, 0xe5,
0x89, 0x7d, 0xfc,
0x89, 0x75, 0xf8,
0x8b, 0x55, 0xfc,
0x8b, 0x45, 0xf8,
0x01, 0xd0,
0x5d,
0xc3
};
這些機器碼就是我們add函數編譯後生成的二進制碼,即最終在內存中,cpu執行的機器碼。我們讓這個數組按照第一節中的方式,就可以在c/c++代碼中進行調用執行了。
三、從文件中讀取二進制碼並執行
似乎本節的意義並不大,無非就是讀取出來,放到buffer中,再執行罷了,主要的執行原理、二進制碼生成都已經講完了,這個就留給大家自行擴展吧。
四、總結
機器碼的獲取,比較關鍵的就是objdump這條命令。
另外執行時,比較關鍵的是,需要把機器碼放到mmap指向的內存中去,不能在普通內存中執行。
代碼地址:
https://gitee.com/bailiyang/cdemo/tree/master/C++/08ExecBinaryFromBuffer/ExecBinaryFromBuffer_linux
參考鏈接:
===================================================
===================================================
業餘時間不定期更新一些想法、思考文章,歡迎關注,共同探討,沉澱技術!