// ****************************************************************** // * constructor // ****************************************************************** EmuExe::EmuExe(Xbe *x_Xbe, DebugMode x_debug_mode, char *x_debug_filename, HWND hwndParent) : Exe() { ConstructorInit(); printf("EmuExe::EmuExe: Generating Exe file...\n"); // ****************************************************************** // * generate pe header // ****************************************************************** { printf("EmuExe::EmuExe: Generating PE header..."); m_Header.m_magic = *(uint32 *)"PE\0\0"; // magic number : "PE\0\0" m_Header.m_machine = IMAGE_FILE_MACHINE_I386; // machine type : i386 m_Header.m_sections = (uint16)(x_Xbe->m_Header.dwSections + 2); // xbe sections + .cxbximp + .cxbxplg m_Header.m_timedate = x_Xbe->m_Header.dwTimeDate; // time/date stamp m_Header.m_symbol_table_addr = 0; // unused m_Header.m_symbols = 0; // unused m_Header.m_sizeof_optional_header = sizeof(OptionalHeader); // size of optional header m_Header.m_characteristics = 0x010F; // should be fine.. printf("OK\n"); } // ****************************************************************** // * generate optional header // ****************************************************************** { printf("EmuExe::EmuExe: Generating Optional Header..."); m_OptionalHeader.m_magic = 0x010B; // magic number : 0x010B // ****************************************************************** // * abitrary linker version : 6.0 // ****************************************************************** m_OptionalHeader.m_linker_version_major = 0x06; m_OptionalHeader.m_linker_version_minor = 0x00; // ****************************************************************** // * size of headers // ****************************************************************** m_OptionalHeader.m_sizeof_headers = sizeof(bzDOSStub) + sizeof(m_Header); m_OptionalHeader.m_sizeof_headers += sizeof(m_OptionalHeader) + sizeof(*m_SectionHeader)*m_Header.m_sections; m_OptionalHeader.m_sizeof_headers = RoundUp(m_OptionalHeader.m_sizeof_headers, PE_FILE_ALIGN); m_OptionalHeader.m_image_base = x_Xbe->m_Header.dwBaseAddr; m_OptionalHeader.m_section_alignment = PE_SEGM_ALIGN; m_OptionalHeader.m_file_alignment = PE_FILE_ALIGN; // ****************************************************************** // * OS version : 4.0 // ****************************************************************** m_OptionalHeader.m_os_version_major = 0x0004; m_OptionalHeader.m_os_version_minor = 0x0000; // ****************************************************************** // * image version : 0.0 // ****************************************************************** m_OptionalHeader.m_image_version_major = 0x0000; m_OptionalHeader.m_image_version_minor = 0x0000; // ****************************************************************** // * subsystem version : 4.0 // ****************************************************************** m_OptionalHeader.m_subsystem_version_major = 0x0004; m_OptionalHeader.m_subsystem_version_minor = 0x0000; m_OptionalHeader.m_win32_version = 0x00000000; m_OptionalHeader.m_checksum = 0x00000000; m_OptionalHeader.m_subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI; // ****************************************************************** // * no special dll characteristics are necessary // ****************************************************************** m_OptionalHeader.m_dll_characteristics = 0x0000; // ****************************************************************** // * TODO: for each of these, check for bad values and correct them // ****************************************************************** m_OptionalHeader.m_sizeof_stack_reserve = 0x00100000; m_OptionalHeader.m_sizeof_stack_commit = x_Xbe->m_Header.dwPeStackCommit; m_OptionalHeader.m_sizeof_heap_reserve = x_Xbe->m_Header.dwPeHeapReserve; m_OptionalHeader.m_sizeof_heap_commit = x_Xbe->m_Header.dwPeHeapCommit; // ****************************************************************** // * this member is obsolete, so we'll just set it to zero // ****************************************************************** m_OptionalHeader.m_loader_flags = 0x00000000; // ****************************************************************** // * we'll set this to the typical 0x10 (16) // ****************************************************************** m_OptionalHeader.m_data_directories = 0x10; // ****************************************************************** // * clear all data directories (we'll setup some later) // ****************************************************************** for(uint32 d=0;d<m_OptionalHeader.m_data_directories;d++) { m_OptionalHeader.m_image_data_directory[d].m_virtual_addr = 0; m_OptionalHeader.m_image_data_directory[d].m_size = 0; } printf("OK\n"); } // ****************************************************************** // * generate section headers // ****************************************************************** { printf("EmuExe::EmuExe: Generating Section Headers...\n"); m_SectionHeader = new SectionHeader[m_Header.m_sections]; // ****************************************************************** // * start appending section headers at this point // ****************************************************************** uint32 dwSectionCursor = x_Xbe->m_SectionHeader[0].dwRawAddr; // ****************************************************************** // * generate xbe section headers // ****************************************************************** { for(uint32 v=0;v<x_Xbe->m_Header.dwSections;v++) { printf("EmuExe::EmuExe: Generating Section Header 0x%.04X...", v); // ****************************************************************** // * generate xbe section name // ****************************************************************** { memset(m_SectionHeader[v].m_name, 0, 8); for(int c=0;c<8;c++) { m_SectionHeader[v].m_name[c] = x_Xbe->m_szSectionName[v][c]; if(m_SectionHeader[v].m_name[c] == '\0') break; } } // ****************************************************************** // * generate xbe section virtual size / addr // ****************************************************************** { uint32 VirtSize = x_Xbe->m_SectionHeader[v].dwVirtualSize; uint32 VirtAddr = x_Xbe->m_SectionHeader[v].dwVirtualAddr - x_Xbe->m_Header.dwBaseAddr; m_SectionHeader[v].m_virtual_size = VirtSize; m_SectionHeader[v].m_virtual_addr = VirtAddr; } // ****************************************************************** // * generate xbe section raw size / addr // ****************************************************************** { // TODO: get this working such that m_sizeof_raw can be the actual raw size, not virtual size uint32 RawSize = RoundUp(x_Xbe->m_SectionHeader[v].dwVirtualSize, PE_FILE_ALIGN); uint32 RawAddr = dwSectionCursor; m_SectionHeader[v].m_sizeof_raw = RawSize; m_SectionHeader[v].m_raw_addr = RawAddr; dwSectionCursor += RawSize; } // ****************************************************************** // * relocation / line numbers will not exist // ****************************************************************** { m_SectionHeader[v].m_relocations_addr = 0; m_SectionHeader[v].m_linenumbers_addr = 0; m_SectionHeader[v].m_relocations = 0; m_SectionHeader[v].m_linenumbers = 0; } // ****************************************************************** // * generate flags for this xbe section // ****************************************************************** { uint32 flags = IMAGE_SCN_MEM_READ; if(x_Xbe->m_SectionHeader[v].dwFlags.bExecutable) { flags |= IMAGE_SCN_MEM_EXECUTE; flags |= IMAGE_SCN_CNT_CODE; } else { flags |= IMAGE_SCN_CNT_INITIALIZED_DATA; } if(x_Xbe->m_SectionHeader[v].dwFlags.bWritable) flags |= IMAGE_SCN_MEM_WRITE; m_SectionHeader[v].m_characteristics = flags; } printf("OK\n"); } } // ****************************************************************** // * generate .cxbximp section header // ****************************************************************** { uint32 i = m_Header.m_sections - 2; printf("EmuExe::EmuExe: Generating Section Header 0x%.04X (.cxbximp)...", i); memcpy(m_SectionHeader[i].m_name, ".cxbximp", 8); // ****************************************************************** // * generate .cxbximp section virtual size / addr // ****************************************************************** { uint32 virt_size = RoundUp(0x6E, PE_SEGM_ALIGN); uint32 virt_addr = RoundUp(m_SectionHeader[i-1].m_virtual_addr + m_SectionHeader[i-1].m_virtual_size, PE_SEGM_ALIGN); m_SectionHeader[i].m_virtual_size = virt_size; m_SectionHeader[i].m_virtual_addr = virt_addr; } // ****************************************************************** // * generate .cxbximp section raw size / addr // ****************************************************************** { uint32 raw_size = RoundUp(m_SectionHeader[i].m_virtual_size, PE_FILE_ALIGN); m_SectionHeader[i].m_sizeof_raw = raw_size; m_SectionHeader[i].m_raw_addr = dwSectionCursor; dwSectionCursor += raw_size; } // ****************************************************************** // * relocation / line numbers will not exist // ****************************************************************** { m_SectionHeader[i].m_relocations_addr = 0; m_SectionHeader[i].m_linenumbers_addr = 0; m_SectionHeader[i].m_relocations = 0; m_SectionHeader[i].m_linenumbers = 0; } // ****************************************************************** // * make this section readable initialized data // ****************************************************************** m_SectionHeader[i].m_characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA; // ****************************************************************** // * update import table directory entry // ****************************************************************** m_OptionalHeader.m_image_data_directory[IMAGE_DIRECTORY_ENTRY_IMPORT].m_virtual_addr = m_SectionHeader[i].m_virtual_addr + 0x08; m_OptionalHeader.m_image_data_directory[IMAGE_DIRECTORY_ENTRY_IMPORT].m_size = 0x28; // ****************************************************************** // * update import address table directory entry // ****************************************************************** m_OptionalHeader.m_image_data_directory[IMAGE_DIRECTORY_ENTRY_IAT].m_virtual_addr = m_SectionHeader[i].m_virtual_addr; m_OptionalHeader.m_image_data_directory[IMAGE_DIRECTORY_ENTRY_IAT].m_size = 0x08; printf("OK\n"); } // ****************************************************************** // * generate .cxbxplg section header // ****************************************************************** { uint32 i = m_Header.m_sections - 1; printf("EmuExe::EmuExe: Generating Section Header 0x%.04X (.cxbxplg)...", i); memcpy(m_SectionHeader[i].m_name, ".cxbxplg", 8); // ****************************************************************** // * generate .cxbxplg section virtual size / addr // ****************************************************************** { uint32 virt_size = RoundUp(m_OptionalHeader.m_image_base + 0x100 + x_Xbe->m_Header.dwSizeofHeaders + 260 + sizeof(Xbe::LibraryVersion) * x_Xbe->m_Header.dwLibraryVersions + sizeof(Xbe::TLS) + (x_Xbe->m_TLS->dwDataEndAddr - x_Xbe->m_TLS->dwDataStartAddr), 0x1000); uint32 virt_addr = RoundUp(m_SectionHeader[i-1].m_virtual_addr + m_SectionHeader[i-1].m_virtual_size, PE_SEGM_ALIGN); m_SectionHeader[i].m_virtual_size = virt_size; m_SectionHeader[i].m_virtual_addr = virt_addr; // our entry point should be the first bytes in this section m_OptionalHeader.m_entry = virt_addr; } // ****************************************************************** // * generate .cxbxplg section raw size / addr // ****************************************************************** { uint32 raw_size = RoundUp(m_SectionHeader[i].m_virtual_size, PE_FILE_ALIGN); m_SectionHeader[i].m_sizeof_raw = raw_size; m_SectionHeader[i].m_raw_addr = dwSectionCursor; dwSectionCursor += raw_size; } // ****************************************************************** // * relocation / line numbers will not exist // ****************************************************************** { m_SectionHeader[i].m_relocations_addr = 0; m_SectionHeader[i].m_linenumbers_addr = 0; m_SectionHeader[i].m_relocations = 0; m_SectionHeader[i].m_linenumbers = 0; } // ****************************************************************** // * make this section readable and executable // ****************************************************************** m_SectionHeader[i].m_characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_CNT_CODE; printf("OK\n"); } } // ****************************************************************** // * generate sections // ****************************************************************** { printf("EmuExe::EmuExe: Generating Sections...\n"); m_bzSection = new uint08*[m_Header.m_sections]; // ****************************************************************** // * generate xbe sections // ****************************************************************** { uint32 kt = x_Xbe->m_Header.dwKernelImageThunkAddr; // ****************************************************************** // * decode kernel thunk address // ****************************************************************** { if((kt ^ XOR_KT_DEBUG) > 0x01000000) kt ^= XOR_KT_RETAIL; else kt ^= XOR_KT_DEBUG; } // ****************************************************************** // * generate xbe sections // ****************************************************************** for(uint32 v=0;v<x_Xbe->m_Header.dwSections;v++) { printf("EmuExe::EmuExe: Generating Section 0x%.04X...", v); uint32 SectionSize = m_SectionHeader[v].m_sizeof_raw; m_bzSection[v] = new uint08[SectionSize]; memset(m_bzSection[v], 0, SectionSize); memcpy(m_bzSection[v], x_Xbe->m_bzSection[v], x_Xbe->m_SectionHeader[v].dwSizeofRaw); printf("OK\n"); } } // ****************************************************************** // * generate .cxbximp section // ****************************************************************** { uint32 i = m_Header.m_sections - 2; printf("EmuExe::EmuExe: Generating Section 0x%.04X (.cxbximp)...", i); uint32 dwVirtAddr = m_SectionHeader[i].m_virtual_addr; uint32 dwRawSize = m_SectionHeader[i].m_sizeof_raw; m_bzSection[i] = new uint08[dwRawSize]; memset(m_bzSection[i], 0, dwRawSize); *(uint32*)&m_bzSection[i][0x00] = dwVirtAddr + 0x38; *(uint32*)&m_bzSection[i][0x04] = 0; *(uint32*)&m_bzSection[i][0x08] = dwVirtAddr + 0x30; *(uint32*)&m_bzSection[i][0x0C] = 0; *(uint32*)&m_bzSection[i][0x10] = 0; *(uint32*)&m_bzSection[i][0x14] = dwVirtAddr + 0x4A; *(uint32*)&m_bzSection[i][0x18] = dwVirtAddr + 0x00; *(uint32*)&m_bzSection[i][0x1C] = 0; *(uint32*)&m_bzSection[i][0x20] = 0; *(uint32*)&m_bzSection[i][0x24] = 0; *(uint32*)&m_bzSection[i][0x28] = 0; *(uint32*)&m_bzSection[i][0x2C] = 0; *(uint32*)&m_bzSection[i][0x30] = dwVirtAddr + 0x38; *(uint32*)&m_bzSection[i][0x34] = 0; *(uint16*)&m_bzSection[i][0x38] = 0x0001; #ifdef _DEBUG memcpy(&m_bzSection[i][0x3A], "CxbxKrnlNoFunc\0\0CxbxKrnl.dll\0\0", 30); #else memcpy(&m_bzSection[i][0x3A], "CxbxKrnlNoFunc\0\0Cxbx.dll\0\0\0\0\0\0", 30); #endif printf("OK\n"); } // ****************************************************************** // * generate .cxbxplg section // ****************************************************************** { uint32 ep = x_Xbe->m_Header.dwEntryAddr; uint32 i = m_Header.m_sections - 1; printf("EmuExe::EmuExe: Generating Section 0x%.04X (.cxbxplg)...", i); // ****************************************************************** // * decode entry point // ****************************************************************** if( (ep ^ XOR_EP_RETAIL) > 0x01000000) ep ^= XOR_EP_DEBUG; else ep ^= XOR_EP_RETAIL; m_bzSection[i] = new uint08[m_SectionHeader[i].m_sizeof_raw]; uint08 *pWriteCursor = m_bzSection[i]; // ****************************************************************** // * append prolog section // ****************************************************************** memcpy(pWriteCursor, Prolog, 0x1000); pWriteCursor += 0x100; // ****************************************************************** // * append xbe header // ****************************************************************** memcpy(pWriteCursor, &x_Xbe->m_Header, sizeof(Xbe::Header)); pWriteCursor += sizeof(Xbe::Header); // ****************************************************************** // * append xbe extra header bytes // ****************************************************************** memcpy(pWriteCursor, x_Xbe->m_HeaderEx, x_Xbe->m_Header.dwSizeofHeaders - sizeof(Xbe::Header)); pWriteCursor -= sizeof(Xbe::Header); pWriteCursor += x_Xbe->m_Header.dwSizeofHeaders; // ****************************************************************** // * append x_debug_filename // ****************************************************************** memcpy(pWriteCursor, x_debug_filename, 260); pWriteCursor += 260; // ****************************************************************** // * append library versions // ****************************************************************** if(x_Xbe->m_LibraryVersion != 0) { memcpy(pWriteCursor, x_Xbe->m_LibraryVersion, sizeof(Xbe::LibraryVersion) * x_Xbe->m_Header.dwLibraryVersions); pWriteCursor += sizeof(Xbe::LibraryVersion) * x_Xbe->m_Header.dwLibraryVersions; } // ****************************************************************** // * append TLS data // ****************************************************************** if(x_Xbe->m_TLS != 0) { memcpy(pWriteCursor, x_Xbe->m_TLS, sizeof(Xbe::TLS)); pWriteCursor += sizeof(Xbe::TLS); memcpy(pWriteCursor, x_Xbe->GetTLSData(), x_Xbe->m_TLS->dwDataEndAddr - x_Xbe->m_TLS->dwDataStartAddr); pWriteCursor += x_Xbe->m_TLS->dwDataEndAddr - x_Xbe->m_TLS->dwDataStartAddr; } // ****************************************************************** // * patch prolog function parameters // ****************************************************************** uint32 WriteCursor = m_SectionHeader[i].m_virtual_addr + m_OptionalHeader.m_image_base + 0x100; // Function Pointer *(uint32 *)((uint32)m_bzSection[i] + 1) = (uint32)CxbxKrnlInit; // Param 8 : Entry *(uint32 *)((uint32)m_bzSection[i] + 6) = (uint32)ep; // Param 7 : dwXbeHeaderSize *(uint32 *)((uint32)m_bzSection[i] + 11) = (uint32)x_Xbe->m_Header.dwSizeofHeaders; // Param 6 : pXbeHeader *(uint32 *)((uint32)m_bzSection[i] + 16) = WriteCursor; WriteCursor += x_Xbe->m_Header.dwSizeofHeaders; // Param 5 : szDebugFilename *(uint32 *)((uint32)m_bzSection[i] + 21) = WriteCursor; WriteCursor += 260; // Param 4 : DbgMode *(uint32 *)((uint32)m_bzSection[i] + 26) = x_debug_mode; // Param 3 : pLibraryVersion if(x_Xbe->m_LibraryVersion != 0) { *(uint32 *)((uint32)m_bzSection[i] + 31) = WriteCursor; WriteCursor += sizeof(Xbe::LibraryVersion) * x_Xbe->m_Header.dwLibraryVersions; } else { *(uint32 *)((uint32)m_bzSection[i] + 31) = 0; } // Param 2 : pTLS if(x_Xbe->m_TLS != 0) { *(uint32 *)((uint32)m_bzSection[i] + 36) = WriteCursor; WriteCursor += sizeof(Xbe::TLS); } else { *(uint32 *)((uint32)m_bzSection[i] + 36) = 0; } // Param 1 : pTLSData if(x_Xbe->m_TLS != 0) { *(uint32 *)((uint32)m_bzSection[i] + 41) = WriteCursor; WriteCursor += x_Xbe->m_TLS->dwDataEndAddr - x_Xbe->m_TLS->dwDataStartAddr; } else { *(uint32 *)((uint32)m_bzSection[i] + 41) = 0; } // Param 0 : hwndParent *(uint32 *)((uint32)m_bzSection[i] + 46) = (uint32)hwndParent; printf("OK\n"); } } // ****************************************************************** // * patch kernel thunk table // ****************************************************************** { printf("EmuExe::EmuExe: Hijacking Kernel Imports...\n"); uint32 kt = x_Xbe->m_Header.dwKernelImageThunkAddr; // ****************************************************************** // * decode kernel thunk address // ****************************************************************** { if( (kt ^ XOR_KT_DEBUG) > 0x01000000) kt ^= XOR_KT_RETAIL; else kt ^= XOR_KT_DEBUG; } // ****************************************************************** // * locate section containing kernel thunk table // ****************************************************************** for(uint32 v=0;v<x_Xbe->m_Header.dwSections;v++) { uint32 imag_base = m_OptionalHeader.m_image_base; uint32 virt_addr = m_SectionHeader[v].m_virtual_addr; uint32 virt_size = m_SectionHeader[v].m_virtual_size; // ****************************************************************** // * modify kernel thunk table, if found // ****************************************************************** if(kt >= virt_addr + imag_base && kt < virt_addr + virt_size + imag_base) { printf("EmuExe::EmuExe: Located Thunk Table in Section 0x%.04X (0x%.08X)...\n", v, kt); uint32 *kt_tbl = (uint32*)&m_bzSection[v][kt - virt_addr - imag_base]; for(int k=0;kt_tbl[k] != 0;k++) { int t = kt_tbl[k] & 0x7FFFFFFF; kt_tbl[k] = CxbxKrnl_KernelThunkTable[t]; if(t != -1) printf("EmuExe::EmuExe: Thunk %.03d : *0x%.08X := 0x%.08X\n", t, kt + k*4, kt_tbl[k]); } break; } } } // ****************************************************************** // * update imcomplete header fields // ****************************************************************** { printf("EmuExe::EmuExe: Finalizing Exe file..."); // ****************************************************************** // * calculate size of code / data / image // ****************************************************************** { uint32 sizeof_code = 0; uint32 sizeof_data = 0; uint32 sizeof_undata = 0; uint32 sizeof_image = 0; for(uint32 v=0;v<m_Header.m_sections;v++) { uint32 characteristics = m_SectionHeader[v].m_characteristics; if( (characteristics & IMAGE_SCN_MEM_EXECUTE) || (characteristics & IMAGE_SCN_CNT_CODE) ) { sizeof_code += m_SectionHeader[v].m_sizeof_raw; } else if( (characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) ) { sizeof_data += m_SectionHeader[v].m_sizeof_raw; } else if( (characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) ) { sizeof_data += m_SectionHeader[v].m_sizeof_raw; } } // ****************************************************************** // * calculate size of image (INCORRECT!) // ****************************************************************** sizeof_image = sizeof_undata + sizeof_data + sizeof_code + m_OptionalHeader.m_sizeof_headers; sizeof_image = RoundUp(sizeof_image, PE_SEGM_ALIGN); // ****************************************************************** // * update optional header as necessary // ****************************************************************** m_OptionalHeader.m_sizeof_code = sizeof_code; m_OptionalHeader.m_sizeof_initialized_data = sizeof_data; m_OptionalHeader.m_sizeof_uninitialized_data = sizeof_undata; m_OptionalHeader.m_sizeof_image = sizeof_image; } // ****************************************************************** // * we'll set code base as the virtual address of the first section // ****************************************************************** m_OptionalHeader.m_code_base = m_SectionHeader[0].m_virtual_addr; // ****************************************************************** // * we'll set data base as the virtual address of the first section // * that is not marked as containing code or being executable // ****************************************************************** for(uint32 v=0;v<m_Header.m_sections;v++) { uint32 characteristics = m_SectionHeader[v].m_characteristics; if( !(characteristics & IMAGE_SCN_MEM_EXECUTE) || !(characteristics & IMAGE_SCN_CNT_CODE) ) { m_OptionalHeader.m_data_base = m_SectionHeader[v].m_virtual_addr; break; } } printf("OK\n"); } }
// construct via Exe file Exe::Exe(const char *x_szFilename) { ConstructorInit(); std::cout << std::setfill('0') << std::hex; std::cout << "Exe::Exe: Opening Exe file..."; FILE *ExeFile = fopen(x_szFilename, "rb"); // verify Exe file was opened if(ExeFile == 0) { SetError("Could not open Exe file.", true); return; } std::cout << "OK\n"; // ignore dos stub (if exists) { std::cout << "Exe::Exe: Reading DOS stub..."; if(fread(&m_DOSHeader.m_magic, sizeof(m_DOSHeader.m_magic), 1, ExeFile) != 1) { SetError("Unexpected read error while reading magic number", true); goto cleanup; } if(m_DOSHeader.m_magic == *reinterpret_cast<const uint16_t*>("MZ")) { std::cout << "Found, Ignoring..."; if(fread(&m_DOSHeader.m_cblp, sizeof(m_DOSHeader)-2, 1, ExeFile) != 1) { SetError("Unexpected read error while reading DOS stub", true); goto cleanup; } fseek(ExeFile, m_DOSHeader.m_lfanew, SEEK_SET); std::cout << "OK\n"; } else { std::cout << "None (OK)\n"; } } // read PE header { std::cout << "Exe::Exe: Reading PE header..."; if(fread(&m_Header, sizeof(m_Header), 1, ExeFile) != 1) { SetError("Unexpected read error while reading PE header", true); goto cleanup; } if(m_Header.m_magic != *reinterpret_cast<const uint32_t*>("PE\0\0")) { SetError("Invalid file (could not locate PE header)", true); goto cleanup; } std::cout << "OK\n"; } // read optional header { std::cout << "Exe::Exe: Reading Optional Header..."; if(fread(&m_OptionalHeader, sizeof(m_OptionalHeader), 1, ExeFile) != 1) { SetError("Unexpected read error while reading PE optional header", true); goto cleanup; } if(m_OptionalHeader.m_magic != 0x010B) { SetError("Invalid file (could not locate PE optional header)", true); goto cleanup; } std::cout << "OK\n"; } // read section headers { m_SectionHeader = new SectionHeader[m_Header.m_sections]; std::cout << "Exe::Exe: Reading Section Headers...\n"; for(uint32_t v=0;v<m_Header.m_sections;v++) { std::cout << "Exe::Exe: Reading Section Header 0x" << std::setw(4) << v << "..."; if(fread(&m_SectionHeader[v], sizeof(SectionHeader), 1, ExeFile) != 1) { char buffer[255]; sprintf(buffer, "Could not read PE section header %d (%Xh)", v, v); SetError(buffer, true); goto cleanup; } std::cout << "OK\n"; } } // read sections { std::cout << "Exe::Exe: Reading Sections...\n"; m_bzSection = new uint8_t*[m_Header.m_sections]; for(uint32_t v=0;v<m_Header.m_sections;v++) { std::cout << "Exe::Exe: Reading Section 0x" << std::setw(4) << v << "..."; uint32_t raw_size = m_SectionHeader[v].m_sizeof_raw; uint32_t raw_addr = m_SectionHeader[v].m_raw_addr; m_bzSection[v] = new uint8_t[raw_size]; memset(m_bzSection[v], 0, raw_size); if(raw_size == 0) { std::cout << "OK\n"; continue; } // read current section from file (if raw_size > 0) { fseek(ExeFile, raw_addr, SEEK_SET); if(fread(m_bzSection[v], raw_size, 1, ExeFile) != 1) { char buffer[255]; sprintf(buffer, "Could not read PE section %d (%Xh)", v, v); SetError(buffer, true); goto cleanup; } } std::cout << "OK\n"; } } std::cout << "Exe::Exe: Exe was successfully opened.\n"; cleanup: if(GetError() != 0) { std::cout << "FAILED!\n"; std::cout << "Exe::Exe: ERROR -> " << GetError() << "\n"; } fclose(ExeFile); }
// construct via Xbe file Xbe::Xbe(const char *x_szFilename) { char szBuffer[260]; ConstructorInit(); std::cout << "Xbe::Xbe: Opening Xbe file..."; FILE *XbeFile = fopen(x_szFilename, "rb"); // verify Xbe file was opened successfully if(XbeFile == 0) { SetError("Could not open Xbe file.", true); return; } std::cout << "OK\n"; // remember the Xbe path { std::cout << "Xbe::Xbe: Storing Xbe Path..."; strcpy(m_szPath, x_szFilename); int v=0, c=0; while(m_szPath[v] != '\0') { if(m_szPath[v] == '\\') c = v+1; v++; } m_szPath[c] = '\0'; } std::cout << "OK\n"; // read Xbe image header { std::cout << "Xbe::Xbe: Reading Image Header..."; if(fread(&m_Header, sizeof(m_Header), 1, XbeFile) != 1) { SetError("Unexpected end of file while reading Xbe Image Header", true); goto cleanup; } if(m_Header.dwMagic != *reinterpret_cast<const uint32_t*>("XBEH")) { SetError("Invalid magic number in Xbe file", true); goto cleanup; } std::cout << "OK\n"; } // read Xbe image header extra bytes if(m_Header.dwSizeofHeaders > sizeof(m_Header)) { std::cout << "Xbe::Xbe: Reading Image Header Extra Bytes..."; uint32_t ExSize = RoundUp(m_Header.dwSizeofHeaders, 0x1000) - static_cast<uint32_t>(sizeof(m_Header)); m_HeaderEx = new char[ExSize]; if(fread(m_HeaderEx, ExSize, 1, XbeFile) != 1) { SetError("Unexpected end of file while reading Xbe Image Header (Ex)", true); goto cleanup; } std::cout << "OK\n"; } // read Xbe certificate { std::cout << "Xbe::Xbe: Reading Certificate..."; fseek(XbeFile, m_Header.dwCertificateAddr - m_Header.dwBaseAddr, SEEK_SET); if(fread(&m_Certificate, sizeof(m_Certificate), 1, XbeFile) != 1) { SetError("Unexpected end of file while reading Xbe Certificate", true); goto cleanup; } setlocale( LC_ALL, "English" ); //wcstombs(m_szAsciiTitle, m_Certificate.wszTitleName, 40); for (int i=0; i<40 && m_Certificate.wszTitleName[i] != 0; i++) m_szAsciiTitle[i] = static_cast<uint8_t>(m_Certificate.wszTitleName[i]); std::cout << "OK\n"; std::cout << "Xbe::Xbe: Title identified as " << m_szAsciiTitle << "\n"; } // read Xbe section headers { std::cout << "Xbe::Xbe: Reading Section Headers...\n"; fseek(XbeFile, m_Header.dwSectionHeadersAddr - m_Header.dwBaseAddr, SEEK_SET); m_SectionHeader = new SectionHeader[m_Header.dwSections]; for(uint32_t v=0;v<m_Header.dwSections;v++) { std::cout << "Xbe::Xbe: Reading Section Header 0x" << std::setfill('0') << std::hex << std::setw(4) << v << "..."; if(fread(&m_SectionHeader[v], sizeof(*m_SectionHeader), 1, XbeFile) != 1) { sprintf(szBuffer, "Unexpected end of file while reading Xbe Section Header %d (%Xh)", v, v); SetError(szBuffer, true); goto cleanup; } std::cout << "OK\n"; } } // read Xbe section names { std::cout << "Xbe::Xbe: Reading Section Names...\n"; m_szSectionName = new char[m_Header.dwSections][9]; for(uint32_t v=0;v<m_Header.dwSections;v++) { std::cout << "Xbe::Xbe: Reading Section Name 0x" << std::setfill('0') << std::hex << std::setw(4) << v << "..."; uint8_t *sn = GetAddr(m_SectionHeader[v].dwSectionNameAddr); memset(m_szSectionName[v], 0, 9); if(sn != 0) { for(int b=0;b<8;b++) { m_szSectionName[v][b] = sn[b]; if(m_szSectionName[v][b] == '\0') break; } } std::cout << "OK (" << m_szSectionName[v] << ")\n"; } } // read Xbe library versions if(m_Header.dwLibraryVersionsAddr != 0) { std::cout << "Xbe::Xbe: Reading Library Versions...\n"; fseek(XbeFile, m_Header.dwLibraryVersionsAddr - m_Header.dwBaseAddr, SEEK_SET); m_LibraryVersion = new LibraryVersion[m_Header.dwLibraryVersions]; for(uint32_t v=0;v<m_Header.dwLibraryVersions;v++) { std::cout << "Xbe::Xbe: Reading Library Version 0x" << std::setfill('0') << std::hex << std::setw(4) << v << "..."; if(fread(&m_LibraryVersion[v], sizeof(*m_LibraryVersion), 1, XbeFile) != 1) { sprintf(szBuffer, "Unexpected end of file while reading Xbe Library Version %d (%Xh)", v, v); SetError(szBuffer, true); goto cleanup; } std::cout << "OK\n"; } // read Xbe kernel library version { std::cout << "Xbe::Xbe: Reading Kernel Library Version..."; if(m_Header.dwKernelLibraryVersionAddr == 0) { SetError("Could not locate kernel library version", true); goto cleanup; } fseek(XbeFile, m_Header.dwKernelLibraryVersionAddr - m_Header.dwBaseAddr, SEEK_SET); m_KernelLibraryVersion = new LibraryVersion; if(fread(m_KernelLibraryVersion, sizeof(*m_LibraryVersion), 1, XbeFile) != 1) { SetError("Unexpected end of file while reading Xbe Kernel Version", true); goto cleanup; } std::cout << "OK\n"; } // read Xbe Xapi library version { std::cout << "Xbe::Xbe: Reading Xapi Library Version..."; if(m_Header.dwXAPILibraryVersionAddr == 0) { SetError("Could not locate Xapi Library Version", true); goto cleanup; } fseek(XbeFile, m_Header.dwXAPILibraryVersionAddr - m_Header.dwBaseAddr, SEEK_SET); m_XAPILibraryVersion = new LibraryVersion; if(fread(m_XAPILibraryVersion, sizeof(*m_LibraryVersion), 1, XbeFile) != 1) { SetError("Unexpected end of file while reading Xbe Xapi Version", true); goto cleanup; } std::cout << "OK\n"; } } // read Xbe sections { std::cout << "Xbe::Xbe: Reading Sections...\n"; m_bzSection = new uint8_t*[m_Header.dwSections]; memset(m_bzSection, 0, m_Header.dwSections); for(uint32_t v=0;v<m_Header.dwSections;v++) { std::cout << "Xbe::Xbe: Reading Section 0x" << std::setfill('0') << std::hex << std::setw(4) << v << "...\n"; uint32_t RawSize = m_SectionHeader[v].dwSizeofRaw; uint32_t RawAddr = m_SectionHeader[v].dwRawAddr; m_bzSection[v] = new uint8_t[RawSize]; fseek(XbeFile, RawAddr, SEEK_SET); if(RawSize == 0) { std::cout << "OK\n"; continue; } if(fread(m_bzSection[v], RawSize, 1, XbeFile) != 1) { sprintf(szBuffer, "Unexpected end of file while reading Xbe Section %d (%Xh) (%s)", v, v, m_szSectionName[v]); SetError(szBuffer, true); goto cleanup; } std::cout << "OK\n"; } } // read Xbe thread local storage if(m_Header.dwTLSAddr != 0) { std::cout << "Xbe::Xbe: Reading Thread Local Storage..."; void *Addr = GetAddr(m_Header.dwTLSAddr); if(Addr == 0) { SetError("Could not locate Thread Local Storage", true); goto cleanup; } m_TLS = new TLS; memcpy(m_TLS, Addr, sizeof(*m_TLS)); std::cout << "OK\n"; } cleanup: if(GetError() != 0) { std::cout << "FAILED!\n"; std::cout << "Xbe::Xbe: ERROR -> " << GetError() << "\n"; } fclose(XbeFile); return; }
// construct via Exe file Exe::Exe(const char *x_szFilename) { ConstructorInit(); printf("Exe::Exe: Opening Exe file..."); FILE *ExeFile = fopen(x_szFilename, "rb"); // verify Exe file was opened if(ExeFile == 0) { SetError("Could not open Exe file.", true); return; } printf("OK\n"); // ignore dos stub (if exists) { printf("Exe::Exe: Reading DOS stub..."); if(fread(&m_DOSHeader.m_magic, sizeof(m_DOSHeader.m_magic), 1, ExeFile) != 1) { SetError("Unexpected read error while reading magic number", true); goto cleanup; } if(m_DOSHeader.m_magic == *(uint16*)"MZ") { printf("Found, Ignoring..."); if(fread(&m_DOSHeader.m_cblp, sizeof(m_DOSHeader)-2, 1, ExeFile) != 1) { SetError("Unexpected read error while reading DOS stub", true); goto cleanup; } fseek(ExeFile, m_DOSHeader.m_lfanew, SEEK_SET); printf("OK\n"); } else { printf("None (OK)\n"); } } // read PE header { printf("Exe::Exe: Reading PE header... (%i bytes)",sizeof(m_Header)); if(fread(&m_Header, sizeof(m_Header), 1, ExeFile) != 1) { SetError("Unexpected read error while reading PE header", true); goto cleanup; } if(m_Header.m_magic != *(uint32*)"PE\0\0") { SetError("Invalid file (could not locate PE header)", true); goto cleanup; } printf("OK\n"); } // read optional header { printf("Exe::Exe: Reading Optional Header..."); if(fread(&m_OptionalHeader, sizeof(m_OptionalHeader), 1, ExeFile) != 1) { SetError("Unexpected read error while reading PE optional header", true); goto cleanup; } if(m_OptionalHeader.m_magic != 0x010B) { SetError("Invalid file (could not locate PE optional header)", true); goto cleanup; } printf("OK\n"); } // read section headers { m_SectionHeader = new SectionHeader[m_Header.m_sections]; printf("Exe::Exe: Reading Section Headers...\n"); for(uint32 v=0;v<m_Header.m_sections;v++) { printf("Exe::Exe: Reading Section Header 0x%.04X...", v); if(fread(&m_SectionHeader[v], sizeof(SectionHeader), 1, ExeFile) != 1) { char buffer[255]; sprintf(buffer, "Could not read PE section header %d (%Xh)", v, v); SetError(buffer, true); goto cleanup; } printf("OK\n", v); } } // read sections { printf("Exe::Exe: Reading Sections...\n"); m_bzSection = new uint08*[m_Header.m_sections]; for(uint32 v=0;v<m_Header.m_sections;v++) { printf("Exe::Exe: Reading Section 0x%.04X...", v); uint32 raw_size = m_SectionHeader[v].m_sizeof_raw; uint32 raw_addr = m_SectionHeader[v].m_raw_addr; m_bzSection[v] = new uint08[raw_size]; memset(m_bzSection[v], 0, raw_size); if(raw_size == 0) { printf("OK\n"); continue; } // read current section from file (if raw_size > 0) { fseek(ExeFile, raw_addr, SEEK_SET); if(fread(m_bzSection[v], raw_size, 1, ExeFile) != 1) { char buffer[255]; sprintf(buffer, "Could not read PE section %d (%Xh)", v, v); SetError(buffer, true); goto cleanup; } } printf("OK\n"); } } printf("Exe::Exe: Exe was successfully opened.\n", x_szFilename); cleanup: if(GetError() != 0) { printf("FAILED!\n"); printf("Exe::Exe: ERROR -> %s\n", GetError()); } fclose(ExeFile); }
// construct via Exe file object Xbe::Xbe(class Exe *x_Exe, const char *x_szTitle, bool x_bRetail) { ConstructorInit(); time_t CurrentTime; time(&CurrentTime); std::cout << "Xbe::Xbe: Pass 1 (Simple Pass)..."; // pass 1 { // standard Xbe magic number //m_Header.dwMagic = *reinterpret_cast<const uint32_t*>(reinterpret_cast<const char*>("XBEH")); m_Header.dwMagic = *reinterpret_cast<const uint32_t*>("XBEH"); // nobody has the private key yet, so zero this out memset(m_Header.pbDigitalSignature, 0, 256); // we'll only allow 0x00010000 for now m_Header.dwBaseAddr = 0x00010000; // this is a constant value m_Header.dwSizeofImageHeader = sizeof(m_Header); // we'll have the same number of sections as the Exe m_Header.dwSections = x_Exe->m_Header.m_sections; // TODO: allow configuration { memset(&m_Header.dwInitFlags, 0, sizeof(m_Header.dwInitFlags)); m_Header.dwInitFlags.bLimit64MB = true; m_Header.dwInitFlags.bDontSetupHarddisk = false; m_Header.dwInitFlags.bMountUtilityDrive = true; } // various PE copies { m_Header.dwPeStackCommit = 0x00010000; //x_Exe->m_OptionalHeader.m_sizeof_stack_commit; m_Header.dwPeHeapReserve = x_Exe->m_OptionalHeader.m_sizeof_heap_reserve; m_Header.dwPeHeapCommit = x_Exe->m_OptionalHeader.m_sizeof_heap_commit; m_Header.dwPeSizeofImage = x_Exe->m_OptionalHeader.m_sizeof_image; m_Header.dwPeChecksum = 0x00000000; m_Header.dwPeTimeDate = x_Exe->m_Header.m_timedate; } // build time/date m_Header.dwTimeDate = static_cast<uint32_t>(CurrentTime); // TODO: generate valid addr if necessary m_Header.dwNonKernelImportDirAddr = 0; // TODO: generate these values m_Header.dwLibraryVersions = 0; m_Header.dwLibraryVersionsAddr = 0; m_Header.dwKernelLibraryVersionAddr = 0; m_Header.dwXAPILibraryVersionAddr = 0; } std::cout << "OK\n"; std::cout << "Xbe::Xbe: Pass 2 (Calculating Requirements)..."; // pass 2 { // make-room cursor uint32_t mrc = m_Header.dwBaseAddr + static_cast<uint32_t>(sizeof(m_Header)); // make room for certificate { m_Header.dwCertificateAddr = mrc; mrc += static_cast<uint32_t>(sizeof(m_Certificate)); } // make room for section headers { m_Header.dwSectionHeadersAddr = mrc; mrc += m_Header.dwSections * static_cast<uint32_t>(sizeof(*m_SectionHeader)); // make room for head/tail reference count words mrc += (m_Header.dwSections+1)*2; // make room for section names for(uint32_t v=0;v<m_Header.dwSections;v++) { uint32_t s = 0; while(s < 8 && x_Exe->m_SectionHeader[v].m_name[s] != '\0') s++; mrc += s + 1; } } // TODO: make room for library versions { } // make room for debug path / debug file names { // TODO: allow this to be configured, right now we will just null out these values m_Header.dwDebugUnicodeFilenameAddr = mrc; m_Header.dwDebugPathnameAddr = mrc; m_Header.dwDebugFilenameAddr = mrc; mrc += 2; } // make room for largest possible logo bitmap { mrc = RoundUp(mrc, 0x10); m_Header.dwLogoBitmapAddr = mrc; m_Header.dwSizeofLogoBitmap = 100*17; // Max Possible mrc += m_Header.dwSizeofLogoBitmap; } // update size of headers m_Header.dwSizeofHeaders = mrc - m_Header.dwBaseAddr; } std::cout << "OK\n"; std::cout << "Xbe::Xbe: Pass 3 (Generating Xbe)...\n"; // pass 3 { m_Header.dwPeBaseAddr = m_Header.dwBaseAddr + RoundUp(m_Header.dwSizeofHeaders, 0x1000) - x_Exe->m_SectionHeader[0].m_virtual_addr; // encode entry point { std::cout << "Xbe::Xbe: Encoding " << (x_bRetail?"Retail":"Debug") << " Entry Point..."; uint32_t ep = x_Exe->m_OptionalHeader.m_entry + m_Header.dwPeBaseAddr; if(x_bRetail) ep ^= XOR_EP_RETAIL; else ep ^= XOR_EP_DEBUG; m_Header.dwEntryAddr = ep; std::cout << "OK (0x" << std::setfill('0') << std::hex << std::setw(8) << ep << ")\n"; } // header write cursor uint32_t hwc = m_Header.dwBaseAddr + static_cast<uint32_t>(sizeof(m_Header)); // check if we need to store extra header bytes (we always will) if(m_Header.dwSizeofHeaders > sizeof(m_Header)) { std::cout << "Xbe::Xbe: Found Extra Header Bytes..."; uint32_t ExSize = RoundUp(m_Header.dwSizeofHeaders - static_cast<uint32_t>(sizeof(m_Header)), 0x1000); m_HeaderEx = new char[ExSize]; std::cout << "OK\n"; } // start a write buffer inside of m_HeaderEx char *szBuffer = m_HeaderEx; // write certificate { // certificate size is a constant m_Certificate.dwSize = sizeof(m_Certificate); m_Certificate.dwTimeDate = static_cast<uint32_t>(CurrentTime); // TODO: generate in the form CX-9999 m_Certificate.dwTitleId = 0xFFFF0002; // title name memset(m_Certificate.wszTitleName, 0, 40); for (int i=0; i<40 && x_szTitle[i] != 0; i++) m_Certificate.wszTitleName[i] = x_szTitle[i]; // zero out alternate ids { for(uint32_t c=0;c<0x10;c++) m_Certificate.dwAlternateTitleId[c] = 0; } // for now we'll just allow any media you could want m_Certificate.dwAllowedMedia = XBEIMAGE_MEDIA_TYPE_HARD_DISK | XBEIMAGE_MEDIA_TYPE_DVD_CD | XBEIMAGE_MEDIA_TYPE_MEDIA_BOARD | XBEIMAGE_MEDIA_TYPE_NONSECURE_HARD_DISK | XBEIMAGE_MEDIA_TYPE_NONSECURE_MODE; // TODO: allow configuration m_Certificate.dwGameRegion = XBEIMAGE_GAME_REGION_MANUFACTURING | XBEIMAGE_GAME_REGION_NA | XBEIMAGE_GAME_REGION_JAPAN | XBEIMAGE_GAME_REGION_RESTOFWORLD; // TODO: allow configuration m_Certificate.dwGameRatings = 0xFFFFFFFF; // always disk 0, AFAIK m_Certificate.dwDiskNumber = 0; // TODO: allow configuration m_Certificate.dwVersion = 0; // generate blank LAN, signature, and alternate signature keys { for(uint32_t v=0;v<0x10;v++) m_Certificate.bzLanKey[v] = m_Certificate.bzSignatureKey[v] = 0; for(uint32_t x=0;x<0x10;x++) for(uint32_t y=0;y<0x10;y++) m_Certificate.bzTitleAlternateSignatureKey[x][y] = 0; } // write certificate { memcpy(szBuffer, &m_Certificate, sizeof(m_Certificate)); szBuffer += sizeof(m_Certificate); hwc += static_cast<uint32_t>(sizeof(m_Certificate)); } } // generate ascii title from certificate title name setlocale( LC_ALL, "English" ); //wcstombs(m_szAsciiTitle, m_Certificate.wszTitleName, 40); for (int i=0; i<40 && m_Certificate.wszTitleName[i] != 0; i++) m_szAsciiTitle[i] = static_cast<uint8_t>(m_Certificate.wszTitleName[i]); // write section headers / section names { m_szSectionName = new char[m_Header.dwSections][9]; m_SectionHeader = new SectionHeader[m_Header.dwSections]; uint32_t SectionCursor = RoundUp(m_Header.dwSizeofHeaders, 0x1000); // head/tail reference count write buffer uint16_t *htrc = reinterpret_cast<uint16_t*>(szBuffer + m_Header.dwSections*sizeof(*m_SectionHeader)); // section write buffer char *secn = reinterpret_cast<char*>(reinterpret_cast<uintptr_t>(htrc) + (m_Header.dwSections+1)*2); // head/tail reference count write cursor uint32_t hwc_htrc = hwc + m_Header.dwSections*static_cast<uint32_t>(sizeof(*m_SectionHeader)); // section write cursor uint32_t hwc_secn = hwc_htrc + (m_Header.dwSections+1)*2; std::cout << "Xbe::Xbe: Generating Section Headers...\n"; for(uint32_t v=0;v<m_Header.dwSections;v++) { std::cout << "Xbe::Xbe: Generating Section Header " << std::setfill('0') << std::hex << std::setw(4) << v << "..."; uint32_t characteristics = x_Exe->m_SectionHeader[v].m_characteristics; memset(&m_SectionHeader[v].dwFlags, 0, sizeof(m_SectionHeader->dwFlags)); if(characteristics & IMAGE_SCN_MEM_WRITE) m_SectionHeader[v].dwFlags.bWritable = true; if( (characteristics & IMAGE_SCN_MEM_EXECUTE) || (characteristics & IMAGE_SCN_CNT_CODE) ) m_SectionHeader[v].dwFlags.bExecutable = true; m_SectionHeader[v].dwFlags.bPreload = true; m_SectionHeader[v].dwVirtualAddr = x_Exe->m_SectionHeader[v].m_virtual_addr + m_Header.dwPeBaseAddr; if(v < m_Header.dwSections-1) m_SectionHeader[v].dwVirtualSize = x_Exe->m_SectionHeader[v+1].m_virtual_addr - x_Exe->m_SectionHeader[v].m_virtual_addr; else m_SectionHeader[v].dwVirtualSize = RoundUp(x_Exe->m_SectionHeader[v].m_virtual_size, 4); m_SectionHeader[v].dwRawAddr = SectionCursor; // calculate sizeof_raw by locating the last non-zero value in the raw section data { uint32_t r = x_Exe->m_SectionHeader[v].m_sizeof_raw; if (r > 0) r--; while(r > 0) { if(x_Exe->m_bzSection[v][r--] != 0) break; } // word aligned m_SectionHeader[v].dwSizeofRaw = RoundUp(r+2, 4); } SectionCursor += RoundUp(m_SectionHeader[v].dwSizeofRaw, 0x1000); // head/tail reference count { m_SectionHeader[v].dwHeadSharedRefCountAddr = hwc_htrc; htrc[v] = 0; hwc_htrc += 2; m_SectionHeader[v].dwTailSharedRefCountAddr = hwc_htrc; htrc[v+1] = 0; } // section name { uint32_t s = 0; memset(secn, 0, 8); m_SectionHeader[v].dwSectionNameAddr = hwc_secn; while(s < 8 && x_Exe->m_SectionHeader[v].m_name[s] != '\0') { m_szSectionName[v][s] = secn[s] = x_Exe->m_SectionHeader[v].m_name[s]; s++; } m_szSectionName[v][s] = '\0'; secn += s+1; hwc_secn += s+1; } m_SectionHeader[v].dwSectionRefCount = 0; // write section digest (just zeros) memset(m_SectionHeader[v].bzSectionDigest, 0, 20); // write section header memcpy(szBuffer, &m_SectionHeader[v], sizeof(*m_SectionHeader)); szBuffer += sizeof(*m_SectionHeader); std::cout << "OK\n"; } hwc = hwc_secn; } // write debug path / debug file names { *reinterpret_cast<uint16_t*>(szBuffer) = 0x0000; szBuffer += 2; hwc += 2; } // write default "OpenXDK" logo bitmap { std::cout << "Xbe::Xbe: Generating \"OpenXDK\" Logo Bitmap..."; uint8_t *RawAddr = GetAddr(m_Header.dwLogoBitmapAddr); memset(RawAddr, 0, 100*17); memcpy(RawAddr, OpenXDK, dwSizeOfOpenXDK); m_Header.dwSizeofLogoBitmap = dwSizeOfOpenXDK; std::cout << "OK\n"; } // write sections { std::cout << "Xbe::Xbe: Generating Sections...\n"; m_bzSection = new uint8_t*[m_Header.dwSections]; memset(m_bzSection, 0, m_Header.dwSections); for(uint32_t v=0;v<m_Header.dwSections;v++) { std::cout << "Xbe::Xbe: Generating Section " << std::setfill('0') << std::hex << std::setw(4) << v << "..."; uint32_t RawSize = m_SectionHeader[v].dwSizeofRaw; m_bzSection[v] = new uint8_t[RawSize]; memcpy(m_bzSection[v], x_Exe->m_bzSection[v], RawSize); std::cout << "OK\n"; } } } std::cout << "Xbe::Xbe: Pass 4 (Finalizing)...\n"; // pass 4 { m_Header.dwSizeofImage = m_SectionHeader[m_Header.dwSections-1].dwVirtualAddr + m_SectionHeader[m_Header.dwSections-1].dwVirtualSize - m_Header.dwBaseAddr; m_Header.dwTLSAddr = 0; // relocate to base : 0x00010000 { std::cout << "Xbe::Xbe: Relocating to Base 0x00010000..."; uint32_t fixCount = 0; uint32_t relo_addr = x_Exe->m_OptionalHeader.m_image_data_directory[5].m_virtual_addr; uint32_t relo_size = x_Exe->m_OptionalHeader.m_image_data_directory[5].m_size; uint32_t dwBaseDiff = m_Header.dwPeBaseAddr - x_Exe->m_OptionalHeader.m_image_base; uint8_t *reloc = GetAddr(relo_addr + m_Header.dwPeBaseAddr); // relocate, if necessary if(reloc != 0) { uint32_t v = 0; // relocate each relocation block while(v < relo_size) { uint32_t block_addr = *reinterpret_cast<uint32_t*>(&reloc[v+0]); uint32_t block_stop = *reinterpret_cast<uint32_t*>(&reloc[v+4]) + v; v += 8; // relocate each rva while(v < block_stop && v < relo_size) { uint16_t data = *reinterpret_cast<uint16_t*>(&reloc[v]); uint32_t type = (data & 0xF000) >> 12; if(type == 0) { v+=2; break; } // 32-bit field relocation if(type == IMAGE_REL_BASED_HIGHLOW) { fixCount++; uint32_t dwFixAddr = block_addr + (data & 0x0FFF) + m_Header.dwPeBaseAddr; uint8_t *bzModRVA = GetAddr(dwFixAddr); if(bzModRVA != 0) *reinterpret_cast<uint32_t*>(bzModRVA) += dwBaseDiff; } else { SetError("Unsupported relocation type", true); goto cleanup; } v+=2; } } } std::cout << "OK (" << std::dec << fixCount << " Fixups)\n"; } // locate kernel thunk table { // unfortunately, GCC doesn't populate the IAT entry in the data directory // so if the value is 0, then it could mean there are no imports, or it // could mean the EXE was compiled by GCC uint32_t ktRVA = x_Exe->m_OptionalHeader.m_image_data_directory[12].m_virtual_addr; if(ktRVA == 0) { // lets check to see if there is an import section. if so, look at offset 16 // for the RVA of the Import Address Table uint32_t importRVA = x_Exe->m_OptionalHeader.m_image_data_directory[1].m_virtual_addr; if(importRVA != 0) { uint8_t *importSection = GetAddr(importRVA + m_Header.dwPeBaseAddr); ktRVA = *reinterpret_cast<uint32_t*>(&importSection[16]); } } uint32_t kt = ktRVA + m_Header.dwPeBaseAddr; kt ^= (x_bRetail ? XOR_KT_RETAIL : XOR_KT_DEBUG ); m_Header.dwKernelImageThunkAddr = kt; } }