API 绝密档案系列之一

API 绝密档案系列之一
API 绝密档案系列之一

看到 qduwg 老师凭"【翻译】3个脱壳相关的重要函数介绍" 也"骗"到一个精,不觉心痒,也弄几个函数来介绍一下,不过我不是翻译,而是著作。我们就从 qduwg 老师介绍的几个函数入手。希望上面的话没有伤到 qduwg 老师的自尊心。我看到你对别人评价的反应,知道你很在意这些。

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 其实只是对底层函数进行了包装(当然对于某些ri ng3层的特定功能还是自己完成的),相当于一个接口,起一个中转和隔离的作用,将用户的函数调用进行预处理,比如检测用户参数的合法性,对用户参数进行重新排序(底层函数的参数排列顺序有时和用户层不同,这样可以防止你轻易的弄明白底层在干什么),将用户的调用分离拆解为若干个更为细小的调用,因为底层函数分类往往更细,这样比较灵活。

使用 GetModuleHandle 函数,在高级语言中可以直接写成:

hMod = GetModuleHandle(lpModuleName);

编译器会根据参数的性质自行决定调用那一个函数,但在汇编中却不能这样使用,你必须明确的指明你要

使用那一个函数。另外在OD中下断点,你也必须明确的指明对那一个函数下断,例如在OD中,进入CPU 窗口,按Ctrl-G,然后输入GetModuleHandle,OD会告诉你“未识的标识符”,你必须清楚的告诉 OD 你到底要在那一个函数下断,是 A 还是 W。按前面的说法其实你只要下 GetModuleHandleW 就可以了(当然有时候在A下断,比较容易知道程序是从那里调用的,如果程序使用的是A调用)。

俗话说,口说无凭。你怎么知道那两个还是最后变成了一个?

看雪老大也在qduwg的文章后说:

引用:

不过这三个函数的定义只需要Google就能找到相关文档,因为太常用,不光是脱壳,编程是经常用的。现在的强壳都不直接调用这些函数了,都自己实现。

其后跟贴更有"牛B王"--nbw 惊人的评论:

引用:

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

以前自己能写个GetProcAddress就觉得很不错了,后来看高手写虚拟机,半小时模拟出来LoadLibrary,那个让偶惊啊。。。。

我没有他们那样的水平,自己不会写,人都说半瓶醋晃荡,醋瓶满了就不响了,我这个瓶子还没有满,所以你们有幸能看到这些垃圾文章(当然也是为了骗一点"加精",风光风光),等有一天我的瓶子也满了(最好能够做到),也就只会“啊...”了。

既然如此,那就只好看看老盖是怎么做的,这个函数在 Kernel32.dll 中,你可能会问,你怎么知道在Ke rnel32.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, GetModuleFileN ame, GetProcAddress, LoadLibrary,LoadResource

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

代码:

这些结果是在 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 了,对于.DBG 文件,在偏移 0x8 的地方,这两个TimeDateStamp一定要一样,否则宁愿不要使用。

下面对fs段加一些详细的说明,很多人可能不太熟悉这个段。

fs段在用户模式(Ring3)和系统模式(Ring0)分别指向两个最重要的系统结构:

Ring3:

fs --> TEB (Thread Environment Block)结构表 --> 7FFDE000

即“线程环境块”。

Ring0:

fs --> KPCR (Kernel Processor Control Region)结构表 --> FFFDF000

即“内核处理器控制域”。

在NT和2K和XP和2k+3中系统这个地址是固定的,随着版本的增大或Update,TEB会有新的内容增加,

在将来的windows系统中,老盖为了防止那些坏人(我可不是坏人,否则说不定也有能力做点坏事)太容易利用这个特性搞破坏,有可能将这个地址变成随机的,也就是每次启动后都会在不同的位置。

这些结构都是老盖没有公布的,所以如果你想使用这些结构,要特别小心,老盖为了防止小人搞破坏,每次Update都有可能修改这些结构而使的你程序崩溃。让你吃免费蓝玻璃。

因为是所谓 UnDocument 的东西,所以最好的办法就是通过老盖的 WinDBG 或他的兄弟 KD 来获得这些结构,由于上面说的原因,这个结构以你自己看到的为准,至于如何使用 WinDBG 和 KD ,我想最好请那个叫 Themida flea老兄来写(这可不是我创出的名字,是这位Themida老兄自己的图标,Themida可是我非常欣赏的强壳,虽然不太稳定)在本论坛的精品“【原创】用WinDbg动态脱Reflector”中,我说我学不会 WinDBG ,这位 Themida 老兄答到:

引用:

一群笨蛋,笑翻。。。

windbg的GUI只是个DEMO,各位可以编写自己的windbgGUI

由此可知,flea 老兄,高人也。flea 老兄不但可以教你们如何使用 WinDBG 和 KD,甚至可以教你们写一个带有自己特色的 debug,例如输入你自己开发的命令 allstruct,哇! 所有undocument 的结构都展现在你眼前,想想,那是什么境界。

下面这些是在我的机器上显示的结构,遗憾的是看不到TEB的完整结构,可以到4F提供的w2kundoc.inc 中看到这个TEB的完整结构,不过我可不能保证是正确的。但对于我们所要讨论的问题,使用WinDBG提供的信息就足够了。使用WinDBG的内核模式或直接使用KD:(双机模式或虚拟机)输入下面的命令:

代码:

这里只是TEB表的部分,但已经够使用的了,如果想在开发程序中使用这些结构,如前所说,可以到4F的inc中去寻找,也可以自己到网上去google一把,但不一定有美满的结果。

代码:

注意这些是WinDBG的扩展命令,由外部模块 kdex2x86.dll 提供(可以到老盖的网站去下载),先觉条件是这个模块必须被装载。

至于那个Ring0的 KPCR 结构如果我的兴趣还在,而且那个瓶子还没有满,再详细讨论,KPCR 的结构巨大无比也复杂无比。前些日子 qduwg 老师发了题为“For菜鸟文章:PE文件格式, qduwg翻译”,我没有留心说漏嘴,大概意思是 PE 结构拿过来使用不就完了,用得着去学吗。其实此话来源就是因为底层的这些结构,和底层的这些结构相比, PE结构那真是小巫见大巫了(PE 文件头其实就是一个非常简单的结构),如果你一个 PE 文件头都要花那么大的力气去学,而且到处都可以找到详细的资料,那么底层的这些结构怎么办??? 其一是这些结构远比 PE 结构更加庞大,更加复杂;其二是根本就没有任何资料和解释,全部要靠你自己去努力去理解,去破解。而且这些巨大的结构有无数多,怎么办,以我看,如果真是那样,不如回家种红薯。没有想到这段无心的话引起了两国战争,伊万大叔立刻就对我发动了战争,伊万大叔在俄国,我在加拿大,你想,加拿大全国警察加军队也不过才几万人,怎么能打的过伊万大叔,于是我只好狼狈逃跑。哈哈,由于我的当机立断,结果世界大战没有爆发,为了消除坏影响,伊万大叔买通看雪老大,将这场争论给完全删了,毁灭罪证,实在可惜,哈哈。伊万大叔在随后的跟贴中可不要对我口诛笔伐。

这些是玩笑话,当不得真,如果不写一些这样的垃圾,我的创作热情恐怕立刻就消失了,所以请看官们忍忍。

这里插一句题外话,大家在使用OD脱壳时,往往为了隐藏OD,会加载IsDebug V1.4.dll来隐藏OD,其实完全不需要加载这个东西,在OD中的数据窗口,按 Ctrl-G ,在打开的小窗中输入 7FFDF000(见上面的

PEB表)然后在偏移量 02(PEB.BeingDebugged 标志)的地方或者干脆输入 7FFDF002, 将鼠标放在这个地址上,Ctrl-E,将 1 改为零就 IsDebug 了,如果已经是 0 就是你已经使用什么 dll 将 Debug 隐藏了。

对这两张表有了一定的认识后,我们再来看上面的那段代码的头部:

代码:

其中:

代码:

就是将那个 7FFDE000 的地址送到 eax 中去,现在我们知道那是 TEB 表。

代码:

根据上面的 TEB 表,我们知道 7FFDE000 偏移 30h 的地方是一个指针,指向 PEB 表。

代码:

根据上面的 PEB 表,我们得到最后结果,原来这几句代码的目的是获得程序启动后被装载的基地址。就这么简单。

代码:

这句是检测用户给出的 lpModuleName 是否为零,如果为零,用户发出的请求是获取自己当前进程的 hModule,这就是为什么要获取程序启动后被装载的基地址的原因了。再往下面的东西不用我解释了把,你可以亲眼看到他将那个Ansi字符串转换成Unicode后就调用 GetModuleHandleW 最后跑到一起去了。

至于 GetModuleHandleW 干了一些什么事,且听下回分解,哈哈这样我可以多骗几个“加精”,qduwg 老师用三个 API 换一个“加精”,我准备用一个 API 调用换 3 到 5 个“加精”,哈哈,那当然还要看雪老大肯给我才行。

后话:过些日子我就要回中国了,回到我可爱的祖国,如果很忙,可能就不能连续的写了,这点请大家谅解,如果成了海带,那就继续制造垃圾。多给我一点鼓励,使我能多写几篇,否则热情一旦消失或瓶子不幸装满了,就没有这些垃圾文章了,哈哈。

另外伊万大叔花重金从专门出产那种体型苗条、曲线流畅的、并会飞的蟑螂的国家--德国(现在中国许多城市的蟑螂多为这个德国种,本土的蟑螂太笨,不会飞,所以蔓延比较慢,危害也比较小,有灭亡的危险)买了一条游艇,还说会开到珠江口,在船上请我喝那个“可爱的水”--vodka,根据伊万大叔提供的资料,vodka 没有任何的味道,最大的好处就是你喝过以后,不影响你和你那一半做某些亲热的动作(不过可没有规定必须是那一半,也许是小密),因为嘴中没有异味。不过我还是认为我们中国的酒好,你看那茅台、五粮液,酒瓶一开满屋香,多来劲,另外中国酒还喝的放心,谁放心?当然是老婆啦,你想,满嘴的酒气,那种可能对小密产生的专用动作不就失效了,想不到中国酒还有这种妙用吧!!不过到时候说不定又要爆发新的战争,为酒而战,不过这次是中俄之战了,哈哈,请看官们不用担心,我依然会毫不犹豫的跳海逃走,幸亏我的游泳技术不错,尤其擅长长距离游泳。

注:修改了一些错笔字,另外为了赢得更高的点击率,将标题也换了,最好那位仁兄大才,给弄一个不吓死人不罢休的标题,那我就感激不尽了。伊万大叔就给了一个主意,说标题上一定要有个“密”字,我觉得有道理,这不,马上就成了绝密了。

相关主题
相关文档
最新文档