这个是在XFish的病毒专题的基础上进行的简单探索。Windows 7上面有很多有趣的地方,对安全研究有很大的意义。这两周有些心得,想跟大家分享一下,这里仅仅探讨一下Windows 7下面的病毒感染。

一、Kernel32基址的获得
 XFish专题中提到了三种方式,具体参见:http://bbs.pediy.com/showthread.php?t=85910

这里直接引用XFish的帖子:
1. 通过线程初始化时, 获得esp堆栈指针中的ExitThread函数的地址,然后通过搜索获得kernel32.dll的基地址。    
2. 遍历seh异常链,然后获得EXCEPTION_REGISTRATION结构prev为-1的异常处理过程地址,这个异常处理过程地址是位于kernel32.dll,通过它搜索得到kernel32.dll的基地址。
3. 通过TEB获得PEB结构地址,然后再获得PEB_LDR_DATA结构地址,然后遍历模块列表,查找kernel32.dll模块的基地址。

我将讨论下,现实中如果要感染windows 7的做法。
第一种通过线程初始化的方式,一般来说,病毒代码很难在线程初始化的时候得到执行。你可能会说,直接修改PE入口点,指向你的病毒代码。据我所知,这样会直接被杀软干掉的。所以现实中不具有可行性。现实中的病毒代码会通过EPO技术,感染文件。即替换任意一个call的目标地址,让它调用自己的病毒代码,并在病毒代码的结尾跳转到被替换的目标代码中执行。这种技术对抗杀软非常有效。
第二种方法和第三种方法在windows xp下都是很好的查找kernel32基址的方法。而且在windows xp下我更偏爱第二种。因为第二种通过TEB,由fs:[0]指向,和windows的SEH机制非常相似。杀软很难通过特征码判断出来。而第三种通过PEB,由fs:[30h]指向,正常程序应该很少操作fs:[30h]。杀软很容易将其列为特征码。
但是,这些仅仅是在windows xp下。
在windows 7下,第二种方法是没有效果的。因为异常处理过程不再位于kernel32.dll当中,而是位于ntdll.dll中。你写一个程序用OD加载后查看下SEH链就明白了。
只能使用第三种方法。
XFish提供的第三种方式的代码如下:

这段代码十分简洁漂亮。
但是如果你尝试在windows 7下面直接用,你会很遗憾的发现你的病毒代码运行不是很正常。因为这段代码基于的假设是系统初始化dll的顺序是ntdll.dll-->kernel32.dll-->其他dll。
在windows 7下面系统初始化dll的顺序变成了ntdll.dll-->kernelBase.dll-->kernel32.dll-->其他dll。
我现在暂时未弄清楚kernelBase.dll的作用(听名字好像和ASLR有关??额,哪位大哥能指点一下?)。
如果你的病毒试图在windows xp和windows 7下都能正常感染,要么通过判断OS类型(但是你还没有GetProcAddress函数,所以你貌似没辙),要么使用第三种感染方式,只不过我们要弄清楚第三种的原理。
XFish的帖子中已经很详尽地解释了第三种得到基址的原理。这里我借用一下。总体思路是通过PEB,获得加载模块的链表。
涉及的数据结构如下:

Ldr是_PEB_LDR_DATA的指针。而_PEB_LDR_DATA就是加载模块链表的头节点。

你肯定知道_LIST_ENTRY就是链表结构体,将我们链表中的各个节点连接起来。
我们链表中的节点是啥样子的?如下:

怎么连的?那个_LIST_ENTRY结构如下:

整个链表的结构如下:

为了病毒能在windows xp和windows 7下面都能运行,只要将BaseDllName与kernel32.dll进行比较就行了。注意这里是进行unicode的字串比较。提供代码如下:


附件是可运行的代码:
VirusTest2.rar [解压密码是:test123]