星之海洋 记忆 – 资源算法

来自这条评论的请求

STAR OCEAN -anamnesis – iTunes – Apple

另外一提,拆到现在我依然没有打开过游戏(看截图就已经不感兴趣了)


首先这个游戏竟然是个自建引擎的游戏,下ipa下了2.7g,好久之后才下下来然后发现不是unity(这家伙把资源全打包在ipa里了)。本来估计se会上程序保护,去百货商店下了个apk后发现竟然没有保护,直接是个 libSOA.so ,那就开始看呗

现在都有点忘了我是怎么找到函数的,好像是直接在exports里面搜decrypt,里面有个 Framework::CFileLoader::SetDecryptFunction ,看了调用在 CGame::OnInitialize 里引用了,参数是个全局偏移,偏移旁边有个函数里面有文件头确认

在最早看到的时候这里是MOV 0x444C4441,并且没有被识别为函数,只是个loc,进去之后按P换成函数之后就能直接F5了

函数很直白,先来文件头ADLD判断,然后判断版本,1版本是个XOR,2版本就是DecryptAES128。

版本1的异或key是参数a4的CHash32结果,转为hex(%x)后的字符串直接作为异或密钥。

版本2是同样参数a4的CHash32,在数字前填0至32长度送入Decrypt

这里CHash32进去大略对比就可以发现是crc32,包括其中crctable正是crc32的table。

到这里以后,我去研究了下SOADec,这个工具是C#写的所以直接扔进dnspy,但算法给我看懵了,乍看和程序算法有点像,但又看不懂

在我后来研究出来结果之后,我才看懂这个的过程。因为异或的可逆性,这个算法是用期望输出(83 76 90 7 0 1 37 0,也就是’SLZ’ 0x7 0x0 0x1  0x25 0x0)猜出密钥,然后把猜的密钥从8长度到5长度挨个尝试,如果异或结果可以正常解压就是正确的密钥,不得不说这个流程很骚

虽然最早搞不懂这个工具的流程,但这不妨碍我debug拿正确密钥。要了个早期资源样本后,在写文件的地方断点拿到了正确的密钥,那个文件的结果是个8长度的hex。同时我还去确认了旧版本,发现17年的版本里面就已经是这个带开关的函数了

有了期望结果,我就开始尝试不同字符的crc,因为这个函数是FileLoader的,所以最有可能的就是文件名或者路径。但是我试了各种组合都不对。最后重新去对比这个CHash32到底是不是crc32,这一比对发现问题了

function crc32_mod($str) {
  $remaining = strlen($str);
  $crc = 0;
  if ($remaining) {
    $crc = $remaining;
    /*
    crc32 标准实现:
    $crc = 0xFFFFFFFF;
    */
    $i = 0;
    do {
      $current_char = ord($str[$i]);
      $remaining--;$i++;
      $crc = CRCTABLE[($current_char ^ $crc) & 0xff] ^ ($crc >> 8);
    } while ($remaining);
  }
  return $crc;
}

这个CHash32并不是标准crc32,和标准crc32的区别在于crc值的初始化是输入长度而不是0xFFFFFFFF。换了crc函数之后,直接就用builtin_download下的相对路径算出结果了。

确认了密钥的生成,然后就是aes密钥的变换。在断点出了密钥的时候我已经试过直接喂给aes,但是结果不对。跟着DecryptAES128进去先调用了 Encrypt::CEncryptAES128::CEncryptAES128 然后才是 Encrypt::CEncryptAES128::Decrypt,CEncryptAES128 里面又进到了Initialize,在里面看到了一个醒目的字符串 09375711857134629684891855841614 。初始化函数里面的过程读了一阵发现这函数基本就是个hex2bin,于是 我就把这个新传拼到key后面转bin,结果还是不对。

在我怀疑人生的途中,又手写了初始化,甚至还写错了出来了个完全不一样的结果,最后用c才重新确认了确实是hex2bin。然后我就把新串给删掉了,结果在输出的16字节往后看到了SLZ……

于是我就把那个串也转bin扔给iv了,然后前16也一起出来了,文件头是DCNE(看看上面ida,看到最底下了吗)

$data = file_get_contents('cc0001_b01a.apk');
$hash = crc32_mod('Character/cc0001_b01a.apk');
$key = sprintf("%00000000000000000000000000000032u", $hash);

$data = openssl_decrypt(
  substr($data, 16),
  'AES-128-CBC',
  hex2bin($key),
  OPENSSL_RAW_DATA+OPENSSL_ZERO_PADDING,
  hex2bin('09375711857134629684891855841614')
);
file_put_contents('cc0001_b01a-dec.apk', $data);

(我怎么毕设摸鱼天天搞这些玩意儿.jpg)

6 thoughts on “星之海洋 记忆 – 资源算法”

        1. 然而是appguard的加壳,不算()
          通信和资源都没变

      1. 我可不是万能拆包机器
      2. 这么火的游戏,想来是有很多人研究的,我觉得你多搜索就能找到,或者真的有心也可以找已有的拆包团队
      3. 同2,这么火的游戏,如果dev有心搞,算法肯定是相当恶心

回复 Tonakai 取消回复

您的电子邮箱地址不会被公开。 必填项已用*标注

To create code blocks or other preformatted text, indent by four spaces:

    This will be displayed in a monospaced font. The first four 
    spaces will be stripped off, but all other whitespace
    will be preserved.
    
    Markdown is turned off in code blocks:
     [This is not a link](http://example.com)

To create not a block, but an inline code span, use backticks:

Here is some inline `code`.

For more help see http://daringfireball.net/projects/markdown/syntax