Results 1 to 5 of 5
  1. #1
    Dwar
    Dwar is offline
    Veteran Dwar's Avatar
    Join Date
    2010 Mar
    Posts
    2,222
    Thanks Thanks Given 
    211
    Thanks Thanks Received 
    2,230
    Thanked in
    292 Posts
    Rep Power
    10

    Beginner's Guide to Hooking

    So we can just focus on the hook itself, and not worry about any obscurities, I have decided to write up a small - and rather stupid - base to focus our work on. You can either scroll down to the end of the post to download it, or you can simply plop the following code in any C++ compiler and have fun:
    Code:
     #define WIN32_LEAN_AND_MEAN
    
    #include <windows.h>
    
    int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrev, LPSTR lpCmdLine, int nShowCmd){
        
        do{
            if(MessageBox(NULL, "Do you touch yourself?", "Hi", MB_YESNO) == IDYES)
                MessageBox(NULL, "Thrilling", "Hi", MB_OK);
            else
                MessageBox(NULL, "BAD!", "Hi", MB_OK);
        }while(MessageBox(NULL, "Exit", "Hi", MB_YESNO) == IDNO);
    
        return 0;
    }
    • Please note that if you decide to compile this yourself, your addresses will probably be different.
    • The define statement ensures that while compiling our program, Visual Studios doesn't throw in any un-wanted headers and libraries.


    There is nothing to overly complicated about this code - it simply loops through a series of commands that display a series of yes-no message boxes until exit is selected to be yes.

    I find - through my gradual course of talking to people - is that the main issue with hooking, and reversing in general, is the interpretation of assembly. Obviously, thinking in C, as demonstrated above, is rather straight-forward as you have a nice block on English words to coat each line. Assembly, however, takes a much different approach to code-layout: in place of words, assembly uses a series of numonetics to represent op-codes (add, sub, (compare)cmp, etc.), and in place of the rapid amount of words per line uses only one command.

    Now, this is of course distinctly different to how most English-speakers construct their sentences, as often we have formulated what to say before we speak the first word; rarely we wait until one word has completed to follow with the other. Slang is a perfect definition of this, as blurring the links between words is something that perfectly relates the difference between C and assembly. Despite all this, I find that assembly is actually far easier than C, an opinion which many do not hold. The reason why is quite simple; even though C falls closer to the English language, the 'block' (if, else, while, etc.) structure widely violates human thinking.

    I am obviously far from understanding the intricacies of the human brain, but personally, when I evaluate a condition is false, I jump to the next method of thought, and idle shortly in the dealings of the current system. Far more, my mind jumps around a lot; rarely does the human brain run in a linear pattern, as is so defined by C - and here we stumble on one of the most decisive abilities of assembly: its ability to switch its location in code with ease.

    However, jumping through code is useless unless we can actively and easily control the conditions on which our code will jump. To accomplish this, assembly uses a series of three components: the cmp/test command, the zero flag, and the conditional jump. To explain this, let me give a brief example; first some C code]
    if(val == 1)
    foo();
    blah();[/syntax]
    Nothing you haven't seen before, we simply compare a value 'val' to one, and if it is true, we call foo() before proceeding onto blah(). Now, let's convert this to assembly, using what we have covered:
    Code:
    mov eax,dword ptr ds:[val]
    cmp eax,1
    jnz @continueon
    call foo
    @continueon:
    call blah
    Few things I haven't covered yet appear in the code above - so let's step through each line of this code. We start off with the mov, which by its name, should have a pretty obvious purpose. The only thing we need to focus on is the dword ptr ds:[] statement; in simplest terms, this retrieves the actual value held at the address passed in the square brackets. Next, we compare eax to one, and jump if not zero. To explain why the label holds the term not zero, we need to cover how the cmp instruction works. When executed, the cmp takes two values, passed in the form 'a,b.' The first thing cmp does with these two instructions is minus b from a; if the result is zero, the zero flag is set. From there, it should be pretty self-explanatory, no?

    Now that we have covered all that, we can almost guess what our written program is going to look like in it's disassembled form.

    Time to start debugging this; open up Olly, and when it starts, open up our program (File>Open). It should land you in a clump of assembly, but worry not, we will soon make sense of this all.

    I see many posts on gamehacking and other forums relating to one simply question: "How do I debug an application?" For many people, who already know the basics of C and assembly, this can be a daunting subject - all of a sudden, you lose control of your environment, and are forced to play by the rules of another programmer, who, in most cases, has deliberately screwed around with his native code to make your job a pain. What a douche-bag.

    But the answer so many people search for is rather simply, and the one I think best (although practice and experience, as I often see as the replies are also good steps): the first job you need to accomplish is to find a place of reference. Debugging an application is much like solving a puzzle, albeit, a lot more fun, but the reference still works. When your pour your puzzle out of the box, it is simply a series of little pieces that you cannot make heads or tails of. But, if you use the picture on the box, you will discover that the puzzle has something notable in it - an odd colour, a face - something of value that you can put to use. From there, you can construct out, until finally, you have the completed puzzle. Except if you're me, because I, although lucky in pretty much every segment of my life, am I not lucky in solving puzzles, and always fail. Woe is me.

    By now, the metaphor should be clear; just like solving a puzzle, to debug our application, our first step is to find a good place of reference. But how are we to do this?

    For any of you with previous experience with Olly (and for any of you about to conclude this sentence I guess), Olly has the ability to locate all the text strings within an application. Simply right click, go to "Search For," and then in the menu, "All Referenced Text Strings," and a lovely box should pop up with several familiar strings. Click on any of them, it really doesn't matter, as they all land you in the same (relatively) spot. If you look to left of which ever reference you choose, you should notice a line to the right of the address that 'blocks' a section of code together - seems we have found our main function, so scroll up to the first address 'blocked' (401000h), and examine the whole function:
    Code:
    00401000  /$ 56             PUSH ESI
    00401001  |. 8B35 94404000  MOV ESI,DWORD PTR DS:[<&USER32.MessageBo>;  USER32.MessageBoxA
    00401007  |> 6A 04          /PUSH 4
    00401009  |. 68 64504000    |PUSH HookPrac.00405064                  ;  ASCII "Hi"
    0040100E  |. 68 4C504000    |PUSH HookPrac.0040504C                  ;  ASCII "Do you touch yourself?"
    00401013  |. 6A 00          |PUSH 0
    00401015  |. FFD6           |CALL ESI
    00401017  |. 83F8 06        |CMP EAX,6
    0040101A  |. 6A 00          |PUSH 0
    0040101C  |. 68 64504000    |PUSH HookPrac.00405064                  ;  ASCII "Hi"
    00401021  |   75 07         |JNZ SHORT HookPrac.0040102A
    00401023  |. 68 40504000    |PUSH HookPrac.00405040                  ;  ASCII "Thrilling"
    00401028  |. EB 05          |JMP SHORT HookPrac.0040102F
    0040102A  |> 68 38504000    |PUSH HookPrac.00405038                  ;  ASCII "BAD!"
    0040102F  |> 6A 00          |PUSH 0
    00401031  |. FFD6           |CALL ESI
    00401033  |. 6A 04          |PUSH 4
    00401035  |. 68 64504000    |PUSH HookPrac.00405064                  ;  ASCII "Hi"
    0040103A  |. 68 30504000    |PUSH HookPrac.00405030                  ;  ASCII "Exit"
    0040103F  |. 6A 00          |PUSH 0
    00401041  |. FFD6           |CALL ESI
    00401043  |. 83F8 07        |CMP EAX,7
    00401046  |.^74 BF          \JE SHORT HookPrac.00401007
    00401048  |. 33C0           XOR EAX,EAX
    0040104A  |. 5E             POP ESI
    0040104B  \. C2 1000        RETN 10
    Debugging seems much less scary when we have a reference, I do dare say. Since we already have the C code, there is no point in stepping through each line of this in this tutorial, but it should be easy enough to follow.

    Now, in my opinion, there are two basic main types of hook you can possibly implement - the traditional hook that calls your function from an overwritten section of code, and the conditional jump hook, which is less a hook, and more a simple byte-modification that acts like a hook. Since the conditional jump method is easier, let's start with that.

    You may be wondering why there is any point of doing a simple byte-modification, as surly anything you can accomplish whatever you are doing with a more traditional hook - and this is certainly true. However, that being said, I would like to ask you a simple question: are you lazy? Because I sure as hell am, and whenever the possibility to avoid work presents itself, I will be the first to jump on it. (Ha, ha, "jump on it" when talking about conditional jumps. See what I did there? Ha... alright, I'll stop.)

    Let's say for example you are incredibly Christian, or even more shocking, a female on the internet; you would disagree that touching yourself is "Thrilling" and not touching yourself is "BAD!". So how do we fix that? Well, we could hook the whole function, and re-write the entire section of code dedicated to determining that - or, as I would much rather do, we could simply change the jump if not zero at 401021h to a jump so it would always display "BAD!". Now, doesn't that seem so much easier?

    Open up your C++ compiler of choice - I'm using VS6.0, because I'm oldskool - and create a new .DLL project(File>New>Win32 Dynamic Link Library) and name it something like "HookPractice_Met1," selecting an empty project. Next, add a new .cpp file(File>New>C++ Source File) and call it main.

    With it created, start off with the typical C++ base for a .DLL:
    Code:
    #define WIN32_LEAN_AND_MEAN
    
    #include <windows.h>
    
    bool __stdcall DllMain(HANDLE hProcess, DWORD reason, LPVOID reserved){
    
    }
    *I realise the typical "approiate" title would be APIENTRY, and not __stdcall, but I like complete control over my functions.*

    None of this code should look new to anyone who has touched C++ before, but a quick run-down: we start off with a #include statement, like all C++ programs do, and bring in the windows header so we can use VirtualProtect - then, we move onto a define statement, which simply tells our compiler to eliminate any un-needed headers and libraries - and finally, we conclude with our DllMain, which is called whenever our target process refers to our .DLL and is passed the reason for being called.

    *Yes, I realise I butchered that last sentence.*

    Now since our we went our .DLL to modify memory when it is attached to the process, makes sense to filter for that event; in the DllMain:
    Code:
    if(reason == DLL_PROCESS_ATTACH){
    
            return 1;
        }
    
        else
            return 0;
    Obviously, if we attach our .DLL, then we want our patch to be executed - and, to clean up code, above our .DLL main we are going to declare a void function called patch:

    void patch(){}

    As with any memory modification, the golden rule applies here too; before you modify, you must de-protect! And, as we also know, we need a loving variable to hold our old protection type. So, within "patch":

    unsigned long hold = NULL;

    Now onto our VirtualProtect call(s), which will give us access to that section of the application's memory, and allow us to actually modify it:
    Code:
    VirtualProtect((void*)0x401021, 2, PAGE_EXECUTE_READWRITE, &hold);
        //our modification here
        VirtualProtect((void*)0x401021, 2, hold, NULL);]
    *If you refer back to the original disassembled code, you will see why we are de-protecting two bytes.*

    With our memory at 401021h now un-protected, we can continue on!

    *An interesting tidbit here: we are not actually un-protecting our address. What we are doing lies more along the lines of re-protecting it - we give our .DLL access to allow it to read, write, and execute memory at the location 401021h to 401023h. And then, after we have done our modifications, we simply restore the old protection type to ensure that the application, or something else hooking it (as piling on hacks is a pretty common user trend these days) does not modify the memory in a way that will cause the application to crash.*

    But how do we modify our data? Here's where c+p'ing from online sources is often a bad idea - when dealing with memory modifications, a lot of people like to continue with what they know best, which are, of course, conventions brought over from .exe-type programs. As such, many sources I see (sadly) use WriteProcessMemory to modify code from within the .DLL.

    Now you may be going, hey, attila, WPM works, so why is it bad? This, like all questions, can be answered with a simple analogy: when writing an essay, is it more efficient to just write on the paper yourself, or to call someone over to write for you? The same applies true for WPM - calling it from your .DLL forces the application you reside in to call another .DLL's code, and then come back to yours. And there is really no need for that, as we just gave ourselves privilege to modify away.

    So, knowing this, and knowing the address, the only other thing we need to grab is our new op-code; go back into Olly, and notice that 401021h currently holds the op-code 75 07h. Modify it to a jmp (space-bar) and you notice it change to EB 07h. However, this is not enough, because we have to factor in another newancse - the x86's little endianess architecture, which basically states that when writing or reading memory, the process interprets the op-codes "backwards" or "right-to-left." With the small switch our new op-code to write becomes 07 EBh. Without further ado, replace the previous comment with:

    *(WORD*)(0x401021) = 0x07EB;

    This simple line can be daunting to interpret at first, but taking it by segments will make it easy to understand. Starting off on the left, we know that we are not modifying the actually modifying 401021h; no, we are modifying the memory it points to, so time to call out our pointer (*). Next, we need to convert the left-side so it can convert to accept the address on the right, which, we know, is a pointer to a dword.

    *Nicely for us, if you can't remember the exact type-casting, VS will point it out.*

    After that, we just have the memory we know, and the reversed op-code we interpreted above. Just remember "0x" designates hex in C++, and you are good to go.

    And that's it for our "patch" function - all that is left to do is call it. In the if conditional of your .DLL main:

    patch();

    Compile, and inject, and you should notice your small change working perfectly! The final code of this part:
    Code:
    #define WIN32_LEAN_AND_MEAN
    
    #include <windows.h>
    
    void patch(){
        unsigned long hold = NULL;
    
        VirtualProtect((void*)0x401021, 2, PAGE_EXECUTE_READWRITE, &hold);
        *(WORD*)(0x401021) = 0x07EB;
        VirtualProtect((void*)0x401021, 2, hold, NULL);
    }
    
    bool __stdcall DllMain(HANDLE hProcess, DWORD reason, LPVOID reserved){
    
        if(reason == DLL_PROCESS_ATTACH){
            patch();
            return 1;
        }
    
        else
            return 0;
    }
    While that is fun, sometimes the full power of a typical hook is nessacary - say, oh I don't know, if we would like to display a message box from us at the end of every loop.

    Now, the theory behind this kind of patch is easy, and, at the same time, very intricate; all we need to do is re-direct a section of the application's code to ours, execute our code, and then return - however, this is easier said than done. When dealing with this type of hook, the primary concern you need to keep in your mind is management: the application will not be aware of our endeavors at all, and as a result, will assume that from before our hook until after, the same data stays in place. This means we have to be certain we restore every register, every flag, and the stack, or else our application will blow up. Literally, shards of code will come flying out of your screen. Not a pretty sight.

    Before we can start diving into the actual code of the hook though, we need to focus on finding a place, and coding our patching function. The same guidelines described above work here perfectly as well - we, ideally, want to touch as little code as possible, as every line we will have to replace. We also want to search for five secluded bytes, as a call (or jump, like we will be doing here) requires five bytes to place.

    Since this is such an isolated loop, we really have limited choices - but luckily for us, our compiler generated a beautiful place:
    Code:
    00401043  |. 83F8 07        |CMP EAX,7
    00401046  |.^74 BF          \JE SHORT HookPrac.00401007
    Five secluded bytes! Perfect for what we need to do; and, with this, we can begin coding.

    A large portion of the code for this we can copy out of the previous section, as we still need to modify a memory address; so, our code (through some c+p'ing):
    Code:
    #define WIN32_LEAN_AND_MEAN
    
    #include <windows.h>
    
    void patch(){
        unsigned long hold = NULL;
    
        VirtualProtect((void*)0x401043, 5, PAGE_EXECUTE_READWRITE, &hold);
    
        VirtualProtect((void*)0x401043, 5, hold, NULL);
    }
    
    bool __stdcall DllMain(HANDLE process, DWORD reason, LPVOID lpReserved){
        if(reason == DLL_PROCESS_ATTACH){
            patch();
            return 1;
        }
    
        else
            return 0;
    }
    Nothing here we haven't seen before - in fact, taking away the adjusted address and length in VirtualProtect, it is a carbon-copy of our previous section.

    *Since we will be displaying a message-box, it makes sense to declare some strings globally in our program; so above patch, but below the #include:

    char *title = "Title", *body = "body text";

    More on this later.*

    Before we we do anything relating to patching, we should start by writing our hook. Now our hook is nothing more than a void function, but to avoid screwing up registers, we are going to give it a special label - declspec(naked). All this type does, in most basic terms, is ensures that when our function is called, it accesses no registers or flags, which is, as we know, perfect for what we are doing:

    __declspec(naked) void hook(){}

    Now, since we are injecting this section of code, we need to make sure that it is interpreted exactly as we want it - so time to switch to inline assembly! Inside the hook block:

    __asm{}

    Our first order of business is to save all our registers, so we can restore them at a later point; to do this, we can use the instruction pushad:

    pushad

    With that saved, we can display our message box. The code for this you can simply pull out of the disassembly (c+p ftw):
    Code:
            push 0
            push title
            push body
            push 0
            call esi
    *If this code is confusing, remember that during optimisation, VS moved a pointer to MessageBoxA into esi.*

    And with that, we need to restore our registers:

    popad

    Onto the last step of any hook - replacing the code! Now, please understand, I did not expect this program to compile like this, so I thought I would have an easier example to show you, but alas, I do not. Our difficulty comes from the fact that, to my knowledge, conditionals are impossible to evaluate in a .DLL that jump to the main portion of the program. So looks like we will have to switch around the code we are replacing to make it work.

    *Before jumping into this, it is important to remember two things; the original instructions, which were:
    Code:
    00401043  |. 83F8 07        |CMP EAX,7
    00401046  |.^74 BF          \JE SHORT HookPrac.00401007
    And that the location we want to jump back to if we are done with the loop is 401048h. With that, we may continue.*

    First let us salvage what little we can, as we can still keep the first line:

    cmp eax,7

    Since we know that when it is equal it jumps back to the top of the loop, it makes sense that when it is not equal it finishes, no? With this simple twisted logic, the code is not so hard for us to write; all that is left is the label trick needed for inline assembly. Since VS will throw a fit if you try a direct jump, you need to move the address into a register, and then jump to the register, and since eax is pointless in the scheme of things (for this program at least, as it gets overwritten), we should maybe choose that:
    Code:
    jnz candy
            mov eax,401007h
            jmp eax
            candy:
                mov eax,401048h
                jmp eax
    And yes, I know, I have awesomely descriptive label names.

    With that, our hook function is done, and we can now work on our patch function. However, unlike with our last example, we no longer have a static address to place in for our patch. To understand this, we need to cover how both the call and jump op-codes work; and no, it is not just a jumble of hex. The five byte op-code is made up of two parts: the E8h(call) or E9(jump) identification byte, and then a four byte (DWORD) collection which is generated by subtracting the caller+5 from the callee's address. Now since in our case the hook function will be dynamically placed, we need to generate this code. But first, we can focus on the leading identification byte; which, since we are jumping back in both cases of our hook function, makes sense to make it a jump - so, in-between the VirtualProtects:

    *(BYTE*)(0x401043) = 0xE9;

    Besides the BYTE designation, this code is almost identical to our last patch, so no need to explain it again, hopefully. Now for the fun operation:

    *(DWORD*)(0x401044) = (unsigned long)&hook - 0x401048;

    This can look confusing at first, but take the strategy of breaking it in parts - already, we have covered the left side, so we can just focus on the math. We know that the & symbol retrieves the address of a function, so we ensure it is in DWORD form with a forced conversion, and then subtract it from the place we put the patch plus five. See, easy?

    Compile, and inject, and you should see some sexy results. The final code:
    Code:
    #define WIN32_LEAN_AND_MEAN
    
    #include <windows.h>
    
    char *title = "DoxCoding", *body = "HaX4LawLz";
    
    __declspec(naked) void hook(){
        __asm{
            pushad
            push 0
            push title
            push body
            push 0
            call esi
            popad
            cmp eax,7
            jnz candy
            mov eax,401007h
            jmp eax
            candy:
                mov eax,401048h
                jmp eax
        }    
    }
    
    void patch(){
        unsigned long hold = NULL;
    
        VirtualProtect((void*)0x401043, 5, PAGE_EXECUTE_READWRITE, &hold);
        *(BYTE*)(0x401043) = 0xE9;
        *(DWORD*)(0x401044) = (unsigned long)&hook - 0x401048;
        VirtualProtect((void*)0x401043, 5, hold, NULL);
    }
    
    bool __stdcall DllMain(HANDLE process, DWORD reason, LPVOID lpReserved){
        if(reason == DLL_PROCESS_ATTACH){
            patch();
            return 1;
        }
    
        else
            return 0;
    }
    Author: <3 attilathedud
    Shoutouts:
    -atom0s = for being smexy at C, and always providing me with help
    -Couch = for the lawls, the fun code, and pointing out my un-clearness in regards to the use of eax
    -learn_more = for correcting some issues with my code
    -Muted = for pointing out un-clear descriptions

    Please register or login to download attachments.

    Please, post your questions on forum, not by PM or mail

    I spend my time, so please pay a little bit of your time to keep world in equilibrium

  2. The Following 3 Users Say Thank You to Dwar For This Useful Post:


  3. #2
    danielc
    danielc is offline
    New member
    Join Date
    2013 May
    Posts
    16
    Thanks Thanks Given 
    0
    Thanks Thanks Received 
    1
    Thanked in
    1 Post
    Rep Power
    0
    Thanks do you have more?

  4. #3
    jackendra
    jackendra is offline
    Guest
    Join Date
    2013 Aug
    Posts
    1
    Thanks Thanks Given 
    0
    Thanks Thanks Received 
    0
    Thanked in
    0 Posts
    Rep Power
    0

    Errors

    Every time I try to use hooks and such, I get a ton of errors, I will post some examples below.
    But, do you know how to fix, do I have to like reference a dll or something
    I am using VS 2012.

    examples:
    1. error C2664: 'MessageBoxW' : cannot convert parameter 2 from 'const char [10]' to 'LPCWSTR'
    2. IntelliSense: argument of type "const char *" is incompatible with parameter of type "LPCWSTR"

    And I get different errors for certain things.
    I really need help, thanks!

  5. #4
    iggy-poop
    iggy-poop is offline
    Guest
    Join Date
    2013 Nov
    Posts
    1
    Thanks Thanks Given 
    0
    Thanks Thanks Received 
    0
    Thanked in
    0 Posts
    Rep Power
    0
    Thanks so much Dwar this is the most easily understandable guide I've found so far

    One think I don't understand, at the end of the first example of changing JNZ to JMP:
    "Compile, and inject, and you should notice your small change working perfectly!"
    Ok no problem compiling the DLL but I'm not clear on how I inject it, could anyone clarify or give me a link?
    Cheers!

  6. #5
    evernoob
    evernoob is offline
    Inactive
    Join Date
    2017 Aug
    Posts
    1
    Thanks Thanks Given 
    0
    Thanks Thanks Received 
    0
    Thanked in
    0 Posts
    Rep Power
    0
    Many Thanks for this wonderful tutorial. It is very detailed and one can walk through with practice on your executable file. I thank you very much for this and I hope you make more. Although this thread is very old, it is one of the most helpful I 've seen on the topic so far. I had a couple of problems at the end, but I caught the main concepts thanks to your explanations. Kudos.

Similar Threads

  1. [C++] Api hooking Technique
    By Dwar in forum C/C++
    Replies: 3
    Last Post: 2013-05-30, 08:42 PM
  2. [Guide] Dragon Nest Ultimate Beginner's Guide
    By Grooguz in forum Dragon Nest Guides, Tutorials
    Replies: 0
    Last Post: 2011-09-30, 09:23 AM
  3. [Asm] Beginner's Guide to x86 Assembly and Debugging Apps
    By Dwar in forum Programming Tutorials
    Replies: 1
    Last Post: 2011-02-13, 05:57 PM
  4. [C++] DirectX9.0 Hooking via Detours
    By Dwar in forum D3D Programming
    Replies: 1
    Last Post: 2010-11-29, 04:14 PM
  5. [Asm] IAT Hooking
    By Dwar in forum Programming Tutorials
    Replies: 1
    Last Post: 2010-11-29, 04:12 PM

Posting Permissions

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