Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

htpeimp.cc

Go to the documentation of this file.
00001 /*
00002  *      HT Editor
00003  *      htpeimp.cc
00004  *
00005  *      Copyright (C) 1999-2002 Stefan Weyergraf (stefan@weyergraf.de)
00006  *
00007  *      This program is free software; you can redistribute it and/or modify
00008  *      it under the terms of the GNU General Public License version 2 as
00009  *      published by the Free Software Foundation.
00010  *
00011  *      This program is distributed in the hope that it will be useful,
00012  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *      GNU General Public License for more details.
00015  *
00016  *      You should have received a copy of the GNU General Public License
00017  *      along with this program; if not, write to the Free Software
00018  *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
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         /* get import directory offset */
00088         /* 1. get import directory rva */
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         /* 2. transform it into an offset */
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         /* make a memfile out of the whole file */
00104 
00105         /* doesn't work because import information is NOT contained into
00106            the import directory !!! only the import dir header. (I !love M$) */
00107 
00108         /*** read import directory ***/
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                 /* get name of dll */
00119                 FILEOFS iname_ofs;
00120                 if (!pe_rva_to_ofs(&pe_shared->sections, import.name, &iname_ofs)
00121                         || file->seek(iname_ofs)) {
00122                         /* ? try as ofs?*/
00123                         if (file->seek(import.name)) goto pe_read_error;
00124                 }
00125                 char *dllname = fgetstrz(file); /* dont forget to free it at the end of the scope !!! */
00126                 dll_count++;
00127 
00128                 /*** imported functions by name or by ordinal ***/
00129 
00130                 /*
00131                  *      First thunk (FT)
00132                  *      The first thunk table will be overwritten by the system/loader with
00133                  *      the function entry-points. So the program will treat this table
00134                  *      as if it contained just imported addresses.
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                  *      ...and Original First Thunk (OFT)
00141                  *      I saw executables that have the OFT ptr set to 0 and seem to
00142                  *      use the FT ptr instead, but also some that have both !=0 and use
00143                  *      the original one (bound executables).
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                         // FIXME: ?
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                         // FIXME: ?
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                         /* follow (original) first thunk */
00196                         if (pe32) {
00197                                 thunk = *(thunk_table+i);
00198 
00199                                 if (thunk.ordinal & 0x80000000) {
00200                                         /* by ordinal */
00201                                         func = new ht_pe_import_function(dll_index, fthunk_rva, thunk.ordinal&0xffff);
00202                                 } else {
00203                                         /* by name */
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                                 // FIXME: is this correct ?
00220                                 if (QWORD_GET_LO(thunk64.ordinal) & 0x80000000) {
00221                                         /* by ordinal */
00222                                         func = new ht_pe_import_function(dll_index, fthunk_rva, QWORD_GET_LO(thunk64.ordinal)&0xffff);
00223                                 } else {
00224                                         /* by name */
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 //      LOG("%s: PE: %d ticks (%d msec) to read imports", file->get_name(), get_timer_tick(h0), get_timer_msec(h0));
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  *      class ht_pe_import_library
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  *      class ht_pe_import_function
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  *      CLASS ht_pe_import_viewer
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 /*              case msg_get_scrollinfo:
00434                         switch (msg->data1.integer) {
00435                                 case gsi_pindicator: {
00436                                         strcpy((char*)msg->data2.ptr, " Enter to view, Backspace to return here");
00437                                         clearmsg(msg);
00438                                         return;
00439                                 }
00440                         }
00441                         break;*/
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 

Generated on Fri May 7 21:15:36 2004 by doxygen 1.3.5