Ter acesso a uma ferramenta de análise enquanto está trabalhando com arquivos executáveis é sempre muito útil. Em sistemas POSIX (Linux, WSL, Cygwin, etc.) ObjDump é uma destas ferramentas. A mesma pode ser utilizada para extrair informação de arquivos objetos.
Aqui veremos como utilizar tal ferramenta e ter uma visão geral de como a mesma se comporta juntamente com a linguagem assembly.
O que é o ObjDump?
Conforme mencionado no início do artigo, ObjDump é uma ferramenta bastante útil para extrair informações de arquivos objetos. Esta ferramenta vem pré-instalada com a maioria das distribuições Linux. A seguir estão as opções de ajuda disponíveis ao executar (em inglês):
$ objdump
Usage: objdump <option(s)> <file(s)>
Display information from object <file(s)>.
At least one of the following switches must be given:
-a, --archive-headers Display archive header information
-f, --file-headers Display the contents of the overall file header
-p, --private-headers Display object format specific file header contents
-P, --private=OPT,OPT... Display object format specific contents
-h, --[section-]headers Display the contents of the section headers
-x, --all-headers Display the contents of all headers
-d, --disassemble Display assembler contents of executable sections
-D, --disassemble-all Display assembler contents of all sections
--disassemble=<sym> Display assembler contents from <sym>
-S, --source Intermix source code with disassembly
--source-comment[=<txt>] Prefix lines of source code with <txt>
-s, --full-contents Display the full contents of all sections requested
-g, --debugging Display debug information in object file
-e, --debugging-tags Display debug information using ctags style
-G, --stabs Display (in raw form) any STABS info in the file
-W, --dwarf[a/=abbrev, A/=addr, r/=aranges, c/=cu_index, L/=decodedline,
f/=frames, F/=frames-interp, g/=gdb_index, i/=info, o/=loc,
m/=macro, p/=pubnames, t/=pubtypes, R/=Ranges, l/=rawline,
s/=str, O/=str-offsets, u/=trace_abbrev, T/=trace_aranges,
U/=trace_info]
Display the contents of DWARF debug sections
-Wk,--dwarf=links Display the contents of sections that link to
separate debuginfo files
-WK,--dwarf=follow-links
Follow links to separate debug info files (default)
-WN,--dwarf=no-follow-links
Do not follow links to separate debug info files
-L, --process-links Display the contents of non-debug sections in
separate debuginfo files. (Implies -WK)
--ctf[=SECTION] Display CTF info from SECTION, (default '.ctf')
-t, --syms Display the contents of the symbol table(s)
-T, --dynamic-syms Display the contents of the dynamic symbol table
-r, --reloc Display the relocation entries in the file
-R, --dynamic-reloc Display the dynamic relocation entries in the file
@<file> Read options from <file>
-v, --version Display this program's version number
-i, --info List object formats and architectures supported
-H, --help Display this information
Como extrair o código assembly
A ferramenta ObjDump pode ser usada para extrair código assembly de um binário já montado. Vamos começar analisando o seguinte programa em assembly para entender melhor a abordagem que pode ser usada.
No exemplo vamos utilizar um programa que demonstra a concorrência utilizando threads (concorrencia.c):
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
volatile int contador = 0;
int loops;
void *worker(void *arg) {
int i;
for (i = 0; i < loops; i++) {
contador++;
}
return NULL;
}
int main(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "uso: concorrencia <loops>\n");
exit(1);
}
loops = atoi(argv[1]);
pthread_t p1, p2;
printf("Valor inicial : %d\n", contador);
pthread_create(&p1, NULL, worker, NULL);
pthread_create(&p2, NULL, worker, NULL);
pthread_join(p1, NULL);
pthread_join(p2, NULL);
printf("Valor final : %d\n", contador);
return 0;
}
Para compilar digite em um terminal:
gcc -o concorrencia.exe main.c -O2 -Wall -pthread -pg
Para visualizar o conteúdo de um binário, podemos utilizar a opção -x como mostrado a seguir:
$ objdump.exe -x concorrencia.exe
concorrencia.exe: file format pei-x86-64
concorrencia.exe
architecture: i386:x86-64, flags 0x0000013b:
HAS_RELOC, EXEC_P, HAS_DEBUG, HAS_SYMS, HAS_LOCALS, D_PAGED
start address 0x0000000100401000
Characteristics 0x26
executable
line numbers stripped
large address aware
Time/Date Tue Sep 20 08:11:12 2022
Magic 020b (PE32+)
MajorLinkerVersion 2
MinorLinkerVersion 39
SizeOfCode 0000000000001800
SizeOfInitializedData 0000000000003600
SizeOfUninitializedData 0000000000000400
AddressOfEntryPoint 0000000000001000
BaseOfCode 0000000000001000
ImageBase 0000000100400000
SectionAlignment 00001000
FileAlignment 00000200
MajorOSystemVersion 4
MinorOSystemVersion 0
MajorImageVersion 0
MinorImageVersion 0
MajorSubsystemVersion 5
MinorSubsystemVersion 2
Win32Version 00000000
SizeOfImage 00023000
SizeOfHeaders 00000600
CheckSum 00021ce5
Subsystem 00000003 (Windows CUI)
DllCharacteristics 00008000
TERMINAL_SERVICE_AWARE
SizeOfStackReserve 0000000000200000
SizeOfStackCommit 0000000000001000
SizeOfHeapReserve 0000000000100000
SizeOfHeapCommit 0000000000001000
LoaderFlags 00000000
NumberOfRvaAndSizes 00000010
The Data Directory
Entry 0 0000000000000000 00000000 Export Directory [.edata (or where ever we found it)]
Entry 1 0000000000009000 000006c0 Import Directory [parts of .idata]
Entry 2 000000000000a000 000004e8 Resource Directory [.rsrc]
Entry 3 0000000000006000 0000018c Exception Directory [.pdata]
Entry 4 0000000000000000 00000000 Security Directory
Entry 5 000000000000b000 0000000c Base Relocation Directory [.reloc]
Entry 6 0000000000005000 0000001c Debug Directory
Entry 7 0000000000000000 00000000 Description Directory
Entry 8 0000000000000000 00000000 Special Directory
Entry 9 0000000000000000 00000000 Thread Storage Directory [.tls]
Entry a 0000000000000000 00000000 Load Configuration Directory
Entry b 0000000000000000 00000000 Bound Import Directory
Entry c 00000000000091bc 00000180 Import Address Table Directory
Entry d 0000000000000000 00000000 Delay Import Directory
Entry e 0000000000000000 00000000 CLR Runtime Header
Entry f 0000000000000000 00000000 Reserved
There is an import table in .idata at 0x100409000
The Import Tables (interpreted .idata section contents)
vma: Hint Time Forward DLL First
Table Stamp Chain Name Thunk
00009000 0000903c 00000000 00000000 0000966c 000091bc
DLL Name: cygwin1.dll
vma: Hint/Ord Member-Name Bound-To
933c 7 __assert_func
934c 15 __cxa_atexit
935c 22 __errno
9368 35 __getreent
9378 46 __main
9384 108 _dll_crt0
9390 115 _impure_ptr
93a0 236 atoi
93a8 258 calloc
93b4 323 close
93bc 380 cygwin_detach_dll
93d0 382 cygwin_internal
93e4 410 dll_dllcrt0
93f4 468 exit
93fc 586 free
9404 627 fwrite
9410 654 getenv
941c 688 getpid
9428 712 gettimeofday
9438 916 malloc
9444 933 memcpy
9450 938 memset
945c 1005 open
9464 1020 perror
9470 1028 posix_memalign
9484 1059 printf
9490 1065 pthread_atfork
94a4 1108 pthread_create
94b8 1120 pthread_join
94c8 1213 realloc
94d4 1444 strlen
94e0 1693 write
00009014 00009144 00000000 00000000 000096b0 000092c4
DLL Name: KERNEL32.dll
vma: Hint/Ord Member-Name Bound-To
94e8 141 CloseHandle
94f6 197 CreateEventA
Como mencionado anteriormente, usamos o programa “concorrencia.exe” como nosso alvo. A saída anterior mostra as informações extraídas do cabeçalho. Isso inclui os metadados do binário do tipo elf (com os detalhes como formato de arquivo, arquitetura, etc.), cabeçalho do programa, seções disponíveis no binário (.text, .rodata) e a tabela de símbolos do executável.
Exibindo o conteúdo de uma seção executável de um código assembler
A seção .text é utilizada em um código Assembly na pré construção do binário. Isso pode ser feito utilizando a opção -d como mostrado a seguir:
$ objdump -d concorrencia.exe
concorrencia: file format elf32-i386
Disassembly of section .text:
08049000 <_start>:
8049000: ba 0e 00 00 00 mov $0xe,%edx
8049005: b9 00 a0 04 08 mov $0x804a000,%ecx
804900a: bb 01 00 00 00 mov $0x1,%ebx
804900f: b8 04 00 00 00 mov $0x4,%eax
8049014: cd 80 int $0x80
8049016: b8 01 00 00 00 mov $0x1,%eax
804901b: bb 00 00 00 00 mov $0x0,%ebx
8049020: cd 80 int $0x80
Como pode ser visto no exemplo acima o código assembly está no formato de sintax da AT&T, porém o mesmo pode ser modificado e mostrar seu conteúdo no formato x86 da Intel com a opção -M.
$ objdump -d concorrencia.exe -M intel
concorrencia: file format elf32-i386
Disassembly of section .text:
08049000 <_start>:
8049000: ba 0e 00 00 00 mov edx,0xe
8049005: b9 00 a0 04 08 mov ecx,0x804a000
804900a: bb 01 00 00 00 mov ebx,0x1
804900f: b8 04 00 00 00 mov eax,0x4
8049014: cd 80 int 0x80
8049016: b8 01 00 00 00 mov eax,0x1
804901b: bb 00 00 00 00 mov ebx,0x0
8049020: cd 80 int 0x80
Como podemos observar a saída no formato Intel é similar a AT&T. No caso descrito o formato Intel não é o padrão de saída. Porém dependendo do ambiente em que você esteja utilizando o mesmo poderá ser. Neste caso é bom conhecer quais os registradores que compõe a saída ou utilizar a opção -M explicitamente.
Se precisar mostrar todas as seções do código assembly no padrão Intel digite a opção -D conforme a seguir.
$ objdump -D concorrencia.exe -M intel
concorrencia: file format elf32-i386
Disassembly of section .text:
08049000 <_start>:
8049000: ba 0e 00 00 00 mov edx,0xe
8049005: b9 00 a0 04 08 mov ecx,0x804a000
804900a: bb 01 00 00 00 mov ebx,0x1
804900f: b8 04 00 00 00 mov eax,0x4
8049014: cd 80 int 0x80
8049016: b8 01 00 00 00 mov eax,0x1
804901b: bb 00 00 00 00 mov ebx,0x0
8049020: cd 80 int 0x80
Disassembly of section .rodata:
0804a000 <msg>:
804a000: 48 dec eax
804a001: 65 6c gs ins BYTE PTR es:[edi],dx
804a003: 6c ins BYTE PTR es:[edi],dx
804a004: 6f outs dx,DWORD PTR ds:[esi]
804a005: 2c 20 sub al,0x20
804a007: 77 6f ja 804a078 <msg+0x78>
804a009: 72 6c jb 804a077 <msg+0x77>
804a00b: 64 21 0a and DWORD PTR fs:[edx],ecx
Exibindo informações de depuração
Podemos também utilzar a opção -g para exibir informações a respeito de depuração de um binário. O resultado a seguir mostra estas informações de um arquivo compilado de um código C.
$ objdump -g mem
mem: file format elf64-x86-64
Contents of the .eh_frame section (loaded from mem):
00000000 0000000000000014 00000000 CIE
Version: 1
Augmentation: “zR”
Code alignment factor: 1
Data alignment factor: -8
Return address column: 16
Augmentation data: 1b
DW_CFA_def_cfa: r7 (rsp) ofs 8
DW_CFA_offset: r16 (rip) at cfa-8
DW_CFA_nop
DW_CFA_nop