static guint32 lookup_var (test_entry_t *entry, const char *name) { if (!strcmp ("file-size", name)) return entry->data_size; if (!strcmp ("pe-signature", name)) return get_pe_header (entry) - 4; if (!strcmp ("pe-header", name)) return get_pe_header (entry); if (!strcmp ("pe-optional-header", name)) return get_pe_header (entry) + 20; if (!strcmp ("section-table", name)) return get_pe_header (entry) + 244; if (!strcmp ("cli-header", name)) return get_cli_header (entry); if (!strcmp ("cli-metadata", name)) return get_cli_metadata_root (entry); if (!strcmp ("tables-header", name)) { guint32 metadata_root = get_cli_metadata_root (entry); guint32 tilde_stream = get_metadata_stream_header (entry, 0); guint32 offset = READ_VAR (guint32, entry->data + tilde_stream); return metadata_root + offset; } printf ("Unknown variable in expression %s\n", name); exit (INVALID_VARIABLE_NAME); }
static guint32 get_cli_header (test_entry_t *entry) { guint32 offset = get_pe_header (entry) + 20; /*pe-optional-header*/ offset += 208; /*cli header entry offset in the pe-optional-header*/ return translate_rva (entry, READ_VAR (guint32, entry->data + offset)); }
//-------------------------------------------------------------------------- bool win32_debmod_t::set_debug_hook(ea_t base) { // the debug hook for borland is located at the very beginning of // the program's text segment, with a clear signature before peheader_t pe; ea_t peoff = get_pe_header(base, &pe); if ( peoff == BADADDR ) return false; ea_t text = base + pe.text_start; uchar buf[4096]; if ( _read_memory(text, buf, sizeof(buf)) != sizeof(buf) ) return false; ssize_t bcc_hook_off = find_bcc_sign(buf, sizeof(buf)); if ( bcc_hook_off == -1 ) return false; uint32 bcc_hook; if ( _read_memory(text+bcc_hook_off, &bcc_hook, 4) != 4 ) return false; // now the bcc_hook might be already relocated or not. // it seems that vista loads files without relocating them for // the 'open file' dialog box. This is an heuristic rule: if ( bcc_hook < base + pe.text_start || bcc_hook > base + pe.imagesize ) return false; const uint32 active_hook = 2; // borland seems to want this number return _write_memory(bcc_hook, &active_hook, 4) == 4; }
//-------------------------------------------------------------------------- // calculate dll image size // since we could not find anything nice, we just look // at the beginning of the DLL module in the memory and extract // correct value from the file header uint32 win32_debmod_t::calc_imagesize(ea_t base) { peheader_t nh; ea_t offset = get_pe_header(base, &nh); if ( offset == BADADDR ) return 0; return nh.imagesize; }
static guint32 translate_rva (test_entry_t *entry, guint32 rva) { guint32 pe_header = get_pe_header (entry); guint32 sectionCount = READ_VAR (guint16, entry->data + pe_header + 2); guint32 idx = pe_header + 244; while (sectionCount-- > 0) { guint32 size = READ_VAR (guint32, entry->data + idx + 8); guint32 base = READ_VAR (guint32, entry->data + idx + 12); guint32 offset = READ_VAR (guint32, entry->data + idx + 20); if (rva >= base && rva <= base + size) return (rva - base) + offset; idx += 40; } printf ("Could not translate RVA %x\n", rva); exit (INVALID_RVA); }
//-------------------------------------------------------------------------- // get name from export directory in PE image in debugged process bool win32_debmod_t::get_pe_export_name_from_process( ea_t imagebase, char *name, size_t namesize) { peheader_t pe; ea_t peoff = get_pe_header(imagebase, &pe); if ( peoff != BADADDR && pe.expdir.rva != 0) { ea_t ea = imagebase + pe.expdir.rva; peexpdir_t expdir; if ( _read_memory(ea, &expdir, sizeof(expdir)) == sizeof(expdir) ) { ea = imagebase + expdir.dllname; name[0] = '\0'; _read_memory(ea, name, namesize); // don't check the return code because // we might have read more than necessary if ( name[0] != '\0' ) return true; } } return false; }
exe_info_t* get_exe_info(FILE* stream, uint32_t offset) { exe_info_t* exe_info = (exe_info_t*) malloc(sizeof(exe_info_t)); if (! exe_info) return NULL; // Get MZ header exe_info->mz_header = get_mz_header(stream, offset); if (! exe_info->mz_header) { free(exe_info); return NULL; } // Set additional parameters (1 block = 512 bytes, 1 paragraph = 16 bytes) exe_info->extra_offset = 0x0200 * exe_info->mz_header->blocks_in_file; if ((exe_info->extra_offset) && (exe_info->mz_header->bytes_in_last_block > 0x0000) && (exe_info->mz_header->bytes_in_last_block < 0x0200)) exe_info->extra_offset -= 0x0200 - exe_info->mz_header->bytes_in_last_block; exe_info->data_offset = 0x0010 * exe_info->mz_header->paragraphs_in_header; exe_info->is_segmented = (exe_info->mz_header->reloc_table_offset == RELOCATION_TABLE_OFFSET) ? 1 : 0; exe_info->ne_header = NULL; exe_info->le_header = NULL; exe_info->lx_header = NULL; exe_info->pe_header = NULL; if (exe_info->is_segmented) { // Get segmented info load_segmented_info(stream, &exe_info->segmented_offset, &exe_info->segmented_syncword); } else { exe_info->segmented_offset = 0x0000; exe_info->segmented_syncword = 0x0000; } if ((! exe_info->segmented_offset) || (! exe_info->segmented_syncword)) return exe_info; switch (exe_info->segmented_syncword) { case NE_HEADER_SYNC: exe_info->ne_header = get_ne_header(stream, exe_info->segmented_offset); break; case LE_HEADER_SYNC: exe_info->le_header = get_le_header(stream, exe_info->segmented_offset); break; case LX_HEADER_SYNC: exe_info->lx_header = get_lx_header(stream, exe_info->segmented_offset); break; case PE_HEADER_SYNC: exe_info->pe_header = get_pe_header(stream, exe_info->segmented_offset); break; default: break; } return exe_info; }