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

汉化工具 HookDx

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

[汉化工具] HookDx

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

HookDx

本帖最后由 shane007 于 2021-2-13 22:23 编辑
4 ]. ^. s2 X6 N( J) B
5 n6 c1 I; |  u' H0 H( ]DirrectxHook 工具
) L" ]: k# K  G" X: x* N6 Q4 l! z* H; f6 X* T/ e( c  O/ p
标 题: 【原创】高手莫入 在游戏中显示自己的文字和图形的方法7 h1 a/ A4 b4 E. Z* ]' U
作 者: runjin8 @7 P0 p1 }" e
时 间: 2009-04-03,23:44
7 }  H2 H* V7 H8 @9 M9 a链 接: http://bbs.pediy.com/showthread.php?t=85368
6 x( @4 a7 l( ~# R
7 d8 n4 b3 P5 N7 ~  s( T) wHook Directx:在游戏中显示自己的文字和图形的方法, ~$ }% L9 ]6 B& a% s

2 D+ H) K' p8 }8 _这个方法出自我大概两年前的一个项目,现在经整理后贴出来和大家分享一下,利用该方法可以在一般的directx游戏里面绘制文本甚至图形对象.
7 `- [$ C0 _* u其实思路上非常简单,大致是这样的:要在directx中绘制文字和各种图形对象,只要获得一个类型为LPDIRECT3DDEVICE9的设备对象指针.怎样获得这个指针呢?我的方法是首先hook掉Direct3DCreate9以获得类型为LPDIRECT3D9的Direct3D对象的接口指针,这个Direct3D对象有一个成员函数为 IDirect3D9::CreateDevice,设备对象指针就是在这个函数里面创建的.所以,只要根据Direct3D对象接口指针找到Direct3D对象的虚函数表,再根据虚函数表确定IDirect3D9::CreateDevice的内存地址,就可以hook这个函数,从而获得类型为LPDIRECT3DDEVICE9的设备对象指针,然后就可以随意绘制文字或者图形了.' c+ E! [. w' ~. C
还有一个要hook的地方,即IDirect3DDevice9::Present,这个函数用于交换当前后备缓存区,刷新窗口.要使得我们自己绘制的东西一直显示在屏幕上,比较好的处理方法是hook掉IDirect3DDevice9::Present,在程序真正调用这个函数前插入我们自己的绘制代码.只要根据设备对象指针找到设备对象的虚函数表,根据虚函数表找到IDirect3DDevice9::Present在内存中的地址就可以hook了.下面是对hook directx的详细说明.+ n' N; w# i2 h8 i2 g
首先是找到Direct3DCreate9的内存地址,然后把入口的5个字节修改为跳转指令.
( N' c# r% p# `. h* |# y    pC=GetProcAddress(GetModuleHandle("d3d9.dll"),"Direct3DCreate9");//获得内存地址! w1 h  z6 O) j) L3 r" v* }
    DWORD oldpro=0;& e: u, S. k$ m/ C2 A
    memcpy(d3dcen5bytes,pC,5);
- T9 v! }1 l7 ]6 ~5 V+ a    VirtualProtect(pC,5,PAGE_EXECUTE_READWRITE,&oldpro);* ~9 U+ I) x/ b$ N( I! P, p
    *(BYTE*)pC=0xe9;//0xe9在汇编中是跳转指令操作码
! F1 Z3 Q* ~5 @* z, R2 O- T    *(DWORD*)((BYTE*)pC+1)=(DWORD)hookedDirect3DCreate9-(DWORD)pC-5;//目标地址-原地址-5. i) E3 z- h* q. u/ K" V( }

6 o  j9 @: C$ c* `/ A& S( K) _4 {$ L% w2 o$ {. K4 K
这样,在程序运行到Direct3DCreate9时就会跳转到hookedDirect3DCreate9,在这个函数中,首先是还原Direct3DCreate9入口的5个字节,然后调用真正的Direct3DCreate9,如果函数调用成功,就会返回类型为LPDIRECT3D9的Direct3D对象指针,这正是我们所需要的,得到这个指针后,就可以根据Direct3D对象的虚函数表确定IDirect3D9::CreateDevice的内存地址,然后就可以把这个函数入口的5个字节修改成为跳转指令,跳到我们自己的函数中去. 有个地方值得注意的是,在directx的虚函数中把this指针作为第一个形参入栈了.例如说sdk中IDirect3D9::CreateDevice的函数说明是这样:
4 n3 c% R: t2 U# Y: DHRESULT CreateDevice(
) }9 S, U% O" y  UINT Adapter,
7 N, z. w8 _! O4 ?+ X+ Z. O  D3DDEVTYPE DeviceType,
! M- K) `; @# Q( e+ {% n" Q6 y  HWND hFocusWindow,  T/ [; h0 W* X" y
  DWORD BehaviorFlags,# x+ Z' G6 X1 P: h* U
  D3DPRESENT_PARAMETERS * pPresentationParameters,
) V& |2 w6 D7 g0 z  IDirect3DDevice9 ** ppReturnedDeviceInterface
  E. F3 r( C( a( j( P9 l);
) e3 c/ c4 V9 S2 [, E+ d- m+ s, c
- L8 t& e9 y8 N0 O5 j& J
0 o: P' F; O  Q1 z2 F8 w7 U0 f而为了程序跳转到我们的代码执行完后保持栈的平衡,hookedDirect3DCreat9函数声明应该是这样:
% G4 {/ K2 d( q# L5 O* m& {HRESULT _stdcall hookedCreateDevice(
2 X; I# ^8 m& C5 o1 _. b+ a( k) J                                  LPDIRECT3D9 pDx9," K+ g7 f4 j9 ^( r8 d# k* t1 X
                                  UINT Adapter,4 g0 \# h  d% m6 N2 f
                                  D3DDEVTYPE DeviceType,4 _4 u: Z1 [" f- u7 @
                                  HWND hFocusWindow,0 g* |! q; Z2 L6 \: r2 V% L
                                  DWORD BehaviorFlags,
" g  C: _. i. y+ M  X9 g                                  D3DPRESENT_PARAMETERS * pPresentationParameters,
, w0 P1 Z4 a  O4 M1 r* u, w$ ]7 n7 I                                  IDirect3DDevice9 ** ppReturnedDeviceInterface& R- }* g: q7 U, I  P: ~( t

! Y0 \& S. n. G' X                                  );
! q/ ^% y6 n* g0 J6 F  Z- ~8 i; R
% o; f) o6 X. |: a4 p7 Z* u6 A其中的LPDIRECT3D9 pDx9就是this指针.
( e& g  \& \3 [- M' ?. `2 \, D/ W7 X2 u! ^, f1 d) {8 w5 {1 E9 F
hookedDirect3DCreate9的关键代码如下:
3 j% c2 G3 J( [1 F7 }/ f( ypCdev=(void*)*(DWORD*)(*(DWORD*)m_pD3D+0x40);//获得IDirect3D9::CreateDevice的地址指针
$ {7 s# \6 v  }4 n! K- g( _& P% ^" @0 `, O1 Z" ^. W8 m
        DWORD oldpro=0;4 I+ v, V$ n( D3 x+ @4 w
        memcpy(devcen5bytes,pCdev,5);//保存IDirect3D9::CreateDevice入口5个字节
6 h& _" F+ k2 v2 n/ M3 C: S' v+ S$ N( S6 B        VirtualProtect(pCdev,5,PAGE_EXECUTE_READWRITE,&oldpro);
0 O$ B* H8 z0 ^$ ~$ s3 A        *(BYTE*)pCdev=0xe9;
6 F# Q2 w# H. u# f        *(DWORD*)((BYTE*)pCdev+1)=(DWORD)hookedCreateDevice-(DWORD)pCdev-5;, B' |0 Y' m3 P5 o  ]7 Z; ]9 E

2 l! f  b( g' Z在hookedCreateDevice中,首先还原原来的CreateDevice函数入口的5个字节,然后调用原来的函数, IDirect3D9::CreateDevice的最后一个参数是一个二重指针,如果函数调用成功,这个二重指针所指向的指针就是我们所需要的设备对象指针,由此找到设备对象的虚函数表,然后确定IDirect3DDevice9::Present的内存地址,然后又可以改掉入口的5个字节为跳转指令. hookedCreateDevice的关键代码如下:
, z" k# Y  Z/ B0 V& l# @. ]* m) D' {pPre=(void*)*(DWORD*)(*(DWORD*)m_pDevice+0x44);//获得IDirect3DDevice9::Present的地址指针
6 X: \) h1 p6 a  ]0 c' y. Q        memcpy(pren5bytes,pPre,5);//保存IDirect3DDevice9::Present入口的5个字节
) ~" P6 @# }3 x3 g! T        DWORD oldpro=0;
) ~- B9 r/ {/ M# r+ w        VirtualProtect(pPre,5,PAGE_EXECUTE_READWRITE,&oldpro);
# \  H4 v6 C) |3 U6 M        *(BYTE*)pPre=0xe9;4 M& h8 ~% d# q1 i) \# J$ g3 @
        *(DWORD*)((BYTE*)pPre+1)=(DWORD)hookedPresent-(DWORD)pPre-5;
- n% t4 c5 @  g- u6 q( V
% {$ S2 J2 q- l+ c5 W实际上这几个函数的hook都是同样的道理,现在,当程序运行到IDirect3DDevice9::Present后又会跳转到hookedPresent,而我们自己的绘制代码就是放在hookedPresent里面.在执行完自己的绘制代码后再调用原来的IDirect3DDevice9::Present.我的hookedPresent的关键代码如下:0 E" k! X. B0 R5 m# [: R1 k
char strdraw[]="The drawing in directx game\nAuthor:RunJin\nEmail:[email protected]";4 J, Y: ?6 y" V& _
            DrawMyText(pDxdevice,strdraw,sizeof strdraw-1);//绘制文本! z$ q7 P' K8 T  [; s% n
            //在这里写入您的其它绘图代码# R& K$ |0 x+ q: M4 m# p! Q* m9 `

7 K8 ]5 n1 p6 l( N0 ^- U
, q7 w5 J  _! K2 y  L再来看看其中的DrawMyText,这个函数是我的绘制文本的函数:$ n7 P" T& o3 Y8 |! @
BOOL _stdcall DrawMyText(LPDIRECT3DDEVICE9 pDxdevice,TCHAR* strText ,int nbuf)0 G+ q: c# h. C4 Q  s
{
" ?$ M7 N9 @  M8 `, g/ G# r
+ u( U" i- [/ Q9 O, x; k6 J! \    if(m_pD3D && pDxdevice){
2 K% r5 p* ~2 ^; W$ @% T( }4 F/ f; g4 c8 E
        RECT myrect;& A" e; r- a* {1 P3 c; I# v3 z# |
        myrect.top=150;  //文本块的y坐标
( g( C) ^# @0 o3 o, W" h- X' t        myrect.left=0; //文本块的左坐标
( F1 {8 n" }* n        myrect.right=500+myrect.left;
) L1 @5 c! M7 J0 q        myrect.bottom=100+myrect.top;+ t/ v% w  T: H' e! f1 o
        pDxdevice->BeginScene();//开始绘制2 F: [3 G1 G  T+ f0 J& L  Y6 e

! t- Y9 B8 i1 m- E7 e" @' j* k% V. L& d        D3DXFONT_DESCA lf;
. ?' W' _: q/ l  T3 @        ZeroMemory(&lf, sizeof(D3DXFONT_DESCA));
6 r, w$ f6 X$ Z; S' i+ X( l( S        lf.Height = 24; //字体高度+ k) }' ?5 F$ n, M7 U/ a
        lf.Width = 12; // 字体宽度
( Z2 X) n7 i7 m5 i: |5 |% n        lf.Weight = 100; " T7 G# e4 t, k7 F
        lf.Italic = false;/ J7 U" @3 c6 a
        lf.CharSet = DEFAULT_CHARSET;' n9 c/ f) G4 u
        strcpy(lf.FaceName, "Times New Roman"); // 字型
8 e3 A- S4 {5 p2 m: O  B; p; K        ID3DXFont* font=NULL;4 P: D% j; Z+ m, v
        if(D3D_OK!=D3DXCreateFontIndirect(pDxdevice, &lf, &font)) //创建字体对象
6 u3 N; V; n) [. o            return false;
' \" t8 e: v7 B# R
# `5 k- B' e* t' @6 R        font->DrawText(# P; f" o% C9 O5 W% b
            NULL,( e; F, ~# N6 p& m  _" v2 t
            strText, // 要绘制的文本$ M" z" D' P1 j1 v6 `( V
            nbuf, $ X, u; b2 X' J, L) @0 L+ R
            &myrect,
& Z: @' {7 o" b& v% S8 D; z8 f  I, W            DT_TOP | DT_LEFT, // 字符居左显示
- L% m6 J! {4 U/ Y. L8 T            D3DCOLOR_ARGB(255,255,255,0));
) Y) a( }/ Y( R+ j, B; J2 F+ j5 O; p! C( K
        pDxdevice->EndScene();//结束绘制* H# \1 {2 u  A9 ]
        font->Release();//释放对象
' }: Q; S7 G2 o! W  l    }6 z# j9 r, |* s+ G! e' S) Z
    return true;/ W' I, j, l' L
}
+ @: s* b- q: S, t$ r
, }! o. j# \, d) g' t' X# y效果图:  D/ l1 ]1 {  U& H; n

/ Q7 L8 i! X5 K  x1 X4 ~) `% R; o5 J( ^8 ?
; N; n6 w: W. o' g0 r& G7 |- ?1 D+ P, A
  
: ~2 V7 e4 p# O5 {7 f
+ R% f! c; Z. X# G
) T6 r; u+ Y4 E) Y4 x1 U$ `, f后记: 代码是以前写的,因此文章就按照着代码来讲.然而现在看来,把函数入口点的5个字节改成跳转指令这种hook方法并不是那么好,其实可以直接改掉虚函数表中的函数指针,这样更加的安全保险.' }+ S" m# C% S2 L% ~

# i* Q& K3 _, S8 q6 q/ J; m% e
; `+ S2 P) [0 F( J8 o& h" P5 J1 ~9 V

本帖子中包含更多资源

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

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

使用道具 举报

沙发
发表于 2010-2-11 01:06 | 只看该作者
http://www.codeproject.com/KB/system/Hooking_DirectX_COM.aspx! P* s7 M5 g* b. m9 z6 z
( F" @5 r. ?$ H% x
发一篇希望有帮助
回复 支持 反对

使用道具 举报

板凳
 楼主| 发表于 2010-2-11 07:51 | 只看该作者
引用第1楼byp100于2010-02-11 01:06发表的  :5 i7 t6 U" W; [4 T5 _
http://www.codeproject.com/KB/system/Hooking_DirectX_COM.aspx8 ^( [' p. [& U* M
, C8 d/ n5 q& o+ c# O3 r/ t) H
发一篇希望有帮助
& S& y# r) o3 U9 m8 u
收到,多谢了,这篇文章我也早就找到过。2 `( V$ Y& V" ]* L0 ~
目前就是要研究如何把汉化和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日,是全球华人共同的冒险解谜类游戏家园。我们致力于提供各类冒险游戏资讯供大家学习交流。本站所有资源均不用于商业用途。

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