简介
我正在尝试学习ELF
文件,并尝试使用它们。目前,我正在学习教程here,它是关于创建一个32位ELF
小文件,它只是以代码42退出。本教程使用NASM
和ld
创建ELF
文件。但是,我想使用GNU Assembler (GAS)
创建一个64位ELF
文件(而不是32位),因为我对它有点熟悉(但不是使用它的Maven!)
我目前被困在教程的一部分,他们开始从头开始制作ELF
文件-这涉及到编写ELF
头和程序头。由于32位和64位ELF
文件略有不同(例如,在ELF头大小方面),我的.s
文件版本如下:
.intel_syntax noprefix
ehdr:
.byte 0x7F
.byte 0x45 # E
.byte 0x4c # L
.byte 0x46 # F
.byte 0x02 # 64 bit ; CLASS
.byte 0x01 # lsb ; DATA
.byte 0x01 # ; VERSION
.byte 0x00 # None/Sytem V ; OS ABI
.8byte 0x0 # ABI VERSION + PADDING
.2byte 0x02 # ET_EXEC ; E_TYPE
.2byte 0x3E # AMD64 ; E_MACHINE
.4byte 0x01 # 1 ; E_VERSION
.8byte _start # ; E_ENTRY
.8byte phdr - ehdr # offset into program header ; E_PHOFF
.8byte 0x00 # offset into section header ; E_SHOFF
.4byte 0x00 # flag ; E_FLAGS
.2byte ehdrsize # ELF header size ; E_EHSIZE
.2byte phdrsize # Program header size ; E_PHSIZE
.2byte 0x01 # Number of program headers ; E_PHNUM
.2byte 0x00 # Section header size ; E_SHENTSIZE
.2byte 0x00 # Number of section headers ; E_SHNUM
.2byte 0x00 # Section header string table index ; E_SHSTRNDX
DECLARE_ELF_HEADER_SIZE:
.set ehdrsize, DECLARE_ELF_HEADER_SIZE - ehdr
phdr:
.4byte 0x01 # PT_LOAD ; P_TYPE
.4byte 0x00 # located at offset 0??? ; P_OFFSET
.8byte ehdr # ; P_VADDR
.8byte ehdr # ; P_PADDR
.8byte filesize # ; P_FILESIZE
.8byte filesize # ; P_MEMSZ
.8byte 5 # R-X ; P_FLAGS
.8byte 0x1000 # P_ALIGN
DECLARE_PHEADER_SIZE:
.set phdrsize, DECLARE_PHEADER_SIZE - phdr
_start:
mov eax, 60
mov edi, 42
syscall
DECLARE_FILE_SIZE:
.set filesize, DECLARE_FILE_SIZE - ehdr
有关ELF文件头的更多信息可以通过查看相应的源代码here找到。由于我还在学习ELF
文件,上述代码可能不正确(如果您发现任何错误,请告诉我!)
问题
假设上面的代码是正确的,我想将上面的.s
文件转换为ELF
文件。为此,本教程使用以下命令:
$ nasm -f bin -o a.out tiny.asm
但是,我无法找到我应该使用GAS来创建相应的ELF
文件的相应命令,这就是我面临的问题。
What I Have Tried...
我尝试了各种方法。我将它们列在下面:
1.在SO上也有一个类似的问题,可以找到here。这种方法使用以下2个命令来获取相应的ELF文件:
$ as --64 -o test.o test.s
$ ld -Ttext 200000 --oformat binary -o test.bin test.o
对.s
文件运行我编写的相同命令,我确实得到了一个ELF文件,沿着以下警告:
ld: warning: cannot find entry symbol _start; defaulting to 0000000000200000
**运行生成的ELF文件会出现分段错误,退出代码为139。**生成的文件的ELF
头如下(通过运行readelf -h <output ELF file>
获得):
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x200078
Start of program headers: 64 (bytes into file)
Start of section headers: 0 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 1
Size of section headers: 0 (bytes)
Number of section headers: 0
Section header string table index: 0
readelf: Error: the segment's file size is larger than its memory size
我相信分段错误的发生是因为Entry Point address
很可能是不正确的(这也是由ld
在错误消息中暗示的)。
1.在这种方法中,我修改了命令:
$ as --64 -o test.o test.s
$ ld -Ttext 200000 --oformat binary -o test.bin test.o
到
$ as --64 -o test.o test.s (same as before)
$ ld -nmagic -s test.o (changed)
这也会创建一个ELF文件,但再次出现以下警告:
ld: warning: cannot find entry symbol _start; defaulting to 0000000000400078
**这再次暗示我们将得到一个分段错误,这确实是新ELF
文件的情况。**该文件的ELF头是:
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x400078
Start of program headers: 64 (bytes into file)
Start of section headers: 0 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 1
Size of section headers: 64 (bytes)
Number of section headers: 0
Section header string table index: 0
没有运气!
1.从ld
给出的警告来看,我们可能希望在.s
文件中添加.global _start
。下面是包含这一行的新.s
文件:
.intel_syntax noprefix
.global _start # Added here
ehdr:
.byte 0x7F
.byte 0x45 # E
.byte 0x4c # L
.byte 0x46 # F
.byte 0x02 # 64 bit ; CLASS
.byte 0x01 # lsb ; DATA
.byte 0x01 # ; VERSION
.byte 0x00 # None/Sytem V ; OS ABI
.8byte 0x0 # ABI VERSION + PADDING
.2byte 0x02 # ET_EXEC ; E_TYPE
.2byte 0x3E # AMD64 ; E_MACHINE
.4byte 0x01 # 1 ; E_VERSION
.8byte _start # ; E_ENTRY
.8byte phdr - ehdr # offset into program header ; E_PHOFF
.8byte 0x00 # offset into section header ; E_SHOFF
.4byte 0x00 # flag ; E_FLAGS
.2byte ehdrsize # ELF header size ; E_EHSIZE
.2byte phdrsize # Program header size ; E_PHSIZE
.2byte 0x01 # Number of program headers ; E_PHNUM
.2byte 0x00 # Section header size ; E_SHENTSIZE
.2byte 0x00 # Number of section headers ; E_SHNUM
.2byte 0x00 # Section header string table index ; E_SHSTRNDX
DECLARE_ELF_HEADER_SIZE:
.set ehdrsize, DECLARE_ELF_HEADER_SIZE - ehdr
phdr:
.4byte 0x01 # PT_LOAD ; P_TYPE
.4byte 0x00 # located at offset 0??? ; P_OFFSET
.8byte ehdr # ; P_VADDR
.8byte ehdr # ; P_PADDR
.8byte filesize # ; P_FILESIZE
.8byte filesize # ; P_MEMSZ
.8byte 5 # R-X ; P_FLAGS
.8byte 0x1000 # P_ALIGN
DECLARE_PHEADER_SIZE:
.set phdrsize, DECLARE_PHEADER_SIZE - phdr
_start:
mov eax, 60
mov edi, 42
syscall
DECLARE_FILE_SIZE:
.set filesize, DECLARE_FILE_SIZE - ehdr
同样,我们使用以下命令为上述代码创建ELF文件:
$ as --64 -o test.o test.s
$ ld -nmagic -s test.o
**这一次,我们没有得到任何错误,ELF文件做了它应该做的事情(即,退出代码42)。**此文件的ELF头是:
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x4000f0
Start of program headers: 64 (bytes into file)
Start of section headers: 0 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 1
Size of section headers: 64 (bytes)
Number of section headers: 0
Section header string table index: 0
问题解决了,嗯?
不幸的是,我不这么认为。深入研究二进制文件会发现它不使用我们在.s
文件中编写的手写ELF
头:
gef➤ search-pattern 'ELF'
[+] Searching 'ELF' in memory
[+] In '/home/VM/Desktop/Experiments/ELF/a.out'(0x400000-0x401000), permission=r-x
0x400001 - 0x400004 → "ELF[...]"
0x400079 - 0x40007c → "ELF[...]"
哎呀,它看起来像ld
(或as
,我不确定!)创建了自己的ELF
头(从有2个位置包含字符串ELF
这一事实可以看出。据我所知,0x400001
处的ELF
字符串是由ld
(或as
)贡献的,而0x400079
处的字符串是我包含在.s
文件中的。
然而,这违背了从头开始编写ELF文件的目的,包括ELF
头和程序头!我也确信这个问题存在于我之前列出的方法1和方法2中,但由于它们无论如何都会退出分割错误,所以我没有在这些方法中强调这个问题。
现在,我不知道该怎么做,所以我非常感谢任何帮助正确构建ELF
文件的帮助!
多谢了!
1条答案
按热度按时间unftdfkk1#
关于
_start
的消息是一个红鲱鱼。这通常用于填充入口点,但由于您手动完成了这一操作,并且没有使用链接器发出ELF头,因此它无关紧要。你搞错博士了。特别地,p_offset
应该是8个字节,p_flags
应该是4个字节,并放置为第二个字段。固定版本为: