Page 1 of 4 1 2 3 ... LastLast
Results 1 to 10 of 40

Thread: Reverse Engineering References

  1. #1
    Codesaurus Skarma's Avatar
    Join Date
    Apr 2009
    Location
    Columbus, OH
    Posts
    227

    Code Reverse Engineering References

    Table of Contents:
    1. Gearbox Models
    2. Multiple Instances
    3. cheat_spawn_warthog
    4. Console Output using Halo Engine
    5. GetBitmapBySequence
    6. ClearSurface
    7. GetFVFVertexSize
    8. ReleaseResources
    9. InitCrc32Table
    10. CalcCrc32
    11. InitCacheDataHeader
    12. InitPlayerCaches
    13. Object Visibility
    14. 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
    Last edited by Skarma; November 5th, 2009 at 05:18 AM.
    Reply With Quote

  2. #2
    Codesaurus Skarma's Avatar
    Join Date
    Apr 2009
    Location
    Columbus, OH
    Posts
    227

    Literature Halo Multiple Instances

    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++:
    Code:
    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:

    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.
    Last edited by Skarma; September 20th, 2009 at 01:05 PM.
    Reply With Quote

  3. #3
    Codesaurus Skarma's Avatar
    Join Date
    Apr 2009
    Location
    Columbus, OH
    Posts
    227

    cheat_spawn_warthog

    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
    Code:
    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:
    Code:
    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.
    Reply With Quote

  4. #4
    Codesaurus Skarma's Avatar
    Join Date
    Apr 2009
    Location
    Columbus, OH
    Posts
    227

    Console Text Output Guide

    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

    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.
    Code:
    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.

    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:
    Code:
    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.
    Code:
    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:
    Code:
    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:
    Code:
    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.
    Code:
    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:
    Code:
    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!
    Code:
     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:
    Code:
    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.
    Code:
    #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_EXECUTE_READWRITE,&old);
     // Draw without console open
     VirtualProtectEx(hand,(void*)0x004C477D,10,PAGE_EXECUTE_READWRITE,&old);
     for( unsigned char i = 0; i < 6; i++ )cText->jmp[i] = nop;
     // DrawWhiteText
     VirtualProtectEx(hand,(void*)0x00495120,10,PAGE_EXECUTE_READWRITE,&old);
     
     
     while(1)
     {
      if (GetAsyncKeyState(VK_F5)&1)
      {
       oDrawGrayText = (pDrawGrayText)DetourFunction((PBYTE)0x004C4770,(PBYTE)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;
    }
    //------------------------------------------------------------------------------
    Last edited by Skarma; September 20th, 2009 at 01:36 PM.
    Reply With Quote

  5. #5
    HA10 Limited's Avatar
    Join Date
    Sep 2006
    Location
    England
    Posts
    7,800

    Re: cheat_spawn_warthog

    Skyline edited this method too to allow spawning of other vehicles for our OS code.
    E.g.
    This video is unable to be displayed because the YouTube video tags were used incorrectly. Please review proper use of the tags here.

    (dont mean to steal thread skarma )
    Reply With Quote

  6. #6
    Chris chrisk123999's Avatar
    Join Date
    May 2009
    Location
    Florida, USA
    Posts
    646

    Re: Console Text Output Guide

    Doesn't the print command do the same thing? Although it doesn't work in-game...
    It works in sapien.
    Reply With Quote

  7. #7
    Codesaurus Skarma's Avatar
    Join Date
    Apr 2009
    Location
    Columbus, OH
    Posts
    227

    Re: cheat_spawn_warthog

    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
    Reply With Quote

  8. #8
    Codesaurus Skarma's Avatar
    Join Date
    Apr 2009
    Location
    Columbus, OH
    Posts
    227

    Re: Console Text Output Guide

    Quote Originally Posted by chrisk123999 View Post
    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...
    Reply With Quote

  9. #9
    HA10 Limited's Avatar
    Join Date
    Sep 2006
    Location
    England
    Posts
    7,800

    Re: cheat_spawn_warthog

    Quote Originally Posted by Skarma View Post
    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
    Reply With Quote

  10. #10
    Taiko Drums = Win
    Join Date
    Sep 2006
    Location
    Longbranch, WA
    Posts
    2,692

    Re: cheat_spawn_warthog

    Hey, Skarma, this is great stuff, but could you please put this into one thread and not 35,001,412 threads?
    Reply With Quote

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •