Linux
自定義“PT_INTERP”解釋器導致分段錯誤?
在閱讀了這篇關於通過更改為自定義解釋器來執行任意程序的文章後
PT_INTERP
,我嘗試在本地進行實驗:$ cat flag.c #include <stdio.h> int main(int argc, char **argv) { printf("Hello World!\n"); return 0; } $ gcc -static flag.c -o flag $ cat solution.c const char interp_section[] __attribute__((section(".interp"))) = "./flag"; $ gcc -s -fno-ident -Wl,--build-id=none -Wl,-e,0 -static -nostdlib solution.c -o solution $ ./solution Segmentation fault $ ./flag Hello World!
這個
PT_INTERP
程序頭包含一個路徑,也就是我們的ELF將在其下執行的解釋器(執行檔)的路徑既然
solution
requests./flag
作為它的解釋器,為什麼不./flag
執行並列印消息“Hello World”,什麼時候solution
執行?而是發生了分段錯誤,這與文章中的行為不同。如何在 中成功註冊和執行自定義解釋器
PT_INTERP
?$ readelf -l solution Elf file type is EXEC (Executable file) Entry point 0x0 There are 4 program headers, starting at offset 64 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flags Align PHDR 0x0000000000000040 0x0000000000400040 0x0000000000400040 0x00000000000000e0 0x00000000000000e0 R 0x8 INTERP 0x0000000000000120 0x0000000000400120 0x0000000000400120 0x0000000000000007 0x0000000000000007 R 0x1 [Requesting program interpreter: ./flag] LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000 0x0000000000000127 0x0000000000000127 R 0x1000 GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x0000000000000000 RW 0x10 Section to Segment mapping: Segment Sections... 00 01 .interp 02 .interp 03
如果你執行
dmesg
,你應該看到類似(solution): Uhuuh, elf segment at 0000000000400000 requested but the memory is mapped already
原因是兩者都在 0x400000 處有一個段
flag
。solution
避免這種情況的一種快速方法是將
tinyelf
helloworld
二進製文件用作flag
; 它沒有衝突的部分,一切正常。改編 TinyELF 範例,將其寫入
flag.c
:#include <asm/unistd.h> long syscall(long n, long a1, long a2, long a3, long a4, long a5, long a6); void _start() { syscall(__NR_write, 1, (long) "Hello World!\n", 13, 0, 0, 0); syscall(__NR_exit, 0, 0, 0, 0, 0, 0); } long syscall(long n, long a1, long a2, long a3, long a4, long a5, long a6) { asm volatile ("movq %4, %%r10;" "movq %5, %%r8;" "movq %6, %%r9;" "syscall;" : "=a"(n) : "a"(n), "D"(a1), "S"(a2), "d"(a3), "r"(a4), "r"(a5), "r"(a6) : "%r10", "%r8", "%r9"); return n; }
如下建構:
gcc -nostartfiles -nostdlib flag.c -o flag
然後
solution
你已經擁有的二進製文件將起作用。