www.xbdev.net
xbdev - software development
Sunday May 11, 2025
Home | Contact | Support
     
 

Patching XBE

XBOX Programming...

 

Patching XBE (Xbox Executable)


Simply put...what patching an xbe does, it convert a debug xbox executable (.xbe) to a retail xbe, that can be run on a standard retail xbox..


First things first....we have 2 identical files...but one is patched and the other isn't....we'll create a short program to see what in essence patching an xbe changes...which offsets.


Size's are identical...e.g if one is 10.01kb, then the other is 10.01kb as well.


Anyhow, I wrote two programs so you could see what is actually happening, it will one improve your coding skills and two help you two see how simple it is to create an xbe patch program.


The first program below, will open two xbe files, called 'pcode.xbe' (e.g. patched xbe) and a non-patched xbe file called 'ncode.xbe'. It first checks the file sizes, and writes the file size of both file to a text file called info.txt...which will be created in the same directory as the main.exe program.

Following that, we'll compare byte by byte of each program and write out any differences and there location to the same text file.


// File: main.cpp
// Author: bkenwright@xbdev.net
 
// compare patched and non-patched xbe's
 
#include <stdio.h>
 
void debug(char *str)
{
      
FILE *fp;
      
fp=fopen("info.txt""a+");
      
fprintf(fp"%s\n"str);
      
fclose(fp);
}
 
// patched xbe is      "pcode.xbe"
// non-patched xbe is  "ncode.xbe"
 
#include <windows.h>
#pragma comment(lib, "Kernel32.lib")
 
int __stdcall WinMain(HINSTANCEHINSTANCEchar*, int)
{
      
//------These few lines just confirm that the two files are identical sizes-----
      
HANDLE h;
      
DWORD dwSize1dwSize2;
     
      
h=CreateFile"ncode.xbe"GENERIC_READFILE_SHARE_READNULLOPEN_EXISTING0);
      
dwSize1 GetFileSizehNULL);
      
CloseHandle(h);
      
h=NULL;
 
      
h=CreateFile"pcode.xbe"GENERIC_READFILE_SHARE_READNULLOPEN_EXISTING0);
      
dwSize2 GetFileSizehNULL);
      
CloseHandle(h);
     
      
char sz1[400];
      
sprintf(sz1"FileSize ncode.xbe: %u \t FileSize pcode.xbe: %u"dwSize1dwSize2);
      
debug(sz1);
     
      
//-----Compare both files and show where they differ-----
 
      
FILE *fp1 fopen"ncode.xbe""rb" );
      
FILE *fp2 fopen"pcode.xbe""rb" );
 
      
int e 1;
      
unsigned char buf1buf2;
 
      
unsigned int offset 0;
 
      
debug("\n");
      
debug("offset\t non-patched\t patched\n");
 
      while (
e)
      {
            
fread(&buf111fp1);
            
fread(&buf211fp2);
 
            
offset++;
 
            if( 
buf1 != buf2)
            {
                  
char sz2[200];
                  
//            offset   before   after
                  
sprintf(sz2"0x%.4X\t 0x%.4X\t 0x%.4X"offsetbuf1buf2);
                  
debug(sz2);
            }
      }

      
fclose(fp1);
      
fclose(fp2);
     
}


Output text file: (info.txt)

FileSize ncode.xbe126976 FileSize pcode.xbe126976

offset       non
-patched       patched

0x0129   0x0045               0x00A5
0x012A  0x008C               0x0046
0x012B  0x0084               0x00FD
0x012C  0x0094               0x00A8

0x0159  0x00D2               0x0036
0x015A  0x0072               0x00C3
0x015B  0x00B3               0x006F
0x015C  0x00EF               0x005B



You can easily see the two main parts that the patcher changes...these are two DWORD values at offset 0x0128 and 0x158.

Debug Release
0x0128 0 x 45 8C 84 94 -> 0 x A5 46 FD A8
KEYS (XOR) 0 x 4B 9D 85 94 -> 0 x AB 57 FC A8


How to convert from debug to release?...lets take 0x128 as an example...an I'll do it byte by byte so you don't get mixed up.

94  XOR 94 .... 0   XOR A8 A8
84  
XOR 85 1....  1   XOR FC FD
8C 
XOR 9D 11.11 XOR 57  46
45  
XOR 4B E... .E  XOR AB A5


so its like this:

dwDebugValue  XOR  dwDebugKey dwTemp

then

dwTemp XOR dwReleaseKey dwReleaseValue


You would do the same with offset
0x0158
.


It's worth looking at the xbe file format specification to see what these offsets mean, first is for the entry point of our program, the second for the kernal table.

// File: main.cpp
// Author: bkenwright@xbdev.net
 
// convert a debug xbe to a retail xbe (patched).
 
#include <stdio.h>
#include <string.h>
 
 
// IMPORTANT, there is no error checking in this code, as you should check that
// the parameters passed are valid etc.
 
void __cdecl main(int argcchar** argv)
{
      if( 
argc )
            return;
 
      
char szOldFile[256];
      
char szNewFile[256];
 
      
strcpyszOldFile"bak_" );
      
strcatszOldFileargv[1] );
     
      
strcpyszNewFileargv[1] );
 
      
// Make a backup of our file
      
renameargv[1], szOldFile  );
 
      
unsigned char dwDebugKeyA [4]  = {0x940x850x9D0x4B };
      
unsigned char dwRetailKeyA[4]  = {0xA80xFC0x570xAB };
     
      
unsigned char dwDebugKeyB [4]  = {0xEF,0xB1,0xF1,0x52};
      
unsigned char dwRetailKeyB[4]  = {0x5B,0x6D,0x40,0xB6};
           
 
      
//-----Compare both files and show where they differ-----
 
      
FILE *fp1 fopenszOldFile"rb" );
      
FILE *fp2 fopenszNewFile"wb+" );
 
      
int e 1;
      
unsigned char dwbuf;
 
      
unsigned int offset 0;
 
      while (
e)
      {
            
fread(&dwbuf11fp1);
 
            if( 
== )
                  break;
 
            if( 
offset >= 0x0128 && offset <= (0x0128+3))
            {
                  static 
int cc 3;
 
                  
dwbuf dwbuf dwDebugKeyA[cc];
                  
dwbuf dwbuf dwRetailKeyA[cc];
 
                  
cc--;
 
                  
fwrite(&dwbuf11fp2);
            }
            else if( 
offset >= 0x158 && offset <= (0x158+3))
            {
                  static 
int bb 3;
 
                  
dwbuf dwbuf dwDebugKeyB[bb];
                  
dwbuf dwbuf dwRetailKeyB[bb];
 
                  
bb--;
 
                  
fwrite(&dwbuf11fp2);
            }
            else
            {
                  
fwrite(&dwbuf11fp2);
            }
 
            
offset++;
      }
 
      
fclose(fp1);
      
fclose(fp2);
}


With a few minor improvements you can create a simple un-patcher, and also better error checking, in-case the file can't be found etc.















 
Advert (Support Website)

 
 Visitor:
Copyright (c) 2002-2025 xbdev.net - All rights reserved.
Designated articles, tutorials and software are the property of their respective owners.