游戏逆向_DLL注入技术

发布时间:2025-12-09 21:42:49 浏览次数:3

DLL注入技术: 是将一个Dll文件强行加载到目标进程中,比如把外挂dll模块注入到游戏进程,这样做的目的在于方便我们通过这个DLL读写目标进程指令或内存数据,(例如 HOOK游戏函数过程或篡改游戏内存数据实现外挂功能),或以被注入进程的身份去执行一些操作等。

全系统注入的优点:利用系统机制实现的全系统进程注入,可绕过比如游戏进程自身的防注入保护机制。比如远线程注入游戏可能会被拦截,但输入法注入,游戏很难拦截。

消息钩子注入

Windows应用程序是基于消息驱动的。应用程序对各种消息响应从而实现各种功能。

消息钩子(Message Hook)是Windows消息处理机制的一个监视点,系统会自动将钩子安装到目标进程中达到监视指定类型消息的功能。也就是说通过SetWindowsHookEx 系统会自动将钩子dll注入到目标进程。

安装钩子的函数原型如下:

HHOOK SetWindowsHookEx(

int idHook, //钩子类型HOOKPROC lpfn,HINSTANCE hMod,DWORD dwThreadId

);

其中dwThreadId为0时,则是全局钩子,即会注入dll到系统所有窗口进程,否则是线程钩子,即只能将dll注入到目标线程所属的进程。当全局钩子时,钩子处理过程HOOKPROC lpfn 必须位于dll中。

步骤和源码

源码将以WH_CBT 钩子为例,实现全系统dll注入。 computer-based training (CBT) 基于电脑的训练,比如创建窗口,移动窗口等操作的都会收到通知。

在以下事件之前,系统都会调用WH_CBT Hook子程,这些事件包括:

  • 激活,建立,销毁,最小化,最大化,移动,改变尺寸等窗口事件;

  • 完成系统指令;

  • 来自系统消息队列中的移动鼠标,键盘事件;

  • 设置输入焦点事件;

  • 同步系统消息队列事件。

  • 安装WH_CBT 钩子将CbtHook.dll注入到notepad进程中的效果:

    编写被注入的Dll和钩子处理过程

    编写一个DLL,并且显式导出CBTProc ()钩子处理过程,主要代码如下:

    LRESULT CALLBACK CBTProc(int nCode, WPARAM wParam, LPARAM lParam)

    {

    char szFileName[MAX_PATH];

    if( (HCBT_CREATEWND == nCode) || (HCBT_ACTIVATE == nCode) )

    {

    memset(szFileName, 0, sizeof(szFileName));

    ::GetModuleFileNameA(NULL, szFileName, sizeof(szFileName));

    DebugPrintA(0, “Code(%d) (%s)\n”, nCode, szFileName);

    }

    return CallNextHookEx(g_hCBT, nCode, wParam, lParam);

    }

    安装HOOK

    编写一个exe,使用SetWindowsHookEx()向系统安装钩子,首先需要将HOOK的DLL 加载到exe本身的进程中,以此得到DLL的模块句柄,再使用GetProcAddress()得到DLL中显示导出的函数MyMessageProc()的函数地址,最后遍历出待注入进程的线程ID,这样SetWindowsHookEx()就可以利用这些参数进行HOOK了。主要代码如下图所示:

    if (NULL == g_hCbtHook)

    g_hCbtHook = ::LoadLibrary(szPathName);

    if (NULL == g_hCbtHook)

    {

    lResult = GetLastError();

    ::DebugPrintA(0, “%s : Load GlobalHook module ‘%s’ fail(%d)\n”, C_ModuleNameA, szPathName, lResult);

    break;

    }

    CBTProc = (PCBTPROC)::GetProcAddress(g_hCbtHook, “CBTProc”);

    if (NULL == g_hCbtHook)

    {

    lResult = GetLastError();

    ::DebugPrintA(0, “%s : Get GlobalHook function fail(%d)\n”, C_ModuleNameA, lResult);

    break;

    }

    g_hCBT = SetWindowsHookEx(WH_CBT, CBTProc, g_hCbtHook, 0);

    if (NULL == g_hCBT)

    {

    lResult = GetLastError();

    ::DebugPrintA(0, “%s : Set GlobalHook fail(%d)\n”, C_ModuleNameA, lResult);

    break;

    }

    卸载钩子

    利用LoadLibrary()得到的模块句柄把本身进程的DLL释放掉,代码如下所示:

    FreeLibrary(g_hCbtHook);
    消息钩子注入只熟悉SetWindowsHookEx()和DLL导出函数就可以很容编写,所以容易实现。

    注册表注入

    注册表(Reg)注入原理是利用在Windows 系统中,当REG以下键值中存在有DLL文件路径时,会跟随EXE文件的启动加载这个 DLL文件路径中的DLL文件。

    AppInit_Dlls注册表:

    注册表项 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows中有两个值:

    LoadAppInit_Dlls:键值中指定要注入的DLL

    AppInit_Dlls:若其键值为1,则注入LoadAppInit_Dlls中指定的DLL,若为0则不注入。注:(1)LoadAppInit_Dlls中的值当如 果遇到有多个DLL文件时,需要用逗号或者空格隔开多个DLL文件的路径,所以DLL的路径中最好不要有空格。

    使用范围:

    任何加载User32.DLL的程序,user32.dll的DllMain会先尝试加载注册表项AppInit_Dlls中的DLL。因为所有的GUI应用程序在启动时都会加载User32.dll,因此这种方法会影响所有的GUI程序。

    使用Process Explorer查看进程模块来确认目标dll是否被注入。

    步骤和源码

    需要解决的就是关于注册表操作的Windows API了,如下所示:

    RegOpenKeyEx

    打开注册表键值

    RegQueryValueEx

    查询键值

    RegSetValueEx

    设置键值

    RegCloseKey

    关闭键值

    主要代码如下:

    BOOL AddRegItem(CHAR* szInjectFilePath)

    {

    //打开键值

    LSTATUS nReg = ERROR_SUCCESS;

    HKEY hKey;

    CHAR szRegPath[MAX_PATH] = “SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows”;

    nReg = RegOpenKeyEx(

    HKEY_LOCAL_MACHINE,

    szRegPath,

    0,

    KEY_ALL_ACCESS,

    &hKey);

    if (nReg != ERROR_SUCCESS)

    {

    return FALSE;

    }

    //查询键值

    DWORD dwReadType;

    DWORD dwReadCount;

    TCHAR szReadBuff[1024] = { 0 };

    nReg = RegQueryValueEx(hKey,

    _T(“AppInit_DLLs”),

    NULL,

    &dwReadType,

    (BYTE*)&szReadBuff,

    &dwReadCount);

    if (nReg != ERROR_SUCCESS)

    {

    return FALSE;

    }

    //若dll名称已经在内容中,则不用重复添加

    if (StrStrI(szReadBuff,szInjectFilePath))

    {

    printf(“dll already in reg=%s\n”, szReadBuff);

    return FALSE;

    }

    //原来已有内容就加入空格后再附加新dll串

    if (0 != _tcscmp(szReadBuff, _T(“”)))

    {

    _tcscat_s(szReadBuff, _T(" "));

    }

    _tcscat_s(szReadBuff, szInjectFilePath);

    //1.把dll路径设置到注册表中

    nReg = RegSetValueEx(hKey,

    _T(“AppInit_DLLs”),

    0,

    REG_SZ,

    (CONST BYTE*)szReadBuff,

    (_tcslen(szReadBuff) + 1)*sizeof(TCHAR));

    //2.启动 注册表加载dll

    BYTE byEnable[4] = { 0x1 };

    nReg = RegSetValueEx(hKey,

    _T(“LoadAppInit_DLLs”),

    0,

    REG_DWORD,

    (CONST BYTE*)byEnable,

    4);

    printf(“RegSetValueEx AppInit_DLLs = %s Result=%d\n”, szReadBuff, nReg);

    }

    需要做网站?需要网络推广?欢迎咨询客户经理 13272073477