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

汉化工具 HookDx

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

[汉化工具] HookDx

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

HookDx

本帖最后由 shane007 于 2021-2-13 22:23 编辑
" E$ v6 r8 d6 T: ?/ ]  |
8 o8 |% S; P3 J2 p/ S+ s" yDirrectxHook 工具
* h3 X/ ]7 W; w. h' o  E9 B% J0 d2 V
标 题: 【原创】高手莫入 在游戏中显示自己的文字和图形的方法1 U0 I8 ^# i7 t* U; g% ]5 _% ?7 l
作 者: runjin
: ]* \$ I. f5 K时 间: 2009-04-03,23:44) H, ~" m) g' Z3 O
链 接: http://bbs.pediy.com/showthread.php?t=85368+ W3 t: ?7 a! b' O: f- {
7 m; a7 j+ [5 p& J7 |. v' f
Hook Directx:在游戏中显示自己的文字和图形的方法8 n( ?/ s3 ~2 L& y4 t/ H/ Z

. [) I* x  d- Z, Y( x% l4 r  e这个方法出自我大概两年前的一个项目,现在经整理后贴出来和大家分享一下,利用该方法可以在一般的directx游戏里面绘制文本甚至图形对象.8 d% x# u# Q0 B- v) X
其实思路上非常简单,大致是这样的:要在directx中绘制文字和各种图形对象,只要获得一个类型为LPDIRECT3DDEVICE9的设备对象指针.怎样获得这个指针呢?我的方法是首先hook掉Direct3DCreate9以获得类型为LPDIRECT3D9的Direct3D对象的接口指针,这个Direct3D对象有一个成员函数为 IDirect3D9::CreateDevice,设备对象指针就是在这个函数里面创建的.所以,只要根据Direct3D对象接口指针找到Direct3D对象的虚函数表,再根据虚函数表确定IDirect3D9::CreateDevice的内存地址,就可以hook这个函数,从而获得类型为LPDIRECT3DDEVICE9的设备对象指针,然后就可以随意绘制文字或者图形了.; K% k* T4 C8 _6 l' J1 e# p
还有一个要hook的地方,即IDirect3DDevice9::Present,这个函数用于交换当前后备缓存区,刷新窗口.要使得我们自己绘制的东西一直显示在屏幕上,比较好的处理方法是hook掉IDirect3DDevice9::Present,在程序真正调用这个函数前插入我们自己的绘制代码.只要根据设备对象指针找到设备对象的虚函数表,根据虚函数表找到IDirect3DDevice9::Present在内存中的地址就可以hook了.下面是对hook directx的详细说明.
$ w, _) ~' Y4 ^- `首先是找到Direct3DCreate9的内存地址,然后把入口的5个字节修改为跳转指令.$ c' G) b" e$ v; L
    pC=GetProcAddress(GetModuleHandle("d3d9.dll"),"Direct3DCreate9");//获得内存地址
. o: W2 E; b- U$ I* m3 ]    DWORD oldpro=0;
* G, F8 P8 s6 c9 D. }" Q    memcpy(d3dcen5bytes,pC,5);
; u, L7 O- X0 H. r    VirtualProtect(pC,5,PAGE_EXECUTE_READWRITE,&oldpro);0 \! S* a9 H' l( ~5 ~; C
    *(BYTE*)pC=0xe9;//0xe9在汇编中是跳转指令操作码9 ~6 t/ r* g- D4 {9 O: O" b2 D2 R
    *(DWORD*)((BYTE*)pC+1)=(DWORD)hookedDirect3DCreate9-(DWORD)pC-5;//目标地址-原地址-5
( K9 r' M" C& C" q4 o
1 M, F' ]/ z- D! r+ M! g! F9 e0 c: ^  c
这样,在程序运行到Direct3DCreate9时就会跳转到hookedDirect3DCreate9,在这个函数中,首先是还原Direct3DCreate9入口的5个字节,然后调用真正的Direct3DCreate9,如果函数调用成功,就会返回类型为LPDIRECT3D9的Direct3D对象指针,这正是我们所需要的,得到这个指针后,就可以根据Direct3D对象的虚函数表确定IDirect3D9::CreateDevice的内存地址,然后就可以把这个函数入口的5个字节修改成为跳转指令,跳到我们自己的函数中去. 有个地方值得注意的是,在directx的虚函数中把this指针作为第一个形参入栈了.例如说sdk中IDirect3D9::CreateDevice的函数说明是这样:! q. l3 ]6 p8 Z
HRESULT CreateDevice(4 ?7 E* Z* l' w5 c
  UINT Adapter,6 m9 R: r+ M  B; I0 k
  D3DDEVTYPE DeviceType,
: \' X3 G5 Z3 Y  HWND hFocusWindow,
, s( G3 N+ n  \* L4 b- U  DWORD BehaviorFlags,
+ `: B( H# T: l+ h7 C0 V6 H. n  D3DPRESENT_PARAMETERS * pPresentationParameters,
" @3 B# k# g+ X* n2 g4 q  IDirect3DDevice9 ** ppReturnedDeviceInterface
/ ^3 S+ B* ?. n9 B4 b. A0 y);
- O# c# X! a1 {, ?3 f6 H& y. K# Y+ G. w1 Y7 F$ y
0 T# y" G: v6 {; m# f( o
而为了程序跳转到我们的代码执行完后保持栈的平衡,hookedDirect3DCreat9函数声明应该是这样:' ~& ?& s8 @- }' e6 q) r
HRESULT _stdcall hookedCreateDevice(
" k2 ?; b, n$ f' X+ }% _                                  LPDIRECT3D9 pDx9,
0 u  I: s  \8 X- c                                  UINT Adapter,
3 d9 [3 o3 h/ [! I  e9 ^; |! h                                  D3DDEVTYPE DeviceType,
9 S  p4 e- i5 N9 A* m                                  HWND hFocusWindow,
7 k3 \, e8 D7 r, J$ J! h! K9 E! p! F                                  DWORD BehaviorFlags,
) g8 P3 q8 I* E, t                                  D3DPRESENT_PARAMETERS * pPresentationParameters,
9 |( b3 Z( N$ c% J                                  IDirect3DDevice9 ** ppReturnedDeviceInterface& F  B7 B; m- i

3 E9 g8 {! h3 y8 e8 w6 ]0 `& a                                  );
$ ?+ l% _4 U5 i8 t' ^) k* ]
) i1 Y) S  b. `4 P其中的LPDIRECT3D9 pDx9就是this指针.
# p. |9 ^* [4 Q5 A, w
- J, ?; r  a0 p/ u( RhookedDirect3DCreate9的关键代码如下:
0 i% ^3 u% w' d  F" X' `3 [$ wpCdev=(void*)*(DWORD*)(*(DWORD*)m_pD3D+0x40);//获得IDirect3D9::CreateDevice的地址指针
# \: X' x- \( T# G2 S& H
: }; B* O: ]7 x        DWORD oldpro=0;
# E. K$ I9 H& X5 o) z+ i+ v        memcpy(devcen5bytes,pCdev,5);//保存IDirect3D9::CreateDevice入口5个字节5 `! t( x: G2 U& W
        VirtualProtect(pCdev,5,PAGE_EXECUTE_READWRITE,&oldpro);9 }6 r1 B, P+ O+ l0 H9 n2 O' t6 q8 d
        *(BYTE*)pCdev=0xe9;
# }* M4 X, c" u; G        *(DWORD*)((BYTE*)pCdev+1)=(DWORD)hookedCreateDevice-(DWORD)pCdev-5;
0 J1 w1 B! O4 [, g! H+ V! m5 g; S0 e8 E
在hookedCreateDevice中,首先还原原来的CreateDevice函数入口的5个字节,然后调用原来的函数, IDirect3D9::CreateDevice的最后一个参数是一个二重指针,如果函数调用成功,这个二重指针所指向的指针就是我们所需要的设备对象指针,由此找到设备对象的虚函数表,然后确定IDirect3DDevice9::Present的内存地址,然后又可以改掉入口的5个字节为跳转指令. hookedCreateDevice的关键代码如下:( v4 I4 I5 ^9 n" ~) R3 }, h4 B
pPre=(void*)*(DWORD*)(*(DWORD*)m_pDevice+0x44);//获得IDirect3DDevice9::Present的地址指针
7 ?2 s8 {5 p* k* N8 J6 e        memcpy(pren5bytes,pPre,5);//保存IDirect3DDevice9::Present入口的5个字节
: Y0 y" ^8 @' u3 A        DWORD oldpro=0;
' G- Q& }5 J/ ^% @0 @. ~: \        VirtualProtect(pPre,5,PAGE_EXECUTE_READWRITE,&oldpro);$ `( {& K2 v: b( R- Y
        *(BYTE*)pPre=0xe9;9 q' Q' m; v; A  g$ f  q! \! U
        *(DWORD*)((BYTE*)pPre+1)=(DWORD)hookedPresent-(DWORD)pPre-5;
1 G% D( u4 {3 d0 \, d' K
: V2 ^% l/ l6 m4 c* @3 B. z+ d实际上这几个函数的hook都是同样的道理,现在,当程序运行到IDirect3DDevice9::Present后又会跳转到hookedPresent,而我们自己的绘制代码就是放在hookedPresent里面.在执行完自己的绘制代码后再调用原来的IDirect3DDevice9::Present.我的hookedPresent的关键代码如下:
8 {% Q# J! \* O# Mchar strdraw[]="The drawing in directx game\nAuthor:RunJin\nEmail:[email protected]";
' }% J% y" T! ]* {- p' A0 D$ v            DrawMyText(pDxdevice,strdraw,sizeof strdraw-1);//绘制文本
/ [7 x$ k7 O  i7 C            //在这里写入您的其它绘图代码( B% p( C( y1 t5 ]

4 p$ K9 N& N& Y: i" L7 Y# a' a: i
- R5 W7 ?& U9 A3 L3 s: ~4 ?: T: n再来看看其中的DrawMyText,这个函数是我的绘制文本的函数:
( p9 k$ O; q6 ~' JBOOL _stdcall DrawMyText(LPDIRECT3DDEVICE9 pDxdevice,TCHAR* strText ,int nbuf)
% c" a3 W8 @& y$ e- s& s9 n{3 F: |9 V; n8 w

* f5 [) U+ [' c4 G% H& C    if(m_pD3D && pDxdevice){* U# t, Z; U3 |, g1 v

% J) _+ E6 l* s# K1 c8 P! n  F7 n  b        RECT myrect;
  j  X( X# Y8 Z. x  k. B3 T5 L        myrect.top=150;  //文本块的y坐标' t( i! X* w, C" n! c
        myrect.left=0; //文本块的左坐标, |/ g+ M& c; W1 p0 X6 B
        myrect.right=500+myrect.left;+ N8 J& z5 ]( q5 X2 _& v1 J
        myrect.bottom=100+myrect.top;
# s$ B( j: L4 {9 {6 X- \3 ^        pDxdevice->BeginScene();//开始绘制
" x; y; y1 {1 W! G4 N' Y6 i: q: g. y$ C" X; ~/ A$ h7 |0 I# x
        D3DXFONT_DESCA lf;8 M3 e, w. V4 z
        ZeroMemory(&lf, sizeof(D3DXFONT_DESCA));
- B0 A, \9 n) L" o/ @1 \% o9 S        lf.Height = 24; //字体高度
0 r4 T+ u7 {% H. S$ |' {        lf.Width = 12; // 字体宽度
+ X7 d; h1 R6 U7 S# `$ Z        lf.Weight = 100; ! D- r! x! |6 x; w  T$ O* F# N) G
        lf.Italic = false;
& D  ]0 b" [: s! y7 x( ~        lf.CharSet = DEFAULT_CHARSET;! C% t+ s' j/ `1 P
        strcpy(lf.FaceName, "Times New Roman"); // 字型
; R3 {9 T- r* ^; F        ID3DXFont* font=NULL;! K( F$ \2 X: E6 y' n) c
        if(D3D_OK!=D3DXCreateFontIndirect(pDxdevice, &lf, &font)) //创建字体对象% ]5 N: p" o  S# n/ r6 g! y
            return false;, C& a$ t, m2 H  K' V9 ]

/ P- S; d. Z3 A" {  X        font->DrawText() d3 e/ Q7 ?& |8 |
            NULL,0 G$ _% w9 i- N" B/ X" G' Q5 D: W
            strText, // 要绘制的文本9 R. W; ]; S/ G) @& `6 s/ y1 B
            nbuf,
; t" @/ ]9 v! S  i! l; s% U            &myrect,
# T5 a& S  [+ B, y3 z( Y# k  E7 q            DT_TOP | DT_LEFT, // 字符居左显示7 W/ Y* ?, u3 ]4 D
            D3DCOLOR_ARGB(255,255,255,0));
$ D5 u# }4 [& g' p
, k3 d0 U, ]  R1 [) G  M        pDxdevice->EndScene();//结束绘制
$ j3 e+ N" z5 @: _* J" B- B6 c        font->Release();//释放对象# V( _" b; Q8 u9 G' |1 s  P4 y$ q% m
    }& ?1 ^- [; L( A  g
    return true;
+ @8 O2 ~- N" k3 V% G}
* z! R% ]& o( B$ k: c8 b% L( w; b9 Z" ?+ ?* J8 }
效果图:
! l' R9 a* p6 D& F9 j% n# E ' ?( C6 {9 K  [2 D# d7 Y- W
- S8 n% [7 `3 P: l$ u/ l1 V+ ~
3 s9 ]& K2 d/ K
  
* b6 U' k' [; @5 q" [  S" b* r) d) j/ a2 W' L7 b9 ]7 t

6 }! r" S& z" {& J) q后记: 代码是以前写的,因此文章就按照着代码来讲.然而现在看来,把函数入口点的5个字节改成跳转指令这种hook方法并不是那么好,其实可以直接改掉虚函数表中的函数指针,这样更加的安全保险.# `3 u! G8 ]  _! m! ]; _# c% g
* \9 Q6 g$ l% c
8 K; v  j2 K" L3 y. S

本帖子中包含更多资源

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

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

使用道具 举报

沙发
发表于 2010-2-11 01:06 | 只看该作者
http://www.codeproject.com/KB/system/Hooking_DirectX_COM.aspx
* i; ?5 e. @4 ^
1 M2 v  x3 G6 l/ D& }! C发一篇希望有帮助
回复 支持 反对

使用道具 举报

板凳
 楼主| 发表于 2010-2-11 07:51 | 只看该作者
引用第1楼byp100于2010-02-11 01:06发表的  :/ l- K! [& L7 w9 A* h/ P  t
http://www.codeproject.com/KB/system/Hooking_DirectX_COM.aspx1 p0 c7 H3 f; {8 T* g6 V2 `& {: E; k
7 j' J' c! r; F2 X; q. w
发一篇希望有帮助
" h* f, E& p, A( f: Z) \* V  `% E; k
收到,多谢了,这篇文章我也早就找到过。4 a4 m& K, J0 ?0 S2 C7 Y. F3 k8 ~/ T
目前就是要研究如何把汉化和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日,是全球华人共同的冒险解谜类游戏家园。我们致力于提供各类冒险游戏资讯供大家学习交流。本站所有资源均不用于商业用途。

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