Skip to content

Instantly share code, notes, and snippets.

@jstaursky
Last active October 4, 2019 00:56
Show Gist options
  • Save jstaursky/92c82e4ed30db5e7e392ee1abd60d474 to your computer and use it in GitHub Desktop.
Save jstaursky/92c82e4ed30db5e7e392ee1abd60d474 to your computer and use it in GitHub Desktop.
Bare bones linear disassembler
// 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, &section, SEC_TYPE_CODE);
continue;
} else if (sflags & SEC_DATA) {
bin_append (&(*b), bfd_h, &section, 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