Files
live-hub-py/tools/unidbg/hydev/rebase_dump.py
T
yml2213 70621cff8f feat(huya): unidbg 金测试打通 - 采集器加密可复现(androidId=PDSuHx..)/GUID=0a7dfa..一致
- 输入图定案: 库内零硬件文件读, 种子=ANDROID_ID+服务端hydeviceid_config+MID, 属性层无关(X1/X2)
- 真机全段解密 dump(phone_dump_hydev_full) + merge_decrypted 合入原文件 → unidbg 可直接加载
- unidbg(JDK21+patch) harness: JNI 桩(SharedPreferences日志化/Settings.Secure/NativeBridge)
  金测试: androidId 加密态与 getGUID 全部与真机一致
- 遗留: NativeBridge.b(100) 原生归属库未定(非hydeviceid/udb/device-util), 当前桩替顶
- 修正结论: '单机不可铸造'判断错误, GUID=b(100)=f(androidId密, config, MID) 输入全可控
2026-08-28 16:06:25 +08:00

75 lines
2.9 KiB
Python

#!/usr/bin/env python3
"""重定位 dump (v3): 用 ORIGINAL .so 的段表定位 .rela.dyn/.init_array (布局一致),
对 DUMP 内同偏移的槽做"运行期地址 -> 链接期偏移"回退 / 导入槽清零.
用法: python3 rebase_dump.py <original.so> <dump.so> <runtime_base> <out.so>
"""
from __future__ import annotations
import struct, sys
R_AARCH64_ABS64 = 257
R_AARCH64_GLOB_DAT = 1025
R_AARCH64_JUMP_SLOT = 1026
R_AARCH64_RELATIVE = 1027
def sections(data):
e_shoff = struct.unpack_from('<Q', data, 0x28)[0]
e_shentsize = struct.unpack_from('<H', data, 0x3A)[0]
e_shnum = struct.unpack_from('<H', data, 0x3C)[0]
e_shstrndx = struct.unpack_from('<H', data, 0x3E)[0]
shdrs = []
for i in range(e_shnum):
sh = struct.unpack_from('<IIQQQQIIQQ', data, e_shoff + i * e_shentsize)
shdrs.append(dict(name=sh[0], type=sh[1], addr=sh[3], offset=sh[4], size=sh[5], entsize=sh[9]))
shstr = shdrs[e_shstrndx]
shstrtab = data[shstr['offset']:shstr['offset'] + shstr['size']]
def sname(idx):
end = shstrtab.find(b'\0', idx)
return shstrtab[idx:end].decode(errors='replace')
for s in shdrs:
s['name'] = sname(s['name'])
return shdrs
def main():
original, dump, base_s, out = sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4]
base = int(base_s, 16)
odata = open(original, 'rb').read()
ddata = bytearray(open(dump, 'rb').read())
count = {'rebase': 0, 'zero': 0}
# dump 文件偏移 == vaddr (运行期镜像与 vaddr 同轴, 已实证)
def rebase_ptr(vaddr):
off = vaddr
if off + 8 > len(ddata):
return
v = struct.unpack_from('<Q', ddata, off)[0]
if off == 0x3b23f0: print('DBG rebase_ptr sees %#x' % v)
if v == 0 or v < 0x700000000000:
return
if base <= v < base + 0x600000:
struct.pack_into('<Q', ddata, off, v - base)
count['rebase'] += 1
else:
struct.pack_into('<Q', ddata, off, 0)
count['zero'] += 1
for s in sections(odata):
if s['name'] in ('.rela.dyn', '.rela.plt'):
for i in range(0, s['size'], 24):
r_offset, r_info, _ = struct.unpack_from('<QQq', odata, s['offset'] + i)
rtype = r_info & 0xffffffff
if rtype in (R_AARCH64_RELATIVE, R_AARCH64_ABS64):
rebase_ptr(r_offset)
elif rtype in (R_AARCH64_GLOB_DAT, R_AARCH64_JUMP_SLOT):
if r_offset + 8 <= len(ddata):
struct.pack_into('<Q', ddata, r_offset, 0)
count['zero'] += 1
elif s['name'] in ('.init_array', '.fini_array'):
for i in range(0, s['size'], 8):
rebase_ptr(s['addr'] + i)
open(out, 'wb').write(ddata)
print(f"[*] rebased {count['rebase']} slots, zeroed {count['zero']} -> {out}")
if __name__ == '__main__':
main()