// ****************************************************************** // * // * .,-::::: .,:: .::::::::. .,:: .: // * ,;;;'````' `;;;, .,;; ;;;'';;' `;;;, .,;; // * [[[ '[[,,[[' [[[__[[\. '[[,,[[' // * $$$ Y$$$P $$""""Y$$ Y$$$P // * `88bo,__,o, oP"``"Yo, _88o,,od8P oP"``"Yo, // * "YUMMMMMP",m" "Mm,""YUMMMP" ,m" "Mm, // * // * Cxbx->Win32->Cxbx->EmuExe.cpp // * // * This file is part of the Cxbx project. // * // * Cxbx and Cxbe are free software; you can redistribute them // * and/or modify them under the terms of the GNU General Public // * License as published by the Free Software Foundation; either // * version 2 of the license, or (at your option) any later version. // * // * This program is distributed in the hope that it will be useful, // * but WITHOUT ANY WARRANTY; without even the implied warranty of // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // * GNU General Public License for more details. // * // * You should have recieved a copy of the GNU General Public License // * along with this program; see the file COPYING. // * If not, write to the Free Software Foundation, Inc., // * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. // * // * (c) 2002-2003 Aaron Robinson // * // * All rights reserved // * // ****************************************************************** #include "Cxbx.h" #include "EmuExe.h" #include "Prolog.h" #include "CxbxKrnl.h" #undef FIELD_OFFSET // prevent macro redefinition warnings #include #include // ****************************************************************** // * constructor // ****************************************************************** EmuExe::EmuExe(Xbe *x_Xbe, uint32 x_debug_console, char *x_debug_filename) : Exe() { ConstructorInit(); // ****************************************************************** // * generate 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.. } // ****************************************************************** // * generate 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 = 0x00001000; 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;dm_Header.dwSections;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; } } } // ****************************************************************** // * generate .cxbximp section header // ****************************************************************** { uint32 i = m_Header.m_sections - 2; memcpy(m_SectionHeader[i].m_name, ".cxbximp", 8); // ****************************************************************** // * generate .cxbximp section virtual size / addr // ****************************************************************** { uint32 virt_size = RoundUp(0x55, 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[1].m_virtual_addr = m_SectionHeader[i].m_virtual_addr + 0x08; m_OptionalHeader.m_image_data_directory[1].m_size = 0x28; // ****************************************************************** // * update import address table directory entry // ****************************************************************** m_OptionalHeader.m_image_data_directory[12].m_virtual_addr = m_SectionHeader[i].m_virtual_addr; m_OptionalHeader.m_image_data_directory[12].m_size = 0x08; } // ****************************************************************** // * generate .cxbxplg section header // ****************************************************************** { uint32 i = m_Header.m_sections - 1; memcpy(m_SectionHeader[i].m_name, ".cxbxplg", 8); // ****************************************************************** // * generate .cxbxplg section virtual size / addr // ****************************************************************** { uint32 virt_size = RoundUp(0x1000 + x_Xbe->m_Header.dwSizeofHeaders, 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; } } // ****************************************************************** // * generate sections // ****************************************************************** { 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;vm_Header.dwSections;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); } } // ****************************************************************** // * generate .cxbximp section // ****************************************************************** { // ****************************************************************** // * TODO: fix up this entire chunk of code, it is a total hack // ****************************************************************** uint32 i = m_Header.m_sections - 2; 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 + 0x48; *(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; memcpy(&m_bzSection[i][0x3A], "_EmuXDummy@0\0\0cxbx.dll\0\0\0\0\0\0", 28); } // ****************************************************************** // * generate .cxbxplg section // ****************************************************************** { uint32 ep = x_Xbe->m_Header.dwEntryAddr; uint32 i = m_Header.m_sections - 1; // ****************************************************************** // * 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]; // ****************************************************************** // * append prolog section // ****************************************************************** memcpy(m_bzSection[i], Prolog, 0x1000); // ****************************************************************** // * append xbe header // ****************************************************************** memcpy(m_bzSection[i] + 0x100, &x_Xbe->m_Header, sizeof(Xbe::Header)); // ****************************************************************** // * append xbe extra header bytes // ****************************************************************** memcpy(m_bzSection[i] + 0x100 + sizeof(Xbe::Header), x_Xbe->m_HeaderEx, x_Xbe->m_Header.dwSizeofHeaders - sizeof(Xbe::Header)); // ****************************************************************** // * append x_debug_filename // ****************************************************************** memcpy(m_bzSection[i] + 0x100 + x_Xbe->m_Header.dwSizeofHeaders, x_debug_filename, 260); // ****************************************************************** // * patch prolog function parameters // ****************************************************************** *(uint32 *)((uint32)m_bzSection[i] + 1) = (uint32)EmuXInit; *(uint32 *)((uint32)m_bzSection[i] + 6) = (uint32)ep; *(uint32 *)((uint32)m_bzSection[i] + 11) = (uint32)x_Xbe->m_Header.dwSizeofHeaders; *(uint32 *)((uint32)m_bzSection[i] + 16) = m_SectionHeader[i].m_virtual_addr + m_OptionalHeader.m_image_base + 0x100; *(uint32 *)((uint32)m_bzSection[i] + 21) = m_SectionHeader[i].m_virtual_addr + m_OptionalHeader.m_image_base + 0x100 + x_Xbe->m_Header.dwSizeofHeaders; *(uint32 *)((uint32)m_bzSection[i] + 26) = x_debug_console; } } // ****************************************************************** // * patch kernel thunk table // ****************************************************************** { 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;vm_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) { uint32 *kt_tbl = (uint32*)&m_bzSection[v][kt - virt_addr - imag_base]; while(*kt_tbl != 0) *kt_tbl++ = KernelThunkTable[*kt_tbl & 0x7FFFFFFF]; break; } } } // ****************************************************************** // * update imcomplete header fields // ****************************************************************** { // ****************************************************************** // * 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