分享
 
 
 

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

王朝system·作者佚名  2006-11-24
窄屏简体版  字體: |||超大  

第五章 监控 Native API 调用

翻译: Kendiv( [url=http://www.pccode.net].net"fcczj@263.net )

更新: Thursday, February 24, 2005

声明:转载请注明出处,并保证文章的完整性,本人保留译文的所有权利。

汇编语言的救援行动

通用解决方案的主要障碍是 C 语言的典型参数传递机制。就像你知道的, C 通常在调用函数的入口点之前会将函数参数传递到 CPU 堆栈中。根据函数需要的参数数量,参数堆栈的大小将有很大的差别。 Windows 2000 的 248 个 Native API 函数需要的参数堆栈的大小位于 0 到 68 字节。这使得编写一个唯一的 hook 函数变得非常困难。微软的 Visual C/C++ 提供了一个完整的汇编( ASM )编译器,该编译器可处理复杂度适中的代码。具有讽刺意味的是,在我的解决方案中所使用的汇编语言的优点正是通常被认为是其最大缺点的特性:汇编语言不提供严格的类型检查机制。只要字节数正确就一切 OK 了,你可以在任何寄存器中存储几乎所有的东西,而且你可以调用任何地址,而不需要关心当前堆栈的内容是什么。尽管这在应用程序开发中是一种很危险的特性,但这确实最容易获取的:在汇编语言中,很容易以不同的参数堆栈调用同一个普通的入口点,稍后将介绍的 API hook Dispatcher 将采用这一特性。

通过将汇编代码放入以关键字 __asm 标记的分隔块中就可调用 Microsoft Visual C/C++ 嵌入式汇编程序。嵌入式汇编缺少宏定义以及 Microsoft's big Macro Assembler ( MASM )的评估能力,但这些并没有严重的限制它的可用性。嵌入式汇编的最佳特性是:它可以访问所有的 C 变量和类型定义,因此很容易混合 C 和 ASM 代码。不过,当在 C 函数中包含有 ASM 代码时,就必须遵守 C 编译器的某些重要的基本约定,以避免和 C 代码的冲突:

l C 函数调用者假定 CPU 寄存器 EBP 、 EBX 、 ESI 和 EDI 已经被保存了。

l 如果在单一函数中,将 ASM 代码和 C 代码混合在一起,则需要小心的保存 C 代码可能保存在寄存器中的中间值。总是保存和恢复在 __asm 语句中使用的所有寄存器。

l 8 位的函数结果( CHAR , BYTE 等)由寄存器 AL 返回。

l 16 位的函数结果( SHORT , WORD 等)由寄存器 AX 返回。

l 32 位的函数结果( INT , LONG , DWORD 等)由寄存器 EAX 返回。

l 64 位的函数结果( __int64 , LONGLONG , DWORDLONG 等)由寄存器对 EDX : EAX 返回。寄存器 EAX 包含 0 到 31 位, EDX 保存 32 到 63 位。

l 有确定参数的函数通常按照 __stdcall 约定进行参数的传递。从调用者的角度来看,这意味着在函数调用之前参数必须以相反的顺序压入堆栈中,被调用的函数负责在返回前从堆栈中移除它们。从被调用的函数的角度来看,这意味着堆栈指针 ESP 指向调用者的返回地址,该地址紧随最后一个参数(按照原始顺序)。( 译注 :这意味着,最先被压入堆栈的是函数的返回地址 )参数的原始顺序被保留下来,因为堆栈是向下增长的,从高位线性地址到低位线性地址。因此,调用者压入堆栈的最后一个参数(即,参数 #1 )将是由 ESP 指向的数组中的第一个参数。

l 某些有确定参数的 API 函数,如著名的 C 运行时库函数(由 ntdll.dll 和 ntoskrnl.exe 导出),通常使用 __cdecl 调用约定,该约定采用与 __stdcall 相同的参数顺序,但强制调用者清理参数堆栈。

l 由 __fastcall 修饰的函数声明,则希望前两个参数位于 CPU 寄存器 ECX 和 EDX 中。如果还需要更多的参数,它们将按照相反的顺序传入堆栈,最后由被调用者清理堆栈,这和 __stdcall 相同。

; this is the function's prologue

push ebp ; save current value ebp

mov ebp, esp ; set stack frame base address

sub esp, SizeOfLocalStorage ; create local storage area

; this is the function's epilogue

mov esp, ebp ; destroy local storage area

pop ebp ; restore value of ebp

ret

列表 5-2. 堆栈帧,序言和尾声

l 很多 C 编译器在进入函数后,会立即针对函数参数构建一个堆栈帧,这需要使用 CPU 的基地址指针寄存器 EBP 。 列表 5-2 给出了此代码,这通常被称为函数的“序言”和“尾声”。有些编译器采用更简洁的 i386 的 ENTER 和 LEAVE 操作符,在“序言被执行后,堆栈将如 图 5-3 所示。 EBP 寄存器作为一分割点将函数的参数堆栈划分为两部分:( 1 )局部存储区域,该区域中包含所有定义于函数范围内的局部变量( 2 )调用者堆栈,其中保存有 EBP 的备份和返回地址。注意,微软的 Visual C/C++ 的最新版中默认不使用堆栈帧。替代的是,代码通过 ESP 寄存器访问堆栈中的值,不过这需要指定变量相对于当前栈顶的偏移量。这种类型的代码非常难以阅读,因为每个 PUSH 和 POP 指令都会影响 ESP 的值和所有参数的偏移量。在此种情况下不再需要 EBP ,它将作为一个附加的通用寄存器。

l 在访问 C 变量时必须非常小心。经常出现在嵌入式 ASM 中的 bug 是:你将一个变量的地址而不是它的值加载到了寄存器中。使用 ptr 和 offset 地址操作符存在潜在的二义性。例如,指令: mov eax , dword ptr SomeVariable 将加载 DWORD 类型的 SomeVariable 变量的值到 EAX 寄存器,但是, mov eax , offset SomeVariable 将加载它的线性地址到 EAX 中。

图 5-3. 堆栈帧的典型布局

Hook 分派程序(Hook Dispatcher)

这部分的代码将较难理解。编写它们花费了我很多时间,而且在这一过程中我还欣赏了无数的蓝屏。我最初的方法是提供一个完全用汇编语言编写的模块。不过,这个方法在链接阶时带来了很大的麻烦,因此,我改为在 C 模块中使用嵌入式汇编。为了避免创建另一个内核模式的驱动程序,我决定将 hook 代码整合到 Spy 设备驱动程序中。还记得在 表 4-2 底部列出的形如 SPY_IO_HOOK_* 的 IOCTL 函数吗?现在我们将和它们来一次亲密接触。后面的示列代码来自 w2k_spy.c 和 w2k_spy.h ,可以在随书 CD 的 \src\w2k_spy 中找到它们。

列表 5-3 的核心部分是 Native API Hook 机制的实现代码。该列表开始处是一对常量和结构体定义,后面的 aSpyHooks[] 需要它们。紧随这个数组的是一个宏,该宏实际上是三行嵌入式汇编语句,这三行汇编语句非常重要,稍后我将介绍它们。 列表 5-3 的最后一部分用来建立 SpyHookInitializeEx() 函数。猛地一看,这个函数的功能似乎很难理解。该函数组合了一下两个功能:

1. SpyHookInitializeEx() 的表面部分包括一段用来设置 aSpyHooks[] 数组的 C 代码,这部分代码用 Spy 设备的 Hook 函数指针以及与之相关联的字符串格式协议来初始化 aSpyHooks[] 数组。 SpyHookInitializeEx() 函数可被分割为两部分:第一部分到第一个 __asm 语句后的 jmp SpyHook9 指令。第二部分显然是从 ASM 标签 ----SpyHook9 开始,该部分位于第二个 __asm 语句块的最后。

2. SpyHookInitializeEx() 的内部部分包括位于两块 C 代码段之间的所有代码。这部分在一开始大量使用了 SpyHook 宏,紧随其后的是一大块复杂的汇编代码。可能你已经猜到了,这些汇编代码就是前面提到的通用 Hook 例程。

#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

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

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有