;8 L0 a; n" p0 r! Y3 ` // 这部分的地址内存是属于win32进程共享的 if (!isnt() && ((dword)hmodule >= 0x80000000)) / K+ p0 y2 ^2 x- H' ~! \* s { 1 I( \# p& o3 o+ x/ y; V/ O$ F) W' p _assert(false); setlasterrorex(error_invalid_handle, sle_error); return false; 8 t8 y# `) _- K6 H( R2 m } // 清零 if (paorigfuncs) memset(paorigfuncs, null, sizeof(proc)); % I3 g. b! B# h- j W0 h% g+ N7 ~
// 调用getnamedimportdescriptor()函数,来得到hmodule -- 即我们需要 // 截获的函数所在的dll模块的引入描述符(import descriptor) pimage_import_descriptor pimportdesc = getnamedimportdescriptor(hmodule, szimportmodule); 0 I" } K: ]. @# t9 d" ^7 b if (pimportdesc == null) / x, H5 z: R; z return false; // 若为空,则模块未被当前进程所引入 ( B) ~" l+ `7 i! X! 2 k8 {/ N; ~ ; i# S. g' \8 |( c+ Q // 从dll模块中得到原始的thunk信息,因为pimportdesc->firstthunk数组中的原始信息已经 & Y( F, @& c( o. k$ d5 \ // 在应用程序引入该dll时覆盖上了所有的引入信息,所以我们需要通过取得pimportdesc->originalfirstthunk # T( b: L$ [( _9 E( I // 指针来访问引入函数名等信息 ! A. N: y6 Y( v0 m4 N- z" W# @3 ` pimage_thunk_data porigthunk = makeptr(pimage_thunk_data, hmodule, pimportdesc->originalfirstthunk);
// 从pimportdesc->firstthunk得到image_thunk_data数组的指针,由于这里在dll被引入时已经填充了 4 ]6 i. b1 D! |! 4 P4 B" | // 所有的引入信息,所以真正的截获实际上正是在这里进行的 - \8 O" G1 Z& {/ D% I5 |4 ^ pimage_thunk_data prealthunk = makeptr(pimage_thunk_data, hmodule, pimportdesc->firstthunk); v1 a4 j# L( z+ h# x
// 穷举image_thunk_data数组,寻找我们需要截获的函数,这是最关键的部分! 4 ~9 Z( P, ^4 J6 ^# @ while (porigthunk->u1.function) { // 只寻找那些按函数名而不是序号引入的函数 & S3 \6 ( d5 k0 x$ ] if (image_ordinal_flag != (porigthunk->u1.ordinal & image_ordinal_flag)) { // 得到引入函数的函数名 ) C8 o, H, Q9 K9 k) ]. r( D pimage_import_by_name pbyname = makeptr(pimage_import_by_name, hmodule, porigthunk->u1.addressofdata); 3 u2 l/ x! x9 B1 C: Y% q' [) m# r7 S: G // 如果函数名以null开始,跳过,继续下一个函数 if (’\0’ == pbyname->name[0]) continue; - q1 }: x! _1 B/ l% E/ I+ S6 E5 t# k
// bdohook用来检查是否截获成功 bool bdohook = false; ) m6 A4 q* ~5 C
// 检查是否当前函数是我们需要截获的函数 if ((pahookfunc.szfunc[0] == pbyname->name[0]) && * @* Y* V/ c. G7 A9 n0 c (strcmpi(pahookfunc.szfunc, (char*)pbyname->name) == 0)) ) P9 h8 T. |6 t3 c, ]" { g; i3 w { $ f- a2 n' \# \& L: L7 Q4 D // 找到了! if (pahookfunc.pproc) bdohook = true; ; c q# c1 H4 E3 P) Z o& i } & u: y4 E% |! D u7 N if (bdohook) # m! O: p/ G3 B8 b { // 我们已经找到了所要截获的函数,那么就开始动手吧 ; E' \. T- k# I! @ // 首先要做的是改变这一块虚拟内存的内存保护状态,让我们可以自由存取 2 R: n5 h, Q% m5 c/ memory_basic_information mbi_thunk; virtualquery(prealthunk, &mbi_thunk, sizeof(memory_basic_information)); 7 n7 , o2 G& + z _assert(virtualprotect(mbi_thunk.baseaddress, mbi_thunk.regionsize, 3 U. K: H* Y& K& q( U8 x page_readwrite, &mbi_thunk.protect)); & g: U3 \7 W# O% n! G
// 保存我们所要截获的函数的正确跳转地址 if (paorigfuncs) paorigfuncs = (proc)prealthunk->u1.function; {+ N; J5 ^- u0 q. D, w; c
// 将image_thunk_data数组中的函数跳转地址改写为我们自己的函数地址! // 以后所有进程对这个系统函数的所有调用都将成为对我们自己编写的函数的调用 - r6 F0 " O. B4 M- k prealthunk->u1.function = (pdword)pahookfunc.pproc; 4 F* u: Y; K& ^ 1 g2 U% P4 P3 k) {6 ]' |+ |