Di HabrΓ© terdapat banyak artikel tentang topik ELF - yang hanya tidak dapat dilakukan oleh orang lain - menjelaskan perangkat mereka, merakitnya secara manual dan otomatis, mengedit, mengenkripsi, dan banyak lagi. Saya, pada gilirannya, ingin berbagi kasus menarik, menurut pendapat saya, yang sekaligus memperkenalkan saya pada banyak aspek pemrograman tingkat rendah dalam praktik:
kompilasi program,
semacam rekayasa balik dan porting pustaka runtime,
file perangkat yang dapat dieksekusi Windows dan Linux,
merakit dan mengedit file tersebut secara manual
Ini dan beberapa aspek lainnya, serta banyak gerakan non-standar, akan disinggung saat porting compiler . Pada saat yang sama, bagian dari pekerjaan yang terkait dengan file yang dapat dieksekusi (dan ELF khususnya) menurut saya adalah yang paling menarik, jadi itu akan menjadi motif utama artikel.
Artikel ini bukan tutorial lengkap, tetapi mungkin menarik bagi pembaca yang tertarik pada satu atau lebih area di atas dan siap untuk menemukan (atau memoles) pendekatan non-standar untuk memecahkan masalah di area ini.
Dalam pekerjaan kita membutuhkan:
gcc compiler, ld linker, gdb debugger
utilitas dari binutils (readelf, strip, hexdump)
pemahaman dasar tentang perangkat portabel yang dapat dieksekusi (PE) dan ELF
Pascal
, Bero TinyPascal Compiler (, BTPC) 2016 - Pascal, (Benjamin Rosseaux). Pascal' (Delphi 7-XE7 FreePascal >= 3) Windows x32. , .
github . , , :
BTPC ( btpc.exe) self-contained - - ~3 . . - , , , . , , .
Pascal', , - -, , -, . , . " ".
Seg fault
BTPC - PE (Portable Executable, Mircosoft), .. "ELF Windows". , ELF, , - .
, PE 2
Portable Executable (PE) β , , Microsoft Windows. PE , , PE- . , API- ..
PE COFF Unix. «» PE β ELF ( Linux Unix) Mach-O ( Mac OS X).
, , Pascal, , , -:
-
- "-"
- "" PE-
PE- , "" .
- . , (Runtime Library, RTL).
Runtime Library 2
RTL- - CRT C/C++. , , , .. , , .
- pre-start post-exit "", main' . , , main, ( ), main .
PE- RTL 9 :
RTLHalt β
RTLWriteChar β charβ stdout
RTLWriteInteger β integer' stdout
RTLWriteLn β linebreak' stdout
RTLReadChar β EAX STDIN
RTLReadInteger β EAX integer' STDOUT
RTLReadLn β STDIN EOF ( )
RTLEOF β EAX EOF. 0 β .
RTLEOLN β 1 DL, - \n, 0 β
- , :
.ENTRYPOINT
JMP StubEntryPoint #
RTLHalt:
... # RTLHalt
RTLWriteChar:
...
... # RTL
RTLFunctionTable: #
DD OFFSET RTLHalt
DD OFFSET RTLWriteChar
DD OFFSET RTLWriteInteger
...
StubEntryPoint:
INVOKE HeapAlloc ... #
MOV ESI, OFFSET RTLFunctionTable #
ProgramEntryPoint:
, RTL, :
StubEntryPoint
ESI
β¦ , ProgramEntryPoint !
, , BTPC ProgramEntryPoint.
, 2 - .
: btpc.pas rtl.asm . btpc.pas blob, :
{ }
procedure EmitStubCode;
begin
OutputCodeDataSize := 0;
OutputCodeString(#77#90#82#195#66#101#82#111#94#102#114#0#80#69#0#0#76#1#1#0#0#0#0#0#...
OutputCodeString(#0#0#0#0#0#0#0#0#0#0#0#0#0#0#16#0#0#0#16#0#0#143##16#0#0#0#0...
OutputCodeString(#0#0#0#0#0#0#0#0#0#0#255#255#255#255#40#16#0#0#53#0#0#0...
OutputCodeString(#101#110#106#97#109#105#110#32#39#66#101#82#111#...
OutputCodeDataSize := 1423;
end;
{ }
- Pascal- , rtl.asm.
, PE .
, :
RTL ( ) , PE- ( , - )
PE- - ( , 255 )
, - NOP
- ( )
BTPC :
stdin
, -
, -
( - PE-)
, "" , ,
PE32
: - . , , . , , ( ). : , , , .
: 4 , 156 . 100 . , 4 , 100 .
, RTL, Excagena, - PE-. / , Excagena , .
-, PE. , , ProgramEntryPoint - , .
- - PE-. - :
(OptionalHeader.SizeOfCode)
(SectionTable.VirtualSize)
(OptionalHeader.SizeOfImage),
- , , :
{ }
CodeSize := OutputCodeGetInt32($29) + (OutputCodeDataSize - CodeStart);
OutputCodePutInt32($29, CodeSize);
{ }
SectionAlignment := OutputCodeGetInt32($45);
{ }
SectionVirtualSize := CodeSize;
Value := CodeSize mod SectionAlignment;
SectionVirtualSize := SectionVirtualSize + (SectionAlignment - Value);
OutputCodePutInt32($10d, SectionVirtualSize);
{ }
OutputCodePutInt32($5d, SectionVirtualSize + OutputCodeGetInt32($39));
, $29, $45, $115 β¦
, - Linux x64 . , :
RTL Linux x64
ELF-
ELF-,
- 3
- "" WinApi .
, , . . - , Win32 API, :
ReadCharBuffer: DB 0x90
ReadCharBytesRead: DB 0x90,0x8D,0x40,0x00
ReadCharEx:
PUSHAD
INVOKE ReadFile, DWORD PTR StdHandleInput, OFFSET ReadCharBuffer, 1, OFFSET ReadCharBytesRead, BYTE 0
TEST EAX, EAX
SETZ AL
OR BYTE PTR IsEOF, AL
CMP DWORD PTR [ReadCharBytesRead], 0
SETZ AL
OR BYTE PTR IsEOF, AL
POPAD
RET
, , . , - " " - ReadCharBuffer ReadCharBytesRead. , β¦
- , , . ( - , - , - ), .
, 64- syscall ( ). , RDI, RSI, RDX . RAX.
x64 pusha, pushad, popa, popad. pushall, popall, . - bss.
, - data.
:
.section .data # -
ReadCharBuffer:
.byte 0x3c
.section .text # -
ReadCharEx:
PUSHALL # - bss
XORQ %RAX, %RAX # syscall #0: read(int fd, void *buf, size_t count)
XORQ %RDI, %RDI # fd : 0 == stdin
MOVQ $ReadCharBuffer, %RSI # buf : ReadCharBuffer
MOVQ $1, %RDX # count : 1 byte
SYSCALL
CMPQ $0, %RAX
SETZ %BL
ORB %BL, (IsEOF)
POPALL
RET
, - . , - , Guard Page.
, , Linux , , , Segmentation fault. , , . , . Guard Page . , , , , .
:
$ gcc -c rtl64.s $ ld rtl64.o -g --output rtl64
ELF - BTPC . .
, BTPC - EmitByte:
procedure OCPopESI;
begin
EmitByte($5e);
LastOutputCodeValue := locPopESI;
end;
procedure OCMovzxEAXAL;
begin
EmitByte($0f);
EmitByte($b6);
EmitByte($c0);
LastOutputCodeValue := locMovzxEAXAL;
end;
, , x64. - ,
1 -
MOV R10, [R12 + R13]
, (, ) "Intel 64 and IA-32 Architectures Developerβs Manual"
. - β R10 "R?".
MOV i8086+. "r/m βR?". , 0x8B.
R10 4 , 3 Rn ModR/M.
"" " REX".
R10 R REX Rn ModR/M.
ModR/M 32- , R/M ModR/M = 100, Mod = 00. SIB.
R12, 1, X REX SIB.
SIB , [#Base + #Index2^(Scale)]. Base R12. 3 = 100 3 Base SIB.
(Index) SIB 3 R13 = 101.
(1 + 1 ), Scale SIB = 00 2^(Scale) = 2^0 = 1.
R13 B REX. SIB.
REX: "0100" + "W:1" + "R:1" + "X:1" + "B:1" = 01001111, hex 0x4F. REX .
ModR/M: "Mod:00" + "Rn:010" + "R/M:100" = 00010100, 0x14.
SIB: "Scale:00" + "Index:101" + "Base:100" = 00101100, 0x2C.
MOV R10, (R12 + R13)
0x4F 0x8B 0x14 0x2C
.
, PE- , , . , BTPC 70 .
: , , .
.
ELF'
, , BTPC - , , "" , , , . .
, , - ELF' - ELF'.
, . 2 :
ELF64 PE32
PE32 ,
readelf' rtl64:
$ readelf --section-headers rtl64 Section Headers: [Nr] Name Type Address Offset Size EntSize Flags Link Info Align [ 0] NULL 0000000000000000 00000000 0000000000000000 0000000000000000 0 0 0 [ 1] .text PROGBITS 00000000004000b0 000000b0 0000000000000317 0000000000000000 AX 0 0 1 [ 2] .data PROGBITS 00000000006003c7 000003c7 00000000000000bf 0000000000000000 WA 0 0 1 [ 3] .symtab SYMTAB 0000000000000000 00000488 0000000000000408 0000000000000018 4 39 8 [ 4] .strtab STRTAB 0000000000000000 00000890 0000000000000248 0000000000000000 0 0 1 [ 5] .shstrtab STRTAB 0000000000000000 00000ad8 0000000000000027 0000000000000000 0 0 1
- ELF' 6 !:
( )
β text
β data
β shstrtab (Section header string table)
symtab
strtab
, . - . ProgramEntryPoint , " ".
? . , 4 , , ELF'.
ld (--nostdlib, --strip-all):
$ ld rtl64.o -g --output rtl64-min -nostdlib --strip-all
ELF 2 - 1.4 . :
$ readelf --section-headers rtl64-min Section Headers: [Nr] Name Type Address Offset Size EntSize Flags Link Info Align [ 0] NULL 0000000000000000 00000000 0000000000000000 0000000000000000 0 0 0 [ 1] .text PROGBITS 00000000004000b0 000000b0 0000000000000317 0000000000000000 AX 0 0 1 [ 2] .data PROGBITS 00000000006003c7 000003c7 00000000000000bf 0000000000000000 WA 0 0 1 [ 3] .shstrtab STRTAB 0000000000000000 00000486 0000000000000017 0000000000000000 0 0 1
2 . , shstrtab . , binutils strip, . shstrtab :
$ strip -R shstrtab rtl64-min $ readelf --section-headers rtl64-min Section Headers: [Nr] Name Type Address Offset Size EntSize Flags Link Info Align [ 0] NULL 0000000000000000 00000000 0000000000000000 0000000000000000 0 0 0 [ 1] .text PROGBITS 00000000004000b0 000000b0 0000000000000317 0000000000000000 AX 0 0 1 [ 2] .data PROGBITS 00000000006003c7 000003c7 00000000000000bf 0000000000000000 WA 0 0 1 [ 3] .shstrtab STRTAB 0000000000000000 00000486 0000000000000017 0000000000000000 0 0 1
Shstrtab . , :
$ hexdump -C rtl64-min 00000480 40 00 00 00 00 00 00 2e 73 68 73 74 72 74 61 62 |@.......shstrtab| 00000490 00 2e 74 65 78 74 00 2e 64 61 74 61 00 00 00 00 |..text..data....| 000004a0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
β¦ ! . , .shstrtab . , , - , .
, ( ). . , .
, :
ENTRY(_start) /* */
SECTIONS
{
. = 0x4000b0; /* */
.data : { *(.data) }
.bss : { *(.bss) *(COMMON) }
. = 0x6000d3; /* */
.text : { *(.text) } /* */
}
ld - . , , ld --verbose
- , , . .
. :
$ ld rtl64.o -g --output rtl64-custom-ld -T linkerScript.ld -nostdlib --strip-all $ readelf --section-headers rtl64-custom-ld Section Headers: [Nr] Name Type Address Offset Size EntSize Flags Link Info Align [ 0] NULL 0000000000000000 00000000 0000000000000000 0000000000000000 0 0 0 [ 1] .data PROGBITS 00000000006000b0 000000b0 00000000000000bf 0000000000000000 WA 0 0 1 [ 2] .text PROGBITS 0000000000a00170 00000170 0000000000000317 0000000000000000 AX 0 0 1 [ 3] .shstrtab STRTAB 0000000000000000 00000487 0000000000000017 0000000000000000 0 0 1
, ! text, , data.
, , . gdb, - , , , , .
, - gdb . , β¦
, , , symtab strtab , . , - - ( , .. )
, . , , . stackoverflow , , . :
, , :
|
|
Elf__hdr.e__shoff |
0x28 |
Text_phdr.p_filesz |
sizeof(Elf__hdr) + sizeof(p_hdr) + 0x20 |
Text_phdr.p_memsz |
sizeof(Elf_hdr) + sizeof(p_hdr) + 0x28 |
Text_shdr.sh_size |
Elf_hdr.e_shoff + sizeof(injection) + 2*sizeof(s_hdr) + 0x20 |
Shstrtab_shdr.sh_offs |
Elf_hdr.e_shoff + sizeof(injection) + 3*sizeof(s_hdr) + 0x18 |
Symtab_shdr.sh_offs |
Elf_hdr.e_shoff + sizeof(injection) + 4*sizeof(s_hdr) + 0x18 |
Strtab_shdr.sh_offs |
Elf_hdr.e_shoff + sizeof(injection) + 5*sizeof(s_hdr) + 0x18 |
: sizeof(injection). .
, , ELF', - , , , .
, , "", "" "", .
. , ELF, , . - . , RTL.
.
- bootstrapping
#
$ btpc.exe < btpc64.pas > btpcCrossWin.exe
# Linuxβ
$ btpcCrossWin.exe < btpc64.pas > btpc64Linux
# , «» , Linux
$ btpc64Linux < btpc64.pas > btpc64Check
Pascal, Linux x64, .
, , . :
BTPC
, Pascal Windows
(RTL)
RTL ELF
, , , . , - . , ,
P.S.
, , . , , 9 . , . . , , , . , ( " ?") . , , , "", , ("" ).
Juga, saya berterima kasih kepada penasihat ilmiah saya, Alexander Konovalov.
Seperti disebutkan di awal, artikel ini tidak dimaksudkan untuk menjelaskan perangkat ELF, mengajarkan cara melakukan trik gila pada mereka, atau program port. Tetapi dengan menggunakan contoh nyata, dia, saya harap, menunjukkan bagaimana solusi non-standar dari masalah biasa dapat dilakukan, hal-hal menarik apa yang dapat diamati dalam proses penyelesaiannya dan penemuan apa yang bisa Anda buat sendiri ... Dan, mungkin, dia akan mendorong seseorang untuk mengambil langkah pertama menuju langkah berikutnya. tantangan yang belum dipetakan tapi menarik ...