

#include <stdio.h>                     // Need this for fopen(..) fwrite(..) etc
#include <string.h>                    // memcpy(..)

// We use this simple function to write data to our file.
void fileout(char *str)
{
      FILE *fp;
      fp=fopen("output.txt", "a+");   // a+ -> if file doesn't exist create it, else
      fprintf(fp, "%s", str);         //       append to the end of the file
      fclose(fp); 
}// End fileout(..)

long FileSize( char * szFileName )
{
	FILE *file = fopen(szFileName, "rb"); // Open the file
	fseek(file, 0, SEEK_END);             // Seek to the end
	long file_size = ftell(file);         // Get the current position
	fclose(file);
	
	return file_size;                     // We have the file size, so return it
}// End FileSize(..)


//-----------------------------stImageHeader Structure------------------------------//
// Remember that we use 'pragma pack(1)' so our data in the stucture is packed nice
// and tight using a 1 byte alignment.
#pragma pack(1)
struct stImageHeader
{
	char          sig[4];
	unsigned char auth_sig[0x100];
	unsigned int  base_address;
	unsigned int  size_header;
	unsigned int  size_image;
	unsigned int  size_image_header;
	unsigned int  time_date;
	unsigned int  cert_addr;
	unsigned int  num_sections;
	unsigned int  sect_addr;
	unsigned int  init_flags;
#define MountUtilityDrive    0x00000001
#define FormatUtilityDrive   0x00000002
#define Limit64Megabytes     0x00000004 
#define DontSetupHarddisk    0x00000008
	unsigned int  entry_point;
#define XOR_ENTRY_DEBUG      0x94859D4B
#define XOR_ENTRY_RETAIL     0xA8FC57AB
	unsigned int  tls_addr;
	unsigned int  pls_stack_commit;
	unsigned int  pe_heap_reserv;
	unsigned int  pe_heap_commit;
	unsigned int  pe_base_addr;
	unsigned int  pe_size_image;
	unsigned int  pe_checksum;
	unsigned int  pe_timedata;
	unsigned int  pathname_addr;
	unsigned int  filename_addr;
	unsigned int  unicode_filename_addr;
	unsigned int  kernel_thunk_addr;
#define XOR_KERNEL_DEBUG     0xEFB1F152
#define XOR_KERNEL_RETAIL    0x5B6D40B6
	unsigned int  non_kernel_dir_addr;
	unsigned int  num_lib_versions;
	unsigned int  lib_vers_addr;
	unsigned int  kernel_lib_vers_addr;
	unsigned int  xapi_lib_vers_addr;
	unsigned int  logo_bitmap_addr;
	unsigned int  logo_bitmap_size;
};
#pragma pack()

//-----------------------------stCertificate Structure------------------------------//
#pragma pack(1)
struct stCertificate
{
	unsigned int  sizeCertStruc;
	unsigned int  timedate;
	unsigned int  titleID;
	wchar_t       title[0x28];         // or 0x50 bytes - unicode title
	unsigned int  alt_titleIDs[0x16];  // 0x40 bytes
	unsigned int  media_flags;
#define XBEIMAGE_MEDIA_TYPE_HARD_DISK           0x00000001 
#define XBEIMAGE_MEDIA_TYPE_DVD_X2              0x00000002 
#define XBEIMAGE_MEDIA_TYPE_DVD_CD              0x00000004 
#define XBEIMAGE_MEDIA_TYPE_CD                  0x00000008 
#define XBEIMAGE_MEDIA_TYPE_DVD_5_RO            0x00000010 
#define XBEIMAGE_MEDIA_TYPE_DVD_9_RO            0x00000020 
#define XBEIMAGE_MEDIA_TYPE_DVD_5_RW            0x00000040 
#define XBEIMAGE_MEDIA_TYPE_DVD_9_RW            0x00000080 
#define XBEIMAGE_MEDIA_TYPE_DONGLE              0x00000100 
#define XBEIMAGE_MEDIA_TYPE_MEDIA_BOARD         0x00000200 
#define XBEIMAGE_MEDIA_TYPE_NONSECURE_HARD_DISK 0x40000000 
#define XBEIMAGE_MEDIA_TYPE_NONSECURE_MODE      0x80000000 
#define XBEIMAGE_MEDIA_TYPE_MEDIA_MASK          0x00FFFFFF 
	unsigned int  game_region;
#define XBEIMAGE_GAME_REGION_NA                 0x00000001 
#define XBEIMAGE_GAME_REGION_JAPAN              0x00000002 
#define XBEIMAGE_GAME_REGION_RESTOFWORLD        0x00000004 
#define XBEIMAGE_GAME_REGION_MANUFACTURING      0x80000000 
	unsigned int  game_ratings;
	unsigned int  disk_number;
	unsigned int  cert_version;
	unsigned char lan_key[0x10];
	unsigned char signature_key[0x10];
	unsigned char alt_signature_key[0x10 * 0x10];
};
#pragma pack()

//-------------------------------stSection Structure--------------------------------//
#pragma pack(1)
struct stSection
{
	unsigned int  flags;
#define SECTION_WRITABLE						0x00000001 
#define SECTION_PRELOAD							0x00000002 
#define SECTION_EXECUTABLE						0x00000004 
#define SECTION_INSERTED_FILE					0x00000008 
#define SECTION_HEAD_PAGE_READ_ONLY				0x00000010 
#define SECTION_TAIL_PAGE_READ_ONLY				0x00000020 
	unsigned int  virt_addr;
	unsigned int  virt_size;
	unsigned int  raw_addr;
	unsigned int  raw_size;
	unsigned int  section_name_addr;
	unsigned int  section_name_ref_count;
	unsigned int  head_shared_page_ref_count_addr;
	unsigned int  tail_shared_page_ref_count_addr;
	unsigned char section_digest[0x14];
};
#pragma pack()


//-------------------------------stLibrary Structure--------------------------------//
#pragma pack(1)
struct stLibrary   // size 16 bytes
{
	char		    library_name[8];
	unsigned short  majour_version;
	unsigned short  minor_version;
	unsigned short  build_version;
	unsigned short  pad;
	//unsigned char   gap_unknown[118];
	//unsigned int    flags;
#define LIB_QFEVERSION						0x1FFF  // 13-Bit Mask 
#define LIB_APPROVED						0x6000  // 02-Bit Mask
#define LIB_DEBUG_BUILD						0x8000  // 01-Bit Mask
};
#pragma pack()

//---------------------------------stTLS Structure----------------------------------//
#pragma pack(1)
struct stTLS
{
	unsigned int  data_start_addr;
	unsigned int  data_end_addr;
	unsigned int  tls_index_addr;
	unsigned int  tls_callback_addr;
	unsigned int  size_zero_fill;
	unsigned int  characteristics;
};
#pragma pack()


//---------------------------Dump All ImageHeader Details---------------------------//

void DumpImageHeaderInfo(unsigned char * pXBE, stImageHeader *pImageHeader)
{
	char buf[1000];
	unsigned int iBaseAddr = pImageHeader->base_address;

	fileout("--ImageHeader (0x178 bytes)----------------------------\n");
	
	// Write out the first 4 char's of the xbe to see what they are
	sprintf(buf, "Sig (0x4) (XBEH) = %c%c%c%c\n", 
										pImageHeader->sig[0], 
										pImageHeader->sig[1], 
										pImageHeader->sig[2],
										pImageHeader->sig[3] );
	fileout(buf);

	fileout("Digital Signature (0x100 bytes) Skip\n");

	sprintf(buf, "Base Address : 0x%08X\n", pImageHeader->base_address);
	fileout(buf);

	sprintf(buf, "Size Header : 0x%08X\n", pImageHeader->size_header);
	fileout(buf);

	sprintf(buf, "Size Image : 0x%08X\n", pImageHeader->size_image);
	fileout(buf);

	sprintf(buf, "Size Image Header : 0x%08X\n", pImageHeader->size_image_header);
	fileout(buf);

	sprintf(buf, "Date & Time : 0x%08X\n", pImageHeader->time_date);
	fileout(buf);

	sprintf(buf, "Certificate Address : 0x%08X \t(0x%08X)\n", 
										pImageHeader->cert_addr,
										pImageHeader->cert_addr - iBaseAddr);
	fileout(buf);

	sprintf(buf, "Num Sections : 0x%08X\n", pImageHeader->num_sections);
	fileout(buf);

	sprintf(buf, "Sections Start Address : 0x%08X \t(0x%08X)\n", 
										pImageHeader->sect_addr,
										pImageHeader->sect_addr - iBaseAddr);
	fileout(buf);

	sprintf(buf, "Init Flags : 0x%08X\n", pImageHeader->init_flags);
	fileout(buf);

	unsigned int init_flags = pImageHeader->init_flags;
	if( init_flags & MountUtilityDrive )
		fileout("\t MountUtilityDrive\n");
	if( init_flags & FormatUtilityDrive )
		fileout("\t FormatUtilityDrive\n");
	if( init_flags & Limit64Megabytes )
		fileout("\t Limit64Megabytes\n");
	if( init_flags & DontSetupHarddisk )
		fileout("\t DontSetupHarddisk\n");


	sprintf(buf, "Program Entry Point : 0x%08X \t(0x%08X)\n", 
										pImageHeader->entry_point,
										pImageHeader->entry_point ^ XOR_ENTRY_RETAIL);
	fileout(buf);


	sprintf(buf, "TLS Header Address : 0x%08X \t(0x%08X)\n", 
										pImageHeader->tls_addr,
										pImageHeader->tls_addr - iBaseAddr);
	fileout(buf);


	sprintf(buf, "PLS Stack Commit : 0x%08X\n", pImageHeader->pls_stack_commit);
	fileout(buf);

	sprintf(buf, "PE Stack Reserved : 0x%08X\n", pImageHeader->pe_heap_reserv);
	fileout(buf);

	sprintf(buf, "PE Heap Committed : 0x%08X\n", pImageHeader->pe_heap_commit);
	fileout(buf);

	sprintf(buf, "PE Base Address : 0x%08X\n", pImageHeader->pe_base_addr);
	fileout(buf);

	sprintf(buf, "PE Size Image : 0x%08X\n", pImageHeader->pe_size_image);
	fileout(buf);

	sprintf(buf, "PE Checksum : 0x%08X\n", pImageHeader->pe_checksum);
	fileout(buf);

	sprintf(buf, "PE Date & Time : 0x%08X\n", pImageHeader->pe_timedata);
	fileout(buf);

	// Small slip up I made...but its just common sense - when we pass a string
	// to sprintf...we need to pass a pointer...hence the & in front of pXBE
	sprintf(buf, "PathName Address : 0x%08X \t(0x%08X)\n\t(%s)\n", 
										pImageHeader->pathname_addr,
										pImageHeader->pathname_addr - iBaseAddr,
										&pXBE[pImageHeader->pathname_addr - iBaseAddr] );
	fileout(buf);

	sprintf(buf, "FileName Address : 0x%08X \t(0x%08X)\n\t(%s)\n", 
										pImageHeader->filename_addr,
										pImageHeader->filename_addr - iBaseAddr,
										&pXBE[pImageHeader->filename_addr - iBaseAddr]);
	fileout(buf);

	sprintf(buf, "Unicode FileName Address : 0x%08X \t(0x%08X)\n\t(%S)\n", 
										pImageHeader->unicode_filename_addr,
										pImageHeader->unicode_filename_addr - iBaseAddr,
										&pXBE[pImageHeader->unicode_filename_addr - iBaseAddr]);
	fileout(buf);


	sprintf(buf, "Kernel Thunk Address : 0x%08X \t(0x%08X)\n", 
										pImageHeader->kernel_thunk_addr,
										pImageHeader->kernel_thunk_addr ^ XOR_KERNEL_RETAIL );
	fileout(buf);

	sprintf(buf, "Non Kernel Dir Address : 0x%08X\n", 
										pImageHeader->non_kernel_dir_addr);
	fileout(buf);

	sprintf(buf, "Num Library Versions : 0x%08X\n", pImageHeader->num_lib_versions);
	fileout(buf);

	sprintf(buf, "Library Address: 0x%08X \t(0x%08X)\n", 
										pImageHeader->lib_vers_addr,
										pImageHeader->lib_vers_addr - iBaseAddr );
	fileout(buf);

	sprintf(buf, "Kernel Library Address: 0x%08X \t(0x%08X)\n", 
										pImageHeader->kernel_lib_vers_addr,
										pImageHeader->kernel_lib_vers_addr - iBaseAddr );
	fileout(buf);

	sprintf(buf, "XAPI Library Address: 0x%08X \t(0x%08X)\n", 
										pImageHeader->xapi_lib_vers_addr,
										pImageHeader->xapi_lib_vers_addr - iBaseAddr );
	fileout(buf);

	sprintf(buf, "Logo Bitmap Address: 0x%08X \t(0x%08X)\n", 
										pImageHeader->logo_bitmap_addr,
										pImageHeader->logo_bitmap_addr - iBaseAddr );
	fileout(buf);

	sprintf(buf, "Logo Bitmap Size : 0x%08X\n\n", pImageHeader->logo_bitmap_size);
	fileout(buf);


}//End DumpImageHeaderInfo(..)

void DumpCertHeaderInfo( unsigned char * pXBE, stCertificate *pCertHeader )
{
	char buf[500];

	fileout("--Certtificate Header (**(fix)**0x1D0 bytes)--------------------\n");


	sprintf(buf, "Size Certificate Area : 0x%08X\n", pCertHeader->sizeCertStruc);
	fileout(buf);

	sprintf(buf, "Data & Time : 0x%08X\n", pCertHeader->timedate);
	fileout(buf);

	sprintf(buf, "Title ID : 0x%08X\n", pCertHeader->titleID);
	fileout(buf);

	sprintf(buf, "Unicode Title : %S\n", pCertHeader->title);
	fileout(buf);

	fileout("Addit Title IDs\n");
	for(int i=0; i<0x16; i++)
	{
		sprintf(buf, "\t%02x - 0x%08X\n", i, pCertHeader->alt_titleIDs[i]);
		fileout(buf);
	}// End for loop

	sprintf(buf, "Media Flags : 0x%08X\n", pCertHeader->media_flags);
	fileout(buf);

	unsigned int flags = pCertHeader->media_flags;
	
	if( flags & XBEIMAGE_MEDIA_TYPE_HARD_DISK )			fileout("\t MEDIA_TYPE_HARD_DISK\n");
	if( flags & XBEIMAGE_MEDIA_TYPE_DVD_X2 )			fileout("\t MEDIA_TYPE_DVD_X2\n");
	if( flags & XBEIMAGE_MEDIA_TYPE_DVD_CD )			fileout("\t MEDIA_TYPE_DVD_CD\n");
	if( flags & XBEIMAGE_MEDIA_TYPE_CD )				fileout("\t MEDIA_TYPE_CD\n");
	if( flags & XBEIMAGE_MEDIA_TYPE_DVD_5_RO )			fileout("\t MEDIA_TYPE_DVD_5_RO\n");
	if( flags & XBEIMAGE_MEDIA_TYPE_DVD_9_RO )			fileout("\t MEDIA_TYPE_DVD_9_RO\n");
	if( flags & XBEIMAGE_MEDIA_TYPE_DVD_5_RW )			fileout("\t MEDIA_TYPE_DVD_5_RW\n");
	if( flags & XBEIMAGE_MEDIA_TYPE_DVD_9_RW )			fileout("\t MEDIA_TYPE_DVD_9_RW\n");
	if( flags & XBEIMAGE_MEDIA_TYPE_DONGLE )			fileout("\t MEDIA_TYPE_DONGLE\n");
	if( flags & XBEIMAGE_MEDIA_TYPE_MEDIA_BOARD )		fileout("\t MEDIA_TYPE_MEDIA_BOARD\n");
	if( flags & XBEIMAGE_MEDIA_TYPE_NONSECURE_HARD_DISK )fileout("\t MEDIA_TYPE_NONSECURE_HARD_DISK\n");
	if( flags & XBEIMAGE_MEDIA_TYPE_NONSECURE_MODE )	fileout("\t MEDIA_TYPE_NONSECURE_MODE\n");
	if( flags & XBEIMAGE_MEDIA_TYPE_MEDIA_MASK )		fileout("\t MEDIA_TYPE_MEDIA_MASK\n");

	sprintf(buf, "Game Region : 0x%08X\n", pCertHeader->game_region);
	fileout(buf);

	flags = pCertHeader->game_region;
	if( flags & XBEIMAGE_GAME_REGION_NA )			fileout("\t REGION_NA\n");
	if( flags & XBEIMAGE_GAME_REGION_JAPAN )		fileout("\t REGION_JAPAN\n");
	if( flags & XBEIMAGE_GAME_REGION_RESTOFWORLD )	fileout("\t REGION_RESTOFWORLD\n");
	if( flags & XBEIMAGE_GAME_REGION_MANUFACTURING )fileout("\t REGION_MANUFACTURING\n");


	sprintf(buf, "Game Rating : 0x%08X\n", pCertHeader->game_ratings);
	fileout(buf);

	sprintf(buf, "Disk Number : 0x%08X\n", pCertHeader->disk_number);
	fileout(buf);

	sprintf(buf, "Certificate Version : 0x%08X\n", pCertHeader->cert_version);
	fileout(buf);

	fileout("LAN Key:\n\t");
	for(  i=0; i<0x10; i++)
	{
		sprintf(buf, "0x%02X ", pCertHeader->lan_key[i]);
		fileout(buf);
	}// End for loop
	fileout("\n");

	fileout("Signature Key:\n\t");
	for(  i=0; i<0x10; i++)
	{
		sprintf(buf, "0x%02X ", pCertHeader->signature_key[i]);
		fileout(buf);
	}// End for loop
	fileout("\n");

	fileout("Alt Signature Key:");
	for(  i=0; i<(0x10*0x10); i++)
	{
		if( (i%0x10) == 0 ) fileout("\n\t");
		sprintf(buf, "0x%02X ", pCertHeader->alt_signature_key[i]);
		fileout(buf);

	}// End for loop
	fileout("\n\n");


}// End DumpCertHeaderInfo(..)

void DumpSectionHeaderInfo( unsigned char * pXBE, unsigned int iBaseAddr,
						    stSection * pSectHeaders, int iNumSect)
{
	char buf[500];
	int iOffset = 0;
	
	fileout("--Section Headers ----------------------------------------------\n\n");
	// Could put this code in a second loop maybe and call the function
	// over and over agian...nice smaller easier to maintain code then :)
	for( int i=0; i<iNumSect; i++)
	{
		sprintf(buf, "====*Section: %s*=====\n", 
			          &pXBE[pSectHeaders[i].section_name_addr - iBaseAddr]);
		fileout(buf);

		sprintf( buf, "Flags: 0x%08X\n", pSectHeaders[i].flags );
		fileout(buf);

		unsigned int flags = pSectHeaders[i].flags;
		if( flags & SECTION_WRITABLE )				fileout("\t SECTION_WRITABLE\n");
		if( flags & SECTION_PRELOAD )				fileout("\t SECTION_PRELOAD\n");
		if( flags & SECTION_EXECUTABLE )			fileout("\t SECTION_EXECUTABLE\n");
		if( flags & SECTION_INSERTED_FILE )			fileout("\t SECTION_INSERTED_FILE\n");
		if( flags & SECTION_HEAD_PAGE_READ_ONLY )	fileout("\t HEAD_PAGE_READ_ONLY\n");
		if( flags & SECTION_HEAD_PAGE_READ_ONLY )	fileout("\t HEAD_PAGE_READ_ONLY\n");
		if( flags & SECTION_TAIL_PAGE_READ_ONLY )	fileout("\t TAIL_PAGE_READ_ONLY\n");


		sprintf(buf, "Virtual Address : 0x%08X \t(0x%08X)\n", 
										pSectHeaders[i].virt_addr,
										pSectHeaders[i].virt_addr - iBaseAddr);
		fileout(buf);

		sprintf( buf, "Virutal Size: 0x%08X\n", pSectHeaders[i].virt_size );
		fileout(buf);

		sprintf( buf, "Raw Address: 0x%08X\n", pSectHeaders[i].raw_addr );
		fileout(buf);

		sprintf( buf, "Raw Size: 0x%08X\n", pSectHeaders[i].raw_size );
		fileout(buf);


		sprintf(buf, "Section Name Address : 0x%08X \t(0x%08X)\n\t(%s)\n", 
								pSectHeaders[i].section_name_addr,
								pSectHeaders[i].section_name_addr - iBaseAddr,
								&pXBE[pSectHeaders[i].section_name_addr - iBaseAddr]);
		fileout(buf);

		sprintf( buf, "Section Name Ref Count: 0x%08X\n", 
			              pSectHeaders[i].section_name_ref_count );
		fileout(buf);

		sprintf( buf, "Section Name Ref Count: 0x%08X\n", 
			              pSectHeaders[i].section_name_ref_count );
		fileout(buf);

		sprintf( buf, "Head Page Ref Addr: 0x%08X\n", 
			              pSectHeaders[i].head_shared_page_ref_count_addr );
		fileout(buf);

		sprintf( buf, "Tail Page Ref Addr: 0x%08X\n", 
			              pSectHeaders[i].tail_shared_page_ref_count_addr );
		fileout(buf);

		fileout("Section Digest:");
		for(int count=0; count<0x14; count++)
		{
			if( (count%0x8) == 0 ) fileout("\n\t");
			sprintf( buf, "0x%02X ", pSectHeaders[i].section_digest[i] );
			fileout(buf);
		}// End inner for loop
		fileout("\n");
	}// End outer for loop
	

	fileout("\n\n");

}// End DumpSectionHeaderInfo(..)

void DumpTLSHeaderInfo( unsigned char * pXBE, stTLS * pTLS )
{
	char buf[500];
	fileout("--TLS Header ---------------------------------------------------\n");

	sprintf(buf, "Data Start Address : 0x%08X\n", pTLS->data_start_addr);
	fileout(buf);

	sprintf(buf, "Data End Address : 0x%08X\n", pTLS->data_end_addr);
	fileout(buf);

	sprintf(buf, "Index Address : 0x%08X\n", pTLS->tls_index_addr);
	fileout(buf);

	sprintf(buf, "Callback Address : 0x%08X\n", pTLS->tls_callback_addr);
	fileout(buf);

	sprintf(buf, "Zero Fill Size : 0x%08X\n", pTLS->size_zero_fill);
	fileout(buf);

	sprintf(buf, "Characteristics: 0x%08X\n\n", pTLS->characteristics);
	fileout(buf);

}// End DumpTLSHeaderInfo(..)

void DumpLibraryHeader( unsigned char * pXBE, stLibrary *pLibs, int iNumLibs)
{
	if( pLibs == 0 ) return;
	if( iNumLibs == 0 ) return;

	char buf[500];
	
	fileout("--Library Header -----------------------------------------------\n");
	
	for( int i=0; i<iNumLibs; i++)
	{

		sprintf( buf, "Library Name : %.7s\n", pLibs[i].library_name );
		fileout(buf);

		sprintf( buf, "Majour Version : 0x%04X\n", pLibs[i].majour_version );
		fileout(buf);

		sprintf( buf, "Minor Version : 0x%04X\n", pLibs[i].minor_version );
		fileout(buf);

		sprintf( buf, "Build Version : 0x%04X\n", pLibs[i].build_version );
		fileout(buf);

		//sprintf( buf, "Flags : 0x%04X\n\n", pLibs[i].flags );
		//fileout(buf);

	}// End for loop

}// End DumpLibraryHeader(..)

//-------------------------------ProcessXBE Function--------------------------------//

void ProcessXBE( unsigned char *pXBE, long iSizeXBE )
{

	char buf[500];

	// Lets fill in our stImageHead Structure
	stImageHeader IH;
	memcpy( &IH, pXBE, sizeof(stImageHeader) );
	DumpImageHeaderInfo( pXBE, &IH );



	// Well if we look at what value we have in our stImageHeader for
	// Certificate Address (0x4) : 0x00010178... we can see the value is
	// a bit high...this is because its using that base address value.
	// which is 0x10000.
	// So if we take that 0x10000, we are left with something like 0x178
	// which seems pretty reasonable, as the stImageHeader is 0x178 bytes in
	// size...which leads us to beleive its located straight after the szImageHeader
	// structure.
	stCertificate Cert;
	int offset = IH.cert_addr - IH.base_address;
	memcpy( &Cert, pXBE + offset, sizeof(stCertificate) );
	sprintf(buf, "{Offset: 0x%08X}\n", offset);
	fileout(buf);
	DumpCertHeaderInfo(pXBE, &Cert);

	// Our Sections..this is where the meat and potatoes of the code is!  Yup
	// this is where all our code and data is located.
	// Now I just allocate space for 50 sections...didn't want to start allocating memory 
	// etc....but if its got more than 50 sections its one mutant super xbe we have here!
	stSection pSections[50];
	int iNumSections = IH.num_sections;
	offset = IH.sect_addr - IH.base_address;

	sprintf(buf, "{Offset: 0x%08X}\n", offset);
	fileout(buf);

	// Now the address offset points to the top of the sections...as the sections are
	// stored as an array...one after the other
	for(int i=0; i<iNumSections; i++)
	{
		memcpy( &pSections[i], pXBE + offset, sizeof(stSection) );
		offset += sizeof(stSection);
	}//End for loop
	DumpSectionHeaderInfo(pXBE, IH.base_address,
		                  pSections, iNumSections);

	// Where nearly there now...not much more to go!  We'll get through this
	// TLS Data
	stTLS tls;
	offset = IH.tls_addr - IH.base_address;
	memcpy( &tls, pXBE + offset, sizeof(stTLS) );
	sprintf(buf, "{Offset: 0x%08X}\n", offset);
	fileout(buf);
	DumpTLSHeaderInfo(pXBE, &tls);

	// Lets get all the library versions finally.
	// Now I've just put a static array together for now...I can't see an xbe having more
	// than 50 librarys...
	stLibrary xbe_standard_libs[0x20];
	int iNumLibs = IH.num_lib_versions;
	offset = IH.lib_vers_addr - IH.base_address;

	sprintf(buf, "{Offset: 0x%08X}\n", offset);
	fileout(buf);

	// I Can't see why...guess I'm getting sloppy..but this loop was bad!  Looks okay
	// to me...must be missing something here.  If anyone can see why this loop
	// wouldn't work give me some feedback on this...many thanx :)
	//
	// for(int j=0; i<iNumLibs; j++)
	// {
	//	 memcpy( &xbe_standard_libs[j], pXBE + offset, sizeof(stLibrary) );
	//	 offset += sizeof(stLibrary);
	// }//End for loop

	memcpy( xbe_standard_libs, pXBE + offset, iNumLibs * sizeof(stLibrary) );
	DumpLibraryHeader(pXBE, &xbe_standard_libs[0], iNumLibs);


	// Hmm...well we should really load the last couple of library's...just so we 
	// can show whats in them
	// Kernel Library
	if( IH.kernel_lib_vers_addr != 0 )
	{
		stLibrary xbe_kernel_lib;
		offset = IH.kernel_lib_vers_addr - IH.base_address;
		sprintf(buf, "{Offset: 0x%08X}\n", offset);
		fileout(buf);

		memcpy( &xbe_kernel_lib, pXBE + offset, sizeof(stLibrary) );
		DumpLibraryHeader(pXBE, &xbe_kernel_lib, 1);
	}// End if

	// XAPI Library
	if( IH.xapi_lib_vers_addr != 0 )
	{
		stLibrary xbe_xapi_lib;
		offset = IH.xapi_lib_vers_addr - IH.base_address;
		sprintf(buf, "{Offset: 0x%08X}\n", offset);
		fileout(buf);

		memcpy( &xbe_xapi_lib, pXBE + offset, sizeof(stLibrary) );
		DumpLibraryHeader(pXBE, &xbe_xapi_lib, 1);
	}

}// End ProcessXBE(..)


//------------------------------Program Entry Point---------------------------------//
//----------------------------------------------------------------------------------//
void main(int argc, char* argv[])
{
	char szFileName[] = "default.xbe";    // Our input xbe
	char buf[500];                        // Large temp char buffer

	long iFileSize = FileSize(szFileName);

	sprintf(buf, "File: %s - xbe filesize: %d bytes\n\n", szFileName, iFileSize);
	fileout(buf);

	// Lets allocate enough memory for the whole xbe and read it all in
	unsigned char * pXBE = new unsigned char[iFileSize];

	// Open our xbe file
	FILE* fp = fopen( szFileName, "r" );
	fseek(fp, 0, SEEK_SET);

	// Read all the contents into our allocated memory 
	fread(pXBE, iFileSize, 1, fp);

	// Close our file.
	fclose( fp );

	//------------------------Our XBE Analysis Code-------------------------//

	ProcessXBE( pXBE, iFileSize );
	
	//------------------------End of XBE Analysis---------------------------//

	// Goodbye

	// Remember, before exiting the program, release the memory we allcoated for 
	// the xbe data we read in
	delete[] pXBE;

}// End main(..)






