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

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

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

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

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

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

标 题: 【转载】在游戏中显示自己的文字和图形的方法4 Q. _: u1 F5 y1 r% F
作 者: runjin
. }) N1 y  [, t3 N! Q时 间: 2009-04-03,22:44:51
' b' M7 c7 D% w链 接: http://bbs.pediy.com/showthread.php?t=85368
- X$ g+ |+ q/ j4 e& T# V( ^5 p9 t5 p$ b
Hook Directx:在游戏中显示自己的文字和图形的方法
# D6 `3 a7 u' w  L! V, L
! N/ O% {: {5 A. d7 i) M这个方法出自我大概两年前的一个项目,现在经整理后贴出来和大家分享一下,利用该方法可以在一般的directx游戏里面绘制文本甚至图形对象.6 \% x9 \, w% d
其实思路上非常简单,大致是这样的:要在directx中绘制文字和各种图形对象,只要获得一个类型为LPDIRECT3DDEVICE9的设备对象指针.怎样获得这个指针呢?我的方法是首先hook掉Direct3DCreate9以获得类型为LPDIRECT3D9的Direct3D对象的接口指针,这个Direct3D对象有一个成员函数为 IDirect3D9::CreateDevice,设备对象指针就是在这个函数里面创建的.所以,只要根据Direct3D对象接口指针找到Direct3D对象的虚函数表,再根据虚函数表确定IDirect3D9::CreateDevice的内存地址,就可以hook这个函数,从而获得类型为LPDIRECT3DDEVICE9的设备对象指针,然后就可以随意绘制文字或者图形了.! V  G' b& k' P: q7 _; z
还有一个要hook的地方,即IDirect3DDevice9::Present,这个函数用于交换当前后备缓存区,刷新窗口.要使得我们自己绘制的东西一直显示在屏幕上,比较好的处理方法是hook掉IDirect3DDevice9::Present,在程序真正调用这个函数前插入我们自己的绘制代码.只要根据设备对象指针找到设备对象的虚函数表,根据虚函数表找到IDirect3DDevice9::Present在内存中的地址就可以hook了.下面是对hook directx的详细说明.
& a* g1 h- c. G9 ^5 o: U1 V首先是找到Direct3DCreate9的内存地址,然后把入口的5个字节修改为跳转指令.
" m; |* q1 Z1 t1 c    pC=GetProcAddress(GetModuleHandle("d3d9.dll"),"Direct3DCreate9");//获得内存地址: O9 ~1 }6 R% x/ J# }1 m
    DWORD oldpro=0;
/ V5 d+ j6 ^5 \: _$ y    memcpy(d3dcen5bytes,pC,5);2 y* V# H2 m" M5 C# W
    VirtualProtect(pC,5,PAGE_EXECUTE_READWRITE,&oldpro);
( A8 }8 w" B' p8 z4 w    *(BYTE*)pC=0xe9;//0xe9在汇编中是跳转指令操作码# s. o1 o8 @2 o/ ?
    *(DWORD*)((BYTE*)pC+1)=(DWORD)hookedDirect3DCreate9-(DWORD)pC-5;//目标地址-原地址-5
0 s* K0 f; K) e' S9 ?* T5 c7 x$ j3 `0 p* x
9 @6 r7 L* S. H* D/ w& \$ z! K
这样,在程序运行到Direct3DCreate9时就会跳转到hookedDirect3DCreate9,在这个函数中,首先是还原Direct3DCreate9入口的5个字节,然后调用真正的Direct3DCreate9,如果函数调用成功,就会返回类型为LPDIRECT3D9的Direct3D对象指针,这正是我们所需要的,得到这个指针后,就可以根据Direct3D对象的虚函数表确定IDirect3D9::CreateDevice的内存地址,然后就可以把这个函数入口的5个字节修改成为跳转指令,跳到我们自己的函数中去. 有个地方值得注意的是,在directx的虚函数中把this指针作为第一个形参入栈了.例如说sdk中IDirect3D9::CreateDevice的函数说明是这样:9 h& P9 x; Z- h; _( }% I0 ?( r
HRESULT CreateDevice(
7 x) U. C0 ~8 L7 W$ U+ i2 d  UINT Adapter,1 l% g# v. \' e& i& T! O3 l
  D3DDEVTYPE DeviceType,( S; n* V1 P& l; v6 S+ G
  HWND hFocusWindow,
* x$ a6 L# w, `: b. g) t  DWORD BehaviorFlags,
, V/ S# ?) O3 q  D3DPRESENT_PARAMETERS * pPresentationParameters,
) N* z& n; |: X+ x& v  IDirect3DDevice9 ** ppReturnedDeviceInterface
$ ^1 @# K. e0 g5 |& I2 f);# Y- F! G. B" f
  O- Q# t0 K) m! U  x: g+ s" O
4 ^, g9 c/ V  ]" f. E0 K' D1 \
而为了程序跳转到我们的代码执行完后保持栈的平衡,hookedDirect3DCreat9函数声明应该是这样:& n% F$ f( R3 a; r
HRESULT _stdcall hookedCreateDevice(7 @4 v2 x7 p" U# G! B' T# [
                                  LPDIRECT3D9 pDx9,
% n  t* K8 A/ @# W( E( p0 w                                  UINT Adapter,
# w! ~+ M$ g+ R& k                                  D3DDEVTYPE DeviceType,
# g' g4 ]& s3 X7 q8 n7 e                                  HWND hFocusWindow,
  p# ]) j- v/ ?, Z, s! z                                  DWORD BehaviorFlags,
2 K# P- s. p8 H! d$ X                                  D3DPRESENT_PARAMETERS * pPresentationParameters,
2 V# |9 ?; H: t( W& P) H                                  IDirect3DDevice9 ** ppReturnedDeviceInterface
- {  d7 O  U/ l- x! e
/ o; T* }' V" z" m: o! M: d                                  );
0 w; D+ n5 x4 N; N- }" \: ?" |' s+ Y4 i# e4 w7 [# ~- b: s
其中的LPDIRECT3D9 pDx9就是this指针.
2 P( h3 y$ f4 |) J! I& t, N
8 O+ B' f$ c; H7 p" LhookedDirect3DCreate9的关键代码如下:
; O$ C; }9 o7 Y3 j. u: H& ~: `pCdev=(void*)*(DWORD*)(*(DWORD*)m_pD3D+0x40);//获得IDirect3D9::CreateDevice的地址指针" l- w- c6 `7 y
$ m, F$ i* H7 b( p; {* N2 Z( _
        DWORD oldpro=0;
& f: F+ K, q; B# b4 H6 t        memcpy(devcen5bytes,pCdev,5);//保存IDirect3D9::CreateDevice入口5个字节
$ z: S8 `0 Y0 @+ b        VirtualProtect(pCdev,5,PAGE_EXECUTE_READWRITE,&oldpro);1 k6 E1 g* b- @: p
        *(BYTE*)pCdev=0xe9;
8 j2 }! u7 l1 b" u        *(DWORD*)((BYTE*)pCdev+1)=(DWORD)hookedCreateDevice-(DWORD)pCdev-5;
5 W: q; e, n! n3 X' d- v" @  i' y% i: ]
在hookedCreateDevice中,首先还原原来的CreateDevice函数入口的5个字节,然后调用原来的函数, IDirect3D9::CreateDevice的最后一个参数是一个二重指针,如果函数调用成功,这个二重指针所指向的指针就是我们所需要的设备对象指针,由此找到设备对象的虚函数表,然后确定IDirect3DDevice9::Present的内存地址,然后又可以改掉入口的5个字节为跳转指令. hookedCreateDevice的关键代码如下:" J- x8 `+ j- v$ L: E) P
pPre=(void*)*(DWORD*)(*(DWORD*)m_pDevice+0x44);//获得IDirect3DDevice9::Present的地址指针
- \! u  w% X  \# W! H        memcpy(pren5bytes,pPre,5);//保存IDirect3DDevice9::Present入口的5个字节7 q  j3 O0 D& _& }+ K2 K
        DWORD oldpro=0;' t. }3 `9 P7 @
        VirtualProtect(pPre,5,PAGE_EXECUTE_READWRITE,&oldpro);* W/ O: G0 v3 a& t8 o6 s
        *(BYTE*)pPre=0xe9;! N2 B! d7 ?* B
        *(DWORD*)((BYTE*)pPre+1)=(DWORD)hookedPresent-(DWORD)pPre-5;/ @0 f& V. u. t6 `
! f  b& Z$ C/ u# H4 n7 K
实际上这几个函数的hook都是同样的道理,现在,当程序运行到IDirect3DDevice9::Present后又会跳转到hookedPresent,而我们自己的绘制代码就是放在hookedPresent里面.在执行完自己的绘制代码后再调用原来的IDirect3DDevice9::Present.我的hookedPresent的关键代码如下:5 O2 [- X! x0 K( u6 m5 {+ r5 k, w
char strdraw[]="The drawing in directx game\nAuthor:RunJin\nEmail:[email protected]";" b9 r- _# @$ L$ C0 F& G, k2 \
            DrawMyText(pDxdevice,strdraw,sizeof strdraw-1);//绘制文本1 o0 d- N! `! K. d* _
            //在这里写入您的其它绘图代码
! y. V5 E' o' B' @$ K* K& q  u7 e0 D& q( @* S

& l  R  E3 R6 N; y* @再来看看其中的DrawMyText,这个函数是我的绘制文本的函数:
1 T4 b6 d6 d7 |: S3 i" S( f$ E5 d, mBOOL _stdcall DrawMyText(LPDIRECT3DDEVICE9 pDxdevice,TCHAR* strText ,int nbuf)/ D7 r- w7 P; R! ~
{  O; v2 A  o8 Y# g# Q

2 j! g/ Y  B* j: Z    if(m_pD3D && pDxdevice){
, v* ?, N! F9 ?
+ ?- N9 r' u+ B9 ?& d) v1 \        RECT myrect;
/ v( @9 {" P! a1 c) x        myrect.top=150;  //文本块的y坐标5 i' i& t$ O' }) v# K1 p. M
        myrect.left=0; //文本块的左坐标9 Y! a* I/ g4 H  ~
        myrect.right=500+myrect.left;+ z. b0 ~% h+ A6 T' d5 {6 q
        myrect.bottom=100+myrect.top;
8 P' u$ [7 u6 o9 w0 I; A        pDxdevice->BeginScene();//开始绘制- v, D5 R2 M3 x, r" f% U$ i9 Z
8 ~8 g6 a7 B, L
        D3DXFONT_DESCA lf;
; m! s- T- F& O$ @- p        ZeroMemory(&lf, sizeof(D3DXFONT_DESCA));
3 q4 N3 X; v+ `% l. M1 T        lf.Height = 24; //字体高度
3 k. h, N  ?! O6 L9 W        lf.Width = 12; // 字体宽度& g6 t4 p5 V. ?% }% o
        lf.Weight = 100;
9 t; @7 }' L' L; a+ \; }        lf.Italic = false;' q. d5 R- }7 P  }$ |! m
        lf.CharSet = DEFAULT_CHARSET;
" H$ `) z. @2 A' j" u5 }; j        strcpy(lf.FaceName, "Times New Roman"); // 字型
; G+ h3 G3 ?. S  P, b- g        ID3DXFont* font=NULL;: o5 N  j: x) E2 Q1 g
        if(D3D_OK!=D3DXCreateFontIndirect(pDxdevice, &lf, &font)) //创建字体对象
* Q% X! Q3 Y; T: }" z8 e6 A            return false;$ j$ Y* _' z5 f1 P  W$ j8 Q/ W

! L8 V# e) h. a        font->DrawText(8 B0 h3 R" r, D' ?% d* F
            NULL,
9 J5 L" {: J8 p            strText, // 要绘制的文本
$ V% e$ ~+ ?0 q            nbuf,
  [( d* Y; d3 w/ l* \  g0 h            &myrect, * y$ k% y- D, e. H
            DT_TOP | DT_LEFT, // 字符居左显示; l1 R8 A' D6 q9 p( g
            D3DCOLOR_ARGB(255,255,255,0)); * `8 S5 u: ?/ J- G3 D! x& R4 C9 f

/ e, x- q: A6 e, o- D! V5 E  T        pDxdevice->EndScene();//结束绘制
9 o5 o9 ], G: k1 G$ d1 {        font->Release();//释放对象$ U) @6 f; @) o
    }' y; U8 [, C) Y7 j5 w
    return true;* Y6 d* T7 o* l  }: o7 E7 K
}
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏1 分享分享 很美好很美好 很差劲很差劲
回复

使用道具 举报

沙发
发表于 2010-4-4 21:49 | 只看该作者
多谢楼主,不过,其实我已经发过了。
3 h4 w; a, y( `+ Z, shttps://www.chinaavg.com/read.php?tid=18802
回复 支持 反对

使用道具 举报

板凳
发表于 2010-4-6 16:02 | 只看该作者
他这个方法不好,局限性比较大
# h2 J0 C! `8 i( B首先不能方便的HOOK所有函数,需要到处打JMP补丁
, u7 L4 f9 u4 o8 N5 P另外每HOOK一个函数都必须自己去查找D3D对象偏移
3 ]2 k# r& q* apCdev=(void*)*(DWORD*)(*(DWORD*)m_pD3D+0x40);//获得IDirect3D9::CreateDevice的地址指针
( z% p( R: I) D8 _比如这里CreateDevice地址指针是m_pD3D+0x40,这个资料里一般是没有的要自己反汇编下1 J& [1 j; Y7 @3 t' L
# c! W9 H) Q$ K
还是007那个方法好,也是我一直在使用的方法5 t* Q; [1 r/ M0 A8 H
直接创建一个自己的D3D对象返回,针对Direct3DCreate9与CreateDevice特别处理一下
, l2 ^8 ?/ ^. L/ s! G# J只需一个钩子,后面所有的D3D事件都得从这过了[s:109]
回复 支持 反对

使用道具 举报

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

本版积分规则

冒险解谜游戏中文网 ChinaAVG

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

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

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

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