저는 Linux 시스템 호출 메커니즘을 이해하려고 노력하고 있습니다. 책을 읽고 있는데 종료 함수가 다음과 같다고 나와 있습니다(gdb 사용).
mov $0x0,%ebx
mov $0x1,%eax
80 int $0x80
나는 이것이 종료 시스템 호출이라는 것을 알고 있지만 내 데비안에서는 다음과 같습니다:
jmp *0x8049698
push $0x8
jmp 0x80482c0
어쩌면 누군가가 왜 다른지 설명해줄 수 있을까요? 0x80482c0에서 disas를 실행하려고 하면 gdb가 다음을 인쇄합니다.
지정된 주소가 포함된 함수가 없습니다.
감사해요!
답변1
코드 호출은 실제로 실행되지 않을 수 있는 exit()
C 라이브러리(libc) 함수에 연결됩니다 .exit()
int $0x80
코드 exit()
의 함수 호출은 실제로 call
프로그램 연결 테이블(PLT)의 명령어로 컴파일됩니다. 런타임 동적 링커는 파일을 /usr/lib/libc.so
메모리에 매핑하는 역할을 합니다. 바로 C 라이브러리입니다. 런타임 동적 링커는 또한 PLT의 항목을 수정하여 궁극적으로 map 에서 코드를 호출합니다 /usr/lib/libc.so
.
내가 아는 한(저는 Arch Linux를 사용하고 있습니다), 두 번째 3개 명령어는 PLT 항목이고, gdb
한 단계씩 들어가면 "exit@plt"를 호출합니다. jmp 0x80482c0
다른 주소로 점프하고 결국 libc.so
코드로 점프합니다.
상당히 복잡한 연습을 통해 이를 스스로 증명할 수 있습니다. 먼저 "exit@plt" 주소를 gdb
알려주는 PLT 테이블 항목의 주소를 얻었습니다 . jmp *0x8049698
내 x86 Arch Linux 시스템에서:
(gdb) disassemble 0x8048310,+20
Dump of assembler code from 0x8048310 to 0x8048324:
0x08048310 <exit@plt+0>: jmp *0x80496e8
0x08048316 <exit@plt+6>: push $0x10
0x0804831b <exit@plt+11>: jmp 0x80482e0
그럼 하세요 readelf -e _program_ > elf.headers
. elf.headers
파일 보기 "섹션 제목:"이라는 텍스트 줄을 찾을 수 있으며 섹션 제목 어딘가에 다음과 같은 내용이 표시됩니다.
[ 9] .rel.dyn REL 08048290 000290 000008 08 A 5 0 4
[10] .rel.plt REL 08048298 000298 000020 08 AI 5 12 4
[11] .init PROGBITS 080482b8 0002b8 000023 00 AX 0 0 4
[12] .plt PROGBITS 080482e0 0002e0 000050 04 AX 0 0 16
"exit@plt"는 주소 0x8048310에 있습니다. ".rel.plt" 섹션에 있습니다. ".rel.plt"는 아마도 "relocator link table"을 의미할 것입니다.
int $0x80
이제 우리는 아마도 존재하지 않는 부분에 도달합니다. ldd _program_
마. 마찬가지로 Arch Linux x86은 다음과 같이 말합니다.
linux-gate.so.1 (0xb77d9000)
libc.so.6 => /usr/lib/libc.so.6 (0xb7603000)
/lib/ld-linux.so.2 (0xb77da000)
"linux-gate.so.1"이 보이나요? 여기에는 시스템 호출을 수행하는 실제 코드가 포함되어 있습니다. 그것은 일 수도 있고 int $0x80
, 지시일 수도 있고 sysenter
, 다른 것일 수도 있습니다. Linux 커널은 실제 코드와 함께 프로세스의 주소 공간에 "작은 공유 라이브러리"를 넣은 다음 작은 공유 라이브러리의 주소를 ELF "보조 벡터"에 전달하도록 되어 있습니다. 세부 사항을 확인하십시오 man vdso
. 동적 링커는 /lib/ld-linux.so.2
ELF 보조 벡터의 세부 사항을 알고 결국 linx-gate.so.1
PLT 어딘가에 주소를 배치하므로 실제 C 함수 호출은 효율적인 시스템 호출을 생성하게 됩니다.
여러 번 전화를 걸면 통화할 때마다 ldd _program_
표시되는 주소가 linux-gate.so.1
달라집니다. 실제로 커널은 자체 코드를 실행하기 위해 스택 위치를 알아야 하는 악성 코드를 혼동시키기 위해 매번 동일한 주소에 스택 상단을 배치하지 않습니다.