Last active
October 4, 2019 00:56
-
-
Save jstaursky/92c82e4ed30db5e7e392ee1abd60d474 to your computer and use it in GitHub Desktop.
Bare bones linear disassembler
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Compile | |
// gcc -Wall Disassembler.c -lbfd -lcapstone -o Disassembler | |
// Usage | |
// ./Disassembler <binary> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <stdint.h> // uint8_t, etc. | |
#include <inttypes.h> // PRI{fmt}{type} | |
#include <string.h> | |
#include <errno.h> | |
#include <stdbool.h> | |
#include <bfd.h> // binary format desc | |
#include <capstone/capstone.h> // disassembly lib | |
typedef enum SectionType { | |
SEC_TYPE_CODE, | |
SEC_TYPE_DATA | |
} SectionType; | |
struct Binary { | |
uint64_t entry; | |
size_t nsections; | |
struct Section* section; | |
}; | |
struct Section { | |
size_t size; | |
uint64_t vaddr; | |
char const* name; | |
SectionType type; | |
uint8_t* bytes; | |
struct Section* next; | |
}; | |
void bin_getsectiondata (struct Binary* b, bfd* bfd_h) | |
{ | |
int sflags; | |
void bin_append (struct Binary*, bfd*, struct bfd_section**, SectionType); | |
b->nsections = 0; | |
b->section = NULL; | |
// Populate bin with executable sections info. | |
for (struct bfd_section* section = (bfd_h)->sections; section; | |
section = section->next) | |
{ | |
// Get section flags to identify section type. | |
sflags = bfd_get_section_flags (bfd_h, section); | |
// Determine section type from the flags add to bin if code section. | |
if (sflags & SEC_CODE) { | |
bin_append (&(*b), bfd_h, §ion, SEC_TYPE_CODE); | |
continue; | |
} else if (sflags & SEC_DATA) { | |
bin_append (&(*b), bfd_h, §ion, SEC_TYPE_DATA); | |
continue; | |
} | |
} | |
} | |
void bin_append (struct Binary* b, bfd* bfd_h, struct bfd_section** section, SectionType type) | |
{ | |
struct Section* new = malloc (sizeof (*new)); | |
new->next = NULL; | |
struct Section** appendee = &b->section; | |
while (*appendee != NULL) | |
appendee = &(*appendee)->next; | |
*appendee = new; | |
b->nsections += 1; | |
new->name = bfd_section_name (bfd_h, *section) ? | |
strdup (bfd_section_name (bfd_h, *section)) : | |
NULL; | |
if (new->name == NULL) | |
new->name = strdup ("no name"); | |
new->size = bfd_section_size (bfd_h, *section); | |
new->vaddr = bfd_section_vma (bfd_h, *section); | |
new->type = type; | |
new->bytes = malloc (new->size); | |
if (new->bytes == NULL) { | |
perror ("malloc failure"); | |
exit (1); | |
} | |
// Transfer section contents. | |
if (!bfd_get_section_contents (bfd_h, *section, new->bytes, 0, new->size)) { | |
perror ("bfd_get_section_contents failure"); | |
exit (1); | |
} | |
return; | |
} | |
void rdisasm (uint8_t* bytes, size_t size, uint64_t vaddr) | |
{ | |
// Setup disassembly library. | |
csh cap_h; | |
cs_insn* insn; | |
// Setup for 32-bit x86 disassembling. | |
cs_open (CS_ARCH_X86, CS_MODE_32, &cap_h); | |
// Enable detailed disassembly mode. | |
cs_option (cap_h, CS_OPT_DETAIL, CS_OPT_ON); | |
// Allocate instruction buffer (Enables control flow manipulation). | |
insn = cs_malloc (cap_h); | |
// TODO implement recursive disassembly. | |
size_t count = cs_disasm (cap_h, bytes, size, vaddr, 0, &insn); | |
for (size_t i = 0; i < count; ++i) { | |
printf ("0x%" PRIx64 ":\t%s\t\t%s\n", insn[i].address, insn[i].mnemonic, | |
insn[i].op_str); | |
} | |
} | |
int main (int argc, char* argv[]) | |
{ | |
char const* fname = argv[1]; | |
bfd* bfd_h; | |
// Initialize libbfd library and open file to create bfd handle. | |
bfd_init (); | |
bfd_h = bfd_openr (fname, NULL); | |
// Ensure file is either an executable or object file. | |
if (!bfd_check_format (bfd_h, bfd_object)) { | |
printf ("error %s is not executable\n", fname); | |
exit (1); | |
} | |
// Determine binary format (COFF, PE, ELF, ..., etc.). | |
if (bfd_get_flavour (bfd_h) == bfd_target_unknown_flavour) { | |
puts ("unrecognizable binary format"); | |
exit (1); | |
} | |
struct Binary bin; | |
// Find files entry point address. | |
bin.entry = bfd_get_start_address (bfd_h); | |
// Get all section information on executable sections. | |
bin_getsectiondata (&bin, bfd_h); | |
for (struct Section** section = &bin.section; *section != NULL; | |
section = &(*section)->next) | |
{ | |
printf ("SECTION %s\n", (*section)->name); | |
// Don't disassemble data sections. | |
if ((*section)->type == SEC_TYPE_DATA) | |
continue; | |
printf ("*** Disassembly of section %s ***\n", (*section)->name); | |
rdisasm ((*section)->bytes, (*section)->size, (*section)->vaddr); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment