简单的工作室

当前位置: 主页>编程技巧>VC++编程>

魔兽中的dx写屏(原版为英文)

时间:2014-07-13 18:43来源:未知 作者:admin 点击:
原文地址: http://www.rohitab.com/discuss/topic/34411-run-time-directx-hooking-using-code-injection-and-vtable/ 相关资料: http://bbs.pediy.com/showthread.php?t=85368highlight=hook+%E6%B8%B8%E6%88%8F+%E6%88%8F 工程代码: http://download.csdn.net/deta
原文地址:
http://www.rohitab.com/discuss/topic/34411-run-time-directx-hooking-using-code-injection-and-vtable/
相关资料:
http://bbs.pediy.com/showthread.php?t=85368&highlight=hook+%E6%B8%B8%E6%88%8F+%E6%88%8F
工程代码:
http://download.csdn.net/detail/langyanduan/4126849
win7x64配置Detours:
http://hi.baidu.com/flicker317/item/97357c9ff5e64ccd7b7f0174


以前对这方面捣鼓了一段时间,后来看到这篇文章,索性就按着它的步骤再进行一次魔兽的写屏,

同时加上了一些自己的理解,和原文稍有出入,重新记录下过程吧。



环境:    Win7 x64
                VS 2010
                DirectX 9.0 SDK
                Detour 2.1
工具:    OD
                Dbgview


我们想要在魔兽中绘制文字和各种图形对象,要获得一个类型为LPDIRECT3DDEVICE8的设备对象指针.


所以我们通过hook掉Direct3DCreate8以获得类型为LPDIRECT3D8的Direct3D对象的接口指针,

这个Direct3D对象有一个成员函数为 IDirect3D8::CreateDevice,设备对象指针就是在这个函数里面创建的.

所以,只要根据Direct3D对象接口指针找到Direct3D对象的虚函数表,再根据虚函数表确定

IDirect3D8::CreateDevice的内存地址,就可以hook这个函数,从而获得类型为LPDIRECT3DDEVICE8的设备对象指针,

然后就可以随意绘制文字或者图形了.


下面就开始进入正题

一、

1. 首先,我们先新建一个空的Win32 App工程Loader,添加以下3个文件:

     inject.h

     inject.cpp

     main.cpp // 通过CreateProcess启动war3并注入我们的dll


[cpp] view plaincopy
  1. ////////////////////////////////////////////////////////////////////////////////////////////  
  2.   
  3. // inject.h  
  4.   
  5. #ifndef __INJECT_H__  
  6. #define __INJECT_H__  
  7.   
  8. #include <windows.h>  
  9. #include <iostream>  
  10.   
  11. HMODULE InjectDLL(DWORD ProcessID, char* dllName);  
  12.   
  13. #endif  

[cpp] view plaincopy
  1. ////////////////////////////////////////////////////////////////////////////////////////////  
  2.   
  3. // inject.cpp  
  4.   
  5. #include "inject.h"  
  6.   
  7. // 这个函数大家应该见多了  
  8. HMODULE InjectDLL(DWORD ProcessID, char* dllName)  
  9. {  
  10.     HANDLE Proc;  
  11.     HANDLE Thread;  
  12.     char buf[50]={0};  
  13.     LPVOID RemoteString, LoadLibAddy;  
  14.     HMODULE hModule = NULL;  
  15.     DWORD dwOut;  
  16.   
  17.     if(!ProcessID)  
  18.         return false;  
  19.   
  20.     Proc = OpenProcess(PROCESS_ALL_ACCESS, 0, ProcessID);  
  21.   
  22.     if(!Proc)  
  23.     {  
  24.         sprintf_s(buf, "OpenProcess() failed: %d", GetLastError());  
  25.         MessageBoxA(NULL, buf, "Loader", NULL);  
  26.         return false;  
  27.     }  
  28.   
  29.     LoadLibAddy = (LPVOID)GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryA");  
  30.     if (!LoadLibAddy) {  
  31.         return false;  
  32.     }  
  33.   
  34.   
  35.     RemoteString = (LPVOID)VirtualAllocEx(Proc, NULL, strlen(dllName), MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);  
  36.     if (!RemoteString) {  
  37.         return false;  
  38.     }  
  39.   
  40.     if (!WriteProcessMemory(Proc, (LPVOID)RemoteString, dllName, strlen(dllName), NULL)) {  
  41.         return false;  
  42.     }  
  43.   
  44.     Thread = CreateRemoteThread(Proc, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibAddy, (LPVOID)RemoteString, NULL, NULL);     
  45.     if (!Thread) {  
  46.         return false;  
  47.     } else {  
  48.         while(GetExitCodeThread(Thread, &dwOut)) {  
  49.             if(dwOut != STILL_ACTIVE) {  
  50.                 hModule = (HMODULE)dwOut;  
  51.                 break;  
  52.             }  
  53.         }  
  54.     }  
  55.   
  56.     CloseHandle(Thread);  
  57.     CloseHandle(Proc);  
  58.   
  59.     return hModule;  
  60. }  

[cpp] view plaincopy
  1. ////////////////////////////////////////////////////////////////////////////////////////////  
  2. // main.cpp  
  3.   
  4. #include "inject.h"  
  5.   
  6. const char* EXE_NAME = "war3.exe -window";  // 这里我们用窗口模式启动魔兽  
  7. const char* DLL_NAME = "dll.dll";       // 要注入的dll名  
  8.   
  9. int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)  
  10. {  
  11.     char path[MAX_PATH];  
  12.     char exename[MAX_PATH];  
  13.     char dllname[MAX_PATH];  
  14.   
  15.     // 获取本程序的完整路径名称,注意这里我们的exe文件要放在魔兽目录下  
  16.     GetModuleFileNameA(0, path, MAX_PATH);  
  17.   
  18.     // 找到路径中的最后一个\符号,并删除之后的字符  
  19.     // (如 D:\Game\魔兽\loader.exe 变成 D:\Game\魔兽\)  
  20.     int pos = 0;  
  21.     for (int k = 0; k < strlen(path); k++) {  
  22.         if (path[k] == '\\') {  
  23.             pos = k;  
  24.         }  
  25.     }  
  26.     path[pos+1] = 0; // null-terminate it for strcat  
  27.   
  28.     // 创建war3路径  
  29.     strcpy_s(exename, path);  
  30.     strcat_s(exename, EXE_NAME);  
  31.   
  32.     // 创建dll路径  
  33.     strcpy_s(dllname, path);  
  34.     strcat_s(dllname, DLL_NAME);  
  35.   
  36.     // 启动war3:  
  37.     STARTUPINFOA siStartupInfo;  
  38.     PROCESS_INFORMATION piProcessInfo;  
  39.     memset(&siStartupInfo, 0, sizeof(siStartupInfo));  
  40.     memset(&piProcessInfo, 0, sizeof(piProcessInfo));  
  41.     siStartupInfo.cb = sizeof(siStartupInfo);  
  42.   
  43.     if (!CreateProcessA(  
  44.         NULL,  
  45.         exename,  
  46.         0,  
  47.         0,  
  48.         false,  
  49.         CREATE_SUSPENDED,  
  50.         0,  
  51.         0,  
  52.         &siStartupInfo,  
  53.         &piProcessInfo)) {  
  54.             MessageBoxA(NULL, exename, "Error", MB_OK);   
  55.     }  
  56.   
  57.     // 获得war3的pid  
  58.     DWORD pId = piProcessInfo.dwProcessId;  
  59.   
  60.     // 注入dll  
  61.     if (!InjectDLL(pId, dllname)) {  
  62.         MessageBoxA(NULL, "Injection failed", "Error", MB_OK);        
  63.     }  
  64.   
  65.     ResumeThread(piProcessInfo.hThread);  
  66.   
  67.     return 0;  
  68. }  
这样我们的装载器就完成了。


2. 接着,我们添加一个空的Win32 dll工程,工程名就要dll吧,包括以下文件:

     main.cpp


先添加dll的入口函数


[cpp] view plaincopy
  1. #include <windows.h>  
  2. #include <d3dx8.h>  
  3. #include <detours.h>  
  4.   
  5. #pragma comment(lib, "detours.lib")  
  6.   
  7. BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)  
  8. {  
  9.     switch (ul_reason_for_call) {  
  10.         case DLL_PROCESS_ATTACH: {  
  11.             DisableThreadLibraryCalls(hModule);  
  12.             // 我们将要在这里进行hook  
  13.         }  
  14.     }  
  15.     return TRUE;  
  16. }  

我们知道,魔兽使用 LoadLibraryA 访问 DirectX 的。这意味着,我们不能直接 hook 住Direct3DCreate8因为
a)d3d8.dll 尚未加载
b)我们不知道它的地址



所以我们hook 住 LoadLibraryA 来获取  Direct3DCreate8 的地址,首先定义LoadLibraryA的形式,

并声明一个变量用来保存LoadLibrayA 的原始地址


[cpp] view plaincopy
  1. typedef HMODULE (WINAPI *LoadLibrary_t)(LPCSTR);  
  2. LoadLibrary_t orig_LoadLibrary = LoadLibraryA;<span>        </span>// 保存 LoadLibraryA 的原始地址  


然后在当 d3d8.dll 真正被加载时,我们在重写的 LoadLibraryA 方法中得到 Direct3DCreate8 的地址并 detour 它。
在测试过程中,可以发现游戏对 DLL 加载了几次。所以如果你在别的游戏中,并不能采用这里的加载次数。


[cpp] view plaincopy
  1. // 我们重写的 LoadLibraryA 方法  
  2. HMODULE WINAPI LoadLibrary_Hook ( LPCSTR lpFileName )   
  3. {  
  4.     static int hooked = 0;  
  5.   
  6.     HMODULE hM = orig_LoadLibrary( lpFileName );  
  7.     if ( strcmp( lpFileName, "d3d8.dll" ) == 0)   
  8.     {  
  9.         hooked++;  
  10.   
  11.         if (hooked == 3) {  
  12.             // 得到 Direct3DCreate8 的地址,然后就可以做我们想做的事情了。。。。  
  13.             pDirect3DCreate8 = (PBYTE)GetProcAddress(hM, "Direct3DCreate8");  
  14.             // 我们对 Direct3DCreate8 进行 hook   
  15.             HookAPI();  
  16.         }  
  17.     }  
  18.   
  19.     return hM;  
  20. }  


[cpp] view plaincopy
  1. // 向前声明  
  2. IDirect3D8* __stdcall hook_Direct3DCreate8(UINT sdkVers);  
  3. void HookAPI();  
  4.   
  5. typedef IDirect3D8* (__stdcall *Direct3DCreate8_t)(UINT SDKVersion);  
  6. Direct3DCreate8_t orig_Direct3DCreate8;<span>   </span>// 用来保存原始地址  
  7.   
  8. // Direct3DCreate8 的地址,在我们重写的 LoadLibraryA 方法中赋值,有了他我们就能对 Direct3DCreate8 进行 hook了  
  9. PBYTE pDirect3DCreate8;  


我们就用微软的 Detour 库来 hook Direct3DCreate8


[cpp] view plaincopy
  1. void HookAPI()  
  2. {  
  3.     // simple detour  
  4.     orig_Direct3DCreate8 = (Direct3DCreate8_t)pDirect3DCreate8;  
  5.   
  6.     DetourRestoreAfterWith();  
  7.     DetourTransactionBegin();  
  8.     DetourUpdateThread(GetCurrentThread());  
  9.   
  10.     DetourAttach(&(PVOID&)orig_Direct3DCreate8, hook_Direct3DCreate8);  
  11.   
  12.     DetourTransactionCommit();  
  13.   
  14. }  



钩住了 Direct3DCreate8 后我们可以通过虚函数表获得 CreateDevice 的地址了,有关虚函数表不知道的可以去问google。


[cpp] view plaincopy
  1. // 重写 Direct3DCreate8 方法  
  2. IDirect3D8* __stdcall hook_Direct3DCreate8(UINT sdkVers)  
  3. {  
  4.     IDirect3D8* pD3d8 = orig_Direct3DCreate8(sdkVers); // real one  
  5.   
  6.     // 通过虚函数表得到 CreateDevice 的地址,CreateDevice 是虚表中的第15个函数  
  7.     DWORD* pVtable = GetVtableAddress(pD3d8);  
  8.     HookFunction(pVtable, (void*)&hook_CreateDevice, (void*)&orig_CreateDevice, 15);  
  9.   
  10.     return pD3d8;  
  11. }  

向前声明



[html] view plaincopy
  1. // CreateDevice  
  2. typedef HRESULT (APIENTRY *CreateDevice_t)(  
  3.     IDirect3D8*,  
  4.     UINT,D3DDEVTYPE,  
  5.     HWND,DWORD,  
  6.     D3DPRESENT_PARAMETERS*,  
  7.     IDirect3DDevice8**);  
  8.   
  9. CreateDevice_t orig_CreateDevice;  
  10.   
  11. HRESULT APIENTRY hook_CreateDevice(  
  12.     IDirect3D8* pInterface,  
  13.     UINT Adapter,  
  14.     D3DDEVTYPE DeviceType,  
  15.     HWND hFocusWindow,  
  16.     DWORD BehaviorFlags,  
  17.     D3DPRESENT_PARAMETERS* pPresentationParameters,  
  18.     IDirect3DDevice8** ppReturnedDeviceInterface);  

这里我们可以获得 LPDIRECT3DDEVICE8 的设备对象指针,并把他们输出,等下我们要用到。



[cpp] view plaincopy
  1. HRESULT APIENTRY hook_CreateDevice(  
  2.     IDirect3D8* pInterface,  
  3.     UINT Adapter,  
  4.     D3DDEVTYPE DeviceType,  
  5.     HWND hFocusWindow,  
  6.     DWORD BehaviorFlags,  
  7.     D3DPRESENT_PARAMETERS* pPresentationParameters,  
  8.     IDirect3DDevice8** ppReturnedDeviceInterface)  
  9. {  
  10.     HRESULT ret = orig_CreateDevice(pInterface, Adapter, DeviceType, hFocusWindow, BehaviorFlags, pPresentationParameters, ppReturnedDeviceInterface);  
  11.   
  12.       
  13.     // Registers MUST be preserved when doing your own stuff!!  
  14.     __asm pushad  
  15.   
  16.     // get a pointer to the created device   
  17.     IDirect3DDevice8* d3ddev = *ppReturnedDeviceInterface;  
  18.   
  19.     // lets log it (format in hex mode to make it easier to work with)  
  20.     char buf[50] = {0};  
  21.   
  22.     wsprintfA(buf, "pD3ddev: %X", d3ddev);  
  23.     OutputDebugStringA(buf);  
  24.   
  25.     __asm popad  
  26.   
  27.     return ret;  
  28. }  


上面用到的2个函数



[cpp] view plaincopy
  1. DWORD* GetVtableAddress(void* pObject)  
  2. {  
  3.     // The first 4 bytes of the object is a pointer to the vtable:  
  4.     return (DWORD*)*((DWORD*)pObject);  
  5. }  
  6.   
  7. // 通过替换虚函数表中的函数地址实现 hook CreateDevice  
  8. void HookFunction(DWORD* pVtable, void* pHookProc, void* pOldProc, int iIndex)  
  9. {  
  10.     // Enable writing to the vtable at address we aquired  
  11.     DWORD lpflOldProtect;  
  12.     VirtualProtect((void*)&pVtable[iIndex], sizeof(DWORD), PAGE_READWRITE, &lpflOldProtect);  
  13.   
  14.     // Store old address  
  15.     if (pOldProc) {  
  16.         *(DWORD*)pOldProc = pVtable[iIndex];  
  17.     }  
  18.   
  19.     // Overwrite original address  
  20.     pVtable[iIndex] = (DWORD)pHookProc;  
  21.   
  22.     // Restore protection  
  23.     VirtualProtect(pVtable, sizeof(DWORD), lpflOldProtect, &lpflOldProtect);  
  24. }  



二、

这样我们就得到了一个 IDirect3DDevice8 指针,然后就可以进行魔兽写屏了。

不过这样的话我们每次必须在游戏初始化D3d之前完成hook,不是很方便。

我们希望能够有一种方法可以不用 hook,就能随时获得设备指针。那我们就继续完成这个任务吧。


我们打开DebugView,运行我们的Loader,得到设备指针。(比如我的:[3296] pD3ddev: 3317FC0)

然后用 od 附加魔兽。

1)我们先 alt + e,查看 d3d8.dll 的模块基址,我这是 54D20000

2)在Command 栏中输入 hr ????????  (下硬件断点,????????是你刚刚获得的设备指针,比如我输入的就是 hr 3317FC0)。

od 就断下了,看看是否是在 d3d8 模块内被断下的,不是的话F9运行,直到是在 d3d8 模块内被断下。

3)断下后记住地址(程序断下后的偏移地址可能会不大一样,以为有很多地方都访问了这个指针,

随便找个地址就可以了,也可以想原文中那样用CE扫描)

就用原文中的地址吧,F9多跑几次断在了原文中的地址。


[plain] view plaincopy
  1. 54D96E29  |> \C746 18 01000>mov dword ptr ds:[esi+0x18],0x1  
  2. 54D96E30  |.  8B76 0C       mov esi,dword ptr ds:[esi+0xC]  
  3. 54D96E33      8B06          mov eax,dword ptr ds:[esi]  
  4. 54D96E35      8B48 08       mov ecx,dword ptr ds:[eax+0x8]<span>        </span>;断在了这里,说明是上一句访问了设备指针,那么esi中的值就是设备指针  
  5. 54D96E38  |.  56            push esi  



然后我们Ctrl + End 来到模块末尾,找一段空的区域,我们将在这获取并保存设备指针。


[plain] view plaincopy
  1. 54E13FC3      00            db 00  
  2. 54E13FC4      00            db 00  
  3. 54E13FC5      00            db 00  
  4. 54E13FC6      00            db 00  
  5. 54E13FC7      00            db 00  
  6. 54E13FC8      00            db 00  
  7. 54E13FC9      00            db 00  
  8. 54E13FCA      00            db 00  
  9. 54E13FCB      00            db 00  
  10. 54E13FCC      00            db 00  
  11. 54E13FCD      00            db 00  
  12. 54E13FCE      00            db 00  
  13. 54E13FCF      00            db 00  
  14. 54E13FD0      00            db 00  
  15. 54E13FD1      00            db 00  
  16. 54E13FD2      00            db 00  
  17. 54E13FD3      00            db 00  
  18. 54E13FD4      00            db 00  
  19. 54E13FD5      00            db 00  
  20. 54E13FD6      00            db 00  


我们就跳到 54E13FC7 这个位置来获取设备指针,然后把值存到 54E13FC3 中。

4)alt + g 回到 54D96E33 处,双击,输入 jmp 54E13FC7


[plain] view plaincopy
  1. 54D96E29  |> \C746 18 01000>mov dword ptr ds:[esi+0x18],0x1  
  2. 54D96E30  |.  8B76 0C       mov esi,dword ptr ds:[esi+0xC]  
  3. 54D96E33      E9 8FD10700   jmp d3d8.54E13FC7  
  4. 54D96E38  |.  56            push esi  

alt + g 转到 54E13FC7,写入原指令,在将 esi 存入 54D96E33,然后在跳到 54D96E38。



[plain] view plaincopy
  1. 54E13FC3      00            db 00  
  2. 54E13FC4      00            db 00  
  3. 54E13FC5      00            db 00  
  4. 54E13FC6      00            db 00  
  5. 54E13FC7      8B06          mov eax,dword ptr ds:[esi]  
  6. 54E13FC9      8B48 08       mov ecx,dword ptr ds:[eax+0x8]  
  7. 54E13FCC      8935 C33FE154 mov dword ptr ds:[0x54E13FC3],esi  
  8. 54E13FD2    ^ E9 612EF8FF   jmp d3d8.54D96E38  

现在我们运行的话程序就会退出,以为 54E13FC3 的属性是不可写的。



这里的54D96E33、54E13FC3、54E13FC7会随每次载入时 d3d8基址的变化而变化,所有我们要进行重定位。

RVA:

76E33 = 54D96E33 - 54D20000

F3FC3 = 54E13FC3 - 54D20000

F3FC7 = 54E13FC7 - 54D20000

之后只要获得 d3d8 的基址,加上偏移量就行了。


注:上面这种方法是让魔兽跳转到模块末尾执行,我们也可以让魔兽跳到我们的模块函数内执行,

保存好设备指针后在跳回去,函数可以这样写:


[cpp] view plaincopy
  1. DWORD g_d3dPoint = 0;  
  2. __declspec(naked) void GetValue()  
  3. {  
  4.     __asm  
  5.     {  
  6.         mov eax, dword ptr ds:[esi];  
  7.         mov ecx, dword ptr ds:[eax + 0x8];  
  8.         mov g_d3dPoint, esi;  
  9.         jmp addr_back;  
  10.     }  
  11. }  

4)新建一个空的Win32 Dll 工程,包含以下文件:
     main.cpp

dll 入口函数


[cpp] view plaincopy
  1. #include <Windows.h>  
  2.   
  3. #include <d3d8.h>  
  4. #include <d3dx8.h>  
  5.   
  6. // 向前声明  
  7. DWORD*      pVtable;  
  8.   
  9. // EndScene (offset : 35)  
  10. BOOL _stdcall DrawMyText(LPDIRECT3DDEVICE8 pDxdevice,TCHAR* strText ,int nbuf);  
  11. typedef HRESULT (APIENTRY *EndScene_t)(IDirect3DDevice8* );  
  12. HRESULT APIENTRY hook_EndScene(IDirect3DDevice8* pInterface);  
  13. EndScene_t orig_EndScene;  
  14.   
  15. DWORD WINAPI Patch_StealD3d8Device(LPVOID param);  
  16. DWORD WINAPI HookAPI(LPVOID param);  
  17. DWORD* GetVtableAddress(void* pObject);  
  18. void HookFunction(DWORD* pVtable, void* pHookProc, void* pOldProc, int iIndex);  
  19.   
  20. // hooks.h  
  21.   
  22. BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)  
  23. {  
  24.     switch (ul_reason_for_call) {  
  25.     case DLL_PROCESS_ATTACH:  
  26.         {  
  27.             DisableThreadLibraryCalls(hModule);  
  28.   
  29.             HANDLE hpThread;  
  30.             hpThread = ::CreateThread(NULL, 0, Patch_StealD3d8Device, NULL, 0, NULL);// 这个线程用来让d3d8.dll执行我们代码,获得设备指针  
  31.             CloseHandle(hpThread);  
  32.   
  33.         }  
  34.         break;  
  35.     case DLL_PROCESS_DETACH:  
  36.         {  
  37.             DWORD hook_addr;  
  38.             HookFunction(pVtable, (void *)orig_EndScene, (void*)&hook_addr, 35);    // 退出时还原虚函数表  
  39.         }  
  40.         break;  
  41.     }  
  42.     return TRUE;  
  43. }  


patch d3d8.dll,让我们的代码执行


[cpp] view plaincopy
  1. DWORD WINAPI Patch_StealD3d8Device(LPVOID param)  
  2. {  
  3.     int base_d3d8 = (int)GetModuleHandle(TEXT("d3d8"));  
  4.   
  5.     // 重定位  
  6.     const int addr_jmp =   base_d3d8 + 0x00076E33;  
  7.     const int addr_cave =  base_d3d8 + 0x000F3FD0;  
  8.     const int addr_value = base_d3d8 + 0x000F3FC7;  
  9.   
  10.     // 我们保存的2进制码  
  11.     byte jmp[] =  "\xE9\x98\xD1\x07"; // 字符串是以 0x00 终止的  
  12.     byte cave[] = "\x8B\x06\x8B\x48\x08\x89\x35\xC5\x3F\x0B\x6D\xE9\x58\x2E\xF8\xFF"; // 0终止,之后的是数据 0,所以是可行的  
  13.   
  14.     // 更改内存的读写属性,让我们能够写入  
  15.     DWORD lpflOldProtect;  
  16.   
  17.     // 写入跳转指令,让程序跳到模块末尾执行我们的代码  
  18.     VirtualProtect((void*)addr_jmp, sizeof(jmp), PAGE_EXECUTE_READWRITE, &lpflOldProtect);  
  19.     memcpy((void*)addr_jmp, (void*)jmp, sizeof(jmp));  
  20.     VirtualProtect((void*)addr_jmp, sizeof(jmp), lpflOldProtect, &lpflOldProtect);  
  21.   
  22.     // 在模块末尾写入我们的代码  
  23.     VirtualProtect((void*)addr_cave, sizeof(cave), PAGE_EXECUTE_READWRITE, &lpflOldProtect);  
  24.     memcpy((void*)addr_cave, (void*)cave, sizeof(cave));  
  25.     // 这里我们要对保存设备指针的地址进行重定位  
  26.     *(int*)(addr_cave + 7) = addr_value;  
  27.     VirtualProtect((void*)addr_cave, sizeof(cave), lpflOldProtect, &lpflOldProtect);  
  28.   
  29.     // 让保存设备指针的地址可写  
  30.     VirtualProtect((void*)addr_value, sizeof(DWORD), PAGE_EXECUTE_READWRITE, &lpflOldProtect);  
  31.   
  32.     // 等待设备指针被保存到指定的地址  
  33.     HANDLE hThread = CreateThread(0, 0, HookAPI, 0, 0, 0);  
  34.     WaitForSingleObject(hThread, INFINITE);  
  35.     CloseHandle(hThread);  
  36.   
  37.     // 还原  
  38.     byte orig[] = {0x8B, 0x06, 0x8B, 0x48, 0x08};  
  39.     VirtualProtect((void*)addr_jmp, sizeof(orig), PAGE_EXECUTE_READWRITE, &lpflOldProtect);  
  40.     memcpy((void*)addr_jmp, (void*)orig, sizeof(orig));  
  41.     VirtualProtect((void*)addr_jmp, sizeof(orig), lpflOldProtect, &lpflOldProtect);  
  42.   
  43.     return 0;  
  44. }  

堵塞线程直到设备指针被保存到指定位置。



[cpp] view plaincopy
  1. DWORD WINAPI HookAPI(LPVOID param)  
  2. {  
  3.     // Aquire base address of d3d8.dll  
  4.     int base_d3d8 = (int)GetModuleHandle(TEXT("d3d8"));  
  5.   
  6.     const int addr_value = base_d3d8 + 0x000F3FC7;  
  7.   
  8.     Sleep(100); // wait for address to get written  
  9.   
  10.     // protect value addr for reading / writing  
  11.     DWORD lpflOldProtect;  
  12.     VirtualProtect((void*)addr_value, sizeof(DWORD), PAGE_EXECUTE_READWRITE, &lpflOldProtect);  
  13.   
  14.     // poll the value until it gets written by our cave  
  15.     DWORD result = 0;  
  16.     while (!result) {  
  17.         result = *(DWORD*)addr_value;  
  18.         Sleep(10);  
  19.     }  
  20.   
  21.     // find the vtable  
  22.     pVtable = GetVtableAddress((void*)result);  
  23.   
  24.     // 这里我们替换虚函数表中的 EndScene 函数指针,执行我们重写的 EndScene 进行写屏  
  25.     HookFunction(pVtable, (void*)&hook_EndScene, (void*)&orig_EndScene, 35);  
  26. //  HookFunction(pVtable, (void*)&hook_DrawIndexedPrimitive, (void*)&orig_DrawIndexedPrimitive, 71);  
  27. //  HookFunction(pVtable, (void*)&hook_Present, (void*)&orig_Present, 15);  
  28. //  HookFunction(pVtable, (void*)&hook_SetStreamSource, (void*)&orig_SetStreamSource, 83);  
  29.   
  30.     return 0;  
  31. }  

下面的没就什么了,直接上代码吧



[cpp] view plaincopy
  1. DWORD* GetVtableAddress(void* pObject)  
  2. {  
  3.     // The first 4 bytes of the object is a pointer to the vtable:  
  4.     return (DWORD*)*((DWORD*)pObject);  
  5. }  
  6.   
  7. void HookFunction(DWORD* pVtable, void* pHookProc, void* pOldProc, int iIndex)  
  8. {  
  9.     // Enable writing to the vtable at address we aquired  
  10.     DWORD lpflOldProtect;  
  11.     VirtualProtect((void*)&pVtable[iIndex], sizeof(DWORD), PAGE_READWRITE, &lpflOldProtect);  
  12.   
  13.     // Store old address  
  14.     if (pOldProc) {  
  15.         *(DWORD*)pOldProc = pVtable[iIndex];  
  16.     }  
  17.   
  18.     // Overwrite original address  
  19.     pVtable[iIndex] = (DWORD)pHookProc;  
  20.   
  21.     // Restore protection  
  22.     VirtualProtect(pVtable, sizeof(DWORD), lpflOldProtect, &lpflOldProtect);  
  23. }  
  24.   
  25.   
  26. //Endscene  
  27. HRESULT APIENTRY hook_EndScene(IDirect3DDevice8* pInterface)  
  28. {  
  29.     __asm pushad  
  30.   
  31.     DrawText((LPDIRECT3DDEVICE8)pInterface, TEXT("by: 狼烟断  2012-03-09"), 20);  
  32.   
  33.     __asm popad  
  34.   
  35.     return orig_EndScene(pInterface);  
  36. }  
  37.   
  38. BOOL _stdcall DrawText(LPDIRECT3DDEVICE8 pDxdevice,TCHAR* strText ,int nbuf)  
  39. {  
  40.     if (pDxdevice) {  
  41.         RECT myrect;  
  42.         myrect.top      = 10;  
  43.         myrect.left     = 50;  
  44.         myrect.right        = 1000 + 50;  
  45.         myrect.bottom   <span>  </span>= 100 + 10;  
  46.   
  47.         HFONT hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);  
  48.         LOGFONT lf = {0};  
  49.         GetObject(hFont, sizeof(lf), &lf);  
  50.         DeleteObject(hFont);  
  51.         hFont = NULL;  
  52.   
  53.         ID3DXFont* g_font = NULL;  
  54.         if(D3D_OK != D3DXCreateFontIndirect(pDxdevice, &lf, &g_font))  
  55.             return FALSE;  
  56.   
  57.         g_font->DrawTextW(  
  58.             strText,  
  59.             nbuf,   
  60.             &myrect,   
  61.             DT_TOP | DT_LEFT,  
  62.             0xFFFFFF00);   
  63.   
  64.         g_font->Release();  
  65.     }  
  66.     return true;  
  67. }  



效果图:






源码下载:工程源码下载.rar

(责任编辑:简单的工作室)
顶一下
(2)
100%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
栏目列表
推荐内容