设为首页收藏本站官方微博

汉化工具 HookDx

[复制链接]
查看: 3007|回复: 3
打印 上一主题 下一主题

[汉化工具] HookDx

跳转到指定楼层
楼主
发表于 2010-2-10 11:50 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

HookDx

本帖最后由 shane007 于 2021-2-13 22:23 编辑 + T8 R# T" u# o5 @) k3 }

& z& w4 ?$ c7 ODirrectxHook 工具- w. o: g5 m; ?6 G% e
5 l. W2 Y$ ~  f
标 题: 【原创】高手莫入 在游戏中显示自己的文字和图形的方法
% q5 t  q8 n+ W8 \, _+ Y作 者: runjin
, w6 I! n) X) W时 间: 2009-04-03,23:44
' x* u1 h4 x5 p) l( U; @+ ^链 接: http://bbs.pediy.com/showthread.php?t=85368
: \, J- H% [; x! f
  q3 G5 ]$ T' P4 _8 p/ DHook Directx:在游戏中显示自己的文字和图形的方法$ l* J6 {! X' y: z6 ]6 ~$ P- ?$ X

3 P. `' G0 N$ M! {  Y这个方法出自我大概两年前的一个项目,现在经整理后贴出来和大家分享一下,利用该方法可以在一般的directx游戏里面绘制文本甚至图形对象.
1 ~! z2 b7 T  O6 ~' \其实思路上非常简单,大致是这样的:要在directx中绘制文字和各种图形对象,只要获得一个类型为LPDIRECT3DDEVICE9的设备对象指针.怎样获得这个指针呢?我的方法是首先hook掉Direct3DCreate9以获得类型为LPDIRECT3D9的Direct3D对象的接口指针,这个Direct3D对象有一个成员函数为 IDirect3D9::CreateDevice,设备对象指针就是在这个函数里面创建的.所以,只要根据Direct3D对象接口指针找到Direct3D对象的虚函数表,再根据虚函数表确定IDirect3D9::CreateDevice的内存地址,就可以hook这个函数,从而获得类型为LPDIRECT3DDEVICE9的设备对象指针,然后就可以随意绘制文字或者图形了.7 H2 Z+ S' D2 s5 \5 E
还有一个要hook的地方,即IDirect3DDevice9::Present,这个函数用于交换当前后备缓存区,刷新窗口.要使得我们自己绘制的东西一直显示在屏幕上,比较好的处理方法是hook掉IDirect3DDevice9::Present,在程序真正调用这个函数前插入我们自己的绘制代码.只要根据设备对象指针找到设备对象的虚函数表,根据虚函数表找到IDirect3DDevice9::Present在内存中的地址就可以hook了.下面是对hook directx的详细说明./ R; P0 c$ F1 w/ c3 f2 q
首先是找到Direct3DCreate9的内存地址,然后把入口的5个字节修改为跳转指令./ k1 o, c. s' G2 ~
    pC=GetProcAddress(GetModuleHandle("d3d9.dll"),"Direct3DCreate9");//获得内存地址& b/ i4 I0 ~  \8 D2 _, w0 q
    DWORD oldpro=0;! ^% @; W- S) Q2 d2 j2 M7 d
    memcpy(d3dcen5bytes,pC,5);
/ p& _1 A5 X: @# D! H2 K4 S    VirtualProtect(pC,5,PAGE_EXECUTE_READWRITE,&oldpro);1 {' B7 F  o8 `
    *(BYTE*)pC=0xe9;//0xe9在汇编中是跳转指令操作码" G( n: P% l8 Q* K% b+ }
    *(DWORD*)((BYTE*)pC+1)=(DWORD)hookedDirect3DCreate9-(DWORD)pC-5;//目标地址-原地址-51 X- ?" q) }; W+ w

, F& |9 ~+ e7 z0 v# g# \
7 f; b0 ]: ^, _  g" [7 S这样,在程序运行到Direct3DCreate9时就会跳转到hookedDirect3DCreate9,在这个函数中,首先是还原Direct3DCreate9入口的5个字节,然后调用真正的Direct3DCreate9,如果函数调用成功,就会返回类型为LPDIRECT3D9的Direct3D对象指针,这正是我们所需要的,得到这个指针后,就可以根据Direct3D对象的虚函数表确定IDirect3D9::CreateDevice的内存地址,然后就可以把这个函数入口的5个字节修改成为跳转指令,跳到我们自己的函数中去. 有个地方值得注意的是,在directx的虚函数中把this指针作为第一个形参入栈了.例如说sdk中IDirect3D9::CreateDevice的函数说明是这样:
  U( i( k+ S8 t4 {# THRESULT CreateDevice(& _, V6 [6 a# {; C$ F" ^# {
  UINT Adapter,9 t6 l# ]3 d" v& j/ {" I; ]
  D3DDEVTYPE DeviceType,9 v5 u/ K8 r6 y; Q- ]" Z
  HWND hFocusWindow,
: _. j" e+ ~/ M4 f1 ]  DWORD BehaviorFlags,( o9 a$ n( e6 i* r3 t6 s
  D3DPRESENT_PARAMETERS * pPresentationParameters,# D0 r2 U  S# S
  IDirect3DDevice9 ** ppReturnedDeviceInterface9 p! o- ^; w. l6 u& i2 o% x
);
" R0 b' I' |& e; J: k! z- U9 i1 L- ]9 [' x+ ~* E& p% D
* T. |# |4 t+ ?
而为了程序跳转到我们的代码执行完后保持栈的平衡,hookedDirect3DCreat9函数声明应该是这样:
& p7 d; Z* J. U) JHRESULT _stdcall hookedCreateDevice(
7 h  |1 l, t% D) W7 n  k) {                                  LPDIRECT3D9 pDx9,% p2 j' ^/ [6 U0 @
                                  UINT Adapter,# r% o' X; O5 R
                                  D3DDEVTYPE DeviceType,' U5 Q9 T  S8 p
                                  HWND hFocusWindow,+ T: T) r7 D. t8 `0 w# |. N( G
                                  DWORD BehaviorFlags,
+ E5 t  j3 L+ g, [2 `7 p  X                                  D3DPRESENT_PARAMETERS * pPresentationParameters,: x9 S5 u9 d' e0 p9 h) f
                                  IDirect3DDevice9 ** ppReturnedDeviceInterface
, d: m1 P( P1 H9 d$ [7 t# g
; \% k2 e6 I' @' G$ h( F                                  );
7 |" x" Y: B1 D5 }2 L  Z3 R1 n) N
其中的LPDIRECT3D9 pDx9就是this指针.
( l7 W, N4 [, V1 a4 G) O/ p  u* `; G9 e+ L
hookedDirect3DCreate9的关键代码如下:  d) V" X' |0 q7 C0 _
pCdev=(void*)*(DWORD*)(*(DWORD*)m_pD3D+0x40);//获得IDirect3D9::CreateDevice的地址指针' }9 s: Y, e, L
2 W5 Q# Q; E" w
        DWORD oldpro=0;4 F# m% ~! L: l2 D
        memcpy(devcen5bytes,pCdev,5);//保存IDirect3D9::CreateDevice入口5个字节
* R' w7 {7 b- }7 W        VirtualProtect(pCdev,5,PAGE_EXECUTE_READWRITE,&oldpro);# u! S! d) [6 X# p1 h3 {4 [
        *(BYTE*)pCdev=0xe9;6 B9 A. o: h: {8 p  T, q7 F
        *(DWORD*)((BYTE*)pCdev+1)=(DWORD)hookedCreateDevice-(DWORD)pCdev-5;8 l) J( b5 n3 p5 v" g: ]

# x! I+ @  {6 B" A+ P在hookedCreateDevice中,首先还原原来的CreateDevice函数入口的5个字节,然后调用原来的函数, IDirect3D9::CreateDevice的最后一个参数是一个二重指针,如果函数调用成功,这个二重指针所指向的指针就是我们所需要的设备对象指针,由此找到设备对象的虚函数表,然后确定IDirect3DDevice9::Present的内存地址,然后又可以改掉入口的5个字节为跳转指令. hookedCreateDevice的关键代码如下:0 }. d* V& f7 t/ W6 X% \# K! _
pPre=(void*)*(DWORD*)(*(DWORD*)m_pDevice+0x44);//获得IDirect3DDevice9::Present的地址指针
$ q) q; B" f7 x        memcpy(pren5bytes,pPre,5);//保存IDirect3DDevice9::Present入口的5个字节
* z7 o/ {7 ?2 v        DWORD oldpro=0;
, O( V) [% ^, G* O  j        VirtualProtect(pPre,5,PAGE_EXECUTE_READWRITE,&oldpro);
1 J* R% ]+ v3 K/ G        *(BYTE*)pPre=0xe9;! {2 R$ f! }) M4 m+ T
        *(DWORD*)((BYTE*)pPre+1)=(DWORD)hookedPresent-(DWORD)pPre-5;9 ^- F  ]2 m1 f. D: Y
) W5 E4 _* A7 m; w2 L+ u/ q& ^
实际上这几个函数的hook都是同样的道理,现在,当程序运行到IDirect3DDevice9::Present后又会跳转到hookedPresent,而我们自己的绘制代码就是放在hookedPresent里面.在执行完自己的绘制代码后再调用原来的IDirect3DDevice9::Present.我的hookedPresent的关键代码如下:
2 U& n) h- N- y4 b' p4 Mchar strdraw[]="The drawing in directx game\nAuthor:RunJin\nEmail:[email protected]";4 h/ x$ v0 _9 T* x, r0 L3 S1 l. H
            DrawMyText(pDxdevice,strdraw,sizeof strdraw-1);//绘制文本% t/ F( l( {% c4 |& ~
            //在这里写入您的其它绘图代码6 z/ n. F% f9 i! r2 c
9 C  g5 U3 a+ q) ^$ [( N1 u

- q; e; F+ c- T) S再来看看其中的DrawMyText,这个函数是我的绘制文本的函数:  P2 S0 l/ n& T
BOOL _stdcall DrawMyText(LPDIRECT3DDEVICE9 pDxdevice,TCHAR* strText ,int nbuf)) l9 t" o( u: i" G" K
{! e) N2 s$ n) \% J/ a( ~. n2 l* e

3 F( {2 v' a9 h. \    if(m_pD3D && pDxdevice){7 M4 A& C; m8 [! @
8 O" T: [$ N2 M2 `* C8 J* \
        RECT myrect;
" J1 _  ~1 D: ~' U        myrect.top=150;  //文本块的y坐标; C) s$ I  a) ^+ u
        myrect.left=0; //文本块的左坐标* P/ p! Z( _+ E& U
        myrect.right=500+myrect.left;
- \6 U4 W% [( P3 c. W! P        myrect.bottom=100+myrect.top;1 c. y4 \* p6 Y! b7 H
        pDxdevice->BeginScene();//开始绘制
- ~; ?1 D. A! I+ U! Z2 Z, g" y5 G
        D3DXFONT_DESCA lf;
% C( m) X6 a5 b! I, Y! T& E5 s3 ?        ZeroMemory(&lf, sizeof(D3DXFONT_DESCA));: B3 d+ n$ u5 J' ~0 M3 r# G: B! \
        lf.Height = 24; //字体高度
, {2 L" i8 f' g' J4 d. o) A        lf.Width = 12; // 字体宽度& M/ h2 D5 K0 c$ d0 h6 H) ?  t
        lf.Weight = 100; ) G- S) w% i& D5 v2 b+ i0 n
        lf.Italic = false;
: p0 A$ X% s; C; [6 Q9 _1 \' B$ V        lf.CharSet = DEFAULT_CHARSET;
& o% X" u" v- `. I  z  Z        strcpy(lf.FaceName, "Times New Roman"); // 字型/ r, q$ ^% {; A, I' c  y! \* Z
        ID3DXFont* font=NULL;; j1 K( `3 h7 l" R
        if(D3D_OK!=D3DXCreateFontIndirect(pDxdevice, &lf, &font)) //创建字体对象
0 O) O, Z0 e4 b2 \& v$ E5 v            return false;2 T8 ]2 H* A8 l2 n' M; Q, Z! S7 X0 v

  ?9 q% i: D" S8 a        font->DrawText(+ e; _: _& W1 D% J  m+ c
            NULL,
4 f- E4 Z, ]- ~* P# l# V            strText, // 要绘制的文本
$ [9 q. h  m1 @. B1 T1 h            nbuf,
* V9 J( \, d3 [& h            &myrect, + q7 v7 m5 [- F" q; Y$ k) ?9 s7 F
            DT_TOP | DT_LEFT, // 字符居左显示
  x( J" ~4 s7 S4 g# u! v            D3DCOLOR_ARGB(255,255,255,0)); ) T, c& b3 d) z) p

6 Z& K0 O+ \- U& E        pDxdevice->EndScene();//结束绘制, B6 \" S$ a* N7 J2 |
        font->Release();//释放对象$ M1 R; V* [/ m) C
    }
! r: L% L. e4 E  e3 b, q/ A    return true;8 J6 e2 n8 j; G; |! L' E* q
}$ [2 ?; l8 d0 l# x& U. J; G/ N
# {9 c" J- d- j- x3 l" X
效果图:8 d( O( x. q, l# e

$ O" M: v5 Y. a% X! U6 h4 h4 I4 l  `
4 d: _( q- k$ l! p% v7 b8 p, b* e9 c4 K9 \, Z
  
! z( A2 v5 T! ~5 C! J; M( L, z4 @7 ]- Q, M' p' u
" E! j! t8 R! T8 C- k+ i/ R
后记: 代码是以前写的,因此文章就按照着代码来讲.然而现在看来,把函数入口点的5个字节改成跳转指令这种hook方法并不是那么好,其实可以直接改掉虚函数表中的函数指针,这样更加的安全保险." J% W0 P: O& A" f, H, @

' x& f) Q% s1 H* k% v& P6 _- e3 O) `+ ^( y4 S. u

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 很美好很美好 很差劲很差劲
回复

使用道具 举报

沙发
发表于 2010-2-11 01:06 | 只看该作者
http://www.codeproject.com/KB/system/Hooking_DirectX_COM.aspx4 ]7 m$ w2 ^6 X4 V

& \5 g- `* y! m9 \, y8 W1 f发一篇希望有帮助
回复 支持 反对

使用道具 举报

板凳
 楼主| 发表于 2010-2-11 07:51 | 只看该作者
引用第1楼byp100于2010-02-11 01:06发表的  :
+ B$ }8 @6 s; X% B  zhttp://www.codeproject.com/KB/system/Hooking_DirectX_COM.aspx
0 f% K: u( {" J% m; ~5 @! u% V: ?$ d3 L" t
发一篇希望有帮助
, J% m" M. m: T" B( E
收到,多谢了,这篇文章我也早就找到过。
5 e5 I) g; }4 [目前就是要研究如何把汉化和hook dx结合起来。
回复 支持 反对

使用道具 举报

地板
 楼主| 发表于 2021-2-13 22:22 | 只看该作者
顶上来
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

冒险解谜游戏中文网 ChinaAVG

官方微博官方微信号小黑屋 微信玩家群  

(C) ChinaAVG 2004 - 2019 All Right Reserved. Powered by Discuz! X3.2
辽ICP备11008827号 | 桂公网安备 45010702000051号

冒险,与你同在。 冒险解谜游戏中文网ChinaAVG诞生于2004年9月9日,是全球华人共同的冒险解谜类游戏家园。我们致力于提供各类冒险游戏资讯供大家学习交流。本站所有资源均不用于商业用途。

快速回复 返回顶部 返回列表