00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "formats.h"
00022 #include "htanaly.h"
00023 #include "htctrl.h"
00024 #include "htdata.h"
00025 #include "htendian.h"
00026 #include "htiobox.h"
00027 #include "htnewexe.h"
00028 #include "htpal.h"
00029 #include "htpe.h"
00030 #include "htpeimp.h"
00031 #include "stream.h"
00032 #include "htstring.h"
00033 #include "httag.h"
00034 #include "log.h"
00035 #include "pe_analy.h"
00036 #include "snprintf.h"
00037 #include "tools.h"
00038
00039 #include <stdlib.h>
00040 #include <string.h>
00041
00042 static ht_view *htpeimports_init(bounds *b, ht_streamfile *file, ht_format_group *group)
00043 {
00044 ht_pe_shared_data *pe_shared=(ht_pe_shared_data *)group->get_shared_data();
00045
00046 if (pe_shared->opt_magic!=COFF_OPTMAGIC_PE32 && pe_shared->opt_magic!=COFF_OPTMAGIC_PE64) return NULL;
00047
00048 bool pe32 = (pe_shared->opt_magic==COFF_OPTMAGIC_PE32);
00049
00050 dword sec_rva, sec_size;
00051 if (pe32) {
00052 sec_rva = pe_shared->pe32.header_nt.directory[PE_DIRECTORY_ENTRY_IMPORT].address;
00053 sec_size = pe_shared->pe32.header_nt.directory[PE_DIRECTORY_ENTRY_IMPORT].size;
00054 } else {
00055 sec_rva = pe_shared->pe64.header_nt.directory[PE_DIRECTORY_ENTRY_IMPORT].address;
00056 sec_size = pe_shared->pe64.header_nt.directory[PE_DIRECTORY_ENTRY_IMPORT].size;
00057 }
00058 if (!sec_rva || !sec_size) return NULL;
00059
00060 int h0=new_timer();
00061 start_timer(h0);
00062
00063 ht_group *g;
00064 bounds c;
00065
00066 c=*b;
00067 g=new ht_group();
00068 g->init(&c, VO_RESIZE, DESC_PE_IMPORTS"-g");
00069 ht_statictext *head;
00070
00071 int dll_count=0;
00072 int function_count=0;
00073
00074 c.y++;
00075 c.h--;
00076 ht_pe_import_viewer *v=new ht_pe_import_viewer();
00077 v->init(&c, DESC_PE_IMPORTS, group);
00078
00079 c.y--;
00080 c.h=1;
00081
00082 PE_IMPORT_DESCRIPTOR import;
00083 FILEOFS dofs;
00084 UINT dll_index;
00085 char iline[256];
00086
00087
00088
00089 FILEOFS iofs;
00090 RVA irva;
00091 UINT isize;
00092 if (pe32) {
00093 irva = pe_shared->pe32.header_nt.directory[PE_DIRECTORY_ENTRY_IMPORT].address;
00094 isize = pe_shared->pe32.header_nt.directory[PE_DIRECTORY_ENTRY_IMPORT].size;
00095 } else {
00096 irva = pe_shared->pe64.header_nt.directory[PE_DIRECTORY_ENTRY_IMPORT].address;
00097 isize = pe_shared->pe64.header_nt.directory[PE_DIRECTORY_ENTRY_IMPORT].size;
00098 }
00099
00100 if (!pe_rva_to_ofs(&pe_shared->sections, irva, &iofs)) goto pe_read_error;
00101 LOG("%s: PE: reading import directory at offset %08x, rva %08x, size %08x...", file->get_filename(), iofs, irva, isize);
00102
00103
00104
00105
00106
00107
00108
00109 dofs = iofs;
00110 dll_index = 0;
00111
00112 while (1) {
00113 file->seek(dofs);
00114 file->read(&import, sizeof import);
00115 create_host_struct(&import, PE_IMPORT_DESCRIPTOR_struct, little_endian);
00116 if ((!import.characteristics) && (!import.name)) break;
00117 dofs = file->tell();
00118
00119 FILEOFS iname_ofs;
00120 if (!pe_rva_to_ofs(&pe_shared->sections, import.name, &iname_ofs)
00121 || file->seek(iname_ofs)) {
00122
00123 if (file->seek(import.name)) goto pe_read_error;
00124 }
00125 char *dllname = fgetstrz(file);
00126 dll_count++;
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136 RVA fthunk_rva = import.first_thunk;
00137 FILEOFS fthunk_ofs;
00138 if (!pe_rva_to_ofs(&pe_shared->sections, fthunk_rva, &fthunk_ofs)) goto pe_read_error;
00139
00140
00141
00142
00143
00144
00145 RVA thunk_rva;
00146 FILEOFS thunk_ofs;
00147 if (import.original_first_thunk) {
00148 thunk_rva = import.original_first_thunk;
00149 if (!pe_rva_to_ofs(&pe_shared->sections, thunk_rva, &thunk_ofs)) goto pe_read_error;
00150 } else {
00151 thunk_rva = fthunk_rva;
00152 thunk_ofs = fthunk_ofs;
00153 }
00154 ht_pe_import_library *lib=new ht_pe_import_library(dllname);
00155 pe_shared->imports.libs->insert(lib);
00156
00157 PE_THUNK_DATA thunk;
00158 PE_THUNK_DATA_64 thunk64;
00159 UINT thunk_count = 0;
00160 file->seek(thunk_ofs);
00161 while (1) {
00162 if (pe32) {
00163 file->read(&thunk, sizeof thunk);
00164 create_host_struct(&thunk, PE_THUNK_DATA_struct, little_endian);
00165 if (!thunk.ordinal) break;
00166 } else {
00167 file->read(&thunk64, sizeof thunk64);
00168 create_host_struct(&thunk64, PE_THUNK_DATA_64_struct, little_endian);
00169 if (!QWORD_GET_LO(thunk64.ordinal)) break;
00170 }
00171 thunk_count++;
00172 }
00173
00174 PE_THUNK_DATA *thunk_table = NULL;
00175 PE_THUNK_DATA_64 *thunk_table64 = NULL;
00176 file->seek(thunk_ofs);
00177 if (pe32) {
00178 thunk_table=(PE_THUNK_DATA*)malloc(sizeof *thunk_table * thunk_count);
00179 file->read(thunk_table, sizeof *thunk_table * thunk_count);
00180
00181 for (UINT i=0; i<thunk_count; i++) {
00182 create_host_struct(thunk_table+i, PE_THUNK_DATA_struct, little_endian);
00183 }
00184 } else {
00185 thunk_table64=(PE_THUNK_DATA_64*)malloc(sizeof *thunk_table64 * thunk_count);
00186 file->read(thunk_table64, sizeof *thunk_table64 * thunk_count);
00187
00188 for (UINT i=0; i<thunk_count; i++) {
00189 create_host_struct(thunk_table64+i, PE_THUNK_DATA_64_struct, little_endian);
00190 }
00191 }
00192 for (dword i=0; i<thunk_count; i++) {
00193 function_count++;
00194 ht_pe_import_function *func;
00195
00196 if (pe32) {
00197 thunk = *(thunk_table+i);
00198
00199 if (thunk.ordinal & 0x80000000) {
00200
00201 func = new ht_pe_import_function(dll_index, fthunk_rva, thunk.ordinal&0xffff);
00202 } else {
00203
00204 FILEOFS function_desc_ofs;
00205 word hint = 0;
00206 if (!pe_rva_to_ofs(&pe_shared->sections, thunk.function_desc_address, &function_desc_ofs)
00207 || file->seek(function_desc_ofs)) {
00208 if (file->seek(thunk.function_desc_address)) goto pe_read_error;
00209 }
00210 file->read(&hint, 2);
00211 hint = create_host_int(&hint, 2, little_endian);
00212 char *name = fgetstrz(file);
00213 func = new ht_pe_import_function(dll_index, fthunk_rva, name, hint);
00214 free(name);
00215 }
00216 } else {
00217 thunk64 = *(thunk_table64+i);
00218
00219
00220 if (QWORD_GET_LO(thunk64.ordinal) & 0x80000000) {
00221
00222 func = new ht_pe_import_function(dll_index, fthunk_rva, QWORD_GET_LO(thunk64.ordinal)&0xffff);
00223 } else {
00224
00225 FILEOFS function_desc_ofs;
00226 word hint = 0;
00227 if (!pe_rva_to_ofs(&pe_shared->sections, QWORD_GET_LO(thunk64.function_desc_address), &function_desc_ofs)) goto pe_read_error;
00228 file->seek(function_desc_ofs);
00229 file->read(&hint, 2);
00230 hint = create_host_int(&hint, 2, little_endian);
00231 char *name = fgetstrz(file);
00232 func = new ht_pe_import_function(dll_index, fthunk_rva, name, hint);
00233 free(name);
00234 }
00235 }
00236 pe_shared->imports.funcs->insert(func);
00237
00238 if (pe32) {
00239 thunk_ofs+=4;
00240 thunk_rva+=4;
00241 fthunk_ofs+=4;
00242 fthunk_rva+=4;
00243 } else {
00244 thunk_ofs+=8;
00245 thunk_rva+=8;
00246 fthunk_ofs+=8;
00247 fthunk_rva+=8;
00248 }
00249 }
00250
00251 dll_index++;
00252
00253 if (pe32) {
00254 free(thunk_table);
00255 } else {
00256 free(thunk_table64);
00257 }
00258
00259 free(dllname);
00260 }
00261
00262 stop_timer(h0);
00263
00264 delete_timer(h0);
00265
00266 ht_snprintf(iline, sizeof iline, "* PE import directory at offset %08x (%d functions from %d libraries)", iofs, function_count, dll_count);
00267 head=new ht_statictext();
00268 head->init(&c, iline, align_left);
00269
00270 g->insert(head);
00271 g->insert(v);
00272
00273 for (UINT i=0; i<pe_shared->imports.funcs->count(); i++) {
00274 ht_pe_import_function *func = (ht_pe_import_function*)pe_shared->imports.funcs->get(i);
00275 assert(func);
00276 ht_pe_import_library *lib = (ht_pe_import_library*)pe_shared->imports.libs->get(func->libidx);
00277 assert(lib);
00278 char addr[32], name[256];
00279 ht_snprintf(addr, sizeof addr, "%08x", func->address);
00280 if (func->byname) {
00281 ht_snprintf(name, sizeof name, "%s", func->name.name);
00282 } else {
00283 ht_snprintf(name, sizeof name, "%04x (by ordinal)", func->ordinal);
00284 }
00285 v->insert_str(i, lib->name, addr, name);
00286 }
00287
00288 v->update();
00289
00290 g->setpalette(palkey_generic_window_default);
00291
00292 pe_shared->v_imports=v;
00293 return g;
00294 pe_read_error:
00295 delete_timer(h0);
00296 errorbox("%s: PE import section seems to be corrupted.", file->get_filename());
00297 g->done();
00298 delete g;
00299 v->done();
00300 delete v;
00301 return NULL;
00302 }
00303
00304 format_viewer_if htpeimports_if = {
00305 htpeimports_init,
00306 NULL
00307 };
00308
00309
00310
00311
00312
00313 ht_pe_import_library::ht_pe_import_library(char *n)
00314 {
00315 name = ht_strdup(n);
00316 }
00317
00318 ht_pe_import_library::~ht_pe_import_library()
00319 {
00320 if (name) free(name);
00321 }
00322
00323
00324
00325
00326
00327 ht_pe_import_function::ht_pe_import_function(UINT li, RVA a, UINT o)
00328 {
00329 libidx = li;
00330 ordinal = o;
00331 address = a;
00332 byname = false;
00333 }
00334
00335 ht_pe_import_function::ht_pe_import_function(UINT li, RVA a, char *n, UINT h)
00336 {
00337 libidx= li;
00338 name.name = ht_strdup(n);
00339 name.hint = h;
00340 address = a;
00341 byname = true;
00342 }
00343
00344 ht_pe_import_function::~ht_pe_import_function()
00345 {
00346 if ((byname) && (name.name)) free(name.name);
00347 }
00348
00349
00350
00351
00352
00353 void ht_pe_import_viewer::init(bounds *b, char *Desc, ht_format_group *fg)
00354 {
00355 ht_text_listbox::init(b, 3, 2, LISTBOX_QUICKFIND);
00356 options |= VO_BROWSABLE;
00357 desc = strdup(Desc);
00358 format_group = fg;
00359 grouplib = false;
00360 sortby = 1;
00361 dosort();
00362 }
00363
00364 void ht_pe_import_viewer::done()
00365 {
00366 ht_text_listbox::done();
00367 }
00368
00369 void ht_pe_import_viewer::dosort()
00370 {
00371 ht_text_listbox_sort_order sortord[2];
00372 UINT l, s;
00373 if (grouplib) {
00374 l = 0;
00375 s = 1;
00376 } else {
00377 l = 1;
00378 s = 0;
00379 }
00380 sortord[l].col = 0;
00381 sortord[l].compare_func = strcmp;
00382 sortord[s].col = sortby;
00383 sortord[s].compare_func = strcmp;
00384 sort(2, sortord);
00385 }
00386
00387 char *ht_pe_import_viewer::func(UINT i, bool execute)
00388 {
00389 switch (i) {
00390 case 2:
00391 if (execute) {
00392 grouplib = !grouplib;
00393 dosort();
00394 }
00395 return grouplib ? (char*)"nbylib" : (char*)"bylib";
00396 case 4:
00397 if (execute) {
00398 if (sortby != 1) {
00399 sortby = 1;
00400 dosort();
00401 }
00402 }
00403 return "byaddr";
00404 case 5:
00405 if (execute) {
00406 if (sortby != 2) {
00407 sortby = 2;
00408 dosort();
00409 }
00410 }
00411 return "byname";
00412 }
00413 return NULL;
00414 }
00415
00416 void ht_pe_import_viewer::handlemsg(htmsg *msg)
00417 {
00418 switch (msg->msg) {
00419 case msg_funcexec:
00420 if (func(msg->data1.integer, 1)) {
00421 clearmsg(msg);
00422 return;
00423 }
00424 break;
00425 case msg_funcquery: {
00426 char *s=func(msg->data1.integer, 0);
00427 if (s) {
00428 msg->msg=msg_retval;
00429 msg->data1.str=s;
00430 }
00431 break;
00432 }
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442 case msg_keypressed: {
00443 if (msg->data1.integer == K_Return) {
00444 select_entry(e_cursor);
00445 clearmsg(msg);
00446 }
00447 break;
00448 }
00449 }
00450 ht_text_listbox::handlemsg(msg);
00451 }
00452
00453 bool ht_pe_import_viewer::select_entry(void *entry)
00454 {
00455 ht_text_listbox_item *i = (ht_text_listbox_item *)entry;
00456
00457 ht_pe_shared_data *pe_shared=(ht_pe_shared_data *)format_group->get_shared_data();
00458
00459 ht_pe_import_function *e = (ht_pe_import_function*)pe_shared->imports.funcs->get(i->id);
00460 if (!e) return true;
00461 if (pe_shared->v_image) {
00462 ht_aviewer *av = (ht_aviewer*)pe_shared->v_image;
00463 PEAnalyser *a = (PEAnalyser*)av->analy;
00464 Address *addr;
00465 if (pe_shared->opt_magic == COFF_OPTMAGIC_PE32) {
00466 addr = a->createAddress32(e->address+pe_shared->pe32.header_nt.image_base);
00467 } else {
00468 addr = a->createAddress64(to_qword(e->address)+pe_shared->pe64.header_nt.image_base);
00469 }
00470 if (av->gotoAddress(addr, NULL)) {
00471 app->focus(av);
00472 vstate_save();
00473 } else {
00474 global_analyser_address_string_format = ADDRESS_STRING_FORMAT_COMPACT | ADDRESS_STRING_FORMAT_ADD_0X;
00475 errorbox("can't follow: %s %y is not valid !", "import address", addr);
00476 }
00477 delete addr;
00478 } else errorbox("can't follow: no image viewer");
00479 return true;
00480 }
00481
00482