首页软件新闻工具软件操作系统办公软件聊天工具多媒体网页制作网页设计网站运营平面设计作品欣赏数据库程序组网
Ghost | Kugoo | 遨游 | Xp | Dw | Fw | Flash | Ps | 迅雷 | CD | ill | CAD | 五笔 | Word | Excel | Wps | Msn | QQ | 学电脑 | Asp | Php | Jsp | 3Dmax | 海报 | 包装 | 标志 | 地产 | 插画

《Undocumented Windows 2000 Secrets》翻译 --- 第五章(2)

来源:佚名(读取中...) 2005-8-17 【字体: 】 切换为
通用解决方案的主要障碍是 C 语言的典型参数传递机制。就像你知道的, C 通常在调用函数的入口点之前会将函数参数传递到 CPU 堆栈中。根据函数需要的参数数量,参数堆栈的大小将有很大的差别。 windows 2000 的 248 个 Native API 函数需要的参数堆栈的大小位于 0 到 68 字节。

#define SPY_CALLS 0x00000100 // max api call nesting level

#define SDT_SYMBOLS_NT4 0xD3

#define SDT_SYMBOLS_NT5 0xF8

#define SDT_SYMBOLS_MAX SDT_SYMBOLS_NT5

// -----------------------------------------------------------------

typedef struct _SPY_HOOK_ENTRY

{

NTPROC Handler;

PBYTE pbFormat;

}

SPY_HOOK_ENTRY, *PSPY_HOOK_ENTRY, **PPSPY_HOOK_ENTRY;

#define SPY_HOOK_ENTRY_ sizeof (SPY_HOOK_ENTRY)

// -----------------------------------------------------------------

typedef struct _SPY_CALL

{

BOOL fInUse; // set if used entry

HANDLE hThread; // id of calling thread

PSPY_HOOK_ENTRY pshe; // associated hook entry

PVOID pCaller; // caller's return address

DWORD dParameters; // number of parameters

DWORD adParameters [1+256]; // result and parameters

}

SPY_CALL, *PSPY_CALL, **PPSPY_CALL;

#define SPY_CALL_ sizeof (SPY_CALL)

// -----------------------------------------------------------------

SPY_HOOK_ENTRY aSpyHooks [SDT_SYMBOLS_MAX];

// -----------------------------------------------------------------

// The SpyHook macro defines a hook entry point in inline assembly

// language. The common entry point SpyHook2 is entered by a call

// instruction, allowing the hook to be identified by its return

// address on the stack. The call is executed through a register to

// remove any degrees of freedom from the encoding of the call.

#define SpyHook \

__asm push eax \

__asm mov eax, offset SpyHook2 \

__asm call eax

// -----------------------------------------------------------------

// The SpyHookInitializeEx() function initializes the aSpyHooks[]

// array with the hook entry points and format strings. It also

// hosts the hook entry points and the hook dispatcher.

// -----------------------------------------------------------------

// The SpyHookInitializeEx() function initializes the aSpyHooks[]

// array with the hook entry points and format strings. It also

// hosts the hook entry points and the hook dispatcher.

void SpyHookInitializeEx (PPBYTE ppbSymbols,

PPBYTE ppbFormats)

{

DWORD dHooks1, dHooks2, i, j, n;

__asm

{

jmp SpyHook9

ALIGN 8

SpyHook1: ; start of hook entry point section

}

// the number of entry points defined in this section

// must be equal to SDT_SYMBOLS_MAX (i.e. 0xF8)

SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook //08

SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook //10

SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook //18

SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook //20

SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook //28

SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook //30

SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook //38

SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook //40

SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook //48

SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook //50

SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook //58

SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook //60

SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook //68

SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook //70

SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook //78

SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook //80

SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook //88

SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook //90

SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook //98

SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook //A0

SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook //A8

SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook //B0

SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook //B8

SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook //C0

SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook //C8

SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook //D0

SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook //D8

SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook //E0

SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook //E8

SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook //F0

SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook SpyHook //F8

__asm

{

SpyHook2: ; end of hook entry point section

pop eax ; get stub return address

pushfd

push ebx

push ecx

push edx

push ebp

push esi

push edi

sub eax, offset SpyHook1 ; compute entry point index

mov ecx, SDT_SYMBOLS_MAX

mul ecx

mov ecx, offset SpyHook2

sub ecx, offset SpyHook1

div ecx

dec eax

mov ecx, gfSpyHookPause ; test pause flag

add ecx, -1

sbb ecx, ecx

not ecx

lea edx, [aSpyHooks + eax * SIZE SPY_HOOK_ENTRY]

test ecx, [edx.pbFormat] ; format string == NULL?

jz SpyHook5

push eax

push edx

call PsGetCurrentThreadId ; get thread id

mov ebx, eax

pop edx

pop eax

cmp ebx, ghSpyHookThread ; ignore hook installer

jz SpyHook5

mov edi, gpDeviceContext

lea edi, [edi.SpyCalls] ; get call context array

mov esi, SPY_CALLS ; get number of entries

SpyHook3:

mov ecx, 1 ; set in-use flag

xchg ecx, [edi.fInUse]

jecxz SpyHook4 ; unused entry found

add edi, SIZE SPY_CALL ; try next entry

dec esi

jnz SpyHook3

mov edi, gpDeviceContext

inc [edi.dMisses] ; count misses

jmp SpyHook5 ; array overflow

SpyHook4:

mov esi, gpDeviceContext

inc [esi.dLevel] ; set nesting level

mov [edi.hThread], ebx ; save thread id

mov [edi.pshe], edx ; save PSPY_HOOK_ENTRY

mov ecx, offset SpyHook6 ; set new return address

xchg ecx, [esp+20h]

mov [edi.pCaller], ecx ; save old return address

mov ecx, KeServiceDescriptorTable

mov ecx, [ecx].ntoskrnl.ArgumentTable

movzx ecx, byte ptr [ecx+eax] ; get argument stack size

shr ecx, 2

inc ecx ; add 1 for result slot

mov [edi.dParameters], ecx ; save number of parameters

lea edi, [edi.adParameters]

xor eax, eax ; initialize result slot

stosd

dec ecx

jz SpyHook5 ; no arguments

lea esi, [esp+24h] ; save argument stack

rep movsd

SpyHook5:

mov eax, [edx.Handler] ; get original handler

pop edi

pop esi

pop ebp

pop edx

pop ecx

pop ebx

popfd

xchg eax, [esp] ; restore eax and...

ret ; ...jump to handler

SpyHook6:

push eax

pushfd

push ebx

push ecx

push edx

push ebp

push esi

push edi

push eax

call PsGetCurrentThreadId ; get thread id

mov ebx, eax

pop eax

mov edi, gpDeviceContext

lea edi, [edi.SpyCalls] ; get call context array

mov esi, SPY_CALLS ; get number of entries

SpyHook7:

cmp ebx, [edi.hThread] ; find matching thread id

jz SpyHook8

add edi, SIZE SPY_CALL ; try next entry

dec esi

jnz SpyHook7

push ebx ; entry not found ?!?

call KeBugCheck

SpyHook8:

push edi ; save SPY_CALL pointer

mov [edi.adParameters], eax ; store NTSTATUS

push edi

call SpyHookProtocol

pop edi ; restore SPY_CALL pointer

mov eax, [edi.pCaller]

mov [edi.hThread], 0 ; clear thread id

mov esi, gpDeviceContext

dec [esi.dLevel] ; reset nesting level

dec [edi.fInUse] ; clear in-use flag

pop edi

pop esi

pop ebp

pop edx

pop ecx

pop ebx

popfd

xchg eax, [esp] ; restore eax and...

ret ; ...return to caller

SpyHook9:

mov dHooks1, offset SpyHook1

mov dHooks2, offset SpyHook2

}

n = (dHooks2 - dHooks1) / SDT_SYMBOLS_MAX;

for (i = j = 0; i < SDT_SYMBOLS_MAX; i++, dHooks1 += n)

{

if ((ppbSymbols != NULL) && (ppbFormats != NULL) &&

(ppbSymbols [j] != NULL))

{

aSpyHooks [i].Handler = (NTPROC) dHooks1;

aSpyHooks [i].pbFormat =

SpySearchFormat (ppbSymbols [j++], ppbFormats);

}

else

{

aSpyHooks [i].Handler = NULL;

aSpyHooks [i].pbFormat = NULL;

}

}

return;

}

列表 5-3. Hook Dispatcher 的实现方式

SpyHook 宏实际是什么呢?在 SpyHookInitializeEx() 函数中,这个宏被重复了多大 248 ( 0xF8 )次,这正好是 windows 2000 Native API 函数的数目。在 列表 5-3 的顶部,这个数目被定义为 SDT_SYMBOLS_MAX 常量,该宏可以使 SDT_SYMBOLS_NT4 或 SDT_SYMBOLS_NT5 。因为我打算支持 Windows NT 4.0 。回到 SpyHook 宏上来:该宏调用的汇编语句在 列表 5-4 中给出了。每个 SpyHook 都产生同样的三行代码:

1. 第一行,将当前 EAX 寄存器的内容保存到堆栈中。

2. 第二行,将 SpyHook2 的线性地址保存到 EAX 中。

3. 第三行,调用 EAX 中的地址(即: call eax )。

你可能会惊讶:当这个 CALL 返回时会发生什么。接下来的一组 SpyHook 代码会被调用吗?不 ---- 这个 CALL 并不支持返回,因为在到达 SpyHook2 之后,这个 CALL 的返回地址就会被立即从堆栈中移出, 列表 5-4 最后的 POP EAX 指令可以证明这一点。这种看上去毫无疑义的代码在古老的汇编程序设计时代曾被广泛的讨论的一种技巧,就像今天我们讨论面向对象的程序设计一样。当 ASM 老大级人物需要构建一个数组,而此数组的每一项都有类似的进入点,但却需要被分派到独立的函数时,就会采用这种技巧。对所有进入点使用几乎相同的代码可以保证它们之间有相等的间隔,因此客户端就可以很容易的通过 CALL 指令的返回地址计算出进入点的在数组中的索引值,数组的基地址和大小以及数组中共有多少项

上一页  [1] [2] [3] 下一页

    相关新闻
    用户评论
数据载入中,请稍后……
评论内容:不能超过250字,不需审核,请自觉遵守互联网相关政策法规。
发表评论: 匿名发表 用户名: loading 位网友发表了评论 查看评论
(0/250)
    推广服务
IT部落推荐阅读
·生活服务
·精彩图文
·赞助商链接