static void sort_and_name_all(struct RP_class *root) { /* first name RuntimeClass struct */ misc_buffer1[0] = 'R'; misc_buffer1[1] = 'T'; misc_buffer1[2] = '_'; get_many_bytes(get_long(root->CRuntime), misc_buffer1 + 3, root->namelen); // 29 APR 2003 - rpd support if ( p_pool != NULL && root->vtbl ) fill_vtbl(misc_buffer1 + 3, root->vtbl); misc_buffer1[3 + root->namelen] = 0x0; set_name(root->CRuntime, misc_buffer1, SN_AUTO); /* next name vtbl if found */ if ( NULL != root->vtbl ) { misc_buffer1[0] = 'v'; misc_buffer1[1] = 't'; misc_buffer1[2] = 'b'; misc_buffer1[3] = 'l'; misc_buffer1[4] = '_'; get_many_bytes(get_long(root->CRuntime), misc_buffer1 + 5, root->namelen); misc_buffer1[5 + root->namelen] = 0x0; set_name(root->vtbl, misc_buffer1, SN_AUTO); } /* sort children by name */ if ( !root->total ) return; qsort(root->children, root->total, sizeof(struct RP_class *), rt_compare_names); /* and finally do it recirsive for all children */ int i; for ( i = 0; i < root->total; i++ ) sort_and_name_all(root->children[i]); }
//--------------------------------------------------------------------------- static bool extractData(uint32 off) { IMAGE_RESOURCE_DATA_ENTRY rd; if ( off + sizeof(rd) > ResTop ) return false; if ( !get_many_bytes(ResBase + off, &rd, sizeof(rd)) ) return false; if ( rd.OffsetToData >= ImgSize || rd.Size > ImgSize || rd.OffsetToData + rd.Size > ImgSize ) return false; void *data = qalloc(rd.Size); if ( data == NULL ) { msg("Not enough memory for resources\n"); return false; } bool res = false; if ( get_many_bytes(curmod.startEA + rd.OffsetToData, data, rd.Size) ) { store(data, rd.Size); res = true; } qfree(data); return res; }
static int __cdecl rt_compare_names(const void *a, const void *b) { struct RP_class *a_c = *(struct RP_class **)a; struct RP_class *b_c = *(struct RP_class **)b; get_many_bytes(get_long(a_c->CRuntime), misc_buffer1, a_c->namelen); get_many_bytes(get_long(b_c->CRuntime), misc_buffer2, b_c->namelen); misc_buffer1[a_c->namelen] = 0x0; misc_buffer2[b_c->namelen] = 0x0; return strcmp(misc_buffer1, misc_buffer2); }
bool find_parse_ip(ea_t ea, bool parsecode) { char id[16]; // Attempt to identify program start from ip get_many_bytes(ea, id, 16); if (memcmp(id, "SEGA SEGASATURN ", 16) != 0) return false; make_ascii_string(ea, 16, ASCSTR_C); make_ascii_string(ea+0x10, 16, ASCSTR_C); make_ascii_string(ea+0x20, 10, ASCSTR_C); make_ascii_string(ea+0x2A, 6, ASCSTR_C); make_ascii_string(ea+0x30, 8, ASCSTR_C); make_ascii_string(ea+0x38, 8, ASCSTR_C); make_ascii_string(ea+0x40, 10, ASCSTR_C); make_ascii_string(ea+0x4A, 6, ASCSTR_C); make_ascii_string(ea+0x50, 16, ASCSTR_C); make_ascii_string(ea+0x60, 0x70, ASCSTR_C); doByte(ea+0xD0, 16); doDwrd(ea+0xE0, 4); doDwrd(ea+0xE4, 4); doDwrd(ea+0xE8, 4); doDwrd(ea+0xEC, 4); doDwrd(ea+0xF0, 4); add_func(get_long(ea+0xF0), BADADDR); doDwrd(ea+0xF4, 4); doDwrd(ea+0xF8, 4); doDwrd(ea+0xFC, 4); if (parsecode) add_func(ea+0x100, BADADDR); return true; }
ByteSize IdaByteSource::readBytes(ByteAddr addr, void *buf, ByteSize size) const { #ifdef NC_USE_THREADS #error You are trying to shoot your leg. IDA API is not thread-safe. #endif if (get_many_bytes(checked_cast<ea_t>(addr), buf, checked_cast<ssize_t>(size))) { return size; } char *charBuf = static_cast<char *>(buf); ByteSize i; for (i = 0; i < size; i++) { ea_t idaAddr = checked_cast<ea_t>(addr + i); char value = get_byte(idaAddr); if (value == 0) { flags_t flags = getFlags(idaAddr); if (!hasValue(flags)) { break; } } *charBuf++ = value; } return i; }
//--------------------------------------------------------------------------- static bool extractDirectory(uint32 off, int level) { IMAGE_RESOURCE_DIRECTORY rd; if ( off + sizeof(rd) >= ResTop ) return false; if ( !get_many_bytes(ResBase + off, &rd, sizeof(rd)) ) return false; off += sizeof(rd); if ( rd.NumberOfNamedEntries != 0 ) { if ( level == 2 ) // language must be ONLY numbered return false; do { if ( !extractEntry(off, level, true) ) return false; off += sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY); } while ( --rd.NumberOfNamedEntries ); } if ( rd.NumberOfIdEntries != 0 ) { do { if ( !extractEntry(off, level, false) ) return false; off += sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY); } while ( --rd.NumberOfIdEntries ); } return true; }
HRESULT STDMETHODCALLTYPE ReadExecutableAtRVA( DWORD relativeVirtualAddress, DWORD cbData, DWORD* pcbData, BYTE data[] ) { #ifdef PDBTOTIL if ( mem_reader != NULL ) { uint32 read; bool ok = mem_reader(m_load_address + relativeVirtualAddress, cbData, data, &read); if ( !ok ) return E_FAIL; *pcbData = read; return S_OK; } #endif #ifndef BUILDING_EFD #ifndef PDBTOTIL if ( get_many_bytes(m_load_address + relativeVirtualAddress, data, cbData) ) { *pcbData = cbData; return S_OK; } #endif #else qnotused(relativeVirtualAddress); qnotused(cbData); qnotused(pcbData); qnotused(data); #endif return S_FALSE; }
static int __cdecl rt_find_by_name(const void *key, const void *elem) { const struct RP_class *cmp_with = *(const struct RP_class **)elem; get_many_bytes(get_long(cmp_with->CRuntime), misc_buffer1, cmp_with->namelen); misc_buffer1[cmp_with->namelen] = 0x0; return strcmp((const char *)key, misc_buffer1); }
//allocates memory and stores a copy of each //byte of the given area uchar *get_segment_data(ea_t s_a, ea_t e_a, ea_t size) { uchar *mem; mem = (uchar *)malloc(size+1); get_many_bytes(s_a,mem,size); return mem; }
static int is_gotbase_call(ea_t addr) { unsigned char buf[4]; get_many_bytes(addr, buf, 4); if ( buf[0] == 0x8B && buf[1] == 0x1C && buf[2] == 0x24 && buf[3] == 0xC3 ) return 1; return 0; }
//-------------------------------------------------------------------------- // find Windows 9x import thunk static bool resolve_thunk(ea_t ea) { push_jump_insns_t thunk; if ( !get_many_bytes(ea, &thunk, sizeof(thunk)) || thunk.push != 0x68 || thunk.jmp != 0xE9 || thunk.ea < 0x80000000 || thunk.ea >= 0xC0000000 ) { return false; } if ( !calc_thunk_target(uint32(ea), thunk.ea) ) msg("%a: Thunked import (%08X) without references\n", ea, thunk.ea); return true; }
void mark_name_from_static_RT(ea_t ea) { ea_t rt = check_for_cruntimeclass( get_long(ea) ); if ( !rt || rt == BADADDR ) return; size_t len = check_for_RTStruct(rt); if ( len ) { char *name = (char *)qalloc(len + 1); get_many_bytes(get_long(rt), name, len); name[len] = 0; set_vtbl_name(name, ea); qfree(name); } }
pdb_class *try_to_find_from_rt(ea_t ea, char **name, bool *free_name) { pdb_class *res = NULL; if ( !ea || ea == BADADDR ) return NULL; // check for ref to const parent CRunTime class from DLL ea_t rt = check_for_cruntimeclass2(ea); if ( rt ) { res = try_find_by_name(rt, name, free_name, false); if ( res ) return res; } // check for ref to base CRunTime class rt = check_for_cruntimeclass(ea); if ( rt ) { res = try_find_by_name(rt, name, free_name); if ( res ) return res; } size_t len; // check for name from static CRunTime class if ( !rt ) { len = check_for_RTStruct(ea); rt = ea; } else len = check_for_RTStruct(rt); if ( len ) { *name = (char *)qalloc(len + 1); get_many_bytes(get_long(rt), *name, len); (*name)[len] = 0; setter(*name, rt, 0, true); res = p_pool->find_class(*name); if ( res ) { *free_name = true; return res; } qfree(*name); // lets check all hierarchy res = try_to_find_from_rt(get_long(rt + 0x10), name, free_name); } return res; }
int sig_add_address(psig_t * sig, short opcodes[256], ea_t ea, bool b, bool line, char options) { unsigned char byte; unsigned char buf[200]; uint32 s, i; bool call; bool cj; ea_t tea; flags_t f; if (line) dline_add(&sig->dl, ea, options); if (is_jump(sig, ea, &call, &cj)) return -1; byte = get_byte_with_optimization(ea); if (remove_instr(byte, ea)) return -1; sig->lines++; opcodes[byte]++; if (!b && !call) { if (cj) { buf[0] = byte; s = 1; } else { s = (uint32)get_item_size(ea); if (s > sizeof(buf)) s = sizeof(buf); get_many_bytes(ea, buf, s); } for (i=0; i<s; i++) { sig->crc_hash += buf[i]; sig->crc_hash += ( sig->crc_hash << 10 ); sig->crc_hash ^= ( sig->crc_hash >> 6 ); } } else if (b)
void output_rt_tree(FILE *fp, struct RP_class *root, int margin) { if ( NULL == root ) return; rt_put_margin(margin,fp); get_many_bytes(get_long(root->CRuntime), misc_buffer1, root->namelen); misc_buffer1[root->namelen] = 0x0; if ( root->vtbl ) fprintf(fp, "%s: adr 0x%X, vtbl 0x%X\n", misc_buffer1, root->CRuntime, root->vtbl); else fprintf(fp, "%s: adr 0x%X\n", misc_buffer1, root->CRuntime ); int i; margin += 4; for ( i = 0; i < root->total; i++ ) output_rt_tree(fp, root->children[i], margin); }
/* * helper function to find GUIDs in data segment and label them */ void find_guids(ea_t start, ea_t end) { uint32_t table_size = sizeof(guid_table)/sizeof(*guid_table); ea_t current_addr = start; int match = 0; /* go over all the data segment searching for GUIDs */ while (current_addr < end) { /* match against table entries */ for (uint32_t i = 0; i < table_size; i++) { EFI_GUID tmp; get_many_bytes(current_addr, &tmp, sizeof(EFI_GUID)); if (tmp.Data1 == guid_table[i].guid.Data1 && tmp.Data2 == guid_table[i].guid.Data2 && tmp.Data3 == guid_table[i].guid.Data3 && memcmp(tmp.Data4, guid_table[i].guid.Data4, sizeof(tmp.Data4)) == 0) { set_name(current_addr, (const char*)guid_table[i].name, SN_CHECK); doDwrd(current_addr, 4); doDwrd(current_addr+4, 4); doDwrd(current_addr+8, 4); doDwrd(current_addr+12, 4); static char string[256] = {0}; qsnprintf(string, sizeof(string), "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", guid_table[i].guid.Data1, guid_table[i].guid.Data2, guid_table[i].guid.Data3, guid_table[i].guid.Data4[0], guid_table[i].guid.Data4[1], guid_table[i].guid.Data4[2], guid_table[i].guid.Data4[3], guid_table[i].guid.Data4[4], guid_table[i].guid.Data4[5], guid_table[i].guid.Data4[6], guid_table[i].guid.Data4[7]); set_cmt(current_addr, string, 0); match = 1; break; } } /* no need to check all 16 bytes if we found a match */ if (match) { current_addr += sizeof(EFI_GUID); match = 0; } else { current_addr++; } } }
/* tries to find CObject class */ ea_t find_root(ea_t start, bool silent) { char buffer[ROOT_LEN+1]; /* check what we get */ size_t len = check_for_RTStruct(start); if ( !len ) /* hm, lets try to find in -20..+20 range */ for ( ea_t cptr = start - 20; cptr < cptr + 24; cptr += sizeof(ea_t) ) { if ( start == cptr ) continue; if ( len = check_for_RTStruct(cptr) ) { start = cptr; break; } } if ( !len ) { if ( !silent ) warning("Passed address (0x%X) dont seems to be CRuntimeClass", start); return NULL; } while( NULL != start ) { if ( len == ROOT_LEN ) /* Hm, may be */ { if ( !get_many_bytes(get_long(start), buffer, ROOT_LEN) ) { if ( !silent ) warning("Cannot get %d bytes at 0x%X", len, get_long(start) ); return NULL; } if ( !strncmp(buffer, (const char *)root_name, ROOT_LEN) ) return start; } start = get_long(start+16); len = check_for_RTStruct(start); if ( !len ) break; } if ( !silent ) warning("Cannot find root"); return NULL; }
//--------------------------------------------------------------------------- static bool initPtrs(const char *fname) { IMAGE_DATA_DIRECTORY res; ea_t nth; nth = get_long(curmod.startEA + 0x3C) + curmod.startEA; size_t off = offsetof(IMAGE_NT_HEADERS, OptionalHeader.DataDirectory [IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress); if ( !get_many_bytes(nth + off, &res, sizeof(res)) || !res.VirtualAddress || !res.Size ) { msg("There are no resources in the module\n"); return false; } ResBase = curmod.startEA + res.VirtualAddress; ResTop = res.Size; ImgSize = curmod.endEA - curmod.startEA; int minres = 2*sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY)+3*sizeof(IMAGE_RESOURCE_DIRECTORY); if ( (res.Size & 3) != 0 || res.Size <= minres || res.VirtualAddress >= ImgSize || res.Size >= ImgSize || res.Size + res.VirtualAddress > ImgSize ) { msg("Invalid resource descriptor\n"); return false; } fr = qfopen(fname, "wb"); if ( fr == NULL ) { msg("Can not create the output file '%s' for the resources\n", fname); return false; } return true; }
// this function find the size of the jump table for indirect switches // (indirect switches have the values table which contains indexes into // the jump table) // in: si->ncases has the size of the values table // out: si->jcases is initialized static bool find_jtable_size(switch_info_ex_t &si) { int size = 0; ea_t ea = si.values; int vsize = si.get_vtable_element_size(); for ( int i=0; i < si.ncases; i++,ea+=vsize ) { uint64 v = 0; if ( !get_many_bytes(ea, &v, vsize) ) break; if ( size < v ) size = (int)v; } if ( size == 0 ) return false; size++; si.jcases = size; return true; }
void IDAMemCopyPaste::copy_buffer(ea_t eaStartAddr, ea_t eaEndAddr) { ssize_t size; // Work out the size, make sure it doesn't exceed the buffer // we have allocated. size = eaEndAddr - eaStartAddr; if (size > MAX_COPYPASTE) { warning("You can only copy a max of %d bytes\n", MAX_COPYPASTE); return; } // Get the bytes from the file, store it in our buffer if (get_many_bytes(eaStartAddr, data, size)) { msg("Successfully copied %d bytes from %a into memory.\n", size, eaStartAddr); } else { msg("FAILED to copy %d bytes from %a into memory.\n", size, eaStartAddr); } }
int __stdcall GetBytes(__int64 offset, void *buf, int length){ return get_many_bytes((ea_t)offset, buf, length);}
/* * function to extract fat archives */ uint8_t extract_fat(ea_t address, char *outputFilename) { #if DEBUG msg("[DEBUG] Trying to extract a fat binary target!\n"); #endif struct fat_header fatHeader; if(!get_many_bytes(address, &fatHeader, sizeof(struct fat_header))) { msg("[ERROR] Read bytes failed!\n"); return 1; } if(validate_fat(fatHeader, address)) return 1; // for fat binaries things are much easier to dump // since the fat_arch struct contains total size of the binary :-) // open output file FILE *outputFile = qfopen(outputFilename, "wb+"); if (outputFile == NULL) { msg("[ERROR] Could not open %s file!\n", outputFilename); return 1; } // write fat_header qfwrite(outputFile, &fatHeader, sizeof(struct fat_header)); // read fat_arch ea_t fatArchAddress = address + sizeof(struct fat_header); uint32_t fatArchSize = sizeof(struct fat_arch)*ntohl(fatHeader.nfat_arch); // write all fat_arch structs void *fatArchBuf = qalloc(fatArchSize); if(!get_many_bytes(fatArchAddress, fatArchBuf, fatArchSize)) { msg("[ERROR] Read bytes failed!\n"); return 1; } qfwrite(outputFile, fatArchBuf, fatArchSize); qfree(fatArchBuf); // write the mach-o binaries inside the fat archive for (uint32_t i = 0; i < ntohl(fatHeader.nfat_arch) ; i++) { struct fat_arch tempFatArch; // read the fat_arch struct if(!get_many_bytes(fatArchAddress, &tempFatArch, sizeof(struct fat_arch))) { msg("[ERROR] Read bytes failed!\n"); return 1; } // read and write the mach-o binary pointed by each fat_arch struct void *tempBuf = qalloc(ntohl(tempFatArch.size)); if(!get_many_bytes(address+ntohl(tempFatArch.offset), tempBuf, ntohl(tempFatArch.size))) { msg("[ERROR] Read bytes failed!\n"); return 1; } qfseek(outputFile, ntohl(tempFatArch.offset), SEEK_SET); qfwrite(outputFile, tempBuf, ntohl(tempFatArch.size)); qfree(tempBuf); // advance to next fat_arch struct fatArchAddress += sizeof(struct fat_arch); } // all done qfclose(outputFile); return 0; }
// 插件可以从plugins.cfg文件中,被传进一个整型参数。 // 当按下不同的热键或者菜单时,您需要一个插件做不同 // 的事情时,这非常有用。 void __stdcall IDAP_run(int arg) { // 插件的实体 //在LOG中显示一个字符串 char *lpInBuf = NULL; char *lpTmpBuf = NULL; char *lpFilePath = NULL; char szValue[MAXSTR + 1] = ""; char szInValue[MAXSTR + 1] = ""; // char szTmp[100] = {0}; int nPatchLogFlags = 1; uval_t nAddres = get_screen_ea(); asize_t nCount = 1; USHORT nWriteRadio = 0; //单选按钮 USHORT nSerializeRadio = -1; //单选按钮 USHORT checkmask = 0; asize_t j = 0; asize_t i = 0; // qstrncpy(szInValue,"",sizeof(szInValue)); if(AskUsingForm_c(dialog, szInValue, &nAddres, &nCount, &nWriteRadio, &nSerializeRadio, &checkmask) == 1) { if(checkmask & 1) { nAddres = get_screen_ea(); } size_t len = strlen(szInValue); for(i = 0; i < len; i++) { if(szInValue[i] != ' ') { szValue[j++] = szInValue[i]; } } len = strlen(szValue); size_t nHexLen = len / 2; if(!len) { if( lpFilePath = askfile_cv(0, "*.*", "OpenPath", 0)) { FILE* handle = fopen(lpFilePath, "rb"); if(handle == NULL) { warning("打开文件失败 Error!\n"); return; } fseek(handle, 0, SEEK_END); nHexLen = ftell(handle); fseek(handle, 0, SEEK_SET); lpTmpBuf = (char *)malloc(nHexLen + 1); memset(lpTmpBuf, 0, nHexLen + 1); fread(lpTmpBuf, 1, nHexLen, handle); fclose(handle); strcpy(szValue, lpFilePath); } else { warning("请输入数据"); return; } } else if(len % 2) { warning("数据长度不是2的倍数"); return; } else { for(i = 0;i < len;i++) { if(!isxdigit(szValue[i])) { warning("数据中含有非16进制值"); return; } } lpTmpBuf = (char *) malloc(nHexLen * 2 + 1); memset(lpTmpBuf, 0, nHexLen * 2 + 1); for(i = 0; i < nHexLen; i++) { sscanf(&szValue[i * 2],"%02x",lpTmpBuf + i); } } if(nSerializeRadio >= 0) { asize_t nSerializeSize = (nSerializeRadio + 1) * 4; asize_t nSerializeCount = nHexLen * nCount / nSerializeSize; for(i = 0; i < nSerializeCount; i++) { reversedbuf((unsigned char*)lpTmpBuf + nSerializeSize *i, nSerializeSize); } } lpInBuf = (char*)malloc(nHexLen * nCount * 2 + 1); memset(lpInBuf, 0, nHexLen * nCount * 2 + 1); for(i = 0; i < nCount; i++) { memcpy(lpInBuf + i * nHexLen, lpTmpBuf, nHexLen); } free(lpTmpBuf); msg("==============修补数据库数据==============\n"); msg("String Value = %s\n",szValue); #ifdef __EA64__ msg("Addres:0x%llX ValueSize = 0x%llX Index:%d check = %d\n",nAddres, nHexLen, nCount,checkmask); #else msg("Addres:0x%08X ValueSize = 0x%08X Index:%d check = %d\n",nAddres, nHexLen, nCount,checkmask); #endif if(!nWriteRadio) { msg("WriteData \n",nWriteRadio); } else { msg("XorWrite Data \n",nWriteRadio); } if( nHexLen * nCount > 0x100) { nPatchLogFlags = askyn_c(0, "%s", "是否打印日志!(默认不打印)\n因为数据量过大会影响IDA会假死!\nNo或Cancel表示不打印日志!\n"); } //////////////////// uint32 nSum = 0; uchar *mem = NULL; if(isLoaded(nAddres) && isLoaded(nAddres + nCount * nHexLen - 1)) { mem = (uchar *)malloc(nCount * nHexLen + 1); if(mem == NULL) { warning("malloc 函数执行失败!"); return; } get_many_bytes(nAddres,mem, nCount * nHexLen); if(nPatchLogFlags > 0) { msg("原始数据:\n"); for(i = 0; i < nCount * nHexLen; i++) { msg("%02X", mem[i]); } msg("\n"); } } else { if(!isLoaded(nAddres)) { warning("数据地址错误: 0x%p",nAddres); } else { warning("写入数据长度过大"); } return; } /////////////////////////// // long nValue = 0; for(j = 0;j < nCount;j++) { for(i = 0;i < nHexLen; i++) { // memcpy(szTmp,&szInValue[j * len + i * 2],2); //sscanf(&szValue[i * 2],"%02x",&nValue); if(nWriteRadio == 1) { lpInBuf[nSum] ^= mem[nSum]; } mem[nSum++] = lpInBuf[nSum]; } } put_many_bytes(nAddres, mem, nSum); if(nPatchLogFlags > 0) { msg("补丁数据:\n"); for(i = 0; i < nSum; i++) { msg("%02X", mem[i]); } msg("\n"); } refresh_idaview_anyway(); //刷新反汇编窗口 free(mem); free(lpInBuf); } return; }
uint8_t extract_mhobject(ea_t address, char *outputFilename) { uint32 magicValue = get_long(address); struct mach_header *mach_header = NULL; struct mach_header_64 *mach_header64 = NULL; uint8_t arch = 0; if (magicValue == MH_MAGIC) { #if DEBUG msg("[DEBUG] Target is 32bits!\n"); #endif mach_header = (struct mach_header *)qalloc(sizeof(struct mach_header)); // retrieve mach_header contents if(!get_many_bytes(address, mach_header, sizeof(struct mach_header))) { msg("[ERROR] Read bytes failed!\n"); return 1; } } else if (magicValue == MH_MAGIC_64) { #if DEBUG msg("[DEBUG] Target is 64bits!\n"); #endif mach_header64 = (struct mach_header_64 *)qalloc(sizeof(struct mach_header_64)); if(!get_many_bytes(address, mach_header64, sizeof(struct mach_header_64))) { msg("[ERROR] Read bytes failed!\n"); return 1; } arch = 1; } // open output file FILE *outputFile = qfopen(outputFilename, "wb+"); if (outputFile == NULL) { msg("[ERROR] Could not open %s file!\n", outputFilename); return 1; } /* * we need to write 3 distinct blocks of data: * 1) the mach_header * 2) the load commands * 3) the code and data from the LC_SEGMENT/LC_SEGMENT_64 commands */ // write the mach_header to the file if (arch) qfwrite(outputFile, mach_header64, sizeof(struct mach_header_64)); else qfwrite(outputFile, mach_header, sizeof(struct mach_header)); // swap the endianness of some fields if it's powerpc target if (magicValue == MH_CIGAM) { mach_header->ncmds = ntohl(mach_header->ncmds); mach_header->sizeofcmds = ntohl(mach_header->sizeofcmds); } else if (magicValue == MH_CIGAM_64) { mach_header64->ncmds = ntohl(mach_header64->ncmds); mach_header64->sizeofcmds = ntohl(mach_header64->sizeofcmds); } // read the load commands uint32_t ncmds = arch ? mach_header64->ncmds : mach_header->ncmds; uint32_t sizeofcmds = arch ? mach_header64->sizeofcmds : mach_header->sizeofcmds; uint32_t headerSize = arch ? sizeof(struct mach_header_64) : sizeof(struct mach_header); uint8_t *loadcmdsBuffer = NULL; loadcmdsBuffer = (uint8_t*)qalloc(sizeofcmds); get_many_bytes(address + headerSize, loadcmdsBuffer, sizeofcmds); // write all the load commands block to the output file // only LC_SEGMENT commands contain further data qfwrite(outputFile, loadcmdsBuffer, sizeofcmds); // and now process the load commands so we can retrieve code and data struct load_command loadCommand; ea_t cmdsBaseAddress = address + headerSize; // read segments so we can write the code and data // only the segment commands have useful information for (uint32_t i = 0; i < ncmds; i++) { get_many_bytes(cmdsBaseAddress, &loadCommand, sizeof(struct load_command)); struct segment_command segmentCommand; struct segment_command_64 segmentCommand64; // swap the endianness of some fields if it's powerpc target if (magicValue == MH_CIGAM || magicValue == MH_CIGAM_64) { loadCommand.cmd = ntohl(loadCommand.cmd); loadCommand.cmdsize = ntohl(loadCommand.cmdsize); } // 32bits targets if (loadCommand.cmd == LC_SEGMENT) { get_many_bytes(cmdsBaseAddress, &segmentCommand, sizeof(struct segment_command)); // swap the endianness of some fields if it's powerpc target if (magicValue == MH_CIGAM) { segmentCommand.nsects = ntohl(segmentCommand.nsects); segmentCommand.fileoff = ntohl(segmentCommand.fileoff); segmentCommand.filesize = ntohl(segmentCommand.filesize); } ea_t sectionAddress = cmdsBaseAddress + sizeof(struct segment_command); struct section sectionCommand; // iterate thru all sections to find the first code offset // FIXME: we need to find the lowest one since the section info can be reordered for (uint32_t x = 0; x < segmentCommand.nsects; x++) { get_many_bytes(sectionAddress, §ionCommand, sizeof(struct section)); // swap the endianness of some fields if it's powerpc target if (magicValue == MH_CIGAM) { sectionCommand.offset = ntohl(sectionCommand.offset); sectionCommand.nreloc = ntohl(sectionCommand.nreloc); sectionCommand.reloff = ntohl(sectionCommand.reloff); } if (sectionCommand.nreloc > 0) { uint32_t size = sectionCommand.nreloc*sizeof(struct relocation_info); uint8_t *relocBuf = (uint8_t*)qalloc(size); get_many_bytes(address + sectionCommand.reloff, relocBuf, size); qfseek(outputFile, sectionCommand.reloff, SEEK_SET); qfwrite(outputFile, relocBuf, size); qfree(relocBuf); } sectionAddress += sizeof(struct section); } // read and write the data uint8_t *buf = (uint8_t*)qalloc(segmentCommand.filesize); get_many_bytes(address + segmentCommand.fileoff, buf, segmentCommand.filesize); // always set the offset qfseek(outputFile, segmentCommand.fileoff, SEEK_SET); qfwrite(outputFile, buf, segmentCommand.filesize); qfree(buf); } // we need this to dump missing relocations else if (loadCommand.cmd == LC_SYMTAB) { struct symtab_command symtabCommand; get_many_bytes(cmdsBaseAddress, &symtabCommand, sizeof(struct symtab_command)); // swap the endianness of some fields if it's powerpc target if (magicValue == MH_CIGAM || magicValue == MH_CIGAM_64) { symtabCommand.nsyms = ntohl(symtabCommand.nsyms); symtabCommand.symoff = ntohl(symtabCommand.symoff); symtabCommand.stroff = ntohl(symtabCommand.stroff); symtabCommand.strsize = ntohl(symtabCommand.strsize); } if (symtabCommand.symoff > 0) { void *buf = qalloc(symtabCommand.nsyms*sizeof(struct nlist)); get_many_bytes(address + symtabCommand.symoff, buf, symtabCommand.nsyms*sizeof(struct nlist)); qfseek(outputFile, symtabCommand.symoff, SEEK_SET); qfwrite(outputFile, buf, symtabCommand.nsyms*sizeof(struct nlist)); qfree(buf); } if (symtabCommand.stroff > 0) { void *buf = qalloc(symtabCommand.strsize); get_many_bytes(address + symtabCommand.stroff, buf, symtabCommand.strsize); qfseek(outputFile, symtabCommand.stroff, SEEK_SET); qfwrite(outputFile, buf, symtabCommand.strsize); qfree(buf); } } // 64bits targets // FIXME: will this work ? needs to be tested :-) else if (loadCommand.cmd == LC_SEGMENT_64) { get_many_bytes(cmdsBaseAddress, &segmentCommand64, sizeof(struct segment_command_64)); // swap the endianness of some fields if it's powerpc target if (magicValue == MH_CIGAM_64) { segmentCommand64.nsects = ntohl(segmentCommand64.nsects); segmentCommand64.fileoff = bswap64(segmentCommand64.fileoff); segmentCommand64.filesize = bswap64(segmentCommand64.filesize); } ea_t sectionAddress = cmdsBaseAddress + sizeof(struct segment_command_64); struct section_64 sectionCommand64; for (uint32_t x = 0; x < segmentCommand64.nsects; x++) { get_many_bytes(sectionAddress, §ionCommand64, sizeof(struct section_64)); // swap the endianness of some fields if it's powerpc target if (magicValue == MH_CIGAM_64) { sectionCommand64.offset = ntohl(sectionCommand64.offset); sectionCommand64.nreloc = ntohl(sectionCommand64.nreloc); sectionCommand64.reloff = ntohl(sectionCommand64.reloff); } if (sectionCommand64.nreloc > 0) { uint32_t size = sectionCommand64.nreloc*sizeof(struct relocation_info); uint8_t *relocBuf = (uint8_t*)qalloc(size); get_many_bytes(address + sectionCommand64.reloff, relocBuf, size); qfseek(outputFile, sectionCommand64.reloff, SEEK_SET); qfwrite(outputFile, relocBuf, size); qfree(relocBuf); } sectionAddress += sizeof(struct section_64); } // read and write the data uint8_t *buf = (uint8_t*)qalloc(segmentCommand64.filesize); get_many_bytes(address + segmentCommand64.fileoff, buf, segmentCommand64.filesize); qfseek(outputFile, segmentCommand64.fileoff, SEEK_SET); qfwrite(outputFile, buf, segmentCommand64.filesize); qfree(buf); } cmdsBaseAddress += loadCommand.cmdsize; } // all done, close file and free remaining buffers! qfclose(outputFile); qfree(mach_header); qfree(mach_header64); qfree(loadcmdsBuffer); return 0; }
/* * function to extract non-fat binaries, 32 and 64bits */ uint8_t extract_macho(ea_t address, char *outputFilename) { uint32 magicValue = get_long(address); struct mach_header *mach_header = NULL; struct mach_header_64 *mach_header64 = NULL; uint8_t arch = 0; if (magicValue == MH_MAGIC || magicValue == MH_CIGAM) { #if DEBUG msg("[DEBUG] Target is 32bits!\n"); #endif mach_header = (struct mach_header *)qalloc(sizeof(struct mach_header)); // retrieve mach_header contents if(!get_many_bytes(address, mach_header, sizeof(struct mach_header))) { msg("[ERROR] Read bytes failed!\n"); return 1; } } else if (magicValue == MH_MAGIC_64 || magicValue == MH_CIGAM_64) { #if DEBUG msg("[DEBUG] Target is 64bits!\n"); #endif mach_header64 = (struct mach_header_64 *)qalloc(sizeof(struct mach_header_64)); if(!get_many_bytes(address, mach_header64, sizeof(struct mach_header_64))) { msg("[ERROR] Read bytes failed!\n"); return 1; } arch = 1; } else { msg("[ERROR] Unknown target!\n"); return 1; } // open output file FILE *outputFile = qfopen(outputFilename, "wb+"); if (outputFile == NULL) { msg("[ERROR] Could not open %s file!\n", outputFilename); return 1; } /* * we need to write 3 distinct blocks of data: * 1) the mach_header * 2) the load commands * 3) the code and data from the LC_SEGMENT/LC_SEGMENT_64 commands */ // write the mach_header to the file if (arch) qfwrite(outputFile, mach_header64, sizeof(struct mach_header_64)); else qfwrite(outputFile, mach_header, sizeof(struct mach_header)); // swap the endianness of some fields if it's powerpc target if (magicValue == MH_CIGAM) { mach_header->ncmds = ntohl(mach_header->ncmds); mach_header->sizeofcmds = ntohl(mach_header->sizeofcmds); } else if (magicValue == MH_CIGAM_64) { mach_header64->ncmds = ntohl(mach_header64->ncmds); mach_header64->sizeofcmds = ntohl(mach_header64->sizeofcmds); } // read the load commands uint32_t ncmds = arch ? mach_header64->ncmds : mach_header->ncmds; uint32_t sizeofcmds = arch ? mach_header64->sizeofcmds : mach_header->sizeofcmds; uint32_t headerSize = arch ? sizeof(struct mach_header_64) : sizeof(struct mach_header); uint8_t *loadcmdsBuffer = NULL; loadcmdsBuffer = (uint8_t*)qalloc(sizeofcmds); get_many_bytes(address + headerSize, loadcmdsBuffer, sizeofcmds); // write all the load commands block to the output file // only LC_SEGMENT commands contain further data qfwrite(outputFile, loadcmdsBuffer, sizeofcmds); // and now process the load commands so we can retrieve code and data struct load_command loadCommand; ea_t cmdsBaseAddress = address + headerSize; ea_t codeOffset = 0; // read segments so we can write the code and data // only the segment commands have useful information for (uint32_t i = 0; i < ncmds; i++) { get_many_bytes(cmdsBaseAddress, &loadCommand, sizeof(struct load_command)); struct segment_command segmentCommand; struct segment_command_64 segmentCommand64; // swap the endianness of some fields if it's powerpc target if (magicValue == MH_CIGAM || magicValue == MH_CIGAM_64) { loadCommand.cmd = ntohl(loadCommand.cmd); loadCommand.cmdsize = ntohl(loadCommand.cmdsize); } // 32bits targets // FIXME: do we also need to dump the relocs info here ? if (loadCommand.cmd == LC_SEGMENT) { get_many_bytes(cmdsBaseAddress, &segmentCommand, sizeof(struct segment_command)); // swap the endianness of some fields if it's powerpc target if (magicValue == MH_CIGAM) { segmentCommand.nsects = ntohl(segmentCommand.nsects); segmentCommand.fileoff = ntohl(segmentCommand.fileoff); segmentCommand.filesize = ntohl(segmentCommand.filesize); } // the file offset info in LC_SEGMENT is zero at __TEXT so we need to get it from the sections // the size is ok to be used if (strncmp(segmentCommand.segname, "__TEXT", 16) == 0) { ea_t sectionAddress = cmdsBaseAddress + sizeof(struct segment_command); struct section sectionCommand; // iterate thru all sections to find the first code offset // FIXME: we need to find the lowest one since the section info can be reordered for (uint32_t x = 0; x < segmentCommand.nsects; x++) { get_many_bytes(sectionAddress, §ionCommand, sizeof(struct section)); // swap the endianness of some fields if it's powerpc target if (magicValue == MH_CIGAM) sectionCommand.offset = ntohl(sectionCommand.offset); if (strncmp(sectionCommand.sectname, "__text", 16) == 0) { codeOffset = sectionCommand.offset; break; } sectionAddress += sizeof(struct section); } } // for all other segments the fileoffset info in the LC_SEGMENT is valid so we can use it else { codeOffset = segmentCommand.fileoff; } // read and write the data uint8_t *buf = (uint8_t*)qalloc(segmentCommand.filesize); get_many_bytes(address + codeOffset, buf, segmentCommand.filesize); // always set the offset qfseek(outputFile, codeOffset, SEEK_SET); qfwrite(outputFile, buf, segmentCommand.filesize); qfree(buf); } // 64bits targets else if (loadCommand.cmd == LC_SEGMENT_64) { get_many_bytes(cmdsBaseAddress, &segmentCommand64, sizeof(struct segment_command_64)); // swap the endianness of some fields if it's powerpc target if (magicValue == MH_CIGAM_64) { segmentCommand64.nsects = ntohl(segmentCommand64.nsects); segmentCommand64.fileoff = bswap64(segmentCommand64.fileoff); segmentCommand64.filesize = bswap64(segmentCommand64.filesize); } if(strncmp(segmentCommand64.segname, "__TEXT", 16) == 0) { ea_t sectionAddress = cmdsBaseAddress + sizeof(struct segment_command_64); struct section_64 sectionCommand64; for (uint32_t x = 0; x < segmentCommand64.nsects; x++) { get_many_bytes(sectionAddress, §ionCommand64, sizeof(struct section_64)); // swap the endianness of some fields if it's powerpc target if (magicValue == MH_CIGAM_64) sectionCommand64.offset = ntohl(sectionCommand64.offset); if (strncmp(sectionCommand64.sectname, "__text", 16) == 0) { codeOffset = sectionCommand64.offset; break; } sectionAddress += sizeof(struct section_64); } } else { codeOffset = segmentCommand64.fileoff; } // read and write the data uint8_t *buf = (uint8_t*)qalloc(segmentCommand64.filesize); get_many_bytes(address + codeOffset, buf, segmentCommand64.filesize); qfseek(outputFile, codeOffset, SEEK_SET); qfwrite(outputFile, buf, segmentCommand64.filesize); qfree(buf); } cmdsBaseAddress += loadCommand.cmdsize; } // all done, close file and free remaining buffers! qfclose(outputFile); qfree(mach_header); qfree(mach_header64); qfree(loadcmdsBuffer); return 0; }
static bool extractEntry(uint32 off, int level, bool named) { IMAGE_RESOURCE_DIRECTORY_ENTRY rde; if ( off + sizeof(rde) >= ResTop ) return false; if ( !get_many_bytes(ResBase + off, &rde, sizeof(rde)) ) return false; if ( (bool)rde.NameIsString != named ) return false; if ( (bool)rde.DataIsDirectory != (level != 2) ) return false; off += sizeof(rde); if ( !named ) { Names[level].Id = rde.Id; } else { ea_t npos = rde.NameOffset; if( npos < off || npos + 2 >= ResTop ) return false; uint32 nlen = get_word(npos + ResBase)*sizeof(wchar_t); if ( !nlen || npos + nlen > ResTop ) return false; wchar_t *p = (wchar_t *)qalloc(nlen + sizeof(wchar_t)); if ( p == NULL ) { msg("Not enough memory for resource names\n"); return false; } if ( !get_many_bytes(npos + sizeof(uint16) + ResBase, p, nlen) ) { bad_name: qfree(p); return false; } p[nlen/sizeof(wchar_t)] = 0; size_t wlen = wcslen(p); if ( !wlen || wlen < nlen/2-1 ) goto bad_name; Names[level].name = p; Names[level].len = uint32((wlen+1)*sizeof(wchar_t)); } if ( level != 2 ) { bool res = false; if ( rde.OffsetToDirectory >= off ) res = extractDirectory(rde.OffsetToDirectory, level+1); if ( Names[level].len ) qfree(Names[level].name); Names[level].name = NULL; Names[level].len = 0; return res; } if ( rde.OffsetToData < off ) return false; return extractData(rde.OffsetToData); }