还记得我们上面使用readelf读取到的信息吗?
程序头: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flags Align PHDR 0x0000000000000040 0x0000000000400040 0x0000000000400040 0x00000000000001f8 0x00000000000001f8 R E 8 INTERP 0x0000000000000238 0x0000000000400238 0x0000000000400238 0x000000000000001c 0x000000000000001c R 1 [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2] LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000 0x00000000000007d4 0x00000000000007d4 R E 200000 LOAD 0x0000000000000e10 0x0000000000600e10 0x0000000000600e10 0x0000000000000228 0x0000000000000230 RW 200000 DYNAMIC 0x0000000000000e28 0x0000000000600e28 0x0000000000600e28 0x00000000000001d0 0x00000000000001d0 RW 8 NOTE 0x0000000000000254 0x0000000000400254 0x0000000000400254 0x0000000000000044 0x0000000000000044 R 4 GNU_EH_FRAME 0x0000000000000680 0x0000000000400680 0x0000000000400680 0x000000000000003c 0x000000000000003c R 4 GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x0000000000000000 RW 10 GNU_RELRO 0x0000000000000e10 0x0000000000600e10 0x0000000000600e10 0x00000000000001f0 0x00000000000001f0 R 1这里面类型是LOAD的头代表需要加载文件的内容到内存,
Offset是文件的偏移值, VirtAddr是虚拟内存地址, FileSiz是需要加载的文件大小, MemSiz是需要分配的内存大小, Flags是内存的访问权限,
这个示例不考虑访问权限(统一使用PAGE_EXECUTE_READWRITE).
这个程序有两个LOAD头, 第一个包含了代码和只读数据(.data, .init, .rodata等节的内容), 第二个包含了可写数据(.init_array, .fini_array等节的内容).
把LOAD头对应的内容加载到指定的内存地址后我们就完成了构想中的第2个第3个步骤, 现在代码和数据都在内存中了.
接下来我们还需要处理动态链接的函数, 处理所需的信息可以从DYNAMIC头得到
DYNAMIC头包含的信息有
一个个看上面代码中涉及到的类型
重定位节 '.rela.plt' 位于偏移量 0x398 含有 2 个条目: 偏移量 信息 类型 符号值 符号名称 + 加数 000000601018 000100000007 R_X86_64_JUMP_SLO 0000000000000000 printf@GLIBC_2.2.5 + 0 000000601020 000200000007 R_X86_64_JUMP_SLO 0000000000000000 __libc_start_main@GLIBC_2.2.5 + 0 Symbol table '.dynsym' contains 4 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND printf@GLIBC_2.2.5 (2) 2: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (2) 3: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__在遍历完程序头以后, 我们可以知道有两个动态链接的函数需要重定位, 它们分别是__libc_start_main和printf, 其中__libc_start_main负责调用main函数
接下来让我们需要设置这些函数的地址