2016-09-14 120 views
10

我試圖把一個ELF文件到內存中,然後執行它,這些步驟如下:加載ELF文件到內存

1文件放入內存

int main() 
{ 
    printf("Hello world! \n"); 
    return 0; 
} 

2-編譯它gcc -o hello hello.c -static

ELF Header: 
    Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 
    Class:        ELF32 
    Data:        2's complement, little endian 
    Version:       1 (current) 
    OS/ABI:       UNIX - System V 
    ABI Version:      0 
    Type:        EXEC (Executable file) 
    Machine:       ARM 
    Version:       0x1 
    Entry point address:    0x8120 
    Start of program headers:   52 (bytes into file) 
    Start of section headers:   119864 (bytes into file) 
    Flags:        0x5000000, Version5 EABI 
    Size of this header:    52 (bytes) 
    Size of program headers:   32 (bytes) 
    Number of program headers:   4 
    Size of section headers:   40 (bytes) 
    Number of section headers:   18 
    Section header string table index: 17 

Program Headers: 
    Type   Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align 
    LOAD   0x000000 0x00008000 0x00008000 0x16828 0x16828 R E 0x1000 
    LOAD   0x016840 0x0001f840 0x0001f840 0x00250 0x02660 RW 0x1000 
    GNU_STACK  0x000000 0x00000000 0x00000000 0x00000 0x00000 RWE 0 
    EXIDX   0x015f40 0x0001df40 0x0001df40 0x008e8 0x008e8 R 0x4 

3-我寫一個裝載機(編譯爲ARM)

mmap2(0x8000, 92200, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x8000 
mmap2(0x1f000, 65536, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x1f000 

3.1-然後我就複製了所有的精靈字節到分配

3.2- JMP主要功能

ldr r0, =0x008160 
blx r0 

.text:00008160 ; int __cdecl main(int argc, const char **argv, const char **envp) 
.text:00008160     EXPORT main 
.text:00008160 main         ; DATA XREF: _start+8o 
.text:00008160           ; .text:off_8150o 
.text:00008160     STMFD   SP!, {R11,LR} 
.text:00008164     ADD    R11, SP, #4 
.text:00008168     LDR    R3, =(aHelloWorld - 0x8174) 
.text:0000816C     ADD    R3, PC, R3 ; "Hello world! " 
.text:00008170     MOV    R0, R3 
.text:00008174     BLX    puts 
.text:00008178     MOV    R3, #0 
.text:0000817C     MOV    R0, R3 
.text:00008180     LDMFD   SP!, {R11,PC} 
.text:00008180 ; End of function main 

的問題是,我每次站上罰球線0x8174,然後跳進去,位的指令後,我總是有在隨機位置的SIGSEGV,更多的時間碰撞指令是=>0x9cc0: ldr r0, [r0, #4]r0=0x70a34

00008000-0002f000 rwxp 00000000 00:00 0 
80000000-80001000 r-xp 00000000 b3:18 129754  /data/local/tmp/main 
80001000-8001a000 rwxp 00001000 b3:18 129754  /data/local/tmp/main 
becdf000-bed00000 rwxp 00000000 00:00 0 
ffff0000-ffff1000 r-xp 00000000 00:00 0   [vectors] 

這些多個指令壓腳提升崩潰:

.text:00009CB4 loc_9CB4        ; CODE XREF: pthread_mutex_lock_impl+18j 
.text:00009CB4     MOV    R3, #0xFFFF0FE0 
.text:00009CBC     BLX    R3 
.text:00009CC0     LDR    R0, [R0,#4] 

在這個位置0x9CB4r00x1f96c(這是確定),在BLX後的r00x70a34

(gdb) x/10x 0xffff0fe0 
0xffff0fe0: 0xee1d0f70 0xe12fff1e 0xee1d0f70 0x00000000 
0xffff0ff0: 0x00000000 0x00000000 0x00000000 0x00000005 
0xffff1000: Cannot access memory at address 0xffff1000 

謝謝!

+4

在將控件傳遞給加載的代碼之前,您至少應該解決所有動態依賴關係。 'main()'也不是你ELF的真正入口點。有所謂的啓動代碼 - 其目的是初始化C運行時。實際入口點地址放置在ELF標頭的某處。 – Sergio

+0

在將可執行文件映射到內存並跳到那裏執行操作系統的加載程序之前,會執行更多操作。 –

+2

嗯,是的,那個「放」電話去哪兒呢?你有沒有加載並初始化C庫?修復了所有的重定位?加載任何東西,不僅僅是一個簡單的,靜態鏈接的,與位置無關的二進制文件需要佔用兩個以上的'mmap'和'memcpy'。 – Notlikethat

回答

3

我試圖把一個ELF文件到內存中,然後執行它,

對於一個完全靜態鏈接的可執行文件,你的步驟將工作(除非你需要跳轉到_start = =入口點0x8120,而不是main)。

然後我就複製了所有的精靈字節到分配

另一個可能的問題是不重視的.p_offset。你memcpy IES應該是這個樣子:

unsigned char buf1[0x16828]; // read 0x16828 bytes from start of file 
memcpy(0x8000, buf1, 0x16828); 

unsigned char buf2[0x250]; // read 0x250 bytes from offset 0x016840 into the file 
memcpy(0x0001f840, buf2, 0x250); 
+0

它看起來不像動態鏈接的可執行文件,因爲沒有INTERP程序頭。如果它是動態鏈接,將包含動態加載器的名稱,並且他必須加載並正確執行。他的問題是他沒有使用正確的入口點。 –

+0

@RossRidge你是對的。他在鏈接上有'靜止'。對不起,我錯過了。 –

+0

re對此答案的以前的版本:在一個動態的二進制文件,你可以像內核一樣加載ELF解釋器到內存中,並跳到它的入口點,對吧?如果你只是想避免調用execve(),那不應該阻止你繼續使用現有的動態鏈接器。 –

2

你的問題是,你需要使用正確的切入點,你需要初始化程序的堆棧(也許寄存器)相同的方式,操作系統將。您需要使用正確的入口點,以便C運行時庫被初始化,否則您對printf(或puts,視情況而定)的調用幾乎肯定會崩潰。您需要正確設置堆棧,因爲這是C運行時庫的初始化代碼將查找程序的參數和環境(以及其他內容)的地方。

你沒有說你正在使用哪種操作系統,但是如果你使用Linux,你可能想看看CesarB describing the initial state of the stack on ARM Linux給出的不同問題的答案。