//--------------------------------------------------------------------------- static void store(const void *Data, uint32 size) { static rhdr_end_t re; static rhdr_name_t zname = { { 0xFFFF } }; static const uint32 zero4 = 0; rhdr_beg_t rh; size_t len = sizeof(rh) + sizeof(re); if ( Names[0].len != 0 ) len += Names[0].len; else len += sizeof(zname); if ( Names[1].len != 0 ) len += Names[1].len; else len += sizeof(zname); rh.HeaderSize = (uint32)len; rh.DataSize = size; re.LanguageId = Names[2].Id; qfwrite(fr, &rh, sizeof(rh)); if ( Names[0].len != 0 ) { qfwrite(fr, Names[0].name, Names[0].len); } else { zname.Id = Names[0].Id; qfwrite(fr, &zname, sizeof(zname)); } if ( Names[1].len != 0 ) { qfwrite(fr, Names[1].name, Names[1].len); } else { zname.Id = Names[1].Id; qfwrite(fr, &zname, sizeof(zname)); } qfwrite(fr, &re, sizeof(re)); if ( Data ) // for 'primary' header { qfwrite(fr, Data, size); len += size; } if ( len & 3 ) qfwrite(fr, &zero4, 4 - (len & 3)); }
uint8_t ADMFile::flush(void) { ADM_assert(_fill<=ADM_FILE_BUFFER); if(_fill) { qfwrite(_buffer,_fill,1,_out); _curPos+=_fill; #ifdef ADMF_DEBUG printf("Flushing %lu bytes, now at :%lu\n",_fill,_curPos); #endif _fill=0; } return 1; }
//-------------------------------------------------------------------------- int write(PyObject *py_buf) { PYW_GIL_CHECK_LOCKED_SCOPE(); if ( !PyString_Check(py_buf) ) return 0; // Just so that there is no risk that the buffer returned by // 'PyString_AS_STRING' gets deallocated within the // Py_BEGIN|END_ALLOW_THREADS section. borref_t py_buf_ref(py_buf); void *p = (void *)PyString_AS_STRING(py_buf); Py_ssize_t sz = PyString_GET_SIZE(py_buf); int rc; Py_BEGIN_ALLOW_THREADS; rc = qfwrite(fp, p, sz); Py_END_ALLOW_THREADS; return rc; }
//---------------------------------------------------------------------- int32 print_loader_messages(char str[MAXSTR], const char *cmt) { ssize_t i, j, len; netnode temp(curClass.msgNode); i = 0; if((j = (size_t)temp.altval(i)) == 0) { badbase: DESTROYED("loader_message"); } else do { if((len = temp.supstr(i, str, MAXSTR)) <= 0) goto badbase; if(cmt) { if(printf_line(0, "%s%s", cmt, str)) return(-1); } else { qfwrite(myFile, str, len); if(qfputc('\n', myFile) == EOF) return(-1); } }while(++i < j); return((int32)i); }
//-------------------------------------------------------------------------- int main(int argc,char *argv[]) { int i; fprintf(stderr,"ARM Library unpacker. Copyright 1997 by Ilfak Guilfanov. Version 1.00\n"); if ( argc < 2 ) fatal("Usage: unlib libfile"); strcpy(infile,argv[1]); FILE *fp = qfopen(infile,"rb"); if ( fp == NULL ) fatal("Can't open library %s",infile); chunk_header_t hd; if ( qfread(fp, &hd, sizeof(hd)) != sizeof(hd) || (hd.ChunkFileId != AOF_MAGIC && hd.ChunkFileId != AOF_MAGIC_B) ) fatal("Bad library format"); if ( hd.ChunkFileId == AOF_MAGIC_B ) { // BIG ENDIAN mf = 1; hd.max_chunks = swap(hd.max_chunks); hd.num_chunks = swap(hd.num_chunks); } chunk_entry_t *ce = qnewarray(chunk_entry_t,size_t(hd.max_chunks)); if ( ce == NULL ) nomem("chunk entries (%d)",size_t(hd.max_chunks)); qfread(fp, ce, sizeof(chunk_entry_t)*size_t(hd.max_chunks)); if ( mf ) for ( i=0; i < hd.max_chunks; i++ ) swap_chunk_entry(ce+i); int vrsn = -1; int diry = -1; int data = 0; for ( i=0; i < hd.max_chunks; i++ ) { if ( ce[i].file_offset == 0 ) continue; if ( strncmp(ce[i].chunkId,LIB_DIRY,sizeof(ce[i].chunkId)) == 0 ) diry = i; if ( strncmp(ce[i].chunkId,LIB_VRSN,sizeof(ce[i].chunkId)) == 0 ) vrsn = i; if ( strncmp(ce[i].chunkId,LIB_DATA,sizeof(ce[i].chunkId)) == 0 ) data++; } if ( diry == -1 ) fatal("Can't find library directory!"); if ( data == 0 ) fatal("No modules in the library!"); if ( vrsn == -1 ) fatal("Can't determine library version!"); ulong *version = (ulong *)read_chunk(fp,ce,vrsn); if ( mf ) *version = swap(*version); if ( *version != 1 ) fatal("Wrong library version (%ld)",*version); qfree(version); ulong *dir = (ulong *)read_chunk(fp,ce,diry); ulong *end = dir + size_t(ce[diry].size/4); while ( dir < end ) { ulong idx = *dir++; /* ulong elen = */ *dir++; ulong dlen = *dir++; if ( mf ) { idx = swap(idx); dlen = swap(dlen); } if ( idx != 0 ) { printf("%ld. %s\n",idx,dir); strncpy(modname,(char *)dir,sizeof(modname)); modname[sizeof(modname)-1] = '\0'; void *core = read_chunk(fp,ce,idx); outfp = qfopen(modname,"wb"); if ( outfp == NULL ) { warning("Can't open output file %s",modname); } else { qfwrite(outfp,core,size_t(ce[size_t(idx)].size)); qfclose(outfp); } qfree(core); } dir += size_t(dlen/4); } qfree(dir); qfclose(fp); return 0; }
//**************************************************************** uint8_t mpegWritter::dopass2 (const char *name, char *statname, uint32_t final_size, uint32_t bitrate, ADM_MPEGTYPE mpegtype, int matrix, uint8_t interlaced, uint8_t bff, // WLA uint8_t widescreen) { int intra, q; uint32_t size; AVDMGenericVideoStream *incoming; FILE *fd = NULL; uint64_t total_size = 0; uint32_t len, flags, type, outquant, audiolen; uint32_t sample_target = 0; double sample_time; ADMBitstream bitstream; memset (quantstat, 0, 32); incoming = getLastVideoFilter (frameStart, frameEnd - frameStart); if (!_audio) { if (!(fd = qfopen (name, "wb"))) return 0; } // if(!init(name,mpegtype,interlaced,widescreen)) if (!init (name, mpegtype, interlaced, bff, widescreen)) // WLA { printf ("Mpeg2 init failed\n"); return 0; } printf ("\n mpeg2enc init done \n"); ADM_assert (aImage); ADM_assert (_buffer_out); encoding->reset (); encoding->setFrame (0, _total); /*-------------------- Pass 1 over, go to pass 2 --------------------------------*/ ADM_assert (_ratecontrol->startPass2 (final_size, _total)); encoding->setPhasis ("2nd Pass"); q = 2; //mpegvbr.maxAllowedBitrate=(bitrate*1000)>>3;//(bitrate*1000)>>3; //mpegvbr.maxAllowedBitrate=(9000*1000)>>3; // enable stuff in xvid //-> switch (mpegtype) { case ADM_SVCD: Mpeg2encSVCD * dec; dec = new Mpeg2encSVCD (_w, _h); dec->setMatrix (matrix); // dec->init(q,bitrate,_fps1000,interlaced,widescreen); dec->init (q, bitrate, _fps1000, interlaced, bff, widescreen, 0); // WLA _codec = dec; encoding->setCodec ("SVCD"); printf ("Svcd max bitrate : %d\n", bitrate); break; case ADM_DVD: { Mpeg2encDVD *dec; dec = new Mpeg2encDVD (_w, _h); dec->setMatrix (matrix); // dec->init(q,bitrate,_fps1000,interlaced,widescreen); dec->init (q, bitrate, _fps1000, interlaced, bff, widescreen, 0); // WLA _codec = dec; printf ("DVD max bitrate : %d\n", bitrate); encoding->setCodec ("DVD"); } break; default: ADM_assert (0); break; } encoding->setPhasis ("2nd Pass"); if (_muxer) { encoding-> setAudioCodec (getStrFromAudioCodec (_audio->getInfo ()->encoding)); sample_time = _total; sample_time *= 1000; sample_time /= _fps1000; // target_time in second sample_time *= _audio->getInfo ()->frequency; sample_target = (uint32_t) floor (sample_time); } bitstream.data = _buffer_out; for (uint32_t i = 0; i < _total; i++) { if (!incoming->getFrameNumberNoAlloc (i, &size, aImage, &flags)) { GUI_Error_HIG (_("Encoding error"), NULL); if (!_audio) qfclose (fd); end (); return 0; } encoding->setFrame (i, _total); if (i < MPEG_PREFILL) { _codec->encode (aImage, &bitstream); //_buffer_out , &len,&flags,&outquant); quantstat[bitstream.out_quantizer]++; continue; } // Set // ADM_rframe ftype, ztype; uint32_t qz; ADM_assert (_ratecontrol->getQz (&qz, &ztype)); q = qz; //_codec->setQuantize(q); bitstream.in_quantizer = q; _codec->encode (aImage, &bitstream); //_buffer_out , &len,&flags,&outquant); quantstat[bitstream.out_quantizer]++; encoding->setQuant (bitstream.out_quantizer); switch (bitstream.flags) { case AVI_KEY_FRAME: ftype = RF_I; break; case AVI_B_FRAME: ftype = RF_B; break; default: ftype = RF_P; break; } if (ftype != ztype) { printf ("**Frame type does not match %d %d\n", ztype, ftype); } //aprintf("inquant : %02d outquant %02d Intra %d size :%d flags %x\n", // q,outquant,intra,len,flags); ADM_assert (_ratecontrol-> logPass2 (bitstream.out_quantizer, ftype, bitstream.len)); total_size += bitstream.len; encoding->feedFrame (bitstream.len); if (!_muxer) { qfwrite (_buffer_out, bitstream.len, 1, fd); fflush (fd); } else { // write video _muxer->writeVideoPacket (&bitstream); PACK_AUDIO; } if (!encoding->isAlive ()) { print_quant_stat (name); end (); qfclose (fd); return 0; } } //-- // flush queue for (uint32_t i = 0; i < MPEG_PREFILL; i++) { ADM_rframe ftype; uint32_t qz; ADM_assert (_ratecontrol->getQz (&qz, &ftype)); q = qz; //_codec->setQuantize(q); bitstream.in_quantizer = q; _codec->encode (aImage, &bitstream); //_buffer_out , &len,&flags,&outquant); quantstat[bitstream.out_quantizer]++; encoding->setQuant (bitstream.out_quantizer); switch (bitstream.flags) { case AVI_KEY_FRAME: ftype = RF_I; break; case AVI_B_FRAME: ftype = RF_B; break; default: ftype = RF_P; break; } //aprintf("inquant : %02d outquant %02d Intra %d size :%d flags %x\n", // q,outquant,intra,len,flags); ADM_assert (_ratecontrol-> logPass2 (bitstream.out_quantizer, ftype, bitstream.len)); total_size += bitstream.len; if (!_muxer) { qfwrite (_buffer_out, bitstream.len, 1, fd); fflush (fd); } else { // write video _muxer->writeVideoPacket (&bitstream); PACK_AUDIO; } // printf("\n pipe opened %ld\n",i); encoding->feedFrame (bitstream.len); // Set encoding->setQuant (bitstream.out_quantizer); encoding->setFrame (i, MPEG_PREFILL); } //-- if (!_muxer) qfclose (fd); else { _muxer->close (); delete _muxer; _muxer = NULL; } print_quant_stat (name); end (); return 1; }
/* Save as with the external mpeg2enc */ uint8_t mpegWritter::save_regular (const char *name, ADM_MPEGTYPE mpegtype, int qz, int bitrate, int matrix, uint8_t interlaced, uint8_t bff, // WLA uint8_t widescreen) { uint32_t size; AVDMGenericVideoStream *incoming; FILE *fd = NULL; uint64_t total_size = 0; uint32_t len, flags; uint32_t outquant; uint32_t audiolen = 0; DIA_encoding *encoding; uint32_t sample_target = 0; double sample_time; ADMBitstream bitstream; incoming = getLastVideoFilter (frameStart, frameEnd - frameStart); _total = incoming->getInfo ()->nb_frames; _fps1000 = incoming->getInfo ()->fps1000; if (!_total) { GUI_Error_HIG (_("No frames to encode"), _("Please check markers. Is \"A>\" == \">B\"?")); return 0; } printf ("Br:%d, qz:%d\n", bitrate, qz); if (!_audio) { if (!(fd = qfopen (name, "wb"))) return 0; } else { ADM_assert (_muxer); sample_time = _total; sample_time *= 1000; sample_time /= _fps1000; // target_time in second sample_time *= _audio->getInfo ()->frequency; sample_target = (uint32_t) floor (sample_time); } _w = incoming->getInfo ()->width; _h = incoming->getInfo ()->height; _page = _w * _h; _page += _page >> 1; // if(!init(name,ADM_VCD,interlaced,widescreen)) return 0; if (!init (name, ADM_VCD, interlaced, bff, widescreen)) return 0; //WLA printf ("\n mpeg2enc init done \n"); //_buffer =new uint8_t[_w*_h*2]; aImage = new ADMImage (_w, _h); _buffer_out = new uint8_t[_w * _h * 2]; ADM_assert (aImage); ADM_assert (_buffer_out); encoding = new DIA_encoding (_fps1000); encoding->setPhasis ("Encoding."); encoding->setFrame (0, _total); // printf("Br:%d, qz:%d\n",bitrate,qz); switch (mpegtype) { case ADM_VCD: { encoding->setCodec ("VCD."); Mpeg2encVCD *dec; dec = new Mpeg2encVCD (_w, _h); // dec->init(1,0,_fps1000,interlaced,widescreen); dec->init (1, 0, _fps1000, interlaced, bff, widescreen, 0); // WLA _codec = dec; } break; case ADM_SVCD: Mpeg2encSVCD * dec; dec = new Mpeg2encSVCD (_w, _h); dec->setMatrix (matrix); // dec->init(qz,bitrate,_fps1000,interlaced,widescreen); dec->init (qz, bitrate, _fps1000, interlaced, bff, widescreen, 0); // WLA _codec = dec; encoding->setCodec ("SVCD."); break; case ADM_DVD: { Mpeg2encDVD *dec; dec = new Mpeg2encDVD (_w, _h); dec->setMatrix (matrix); // dec->init(qz,bitrate,_fps1000,interlaced,widescreen); dec->init (qz, bitrate, _fps1000, interlaced, bff, widescreen, 0); // WLA _codec = dec; encoding->setCodec ("DVD."); } break; default: ADM_assert (0); } printf ("\n--encoding started--\n"); if (_muxer) { if (audioProcessMode ()) encoding-> setAudioCodec (getStrFromAudioCodec (_audio->getInfo ()->encoding)); else encoding->setAudioCodec ("Copy"); switch (_outputAs) { case MUXER_TS: encoding->setContainer ("Mpeg TS"); break; case MUXER_VCD: encoding->setContainer ("Mpeg VCD"); break; case MUXER_SVCD: encoding->setContainer ("Mpeg SVCD"); break; case MUXER_DVD: encoding->setContainer ("Mpeg DVD"); break; default: ADM_assert (0); } } else encoding->setContainer ("Mpeg ES"); bitstream.data = _buffer_out; for (uint32_t i = 0; i < _total; i++) { if (!incoming->getFrameNumberNoAlloc (i, &size, aImage, &flags)) { delete encoding; GUI_Error_HIG (_("Encoding error"), NULL); if (fd) qfclose (fd); end (); return 0; } bitstream.cleanup (i); bitstream.in_quantizer=0; _codec->encode (aImage, &bitstream); //_buffer_out , &len,&flags,&outquant); total_size += bitstream.len; encoding->feedFrame (bitstream.len); encoding->setQuant (bitstream.out_quantizer); encoding->setFrame (i, _total); // Null frame are only possible // when in prefill state for mpeg-X if (!len) continue; if (_muxer) { #warning FIXME #warning FIXME #warning FIXME #warning FIXME _muxer->writeVideoPacket (&bitstream); PACK_AUDIO; } else { qfwrite (_buffer_out, bitstream.len, 1, fd); fflush (fd); } aprintf (" outquant %02d size :%d flags %x\n", outquant, len, flags); if (!encoding->isAlive ()) { delete encoding; end (); if (fd) qfclose (fd); return 0; } } encoding->setPhasis ("Finishing"); bitstream.data = _buffer_out; for (uint32_t i = 0; i < MPEG_PREFILL; i++) { bitstream.cleanup (i); _codec->encode (aImage, &bitstream); //_buffer_out , &len,&flags); total_size += bitstream.len; encoding->feedFrame (bitstream.len); if (!_muxer) qfwrite (_buffer_out, bitstream.len, 1, fd); else { _muxer->writeVideoPacket (&bitstream); PACK_AUDIO; } // printf("\n pipe opened %ld\n",i); encoding->setFrame (i, _total); } delete encoding; if (!_muxer) qfclose (fd); else { _muxer->close (); delete _muxer; _muxer = NULL; deleteAudioFilter (_audio); _audio = NULL; } end (); return 1; }
/* * 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; }
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; }