Persistent DLL Proxy Injection

Introduction

I’m back and Happy 2023! It certainly has been a while. I’ve recently been attempting to do more low level learning and discovered a way to keep myself interested long enough to actually learn something by hacking one of my favorite games. Megaman Legends was a ps1 and n64 game that was also released in Japan on pc. Unfortunately the game is only in Japanese and fullscreen only. This is an effort to fix some of these quality of life issues in the game while also learning the basics of game hacking in general. Here we go!

How does one “hack” a game?

Good question. First we need to understand how a game runs on a computer. When we start a program exe it loads itself into memory and imports various helper functions from dll files. These dll files can do various things such as exposing the windows api, interfacing with graphics drivers, and more. When you play a video game it stores data about things happening in the game in ram or memory. With special tools or code we can manipulate these values stored in the game’s memory to make it do things we want. This is possible with a tool like cheat engine. We can attach cheat engine to our game’s process and poke around memory and find memory addresses with data of interest. If we can find where our game stores player health we can manually change this value to give our player max health whenever we want. This is cool but say we wanted to do more complex tasks with our games memory such as loading a specific level on command or automating certain tasks? It would be nice if we could somehow “inject” our own code into the game’s process. This is possible via several techniques but we are going to use something called dll proxying.

dll proxying?

Remember when I said our game exe on launch imports a bunch of functions from various dlls? Our exe has something called a dll import table. This table tells the exe every single dll it needs to import as well as the functions imported from their respective dlls. The idea is we make our own dll that takes the place of one of the existing dlls our game imports. We then take those function calls and forward them to the real dll while then spawning a seperate thread to run our own code. Sounds easy right? Well… it actually is.

First we need to open our game exe in Ida. Ida is a decompiler, and a very powerful tool for reverse engineering. In this case I am using the free community verison. On the main window in Ida we can see a imports and exports tab. We want to check the imports tab to view all of the dlls our game imports and their respective function names and/or ordinal numbers. With this information we can being building our pwn hax dll.

ida

Writing a custom dll

I started with a new project in Visual Studio 2019 and selected the dll template. This will auto generate some sample code for us to use. Essentially some events we can use to call code in our dll such as on process attach, detach, etc. In this case I am putting my main function call inside DLL_PROCESS_ATTACH as I would like my code to start when the game main process starts. Additionally I am launching my main function in a thread so I do not interrupt the execution of the main game process and vise versa. I recommend at this point adding some simple console output in your main function for the sake of verifying functionality.

BOOL APIENTRY DllMain(HMODULE hModule,
    DWORD  ul_reason_for_call,
    LPVOID lpReserved
)
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        CloseHandle(CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)YourMainFunctionHere, hModule, 0, nullptr));
        //return InitInstance(hModule);
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

Cool. Now we have a dll, with a call to our main dll function. How do we forward the functions to the dll we want to proxy. Fortunately for us this is incredible easy. In Ida we need to pick a dll we want to proxy. I chose ole32 as the game I am wanting to hack only has one import from this dll. This is less code for us to write. All we have to do is add this line to the top of our dllmain.cpp and change it so it has the name of the function and dll we want to proxy. CoInitialize is the function we want to export from ole32 back to our game. @927 is the oridnal number for the function we want to export from ole32. Now our dll will “act” like the original ole32 maintaining all the original functionality while we can now add code that will execute in the games process. But wait, we’re not done yet…

#pragma comment(linker,"/export:CoInitialize=ole32.CoInitialize,@927")

Patching our PE (Portable Executable)

This is where we tie it all together. Now we need to build our dll. We can name it whatever we want (as long as its the same length as the proxy dll name). Then copy our compiled dll so that it is next to our exe (In the same folder). Next we need to open our game exe in a hex editor and do a string search for our dll we want to proxy. In my case this will be “ole32.dll”.

starfield

All we have to do is update this area with the name of our new dll. I believe the name of our new dll must match the length of our old dll as to not throw off padding but you can experiment with this.

starfield

I wrote a python script to patch and unpatch my game dll for debug purposes. This is nice too as if you are planning on distributing your dll patch to other users so they don’t have to manually patch their games through a hex editor. This can be found here: https://github.com/BuckarewBanzai/MML2-Toolkit/blob/main/dash-patcher.py

Testing

If all goes well when you launch your game now you will see a console spawned with it. You are now running code in your game’s process! From here you can manipulate game memory, load custom assets, create training tools. The sky is the limit!

starfield

Stay tuned for part 2 (If we’re lucky it will come before sometime next year ;-;) where I will go over how to find valuable memory addresses, adding features like window mode, and reversing game asset file formats.

Thanks for reading!

 
comments powered by Disqus