This document provides some brief examples of how to use libopdis and the opdis command line utility.
Use the -N option to disassemble a symbol in an object file using the control-flow algorithm.
opdis -N main a.out
Note: Only symbols recognized by libbfd can be disassembled. The --list-bfd-symbols option can be used to list all available symbols in a BFD target:
opdis --list-bfd-symbols -B a.out
Enclose the hexadecimal bytes in quotes as an argument to the -b option.
opdis -b '90 90 90 90' opdis -b 'CC' opdis -b "`od -j 0x1C20 -t x1 -A x -N 16 -w16 a.out | head -1 | cut -f 1 -d ' ' --complement `"
1. Use readelf to get the offset, size, and vma of the .text section.
readelf -S a.out | grep -A 1 text [14] .text PROGBITS 0000000000401c20 00001c20 0000000000004de8 0000000000000000 AX 0 0 16
This section can be mapped to the load address with the option -m :0x1C20@0x401C20+0x4DE8 (:offset+size). The section can be disassembled using the option -l @0x401C20+0x4DE8 (+length).
2. Use readelf to get the address of the main symbol.
readelf -s a.out | grep main 17: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main\@GLIBC_2.2.5 (3) 124: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main\@\@GLIBC_ 208: 00000000004026c0 1417 FUNC GLOBAL DEFAULT 14 main
The symbol can be disassembled using -c @0x4026C0 ().
3. Run opdis to generate the disassembly.
Linear disassembly of text section:
opdis -m :0x1C20@0x401C20+0x4DE8 -l @0x401C20+0x4DE8
Control-flow disassembly of entry point:
opdis -m :0x1C20@0x401C20+0x4DE8 -c @0x4026C0
First, an opdis_buf_t must be allocated and filled with the contents of the memory location. The VMA of the memory location can be used as the VMA of the opdis_buf_t. Next, an opdis_t is created using the default values, and opdis_disasm_linear is used to disassemble the bytes.
#include <opdis/opdis.h> void disassemble_mem( void * src, opdis_offset_t length ) { opdis_t o; opdis_buf_t buf = opdis_buf_alloc( length, (opdis_vma_t) src ); opdis_buf_fill( buf, 0, src, length ); o = opdis_init(); opdis_disasm_linear( o, buf, (opdis_vma_t) src, length ); opdis_term( o ); }
Note that the opdis_t is never configured, so the default values are used. This means that the architecture is i386, the syntax is Intel, and the instructions are written to STDOUT.
This is the same as disassembling a memory location except that the opdis_buf_t is read from a file.
#include <opdis/opdis.h> void disassemble_file( FILE * f, opdis_vma_t vma, opdis_offset_t offset ) { opdis_t o; opdis_buf_t buf = opdis_buf_read( f, 0, 0 ); o = opdis_init(); opdis_disasm_linear( o, buf, offset, length ); opdis_term( o ); }
Initializing an opdis_t from a valid bfd pointer will configure the target architecture automatically. A valid BFD section can then be disassembled using opdis_disasm_bfd_section.
#include <opdis/opdis.h> int disassemble_bfd_section( const char * filename, const char * sec_name ) { opdis_t o; struct bfd_section * section; bfd *abfd = bfd_openr( filename, NULL ); if (! abfd ) { fprintf( stderr, "Unable to create BFD for %s\n", filename ); return 0; } if ( bfd_get_flavour( abfd ) == bfd_target_unknown_flavour ) { fprintf( stderr, "Unknown BFD flavor: cannot continue\n" ); return 0; } section = bfd_get_section_by_name( abfd, sec_name ); if (! section ) { fprintf( stderr, "Cannot find BFD section %s\n", sec_name ); return 0; } o = opdis_init_from_bfd( abfd ); opdis_disasm_bfd_section( o, section ) opdis_term( o ); return 1; }
Note: opdis_init_from_bfd only configures the architecture of the opdis_t. The other options will be set to their defaults, e.g. the instructions will be printed to STDOUT.
As with disassembling a BFD section, a valid bfd object can be used to configure an opdis_t. The opdis_disasm_bfd_entry function can be used to disassemble the entry point of the object file, if one exists.
#include <opdis/opdis.h> int disassemble_bfd_entry( const char * filename ) { opdis_t o; bfd *abfd = bfd_openr( filename, NULL ); if (! abfd ) { fprintf( stderr, "Unable to create BFD for %s\n", filename ); return 0; } if ( bfd_get_flavour( abfd ) == bfd_target_unknown_flavour ) { fprintf( stderr, "Unknown BFD flavor: cannot continue\n" ); return 0; } o = opdis_init_from_bfd( abfd ); opdis_disasm_bfd_entry( o, abfd ) opdis_term( o ); return 1; }