загрузить файл 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-тогда я скопировал все байты elf в распределения

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]

в этом месте 0x9CB4, стоимостью r0 is 0x1f96c (это нормально), после blx значение r0 is 0x70a34

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

спасибо!

2 ответов


Я пытаюсь поместить файл elf в память, а затем выполнить его,

для полностью статически связанного исполняемого файла ваши шаги будут работать (за исключением того, что вам нужно перейти к _start == точка входа 0x8120, не main).

тогда я скопировал все байты elf в распределения

еще одна возможная проблема-не обращая внимания на .p_offset. Ваш memcpyies должен выглядеть примерно так это:

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);

ваша проблема в том, что вам нужно использовать правильную точку входа, и вам нужно инициализировать стек программы (и, возможно, регистры) так же, как и ОС. Вам нужно использовать правильную точку входа, чтобы библиотека времени выполнения C была инициализирована, иначе ваш вызов printf (или puts как это может быть) почти наверняка произойдет сбой. Вам нужно правильно настроить стек, потому что именно там код инициализации библиотеки времени выполнения C будет искать аргументы программы и окружающая среда (и, возможно, другие вещи).

вы не сказали, какую операционную систему вы используете, но если вы используете Linux, вы можете посмотреть как ответ на другой вопрос, заданный CesarB описание начального состояния стека в arm Linux.