文章作者: Hume/CVC.GB
信息来源:D哥BLOG
一点理论
API地址的获取方法很多,在API函数地址的获取(1)中介绍的方法实际上是有很大缺陷的,要求
病毒定位的代码必须在Windows PE Loader加载程序后程序未改变esp的值之前执行,也就是说
如果程序进行了堆栈操作那么我们无法保证[esp]中的地址还位于Kernel32中了,因此如果为了
满足多态,EPO等对Vir代码入口的不同要求,必须寻找其他良方。
事实上,如果你了解Windows的SEH机制,就会很快找到一种简单的方法。那就是遍历SEH链,
在链中查找prev成员等于0xFFFFFFFF 的EXCEPTION_REGISTER结构(具体参见杂志的SEH介绍),
该结构中handler值是所谓的系统异常处理例程,他总是位于Kernel32.dll中!根据这一特性,
就可以查找Kernel32.dll在内存中的基地址了。
利用遍历SEH链表取得API的步骤如下:
a)遍历SEH链,找到prev等于0xFFFFFFFF 的EXCEPTION_REGISTER结构,获取handler值;
b)用类似方法1的方式查找kernel32.dll的基地址;
c)搜索kernel32.dll的IAT,获取GetProcAddress的地址;
d)以GetProceAddress获取其他任何Win32 API函数地址。
so easy。
代码实例
以下是该思路的实现的例子,敬请欣赏:
;walking through the seh frame to get kernel32 addr
;search kernel32.dll to get GetProcAddress addr
;then use base of kernel32 and GetProcAddress to
;get all needed APIs
include '%fasinc%/win32as.inc'
include '%fasinc%/pestruc.h'
.data
buf rb 256
fmt db "Kernel32 base is: %X",0
zTit db "By Hume 2K2+",0
hModulek32 dd 0
.codew
api_List:
api_ends:
StArT:
xor esi,esi
lods dword [fs:esi]
@@:
inc eax
je @F
dec eax
xchg esi,eax
LODSD ;next seh_frame
jmp near @B
@@:
LODSD ;kernel32 func...
;compare if PE_hdr
xchg esi,eax
find_pe_header:
dec esi
xor si,si ;kernel32 is 64kb align
mov eax,[esi]
add ax,-'MZ' ;anti heuristic
jne find_pe_header
mov edi,[esi+mzh.e_lfanew] ;.e_lfanew
mov eax,[esi+edi]
add eax,-'PE' ;anti heuristic
jne find_pe_header
; mov [hModulek32],esi
push esi
;esi=VA Kernel32.BASE
;edi=RVA K32.pehdr
mov ebp,esi
mov edi,[ebp+edi+peh.DataDirectory]
push edi esi
mov eax,[ebp+edi+peexc.AddressOfNames]
mov edx,[ebp+edi+peexc.AddressOfNameOrdinals]
call @F
db "GetProcAddress",0
@@:
pop edi
mov ecx,15
sub eax,4
next_:
add eax,4
add edi,ecx
sub edi,15
mov esi,[ebp+eax]
add esi,ebp
mov ecx,15
repz cmpsb
jnz next_
pop esi edi
sub eax,[ebp+edi+peexc.AddressOfNames]
shr eax,1
add edx,ebp
movzx eax,word [edx+eax]
add esi,[ebp+edi+peexc.AddressOfFunctions]
add ebp,[esi+eax*4] ;ebp=Kernel32.GetProcAddress.addr
;use GetProcAddress and hModule to get other func
pop esi ;esi=kernel32 Base
;int 3
invoke ExitProcess,0
.end StArT