![](/img/trans.png)
[英]how do you intercept the address of an instruction that is writing to a segment of memory?
[英]How can you mark a segment of memory as executable in C?
我最近在研究一些 JIT 編譯器。 據我所知,JIT 是一種將一些腳本語言代碼即時(在執行之前)編譯為本機代碼的技術。 當我想象這樣一個編譯器的內部時,我發現生成的本機代碼所在的地方一定有一段動態分配的緩沖區。 但是我們需要一種方法來從保存數據的緩沖區中開始運行代碼。 我的意思是,您不能只是將一些代碼放入char[]
,然后因為安全隱患而跳入執行,為此操作系統必須阻止您這樣做。 必須有某種方式將緩沖區標記為可執行文件。 考慮以下幼稚的方法:
#include <stdlib.h>
void *jit_some_native_code(void) {
void *code_segment = malloc(1024);
/*
* bla bla bla...
* Generate code into this code_segment.
*/
return code_segment;
}
int main(void) {
void *code = jit_some_native_code();
/*
* How can I start executing instruction in code?
*/
typedef void (*func_ptr_t)(void);
/*
* This won't work. OS bans you doing so.
*/
((func_ptr_t)code)();
}
在 Ubuntu 上,代碼將運行,但會以狀態代碼 26 退出。鑒於 C 的類型不安全性質,代碼可以編譯,但對於 C++,編譯器只會阻止您。 這是否意味着 JIT 必須繞過編譯器,同時設置可執行標志?
編輯:除了mprotect
,如果您使用mmap
,您還可以指定要映射的頁面的權限:
PROT_EXEC Pages may be executed.
PROT_READ Pages may be read.
PROT_WRITE Pages may be written.
PROT_NONE Pages may not be accessed.
因此,該頁面將具有可執行權限。
如果要在堆可執行文件中創建一個區域,可以使用mprotect 。
int main() {
typedef void (*func_t)(void);
void *code = &some_jit_func;
int pagesize = getpagesize();
mprotect(code, pagesize,PROT_EXEC);
((func_t)code)();
}
您還可以使用 PROT_READ/PROT_WRITE 或標志
在您的代碼中,您正在獲取現有函數的地址。 這自然會指向一個已經可以執行的內存區域。 但是同一個區域在任何現代系統上都是不可寫的。
另一方面,如果您 malloc() 一些內存,它將是可寫但不可執行的。 因此,您在 jit 編譯器中構建的任何代碼都將無法執行,並且嘗試調用您在那里構建的函數將失敗。 您必須首先使用mprotect使內存可執行。
出於安全原因,您應該遵循W^X
原則。 這意味着任何頁面都只能是可寫或可執行的,但不能兩者兼而有之。 當您使用 mprotect 使代碼可執行時,也會使其不可寫,反之亦然。 永遠不要將可寫和可執行結合起來。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.