首页
社区
课程
招聘
[原创]Galgame汉化中的逆向(四)_IDA静态分析psv游戏
发表于: 2020-11-27 18:23 8465

[原创]Galgame汉化中的逆向(四)_IDA静态分析psv游戏

2020-11-27 18:23
8465

本帖在论坛和我的博客同时发布
上期链接Galgame汉化中的逆向(五):Switch平台下的Unity后端il2cpp分析

前三篇都在谈pc汉化中的基本方法,这篇来说说主机汉化的操作。由于主机的特殊性,用户权限比较低,一般很难做到动态调试(大多是只有比较完善的模拟器才能动态调试),甚至连编写自制软件都不能用类似于gdb的调试,往往都是插入log来看输出。而且因为主机游戏往往没有加壳和混淆什么的(本身主机系统加密防破解就很变态了,游戏就没必要再搞防护了),因此一般都是进行静态分析。静态分析最重要的是定位,通常是通过特征字节来定位(如游戏opcode,文件magic等),或者根据代码量、大的switch结构、相关字符串(别抱太大希望,字符串很难找到refer)。这篇来谈谈如何用ida静态分析主机游戏,在魔改算法不容易看出来的情况下,如何将ida的伪代码翻译成可执行的代码。本次以psv游戏arm汇编为例。

BG_NAMING

此游戏有一堆*.ARC *.BIN 文件,直接用GARBRO打开,可以看到文件名但是无法打开每个文件,观察可知是用了叫做gss的游戏引擎。简单分析可知 *.bin为索引文件。以SCRDATA.BIN SCRDATA.ARC为例,文件头如下所示。

psv_scrbin_scrarc

这里看着SCRDATA.BIN SCRDATA.ARC规律很明显,两者结合(根据SCRDATA.BIN 中的索引来打印SCRDATA.ARC的每项头信息)简单打印一下,可以得到如下的数据:

b'LSDARC V.100' 325
0 AUTOEXEC 0 0x0 0x1a6 0x800
1 DEBUG 0 0x800 0x143 0x800
2 INIT 1 NH 0x1000 0x1612 0x1000
3 PRG_BG 1 NH 0x2000 0x14c6 0x1000
4 PRG_EFFECT 1 NH 0x3000 0xc0d 0x1000
5 PRG_NAME 1 ND 0x4000 0x689 0x800
6 PRG_ROUTE 1 NH 0x4800 0x2e18 0x2800
7 PRG_STAND 1 NH 0x7000 0x31e0 0x2800
8 RELOAD 1 ND 0x9800 0x349 0x800
9 SELECT2 0 0xa000 0x102 0x800
10 COM001 1 WD 0xa800 0x3f1 0x800
11 COM002 1 NH 0xb000 0x130d 0x1800
12 COM003 0 0xc800 0xa23 0x1000
13 COM004 1 NH 0xd800 0x3e80 0x3800
14 COM005 1 NH 0x11000 0x1fb0 0x2000
15 COM006 1 NH 0x13000 0x4973 0x4000
16 COM007 1 NH 0x17000 0x1003 0x1000
17 COM008 1 NH 0x18000 0x3e5a 0x3800
18 COM009 1 NH 0x1b800 0x194f 0x1800
19 COM010 1 NH 0x1d000 0x2ad2 0x2800

...

根据对照很容易分析出SCRDATA.BIN数据结构,文件magic为12字节,之后4字节为index数量。然后就是index_entry了。

magic[12] //"LSDARC V.100"
count 4
index[]
|IsPacked 4 //导入不用打包,IsPacked调成0即可
|Offset 4
|UnpackedSize 4
|Size 4 //0x800的倍数
|Name 00

同理可得SCRDATA.ARC的数据结构。

//unpacked
53 43 52 20 32 2E 30 30 //SCR 2.00

//packed
fileblock[]
|magic[4] //4C 53 44 1A, LSD\x1A
|enc_method 1 //enc_method, B W S
|pack_method 1 //pack_method, D R H W
|unpacked_size 4 //may be different than the value in BIN index, often 4 byte asign

上面文件数据结构分析,我们发现有是否压缩的flag和压缩后和解压的体积,再加上来查看*.ARC文件,内部比较紧凑,因此判定是压缩或者加密了。我们观察得到pack_method字段有"D,R,H,W"这四个很醒目的标识符,这里可以作为突破口。必须用ida6.8安装VitaLoaderIDA载入eboot.binsearch immediate搜索"H"等标志位即可找到。

同时我们注意到GARBRO源码中已经有了框架分析了一部分,但是最难的一个函数UnpackH仍是throw new NotImplementedException();我们需要自己分析一下补全。

unpack_flag

同时,我们在定位处上下翻翻,还能看到huffmanrunleng的字符串,因此压缩算法很可能是基于这两种算法的魔改。

huffman_decode

下面以UnpackH函数为例(其他函数UnpackD, UnpackW等也同理),来谈谈如何分析。伪代码层面上的分析一般有下列方法:

猜每个变量的含义并改名(字符串缓冲区,当前位置指针等比较容易识别)

修改到合适数据类型,

有些是数组和结构的,添加结构体看着舒服一些。

还有一些情况,地址显示的是负号,我们需要手动invert signed

合并相同变量(注意不能乱合并,尤其是临时赋值的)

用上面方法初步分析整理,可得到如下的伪代码。

下面,我们就需要将伪代码来转换成可执行代码了,由于GARBRO有了一部分解包代码,我们就在此基础上完善了,而且c#代码也和c很相似,就把ida的伪代码转换成c#代码。这个操作其实难度不是很大,但是需要非常细心,错一处最后结果都可能有问题,而且很不好调试。一般情况下看着解包后的数据有规律且可读,通常情况下就可以认为是正确了,但是遇到特殊情况需要用金手指插件去dump内存,然后去逐字节比对。至于为什么不直接dump解包,因为dump过程非常繁琐,游戏不是把所有资源都加载的,主机上的hook非常麻烦。因此还是很有必要来分析静态解包方法的。

以下为伪代码和c#代码,如将0x811c6780这个地址命名为buf1,所有这个基地址的偏移也可用数组表示。

*(_DWORD *)(8 * v29 + 0x811C8784) != (v27 & *(_DWORD *)(8 * cur_char2 + 0x8107F828)) 转换为BitConverter.ToUInt32(buf, (int)off2 + 8 * v29) != (v27 & dword_8107F828[2 * cur_char2])

注意指针加减*((dword *)addr + 1), 其实是addr+4的地址里的dword值。

同时要特别注意高级语言的数据类型,数据类型不对可能会把后面数组里的内容覆盖了。

我们注意到伪代码里有调用dword_8107F828,去ida里看看相应的地址,把截至到0的数据dump出来作为全局变量到c#里。

ida_array_8107F748

由于c#的goto不能跳入其他循环,遇到这种情况我们就需要把goto进入的代码都粘贴过来了。

就是寻找所有的子函数调用,并将其逐个还原。有时候可能伪代码显示有点问题,要看看汇编。

在运行结果正确的技术上,这时候可以进行整体的考虑了。即站在更高层来分析那些代码逻辑是相同的,把每部分相同功能的变量与代码提到外层,使得整体看着简洁。同时优化位运算等操作的可读性。此处UnpackH这个函数的整体还原代码如下:

根据这个游戏,我把GARBROgss引擎解包完善了,详见我的github同时我也pull request了,不过作者好像好久没维护了。

还原算法后测试一下,发现剧本提取没问题,文字也都出来了,同理图片封包格式也一样。

ida2csharp1

至于封包,我们可以走一个捷径,就是这个游戏有个IsPacked 这个flag。修改这个flag,我们可以不压缩和加密,直接把原来文件封包,就是要注意一下0x800等字节对齐与补零,索引重建等。

之后为了汉化文本超长,需要分析一下opcode。这个游戏根据猜测把opcode打印一下即可看出规律,分析出每条指令是干什么的。这游戏比较简单,放一下opcode打印代码和图了,不再详细分析了。当然还有字库问题,这个相对来说处理起来不难,这里不再赘述了。

opcode_option

另外此游戏psv和psp文件结构非常相似,一些内容也可以用psp模拟器测试提高效率。至于psp的mips汇编和如何动态调试,这些我打算之后出教程。

这些都分析完后,重新导入文本和图片,搞定!

psv_test

psp_importpic_test2

 
 
 
 
 
 
 
 
 
// UnpackH
int __fastcall sub_81043752(_BYTE *buf_packed, _BYTE *output, int unpacked_size)
{
  _BYTE *buf; // r10@1
  _BYTE *cur_addr; // r6@1
  int v7; // t1@1
  int v8; // r2@1
  int i1; // r8@1
  int v10; // r1@2
  signed int cur_char1; // r5@2
  int v12; // r0@4
  int v13; // r7@7
  int v14; // lr@7
  unsigned int v15; // r7@8
  int v16; // r10@9
  int v17; // r0@10
  int v18; // r6@6
  signed int v19; // r7@6
  int i2; // r5@12
  _BYTE *buf3_addr; // lr@13
  int v22; // r4@15
  int v23; // r0@18
  int v24; // r12@19
  __int64 v25; // r0@19
  int cur_char2; // r9@19
  unsigned int v27; // r5@19
  int v28; // lr@20
  int v29; // lr@23
  char v30; // lr@28
  _BYTE *v32; // [sp+0h] [bp-50h]@2
  signed __int64 v33; // [sp+8h] [bp-48h]@18
  int next; // [sp+10h] [bp-40h]@1
  int v35; // [sp+14h] [bp-3Ch]@18
  _BYTE *cur_output; // [sp+1Ch] [bp-34h]@1
  int first_char; // [sp+28h] [bp-28h]@1
 
  buf = (_BYTE *)&unk_811C6780;
  cur_output = output;
  memset(0x811C6780, 0, 0x2000);                // buf1
  memset(0x811C8784, 0, 0x800);                 // buf2
  memset(0x811C8F84, 0, 0x800);                 // buf3
  v7 = *buf_packed;
  cur_addr = buf_packed + 2;
  v8 = 0;
  first_char = v7;
  i1 = 0;
  next = 2;
  do
  {
    v10 = next;
    cur_char1 = *cur_addr;
    v32 = cur_addr + 1;
    ++next;
    if ( *cur_addr )
    {
      if ( cur_char1 >= 8 )
      {
        v13 = cur_addr[1];
        v14 = cur_addr[2];
        if ( cur_char1 >= 0xD )
        {
          v16 = (unsigned __int8)v13 + (v14 << 8);
          if ( cur_char1 < 0x10 )
          {
            *(_BYTE *)(8 * i1 + 0x811C8F88) = cur_char1;// buf3 + 4
            *(_DWORD *)(8 * i1 + 0x811C8F84) = v16;// buf3
            *(_BYTE *)(8 * i1 + 0x811C8F88) = v8;// bu3 + 4
            v32 = cur_addr + 3;
            next = v10 + 3;
            i1 = (unsigned __int8)(i1 + 1);
          }
          else
          {
            v17 = cur_addr[3];
            *(_BYTE *)(8 * i1 + 0x811C8F88) = cur_char1;// buf3+4
            v32 = cur_addr + 4;
            *(_DWORD *)(8 * i1 + 0x811C8F84) = v16 + (v17 << 16);// buf3
            *(_BYTE *)(8 * i1 + 0x811C8F89) = v8;// buf3+5
            next = v10 + 4;
            i1 = (unsigned __int8)(i1 + 1);
          }
        }
        else
        {
          v15 = v13 & 0xFFFF00FF | ((unsigned __int8)v14 << 8);
          buf[2 * (unsigned __int16)v15] = v8;
          buf[2 * (unsigned __int16)v15 + 1] = cur_char1;
          v32 = cur_addr + 3;
          next = v10 + 3;
        }
      }
      else
      {
        v32 = cur_addr + 2;
        next = v10 + 2;
        v12 = cur_addr[1];
        buf[2 * v12] = v8;
        buf[2 * v12 + 1] = cur_char1;
      }
    }
    buf = (_BYTE *)&unk_811C6780;
    cur_addr = v32;
    ++v8;
  }
  while ( v8 != 0x100 );
  v18 = 0;
  v19 = 13;
  do
  {
    i2 = 0;
    *(_BYTE *)(v19 + 0x811C9784) = v18;         // buf4, buf2+0x1000
    if ( i1 )
    {
      buf3_addr = (_BYTE *)&dword_811C8F84;
      do
      {
        if ( buf3_addr[4] == v19 )
        {
          v22 = *((_DWORD *)buf3_addr + 1);
          *(_DWORD *)(8 * v18 + 0x811C8784) = *(_DWORD *)buf3_addr;// buf2
          *(_DWORD *)(8 * v18 + 0x811C8788) = v22;// buf2+4
          v18 = (unsigned __int8)(v18 + 1);
        }
        ++i2;
        buf3_addr += 8;
      }
      while ( i2 != i1 );
    }
    v19 = (unsigned __int16)(v19 + 1);
  }
  while ( v19 != 24 );
  unk_811C979C = v18;
  v35 = 0;
  v33 = 0i64;
  qword_811C97A8 = 0i64;
  v23 = unpacked_size;
  if ( !unpacked_size )
    return v35;
  while ( 1 )
  {
    v24 = next + ((unsigned int)(v33 & 0x1F) >> 3) + ((v33 >> 3) & 0xFFFFFFFC);
    LOBYTE(v23) = buf_packed[v24 + 3];
    v25 = (signed int)(((buf_packed[v24] | (buf_packed[v24 + 1] << 8)) & 0xFF00FFFF | (buf_packed[v24 + 2] << 16)) & 0xFFFFFF | (v23 << 24));
    cur_char2 = first_char;
    v27 = sub_8105E56C(v25, HIDWORD(v25), (v33 & 0x1F) - (v33 & 0x18));
    if ( first_char != 0xD )
    {
      while ( 1 )
      {
        v28 = v27 & *(_DWORD *)(8 * cur_char2 + 0x8107F828);// const1
        dword_811C8780 = 2 * v28 + 0x811C6780// buf1
        if ( cur_char2 == *(_BYTE *)(2 * v28 + 0x811C6781) )// buf1+1
          break;
        cur_char2 = (unsigned __int16)(cur_char2 + 1);
        if ( (unsigned __int16)cur_char2 == 0xD )
          goto LABEL_22;
      }
      v30 = *(_BYTE *)(2 * v28 + 0x811C6780);   // buf1
      goto LABEL_29;
    }
LABEL_22:
    if ( cur_char2 == 0x18 )
      break;
    while ( 1 )
    {
      v29 = *(_BYTE *)(cur_char2 + 0x811C9784); // buf4
      if ( v29 != *(_BYTE *)(cur_char2 + 0x811C9785) )// buf4+1
        break;
LABEL_26:
      if ( ++cur_char2 == 0x18 )
        goto LABEL_33;
    }
    while ( *(_DWORD *)(8 * v29 + 0x811C8784) != (v27 & *(_DWORD *)(8 * cur_char2 + 0x8107F828)) )// buf2, const1
    {
      v29 = (unsigned __int16)(v29 + 1);
      if ( (unsigned __int16)v29 == *(_BYTE *)(cur_char2 + 0x811C9785) )// buf4+1
        goto LABEL_26;
    }
    v30 = *(_BYTE *)(8 * v29 + 0x811C8789);     // buf2+5
LABEL_29:
    *cur_output = v30;
    qword_811C97A8 = v33 + (unsigned __int16)cur_char2;
    v23 = v35 + 1;
    ++cur_output;
    v33 += (unsigned __int16)cur_char2;
    v35 = v23;
    if ( v23 == unpacked_size )
      return v35;
  }
LABEL_33:
  sub_8104332C();                               // None
  return 0;
}
// UnpackH
int __fastcall sub_81043752(_BYTE *buf_packed, _BYTE *output, int unpacked_size)
{
  _BYTE *buf; // r10@1
  _BYTE *cur_addr; // r6@1
  int v7; // t1@1
  int v8; // r2@1
  int i1; // r8@1
  int v10; // r1@2
  signed int cur_char1; // r5@2
  int v12; // r0@4
  int v13; // r7@7
  int v14; // lr@7
  unsigned int v15; // r7@8
  int v16; // r10@9
  int v17; // r0@10
  int v18; // r6@6
  signed int v19; // r7@6
  int i2; // r5@12
  _BYTE *buf3_addr; // lr@13
  int v22; // r4@15
  int v23; // r0@18
  int v24; // r12@19
  __int64 v25; // r0@19
  int cur_char2; // r9@19
  unsigned int v27; // r5@19
  int v28; // lr@20
  int v29; // lr@23
  char v30; // lr@28
  _BYTE *v32; // [sp+0h] [bp-50h]@2
  signed __int64 v33; // [sp+8h] [bp-48h]@18
  int next; // [sp+10h] [bp-40h]@1
  int v35; // [sp+14h] [bp-3Ch]@18
  _BYTE *cur_output; // [sp+1Ch] [bp-34h]@1
  int first_char; // [sp+28h] [bp-28h]@1
 
  buf = (_BYTE *)&unk_811C6780;
  cur_output = output;
  memset(0x811C6780, 0, 0x2000);                // buf1
  memset(0x811C8784, 0, 0x800);                 // buf2
  memset(0x811C8F84, 0, 0x800);                 // buf3
  v7 = *buf_packed;
  cur_addr = buf_packed + 2;
  v8 = 0;
  first_char = v7;
  i1 = 0;
  next = 2;
  do
  {
    v10 = next;
    cur_char1 = *cur_addr;
    v32 = cur_addr + 1;
    ++next;
    if ( *cur_addr )
    {
      if ( cur_char1 >= 8 )
      {
        v13 = cur_addr[1];
        v14 = cur_addr[2];
        if ( cur_char1 >= 0xD )
        {
          v16 = (unsigned __int8)v13 + (v14 << 8);
          if ( cur_char1 < 0x10 )
          {
            *(_BYTE *)(8 * i1 + 0x811C8F88) = cur_char1;// buf3 + 4
            *(_DWORD *)(8 * i1 + 0x811C8F84) = v16;// buf3
            *(_BYTE *)(8 * i1 + 0x811C8F88) = v8;// bu3 + 4
            v32 = cur_addr + 3;
            next = v10 + 3;
            i1 = (unsigned __int8)(i1 + 1);
          }
          else
          {
            v17 = cur_addr[3];
            *(_BYTE *)(8 * i1 + 0x811C8F88) = cur_char1;// buf3+4
            v32 = cur_addr + 4;
            *(_DWORD *)(8 * i1 + 0x811C8F84) = v16 + (v17 << 16);// buf3
            *(_BYTE *)(8 * i1 + 0x811C8F89) = v8;// buf3+5
            next = v10 + 4;
            i1 = (unsigned __int8)(i1 + 1);
          }
        }
        else
        {
          v15 = v13 & 0xFFFF00FF | ((unsigned __int8)v14 << 8);
          buf[2 * (unsigned __int16)v15] = v8;
          buf[2 * (unsigned __int16)v15 + 1] = cur_char1;
          v32 = cur_addr + 3;
          next = v10 + 3;
        }
      }
      else
      {
        v32 = cur_addr + 2;
        next = v10 + 2;
        v12 = cur_addr[1];
        buf[2 * v12] = v8;
        buf[2 * v12 + 1] = cur_char1;
      }
    }
    buf = (_BYTE *)&unk_811C6780;
    cur_addr = v32;
    ++v8;
  }
  while ( v8 != 0x100 );
  v18 = 0;
  v19 = 13;
  do
  {
    i2 = 0;
    *(_BYTE *)(v19 + 0x811C9784) = v18;         // buf4, buf2+0x1000
    if ( i1 )
    {
      buf3_addr = (_BYTE *)&dword_811C8F84;
      do
      {
        if ( buf3_addr[4] == v19 )
        {
          v22 = *((_DWORD *)buf3_addr + 1);
          *(_DWORD *)(8 * v18 + 0x811C8784) = *(_DWORD *)buf3_addr;// buf2
          *(_DWORD *)(8 * v18 + 0x811C8788) = v22;// buf2+4
          v18 = (unsigned __int8)(v18 + 1);
        }
        ++i2;
        buf3_addr += 8;
      }
      while ( i2 != i1 );
    }
    v19 = (unsigned __int16)(v19 + 1);
  }
  while ( v19 != 24 );
  unk_811C979C = v18;
  v35 = 0;
  v33 = 0i64;
  qword_811C97A8 = 0i64;
  v23 = unpacked_size;
  if ( !unpacked_size )
    return v35;
  while ( 1 )
  {
    v24 = next + ((unsigned int)(v33 & 0x1F) >> 3) + ((v33 >> 3) & 0xFFFFFFFC);
    LOBYTE(v23) = buf_packed[v24 + 3];
    v25 = (signed int)(((buf_packed[v24] | (buf_packed[v24 + 1] << 8)) & 0xFF00FFFF | (buf_packed[v24 + 2] << 16)) & 0xFFFFFF | (v23 << 24));
    cur_char2 = first_char;
    v27 = sub_8105E56C(v25, HIDWORD(v25), (v33 & 0x1F) - (v33 & 0x18));
    if ( first_char != 0xD )
    {
      while ( 1 )
      {
        v28 = v27 & *(_DWORD *)(8 * cur_char2 + 0x8107F828);// const1
        dword_811C8780 = 2 * v28 + 0x811C6780// buf1
        if ( cur_char2 == *(_BYTE *)(2 * v28 + 0x811C6781) )// buf1+1
          break;
        cur_char2 = (unsigned __int16)(cur_char2 + 1);
        if ( (unsigned __int16)cur_char2 == 0xD )
          goto LABEL_22;
      }
      v30 = *(_BYTE *)(2 * v28 + 0x811C6780);   // buf1
      goto LABEL_29;
    }
LABEL_22:
    if ( cur_char2 == 0x18 )
      break;
    while ( 1 )
    {
      v29 = *(_BYTE *)(cur_char2 + 0x811C9784); // buf4
      if ( v29 != *(_BYTE *)(cur_char2 + 0x811C9785) )// buf4+1
        break;
LABEL_26:
      if ( ++cur_char2 == 0x18 )
        goto LABEL_33;
    }
    while ( *(_DWORD *)(8 * v29 + 0x811C8784) != (v27 & *(_DWORD *)(8 * cur_char2 + 0x8107F828)) )// buf2, const1
    {
      v29 = (unsigned __int16)(v29 + 1);
      if ( (unsigned __int16)v29 == *(_BYTE *)(cur_char2 + 0x811C9785) )// buf4+1
        goto LABEL_26;
    }
    v30 = *(_BYTE *)(8 * v29 + 0x811C8789);     // buf2+5
LABEL_29:
    *cur_output = v30;
    qword_811C97A8 = v33 + (unsigned __int16)cur_char2;
    v23 = v35 + 1;
    ++cur_output;
    v33 += (unsigned __int16)cur_char2;
    v35 = v23;
    if ( v23 == unpacked_size )
      return v35;
  }
LABEL_33:
  sub_8104332C();                               // None
  return 0;
}
 
 
 
buf = (_BYTE *)&unk_811C6780;
cur_output = output;
memset(0x811C6780, 0, 0x2000);                // buf1
memset(0x811C8784, 0, 0x800);                 // buf2
memset(0x811C8F84, 0, 0x800);                 // buf3
v7 = *buf_packed;
cur_addr = buf_packed + 2;
v8 = 0;
first_char = v7;
i1 = 0;
next = 2;
buf = (_BYTE *)&unk_811C6780;
cur_output = output;
memset(0x811C6780, 0, 0x2000);                // buf1
memset(0x811C8784, 0, 0x800);                 // buf2
memset(0x811C8F84, 0, 0x800);                 // buf3
v7 = *buf_packed;
cur_addr = buf_packed + 2;
v8 = 0;
first_char = v7;
i1 = 0;
next = 2;
var buf = new Byte[0x10000];
Array.Clear(buf, 0, buf.Length);
const uint off2 = 0x2004;
const uint off3 = 0x2804;
const uint off4 = 0x3004; //0x811C9784
 
uint cur_addr = 2, pre_pos, next_pos = 2, cur_output_addr = 0;
byte outchar, i1 = 0, i2, v29, first_char = buf_packed[0];
int idx1 = 0, v28=0;
var buf = new Byte[0x10000];
Array.Clear(buf, 0, buf.Length);
const uint off2 = 0x2004;
const uint off3 = 0x2804;
const uint off4 = 0x3004; //0x811C9784
 
uint cur_addr = 2, pre_pos, next_pos = 2, cur_output_addr = 0;
byte outchar, i1 = 0, i2, v29, first_char = buf_packed[0];
int idx1 = 0, v28=0;
 
dword_8107F828:
00000000 00000000 00000001 00000000 00000003 00000000 00000007 00000000
0000000F 00000000 0000001F 00000000 0000003F 00000000 0000007F 00000000
000000FF 00000000 000001FF 00000000 000003FF 00000000 000007FF 00000000
00000FFF 00000000 00001FFF 00000000 00003FFF 00000000 00007FFF 00000000
0000FFFF 00000000 0001FFFF 00000000 0003FFFF 00000000 0007FFFF 00000000
000FFFFF 00000000 001FFFFF 00000000 003FFFFF 00000000 007FFFFF 00000000
00FFFFFF 00000000 00000000 00000000 00000000 00000000 00000007 0000000F
dword_8107F828:
00000000 00000000 00000001 00000000 00000003 00000000 00000007 00000000
0000000F 00000000 0000001F 00000000 0000003F 00000000 0000007F 00000000
000000FF 00000000 000001FF 00000000 000003FF 00000000 000007FF 00000000
00000FFF 00000000 00001FFF 00000000 00003FFF 00000000 00007FFF 00000000
0000FFFF 00000000 0001FFFF 00000000 0003FFFF 00000000 0007FFFF 00000000
000FFFFF 00000000 001FFFFF 00000000 003FFFFF 00000000 007FFFFF 00000000
00FFFFFF 00000000 00000000 00000000 00000000 00000000 00000007 0000000F
static readonly uint[] dword_8107F828 = {
    0x00000000, 0x00000000, 0x00000001, 0x00000000, 0x00000003, 0x00000000, 0x00000007, 0x00000000,
    0x0000000F, 0x00000000, 0x0000001F, 0x00000000, 0x0000003F, 0x00000000, 0x0000007F, 0x00000000,
    0x000000FF, 0x00000000, 0x000001FF, 0x00000000, 0x000003FF, 0x00000000, 0x000007FF, 0x00000000,
    0x00000FFF, 0x00000000, 0x00001FFF, 0x00000000, 0x00003FFF, 0x00000000, 0x00007FFF, 0x00000000,
    0x0000FFFF, 0x00000000, 0x0001FFFF, 0x00000000, 0x0003FFFF, 0x00000000, 0x0007FFFF, 0x00000000,
    0x000FFFFF, 0x00000000, 0x001FFFFF, 0x00000000, 0x003FFFFF, 0x00000000, 0x007FFFFF, 0x00000000,
    0x00FFFFFF, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000007, 0x0000000F,
    0x0000001F, 0x0000003F, 0x0000007F, 0x000000FF, 0x000001FF, 0x000003FF, 0x000007FF, 0x00000FFF,
    0x00001FFF, 0x00003FFF, 0x00007FFF, 0x0000FFFF, 0x0001FFFF, 0x0003FFFF, 0x000FFFFF, 0x00000000,
    0x06050403, 0x0A090807, 0x0E0D0C0B, 0x00000000, 0x00000001, 0x00000002, 0x00000004, 0x00000008,
    0x00000010, 0x00000020, 0x00000040, 0x00000080, 0x00000100, 0x00000200, 0x00000400, 0x00000800,
    0x00001000, 0x00002000, 0x00004000, 0x00000000, 0xFFFF0001, 0x00000000, 0x00000000, 0x00000001,
    0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000001, 0x00000001,
        };
static readonly uint[] dword_8107F828 = {
    0x00000000, 0x00000000, 0x00000001, 0x00000000, 0x00000003, 0x00000000, 0x00000007, 0x00000000,
    0x0000000F, 0x00000000, 0x0000001F, 0x00000000, 0x0000003F, 0x00000000, 0x0000007F, 0x00000000,
    0x000000FF, 0x00000000, 0x000001FF, 0x00000000, 0x000003FF, 0x00000000, 0x000007FF, 0x00000000,
    0x00000FFF, 0x00000000, 0x00001FFF, 0x00000000, 0x00003FFF, 0x00000000, 0x00007FFF, 0x00000000,
    0x0000FFFF, 0x00000000, 0x0001FFFF, 0x00000000, 0x0003FFFF, 0x00000000, 0x0007FFFF, 0x00000000,
    0x000FFFFF, 0x00000000, 0x001FFFFF, 0x00000000, 0x003FFFFF, 0x00000000, 0x007FFFFF, 0x00000000,
    0x00FFFFFF, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000007, 0x0000000F,
    0x0000001F, 0x0000003F, 0x0000007F, 0x000000FF, 0x000001FF, 0x000003FF, 0x000007FF, 0x00000FFF,
    0x00001FFF, 0x00003FFF, 0x00007FFF, 0x0000FFFF, 0x0001FFFF, 0x0003FFFF, 0x000FFFFF, 0x00000000,
    0x06050403, 0x0A090807, 0x0E0D0C0B, 0x00000000, 0x00000001, 0x00000002, 0x00000004, 0x00000008,
    0x00000010, 0x00000020, 0x00000040, 0x00000080, 0x00000100, 0x00000200, 0x00000400, 0x00000800,
    0x00001000, 0x00002000, 0x00004000, 0x00000000, 0xFFFF0001, 0x00000000, 0x00000000, 0x00000001,
    0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000001, 0x00000001,
        };
LABEL_22:
    if ( cur_char2 == 0x18 )
      break;
    while ( 1 )
    {
      v29 = *(_BYTE *)(cur_char2 + 0x811C9784); // buf4
      if ( v29 != *(_BYTE *)(cur_char2 + 0x811C9785) )// buf4+1
        break;
LABEL_26:
      if ( ++cur_char2 == 0x18 )
        goto LABEL_33;
    }
    while ( *(_DWORD *)(8 * v29 + 0x811C8784) != (v27 & *(_DWORD *)(8 * cur_char2 + 0x8107F828)) )// buf2, const1
    {
      v29 = (unsigned __int16)(v29 + 1);
      if ( (unsigned __int16)v29 == *(_BYTE *)(cur_char2 + 0x811C9785) )// buf4+1
        goto LABEL_26;
    }
LABEL_22:
    if ( cur_char2 == 0x18 )
      break;
    while ( 1 )
    {
      v29 = *(_BYTE *)(cur_char2 + 0x811C9784); // buf4
      if ( v29 != *(_BYTE *)(cur_char2 + 0x811C9785) )// buf4+1
        break;
LABEL_26:
      if ( ++cur_char2 == 0x18 )
        goto LABEL_33;
    }
    while ( *(_DWORD *)(8 * v29 + 0x811C8784) != (v27 & *(_DWORD *)(8 * cur_char2 + 0x8107F828)) )// buf2, const1
    {
      v29 = (unsigned __int16)(v29 + 1);
      if ( (unsigned __int16)v29 == *(_BYTE *)(cur_char2 + 0x811C9785) )// buf4+1
        goto LABEL_26;
    }
LABEL_26_2:
while (true)
{
    v29 = buf[off4 + cur_char2];
    if (v29 != buf[off4 + 1 + cur_char2])
        break;
    LABEL_26: //goto can not jump here
    if (++cur_char2 == 0x18)
    {
        return 0;
        //outchar = buf[off2 + 5 + 8 * v29]; //this seems a hack...
        //goto LABEL_29;                  
    }
}
while (BitConverter.ToUInt32(buf, (int)off2 + 8 * v29) !=
       (v27 & dword_8107F828[2 * cur_char2]))
{
    v29++;
    if (v29 == buf[off4 + 1 + cur_char2 ])
    {
        if (++cur_char2 == 0x18)
        {
            return 0;
        }
        goto LABEL_26_2;
    }
}
LABEL_26_2:
while (true)
{
    v29 = buf[off4 + cur_char2];
    if (v29 != buf[off4 + 1 + cur_char2])
        break;
    LABEL_26: //goto can not jump here
    if (++cur_char2 == 0x18)
    {
        return 0;

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 7
支持
分享
最新回复 (4)
雪    币: 7
活跃值: (4331)
能力值: ( LV9,RANK:270 )
在线值:
发帖
回帖
粉丝
2
呐呐呐
2020-11-28 21:06
0
雪    币: 7016
活跃值: (3322)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
牛B啊大佬。学习一个
2020-12-30 09:02
0
雪    币: 10
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
4
大佬能讲讲 GALGAME中的OPCODE逆向吗
2021-1-10 16:37
0
雪    币: 642
活跃值: (96)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
5
大佬厉害
2021-3-10 14:34
0
游客
登录 | 注册 方可回帖
返回
//