Home | History | Annotate | Download | only in libdisasm
      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #include <string.h>
      4 
      5 #include "libdis.h"
      6 #include "ia32_insn.h"
      7 #include "ia32_invariant.h"
      8 #include "x86_operand_list.h"
      9 
     10 
     11 #ifdef _MSC_VER
     12         #define snprintf        _snprintf
     13         #define inline          __inline
     14 #endif
     15 
     16 unsigned int x86_disasm( unsigned char *buf, unsigned int buf_len,
     17                 uint32_t buf_rva, unsigned int offset,
     18                 x86_insn_t *insn ){
     19         int len, size;
     20 	unsigned char bytes[MAX_INSTRUCTION_SIZE];
     21 
     22         if ( ! buf || ! insn || ! buf_len ) {
     23                 /* caller screwed up somehow */
     24                 return 0;
     25         }
     26 
     27 
     28 	/* ensure we are all NULLed up */
     29 	memset( insn, 0, sizeof(x86_insn_t) );
     30         insn->addr = buf_rva + offset;
     31         insn->offset = offset;
     32 	/* default to invalid insn */
     33 	insn->type = insn_invalid;
     34 	insn->group = insn_none;
     35 
     36         if ( offset >= buf_len ) {
     37                 /* another caller screwup ;) */
     38                 x86_report_error(report_disasm_bounds, (void*)(long)buf_rva+offset);
     39                 return 0;
     40         }
     41 
     42         len = buf_len - offset;
     43 
     44 	/* copy enough bytes for disassembly into buffer : this
     45 	 * helps prevent buffer overruns at the end of a file */
     46 	memset( bytes, 0, MAX_INSTRUCTION_SIZE );
     47 	memcpy( bytes, &buf[offset], (len < MAX_INSTRUCTION_SIZE) ? len :
     48 		MAX_INSTRUCTION_SIZE );
     49 
     50         /* actually do the disassembly */
     51 	/* TODO: allow switching when more disassemblers are added */
     52         size = ia32_disasm_addr( bytes, len, insn);
     53 
     54         /* check and see if we had an invalid instruction */
     55         if (! size ) {
     56                 x86_report_error(report_invalid_insn, (void*)(long)buf_rva+offset );
     57                 return 0;
     58         }
     59 
     60         /* check if we overran the end of the buffer */
     61         if ( size > len ) {
     62                 x86_report_error( report_insn_bounds, (void*)(long)buf_rva + offset );
     63 		MAKE_INVALID( insn, bytes );
     64 		return 0;
     65 	}
     66 
     67         /* fill bytes field of insn */
     68         memcpy( insn->bytes, bytes, size );
     69 
     70         return size;
     71 }
     72 
     73 unsigned int x86_disasm_range( unsigned char *buf, uint32_t buf_rva,
     74                       unsigned int offset, unsigned int len,
     75                       DISASM_CALLBACK func, void *arg ) {
     76         x86_insn_t insn;
     77         unsigned int buf_len, size, count = 0, bytes = 0;
     78 
     79         /* buf_len is implied by the arguments */
     80         buf_len = len + offset;
     81 
     82         while ( bytes < len ) {
     83                 size = x86_disasm( buf, buf_len, buf_rva, offset + bytes,
     84                                    &insn );
     85                 if ( size ) {
     86                         /* invoke callback if it exists */
     87                         if ( func ) {
     88                                 (*func)( &insn, arg );
     89                         }
     90                         bytes += size;
     91                         count ++;
     92                 } else {
     93                         /* error */
     94                         bytes++;        /* try next byte */
     95                 }
     96 
     97 		x86_oplist_free( &insn );
     98         }
     99 
    100         return( count );
    101 }
    102 
    103 static inline int follow_insn_dest( x86_insn_t *insn ) {
    104         if ( insn->type == insn_jmp || insn->type == insn_jcc ||
    105              insn->type == insn_call || insn->type == insn_callcc ) {
    106                 return(1);
    107         }
    108         return(0);
    109 }
    110 
    111 static inline int insn_doesnt_return( x86_insn_t *insn ) {
    112         return( (insn->type == insn_jmp || insn->type == insn_return) ? 1: 0 );
    113 }
    114 
    115 static int32_t internal_resolver( x86_op_t *op, x86_insn_t *insn ){
    116         int32_t next_addr = -1;
    117         if ( x86_optype_is_address(op->type) ) {
    118                 next_addr = op->data.sdword;
    119         } else if ( op->type == op_relative_near ) {
    120 		next_addr = insn->addr + insn->size + op->data.relative_near;
    121         } else if ( op->type == op_relative_far ) {
    122 		next_addr = insn->addr + insn->size + op->data.relative_far;
    123         }
    124         return( next_addr );
    125 }
    126 
    127 unsigned int x86_disasm_forward( unsigned char *buf, unsigned int buf_len,
    128                         uint32_t buf_rva, unsigned int offset,
    129                         DISASM_CALLBACK func, void *arg,
    130                         DISASM_RESOLVER resolver, void *r_arg ){
    131         x86_insn_t insn;
    132         x86_op_t *op;
    133         int32_t next_addr;
    134         uint32_t next_offset;
    135         unsigned int size, count = 0, bytes = 0, cont = 1;
    136 
    137         while ( cont && bytes < buf_len ) {
    138                 size = x86_disasm( buf, buf_len, buf_rva, offset + bytes,
    139                            &insn );
    140 
    141                 if ( size ) {
    142                         /* invoke callback if it exists */
    143                         if ( func ) {
    144                                 (*func)( &insn, arg );
    145                         }
    146                         bytes += size;
    147                         count ++;
    148                 } else {
    149                         /* error */
    150                         bytes++;        /* try next byte */
    151                 }
    152 
    153                 if ( follow_insn_dest(&insn) ) {
    154                         op = x86_get_dest_operand( &insn );
    155                         next_addr = -1;
    156 
    157                         /* if caller supplied a resolver, use it to determine
    158                          * the address to disassemble */
    159                         if ( resolver ) {
    160                                 next_addr = resolver(op, &insn, r_arg);
    161                         } else {
    162                                 next_addr = internal_resolver(op, &insn);
    163                         }
    164 
    165                         if (next_addr != -1 ) {
    166                                 next_offset = next_addr - buf_rva;
    167                                 /* if offset is in this buffer... */
    168                                 if ( (uint32_t)next_addr >= buf_rva &&
    169                                      next_offset < buf_len ) {
    170                                         /* go ahead and disassemble */
    171                                         count += x86_disasm_forward( buf,
    172                                                             buf_len,
    173                                                             buf_rva,
    174                                                             next_offset,
    175                                                             func, arg,
    176                                                             resolver, r_arg );
    177                                 } else  {
    178                                         /* report unresolved address */
    179                                         x86_report_error( report_disasm_bounds,
    180                                                      (void*)(long)next_addr );
    181                                 }
    182                         }
    183                 } /* end follow_insn */
    184 
    185                 if ( insn_doesnt_return(&insn) ) {
    186                         /* stop disassembling */
    187                         cont = 0;
    188                 }
    189 
    190 		x86_oplist_free( &insn );
    191         }
    192         return( count );
    193 }
    194 
    195 /* invariant instruction representation */
    196 size_t x86_invariant_disasm( unsigned char *buf, int buf_len,
    197 		x86_invariant_t *inv ){
    198 	if (! buf || ! buf_len || ! inv  ) {
    199 		return(0);
    200 	}
    201 
    202 	return ia32_disasm_invariant(buf, buf_len, inv);
    203 }
    204 size_t x86_size_disasm( unsigned char *buf, unsigned int buf_len ) {
    205 	if (! buf || ! buf_len  ) {
    206 		return(0);
    207 	}
    208 
    209 	return ia32_disasm_size(buf, buf_len);
    210 }
    211