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

汉化工具 HookDx

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

[汉化工具] HookDx

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

HookDx

本帖最后由 shane007 于 2021-2-13 22:23 编辑 # i/ Y. Q  K6 b, p

  L0 F, k8 m; s, g3 d; ^5 jDirrectxHook 工具/ g! W/ f% ^8 o7 ~0 e, c
) d- S6 m3 I$ k
标 题: 【原创】高手莫入 在游戏中显示自己的文字和图形的方法
4 G8 C) u; @) J作 者: runjin  B# _- c1 f7 M; ?
时 间: 2009-04-03,23:44
) S9 u0 I" V7 {/ t( E6 E链 接: http://bbs.pediy.com/showthread.php?t=85368
3 G& L) k  I" Z  }' K1 i4 j- G
7 B! M1 {7 L, |* Q- u' O- \+ MHook Directx:在游戏中显示自己的文字和图形的方法$ q* Z& P" u* m3 ?, C  |8 T/ l
/ k& P, c6 c5 R6 L' c3 l% J
这个方法出自我大概两年前的一个项目,现在经整理后贴出来和大家分享一下,利用该方法可以在一般的directx游戏里面绘制文本甚至图形对象.
: S  ]* B7 z5 z% _其实思路上非常简单,大致是这样的:要在directx中绘制文字和各种图形对象,只要获得一个类型为LPDIRECT3DDEVICE9的设备对象指针.怎样获得这个指针呢?我的方法是首先hook掉Direct3DCreate9以获得类型为LPDIRECT3D9的Direct3D对象的接口指针,这个Direct3D对象有一个成员函数为 IDirect3D9::CreateDevice,设备对象指针就是在这个函数里面创建的.所以,只要根据Direct3D对象接口指针找到Direct3D对象的虚函数表,再根据虚函数表确定IDirect3D9::CreateDevice的内存地址,就可以hook这个函数,从而获得类型为LPDIRECT3DDEVICE9的设备对象指针,然后就可以随意绘制文字或者图形了.
% `# t) M3 B, b& V# o3 Q+ }还有一个要hook的地方,即IDirect3DDevice9::Present,这个函数用于交换当前后备缓存区,刷新窗口.要使得我们自己绘制的东西一直显示在屏幕上,比较好的处理方法是hook掉IDirect3DDevice9::Present,在程序真正调用这个函数前插入我们自己的绘制代码.只要根据设备对象指针找到设备对象的虚函数表,根据虚函数表找到IDirect3DDevice9::Present在内存中的地址就可以hook了.下面是对hook directx的详细说明.4 x9 x$ [* ]& f8 ?
首先是找到Direct3DCreate9的内存地址,然后把入口的5个字节修改为跳转指令.2 |/ ~9 H" g2 F9 C" p
    pC=GetProcAddress(GetModuleHandle("d3d9.dll"),"Direct3DCreate9");//获得内存地址# W( ^/ R" [7 Q( `: e% O0 O
    DWORD oldpro=0;
9 p6 `! O; X5 W    memcpy(d3dcen5bytes,pC,5);
$ K" g1 j: f; L% T6 J/ Y    VirtualProtect(pC,5,PAGE_EXECUTE_READWRITE,&oldpro);
! l9 O$ ~- h9 D& Z+ [. W, D  `    *(BYTE*)pC=0xe9;//0xe9在汇编中是跳转指令操作码
) Z- \/ J2 K% A6 H9 Y! k1 y    *(DWORD*)((BYTE*)pC+1)=(DWORD)hookedDirect3DCreate9-(DWORD)pC-5;//目标地址-原地址-5
) a- A) \3 A# k4 _0 M  x  O% T. Z7 R
/ ^  e) D: ~5 j1 h7 Q; k- y" |  L$ {
这样,在程序运行到Direct3DCreate9时就会跳转到hookedDirect3DCreate9,在这个函数中,首先是还原Direct3DCreate9入口的5个字节,然后调用真正的Direct3DCreate9,如果函数调用成功,就会返回类型为LPDIRECT3D9的Direct3D对象指针,这正是我们所需要的,得到这个指针后,就可以根据Direct3D对象的虚函数表确定IDirect3D9::CreateDevice的内存地址,然后就可以把这个函数入口的5个字节修改成为跳转指令,跳到我们自己的函数中去. 有个地方值得注意的是,在directx的虚函数中把this指针作为第一个形参入栈了.例如说sdk中IDirect3D9::CreateDevice的函数说明是这样:
! c) Q0 n  o3 fHRESULT CreateDevice(& ?9 w" m  b% Y" Y8 C
  UINT Adapter,2 M7 e/ O/ ?; @
  D3DDEVTYPE DeviceType,
; `' u$ b5 S: g  }& [/ y- L  HWND hFocusWindow,
9 W5 n4 f& ]# f, |8 ?# b( \  DWORD BehaviorFlags,2 [! ^; {' a) I7 y. `3 c2 z
  D3DPRESENT_PARAMETERS * pPresentationParameters,$ K# e' A/ ]+ U* @
  IDirect3DDevice9 ** ppReturnedDeviceInterface, U, N, D( b* K) ^" M+ l2 r* [; r
);
0 Q8 s# Q: Z" V- N4 z
/ E+ ?2 L2 z( @0 ^! K- I# q
' ~: L6 \% b. p" ]1 X: U而为了程序跳转到我们的代码执行完后保持栈的平衡,hookedDirect3DCreat9函数声明应该是这样:
# d0 r, p  Q9 a- f: l7 {3 FHRESULT _stdcall hookedCreateDevice(
1 ~" B6 n. |$ g7 F                                  LPDIRECT3D9 pDx9,4 p+ X& t6 {$ z! M5 B) \
                                  UINT Adapter,: \( r' }0 Z9 s  a; x4 q" z
                                  D3DDEVTYPE DeviceType,
" D. p& U  O, [* @+ i                                  HWND hFocusWindow,
8 n7 x8 ]- P/ {8 A                                  DWORD BehaviorFlags,
. K2 m: I( z& _. Y" J                                  D3DPRESENT_PARAMETERS * pPresentationParameters,
8 G# u. e) g4 l                                  IDirect3DDevice9 ** ppReturnedDeviceInterface& `1 ]! }2 |+ R9 f3 J2 e

, J0 o8 I9 j) |5 }, H4 c; s* z                                  );- @6 R# a) c" C0 V# Z4 ^+ Y+ p1 d

; c: F* z8 C# a! C( c其中的LPDIRECT3D9 pDx9就是this指针.$ _0 a: s; p6 ?$ d4 G5 o$ u

7 b3 \3 O: H* ?7 O5 EhookedDirect3DCreate9的关键代码如下:7 S/ n/ ]3 D3 c8 B
pCdev=(void*)*(DWORD*)(*(DWORD*)m_pD3D+0x40);//获得IDirect3D9::CreateDevice的地址指针
- Q- Q2 w, [% @$ k4 l- ]" q
- g$ A" I4 F, h0 M' `" I9 S9 _9 Y        DWORD oldpro=0;
* f7 z" V% Z2 N1 ~/ x        memcpy(devcen5bytes,pCdev,5);//保存IDirect3D9::CreateDevice入口5个字节
3 o! K1 w6 f$ x/ b        VirtualProtect(pCdev,5,PAGE_EXECUTE_READWRITE,&oldpro);
& L( K7 F+ w9 E5 `& s        *(BYTE*)pCdev=0xe9;( V( h+ [- `4 ^) i' B
        *(DWORD*)((BYTE*)pCdev+1)=(DWORD)hookedCreateDevice-(DWORD)pCdev-5;
8 I% I4 f3 k# B# _( \2 f; I
6 ~2 x$ I! c% ~; _: G& J& }在hookedCreateDevice中,首先还原原来的CreateDevice函数入口的5个字节,然后调用原来的函数, IDirect3D9::CreateDevice的最后一个参数是一个二重指针,如果函数调用成功,这个二重指针所指向的指针就是我们所需要的设备对象指针,由此找到设备对象的虚函数表,然后确定IDirect3DDevice9::Present的内存地址,然后又可以改掉入口的5个字节为跳转指令. hookedCreateDevice的关键代码如下:
* V, C2 p& F5 O$ d: FpPre=(void*)*(DWORD*)(*(DWORD*)m_pDevice+0x44);//获得IDirect3DDevice9::Present的地址指针' i& y; U2 M5 G0 h6 y/ \$ o/ D
        memcpy(pren5bytes,pPre,5);//保存IDirect3DDevice9::Present入口的5个字节
. O8 e7 S# ^3 C! N  V3 q' O        DWORD oldpro=0;
& r# P( p. w% \: S        VirtualProtect(pPre,5,PAGE_EXECUTE_READWRITE,&oldpro);
) F3 m7 n6 d8 y, w        *(BYTE*)pPre=0xe9;& L! O0 T: z* m+ f* S
        *(DWORD*)((BYTE*)pPre+1)=(DWORD)hookedPresent-(DWORD)pPre-5;& G- H0 t' f  g7 `% o& o

; |. K' F$ W7 b+ `$ v实际上这几个函数的hook都是同样的道理,现在,当程序运行到IDirect3DDevice9::Present后又会跳转到hookedPresent,而我们自己的绘制代码就是放在hookedPresent里面.在执行完自己的绘制代码后再调用原来的IDirect3DDevice9::Present.我的hookedPresent的关键代码如下:6 F+ v7 R3 P( J( F9 t
char strdraw[]="The drawing in directx game\nAuthor:RunJin\nEmail:[email protected]";
4 x# Z1 _% v8 }4 l; z            DrawMyText(pDxdevice,strdraw,sizeof strdraw-1);//绘制文本
# A2 o+ ]8 w6 }+ \            //在这里写入您的其它绘图代码
# B& Y* @9 ^  ]9 m; U- U; |% v
# k8 T& R6 N" }  C4 w0 M+ s4 E! H6 L4 U1 `  y6 T+ z
再来看看其中的DrawMyText,这个函数是我的绘制文本的函数:
. k7 v/ U2 [2 N" pBOOL _stdcall DrawMyText(LPDIRECT3DDEVICE9 pDxdevice,TCHAR* strText ,int nbuf)# E$ P$ M  N7 p4 t; \
{
5 B& O7 I/ |6 |  T, Y1 F( K; m
% t1 H- O* M! O0 t3 t1 A0 `1 V    if(m_pD3D && pDxdevice){
, f) S  f$ u8 m; b. E/ m1 V, a; q8 |1 c% d; @* N, u1 H5 p9 T
        RECT myrect;
& B3 m5 k  o; v  J& f2 X        myrect.top=150;  //文本块的y坐标
$ v2 g% z. ]2 c5 s, I3 t        myrect.left=0; //文本块的左坐标
8 |  \2 w( I, A2 f7 f0 P, d        myrect.right=500+myrect.left;9 }/ u$ j9 s' [! \( W, }, k
        myrect.bottom=100+myrect.top;( M' [$ f4 y0 H( t
        pDxdevice->BeginScene();//开始绘制8 d  B3 |) }: R* X6 B6 o& l: V

5 K% S; S: I8 K  q- k5 H        D3DXFONT_DESCA lf;5 j& G, H- u! t
        ZeroMemory(&lf, sizeof(D3DXFONT_DESCA));# F* D- u+ I- S# M8 o
        lf.Height = 24; //字体高度" K. l9 D* u, G( ?4 p- S
        lf.Width = 12; // 字体宽度
) U( X; H4 `! B0 M        lf.Weight = 100; " _* b" t+ L3 \# _7 u
        lf.Italic = false;
- L+ L9 }# x# `3 s. [8 I        lf.CharSet = DEFAULT_CHARSET;: V' L2 ?4 z: U1 J# h# R+ i& V  b; U
        strcpy(lf.FaceName, "Times New Roman"); // 字型4 y; {; C% S4 R
        ID3DXFont* font=NULL;; q9 Z' H* V: l) D' L; r+ J
        if(D3D_OK!=D3DXCreateFontIndirect(pDxdevice, &lf, &font)) //创建字体对象, d; ?# V& v7 y% C
            return false;
: U# F7 b: R" V; ^, Y
$ W( D* X) r; ^/ W/ T0 v        font->DrawText(5 |# `( P/ p! K. a& Q
            NULL,6 J; g  o3 _4 C% J
            strText, // 要绘制的文本/ \9 {, V+ m9 X3 f! C
            nbuf,
% ^0 ?& r2 _8 Y            &myrect,
& T2 r7 r9 V; S            DT_TOP | DT_LEFT, // 字符居左显示0 C/ _4 l% G6 B+ n- n$ q/ C
            D3DCOLOR_ARGB(255,255,255,0)); + Y" ~1 X! R6 k( F% b% v

" {$ q3 t% V6 A/ ]( i        pDxdevice->EndScene();//结束绘制
; z! O# g4 c5 L+ g) {; m% Z        font->Release();//释放对象
6 F! Y( |4 K& F3 ]% X    }
' y$ i) ?. A4 W. k, M% ]& U- X    return true;
7 N; i$ S( G1 ?$ M* |" o}% g# g, W' p& b" Y- q
) w. Y, X# D1 r; F& h2 R' O
效果图:( H. z+ u* `- B  J
) I% K2 p( ~$ {

% `5 U: s0 L( R2 W4 [6 A- z- |/ o7 ?% X# E! |/ K: O
  
2 Y3 n4 o. s& b6 n4 Q8 l5 L- x$ e2 I! p( x
, V7 z6 L3 a- C9 R% l) ^
后记: 代码是以前写的,因此文章就按照着代码来讲.然而现在看来,把函数入口点的5个字节改成跳转指令这种hook方法并不是那么好,其实可以直接改掉虚函数表中的函数指针,这样更加的安全保险.
, s7 X# T$ ~5 h8 @8 ~* Y  D, t
* p* P; |" V( v+ d# H: `1 I+ n% G$ b9 ^) p0 |# Z

本帖子中包含更多资源

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

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

使用道具 举报

沙发
发表于 2010-2-11 01:06 | 只看该作者
http://www.codeproject.com/KB/system/Hooking_DirectX_COM.aspx5 }% d  P2 z2 k0 @; e& |5 E+ p
) T/ w, X5 b0 l/ f  X: n$ p6 D
发一篇希望有帮助
回复 支持 反对

使用道具 举报

板凳
 楼主| 发表于 2010-2-11 07:51 | 只看该作者
引用第1楼byp100于2010-02-11 01:06发表的  :
" }4 T  `  n2 m/ o! N0 vhttp://www.codeproject.com/KB/system/Hooking_DirectX_COM.aspx8 V* i1 s1 {; i0 `- [; J

& O* j" }% }# K# J1 g/ ^2 G发一篇希望有帮助
  v# N; c2 X8 I
收到,多谢了,这篇文章我也早就找到过。/ ^3 Y; d4 |. F0 ~! c
目前就是要研究如何把汉化和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日,是全球华人共同的冒险解谜类游戏家园。我们致力于提供各类冒险游戏资讯供大家学习交流。本站所有资源均不用于商业用途。

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