kernel32.dll这个文件十分重要,它包含很了我们需要使用的函数。比如说,GetProcAdress和LoadLibraryA这个两个函数。想想,通过这两个函数 我们就可以得到所有的函数。如果我们确定了这个动态链接库文件的基址,就可以找到这两个函数的偏移量。怎么确定这个动态链接库的基址呢?这里一共有三个方法
1PEB
peb是process environment block的缩写,每个进程都对应着一个PEB数据结构,通过fs:[30h]可以定位到它。PEB结构包含进程堆信息,二进制镜像信息,还有更重要的三个链接列表,它们与已经映射到进程空间的装载模块有关。从模块装载到模块初始化的序列上,这些链接列表的目的都是不同的。初始化链接列表中最有用的信息是kernel32.dll文件总是作为第二个模块被初始化。通过浏览这个列表的第二个入口点,一个人可以确切地得到kernel32.dll的基址。
代码如下:
push esi
xor eax,eax
mov eax,fs:[eax+0x30] ;fs指向teb结构,teb+0x30地方指向peb结构
test eax,eax
jne jmp windows_9x
windows_nt:
mov eax,[eax+0x0c] ;peb+0x0c地方指向PEB_LDR_DATA结构
mov esi,[eax+0x1c] ; PEB_LDR_DATA+0x1c地方就是一些动态连接库的地址了
lodsd
mov eax,[eax+0x08]
jmp found:
windows_9x:
mov eax,[eax+0x34]
lea eax,[eax+0x7c]
mov eax,[eax+0x3c]
found:
pop esi
ret
注:
typedef struct _PEB_LDR_DATA {
ULONG Length;
BOOLEAN Initialized;
PVOID SsHandle;
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
} PEB_LDR_DATA, *PPEB_LDR_DATA;
2通过异常处理函数链表查找kernel32.dll基地址(SEH)
当一个异常发生时,系统会从fs:[0]处读取异常处理函数链表首指针,开始问所有在应用程序中注册的
异常处理函数,比如上面的"除0异常",系统会把这个异常通知我们的异常处理函数,函数识别出是"除0异常",
并给予了处理(输出了"Can not Divide by Zero!"),并告诉系统"我已经处理过了,不用再问其它函数了".
如果我们的函数不打算处理这个异常可以交给兄弟节点中异常处理函数指针指向的其它异常处理函数
处理,如果程序中注册的异常处理均不处理这个异常,那么系统将把它发送给当前调试工具,如果应用程序当
前不处在调试状态或是调试工具也不处理这个异常的话,系统将把它发送给kernel32的UnhandledExceptionFilter
函数进行处理,当然它是由程序异常处理链最后一个节点的pfnHandler(参考EXCEPTION_REGISTRATION_RECORD)函数指针成员指向的,该节点的pNext成员将指向0xffffffff.
EXCEPTION_REGISTRATION STRUCT
Prev dd ? ;指向前一个EXCEPTION_REGISTRATION结构的指针
Handle dd ? ;当前异常处理回调函数地址
EXCEPTION_REGISTRATION ENDS
代码如下:
push esi
push ecx
xor ecx,ecx
mov esi,fs[ecx]
not ecx
exception_next:
lodsd
mov esi,eax
cmp [esi],ecx
jne exception_next
mov eax,[eax+04h]
jump_down:
dec eax
xor ax,ax
cmp word ptr [eax],5a4dh
jnz jump_down
pop ecx
pop esi