使用非调用手法获取API,其实是PE病毒的基本手段之一。
搜索输出表,导出GetModuleHandle,LoadLibraryA,GetProcAddress函数的地址,然后用LoadLibraryA调用USER32.DLL,然后再使用GetProcAddress得到MessageBoxA()的函数,得到输出框。
GetModuleHandle暂时没用到。。。汗一个。
.386
.model flat
;kernel_ equ 0BFF70000h
.data
szTitle db "Test for GetApi",0
szMessage db "perfect,we got the api!",0
u32 db "User32.dll",0
kernel dd ?
Counter dd 00000000h
heap_start label byte
dd 00000000h
AddressTableVA dd 00000000h
OrdinalTableVA dd 00000000h
NameTableVA dd 00000000h
@@Offset label byte
_MessageBoxA dd 00000000h
@@Namez label byte
@MessaeBoxA db "MessageBoxA",0
_Namez label byte
@GetModuleHandle db "GetModuleHandleA",0
@GetProcAddress db "GetProcAddress",0
@LoadLibraryA db "LoadLibraryA",0
@ExitProcess db "ExitProcess",0
db 0BBh
_Offsetz label byte
_GetModuleHandle dd 00000000h
_GetProcAddress dd 00000000h
_LoadLibraryA dd 00000000h
_ExitProcess dd 00000000h
;_MessageBoxA dd 00000000h
heap_end label byte
.code
s_start label byte
test1:
call delta
delta:
pop ebp ;重定位
sub ebp,offset delta ;ebp得到修正值
mov esi,[esp] ;Kernal32的地址
and esi,0ffe00000h ;数据对齐
call GetK32 ;返回EAX=得到的 KENNEL地址
; mov dword ptr [ebp+kernel],eax
; mov dword ptr [ebp+kernel],eax
lea edi,[ebp+kernel]
stosd
lea edi,[ebp+_Offsetz]
lea esi,[ebp+_Namez]
call GetAPIs
push offset u32
call dword ptr [ebp+_LoadLibraryA]
lea edx,[ebp+@MessaeBoxA]
push edx
push eax
mov eax,dword ptr [ebp+_GetProcAddress]
call eax
xor ebx,ebx
push ebx
push offset szTitle
push offset szMessage
push ebx
call eax
push 00h
call [ebp+_ExitProcess]
GetK32:
_1:
cmp word ptr [esi],"ZM" ;对照是否MZ
jz CheckPE
_2:
sub esi,10000h ;不是就减去一页再次对比
jmp _1
CheckPE:
mov edi,[esi+3ch] ;找到对应PE
add edi,esi ;相对地址转绝对地址
cmp dword ptr [edi],"EP" ;对照是否“PE”
jz WeGotK32 ;是,我们得到K32地址。
jmp _2 ;不是。。。汗一个。重来。。
;WeFailed: 暂时没用它。。
; mov esi,0BFF70000h
WeGotK32:
xchg eax,esi ;eax= address of k32
ret
GetAPI proc
mov edx,esi ; Save ptr to name
@_1: cmp byte ptr [esi],0 ; Null-terminated char?
jz @_2 ; Yeah, we got it.
inc esi ; Nopes, continue searching
jmp @_1 ; bloooopz...
@_2: inc esi ; heh, don't forget this ;)
sub esi,edx ; ESI = API Name size
mov ecx,esi ; ECX = ESI :)
xor eax,eax ; EAX = 0
mov word ptr [ebp+Counter],ax ; Counter set to 0
mov esi,[ebp+kernel] ; Get kernel's PE head. offset
add esi,3Ch
lodsw ; in AX
add eax,[ebp+kernel] ; Normalize it
mov esi,[eax+78h] ; Get Export Table RVA
add esi,[ebp+kernel] ; Ptr to Address Table RVA
add esi,1Ch
lodsd ; EAX = Address Table RVA
add eax,[ebp+kernel] ; Normalize
mov dword ptr [ebp+AddressTableVA],eax ; Store it in VA form
lodsd ; EAX = Name Ptrz Table RVA
add eax,[ebp+kernel] ; Normalize
push eax ; mov [ebp+NameTableVA],eax
lodsd ; EAX = Ordinal Table RVA
add eax,[ebp+kernel] ; Normalize
mov dword ptr [ebp+OrdinalTableVA],eax ; Store in VA form
pop esi ; ESI = Name Ptrz Table VA
@_3: push esi ; Save ESI for l8r restore
lodsd ; Get value ptr ESI in EAX
add eax,[ebp+kernel] ; Normalize
mov esi,eax ; ESI = VA of API name
mov edi,edx ; EDI = ptr to wanted API
push ecx ; ECX = API size
cld ; Clear direction flag
rep cmpsb ; Compare both API names
pop ecx ; Restore ECX
jz @_4 ; Jump if APIs are 100% equal
pop esi ; Restore ESI
add esi,4 ; And get next value of array
inc word ptr [ebp+Counter] ; Increase counter
jmp @_3 ; Loop again
@_4: pop esi ; Avoid shit in stack
movzx eax,word ptr [ebp+Counter] ; Get in AX the counter
shl eax,1 ; EAX = AX * 2
add eax,dword ptr [ebp+OrdinalTableVA] ; Normalize
xor esi,esi ; Clear ESI
xchg eax,esi ; EAX = 0, ESI = ptr to Ord
lodsw ; Get Ordinal in AX
shl eax,2 ; EAX = AX * 4
add eax,dword ptr [ebp+AddressTableVA] ; Normalize
mov esi,eax ; ESI = ptr to Address RVA
lodsd ; EAX = Address RVA
add eax,[ebp+kernel] ; Normalize and all is done.
ret
GetAPI endp
;---------------------------------------------------------------------------
;---------------------------------------------------------------------------
GetAPIs proc
@@1: push esi
push edi
call GetAPI
pop edi
pop esi
stosd
@@2: cmp byte ptr [esi],0
jz @@3
inc esi
jmp @@2
@@3: cmp byte ptr [esi+1],0BBh
jz @@4
inc esi
jmp @@1
@@4: ret
GetAPIs endp
;kernel dd kernel_
;kernel_ equ 077e60000h
;@@Namez label byte
;@MessaeBoxA db "MessageBoxA",0
align dword
s_end label byte
end test1
最后我们看到了感动的弹出框,perfect,we got the api。
是不是应该激动一下。应该是。因为我们并没有调用任何的函数,挺不容易的,一个小程序耗费了很长时间,
其实还是基础太差。。加强ING。。。