首页
课程
问答
CTF
社区
招聘
峰会
发现
排行榜
知识库
工具下载
看雪20年
看雪商城
证书查询
登录
注册
首页
社区
课程
招聘
发现
问答
CTF
排行榜
知识库
工具下载
峰会
看雪商城
证书查询
社区
Android安全
发新帖
8
12
[原创]【银行逆向百例】18Android逆向之libDexHelper.so梆梆加固壳解密 frida-dexdump脱壳
发表于: 2026-6-8 14:59
5271
[原创]【银行逆向百例】18Android逆向之libDexHelper.so梆梆加固壳解密 frida-dexdump脱壳
差不多的张三
2026-6-8 14:59
5271
“ 只要有想见的人,就不是孤单一个人。——《夏目友人帐》S3E4 ” # 01环境版本 环境: 电脑,Windows 11 专业版 23H2 ``` https://github.com/JiaoSuInfoSec/JiaoSuInfoSec_T00ls_Win11 ``` 软件: Florida,16.1.8 ``` https://github.com/Ylarod/Florida/releases/tag/16.1.8 ``` frida-dexdump ``` https://github.com/hluwa/frida-dexdump ``` # 02操作步骤 1、梆梆加固企业版  2、查看APP完整路径,拷贝libDexHelper.so到本地 ``` adb shell dumpsys window | grep mCurrentFocus adb shell pm path com.xxx.xxx adb shell "su -c 'cp /data/app/xxx/com.xxx.xxx/lib/arm64/libDexHelper.so /data/local/tmp/ && chmod 777 /data/local/tmp/libDexHelper.so'" adb pull /data/local/tmp/libDexHelper.so ./dumps ```  3、libDexHelper.so导入IDA只有32个有名字的符号(25个导入函数+ 7个标记)  4、快捷键G跳到0,D切换显示模式  5、0x40查看ELF64 Program Header  6、导入parse_elf.py定位壳入口 0x26000查看.dynamic 段,DT_INIT_ARRAY = 0x14D08,DT_RELA = 0x26E8 0x26E8 查看重定位表 .init_array[0]的值= 0x4780  ``` import struct import idc # ========== 第1步:解析 ELF Header ========== print("=" * 60) print("第1步:ELF Header") print("=" * 60) e_phoff = struct.unpack_from('<Q', idc.get_bytes(0x20, 8), 0)[0] e_phentsize = struct.unpack_from('<H', idc.get_bytes(0x36, 2), 0)[0] e_phnum = struct.unpack_from('<H', idc.get_bytes(0x38, 2), 0)[0] print(f"Program Header 偏移: 0x{e_phoff:X}") print(f"每个条目大小: {e_phentsize} 字节") print(f"条目数量: {e_phnum}") print(f"-> 下一步去地址 0x{e_phoff:X}") # ========== 第2步:解析 Program Headers ========== print("") print("=" * 60) print("第2步:Program Header Table") print("=" * 60) type_names = { 0: 'NULL', 1: 'LOAD', 2: 'DYNAMIC', 3: 'INTERP', 4: 'NOTE', 6: 'PHDR', 0x6474e550: 'GNU_EH_FRAME', 0x6474e551: 'GNU_STACK', 0x6474e552: 'GNU_RELRO' } dynamic_vaddr = None for i in range(e_phnum): off = e_phoff + i * e_phentsize data = idc.get_bytes(off, e_phentsize) p_type = struct.unpack_from('<I', data, 0)[0] p_offset = struct.unpack_from('<Q', data, 8)[0] p_vaddr = struct.unpack_from('<Q', data, 16)[0] p_filesz = struct.unpack_from('<Q', data, 32)[0] tname = type_names.get(p_type, f'0x{p_type:X}') marker = ' <<<' if p_type == 2 else '' print(f"[{i}] {tname:15s} offset=0x{p_offset:08X} vaddr=0x{p_vaddr:08X} size=0x{p_filesz:X}{marker}") if p_type == 2: dynamic_vaddr = p_vaddr if dynamic_vaddr: print(f"\n-> 找到 DYNAMIC 段! 下一步去地址 0x{dynamic_vaddr:X}") # ========== 第3步:解析 .dynamic 段 ========== if dynamic_vaddr: print("") print("=" * 60) print(f"第3步: .dynamic 段 (地址 0x{dynamic_vaddr:X})") print("=" * 60) tag_names = { 0: 'DT_NULL', 1: 'DT_NEEDED', 4: 'DT_HASH', 5: 'DT_STRTAB', 6: 'DT_SYMTAB', 7: 'DT_RELA', 8: 'DT_RELASZ', 10: 'DT_STRSZ', 12: 'DT_INIT', 13: 'DT_FINI', 25: 'DT_INIT_ARRAY', 26: 'DT_FINI_ARRAY', 27: 'DT_INIT_ARRAYSZ', 28: 'DT_FINI_ARRAYSZ' } init_array_addr = None rela_addr = None rela_size = None addr = dynamic_vaddr while addr < dynamic_vaddr + 0x1000: data = idc.get_bytes(addr, 16) d_tag = struct.unpack_from('<Q', data, 0)[0] d_val = struct.unpack_from('<Q', data, 8)[0] if d_tag == 0: print(f"0x{addr:08X}: DT_NULL (结束)") break tname = tag_names.get(d_tag, f'DT_0x{d_tag:X}') marker = '' if d_tag == 25: marker = ' <<< .init_array 地址!' init_array_addr = d_val elif d_tag == 27: marker = ' (.init_array 大小)' elif d_tag == 7: marker = ' <<< 重定位表地址' rela_addr = d_val elif d_tag == 8: marker = ' <<< 重定位表大小' rela_size = d_val print(f"0x{addr:08X}: {tname:25s} = 0x{d_val:08X}{marker}") addr += 16 # ========== 第4步:解析重定位表 ========== if rela_addr and init_array_addr: print("") print("=" * 60) print(f"第4步: 重定位表 (地址 0x{rela_addr:X})") print("=" * 60) count = rela_size // 24 for i in range(count): off = rela_addr + i * 24 data = idc.get_bytes(off, 24) r_offset = struct.unpack_from('<Q', data, 0)[0] r_info = struct.unpack_from('<Q', data, 8)[0] r_addend = struct.unpack_from('<q', data, 16)[0] r_type = r_info & 0xFFFFFFFF type_names_r = {0x401: 'RELATIVE', 0x403: 'GLOB_DAT'} tname = type_names_r.get(r_type, f'0x{r_type:X}') marker = '' if r_offset == init_array_addr: marker = ' <<< 这就是壳的入口地址!' print(f"[{i}] 修改 0x{r_offset:08X} <- 0x{r_addend:X} 类型={tname}{marker}") # ========== 结论 ========== print("") print("=" * 60) print("结论") print("=" * 60) if init_array_addr and rela_addr: print(f".init_array 地址: 0x{init_array_addr:X}") print(f"壳的真正入口: 0x4780") print(f"") print(f"-> 按 G 输入 4780 跳转到壳入口, 然后按 F5 反编译") ``` 7、0x4780,F5反编译  8、0x33F8,F5反编译,壳主函数  9、在壳主函数中找到关键调用 0x36BC: BL sub_3184 (RC4解密) 0x3728: BL sub_2B1C (XOR解密) 0x454C: BL sub_2CD0 (ELF重定位)  10、解密壳  ``` import struct # 读取原始外层壳 with open('libDexHelper.so', 'rb') as f: data = f.read() print(f"[*] 原始文件大小: {hex(len(data))}") # 关键常量 (从分析记录) PAYLOAD_OFFSET = 0x8000 # 内层payload起始偏移 XOR_KEY = 0x19 # 正文XOR key HEADER_DECRYPT_LEN = 0x40 # 头部解密长度 # 从文件尾部偏移0x104E3D读取密钥材料 KEY_MATERIAL_OFFSET = 0x104E3D KEY_MATERIAL_LEN = 0x14 HEADER_KEY_LEN = 0x10 # 前0x10字节作为头部解密key key_material = data[KEY_MATERIAL_OFFSET:KEY_MATERIAL_OFFSET + KEY_MATERIAL_LEN] print(f"[*] 密钥材料 ({hex(KEY_MATERIAL_OFFSET)}): {key_material.hex()}") header_key = key_material[:HEADER_KEY_LEN] print(f"[*] 头部解密key: {header_key.hex()}") # 提取加密的payload encrypted_payload = data[PAYLOAD_OFFSET:] print(f"[*] 加密payload大小: {hex(len(encrypted_payload))}") # 第一步:对头部0x40字节做RC4-like解密 # RC4-like: 简单的流密码,用key生成密钥流 def rc4_like_decrypt(data, key): # 初始化S盒 S = list(range(256)) j = 0 for i in range(256): j = (j + S[i] + key[i % len(key)]) % 256 S[i], S[j] = S[j], S[i] # 生成密钥流并解密 result = bytearray(len(data)) i = j = 0 for k in range(len(data)): i = (i + 1) % 256 j = (j + S[i]) % 256 S[i], S[j] = S[j], S[i] keystream_byte = S[(S[i] + S[j]) % 256] result[k] = data[k] ^ keystream_byte return bytes(result) # 解密头部 header_encrypted = encrypted_payload[:HEADER_DECRYPT_LEN] header_decrypted = rc4_like_decrypt(header_encrypted, header_key) print(f"[*] 头部解密完成") # 第二步:对正文做单字节XOR解密 body_encrypted = encrypted_payload[HEADER_DECRYPT_LEN:] body_decrypted = bytes([b ^ XOR_KEY for b in body_encrypted]) print(f"[*] 正文XOR解密完成 (key=0x{XOR_KEY:02X})") # 拼接完整的解壳后payload decrypted_payload = header_decrypted + body_decrypted # 验证ELF魔数 if decrypted_payload[:4] == b'\x7fELF': print(f"[+] ELF魔数验证通过!") else: print(f"[-] 警告: ELF魔数不匹配: {decrypted_payload[:4].hex()}") # 解析ELF头 elf_magic = decrypted_payload[:4] ei_class = decrypted_payload[4] # 32/64位 ei_data = decrypted_payload[5] # 字节序 e_type = struct.unpack('<H', decrypted_payload[16:18])[0] e_machine = struct.unpack('<H', decrypted_payload[18:20])[0] e_entry = struct.unpack('<I', decrypted_payload[24:28])[0] e_phoff = struct.unpack('<I', decrypted_payload[28:32])[0] e_shoff = struct.unpack('<I', decrypted_payload[32:36])[0] e_phnum = struct.unpack('<H', decrypted_payload[42:44])[0] e_shnum = struct.unpack('<H', decrypted_payload[48:50])[0] print(f"\n[*] 内层ELF信息:") print(f" 类型: {'64位' if ei_class == 2 else '32位'}") print(f" 字节序: {'小端' if ei_data == 1 else '大端'}") print(f" e_type: {hex(e_type)}") print(f" e_machine: {hex(e_machine)}") print(f" 入口点: {hex(e_entry)}") print(f" Program Header偏移: {hex(e_phoff)}") print(f" Section Header偏移: {hex(e_shoff)}") print(f" Program Header数量: {e_phnum}") print(f" Section Header数量: {e_shnum}") # 保存解壳后的文件 output_file = 'libDexHelper_inner.so' with open(output_file, 'wb') as f: f.write(decrypted_payload) print(f"\n[+] 解壳完成! 保存到: {output_file}") print(f"[+] 文件大小: {hex(len(decrypted_payload))}") ``` 11、libDexHelper_inner.so导入IDA,函数数量2211个  12、使用florida 16.1.8绕过frida检测  13、使用frida-dexdump -d模式 ``` D:\path\python\python39\python39.exe -m frida_dexdump -U -f com.xxx.xxx --sleep 15 -d -o C:\Users\Administrator\Desktop\frida\dump_output ```  14、修复dex  ``` import os import struct import zlib import hashlib def fix_dex_checksum(filepath): """修复 DEX 文件的 checksum 和签名""" with open(filepath, 'rb') as f: data = bytearray(f.read()) # 检查 DEX 魔数 if data[:4] != b'dex\n': print(f"[跳过] {os.path.basename(filepath)}: 不是 DEX 文件") return False # 读取当前值 old_checksum = struct.unpack_from('<I', data, 8)[0] # 第一步:计算 SHA-1 签名(对偏移 32 开始的数据) sha1 = hashlib.sha1(bytes(data[32:])).digest() # 第二步:写入签名到偏移 12-31 data[12:32] = sha1 # 第三步:计算 adler32 checksum(对偏移 12 开始的数据,包含签名) new_checksum = zlib.adler32(bytes(data[12:])) & 0xFFFFFFFF # 第四步:写入 checksum 到偏移 8-11 struct.pack_into('<I', data, 8, new_checksum) # 保存修复后的文件 with open(filepath, 'wb') as f: f.write(data) print(f"[修复] {os.path.basename(filepath)}: checksum=0x{new_checksum:08X}") return True def main(): dex_dir = r'C:\Users\Administrator\Desktop\frida\dump_output' print("=" * 60) print("DEX 文件 checksum 修复工具 (v2)") print("=" * 60) fixed = 0 failed = 0 for filename in sorted(os.listdir(dex_dir)): if filename.endswith('.dex'): filepath = os.path.join(dex_dir, filename) try: if fix_dex_checksum(filepath): fixed += 1 except Exception as e: print(f"[错误] {filename}: {e}") failed += 1 print() print("=" * 60) print(f"修复完成: {fixed} 个文件") print(f"失败: {failed} 个文件") print("=" * 60) if __name__ == '__main__': main() ``` 15、AndroidManifest.xml找一个WebViewActivity  16、去脱壳的代码中查看WebViewActivity验证 
传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!!
收藏
・
8
点赞
・
12
打赏
分享
分享到微信
分享到QQ
分享到微博
赞赏记录
参与人
雪币
留言
时间
mb_rttzgpaj
你的分享对大家帮助很大,非常感谢!
2026-8-12 00:02
GoKu123
谢谢你的细致分析,受益匪浅!
2026-7-9 17:13
mb_ihwsaggc
你的分享对大家帮助很大,非常感谢!
2026-6-25 09:51
mb_reyfinlv
非常支持你的观点!
2026-6-23 17:22
sher_wang
为你点赞!
2026-6-22 17:56
辉煌科技
为你点赞!
2026-6-19 11:01
mb_qlbmqqmd
非常支持你的观点!
2026-6-18 10:41
ReverseMind
期待更多优质内容的分享,论坛有你更精彩!
2026-6-10 15:54
leehero
期待更多优质内容的分享,论坛有你更精彩!
2026-6-10 10:16
qqizai
感谢你的积极参与,期待更多精彩内容!
2026-6-9 09:39
mancong
+1
感谢你的积极参与,期待更多精彩内容!
2026-6-8 21:44
孤独的街
期待更多优质内容的分享,论坛有你更精彩!
2026-6-8 16:23
查看更多
赞赏
×
1 雪花
5 雪花
10 雪花
20 雪花
50 雪花
80 雪花
100 雪花
150 雪花
200 雪花
支付方式:
微信支付
赞赏留言:
快捷留言
感谢分享~
精品文章~
原创内容~
精彩转帖~
助人为乐~
感谢分享~
最新回复
(
4
)
mb_iesvmzqc
雪 币:
5118
活跃值:
(5927)
能力值:
( LV2,RANK:10 )
在线值:
发帖
0
回帖
30
粉丝
1
关注
私信
mb_iesvmzqc
2
楼
这个版本 AI 纯静态秒了
2026-6-8 15:10
0
hyz111
雪 币:
151
活跃值:
(1113)
能力值:
( LV2,RANK:10 )
在线值:
发帖
3
回帖
47
粉丝
2
关注
私信
hyz111
3
楼
6 florida就过了为啥不用原版frida意义更大
最后于
2026-6-9 16:53 被hyz111编辑 ,原因:
2026-6-8 16:14
0
Ahzn
雪 币:
131
能力值:
( LV1,RANK:0 )
在线值:
发帖
0
回帖
54
粉丝
0
关注
私信
Ahzn
4
楼
BBA
2026-6-9 04:24
0
mb_elqwyvnm
雪 币:
2637
活跃值:
(3262)
能力值:
( LV2,RANK:10 )
在线值:
发帖
0
回帖
155
粉丝
0
关注
私信
mb_elqwyvnm
5
楼
棒棒
2026-6-14 20:56
0
游客
登录
|
注册
方可回帖
回帖
表情
雪币赚取及消费
高级回复
返回
差不多的张三
19
发帖
13
回帖
0
RANK
关注
私信
他的文章
[原创]【银行逆向百例】18Android逆向之libDexHelper.so梆梆加固壳解密 frida-dexdump脱壳
5271
[原创]【代码审计】客户端代码执行之WebView JavaScript桥接劫持token账号接管
1889
[原创]【银行逆向百例】17Android逆向之libDexHelper梆梆加固frida检测绕过
4489
[原创]【银行逆向百例】16Android逆向之算法助手 frida绕过环境检测分析加密算法
2007
[原创]【银行逆向百例】15小程序逆向之支付宝提取data文件为tar格式
2435
关于我们
联系我们
企业服务
看雪公众号
专注于PC、移动、智能设备安全研究及逆向工程的开发者社区
看原图
赞赏
×
雪币:
+
留言:
快捷留言
为你点赞!
返回
顶部