byte数组穿换成pcm格式_实例讲解未知游戏文件格式的逆向分析方法(下)

8d3c288c0c6ec0ce4d111275f63b2214.gif

(接上文) 

现在,我们知道v8绝对是一个类。接下来,让我们暂时离开这里,回到50B9A2,考察一下50B91E函数:

    _BYTE *__stdcall sub_50B91E(int a1, int a2, unsigned int a3)

    {

      unsigned int v3; // ecx@1

      unsigned int v4; // esi@1

      _BYTE *result; // eax@2

      v3 = 0;

      v4 = 0;

      if ( a3 )

      {

        do

        {

          result = (_BYTE *)(v4 + a2);

          *result ^= *(_BYTE *)(a1 + v3++ + 116);

          if ( v3 >= 0x1000 )

            v3 = 0;

          ++v4;

        }

        while ( v4 < a3 );

      }

      return result;

    }

首先,让我们重命名最后两个参数,因为我们已经知道它们是什么:

    _BYTE *__stdcall sub_50B91E(int a1, int pDestBuffer, unsigned int uiSize)

    {

      unsigned int v3; // ecx@1

      unsigned int v4; // esi@1

      _BYTE *result; // eax@2

      v3 = 0;

      v4 = 0;

      if ( uiSize )

      {

        do

        {

          result = (_BYTE *)(v4 + pDestBuffer);

          *result ^= *(_BYTE *)(a1 + v3++ + 116);

          if ( v3 >= 0x1000 )

            v3 = 0;

          ++v4;

        }

        while ( v4 < uiSize );

      }

      return result;

    }

在这里,最重要的一行代码是:

   *result ^= *(_BYTE *)(a1 + v3++ + 116);

我们知道,XOR通常用于加密/解密过程。如您所见,它会逐字节地处理位于a1+116+v3处的数组,并对该数组的加密缓冲区中的每个字节都进行异或操作。如果v3等于4096(0x1000h),则将其重置为0。XOR处理将持续到v4(在每次迭代结束时都会递增)大于或等于参数uiSize时为止。

看上去,这可能有点难以理解,不过不要担心,我们可以借助于动态分析工具来搞定它。

2f52f6daf43135a8e193b8e67dff853b.png使用OllyDbg进行动态分析

首先,在OllyDbg中加载pbclient.exe,然后,单击“E”按钮并选择“pbclient.exe”模块,以确保我们处于正确的模块中。

我们将在CreateFileA调用(还记得吗?它位于0x52AE36中)的第一个参数处设置一个断点,它实际上就是我们的文件名。

(注意:设置断点后不要删除,我们以后还会需要它们)

它位于0x52AE82处:

d9b618ca80db28878b4878e52c269817.png

让我们现在就开始动手吧!如果它崩溃了,建议先下载Stealth64插件,如果您使用的是64位Windows 7系统的话。同时,我们还启用了除“Misc”部分之外的所有选项。

如果一切顺利,它现在将会在图示中的位置中断:

e0232ba42a81d1bef0bccc2ede045e90.png

我们已经知道,它将使用anim.bus(同时,我们也得到了它使用这个函数的确认)。让我们在调用MapViewOfFile之后立即设置另一个断点,以获取映射视图的地址(返回值通常存储在EAX中):

16b1652d3344f304da9e7d2e4fbbe820.png

(顺便说一句,一定要确保Anim.bus没有在任何地方打开,否则,它可能会失败!)

如果成功,映射视图的地址将存放到EAX寄存器中,因此,请在“Registers”窗口中右键单击它,然后,单击“Follow in Dump”选项:

11b3e5a532b7cd63839986127c0df194.png

让我们直接转到0x50B91E(执行XOR的地方),并在那里设置另一个断点,然后恢复游戏从而再次触发断点。

7595fc288916b2af0125ef07e6894f9c.png

使用F8单步跟踪指令,直到:

 0050B931  |. 8A540A 74      |MOV DL,BYTE PTR DS:[EDX+ECX+74] ; 74h => 114

这里,ECX用作数组的计数器。这里,它会与EDX的值相加,而EDX就是a1(记住,a1是一个类)。然后,加上距离数组开头的偏移量(74h/114)。

下面给出更加易于理解的伪代码:

   uint8_t DL = a1->xor_array[ECX]; //xor_array starts 74h into a1, and ECX is incremented after each iteration

我们来看看下面一行代码:

   0050B935  |. 03C6           |ADD EAX,ESI

EAX保存的是目标缓冲区的地址。它也会在每次迭代结束时递增,直到“uiSize”字节被异或为止。

之后,继续在转储中跟踪EAX,并在循环(POP ESI)指令后设置断点,恢复游戏并查看转储窗口:

e78bdaddbaa887811d1c732baba1e9c0.png

它好像已经解密了缓冲区中的内容!

4ac0feddc533b4260ca8de1cd5162495.png

我们跳过33个字节,并解密了272个字节的内容。但是如果我们仔细查看Data文件夹中的Anim.bus,会发现文件Anim.bus的大小是305个字节。而272+33正好等于……

305!这说明整个Anim.bus文件都被解密了。

那么,解密缓冲区后,我们能够得到哪些有用的信息呢?不多,只不过看起来更像个文件夹名称而已。

接下来,我们可以编写一个简单应用程序,让它执行与游戏完全相同的操作,即使用CreateFile、OpenFileMapping和MapViewOfFile将文件映射到内存,并解密缓冲区中的内容(记住,起始位置是缓冲区地址+33个字节!)。要想完成解密,还需要获取用作XOR密钥的字节数组中的内容,该数组长度为4096字节(4KB)。为此,需要重新关闭并运行该游戏,并触发该指令:

   0050B931  |. 8A540A 74      |MOV DL,BYTE PTR DS:[EDX+ECX+74] ; 74h => 114

读取EDX的值,加上114,即数组开头的地址。在转储窗口中跟踪它,将该地址加上4096,即数组末尾的地址。之后,只需复制这两个地址之间的所有字节,并利用Notepad++格式化所有内容即可。

如果在此过程中遇到麻烦,可以访问下列地址:

· http://pastebin.com/skZKAx27

下面给出解密函数:

    bool DecryptData(uint8_t* puiBuffer, const size_t uiSize)

    {

             if (!uiSize)

             {

           

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值