2013-10-28 44 views
14

是否有可能通過動態分配內存,寫一些彙編操作碼給它創造一個動態功能(如的0x90爲0xC2NOP RET),創建一個函數指針,它指向的是動態內存並執行它像一個C程序中的常規函數​​?C函數指針:我可以跳轉到堆內存彙編代碼嗎?

目標應該是一個普通的x86 Linux系統。

+0

類似的,但不是相同的東西 - 'int main = 0xc290;'編譯併成功運行。 – ugoren

+0

@ugoren僅在某些情況下。 – glglgl

+0

@glglgl,在問題描述的情況下。 – ugoren

回答

3

該內存沒有堆內存(請參閱下面的註釋)。此外,我認爲你不能改變堆內存的執行權限。

在Linux上,您可以使用以下方法:

#include <sys/mman.h> 
size_t size = 0x1000; // 1 page 
// this will be mapped somewhere between /lib/x86_64-linux-gnu/ld-2.15.so 
// and stack (see note and memory map below) 
void *code = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS, -1, 0); 
// use `code` to write your instructions 
// then store location at which you want to jump to in `fp` 
void *fp = ...; 
mprotect(code, size, PROT_READ | PROT_EXEC); 
// use some inline assembly to jump to fp 

注意:在Linux上,用戶映射內存位於不同的區域(像從400000000000和最多疊加在x86 Linux和可能是在x64上的7f0000000000)。堆位於程序的ELF段之後,位於區域之前,可用於mmap。堆本身可以直接使用brk系統調用進行分配(現在替代爲malloc)。看到這個例子(得到了我的Ubuntu 12.10 64位):

➜ ~ ps 
    PID TTY   TIME CMD 
9429 pts/3 00:00:07 zsh 
20069 pts/3 00:00:00 git-credential- 
22626 pts/3 00:00:00 ps 
➜ ~ cat /proc/9429/maps 
00400000-004a2000 r-xp 00000000 08:01 6291468       /bin/zsh5 
006a1000-006a2000 r--p 000a1000 08:01 6291468       /bin/zsh5 
006a2000-006a8000 rw-p 000a2000 08:01 6291468       /bin/zsh5 
006a8000-006bc000 rw-p 00000000 00:00 0 
01a51000-01fd8000 rw-p 00000000 00:00 0         [heap] 
... 
7f6529d61000-7f6529d91000 rw-p 00000000 00:00 0 
... 
7f652d0d3000-7f652d0d5000 rw-p 00023000 08:01 44833271     /lib/x86_64-linux-gnu/ld-2.15.so 
7fffd7c7f000-7fffd7cae000 rw-p 00000000 00:00 0       [stack] 
7fffd7dff000-7fffd7e00000 r-xp 00000000 00:00 0       [vdso] 
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0     [vsyscall] 

正如你所看到的,heap不是可執行文件(並且是理所當然的),所以你不能用malloc獲得可執行內存。

2

許多系統很長一段時間都在虛擬內存頁面上有標誌,告訴它們是否可以包含可執行代碼。內存分配堆最有可能不會有這個「可執行」標誌集。所以不,你不能直接做到這一點。

如果您想這樣做,您必須使用操作系統特定的功能,並且可能必須以「管理員」或「根」身份運行該程序才能夠執行此操作,儘管似乎並不必要。

+2

我不認爲你需要成爲根,分配可執行內存不是這樣一個系統危害的事情,並有其用途(幾乎所有當前的瀏覽器在JavaScript引擎中)。 –

+0

更不用說越來越多的無處不在的.Net框架。 – Blindy

17

一般來說是的,但你需要進入系統特定的東西來這樣做。我猜想這並不令人感到意外,因爲您將使用二進制彙編指令的事實使其非常清晰。

您需要注意的是,您不能假設現代操作系統上的堆內存是可執行的,因此您可能需要跳過一些環節才能實現。您不能只調用malloc()並假定返回的指針指向可以執行代碼的內存。

在Linux中,您可以使用mmap()來要求內核爲您映射一些內存,並且通過在調用中指定PROT_EXEC標誌,您可以要求它使內存可執行。

+1

在Windows下,您可以使用[VirtualProtect](http://msdn.microsoft.com/zh-cn/library/aa366898%28v=vs.85%29。aspx) – Asaf

+1

我會說你甚至不能假定堆內存是可執行的。但是你並不需要這樣的記憶。看到我的答案。 –