2016-09-14 62 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给出的不同问题的答案。