欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

[原创]TX某游戏内存加载d3d9的一个HOOK思路

[原创]TX某游戏内存加载d3d9的一个HOOK思路

首先声明:本帖内容仅供技术交流,不涉及任何与过保护、作弊功能等任何违法行为有关的内容。
玩儿过TX某F的同学应该知道,某F在vista以上系统会加载d3d9.dll,而xp环境下就不加载d3d9.dll了,而且模块列表里也找不到d3d9.dll,这是为什么呢?
(因为没有xp系统的真机,所以就不放测试截图了)
有些同学以为*F是加载了D3D\\d3d9xpsp3.dll这个文件,其实不是,这个文件只是*f用来做内存校验的

真正的d3d9.dll被打包进了cross****Base.dll中,在运行时解密出来当做内存dll加载,所以你只能在模块列表里看到一个d3d8thk.dll(因为这是d3d9.dll的依赖库)。
那碰到这种内存dll的情况该如何做d3d hook呢?ida打开d3d9xpsp3.dll看一看,找到我们最亲切的D3DCreateDevice9同学

加载符号之后基本就能看个大概了

IDirect3D9 *__stdcall Direct3DCreate9(UINT SDKVersion)
{
  HMODULE v1; // eax@3
  FARPROC v2; // eax@4
  UINT v4; // eax@6
  BYTE Data[4]; // [sp+0h] [bp-108h]@1
  CHAR OutputString; // [sp+4h] [bp-104h]@10
  if ( GetD3DRegValue(4, "LoadDebugRuntime", Data, 4) )
  {
    if ( *(_DWORD *)Data )
    {
      v1 = LoadLibraryA("d3d9d.dll");
      if ( v1 )
      {
        v2 = GetProcAddress(v1, "Direct3DCreate9");
        if ( v2 )
          return (IDirect3D9 *)((int (__stdcall *)(_DWORD))v2)(SDKVersion);
      }
    }
  }
  v4 = SDKVersion & 0x7FFFFFFF;
  if ( (SDKVersion & 0x7FFFFFFF) != 31 && (v4 < 0x20 || v4 > 0x20 && v4 < 0x84) )
  {
    StringCbPrintfA(
      &OutputString,
      0x100u,
      "\nD3D ERROR: D3D header version mismatch.\nThe application was compiled against and will only work with D3D_SDK_VERSION (%d), but the currently installed runtime is version (%d).\nRecompile the application against the appropriate SDK for the installed runtime.\n\n",
      SDKVersion & 0x7FFFFFFF,
      32);
    OutputDebugStringA(&OutputString);
    return 0;
  }
  if ( !operator new(0x47B8u) )
    return 0;
  return (IDirect3D9 *)CEnum::CEnum(SDKVersion);
}

那么我们需要的IDirect3D9 *指针就由CEnum::CEnum里返回得到
在CEnum::CEnum靠近return的地方可以看到:

v2就是我们要的IDirect3D9 *指针了。
if ( !RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\DirectDraw\\GammaCalibrator", 0, 1u, &phkResult) )

这不就是一个很棒的hook点么,在这里返回值v2的值已经确定了,后面没有对v2的赋值操作了。
但是怎么获得这个返回值v2呢?看下汇编:
*((_DWORD *)v2 + 4520) = 0;
  *((_DWORD *)v2 + 4521) = 0;
  *((_DWORD *)v2 + 4522) = 0;
  *((_DWORD *)v2 + 4523) = 0;

刚好对应
mov     [ebx+46A0h], esi
.text:4B66ADA7                 mov     [ebx+46A4h], esi
.text:4B66ADAD                 mov     [ebx+46A8h], esi
.text:4B66ADB3                 mov     [ebx+46ACh], esi
.text:4B66ADB9                 call    ds:__imp__RegOpenKeyExA@20

那么在RegOpenKeyExA的detour函数中取ebx不就可以了?
赶紧写个demo
先HOOK RegOpenKeyExA,这里必须inline hook因为内存dll的IAT你是hook不到的
LONG(WINAPI *m_pfnRegOpenKeyExA)(HKEY hKey, LPCSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult) = NULL;
IDirect3D9 *(WINAPI *m_pfnDirect3DCreate9)(UINT SDKVersion) = NULL;

//开始hook,最好在dllmain里做
m_pfnRegOpenKeyExA = (LONG(WINAPI *)(HKEY , LPCSTR , DWORD , REGSAM , PHKEY ))
					GetProcAddress(GetModuleHandle(L"Advapi32.dll"), "RegOpenKeyExA");
				if (m_pfnRegOpenKeyExA)
				{
					DetourTransactionBegin();
					DetourAttach(&(void *&)m_pfnRegOpenKeyExA, NewRegOpenKeyExAProxyXPSP3);
					DetourTransactionCommit();
				}

//取返回值IDirect3D9 *
DWORD m_Direct3DCreate9_RetVal = NULL;
LONG WINAPI NewRegOpenKeyExA(HKEY hKey, LPCSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult)
{
	if (0 == strcmp("Software\\Microsoft\\DirectDraw\\GammaCalibrator", lpSubKey))
	{
		DWORD *pVTable = *(DWORD **)m_Direct3DCreate9_RetVal;
		if (!m_pfnIDirect3D9_CreateDevice)
		{
			m_pfnIDirect3D9_CreateDevice = (HRESULT(WINAPI *)(IDirect3D9 *, UINT, D3DDEVTYPE, HWND, DWORD, D3DPRESENT_PARAMETERS *, IDirect3DDevice9 **))pVTable[16];
			//Direct3DCreate9返回值是IDirect3D9 *指针,它的虚函数表第17个就是->CreateDevice啦,替换虚函数表或者inline都可以随便你了~
		}
	}
	return m_pfnRegOpenKeyExA(hKey, lpSubKey, ulOptions, samDesired, phkResult);
}
//由于ebx是易失寄存器,我们需要在每一个调用中首先保存ebx再进真正的detour函数,防止在detour函数中ebx被编译器生成的代码改掉
__declspec(naked) void NewRegOpenKeyExAProxyXPSP3()
{
	__asm {
		mov dword ptr[m_Direct3DCreate9_RetVal], ebx;
		jmp  NewRegOpenKeyExA;
	}
}

将该dll用系统dll劫持、lsp劫持、内核注入或者别的手段注入游戏,保证该dll先于d3d9初始化,即可成功hook到Direct3DCreate9。
那么就又有人要问了:万一换别的系统呢?又不是每个系统的d3d9.dll都有这玩意
于是我用ida看过一遍从xpsp3开始到win10 14393的所有d3d9.dll,都有
if ( !RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\DirectDraw\\GammaCalibrator", 0, 1u, &phkResult) )

也就是说这种方法是全系统支持的。
ps:直接hook d3d9里的东西是必然会被检测的,但这并不在本帖的讨论范围内,本帖仅提供一种另类(火星?)的内存dll的hook思路,仅此而已。

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功