//-------------------------------------------------------------------------- static void load_subspaces(linput_t *li, header &h, long fpos, int n) { if ( !n ) return; char buf[MAXSTR]; for ( int i=0; i < n; i++ ) { subspace_dictionary_record sr; qlseek(li, fpos + i*sizeof(sr)); lread(li, &sr, sizeof(sr)); sr.swap(); if ( !sr.is_loadable() || !sr.subspace_length ) continue; if ( sr.fixup_request_quantity ) complain_fixup(); ea_t start = sr.subspace_start; ea_t end = start + sr.initialization_length; file2base(li, sr.file_loc_init_value, start, end, FILEREG_PATCHABLE); end = start + sr.subspace_length; char *name = get_space_name(li, h, sr.name.n_strx, buf, sizeof(buf)); set_selector(i, 0); const char *sclass = strstr(name, "CODE") ? CLASS_CODE : CLASS_DATA; add_segm(i, start, end, name, sclass); if ( i == first_text_subspace_idx ) first_text_subspace_fpos = sr.file_loc_init_value; // sr.alignment, } }
//---------------------------------------------------------------------- // // loads a 512 byte trainer (located at file offset INES_HDR_SIZE) // to TRAINER_START_ADDRESS // static void load_trainer( linput_t *li ) { if( !INES_MASK_SRAM( hdr.rom_control_byte_0 ) ) { bool success = add_segm( 0, TRAINER_START_ADDRESS, TRAINER_START_ADDRESS + TRAINER_SIZE, "TRAINER", CLASS_CODE ) == 1; msg("creating TRAINER segment..%s", success ? "ok!\n" : "failure!\n"); set_segm_addressing( getseg( TRAINER_START_ADDRESS ), 0 ); } file2base(li, INES_HDR_SIZE, TRAINER_START_ADDRESS, TRAINER_START_ADDRESS + TRAINER_SIZE, FILEREG_PATCHABLE); }
//----------------------------------------------------------------------- static void read_text(linput_t *li) { text txt; const int size = offsetof(text, segment); lread(li, &txt, size); if ( txt.length != 0 ) { uint32 fptr = qltell(li); ea_t sea = getsea(txt.txt_IN); if ( sea != BADADDR ) { sea += txt.txt_offset; file2base(li, fptr, sea, sea+txt.length, FILEREG_PATCHABLE); } qlseek(li, fptr+txt.length); } }
//---------------------------------------------------------------------- // // load 8k prg rom bank into database // static void load_8k_prg_rom_bank( linput_t *li, uchar banknr, ea_t address ) { if( (banknr == 0) || (hdr.prg_page_count_16k == 0) ) return; // this is the file offset to begin reading pages from long offset = INES_HDR_SIZE + (INES_MASK_TRAINER(hdr.rom_control_byte_0) ? TRAINER_SIZE : 0) + (banknr - 1) * PRG_ROM_8K_BANK_SIZE; // load page from ROM file into segment msg("mapping 8k PRG-ROM page %02d to %08x-%08x (file offset %08x) ..", 1, address, address + PRG_ROM_8K_BANK_SIZE, offset); if( file2base(li, offset, address, address + PRG_ROM_8K_BANK_SIZE, FILEREG_PATCHABLE) == 1) msg("ok\n"); else msg("failure (corrupt ROM image?)\n"); }
//---------------------------------------------------------------------------- static bool map_psram(linput_t *li, uint32 psram_start_in_file) { bool succeeded = false; segment_t s; s.startEA = 0x00000; s.endEA = 0x10000; s.sel = allocate_selector(s.startEA >> 4); if ( !file2base(li, psram_start_in_file, s.startEA, s.endEA, FILEREG_PATCHABLE) ) loader_failure("Failed mapping 0x%x -> [0x%a, 0x%a)\n", psram_start_in_file, s.startEA, s.endEA); succeeded = add_segm(s.sel, s.startEA, s.endEA, "RAM", NULL); if ( succeeded ) succeeded = true; else loader_failure("Failed adding RAM segment\n"); return succeeded; }
//---------------------------------------------------------------------- // // load 8k chr rom bank into database // static void load_chr_rom_bank( linput_t *li, uchar banknr, ea_t address ) { // todo: add support for PPU // this function currently is disabled, since no // segment for the PPU is created msg("The loader was trying to load a CHR bank but the PPU is not supported yet.\n"); return; if( (banknr == 0) || (hdr.chr_page_count_8k == 0) ) return; // this is the file offset to begin reading pages from long offset = INES_HDR_SIZE + (INES_MASK_TRAINER(hdr.rom_control_byte_0) ? TRAINER_SIZE : 0) + PRG_PAGE_SIZE * hdr.prg_page_count_16k + (banknr - 1) * CHR_ROM_BANK_SIZE; // load page from ROM file into segment msg("mapping CHR-ROM page %02d to %08x-%08x (file offset %08x) ..", banknr, address, address + CHR_PAGE_SIZE, offset); if( file2base(li, offset, address, address + CHR_ROM_BANK_SIZE, FILEREG_PATCHABLE) == 1) msg("ok\n"); else msg("failure (corrupt ROM image?)\n"); }
/* * this is where we finally load the file and create segments and other processing */ void idaapi load_file(linput_t *li, ushort neflags, const char *fileformatname) { /* reset file position to 0 - accept_file changed it? */ qlseek(li, 0); /* add header structures */ add_types(); create_filename_cmt(); /* process header and create its own segment */ EFI_IMAGE_TE_HEADER teHeader = {0}; if (qlread(li, &teHeader, sizeof(EFI_IMAGE_TE_HEADER)) != sizeof(EFI_IMAGE_TE_HEADER)) { warning("Failed to read TE header\n"); return; } /* read the data to the database */ /* header starts at 0 */ ea_t delta = teHeader.StrippedSize - sizeof(EFI_IMAGE_TE_HEADER); ea_t header_start = teHeader.ImageBase - delta; /* header total size is the TE header plus all sections that follow */ ea_t header_end = teHeader.ImageBase - delta + sizeof(EFI_IMAGE_TE_HEADER) + teHeader.NumberOfSections * sizeof(EFI_IMAGE_SECTION_HEADER); #if 1 msg("Header start: 0x%llx\n", header_start); msg("Header end: 0x%llx\n", header_end); msg("Delta: 0x%llx\n", delta); #endif file2base(li, 0, header_start, header_end, 1); /* create the HEADER segment */ add_segm(0, header_start, header_end, "HEADER", "DATA"); /* set header structures */ doStruct(teHeader.ImageBase - delta, sizeof(EFI_IMAGE_TE_HEADER), efi_image_te_header_struct); for (uint8_t i = 0; i < teHeader.NumberOfSections; i++) { doStruct(teHeader.ImageBase - delta + sizeof(EFI_IMAGE_TE_HEADER) + i * sizeof(EFI_IMAGE_SECTION_HEADER), sizeof(EFI_IMAGE_SECTION_HEADER), efi_image_section_header_struct); } int headerPosition = sizeof(EFI_IMAGE_TE_HEADER); /* read sections */ for (uint8_t i = 0; i < teHeader.NumberOfSections; i++) { qlseek(li, headerPosition); EFI_IMAGE_SECTION_HEADER sectionHeader = {0}; qlread(li, §ionHeader, sizeof(EFI_IMAGE_SECTION_HEADER)); msg("Section name: %s\n", sectionHeader.Name); /* ok */ uint32_t position = sectionHeader.PointerToRawData - delta; msg("Position %x\n", position); qlseek(li, position); ea_t section_start = sectionHeader.VirtualAddress + teHeader.ImageBase - delta; ea_t section_end = 0; if (sectionHeader.Misc.VirtualSize > sectionHeader.SizeOfRawData) { section_end = sectionHeader.VirtualAddress + teHeader.ImageBase - delta + sectionHeader.Misc.VirtualSize; } else { section_end = sectionHeader.VirtualAddress + teHeader.ImageBase - delta + sectionHeader.SizeOfRawData; } msg("Section start: 0x%llx\n", section_start); msg("Section end: 0x%llx\n", section_end); file2base(li, position, section_start, section_end, 1); int bitness = -1; switch (teHeader.Machine) { case IMAGE_FILE_MACHINE_I386: bitness = 1; break; case IMAGE_FILE_MACHINE_X64: bitness = 2; break; default: bitness = 0; } const char *classType; if (qstrcmp((const char*)sectionHeader.Name, ".text") == 0) { classType = "CODE"; } else { classType = "DATA"; } add_segm(0, section_start, section_end, (const char*)sectionHeader.Name, classType); set_segm_addressing(get_segm_by_name((const char *)sectionHeader.Name), bitness); /* try to find the GUIDs in data section */ if (qstrcmp((const char *)sectionHeader.Name, ".data") == 0) { find_guids(section_start, section_end); } /* advance to next section */ headerPosition += sizeof(EFI_IMAGE_SECTION_HEADER); } /* configure the entrypoint address */ add_entry(teHeader.AddressOfEntryPoint + teHeader.ImageBase - delta, teHeader.AddressOfEntryPoint + teHeader.ImageBase - delta, "_start", 1); /* all done */ }
//----------------------------------------------------------------------------- // process a file record according to its "record_type". // return true if there is no more records to process. static bool process_record(linput_t *li, const uchar record_type, bool load) { bool finished = false; switch (record_type) { // A record with a header byte of $81 is a record that may contain code or // data from arbitrary segments. // // header : 1 byte // segment : 1 byte // gran : 1 byte // start_addr : 4 bytes (entry point) // length : 2 bytes // data : length bytes case 0x81: { mas_header_t header; memset(&header, 0, sizeof header); // read the header if (qlread(li, &header, sizeof header) != sizeof header) mas_error("unable to read header (%d bytes)", sizeof header); // granularities that differ from 1 are rare and mostly appear // in DSP CPU's that are not designed for byte processing. if (header.gran != 1) mas_error("unsupported granularity (%d)", header.gran); // set processor if (!mas_set_cpu(header.header)) mas_error("processor type '0x%X' is currently unsupported", header.header); if (!load) // we have the processor, nothing else to do { finished = true; break; } // get segment name const char *segname = mas_get_segname(header.segment); if (segname == NULL) mas_error("invalid segment '0x%X'", header.segment); #if defined(DEBUG) msg("MAS: ready to read %d bytes (0x%X -> 0x%X)\n", header.length, header.start_addr, header.start_addr + header.length); #endif // send code in the database file2base(li, qltell(li), header.start_addr, header.start_addr + header.length, FILEREG_PATCHABLE); // set selector sel_t selector = allocate_selector(0); // create segment add_segm(selector, header.start_addr, header.start_addr + header.length, segname, segname); } break; // The last record in a file bears the Header $00 and has only a string as // data field. This string does not have an explicit length specification; // its end is equal to the file's end. // // The string contains only the name of the program that created the file // and has no further meaning. // // creator : x bytes case 0x00: { ulong length = qlsize(li) - qltell(li); #if defined(DEBUG) msg("MAS: creator length : %ld bytes\n", length); #endif if (length >= sizeof creator) mas_error("creator length is too large (%ld >= %ld", length, sizeof creator); int tmp; if ((tmp = qlread(li, creator, length)) != length) mas_error("unable to read creator string (i read %d)", tmp); creator[tmp] = '\0'; } finished = true; break; // entry_point : 4 bytes case 0x80: { if (qlread(li, &entry_point, 4) != 4) mas_error("unable to read entry_point"); if (load) { #if defined(DEBUG) msg("MAS: detected entry point : 0x%X\n", entry_point); #endif inf.startIP = entry_point; // entry point segment_t *s = getseg(entry_point); inf.start_cs = s ? s->sel : 0; // selector of code } } break; default: // start_addr : 4 bytes // length : 2 bytes // data : length bytes if (record_type >= 0x01 && record_type <= 0x7F) { struct header { int start_addr; short length; } header; memset(&header, 0, sizeof header); // read the header if (qlread(li, &header, sizeof header) != sizeof header) mas_error("unable to read header (%d bytes)", sizeof header); if (load) { // send code in the database file2base(li, qltell(li), header.start_addr, header.start_addr + header.length, FILEREG_PATCHABLE); #if defined(DEBUG) msg("MAS: i've read %d DATA bytes (0x%X -> 0x%X)\n", header.length, header.start_addr, header.start_addr + header.length); #endif // set selector sel_t selector = allocate_selector(0); // create data segment add_segm(selector, header.start_addr, header.start_addr + header.length, "DATA", "DATA"); } else qlseek(li, qltell(li)+header.length); } else mas_error("invalid record type '0x%X'\n", record_type); } return finished; }
//-------------------------------------------------------------------------- // // load file into the database. // void idaapi load_file(linput_t *li, ushort /*neflag*/, const char * /*fileformatname*/) { // int i; aif_header_t hd; if ( ph.id != PLFM_ARM ) set_processor_type("arm", SETPROC_ALL|SETPROC_FATAL); lread(li,&hd,sizeof(hd)); mf = uchar(match_zero_code(hd) - 1); if ( (hd.address_mode & 0xFF) != 32 ) { if ( (hd.address_mode & 0xFF) != 0 ) loader_failure("26-bit modules are not supported"); msg("Old AIF format file..."); } if ( hd.decompress_code != NOP ) loader_failure("Compressed modules are not supported"); if ( hd.self_reloc_code != NOP ) loader_failure("Self-relocating modules are not supported"); inf.baseaddr = 0; int isexec = is_bl(hd.entry_point); uint32 offset = sizeof(aif_header_t); uint32 start = hd.image_base; if ( isexec ) { start += sizeof(aif_header_t); hd.readonly_size -= sizeof(aif_header_t); } uint32 end = start + hd.readonly_size; file2base(li, offset, start, end, FILEREG_PATCHABLE); offset += hd.readonly_size; create_section(1, start, end, NAME_CODE, CLASS_CODE); if ( hd.readwrite_size != 0 ) { start = (hd.address_mode & AIF_SEP_DATA) ? hd.data_base : end; end = start + hd.readwrite_size; file2base(li, offset, start, end, FILEREG_PATCHABLE); offset += hd.readwrite_size; create_section(2, start, end, NAME_DATA, CLASS_DATA); } if ( hd.zero_init_size != 0 ) { start = end; end = start + hd.zero_init_size; create_section(3, start, end, NAME_BSS, CLASS_BSS); } create_filename_cmt(); if ( isexec ) hd.entry_point = hd.image_base + offsetof(aif_header_t,entry_point) + ((hd.entry_point & ~BLMASK) << 2) + 8; inf.start_cs = 1; inf.startIP = hd.entry_point; inf.beginEA = hd.entry_point; if ( hd.debug_size != 0 ) { msg("Debugging information is present (%u bytes at file offset 0x%X)...\n", hd.debug_size, offset); uchar *di = qalloc_array<uchar>(size_t(hd.debug_size)); if ( di == NULL ) nomem("AIF debugging info"); qlseek(li,offset); lread(li, di, size_t(hd.debug_size)); uchar *ptr = di; uchar *end = di + size_t(hd.debug_size); section_t *sect = NULL; while ( ptr < end ) { size_t len = process_item(ptr, end-ptr, sect); if ( len == 0 ) { warning("Corrupted debug info."); break; } ptr += len; } qfree(di); } }