[转] Windows下Hook DirectX
首先说,这篇文章是很久以前为了玩成某游戏的HOOK找到的资料,虽然一直没用上,但是还是让我保留下来了。直接贴上了。。看不懂也不要问我,我都没看。
也许看得懂的人对他们来说这是一个思路,不懂的就当垃圾文不看就好。。
我们要想拥有自己的窗口,那么就必须在诸仙的进程启动之前得到Direct3DCreate8接口(诸仙用Direct3D8)。所以启动过程如下:
//启动诸仙并获取诸仙进程句柄
ZhuXianProc.OpenExe("C:\\游戏目录\\诛仙\\element\\elementclient.exe");
if(!ZhuXianProc.GetProcess())
{
MessageBox(NULL,
" 无法正常启动《诸仙》主程序\n\n获取帮助请与本工作室技术人员联系",
"天涯工作室程序运行错误提示!",MB_OK);
return TRUE;
}
//在程序运行之前先HOOK住所需要HOOK的API
HookApi("C:\\游戏目录\\诛仙\\element\\elementclient.exe","C:\\游戏目录\\诛仙\\element\\ZxDll.dll");
ZhuXianFunc();
ZhuXianProc.CloseAllHandle();
关于ZhuXianProc是一个CGetProc类型,这个类主要是打开进程和取得进程的一些信息,GetProcess()取的改进程的句柄。这个类里面要解释下的是:
void CGetProc::OpenExe(CString str)
{
memset(&si,0,sizeof(si));
si.cb=sizeof(si);
si.wShowWindow=SW_SHOW;
si.dwFlags=STARTF_USESHOWWINDOW;
CreateProcess(str,NULL,NULL,FALSE,NULL,Create_SUSPENDED,NULL,NULL,&si,&pi);
}
“Create_SUSPENDED”指明该进程并不是一开始就让他运行,原因是我们要想得到Direct3DCreate8接口就必须在运行进程之前注入我们的DLL,并让我们的DLL里的HOOK Direct3DCreate8接口跑到他的初始化之前。
我们来看看HookApi()的内容:
bool CUIThread::HookApi(char* pszFileExe,char* pszFileDll)
{
//让程序启动的时候JMP到自己的DLL中去
HANDLE hProcess = ZhuXianProc.GetProcess();
// 在目标进程申请空间,存放字符串pszDllName,作为远程线程的参数
int cbSize = (strlen(pszFileDll) + 1);
LPVOID lpRemoteDllName = ::VirtualAllocEx(hProcess, NULL, cbSize, MEM_COMMIT, PAGE_READWRITE);
::WriteProcessMemory(hProcess, lpRemoteDllName, pszFileDll, cbSize, NULL);
// 取得LoadLibraryA函数的地址,我们将以它作为远程线程函数启动
HMODULE hModule=::GetModuleHandle ("kernel32.dll");
LPTHREAD_START_ROUTINE pfnStartRoutine = (LPTHREAD_START_ROUTINE)::GetProcAddress(hModule, "LoadLibraryA");
// 启动远程线程
::ResumeThread(ZhuXianProc.GetThread());
HANDLE hRemoteThread = ::CreateRemoteThread(hProcess, NULL, 0, pfnStartRoutine, lpRemoteDllName, 0, NULL);
if(hRemoteThread == NULL)
{
::CloseHandle(hProcess);
return FALSE;
}
::CloseHandle(hRemoteThread);
return TRUE;
}
这段关键是在:
// 启动远程线程
::ResumeThread(ZhuXianProc.GetThread());
HANDLE hRemoteThread = ::CreateRemoteThread(hProcess, NULL, 0, pfnStartRoutine, lpRemoteDllName, 0, NULL);
必须这样,ResumeThread诸仙进程之后立即启动我们的DLL。呵呵,也不能弄反,如果进程没启动,我们注入的DLL就启动了,进程可能就崩溃了。 在这里有个小技巧,诸仙进程启动不代表就立即进行Direct3DCreate8初始化,他还有些事情要做,到他初始化的时候我们的DLL早就跑了一段了:)。
3.来看看我们的重点,我们注入的ZXDLL.DLL到底做了些什么事情。
#pragma comment(lib, "d3d8.lib")
// CZxDllApp BEGIN_MESSAGE_MAP(CZxDllApp, CWinApp)
END_MESSAGE_MAP()
// CZxDllApp 构造 CZxDllApp::CZxDllApp()
{
// TODO: 在此处添加构造代码,
// 将所有重要的初始化放置在 InitInstance 中
} // 唯一的一个 CZxDllApp 对象
CZxDllApp theApp; CAPIHook hookapi2("d3d8.dll","Direct3DCreate8",(PROC)NewDirect3DCreate8);
// CZxDllApp 初始化 BOOL CZxDllApp::InitInstance()
{
CWinApp::InitInstance();
return TRUE;
}
看完DLL的这一段小程序,基本上是VC向导完成的,只有一句:
CAPIHook hookapi2("d3d8.dll","Direct3DCreate8",(PROC)NewDirect3DCreate8);
这句在DLL一运行的时候他就运行了,并把Direct3DCreate8给变成了新的入口地址NewDirect3DCreate8了,那么当诸仙运行的时候这个函数就跑到我们的NewDirect3DCreate8里来了,呵呵,正好,我们抓住了Direct3DCreate8接口了,来我们一起看看NewDirect3DCreate8函数里的内容。
IDirect3D8 * WINAPI NewDirect3DCreate8(UINT SDKVersion)
{
static int count = 0;
static IDirect3D8* test = NULL; hookapi2.Unhook();
IDirect3D8 * m = Direct3DCreate8(SDKVersion);
hookapi2.Rehook();//程序一共3个3维平面驱动 count++;
if(count==2){//1,窗口模式请用2,全屏模式请用3
lpD3D = m;
//替换VTable,实现对IDirect3Draw 的 COM接口的挂钩
NewlpD3d = new MyIDirect3D8;
m = (IDirect3D8*)NewlpD3d;
} return m;
}
呵呵,诸仙对IDirect3D8接口其实是驱动了3次,我没查出来第一次是干什么的,但是后两次一个是在窗口模式下用的,一个是在全屏模式下用的。光得到IDirect3D8接口是没用的这里我们还要进行COM HOOK 获得Direct3DDevice8(D3D 设备) 的接口的指针从而得到我们的Render该放到什么地方。
COM HOOK其实就是写一个同样的类用来替换COM的VTable,不做详细的解释,实在搞不懂就google(俺也是这么得来的:))。MyIDirect3D8就是一个新的IDirect3D8类,他是从IDirect3D8继承来的,定义如下:
class MyIDirect3D8 : public IDirect3D8
{
public:
HRESULT APIENTRY QueryInterface(REFIID riid, void** ppvObj);
ULONG APIENTRY AddRef();
ULONG APIENTRY Release(); /*** IDirect3D8 methods ***/
HRESULT APIENTRY RegisterSoftwareDevice(void* pInitializeFunction);
UINT APIENTRY GetAdapterCount();
HRESULT APIENTRY GetAdapterIdentifier(UINT Adapter,DWORD Flags,D3DADAPTER_IDENTIFIER8* pIdentifier);
UINT APIENTRY GetAdapterModeCount(UINT Adapter);
HRESULT APIENTRY EnumAdapterModes(UINT Adapter,UINT Mode,D3DDISPLAYMODE* pMode);
HRESULT APIENTRY GetAdapterDisplayMode(UINT Adapter,D3DDISPLAYMODE* pMode);
HRESULT APIENTRY CheckDeviceType(UINT Adapter,D3DDEVTYPE CheckType,D3DFORMAT DisplayFormat,D3DFORMAT BackBufferFormat,BOOL Windowed);
HRESULT APIENTRY CheckDeviceFormat(UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT AdapterFormat,DWORD Usage,D3DRESOURCETYPE RType,D3DFORMAT CheckFormat);
HRESULT APIENTRY CheckDeviceMultiSampleType(UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT SurfaceFormat,BOOL Windowed,D3DMULTISAMPLE_TYPE MultiSampleType);
HRESULT APIENTRY CheckDepthStencilMatch(UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT AdapterFormat,D3DFORMAT RenderTargetFormat,D3DFORMAT DepthStencilFormat);
HRESULT APIENTRY GetDeviceCaps(UINT Adapter,D3DDEVTYPE DeviceType,D3DCAPS8* pCaps);
HMONITOR APIENTRY GetAdapterMonitor(UINT Adapter);
HRESULT APIENTRY CreateDevice(UINT Adapter,D3DDEVTYPE DeviceType,HWND hFocusWindow,DWORD BehaviorFlags,D3DPRESENT_PARAMETERS* pPresentationParameters,IDirect3DDevice8** ppReturnedDeviceInterface);
MyIDirect3D8(void); IDirect3D8 * lpD3D;
IDirect3DDevice8 * lpD3DD8;
IDirect3DDevice8 * lpD3DD8bak;
ULONG m_count;
};
pGame就是我们的外挂的主类包括界面处理等等,在下一点讲解。 IpD3DDevice是Direct3DDevice8(D3D 设备) 的接口的指针,我们也要想办法解决,不急,等下慢慢说。
替换VTable其实很简单,我们只需要new一个我们自己的的MyIDirect3D8把老的IDirect3D8的指针内容直接替换就行了,呵呵:
//替换VTable,实现对IDirect3Draw 的 COM接口的挂钩
NewlpD3d = new MyIDirect3D8;
m = (IDirect3D8*)NewlpD3d; Direct3DDevice8(D3D 设备) 的接口的指针是在IDirect3D8里面Create的我们再看看MyIDirect3D8的CreateDevice函数如何定义: HRESULT APIENTRY MyIDirect3D8::CreateDevice(UINT Adapter,D3DDEVTYPE DeviceType,HWND hFocusWindow,DWORD BehaviorFlags,D3DPRESENT_PARAMETERS* pPresentationParameters,IDirect3DDevice8** ppReturnedDeviceInterface)
{
static MyIDirect3DDevice8 * id3dd8 = NULL; HRESULT m = lpD3D->CreateDevice(Adapter,DeviceType,hFocusWindow,BehaviorFlags,pPresentationParameters,ppReturnedDeviceInterface);
lpD3DD8 = *ppReturnedDeviceInterface; //Hook IDirect3DDevice8
::ShowWindow(hFocusWindow,SW_HIDE);
lpD3D->CreateDevice(Adapter,DeviceType,hFocusWindow,BehaviorFlags,pPresentationParameters,&lpD3DD8bak);
::ShowWindow(hFocusWindow,SW_SHOW);
::SetFocus(hFocusWindow); id3dd8 = new MyIDirect3DDevice8(lpD3DD8bak);
*ppReturnedDeviceInterface = (IDirect3DDevice8*)id3dd8; return m;
}
至于::ShowWindow(hFocusWindow,SW_HIDE);初始化后::ShowWindow(hFocusWindow,SW_SHOW);保证进程不挂,呵呵。
IDirect3DDevice8要想得到IDirect3DDevice8的里面的内容,我们也采用同样方法的偷粱换柱子。MyIDirect3DDevice8定义就不再贴出来了,浪费页面。要解释下的地方是
HRESULT APIENTRY MyIDirect3DDevice8::BeginScene()
{
return g_pD3DDevice->BeginScene();
} HRESULT APIENTRY MyIDirect3DDevice8::EndScene()
{
if(pGame!=NULL) pGame->Render();
return g_pD3DDevice->EndScene();
}
我们的画图函数按道理讲要放到BeginScene()之后,但是我们不是写自己的3D游戏,而是在做外挂,
程序是这么处理的:
别人调用BeginScene();
别人Render();
别人调用EndScene();
看看这个,我们把自己的pGame->Render();放到MyIDirect3DDevice8::BeginScene()里,结果就是自己的画图全被别人的图覆盖了,所有选择放到MyIDirect3DDevice8::EndScene()里去。
到这里我们从诸仙得到的东西已经能满足我们的需求了,那我们就专心的干我们的事情吧,做外挂界面吧。
[转] Windows下Hook DirectX的更多相关文章
- Windows下x86和x64平台的Inline Hook介绍
前言 我在之前研究文明6的联网机制并试图用Hook技术来拦截socket函数的时候,熟悉了简单的Inline Hook方法,但是由于之前的方法存在缺陷,所以进行了深入的研究,总结出了一些有关Windo ...
- windows下捕获dump
一般要捕获异常只需要两个函数:SetUnhandledExceptionFilter截获异常:MiniDumpWriteDump写dump文件.但是由于CRT函数可能会在内部调用SetUnh ...
- 纯windows下制作变色龙引导安装U盘教程
原创教程:纯windows下制作变色龙引导安装U盘教程 支持Mavericks和Yosemite 支持白苹果 目标:windows下制作带 Chamelon变色龙引导的黑苹果安装U盘,支持PC机引导安 ...
- Windows下安装Eric5时出现的“Sorry, please install QtHelp.”问题解决办法
解决Windows下安装Eric5时出现的“Sorry, please install QtHelp.”问题 PyQt4在Windows中使用了DirectX作为加速,不过,PyQt4没有使用最新 ...
- 在Windows下使用MinGW静态编译Assimp
使用MinGW静态编译Assimp 到了5月份了,没有写一篇日志,于是自己从知识库里面拿出一篇文章充数吧.这次将要解说怎样在Windows下使用MinGW静态编译Assimp. Assimp是眼下比較 ...
- windows下VC界面 DIY系列1----写给想要写界面的C++程序猿的话
非常早就想写关于C++ UI开发的一系列博文,博客专栏刚审核通过,就立即開始刷博文,不能辜负自己的一番热血,我并非写界面的高手,仅仅想通过写博文提高我自己的技术积累,也顺便帮助大家解决界面开发的瓶颈. ...
- windows下架设SVN服务器并设置开机启动
原文:windows下架设SVN服务器并设置开机启动 1.安装SVN服务器,到http://subversion.apache.org/packages.html上下载windows版的SVN,并安装 ...
- 持续集成 windows下jenkins常见问题填坑
[过程改进]持续集成 windows下jenkins常见问题填坑 没有什么高深的东西,1 2天的时间大多数人都能自己摸索出来,这里将自己遇到过的问题分享出来避免其他同学再一次挖坑. 目录 1. 主从节 ...
- WINDOWS下搭建SVN服务器端的步骤分享(Subversion)
1.获取svn程序 2.安装 Subversion(以下简称SVN)的服务器端和客户端.下载下来的服务器端是个 zip压缩包,直接解压缩即可,比如我解压到 E:\subversion .客户端安装文件 ...
- Windows下编译SDL
Windows下编译SDL的理由我就不多说了,无论用VS来编译或调试SDL库都是很方便的.而且SDL源代码中也包含了VC工程,你所要做的只是解压VC工程,进行适当的配置,然后编译.调试. 编译SDL大 ...
随机推荐
- 如何通过dump文件定位崩溃,解决问题
1.dump文件是附加堆栈信息的存储文件的简称,文件扩展名".dmp",通过dump文件我们可以得到程序运行某一时刻的堆栈数据.2.当程序意外崩溃后,通常程序会立即中断运行,拿到这 ...
- 认证全家桶(Cookie、Session、Token、JWT)
什么是认证(Authentication) 通俗地讲就是验证当前用户的身份,证明"你是你自己"(比如:你每天上下班打卡,都需要通过指纹打卡,当你的指纹和系统里录入的指纹相匹配时,就 ...
- 个人数据保全计划:(2) NAS基础知识
前言 距离去年国庆入手了NAS至今有好几个月时间了,NAS折腾起来有点麻烦,且实际作用因人而异,并没有想象中的好用,所以说好的这个系列一直没有更新~ 还有另一方面的原因,这些NAS的系统基于Linux ...
- Android开发环境的搭建(一)
开发环境的搭建 Android 应用程序一般使用 Android 软件开发工具包,采用 Java 语言来开发. Android软件开发需要用到的开发工具,如图所示: JDK:相信大家在学习Java语言 ...
- 11.3 shtctl的指定省略(harib08c)
ps:能力有限,若有错误及纰漏欢迎指正.交流 11.3 shtctl的指定省略(harib08c) 对bootpack.h做了如下改动 struct SHEET { unsigned char *bu ...
- Python类的继承,你了解多少?
"三人行必有我师焉!"."不耻下问",中国的圣人先师孔子留下的文化瑰宝传承在生活中的每个角落. 孔子是中国古代最伟大的思想家.教育家.如果说中国有一种根本的立国 ...
- vue核心原理(Diff算法、虚拟dom)
核心原理&源码 Diff 算法 这里参考大佬文章:https://mp.weixin.qq.com/s/oAlVmZ4Hbt2VhOwFEkNEhw diff 算法的进化 关于 diff 算法 ...
- Gin中间件middleware
类型 全局中间件 单个路由中间件 群组中间件 Reference
- 记一次 .NET 某医疗住院系统 崩溃分析
一:背景 1. 讲故事 最近收到了两起程序崩溃的dump,查了下都是经典的 double free 造成的,蛮有意思,这里就抽一篇出来分享一下经验供后面的学习者避坑吧. 二:WinDbg 分析 1. ...
- 剑指 offer 第 28 天
第 28 天 搜索与回溯算法(困难) 剑指 Offer 37. 序列化二叉树 请实现两个函数,分别用来序列化和反序列化二叉树. 你需要设计一个算法来实现二叉树的序列化与反序列化.这里不限定你的序列 / ...