(4)恶意代码的亲密接触之文件搜索和API导址
2009-03-19 17:25
274 查看
恶意代码的亲密接触之文件搜索和API导址
在前一篇文章中介绍了病毒的相关基础知识后,从本文开始我们就要深入病毒内部,开始看一些具体的病毒编码片断,在本文中我们会看到API函数搜索以及文件搜索的技术,为后面更加深入的探讨打下良好的基础,如果你已经准备好了,就让作者带你进入这无所不用其极的病毒技术世界吧。获取Kernel32.DLL 基址
获取Kernel32.DLL基址的方法很多,最常见的一种是搜索法,如果已知Kernel32.DLL加载的大致地址,那么可由该地址向高地址或低地址进行搜索可以找到其基址。另外一种方法是搜索NT PEB 结构中的模块列表获取Kernel32.DLL的准确加载基址。下面看一下具体的实现代码。
方法1:暴力搜索获取Kernel32.DLL 的基址
最初的病毒是指定一个大致的加载地址,比如根据实验在9X 下其加载地址是0xBFF70000;在Windows 2000下加载基址是0x77E80000;在XP 和2003 下其加载基址是0x77E60000,因此在NT系统下就可以从0x77e00000开始向高地址搜索,在9X 下可以从0xBFF00000 开始向高地址搜索,如果搜索到Kernel32.DLL的加载地址,其头部一定是“MZ”标志,由模块起始偏移0x3C的双字确定的PE头部标志必然是“PE”标志,因此可根据这两个标志判断是否找到了模块加载地址,也许有人认为该方法不可靠,因为如果恰好有某段数据符合这两个特征,那么找到的基址可能就是错误的,但经实验证明,该判断方法非常可靠,基本不会出现错误。有一点需要注意的是,在所有版本的Windows系统下Kernel32.DLL的加载基址都是按照0x10000对齐的,根据这一特点可以不必逐字节搜索,按照64K 对齐的边界地址搜索即可。
从大致的一个地址开始搜索Kernel32.DLL基址可能会出现读写到未映射内存区域的情况,因此需要和SEH 配合使用。如果有在各个版本下准确获取Kernel32.DLL中某地址的通用方法,那么就可以更可靠地从该地址开始向低地址搜索,显然会更加通用。事实上,这种方法是存在的。在系统加载PE文件跳转到PE入口点第一条指令的时候,堆栈顶保存的就是Kernel32.DLL 中的某个地址,Elkern中采用的就是这种方法:
_start: pushfd ;If some flags,especial DF,changed,some APIs can crash down!!! pushad _start_@1 equ $ ;...... mov ebx,[esp+9*4] ;前面已经由pushfd 和pushad 压入了9 个双字 and ebx,0ffe00000h ;该地址为Kernel32.dll 模块下方的某个地址 ;先减去0x100000 确保该地址处于Kernel32.dll 的下方 ;向高地址搜索如果将来Windows 的发行版本中Kernel32.dll ;大小和代码结构发生变化,该方法可能无效 |
struct EXCEPTION_REGISTRATION{ struct EXCEPTION_REGISTRATION *prev; void* handler; }; |
xor esi,esi lods dword [fs:esi];取得SEH 链表的头指针 @@: inc eax ;是否是最后一个SEH 节点,检查prev 是 否为0xFFFFFFFF je @F dec eax xchg esi,eax LODSD ;下一个SEH 节点 jmp near @B @@: LODSD ;取得Kernel32.dll中UnhandledExceptionFilter的地址 |
始动态映射TEB 了,也就是说,指向TEB 的指针值不再固定,因此这种硬编码的方法也就走到了尽头。此时可以按照前面的方法向低地址搜索判断直到找到Kernel32.dll的基址为止。Elkern中判断是否找到了Kernel32.dll基址的相关代码如下:
search_api_addr_@1: add ebx,10000h jz short search_api_addr_seh_restore cmp word ptr [ebx],'ZM' ;是否是MZ 标志 jnz short search_api_addr_@1 mov eax,[ebx+3ch] add eax,ebx cmp word ptr [eax],'EP' ;是否具有PE 标志 jnz short search_api_addr_@1 ;找到了kernel32.dll 的基址 |
前述TEB偏移0x30处,亦即FS:[0x30]地址处保存着一个重要的指针,该指针指向PEB(进程环境块),PEB成员很多,这里并不介绍PEB的详细结构。我们只需要知道PEB结构的偏移0xC处保存着另外一个重要指针ldr,该指针指向PEB_LDR_DATA 结构:
typedef struct _PEB_LDR_DATA { ULONG Length; // +0x00 BOOLEAN Initialized; // +0x04 PVOID SsHandle; // +0x08 LIST_ENTRY InLoadOrderModuleList; // +0x0c LIST_ENTRY InMemoryOrderModuleList; // +0x14 LIST_ENTRY InInitializationOrderModuleList;// +0x1c } PEB_LDR_DATA,*PPEB_LDR_DATA; // +0x24 |
LDR_MODULE结构如下所示:
typedef struct _LDR_MODULE { LIST_ENTRY InLoadOrderModuleList; // +0x00 LIST_ENTRY InMemoryOrderModuleList; // +0x08 LIST_ENTRY InInitializationOrderModuleList;// +0x10 PVOID BaseAddress; // +0x18 PVOID EntryPoint; // +0x1c ULONG SizeOfImage; // +0x20 UNICODE_STRING FullDllName; // +0x24 UNICODE_STRING BaseDllName; // +0x2c ULONG Flags; // +0x34 SHORT LoadCount; // +0x38 SHORT TlsIndex; // +0x3a LIST_ENTRY HashTableEntry; // +0x3c ULONG TimeDateStamp; // +0x44 // +0x48 } LDR_MODULE, *PLDR_MODULE; |
mov eax, dword ptr fs:[30h] ;获取PEB 基址 mov eax, dword ptr [eax+0ch] ;获取PEB_LDR_DATA 结构指针 mov esi, dword ptr [eax+1ch] ;获取InInitializationOrderModuleList 链表头第一个LDR_MODULE 节点 InInitializationOrderModuleList 成员的指针 93 2005.08 程序员 lodsd ;获取双向链表当前节点后继的指针 mov ebx, dword ptr [eax+08h] ;取其基地址,该结构当前包含的是 ;kernel32.dll 相关的信息 |
法在Win9X系统上无效。听起来可能比较费解,还是用一张图更加清晰一些(见图6)。
图6:利用PEB 搜索kernel32.dll 基地址的过程 |
相关文章推荐
- (5)恶意代码的亲密接触之文件搜索和API导址
- (6)恶意代码的亲密接触之文件搜索和API导址
- 恶意代码的亲密接触之文件搜索和API导址
- 恶意代码的亲密接触之文件搜索和API导址--6
- 恶意代码的亲密接触之文件搜索和API导址--5
- 恶意代码的亲密接触之文件搜索和API导址--4
- 亲密接触恶意代码之文件感染和内存驻留
- 亲密接触恶意代码之文件感染和内存驻留--9
- 亲密接触恶意代码之文件感染和内存驻留
- 亲密接触恶意代码之文件感染和内存驻留--7
- (7)亲密接触恶意代码之文件感染和内存驻留
- (8)亲密接触恶意代码之文件感染和内存驻留
- (9)亲密接触恶意代码之文件感染和内存驻留
- 恶意代码的亲密接触之病毒编程技术
- 恶意代码的亲密接触之病毒编程技术--2
- 恶意代码的亲密接触之病毒编程技术(2)
- 恶意代码的亲密接触之病毒编程技术--1
- 恶意代码的亲密接触之病毒编程技术(3)
- 恶意代码的亲密接触——病毒编程技术(上)
- 恶意代码的亲密接触之病毒编程技术--3