00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <stdio.h>
00022 #include <stdlib.h>
00023 #include <string.h>
00024
00025 #include "analy.h"
00026 #include "analy_alpha.h"
00027 #include "analy_ia64.h"
00028 #include "analy_il.h"
00029 #include "analy_names.h"
00030 #include "analy_register.h"
00031 #include "analy_ppc.h"
00032 #include "analy_x86.h"
00033 #include "global.h"
00034 #include "htctrl.h"
00035 #include "htdebug.h"
00036 #include "htiobox.h"
00037 #include "htpe.h"
00038 #include "htstring.h"
00039 #include "ilopc.h"
00040 #include "pe_analy.h"
00041 #include "pestruct.h"
00042 #include "snprintf.h"
00043 #include "x86asm.h"
00044
00045
00046
00047
00048 void PEAnalyser::init(ht_pe_shared_data *Pe_shared, ht_streamfile *File)
00049 {
00050 pe_shared = Pe_shared;
00051 file = File;
00052
00053 validarea = new Area();
00054 validarea->init();
00055
00056 Analyser::init();
00057 }
00058
00059
00060
00061
00062
00063 int PEAnalyser::load(ht_object_stream *f)
00064 {
00065
00066
00067
00068
00069
00070 GET_OBJECT(f, validarea);
00071 return Analyser::load(f);
00072 }
00073
00074
00075
00076
00077 void PEAnalyser::done()
00078 {
00079 validarea->done();
00080 delete validarea;
00081 Analyser::done();
00082 }
00083
00084
00085
00086
00087 void PEAnalyser::beginAnalysis()
00088 {
00089 char buffer[1024];
00090
00091 setLocationTreeOptimizeThreshold(100);
00092 setSymbolTreeOptimizeThreshold(100);
00093
00094 bool pe32 = (pe_shared->opt_magic == COFF_OPTMAGIC_PE32);
00095
00096
00097
00098
00099 Address *entry;
00100 if (pe32) {
00101 entry = createAddress32(pe_shared->pe32.header.entrypoint_address+pe_shared->pe32.header_nt.image_base);
00102 } else {
00103 entry = createAddress64(to_qword(pe_shared->pe64.header.entrypoint_address)+pe_shared->pe64.header_nt.image_base);
00104 }
00105 pushAddress(entry, entry);
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123 COFF_SECTION_HEADER *s=pe_shared->sections.sections;
00124 char blub[100];
00125 for (UINT i=0; i<pe_shared->sections.section_count; i++) {
00126 Address *secaddr;
00127 if (pe32) {
00128 secaddr = createAddress32(s->data_address+pe_shared->pe32.header_nt.image_base);
00129 } else {
00130 secaddr = createAddress64(to_qword(s->data_address)+pe_shared->pe64.header_nt.image_base);
00131 }
00132 ht_snprintf(blub, sizeof blub, "; section %d <%s>", i+1, getSegmentNameByAddress(secaddr));
00133 addComment(secaddr, 0, "");
00134 addComment(secaddr, 0, ";******************************************************************");
00135 addComment(secaddr, 0, blub);
00136 ht_snprintf(blub, sizeof blub, "; virtual address %08x virtual size %08x", s->data_address, s->data_vsize);
00137 addComment(secaddr, 0, blub);
00138 ht_snprintf(blub, sizeof blub, "; file offset %08x file size %08x", s->data_offset, s->data_size);
00139 addComment(secaddr, 0, blub);
00140 addComment(secaddr, 0, ";******************************************************************");
00141
00142
00143 ht_snprintf(blub, sizeof blub, "; end of section <%s>", getSegmentNameByAddress(secaddr));
00144 Address *secend_addr = (Address *)secaddr->duplicate();
00145 secend_addr->add(MAX(s->data_size, s->data_vsize));
00146 newLocation(secend_addr)->flags |= AF_FUNCTION_END;
00147 addComment(secend_addr, 0, "");
00148 addComment(secend_addr, 0, ";******************************************************************");
00149 addComment(secend_addr, 0, blub);
00150 addComment(secend_addr, 0, ";******************************************************************");
00151
00152 validarea->add(secaddr, secend_addr);
00153 Address *seciniaddr = (Address *)secaddr->duplicate();
00154 seciniaddr->add(MIN(s->data_size, s->data_vsize));
00155 if (validAddress(secaddr, scinitialized) && validAddress(seciniaddr, scinitialized)) {
00156 initialized->add(secaddr, seciniaddr);
00157 }
00158 s++;
00159 delete secaddr;
00160 delete secend_addr;
00161 delete seciniaddr;
00162 }
00163
00164
00165
00166 int export_count=pe_shared->exports.funcs->count();
00167 int *entropy = random_permutation(export_count);
00168 for (int i=0; i<export_count; i++) {
00169 ht_pe_export_function *f=(ht_pe_export_function *)pe_shared->exports.funcs->get(*(entropy+i));
00170 Address *faddr;
00171 if (pe32) {
00172 faddr = createAddress32(f->address+pe_shared->pe32.header_nt.image_base);
00173 } else {
00174 faddr = createAddress64(to_qword(f->address)+pe_shared->pe64.header_nt.image_base);
00175 }
00176 if (validAddress(faddr, scvalid)) {
00177 char *label;
00178 if (f->byname) {
00179 ht_snprintf(buffer, sizeof buffer, "; exported function %s, ordinal %04x", f->name, f->ordinal);
00180 } else {
00181 ht_snprintf(buffer, sizeof buffer, "; unnamed exported function, ordinal %04x", f->ordinal);
00182 }
00183 label = export_func_name((f->byname) ? f->name : NULL, f->ordinal);
00184 addComment(faddr, 0, "");
00185 addComment(faddr, 0, ";********************************************************");
00186 addComment(faddr, 0, buffer);
00187 addComment(faddr, 0, ";********************************************************");
00188 pushAddress(faddr, faddr);
00189 assignSymbol(faddr, label, label_func);
00190 free(label);
00191 }
00192 delete faddr;
00193 }
00194 if (entropy) free(entropy);
00195
00196 int import_count=pe_shared->imports.funcs->count();
00197 entropy = random_permutation(import_count);
00198 for (int i=0; i<import_count; i++) {
00199 ht_pe_import_function *f=(ht_pe_import_function *)pe_shared->imports.funcs->get(*(entropy+i));
00200 ht_pe_import_library *d=(ht_pe_import_library *)pe_shared->imports.libs->get(f->libidx);
00201 char *label;
00202 label = import_func_name(d->name, (f->byname) ? f->name.name : NULL, f->ordinal);
00203 Address *faddr;
00204 if (pe32) {
00205 faddr = createAddress32(f->address+pe_shared->pe32.header_nt.image_base);
00206 } else {
00207 faddr = createAddress64(to_qword(f->address)+pe_shared->pe64.header_nt.image_base);
00208 }
00209 addComment(faddr, 0, "");
00210 if (!assignSymbol(faddr, label, label_func)) {
00211
00212
00213 addComment(faddr, 0, "; duplicate import");
00214 ht_snprintf(buffer, sizeof buffer, "%s_%x", label, f->address);
00215 assignSymbol(faddr, buffer, label_func);
00216 }
00217 if (pe32) {
00218 data->setIntAddressType(faddr, dst_idword, 4);
00219 } else {
00220 data->setIntAddressType(faddr, dst_iqword, 8);
00221 }
00222 free(label);
00223 delete faddr;
00224 }
00225 if (entropy) free(entropy);
00226
00227 int dimport_count=pe_shared->dimports.funcs->count();
00228 entropy = random_permutation(dimport_count);
00229 for (int i=0; i<dimport_count; i++) {
00230
00231 ht_pe_import_function *f=(ht_pe_import_function *)pe_shared->dimports.funcs->get(*(entropy+i));
00232 ht_pe_import_library *d=(ht_pe_import_library *)pe_shared->dimports.libs->get(f->libidx);
00233 if (f->byname) {
00234 ht_snprintf(buffer, sizeof buffer, "; delay import function loader for %s, ordinal %04x", f->name.name, f->ordinal);
00235 } else {
00236 ht_snprintf(buffer, sizeof buffer, "; delay import function loader for ordinal %04x", f->ordinal);
00237 }
00238 char *label;
00239 label = import_func_name(d->name, f->byname ? f->name.name : NULL, f->ordinal);
00240 Address *faddr;
00241 if (pe32) {
00242 faddr = createAddress32(f->address);
00243 } else {
00244 faddr = createAddress64(to_qword(f->address));
00245 }
00246 addComment(faddr, 0, "");
00247 addComment(faddr, 0, ";********************************************************");
00248 addComment(faddr, 0, buffer);
00249 addComment(faddr, 0, ";********************************************************");
00250 assignSymbol(faddr, label, label_func);
00251 free(label);
00252 delete faddr;
00253 }
00254 if (entropy) free(entropy);
00255
00256 addComment(entry, 0, "");
00257 addComment(entry, 0, ";****************************");
00258 if (pe_shared->coffheader.characteristics & COFF_DLL) {
00259 addComment(entry, 0, "; dll entry point");
00260 } else {
00261 addComment(entry, 0, "; program entry point");
00262 }
00263 addComment(entry, 0, ";****************************");
00264 assignSymbol(entry, "entrypoint", label_func);
00265
00266 setLocationTreeOptimizeThreshold(1000);
00267 setSymbolTreeOptimizeThreshold(1000);
00268 delete entry;
00269
00270 Analyser::beginAnalysis();
00271 }
00272
00273
00274
00275
00276 OBJECT_ID PEAnalyser::object_id() const
00277 {
00278 return ATOM_PE_ANALYSER;
00279 }
00280
00281
00282
00283
00284 UINT PEAnalyser::bufPtr(Address *Addr, byte *buf, int size)
00285 {
00286 FILEOFS ofs = addressToFileofs(Addr);
00287
00288
00289
00290 assert(ofs != INVALID_FILE_OFS);
00291 file->seek(ofs);
00292 return file->read(buf, size);
00293 }
00294
00295 bool PEAnalyser::convertAddressToRVA(Address *addr, RVA *r)
00296 {
00297 OBJECT_ID oid = addr->object_id();
00298 if (oid==ATOM_ADDRESS_FLAT_32) {
00299 *r = ((AddressFlat32*)addr)->addr - pe_shared->pe32.header_nt.image_base;
00300 return true;
00301 } else if (oid == ATOM_ADDRESS_X86_FLAT_32) {
00302 *r = ((AddressX86Flat32*)addr)->addr - pe_shared->pe32.header_nt.image_base;
00303 return true;
00304 } else if (oid == ATOM_ADDRESS_FLAT_64) {
00305 qword q = ((AddressFlat64*)addr)->addr - pe_shared->pe64.header_nt.image_base;
00306 if (QWORD_GET_HI(q)) return false;
00307 *r = QWORD_GET_LO(q);
00308 return true;
00309 }
00310 return false;
00311 }
00312
00313
00314
00315
00316 Address *PEAnalyser::createAddress32(dword addr)
00317 {
00318 switch (pe_shared->coffheader.machine) {
00319 case COFF_MACHINE_I386:
00320 case COFF_MACHINE_I486:
00321 case COFF_MACHINE_I586:
00322 return new AddressX86Flat32(addr);
00323 }
00324
00325 return new AddressFlat32(addr);
00326 }
00327
00328
00329
00330
00331 Address *PEAnalyser::createAddress64(qword addr)
00332 {
00333 return new AddressFlat64(addr);
00334 }
00335
00336 Address *PEAnalyser::createAddress()
00337 {
00338 switch (pe_shared->coffheader.machine) {
00339 case COFF_MACHINE_I386:
00340 case COFF_MACHINE_I486:
00341 case COFF_MACHINE_I586:
00342 if (pe_shared->opt_magic == COFF_OPTMAGIC_PE64) {
00343 return new AddressFlat64();
00344 } else {
00345 return new AddressX86Flat32();
00346 }
00347 }
00348 if (pe_shared->opt_magic == COFF_OPTMAGIC_PE64) {
00349 return new AddressFlat64();
00350 }
00351 return new AddressFlat32();
00352 }
00353
00354
00355
00356
00357 Assembler *PEAnalyser::createAssembler()
00358 {
00359 switch (pe_shared->coffheader.machine) {
00360 case COFF_MACHINE_I386:
00361 case COFF_MACHINE_I486:
00362 case COFF_MACHINE_I586:
00363 Assembler *a = new x86asm(X86_OPSIZE32, X86_ADDRSIZE32);
00364 a->init();
00365 return a;
00366 }
00367 return NULL;
00368 }
00369
00370
00371
00372
00373 FILEOFS PEAnalyser::addressToFileofs(Address *Addr)
00374 {
00375
00376
00377
00378 if (validAddress(Addr, scinitialized)) {
00379
00380 FILEOFS ofs;
00381 RVA r;
00382 if (!convertAddressToRVA(Addr, &r)) return INVALID_FILE_OFS;
00383 if (!pe_rva_to_ofs(&pe_shared->sections, r, &ofs)) return INVALID_FILE_OFS;
00384 return ofs;
00385 } else {
00386
00387 return INVALID_FILE_OFS;
00388 }
00389 }
00390
00391
00392
00393
00394 char *PEAnalyser::getSegmentNameByAddress(Address *Addr)
00395 {
00396 static char sectionname[9];
00397 pe_section_headers *sections=&pe_shared->sections;
00398 int i;
00399 RVA r;
00400
00401 if (!convertAddressToRVA(Addr, &r)) return NULL;
00402 pe_rva_to_section(sections, r, &i);
00403 COFF_SECTION_HEADER *s=sections->sections+i;
00404 if (!pe_rva_is_valid(sections, r)) return NULL;
00405 memmove(sectionname, s->name, 8);
00406 sectionname[8]=0;
00407 return sectionname;
00408 }
00409
00410
00411
00412
00413 const char *PEAnalyser::getName()
00414 {
00415 return file->get_desc();
00416 }
00417
00418
00419
00420
00421 const char *PEAnalyser::getType()
00422 {
00423 return "PE/Analyser";
00424 }
00425
00426
00427
00428
00429 void PEAnalyser::initCodeAnalyser()
00430 {
00431 Analyser::initCodeAnalyser();
00432 }
00433
00434 static char *string_func(dword ofs, void *context)
00435 {
00436 char str[1024];
00437 static char str2[1024];
00438 ht_pe_shared_data *pe = (ht_pe_shared_data*)context;
00439 if (ofs < pe->il->string_pool_size) {
00440 dword length;
00441 dword o = ILunpackDword(length, (byte*)&pe->il->string_pool[ofs], 10);
00442 wide_char_to_multi_byte(str, (byte*)&pe->il->string_pool[ofs+o], length/2+1);
00443 escape_special_str(str2, sizeof str2, str, "\"");
00444 return str2;
00445 } else {
00446 return NULL;
00447 }
00448 }
00449
00450 static char *token_func(dword token, void *context)
00451 {
00452 static char tokenstr[1024];
00453
00454 switch (token & IL_META_TOKEN_MASK) {
00455 case IL_META_TOKEN_TYPE_REF:
00456 case IL_META_TOKEN_TYPE_DEF: {
00457 sprintf(tokenstr, "typedef");
00458 break;
00459 }
00460 case IL_META_TOKEN_FIELD_DEF: {
00461 sprintf(tokenstr, "fielddef");
00462 break;
00463 }
00464 case IL_META_TOKEN_METHOD_DEF: {
00465 sprintf(tokenstr, "methoddef");
00466 break;
00467 }
00468 case IL_META_TOKEN_MEMBER_REF: {
00469 sprintf(tokenstr, "memberref");
00470 break;
00471 }
00472 case IL_META_TOKEN_TYPE_SPEC: {
00473 sprintf(tokenstr, "typespec");
00474 break;
00475 }
00476 default:
00477 return NULL;
00478 }
00479 return tokenstr;
00480 }
00481
00482
00483
00484
00485 void PEAnalyser::initUnasm()
00486 {
00487 bool pe64 = false;
00488 if (pe_shared->opt_magic == COFF_OPTMAGIC_PE64) {
00489 pe64 = true;
00490 }
00491 DPRINTF("pe_analy: ");
00492 if (pe_shared->il) {
00493 analy_disasm = new AnalyILDisassembler();
00494 ((AnalyILDisassembler *)analy_disasm)->init(this, string_func, token_func, pe_shared);
00495 } else {
00496 switch (pe_shared->coffheader.machine) {
00497 case COFF_MACHINE_I386:
00498 case COFF_MACHINE_I486:
00499 case COFF_MACHINE_I586:
00500 if (pe64) {
00501 errorbox("x86 cant be used in PE64 format.");
00502 } else {
00503 DPRINTF("initing analy_x86_disassembler\n");
00504 analy_disasm = new AnalyX86Disassembler();
00505 ((AnalyX86Disassembler *)analy_disasm)->init(this, 0);
00506 }
00507 break;
00508 case COFF_MACHINE_R3000:
00509 DPRINTF("no apropriate disassembler for MIPS\n");
00510 warnbox("No disassembler for MIPS!");
00511 break;
00512 case COFF_MACHINE_R4000:
00513 DPRINTF("no apropriate disassembler for MIPS\n");
00514 warnbox("No disassembler for MIPS!");
00515 break;
00516 case COFF_MACHINE_R10000:
00517 DPRINTF("no apropriate disassembler for MIPS\n");
00518 warnbox("No disassembler for MIPS!");
00519 break;
00520 case COFF_MACHINE_ALPHA:
00521 DPRINTF("initing alpha_axp_disassembler\n");
00522 analy_disasm = new AnalyAlphaDisassembler();
00523 ((AnalyAlphaDisassembler *)analy_disasm)->init(this);
00524 break;
00525 case COFF_MACHINE_POWERPC_LE:
00526 DPRINTF("no apropriate disassembler for POWER PC\n");
00527 warnbox("No disassembler for POWER PC!");
00528 break;
00529 case COFF_MACHINE_POWERPC_BE:
00530 analy_disasm = new AnalyPPCDisassembler();
00531 ((AnalyPPCDisassembler*)analy_disasm)->init(this);
00532 break;
00533 case COFF_MACHINE_IA64:
00534 if (!pe64) {
00535 errorbox("Intel IA64 cant be used in PE32 format.");
00536 } else {
00537 analy_disasm = new AnalyIA64Disassembler();
00538 ((AnalyIA64Disassembler*)analy_disasm)->init(this);
00539 }
00540 break;
00541 case COFF_MACHINE_UNKNOWN:
00542 default:
00543 DPRINTF("no apropriate disassembler for machine %04x\n", pe_shared->coffheader.machine);
00544 warnbox("No disassembler for unknown machine type %04x!", pe_shared->coffheader.machine);
00545 }
00546 }
00547 }
00548
00549
00550
00551
00552 void PEAnalyser::log(const char *msg)
00553 {
00554
00555
00556
00557
00558
00559
00560 }
00561
00562
00563
00564
00565 Address *PEAnalyser::nextValid(Address *Addr)
00566 {
00567 return (Address *)validarea->findNext(Addr);
00568 }
00569
00570
00571
00572
00573 void PEAnalyser::store(ht_object_stream *st)
00574 {
00575
00576
00577
00578
00579
00580 PUT_OBJECT(st, validarea);
00581 Analyser::store(st);
00582 }
00583
00584
00585
00586
00587 int PEAnalyser::queryConfig(int mode)
00588 {
00589 switch (mode) {
00590 case Q_DO_ANALYSIS:
00591 case Q_ENGAGE_CODE_ANALYSER:
00592 case Q_ENGAGE_DATA_ANALYSER:
00593 return true;
00594 default:
00595 return 0;
00596 }
00597 }
00598
00599
00600
00601
00602 Address *PEAnalyser::fileofsToAddress(FILEOFS fileofs)
00603 {
00604 RVA r;
00605 if (pe_ofs_to_rva(&pe_shared->sections, fileofs, &r)) {
00606 if (pe_shared->opt_magic == COFF_OPTMAGIC_PE32) {
00607 return createAddress32(r+pe_shared->pe32.header_nt.image_base);
00608 } else {
00609 return createAddress64(to_qword(r)+pe_shared->pe64.header_nt.image_base);
00610 }
00611 } else {
00612 return new InvalidAddress();
00613 }
00614 }
00615
00616
00617
00618
00619 bool PEAnalyser::validAddress(Address *Addr, tsectype action)
00620 {
00621 pe_section_headers *sections=&pe_shared->sections;
00622 int sec;
00623 RVA r;
00624 if (!convertAddressToRVA(Addr, &r)) return false;
00625 if (!pe_rva_to_section(sections, r, &sec)) return false;
00626 COFF_SECTION_HEADER *s=sections->sections+sec;
00627 switch (action) {
00628 case scvalid:
00629 return true;
00630 case scread:
00631 return s->characteristics & COFF_SCN_MEM_READ;
00632 case scwrite:
00633 return s->characteristics & COFF_SCN_MEM_WRITE;
00634 case screadwrite:
00635 return s->characteristics & COFF_SCN_MEM_WRITE;
00636 case sccode:
00637
00638 if (!pe_rva_is_physical(sections, r)) return false;
00639 return (s->characteristics & (COFF_SCN_MEM_EXECUTE | COFF_SCN_CNT_CODE));
00640 case scinitialized:
00641 if (!pe_rva_is_physical(sections, r)) return false;
00642 return true;
00643
00644 }
00645 return false;
00646 }
00647
00648