Linux

自定義“PT_INTERP”解釋器導致分段錯誤?

  • October 6, 2021

在閱讀了這篇關於通過更改為自定義解釋器來執行任意程序的文章後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將在其下執行的解釋器(執行檔)的路徑

既然solutionrequests./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 處有一個段flagsolution

避免這種情況的一種快速方法是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你已經擁有的二進製文件將起作用。

引用自:https://unix.stackexchange.com/questions/671908