char *ropit_x86_list_disasm (uint8_t *bytes, int len) { int pos = 0; // current position in buffer int size; // size of instruction x86_insn_t insn; // instruction char line[4096] = {0}; int linelen = 4096; char *listing = NULL; listing = calloc(2048, sizeof(*listing)); x86_init(opt_none, NULL, NULL); while ( pos < len ) { // disassemble address size = x86_disasm(bytes, len, 0, pos, &insn); if ( size ) { // print instruction x86_format_insn(&insn, line, linelen, intel_syntax); // printf("%s\n", line); strcat(listing, line); strcat(listing, "\n"); pos += size; } else { pos++; } x86_oplist_free(&insn); } x86_cleanup(); return listing; }
void perplex_section(pefile_t *pefile, int section_number) { char *data; size_t size; x86_insn_t insn; int pos = 0; int section_start; assert(pefile != NULL); section_start = pefile->pimage_section_headers[section_number].VirtualAddress + pefile->image_nt_headers.OptionalHeader.ImageBase; data = get_section_data(pefile, section_number, &size); if (data == NULL) return; x86_init(opt_none, 0); while (pos < size) { char line[512]; int insn_size = x86_disasm(data, size, 0, pos, &insn); if (insn_size > 0) { x86_format_insn(&insn, line, sizeof line, intel_syntax); //printf("%08X: %s\n", pos + section_start, line); pos += insn_size; } else { //printf("%08X: Invalid Instruction\n", pos + section_start); pos++; } } x86_cleanup(); }
// disasm 1 instruction char *ropit_x86_disasm (uint8_t *bytes, int len, int *sz_dis) { int sz_inst, len_disasm; /* sz_inst of instruction */ x86_insn_t insn; /* instruction */ char line[1024]; int sz_line = 1024; char *disasm; if (!bytes || len <= 0 || !sz_dis) { debug_printf (MESSAGE_ERROR, stderr, "error: ropit_x86_disasm(): Bad parameter(s)\n"); return NULL; } len_disasm = 0; x86_init(opt_none, NULL, NULL); sz_inst = x86_disasm (bytes, len, 0, 0, &insn); if (sz_inst > 0) { len_disasm = x86_format_insn (&insn, line, sz_line, intel_syntax); *sz_dis = sz_inst; } x86_oplist_free (&insn); x86_cleanup(); if (len_disasm == 0) return NULL; disasm = calloc (len_disasm, sizeof(*disasm)); if (!disasm) { debug_printf (MESSAGE_ERROR, stderr, "error: ropit_x86_disasm(): Failed disasm alloc\n"); return NULL; } memcpy (disasm, line, len_disasm); return disasm; }
void *decode_instructions( void *buf, void *buf_limit, void *(*putxml_fptr)(void *putxml_data, const char *element_format, void *element_data), void *putxml_data, void *(*printf_fptr)(void *printf_data, const char *format, ...), void *printf_data, const char *config_string) { #define PUTXML(efmt, edata) (*putxml_fptr)(putxml_data, (const char*)(efmt), (void*)(edata)) #define PRINTF(fmt, x) (*printf_fptr)(printf_data, (const char*)(fmt), x) #define PRINTF2(fmt, x, y) (*printf_fptr)(printf_data, (const char*)(fmt), x, y) size_t buf_size = (char*)buf_limit - (char*)buf; unsigned char *uc_buf = (unsigned char*) buf; int have_opnd, which; x86_insn_t insn; x86_op_t *opnd; intptr_t addr; char sbuf[MAX_OP_STRING * 2]; size_t pos, size; if (!putxml_fptr) { putxml_fptr = empty_putxml; } if (!printf_fptr) { intptr_t stdio_fprintf_addr = (intptr_t) &fprintf; printf_fptr = (void * (*)(void *, const char *, ...)) stdio_fprintf_addr; if (!printf_data) printf_data = stdout; } x86_init(0, 0, 0); PUTXML("insns", buf); PUTXML("mach name='%s'/", "i386(base-hsdis)"); PUTXML("format bytes-per-line='%p'/", (intptr_t)FORMAT_BYTES_PER_LINE); for (pos = 0; pos < buf_size; pos += size) { size = x86_disasm(uc_buf, buf_size, (intptr_t) buf, pos, &insn); PUTXML("insn", (char*)buf + pos); if (size == 0) { PRINTF("invalid\t0x%02x", uc_buf[pos]); size = 1; /* to make progress */ } else { PRINTF2("%s%s", insn.prefix_string, insn.mnemonic); have_opnd = 0; for (which = 0; which < 3; which++) { /* dest comes first, then src and/or imm */ switch (which) { case 0: opnd = x86_operand_1st(&insn); break; case 1: opnd = x86_operand_2nd(&insn); break; default: opnd = x86_operand_3rd(&insn); break; } if (!opnd) continue; if (opnd->flags & op_implied) continue; if (!have_opnd++) PRINTF("\t", 0); else PRINTF(", ", 0); addr = addr_from_operand(opnd); if (!(addr && PUTXML("addr/", addr))) { x86_format_operand(opnd, sbuf, sizeof(sbuf), intel_syntax); PRINTF("%s", sbuf); } } } PUTXML("/insn", (char*)buf + pos + size); PRINTF("\n", 0); } PUTXML("/insns", (char*)buf + pos); x86_cleanup(); return (char*)buf + pos; }
int main(int argc, char *argv[]) { char line[128]; struct stat sbuf; char *input = NULL; char *buf = NULL; FILE *fd = NULL; int ret = 0; int offset = 0; int size = 0; x86_insn_t x86dis; printf("\n[*] simple x86 shellcode disassembler\n"); printf("[*] trivially implemented thanks 2 libdisasm!\n"); printf("[*] written by [email protected]\n"); input = argv[1]; if (!argv[1]) { printf("[*] usage: %s <shellcode as binary.file>\n", argv[0]); ret = 1; goto die; } memset((char *)&sbuf, 0, sizeof(sbuf)); if (stat(input, &sbuf) == -1) { printf("[!] unable to stat %s!\n", input); ret = 1; goto die; } buf = malloc(sbuf.st_size); if (!buf) { printf("[!] failed to allocate %u bytes!\n", sbuf.st_size); ret = 1; goto die; } fd = fopen(input, "r"); if (!fd) { printf("[!] unable to open %s\n", input); ret = 1; goto die; } if (fread(buf, 1, sbuf.st_size, fd) != sbuf.st_size) { printf("[!] failed to read in %u bytes!\n", sbuf.st_size); ret = 1; goto die; } fclose(fd); fd = NULL; printf("\n"); x86_init(opt_none, NULL, NULL); while (offset < sbuf.st_size) { size = x86_disasm(buf, sbuf.st_size, 0, offset, &x86dis); if (!size) { printf("[!] invalid op at %i!\n", offset); break; } memset(line, 0, sizeof(line)); x86_format_insn(&x86dis, line, sizeof(line), intel_syntax); printf("%08X: %s\n", offset, line); offset += size; } x86_cleanup(); die: printf("\n"); if (buf) { free(buf); } if (fd) { fclose(fd); } return ret; }
// find valid instructions offsets before ret int _ropit_x86_find_gadgets (uint8_t *bytes, int len, int64_t *rets, int n_rets) { int sz_inst; /* size of instruction */ x86_insn_t insn; /* instruction */ int idx_ret, sz_ret; int valid_gadget; // back track instruction count int n_backtrack_inst, n_backtrack_bytes; // start for rop search uint8_t *start, *gadget_start; // disassemble int len_disasm; int sz_dst; char disassembled[DISASSEMBLED_SIZE_MAX] = {0}; // cache FILE *fp_cache; struct cache_t *caches; int idx_caches, n_caches; struct gadget_t *gadgets; int idx_gadgets, n_gadgets; // cache queue struct gadget_cache_queue_t *cache_queue; // count int count_gadgets; // check params if (!bytes || len <= 0) { debug_printf (MESSAGE_ERROR, stderr, "error: _ropit_x86_find_gadgets(): Bytes null or len <= 0\n"); return NULL; } // search rets if (!rets || n_rets <= 0) { debug_printf (MESSAGE_ERROR, stderr, "error: _ropit_x86_find_gadgets(): No rets\n"); return NULL; } // init gadget_cache fp_cache = fopen("tmp/gadget_cache", "w"); if (!fp_cache) { debug_printf (MESSAGE_ERROR, stderr, "error: _ropit_x86_find_gadgets(): Failed open (w)\n"); return NULL; } // init cache_queue cache_queue = NULL; if (!gadget_cache_queue_init(&cache_queue)) { debug_printf (MESSAGE_ERROR, stderr, "error: _ropit_x86_find_gadgets(): Cache queue allocation failed\n"); return NULL; } gadget_cache_queue_set_file (cache_queue, fp_cache); // init gadgets n_gadgets = 1024; gadgets = calloc(sizeof(struct gadget_t), n_gadgets); if (!gadgets) { debug_printf (MESSAGE_ERROR, stderr, "error: _ropit_x86_find_gadgets(): Failed allocating caches\n"); return NULL; } for (idx_gadgets = 0; idx_gadgets < n_gadgets; idx_gadgets++) gadget_init(&(gadgets[idx_gadgets]), DISASSEMBLED_SIZE_MAX); // init caches n_caches = 1; caches = calloc(sizeof(struct cache_t), n_caches); if (!caches) { debug_printf (MESSAGE_ERROR, stderr, "error: _ropit_x86_find_gadgets(): Failed allocating caches\n"); return NULL; } for (idx_caches = 0; idx_caches < n_caches; idx_caches++) { cache_init(&(caches[idx_caches]), 1024); } // init disasm x86_init(opt_none, NULL, NULL); idx_caches = 0; idx_gadgets = 0; count_gadgets = 0; for (idx_ret = 0; idx_ret < n_rets; idx_ret++) { start = bytes + rets[idx_ret]; n_backtrack_inst = 0; n_backtrack_bytes = 0; while ( bytes <= start && start <= bytes + len ) { /* disassemble address */ sz_inst = x86_disasm(start, len - (start - bytes), 0, 0, &insn); x86_oplist_free(&insn); if (sz_inst <= 0) { // printf("not found inst\n"); n_backtrack_bytes++; } else { // printf("found inst\n"); n_backtrack_bytes = 0; valid_gadget = 0; // gadget_start = start; if (gadget_start == bytes + rets[idx_ret]) valid_gadget = 1; else { n_backtrack_inst = 0; // check gadget validity while (bytes <= gadget_start && gadget_start <= bytes + rets[idx_ret]) { /* disassemble address */ sz_inst = x86_disasm(gadget_start, gadget_start - bytes, 0, 0, &insn); x86_oplist_free(&insn); if (sz_inst <= 0) break; else { n_backtrack_inst++; gadget_start += sz_inst; if (gadget_start == bytes + rets[idx_ret]) { valid_gadget = 1; break; } } } } if (valid_gadget == 1) { // ++count_gadgets; // get ret size sz_ret = x86_disasm(bytes + rets[idx_ret], 10, 0, 0, &insn); x86_oplist_free(&insn); // fill gadget structure gadgets[idx_gadgets].ret_addr = rets[idx_ret]; gadgets[idx_gadgets].ret_bytes = rets[idx_ret] + bytes; gadgets[idx_gadgets].address = start - bytes; gadgets[idx_gadgets].len_bytes = (rets[idx_ret] - (start - bytes)) + sz_ret; if (gadgets[idx_gadgets].sz_bytes < gadgets[idx_gadgets].len_bytes) { gadgets[idx_gadgets].bytes = realloc (gadgets[idx_gadgets].bytes, gadgets[idx_gadgets].len_bytes); gadgets[idx_gadgets].sz_bytes = gadgets[idx_gadgets].len_bytes; } memcpy(gadgets[idx_gadgets].bytes, start, gadgets[idx_gadgets].len_bytes); if (cache_add (&(caches[idx_caches]), &(gadgets[idx_gadgets])) == -ERR_CACHE_FULL) { gadget_cache_queue_add (cache_queue, &(caches[idx_caches])); gadget_cache_queue_fwrite_worker (cache_queue); cache_reset (&(caches[idx_caches])); } idx_gadgets = (idx_gadgets + 1) % n_gadgets; } } --start; // maximum intel instruction size is 15 // maximum instructions in a gadget is hardcoded to 8 here /* TODO : Get more gadgets with n_backtrack_inst instructions * Effectively, we stop at the first gadget which has * n_backtrack_inst instructions while there might be multiple * possibilities. */ if (n_backtrack_bytes >= 15 || n_backtrack_inst == 8) break; } } x86_cleanup(); // write remaining gadgets gadget_cache_queue_add (cache_queue, &(caches[idx_caches])); gadget_cache_queue_fwrite_worker (cache_queue); cache_reset (&(caches[idx_caches])); // clean up for (idx_caches = 0; idx_caches < n_caches; idx_caches++) free(caches[idx_caches].objects); free(caches); for (idx_gadgets = 0; idx_gadgets < n_gadgets; idx_gadgets++) { // gadget_free(&(gadgets[idx_gadgets])); // free (gadgets[idx_gadgets].repr); free (gadgets[idx_gadgets].bytes); } free(gadgets); gadget_cache_queue_destroy (&cache_queue); fclose (fp_cache); return count_gadgets; }
void ApiHook_cleanup() { x86_cleanup(); }