├── .gitattributes ├── .gitignore ├── README.md ├── XboxImageXploder.sln └── XboxImageXploder ├── XboxExecutable.cpp ├── XboxExecutable.h ├── XboxImageXploder.cpp ├── XboxImageXploder.vcxproj └── XboxImageXploder.vcxproj.filters /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | build/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | 28 | # MSTest test Results 29 | [Tt]est[Rr]esult*/ 30 | [Bb]uild[Ll]og.* 31 | 32 | # NUNIT 33 | *.VisualState.xml 34 | TestResult.xml 35 | 36 | # Build Results of an ATL Project 37 | [Dd]ebugPS/ 38 | [Rr]eleasePS/ 39 | dlldata.c 40 | 41 | # DNX 42 | project.lock.json 43 | artifacts/ 44 | 45 | *_i.c 46 | *_p.c 47 | *_i.h 48 | *.ilk 49 | *.meta 50 | *.obj 51 | *.pch 52 | *.pdb 53 | *.pgc 54 | *.pgd 55 | *.rsp 56 | *.sbr 57 | *.tlb 58 | *.tli 59 | *.tlh 60 | *.tmp 61 | *.tmp_proj 62 | *.log 63 | *.vspscc 64 | *.vssscc 65 | .builds 66 | *.pidb 67 | *.svclog 68 | *.scc 69 | 70 | # Chutzpah Test files 71 | _Chutzpah* 72 | 73 | # Visual C++ cache files 74 | ipch/ 75 | *.aps 76 | *.ncb 77 | *.opensdf 78 | *.sdf 79 | *.cachefile 80 | 81 | # Visual Studio profiler 82 | *.psess 83 | *.vsp 84 | *.vspx 85 | 86 | # TFS 2012 Local Workspace 87 | $tf/ 88 | 89 | # Guidance Automation Toolkit 90 | *.gpState 91 | 92 | # ReSharper is a .NET coding add-in 93 | _ReSharper*/ 94 | *.[Rr]e[Ss]harper 95 | *.DotSettings.user 96 | 97 | # JustCode is a .NET coding add-in 98 | .JustCode 99 | 100 | # TeamCity is a build add-in 101 | _TeamCity* 102 | 103 | # DotCover is a Code Coverage Tool 104 | *.dotCover 105 | 106 | # NCrunch 107 | _NCrunch_* 108 | .*crunch*.local.xml 109 | 110 | # MightyMoose 111 | *.mm.* 112 | AutoTest.Net/ 113 | 114 | # Web workbench (sass) 115 | .sass-cache/ 116 | 117 | # Installshield output folder 118 | [Ee]xpress/ 119 | 120 | # DocProject is a documentation generator add-in 121 | DocProject/buildhelp/ 122 | DocProject/Help/*.HxT 123 | DocProject/Help/*.HxC 124 | DocProject/Help/*.hhc 125 | DocProject/Help/*.hhk 126 | DocProject/Help/*.hhp 127 | DocProject/Help/Html2 128 | DocProject/Help/html 129 | 130 | # Click-Once directory 131 | publish/ 132 | 133 | # Publish Web Output 134 | *.[Pp]ublish.xml 135 | *.azurePubxml 136 | ## TODO: Comment the next line if you want to checkin your 137 | ## web deploy settings but do note that will include unencrypted 138 | ## passwords 139 | #*.pubxml 140 | 141 | *.publishproj 142 | 143 | # NuGet Packages 144 | *.nupkg 145 | # The packages folder can be ignored because of Package Restore 146 | **/packages/* 147 | # except build/, which is used as an MSBuild target. 148 | !**/packages/build/ 149 | # Uncomment if necessary however generally it will be regenerated when needed 150 | #!**/packages/repositories.config 151 | 152 | # Windows Azure Build Output 153 | csx/ 154 | *.build.csdef 155 | 156 | # Windows Store app package directory 157 | AppPackages/ 158 | 159 | # Visual Studio cache files 160 | # files ending in .cache can be ignored 161 | *.[Cc]ache 162 | # but keep track of directories ending in .cache 163 | !*.[Cc]ache/ 164 | 165 | # Others 166 | ClientBin/ 167 | [Ss]tyle[Cc]op.* 168 | ~$* 169 | *~ 170 | *.dbmdl 171 | *.dbproj.schemaview 172 | *.pfx 173 | *.publishsettings 174 | node_modules/ 175 | orleans.codegen.cs 176 | 177 | # RIA/Silverlight projects 178 | Generated_Code/ 179 | 180 | # Backup & report files from converting an old project file 181 | # to a newer Visual Studio version. Backup files are not needed, 182 | # because we have git ;-) 183 | _UpgradeReport_Files/ 184 | Backup*/ 185 | UpgradeLog*.XML 186 | UpgradeLog*.htm 187 | 188 | # SQL Server files 189 | *.mdf 190 | *.ldf 191 | 192 | # Business Intelligence projects 193 | *.rdl.data 194 | *.bim.layout 195 | *.bim_*.settings 196 | 197 | # Microsoft Fakes 198 | FakesAssemblies/ 199 | 200 | # Node.js Tools for Visual Studio 201 | .ntvs_analysis.dat 202 | 203 | # Visual Studio 6 build log 204 | *.plg 205 | 206 | # Visual Studio 6 workspace options file 207 | *.opt 208 | 209 | # LightSwitch generated files 210 | GeneratedArtifacts/ 211 | _Pvt_Extensions/ 212 | ModelManifest.xml 213 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # XboxImageXploder 2 | XboxImageXploder is a command line tool for adding new code segments to original xbox executables (XBEs). Use it to create code caves of any size where you can place new code or data for modifications to xbes. Multiple segments can be added and it works with both retail and debug executables. 3 | 4 | ## Usage 5 | ``` 6 | XboxImageXploder.exe 7 | 8 | xbe_file: File path to the xbe file 9 | section_name: Name of the new code section 10 | section_size: Size of the new code section 11 | ``` 12 | 13 | \ 14 | Example usage to create a new segment of 8192 bytes called ".hacks": 15 | ``` 16 | XboxImageXploder.exe X:\Xbox\Test\test.xbe .hacks 8192 17 | ``` 18 | \ 19 | After the segment is created the name, virtual address, virtual size, file offset, and file size of the new segment will be printed: 20 | ``` 21 | Section Name: .hacks 22 | Virtual Address: 0x008ceda0 23 | Virtual Size: 0x00002000 24 | File Offset: 0x001c8000 25 | File Size: 0x00002000 26 | ``` 27 | 28 | The virtual address and size will tell you where in memory the segment is located and how much memory is allocated for it. The file offset and size will tell you where in the xbe file the segment is located. This information can be used for writing your new code based on the virtual memory address, and writing it to the specified file offset in the xbe file. 29 | 30 | ## Adding new code 31 | Coming soon... 32 | -------------------------------------------------------------------------------- /XboxImageXploder.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.23107.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "XboxImageXploder", "XboxImageXploder\XboxImageXploder.vcxproj", "{ADB659EE-FAF7-4553-8020-5DC198A6C022}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {ADB659EE-FAF7-4553-8020-5DC198A6C022}.Debug|x64.ActiveCfg = Debug|x64 17 | {ADB659EE-FAF7-4553-8020-5DC198A6C022}.Debug|x64.Build.0 = Debug|x64 18 | {ADB659EE-FAF7-4553-8020-5DC198A6C022}.Debug|x86.ActiveCfg = Debug|Win32 19 | {ADB659EE-FAF7-4553-8020-5DC198A6C022}.Debug|x86.Build.0 = Debug|Win32 20 | {ADB659EE-FAF7-4553-8020-5DC198A6C022}.Release|x64.ActiveCfg = Release|x64 21 | {ADB659EE-FAF7-4553-8020-5DC198A6C022}.Release|x64.Build.0 = Release|x64 22 | {ADB659EE-FAF7-4553-8020-5DC198A6C022}.Release|x86.ActiveCfg = Release|Win32 23 | {ADB659EE-FAF7-4553-8020-5DC198A6C022}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /XboxImageXploder/XboxExecutable.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | XboxImageXploder - Utility for modifying xbox executables. 3 | 4 | XboxExecutable.h - Types and functions for parsing and modifying xbox executable files. 5 | 6 | Author - Grimdoomer 7 | */ 8 | 9 | #include "XboxExecutable.h" 10 | #include 11 | 12 | XboxExecutable::XboxExecutable(std::string fileName) : sFileName(), vSectionHeaderNames(), sDebugFullFileName(), sDebugFileNameUnicode() 13 | { 14 | // Initialize fields. 15 | this->sFileName = fileName; 16 | this->hFileHandle = INVALID_HANDLE_VALUE; 17 | this->bIsValid = false; 18 | } 19 | 20 | XboxExecutable::~XboxExecutable() 21 | { 22 | // Mark the object as invalid so no one else can use it. 23 | this->bIsValid = false; 24 | 25 | // Free buffers if allocated. 26 | if (this->pSectionHeaders) 27 | { 28 | free(this->pSectionHeaders); 29 | } 30 | 31 | if (this->pLibraryVersions) 32 | { 33 | free(this->pLibraryVersions); 34 | } 35 | 36 | if (this->pbLogoBitmap) 37 | { 38 | free(this->pbLogoBitmap); 39 | } 40 | 41 | // Check to see if the file handle is still open. 42 | if (this->hFileHandle != INVALID_HANDLE_VALUE) 43 | { 44 | // Close the file handle. 45 | CloseHandle(this->hFileHandle); 46 | } 47 | } 48 | 49 | bool XboxExecutable::ReadExecutable() 50 | { 51 | bool result = false; 52 | DWORD BytesRead = 0; 53 | BYTE abHeaderData[XBE_IMAGE_HEADER_MIN_SIZE]; 54 | BYTE* pbBuffer = nullptr; 55 | 56 | // Open the image file for reading and writing. 57 | this->hFileHandle = CreateFileA(this->sFileName.c_str(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 58 | if (this->hFileHandle == INVALID_HANDLE_VALUE) 59 | { 60 | // Failed to open the file. 61 | printf("Failed to open \"%s\": %d\n", this->sFileName.c_str(), GetLastError()); 62 | return false; 63 | } 64 | 65 | // Check to make sure the file is large enough to be an executable. 66 | if (GetFileSize(this->hFileHandle, nullptr) < XBE_IMAGE_HEADER_MIN_SIZE) 67 | { 68 | // The file is too small to be a valid xbox executable. 69 | printf("File is too small to be valid!\n"); 70 | return false; 71 | } 72 | 73 | // Read enough of the header to get the true size of the image headers. 74 | if (ReadFile(this->hFileHandle, abHeaderData, XBE_IMAGE_HEADER_MIN_SIZE, &BytesRead, nullptr) == FALSE || BytesRead != XBE_IMAGE_HEADER_MIN_SIZE) 75 | { 76 | // Failed to read the image header. 77 | printf("Failed to read image header!\n"); 78 | goto Cleanup; 79 | } 80 | 81 | // Validate the size of the image header. 82 | XBE_IMAGE_HEADER* pTempHeader = (XBE_IMAGE_HEADER*)abHeaderData; 83 | if (pTempHeader->SizeOfImageHeader < XBE_IMAGE_HEADER_MIN_SIZE) 84 | { 85 | // Image header size is invalid. 86 | printf("Xbe image header size is invalid!\n"); 87 | goto Cleanup; 88 | } 89 | 90 | // Allocate a buffer we can use to read the executable header. 91 | DWORD headersSize = pTempHeader->SizeOfHeaders; 92 | pbBuffer = (PBYTE)malloc(headersSize); 93 | if (pbBuffer == nullptr) 94 | { 95 | // Not enough memory for allocation. 96 | printf("Failed to allocate memory for header data!\n"); 97 | return false; 98 | } 99 | 100 | // Seek back to the start of the image. 101 | SetFilePointer(this->hFileHandle, 0, nullptr, FILE_BEGIN); 102 | 103 | // Read the image header. 104 | if (ReadFile(this->hFileHandle, pbBuffer, headersSize, &BytesRead, nullptr) == FALSE || BytesRead != headersSize) 105 | { 106 | // Failed to read the image header. 107 | printf("Failed to read image header!\n"); 108 | goto Cleanup; 109 | } 110 | 111 | // Check if the xbe header is valid. 112 | this->sHeader = *(XBE_IMAGE_HEADER*)pbBuffer; 113 | if (this->sHeader.Magic != XBE_IMAGE_HEADER_MAGIC) 114 | { 115 | // Xbe header is invalid. 116 | printf("Xbe header has invalid magic!\n"); 117 | goto Cleanup; 118 | } 119 | 120 | // Clear additional fields if they are not used. 121 | memset((PBYTE)&this->sHeader + this->sHeader.SizeOfImageHeader, 0, sizeof(XBE_IMAGE_HEADER) - this->sHeader.SizeOfImageHeader); 122 | 123 | // Check the size of the certificate is valid. 124 | this->sCertificate = *(XBE_IMAGE_CERTIFICATE*)(pbBuffer + XBE_HEADER_OFFSET_OF(&this->sHeader, this->sHeader.CertificateAddress)); 125 | if (this->sCertificate.Size < XBE_IMAGE_CERTIFICATE_MIN_SIZE) 126 | { 127 | // Xbe certificate has invalid size. 128 | printf("Xbe certificate has invalid size!\n"); 129 | goto Cleanup; 130 | } 131 | 132 | // Clear additional fields if they are not used. 133 | memset((PBYTE)&this->sCertificate + this->sCertificate.Size, 0, sizeof(XBE_IMAGE_CERTIFICATE) - this->sCertificate.Size); 134 | 135 | // Allocate memory for the section headers. 136 | this->pSectionHeaders = (XBE_IMAGE_SECTION_HEADER*)malloc(this->sHeader.NumberOfSections * sizeof(XBE_IMAGE_SECTION_HEADER)); 137 | if (this->pSectionHeaders == nullptr) 138 | { 139 | // Failed to allocate memory for section headers. 140 | printf("Failed to allocate memory for section headers!\n"); 141 | goto Cleanup; 142 | } 143 | 144 | // Loop and read all of the section headers. 145 | for (int i = 0; i < this->sHeader.NumberOfSections; i++) 146 | { 147 | // Read the section header. 148 | this->pSectionHeaders[i] = *(XBE_IMAGE_SECTION_HEADER*)(pbBuffer + 149 | XBE_HEADER_OFFSET_OF(&this->sHeader, this->sHeader.SectionHeadersAddress) + (i * sizeof(XBE_IMAGE_SECTION_HEADER))); 150 | 151 | // Check if the section header has a name. 152 | if (this->pSectionHeaders[i].SectionNameAddress) 153 | { 154 | // Save the section header name. 155 | char *pNamePtr = (char*)pbBuffer + XBE_HEADER_OFFSET_OF(&this->sHeader, this->pSectionHeaders[i].SectionNameAddress); 156 | this->vSectionHeaderNames.push_back(std::string(pNamePtr)); 157 | } 158 | else 159 | { 160 | // No name, this should never happen. 161 | this->vSectionHeaderNames.push_back(std::string()); 162 | } 163 | } 164 | 165 | // Check if there are import modules and if so read the import table. 166 | if (this->sHeader.ImportTableAddress > 0) 167 | { 168 | // Loop and read all the import table entries. 169 | XBE_IMAGE_IMPORT_DESCRIPTOR* pImportDescriptor = (XBE_IMAGE_IMPORT_DESCRIPTOR*)(pbBuffer + XBE_HEADER_OFFSET_OF(&this->sHeader, this->sHeader.ImportTableAddress)); 170 | while (pImportDescriptor->ImageThunkData != 0) 171 | { 172 | // Save the import module name. 173 | WCHAR* pNamePtr = (WCHAR*)(pbBuffer + XBE_HEADER_OFFSET_OF(&this->sHeader, pImportDescriptor->ModuleNameAddress)); 174 | this->mImportDirectory.emplace(pImportDescriptor->ImageThunkData, std::wstring(pNamePtr)); 175 | 176 | // Next import entry. 177 | pImportDescriptor++; 178 | } 179 | } 180 | 181 | // Allocate memory for the library versions. 182 | this->pLibraryVersions = (XBOX_LIBRARY_VERSION*)malloc(this->sHeader.NumberOfLibraryVersions * sizeof(XBOX_LIBRARY_VERSION)); 183 | if (this->pLibraryVersions == nullptr) 184 | { 185 | // Failed to allocate memory for library versions array. 186 | printf("Failed to allocate memory for library versions!\n"); 187 | goto Cleanup; 188 | } 189 | 190 | // Loop and read all of the library versions. 191 | for (int i = 0; i < this->sHeader.NumberOfLibraryVersions; i++) 192 | { 193 | this->pLibraryVersions[i] = *(XBOX_LIBRARY_VERSION*)(pbBuffer + 194 | XBE_HEADER_OFFSET_OF(&this->sHeader, this->sHeader.LibraryVersionsAddress) + (i * sizeof(XBOX_LIBRARY_VERSION))); 195 | } 196 | 197 | // Check if there are library features and if so read them. 198 | if (this->sHeader.NumberOfLibraryFeatures > 0) 199 | { 200 | // Allocate memory for the library features. 201 | this->pLibraryFeatures = (XBOX_LIBRARY_VERSION*)malloc(this->sHeader.NumberOfLibraryFeatures * sizeof(XBOX_LIBRARY_VERSION)); 202 | if (this->pLibraryFeatures == nullptr) 203 | { 204 | // Failed to allocate memory for library features array. 205 | printf("Failed to allocate memory for library features!\n"); 206 | goto Cleanup; 207 | } 208 | 209 | // Loop and read all of the library features. 210 | for (int i = 0; i < this->sHeader.NumberOfLibraryFeatures; i++) 211 | { 212 | this->pLibraryFeatures[i] = *(XBOX_LIBRARY_VERSION*)(pbBuffer + 213 | XBE_HEADER_OFFSET_OF(&this->sHeader, this->sHeader.LibraryFeaturesAddress) + (i * sizeof(XBOX_LIBRARY_VERSION))); 214 | } 215 | } 216 | 217 | // Check if the code view debug info address is valid. 218 | if (this->sHeader.CodeViewDebugInfoAddress != NULL) 219 | { 220 | // Not sure how to handle this yet... 221 | this->sHeader.CodeViewDebugInfoAddress = 0; 222 | //DebugBreak(); 223 | } 224 | 225 | // Fixup library version addresses. 226 | if (this->sHeader.KernelLibraryVersionAddress) 227 | this->sHeader.KernelLibraryVersionAddress -= this->sHeader.LibraryVersionsAddress; 228 | if (this->sHeader.XAPILibraryVersionAddress) 229 | this->sHeader.XAPILibraryVersionAddress -= this->sHeader.LibraryVersionsAddress; 230 | 231 | // Read the debug file names. 232 | if (this->sHeader.FullFileNameAddress) 233 | this->sDebugFullFileName = (CHAR*)(pbBuffer + XBE_HEADER_OFFSET_OF(&this->sHeader, this->sHeader.FullFileNameAddress)); 234 | if (this->sHeader.FileNameAddress) 235 | this->sHeader.FileNameAddress -= this->sHeader.FullFileNameAddress; 236 | if (this->sHeader.UnicodeFileNameAddress) 237 | this->sDebugFileNameUnicode = (WCHAR*)(pbBuffer + XBE_HEADER_OFFSET_OF(&this->sHeader, this->sHeader.UnicodeFileNameAddress)); 238 | 239 | // Allocate memory for the logo bitmap. 240 | this->pbLogoBitmap = (BYTE*)malloc(this->sHeader.LogoBitmapSize); 241 | if (this->pbLogoBitmap == nullptr) 242 | { 243 | // Failed to allocate memory for the logo bitmap. 244 | printf("Failed to allocate memory for the logo bitmap!\n"); 245 | goto Cleanup; 246 | } 247 | 248 | // Copy the logo bitmap data. 249 | memcpy(this->pbLogoBitmap, pbBuffer + XBE_HEADER_OFFSET_OF(&this->sHeader, this->sHeader.LogoBitmapAddress), this->sHeader.LogoBitmapSize); 250 | 251 | // Successfully read the image header. 252 | result = this->bIsValid = true; 253 | 254 | Cleanup: 255 | // Free the temporary header buffer. 256 | free(pbBuffer); 257 | 258 | return result; 259 | } 260 | 261 | bool XboxExecutable::AddSectionForHacks(std::string sectionName, int sectionSize) 262 | { 263 | DWORD BytesWritten = 0; 264 | 265 | // Check to make sure the executable was loaded and is valid. 266 | if (this->bIsValid == false) 267 | return false; 268 | 269 | // Allocate a new array for the section headers. 270 | XBE_IMAGE_SECTION_HEADER *pNewSectionHeaders = (XBE_IMAGE_SECTION_HEADER*)malloc(sizeof(XBE_IMAGE_SECTION_HEADER) * (this->sHeader.NumberOfSections + 1)); 271 | if (pNewSectionHeaders == nullptr) 272 | { 273 | // Failed to allocate memory for new section header array. 274 | printf("Failed to allocate memory for new section headers!\n"); 275 | return false; 276 | } 277 | 278 | // Copy the old section headers into the new array. 279 | memcpy(pNewSectionHeaders, this->pSectionHeaders, this->sHeader.NumberOfSections * sizeof(XBE_IMAGE_SECTION_HEADER)); 280 | 281 | // Free the old array and assign the new pointer. 282 | free(this->pSectionHeaders); 283 | this->pSectionHeaders = pNewSectionHeaders; 284 | this->sHeader.NumberOfSections += 1; 285 | 286 | // Pointers for easy access. 287 | XBE_IMAGE_SECTION_HEADER *pNewSection = &this->pSectionHeaders[this->sHeader.NumberOfSections - 1]; 288 | XBE_IMAGE_SECTION_HEADER *pLastSection = &this->pSectionHeaders[this->sHeader.NumberOfSections - 2]; 289 | 290 | // Initialize the new section header. 291 | memset(pNewSection, 0, sizeof(XBE_IMAGE_SECTION_HEADER)); 292 | pNewSection->SectionFlags = (XBE_SECTION_FLAGS_WRITABLE | XBE_SECTION_FLAGS_PRELOAD | XBE_SECTION_FLAGS_EXECUTABLE); 293 | pNewSection->VirtualAddress = ALIGN_TO(pLastSection->VirtualAddress + pLastSection->VirtualSize, 4096); 294 | pNewSection->VirtualSize = ALIGN_TO(sectionSize, 4); 295 | pNewSection->RawAddress = ALIGN_TO(pLastSection->RawAddress + pLastSection->RawSize, 4096); 296 | pNewSection->RawSize = ALIGN_TO(sectionSize, 4); 297 | pNewSection->SectionNameReferenceCount = 0; 298 | 299 | // Save the section header name. 300 | this->vSectionHeaderNames.push_back(sectionName); 301 | 302 | // Some xbe files will contain the original PE headers and include that data and the logo bitmap into SizeOfHeaders. Others 303 | // don't and SizeOfHeaders does not include the size of the logo bitmap. To make things easier we set SizeOfHeaders to the absolute 304 | // maximum header size possible based on the virtual address of the first image section. 305 | this->sHeader.SizeOfHeaders = this->pSectionHeaders[0].VirtualAddress - this->sHeader.BaseAddress; 306 | 307 | // Check if the xbe has a valid PE header. 308 | bool hasPeHeaders = false; 309 | if (this->sHeader.PEBaseAddress > 0) 310 | { 311 | WORD wMagic = 0; 312 | 313 | // Seek to where the PE headers should start and check the magic value. 314 | SetFilePointer(this->hFileHandle, this->sHeader.PEBaseAddress - this->sHeader.BaseAddress, NULL, FILE_BEGIN); 315 | if (ReadFile(this->hFileHandle, &wMagic, 2, &BytesWritten, NULL) == FALSE || BytesWritten != 2) 316 | { 317 | // Failed to read PE header magic. 318 | printf("Failed to read PE header data!\n"); 319 | return false; 320 | } 321 | 322 | // Check if the xbe contains the original PE headers. 323 | hasPeHeaders = wMagic == 'ZM'; 324 | } 325 | 326 | // Calculate how much space we have to work with based on whether or not the image has a valid PE header. 327 | DWORD headerSizeRemaining = 0; 328 | DWORD logoBitmapEndOffset = (this->sHeader.LogoBitmapAddress - this->sHeader.BaseAddress) + this->sHeader.LogoBitmapSize; 329 | if (hasPeHeaders == true) 330 | headerSizeRemaining = (this->sHeader.PEBaseAddress - this->sHeader.BaseAddress) - logoBitmapEndOffset; 331 | else 332 | headerSizeRemaining = this->sHeader.SizeOfHeaders - logoBitmapEndOffset; 333 | 334 | // Calculate the expected size increase and check if there's enough room in the header. We add an additional 16 bytes here to account 335 | // for padding on data that has moved around and may increase/decrease in size (it's not very scientific and should be calculated in a 336 | // more accurate way). 337 | DWORD headerSizeRequired = ALIGN_TO(sizeof(XBE_IMAGE_SECTION_HEADER) + sectionName.length() + 16, 4); 338 | if (headerSizeRequired > headerSizeRemaining) 339 | { 340 | // Check if the image still has the PE headers and determine if discarding them will help. 341 | if (hasPeHeaders == true && this->sHeader.SizeOfHeaders - logoBitmapEndOffset >= headerSizeRequired) 342 | { 343 | // Discard the PE headers to make room for the new section headers. 344 | printf("Not enough space in XBE header to add new section data, PE headers will be discarded...\n"); 345 | this->sHeader.PEBaseAddress = 0; 346 | hasPeHeaders = false; 347 | } 348 | else 349 | { 350 | // Not enough space remaining in the header to add a new section. 351 | printf("Not enough space in XBE header to add new section data! Adding a new section not possible!\n"); 352 | return false; 353 | } 354 | } 355 | 356 | // Allocate a new buffer for the header data. 357 | BYTE *pbNewHeader = (PBYTE)malloc(this->sHeader.SizeOfHeaders); 358 | if (pbNewHeader == nullptr) 359 | { 360 | // Failed to allocate memory for new header buffer. 361 | printf("Failed to allocate memory for new header buffer!\n"); 362 | return false; 363 | } 364 | 365 | // Initialize the new header buffer. 366 | memset(pbNewHeader, 0, this->sHeader.SizeOfHeaders); 367 | 368 | // Copy the xbe header to the new buffer. 369 | XBE_IMAGE_HEADER *pXbeHeader = (XBE_IMAGE_HEADER*)pbNewHeader; 370 | *pXbeHeader = this->sHeader; 371 | pXbeHeader->SizeOfImageHeader = this->sHeader.SizeOfImageHeader; 372 | 373 | // Copy the xbe certificate to the new buffer. 374 | XBE_IMAGE_CERTIFICATE *pCertificate = (XBE_IMAGE_CERTIFICATE*)ALIGN_TO(((PBYTE)pXbeHeader + pXbeHeader->SizeOfImageHeader), 4); 375 | *pCertificate = this->sCertificate; 376 | 377 | // Update certificate address. 378 | pXbeHeader->CertificateAddress = XBE_HEADER_ADDRESS_OF(pXbeHeader, pCertificate); 379 | 380 | // Copy section headers to the new buffer. 381 | XBE_IMAGE_SECTION_HEADER *pSectionHeaders = (XBE_IMAGE_SECTION_HEADER*)ALIGN_TO((PBYTE)pCertificate + this->sCertificate.Size, 4); 382 | memcpy(pSectionHeaders, this->pSectionHeaders, sizeof(XBE_IMAGE_SECTION_HEADER) * pXbeHeader->NumberOfSections); 383 | 384 | // Update the section pointer to our new section. 385 | pNewSection = &pSectionHeaders[pXbeHeader->NumberOfSections - 1]; 386 | 387 | // Update the section headers address. 388 | pXbeHeader->SectionHeadersAddress = XBE_HEADER_ADDRESS_OF(pXbeHeader, pSectionHeaders); 389 | 390 | // Loop through all of the section headers and correct the section name addresses. 391 | WORD *pSharedPagePtr = (WORD*)ALIGN_TO(pSectionHeaders + pXbeHeader->NumberOfSections, 4); 392 | char *pNamePtr = (char*)ALIGN_TO(pSharedPagePtr + pXbeHeader->NumberOfSections + 1, 4); 393 | for (int i = 0; i < pXbeHeader->NumberOfSections; i++) 394 | { 395 | // Update the section header shared head/tail page address. 396 | pSectionHeaders[i].HeadSharedPageReferenceCount = XBE_HEADER_ADDRESS_OF(pXbeHeader, pSharedPagePtr + i); 397 | pSectionHeaders[i].TailSharedPageReferenceCount = XBE_HEADER_ADDRESS_OF(pXbeHeader, pSharedPagePtr + i + 1); 398 | 399 | // Update the section name address. 400 | pSectionHeaders[i].SectionNameAddress = XBE_HEADER_ADDRESS_OF(pXbeHeader, pNamePtr); 401 | 402 | // Write name to buffer. 403 | strcpy(pNamePtr, this->vSectionHeaderNames.at(i).c_str()); 404 | pNamePtr += this->vSectionHeaderNames.at(i).size() + 1; 405 | } 406 | 407 | // Check if the module contains an import table. 408 | if (pXbeHeader->ImportTableAddress > 0) 409 | { 410 | // Update the import table address. 411 | pNamePtr = (char*)ALIGN_TO(pNamePtr, 4); 412 | pXbeHeader->ImportTableAddress = XBE_HEADER_ADDRESS_OF(pXbeHeader, pNamePtr); 413 | pNamePtr += sizeof(XBE_IMAGE_IMPORT_DESCRIPTOR) * (this->mImportDirectory.size() + 1); 414 | 415 | // Loop and write module import data. 416 | XBE_IMAGE_IMPORT_DESCRIPTOR* pImportDescriptor = (XBE_IMAGE_IMPORT_DESCRIPTOR*)((BYTE*)pXbeHeader + XBE_HEADER_OFFSET_OF(pXbeHeader, pXbeHeader->ImportTableAddress)); 417 | for (auto iter = this->mImportDirectory.begin(); iter != this->mImportDirectory.end(); iter++) 418 | { 419 | // Write the import entry. 420 | pImportDescriptor->ImageThunkData = iter->first; 421 | pImportDescriptor->ModuleNameAddress = XBE_HEADER_ADDRESS_OF(pXbeHeader, pNamePtr); 422 | 423 | // Write name to buffer. 424 | lstrcpyW((WCHAR*)pNamePtr, iter->second.c_str()); 425 | pNamePtr += (iter->second.size() + 1) * sizeof(wchar_t); 426 | 427 | // Next import entry. 428 | pImportDescriptor++; 429 | } 430 | 431 | // Write a null entry to signal the end of the import table. 432 | pImportDescriptor->ImageThunkData = 0; 433 | pImportDescriptor->ModuleNameAddress = 0; 434 | } 435 | 436 | // Copy library versions to the new buffer. 437 | XBOX_LIBRARY_VERSION *pLibraryVersions = (XBOX_LIBRARY_VERSION*)ALIGN_TO(pNamePtr, 4); 438 | memcpy(pLibraryVersions, this->pLibraryVersions, sizeof(XBOX_LIBRARY_VERSION) * pXbeHeader->NumberOfLibraryVersions); 439 | 440 | // Update the library version addresses. 441 | pXbeHeader->LibraryVersionsAddress = XBE_HEADER_ADDRESS_OF(pXbeHeader, pLibraryVersions); 442 | pXbeHeader->KernelLibraryVersionAddress += pXbeHeader->LibraryVersionsAddress; 443 | pXbeHeader->XAPILibraryVersionAddress += pXbeHeader->LibraryVersionsAddress; 444 | 445 | // Setup pointer to additional header data. 446 | BYTE *pbNextPointer = (PBYTE)(pLibraryVersions + pXbeHeader->NumberOfLibraryVersions); 447 | 448 | // Check the original size of the header to determine if it was possible to have library features or not. 449 | if (this->sHeader.SizeOfImageHeader > FIELD_OFFSET(XBE_IMAGE_HEADER, LibraryFeaturesAddress)) 450 | { 451 | // Check if there are library features, and if so copy them to the new buffer. 452 | if (pXbeHeader->NumberOfLibraryFeatures > 0) 453 | { 454 | // Copy library features to the new buffer. 455 | XBOX_LIBRARY_VERSION *pLibraryFeatures = (XBOX_LIBRARY_VERSION*)ALIGN_TO(pLibraryVersions + pXbeHeader->NumberOfLibraryVersions, 4); 456 | memcpy(pLibraryFeatures, this->pLibraryFeatures, sizeof(XBOX_LIBRARY_VERSION) * pXbeHeader->NumberOfLibraryFeatures); 457 | 458 | // Update the library features address. 459 | pXbeHeader->LibraryFeaturesAddress = XBE_HEADER_ADDRESS_OF(pXbeHeader, pLibraryFeatures); 460 | pbNextPointer += (DWORD)(pXbeHeader->NumberOfLibraryFeatures * sizeof(XBOX_LIBRARY_VERSION)); 461 | } 462 | } 463 | 464 | // Copy the debug file name (unicode). 465 | wchar_t *pDebugNameUnic = (wchar_t*)ALIGN_TO(pbNextPointer, 4); 466 | lstrcpyW(pDebugNameUnic, this->sDebugFileNameUnicode.c_str()); 467 | 468 | // Copy the debug file name. 469 | char *pDebugFileName = (char*)ALIGN_TO(pDebugNameUnic + this->sDebugFileNameUnicode.size() + 1, 4); 470 | strcpy(pDebugFileName, this->sDebugFullFileName.c_str()); 471 | 472 | // Update debug file name addresses. 473 | pXbeHeader->UnicodeFileNameAddress = XBE_HEADER_ADDRESS_OF(pXbeHeader, pDebugNameUnic); 474 | pXbeHeader->FullFileNameAddress = XBE_HEADER_ADDRESS_OF(pXbeHeader, pDebugFileName); 475 | pXbeHeader->FileNameAddress = pXbeHeader->FullFileNameAddress + (this->sDebugFullFileName.size() - this->sDebugFileNameUnicode.size()); 476 | 477 | // Copy the logo bitmap data. 478 | BYTE *pbBitmapData = (BYTE*)ALIGN_TO(pDebugFileName + this->sDebugFullFileName.size() + 1, 4); 479 | memcpy(pbBitmapData, this->pbLogoBitmap, pXbeHeader->LogoBitmapSize); 480 | 481 | // Update the logo bitmap data address. 482 | pXbeHeader->LogoBitmapAddress = XBE_HEADER_ADDRESS_OF(pXbeHeader, pbBitmapData); 483 | 484 | // Update the image size. 485 | pXbeHeader->SizeOfImage += ALIGN_TO(pNewSection->VirtualSize, 4); 486 | 487 | // Check if we need to copy in the original PE headers. 488 | DWORD imageDataStart = FindImageDataStartOffset(); 489 | if (hasPeHeaders == true) 490 | { 491 | // Seek to the start of the PE headers. 492 | DWORD peHeaderOffset = this->sHeader.PEBaseAddress - this->sHeader.BaseAddress; 493 | SetFilePointer(this->hFileHandle, peHeaderOffset, NULL, FILE_BEGIN); 494 | 495 | DWORD peHeadersSize = pXbeHeader->SizeOfHeaders - peHeaderOffset; 496 | BYTE* pNewPeHeaders = (BYTE*)pXbeHeader + (pXbeHeader->SizeOfHeaders - peHeadersSize); 497 | 498 | // Read the PE headers into the new header buffer. 499 | if (ReadFile(this->hFileHandle, pNewPeHeaders, peHeadersSize, &BytesWritten, NULL) == FALSE || BytesWritten != peHeadersSize) 500 | { 501 | // Failed to read in pe headers. 502 | printf("Failed to read original PE headers %d\n", GetLastError()); 503 | return false; 504 | } 505 | 506 | // Update the PE headers address. 507 | pXbeHeader->PEBaseAddress = pXbeHeader->BaseAddress + (pXbeHeader->SizeOfHeaders - peHeadersSize); 508 | } 509 | 510 | // Seek to the beginning of the file and write the new image header. 511 | SetFilePointer(this->hFileHandle, 0, nullptr, FILE_BEGIN); 512 | if (WriteFile(this->hFileHandle, pbNewHeader, pXbeHeader->SizeOfHeaders, &BytesWritten, nullptr) == FALSE || BytesWritten != pXbeHeader->SizeOfHeaders) 513 | { 514 | // Failed to write new image headers. 515 | printf("Failed to write new image headers to file!\n"); 516 | return false; 517 | } 518 | 519 | // Allocate an empty buffer to write to the file for the new section. 520 | DWORD NewSectionSize = ALIGN_TO(sectionSize, 0x1000); 521 | BYTE *pbBlankData = (PBYTE)malloc(NewSectionSize); 522 | if (pbBlankData == nullptr) 523 | { 524 | // Failed to allocate blank data for new section. 525 | printf("Failed to allocate blank data for new section!\n"); 526 | return false; 527 | } 528 | 529 | // Initialize the data to all 00s. 530 | memset(pbBlankData, 0, NewSectionSize); 531 | 532 | // Seek to the end of the file and write the blank data. 533 | SetFilePointer(this->hFileHandle, 0, nullptr, FILE_END); 534 | 535 | // Write the new section data. 536 | if (WriteFile(this->hFileHandle, pbBlankData, NewSectionSize, &BytesWritten, nullptr) == FALSE || BytesWritten != NewSectionSize) 537 | { 538 | // Failed to write new section data to the file. 539 | printf("Failed to write new section data to file!\n"); 540 | return false; 541 | } 542 | 543 | // Print the new section info. 544 | printf("\nSection Name: \t\t%s\n", sectionName.c_str()); 545 | printf("Virtual Address: \t0x%08x\n", pNewSection->VirtualAddress); 546 | printf("Virtual Size: \t\t0x%08x\n", pNewSection->VirtualSize); 547 | printf("File Offset: \t\t0x%08x\n", pNewSection->RawAddress); 548 | printf("File Size: \t\t0x%08x\n\n", pNewSection->RawSize); 549 | 550 | // Free temp buffers. 551 | free(pbBlankData); 552 | free(pbNewHeader); 553 | 554 | // Successfully added the new section to the image. 555 | return true; 556 | } 557 | 558 | DWORD XboxExecutable::FindImageDataStartOffset() 559 | { 560 | DWORD lowestOffset = 0xFFFFFFFF; 561 | 562 | // Loop through all the sections and find the lowest image offset. 563 | for (int i = 0; i < this->sHeader.NumberOfSections; i++) 564 | { 565 | // Check if this section is the lowest we've seen so far. 566 | if (this->pSectionHeaders[i].RawAddress < lowestOffset) 567 | lowestOffset = this->pSectionHeaders[i].RawAddress; 568 | } 569 | 570 | return lowestOffset; 571 | } -------------------------------------------------------------------------------- /XboxImageXploder/XboxExecutable.h: -------------------------------------------------------------------------------- 1 | /* 2 | XboxImageXploder - Utility for modifying xbox executables. 3 | 4 | XboxExecutable.h - Types and functions for parsing and modifying xbox executable files. 5 | 6 | Author - Grimdoomer 7 | */ 8 | 9 | #pragma once 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | // --------------------------------------------------------------------------------------- 16 | // Types 17 | // --------------------------------------------------------------------------------------- 18 | 19 | #define XBE_IMAGE_HEADER_MAGIC 'HEBX' 20 | 21 | #define XBE_IMAGE_HEADER_MIN_SIZE 0x170 22 | 23 | #define XBE_IMAGE_SIGNATURE_LENGTH 256 24 | #define XBE_IMAGE_SYMMETRICAL_KEY_LENGTH 16 25 | #define XBE_IMAGE_DIGEST_LENGTH 20 26 | 27 | #define XBE_IMAGE_FLAGS_MOUNT_UTILITY_DRIVE 1 28 | 29 | #define XBE_IMAGE_ENTRYPOINT_XOR_DEBUG 0x94859D4B 30 | #define XBE_IMAGE_ENTRYPOINT_XOR_RETAIL 0xA8FC57AB 31 | 32 | #define XBE_IMAGE_THUNK_ADDRESS_XOR_DEBUG 0xEFB1F152 33 | #define XBE_IMAGE_THUNK_ADDRESS_XOR_RETAIL 0x5B6D40B6 34 | 35 | #define XBE_HEADER_OFFSET_OF(header, addr) (addr - (header)->BaseAddress) 36 | 37 | #define XBE_HEADER_ADDRESS_OF(header, ptr) (((DWORD)((char*)(ptr) - (char*)header)) + (header)->BaseAddress) 38 | 39 | #define ALIGN_TO(addr, align) ((size_t)(addr) + (((size_t)(addr) % align) == 0 ? 0 : align - ((size_t)(addr) % align))) 40 | 41 | struct XBE_IMAGE_HEADER 42 | { 43 | /* 0x00 */ DWORD Magic; 44 | /* 0x04 */ BYTE Signature[XBE_IMAGE_SIGNATURE_LENGTH]; 45 | /* 0x104 */ DWORD BaseAddress; 46 | /* 0x108 */ DWORD SizeOfHeaders; 47 | /* 0x10C */ DWORD SizeOfImage; 48 | /* 0x110 */ DWORD SizeOfImageHeader; 49 | /* 0x114 */ DWORD CreationTimestamp; 50 | /* 0x118 */ DWORD CertificateAddress; 51 | /* 0x11C */ DWORD NumberOfSections; 52 | /* 0x120 */ DWORD SectionHeadersAddress; 53 | /* 0x124 */ DWORD ImageFlags; 54 | /* 0x128 */ DWORD EntryPoint; 55 | /* 0x12C */ DWORD TLSAddress; 56 | /* 0x130 */ DWORD PEStackCommit; 57 | /* 0x134 */ DWORD PEHeapReserve; 58 | /* 0x138 */ DWORD PEHeapCommit; 59 | /* 0x13C */ DWORD PEBaseAddress; // From the original PE header, may be NULL or not correlate with XBE headers 60 | /* 0x140 */ DWORD PESizeOfImage; 61 | /* 0x144 */ DWORD PEChecksum; 62 | /* 0x148 */ DWORD PETimestamp; 63 | /* 0x14C */ DWORD FullFileNameAddress; 64 | /* 0x150 */ DWORD FileNameAddress; 65 | /* 0x154 */ DWORD UnicodeFileNameAddress; 66 | /* 0x158 */ DWORD KernelImageThunkAddress; 67 | /* 0x15C */ DWORD ImportTableAddress; 68 | /* 0x160 */ DWORD NumberOfLibraryVersions; 69 | /* 0x164 */ DWORD LibraryVersionsAddress; 70 | /* 0x168 */ DWORD KernelLibraryVersionAddress; 71 | /* 0x16C */ DWORD XAPILibraryVersionAddress; 72 | /* 0x170 */ DWORD LogoBitmapAddress; 73 | /* 0x174 */ DWORD LogoBitmapSize; 74 | /* 0x178 */ DWORD LibraryFeaturesAddress; 75 | /* 0x17C */ DWORD NumberOfLibraryFeatures; 76 | /* 0x180 */ DWORD CodeViewDebugInfoAddress; 77 | }; 78 | 79 | #define XBE_IMAGE_CERT_TITLE_NAME_LENGTH 40 80 | 81 | #define XBE_IMAGE_CERTIFICATE_MIN_SIZE 0x1D0 82 | 83 | struct XBE_IMAGE_CERTIFICATE 84 | { 85 | /* 0x00 */ DWORD Size; 86 | /* 0x04 */ DWORD CreationTimestmap; 87 | /* 0x08 */ DWORD TitleID; 88 | /* 0x0C */ WCHAR TitleName[XBE_IMAGE_CERT_TITLE_NAME_LENGTH]; 89 | /* 0x5C */ DWORD AlternateTitleIDs[16]; 90 | /* 0x9C */ DWORD MediaFlags; 91 | /* 0xA0 */ DWORD GameRegion; 92 | /* 0xA4 */ DWORD GameRatings; 93 | /* 0xA8 */ DWORD DiskNumber; 94 | /* 0xAC */ DWORD Version; 95 | /* 0xB0 */ CHAR LANKey[XBE_IMAGE_SYMMETRICAL_KEY_LENGTH]; 96 | /* 0xC0 */ CHAR SignatureKey[XBE_IMAGE_SYMMETRICAL_KEY_LENGTH]; 97 | /* 0xD0 */ CHAR AlternateSignatureKeys[16][XBE_IMAGE_SYMMETRICAL_KEY_LENGTH]; 98 | /* 0x1D0 */ DWORD OriginalSizeOfCertificate; 99 | /* 0x1D4 */ DWORD OnlineServiceName; 100 | /* 0x1D8 */ DWORD RuntimeSecurityFlags; 101 | /* 0x1DC */ CHAR UnknownKey[XBE_IMAGE_SYMMETRICAL_KEY_LENGTH]; 102 | }; 103 | 104 | #define XBE_SECTION_FLAGS_WRITABLE 0x00000001 105 | #define XBE_SECTION_FLAGS_PRELOAD 0x00000002 106 | #define XBE_SECTION_FLAGS_EXECUTABLE 0x00000004 107 | #define XBE_SECTION_FLAGS_INSERTED_FILE 0x00000008 108 | #define XBE_SECTION_FLAGS_HEAD_PAGE_READ_ONLY 0x00000010 109 | #define XBE_SECTION_FLAGS_TAIL_PAGE_READ_ONLY 0x00000020 110 | 111 | struct XBE_IMAGE_SECTION_HEADER 112 | { 113 | /* 0x00 */ DWORD SectionFlags; 114 | /* 0x04 */ DWORD VirtualAddress; 115 | /* 0x08 */ DWORD VirtualSize; 116 | /* 0x0C */ DWORD RawAddress; 117 | /* 0x10 */ DWORD RawSize; 118 | /* 0x14 */ DWORD SectionNameAddress; 119 | /* 0x18 */ DWORD SectionNameReferenceCount; 120 | /* 0x1C */ DWORD HeadSharedPageReferenceCount; 121 | /* 0x20 */ DWORD TailSharedPageReferenceCount; 122 | /* 0x24 */ CHAR SectionDigest[XBE_IMAGE_DIGEST_LENGTH]; 123 | }; 124 | 125 | struct XBOX_LIBRARY_VERSION 126 | { 127 | /* 0x00 */ CHAR LibraryName[8]; 128 | /* 0x08 */ WORD MajorVersion; 129 | /* 0x0A */ WORD MinorVersion; 130 | /* 0x0C */ WORD BuildVersion; 131 | /* 0x0E */ WORD Flags; 132 | }; 133 | 134 | struct XBE_IMAGE_IMPORT_DESCRIPTOR 135 | { 136 | /* 0x00 */ DWORD ImageThunkData; 137 | /* 0x04 */ DWORD ModuleNameAddress; 138 | }; 139 | 140 | // --------------------------------------------------------------------------------------- 141 | // XboxExecutable 142 | // --------------------------------------------------------------------------------------- 143 | class XboxExecutable 144 | { 145 | private: 146 | std::string sFileName; 147 | HANDLE hFileHandle; 148 | 149 | bool bIsValid; 150 | XBE_IMAGE_HEADER sHeader; 151 | XBE_IMAGE_CERTIFICATE sCertificate; 152 | 153 | XBE_IMAGE_SECTION_HEADER *pSectionHeaders; 154 | std::vector vSectionHeaderNames; 155 | 156 | std::map mImportDirectory; 157 | 158 | XBOX_LIBRARY_VERSION *pLibraryVersions; 159 | XBOX_LIBRARY_VERSION *pLibraryFeatures; 160 | 161 | std::string sDebugFullFileName; 162 | std::wstring sDebugFileNameUnicode; 163 | 164 | BYTE *pbLogoBitmap; 165 | 166 | DWORD FindImageDataStartOffset(); 167 | 168 | public: 169 | XboxExecutable(std::string fileName); 170 | ~XboxExecutable(); 171 | 172 | bool ReadExecutable(); 173 | 174 | bool AddSectionForHacks(std::string sectionName, int sectionSize); 175 | }; -------------------------------------------------------------------------------- /XboxImageXploder/XboxImageXploder.cpp: -------------------------------------------------------------------------------- 1 | // XboxImageXploder.cpp : Defines the entry point for the console application. 2 | // 3 | 4 | #include 5 | #include 6 | #include "XboxExecutable.h" 7 | 8 | void PrintUse() 9 | { 10 | printf("XboxImageXploder.exe \n\n"); 11 | } 12 | 13 | int main(int argc, char **argv) 14 | { 15 | printf("XboxImageXploder v1.2 by Grimdoomer\n\n"); 16 | 17 | // Check if the correct number of arguments were provided. 18 | if (argc != 4) 19 | { 20 | // Invalid number of arguments. 21 | PrintUse(); 22 | return 0; 23 | } 24 | 25 | // Parse the arguments. 26 | std::string sFileName(argv[1]); 27 | std::string sSectionName(argv[2]); 28 | int sectionSize = atoi(argv[3]); 29 | 30 | // Create a new XboxExecutable object and try to read it. 31 | XboxExecutable *pXbe = new XboxExecutable(sFileName); 32 | if (pXbe->ReadExecutable() == false) 33 | { 34 | // Failed to read xbe. 35 | delete pXbe; 36 | return 0; 37 | } 38 | 39 | // Try to add the new section to the executable. 40 | if (pXbe->AddSectionForHacks(sSectionName, sectionSize) == false) 41 | { 42 | // Failed to add new section to the file. 43 | delete pXbe; 44 | return 0; 45 | } 46 | 47 | // Successfully added the new section. 48 | printf("Successfully added new section to image!\n"); 49 | return 0; 50 | } 51 | 52 | -------------------------------------------------------------------------------- /XboxImageXploder/XboxImageXploder.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {ADB659EE-FAF7-4553-8020-5DC198A6C022} 23 | Win32Proj 24 | XboxImageXploder 25 | 10.0 26 | 27 | 28 | 29 | Application 30 | true 31 | v143 32 | Unicode 33 | 34 | 35 | Application 36 | false 37 | v143 38 | true 39 | Unicode 40 | 41 | 42 | Application 43 | true 44 | v143 45 | Unicode 46 | 47 | 48 | Application 49 | false 50 | v143 51 | true 52 | Unicode 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | true 74 | 75 | 76 | true 77 | 78 | 79 | false 80 | 81 | 82 | false 83 | 84 | 85 | 86 | NotUsing 87 | Level3 88 | Disabled 89 | WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 90 | true 91 | MultiThreadedDebug 92 | 93 | 94 | Console 95 | true 96 | 97 | 98 | 99 | 100 | 101 | 102 | Level3 103 | Disabled 104 | _DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 105 | true 106 | MultiThreadedDebug 107 | 108 | 109 | Console 110 | true 111 | 112 | 113 | 114 | 115 | Level3 116 | 117 | 118 | MaxSpeed 119 | true 120 | true 121 | WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 122 | true 123 | MultiThreaded 124 | 125 | 126 | Console 127 | true 128 | true 129 | true 130 | 131 | 132 | 133 | 134 | Level3 135 | 136 | 137 | MaxSpeed 138 | true 139 | true 140 | NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 141 | true 142 | MultiThreaded 143 | 144 | 145 | Console 146 | true 147 | true 148 | true 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /XboxImageXploder/XboxImageXploder.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Header Files 20 | 21 | 22 | 23 | 24 | Source Files 25 | 26 | 27 | Source Files 28 | 29 | 30 | --------------------------------------------------------------------------------