本帖在论坛和我的博客 同时发布 上期链接Galgame汉化中的逆向(五):Switch平台下的Unity后端il2cpp分析
前三篇都在谈pc汉化中的基本方法,这篇来说说主机汉化的操作。由于主机的特殊性,用户权限比较低,一般很难做到动态调试(大多是只有比较完善的模拟器才能动态调试),甚至连编写自制软件都不能用类似于gdb的调试,往往都是插入log来看输出。而且因为主机游戏往往没有加壳和混淆什么的(本身主机系统加密防破解就很变态了,游戏就没必要再搞防护了),因此一般都是进行静态分析。静态分析最重要的是定位,通常是通过特征字节来定位(如游戏opcode,文件magic等),或者根据代码量、大的switch结构、相关字符串(别抱太大希望,字符串很难找到refer)。这篇来谈谈如何用ida静态分析主机游戏,在魔改算法不容易看出来的情况下,如何将ida的伪代码翻译成可执行的代码。本次以psv游戏arm汇编为例。
此游戏有一堆*.ARC
*.BIN
文件,直接用GARBRO
打开,可以看到文件名但是无法打开每个文件,观察可知是用了叫做gss 的游戏引擎。简单分析可知 *.bin
为索引文件。以SCRDATA.BIN
SCRDATA.ARC
为例,文件头如下所示。
这里看着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.bin
, search immediate
搜索"H"等标志位即可找到。
同时我们注意到GARBRO
源码中已经有了框架分析了一部分,但是最难的一个函数UnpackH
仍是throw new NotImplementedException();
我们需要自己分析一下补全。
同时,我们在定位处上下翻翻,还能看到huffman
和runleng
的字符串,因此压缩算法很可能是基于这两种算法的魔改。
下面以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#里。
由于c#的goto不能跳入其他循环,遇到这种情况我们就需要把goto进入的代码都粘贴过来了。
就是寻找所有的子函数调用,并将其逐个还原。有时候可能伪代码显示有点问题,要看看汇编。
在运行结果正确的技术上,这时候可以进行整体的考虑了。即站在更高层来分析那些代码逻辑是相同的,把每部分相同功能的变量与代码提到外层,使得整体看着简洁。同时优化位运算等操作的可读性。此处UnpackH
这个函数的整体还原代码如下:
根据这个游戏,我把GARBRO
的gss
引擎解包完善了,详见我的github 同时我也pull request 了,不过作者好像好久没维护了。
还原算法后测试一下,发现剧本提取没问题,文字也都出来了,同理图片封包格式也一样。
至于封包,我们可以走一个捷径,就是这个游戏有个IsPacked
这个flag。修改这个flag,我们可以不压缩和加密,直接把原来文件封包,就是要注意一下0x800等字节对齐与补零,索引重建等。
之后为了汉化文本超长,需要分析一下opcode。这个游戏根据猜测把opcode打印一下即可看出规律,分析出每条指令是干什么的。这游戏比较简单,放一下opcode打印代码和图了,不再详细分析了。当然还有字库问题,这个相对来说处理起来不难,这里不再赘述了。
另外此游戏psv和psp文件结构非常相似,一些内容也可以用psp模拟器测试提高效率。至于psp的mips汇编和如何动态调试,这些我打算之后出教程。
这些都分析完后,重新导入文本和图片,搞定!
/
/
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
;
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!