00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "analy.h"
00022 #include "analy_names.h"
00023 #include "analy_ppc.h"
00024 #include "analy_register.h"
00025 #include "analy_x86.h"
00026 #include "global.h"
00027 #include "macho_analy.h"
00028
00029 #include "htctrl.h"
00030 #include "htdebug.h"
00031 #include "htiobox.h"
00032 #include "htmacho.h"
00033 #include "htstring.h"
00034 #include "pestruct.h"
00035 #include "snprintf.h"
00036
00037
00038 extern "C" {
00039 #include "demangle.h"
00040 }
00041
00042 #include <stdio.h>
00043 #include <stdlib.h>
00044 #include <string.h>
00045
00046
00047
00048
00049
00050 void MachoAnalyser::init(ht_macho_shared_data *Macho_shared, ht_streamfile *File)
00051 {
00052 macho_shared = Macho_shared;
00053 file = File;
00054
00055 validarea = new Area();
00056 validarea->init();
00057
00058 Analyser::init();
00059 }
00060
00061 void MachoAnalyser::beginAnalysis()
00062 {
00063 setLocationTreeOptimizeThreshold(100);
00064 setSymbolTreeOptimizeThreshold(100);
00065
00066 MACHO_COMMAND_U **pp;
00067
00068
00069
00070 UINT entrypoint_count = 0;
00071 pp = macho_shared->cmds.cmds;
00072 for (UINT i=0; i < macho_shared->cmds.count; i++) {
00073 if (((*pp)->cmd.cmd == LC_UNIXTHREAD) || ((*pp)->cmd.cmd == LC_THREAD)) {
00074 MACHO_THREAD_COMMAND *s = (MACHO_THREAD_COMMAND*)*pp;
00075 Address *entry;
00076 switch (macho_shared->header.cputype) {
00077 case MACHO_CPU_TYPE_POWERPC:
00078 entry = createAddress32(s->state.state_ppc.srr0);
00079 break;
00080 case MACHO_CPU_TYPE_I386:
00081 entry = createAddress32(s->state.state_i386.eip);
00082 break;
00083 default: assert(0);
00084 }
00085 char desc[128];
00086 sprintf(desc, "entrypoint%d", entrypoint_count++);
00087 pushAddress(entry, entry);
00088 assignSymbol(entry, desc, label_func);
00089 addComment(entry, 0, "");
00090 addComment(entry, 0, ";****************************");
00091 addComment(entry, 0, "; thread entrypoint");
00092 addComment(entry, 0, ";****************************");
00093 delete entry;
00094 }
00095 pp++;
00096 }
00097
00098
00099
00100
00101
00102 char blub[100];
00103 pp = macho_shared->cmds.cmds;
00104 for (UINT i=0; i < macho_shared->cmds.count; i++) {
00105 if ((*pp)->cmd.cmd == LC_SEGMENT) {
00106 MACHO_SEGMENT_COMMAND *s = (MACHO_SEGMENT_COMMAND*)*pp;
00107
00108 Address *secaddr;
00109
00110 secaddr = createAddress32(s->vmaddr);
00111 if (validAddress(secaddr, scvalid)) {
00112 ht_snprintf(blub, sizeof blub, "; section %d <%s>", i+1, getSegmentNameByAddress(secaddr));
00113 addComment(secaddr, 0, "");
00114 addComment(secaddr, 0, ";******************************************************************");
00115 addComment(secaddr, 0, blub);
00116 ht_snprintf(blub, sizeof blub, "; virtual address %08x virtual size %08x", s->vmaddr, s->vmsize);
00117 addComment(secaddr, 0, blub);
00118 ht_snprintf(blub, sizeof blub, "; file offset %08x file size %08x", s->fileoff, s->filesize);
00119 addComment(secaddr, 0, blub);
00120 addComment(secaddr, 0, ";******************************************************************");
00121
00122
00123 ht_snprintf(blub, sizeof blub, "; end of section <%s>", getSegmentNameByAddress(secaddr));
00124 Address *secend_addr = (Address *)secaddr->duplicate();
00125
00126 secend_addr->add(s->vmsize);
00127 newLocation(secend_addr)->flags |= AF_FUNCTION_END;
00128 addComment(secend_addr, 0, "");
00129 addComment(secend_addr, 0, ";******************************************************************");
00130 addComment(secend_addr, 0, blub);
00131 addComment(secend_addr, 0, ";******************************************************************");
00132
00133 validarea->add(secaddr, secend_addr);
00134
00135 delete secend_addr;
00136 }
00137 delete secaddr;
00138 }
00139 pp++;
00140 }
00141
00142
00143
00144 pp = macho_shared->cmds.cmds;
00145 for (UINT i=0; i < macho_shared->cmds.count; i++) {
00146 if ((*pp)->cmd.cmd == LC_SYMTAB) {
00147 MACHO_SYMTAB_COMMAND *s = (MACHO_SYMTAB_COMMAND*)*pp;
00148 int *entropy = random_permutation(s->nsyms);
00149 for (UINT j=0; j<s->nsyms; j++) {
00150 file->seek(s->symoff+entropy[j]*sizeof (MACHO_SYMTAB_NLIST));
00151 MACHO_SYMTAB_NLIST nlist;
00152 if (file->read(&nlist, sizeof nlist) != sizeof nlist) break;
00153 create_host_struct(&nlist, MACHO_SYMTAB_NLIST_struct, macho_shared->image_endianess);
00154 if (nlist.strx && (nlist.type & MACHO_SYMBOL_N_TYPE == MACHO_SYMBOL_TYPE_N_SECT)) {
00155 char macho_buffer[1024];
00156 file->seek(s->stroff+nlist.strx);
00157 char *label = fgetstrz(file);
00158
00159 Address *address = createAddress32(nlist.value);
00160 if (validAddress(address, scvalid)) {
00161 char *demangled = NULL;
00162 make_valid_name(label, label);
00163 ht_snprintf(macho_buffer, sizeof macho_buffer, "; function %s", (demangled) ? demangled : label);
00164 if (demangled) free(demangled);
00165 addComment(address, 0, "");
00166 addComment(address, 0, ";********************************************************");
00167 addComment(address, 0, macho_buffer);
00168 addComment(address, 0, ";********************************************************");
00169 pushAddress(address, address);
00170 assignSymbol(address, label, label_func);
00171 } else {
00172
00173 }
00174 delete address;
00175 free(label);
00176 }
00177 }
00178 free(entropy);
00179 }
00180 pp++;
00181 }
00182 setLocationTreeOptimizeThreshold(1000);
00183 setSymbolTreeOptimizeThreshold(1000);
00184
00185 Analyser::beginAnalysis();
00186 }
00187
00188
00189
00190
00191 void MachoAnalyser::initInsertSymbols(int shidx)
00192 {
00193 }
00194
00195
00196
00197
00198 int MachoAnalyser::load(ht_object_stream *f)
00199 {
00200 GET_OBJECT(f, validarea);
00201 return Analyser::load(f);
00202 }
00203
00204
00205
00206
00207 void MachoAnalyser::done()
00208 {
00209 validarea->done();
00210 delete validarea;
00211 Analyser::done();
00212 }
00213
00214 OBJECT_ID MachoAnalyser::object_id() const
00215 {
00216 return ATOM_MACHO_ANALYSER;
00217 }
00218
00219
00220
00221
00222 UINT MachoAnalyser::bufPtr(Address *Addr, byte *buf, int size)
00223 {
00224 FILEOFS ofs = addressToFileofs(Addr);
00225
00226
00227
00228 assert(ofs != INVALID_FILE_OFS);
00229 file->seek(ofs);
00230 return file->read(buf, size);;
00231 }
00232
00233 bool MachoAnalyser::convertAddressToMACHOAddress(Address *addr, MACHOAddress *r)
00234 {
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245 if (addr->object_id() == ATOM_ADDRESS_FLAT_32) {
00246 *r = ((AddressFlat32*)addr)->addr;
00247 return true;
00248 } else if (addr->object_id() == ATOM_ADDRESS_X86_FLAT_32) {
00249 *r = ((AddressX86Flat32*)addr)->addr;
00250 return true;
00251 }
00252 return false;
00253 }
00254
00255 Address *MachoAnalyser::createAddress()
00256 {
00257 switch (macho_shared->header.cputype) {
00258 case MACHO_CPU_TYPE_I386: {
00259 return new AddressX86Flat32();
00260 }
00261 case MACHO_CPU_TYPE_POWERPC: {
00262 return new AddressFlat32();
00263 }
00264 }
00265 assert(0);
00266 return NULL;
00267 }
00268
00269 Address *MachoAnalyser::createAddress32(dword addr)
00270 {
00271 switch (macho_shared->header.cputype) {
00272 case MACHO_CPU_TYPE_I386: {
00273 return new AddressX86Flat32(addr);
00274 }
00275 case MACHO_CPU_TYPE_POWERPC: {
00276 return new AddressFlat32(addr);
00277 }
00278 }
00279 assert(0);
00280 return NULL;
00281 }
00282
00283
00284
00285
00286 Assembler *MachoAnalyser::createAssembler()
00287 {
00288
00289
00290
00291
00292
00293
00294 return NULL;
00295 }
00296
00297
00298
00299
00300 FILEOFS MachoAnalyser::addressToFileofs(Address *Addr)
00301 {
00302 if (validAddress(Addr, scinitialized)) {
00303 uint32 ofs;
00304 MACHOAddress ea;
00305 if (!convertAddressToMACHOAddress(Addr, &ea)) return INVALID_FILE_OFS;
00306 if (!macho_addr_to_ofs(&macho_shared->sections, 0, ea, &ofs)) return INVALID_FILE_OFS;
00307 return ofs;
00308 } else {
00309 return INVALID_FILE_OFS;
00310 }
00311 }
00312
00313
00314
00315
00316 char *MachoAnalyser::getSegmentNameByAddress(Address *Addr)
00317 {
00318 static char macho_sectionname[33];
00319 macho_sections *sections = &macho_shared->sections;
00320 int i;
00321 MACHOAddress ea;
00322 if (!convertAddressToMACHOAddress(Addr, &ea)) return NULL;
00323 if (!macho_addr_to_section(sections, 0, ea, &i)) return NULL;
00324 strncpy(macho_sectionname, (char*)sections->sections[i].sectname, 16);
00325 macho_sectionname[16] = 0;
00326 return macho_sectionname;
00327 }
00328
00329
00330
00331
00332 const char *MachoAnalyser::getName()
00333 {
00334 return file->get_desc();
00335 }
00336
00337
00338
00339
00340 const char *MachoAnalyser::getType()
00341 {
00342 return "Mach-O/Analyser";
00343 }
00344
00345
00346
00347
00348 void MachoAnalyser::initCodeAnalyser()
00349 {
00350 Analyser::initCodeAnalyser();
00351 }
00352
00353
00354
00355
00356 void MachoAnalyser::initUnasm()
00357 {
00358 DPRINTF("macho_analy: ");
00359 UINT machine = macho_shared->header.cputype;
00360 bool macho64 = false;
00361 switch (machine) {
00362 case MACHO_CPU_TYPE_I386:
00363 DPRINTF("initing analy_x86_disassembler\n");
00364 analy_disasm = new AnalyX86Disassembler();
00365 ((AnalyX86Disassembler*)analy_disasm)->init(this, macho64 ? ANALYX86DISASSEMBLER_FLAGS_FLAT64 : 0);
00366 break;
00367 case MACHO_CPU_TYPE_POWERPC:
00368 DPRINTF("initing analy_ppc_disassembler\n");
00369 analy_disasm = new AnalyPPCDisassembler();
00370 ((AnalyPPCDisassembler*)analy_disasm)->init(this);
00371 break;
00372 default:
00373 DPRINTF("no apropriate disassembler for machine %04x\n", machine);
00374 warnbox("No disassembler for unknown machine type %04x!", machine);
00375 }
00376 }
00377
00378
00379
00380
00381 void MachoAnalyser::log(const char *msg)
00382 {
00383
00384
00385
00386
00387
00388
00389 }
00390
00391
00392
00393
00394 Address *MachoAnalyser::nextValid(Address *Addr)
00395 {
00396 return (Address *)validarea->findNext(Addr);
00397 }
00398
00399
00400
00401
00402 void MachoAnalyser::store(ht_object_stream *f)
00403 {
00404 PUT_OBJECT(f, validarea);
00405 Analyser::store(f);
00406 }
00407
00408
00409
00410
00411 int MachoAnalyser::queryConfig(int mode)
00412 {
00413 switch (mode) {
00414 case Q_DO_ANALYSIS:
00415 case Q_ENGAGE_CODE_ANALYSER:
00416 case Q_ENGAGE_DATA_ANALYSER:
00417 return true;
00418 default:
00419 return 0;
00420 }
00421 }
00422
00423
00424
00425
00426 Address *MachoAnalyser::fileofsToAddress(FILEOFS fileofs)
00427 {
00428 MACHOAddress ea;
00429 if (macho_ofs_to_addr(&macho_shared->sections, 0, fileofs, &ea)) {
00430
00431
00432
00433
00434
00435 return createAddress32(ea);
00436 } else {
00437 return new InvalidAddress();
00438 }
00439 }
00440
00441
00442
00443
00444 bool MachoAnalyser::validAddress(Address *Addr, tsectype action)
00445 {
00446 macho_sections *sections = &macho_shared->sections;
00447 int sec;
00448 byte cls = 0;
00449 MACHOAddress ea;
00450 if (!convertAddressToMACHOAddress(Addr, &ea)) return false;
00451 if (!macho_addr_to_section(sections, cls, ea, &sec)) return false;
00452
00453
00454 MACHO_SECTION *s = §ions->sections[sec];
00455 switch (action) {
00456 case scvalid:
00457 return true;
00458 case scread:
00459 return true;
00460 case scwrite:
00461 case screadwrite: {
00462 bool writable =
00463 ((s->flags & MACHO_SECTION_TYPE) != MACHO_S_CSTRING_LITERALS) &&
00464 ((s->flags & MACHO_SECTION_TYPE) != MACHO_S_4BYTE_LITERALS) &&
00465 ((s->flags & MACHO_SECTION_TYPE) != MACHO_S_8BYTE_LITERALS)
00466 ;
00467 return writable;
00468 }
00469 case sccode:
00470 return ((s->flags & MACHO_SECTION_TYPE) == MACHO_S_REGULAR);
00471 case scinitialized:
00472 return ((s->flags & MACHO_SECTION_TYPE) != MACHO_S_ZEROFILL);
00473 }
00474 return false;
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494 return false;
00495 }
00496
00497