사용자 정의 "PT_INTERP" 해석기가 분할 오류를 일으킬 수 있습니까?

사용자 정의 "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요청이 해석기 역할을 하는데 실행될 때 "Hello World" 메시지를 실행하고 인쇄 ./flag하지 않는 이유는 무엇입니까 ? 대신 이 문서의 동작과 다른 분할 오류가 발생합니다../flagsolution

사용자 정의 인터프리터를 성공적으로 등록하고 실행하는 방법은 무엇입니까 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

답변1

실행하면 dmesg다음과 같은 내용이 표시됩니다.

(solution): Uhuuh, elf segment at 0000000000400000 requested but the memory is mapped already

flag그 이유는 및 둘 다 solution0x400000에 위치한 세그먼트를 갖고 있기 때문입니다 .

이를 피하는 빠른 방법은 다음을 사용하는 것입니다.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기존 바이너리가 작동합니다.

관련 정보