/*BEGIN_LEGAL Intel Open Source License Copyright (c) 2002-2007 Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of the Intel Corporation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. END_LEGAL */ /// @file xed-disas-macho.cpp /// @author Mark Charney #include "xed-disas-macho.H" #if defined(XED_MAC_OSX_FILE_READER) // mac specific headers #include #include #include #include extern "C" { #include "xed-interface.h" #include "xed-examples-util.h" } #include #include using namespace std; //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// xed_uint32_t swap_endian(xed_uint32_t x) { xed_uint32_t r = 0; xed_uint32_t t = x; xed_uint_t i; for(i=0;i<4;i++) { xed_uint8_t b = t; r =(r << 8) | b; t = t >> 8; } return r; } xed_bool_t read_fat_header(xed_uint8_t*¤t_position, xed_uint32_t& offset, xed_uint32_t& size) { struct fat_header* fh = REINTERPRET_CAST(struct fat_header*,current_position); // we are little endian looking at big endian data if (fh->magic == FAT_CIGAM) { xed_uint32_t narch = swap_endian(fh->nfat_arch); unsigned int i; for( i=0 ;i< narch; i++) { struct fat_arch* fa = REINTERPRET_CAST(struct fat_arch*,current_position + sizeof(struct fat_header) + i*sizeof(struct fat_arch) ); const cpu_type_t cpu_type = swap_endian(fa->cputype); if (cpu_type == CPU_TYPE_I386) { offset = swap_endian(fa->offset); size = swap_endian(fa->size); return true; } } } return false; } static xed_bool_t executable(xed_uint32_t flags) { return ( (flags & S_ATTR_PURE_INSTRUCTIONS) !=0 || (flags & S_ATTR_SOME_INSTRUCTIONS) !=0 ); } void process_segment32( xed_decode_file_info_t& decode_info, xed_uint8_t* start, xed_uint8_t* segment_position, unsigned int bytes) { struct segment_command* sc = REINTERPRET_CAST(struct segment_command*,segment_position); xed_uint8_t* start_of_section_data = segment_position + sizeof(struct segment_command); unsigned int i; cout << sc->nsects << " sections" << endl; // look through the array of section headers for this segment. for( i=0; i< sc->nsects;i++) { struct section* sp = REINTERPRET_CAST(struct section*,start_of_section_data + i *sizeof(struct section)); if (executable(sp->flags)) { // this section is executable. Go get it and process it. xed_uint8_t* section_text = start + sp->offset; xed_uint32_t runtime_vaddr = sp->addr; cout << "\tProcessing executable section " << i << " addr in mem: " << hex; #if defined(__LP64__) cout << REINTERPRET_CAST(xed_uint64_t,section_text); #else cout << REINTERPRET_CAST(xed_uint32_t,section_text); #endif cout << dec << " len= " << sp->size << " at offset " << sp->offset << " runtime addr " << hex << runtime_vaddr << dec << endl; xed_disas_test(&decode_info.dstate, start, section_text, section_text + sp->size, decode_info.ninst, runtime_vaddr, decode_info.decode_only,0); } } } //////////////////////////////////////////////////////////////////////////// void process_macho64(xed_uint8_t* start, unsigned int length, xed_decode_file_info_t& decode_info) { xedex_derror("process_macho64 not done yet"); } void process_macho32(xed_uint8_t* start, unsigned int length, xed_decode_file_info_t& decode_info) { xed_uint8_t* current_position = start; //current_position is updated when each section is read // the fat header reader bumps current_position to the value for the // correct architecture. xed_uint32_t offset=0; // offset to of load commands for this architecture xed_uint32_t size; xed_uint_t i; xed_bool_t okay = read_fat_header(current_position, offset, size); if (!okay) { xedex_dwarn("Could not find x86 section of fat binary -- checking for mach header"); } if (CLIENT_VERBOSE2) printf("Offset of load sections = %x\n", offset); // skip to the correct architecture current_position += offset; struct mach_header* mh = REINTERPRET_CAST(struct mach_header*,current_position); if (mh->magic != MH_MAGIC) { xedex_derror("Could not find mach header"); } current_position += sizeof(struct mach_header); if (CLIENT_VERBOSE2) printf("Number of load command sections = %d\n", mh->ncmds); // load commands point to segments which contain sections. //xed_uint8_t* segment_position = current_position + mh->sizeofcmds; for( i=0;i< mh->ncmds; i++) { struct load_command* lc = REINTERPRET_CAST(struct load_command*,current_position); //current_position += sizeof(struct load_command); if (CLIENT_VERBOSE2) printf("load command %d\n",i ); if (lc->cmd == LC_SEGMENT) { if (CLIENT_VERBOSE2) printf("\tload command %d is a LC_SEGMENT\n", i); // we add the FAT offset to the start pointer to get to the relative start point. process_segment32( decode_info, start + offset, current_position, lc->cmdsize ); } current_position += lc->cmdsize; //segment_position = segment_position + lc->cmdsize; } } void xed_disas_macho(const char* input_file_name, const xed_state_t* dstate, int ninst, xed_bool_t sixty_four_bit, xed_bool_t decode_only) { xed_uint8_t* region = 0; void* vregion = 0; unsigned int len = 0; xed_map_region(input_file_name, &vregion, &len); region = REINTERPRET_CAST(xed_uint8_t*,vregion); xed_decode_file_info_t decode_info; xed_decode_file_info_init(&decode_info,dstate, ninst, decode_only); if (sixty_four_bit) { process_macho64(region, len, decode_info); } else { process_macho32(region, len, decode_info); } xed_print_decode_stats(); } #endif