Aggiungiamo delle label ad un file ELF - Linux executable
Pubblicato da Pusillus il 14/02/2000
Livello avanzato
Introduzione
Da qualche tempo questo SO sta riscuotendo sempre piu' popolarita' alla faccia di chi non aveva mai visto come un concorrente un progetto open source! (vedi Micro$oft).
Fino a poco tempo fa dal punto di vista del reversing non si era guardato molto a Linux perche' tutto il software era distribuito in forma di sorgente e quindi ritenuto poco utile. Ma ultimamente le cose stanno cambiando e molte software house stanno implementando programmi e giochi per Linux.
Certo siamo ancora agli albori, non esistono dei debugger di sistema come SoftIce per Linux (a parte kdb.....), i disassembler sono home made ecc. ecc., ma questo rende tutto ancora piu' interessante no!?
Da questo punto di vista Linux e' una fonte inesauribile visto che sono disponibili in in rete documentazioni di ogni tipo e i sorgenti di qualsiasi cosa si voglia.
Programmi usati
Iniziamo
Ulteriori informazioni su questi tools e alcuni interessanti tutorial sono disponibili su http://hculinux.cjb.net
Dopo questo breve preambolo, inizierei subito a spiegarvi gli intenti di questo tute:
quello che vi propongo e' un breve studio del formato ELF comune a Linux a e a molti altri Unix in circolazione.
In pratica si tratta dell'equivalente del formato PE per il Windows, anzi si puo dire che il PE non e' altro che una scopiazzatura del formato ELF molto semplificata, infatti il formato ELF e' molto piu' complicato ma per fortuna ben documentato.
Lo scopo di questo tute e' quello di aggiungere alcune informazioni all'interno dell'ELF che ci permetteranno di definire delle label in modo da facilitarne il debugging, sara' possibile quindi settare un breakpoint su una label con un nome da noi impostato corrispondente ad un determinato indirizzo.
Quando viene compilato un programma con il GCC con le opzioni di debugging (-g) all'interno del programma eseguibile saranno presenti tutte le infomazioni che permettono al debugger di raggiungere variabili funzioni etichette ecc.. Ma attraverso un semplice comando: "strip" e' possibile eliminare tutte queste utili info in un colpo solo e far diventare il programma abbastanza criptico considerando pure il fatto che il formato AT&T dell'assembler mostrato dal debugger non ci molto familiare, anche se si dice che sia meno contraddittorio di quello Intel.
La struttura di un file eseguibile ELF questa:
Execution View
==============
ELF header
Program header table
Segment 1
Segment 2
...
Section header table (optional)
ELF header: risiede all'inzio del file e descrive l'organizzazione del file.
ELF header
#define EI_NIDENT 16
typedef struct {
unsigned char e_ident[EI_NIDENT];
Elf32_Half e_type;
Elf32_Half e_machine;
Elf32_Word e_version;
Elf32_Addr e_entry;
Elf32_Off e_phoff;
Elf32_Off e_shoff;
Elf32_Word e_flags;
Elf32_Half e_ehsize;
Elf32_Half e_phentsize;
Elf32_Half e_phnum;
Elf32_Half e_shentsize;
Elf32_Half e_shnum;
Elf32_Half e_shstrndx;
} Elf32_Ehdr;
e_ident: marcaggio del file come ELF uguale a: '0x7f E L F';typedef struct {
Elf32_Word sh_name;
Elf32_Word sh_type;
Elf32_Word sh_flags;
Elf32_Addr sh_addr;
Elf32_Off sh_offset;
Elf32_Word sh_size;
Elf32_Word sh_link;
Elf32_Word sh_info;
Elf32_Word sh_addralign;
Elf32_Word sh_entsize;
} Elf32_Shdr;
sh_name : in questa variabile e' contenuto un indice alla sezione 'section header string table (.shstrtab)' nella quale risiedono i nomi di tutte le sezioni del file ELF (1);typedef Struct {
Elf32_Word st_name;
Elf32_Addr st_value;
Elf32_Word st_size;
unsigned char st_info;
unsigned char st_other;
Elf32_Half st_shndx;
} Elf32_Sym;
st_name : indice alla .strtab contenente i nomi dei simboli; File : mainstrip Size : 2980 bytes 12%
00000000: 7F 45 4C 46 01 01 01 00 00 00 00 00 00 00 00 00 ?ELF A A A
00000010: 02 00 03 00 01 00 00 00 30 83 04 08 34 00 00 00 B C A 0â D
00000020: BC 07 00 00 00 00 00 00 34 00 20 00 06 00 28 00 +^G 4 ^F
-->00000030: 19 00 18 00 06 00 00 00 34 00 00 00 34 80 04 08 ^Y ^X ^F 4
00000040: 34 80 04 08 C0 00 00 00 C0 00 00 00 05 00 00 00 4Ç^D^H+ + E
00000050: 04 00 00 00 03 00 00 00 F4 00 00 00 F4 80 04 08 ^D ^C
00000060: F4 80 04 08 13 00 00 00 13 00 00 00 04 00 00 00 Ç^D^H^S ^S
Adesso dobbiamo ispezionare la .shstrtab (la tabella contenete i nomi delle sezioni), trovare i nomi corrispondenti alla .strtab e alla .symtab e prender nota dell'index all'interno della sezione. Fortunatamente il comando strip non altera il contenuto della .shstrtab e i nomi delle sezioni rimangono invariati anche se i realativi section headers vengono rimossi.000006E5: 00 2E 73 79 6D 74 61 62 00 2E 73 74 72 74 61 62 .symtab .strtab
000006F5: 00 2E 73 68 73 74 72 74 61 62 00 2E 69 6E 74 65 .shstrtab .inte
00000705: 72 70 00 2E 6E 6F 74 65 2E 41 42 49 2D 74 61 67 rp .note.ABI-tag
00000715: 00 2E 68 61 73 68 00 2E 64 79 6E 73 79 6D 00 2E .hash .dynsym .
00000725: 64 79 6E 73 74 72 00 2E 67 6E 75 2E 76 65 72 73 dynstr .gnu.vers
00000735: 69 6F 6E 00 2E 67 6E 75 2E 76 65 72 73 69 6F 6E ion .gnu.version
00000745: 5F 72 00 2E 72 65 6C 2E 67 6F 74 00 2E 72 65 6C _r .rel.got .rel
00000755: 2E 70 6C 74 00 2E 69 6E 69 74 00 2E 70 6C 74 00 .plt .init .plt
00000765: 2E 74 65 78 74 00 2E 66 69 6E 69 00 2E 72 6F 64 .text .fini .rod
00000775: 61 74 61 00 2E 64 61 74 61 00 2E 65 68 5F 66 72 ata .data .eh_fr
00000785: 61 6D 65 00 2E 63 74 6F 72 73 00 2E 64 74 6F 72 ame .ctors .dtor
00000795: 73 00 2E 67 6F 74 00 2E 64 79 6E 61 6D 69 63 00 s .got .dynamic
000007A5: 2E 62 73 73 00 2E 63 6F 6D 6D 65 6E 74 00 2E 6E .bss .comment .n
000007B5: 6F 74 65 00 00 00 00 00 00 00 00 00 00 00 00 00 ote
come potrete notare i nomi delle sezioni sono in testa alla .shstrtab e gli indici corrispondenti sono .symtab=1 .strtab=9 . Questi due valori ci saranno utili per la costituzione dei nuovi section headers.sh_type sh_link sh_info
======= ======= =======
SHT_DYNAMIC The section header index of 0 the string table used by entries in the section.
SHT_HASH The section header index of 0 the symbol table to which the hash table applies.
SHT_REL, The section header index of The section header index of
SHT_RELA the associated symbol table. the section to which the relocation applies.
SHT_SYMTAB, The section header index of One greater than the symbol
SHT_DYNSYM the associated string table. table index of the last local symbol (binding STB_LOCAL).
other SHN_UNDEF 0
section header .strtab:
hstrtab.sh_name = 00000009; indice alla .shstrtab
hstrtab.sh_type = 00000003; SHT_STRTAB
hstrtab.sh_flags = 00000000;
hstrtab.sh_addr = 00000000;
hstrtab.sh_offset = 00000C34; offset dove risiedera' nel file la .strtab (5)
hstrtab.sh_size = 00000028; dimensione della sezione in bytes
hstrtab.sh_link = 00000000;
hstrtab.sh_info = 00000000;
hstrtab.sh_addralign = 00000001; tipo di allineamento
hstrtab.sh_entsize = 00000000; non specificato, si tratta di null-terminated strings
(5) la .strtab sara' inserita dopo la .symtab quindi considerando i 40h bytes che compongono la .symtab ci troveremo prorio a 0C34h.00000BA4: 01 00 00 00 02 00 00 00 00 00 00 00 00 00 00 00 ^A ^B
00000BB4: F4 0B 00 00 40 00 00 00 1A 00 00 00 03 00 00 00 ^K @ ^Z ^C
00000BC4: 04 00 00 00 10 00 00 00 09 00 00 00 03 00 00 00 ^D ^P ^C
00000BD4: 00 00 00 00 00 00 00 00 34 0C 00 00 28 00 00 00 4^L (
00000BE4: 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 ^A
00000BF4: 01 00 00 00 00 00 00 00 00 00 00 00 00 00 0C 00 ^A ^L
00000C04: 02 00 00 00 F5 83 04 08 00 00 00 00 00 00 0C 00 ^B §â^D^H ^L
00000C14: 08 00 00 00 E8 83 04 08 00 00 00 00 00 00 0C 00 ^H Þâ^D^H ^L
00000C24: 0E 00 00 00 DB 83 04 08 00 00 00 00 00 00 0C 00 ^N _â^D^H ^L
00000C34: 00 00 72 69 67 61 33 00 72 69 67 61 32 00 72 69 riga3 riga2 ri
00000C44: 67 61 31 00 00 00 00 00 00 00 00 00 00 00 00 00 ga1
00000C54: 00 00 00 00 00 00 00 00
Finalmente abbiamo concluso la manipolazione del file, e devo dire che smanettare con gli editor hex e' una bella scocciatura!>gdb mainstrip
GNU gdb 4.18
Copyright 1998 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i686-pc-linux-gnu"...
(no debugging symbols found)...
(gdb) br riga1
Breakpoint 1 at 0x80483db
(gdb) br riga2
Breakpoint 2 at 0x80483e8
(gdb) br riga3
Breakpoint 3 at 0x80483f5
(gdb) run
Starting program: /mainstrip
Breakpoint 1, 0x80483db in riga1 ()
(gdb) disassemble riga1
Dump of assembler code for function riga1:
0x80483db <riga1>: mov %ebp,%esp
0x80483dd <riga1+2>: pop %ebp
0x80483de <riga1+3>: ret
0x80483df <riga1+4>: nop
0x80483e0 <riga1+5>: push %ebp
0x80483e1 <riga1+6>: mov %esp,%ebp
0x80483e3 <riga1+8>: mov %ebp,%esp
0x80483e5 <riga1+10>: pop %ebp
0x80483e6 <riga1+11>: ret
0x80483e7 <riga1+12>: nop
End of assembler dump.
(gdb) cont
Continuing.
Breakpoint 2, 0x80483e8 in riga2 ()
(gdb) disassemble riga2
Dump of assembler code for function riga2:
0x80483e8 <riga2>: push $0x8048464
0x80483ed <riga2+5>: call 0x8048314 <printf>
0x80483f2 <riga2+10>: add $0x4,%esp
End of assembler dump.
(gdb) cont
Continuing.
ciao bello
Breakpoint 3, 0x80483f5 in riga3 ()
(gdb) cont
Continuing.
Program exited normally.
(gdb) q
>
Quello che abbiamo fatto non e' molto, solo un piccolo aiuto per il debugging. Sicuramente inserire a mano queste informazioni e' una grossa perdita di tempo e non ne varrebbe la pena, ma ho fatto un programmino che dovrebbe fare tutto questo per noi. Purtroppo credo sia pieno di bachi perche' l'ho dovuto fare in piu' riprese, spero presto di dedicargli un po del mio tempo per sistemare il sorgente C, renderlo pubblico e magari aggiungere altre funzioni oltre all'inserimento di labels, ammesso che sia possibile, visto che non ho potuto ancora approfondire la faccenda. Magari qualche volenteroso potrebbe darmi una mano ;))Conclusioni
Spero di non essere stato troppo noiso, e di avervi proposto qualcosa di diverso del solito Win reversing.
Pusillus.