Function Hooking Part 1 - Test Program

Table of Contents

I have recently been spending time learning more about reverse engineering and patching applications including fixing older programs that I do not have the source code for. I’ve started looking into function hooking and identifying how it works and different scenarios I could use it. There are a ton of articles online but most of them do not provide simple examples for starters or are focused on Windows API. While Windows API hooking is useful, I am more interested in hooking higher level functions.

I’m going to walk through an example of hooking a small custom application and what tools and libraries I have found useful. Hopefully this example will help others that are wanting to get started with function hooking.

What Is Function Hooking?

Function hooking is a technique that allows the user to intercept and redirect the execution of a function in a running application. This can be combined with DLL injection to patch a program that cannot be recompiled (i.e. the user doesn’t have the source code) or to add new functionality (i.e. adding a new feature to a game). Some reasons to use function hooking on red team engagements include:

  • Intercepting and/or manipulating data before it is processed or sent somewhere
  • Disabling functionality

There are many other articles out there that can explain function hooking better than I can. One article you can checkout is http://kylehalladay.com/blog/2020/11/13/Hooking-By-Example.html.

Overview

Now that you know what function hooking is, how can this be used? Let’s start by creating an application that can hook a specific function. Having the source code will make it easier to reverse engineer in order to find and write a signature for the function compared to starting out with a larger, closed source application.

While Windows API function hooking may be useful in different scenarios, there may also be times you would want to hook a custom function. If you have ever used API Monitor to view the API calls an application uses, you may find it overwhelming with the number of requests being made. This may also make it hard to focus in on the specific area of the application you are wanting to monitor or manipulate.

Our example will create a simple console application that adds two numbers together and prints the result to the console. Using this program you will create a DLL, that when it’s injected into the program, will alter the functionality of the function that adds the numbers.

When initially searching for references around function hooking it was hard to find anything that wasn’t specific to Windows API hooking. I was able to find Zer0Mem0ry’s Gihub repo which provides some code examples on function hooking. The repository does not have any documentation so I had to search through the code to figure out how to get the pieces to work. Most of the code and ideas in this post come from that repository.

Writing The Program

I started by creating my own application. As mentioned previously, I based most of my code and ideas from Zer0Mem0ry. I created a similar test application that outputs the sum of two numbers.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <windows.h>
#include <stdio.h>

// can compile using the following command
// i686-w64-mingw32-gcc test.c -o test32.exe

//this is the test function we will be hooking
int sum(int x, int y)
{
	return x + y;
}

int main()
{
	while(1)
	{
		//this will print the result of 5 + 5
		int s = sum(5,5);
		printf("test: 5 + 5 = %d\n", s);
		Sleep(5000);
	}
}

This program has a continuous loop that calls the “sum” function to add two numbers together, prints the output, and then sleeps for 5 seconds. I wanted to hook the “sum” function and change the integers being passed to it.

Function Signature

Now that the program is compiled, I needed to identify where at in the program the “sum” function was located so I analyzed the program by loading it into Ghidra.

entry

Since the program was compiled without stripping any debug symbols, it is easy to see the decompiled “main” function looks almost identical to the C code. Clicking on the “sum” function in the decompiler window or in the symbol tree in on the left, will show the decompiled function.

sum

Just like the “main” function, this one also looks similar to our C code. Looking in the middle at the listing window, you can see the “sum” function starts at address 0x00401530. This address might not be the same when executed, so I needed to search for this function based off of the bytes that make up the function. Next to the address, you can see the function starts with 0x55. I took the first X bytes of the “sum” function and injected the DLL to scan for these in memory when the program is running. This allowed me to hook the function and make whatever changes I wanted. The number of bytes needed will depend of the application. The larger the application, the more bytes will likely be needed in order to narrow the search down to one unique location.

xxd

As seen in the image above, the 9 bytes I selected were only identified once in the program. The next step was to create the DLL that will scan for this function and perform the hooking.

Writing The DLL

The DLL will utilize Microsoft Detours to intercept and re-write the in-memory code for the target function. A more detailed overview of what Detours is can be found here on Microsoft’s website. In addition to Detours, I utilized the signature scanner code from Zer0Mem0ry in order to find the function in memory.

I created a new C++ DLL project in Visual Studio and imported Detours via the Nuget Package manager (Project -> Manage NuGet Packages… -> Browse -> Detours -> install). I also included the “sigscan.h” header to the project. Once all that was completed, the code below was added to the project and compiled to a DLL.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include "pch.h"
#include <Windows.h>
#include <iostream>
#include "detours.h"
#include "sigscan.h"
#include <stdio.h>

DWORD AddressOfSum = 0;
typedef int(*sum)(int x, int y);

int HookSum(int x, int y)
{
	// manipulate the arguments
	printf("Adding 100 to x and y!\n");
	x += 100;
	y += 100;
	// redirect the program to original function
	sum originalSum = (sum)AddressOfSum;
	return originalSum(x, y);
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{
	if (ul_reason_for_call == DLL_PROCESS_ATTACH)
	{
		printf("Injected\n");
		// We will use signature scanning to find the function that we want to hook
		SigScan Scanner;
		char program[] = "test32.exe";
		char s[] = "\x55\x89\xE5\x8B\x55\x08\x8B\x45\x0C";
		char mask[] = "xxxxxxxxx";
		AddressOfSum = Scanner.FindPattern(program, s, mask);
		printf("Address of sum: %p\n", (LPVOID&)AddressOfSum);
		DetourTransactionBegin();
		DetourUpdateThread(GetCurrentThread());
		// this will hook the function
		DetourAttach(&(LPVOID&)AddressOfSum, &HookSum);
		DetourTransactionCommit();
	}
	else if (ul_reason_for_call == DLL_PROCESS_DETACH)
	{
		// unhook
		DetourTransactionBegin();
		DetourUpdateThread(GetCurrentThread());
		// this will hook the function
		DetourDetach(&(LPVOID&)AddressOfSum, &HookSum);
		DetourTransactionCommit();
	}
	return TRUE;
}

Let’s walk through a few main parts of the code:

  • When the DLL is injected and attached to the process, it first prints out “Injected”. This is just to let you know the injection worked.
  • I initialized the “SigScanner”, specified the program to search through in memory (test32.exe), and specified the signature of the “sum” function that was found previously (line 30).
  • At line 32, the scanner searched for the address of the function and then prints it out to the user on line 33.
  • The remainder of the function is using the Detours library. Detours takes the address and performs the hooking function (line 37) to redirect the execute of that function to the new function “HookSum”.
  • When the process is detached, Detours does some cleanup activity.

Jumping up to the “HookSum” function:

  • The function will print additional information to the console.
  • The function will then manipulate the integers that were intially passed to the function.
  • At the end, the function turns execution back to the original “Sum” function. This step could be optional depending on what you’re planning on using the hook for.

Testing

Now that everything is compiled, let’s test it out.

hooking

As you can see in the left console, the program initially runs like normal and prints out the sum of 5+5. After injecting the DLL, you can see that it was successfully injected and prints the address of the “sum” function. It then started printing out the modified sum of 5+5.

Wrap-Up

In this example I am only demonstrating one simple way to hook a function. While this example may not be useful in real life, it should provide an understanding of how function hooking works.

In part 2, I will cover using these same concepts against a known application and how it could be used during a red team engagement.

Example code here.

References / Acknowledgements