/* * Xenoborg - Xbox Emulator * Copyright (C) 2006-2010 blueshogun96 * * Name: xbe.h * Desc: Xbe loader. * * Changelog: * 10/14/2010 - Initial import from an old build. Fixed it up a bit because * the old version looks so ugly. * * 10/15/2010 - Added support for Sega Chihiro .xbe files. The XOR keys are * different than normal Xbox xbe files. Chihiro mode will be a * seperate Xenoborg build though. */ #pragma warning (disable:4996) #include "..\\win32.h" #include "..\\dbg_console.h" #include "..\\crc32.h" #include "xbe.h" //----------------------------------------------------------------------------- // Name: OpenFile // Desc: Opens an xbe file, determines some basic // properties such as file size, and loads // the data into system memory. //----------------------------------------------------------------------------- int xbe_load( char* szXbeFileName, struct Xbe_t* xbe ) { // File pointer for xbe file FILE* fpXbe = NULL; // Check for valid string if( !szXbeFileName ) { DbgPrintf( "XBELoad(): Invalid String!\n" ); return FALSE; } // Open xbe file if( !( fpXbe = fopen( szXbeFileName, "rb" ) ) ) { DbgPrintf( "XBELoad(): Unable to load Xbe file!\n" ); return FALSE; } // Allocate memory for saved string // memset( xbe->m_szXbeFileName, 0x0, sizeof( *xbe->m_szXbeFileName ) ); // xbe->m_szXbeFileName = (char*) malloc( sizeof( char ) * strlen( szXbeFileName ) ); // new char[ strlen( szXbeFileName ) ]; // strcpy( xbe->m_szXbeFileName, szXbeFileName ); xbe->m_szXbeFileName = szXbeFileName; // Retreive xbe's size fseek( fpXbe, 0, SEEK_END ); xbe->m_lXbeFileSize = ftell( fpXbe ); // Allocate memory for xbe data xbe->m_pXbeData = /*(BYTE*) malloc( sizeof( BYTE ) * xbe->m_lXbeFileSize );*/ new unsigned char[ xbe->m_lXbeFileSize ]; // Close xbe file fclose( fpXbe ); // Get the 32-bit crc crc_generate_tables(); xbe->crc = crc_update( -1, xbe->m_pXbeData, xbe->m_lXbeFileSize ); // Process Xbe's data if( !xbe_process_data(xbe) ) return FALSE; // Mark xbe file as opened successfully. xbe->m_bXbeHasBeenOpened = 1; return TRUE; } //----------------------------------------------------------------------------- // Name: CloseFile // Desc: ... //----------------------------------------------------------------------------- void xbe_unload( struct Xbe_t* xbe ) { DbgPrintf( "Closing Xbe file... \n" ); // Release data pointers and reset variables { if( xbe->m_pXbeData ) { /*free( xbe->m_pXbeData );*/ delete[] xbe->m_pXbeData; xbe->m_pXbeData = NULL; } /* if( xbe->m_szXbeFileName ) { free( xbe->m_szXbeFileName ); // delete[] xbe->m_szXbeFileName; xbe->m_szXbeFileName = NULL; } */ if( xbe->m_XbeSectionHeader ) { free( xbe->m_XbeSectionHeader ); xbe->m_XbeSectionHeader = NULL; } if( xbe->m_XbeStandardLibrary ) { free( xbe->m_XbeStandardLibrary ); xbe->m_XbeStandardLibrary = NULL; } } SetWindowTextA( GetActiveWindow(), "Xenoborg" ); xbe->m_bXbeHasBeenOpened = 0; } //----------------------------------------------------------------------------- // Name: ProcessXbeData // Desc: Processes and organizes xbe's data into // sections, checks to see if the xbe file // is legit. Xbe has to have been previously // loaded in order to use Xbe function. //----------------------------------------------------------------------------- int xbe_process_data( struct Xbe_t* xbe ) { FILE* fpXbe = NULL; // File pointer for xbe file UINT* ptr = NULL; // Temporary pointer to xbe data // UINT i; // Discontinue if the xbe file's existance has not been verified // if( !xbe->m_bXbeHasBeenOpened ) // return FALSE; DbgPrintf( "Loading Xbe file...\n\n" ); // Reopen the xbe file if( !( fpXbe = fopen( xbe->m_szXbeFileName, "r" ) ) ) { DbgPrintf( "XBEProcessData(): Unable to load Xbe file!\n" ); return FALSE; } // Seek to the beginning of file fseek( fpXbe, 0, SEEK_SET ); // Read xbe data into memory pointer fread( xbe->m_pXbeData, xbe->m_lXbeFileSize, 1, fpXbe ); // Close the file handle fclose( fpXbe ); // Create a copy of the xbe data to prevent alteration of the // actual data itself. ptr = (UINT*) xbe->m_pXbeData; // Xbe legitimacy check { int offset = 0; // File location offset char* header = "XBEH"; // Xbe header // Check to see if we have a valid Xbe file for( offset = 0; offset != 4; offset++ ) { // If any chars in the file's header don't match, we have // a bogus xbe file. if( ( (char*) ptr )[offset] != header[offset] ) { DbgPrintf( "Xbe Error: Not a valid xbe file!\n" ); return FALSE; } } // Xbe is legitimate! } // Xbe parsing // { DWORD offset = 0; // File location offset // Xbe Header { // Fill in Xbe image header structure memcpy( &xbe->m_XbeHeader, xbe->m_pXbeData, sizeof( XbeImageHeader ) ); } // Xbe Certificate { // Set the offset for the Xbe certificate offset = xbe->m_XbeHeader.dwCertificateAddr - xbe->m_XbeHeader.dwBaseAddr; // Read in the Xbe certificate data memcpy( &xbe->m_XbeCertificate, xbe->m_pXbeData + offset, sizeof( XbeCertificate ) ); } // Xbe Section Header(s) { // Allocate memory for the Xbe's section headers xbe->m_XbeSectionHeader = (XbeSectionHeader*) malloc( sizeof( XbeSectionHeader ) * xbe->m_XbeHeader.dwNumSections ); // = new XbeSectionHeader[xbe->m_XbeHeader.dwNumSections]; // Set the offset for the first xbe section header offset = xbe->m_XbeHeader.dwSectionAddr - xbe->m_XbeHeader.dwBaseAddr; // Retreive data for each and every section header in the Xbe for( DWORD i = 0; i < xbe->m_XbeHeader.dwNumSections; i++ ) { memcpy( &xbe->m_XbeSectionHeader[i], xbe->m_pXbeData + offset, sizeof( XbeSectionHeader ) ); offset += sizeof( XbeSectionHeader ); } } // Xbe TLS { if (xbe->m_XbeHeader.dwTLSAddr>xbe->m_XbeHeader.dwBaseAddr) { try { // Set the offset for the Xbe's TLS data offset = xbe->m_XbeHeader.dwTLSAddr - xbe->m_XbeHeader.dwBaseAddr; // Read TLS data memcpy( &xbe->m_XbeTLS, xbe->m_pXbeData + offset, sizeof( XbeTLS ) ); } catch( ... ) { DbgPrintf( "This Xbe Contains no TLS data.\n" ); } } else { DbgPrintf( "This Xbe Contains no TLS data.\n" ); } } // Xbe Librarie(s) { // Set the offset for the first standard library in the xbe offset = xbe->m_XbeHeader.dwLibVersionAddr - xbe->m_XbeHeader.dwBaseAddr; // Allocate memory for xbe's standard libraries xbe->m_XbeStandardLibrary = (XbeLibrary*) malloc( sizeof( XbeLibrary ) * xbe->m_XbeHeader.dwNumLibVersions ); // = new XbeLibrary[xbe->m_XbeHeader.dwNumLibVersions]; // Retreive data for each and every library for( DWORD i = 0; i < xbe->m_XbeHeader.dwNumLibVersions; i++ ) { memcpy( &xbe->m_XbeStandardLibrary[i], xbe->m_pXbeData + offset, sizeof( XbeLibrary ) ); offset += sizeof( XbeLibrary ); } // Set the offset for the Xbe's kernel library offset = xbe->m_XbeHeader.dwKernelLibVersionAddr - xbe->m_XbeHeader.dwBaseAddr; // Read kernel library data if (xbe->m_XbeHeader.dwKernelLibVersionAddr) { try { memcpy( &xbe->m_XbeKernelLibrary, xbe->m_pXbeData + offset, sizeof( XbeLibrary ) ); } catch( ... ) { DbgPrintf( "This Xbe contains no Kernel Library.\n" ); } } // Set the offset for the Xbe's Xapi library offset = xbe->m_XbeHeader.dwXapiLibVersionAddr - xbe->m_XbeHeader.dwBaseAddr; // Read Xapi library data if (xbe->m_XbeHeader.dwXapiLibVersionAddr && int(offset) > 0 ) { try { memcpy( &xbe->m_XbeXapiLibrary, xbe->m_pXbeData + offset, sizeof( XbeLibrary ) ); } catch( ... ) { DbgPrintf( "This Xbe contains no Xapi Library.\n" ); } } } // Output information to debug file DbgPrintf( "\n**********Xbe general**********\n" ); DbgPrintf( "Xbe file name: %s\nFile size: %d bytes\n", xbe->m_szXbeFileName, xbe->m_lXbeFileSize ); DbgPrintf( "Base Address: 0x%08X\n", xbe->m_XbeHeader.dwBaseAddr ); DbgPrintf( "CRC32: 0x%.08X\n", xbe->crc ); // Check for a Sega Chihiro .xbe if( ( xbe->m_XbeHeader.dwEntryPoint & 0xF0000000 ) == 0x40000000 ) { DbgPrintf( "Xbe type: Chihiro\n" ); // This is a Sega Chihiro .xbe xbe->m_bIsChihiro = TRUE; // Decode actual entry point xbe->m_dwActualEntryPoint = xbe->m_XbeHeader.dwEntryPoint ^ XOR_ENTRY_CHIHIRO; DbgPrintf( "Entry point: 0x%08X ^ 0x%08X = 0x%08X\n", xbe->m_XbeHeader.dwEntryPoint, XOR_ENTRY_CHIHIRO, xbe->m_dwActualEntryPoint ); // Decode kernel thunk location DbgPrintf( "Kernel Thunk Address: 0x%08X ^ 0x%08X = 0x%08X\n", xbe->m_XbeHeader.dwKernelThunkAddr, XOR_KERNEL_CHIHIRO, xbe->m_XbeHeader.dwKernelThunkAddr ^ XOR_KERNEL_CHIHIRO ); } else { DbgPrintf( "Xbe type: Xbox\n" ); // This is a Microsoft Xbox .xbe xbe->m_bIsChihiro = FALSE; if( ( xbe->m_XbeHeader.dwEntryPoint ^ XOR_ENTRY_RETAIL ) > 0x01000000 ) { // Decode actual entry point xbe->m_dwActualEntryPoint = xbe->m_XbeHeader.dwEntryPoint ^ XOR_ENTRY_DEBUG; DbgPrintf( "Entry point: 0x%08X ^ 0x%08X = 0x%08X\n", xbe->m_XbeHeader.dwEntryPoint, XOR_ENTRY_DEBUG, xbe->m_dwActualEntryPoint ); // Decode kernel thunk location DbgPrintf( "Kernel Thunk Address: 0x%08X ^ 0x%08X = 0x%08X\n", xbe->m_XbeHeader.dwKernelThunkAddr, XOR_KERNEL_DEBUG, xbe->m_XbeHeader.dwKernelThunkAddr ^ XOR_KERNEL_DEBUG ); } else { // Decode actual entry point xbe->m_dwActualEntryPoint = xbe->m_XbeHeader.dwEntryPoint ^ XOR_ENTRY_RETAIL; DbgPrintf( "Entry point: 0x%08X ^ 0x%08X = 0x%08X\n", xbe->m_XbeHeader.dwEntryPoint, XOR_ENTRY_RETAIL, xbe->m_dwActualEntryPoint ); // Decode kernel thunk location DbgPrintf( "Kernel Thunk Address: 0x%08X ^ 0x%08X = 0x%08X\n", xbe->m_XbeHeader.dwKernelThunkAddr, XOR_KERNEL_RETAIL, xbe->m_XbeHeader.dwKernelThunkAddr ^ XOR_KERNEL_RETAIL ); } } DbgPrintf( "\n**********Xbe section(s) info**********\n" ); DbgPrintf( "Section Address: 0x%08X\n", xbe->m_XbeHeader.dwSectionAddr ); DbgPrintf( "Number of Sections: %d\n", xbe->m_XbeHeader.dwNumSections ); for( DWORD i = 0; i < xbe->m_XbeHeader.dwNumSections; i++ ) { offset = xbe->m_XbeSectionHeader[i].dwSectionNameAddr - xbe->m_XbeHeader.dwBaseAddr; DbgPrintf( "Section Name (#%d): %s\n", i, xbe->m_pXbeData + offset ); } // } char string[128]; sprintf( string, "Xenoborg: %S", xbe->m_XbeCertificate.wcTitle ); SetWindowTextA( GetActiveWindow(), string ); // if( !XBEWriteToMemory() ){}; return TRUE; } //----------------------------------------------------------------------------- // Name: XBEWriteToMemory // Desc: Loads the XBE file into Ram starting at the XBE's base address. //----------------------------------------------------------------------------- //BOOL XBEWriteToMemory() //{ // // Save a copy of the actual base address // DWORD dwBaseAddress = xbe->m_XbeHeader.dwBaseAddr; // // DbgPrintf( "Writing Xbe data to the reserved address...\n" ); // // if( !xbe->m_pXbeData ) // { // EmuError( "NULL Xbe data!\n" ); // return FALSE; // } // // // Now that we have a loaded .xbe file, allow the 64mb region of memory to be // // both read and written to. // // TODO: Prevent writing to the header? // // void* pBaseAddress = (void*) 0x10000; // DWORD dwMemSize = (64*1024*1024)-0x10000; // DWORD dwOldProtect; // // if( !VirtualProtect( pBaseAddress, dwMemSize, PAGE_READWRITE, &dwOldProtect ) ) // { // DWORD dwError = GetLastError(); // return EmuError( "Error setting protection settings to required memory range!\nError code: 0x%.08X" ); // } // // // Zero out the entire 64mb region // ZeroMemory( ((DWORD*)pBaseAddress)+0x1000, dwMemSize-0x1000 ); // // try // { // // Write the XBE's bytes into memory // for( DWORD offset = 0x1000; offset < (unsigned) xbe->m_lXbeFileSize; offset++ ) // { // ((BYTE*)pBaseAddress)[offset/*+dwBaseAddress*/] = xbe->m_pXbeData[offset]; // } // } // catch( ... ) // { // EmuError( "Error loading Xbe file into memory!\n" ); // return FALSE; // } // // // Success // DbgPrintf( "Successfully written xbe contents to 0x10000.\n" ); // // return TRUE; //}