Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Game Reverse Engineering: Analyzing Startup Process Vulnerabilities and Implementing DLL Injection

Tech Jul 20 4

Understanding Game Startup Process Vulnerabilities

This technical analysis focuses on reverse engineering game startup processes to identify vulnerabilities that can be exploited through DLL injection techniques. The following implementation demonstrates how to create a custom game launcher that injects code into the target game process during initialization.

Implementation Overview

The solution involves two main components: a modified DLL file and a launcher application that creates the game process and performs the injection. The approach uses entry point injection rather than window hooking for better stealth and reliability.

Modifying the DLL Implementation

The first step involves modifying the DLL code to remove window hooking functionality and prepare for entry point injection. Below is the revised implementation:


// GameHookDll.cpp: DLL initialization implementation
//

#include "pch.h"
#include "framework.h"
#include "GameHookDll.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// Remove window hooking macros
// #define WNDHOOK
#ifdef WNDHOOK
typedef struct GameDllData
{
    HHOOK     keyHook;
    unsigned  KbdProc;
    unsigned  SetDll;

}*PGameDllData;
void GameSetDll(GameDllData gameDll);
GameDllData dllData;
#endif

BEGIN_MESSAGE_MAP(CGameHookDllApp, CWinApp)
END_MESSAGE_MAP()

// CGameHookDllApp constructor
CGameHookDllApp::CGameHookDllApp()
{
    
}

CGameHookDllApp theApp;
CGameHookDllApp* PtheApp;

HHOOK keyHook;
LRESULT CALLBACK KeyProcCallback(int nCode, WPARAM wParam, LPARAM lParam);

BOOL CGameHookDllApp::InitInstance()
{
    CWinApp::InitInstance();
    PtheApp = this;
#ifdef WNDHOOK
    dllData.KbdProc = (DWORD)(KeyProcCallback);
    dllData.SetDll = 0;
#else
    keyHook = SetWindowsHook(WH_KEYBOARD, KeyProcCallback);
#endif
    
    return TRUE;
}

LRESULT CALLBACK KeyProcCallback(int nCode, WPARAM wParam, LPARAM lParam)
{
    if (nCode == 0)
    {
        if ((lParam & (1 << 31)) == 0)
        {
            switch (wParam)
            {
            case VK_HOME:
                if (PtheApp->wndMain == NULL)
                {
                    PtheApp->wndMain = new CGameUI();
                    PtheApp->wndMain->Create(IDD_MAIN);
                }
                PtheApp->wndMain->ShowWindow(TRUE);
                break;
            }
        }
    }
    return CallNextHookEx(keyHook, nCode, wParam, lParam);
}

#ifdef WNDHOOK
void GameInit(GameDllData* gameDll)
{
    gameDll->KbdProc = dllData.KbdProc;
    gameDll->keyHook = dllData.keyHook;
    gameDll->SetDll = dllData.SetDll;
}

void GameSetDll(GameDllData gameDll)
{
    dllData = gameDll;
}
#else
void GameInit()
{
}
#endif

Creating the Launcher Application

The launcher application creates the game process and performs the injection. The following code demonstrates the implementation:


// GameLauncherDlg.cpp: Launcher implementation
//

#include "pch.h"
#include "framework.h"
#include "GameLauncher.h"
#include "GameLauncherDlg.h"
#include "afxdialogex.h"
#include <gameinject.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// About dialog implementation
class CAboutDlg : public CDialogEx
{
public:
    CAboutDlg();

#ifdef AFX_DESIGN_TIME
    enum { IDD = IDD_ABOUTBOX };
#endif

protected:
    virtual void DoDataExchange(CDataExchange* pDX);
    DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()

// CGameLauncherDlg dialog
CGameLauncherDlg::CGameLauncherDlg(CWnd* pParent /*=nullptr*/)
    : CDialogEx(IDD_GAMELAUNCHER_DIALOG, pParent)
{
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CGameLauncherDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CGameLauncherDlg, CDialogEx)
    ON_WM_SYSCOMMAND()
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    ON_BN_CLICKED(IDOK, &CGameLauncherDlg::OnBnClickedLaunch)
END_MESSAGE_MAP()

BOOL CGameLauncherDlg::OnInitDialog()
{
    CDialogEx::OnInitDialog();

    // Add "About..." menu to system menu
    ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
    ASSERT(IDM_ABOUTBOX < 0xF000);

    CMenu* pSysMenu = GetSystemMenu(FALSE);
    if (pSysMenu != nullptr)
    {
        BOOL bNameValid;
        CString strAboutMenu;
        bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
        ASSERT(bNameValid);
        if (!strAboutMenu.IsEmpty())
        {
            pSysMenu->AppendMenu(MF_SEPARATOR);
            pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
        }
    }

    // Set dialog icons
    SetIcon(m_hIcon, TRUE);
    SetIcon(m_hIcon, FALSE);

    return TRUE;
}

void CGameLauncherDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
    if ((nID & 0xFFF0) == IDM_ABOUTBOX)
    {
        CAboutDlg dlgAbout;
        dlgAbout.DoModal();
    }
    else
    {
        CDialogEx::OnSysCommand(nID, lParam);
    }
}

void CGameLauncherDlg::OnPaint()
{
    if (IsIconic())
    {
        CPaintDC dc(this);
        SendMessage(WM_ICONERASEBKGND, reinterpret_cast<wparam>(dc.GetSafeHdc()), 0);

        int cxIcon = GetSystemMetrics(SM_CXICON);
        int cyIcon = GetSystemMetrics(SM_CYICON);
        CRect rect;
        GetClientRect(&rect);
        int x = (rect.Width() - cxIcon + 1) / 2;
        int y = (rect.Height() - cyIcon + 1) / 2;

        dc.DrawIcon(x, y, m_hIcon);
    }
    else
    {
        CDialogEx::OnPaint();
    }
}

HCURSOR CGameLauncherDlg::OnQueryDragIcon()
{
    return static_cast<hcursor>(m_hIcon);
}

/*
    ProcessCallback function receives a pointer to the game process structure.
    The game won't complete initialization until this function finishes.
    This provides an opportunity to analyze the game startup process.
*/
void ProcessCallback (LPPROCESS_INFORMATION processInfo) {
    AfxMessageBox(L"Game process initialized");
}

void CGameLauncherDlg::OnBnClickedLaunch()
{
    CString launchParams;
    launchParams.Format(L"\"%s\" %d 218.77.62.16 2001 am 218.77.62.16 4000 0", 
        L"C:\\GameDirectory\\game.exe", GetTickCount());
    
    // Launch process and perform entry point injection
    GameInjector::InjectByEntry(L"C:\\GameDirectory\\game.exe", // Game executable path
        L"C:\\GameDirectory\\", // Game directory
        launchParams.GetBuffer(), // Command line parameters
        L"C:\\Injectables\\GameHook.dll", // DLL to inject
        ProcessCallback // Callback function
        );
}
</hcursor></wparam></gameinject.h>

Technical Considerations

When implementing game process injection, it's important to:

  • Avoid modifying the game window title, as this can trigger anti-cheat detection
  • Use entry point injection rather than window hooking for better stealth
  • Ensure the callback function completes before the game fully initializes
  • Handle process creation and injection errors gracefully

This implemantation demonstrates a basic approach to game reverse engineering and DLL injection. Advanced implementations would need to consider anti-cheat mechanisms, process hiding techniques, and more sophisticated injection methods.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.