[Beliebtes Material](https://qiita.com/search?q=%E3%82%BB%E3%82%B0%E3%83%95%E3%82%A9%E3%82%89%E3 Es ist eine Huckepackfahrt auf% 81% 9B% E3% 82% 8B).
Ich verwende x86-64 Ubuntu 19.04 + gcc 8.3.0 als Betriebsüberprüfungsumgebung.
Bauen und ausführen
$ gcc -xc /dev/null -nostdlib -Wl,-e0xfa -Wl,-Ttext=0x2504890000 -zexecstack && ./a.out
Segmentation fault (core dumped)
$
Versuchen Sie zunächst, das kleinste C-Programm zu kompilieren, das keine Warnung ausgibt.
int main(){}
Da es schwierig ist, den Quellcode vorzubereiten, verwende ich den Befehl echo, um mit | eine Verbindung zum Compiler herzustellen und ihn direkt als Standardeingabe einzugeben. Da der Compiler den Typ der Eingabedatei nicht durch die Erweiterung der Eingabedatei bestimmen kann, verwenden Sie die Befehlszeilenoption "-xc", um anzugeben, dass es sich um eine C-Quelle handelt.
$ echo 'int main(){}' | gcc -xc - && ls -l a.out
-rwxr-xr-x 1 fujita fujita 16344 Jul 8 22:31 a.out
$
Eine ausführbare Datei von ca. 16 KB wurde erstellt. Wenn ich das generierte a.out an den Befehl readelf weitergebe
$ readelf -S a.out
There are 28 section headers, starting at offset 0x38d8:
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .interp PROGBITS 00000000000002a8 000002a8
000000000000001c 0000000000000000 A 0 0 1
[ 2] .note.gnu.build-i NOTE 00000000000002c4 000002c4
0000000000000024 0000000000000000 A 0 0 4
[ 3] .note.ABI-tag NOTE 00000000000002e8 000002e8
0000000000000020 0000000000000000 A 0 0 4
[ 4] .gnu.hash GNU_HASH 0000000000000308 00000308
0000000000000024 0000000000000000 A 5 0 8
[ 5] .dynsym DYNSYM 0000000000000330 00000330
0000000000000090 0000000000000018 A 6 1 8
[ 6] .dynstr STRTAB 00000000000003c0 000003c0
000000000000007d 0000000000000000 A 0 0 1
[ 7] .gnu.version VERSYM 000000000000043e 0000043e
000000000000000c 0000000000000002 A 5 0 2
[ 8] .gnu.version_r VERNEED 0000000000000450 00000450
0000000000000020 0000000000000000 A 6 1 8
[ 9] .rela.dyn RELA 0000000000000470 00000470
00000000000000c0 0000000000000018 A 5 0 8
[10] .init PROGBITS 0000000000001000 00001000
0000000000000017 0000000000000000 AX 0 0 4
[11] .plt PROGBITS 0000000000001020 00001020
0000000000000010 0000000000000010 AX 0 0 16
[12] .plt.got PROGBITS 0000000000001030 00001030
0000000000000008 0000000000000008 AX 0 0 8
[13] .text PROGBITS 0000000000001040 00001040
0000000000000151 0000000000000000 AX 0 0 16
[14] .fini PROGBITS 0000000000001194 00001194
0000000000000009 0000000000000000 AX 0 0 4
[15] .rodata PROGBITS 0000000000002000 00002000
0000000000000004 0000000000000004 AM 0 0 4
[16] .eh_frame_hdr PROGBITS 0000000000002004 00002004
000000000000003c 0000000000000000 A 0 0 4
[17] .eh_frame PROGBITS 0000000000002040 00002040
0000000000000108 0000000000000000 A 0 0 8
[18] .init_array INIT_ARRAY 0000000000003df0 00002df0
0000000000000008 0000000000000008 WA 0 0 8
[19] .fini_array FINI_ARRAY 0000000000003df8 00002df8
0000000000000008 0000000000000008 WA 0 0 8
[20] .dynamic DYNAMIC 0000000000003e00 00002e00
00000000000001c0 0000000000000010 WA 6 0 8
[21] .got PROGBITS 0000000000003fc0 00002fc0
0000000000000040 0000000000000008 WA 0 0 8
[22] .data PROGBITS 0000000000004000 00003000
0000000000000010 0000000000000000 WA 0 0 8
[23] .bss NOBITS 0000000000004010 00003010
0000000000000008 0000000000000000 WA 0 0 1
[24] .comment PROGBITS 0000000000000000 00003010
0000000000000023 0000000000000001 MS 0 0 1
[25] .symtab SYMTAB 0000000000000000 00003038
00000000000005b8 0000000000000018 26 43 8
[26] .strtab STRTAB 0000000000000000 000035f0
00000000000001e9 0000000000000000 0 0 1
[27] .shstrtab STRTAB 0000000000000000 000037d9
00000000000000f9 0000000000000000 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
l (large), p (processor specific)
$
Sie können sehen, dass es viele Abschnitte enthält.
Versuchen Sie dann, die 0-Zeichen-Quelle zu kompilieren. Verwenden Sie / dev / null anstelle der Quelldatei, die beim Lesen immer eine EOF zurückgibt. Sie benötigen nicht einmal einen Start, um main aufzurufen. Geben Sie daher die Option \ `-nostdlib' an. Wenn Sie dies verwenden, wird die Standard-Startadresse für die Programmausführung _start nicht gefunden und der Linker warnt Sie. Verwenden Sie daher die Option -Wl, -e0, um 0 als Startadresse für die temporäre Ausführung anzugeben.
$ gcc -xc /dev/null -nostdlib -Wl,-e0 && ls -l a.out
-rwxr-xr-x 1 fujita fujita 9512 Jul 8 22:35 a.out
$
Eine ausführbare Datei von ca. 9,5 KB wurde erstellt. Wenn Sie dies dem Befehl readelf zuführen
$ readelf -S a.out
There are 12 section headers, starting at offset 0x2228:
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .interp PROGBITS 0000000000000200 00000200
000000000000001c 0000000000000000 A 0 0 1
[ 2] .note.gnu.build-i NOTE 000000000000021c 0000021c
0000000000000024 0000000000000000 A 0 0 4
[ 3] .gnu.hash GNU_HASH 0000000000000240 00000240
000000000000001c 0000000000000000 A 4 0 8
[ 4] .dynsym DYNSYM 0000000000000260 00000260
0000000000000018 0000000000000018 A 5 1 8
[ 5] .dynstr STRTAB 0000000000000278 00000278
0000000000000001 0000000000000000 A 0 0 1
[ 6] .eh_frame PROGBITS 0000000000001000 00001000
0000000000000000 0000000000000000 A 0 0 8
[ 7] .dynamic DYNAMIC 0000000000001f20 00001f20
00000000000000e0 0000000000000010 WA 5 0 8
[ 8] .comment PROGBITS 0000000000000000 00002000
0000000000000023 0000000000000001 MS 0 0 1
[ 9] .symtab SYMTAB 0000000000000000 00002028
0000000000000168 0000000000000018 10 12 8
[10] .strtab STRTAB 0000000000000000 00002190
0000000000000027 0000000000000000 0 0 1
[11] .shstrtab STRTAB 0000000000000000 000021b7
000000000000006c 0000000000000000 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
l (large), p (processor specific)
$
Sie können sehen, dass die ausführbare Datei immer noch mehrere Abschnitte enthält, jedoch weniger als das kleinste Hauptbeispiel.
Einige Befehlszeilenoptionen für den Linker geben die Startadresse des Abschnitts an. Versuchen wir, den Wert 0x123456789abcdef0 als Startadresse des Textabschnitts anzugeben, der nicht in der Liste der obigen Abschnitte enthalten ist. Die folgende Befehlszeilenoption "-Wl, -Ttext = 0x123456789abcdef0" ist anwendbar.
$ gcc -xc /dev/null -nostdlib -Wl,-e0 -Wl,-Ttext=0x123456789abcdef0 && ls -l a.out
-rwxr-xr-x 1 fujita fujita 9512 Jul 8 22:41 a.out
$ readelf -S a.out
There are 12 section headers, starting at offset 0x2228:
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .interp PROGBITS 0000000000000238 00000238
000000000000001c 0000000000000000 A 0 0 1
[ 2] .note.gnu.build-i NOTE 0000000000000254 00000254
0000000000000024 0000000000000000 A 0 0 4
[ 3] .gnu.hash GNU_HASH 0000000000000278 00000278
000000000000001c 0000000000000000 A 4 0 8
[ 4] .dynsym DYNSYM 0000000000000298 00000298
0000000000000018 0000000000000018 A 5 1 8
[ 5] .dynstr STRTAB 00000000000002b0 000002b0
0000000000000001 0000000000000000 A 0 0 1
[ 6] .eh_frame PROGBITS 123456789abce000 00001000
0000000000000000 0000000000000000 A 0 0 8
[ 7] .dynamic DYNAMIC 123456789abcef20 00001f20
00000000000000e0 0000000000000010 WA 5 0 8
[ 8] .comment PROGBITS 0000000000000000 00002000
0000000000000023 0000000000000001 MS 0 0 1
[ 9] .symtab SYMTAB 0000000000000000 00002028
0000000000000168 0000000000000018 10 12 8
[10] .strtab STRTAB 0000000000000000 00002190
0000000000000027 0000000000000000 0 0 1
[11] .shstrtab STRTAB 0000000000000000 000021b7
000000000000006c 0000000000000000 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
l (large), p (processor specific)
$
Ich weiß nicht, was der Abschnitt ist, aber Sie können sehen, dass der Abschnitt ".eh_frame" betroffen ist und eine ähnliche Adresse hat. Es scheint, dass die unteren 16 Bits der Adresse, die der Wert des Versatzelements ist, von "def0" bis "e000" ausgerichtet sind. Diese Abschnittsinformationen sollten in der ausführbaren Datei a.out enthalten sein. Versuchen Sie einen hexadezimalen Speicherauszug mit dem Befehl hexdump
$ hexdump -C a.out | head -24
00000000 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 |.ELF............|
00000010 03 00 3e 00 01 00 00 00 00 00 00 00 00 00 00 00 |..>.............|
00000020 40 00 00 00 00 00 00 00 28 22 00 00 00 00 00 00 |@.......("......|
00000030 00 00 00 00 40 00 38 00 09 00 40 00 0c 00 0b 00 |[email protected]...@.....|
00000040 06 00 00 00 04 00 00 00 40 00 00 00 00 00 00 00 |........@.......|
00000050 40 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 |@.......@.......|
00000060 f8 01 00 00 00 00 00 00 f8 01 00 00 00 00 00 00 |................|
00000070 08 00 00 00 00 00 00 00 03 00 00 00 04 00 00 00 |................|
00000080 38 02 00 00 00 00 00 00 38 02 00 00 00 00 00 00 |8.......8.......|
00000090 38 02 00 00 00 00 00 00 1c 00 00 00 00 00 00 00 |8...............|
000000a0 1c 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 |................|
000000b0 01 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 |................|
000000c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000000d0 b1 02 00 00 00 00 00 00 b1 02 00 00 00 00 00 00 |................|
000000e0 00 10 00 00 00 00 00 00 01 00 00 00 04 00 00 00 |................|
000000f0 00 10 00 00 00 00 00 00 00 e0 bc 9a 78 56 34 12 |............xV4.|
00000100 00 e0 bc 9a 78 56 34 12 00 00 00 00 00 00 00 00 |....xV4.........|
00000110 00 00 00 00 00 00 00 00 00 10 00 00 00 00 00 00 |................|
00000120 01 00 00 00 06 00 00 00 20 1f 00 00 00 00 00 00 |........ .......|
00000130 20 ef bc 9a 78 56 34 12 20 ef bc 9a 78 56 34 12 | ...xV4. ...xV4.|
00000140 e0 00 00 00 00 00 00 00 e0 00 00 00 00 00 00 00 |................|
00000150 00 10 00 00 00 00 00 00 02 00 00 00 06 00 00 00 |................|
00000160 20 1f 00 00 00 00 00 00 20 ef bc 9a 78 56 34 12 | ....... ...xV4.|
00000170 20 ef bc 9a 78 56 34 12 e0 00 00 00 00 00 00 00 | ...xV4.........|
$
Sie können sehen, dass 8 Bytes von der Adresse 000000f8, die die Startadresse von ".eh_frame" zu sein scheint, in Little Endian gespeichert sind.
Bei Verwendung von \ -Wl, -Ttext = 0xXXXXXXXXXXXX0000 'wird unter der Annahme, dass die unteren 16 Bits ignoriert werden, um ein Ausrichten der Adressen zu vermeiden, jede Bytezeichenfolge von Adresse 000000fa als Adresse von
.eh_framein die Ausführungsdatei eingebettet. Ich denke ich kann es schaffen. Geben Sie als Test \
-Wl, -Ttext = 0x2504890000' an und platzieren Sie 89 04 25 von der Adresse 000000fa. Geben Sie die 000000fa-Adresse als Ausführungsadresse mit \ -e0xfa an und geben Sie außerdem -zexecstack an, um die Ausführung in anderen Bereichen als dem Codebereich zu ermöglichen.
$ gcc -xc /dev/null -nostdlib -Wl,-e0xfa -Wl,-Ttext=0x2504890000 -zexecstack && ls -l a.out
-rwxr-xr-x 1 fujita fujita 9512 Jul 8 22:49 a.out
$ ./a.out
Segmentation fault (core dumped)
$
Ich konnte bestätigen, dass segfo durch Ausführen des generierten a.out generiert wird. Verwenden Sie den Befehl objdump, um die Anweisungen anzuzeigen, die in die ausführbare Datei von Adresse 000000fa eingebettet sind.
$ objdump -D -bbinary -mi386 -Mintel,x86-64 --start-address=0xfa a.out | head -8
a.out: file format binary
Disassembly of section .data:
000000fa <.data+0xfa>:
fa: 89 04 25 00 00 00 00 mov DWORD PTR ds:0x0,eax
$
Der Inhalt besteht darin, den Wert des EAX-Registers auf die Adresse 0 zu schreiben. Wenn Sie dies versuchen, können Sie feststellen, dass der Betriebssystemschutz in Segfo beendet wurde.
Mit dem oben genannten wurde der Titel "Segfo mit 0 Zeichen mit gcc" erreicht. Darüber hinaus ist es möglich, einen anderen Fehler als Segfo auszugeben, indem der Inhalt von \ `-Wl, -Ttext = 0xXXXXXXXXXXXX0000 'erstellt wird.
Rufen Sie den Software-Interrupt INT3 zum Debuggen auf
$ gcc -xc /dev/null -nostdlib -Wl,-e0xfa -Wl,-Ttext=0xcc0000 -zexecstack && ls -l a.out
-rwxr-xr-x 1 fujita fujita 9512 Jul 8 22:55 a.out
$ objdump -D -bbinary -mi386 -Mintel,x86-64 --start-address=0xfa a.out | head -8
a.out: file format binary
Disassembly of section .data:
000000fa <.data+0xfa>:
fa: cc int3
$ ./a.out
Trace/breakpoint trap (core dumped)
$
Führen Sie UD2 aus, das als unzulässige Anweisung reserviert ist
$ gcc -xc /dev/null -nostdlib -Wl,-e0xfa -Wl,-Ttext=0x0b0f0000 -zexecstack && ls -l a.out
-rwxr-xr-x 1 fujita fujita 9512 Jul 8 22:56 a.out
$ objdump -D -bbinary -mi386 -Mintel,x86-64 --start-address=0xfa a.out | head -8
a.out: file format binary
Disassembly of section .data:
000000fa <.data+0xfa>:
fa: 0f 0b ud2
$ ./a.out
Illegal instruction (core dumped)
$
Teilen Sie den Wert des AX-Registers durch den Inhalt der Adresse 0x100, in der 0 gespeichert ist, und erzeugen Sie einen 0-Teilungsfehler.
$ gcc -xc /dev/null -nostdlib -Wl,-e0xfa -Wl,-Ttext=0x35f60000 -zexecstack && ls -l a.out
-rwxr-xr-x 1 fujita fujita 9512 Jul 8 22:58 a.out
$ objdump -D -bbinary -mi386 -Mintel,x86-64 --start-address=0xfa a.out | head -9
a.out: file format binary
Disassembly of section .data:
000000fa <.data+0xfa>:
fa: f6 35 00 00 00 00 div BYTE PTR [rip+0x0] # 0x100
100: 00 00 add BYTE PTR [rax],al
$ ./a.out
Floating point exception (core dumped)
$
Es macht Spaß, verschiedene Dinge auszuprobieren.
Das Ende.
Recommended Posts