Microsurgery ELF'a atau "Mengapa, itu sangat mungkin ?!"

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 . , , :





Isi proyek: 2 file sumber (btpc.pas di Pascal dan rtl.asm di assembler) dan 1 biner
: 2 (btpc.pas Pascal rtl.asm ) 1

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





  • - ( )





Dengan cara ini, kode dari rtl.asm masuk ke btpc.pas
rtl.asm btpc.pas

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"





  1. . - – R10 "R?".





  2. MOV i8086+. "r/m β†’R?". , 0x8B.





  3. R10 4 , 3 Rn ModR/M.





  4. "" " REX".





  5. R10 R REX Rn ModR/M.





  6. ModR/M 32- , R/M ModR/M = 100, Mod = 00. SIB.





  7. R12, 1, X REX SIB.





  8. SIB , [#Base + #Index2^(Scale)]. Base R12. 3 = 100 3 Base SIB.





  9. (Index) SIB 3 R13 = 101.





  10. (1 + 1 ), Scale SIB = 00 2^(Scale) = 2^0 = 1.





  11. R13 B REX. SIB.





  12. REX: "0100" + "W:1" + "R:1" + "X:1" + "B:1" = 01001111, hex 0x4F. REX .





  13. ModR/M: "Mod:00" + "Rn:010" + "R/M:100" = 00010100, 0x14.





  14. 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





Bagian kode dipetakan ke awal file

, . - . 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 . , . . , , , . , ( " ?") . , , , "", , ("" ).





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 ...





Tautan

  • Spesifikasi ELF





  • Penyusun sumber BTPC





  • Versi porting dari BTPC64












All Articles