datochan 发表于 2009-2-17 12:04

讲一下逆向分析在编程中的应用吧

本文适合还没有入门的新朋友上手用的,所以,各位大牛就可以飘过不看它了!

   游戏的服务器列表更新了,而存服务器信息的XML在游戏的更新服务器上加密保存的,没能力分析它的解密算法,就想写个程序,从内存里读出来,工作量就是那么多,不如索性做成教程,分享给像我一样刚刚入门的朋友,说不定就又能混一篇精华,哈哈……

       其实真的不知道该给这个破烂起个什么名字了,怎么看怎么感觉在教人做外挂¥%#¥%


      不多废话,进入主题,我现在要找服务器列表,当然就要先从内存里搜一个服务器的名字(别的信息不知道,只能搜名字了!)


在OD里的数据区中看一下这几个地址,确定,第一个地址也就是:01329F6C
就是我们像要的地址了,至于为什么,你看一下就可以知道了(因为第一个在一个结构体数组里,其他的都是独立的,所以第一个是!)。

好了,在OD里,来到01329F6C这个地址,在第一个DWORD上下内存访问断点:


来到这里:


现在我们需要知道的是,EAX的内容是从哪里来的,所以向上看:0040CA3B|> \8BC2          |mov   eax, edx                        ;1是EDX给的EAX,再向上:0040CA17|.8B83 18010000   |mov   eax, dword ptr
0040CA1D|.8B34A8            |mov   esi, dword ptr
0040CA20|.8D04A8            |lea   eax, dword ptr
0040CA23|.8D57 04            |lea   edx, dword ptr           ;1
0040CA26|.85D2                |test    edx, edx
0040CA28|.C746 3C 01000>|mov   dword ptr , 1
0040CA2F|.8D9E 8C000000|lea   ebx, dword ptr
0040CA35|.75 04                |jnz   short 0040CA3B
这个流程应该是比较简单的,我就从头分析一下:0040C8C0/$6A FF         push    -1
0040C8C2|.68 08184600   push    00461808                         ;咐|g; SE 处理程序安装
0040C8C7|.64:A1 0000000>mov   eax, dword ptr fs:
0040C8CD|.50            push    eax
0040C8CE|.64:8925 00000>mov   dword ptr fs:, esp
0040C8D5|.83EC 24       sub   esp, 24
0040C8D8|.53            push    ebx
0040C8D9|.8BD9          mov   ebx, ecx
0040C8DB|.8B83 78010000 mov   eax, dword ptr          ;取出返回值,如果是-1就不做处理!
0040C8E1|.83F8 FF       cmp   eax, -1
0040C8E4|.895C24 08   mov   dword ptr , ebx
0040C8E8|.0F84 89000000 je      0040C977
0040C8EE|.55            push    ebp
0040C8EF|.57            push    edi
0040C8F0|.8D4C24 2C   lea   ecx, dword ptr
0040C8F4|.51            push    ecx
0040C8F5|.8D5424 2C   lea   edx, dword ptr
0040C8F9|.52            push    edx
0040C8FA|.50            push    eax
0040C8FB|.8D8B 58010000 lea   ecx, dword ptr
0040C901|.E8 0ACAFFFF   call    00409310
0040C906|.33ED          xor   ebp, ebp
0040C908|.3BC5          cmp   eax, ebp                         ;如果函数返回值是0,就走人~~~
0040C90A|.74 69         je      short 0040C975
0040C90C|.8B78 04       mov   edi, dword ptr
0040C90F|.3BFD          cmp   edi, ebp
0040C911|.74 62         je      short 0040C975
0040C913|.56            push    esi                              ;ESI和EBX的值都是004812A8
0040C914|.8BB3 DC000000 mov   esi, dword ptr
跟进ESI看下:
011A21E80D F0 AD BA 70 5C 32 01 58 7D 32 01 2C 7F 32 01.瓠簆\2 X}2 ,2
011A21F80D F0 AD BA 88 31 32 01 A8 31 32 01 A8 31 32 01.瓠簣12 ?2 ?2
011A22080D F0 AD BA 28 01 30 01 42 01 30 01 42 01 30 01.瓠? 0 B 0 B 0
011A22180D F0 AD BA 28 23 1A 01 00 00 00 00 0D F0 AD BA.瓠?#.....瓠
011A222880 23 1A 01 00 00 00 00 00 F0 AD BA 0D F0 AD BA
继续:0040C91A|.8B46 04       mov   eax, dword ptr          ;取出了各个大区的序号•~~
0040C91D|.3BC5          cmp   eax, ebp
到这里可以知道,大区的地址指针+偏移的形式应该在:+4]

看下EAX的内容:01325C7001 00 00 00 B9 E3 B6 AB C7 F8 00 00 58 F8 17 04   ...广东区..X?
01325C8000 00 00 00 58 F8 17 04 EA 76 94 7C 00 00 1A 01....X? 陃攟..
01325C9064 77 94 7C D0 31 30 01 00 00 1A 01 D8 31 30 01dw攟?0 ..?0
01325CA000 00 00 00 64 77 94 7C 50 32 30 01 00 00 1A 01....dw攟P20 ..
01325CB098 83 1A 01 C0 30 30 01 00 00 1A 01 00 00 00 00槂?0 ......
01325CC006 00 00 00 B0 4E 31 01 0F 00 00 00 A8 4E 31 01   ...癗1...∟1
01325CD0A8 4E 31 01 30 18 00 00 78 01 1A 01 28 03 1A 01∟1 0 ..x   (   
01325CE001 00 00 00 40 05 1A 01 38 00 00 00 48 32 30 01   ...@   8...H20
01325CF078 01 1A 01 30 2E 38 32 30 34 2E 30 36 00 00 00x   0.8204.06...
这个就是服务器大区的大概的结构了,里面各个数据的含义还不是很清楚,不过不用着急,通过代码,我们都会弄明白的!
继续回到代码中分析:0040C91F|.C74424 1C FFF>       mov           dword ptr , -1
0040C927|.75 04                         jnz           short 0040C92D
0040C929|.33C0                         xor           eax, eax
0040C92B|.EB 18                         jmp           short 0040C945
0040C92D|>8B4E 08                        mov           ecx, dword ptr
看一下ECX的内容吧:0132D0480D F0 AD BA 0D F0 AD BA 0D F0 AD BA 0D F0 AD BA.瓠?瓠?瓠?瓠
0132D0580D F0 AD BA 0D F0 AD BA 0D F0 AD BA 0D F0 AD BA.瓠?瓠?瓠?瓠
0132D0680D F0 AD BA 0D F0 AD BA 0D F0 AD BA 0D F0 AD BA.瓠?瓠?瓠?瓠
0132D0780D F0 AD BA 0D F0 AD BA 0D F0 AD BA 0D F0 AD BA.瓠?瓠?瓠?瓠
都是同一个数字,暂且不多考虑,估计接下来应该是遍历大区的信息啊,想下,我们在写程序的时候,循环需要什么来着,对,就是循环多少次啊,接下来的代码就是计算有多少个大区,以控制循环多少次了!0040C930|.2BC8                                sub   ecx, eax
0040C932|.B8 8DC0088C               mov   eax, 8C08C08D
0040C937|.F7E9                                imul    ecx
0040C939|.03D1                                  add   edx, ecx
0040C93B|.C1FA 08                             sar   edx, 8
0040C93E|.8BC2                                  mov   eax, edx
0040C940|.C1E8 1F                               shr   eax, 1F
0040C943|.03C2                                add   eax, edx                ;这里就是大区的数量了OD显示的是0x12,即有0x12个大区
好了,到这里,EAX里存的就是有多少个大区了
继续看0040C945|>33C9                                xor   ecx, ecx
0040C947|.3BC5                                cmp   eax, ebp
0040C949|.76 29                             jbe   short 0040C974
0040C94B|.8B97 84000000               mov   edx, dword ptr          ;取出我们选择的大区的序号
0040C951|.8B76 04                               mov   esi, dword ptr             ;取出大区的首个元素:序号
下面开始循环,遍历各个大区,我们取大区的信息也主要就依靠这个循环了~~~0040C954|.33FF                        xor   edi, edi
0040C956|.897424 24                   mov   dword ptr , esi
0040C95A|.897C24 10                   mov   dword ptr , edi
0040C95E|.8BFF                          mov   edi, edi
0040C960|>391437      /                cmp   dword ptr , edx         ;循环比较,看看取那个区下的服务器
0040C963|.74 26                         |je      short 0040C98B                           ;只要是我们选的区,拿就跳走,不是就继续循环
0040C965|.41            |                inc   ecx
0040C966|.81C7 D4010000 |        add   edi, 1D4                                  ;在内存里,每个大区信息的结构体大小为0x1D4
0040C96C|.3BC8          |                cmp   ecx, eax
0040C96E|.^ 72 F0         \                jb      short 0040C960
0040C970|.897C24 10                   mov   dword ptr , edi
根据这个循环,我们可以很轻松的写出遍历所有大区的代码了,不过不用太着急,在这里标记一下,因为,这个大区的结构中很多的数据成员,我们都不清楚,现在只知道第一个成员是大区的ID,第二个是名字,而且结构的大小要凑够0x1D4,其他的都还未知,继续分析,或许等下就清晰了,嘿嘿!

       继续看代码:0040C98B|> \8B8437 C80100>        mov   eax, dword ptr       ;看到了吧,大区数构中偏移第1C8的成员是个最小值
0040C992|.3BC5                        cmp   eax, ebp
0040C994|.897C24 10                   mov   dword ptr , edi
0040C998|.75 06                     jnz   short 0040C9A0
0040C99A|.896C24 20                   mov   dword ptr , ebp
0040C99E|.EB 1E                         jmp   short 0040C9BE
0040C9A0|>8B8C37 CC0100> mov   ecx, dword ptr       ;大区数构中偏移第1CC的成员是个最大值
0040C9A7|.2BC8                          sub   ecx, eax                        ;同算大区的数量一样,计算服务器的数量
0040C9A9|.B8 E1830F3E       mov   eax, 3E0F83E1
0040C9AE|.F7E9                        imul    ecx                               ;3E0F83E1*(最大值-最小值)
0040C9B0|.C1FA 06                     sar   edx, 6                            ;取其积的高32位值右移6位
0040C9B3|.8BC2                        mov   eax, edx
0040C9B5|.C1E8 1F                       shr   eax, 1F                           ;再移动0x1F位
0040C9B8|.03C2                        add   eax, edx                        ;取他们的和OD显示是4,即4个服务器,循环4次
0040C9BA|.894424 20                   mov   dword ptr , eax         ;把结果保存一下
哈哈,结构越来越清晰,思路越来越明确,大家猜下,接下来是要干什么了啊~~~~0040C9BE|> \8B83 1C010000 mov   eax, dword ptr           ; 还不清楚它的作用,OD显示是6,先不管它
0040C9C4|.33D2                     xor   edx, edx
0040C9C6|.85C0          test    eax, eax
0040C9C8|.894424 18   mov   dword ptr , eax
0040C9CC|.0F8E 95010000 jle   0040CB67
0040C9D2|.33C9          xor   ecx, ecx
0040C9D4|.EB 0A         jmp   short 0040C9E0                  ;下面的代码应该很眼熟吧,典型的For循环
0040C9D6|>8B4C24 2C   /mov   ecx, dword ptr
0040C9DA|.8B5424 28   |mov   edx, dword ptr
0040C9DE|.8BFF          |mov   edi, edi
0040C9E0|>3B5424 20      cmp   edx, dword ptr           ;将计数器EDX跟服务器的数量进行比较,看看循环是否结束
0040C9E4|.0F83 42010000 |jnb   0040CB2C
0040C9EA|.8B8437 C80100>|mov   eax, dword ptr    ;取出第一个服务器的信息结构的首地址


[ 本帖最后由 bester 于 2009-2-17 13:07 编辑 ]

datochan 发表于 2009-2-17 12:56

真郁闷,这一个帖子发了N遍了·~~

好了,现在我们正式的开始写程序,程序可以写成DLL的方式,也可以写成EXE的方式,由于DLL的调试不是很方便,我就只贴一下DLL方式的代码,至于EXE方式的,大家可以看附件的程序,不多说了,大家看代码就好:/************************************************************************/
/* 函数名:GetAreaInfo
/* 参数:无
/* 返回值:返回一个指向大区结构的指针
/* 功能:获取服务器列表中大区的结构体指针
/* 作者:bester @ 2/17/2009
/************************************************************************/
__declspec(naked) PGAME_AREA_INFO WINAPI GetAreaInfo()
{
    __asm
    {
            mov      eax, dword ptr
            test    eax, eax
            je      NULL_POINT
            mov      eax, dword ptr
            test    eax, eax
            je      NULL_POINT
            mov      eax, dword ptr
NULL_POINT:
      retn;
    }
}

/************************************************************************/
/* 函数名:GetAreaNum
/* 参数:无
/* 返回值:返回游戏更新列表中大区的个数
/* 功能:获取游戏更新列表中大区的个数
/* 作者:bester @ 2/17/2009
/************************************************************************/
__declspec(naked) int WINAPI GetAreaNum()
{
    _asm
    {
      mov      eax, dword ptr
      test    eax, eax
      je      NULL_POINT
      mov      eax, dword ptr
      test    eax, eax
      je      NULL_POINT
      mov      eax, dword ptr
      test    eax, eax
      je      NULL_POINT
      mov      ecx, dword ptr
      test    ecx, ecx
      je      NULL_POINT
      mov      ecx, dword ptr
      test    ecx, ecx
      je      NULL_POINT
      mov      ecx, dword ptr
      test    ecx, ecx
      je      NULL_POINT
      sub      ecx,eax
      mov   eax, 0x8C08C08D
      imul    ecx
      add   edx, ecx
      sar   edx, 0x8
      mov   eax, edx
      shr   eax, 0x1F
      add   eax, edx
NULL_POINT:
      retn;
    }
}

/************************************************************************/
/* 函数名:GetServerInfo
/* 参数:无
/* 返回值:返回一个指向服务器结构体的指针
/* 功能:获取服务器列表中服务器的结构体指针
/* 作者:bester @ 2/17/2009
/************************************************************************/
PGAME_SERVERLIST_INFO CMyForm::GetServerInfo(PGAME_AREA_INFO    pAreaInfo)
{
    return pAreaInfo->pServerListOfFirst;
}

/************************************************************************/
/* 函数名:GetServerNum
/* 参数:指定的大区结构体指针
/* 返回值:返回指定的大区中服务器的数量
/* 功能:获取指定的大区中服务器的个数
/* 作者:bester @ 2/17/2009
/************************************************************************/
int WINAPI GetServerNum(PGAME_AREA_INFO pAreaInfo)
{
    DWORD    TheServerNum    =    0;
    TheServerNum    =    (DWORD)pAreaInfo->pTheEndData - (DWORD)pAreaInfo->pServerListOfFirst;

    _asm
    {
      mov      ECX,TheServerNum
      mov   eax, 0x3E0F83E1
      imul    ecx               ;3E0F83E1*(最大值-最小值)
      sar   edx, 0x6          ;取其积的高32位值右移6位
      mov   eax, edx
      shr   eax, 0x1F         ;再移动0x1F位
      add   eax, edx          ;OD显示是4,即有4个服务器,循环次数为4次
      mov      TheServerNum,eax
    }
    return    TheServerNum;
}

/************************************************************************/
/* 函数名:GetTheMaxServerNum
/* 参数:无
/* 返回值:返回游戏指定的每个区最多可拥有服务器的数量
/* 功能:如果取到的服务器个数大于等于这个数就说明出错了
/* 作者:bester @ 2/17/2009
/************************************************************************/
__declspec(naked) int WINAPI GetTheMaxServerNum()
{
    __asm
    {
      mov      eax, dword ptr
      test    eax, eax
      je      NULL_POINT
      mov      eax, dword ptr
NULL_POINT:
      retn;
    }
}

/************************************************************************/
/* 函数名:OnBtnRefurbish
/* 参数:无
/* 返回值:无
/* 功能:获取游戏更新程序的服务器列表中的数据并更新到程序的列表视图中
/* 作者:bester @ 2/17/2009
/************************************************************************/
void CMyForm::OnBtnRefurbish()
{

    CString      szTemp    =    "";
    int AreaNum            =    GetAreaNum();
    szTemp.Format("获取到大区的数量是0x%08X",AreaNum);
    MessageBox(szTemp);
    try
    {
      PGAME_SERVERLIST_INFO    pServerListInfo    = NULL;
      PGAME_AREA_INFO            pAreaInfo    =    GetAreaInfo();
      if (pAreaInfo != NULL)
      {
            for (int x=0; x<=AreaNum; x++,pAreaInfo++)
            {
                pServerListInfo    = pAreaInfo->pServerListOfFirst;
                if (pServerListInfo != NULL)
                {
                  for (int y=0; y<=GetServerNum(pAreaInfo); y++, pServerListInfo++)
                  {
                        //序号
                        szTemp.Format(_T("%.2d"), y+1);
                        m_ServerList.InsertItem(y,szTemp);
                        //大区的名字
                        m_ServerList.SetItemText(y,1,pServerListInfo->szName);
                        //服务器的名字
                        m_ServerList.SetItemText(y,2,pServerListInfo->szName);
                        //IP和Port
                        m_ServerList.SetItemText(y,3,pServerListInfo->sServerIpPort);
                  }
                }
            }
      }
      UpdateData();
      delete    pServerListInfo;
      delete    pAreaInfo;
    }catch(...)
    {
      ::AfxMessageBox("遍历服务器列表时,出现异常……");
    }
}
最后看下效果吧:



总的来说,还是不错的,是吗?
哈哈,本人才疏学浅,也只能讲点这些简单的东西了,仅希望能以此抛砖引玉,引来大牛的分享……

[ 本帖最后由 bester 于 2009-2-18 02:25 编辑 ]

datochan 发表于 2009-2-17 12:42

发一个帖子里,就自动给截断了,不知道什么原因,希望管理员查一下~~~

不如我们跟进去看看,服务器结构是什么样子,哈哈
0132A5B80A 00 00 00 BA F9 C2 AB C9 BD 00 40 A0 F9 17 04....葫芦山.@狔
0132A5C894 FA 17 04 00 00 00 00 00 E9 92 7C 40 00 93 01旡.....閽|@.?
不多介绍了,继续看下面的代码:
0040C9F1|.8D3C01                      |lea   edi, dword ptr          ;ECX是结构偏移的计数器,大家都应该能看明白的
0040C9F4|.42                                |inc   edx                              ;循环计数器了,不用我讲的•~~
0040C9F5|.81C1 08010000         |add   ecx, 108                     ;每个服务器信息结构的大小是0x108,指到数组的下个成员
0040C9FB|.85ED                        |test    ebp, ebp
0040C9FD|.895424 28                  |mov   dword ptr , edx          ;保存服务器的序号信息
0040CA01|.894C24 2C                     |mov   dword ptr , ecx          ;保存服务器信息结构的偏移信息
0040CA05|.0F8C A9020000       |jl      0040CCB4
0040CA0B|.3BAB 1C010000       |cmp   ebp, dword ptr          ;看来这个0x11C很关键哦,
0040CA11|.0F8D 9D020000       |jge   0040CCB4                         ;大于等于就跳走了~~~
这里用到了这个0x11C这个变量,根据上面代码的最后两行,如果服务器数量大于等于6就跳走,估计是个用来防止异常的,有兴趣的朋友可以跟一下,这里就不多说了!
继续看代码:
0040CA17|.8B83 18010000 |mov   eax, dword ptr          ;取出第一个服务器结构的首地址
0040CA1D|.8B34A8      |mov   esi, dword ptr
0040CA20|.8D04A8      |lea   eax, dword ptr        ;dword ptr 不会被看糊涂吧,取结构体成员的基本方法!
0040CA23|.8D57 04       |lea   edx, dword ptr          ;还记得EDI里存的是什么吧,哈哈,偏移+4就是取服务器名字了~
0040CA26|.85D2          |test    edx, edx
0040CA28|.C746 3C 01000>|mov   dword ptr , 1
0040CA2F|.8D9E 8C000000 |lea   ebx, dword ptr
0040CA35|.75 04         |jnz   short 0040CA3B
0040CA37|.33C0          |xor   eax, eax
0040CA39|.EB 14         |jmp   short 0040CA4F
0040CA3B|>8BC2          |mov   eax, edx                         ;1
0040CA3D|.8D48 01       |lea   ecx, dword ptr
0040CA40|.894C24 30   |mov   dword ptr , ecx
0040CA44|>8A08          |/mov   cl, byte ptr             ;断在了这里,也就是说,这里取了服务器的列表信息!
0040CA46|.40            ||inc   eax                                  ;眼熟不?哈哈
0040CA47|.84C9          ||test    cl, cl
0040CA49|.^ 75 F9         |\jnz   short 0040CA44
好了,分析就基本上到此结束了,没有必要再继续分析了,接下来就是分析一下,我们需要什么东西,然后就是怎么把我们分析得到的东西转换成代码!

先想想我们现在需要的东西:各个大区的序号,还有大区的名字,服务器的名字,服务器的IP和端口号,需要的数据就这么多了,接下来看看我们现在分析到了什么数据~

先看下服务器的结构中,我们已经知道了哪些数据

1.       每个服务器信息结构的大小是0x108
2.        直接引用服务器的数据,如下:

0132A5B80A 00 00 00 BA F9 C2 AB C9 BD 00 40 A0 F9 17 04....葫芦山.@狔
0132A5C894 FA 17 04 00 00 00 00 00 E9 92 7C 40 00 93 01旡.....閽|@.?


我们需要的数据很少,只需要名字和IP及端口就OK了,所以直接看数据段,来肉眼来定一下就可以了
这样,我们定义的结构体,如下:
//    游戏服务器的数据结构定义
typedef struct    _GAME_SERVERLIST_INFO
{
    DWORD             dwServerNo;                  //    服务器的序号 0
    char                   szName;                   //    名字offset 4
    DWORD             dwUnknow1;            //    未知offset C            
    char                   sServerIpPort;         //    IP和端口 offset 1C8
    DWORD             dwUnknow2;            //    结尾的数据 offset 1CC    用来补齐0x108的结构大小
} GAME_SERVERLIST_INFO, *PGAME_SERVERLIST_INFO;
再看大区的数据结构中,我们知道的数据:

1.        现在只知道第一个成员是大区的ID,第二个是名字,而且结构的大小要凑够0x1D4
2.        看到了吧,大区数构中偏移第1C8的成员是个最小值
3.        大区数构中偏移第1CC的成员是个最大值


好了,现在我们来定义大区的结构体,如下://    游戏大区的数据结构定义
typedef struct    _GAME_AREA_INFO
{
    DWORD                                          dwTheAreaNo;            //    大区的序号 0
    char                                                  szName;                //    名字offset 4
    DWORD                                          dwUnknow1;            //    未知offset C            这些数据对我们不重要,直接掠过
    _GAME_SERVERLIST_INFO            *pServerListOfFirst;    //    首个服务器 offset 1C8
    PDWORD                                      pTheEndData;            //    结尾的数据 offset 1CC
    PDWORD                                          pTheEndData2;            //    结尾的数据 1D0            用来补齐0x1D4的结构大小
} GAME_AREA_INFO, *PGAME_AREA_INFO;
到现在,数据已经整理好了,应该可以写代码了,在写代码以前呢,我们整理总结一下我们收集到的数据:

1.        这个程序的基址是:004812A8
2.        大区的地址指针+偏移的形式应该在:+4]
3.        计算大区数量的算法如下:
+DC]+8] 减去 +DC]+4] 然后在:
0040C932|.B8 8DC0088C               mov   eax, 8C08C08D
0040C937|.F7E9                                imul    ecx
0040C939|.03D1                                  add   edx, ecx
0040C93B|.C1FA 08                             sar   edx, 8
0040C93E|.8BC2                                  mov   eax, edx
0040C940|.C1E8 1F                               shr   eax, 1F
0040C943|.03C2                                add   eax, edx
4.        计算每个区服务器数量的算法如下:
用GAME_AREA_INFO:: pTheEndData 减去GAME_AREA_INFO::pServerListOfFirst 然后再如下计算:
0040C9A9|.B8 E1830F3E   mov   eax, 3E0F83E1
0040C9AE|.F7E9            imul    ecx                               ;3E0F83E1*(最大值-最小值)
0040C9B0|.C1FA 06      sar   edx, 6                            ;取其积的高32位值右移6位
0040C9B3|.8BC2            mov   eax, edx
0040C9B5|.C1E8 1F      shr   eax, 1F                           ;再移动0x1F位
0040C9B8|.03C2            add   eax, edx          ;OD显示是4,即有4个服务器,循环次数为4次
0040C9BA|.894424 20   mov   dword ptr , eax         ;把结果保存一下

5.        基址:004812A8 加上0x11C 中的值是最大的服务器数量,若算出来的服务器数量大于等于这个数,就是出错了,应该加容错处理!


[ 本帖最后由 bester 于 2009-2-17 12:54 编辑 ]

creantan 发表于 2009-2-17 13:02

学习了。。。哈哈。。好文。。

oh_lucifer 发表于 2009-2-17 13:11

相当不错的文章hoho~~~

支持啊....

内存读。
省的解密了~

lawry 发表于 2009-2-17 13:12

学习了
谢谢楼主

mingjie_520 发表于 2009-2-17 13:35

粗粗的看了一边,能理解个40%还的努力啊

zapline 发表于 2009-2-17 14:52

:funk: 我再努力几年
追上你;P

Squn 发表于 2009-2-17 15:30

我晕.好东西.. :loveliness:

IsQun 发表于 2009-2-17 15:35

支持原创:D :D
页: [1] 2 3 4 5 6
查看完整版本: 讲一下逆向分析在编程中的应用吧