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

汉化教程 【转载】在游戏中显示自己的文字和图形的方法

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

[汉化教程] 【转载】在游戏中显示自己的文字和图形的方法

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

【转载】在游戏中显示自己的文字和图形的方法

标 题: 【转载】在游戏中显示自己的文字和图形的方法
5 N2 {- q! t; h作 者: runjin, B1 s4 G7 r6 [, _; e
时 间: 2009-04-03,22:44:51
* @6 N3 n" `# \, x链 接: http://bbs.pediy.com/showthread.php?t=85368" g. z8 U2 z4 J: U) y8 Q+ Y
. U  ]# h# b" t( `
Hook Directx:在游戏中显示自己的文字和图形的方法
; Z3 \, d- h$ ]4 M* D  c  e: \2 [( B: {$ p+ `
这个方法出自我大概两年前的一个项目,现在经整理后贴出来和大家分享一下,利用该方法可以在一般的directx游戏里面绘制文本甚至图形对象.9 ~" q2 t! D2 C
其实思路上非常简单,大致是这样的:要在directx中绘制文字和各种图形对象,只要获得一个类型为LPDIRECT3DDEVICE9的设备对象指针.怎样获得这个指针呢?我的方法是首先hook掉Direct3DCreate9以获得类型为LPDIRECT3D9的Direct3D对象的接口指针,这个Direct3D对象有一个成员函数为 IDirect3D9::CreateDevice,设备对象指针就是在这个函数里面创建的.所以,只要根据Direct3D对象接口指针找到Direct3D对象的虚函数表,再根据虚函数表确定IDirect3D9::CreateDevice的内存地址,就可以hook这个函数,从而获得类型为LPDIRECT3DDEVICE9的设备对象指针,然后就可以随意绘制文字或者图形了.
  C- `0 d' z% R; y' u. y还有一个要hook的地方,即IDirect3DDevice9::Present,这个函数用于交换当前后备缓存区,刷新窗口.要使得我们自己绘制的东西一直显示在屏幕上,比较好的处理方法是hook掉IDirect3DDevice9::Present,在程序真正调用这个函数前插入我们自己的绘制代码.只要根据设备对象指针找到设备对象的虚函数表,根据虚函数表找到IDirect3DDevice9::Present在内存中的地址就可以hook了.下面是对hook directx的详细说明.
+ D' n2 ~5 X$ ?) l( _: o首先是找到Direct3DCreate9的内存地址,然后把入口的5个字节修改为跳转指令.
: u1 b* p# m/ I" ]2 [    pC=GetProcAddress(GetModuleHandle("d3d9.dll"),"Direct3DCreate9");//获得内存地址) z2 `9 r/ K; I2 u4 |9 ]2 i* P& X# F$ b
    DWORD oldpro=0;
  r- T0 g' q1 ]' z    memcpy(d3dcen5bytes,pC,5);
% z2 V" x: J" F6 Z    VirtualProtect(pC,5,PAGE_EXECUTE_READWRITE,&oldpro);
# k& i  j+ ^0 }: T' e    *(BYTE*)pC=0xe9;//0xe9在汇编中是跳转指令操作码
+ M* |2 Y* q! u% Z6 R2 e" Y    *(DWORD*)((BYTE*)pC+1)=(DWORD)hookedDirect3DCreate9-(DWORD)pC-5;//目标地址-原地址-5% R4 i# N8 `& Z$ Q  c, }4 q* f

1 a1 ^% I; F' q" J0 Z1 Z/ ?# G0 O* y* _& d8 p
这样,在程序运行到Direct3DCreate9时就会跳转到hookedDirect3DCreate9,在这个函数中,首先是还原Direct3DCreate9入口的5个字节,然后调用真正的Direct3DCreate9,如果函数调用成功,就会返回类型为LPDIRECT3D9的Direct3D对象指针,这正是我们所需要的,得到这个指针后,就可以根据Direct3D对象的虚函数表确定IDirect3D9::CreateDevice的内存地址,然后就可以把这个函数入口的5个字节修改成为跳转指令,跳到我们自己的函数中去. 有个地方值得注意的是,在directx的虚函数中把this指针作为第一个形参入栈了.例如说sdk中IDirect3D9::CreateDevice的函数说明是这样:5 h) ]. a9 Y2 H$ |: Z
HRESULT CreateDevice(! A) s$ b* A5 ]: _/ s' c
  UINT Adapter,2 O  V! Z3 H9 S/ N; }
  D3DDEVTYPE DeviceType,
2 g9 I+ t# o& o) d/ Q/ t  HWND hFocusWindow,( D( Q2 i# U4 @. W# N
  DWORD BehaviorFlags,
( L1 {. t) x% S* ^+ @9 v  D3DPRESENT_PARAMETERS * pPresentationParameters,/ T8 A6 H* n5 r. L/ r  e- {
  IDirect3DDevice9 ** ppReturnedDeviceInterface4 e* T3 B3 Z3 N( M  r. m  q) c
);
) c9 t7 ~$ R* G' n% _- u9 c6 z, f( U1 r
, p; a. E+ V  _( X5 M4 u6 \( Q, K
而为了程序跳转到我们的代码执行完后保持栈的平衡,hookedDirect3DCreat9函数声明应该是这样:
+ B; ?. I. D- ZHRESULT _stdcall hookedCreateDevice(
! F0 m$ [- F  X. e- N" R; X7 n/ ^                                  LPDIRECT3D9 pDx9,1 V8 J8 ?, R# G1 e
                                  UINT Adapter,
+ b2 `1 Z+ a3 r; y- X                                  D3DDEVTYPE DeviceType,
' r) u" v2 [" ]! J% E                                  HWND hFocusWindow,8 ]& D6 o) V' u9 v( N
                                  DWORD BehaviorFlags,
0 q$ R3 g, [$ z4 L6 G                                  D3DPRESENT_PARAMETERS * pPresentationParameters,
9 V8 h1 {3 J* }+ p. a) B8 i                                  IDirect3DDevice9 ** ppReturnedDeviceInterface" E, N' L( ^2 E2 m* A

( I, [) _8 z" W7 h                                  );
1 v' J% P$ J  M8 b
1 @& j: o; G( L0 ^# N" e2 ]8 L其中的LPDIRECT3D9 pDx9就是this指针.) s1 C, B) k" ?- h6 t$ S  z: t

  D4 X" m* o  }* w3 i; y6 Z! @. VhookedDirect3DCreate9的关键代码如下:
6 R2 l' l& N. {2 }( X) u# JpCdev=(void*)*(DWORD*)(*(DWORD*)m_pD3D+0x40);//获得IDirect3D9::CreateDevice的地址指针
5 ~1 y: F3 T* V  f: J3 C4 H' |' S: i( T2 t
        DWORD oldpro=0;% [. z3 u* n9 r  E) b
        memcpy(devcen5bytes,pCdev,5);//保存IDirect3D9::CreateDevice入口5个字节
! z2 J. O2 t0 G        VirtualProtect(pCdev,5,PAGE_EXECUTE_READWRITE,&oldpro);
8 E0 i1 x0 G% j+ Q( l3 U% E5 q% x/ ?$ G        *(BYTE*)pCdev=0xe9;! }4 c7 {& q9 m1 v" n% G
        *(DWORD*)((BYTE*)pCdev+1)=(DWORD)hookedCreateDevice-(DWORD)pCdev-5;
6 R3 H& b) b  P" n& ^) T) L: O
5 C& U( g# E" r7 K; j( z在hookedCreateDevice中,首先还原原来的CreateDevice函数入口的5个字节,然后调用原来的函数, IDirect3D9::CreateDevice的最后一个参数是一个二重指针,如果函数调用成功,这个二重指针所指向的指针就是我们所需要的设备对象指针,由此找到设备对象的虚函数表,然后确定IDirect3DDevice9::Present的内存地址,然后又可以改掉入口的5个字节为跳转指令. hookedCreateDevice的关键代码如下:
2 l  G5 @! e* ]' GpPre=(void*)*(DWORD*)(*(DWORD*)m_pDevice+0x44);//获得IDirect3DDevice9::Present的地址指针
" q+ {5 a* E8 C& M# R* x        memcpy(pren5bytes,pPre,5);//保存IDirect3DDevice9::Present入口的5个字节
1 t4 c1 c+ K* U& p' L        DWORD oldpro=0;
3 r7 g( \7 y- J2 P        VirtualProtect(pPre,5,PAGE_EXECUTE_READWRITE,&oldpro);8 {. B3 n( T6 x1 w3 j5 Y
        *(BYTE*)pPre=0xe9;
: k/ K" i. C7 f! |0 T! _        *(DWORD*)((BYTE*)pPre+1)=(DWORD)hookedPresent-(DWORD)pPre-5;7 P* m. u+ z( g) U$ }. Z

) {* @& J8 ~5 a$ V% @实际上这几个函数的hook都是同样的道理,现在,当程序运行到IDirect3DDevice9::Present后又会跳转到hookedPresent,而我们自己的绘制代码就是放在hookedPresent里面.在执行完自己的绘制代码后再调用原来的IDirect3DDevice9::Present.我的hookedPresent的关键代码如下:
  l& F9 l+ S& F2 f: S4 e% `% Mchar strdraw[]="The drawing in directx game\nAuthor:RunJin\nEmail:[email protected]";5 ~3 O8 C7 ^9 }
            DrawMyText(pDxdevice,strdraw,sizeof strdraw-1);//绘制文本
. y2 f( v$ r% m            //在这里写入您的其它绘图代码1 s0 }9 g7 t) a9 o

% |$ _; E* R* u! T2 T% A; t& }
再来看看其中的DrawMyText,这个函数是我的绘制文本的函数:
2 z7 m* @0 j4 |- q! gBOOL _stdcall DrawMyText(LPDIRECT3DDEVICE9 pDxdevice,TCHAR* strText ,int nbuf)0 y  l; d" o/ _! N7 P/ b
{* h# U8 v& w8 M

5 n% ^% X" A6 P6 E# i    if(m_pD3D && pDxdevice){' T1 J8 i/ ?. U. N5 o' @) T
! d' N" O- g& P  ]+ [3 p
        RECT myrect;
) g/ I$ J0 @6 [" t. @        myrect.top=150;  //文本块的y坐标& }  j* r  }% t
        myrect.left=0; //文本块的左坐标
# t3 w8 s* {2 Y5 C        myrect.right=500+myrect.left;* C' `% k' ]( w
        myrect.bottom=100+myrect.top;
4 z) y+ |, X( M/ h        pDxdevice->BeginScene();//开始绘制
$ O" a6 }7 q9 g) W$ N
5 @0 i6 w. \! r+ H  M        D3DXFONT_DESCA lf;) T8 r1 t, Q. I5 P" b! \
        ZeroMemory(&lf, sizeof(D3DXFONT_DESCA));2 [# @" d- C/ [, {7 ~( k
        lf.Height = 24; //字体高度3 ^$ F; J/ h$ S) v. k
        lf.Width = 12; // 字体宽度: q' A' f4 N; I% W5 v) r
        lf.Weight = 100;
/ e5 x! q& ]6 v        lf.Italic = false;! u5 j" E, \9 Y' m+ e0 q5 v
        lf.CharSet = DEFAULT_CHARSET;
3 F2 @9 I2 m% k0 y$ T        strcpy(lf.FaceName, "Times New Roman"); // 字型2 Y6 ?, G- Y& B- c; J* A
        ID3DXFont* font=NULL;( S- K0 u; x1 ^& |- m
        if(D3D_OK!=D3DXCreateFontIndirect(pDxdevice, &lf, &font)) //创建字体对象6 a+ P4 I, A& ]3 z. y
            return false;
: K4 F* u. g* m8 l6 T! F) x. s1 a9 n+ |7 H6 |! p8 W
        font->DrawText(2 _$ _" k# k* G. r- Q/ ^0 D
            NULL,* R0 U1 d1 g! Z+ j$ [
            strText, // 要绘制的文本
3 y* l) D' E# w2 K& f5 \+ ]) Z            nbuf,
& s4 U7 m6 @# `- B' }            &myrect, ; p, D4 B% l5 f1 ?
            DT_TOP | DT_LEFT, // 字符居左显示
, T! N' R8 N8 v            D3DCOLOR_ARGB(255,255,255,0));
; E3 @' M) X: f4 a0 K# E+ V8 D  ]- p; g) ?
        pDxdevice->EndScene();//结束绘制
) L( x+ P; I/ J- R0 m0 P: o        font->Release();//释放对象
' P/ c  ]+ E. L8 @: q    }$ D& A+ G2 f+ k- |  C+ |
    return true;
5 x. a% ?* P! Y# F  E# D5 G  U8 Q) }}
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏1 分享分享 很美好很美好 很差劲很差劲
回复

使用道具 举报

沙发
发表于 2010-4-4 21:49 | 只看该作者
多谢楼主,不过,其实我已经发过了。
6 k+ t# B) l6 A* r( ~https://www.chinaavg.com/read.php?tid=18802
回复 支持 反对

使用道具 举报

板凳
发表于 2010-4-6 16:02 | 只看该作者
他这个方法不好,局限性比较大0 p( c; I' t) V7 c( ?4 G
首先不能方便的HOOK所有函数,需要到处打JMP补丁
" S/ s- P! r/ J! y/ u- l4 B另外每HOOK一个函数都必须自己去查找D3D对象偏移
' P0 d" k/ m5 o9 V$ t( a' TpCdev=(void*)*(DWORD*)(*(DWORD*)m_pD3D+0x40);//获得IDirect3D9::CreateDevice的地址指针/ S) }" j+ A& `
比如这里CreateDevice地址指针是m_pD3D+0x40,这个资料里一般是没有的要自己反汇编下, }& O) g! `4 ?2 W1 |
5 |# x. N" l" ~! p
还是007那个方法好,也是我一直在使用的方法, H- ~1 a  t. T
直接创建一个自己的D3D对象返回,针对Direct3DCreate9与CreateDevice特别处理一下  N0 {# c( P7 _. }& L- ^  x2 \
只需一个钩子,后面所有的D3D事件都得从这过了[s:109]
回复 支持 反对

使用道具 举报

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

本版积分规则

冒险解谜游戏中文网 ChinaAVG

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

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

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

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