I've been doing quite a bit of reversing of Halo structures and thought I would share it. As far as know, I've seen no documentation on this. I'm writing this for developers, but anyone can learn from it. I started reversing these structures while looking for a new way to make an aimbot and was fortunatly successful. Bitterbanana and Odie5533 ( who used the same method ) wrote a code cave and jmp'd to it from the function that updates players' world coordinates. The code cave then created an array of pointers to player data structures from the function. The reason for this was because the player data structures are dynamic. I found a new way to go about this without code caving or even touching any halo functions. No, this isn't a guide on how to make an aimbot, but this lead me to a lot of great information you are about to read and could be useful in many applications.
I did a bit of reversing on the Unreal Engine a few months ago. There is an array in the UE called GObjObjects. GObjObjects array has a pointer to an object table along with the number of objects and the size of the table. This table has pointers to every object structure in the entire game! Pretty cool huh? Well, I quit working on Unreal Engine since it was such a pain in the arse! I came back to Halo a few weeks after and decided to see if there was a similar table. Low and behold, I discovered it! All I did was grab the base pointer of my dynamic player structure ( searched for my world coordinates for this ), and did a pointer search. From the results, I was brought to this array table. Now, Halo's object table is very small compared to UE's so I was pretty excited. UE's object table contained over 200,000 objects compared to 100+ in Halo!!
Every data section begins with a header and sometimes a footer. The header contains some good info about the table / structures below it including the number of objects / size / max / pointer to first / etc. The object table contains every object in the game. This includes all scenery, vehicles, players, weapons, equipment, gametype flags ( flags, oddballs), and decals ( and possibly more ). There is a 12 byte array for each object in the table, which includes a pointer to that objects data structure, the size of the structure, and the object ID. I'm not sure what the other 2 shorts are, but I think it has to do with the object type or something.
The following structures and addresses in this doc are from Halo Trial. Halo PC and CE could have some changes, but for the most part they are identical besides the addresses.
Code:struct Object_Table_Header { unsigned char TName[32]; // 'object' unsigned short MaxObjects; // Maximum number of objects - 0x800(2048 objects) unsigned short Size; // Size of each object array - 0x0C(12 bytes) unsigned long Unknown0; // always 1? unsigned char Data[4]; // '@t@d' - translates to 'data'? unsigned short Unknown1; // Something to do with number of objects unsigned short Max; // Max number of objects the game has reached (slots maybe?) unsigned short Num; // Number of objects in the current game unsigned short NextObjectIndex; // Index number of the next object to spawn unsigned short NextObjectID; // ID number of the next object to spawn unsigned long FirstObject; // Pointer to the first object in the table }; // 0x4BB206B4You can do a simple loop through the object table to search for certain objects, to grab them all, or whatever else.Code:struct Object_Table_Array { unsigned short ObjectID; // Matches up to Object ID in static player table ( for players ) unsigned short Unknown0; unsigned short Unknown1; unsigned short Size; // Structure size unsigned long Offset; // Pointer to the object data structure };
Example:
You could do them one at a time instead of creating a huge array of structures. Then you can do what you need to and get out. All depends on what you are developing! =]Code:// Declare pointers to our structures Object_Table_Header * ObjectTableHeader; Object_Table_Array * ObjectTableArray[2048]; // Assign the static address to the header ObjectTableHeader = (Object_Table_Header*) 0x4BB206B4; // Loop through the table and add each array as a new element for( unsigned short i = 0; i < Object_Table_Header->MaxObjects; i++ ) ObjectTableArray[i] = (Object_Table_Array*)(Object_Table_Header->FirstObject + ( i * Object_Table_Header->Size));
I think that about covers the object table! I haven't reversed each object type's structures. I only reversed some of the player data structure. I didn't go too deep because I really didn't need all the extra info. There is a TON of stuff in the structures though including matrices. Just as an example, here's some of the player structure I have reversed, although this is just a small chunk of it:
Here's some useful info - the object indexes aren't referenced in the object table. But, this is a very useful number! Instead of looping through the object table again, you can just use the index number as the array element index. Let's assume the WeaponIndex is 8. ObjectTableArray[8] would be the array for the current players' weapon! Pretty nifty huh?Code:struct Dynamic_Player { unsigned short MetaIndex; unsigned short MetaID; // matches against the map's meta table unsigned char Unknown0[88]; float x; // world coordinate float y; // world coordinate float z; // world coordinate float x2; //movement vector float y2; //movement vector float z2; //movement vector float LegsPitch; float LegsYaw; float LegsRoll; float ScaleX; float ScaleY; float ScaleZ; unsigned char Unknown1[84]; float Health; float Shield; unsigned char Unknown2[48]; unsigned short WeaponIndex; unsigned short WeaponID; unsigned short VehicleIndex; unsigned short VehicleID; unsigned char Unknown3[228]; unsigned long IsInvisible; // normal = 0x41 invis = 0x51 (bitfield?) unsigned char IsCrouching; // crouch = 1, jump = 2 };
The meta index / id is a reference to the meta index which is in the map file structure. These object structures are actually for the mod2 (models). If you follow the reference, you will find the objects name, tag class heirarchy, spawn location, object type, etc.
Now onto the static player table! In addition to dynamic structures, there are static ones. Ones that are always at the same address in memory, no matter what. The static player structures have less important info and are more of a player index than anything. There is some good information though. Just like the object table, the player table has a header. I won't go into details since I commented it pretty heavily.
Code:struct Static_Player_Header { unsigned char TName[32]; // 'players' unsigned short MaxSlots; // Max number of slots/players possible unsigned short SlotSize; // Size of each Static_Player struct unsigned long Unknown; // always 1? unsigned char Data[4]; // '@t@d' - translated as 'data'? unsigned short IsInMainMenu; // 0 = in game 1 = in main menu / not in game unsigned short SlotsTaken; // or # of players unsigned short NextPlayerIndex; // Index # of the next player to join unsigned shoft NextPlayerID; // ID # of the next player to join unsigned long FirstPlayer; // Pointer to the first static player }; //0x4BD7AF94I reversed some of the stats array table. It's not complete unfortunatly. Each array is 48 bytes. Here's what I got:Code:struct Static_Player { unsigned short PlayerID; // Stats at 0x70EC unsigned short PlayerID2; // ??? wchar_t PlayerName0[12]; // Unicode / Max - 11 Chars + EOS (12 total) long Unknown0; // Always -1 / 0xFFFFFFFF unsigned long Team; // 0 = Red / 1 = Blue unsigned long SwapID; // ObjectID unsigned short SwapType; // 8 = Vehicle / 6 = Weapon short SwapSeat; // Warthog - Driver = 0 / Passenger = 1 / Gunner = 2 / Weapon = -1 unsigned long RespawnTimer; // ?????? Counts down when dead, Alive = 0 unsigned long Unknown1; // Always 0 unsigned short ObjectIndexNum; unsigned short ObjectID; // Matches against object table unsigned long Unknown3; // Some sort of ID unsigned long LocationID; // This is very, very interesting. BG is split into 25 location ID's. 1 -19 long Unknown4; // Always -1 / 0xFFFFFFFF unsigned long BulletCount; // Something to do with bullets increases - weird. wchar_t PlayerName1[12]; // Unicode / Max - 11 Chars + EOS (12 total) unsigned long Unknown5; // 02 00 FF FF unsigned long PlayerIndex; };
Code:struct Stats_Header { unsigned long RecordedAnimations; // Pointer to Recorded Animations data table unsigned char Unknown0[4]; // Zero's float LastDecalLocation0[12]; // World coordinates of the last bullet/nade hit anywhere on map x,y, applies to BSP only, not objects unsigned char Unknown1[48]; // Zero's float LastDecalLocation1[12]; // Same as other one. float Unknown2[2]; // Some floats. idk. unsigned char Unknown3[40]; // Zero's unsigned long DecalIDArray; // Pointer to an array of Decal ID's (correlates with LastDecalLocation) unsigned long Unknown3; // Pointer unsigned char Unknown4[20]; unsigned long LocationID0; unsigned long LocationID1; unsigned long Unknown5; unsigned char Unknown6[130]; // Zero's unsigned long Unknown7; // Pointer unsigned long Unknown8; // Pointer }; // 0x006A7DB8Code:struct Stats_Array { unsigned char IsInGame; unsigned char Unknown0[5]; unsigned short PlayerID; unsigned short Kills; unsigned char Unknown1[6]; unsigned short Assists; unsigned char Unknown2[6]; unsigned short Betrayed; // Suicides count! unsigned short TotalDeaths; // Everytime you die, no matter what.. unsigned short Suicides; unsigned short FlagSteals; unsigned short FlagReturns; unsigned short FlagScores; unsigned char Unknown3[12]; }; //size - 48 bytes 0x30 starts at 0x006A7F30Now for some map file reversing! =] I am currently working on an in-game level editor. It's pretty much like Spark Edit, but live, during game. I'm using all these structures and the map file structures to accomplish this + some 3d world -> 2d screen space math.Code:struct Stats_Footer { unsigned long RedFlag; // Pointer to scenario meta data unsigned long BlueFlag; // Pointer to scenario meta data unsigned short RedFlagIndex; // Object Index # unsigned short RedFlagID; // Object ID unsigned short BlueFlagIndex; // Object Index # unsigned short BlueFlagID; // Object ID unsigned long BlueFlagScores; // # of flags captured unsigned long RedFlagScores; // # of flags captured unsigned long FlagCaptureLimit; // Num of flags to capture to win bool RedFlagStolen; // 0 - At base 1 - Flag is stolen bool BlueFlagStoled; // 0 - At base 1 - Flag is stolen unsigned short Unknown; // Zero's? unsigned long RedFlagTimer; // Respawn time? unsigned long BlueFlagTimer; // Respawn time? }; // 0x006A8230
The map header sets up the whole map file. The TagIndexOffset is a pointer to the meta index. The meta index is just like the object table, but a different format. The meta index has all of the elements of the game including objects, sounds, bitmaps, shaders, collision, hud interface, fonts, etc. Pretty much everything you would see in HMT. The meta array's in the index contain the tag class hierarchy, a pointer to the metas name, a pointer to the meta structure and most important our meta ID. Remember the object structures? The first thing in an object structure is the meta ID which we can match up here.
The first thing in the meta index is the header. This is also a VERY important piece of the puzzle, because it sets up more parts of the map. I won't go into details. The first tag in the index is the scnr also know as the 'Scenario'. This contains a utopia of reflexives. A reflexive is just a type of array. It points to a structure with extra information. Our meta data structures all have reflexives too. It is just extra info about that tag. The scenario has all our spawns and triggers. It holds all the spawn points of every object, player, and gametype flags (flags, oddballs, koth, race, etc).
The whole entire map file is loaded into memory, but it is split into sections throughout memory. Fortunatly they are static. So without boring you any longer with all this information, here are the map structures I have reversed:
Code:struct sMapHeader { unsigned short Unknown; unsigned short Version; // 5 = Xbox, 6 = Trial, 7 = PC, 609 = CE unsigned char Unknown2[700]; unsigned long Header; // 'head''Ehed' unsigned long TagIndexMetaLength; unsigned char BuildDate[32]; // Year.Month.Day.Build - I guess they use this to make sure that a certain build will only open that build's map files, because this string is in the app too unsigned char Unknown3[672]; unsigned long MapType; // 0 = singleplayer, 1 = multiplayer, 2 = ui - this also determines the size of the cache file. UI = 35MB, multiplayer = 47MB, and singleplayer = 270MB unsigned char MapName[32]; unsigned char Unknown4[60]; unsigned long DecompLen; // Actual len of decompressed data. Halo sticks garbage on the end so that the file is one of several fixed sizes (35, etc). unsigned long TagIndexOffset; unsigned long Footer; // 'foot' 'Gfot' }; // 0x006A2000 - Trial Bloodgulch BaseCode:struct sIndexHeader { unsigned long IndexMagic; unsigned long BaseIdent; unsigned long Unknown; unsigned long NumOfTags; unsigned long VertexObjectCount; unsigned long ModelRawDataOffset; unsigned long IndicesObjectCount; unsigned long IndicesOffset; unsigned long ModelRawDataSize; }; // 0x4BF10000 - Trial Bloodgulch BaseCode:struct sTagIndex { unsigned char TagClass[3][4]; unsigned long TagID; TagName * TName; unsigned long Offset; unsigned long Zeros[2]; }; // Starts at 0x4BF10028 - Trial Bloogulch BaseCode:struct sTagName { unsigned char Name[1]; }; // Starts at 0x4BF22D68 - Trial Bloodgulch BaseCode:struct sScnrHeader { unsigned char unk_str1[16]; unsigned char unk_str2[16]; unsigned char unk_str3[16]; Reflexive SkyBox; unsigned long unk1; Reflexive ChildScenarios; unsigned long unneeded1[46]; unsigned long EditorScenarioSize; unsigned long unk2; unsigned long unk3; unsigned long pointertoindex; unsigned long unneeded2[2]; unsigned long pointertoendofindex; unsigned long zero1[57]; Reflexive ObjectNames; Reflexive Scenery; //============== Reflexive SceneryRef;//================= Reflexive Biped; Reflexive BipedRef;//=================== Reflexive Vehicle;//============= Reflexive VehicleRef;//================= Reflexive Equip; Reflexive EquipRef; Reflexive Weap; Reflexive WeapRef; Reflexive DeviceGroups; Reflexive Machine; Reflexive MachineRef; Reflexive Control; Reflexive ControlRef; Reflexive LightFixture; Reflexive LightFixtureRef; Reflexive SoundScenery; //=============== Reflexive SoundSceneryRef; //================= Reflexive Unknown1[7]; Reflexive PlayerStartingProfile; Reflexive PlayerSpawn;//============== Reflexive TriggerVolumes; Reflexive Animations; Reflexive MultiplayerFlags;//============== Reflexive MpEquip;//=============== Reflexive StartingEquip;//=============== Reflexive BspSwitchTrigger; Reflexive Decals;//================ Reflexive DecalsRef;//=============== Reflexive DetailObjCollRef; Reflexive Unknown3[7]; Reflexive ActorVariantRef; Reflexive Encounters; //below this, structs still not confirmed Reflexive CommandLists; Reflexive Unknown2; Reflexive StartingLocations;//=============== Reflexive Platoons; Reflexive AiConversations; unsigned long ScriptSyntaxDataSize;//============= unsigned long Unknown4; Reflexive ScriptCrap; Reflexive Commands; Reflexive Points; Reflexive AiAnimationRefs; Reflexive GlobalsVerified; Reflexive AiRecordingRefs; Reflexive Unknown5; Reflexive Participants; Reflexive Lines; Reflexive ScriptTriggers; Reflexive VerifyCutscenes; Reflexive VerifyCutsceneTitle; Reflexive SourceFiles; Reflexive CutsceneFlags; Reflexive CutsceneCameraPoi; Reflexive CutsceneTitles; Reflexive Unknown6[8]; unsigned long Unknown7[2]; Reflexive StructBsp; }; // 0x4BF3EDA0 - Trial Bloodgulch BaseCode:struct Reflexive { unsigned long Count; unsigned long Offset; unsigned long Zeros; };Recently I have looked through some Halo 2 structures. They follow the same format, but are slightly modified. I know there is extra info in the static player table and the object table looks exactly the same. This can make your applications easily portable between versions.Code:struct _PlayerSpawn { float x; float y; float z; float Yaw; unsigned long Team; unsigned long Unknown[8]; }
I think I have gone over enough material for now. I will be updating. Hope you learned something from this! =]
Here are some examples of stuff I'm working through my research:
http://www.xfire.com/video/13f09/
http://www.xfire.com/video/13944/
![]()






Bookmarks