b站的古早游戏,一测之后就砍了,整理云盘的时候发现还留着安装包,所以尝试解一下资源.
拖进as发现是unitycn,用了frida dump SetAssetBundleKey
和SetAssetBundleDecryptKey
的传入,没有任何结果,怀疑是没有调用.
把global-metadata.dat和il2cpp.so导进 il2CppDumper 里面也有报错没法生成dump.cs
il2cpp bridge 在我这边还有点问题用不了,所以没法追踪函数调用,所以我上传到这里希望大家帮我拿到key 
安装包以及一些其他东西都在谷歌云盘
安装包的game.dat应该加密了。
ida看的时候sub_8EC128应该就是MetadataLoader::LoadMetadataFile
也就是加载global-metadata.dat或game.dat的地方。
sub_8EC128
__int64 __fastcall sub_8EC128(__int64 a1)
{
unsigned __int64 v2; // x8
const char *v3; // x9
char **v4; // x1
__int64 v5; // x0
char *v6; // x8
unsigned __int64 v7; // x9
const char *v8; // x0
__int64 v9; // x19
__int64 v10; // x0
const char *v11; // x1
__int64 v12; // x20
char *v14; // [xsp+0h] [xbp-60h] BYREF
__int64 v15; // [xsp+8h] [xbp-58h]
_QWORD v16[2]; // [xsp+10h] [xbp-50h] BYREF
const char *v17; // [xsp+20h] [xbp-40h]
_QWORD v18[2]; // [xsp+28h] [xbp-38h] BYREF
char *v19; // [xsp+38h] [xbp-28h]
char *v20; // [xsp+40h] [xbp-20h] BYREF
unsigned __int64 v21; // [xsp+48h] [xbp-18h]
((void (__fastcall *)(_QWORD *__return_ptr))loc_92EF38)(v16);
v14 = "Metadata";
v15 = 8LL;
v2 = (unsigned __int64)LOBYTE(v16[0]) >> 1;
if ( (v16[0] & 1) != 0 )
v3 = v17;
else
v3 = (char *)v16 + 1;
if ( (v16[0] & 1) != 0 )
v2 = v16[1];
v20 = (char *)v3;
v21 = v2;
sub_8CA04C(v18, &v20, &v14);
if ( (v16[0] & 1) != 0 )
sub_6DC6D0(v17);
strtod((const char *)a1, v4);
if ( (v18[0] & 1) != 0 )
v6 = v19;
else
v6 = (char *)v18 + 1;
if ( (v18[0] & 1) != 0 )
v7 = v18[1];
else
v7 = (unsigned __int64)LOBYTE(v18[0]) >> 1;
v14 = (char *)a1;
v15 = v5;
v20 = v6;
v21 = v7;
sub_8CA04C(v16, &v20, &v14);
if ( off_2F2F2D0 && *(_BYTE *)(a1 + 1) == 97 )
{
if ( (v16[0] & 1) != 0 )
v8 = v17;
else
v8 = (char *)v16 + 1;
v9 = off_2F2F2D0(v8);
}
else
{
LODWORD(v20) = 0;
v10 = ((__int64 (__fastcall *)(_QWORD *, __int64, __int64, __int64, _QWORD, char **))dword_8BF9EC)(
v16,
3LL,
1LL,
1LL,
0LL,
&v20);
if ( (_DWORD)v20 )
{
if ( (v16[0] & 1) != 0 )
v11 = v17;
else
v11 = (char *)v16 + 1;
sub_92E5A8("ERROR: Could not open %s", v11);
}
else
{
v12 = v10;
v9 = sub_92E764();
((void (__fastcall *)(__int64, char **))((char *)&qword_8BFD90[9] + 4))(v12, &v20);
if ( !(_DWORD)v20 )
goto LABEL_28;
sub_92E774(v9);
}
v9 = 0LL;
}
LABEL_28:
if ( (v16[0] & 1) != 0 )
sub_6DC6D0(v17);
if ( (v18[0] & 1) != 0 )
sub_6DC6D0(v19);
return v9;
}
.
sub_8EBF18是MetadataCache::Initialize
sub_8EBF18
__int64 __fastcall sub_8EBF18(_DWORD *a1, int *a2)
{
const char *v4; // x0
__int64 result; // x0
unsigned __int64 v6; // kr00_8
__int64 v7; // x0
__int64 v8; // x13
__int64 v9; // x8
int *v10; // x13
unsigned int v11; // w14
int v12; // w14
__int64 v13; // x14
__int64 v14; // x14
__int64 v15; // x14
char v16[16]; // [xsp+0h] [xbp-30h] BYREF
if ( (sub_8EBE7C() & 1) != 0 )
{
v4 = v16;
strcpy(v16, "game.dat");
}
else
{
v4 = "global-metadata.dat";
}
result = sub_8EC128(v4);
qword_2F2F2F0 = result;
if ( result || (result = sub_8EC128("global-metadata.dat"), qword_2F2F2F0 = result, off_2F2F2D8 = 0LL, result) )
{
qword_2F2F2F8 = result;
v6 = *(int *)(result + 172);
*a1 = v6 / 0x28;
dword_2F2F300 = v6 / 0x28;
*a2 = *(int *)(result + 180) >> 6;
qword_2F2F308 = sub_92E730((int)(v6 / 0x28), 24LL);
qword_2F2F310 = sub_92E730(*(int *)(qword_2F2F2E8 + 48), 8LL);
qword_2F2F318 = sub_92E730(*(int *)(qword_2F2F2F8 + 164) / 0x58uLL, 8LL);
qword_2F2F320 = sub_92E730((unsigned __int64)*(int *)(qword_2F2F2F8 + 52) >> 5, 8LL);
v7 = sub_92E730(*(int *)(qword_2F2F2E8 + 64), 8LL);
v8 = qword_2F2F2E8;
qword_2F2F328 = v7;
result = 1LL;
if ( *(int *)(qword_2F2F2E8 + 48) >= 1 )
{
v9 = 0LL;
while ( 1 )
{
v10 = *(int **)(*(_QWORD *)(v8 + 56) + 8 * v9);
v11 = *((unsigned __int8 *)v10 + 10);
if ( v11 <= 0x1E )
{
v12 = 1 << v11;
if ( (v12 & 0x13467FFE) != 0 )
{
v13 = *v10;
if ( (_DWORD)v13 != -1 )
{
v14 = qword_2F2F2F0 + *(int *)(qword_2F2F2F8 + 160) + 88 * v13;
LABEL_16:
*(_QWORD *)v10 = v14;
goto LABEL_17;
}
goto LABEL_15;
}
if ( (v12 & 0x40080000) != 0 )
{
v15 = *v10;
if ( (_DWORD)v15 != -1 )
{
v14 = qword_2F2F2F0 + *(int *)(qword_2F2F2F8 + 104) + 16 * v15;
goto LABEL_16;
}
LABEL_15:
v14 = 0LL;
goto LABEL_16;
}
}
LABEL_17:
v8 = qword_2F2F2E8;
if ( ++v9 >= *(int *)(qword_2F2F2E8 + 48) )
return 1LL;
}
}
}
return result;
}
.
其中的os::File::Open函数调用
os::File::Open
v10 = ((__int64 (__fastcall *)(_QWORD *, __int64, __int64, __int64, _QWORD, char **))dword_8BF9EC)(
v16,
3LL,
1LL,
1LL,
0LL,
&v20);
v9 = off_2F2F2D0(v8);可能是解密位置。
但是我开frida-sever 就崩。现场学的,不知道有没有检测。
游戏闪退的话是检测开发者模式还有usb调试,隐藏一下就行了?
是加密了,所以我直接dump的global-metadata.dat,也在谷歌云盘里面,看起来应该是没啥问题
我的frida脚本
var FALLBACK_OFFSET = 0x8EC128;
var finded = false
var addr;
var notFirstTime = true
var s_GlobalMetadataHeader;
var completed = false;
var metadataLoaderFunc = null;
var searchAttempted = false;
function get_self_process_name() {
var openPtr = Module.getExportByName('libc.so', 'open');
var open = new NativeFunction(openPtr, 'int', ['pointer', 'int']);
var readPtr = Module.getExportByName("libc.so", "read");
var read = new NativeFunction(readPtr, "int", ["int", "pointer", "int"]);
var closePtr = Module.getExportByName('libc.so', 'close');
var close = new NativeFunction(closePtr, 'int', ['int']);
var path = Memory.allocUtf8String("/proc/self/cmdline");
var fd = open(path, 0);
if (fd != -1) {
var buffer = Memory.alloc(0x1000);
var result = read(fd, buffer, 0x1000);
close(fd);
result = ptr(buffer).readCString();
return result;
}
return "-1";
}
var intervalId = setInterval(() => {
if (completed) {
clearInterval(intervalId);
return;
}
if (finded) {
if (addr != null && metadataLoaderFunc == null && !searchAttempted) {
if (metadataLoaderFunc == null) {
metadataLoaderFunc = addr.base.add(FALLBACK_OFFSET);
}
}
if (metadataLoaderFunc != null) {
if (notFirstTime) {
notFirstTime = false;
try {
Interceptor.attach(metadataLoaderFunc, {
onEnter: function (args) {
console.log("MetadataLoader::LoadMetadataFile 被调用");
},
onLeave: function (retval) {
console.log("s_GlobalMetadataHeader:" + retval.toString(16));
s_GlobalMetadataHeader = retval;
save(get_size());
completed = true;
}
});
} catch (e) {
completed = true;
}
}
}
} else {
try {
addr = Process.findModuleByName("libil2cpp.so");
if (addr != null) {
console.log("找到libil2cpp.so模块,基址: " + addr.base.toString(16));
finded = true;
}
} catch (e) {
}
}
}, 100);
function get_size() {
const metadataHeader = s_GlobalMetadataHeader;
let fileOffset = 0x10C;
let lastCount = 0;
let lastOffset = 0;
while (true) {
lastCount = Memory.readInt(ptr(metadataHeader).add(fileOffset));
if (lastCount !== 0) {
lastOffset = Memory.readInt(ptr(metadataHeader).add(fileOffset - 4));
break;
}
fileOffset -= 8;
if (fileOffset <= 0) {
console.log("获取到的大小错误!");
break;
}
}
return lastOffset + lastCount;
}
function save(size) {
var file = new File("/data/data/" + get_self_process_name() + "/global-metadata.dat", "wb");
var contentBuffer = Memory.readByteArray(s_GlobalMetadataHeader, size);
file.write(contentBuffer);
file.flush();
file.close();
console.log("global-metadata已导出到/data/data/" + get_self_process_name() + "/global-metadata.dat")
}
有点神奇,我装了我不是开发者模块隐藏usb调试和开发者后可以在开frida-sever的情况下正常打开这个游戏,但是我只要frida -U -f com.bilibili.yeying.bilibili -o resume=true就直接白屏卡住。
frida的版本是16.7.07,cpu架构是arm64-v8a。
ida逆向.so没什么问题,可能是的有些参数不一致。
┗━━ ./UnityCNBurst "F:\workspace\yeying\global-metadata.dat"
Found valid key: Nightingale@2019
Elapsed time: 0.014814 sec
Total keys checked: 370461
Keys per second: 25007492.912110165
前两天数据填错了没跑出来难绷,直接暴搜global-metadat.dat就有key
2 个赞
import re
import sys
from UnityPy.helpers.ArchiveStorageManager import brute_force_key
from UnityPy.streams.EndianBinaryReader import EndianBinaryReader
if __name__ == "__main__":
if len(sys.argv) < 3:
print("Usage: python brute_force.py <path_to_bundlefile> <path_to_global_metadata.dat>")
sys.exit(1)
bundlefile_path = sys.argv[1]
global_metadata_path = sys.argv[2]
with open(bundlefile_path, "rb") as f:
data = f.read()
reader = EndianBinaryReader(data)
_ = reader.read_string_to_null()
_ = reader.read_u_int()
_ = reader.read_string_to_null()
_ = reader.read_string_to_null()
reader.Position += 57
signatureBytes = reader.read_bytes(0x10)
signatureKey = reader.read_bytes(0x10)
key = brute_force_key(global_metadata_path, signatureKey, signatureBytes, re.compile(rb"(?=([\x20-\x7E]{16}))"))
print(key)
如果用UnityPy大概是这样的
3 个赞