Habréには、ELFトピックに関する多くの記事があります-人々だけがそれらを使用しません-デバイスを説明し、手動および自動で組み立て、編集、暗号化などを行います。次に、私の意見では、実際の低レベルプログラミングの多くの側面を一度に紹介した興味深い事例を共有したいと思います。
プログラムの編集、
ランタイムライブラリの一種のリバースエンジニアリングと移植、
デバイス実行可能ファイルWindowsおよびLinux、
このようなファイルを手動で組み立てて編集する
コンパイラを移植する際には、これらの側面やその他のいくつかの側面、および多くの非標準的な動きに触れます。同時に、実行可能ファイル(特にELF)に関連する作業の一部が最も興味深いと思われたので、それが記事のモチーフになります。
この記事は完全なチュートリアルではありませんが、上記の1つ以上の領域に関心があり、これらの領域の問題を解決するための非標準的なアプローチを発見(またはブラッシュアップ)する準備ができている読者にとって興味深いかもしれません。
作業の過程で必要なもの:
gccコンパイラ、ldリンカー、gdbデバッガ
binutilsのユーティリティ(readelf、strip、hexdump)
ポータブル実行可能(PE)および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
github.
, , , . , - . , ,
P.S.
, , . , , 9 . , . . , , , . , ( " ?") . , , , "", , ("" ).
また、科学顧問のアレクサンダー・コノバロフにも感謝せずにはいられません。
冒頭で述べたように、この記事はELFデバイスの説明、それらのクレイジーなトリックの実行方法、またはプログラムの移植を目的としたものではありません。しかし、実際の例を使用して、彼女は、通常の問題の非標準的な解決策がどのようになり得るか、それらを解決する過程でどのような興味深いことが観察できるか、そして自分自身のためにどのような発見をするかを示しました...そして多分彼女は誰かに次の一歩を踏み出すように勧めます未踏だがエキサイティングな挑戦...
リンク
ELF仕様
ソースBTPCコンパイラ
BTPC64の移植バージョン