安全中国首页 > 文章中心 > 编释语言
 
安全中国网友投稿专用上传FTP空间:
Ftp服务器:download.anqn.com
Ftp端口:21
用户名:anqn
密 码:anqn.com
 

笑解 API 函数 --API 绝密档案系列之一

更新时间:2008-3-4 0:49:23
责任编辑:流火
热 点:
1. HMODULE GetModuleHandle(
LPCTSTR lpModuleName // address of module name to return handle 
// for
);

GetModuleHandle 实际上分为两个函数

GetModuleHandleA--处理 Ansi 字符串
GetModuleHandleW--处理 Unicode 字符串

其实真正干活的函数是,GetModuleHandleW (指NT以后的系统),GetModuleHandleA 只不过将用户输入的 Ansi 字符串转成 Unicode 字符串然后就直接调用 GetModuleHandleW,所以在 OD 中如果下断拦截这个函数,直接拦截 GetModuleHandleW 就可以了,保险一个都跑不掉。我看一些新手写 Hook 程序时往往不厌其烦的将每个函数都“沟”一下,其实大可不必,随着我的文章深入,你会发现一个基本原则--千条江河归大海,大部分的调用其实最后都是进入最底层的 ntoskrnl.exe、Hal.dll、和其他几个内核程序。而我们平常打交道最多的 Kernel32.dll 和 ntdll.dll 其实只是对底层函数进行了包装(当然对于某些ring3层的特定功能还是自己完成的),相当于一个接口,起一个中转和隔离的作用,将用户的函数调用进行预处理,比如检测用户参数的合法性,对用户参数进行重新排序(底层函数的参数排列顺序有时和用户层不同,这样可以防止你轻易的弄明白底层在干什么),将用户的调用分离拆解为若干个更为细小的调用,因为底层函数分类往往更细,这样比较灵活。
使用 GetModuleHandle 函数,在高级语言中可以直接写成:
hMod = GetModuleHandle(lpModuleName); 
编译器会根据参数的性质自行决定调用那一个函数,但在汇编中却不能这样使用,你必须明确的指明你要使用那一个函数。另外在OD中下断点,你也必须明确的指明对那一个函数下断,例如在OD中,进入CPU窗口,按Ctrl-G,然后输入GetModuleHandle,OD会告诉你 “未识的标识符”,你必须清楚的告诉 OD 你到底要在那一个函数下断,是 A 还是 W。按前面的说法其实你只要下 GetModuleHandleW 就可以了(当然有时候在A下断,比较容易知道程序是从那里调用的,如果程序使用的是A调用)。

俗话说,口说无凭。你怎么知道那两个还是最后变成了一个?
看雪老大也在qduwg的文章后说:

QUOTE:
不过这三个函数的定义只需要Google就能找到相关文档,因为太常用,不光是脱壳,编程是经常用的。
现在的强壳都不直接调用这些函数了,都自己实现。
其后跟贴更有"牛B王"--nbw 惊人的评论:

QUOTE:
可以参考以下MSDN。写壳都是自己实现。

以前自己能写个GetProcAddress就觉得很不错了,后来看高手写虚拟机,半小时模拟出来LoadLibrary,那个让偶惊啊。。。。
我没有他们那样的水平,自己不会写,人都说半瓶醋晃荡,醋瓶满了就不响了,我这个瓶子还没有满,所以你们有幸能看到这些垃圾文章(当然也是为了骗一点"加精",风光风光),等有一天我的瓶子也满了(最好能够做到),也就只会“啊...”了。

既然如此,那就只好看看老盖是怎么做的,这个函数在 Kernel32.dll 中,你可能会问,你怎么知道在Kernel32.dll中的?qduwg 老师在翻译文中可惜漏掉了可能他认为不重要的信息:

QuickInfo
Windows NT: Requires version 3.1 or later.
Windows: Requires Windows 95 or later.
Windows CE: Unsupported.
Header: Declared in winbase.h.
Import Library: Use kernel32.lib. //这里指明了函数的归宿
Unicode: Implemented as Unicode and ANSI versions on Windows NT.

See Also
Dynamic-Link Libraries Overview, Dynamic-Link Library Functions, FreeLibrary, GetModuleFileName, GetProcAddress, LoadLibrary,LoadResource 

现在我们来看看 GetModuleHandleA 的具体操作:


77E80B1A ; HMODULE __stdcall GetModuleHandleA(LPCSTR lpModuleName)
77E80B1A public GetModuleHandleA
77E80B1A GetModuleHandleA proc near ; CODE XREF: sub_77E684C2+2p
77E80B1A ; CreateRemoteThread+FBp ...
77E80B1A
77E80B1A lpModuleName= dword ptr 8
77E80B1A
77E80B1A push ebp
77E80B1B mov ebp, esp
77E80B1D cmp [ebp+lpModuleName], 0
77E80B21 jnz short loc_77E80B31 ; lpModuleName 是有效的则转移
77E80B23 mov eax, large fs:18h ; TEB.NT_TIB.Self
77E80B29 mov eax, [eax+30h] ; TEB.Peb
77E80B2C mov eax, [eax+8] ; PEB.ImageBaseAddress
77E80B2F jmp short loc_77E80B45
77E80B31
77E80B31 loc_77E80B31: ; CODE XREF: GetModuleHandleA+7j
77E80B31 push [ebp+lpModuleName]
77E80B34 call @AnsiStrToUnicodeStr ; 将Ansi字符串转成Unicode字符串
77E80B39 test eax, eax
77E80B3B jz short loc_77E80B45
77E80B3D push dword ptr [eax+4] ; lpModuleName
77E80B40 call GetModuleHandleW ; 这里开始同流合污了。
77E80B45
77E80B45 loc_77E80B45: ; CODE XREF: GetModuleHandleA+15j
77E80B45 ; GetModuleHandleA+21j
77E80B45 pop ebp
77E80B46 retn 4
77E80B46 GetModuleHandleA endp
这些结果是在 IDA 中分析的,在使用IDA分析这些内核模块时请注意,一定要将那个符号文件.PDB和调试符号文件.DBG从老盖的网站上下载回来(注意要下载最新的版本),和你要分析的文件放在一个目录下,这样,IDA就会自动加载这些符号文件,分析出的结果可读性大为提高。另外值得注意的是 windows 的这些系统模块和符号文件的版本一定要相同,大多数的情况下,符号文件的版本会相对低一点,这样你可以到系统目录下去寻找过去版本的系统模块,windows在update时会将这些旧的系统模块保存在其他目录,具体的版本对于可执行模块来讲,比较简单,就是PE文件头中的TimeDateStamp,使用任何工具查看都行。
IMAGE_FILE_HEADER STRUCT
Machine WORD ?
NumberOfSections WORD ?
TimeDateStamp DWORD ? //就是这里,不明白的话请看 qduwg 的翻译文章
PointerToSymbolTable DWORD ?
NumberOfSymbols DWORD ?
SizeOfOptionalHeader WORD ?
Characteristics WORD ?
IMAGE_FILE_HEADER ENDS

对于PDB文件比较麻烦,我没有现成的工具来查看这个 TimeDateStamp ,用任何十六进制编辑器打开这个.PDB文件在偏移 0x4404 的地方就是这个 TimeDateStamp 了,这两个TimeDateStamp一定要一样,否则宁愿不要使用。

1 2 下一页

 
相关文章
一日一文章
 
一日一软件
一日一动画