модификация elf, добавление сегмента+секции
Коллеги, помогите пожалуйста.
изучаю структуру elf файла. сегмент с кодом запретил для чтения, записи и исполнения. добавил в конец сегмент с выравниванием 4096, в нём короткий код , который через mprotect возвращает сегменту права и переходит по первоначальной точке входа.
Всё идёт хорошо, пока оригинальный код не делает mov rax,fs:28h
получается segfault. значение fs — 0
тут код, где падает endbr64
.text:00000000004ED074 push rbp
.text:00000000004ED075 mov rbp, rsp
.text:00000000004ED078 push r15
.text:00000000004ED07A push r14
.text:00000000004ED07C push r13
.text:00000000004ED07E push r12
.text:00000000004ED080 push rbx
.text:00000000004ED081 sub rsp, 0E8h
.text:00000000004ED088 mov [rbp+var_58], rsi
.text:00000000004ED08C mov [rbp+var_50], rdx
.text:00000000004ED090 mov [rbp+var_48], rcx
.text:00000000004ED094 mov [rbp+var_40], r8
.text:00000000004ED098 mov [rbp+var_38], r9
.text:00000000004ED09C movzx r12d, byte ptr [rdi]
.text:00000000004ED0A0 mov rax, fs :28h ; вот тут segfault
.text:00000000004ED0A9 mov [rbp+var_68], rax
.text:00000000004ED0AD xor eax , eax
.text:00000000004ED0AF lea rax, [rbp+arg_0]
.text:00000000004ED0B3 mov [rbp+var_F8], 8
.text:00000000004ED0BD mov [rbp+var_F0], rax
.text:00000000004ED0C4 lea rax, [rbp+var_60]
.text:00000000004ED0C8 mov [rbp+var_E8], rax
.text:00000000004ED0CF test r12b, r12b
.text:00000000004ED0D2 jz __libc_message_impl_cold
Тут структура сегментов до и после ДО
readelf -lW u
Elf file type is EXEC (Executable file)
Entry point 0x405e30
There are 10 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x000000 0x0000000000400000 0x0000000000400000 0x0005e8 0x0005e8 R 0x1000
LOAD 0x001000 0x0000000000401000 0x0000000000401000 0x176231 0x176231 R E 0x1000
LOAD 0x178000 0x0000000000578000 0x0000000000578000 0x04f8c7 0x04f8c7 R 0x1000
LOAD 0x1c85a0 0x00000000005c85a0 0x00000000005c85a0 0x00c6a4 0x014d38 RW 0x1000
NOTE 0x000270 0x0000000000400270 0x0000000000400270 0x000030 0x000030 R 0x8
NOTE 0x0002a0 0x00000000004002a0 0x00000000004002a0 0x000044 0x000044 R 0x4
TLS 0x1c85a0 0x00000000005c85a0 0x00000000005c85a0 0x000068 0x0000b8 R 0x8
GNU_PROPERTY 0x000270 0x0000000000400270 0x0000000000400270 0x000030 0x000030 R 0x8
GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x10
GNU_RELRO 0x1c85a0 0x00000000005c85a0 0x00000000005c85a0 0x00aa60 0x00aa60 R 0x1
Section to Segment mapping:
Segment Sections...
00 .note.gnu.property .note.gnu.build-id .note.ABI-tag .rela.plt
01 .init .plt .text .fini
02 .rodata .stapsdt.base rodata.cst32 .eh_frame .gcc_except_table
03 .tdata .init_array .fini_array .data.rel.ro .got .got.plt .data .bss
04 .note.gnu.property
05 .note.gnu.build-id .note.ABI-tag
06 .tdata .tbss
07 .note.gnu.property
08
09 .tdata .init_array .fini_array .data.rel.ro .got
ПОСЛЕ
данные патченного файла readelf -lW m
Elf file type is EXEC (Executable file)
Entry point 0x5de000
There are 12 program headers, starting at offset 624
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x000000 0x0000000000400000 0x0000000000400000 0x0005e8 0x0005e8 R 0x1000
LOAD 0x001000 0x0000000000401000 0x0000000000401000 0x176231 0x176231 0x1000
LOAD 0x178000 0x0000000000578000 0x0000000000578000 0x04f8c7 0x04f8c7 R 0x1000
LOAD 0x1c85a0 0x00000000005c85a0 0x00000000005c85a0 0x00c6a4 0x014d38 RW 0x1000
NOTE 0x000270 0x0000000000400270 0x0000000000400270 0x000030 0x000030 R 0x8
NOTE 0x0002a0 0x00000000004002a0 0x00000000004002a0 0x000044 0x000044 R 0x4
TLS 0x1c85a0 0x00000000005c85a0 0x00000000005c85a0 0x000068 0x0000b8 R 0x8
GNU_PROPERTY 0x000270 0x0000000000400270 0x0000000000400270 0x000030 0x000030 R 0x8
GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x10
GNU_RELRO 0x1c85a0 0x00000000005c85a0 0x00000000005c85a0 0x00aa60 0x00aa60 R 0x1
LOAD 0x24a000 0x00000000005de000 0x00000000005de000 0x000033 0x000033 R E 0x1000
LOAD 0x24a000 0x00000000005de000 0x00000000005de000 0x000033 0x000033 R E 0x1000
Section to Segment mapping:
Segment Sections...
00 .note.gnu.property .note.gnu.build-id .note.ABI-tag .rela.plt
01
02 .rodata .stapsdt.base rodata.cst32 .eh_frame .gcc_except_table
03 .tdata .init_array .fini_array .data.rel.ro .got .got.plt .data .bss
04 .note.gnu.property
05 .note.gnu.build-id .note.ABI-tag
06 .tdata .tbss
07 .note.gnu.property
08
09 .tdata .init_array .fini_array .data.rel.ro .got
10 .coDDde
11 .coDDde
информация gdb о сегментах после segfault
(gdb) maintenance info sections
Exec file: m, file type elf64-x86-64.
[0] 0x00400270->0x004002a0 at 0x00000270: .note.gnu.property ALLOC LOAD READONLY DATA HAS_CONTENTS
[1] 0x004002a0->0x004002c4 at 0x000002a0: .note.gnu.build-id ALLOC LOAD READONLY DATA HAS_CONTENTS
[2] 0x004002c4->0x004002e4 at 0x000002c4: .note.ABI-tag ALLOC LOAD READONLY DATA HAS_CONTENTS
[3] 0x004002e8->0x004005e8 at 0x000002e8: .rela.plt ALLOC LOAD READONLY DATA HAS_CONTENTS
[4] 0x00401000->0x0040101b at 0x00001000: .init READONLY CODE HAS_CONTENTS
[5] 0x00401020->0x00401220 at 0x00001020: .plt READONLY CODE HAS_CONTENTS
[6] 0x00401240->0x00577223 at 0x00001240: .text READONLY CODE HAS_CONTENTS
[7] 0x00577224->0x00577231 at 0x00177224: .fini READONLY CODE HAS_CONTENTS
[8] 0x00578000->0x0059a7c4 at 0x00178000: .rodata ALLOC LOAD READONLY DATA HAS_CONTENTS
[9] 0x0059a7c4->0x0059a7c5 at 0x0019a7c4: .stapsdt.base ALLOC LOAD READONLY DATA HAS_CONTENTS
[10] 0x0059a7e0->0x0059a840 at 0x0019a7e0: rodata.cst32 ALLOC LOAD READONLY DATA HAS_CONTENTS
[11] 0x0059a840->0x005c2308 at 0x0019a840: .eh_frame ALLOC LOAD READONLY DATA HAS_CONTENTS
[12] 0x005c2308->0x005c78c7 at 0x001c2308: .gcc_except_table ALLOC LOAD READONLY DATA HAS_CONTENTS
[13] 0x005c85a0->0x005c8608 at 0x001c85a0: .tdata ALLOC LOAD DATA HAS_CONTENTS
[14] 0x005c8608->0x005c8658 at 0x001c8608: .tbss ALLOC
[15] 0x005c8608->0x005c8650 at 0x001c8608: .init_array ALLOC LOAD DATA HAS_CONTENTS
[16] 0x005c8650->0x005c8660 at 0x001c8650: .fini_array ALLOC LOAD DATA HAS_CONTENTS
[17] 0x005c8660->0x005d2f48 at 0x001c8660: .data.rel.ro ALLOC LOAD DATA HAS_CONTENTS
[18] 0x005d2f48->0x005d2fe0 at 0x001d2f48: .got ALLOC LOAD DATA HAS_CONTENTS
[19] 0x005d2fe8->0x005d3100 at 0x001d2fe8: .got.plt ALLOC LOAD DATA HAS_CONTENTS
[20] 0x005d3100->0x005d4c44 at 0x001d3100: .data ALLOC LOAD DATA HAS_CONTENTS
[21] 0x005d4c60->0x005dd2d8 at 0x001d4c44: .bss ALLOC
[22] 0x00000000->0x0000002b at 0x001d4c44: .comment READONLY HAS_CONTENTS
[23] 0x00000000->0x000018cc at 0x001d4c70: .note.stapsdt READONLY HAS_CONTENTS
[24] 0x005de000->0x005de033 at 0x0024a000: .coDDde ALLOC LOAD READONLY CODE HAS_CONTENTS
Подскажите, пожалуйста, где я мог нахимичать при модификации elf?
Re: модификация elf, добавление сегмента+секции
От:
kov_serg
Дата: 20.02.25 14:42
Оценка:
Здравствуйте, Molchalnik, Вы писали:
M>Подскажите, пожалуйста, где я мог нахимичать при модификации elf?
До
LOAD 0x001000 0x0000000000401000 0x0000000000401000 0x176231 0x176231 R E 0x1000
...
01 .init .plt .text .fini
После
LOAD 0x001000 0x0000000000401000 0x0000000000401000 0x176231 0x176231 0x1000
...
01
Re[2]: модификация elf, добавление сегмента+секции
Здравствуйте, kov_serg, Вы писали:
. _>Здравствуйте, Molchalnik, Вы писали:
M>>Подскажите, пожалуйста, где я мог нахимичать при модификации elf?
_>До
LOAD 0x001000 0x0000000000401000 0x0000000000401000 0x176231 0x176231 R E 0x1000
_>...
_> 01 .init .plt .text .fini
_>
. _>После
_> LOAD 0x001000 0x0000000000401000 0x0000000000401000 0x176231 0x176231 0x1000
_>...
_> 01
_>
а в чём проблема? я mprotect'ом при запуске ставлю права на исполнение и права на чтение этому сегменту назад
вот таким кодом
.coDDde:00000000005DE000 public start
.coDDde:00000000005DE000 start proc near
.coDDde:00000000005DE000 xor rax, rax
.coDDde:00000000005DE003 mov rdi, offset _init_proc ; start
.coDDde:00000000005DE00D mov rdx, 5 ; prot
.coDDde:00000000005DE014 mov rsi, 177000h ; len
.coDDde:00000000005DE01E mov rax, 0Ah
.coDDde:00000000005DE025 syscall ; LINUX - sys_mprotect
.coDDde:00000000005DE027 mov rax, offset _start
.coDDde:00000000005DE031 jmp rax
.coDDde:00000000005DE031 start endp
.coDDde:00000000005DE031
.coDDde:00000000005DE031 _coDDde ends
_init_proc — это чётко 0x401000, длина вроде на сегмент с округлением по страницам к верху... _start — это первоначальная точка входа, 0x0405e40. Переход осуществляется туда. Если бы не было прав на исполнение и чтение, segfault был бы на первой команде по адресу функции _start 0x0405e40, а доходит аш до 0x04ED09C
Re[2]: модификация elf, добавление сегмента+секции
Здравствуйте, kov_serg, Вы писали:
Собственно, после вызова _start я отладчиком прошёл до вызова __libc_start_main_impl
; Attributes: noreturn fuzzy-sp
.text:0000000000405E30
.text:0000000000405E30 public _start
.text:0000000000405E30 _start proc near
.text:0000000000405E30 ; __unwind {
.text:0000000000405E30 endbr64
.text:0000000000405E34 xor ebp , ebp
.text:0000000000405E36 mov r9, rdx
.text:0000000000405E39 pop rsi
.text:0000000000405E3A mov rdx, rsp
.text:0000000000405E3D and rsp, 0FFFFFFFFFFFFFFF0h
.text:0000000000405E41 push rax
.text:0000000000405E42 push rsp
.text:0000000000405E43 xor r8d, r8d
.text:0000000000405E46 xor ecx , ecx
.text:0000000000405E48 mov rdi, offset main
.text:0000000000405E4F db 67h
.text:0000000000405E4F call __libc_start_main_impl
а __libc_start_main_impl
- это тот код, который я приводил ниже, вот он, ещё раз дублирую :
(позднейшее уточнение) потом ещё кучка операций, а потом это:
.text:00000000004ED074 push rbp
.text:00000000004ED075 mov rbp, rsp
.text:00000000004ED078 push r15
.text:00000000004ED07A push r14
.text:00000000004ED07C push r13
.text:00000000004ED07E push r12
.text:00000000004ED080 push rbx
.text:00000000004ED081 sub rsp, 0E8h
.text:00000000004ED088 mov [rbp+var_58], rsi
.text:00000000004ED08C mov [rbp+var_50], rdx
.text:00000000004ED090 mov [rbp+var_48], rcx
.text:00000000004ED094 mov [rbp+var_40], r8
.text:00000000004ED098 mov [rbp+var_38], r9
.text:00000000004ED09C movzx r12d, byte ptr [rdi]
.text:00000000004ED0A0 mov rax, fs :28h ; вот тут segfault
таким образом код прекрасно исполняется , два десятка инструкций выполнены до segfault
это-то меня и озадачивает
Re[3]: модификация elf, добавление сегмента+секции
От:
kov_serg
Дата: 20.02.25 19:12
Оценка:
Здравствуйте, Molchalnik, Вы писали:
M>таким образом код прекрасно исполняется , два десятка инструкций выполнены до segfault
поставте бряк на catch syscall arch_prctl
Заведите в своём коде static __thread int var = 0;
прогоните с strace
еще можете тут покопать:
https://github.com/bminor/glibc/blob/master/elf/rtld.c#L733
https://github.com/bminor/glibc/blob/master/elf/rtld.c#L1298
https://github.com/bminor/glibc/blob/master/sysdeps/x86_64/nptl/tls.h#L142
Re[4]: модификация elf, добавление сегмента+секции
Здравствуйте, kov_serg, Вы писали:
_>поставте бряк на catch syscall arch_prctl
прогнал gdb ./t
GNU gdb (Ubuntu 15.0.50.20240403-0ubuntu1) 15.0.50.20240403-git
Type "apropos word " to search for commands related to "word "...
Reading symbols from ./t...
(No debugging symbols found in ./t)
(gdb) catch syscall arch_prctl
Catchpoint 1 (syscall 'arch_prctl' [158])
(gdb) run
Starting program: t
This GDB supports auto-downloading debuginfo from the following URLs:
<https://debuginfod.ubuntu.com>
Enable debuginfod for this session? (y or [n]) y
Debuginfod has been enabled.
To make this setting permanent, add 'set debuginfod enabled on' to .gdbinit.
Downloading separate debug info for system-supplied DSO at 0x7ffff7ffd000
Program received signal SIGSEGV, Segmentation fault.
0x00000000004ed0a0 in ?? ()
_>Заведите в своём коде static __thread int var = 0;
_>прогоните с strace
strace до ввода статической переменной
strace ./m
execve("./m", ["./m"], 0x7ffeb677f330 /* 78 vars */) = 0
mprotect(0x401000, 1536000, PROT_READ|PROT_EXEC) = 0
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x28} ---
+++ killed by SIGSEGV (core dumped) +++
Segmentation fault (core dumped)
после ввода статической переменной
strace ./t
execve("./t", ["./t"], 0x7ffd4e270b00 /* 78 vars */) = 0
mprotect(0x401000, 1536000, PROT_READ|PROT_EXEC) = 0
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x28} ---
+++ killed by SIGSEGV (core dumped) +++
Segmentation fault (core dumped)
Re[4]: модификация elf, добавление сегмента+секции
Здравствуйте, kov_serg, Вы писали:
_>еще можете тут покопать:
Единственное, что настораживает, в отладчике виден mprotect с длинной 17 7000 , а в strace какая-то огромная длина 153 6000 вылезает
Re[5]: модификация elf, добавление сегмента+секции
От:
kov_serg
Дата: 21.02.25 09:48
Оценка:
Здравствуйте, Molchalnik, Вы писали:
M>после ввода статической переменной
Вы не просто переменную заведите вы её увеличте на 1.
Re[6]: модификация elf, добавление сегмента+секции
Здравствуйте, kov_serg, Вы писали:
_>Вы не просто переменную заведите вы её увеличте на 1.
сделал. теперь код программы, которую я патчу, такой #include <iostream>
int main()
{
static __thread int var = 0;
(void )var;
auto lang = "C++" ;
std::cout << "Hello and welcome to " << lang << "!\n" ;
volatile int varrr = var;
varrr = varrr + 1;
var = varrr;
++var;
return 0;
}
strace этой программы до моего кривого патча strace ./t
execve("./t", ["./t"], 0x7fffeccd6a10 /* 78 vars */) = 0
brk(NULL) = 0x7f7e000
brk(0x7f7ed80) = 0x7f7ed80
arch_prctl(ARCH_SET_FS, 0x7f7e400) = 0
set_tid_address(0x7f7e6d0) = 2555951
set_robust_list(0x7f7e6e0, 24) = 0
rseq(0x7f7ed20, 0x20, 0, 0x53053053) = 0
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
readlinkat(AT_FDCWD, "/proc/self/exe", "resourcetocpp/cmak"..., 4096) = 49
getrandom("\x34\x9c\x3d\xb2\xe2\x89\xe0\x57", 8, GRND_NONBLOCK) = 8
brk(NULL) = 0x7f7ed80
brk(0x7f9fd80) = 0x7f9fd80
brk(0x7fa0000) = 0x7fa0000
mprotect(0x5c8000, 45056, PROT_READ) = 0
futex(0x5d5dfc, FUTEX_WAKE_PRIVATE, 2147483647) = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0x4), ...}) = 0
write(1, "Hello and welcome to C++!\n", 26Hello and welcome to C++!
) = 26
exit_group(0) = ?
+++ exited with 0 +++
strace этой программы после патча strace ./t
execve("./t", ["./t"], 0x7ffce65de1f0 /* 78 vars */) = 0
mprotect(0x401000, 1536000, PROT_READ|PROT_EXEC) = 0
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x28} ---
+++ killed by SIGSEGV (core dumped) +++
Segmentation fault (core dumped)
UPD. поправлен код последнего strace
Re[5]: модификация elf, добавление сегмента+секции
От:
kov_serg
Дата: 21.02.25 11:16
Оценка:
Здравствуйте, Molchalnik, Вы писали:
M>Единственное, что настораживает, в отладчике виден mprotect с длинной 17 7000 , а в strace какая-то огромная длина 153 6000 вылезает
А как вы вызываете .init из первого сегмента?
.init
This section holds executable instructions that contribute to the process
initialization code. When a program starts to run, the system executes the
code in this section before calling the main program entry point (called
main for C programs).
Re[7]: модификация elf, добавление сегмента+секции
От:
kov_serg
Дата: 21.02.25 11:41
Оценка:
Здравствуйте, Molchalnik, Вы писали:
M>[cut=сделал. теперь код программы, которую я патчу, такой]
Вот тут есть
M>arch_prctl(ARCH_SET_FS, 0x7f7e400) = 0
А тут:
M>[cut=strace этой программы после патча]
M>[code]
M>strace ./t
M>execve("./t", ["./t"], 0x7ffce65de1f0 /* 78 vars */) = 0
M>mprotect(0x401000, 1536000, PROT_READ|PROT_EXEC) = 0
где arch_prctl(ARCH_SET_FS ?
M>--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x28} ---
M>UPD. поправлен код последнего strace
Re[8]: модификация elf, добавление сегмента+секции
Здравствуйте, kov_serg, Вы писали:
_>Вот тут есть
M>>arch_prctl(ARCH_SET_FS, 0x7f7e400) = 0
спасибо за подсказку (и за науку по инструментам), я нашёл причину. проваливается функция _dl_relocate_static_pie, и программа идёт на выход, который не может исполнить из-за незавершённости инициализации
это если я ничего в отладчике не пропустил
подробности регистры до
rax 0x140 0000
rbx 1
rcx f68
rdx 0x140 0000
rsi 5d27a8
rdi 1d
после запуска rax, rdx не меняются
но запускается такой вот код
mov r15, offset qword_4002E8
.text:00000000004C51BD mov r13, 4005E8h
.text:00000000004C51C4 cmp r15, r13
.text:00000000004C51C7 jb short loc_4C51E0
loc_4C51E0:
.text:00000000004C51E0 cmp dword ptr [r15+8], 25h ; '%'
.text:00000000004C51E5 mov r14, [r15]
.text:00000000004C51E8 jz short loc_4C51D0 ; до патча это условие срабатывает в другую ветку, а после - на код ниже
00000000004C51EA lea rdi, aUnexpectedRelo ; "Unexpected reloc type in static binary."...
.text:00000000004C51F1 call __libc_fatal
только вот я не знаю, что теперь с этим делать
Re[8]: модификация elf, добавление сегмента+секции
Здравствуйте, kov_serg, Вы писали:
_>А тут:
проверяет по адресу 4002F0 0x25(='%'), и если не оно, то пытается выйти с ошибкой Unexpected reloc type in static library, но у него не выходит, он напарывается на segfault
0x4002F0 — это самое начало, сразу после заголовка... чтобы я там мог нахимичать?
Re[8]: модификация elf, добавление сегмента+секции
Здравствуйте, kov_serg, Вы писали:
_>А тут:
кажется, я близок к пониманию, но ещё не нашёл ошибку, поэтому принимаю советы.
в новом, пропатченном elf этот адрес оказался в глубине pht entry, т.е. pht entry совпал с началом библиотеки
а в старом это где-то за меткой aGNU_1 (так IDA показывает)
походу, я не туда записал заголовок pht. ну или надо всё как-то смещать, чтобы не наезжало одно на другое.
Re[9]: модификация elf, добавление сегмента+секции
От:
kov_serg
Дата: 24.02.25 11:12
Оценка:
Здравствуйте, Molchalnik, Вы писали:
M>походу, я не туда записал заголовок pht. ну или надо всё как-то смещать, чтобы не наезжало одно на другое.
https://compilepeace.github.io/BINARY_DISSECTION_COURSE/
Пока на собственное сообщение не было ответов, его можно удалить.
Удалить