从头开始创建简单的小型ELF

时间:2016-02-01 16:58:36

标签: linux linux-kernel executable elf

我目前正在尝试使用基于文档的ELFIO库创建简单的ELF可执行文件(第8页)[1]。这是从readelf输出的,当他们的代码略微修改后的版本上运行时(没什么重要的,只是不同的字符串和地址库。对齐,标志等都没有改变。)

ELF Header:
  Magic:   7f 45 4c 46 01 01 01 03 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - GNU
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Intel 80386
  Version:                           0x1
  Entry point address:               0x400000
  Start of program headers:          52 (bytes into file)
  Start of section headers:          4168 (bytes into file)
  Flags:                             0x0
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         2
  Size of section headers:           40 (bytes)
  Number of section headers:         4
  Section header string table index: 1

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .shstrtab         STRTAB          00000000 00102e 000017 00      0   0  0
  [ 2] .text             PROGBITS        00400000 001000 00001d 00  AX  0   0 16
  [ 3] .data             PROGBITS        00400020 001020 00000e 00  WA  0   0  4
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings)
  I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)

There are no section groups in this file.

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x001000 0x00400000 0x00400000 0x0001d 0x0001d R E 0x1000
  LOAD           0x001020 0x00400020 0x00400020 0x0000e 0x0000e RW  0x10

 Section to Segment mapping:
  Segment Sections...
   00     .text 
   01     .data 

此可执行文件运行正常。我想从文本部分进一步移动数据部分,所以我选择了地址0x400040。在这里你可以看到它就是我所做的一切。

ELF Header:
  Magic:   7f 45 4c 46 01 01 01 03 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - GNU
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Intel 80386
  Version:                           0x1
  Entry point address:               0x400000
  Start of program headers:          52 (bytes into file)
  Start of section headers:          4168 (bytes into file)
  Flags:                             0x0
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         2
  Size of section headers:           40 (bytes)
  Number of section headers:         4
  Section header string table index: 1

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .shstrtab         STRTAB          00000000 00102e 000017 00      0   0  0
  [ 2] .text             PROGBITS        00400000 001000 00001d 00  AX  0   0 16
  [ 3] .data             PROGBITS        00400040 001020 00000e 00  WA  0   0  4
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings)
  I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)

There are no section groups in this file.

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x001000 0x00400000 0x00400000 0x0001d 0x0001d R E 0x1000
  LOAD           0x001020 0x00400040 0x00400040 0x0000e 0x0000e RW  0x10

 Section to Segment mapping:
  Segment Sections...
   00     .text 
   01     .data 

但是,这个文件保留seg。一开始就错了。我真的不明白发生了什么。起初我虽然它与部分和段的对齐有关,但它们对我来说似乎没问题。我还怀疑ASLR(因为Hello World的地址是硬编码的,没有重定位)并试图在/proc/sys/kernel/randomize_va_space中将其关闭。我还检查了linux内核源代码,特别是文件fs/binfmt_elf.c,但为了完全理解那里发生了什么,我需要更多时间。所以我想请求你的帮助。如果你知道地址0x400040有什么问题,为什么这个文件会保留seg。错误,或者你可以指向我内核中的某些代码行,那么我真的很感激。

修改:我还尝试了gdb,但bt提供了No stack。在入口点地址上设置读取观察点不起作用。

编辑2:在使用该文件后,我发现将第二段的文件偏移从0x1020移动到0x1040会导致文件正常工作。所以现在我的问题是,文件偏移和虚拟地址是否需要处于某种关系?

[1] http://elfio.sourceforge.net/elfio.pdf

2 个答案:

答案 0 :(得分:2)

  

所以现在我的问题是,文件偏移和虚拟地址是否需要处于某种关系?

是:文件偏移量必须VirtAddrPhysAddr模数页面大小一致,因为文件是mmap直接(由内核加载程序)

如果您不保持这种关系,内核将创建一个新流程,尝试将您的可执行文件映射到它,发现您违反了基本约束,并将终止您的流程(使用SIGKILL , 我相信)。您的进程永远不会在用户空间中执行单个指令。

答案 1 :(得分:-1)

没有创建堆栈框架,这意味着在入口点之前出现了一些问题。 请告诉我文件是否与libc等任何库模块链接,因为它们将提供初始设置来调用我们的入口点函数。 使用gdb并在_start创建断点。如果您没有与图书馆链接,那么设置堆栈,参数,环境的任务将由您负责。