冒险解谜游戏中文网 ChinaAVG

标题: GDI32.DLL的代理DLL(solidji 请进) [打印本页]

作者: shane007    时间: 2010-4-9 20:42
标题: GDI32.DLL的代理DLL(solidji 请进)
solidji4 T9 U* i% e7 U# _; Z

# j0 d, n$ D% Y3 d/ Q' [3 X 你好,先给你安排一个小任务,这个任务对你来说应该很简单。
3 Q5 p% U! K$ q http://aluigi.altervista.org/mytoolz/dllproxyskel.zip! i5 b8 V& |$ W6 z( w8 W

# ~: r- \# j( U" N 上面是老外开发的一个制作代理DLL的工具,他的网站上面也有例子。
, x! u) E! I3 l 但是比较复杂,我暂时没有时间仔细研究。0 e& A1 H, d" X: Q; a  O8 T; U
 请你用上面的工具作一个GDI32.DLL的代理DLL,HOOK其中的1个函数即可,
+ [  q7 j: T% }& N 比如Exttextout,也就是说想让你做个最简单的例子。以备扩充修改。
. H( i0 z$ E$ p: x6 n    请发布代码。
作者: solidji    时间: 2010-4-10 20:41
标题: dllproxyskel.c
显示AlterVista
  J/ ^* R, h9 v打不开页面,我搜索看看; [7 z& S8 D" H
-------
9 m6 M( V/ e. B' ?6 O2 N" D. k% |0 y哦有了dllproxyskel.c,就两个文件,代码很少
作者: solidji    时间: 2010-4-11 00:55
标题: dllproxyskel
dllproxyskel使用起来比较简单,dllproxyskel自动从你输入的原始DLL中提取所有导出函数符号5 z" @4 m7 w( `" F2 z/ n
然后按一定的格式生成.c文件,自动将所有的dll函数信息记录进.def, 做好替换 函数在.c,7 U* e; j0 X2 b
通过在.c文件中#ifdef DLL_PATH 来寻找原始DLL路径(默认为\\system32),原始DLL里的函数调用是原函数名前面加个下划线_1 q6 M2 l& D0 _- D/ l# s
比如Exttextout,在.c里做完自己的事后可以调用 _Exttextout 来完全其原本的工作8 i) k, z, O7 _$ F$ |- I+ z% ~
9 |1 E+ p0 N% Q
命令行输入- j! E! X$ c! E, o" j
dllproxyskel.exe <input.dll>* B" r( j' F4 o# l0 K
- open file D:\\项目\\dllproxyskel\\input.dll$ g4 _9 X8 h  _; q) |, S. w
[attach]15892[/attach] 4 Z4 v) t  j1 c* t1 ~5 y; J% y8 a

! H/ p! ?1 s3 ]) S# u------------------------------------------------------------------
' v2 e5 l8 M# u3 ~6 ]  k# D我们需要额外添加的代码
  C0 C4 [. W' p8 n! J/ R% L* U#define _WINGDI_    //这个值从wingdi.h里获取,仅仅在代理系统DLL的时候需要
% @3 k  p7 c: w. b0 u//定义了两种声明代理函数的宏,CALL_FUNCTION与CALL_FUNCTION2
6 Q$ g7 M" v4 {4 A/ X5 n+ e0 S//这里我采用第二种,将返回值与函数名与参数列表一起作为宏内容,下面第一个参数BOOL 是ExtTextOutA的返回值0 A8 Y. N( {0 c9 R  L- z9 ~
CALL_FUNCTION2(BOOL, ExtTextOutA,
: q5 Q6 L3 H0 ]* Z/ g              HDC hdc,
, |, {& j, b5 O* f0 e9 I              INT         x,( y6 X0 s$ i  `+ }& _' Q
              INT         y,
, v0 ?( l6 R4 O$ ?) \              UINT        flags,
7 o; R, J2 }5 ]  N& R, T+ K              const RECT* lprect,
0 }; J/ A+ A: j/ j              LPCSTR      str,3 Z5 ~# B, f7 @/ l' h. Q
              UINT        count,
+ f# K' v3 _  Q* `# d" t              const INT*  lpDx
# _6 f- V6 n# S1 S. H) {6 h3 P4 _( V" T' b8 ]8 u: P0 O
    //这里可以做任何你想做的事了,HOOK成功. {1 J1 O/ ~  s" g
    outputdebugstr("HOOK ExtTextOutA suscess!");5 K$ H2 h5 R+ t
       BOOL result = _ExtTextOutA(x, y, flags, lprect, str,count,lpDx);//调用原始函数
8 X3 v5 n8 S# N. [5 K3 G       return(result);
$ K* D. z6 y$ U! @5 G}3 s) r; P. n" [7 ?* s

/ v2 b: _0 G8 l8 u0 H注意,生成的代码需要用gcc/mingw来编译,
8 J! v4 v8 O4 }5 v主要是因为其中使用了gcc宏扩展  {+ Z. z4 a1 i5 r4 N* n) O1 W4 R) A  `: A
#define CALLING_CONVENTION WINAPI       // default for Windows DLLs) X/ v1 K2 v9 _3 b7 V2 ~
#define PROXY_FUNCTION(FUNCTION_NAME)   /* for the proxified functions not modified */ \\+ ~6 e9 D! e9 q/ V- B9 M
        void CALLING_CONVENTION  FUNCTION_NAME(void)% b; T) ^6 j0 R1 g: O* Z
#define PROXY_FUNCTIONX(FUNCTION_NAME) \\
' U6 Y3 A; H) x5 P$ Y" X        static PROXY_FUNCTION(*_##FUNCTION_NAME) = NULL; \\
1 u6 w$ D) u. z- m0 m4 W        PROXY_FUNCTION(FUNCTION_NAME) { \\
% M5 u- b% z- W+ ^8 g. n& n            POP_EBP __asm__("jmp *__"#FUNCTION_NAME); \\
6 S  L9 c6 N$ {        }
1 b% Y7 K: ^) v. H$ L#define CALL_FUNCTION(FUNCTION_NAME) \\" F6 H4 o! L5 B$ C4 H; @
        static CALLING_CONVENTION FUNCTION_NAME##_(*_##FUNCTION_NAME) = NULL; \\
1 {. y. N$ }6 z0 b, S: }& h        CALLING_CONVENTION FUNCTION_NAME##_(FUNCTION_NAME)# y$ v/ z  T5 r; {  L( n+ X0 {
#define CALL_FUNCTION2(FUNCTION_RET, FUNCTION_NAME, FUNCTION_ARGS ...) \\
# q8 B% L4 w3 S7 w6 o: z        static CALLING_CONVENTION FUNCTION_RET (*_##FUNCTION_NAME)(FUNCTION_ARGS) = NULL; \\1 F  I7 i- |  z: A
        CALLING_CONVENTION FUNCTION_RET FUNCTION_NAME(FUNCTION_ARGS)
$ c7 |" {% A3 @! a
3 H) @3 T/ X. H0 a/ s! t+ w/ `5 Y5 Y/ X
等我回头翻译到VC里4 _9 e" G! A. ?9 W
待续
作者: shane007    时间: 2010-4-11 06:38
收到。等待你的vc版代码。
作者: scgame    时间: 2010-4-12 09:02
哦...那看来在不知道函数拿几个arguments的话是不能替换的吧# ^  A$ K- i& b  J8 K; `
那除非用的是GDI的createText画字的游戏,别的似乎还不能用hook解决啊
作者: shane007    时间: 2010-4-12 11:16
引用第4楼scgame于2010-04-12 09:02发表的 :
) c6 L, k- M4 C- \1 }' j哦...那看来在不知道函数拿几个arguments的话是不能替换的吧
7 [- a1 N& w+ {- c; `那除非用的是GDI的createText画字的游戏,别的似乎还不能用hook解决啊

* N; e; Q0 {4 y; P3 h. T7 Z, T8 h# d7 K
windows GDI 的API查查msdn就知道参数了,看vs里的头文件也能知道啊。
& G0 g$ e* o5 {6 `' |3 F* h这个工具对directx 的com 接口的hook还是不行的,需要用别的办法。0 s2 y0 ^* h4 _1 p8 @7 O3 Z

: N7 X1 ?! k$ H1 X对了,想等vc版的代码出来以后,我想安排你做exttextout的文本替换部分,行吗?; {8 Z8 I3 s2 Y" [
我会给你写个简单的设计书,你照着做即可。请先找一下关于hash的代码。
作者: scgame    时间: 2010-4-12 11:59
哦,solidji的不可以直接用吗?我是用CodeBlocks+MingW的,不用写成VC的我也可以
7 Y. F* Y! K3 h( B" g9 k/ Y2 V$ U: S. M. i+ S" }% l
这个我可以试试看,蛮有趣的& ?/ @- z) B; ?' h8 y( k6 {
是用hash链表把中文字"归类"吗?
作者: solidji    时间: 2010-4-12 15:24
directx 的com 接口的hook,) }  _: Q% L4 x
因为不是直接导出函数的DLL, 有很多接口是通过对象的方法来调用,  N( X7 {! }6 g+ M
无法这样通过枚举PE文件头里的导出模块名来取出某个"对象方法"7 X, {4 A* Y! O8 b8 k5 z2 k

- y4 n7 z/ x' |5 H* F! Z( M1 v007之前有篇贴子的办法才行,就是在创建对象的时候COM对象整个替换掉
作者: shane007    时间: 2010-4-12 17:07
引用第6楼scgame于2010-04-12 11:59发表的 :
, V, A( T" B' Y% w8 M  H& J  R( R哦,solidji的不可以直接用吗?我是用CodeBlocks+MingW的,不用写成VC的我也可以
6 t$ K3 b' w' W" a2 u- {( I  `8 w1 X8 [2 k/ a  H8 r
这个我可以试试看,蛮有趣的 ; V' o1 k8 p, Q. C% r0 {: G
是用hash链表把中文字"归类"吗?
1 L1 F8 r+ |& I" p8 Q, |7 u
3 V0 M2 x& s$ D+ e.......
2 c0 R6 E0 v' B; S1 d" i

* ^( Q2 f, q* |& `# y1 r最近几天我把设计书写好,你按要求编就行了,请关注。
作者: solidji    时间: 2010-4-13 20:15
非常遗憾的说,鉴于VC严格的格式检查,命名规则等原因。。。这份自动生成gcc的C代码很难改成通过VC编译的了; O8 M% Z$ P/ R
另外由于gdi32.dll是一个比较特殊的系统DLL,<windows.h>用到了大量由<wingdi.h>定义的的结构如LPDEVMODEA- J7 G" `! o! e2 @+ o+ l  J
所以无法通过 #define _WINGDI_ 来取消重复定义的问题  Z; s# ~6 D) i' a" c+ j
说白了就是你自己想生成一个gdi32.dll,这个DLL里的导出函数与原来的DLL一样,都有exttextout
0 J7 x- w# q) G2 n7 R# J) W$ c可是你自己定义导出函数exttextout的话,系统会提示你exttextout已经在wingdi.h里定义过了
) g5 n) q4 {9 U+ g, T0 g/ _3 u/ l- \& b如果是一般的DLL,直接不让wingdi.h载入就是了,可是windows.h又必须载入wingdi.h,这样就绕不开这个重定义的麻烦& m* c4 K" x9 _6 P. M' f4 Q5 Q9 O
- c; ~: G3 H! Z# ?% P8 S
我想的解决方法:
" g: i2 _$ E" g" K% N- Y6 R# m1,定义自己的名字空间namespace,将exttextout这些包含进去,或者/FORCE 这类强制链接命令强制跳过检查通过链接  V( C3 ]$ H$ g! q
2,去掉#include <windows.h>这一句,而自己用到的全部自己定义,(在很大量的情况下就比较麻烦)9 D0 a/ e; b5 w2 u& g+ m4 m* X
    #define DECLARE_HANDLE(n)   typedef struct n##__{int i;}*n' C, m/ x. `3 h
         DECLARE_HANDLE(HINSTANCE);
2 U+ z* P/ S/ a# c        typedef HINSTANCE HMODULE;5 w; I& U, z$ F! v8 R" w
        DECLARE_HANDLE(HWND);9 X5 K* t# w# f% {& c; z
        #define LPVOID              void *
* M: |6 j- N! X/ {2 I2 X& C& t        #define DWORD               unsigned int- R* Q' p5 N/ A' K6 V
        #define UINT                unsigned int. \" _$ {2 w, U* n5 g# _5 w
        #define LPCSTR              char& T& z9 z6 L/ J# m% m+ ?
       #define LPCTSTR             char
# u" s+ v7 M! C0 I; J3 U; z       .............像这样用到多少自己定义多少5 G3 b5 ?3 o8 b' e  r( Y% d6 r  M

. i* A1 |0 S# F2 i/ D3.改造def,使用函数转发器
% v# L$ [; y/ L6 N0 \在.def  文件里转发,4 p5 v3 h! N( k  M0 t4 d
EXPORTS
/ y8 m) T# s+ k3 a8 a, H& |  AbortDoc=myAbortDoc @11 F. `9 G* k: S! |5 c, l
  AbortPath=myAbortPath  @2
% c+ S% O$ F; n0 v0 t( z  ExtTextOutA=myExtTextOutA @222) M- A& ]8 B0 |- t9 c- n3 ]' M. o; r
然后.c里声明myExtTextOutA 来实现函数部分,这样导出函数就还是ExtTextOutA,但是转发到了myExtTextOutA ! f9 q; H$ U% ?7 ^
你实现myExtTextOutA 自然不会和wingdi.h出现重复定义的冲突了
: u; |- ~4 A( \& K' ?$ B; l; z6 o: _# B- V+ ^' x
算了,等我用函数转发器的办法另外实现一个吧,dllproxyskel完全拿他当个PE文件“导出函数”模块名导出器使用
作者: shane007    时间: 2010-4-13 20:39
收到,那我等你实现的版本。
作者: scgame    时间: 2010-4-14 07:56
我也碰到这个问题了,MingW的编译不了 [s:102]
作者: scgame    时间: 2010-4-14 12:39
发现有个叫APIHijack的库很受人推崇,终于把代码问题解决了,没有前面所说的问题,不过再编译他的cpp里的汇编出问题了...我觉得可能是我用code::blocks+mingW的关系,他给的例子我都编译不了 [s:102]) ~: Z+ R; K1 A% L
& j9 H% a3 q) m
先下个VC++试试看吧
作者: solidji    时间: 2010-4-14 15:34
标题: gdi32  code
改好了,用第一种方式实现的.
2 T- D. n8 e7 q8 m如果需要用到的系统头文件定义变量过多的话,可能不太适合,看你自己主要想实现什么功能吧
' v8 ]" R( c( l& w  @3 w7 F; A# o1 S$ k% \, C$ Y& j* c
代码先贴出来,gdi32.h里的东西是我从生成的gdi32.c里拷贝 分离出来的,原本是想改进一下, 2 M/ Y- ^( s1 N# n- G" a
让gdi32.c里#include <windows.h>正常使用,gdi32.h里放重复定义的导出函数
3 Y6 Z7 W, a5 F0 M: E+ r0 `4 w这样尽量减少自己需要自定义的结构. 这一步还没分离完成,不过仅仅是想HOOK ExtTextOutA的话已经够用了
" z4 C9 ~& J' z[attach]15911[/attach]
5 b2 x# v; L) L$ ^8 z
) [* f; O1 l, O8 g" D, X相对原始生成.c文件,修改的部分有
3 _) w* @$ A' y" C* ]# b# a1,    //_ExtTextOutA = (void *)GetProcAddress(hm, "ExtTextOutA");
! V7 T( y' ]' s( n    _ExtTextOutA = (ExtTextOutA_)GetProcAddress(hm, "ExtTextOutA");
0 P9 R5 f: w4 H' w2,//PROXY_FUNCTION(ExtTextOutA)
( F$ u* y/ `; l' d7 n+ Z# ^    由自己定义的钩子函数ExtTextOutA取代
: i: y8 @- G9 ?! Q- R, N3,gcc宏移值
9 E+ x; i# Q, w, J0 R#define POP_EBP     __asm{pop ebp}
+ s. _2 b8 g7 e! J* q#define PROXY_FUNCTION(FUNCTION_NAME) \\
8 i, F5 K5 S  b2 c6 [( I        PROXY_PROTOTYPE(*_##FUNCTION_NAME) = 0; \\ , j) H/ _. \, I: i2 L: d
        PROXY_PROTOTYPE(FUNCTION_NAME) { \\
1 B1 B& E9 p, J# w4 A        POP_EBP __asm {jmp _##FUNCTION_NAME} \\ " N5 r6 V; R) O
        } + x. i3 M* J5 E' v2 _" ?+ u

) z) l3 Q4 t$ U3 D9 Z记得为VC链接命令行添加 /DEF:"gdi32.def" ' o* b- F/ V* H6 K& ?
PS:APIhijack好像只是打钩子,而不是伪造DLL
作者: shane007    时间: 2010-4-14 17:14
收到,多谢了。
* h  Z# R/ U" A7 D% Y* K对了,是否能加上一个vc的工程文件?, x" U- C6 I  K2 ^% }" ?3 x
还有,_ExtTextOutA 建议改名为real_ExtTextOutA,更容易明白。
+ {8 a( ?) u6 \7 k0 W我们修改过的ExtTextOutA等函数能否独立出来放在一个文件里,这样结构更清晰。
作者: solidji    时间: 2010-4-14 17:53
这样命名是根据原作者的风格,我整理下在改吧,
9 C5 N# p& [# A: @* W  W0 m& P% ^看能不能把重定义的部分分离得更彻底一些
作者: scgame    时间: 2010-4-14 20:39
我不明白ExtTextOutA_是哪来的 [s:105]
0 a6 Q3 U2 H: }, qp.s 原来那个叫钩子.我还是第一次接触这个概念,嘿嘿
作者: scgame    时间: 2010-4-14 21:56
VC 和VC++有区别吗! k+ h, F8 l; p; M
我下了个VC++ 2008的,编译不了啊. X1 f* f+ i" P8 n$ Y# ~- E
    _CreateFontIndirectA = (void *)GetProcAddress(hm, "CreateFontIndirectA");
3 p) k% q4 T9 f3 V) }, z+ O5 J等等都有这么个错4 R3 G- s- Z! ]& O% c
Conversion from 'void*' to pointer to non-'void' requires an explicit cast+ M5 A/ Q; p* V  s; W

$ L0 ]! C, T3 A我先用钩子试试看看能不能编译
作者: shane007    时间: 2010-4-14 22:49
试试看http://sourceforge.net/projects/dev-cpp/6 ~0 V7 t7 ~! A! v6 F3 K
这个呢?是gcc的。
作者: scgame    时间: 2010-4-14 23:52
原来是VC++是cpp不是c的原因  [s:116]
作者: scgame    时间: 2010-4-19 05:46
我再来求救一下,编译好的gd32.dll好像没起作用嘛,我加了个while(1);
6 ]. h0 Z9 q# @  L. H( ^运行了个测试程序还是没成功啊: C& ^2 O: [7 Q% P" }/ w$ D( f% v

* x5 Y5 Q0 ^! o  n$ k# E我还是看得不是很懂,比如说' H; [1 S4 Y# G8 J  j6 f" m
这个BOOL,有一个#define,还有一个typedef7 m, D% D) a; m
那在我们改的函数那里就是+ G& m& T# e7 f7 |: I  C# x
BOOL ExtTextOutA(blah blah)8 B" ~) W& c- J+ H  w* I
那是不是说我们的定义就是
  1. (WINAPI *ExtTextOutA_)(
  2.                 HDC         hdc,
  3.                 int         x,
  4.                 int         y,
  5.                 unsigned int         flags,
  6.                 const RECT* lprect,
  7.                 LPCSTR      str,
  8.                 unsigned int        count,
  9.                 const int*  lpDx
  10. );
复制代码
还有就是不明白
2 ?; c# |2 r1 o9 J; x# z$ ~$ [: ~, VExtTextOutA_ _ExtTextOutA = 0;' `# T. z) q9 X) A
这个ExtTextOutA_和_ExtTexOutA又是怎么定义的
作者: solidji    时间: 2010-4-20 11:34
typedef BOOL (WINAPI *ExtTextOutA_)& ]1 U. d& `& O& @5 t
就是定义了一个函数类型,我们故意把他定义成和原始的API ExtTextOutA一样  P1 Y$ N1 }6 Z. T  s
就是为了ExtTextOutA_ _ExtTextOutA 声明一个与原始API ExtTextOutA一样一样的函数指针
* e6 L! {5 I9 P; d7 _1 {5 K% D然后_ExtTextOutA = (ExtTextOutA_)GetProcAddress(hm, "ExtTextOutA"); 为这个函数指针赋值为原始API的函数地址
8 N1 _' C) g2 _7 R9 n$ o$ T- n这样_ExtTextOutA  就是real_ExtTextOutA的意思,完全把他当原始API ExtTextOutA 来使用就是了
4 Y$ A2 n- W* {, G+ m* P& J9 }7 o# O1 K: z* ~
你编译的DLL有点问题,我打开PE文件找到  ExtTextOutA  部分,发现虽然你导出了ExtTextOutA ,但却不是你实现的那个
  j& |& m1 w+ ]0 N6 c0 e
+ @. d+ q& V) h1 Q6 y* E
( j( t9 p9 W# i[attach]15939[/attach]
1 N& r: @( c. i8 }
, c9 G, m% n% ?4 \
  1. //6A80偏移处你 实际上的函数体代码,可以看到只是个简单的代理,明显不是你自己实现的那个
  2. 10006A80 >  8B4424 20           mov eax,dword ptr ss:[esp+20]
  3. 10006A84    8B4C24 1C           mov ecx,dword ptr ss:[esp+1C]
  4. 10006A88    8B5424 18           mov edx,dword ptr ss:[esp+18]
  5. 10006A8C    50                  push eax
  6. 10006A8D    8B4424 18           mov eax,dword ptr ss:[esp+18]
  7. 10006A91    51                  push ecx
  8. 10006A92    8B4C24 18           mov ecx,dword ptr ss:[esp+18]
  9. 10006A96    52                  push edx
  10. 10006A97    8B5424 18           mov edx,dword ptr ss:[esp+18]
  11. 10006A9B    50                  push eax
  12. 10006A9C    8B4424 18           mov eax,dword ptr ss:[esp+18]
  13. 10006AA0    51                  push ecx
  14. 10006AA1    8B4C24 18           mov ecx,dword ptr ss:[esp+18]
  15. 10006AA5    52                  push edx
  16. 10006AA6    50                  push eax
  17. 10006AA7    51                  push ecx
  18. 10006AA8    FF15 80520110       call dword ptr ds:[10015280]                            ; GDI32.ExtTextOutA
  19. 10006AAE    A3 24570110         mov dword ptr ds:[10015724],eax
  20. 10006AB3    C3                  retn
复制代码

, Z. A% z; d% I4 Q+ T$ E
9 S0 ]+ q/ ~1 `2 E0 u* D- A1 b我想主要是你定义ExtTextOutA 的时候漏了个int, VC认为这是你另外一个内部函数,而导出的是另外一个
  1. int ExtTextOutA(
  2. HDC         hdc,
  3. int         x,
  4. int         y,
  5. unsigned int         flags,
  6. const RECT* lprect,
  7. LPCSTR      str,
  8. unsigned int        count,
  9. const int*  lpDx)
  10. {
  11.   
  12. // MessageBox(0, "i'm in ExtTextOutA now!", 0, 0);//做你想做的事情
复制代码
( d; ~1 w5 b# _* d7 Z2 p
另外附上我重新帮你编译过的DEBUG版DLL
  y5 H4 x5 L( n  V3 ~  S
* ^; U) W, D, g! H, f* S$ b[attach]15940[/attach]
作者: shane007    时间: 2010-4-20 11:53
solidji,请放代码,把scgame错误的地方注释说明一下,便于大家学习。
作者: solidji    时间: 2010-4-20 12:19
他的代码就漏了个函数返回类型BOOL或int,
0 ?' e3 |8 \" X2 A2 D3 {* Q) C
int
ExtTextOutA() A4 E& F8 r0 x: ]3 q
导致了导出函数链接没对
# d5 Z2 I1 j+ `' i, H% P. M直接看他的代码就行了
作者: scgame    时间: 2010-4-20 21:31
啊,原来是这样,
2 M. T' K/ Y  z5 p% v7 k谢谢,solidji5 u3 c; t% r- J% g( p
solidji能不能再推荐些教程' d0 `. D7 o3 r
我对这方面(导出,API)之类的不太了解




欢迎光临 冒险解谜游戏中文网 ChinaAVG (https://chinaavg.com/) Powered by Discuz! X3.2