Table of Contents:- Gearbox Models
- Multiple Instances
- cheat_spawn_warthog
- Console Output using Halo Engine
- GetBitmapBySequence
- ClearSurface
- GetFVFVertexSize
- ReleaseResources
- InitCrc32Table
- CalcCrc32
- InitCacheDataHeader
- InitPlayerCaches
- Object Visibility
- 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
, 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. 
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! 
Code:
// 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
Code:
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
Bookmarks