PDA

View Full Version : [MISC] Reverse Engineering References



Skarma
September 20th, 2009, 12:29 PM
Table of Contents:
Gearbox Models (http://www.modacity.net/forums/showpost.php?p=463585&postcount=14)
Multiple Instances (http://www.modacity.net/forums/showpost.php?p=463551&postcount=2)
cheat_spawn_warthog (http://www.modacity.net/forums/showpost.php?p=463559&postcount=3)
Console Output using Halo Engine (http://www.modacity.net/forums/showpost.php?p=463560&postcount=4)
GetBitmapBySequence (http://www.modacity.net/forums/showpost.php?p=471424&postcount=32)
ClearSurface (http://www.modacity.net/forums/showpost.php?p=475276&postcount=33)
GetFVFVertexSize (http://www.modacity.net/forums/showpost.php?p=475772&postcount=34)
ReleaseResources (http://www.modacity.net/forums/showpost.php?p=478742&postcount=35)
InitCrc32Table (http://www.modacity.net/forums/showpost.php?p=480526&postcount=36)
CalcCrc32 (http://www.modacity.net/forums/showpost.php?p=480579&postcount=37)
InitCacheDataHeader (http://www.modacity.net/forums/showpost.php?p=480607&postcount=38)
InitPlayerCaches (http://www.modacity.net/forums/showpost.php?p=480637&postcount=39)
Object Visibility (http://www.modacity.net/forums/showpost.php?p=483472&postcount=40)
Console Stuff:
__________________________________________________ ________________

For now, this is just for upgrading your gray matter, because there is still a few bugs I need to work out. That and the addresses are for the trial version :ohdear:, don't worry I will update this to CE soon. Just don't try to compile this and run to me when you fail.

The following code is the console command processing function in C++ I reversed straight from Halo's engine in assembly. OllyDbg was used for the analyzation. I commented on most of the code so others can understand it better.

The main problem I am having is with the Cmd parameter. It is not pushed on the stack before this function is called, it is moved into the EDI 32-bit register. There is no way to specify which parameter uses which register and no calling convention that I am aware of uses EDI like this. Just seems like a compiler optimization, which is why I added the simple fix at the beginning. I was hoping someone like kornman00 had advice on something like this.

I also think my GetScriptIndex function proto is not correct. The first 3 params are also moved into registers, if I remember correctly. If anyone can help me fix up bugs, awesome. :downs:

I know reversing this entire function was not really necessary, I did it for knowledge of how it works and what is going on and to share it with others. I also can't get enough of what I do in my free time, I love reversing code! :eng101:


// Functions used in ConsoleCmd()
void(*ConsoleTxt)(int, const char* pString, ...) = (void(*)(int, const char*, ...))0x004C4770;
int(*UnkFunc)(int) = (int(*)(int))0x004C48B0;
int(*GetScriptIndex)(char*,int,int,int,void*) = (int(*)(char*,int,int,int,void*))0x00482250;
bool(*ScriptCmd)(const char* script) = (bool(*)(const char*))0x004829C0;

// Globals used in ConsoleCmd()
char* StoredCmds = (char*)0x006AE484;
short* StoredCmdsCount = (short*)0x006AEC7C;
short* LastCmdIndex = (short*)0x006AEC7E;
short* ListedCmdIndex = (short*)0x006AEC80; //when u cycle through them
char* pUnknown = (char*)0x006FFD9D;

bool __cdecl ConsoleCmd(const char* Cmd,int Num)
{
// EDI param temporary fix
DWORD Address = 0;
__asm mov Address,edi
if(Address == 0x006AE378)
__asm mov Cmd,edi

char Dest[255];
int Base = 0;

// Compares the first and second character of Cmd string against characters it doesn't like
if(*Cmd != ';' && *Cmd != '#' && (*Cmd != '/' || *(Cmd + 1) != '/'))
{
// Copy Cmd string into another variable, w/o null-terminating character
// unless the amount of characters in Cmd is less than 255
strncpy(Dest, Cmd, 255);

// Check if there is a space character in the Cmd string
// If there is a space, return a pointer to the first occurrence
// and put a null terminating character there
char* SpaceResult = strchr(Dest, ' ');
if(SpaceResult)
*SpaceResult = 0;

/* Once entered, commands are stored. Previously entered cmds can be accessed
using the UP/Down arrow keys. Max is 8. */

// Updates the index number of the last command stored
// so we can store our command string in the right address
// Max stored commands is 8
short StoreIndex = *LastCmdIndex;
StoreIndex = (StoreIndex + 1) % 8; // modulo-n counter. sheer awesomeness.
if(StoreIndex < 0)
StoreIndex = 0;
*LastCmdIndex = StoreIndex;

// Gets the address where our Cmd is stored and copies it there
// Each stored element is max 255 characters
char* CmdStoreAddress = &StoredCmds[StoreIndex];
strncpy(CmdStoreAddress, Cmd, 255);

// Updates the amount of stored commands
// Once it reaches the max(8), it will always be that way
short Count = *StoredCmdsCount;
Count++;
*StoredCmdsCount = 8;
if(Count <= 8)
*StoredCmdsCount = Count;

// We are no longer cycling through the stored index, reset it
*ListedCmdIndex = -1;

// Searches list of scripts and returns an index to it
// Not found? Invalid command.
int ScriptIndex = GetScriptIndex(Dest, UnkFunc(Num), 256, 0x28, &Base);
if(ScriptIndex <= 0)
{
BAD_CMD:
// Invalid console command, draw some output text
ConsoleTxt(0, "Requested function \"%s\" cannot be executed now.", Dest);
return false;
}
else
{
// Compares inputed Cmd against script
while(_stricmp(Dest, (const char*)(&Base + (ScriptIndex * sizeof(int)))))
{
--ScriptIndex;
if(ScriptIndex <= 0)
goto BAD_CMD;
}
// Not sure what the unknown is yet, but this runs the known script command
*pUnknown = 1;
bool bResult = ScriptCmd(Cmd);
*pUnknown = 0;
return bResult;
}
}
else
return false;
}Assembly version of the same code, for reference

CPU Disasm
Address Command Comments
004C4970 MOV AL,BYTE PTR DS:[EDI] ; halo.004C4970(guessed Arg1)
004C4972 SUB ESP,500
004C4978 CMP AL,3B
004C497A JE SHORT 004C498A
004C497C CMP AL,23
004C497E JE SHORT 004C498A
004C4980 CMP AL,2F
004C4982 JNE SHORT 004C4993
004C4984 CMP BYTE PTR DS:[EDI+1],2F
004C4988 JNE SHORT 004C4993
004C498A XOR AL,AL
004C498C ADD ESP,500
004C4992 RETN
004C4993 PUSH EBX
004C4994 PUSH 0FF ; /Arg3 = 0FF
004C4999 LEA EAX,[LOCAL.319] ; |
004C499D PUSH EDI ; |Arg2 => ARG.EDI
004C499E PUSH EAX ; |Arg1 => OFFSET LOCAL.319
004C499F CALL 0061DCA0 ; \halo.0061DCA0
004C49A4 LEA ECX,[LOCAL.319]
004C49A8 PUSH 20 ; /Arg2 = 20
004C49AA XOR EBX,EBX ; |
004C49AC PUSH ECX ; |Arg1 => OFFSET LOCAL.319
004C49AD MOV BYTE PTR SS:[LOCAL.256+3],BL ; |
004C49B4 CALL 0061F9F0 ; \halo.0061F9F0
004C49B9 ADD ESP,14
004C49BC CMP EAX,EBX
004C49BE JE SHORT 004C49C2
004C49C0 MOV BYTE PTR DS:[EAX],BL
004C49C2 MOVSX EAX,WORD PTR DS:[6AEC7E]
004C49C9 INC EAX
004C49CA AND EAX,80000007
004C49CF JNS SHORT 004C49D6
004C49D1 DEC EAX
004C49D2 OR EAX,FFFFFFF8
004C49D5 INC EAX
004C49D6 MOV WORD PTR DS:[6AEC7E],AX
004C49DC MOVSX EAX,AX
004C49DF IMUL EAX,EAX,0FF
004C49E5 MOV EDX,EDI
004C49E7 ADD EAX,OFFSET halo.006AE484
004C49EC LEA ESP,[LOCAL.320]
004C49F0 /MOV CL,BYTE PTR DS:[EDX]
004C49F2 |INC EDX
004C49F3 |MOV BYTE PTR DS:[EAX],CL
004C49F5 |INC EAX
004C49F6 |CMP CL,BL
004C49F8 \JNE SHORT 004C49F0
004C49FA MOVSX EAX,WORD PTR DS:[6AEC7C]
004C4A01 INC EAX
004C4A02 CMP EAX,8
004C4A05 MOV WORD PTR DS:[6AEC7C],8
004C4A0E JG SHORT 004C4A16
004C4A10 MOV WORD PTR DS:[6AEC7C],AX
004C4A16 MOV EDX,DWORD PTR SS:[ARG.1]
004C4A1D PUSH ESI
004C4A1E PUSH EDX
004C4A1F MOV WORD PTR DS:[6AEC80],0FFFF
004C4A28 CALL 004C48B0
004C4A2D LEA ECX,[LOCAL.255]
004C4A34 PUSH ECX ; /Arg2 => OFFSET LOCAL.255
004C4A35 PUSH 28 ; |Arg1 = 28
004C4A37 MOV ECX,100 ; |
004C4A3C MOV EDX,EAX ; |
004C4A3E LEA EAX,[LOCAL.319] ; |
004C4A42 CALL 00482250 ; \halo.00482250
004C4A47 ADD ESP,0C
004C4A4A MOV ESI,EAX
004C4A4C CMP SI,BX
004C4A4F JLE SHORT 004C4A73
004C4A51 /MOVSX EDX,SI
004C4A54 |MOV EAX,DWORD PTR SS:[EDX*4+ESP+104]
004C4A5B |PUSH EAX ; /Arg2
004C4A5C |LEA ECX,[LOCAL.319] ; |
004C4A60 |PUSH ECX ; |Arg1 => OFFSET LOCAL.319
004C4A61 |CALL 00622D3B ; \halo.00622D3B
004C4A66 |ADD ESP,8
004C4A69 |TEST EAX,EAX
004C4A6B |JE SHORT 004C4A91
004C4A6D |DEC ESI
004C4A6E |CMP SI,BX
004C4A71 \JG SHORT 004C4A51
004C4A73 LEA EDX,[LOCAL.319]
004C4A77 PUSH EDX
004C4A78 PUSH OFFSET halo.00664708 ; ASCII "Requested function "%s" cannot be executed now."
004C4A7D PUSH EBX
004C4A7E CALL 004C4770
004C4A83 ADD ESP,0C
004C4A86 POP ESI
004C4A87 MOV AL,BL
004C4A89 POP EBX
004C4A8A ADD ESP,500
004C4A90 RETN
004C4A91 PUSH EDI
004C4A92 MOV BYTE PTR DS:[6FFD9D],1
004C4A99 CALL 004829C0
004C4A9E ADD ESP,4
004C4AA1 POP ESI
004C4AA2 MOV BYTE PTR DS:[6FFD9D],BL
004C4AA8 POP EBX
004C4AA9 ADD ESP,500
004C4AAF RETN

Skarma
September 20th, 2009, 01:03 PM
Is anyone interested in making an app to allow you to run multiple instances of Halo? Would it be useful to you?
Some gamers, like me, find it useful to be able to run multiple instances of a game. Extremely so when you don't have a partner to help you reverse! Pretty much all games add this check to make sure you don't open an instance of it more than once. I'm sure there is more than one method of these checks, but so far I have seen the same exact method in a few games. It's very simple and easy to bypass. I'm not gonna go into details really, except show you what they are doing and what extra steps to take. After all, it is a few simple NOP's and changing a profile path.

Before the game window is created, it creates a named mutex with CreateMutex() for all the processes running on your system. If the function fails, that means that there is already a process running that created a mutex with that name and returns a handle to the existing object.
If the function succeeded, the FindWindow() function is called with the class and game title. If the function fails, it means there is another process instance with those names.
The check for Halo looks like this in C++:

HANDLE hWnd = CreateMutex( NULL, true, "Halo" );
if( GetLastError( ) != ERROR_SUCCESS )
{
CWnd *pWnd = CWnd::FindWindow( "Halo", "Halo" );
if( !pWnd )
{
CloseHandle( hWnd );
}
else
{
WINDOWPLACEMENT *pPlacement;
GetWindowPlacement( hWnd, &pPlacement );
SetForegroundWindow( hWnd );

// #define SW_SHOWMINIMIZED 2
if( pPlacement->showCmd != SW_SHOWMINIMIZED )
{
ShowWindow( hWnd, SW_RESTORE );
}
}
}
Here's what it looks like in OllyDbg:
http://img10.imageshack.us/img10/1481/procn.jpg
See how easy that check is? Well, you should know what to do from there Mr. Coder.
But WAIT. I thought I was done there, but nope. Whenever you start Halo, it auto loads the last profile used and then puts your saved games folder in use. To fix it, search for the string in OllyDbg of the path your saved games folder is set to and change it to something else like Gaylo.
Oh yea, if you want to play multiplayer, you will have to run the games on separate ports, usually done through command line parameters. For changing the client port, you would need to use ‘-cport 1234′. Of course, ‘1234′ could be any port number.
Thats all there is to it, thanks for reading. Hope it helps some of you.

Skarma
September 20th, 2009, 01:23 PM
This is the cheat_spawn_warthog console command, in C++. This is reversed from assembly in Olly and is exactly how Halo does it. Some of the types you might not recognize, if you need them I'll post them. Address for Halo PC 1.08

typedef void(*SpawnObject_t)(TagReference*, int);
SpawnObject_t SpawnObject = (SpawnObject_t)0x0045A960;

int CheatSpawnWarthog(void)
{
int LoopCount = 0;
int VehicleIndex = 0;
Globals* globals = *(Globals**)0x00746EC0;
Globals_MultiplayerInformation* MPInfo;
Globals_MultiplayerInformation_Vehicles* Vehicles;
TagReference* Vehicle;
if(globals->MultiplayerInformation.Count > 0)
{
MPInfo = (Globals_MultiplayerInformation*)globals->MultiplayerInformation.Address;
VehicleIndex = MPInfo->Vehicles.Count;
if(VehicleIndex > 0)
{
Vehicles = (Globals_MultiplayerInformation_Vehicles*)MPInfo->Vehicles.Address;
Vehicle = (TagReference*)&Vehicles->Vehicle;
while(!strstr(Vehicle->Name,"warthog"))
{
VehicleIndex = MPInfo->Vehicles.Count;
LoopCount++;

if(LoopCount > VehicleIndex)
return VehicleIndex;
Vehicle = (TagReference*)(MPInfo->Vehicles.Address + (LoopCount * 16));
}
SpawnObject(Vehicle,1);
}
}
return VehicleIndex;
}
Needed structs:

struct Globals{
char Unknown[248];
TagBlock Sounds;
TagBlock Camera;
TagBlock PlayerControl;
TagBlock Difficulty;
TagBlock Grenades;
TagBlock RasterizerData;
TagBlock InterfaceBitmaps;
TagBlock WeaponList;
TagBlock CheatPowerups;
TagBlock MultiplayerInformation;
TagBlock PlayerInformation;
TagBlock FirstPersonInterface;
TagBlock FallingDamage;
TagBlock Materials;
TagBlock PlaylistMembers;
};
struct Globals_MultiplayerInformation{
TagReference Flag;
TagReference Unit;
TagBlock Vehicles;
TagReference HillShader;
TagReference FlagShader;
TagReference Ball;
TagBlock Sounds;
};
struct Globals_MultiplayerInformation_Vehicles{
TagReference Vehicle;
};

With a valid TagReference, you can spawn ANY object with SpawnObject() function, not just a warthog. :downs:

Skarma
September 20th, 2009, 01:28 PM
E: Outdated, I've updated my methods since then, but I decided to post anyway since it's very informational.

Console Output using Halo Engine
By: Skarma
September 05, 2008
-----------------------------------------------------------------
Using Halo engine to draw console text
http://img204.imageshack.us/img204/7944/halotextzj0.png
Console output using Halo engine
Prologue
This is a short reference guide on how Halo outputs messages for the console and how to hook it so you can do it youself. The examples given will be in Assembly and C++. Programming experience is required to follow along, although it is still a good read. I will be showing pictures of disassembly with comments to the side, so you can see a more visual of what's happening.
Where to start
There are other text output functions in Halo, but I will be focusing on just one. The most common used one is the console output. If you have ever used console or devmode, you know what I am refering to. "Requested function "%s" cannot be executed now." is probably the most common string you will see, since it always outputs when a console or devmode command is not valid.
If you don't already know how to use console, you will need to edit the Halo desktop shortcut and add a command line parameter to enable it. To do so, create a shortcut to "halo.exe" on your desktop if you have not done so already. Right click the shortcut and click on Properties. A new window will pop up and you will see an edit box field named Target, which we will be editing. To enable console, you will need to add -console at the end of the Target box, after the quotes. Put a space between each parameter that you add. When I am working with Halo and I need to access tools, I also add -window as a parameter which will run Halo in a window every time I start it with the shortcut.

Example:
"C:\Program Files\Microsoft Games\Halo\halo.exe" -window -console
For a full list of argument, visit: http://hce.halomaps.org/index.cfm?nid=309.
To open / close console, press the Tilde ( ~ ) key anytime that Halo is open. To output the string I mentioned earlier, just type in some random text into the console box and press enter. I will not be using this string as a reference point, since is a different text out function that I don't personally like. I will be using the string "sv_kick is a server-only function!". You move a color into a register before calling it, which is why I like it. I use a debugger called OllyDbg to analyze binary code, which I will using in this guide for Halo. If you don't already have it you can download it at the official website: http://www.ollydbg.de/. I am already assuming you know how to use a debugger, so unfortunatly I will not be going over that subject. Let's move on.
Finding the console output function
Let's start by attaching Halo to OllyDbg. If you have a version of Halo before 1.08 and it has SafeDisc ( no crack ), you will need to reset the debug port, which is an anti debug protection SafeDisc uses. It's a simple detection, but there are tools on the net to bypass this. I like using HelioS Debug Reset. Fortunately for us, the 1.08 patch removed this protection and allows you to play with no cd.
Once attached, open Executable Modules and double click halo.exe a few times to open it in the CPU window. Right click in the CPU window and select Search for > All referenced text strings. Once in the reference window, right click and select Search for text. We need to find the string we will be referencing from, so just type in sv_kick is and click OK. It will bring you to the string we need, which was "sv_kick is a server-only function!". Hit Enter or double click it to see it in the CPU window.
Examine the function
The address for Halo 1.08 is 0x004E3C85, where this string is pushed on the stack. Let's examine the code.
http://img530.imageshack.us/img530/573/ollymm4.png
I have commented out the above disassembly, which tells exactly what is happening. This is the regular procedure of outputting console text. When formatted arguments are added, they are also pushed on the stack before the text function is called, but we won't be dealing with that since we can format a string in our code before we push it on the stack.
You can see above that they are pushing a colour from a static address in memory. If you go to that address in RAM hex editor, you will see an array of floating point values in the format of ARGB ( Alpha, Red, Green, Blue ). You will also notice that it is 1.0f, 1.0f, 0.0f, 0.0f which is Red, the colour of the string when it is outputted to the Halo screen. This is how I figured out that this was the colour. Usually, colour values are in the range from 0 to 255. Well, this is the same thing, but using floats. If you have a colour value in this range, you can do an easy conversion: float value = range / 255.
After the colour is moved to EAX, the string is pushed on top of the stack, then the console output function is called, followed by a stack balance. If you don't balance out the stack, the game will just crash.
Pretty simple huh? Let's continue on and put it to good use!
Recreating the function in C++
I like using DLL projects, because you can directly work with the process once you have it injected into the process space. The benefits are not having to use any Windows memory API's like WriteProcessMemory, which are slow. Instead we can use pointers, since we have direct access to the process, which is more efficient in the end.
In C++, you can use the __asm keyword to write inline assembly, just like what we see in a debugger. I will be using this to recreate our function. We don't need to return anything, so our function will be of a void type. I want to be able to use custom colours. Let's use a float array of 4 elements for our color parameter ( remember ARGB? ). We also need to pass a string, which is in ASCII, so I will use a pointer to a char. The function I use looks exactly like this:

void hkTextOut( char * pString, float fColor[4] )
{
__asm
{
MOV EAX,fColor
PUSH pString
CALL DWORD PTR DS:[oTextOut]
ADD ESP, 04h
}
}
We need to create a function prototype and an instance so we can detour this function in Halo to our recreated function. This is also called hooking. oTextOut will be a call to the original function.

typedef void (*pTextOut)(char *pString, const float fColor[4]);
pTextOut oTextOut;
Detouring
The word detouring is exactly what it means. We detour something. In this case we are detouring the original console output function to our function, which will then call the original. There are a few ways of doing this. You can use Microsoft Detours Library, which is free to download. In the most recent library version is the function DetourAttach, which accomplishes what we need. In the old detours library, the function was called DetourFunction, which ultimately does the same exact thing. The other way we could do it is write our own detour function, so we do not need to include any extra files. I choose to write my own, which I will share with you:

void *DetourFunc(BYTE *src, const BYTE *dst, const int len)
{
BYTE *jmp = (BYTE*)malloc(len+5);
DWORD dwback;
VirtualProtect(src, len, PAGE_READWRITE, &dwback);
memcpy(jmp, src, len); jmp += len;

jmp[0] = 0xE9;
*(DWORD*)(jmp+1) = (DWORD)(src+len - jmp) - 5;
src[0] = 0xE9;
*(DWORD*)(src+1) = (DWORD)(dst-src) - 5;
VirtualProtect(src, len, dwback, &dwback);
return (jmp-len);
}
To use this function to detour the original Halo function, we will do this:

DWORD dwTextOut = 0x00496CD0;
oTextOut = (pTextOut)DetourFunc((PBYTE)dwTextOut,(PBYTE)&hkTextOut, 6);
The length is usually 5 or 6 bytes, depending on the disassembly. This just inserts a JMP from the original code to our function so each time it gets called, it will "detour" to ours. The alternate way to do this would be to write a code cave, which is best when writing a normal Windows Application, but this is not needed since we have direct access.
Page Protection & Calling our output function
Like most binary executables, it is write protected, which means we cannot modify any code in memory, so calling our DetourFunc will not do anything and most likely crash the game or our application. We need to change the access protection of the region we are modifying. The VirtualProtect API is just fine for doing this. After we are done, we should put the original protection back, just in case. While we have access we need to call our the console output function before setting the original protection. I wrote the below function for drawing text to minimize the task to something very, very simple. The detouring and page protection is all done for you when you call it.
Note: When detouring the text function, we need to write the original bytes back. If you enter in a console command while the function is detoured, the game will crash. In the below function I declare the original bytes and write them after I am done drawing text and before I change back the original page protection.

DWORD __stdcall hkDrawText(char *pString, const float fColor[4])
{
DWORD dwOldProtect = 0;
DWORD dwTextOut = 0x00496CD0;
BYTE bTextOutOrig[6] = {0x83, 0xEC, 0x10, 0x57, 0x8B, 0xF8};
VirtualProtect((void*)dwTextOut, 10, PAGE_EXECUTE_READWRITE, &dwOldProtect);
oTextOut = (pTextOut)DetourFunc((PBYTE)dwTextOut,(PBYTE)&hkTextOut, 6);

hkTextOut(pString, fColor);
memcpy((void*)dwTextOut, (void*)bTextOutOrig, 6);
VirtualProtect((void*)dwTextOut, 10, dwOldProtect, &dwOldProtect);
return 0;
}

Custom Colours and Drawing Text!

To create your own custom colours for your text output, you need to create a float array of 4 elements in the format of ARGB:

float fRed[4] = {1.0f, 1.0f, 0.0f, 0.0f};
float fGreen[4] = {1.0f, 0.0f, 1.0f, 0.0f};
float fBlue[4] = {1.0f, 0.0f, 0.0f, 1.0f};
These are just examples. I explained earlier how to do a conversion from those 0 to 255 values. Let's call our function!

hkDrawText( "I am drawing text! Woo!", fGreen );
That's it! If you want to format you string with additional arguements, you can use sprintf function in the fstream header like so:

char buf[256]; // will hold our formatted string
int a = 2; // an argument I am adding
sprintf(buf, "This is example %i with blue text!", a); // format our string
hkDrawText(buf, fBlue); // draw
Epilogue
This ends the draw text guide. I hope it was as exciting for you as it was for me!
-------------------------------------------------------------------------------------------------------
I have hooked 2 functions that can draw text like console output through Halo's Engine! I don't feel like explaining how it's all done, but I will just provide the source code here as an example of how to do it in C++/inline asm. One draws gray text and one draws white text.

#include <windows.h>
#include <detours.h>
//------------------------------------------------------------------------------
typedef void (*pDrawGrayText)(char * pString);
pDrawGrayText oDrawGrayText;
//------------------------------------------------------------------------------
void hkDrawGrayText(char * pString)
{
__asm PUSH pString
__asm PUSH 0;
__asm CALL DWORD PTR DS:[oDrawGrayText];
__asm ADD ESP, 08h;
}
//------------------------------------------------------------------------------
typedef void (*pDrawWhiteText)(char * pString);
pDrawWhiteText oDrawWhiteText;
//------------------------------------------------------------------------------
void hkDrawWhiteText(char * pString)
{
__asm MOV EAX,DWORD PTR DS:[0x0067D1EC]
__asm PUSH pString
__asm CALL DWORD PTR DS:[oDrawWhiteText];
__asm ADD ESP, 04h;
}
//------------------------------------------------------------------------------
DWORD __stdcall dwHook( void *)
{
HANDLE hand = GetCurrentProcess();
DWORD old = NULL;
struct AText { unsigned char back[6]; };
struct BText { unsigned char back[6]; };
struct CText { unsigned char jmp[6]; };
AText * aText = ( AText * )0x004C4770; //graytext
BText * bText = ( BText * )0x00495120; //whitetext
CText * cText = ( CText * )0x004C477D; //draw w/console closed
unsigned char nop = 0x90;
unsigned char back1[6] = { 0xA0, 0xC0, 0xE2, 0x6A, 0x00, 0x81 };
unsigned char back2[6] = { 0x83, 0xEC, 0x10, 0x57, 0x8B, 0xF8 };
// DrawGrayText
VirtualProtectEx(hand,(void*)0x004C4770,10,PAGE_EX ECUTE_READWRITE,&old);
// Draw without console open
VirtualProtectEx(hand,(void*)0x004C477D,10,PAGE_EX ECUTE_READWRITE,&old);
for( unsigned char i = 0; i < 6; i++ )cText->jmp[i] = nop;
// DrawWhiteText
VirtualProtectEx(hand,(void*)0x00495120,10,PAGE_EX ECUTE_READWRITE,&old);


while(1)
{
if (GetAsyncKeyState(VK_F5)&1)
{
oDrawGrayText = (pDrawGrayText)DetourFunction((PBYTE)0x004C4770,(P BYTE)hkDrawGrayText );
hkDrawGrayText("DeltronZero :]");
for( unsigned char a = 0; a < 6; a++ ) aText->back[a] = back1[a];
}
if (GetAsyncKeyState(VK_F6)&1)
{
oDrawWhiteText = (pDrawWhiteText)DetourFunction((PBYTE)0x00495120,( PBYTE)hkDrawWhiteText );
hkDrawWhiteText("DeltronZero :]");
for( unsigned char a = 0; a < 6; a++ ) bText->back[a] = back2[a];
}
Sleep( 10 );
}
return 0;
}
//------------------------------------------------------------------------------
bool __stdcall DllMain( HMODULE hModule, DWORD ulReason, LPVOID lpReserved )
{
if( ulReason == DLL_PROCESS_ATTACH )
{
CreateThread( 0, 0, dwHook, 0, 0, 0 );
}
return true;
}
//------------------------------------------------------------------------------

Limited
September 20th, 2009, 01:29 PM
Skyline edited this method too to allow spawning of other vehicles for our OS code.
E.g.
KTNbqpPcGiE

(dont mean to steal thread skarma :))

chrisk123999
September 20th, 2009, 01:31 PM
Doesn't the print command do the same thing? Although it doesn't work in-game...
It works in sapien.

Skarma
September 20th, 2009, 01:33 PM
Wow, nice. Glad you got the code to work and glad someone found it useful! w00t

I didn't realize I posted this on alot of forums, didn't know anyone even seen it lol

Skarma
September 20th, 2009, 01:35 PM
Doesn't the print command do the same thing? Although it doesn't work in-game...
It works in sapien.I bet you the print command doesn't have text formatting, custom colors and changable coordinates...

Limited
September 20th, 2009, 01:39 PM
Wow, nice. Glad you got the code to work and glad someone found it useful! w00t

I didn't realize I posted this on alot of forums, didn't know anyone even seen it lol
Oh well, we didnt really use your code/work, Skyline worked it out himself. Although you did tell me it was possible on MSN at the time :D

FRain
September 20th, 2009, 01:40 PM
Hey, Skarma, this is great stuff, but could you please put this into one thread and not 35,001,412 threads?

Skarma
September 20th, 2009, 01:41 PM
Oh well, we didnt really use your code/work, Skyline worked it out himself. Although you did tell me it was possible on MSN at the time :DWell, shit on a stick. My bad. Back to hopelessness...:haw:


Hey, Skarma, this is great stuff, but could you please put this into one thread and not 35,001,412 threads?too late =p

chrisk123999
September 20th, 2009, 01:41 PM
No, but I was just saying.

Limited
September 20th, 2009, 01:44 PM
I looked into this for testing purposes, but I was looking at the CreateWindowExA API, thinking that around it, would be the check to see if process was already running, didnt realise Halo used the MutexA API.

Nice work.

The issue I had also, was I kept corrupting Halo's exe, is there a way to bypass the protection?

Skarma
September 20th, 2009, 01:51 PM
Address are for Halo PC 1.08. Just some rendering code for Halo. There are so many more functions for rendering, but gotta start somewhere.
These structs are from the GBXModel tag in the Halo map files. They describe every model in that map and needed for rendering models. Reversed using MHS, Olly, and Guerilla(Bungie's tag editor).

#ifndef GBXMODEL_H
#define GBXMODEL_H
#include <windows.h>
#include <d3d9.h>
struct GBXModel;
struct GBXModel_Markers;
struct GBXModel_Markers_Instances;
struct GBXModel_Nodes;
struct GBXModel_Regions;
struct GBXModel_Regions_Permutations;
struct GBXModel_Geometries;
struct GBXModel_Geometries_Parts;
struct GBXModel_Geometries_Parts_Indices;
struct GBXModel_Geometries_Parts_Vertices;
struct GBXModel_Shaders;

struct GBXModel{
int Flags : 32;
int NodeListChecksum;
float SuperHighDetailCutoff;
float HighDetailCutoff;
float MediumDetailCutoff;
float LowDetailCutoff;
float SuperLowDetailCutoff;
short SuperHighDetailNodeCount;
short HighDetailNodeCount;
short MediumDetailNodeCount;
short LowDetailNodeCount;
short SuperLowDetailNodeCount;
char Unknown[10];
float BaseMapUScale;
float BaseMapVScale;
char Unknown2[116];
TagBlock Markers;
TagBlock Nodes;
TagBlock Regions;
TagBlock Geometries;
TagBlock Shaders;
};
struct GBXModel_Markers{
char Name[32];
short MagicIdentifier;
char Unknown[18];
TagBlock Instances;
};
struct GBXModel_Markers_Instances{
unsigned char RegionIndex;
unsigned char PermutationIndex;
unsigned short NodeIndex;
float Translation[3]; // xyz
float Rotation[4]; // ijkw
};
struct GBXModel_Nodes{
char Name[32];
short NextSiblingNodeIndex;
short FirstChildNodeIndex;
short ParentNodeIndex;
short Unknown;
float DefaultTranslation[3]; // xyz
float DefaultRotation[4]; // ijkw
float NodeDistanceFromParent;
char Unknown2[84];
};
struct GBXModel_Regions{
char Name[64];
TagBlock Permutations;
};
struct GBXModel_Regions_Permutations{
char Name[32];
int Flags;
char Unknown[28];
short SuperLow;
short Low;
short Medium;
short High;
short SuperHigh;
char Unknown2[14];
};
struct GBXModel_Geometries{
char Unknown[36];
TagBlock Parts;
};
struct GBXModel_Geometries_Parts_Indices{
unsigned short PrimitiveTypeIndex;
unsigned short Unknown;
unsigned int IndiceCount;
int Unknown2;
IDirect3DIndexBuffer9* pIndexData;
};
struct GBXModel_Geometries_Parts_Vertices{
unsigned short StrideIndex;
unsigned short Unknown;
unsigned int VerticeCount;
int Unknown2[2];
IDirect3DVertexBuffer9* pStreamData;
};
struct GBXModel_Geometries_Parts{
int Flags : 32;
char PrevFilthyPartIndex;
char NextFilthyPartIndex;
short ShaderIndex;
short CentroidPrimaryNode;
short CentroidSecondaryNode;
float CentroidPrimeryWeight;
float CentroidSecondaryWeight;
float Centroid[3]; // xyz
char Unknown[36];
GBXModel_Geometries_Parts_Indices IndiceInfo;
GBXModel_Geometries_Parts_Vertices VerticeInfo;
char Unknown2[28];
};
struct GBXModel_Shaders{
TagReference Shader;
unsigned char Permutation;
char Unknown[15];
};
#endif /* GBXMODEL_H */
Some needed globals for the following functions:

bool* g_bSoftware = (bool*)0x0069C690;
unsigned short* g_pStrideTable = (unsigned short*)0x0065DE50;
unsigned int* g_pPrimitiveTypeTable = (unsigned int*)0x0065E084;
IDirect3DDevice9*** pHaloDevice = (IDirect3DDevice9***)0x0071D09C;
IDirect3DDevice9* g_pDevice = (IDirect3DDevice9*)**pHaloDevice;
struct _ModelInfo{
char Unknown[48];
GBXModel_Geometries_Parts_Indices* IndiceInfo;
char Unknown2[4];
unsigned int PrimitiveCount;
char Unknown3[4];
GBXModel_Geometries_Parts_Vertices* VerticeInfo;
};
_ModelInfo* ModelInfo = (_ModelInfo*)0x006E1750;
A function that does some if statements and calls different render functions, I have only done one out of five or six here, so this function is not even near complete, because I have to reverse 6 other functions to finish this one ><

HRESULT Unknown(_ModelInfo* pModelInfo)
{
if(pModelInfo->IndiceInfo)
{
if(pModelInfo->VerticeInfo)
{
return RenderModel(pModelInfo->PrimitiveCount, pModelInfo->VerticeInfo, pModelInfo->IndiceInfo);
}
//...More code Here
}
//...More Code Here
}
A function that renders a model. It is missing a chunk of code because it was some advanced assembly that changed the vertex processing mode based on the stride count(?). Other than that, it is complete and untested lol. Also, it can't render more than 10,000 primitives at once, or at least it doesn't want you to, so it loops and renders in chunks if it is greater.

HRESULT RenderModel(unsigned int PrimitiveCount, GBXModel_Geometries_Parts_Vertices* VerticeInfo, GBXModel_Geometries_Parts_Indices* IndiceInfo)
{
unsigned short Stride;
D3DPRIMITIVETYPE PrimitiveType;
unsigned int PrimCount;
unsigned int StartIndex = 0;
while(PrimitiveCount > 0)
{
if(!IndiceInfo)
break;
if(!IndiceInfo->pIndexData)
break;
if(!VerticeInfo)
break;
if(!VerticeInfo->pStreamData)
break;

PrimCount = 10000;
if(PrimitiveCount <= 10000)
PrimCount = PrimitiveCount;
Stride = *(unsigned short*)((unsigned long)g_pStrideTable + (VerticeInfo->StrideIndex * 2));
PrimitiveType = *(D3DPRIMITIVETYPE*)((unsigned long)g_pPrimitiveTypeTable + (IndiceInfo->PrimitiveTypeIndex * 4));
g_pDevice->SetSoftwareVertexProcessing(*g_bSoftware);
g_pDevice->SetStreamSource(0, VerticeInfo->pStreamData, 0, Stride);
g_pDevice->SetIndices(IndiceInfo->pIndexData);
g_pDevice->DrawIndexedPrimitive(PrimitiveType, 0, 0,VerticeInfo->VerticeCount, StartIndex, PrimCount);
PrimitiveCount -= PrimCount;
if(IndiceInfo->PrimitiveTypeIndex){
if(IndiceInfo->PrimitiveTypeIndex == 1){
StartIndex += PrimCount;
}
}
else{
StartIndex += PrimCount + PrimCount * 2;
}
}
return g_pDevice->SetSoftwareVertexProcessing(*g_bSoftware);
}

teh lag
September 20th, 2009, 01:52 PM
Do you think you could maybe keep these to one thread?

Limited
September 20th, 2009, 01:56 PM
Ah yeah, thinks is the method Omega used for his version changer.

king_nothing_
September 20th, 2009, 03:15 PM
I would be interested in such an app, as I have two copies of Halo and two monitors. I've tried to figure out a way to do it in the past but was never able to.

Pyong Kawaguchi
September 20th, 2009, 03:47 PM
If It would be possible to dedicate another keyboard/mouse combo to the other window, that would be great aswell.

Aßyll
September 20th, 2009, 05:31 PM
Another option for running multiple instances of ANYTHING I've found is Sandboxie. (http://www.sandboxie.com/index.php?DownloadSandboxie) I tested it with Halo a bit, and I got 2 instances to start up easily. The first one I ran started a LAN server just fine, the second didn't seem to want to work. I think there are a few more inherit issues with 2 instances of halo sharing resources - namely .map files, and maybe network shtuff.

Skarma
September 20th, 2009, 05:34 PM
To fix the network problem, you just have to change the client ports through the command line parameters, like in my first post.

Choking Victim
September 20th, 2009, 06:54 PM
This is some pretty cool research, have you seen anything that would cause this problem:

If a model has vertices weighted to > 41 nodes, then the vertices will stretch.

I could give you examples if you want.

Skarma
September 20th, 2009, 07:42 PM
This is some pretty cool research, have you seen anything that would cause this problem:

If a model has vertices weighted to > 41 nodes, then the vertices will stretch.

I could give you examples if you want.Nope, I did this research a long time ago. If you could tell me where in the model structures this value is located, I could check it out. I barely know anything about modeling, just some direct3d stuff which helped greatly with this. Is a node another name for a single vertex?

Advancebo
September 20th, 2009, 07:44 PM
A node is like the central point of activity. Like the bones on the cyborg model, that controls the arms, legs, and body movement. Or the frames on a warthog, that controls the wheels, suspension, and chaingun.

Skarma
September 20th, 2009, 07:54 PM
Gotcha. Well, I really need to reverse more model functions so I can figure out stuff for my Forge project. I'll post all my research in this thread. I just need a bit more info to hunt down your problem asap.

Dwood
September 20th, 2009, 09:26 PM
Must_spread_rep.

FRain
September 20th, 2009, 10:48 PM
Dude, keep it to one thread!

Con
September 20th, 2009, 10:52 PM
Skarma you are just awesome

Con
September 21st, 2009, 07:10 PM
Skarma, post all future information in this thread and edit the OP to include a link to that post. This way we can keep all of your information together under one release thread and people wont have to go searching for each one.
edit: If you want me to give the thread a better name, just let me know.

FireScythe
September 22nd, 2009, 12:49 PM
This reminded me of a program I made to automatically build tag definitions from guerilla exported text files. It was originally built for kornmans old C# tag interface, but i've repurposed it to build definitions for OS. So the output isn't quite what you need but it might help somewhat.

Things to note though, it doesn't put any pads or flag/enum values and it doesn't check for duplicate names. No error checking and such either, so no guarantees or warranties :P.
Link (http://cid-d439194bef5aa58e.skydrive.live.com/self.aspx/Public/AutoTagDefinitionBuilderOS.zip).

Use empty/new tags when you export from guerilla, and its best to not export from guerilla with one of every block and sub block added as guerilla crashes if you do.

Typical I/O:
In

biped untitled
3
flags word flags 0
bounding radius real 0.000000
bounding offset real point 3d 0.000000 0.000000 0.000000
origin offset real point 3d 0.000000 0.000000 0.000000
acceleration scale real 0.000000
model tag reference mod2
animation graph tag reference antr
collision model tag reference coll
physics tag reference phys
modifier shader tag reference shdr
creation effect tag reference effe
render bounding radius real 0.000000
A in enum none
B in enum none
C in enum none
D in enum none
hud text message index short integer 0
forced shader permuation index short integer 0
attachments block 1
element 0
type tag reference ÿÿÿÿ
marker string
primary scale enum none
secondary scale enum none
change color enum none
end element 0
widgets block 1
element 0
reference tag reference ÿÿÿÿ
end element 0
functions block 1
element 0
flags long flags 0
period real 0.000000
scale period by enum none
function enum one
scale function by enum none
wobble function enum one
wobble period real 0.000000
wobble magnitude real 0.000000
square wave threshold real fraction 0.000000
step count short integer 0
map to enum linear
sawtooth count short integer 0
add enum none
scale result by enum none
bounds mode enum clip
bounds fraction bounds 0.000000 0.000000
turn off with short block index NONE -1
scale by real 0.000000
usage string
end element 0
change colors block 1
element 0
darken by enum none
scale by enum none
scale flags long flags 0
color lower bound real rgb color 0.000000 0.000000 0.000000
color upper bound real rgb color 0.000000 0.000000 0.000000
permutations block 1
element 0
weight real 0.000000
color lower bound real rgb color 0.000000 0.000000 0.000000
color upper bound real rgb color 0.000000 0.000000 0.000000
end element 0
end element 0
predicted resources block 1
element 0
type enum bitmap
resource index short integer 0
tag index long integer 0
end element 0
flags long flags 0
default team enum none
constant sound volume enum silent
rider damage fraction real 0.000000
integrated light toggle tag reference effe
A in enum none
B in enum none
C in enum none
D in enum none
camera field of view angle 0.000000
camera stiffness real 0.000000
camera marker name string
camera submerged marker name string
pitch auto-level angle 0.000000
pitch range angle bounds 0.000000 0.000000
camera tracks block 1
element 0
track tag reference trak
end element 0
seat acceleration scale real vector 3d 0.000000 0.000000 0.000000
soft ping threshold real 0.000000
soft ping interrupt time real 0.000000
hard ping threshold real 0.000000
hard ping interrupt time real 0.000000
hard death threshold real 0.000000
feign death threshold real 0.000000
feign death time real 0.000000
distance of evade anim real 0.000000
distance of dive anim real 0.000000
stunned movement threshold real 0.000000
feign death chance real 0.000000
feign repeat chance real 0.000000
spawned actor tag reference actv
spawned actor count short integer bounds 0 0
spawned velocity real 0.000000
aiming velocity maximum angle 0.000000
aiming acceleration maximum angle 0.000000
casual aiming modifier real fraction 0.000000
looking velocity maximum angle 0.000000
looking acceleration maximum angle 0.000000
AI vehicle radius real 0.000000
AI danger radius real 0.000000
melee damage tag reference jpt!
motion sensor blip size enum medium
NEW HUD INTERFACES block 1
element 0
unit hud interface tag reference unhi
end element 0
dialogue variants block 1
element 0
variant number short integer 0
dialogue tag reference udlg
end element 0
grenade velocity real 0.000000
grenade type enum human fragmentation
grenade count short integer 0
powered seats block 1
element 0
driver powerup time real 0.000000
driver powerdown time real 0.000000
end element 0
weapons block 1
element 0
weapon tag reference weap
end element 0
seats block 1
element 0
flags long flags 0
label string
marker name string
acceleration scale real vector 3d 0.000000 0.000000 0.000000
yaw rate real 0.000000
pitch rate real 0.000000
camera marker name string
camera submerged marker name string
pitch auto-level angle 0.000000
pitch range angle bounds 0.000000 0.000000
camera tracks block 1
element 0
track tag reference trak
end element 0
unit hud interface block 1
element 0
unit hud interface tag reference unhi
end element 0
hud text message index short integer 0
yaw minimum angle 0.000000
yaw maximum angle 0.000000
built-in gunner tag reference actv
end element 0
moving turning speed angle 0.000000
flags long flags 0
stationary turning threshold angle 0.000000
A in enum none
B in enum none
C in enum none
D in enum none
DON'T USE tag reference jpt!
bank angle angle 0.000000
bank apply time real 0.000000
bank decay time real 0.000000
pitch ratio real 0.000000
max velocity real 0.000000
max sidestep velocity real 0.000000
acceleration real 0.000000
deceleration real 0.000000
angular velocity maximum angle 0.000000
angular acceleration maximum angle 0.000000
crouch velocity modifier real 0.000000
maximum slope angle angle 0.000000
downhill falloff angle angle 0.000000
downhill cutoff angle angle 0.000000
downhill velocity scale real 0.000000
uphill falloff angle angle 0.000000
uphill cutoff angle angle 0.000000
uphill velocity scale real 0.000000
footsteps tag reference foot
jump velocity real 0.000000
maximum soft landing time real 0.000000
maximum hard landing time real 0.000000
minimum soft landing velocity real 0.000000
minimum hard landing velocity real 0.000000
maximum hard landing velocity real 0.000000
death hard landing velocity real 0.000000
standing camera height real 0.000000
crouching camera height real 0.000000
crouch transition time real 0.000000
standing collision height real 0.000000
crouching collision height real 0.000000
collision radius real 0.000000
autoaim width real 0.000000
contact points block 1
element 0
marker name string
end element 0
out

#pragma region biped
struct biped_group
{
#pragma region Attachments
struct attachments_block
{
TAG_FIELD(tag_reference, type, "����");
TAG_FIELD(tag_string, marker);
TAG_FIELD(_enum, primary_scale);
TAG_FIELD(_enum, secondary_scale);
TAG_FIELD(_enum, change_color);
};
#pragma endregion
#pragma region Widgets
struct widgets_block
{
TAG_FIELD(tag_reference, reference, "����");
};
#pragma endregion
#pragma region Functions
struct functions_block
{
TAG_FIELD(long_flags, flags);
TAG_FIELD(real, period);
TAG_FIELD(_enum, scale_period_by);
TAG_FIELD(_enum, function);
TAG_FIELD(_enum, scale_function_by);
TAG_FIELD(_enum, wobble_function);
TAG_FIELD(real, wobble_period);
TAG_FIELD(real, wobble_magnitude);
TAG_FIELD(real_fraction, square_wave_threshold);
TAG_FIELD(int16, step_count);
TAG_FIELD(_enum, map_to);
TAG_FIELD(int16, sawtooth_count);
TAG_FIELD(_enum, add);
TAG_FIELD(_enum, scale_result_by);
TAG_FIELD(_enum, bounds_mode);
TAG_FIELD(tag_string, bounds);
TAG_FIELD(int16, turn_off_with);
TAG_FIELD(real, scale_by);
TAG_FIELD(tag_string, usage);
};
#pragma endregion
#pragma region Change Colors
struct change_colors_block
{
#pragma region Permutations
struct permutations_block
{
TAG_FIELD(real, weight);
TAG_FIELD(real_rgb_color, color_lower_bound);
TAG_FIELD(real_rgb_color, color_upper_bound);
};
#pragma endregion
TAG_FIELD(_enum, darken_by);
TAG_FIELD(_enum, scale_by);
TAG_FIELD(long_flags, scale_flags);
TAG_FIELD(real_rgb_color, color_lower_bound);
TAG_FIELD(real_rgb_color, color_upper_bound);
TAG_TBLOCK(permutations, permutations_block);
};
#pragma endregion
#pragma region Predicted Resources
struct predicted_resources_block
{
TAG_FIELD(_enum, type);
TAG_FIELD(int16, resource_index);
TAG_FIELD(int32, tag_index);
};
#pragma endregion
#pragma region Camera Tracks
struct camera_tracks_block
{
TAG_FIELD(tag_reference, track, "trak");
};
#pragma endregion
#pragma region NEW HUD INTERFACES
struct new_hud_interfaces_block
{
TAG_FIELD(tag_reference, unit_hud_interface, "unhi");
};
#pragma endregion
#pragma region Dialogue Variants
struct dialogue_variants_block
{
TAG_FIELD(int16, variant_number);
TAG_FIELD(tag_reference, dialogue, "udlg");
};
#pragma endregion
#pragma region Powered Seats
struct powered_seats_block
{
TAG_FIELD(real, driver_powerup_time);
TAG_FIELD(real, driver_powerdown_time);
};
#pragma endregion
#pragma region Weapons
struct weapons_block
{
TAG_FIELD(tag_reference, weapon, "weap");
};
#pragma endregion
#pragma region Seats
struct seats_block
{
#pragma region Camera Tracks
struct camera_tracks_block
{
TAG_FIELD(tag_reference, track, "trak");
};
#pragma endregion
#pragma region Unit Hud Interface
struct unit_hud_interface_block
{
TAG_FIELD(tag_reference, unit_hud_interface, "unhi");
};
#pragma endregion
TAG_FIELD(long_flags, flags);
TAG_FIELD(tag_string, label);
TAG_FIELD(tag_string, marker_name);
TAG_FIELD(real_vector3d, acceleration_scale);
TAG_FIELD(real, yaw_rate);
TAG_FIELD(real, pitch_rate);
TAG_FIELD(tag_string, camera_marker_name);
TAG_FIELD(tag_string, camera_submerged_marker_name);
TAG_FIELD(angle, pitch_auto_level);
TAG_FIELD(angle_bounds, pitch_range);
TAG_TBLOCK(camera_tracks, camera_tracks_block);
TAG_TBLOCK(unit_hud_interface, unit_hud_interface_block);
TAG_FIELD(int16, hud_text_message_index);
TAG_FIELD(angle, yaw_minimum);
TAG_FIELD(angle, yaw_maximum);
TAG_FIELD(tag_reference, built_in_gunner, "actv");
};
#pragma endregion
#pragma region Contact Points
struct contact_points_block
{
TAG_FIELD(tag_string, marker_name);
};
#pragma endregion

#pragma region Fields
TAG_FIELD(word_flags, flags);
TAG_FIELD(real, bounding_radius);
TAG_FIELD(real_point3d, bounding_offset);
TAG_FIELD(real_point3d, origin_offset);
TAG_FIELD(real, acceleration_scale);
TAG_FIELD(tag_reference, model, "mod2");
TAG_FIELD(tag_reference, animation_graph, "antr");
TAG_FIELD(tag_reference, collision_model, "coll");
TAG_FIELD(tag_reference, physics, "phys");
TAG_FIELD(tag_reference, modifier_shader, "shdr");
TAG_FIELD(tag_reference, creation_effect, "effe");
TAG_FIELD(real, render_bounding_radius);
TAG_FIELD(_enum, a_in);
TAG_FIELD(_enum, b_in);
TAG_FIELD(_enum, c_in);
TAG_FIELD(_enum, d_in);
TAG_FIELD(int16, hud_text_message_index);
TAG_FIELD(int16, forced_shader_permuation_index);
TAG_TBLOCK(attachments, attachments_block);
TAG_TBLOCK(widgets, widgets_block);
TAG_TBLOCK(functions, functions_block);
TAG_TBLOCK(change_colors, change_colors_block);
TAG_TBLOCK(predicted_resources, predicted_resources_block);
TAG_FIELD(long_flags, flags);
TAG_FIELD(_enum, default_team);
TAG_FIELD(_enum, constant_sound_volume);
TAG_FIELD(real, rider_damage_fraction);
TAG_FIELD(tag_reference, integrated_light_toggle, "effe");
TAG_FIELD(_enum, a_in);
TAG_FIELD(_enum, b_in);
TAG_FIELD(_enum, c_in);
TAG_FIELD(_enum, d_in);
TAG_FIELD(angle, camera_field_of_view);
TAG_FIELD(real, camera_stiffness);
TAG_FIELD(tag_string, camera_marker_name);
TAG_FIELD(tag_string, camera_submerged_marker_name);
TAG_FIELD(angle, pitch_auto_level);
TAG_FIELD(angle_bounds, pitch_range);
TAG_TBLOCK(camera_tracks, camera_tracks_block);
TAG_FIELD(real_vector3d, seat_acceleration_scale);
TAG_FIELD(real, soft_ping_threshold);
TAG_FIELD(real, soft_ping_interrupt_time);
TAG_FIELD(real, hard_ping_threshold);
TAG_FIELD(real, hard_ping_interrupt_time);
TAG_FIELD(real, hard_death_threshold);
TAG_FIELD(real, feign_death_threshold);
TAG_FIELD(real, feign_death_time);
TAG_FIELD(real, distance_of_evade_anim);
TAG_FIELD(real, distance_of_dive_anim);
TAG_FIELD(real, stunned_movement_threshold);
TAG_FIELD(real, feign_death_chance);
TAG_FIELD(real, feign_repeat_chance);
TAG_FIELD(tag_reference, spawned_actor, "actv");
TAG_FIELD(short_bounds, spawned_actor_count);
TAG_FIELD(real, spawned_velocity);
TAG_FIELD(angle, aiming_velocity_maximum);
TAG_FIELD(angle, aiming_acceleration_maximum);
TAG_FIELD(real_fraction, casual_aiming_modifier);
TAG_FIELD(angle, looking_velocity_maximum);
TAG_FIELD(angle, looking_acceleration_maximum);
TAG_FIELD(real, ai_vehicle_radius);
TAG_FIELD(real, ai_danger_radius);
TAG_FIELD(tag_reference, melee_damage, "jpt!");
TAG_FIELD(_enum, motion_sensor_blip_size);
TAG_TBLOCK(new_hud_interfaces, new_hud_interfaces_block);
TAG_TBLOCK(dialogue_variants, dialogue_variants_block);
TAG_FIELD(real, grenade_velocity);
TAG_FIELD(_enum, grenade_type);
TAG_FIELD(int16, grenade_count);
TAG_TBLOCK(powered_seats, powered_seats_block);
TAG_TBLOCK(weapons, weapons_block);
TAG_TBLOCK(seats, seats_block);
TAG_FIELD(angle, moving_turning_speed);
TAG_FIELD(long_flags, flags);
TAG_FIELD(angle, stationary_turning_threshold);
TAG_FIELD(_enum, a_in);
TAG_FIELD(_enum, b_in);
TAG_FIELD(_enum, c_in);
TAG_FIELD(_enum, d_in);
TAG_FIELD(tag_reference, don_t_use, "jpt!");
TAG_FIELD(angle, bank_angle);
TAG_FIELD(real, bank_apply_time);
TAG_FIELD(real, bank_decay_time);
TAG_FIELD(real, pitch_ratio);
TAG_FIELD(real, max_velocity);
TAG_FIELD(real, max_sidestep_velocity);
TAG_FIELD(real, acceleration);
TAG_FIELD(real, deceleration);
TAG_FIELD(angle, angular_velocity_maximum);
TAG_FIELD(angle, angular_acceleration_maximum);
TAG_FIELD(real, crouch_velocity_modifier);
TAG_FIELD(angle, maximum_slope_angle);
TAG_FIELD(angle, downhill_falloff_angle);
TAG_FIELD(angle, downhill_cutoff_angle);
TAG_FIELD(real, downhill_velocity_scale);
TAG_FIELD(angle, uphill_falloff_angle);
TAG_FIELD(angle, uphill_cutoff_angle);
TAG_FIELD(real, uphill_velocity_scale);
TAG_FIELD(tag_reference, footsteps, "foot");
TAG_FIELD(real, jump_velocity);
TAG_FIELD(real, maximum_soft_landing_time);
TAG_FIELD(real, maximum_hard_landing_time);
TAG_FIELD(real, minimum_soft_landing_velocity);
TAG_FIELD(real, minimum_hard_landing_velocity);
TAG_FIELD(real, maximum_hard_landing_velocity);
TAG_FIELD(real, death_hard_landing_velocity);
TAG_FIELD(real, standing_camera_height);
TAG_FIELD(real, crouching_camera_height);
TAG_FIELD(real, crouch_transition_time);
TAG_FIELD(real, standing_collision_height);
TAG_FIELD(real, crouching_collision_height);
TAG_FIELD(real, collision_radius);
TAG_FIELD(real, autoaim_width);
TAG_TBLOCK(contact_points, contact_points_block);
#pragma endregion
};
#pragma endregion

Skarma
September 22nd, 2009, 02:13 PM
it doesn't put any padsThe only thing holding me back from using it. In Guerilla, some of the variable names are cutoff, so I might use it for those. I'm OCD when it comes to getting struct member offsets correct, which is why I like doing it manually and double check everything. I was even thinking about making a function to compare my struct sizes to the actual structs sizes, just to be sure I didn't miss anything lol!

I got a weird system going on for reversing tags lol First I open Halo CE and start a server. Then I use a function I wrote that iterates through the map tag index thats loaded in virtual memory and prints out the addresses of every tag of a specified taggroup and it's tag path. Then I open a tag group I want to reverse in Guerilla and go to the address in a memory hex editor that was printed out for the equivelent tag I opened in guerilla. The reason I don't just view the tags in a binary hex editor, is because guerillas tag format is not the same as when its compiled into the map and makes it confusing. Plus seeing where the pointers actually point to in memory is very helpful, I don't have to go using magic algos, I can just go to the pointer address.

For finding unknowns and padding, I changed variables in guerilla, saved the tag as a different name, then open both tags in a binary hex editor and switch back and forth looking for the changes lol. The way I do it is actually quite efficient for me even though it sounds rough

I've reversed quite a few tags already, it's just a slow process when there are so many different tags and tag blocks. I will post all completed ones.

Thanks for the info and app FireScythe. It will come in handy. Maybe you want to help with my Forge project, seeing as you are a very good coder. :downs: or maybe not

FireScythe
September 22nd, 2009, 03:23 PM
Well it's not meant to be a one click and your done, just a way to get a basic structure so you can fill in the blanks, without having to type and format everything yourself.


Maybe you want to help with my Forge project, seeing as you are a very good coder. :downs: or maybe not.Well i'm still busy working with OS (Post processing stuff) so I haven't the time for other projects (plus i'm probably not at the skill level you think i am :P).

Skarma
October 8th, 2009, 02:08 AM
This function was one I didn't care to reverse, but it caught my attention of some reason or another. This function is called in the player nametags function(as well as many other functions). I'm working on the nametags function because it has the engine world space to screen space, which I'm using for CE Forge. I will be posting that next when it's done. This is for Halo CE 1.08.

Thnx to OllyDbg, IDA Pro, Hexrays, and Kornman00.

Needed structs/globals:


typedef signed int int32; typedef unsigned int uint32;
typedef signed short int16; typedef unsigned short uint16;
typedef signed char int8; typedef unsigned char uint8;

#define TAGINDEX 0x00816D04
#define INVALID -1

struct Identity
{
union
{
uint32 Ident;
struct
{
int16 Index;
int16 Salt;
};
};
};

struct TagInstance
{
union
{
uint32 TagGroup; // 0x00
uint8 TagGroupC[4]; // 0x00
};
union
{
uint32 TagChild; // 0x04
uint8 TagChildC[4]; // 0x04
};
union
{
uint32 TagParent; // 0x08
uint8 TagParentC[4]; // 0x08
};
Identity Tag; // 0x0C
uint8 *Name; // 0x10
void *Address; // 0x14
uint32 Location; // 0x18
uint32 _Unused; // 0x1C
}; // Size = 32 bytes(0x20)
struct TagBlock
{
uint32 Count; // 0x00
uint32 Address; // 0x04
uint32 Padding; // 0x08
}; // Size = 12 bytes(0x0C)
struct TagReference
{
uint32 TagGroup; // 0x00
uint8* Name; // 0x04
uint32 NameLength; // 0x08
Identity Tag; // 0x0C
}; // Size = 16 bytes(0x10)
struct Bitmap // 'bitm'
{
// Sprite Processing
uint32 SpriteBudgetSize;
uint32 SpriteBudgetCount;

// Post Processing
uint32 DetailFadeFactor;
uint32 SharpenAmount;
uint32 BumpHeight;

// Usage
uint16 Usage;

// Format
uint16 Format;

// Color Plate
uint16 ColorPlateWidth;
uint16 ColorPlateHeight;
uint32 CompressedColorPlateData;
uint8 Unknown[24];

// Processed Pixel Data
uint32 ProcessedPixelData;
uint8 Unknown2[20];

// ...More Sprite Processing
uint32 SpriteSpacing;
TagBlock Sequences;
TagBlock Bitmaps;
};
//----------------------------------------------
struct BitmapSequence
{
uint8 Name[32];
uint16 FirstBitmapIndex;
uint16 BitmapCount;
uint8 Unknown[12];
TagBlock Sprites;
};
//----------------------------------------------
struct BitmapSequenceSprite
{
float Unknown;
uint32 BitmapIndex;
float Left;
float Right;
float Top;
float Bottom;
float RegistrationPoint[2];
};
//----------------------------------------------
struct BitmapBitmap
{
uint32 Signature; // 'bitm'
uint16 Width;
uint16 Height;
uint16 Depth;
uint16 Type;
uint16 Format;
uint16 Flags;
uint16 RegistrationPointX;
uint16 RegistrationPointY;
uint16 MipMapCount;
uint32 PixelsOffset;
uint32 Size;
Identity BitmapIdent; // Maybe??
uint8 Unknown[12];
};


BitmapBitmap* GetBitmapBySequence(Identity BitmapIdentity, uint32 SpriteIndex, uint32 SequenceIndex)
{
uint16 BitmapIndex;
if(BitmapIdentity.Ident != INVALID)
{
uint32 BitmInstOffset = sizeof(TagInstance) * BitmapIdentity.Index;
TagInstance* BitmInstance = (TagInstance*)((uint32)*(Bitmap**)TAGINDEX + BitmInstOffset);
Bitmap* pBitmap = (Bitmap*)BitmInstance->Address;

if(!pBitmap)
return NULL;

if(pBitmap->Sequences.Count > 0)
{
uint32 BitmSeqOffset = sizeof(BitmapSequence) * (SequenceIndex % pBitmap->Sequences.Count);
BitmapSequence* BitmSequence = (BitmapSequence*)(pBitmap->Sequences.Address + BitmSeqOffset);

if(BitmSequence->BitmapCount <= 0)
{
if(BitmSequence->Sprites.Count)
{
uint32 BitmSeqSpriteOffset = sizeof(BitmapSequenceSprite) * SpriteIndex;
BitmapSequenceSprite* BitmSeqSprite = (BitmapSequenceSprite*)((uint32)BitmSequence->Sprites.Address + BitmSeqSpriteOffset);
BitmapIndex = BitmSeqSprite->BitmapIndex;
}
else
BitmapIndex = SpriteIndex;
}
else
BitmapIndex = BitmSequence->FirstBitmapIndex + (SpriteIndex % BitmSequence->BitmapCount);
}
else
BitmapIndex = SpriteIndex;

if(BitmapIndex == INVALID)
BitmapIndex = SpriteIndex;

if(BitmapIndex >= 0 && BitmapIndex < pBitmap->Bitmaps.Count)
{
uint32 BitmBitmOffset = sizeof(BitmapBitmap) * BitmapIndex;
return (BitmapBitmap*)(pBitmap->Bitmaps.Address + BitmBitmOffset);
}
}

return NULL;
}

Original Disassembly:

CPU Disasm
Address Command
0043F290 PUSH EBX
0043F291 XOR EBX,EBX
0043F293 CMP EAX,-1
0043F296 JE 0043F325
0043F29C MOV ECX,DWORD PTR DS:[816D04]
0043F2A2 AND EAX,0000FFFF
0043F2A7 SHL EAX,5
0043F2AA PUSH ESI
0043F2AB MOV ESI,DWORD PTR DS:[ECX+EAX+14]
0043F2AF TEST ESI,ESI
0043F2B1 JE SHORT 0043F320
0043F2B3 MOV ECX,DWORD PTR DS:[ESI+54]
0043F2B6 TEST ECX,ECX
0043F2B8 PUSH EBP
0043F2B9 JLE SHORT 0043F300
0043F2BB MOVSX EAX,WORD PTR SS:[Arg1]
0043F2C0 CDQ
0043F2C1 IDIV ECX
0043F2C3 MOV EBP,DWORD PTR DS:[ESI+58]
0043F2C6 MOV ECX,EDX
0043F2C8 SHL ECX,6
0043F2CB MOV AX,WORD PTR DS:[EBP+ECX+22]
0043F2D0 ADD ECX,EBP
0043F2D2 TEST AX,AX
0043F2D5 JLE SHORT 0043F2E6
0043F2D7 MOVSX EBP,AX
0043F2DA MOVSX EAX,DI
0043F2DD CDQ
0043F2DE IDIV EBP
0043F2E0 ADD DX,WORD PTR DS:[ECX+20]
0043F2E4 JMP SHORT 0043F2FA
0043F2E6 MOV EAX,DWORD PTR DS:[ECX+34]
0043F2E9 TEST EAX,EAX
0043F2EB JE SHORT 0043F300
0043F2ED MOV EAX,DWORD PTR DS:[ECX+38]
0043F2F0 MOVSX EDX,DI
0043F2F3 SHL EDX,5
0043F2F6 MOV DX,WORD PTR DS:[EAX+EDX]
0043F2FA CMP DX,0FFFF
0043F2FE JNE SHORT 0043F302
0043F300 MOV EDX,EDI
0043F302 TEST DX,DX
0043F305 POP EBP
0043F306 JL SHORT 0043F320
0043F308 MOV ECX,DWORD PTR DS:[ESI+60]
0043F30B MOVSX EAX,DX
0043F30E CMP EAX,ECX
0043F310 JGE SHORT 0043F320
0043F312 MOV ECX,DWORD PTR DS:[ESI+64]
0043F315 LEA EAX,[EAX*2+EAX]
0043F318 SHL EAX,4
0043F31B POP ESI
0043F31C ADD EAX,ECX
0043F31E POP EBX
0043F31F RETN
0043F320 POP ESI
0043F321 MOV EAX,EBX
0043F323 POP EBX
0043F324 RETN
0043F325 MOV EAX,EBX
0043F327 POP EBX
0043F328 RETN

Skarma
October 16th, 2009, 11:46 PM
This function was reversed from Halo CE 1.08 using OllyDbg, IDA Pro, Hexrays and my brain.

This function clears a surface that can be a render target, a stencil buffer, or a depth buffer. Refer to IDirect3DDevice9 interface documentation on MSDN for more information on the Direct3d functions.

Note: pDevice should be the global device, defined outside of this function, but for no-compile error sake, I just threw it in there.

//----- (00530170) --------------------------------------------------------
HRESULT ClearSurface(WORD SurfaceIndex, D3DCOLOR Color, bool bClear)
{
IDirect3DDevice9* pDevice = NULL;
IDirect3DSurface9* pSurface = NULL;
D3DSURFACE_DESC* pDesc;
D3DVIEWPORT9 vp;

if(SurfaceIndex < 9)
{
if(SurfaceIndex >= 0)
pSurface = (IDirect3DSurface9*)((20 * SurfaceIndex) + (int)0x00638A2C);
}

pDevice->SetRenderTarget(0, pSurface);
*(short*)0x00638A18 = SurfaceIndex;

if(SurfaceIndex == 1)
{
vp.X = *(WORD*)0x0075C176;
vp.Y = *(WORD*)0x0075C174;
vp.Width = *(WORD*)0x0075C17A - *(WORD*)0x0075C176;
vp.Height = *(WORD*)0x0075C178 - *(WORD*)0x0075C174;
}
else
{
pSurface->GetDesc(pDesc);
vp.X = 0;
vp.Y = 0;
vp.Width = pDesc->Width;
vp.Height = pDesc->Height;
}

vp.MinZ = 0.0f;
vp.MaxZ = 1.0f;
pDevice->SetViewport(&vp);

if(bClear)
{
DWORD Flags = D3DCLEAR_TARGET;
if(SurfaceIndex == 1 || SurfaceIndex == 2)
Flags = D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL;

return pDevice->Clear(0, NULL, Flags, Color, 1.0f, 0);
}
return bClear;
}

Skarma
October 18th, 2009, 02:45 AM
Reversed from Halo CE 1.08 using OllyDbg, IDA Pro, Hexrays, and msdn.

Returns the size of a vertex for a flexible vertex format (FVF).

//----- (0058751A) --------------------------------------------------------
DWORD GetFVFVertexSize(DWORD fvf)
{
DWORD Size;

switch(fvf & D3DFVF_POSITION_MASK)
{
case D3DFVF_XYZ:
Size = 12;
break;
case D3DFVF_XYZRHW:
case D3DFVF_XYZB1:
Size = 16;
break;
case D3DFVF_XYZB2:
Size = 20;
break;
case D3DFVF_XYZB3:
Size = 24;
break;
case D3DFVF_XYZB4:
Size = 28;
break;
case D3DFVF_XYZB5:
Size = 32;
break;
default:
Size = 0;
break;
}

if(fvf & D3DFVF_NORMAL)
Size += 12;
if(fvf & D3DFVF_PSIZE)
Size += 4;
if(fvf & D3DFVF_DIFFUSE)
Size += 4;
if(fvf < 0)
Size += 4;

DWORD TexCount = (fvf & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
DWORD TexCoords = (fvf >> D3DFVF_TEXCOUNT_SHIFT) >> D3DFVF_TEXCOUNT_SHIFT;

if(TexCoords)
{
if(TexCount >= 0)
{
for(TexCoords; TexCoords > 0; TexCoords--)
{
switch(TexCoords & 3)
{
case D3DFVF_TEXTUREFORMAT1:
Size += 4;
break;
case D3DFVF_TEXTUREFORMAT2:
Size += 8;
break;
case D3DFVF_TEXTUREFORMAT3:
Size += 12;
break;
case D3DFVF_TEXTUREFORMAT4:
Size += 16;
break;
}

TexCoords = TexCoords >> 2;
}
}
}
else
Size += TexCount * 8;

return Size;
}

Skarma
October 25th, 2009, 03:39 AM
Reversed from Halo CE 1.08 using OllyDbg, IDA Pro, Hexrays, and msdn.

This function releases resources used in Halo rendering code. There is a total of 9 textures and surfaces. Halo only uses one vertex buffer and one index buffer for optimization. They pack as much object data in one buffer, instead of creating one for each object or whatever.


struct s_RenderTarget
{
UINT Width;
UINT Height;
D3DFORMAT Format;
IDirect3DSurface9* pSurface;
IDirect3DBaseTexture9* pTexture;
};

//----- (00530100) --------------------------------------------------------
void ReleaseResources()
{
s_RenderTarget* RenderTarget = (s_RenderTarget*)0x00638A20;
IDirect3DIndexBuffer9* pIndexData = *(IDirect3DIndexBuffer9**)0x006B83D8;
IDirect3DVertexBuffer9* pVertexBuffer = *(IDirect3DVertexBuffer9**)0x006B83DC;
for(UINT i = 0; i < 9; i++)
{
if(RenderTarget[i].pSurface)
{
RenderTarget[i].pSurface->Release();
RenderTarget[i].pSurface = NULL;
}
if(RenderTarget[i].pTexture)
{
RenderTarget[i].pTexture->Release();
RenderTarget[i].pTexture = NULL;
}
}

*(WORD*)0x00638A18 = 0xFFFF;

if(pIndexData)
{
pIndexData->Release();
pIndexData = NULL;
}
if(pVertexBuffer)
{
pVertexBuffer->Release();
pVertexBuffer = NULL;
}
}

Skarma
October 28th, 2009, 08:38 PM
Reversed from Halo CE 1.08 using OllyDbg, IDA Pro, Hexrays, and msdn.

Creates a CRC table from all 256 possible ASCII characters. The only argument used in this function in Halo CE 1.08 is 0x00652968, where the table is stored. This is called only once when Halo first loads up.

The byte at 0x006B4CA0 is set to 1 after the Crc table is initialized.


//----- (004D3840) --------------------------------------------------------

#define Crc32Poly 0xEDB88320

void InitCrc32Table(DWORD Crc32Table[256])
{
for(DWORD i = 0; i < 256; i++)
{
DWORD Crc32 = i;

for(DWORD j = 8; j > 0; j--)
{
if(Crc32 & 1)
Crc32 = (Crc32 >> 1) ^ Crc32Poly;
else
Crc32 >>= 1;
}

Crc32Table[i] = Crc32;
}
}

Skarma
October 28th, 2009, 09:55 PM
Reversed from Halo CE 1.08 using OllyDbg, IDA Pro, Hexrays, and msdn.

Calculates a Crc32 from the inputed buffer, the buffer length, and the current Crc32 value. It first checks if a Crc32 lookup table has been created, then uses it in calculating the Crc32.


//----- (004D37E0) --------------------------------------------------------
bool *Crc32TableInit = (bool *)0x006B4CA0;
DWORD *Crc32Table = (DWORD *)0x00652968; // 256 dwords

void CalcCrc32(DWORD *Crc32, constchar *Buffer, DWORD Length)
{
DWORD Crc = *Crc32;

if(!*Crc32TableInit)
{
InitCrc32Table(Crc32Table);
*Crc32TableInit = true;
}

for(DWORD i = 0; i < Length; i++)
{
Crc = (*Crc32 >> 8) ^ Crc32Table[(*Buffer++ ^ *Crc32) & 0xFF];
}

*Crc32 = Crc;
}

Skarma
October 28th, 2009, 11:38 PM
Reversed from Halo CE 1.08 using OllyDbg, IDA Pro, Hexrays, and msdn.

Initializes a cache data header, calculates crc32 of the cache size, and updates the next available cache offset.

//----- (0053B780) --------------------------------------------------------
struct Identity
{
union
{
uint32 Ident;

struct
{
int16 Index;
int16 Salt;
};
};
};

struct DataHeader
{
unsigned char Name[32];
WORD Max;
WORD Size;
bool IsValid;
bool IdentifierZeroInvalid;
WORD Padding;
DWORD Signature;
short NextIndex;
short LastIndex;
Identity Next;
DWORD First;
};

DWORD *CacheBaseAddress = (DWORD *)0x0067DCC0;
DWORD *CacheNextAvailOffset = (DWORD *)0x0067DCC4;
DWORD *CacheCrc32 = (DWORD *)0x0067DCCC;

DWORD InitCacheDataHeader(DWORD ElementCount, DWORD ElementSize, constchar *CacheName)
{
DWORD CacheSize = sizeof(DataHeader) + (ElementCount * ElementSize);
DWORD CacheAddress = *CacheBaseAddress + *CacheNextAvailOffset;
*CacheNextAvailOffset += CacheSize;

CalcCrc32(CacheCrc32, (constchar*)&CacheSize, 4);

memset((void*)CacheAddress, 0, sizeof(DataHeader));
strncpy_s((char*)CacheAddress, 31, CacheName, 31);
//Sub005C8DA0(CacheAddress, CacheName, 31);
// Actual call^, IDA says it's stncpy.
// When compared in olly, they look similar and achieve same results
// Guess they wrote their own strncpy func? heh

DataHeader *newDataHeader = (DataHeader*)CacheAddress;
newDataHeader->Max = (WORD)ElementCount;
newDataHeader->Size = (WORD)ElementSize;
newDataHeader->Signature = 'd@t@';
newDataHeader->First = CacheAddress + sizeof(DataHeader);
newDataHeader->IsValid = false;

return CacheAddress;
}

Skarma
October 29th, 2009, 01:06 AM
Reversed from Halo CE 1.08 using OllyDbg, IDA Pro, Hexrays, and msdn.

Initializes the player data caches, including those without data headers. I provided a bunch of the needed structs, only thing extra you will need is CRC stuff from my other posts.


//----- (004763C0) --------------------------------------------------------
struct Identity
{
union
{
uint32 Ident;

struct
{
int16 Index;
int16 Salt;
};
};
};

struct DataHeader
{
unsigned char Name[32];
WORD Max;
WORD Size;
bool IsValid;
bool IdentifierZeroInvalid;
WORD Padding;
DWORD Signature;
short NextIndex;
short LastIndex;
Identity Next;
DWORD First;
};

struct Players
{
short PlayerID;
short IsLocal; // 0=Local(no bits set), -1=Other Client(All bits set)
wchar_t Name[12]; // Unicode
Identity UnknownIdent;
long Team; // 0=Red, 1=Blue
Identity SwapObject;
short SwapType;
short SwapSeat; // Warthog-Driver=0, Passenger=1, Gunner=2, Weapon=-1
long RespawnTimer; // Counts down when dead, Alive=0
long Unknown;
Identity CurrentBiped;
Identity PreviousBiped;
long ClusterIndex;
Identity UnknownIdent1;
long LastBulletShotTime; // since game start(0)
wchar_t Name1[12];
Identity UnknownIdent2;
long PlayerInfo;
long Unknown1;
float VelocityMultiplier;
Identity UnknownIdent3[4];
long Unknown2;
long LastDeathTime; // since game start(0)
char Unknown3[18];
short KillsCount;
char Unknown4[6];
short AssistsCount;
char Unknown5[8];
short BetrayedCount;
short DeathCount;
short SuicideCount;
char Unknown6[18];
short FlagStealCount;
short FlagReturnCount;
short FlagCaptureCount;
char Unknown7[6];
Identity UnknownIdent4;
char Unknown8[8];
short Ping;
char Unknown9[14];
Identity UnknownIdent5;
long Unknown10;
long SomeTime;
float World[3];
Identity UnknownIdent6;
char Unknown11[20];
char Melee : 1;
char Swap : 1;
char UnknownBit : 1;
char Flashlight : 1;
char UnknownBit1 : 4;
char UnknownBit2 : 5;
char Reload : 1;
char UnknownBit3 : 2;
char Unknown12[26];
float Rotation[2];
float VerticalVelocityMultiplier;
float HorizontalVelocityMultiplier;
float RateOfFireVelocityMultiplier;
char Unknown13[180];
};

struct s_PlayerData
{
DataHeader PlayerHeader;
Players Player[16];
};

struct Teams
{
unsignedchar Unknown[64];
};

struct s_TeamData
{
DataHeader TeamHeader;
Teams Team[16];
};

struct s_LocalPlayer
{
Identity UnknownIdent;
Identity PlayerIdent;
Identity UnknownIdent1;
unsignedshort Unknown;
char Unknown1[138];
};

struct s_LocalObject
{
char Unknown0[16];
Identity Biped;
char Unknown1[8];
float Rotation[2];
char Unknown2[36];
float PitchMinimum;
float PitchMaximum;
};

s_PlayerData *PlayerData = *(s_PlayerData**)0x008154E0;
s_TeamData *TeamData = *(s_TeamData**)0x008154DC;
s_LocalPlayer *LocalPlayer = *(s_LocalPlayer**)0x008154D8;
s_LocalObject *LocalObject = *(s_LocalObject**)0x0064C2C4;

void InitPlayerCaches()
{
DWORD LocalPlayerSize = sizeof(s_LocalPlayer);
DWORD LocalObjectSize = sizeof(s_LocalObject);

PlayerData = (s_PlayerData*)InitCacheHeader(16, 512, "players");
TeamData = (s_TeamData*)InitCacheHeader(16, 64, "teams");
LocalPlayer = (s_LocalPlayer*)(*CacheBaseAddress + *CacheNextAvailOffset);

*CacheNextAvailOffset += LocalPlayerSize;
CalcCrc32(CacheCrc32, (const char*)&LocalPlayerSize, 4);

LocalPlayer->UnknownIdent.Ident = -1;
LocalPlayer->PlayerIdent.Ident = -1;
LocalPlayer->Unknown = 0;
LocalObject = (s_LocalObject*)(*CacheBaseAddress + *CacheNextAvailOffset);

*CacheNextAvailOffset += LocalObjectSize;
CalcCrc32(CacheCrc32, (const char*)&LocalObjectSize, 4);
}

Skarma
November 5th, 2009, 05:12 AM
Halo uses frustum culling on sphere bounding volumes to determine object visibility. There is a sphere-tree in memory I found that contains all the necessary information to determine if an object is completely outside, partially inside, or completely inside the view frustum. All the frustum plane normals and positions are calculated and filled into the sphere-tree before the object rendering code is even called, not sure exactly how or where yet.

The sphere-tree is located at memory address 0x0075E2B0 for Halo CE 1.08, if you want to check it out. It is an array of 128? possible sphere volumes. The format is this:

Note: The plane normals, plane positions, and unknown reals are quaternions. There is a total of 6 planes in the view frustum.


struct BoundingSphere
{
uint32 Index;
real UnknownReal[4];
BoundingFrustum Frustum;
int8 padding[76];
};

Needed declarations for the function

#define OUT_FRUSTUM 0
#define PARTIAL_FRUSTUM 1
#define IN_FRUSTUM 2


#define DotProduct(a,b) ((a)[0] * (b)[0] + (a)[1] * (b)[1] + (a)[2] * (b)[2])


typedef unsigned int uint32;
typedef unsigned short uint16;
typedef float real;

struct BoundingFrustum
{
real UnknownReal[27];
real PlaneNorm[6][4];
real NearClippingDistance;
real FarClippingDistance;
real PlanePos[6][4];
};


uint16 GetObjectVisibility(real *SphereCentre, BoundingFrustum *Frustum, real SphereRadius)
{
real Distance[6];

if((SphereCentre[0] - SphereRadius) > Frustum->PlanePos[4][3]) return OUT_FRUSTUM;
if((SphereCentre[1] - SphereRadius) > Frustum->PlanePos[5][1]) return OUT_FRUSTUM;
if((SphereCentre[2] - SphereRadius) > Frustum->PlanePos[5][3]) return OUT_FRUSTUM;

if((SphereCentre[0] + SphereRadius) < Frustum->PlanePos[4][2]) return OUT_FRUSTUM;
if((SphereCentre[1] + SphereRadius) < Frustum->PlanePos[5][0]) return OUT_FRUSTUM;
if((SphereCentre[2] + SphereRadius) < Frustum->PlanePos[5][2]) return OUT_FRUSTUM;

for(uint32 i = 0; i < 6; i++)
{
Distance[i] = DotProduct(Frustum->PlaneNorm[i], SphereCentre) - Frustum->PlaneNorm[i][3];
if(Distance[i] > SphereRadius) return OUT_FRUSTUM;
}

for(uint32 i = 0; i < 6; i++)
{
if(i==4) continue; // doesn't check the 5th plane
if(Distance[i] > -SphereRadius) return PARTIAL_FRUSTUM;
}

return IN_FRUSTUM;
}