Game Reverse Engineering: Analyzing Startup Process Vulnerabilities and Implementing DLL Injection
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.