В настоящее время я слежу за книгой Денниса Андрисса о бинарном дизассемблировании и инструментарии.
В следующей главе мы написали инжектор для файлов типа ELF. Инжектор размещает раздел кода по адресу 0x80000 [+offset %16], перезаписывая раздел .note.ABI-tag (который содержит только информацию, не связанную с выполнением, поэтому перезаписывать его безопасно).
Программа, которую я модифицирую, представляет собой простую программу hello_username, например:
#include <iostream>
using namespace std;
main()
{
cout << "hello Lucky" << endl;
return 0;
}
Код, который я туда помещаю, выглядит так:
BITS 64
section .text
global main
main:
push rax
push rcx
push rdx
push rsi
push rdi
push r11
mov rax, 0x1 ;syscall to print (sys_write)
mov rdi, 0x1 ;stdout
lea rsi, [rel $+rankle-$] ;offset to prank
mov rdx, [rel $+size-$] ;length of prank
syscall
pop r11
pop rdi
pop rsi
pop rdx
pop rcx
pop rax
push 0x1080 ;find "entry_point" using readelf program
ret
rankle : db "Yikes! U got pranked!", 0
size : dd 22
Хотя я считаю, что нам не нужно проталкивать rcx и r11, код простой и понятный, я компилирую его с помощью
nasm -f bin -o pranked.bin hi_there.asm
После этого я инжектирую его написанной нами программой, и помимо инъектирования раздела еще и переопределяю точку входа. Вот вывод readelf до операции:
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: DYN (Shared object file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x1080
Start of program headers: 64 (bytes into file)
Start of section headers: 15344 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 11
Size of section headers: 64 (bytes)
Number of section headers: 30
Section header string table index: 29
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
0000000000000028 0000000000000000 A 5 0 8
[ 5] .dynsym DYNSYM 0000000000000330 00000330
0000000000000138 0000000000000018 A 6 1 8
[ 6] .dynstr STRTAB 0000000000000468 00000468
0000000000000163 0000000000000000 A 0 0 1
[ 7] .gnu.version VERSYM 00000000000005cc 000005cc
000000000000001a 0000000000000002 A 5 0 2
[ 8] .gnu.version_r VERNEED 00000000000005e8 000005e8
0000000000000040 0000000000000000 A 6 2 8
[ 9] .rela.dyn RELA 0000000000000628 00000628
0000000000000120 0000000000000018 A 5 0 8
[10] .rela.plt RELA 0000000000000748 00000748
0000000000000060 0000000000000018 AI 5 23 8
[11] .init PROGBITS 0000000000001000 00001000
0000000000000017 0000000000000000 AX 0 0 4
[12] .plt PROGBITS 0000000000001020 00001020
0000000000000050 0000000000000010 AX 0 0 16
[13] .plt.got PROGBITS 0000000000001070 00001070
0000000000000008 0000000000000008 AX 0 0 8
[14] .text PROGBITS 0000000000001080 00001080
00000000000001e1 0000000000000000 AX 0 0 16
[ .... ]
Вы можете видеть, что точка входа — 0x1080, здесь начинается раздел .text. (Функция _start находится здесь, проверил с помощью objdump)
Теперь, после инъекции, тот же вывод:
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: DYN (Shared object file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x80370
Start of program headers: 64 (bytes into file)
Start of section headers: 15344 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 11
Size of section headers: 64 (bytes)
Number of section headers: 30
Section header string table index: 29
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] .init PROGBITS 0000000000001000 00001000
0000000000000017 0000000000000000 AX 0 0 4
[ 4] .gnu.hash GNU_HASH 0000000000000308 00000308
0000000000000028 0000000000000000 A 5 0 8
[ 5] .dynsym DYNSYM 0000000000000330 00000330
0000000000000138 0000000000000018 A 6 1 8
[ 6] .dynstr STRTAB 0000000000000468 00000468
0000000000000163 0000000000000000 A 0 0 1
[ 7] .gnu.version VERSYM 00000000000005cc 000005cc
000000000000001a 0000000000000002 A 5 0 2
[ 8] .gnu.version_r VERNEED 00000000000005e8 000005e8
0000000000000040 0000000000000000 A 6 2 8
[ 9] .rela.dyn RELA 0000000000000628 00000628
0000000000000120 0000000000000018 A 5 0 8
[10] .rela.plt RELA 0000000000000748 00000748
0000000000000060 0000000000000018 AI 5 23 8
[11] .plt PROGBITS 0000000000001020 00001020
0000000000000050 0000000000000010 AX 0 0 16
[12] .plt.got PROGBITS 0000000000001070 00001070
0000000000000008 0000000000000008 AX 0 0 8
[13] .text PROGBITS 0000000000001080 00001080
00000000000001e1 0000000000000000 AX 0 0 16
[...]
[25] .bss NOBITS 0000000000004060 00003048
0000000000000118 0000000000000000 WA 0 0 32
[26] .pranked PROGBITS 0000000000080370 00004370
000000000000004a 0000000000000000 AX 0 0 16
[27] .symtab SYMTAB 0000000000000000 00003070
00000000000006f0 0000000000000018 28 49 8
[28] .strtab STRTAB 0000000000000000 00003760
0000000000000382 0000000000000000 0 0 1
[29] .shstrtab STRTAB 0000000000000000 00003ae2
0000000000000107 0000000000000000 0 0 1
Вы можете видеть, что новый раздел находится там, начиная с 0x80370, и новая точка входа в заголовке ELF указывает на это (дважды проверил это с помощью шестнадцатеричного редактора).
Итак, теперь начинаются проблемы:
Если я попытаюсь запустить программу, она правильно распечатает «Ура! Вас разыграли! \», за которым сразу же следует ОШИБКА СЕГМЕНТАЦИИ.
Это сводит меня с ума, так как я возился с этим уже больше недели! К сожалению, gdb здесь не очень поможет, но, по крайней мере, я мог получить фрейм стека до SIGSEV:
#0 0x0000000000001080 in ?? ()
(gdb) info f
Stack level 0, frame at 0x7fffb20db438:
rip = 0x1080; saved rip = 0x1
called by frame at 0x7fffb20db440
Arglist at 0x7fffb20db428, args:
Locals at 0x7fffb20db428, Previous frame's sp is 0x7fffb20db438
Saved registers:
rip at 0x7fffb20db430
И именно здесь я застрял. Почему написано 1080 в ?? (). Думаю, мой расчет точки входа тоже должен быть правильным. И рип тоже указывает на функцию _start....
Как я могу заставить это снова перейти к правильной точке входа? Я просто хочу написать мод для программы hello world, в этом не должно быть слишком много черной магии...
push 0x1080
— 0x1080 кажется смещением от начала изображения в памяти, а не абсолютным виртуальным адресом. - person 500 - Internal Server Error   schedule 02.10.2019push 0x1080
для точки входа или вообще для любого адреса? - person Paweł Łukasik   schedule 02.10.20190
при дизассемблировании, если вы не используете параметры objdump для его установки. - person Peter Cordes   schedule 03.10.2019