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

汉化工具 HookDx

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

[汉化工具] HookDx

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

HookDx

本帖最后由 shane007 于 2021-2-13 22:23 编辑 - Z, d# M0 Q* |' D: P2 P& u

( C4 B, I* }1 T0 w, ^DirrectxHook 工具
# i) Q/ {; a) a" i, @( b9 |' A/ b9 [# C8 V
标 题: 【原创】高手莫入 在游戏中显示自己的文字和图形的方法
1 B1 p- j0 M1 R) Q0 a% V' a+ s9 n作 者: runjin4 ?( I, a1 y+ Z( r1 M% y
时 间: 2009-04-03,23:44% g" G/ P( }4 W1 t: p6 v8 I
链 接: http://bbs.pediy.com/showthread.php?t=853688 S+ i5 A+ r2 t+ r% r. O7 D8 I

$ Z9 s4 H: _1 X* x6 G: YHook Directx:在游戏中显示自己的文字和图形的方法
4 z7 x. a- r- V: P' h6 V; t7 T! [  S+ d6 P$ b
这个方法出自我大概两年前的一个项目,现在经整理后贴出来和大家分享一下,利用该方法可以在一般的directx游戏里面绘制文本甚至图形对象.. R; Y+ r, E# ?3 V
其实思路上非常简单,大致是这样的:要在directx中绘制文字和各种图形对象,只要获得一个类型为LPDIRECT3DDEVICE9的设备对象指针.怎样获得这个指针呢?我的方法是首先hook掉Direct3DCreate9以获得类型为LPDIRECT3D9的Direct3D对象的接口指针,这个Direct3D对象有一个成员函数为 IDirect3D9::CreateDevice,设备对象指针就是在这个函数里面创建的.所以,只要根据Direct3D对象接口指针找到Direct3D对象的虚函数表,再根据虚函数表确定IDirect3D9::CreateDevice的内存地址,就可以hook这个函数,从而获得类型为LPDIRECT3DDEVICE9的设备对象指针,然后就可以随意绘制文字或者图形了.
5 ]% q  h0 U$ w$ U2 N还有一个要hook的地方,即IDirect3DDevice9::Present,这个函数用于交换当前后备缓存区,刷新窗口.要使得我们自己绘制的东西一直显示在屏幕上,比较好的处理方法是hook掉IDirect3DDevice9::Present,在程序真正调用这个函数前插入我们自己的绘制代码.只要根据设备对象指针找到设备对象的虚函数表,根据虚函数表找到IDirect3DDevice9::Present在内存中的地址就可以hook了.下面是对hook directx的详细说明.
- j/ r$ ?: N- e7 s首先是找到Direct3DCreate9的内存地址,然后把入口的5个字节修改为跳转指令.$ \2 V! U' Y( A( I& M9 u  N1 n3 J
    pC=GetProcAddress(GetModuleHandle("d3d9.dll"),"Direct3DCreate9");//获得内存地址) ?; n7 ~) `1 ^$ [. s9 s& x5 C
    DWORD oldpro=0;* X2 A9 P4 h# r6 d, ]+ K2 r1 D' d
    memcpy(d3dcen5bytes,pC,5);
, c, ?& n8 K$ L# u) f& I    VirtualProtect(pC,5,PAGE_EXECUTE_READWRITE,&oldpro);" D- S* i& @7 s  r; a3 e
    *(BYTE*)pC=0xe9;//0xe9在汇编中是跳转指令操作码: V" ]4 X; G# D' J0 i
    *(DWORD*)((BYTE*)pC+1)=(DWORD)hookedDirect3DCreate9-(DWORD)pC-5;//目标地址-原地址-5- m* f) p+ d- N

, x6 X+ {! D: T8 W/ M7 Y8 u, d6 X( W- a2 i
这样,在程序运行到Direct3DCreate9时就会跳转到hookedDirect3DCreate9,在这个函数中,首先是还原Direct3DCreate9入口的5个字节,然后调用真正的Direct3DCreate9,如果函数调用成功,就会返回类型为LPDIRECT3D9的Direct3D对象指针,这正是我们所需要的,得到这个指针后,就可以根据Direct3D对象的虚函数表确定IDirect3D9::CreateDevice的内存地址,然后就可以把这个函数入口的5个字节修改成为跳转指令,跳到我们自己的函数中去. 有个地方值得注意的是,在directx的虚函数中把this指针作为第一个形参入栈了.例如说sdk中IDirect3D9::CreateDevice的函数说明是这样:
+ f5 P$ M# [" g' [# A9 i* o: [HRESULT CreateDevice(/ F7 b- G" g7 j: G
  UINT Adapter,0 P( B% i: N0 v; R" L% N% z. @
  D3DDEVTYPE DeviceType,
/ z# L6 n' [2 E5 j1 Z; N! d5 N  HWND hFocusWindow,1 Z& ~3 H& |! A& Q; F
  DWORD BehaviorFlags,
. C/ F9 ^7 s3 Z0 R* I  D3DPRESENT_PARAMETERS * pPresentationParameters,
2 y9 ]- }$ M- B; B  IDirect3DDevice9 ** ppReturnedDeviceInterface
6 p- }  j. x" B1 x2 W/ e( W8 ~);
) c' L6 r( ~4 \( J" N
- o) L! s: O& C+ r( ]* |* o9 U7 \! T0 u9 F1 ^
而为了程序跳转到我们的代码执行完后保持栈的平衡,hookedDirect3DCreat9函数声明应该是这样:
9 v1 u1 }7 ?/ t7 S! WHRESULT _stdcall hookedCreateDevice(+ y' }( H. v% A/ r# B
                                  LPDIRECT3D9 pDx9,
0 e7 A2 v9 F4 B5 P                                  UINT Adapter,+ m4 w) x+ \) T6 j" d3 T  @9 T
                                  D3DDEVTYPE DeviceType,
2 L/ w" ]6 i) k0 B                                  HWND hFocusWindow,
5 y! J/ P2 ~3 d: B# }# {2 @                                  DWORD BehaviorFlags,, V8 W) M; c: o; D3 s/ K
                                  D3DPRESENT_PARAMETERS * pPresentationParameters,  K  P6 g# L' B# D
                                  IDirect3DDevice9 ** ppReturnedDeviceInterface
$ M5 O' R/ [6 K! t0 Y! @5 w0 b8 {( M& Y& f3 n- C
                                  );' ]- o4 r$ N( H# _2 l6 d
5 e2 \6 K9 \1 V4 ]! w! k
其中的LPDIRECT3D9 pDx9就是this指针.7 S/ G, I8 m8 \

, ]" a5 Y0 n% m8 @7 n: V( z2 g) j( m- khookedDirect3DCreate9的关键代码如下:
' C9 |+ ^* z; u& ^" ^pCdev=(void*)*(DWORD*)(*(DWORD*)m_pD3D+0x40);//获得IDirect3D9::CreateDevice的地址指针! Q) l# }( ~6 W5 N6 J$ n

( n8 w4 e/ I/ {1 G        DWORD oldpro=0;
7 `. F  O2 C8 @3 k7 C+ ?8 k        memcpy(devcen5bytes,pCdev,5);//保存IDirect3D9::CreateDevice入口5个字节5 L4 _- R* O1 E
        VirtualProtect(pCdev,5,PAGE_EXECUTE_READWRITE,&oldpro);. p; X( _6 n, B! C6 }
        *(BYTE*)pCdev=0xe9;
! N0 _' ~1 F/ {  v6 M5 ?        *(DWORD*)((BYTE*)pCdev+1)=(DWORD)hookedCreateDevice-(DWORD)pCdev-5;
( f3 X& M! L* S: x  z" d% E$ |6 X2 G
" z  x0 A( `$ ?$ @3 ^在hookedCreateDevice中,首先还原原来的CreateDevice函数入口的5个字节,然后调用原来的函数, IDirect3D9::CreateDevice的最后一个参数是一个二重指针,如果函数调用成功,这个二重指针所指向的指针就是我们所需要的设备对象指针,由此找到设备对象的虚函数表,然后确定IDirect3DDevice9::Present的内存地址,然后又可以改掉入口的5个字节为跳转指令. hookedCreateDevice的关键代码如下:$ I( r: n/ l5 I  R5 Q  r2 X
pPre=(void*)*(DWORD*)(*(DWORD*)m_pDevice+0x44);//获得IDirect3DDevice9::Present的地址指针
4 }( P+ J* \' s+ a  m. ~        memcpy(pren5bytes,pPre,5);//保存IDirect3DDevice9::Present入口的5个字节, ^: u- A$ O  V4 r* b
        DWORD oldpro=0;8 D6 G0 @: H8 A9 J8 W& d
        VirtualProtect(pPre,5,PAGE_EXECUTE_READWRITE,&oldpro);! |8 H2 G; j, v" C. X% N! p5 K
        *(BYTE*)pPre=0xe9;' U2 U7 d) r6 c$ p% c, K# b! v: p
        *(DWORD*)((BYTE*)pPre+1)=(DWORD)hookedPresent-(DWORD)pPre-5;
5 k* i8 d1 Q) Y9 z3 u* K. h) x9 l+ z' M  C' S# e* D4 {  E
实际上这几个函数的hook都是同样的道理,现在,当程序运行到IDirect3DDevice9::Present后又会跳转到hookedPresent,而我们自己的绘制代码就是放在hookedPresent里面.在执行完自己的绘制代码后再调用原来的IDirect3DDevice9::Present.我的hookedPresent的关键代码如下:
% Z6 Z# x* n5 Uchar strdraw[]="The drawing in directx game\nAuthor:RunJin\nEmail:[email protected]";+ `* P* ^3 W" l) u; z1 o
            DrawMyText(pDxdevice,strdraw,sizeof strdraw-1);//绘制文本. |' R: A3 S/ j& P1 y
            //在这里写入您的其它绘图代码8 F2 P, j3 V' t

8 D) m/ ^; o, y7 U; _: o
$ T8 P8 }# @: |) Z( }4 S+ U1 [再来看看其中的DrawMyText,这个函数是我的绘制文本的函数:
" g! |$ m, K' ~9 n5 F2 [BOOL _stdcall DrawMyText(LPDIRECT3DDEVICE9 pDxdevice,TCHAR* strText ,int nbuf)% _9 b* m2 X2 r' f$ ?. O) {. r1 m
{
0 U( z+ f# _8 P7 i0 }0 T3 c' j  _+ \- G: j2 G0 `7 o9 S4 `, i
    if(m_pD3D && pDxdevice){' Z9 n9 F+ g6 d5 p& u9 d
4 Z( [7 T7 b7 Z- x
        RECT myrect;1 W7 m* g' `& I/ `# }4 W: _1 v
        myrect.top=150;  //文本块的y坐标
, x/ B9 Y; h9 [" D        myrect.left=0; //文本块的左坐标" v3 M- T& V0 \& J$ p$ ^1 d
        myrect.right=500+myrect.left;, X, K( {% g1 e- X/ O3 k% _
        myrect.bottom=100+myrect.top;$ q8 \& W' d- `- h/ ?/ l* K" F
        pDxdevice->BeginScene();//开始绘制
  z0 Q* e$ `/ V! Z
8 l9 I( h8 Q9 h0 w        D3DXFONT_DESCA lf;, o1 i; k5 O9 o2 e
        ZeroMemory(&lf, sizeof(D3DXFONT_DESCA));
5 P# p: c1 |* F& R        lf.Height = 24; //字体高度
1 i6 o. O, U7 W& s$ k1 X        lf.Width = 12; // 字体宽度
( n2 Z5 A8 z5 y/ y, h" k7 P        lf.Weight = 100;
- h, E3 |) ~9 S        lf.Italic = false;
  s0 Z1 g& V8 z2 ?* E        lf.CharSet = DEFAULT_CHARSET;! T- H" U, F, T2 ?  Y4 ~) _( ?
        strcpy(lf.FaceName, "Times New Roman"); // 字型
$ y% E, v7 E  X, `        ID3DXFont* font=NULL;
- E" f1 X5 Z* Y  H3 A4 f0 v- X3 e  [; ?        if(D3D_OK!=D3DXCreateFontIndirect(pDxdevice, &lf, &font)) //创建字体对象8 f' h% Q' Z; z! w) i
            return false;
) ~/ M" b2 ~. @; p& {) g; C5 J# g2 f
        font->DrawText(. p* v4 s* q# @/ _% J3 y% a
            NULL,' c( Z! F; k4 u. n, a
            strText, // 要绘制的文本
- g# F9 F$ j; w) E* U: W: Z$ c            nbuf,
5 n7 x2 C% F* P3 \            &myrect, 8 y& }2 E9 D7 d" l, o: T; ~
            DT_TOP | DT_LEFT, // 字符居左显示9 t  n3 ]( F" L& C5 [! O
            D3DCOLOR_ARGB(255,255,255,0));
: O6 M5 x0 k7 ~: `  j% W  f, s* k$ j/ v' M, t' V
        pDxdevice->EndScene();//结束绘制' F) M: x% g! p1 H7 ]3 |1 z; C
        font->Release();//释放对象  U. v5 z' L% }) |- M
    }+ l% y9 P4 o( Q( u* X! O
    return true;# ~  W+ r1 V* Y# M2 \. X6 M  C
}
. k9 Y. A$ _" f
% C+ A& i2 v9 P0 Y0 ~. y( W效果图:; S/ M: v% u& X

/ p% {3 D  N$ y' y1 O
: \; @9 t! O; }$ s; A- `% U1 Z& _* p8 M* C' y; c% t+ q
  3 `( W! W+ r$ j2 Q; s

3 [. s2 |, p' r( e: ^; i: i! }1 U. f: E) i& I" p' _5 D
后记: 代码是以前写的,因此文章就按照着代码来讲.然而现在看来,把函数入口点的5个字节改成跳转指令这种hook方法并不是那么好,其实可以直接改掉虚函数表中的函数指针,这样更加的安全保险.8 j/ N& q* R* C. b

; W- a) E* |" Z: K9 \* g0 w$ N* l& P8 ^  C" l

本帖子中包含更多资源

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

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

使用道具 举报

沙发
发表于 2010-2-11 01:06 | 只看该作者
http://www.codeproject.com/KB/system/Hooking_DirectX_COM.aspx
9 I2 a* T* F1 O( _( Z3 u% K+ e! N8 Y/ N2 G/ k6 E% _' T" X
发一篇希望有帮助
回复 支持 反对

使用道具 举报

板凳
 楼主| 发表于 2010-2-11 07:51 | 只看该作者
引用第1楼byp100于2010-02-11 01:06发表的  :
; \, G3 {+ ^6 N' J8 u7 J& ^http://www.codeproject.com/KB/system/Hooking_DirectX_COM.aspx+ b5 P6 D5 f# z5 G) o

1 h( ^% q+ W$ Y) w5 A4 k9 x发一篇希望有帮助
' i& m" W. K' a$ _% H% F
收到,多谢了,这篇文章我也早就找到过。
& I; O: ?* D) r; X目前就是要研究如何把汉化和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日,是全球华人共同的冒险解谜类游戏家园。我们致力于提供各类冒险游戏资讯供大家学习交流。本站所有资源均不用于商业用途。

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