[原创]深入浅出 Ollvm 混淆原理及反混淆技术-Android安全-看雪安全社区|专业技术交流与安全研究论坛
[分享]Ollvm 指令替换混淆还原神器:GAMBA 使用指南-Android安全-看雪安全社区|专业技术交流与安全研究论坛
reverse-skill/skills/reverse-engineering/references/ollvm-deobfuscation.md at main · zhaoxuya520/reverse-skill
Deflat 是经典的基于符号执行的去混淆工具。它利用 Angr 框架模拟执行,能够精准地计算出每个基本块的“下一跳”目标
例如需要去ollvm的代码
text:0000000000025BC0 ; =============== S U B R O U T I N E =======================================
.text:0000000000025BC0
.text:0000000000025BC0 ; QIMEI 核心生成引擎 (超大+混淆)。据 type 参数生成不同 QIMEI 子串: type=0 → z 设备ID; type=1 → o 缓存QIMEI; type=3 → z2 设备ID+版本; type=6 → m QIMEI字符串; type=7 → r 上报串; type=13 → r4 加密; type=15 → a 加密字节。内含 q16/q36 标识、plzdontcrackme856c91 反破解提示、XTEA 加密、设备特征采集 (ActivityThread/signatures/NetworkInterface/stat 等)
.text:0000000000025BC0 ; Attributes: bp-based frame
.text:0000000000025BC0
.text:0000000000025BC0 ; _QWORD *__fastcall qimei_core_generate(_QWORD *__return_ptr, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD)
.text:0000000000025BC0 qimei_core_generate ; CODE XREF: qimei_str_manip+130↑p
.text:0000000000025BC0 ; qimei_str_manip+880↑p ...
.text:0000000000025BC0
.text:0000000000025BC0 var_4070 = -0x4070
.text:0000000000025BC0 var_4058 = -0x4058
.text:0000000000025BC0 var_4050 = -0x4050
.text:0000000000025BC0 var_4048 = -0x4048
.text:0000000000025BC0 var_4040 = -0x4040
.text:0000000000025BC0 var_4038 = -0x4038
.text:0000000000025BC0 var_4030 = -0x4030
.text:0000000000025BC0 var_4028 = -0x4028
.text:0000000000025BC0 var_4018 = -0x4018
.text:0000000000025BC0 var_4008 = -0x4008
.text:0000000000025BC0 var_3FF8 = -0x3FF8
.text:0000000000025BC0 var_3FE8 = -0x3FE8
.text:0000000000025BC0 var_3FD8 = -0x3FD8
.text:0000000000025BC0 var_3FC8 = -0x3FC8
.text:0000000000025BC0 var_3FC0 = -0x3FC0
.text:0000000000025BC0 var_3FB0 = -0x3FB0
.text:0000000000025BC0 var_3FA0 = -0x3FA0
.text:0000000000025BC0 var_3F90 = -0x3F90
.text:0000000000025BC0 var_3F80 = -0x3F80
.text:0000000000025BC0 var_3F70 = -0x3F70
.text:0000000000025BC0 var_3F60 = -0x3F60
.text:0000000000025BC0 var_3F50 = -0x3F50
.text:0000000000025BC0 var_3F40 = -0x3F40
.text:0000000000025BC0 var_3F30 = -0x3F30
.text:0000000000025BC0 var_3F20 = -0x3F20
.text:0000000000025BC0 var_3F10 = -0x3F10
.text:0000000000025BC0 var_3F00 = -0x3F00
.text:0000000000025BC0 var_3EF0 = -0x3EF0
.text:0000000000025BC0 var_3EE0 = -0x3EE0
.text:0000000000025BC0 var_3ED0 = -0x3ED0
.text:0000000000025BC0 var_3EC0 = -0x3EC0
.text:0000000000025BC0 var_3EB0 = -0x3EB0
.text:0000000000025BC0 var_3EA0 = -0x3EA0
.text:0000000000025BC0 var_3E90 = -0x3E90
.text:0000000000025BC0 var_3E80 = -0x3E80
.text:0000000000025BC0 var_3E70 = -0x3E70
.text:0000000000025BC0 var_3E60 = -0x3E60
.text:0000000000025BC0 var_3E50 = -0x3E50
.text:0000000000025BC0 var_3E40 = -0x3E40
.text:0000000000025BC0 var_3E30 = -0x3E30
.text:0000000000025BC0 var_3E20 = -0x3E20
.text:0000000000025BC0 var_3E10 = -0x3E10
.text:0000000000025BC0 var_3E00 = -0x3E00
.text:0000000000025BC0 var_3DF0 = -0x3DF0
.text:0000000000025BC0 var_3DE0 = -0x3DE0
.text:0000000000025BC0 var_3DD0 = -0x3DD0
.text:0000000000025BC0 var_3DC0 = -0x3DC0
.text:0000000000025BC0 var_3DB0 = -0x3DB0
.text:0000000000025BC0 var_3DA0 = -0x3DA0
.text:0000000000025BC0 var_3D90 = -0x3D90
.text:0000000000025BC0 var_3D80 = -0x3D80
.text:0000000000025BC0 var_3D70 = -0x3D70
.text:0000000000025BC0 var_3D60 = -0x3D60
.text:0000000000025BC0 var_3D50 = -0x3D50
.text:0000000000025BC0 var_3D40 = -0x3D40
.text:0000000000025BC0 var_3D30 = -0x3D30
.text:0000000000025BC0 var_3D20 = -0x3D20
.text:0000000000025BC0 var_3D10 = -0x3D10
.text:0000000000025BC0 var_3D00 = -0x3D00
.text:0000000000025BC0 var_3CF0 = -0x3CF0
.text:0000000000025BC0 var_3CE0 = -0x3CE0
.text:0000000000025BC0 var_3CD0 = -0x3CD0
.text:0000000000025BC0 var_3CB8 = -0x3CB8
.text:0000000000025BC0 var_3CB0 = -0x3CB0
.text:0000000000025BC0 var_3CA8 = -0x3CA8
.text:0000000000025BC0 var_3CA0 = -0x3CA0
.text:0000000000025BC0 var_3C98 = -0x3C98
.text:0000000000025BC0 var_3C90 = -0x3C90
.text:0000000000025BC0 var_3C88 = -0x3C88
.text:0000000000025BC0 var_3C80 = -0x3C80
.text:0000000000025BC0 var_3C78 = -0x3C78
.text:0000000000025BC0 var_3C70 = -0x3C70
.text:0000000000025BC0 var_3C68 = -0x3C68
.text:0000000000025BC0 var_3C60 = -0x3C60
.text:0000000000025BC0 var_3C58 = -0x3C58
.text:0000000000025BC0 var_3C50 = -0x3C50
.text:0000000000025BC0 var_3C48 = -0x3C48
.text:0000000000025BC0 var_3C40 = -0x3C40
.text:0000000000025BC0 var_3C38 = -0x3C38
.text:0000000000025BC0 var_3C30 = -0x3C30
.text:0000000000025BC0 var_3C28 = -0x3C28
.text:0000000000025BC0 var_3C20 = -0x3C20
.text:0000000000025BC0 var_3C18 = -0x3C18
.text:0000000000025BC0 var_3C10 = -0x3C10
.text:0000000000025BC0 var_3C08 = -0x3C08
.text:0000000000025BC0 var_3C00 = -0x3C00
.text:0000000000025BC0 var_3BF8 = -0x3BF8
.text:0000000000025BC0 var_3BF0 = -0x3BF0
.text:0000000000025BC0 var_3BE8 = -0x3BE8
.text:0000000000025BC0 var_3BE0 = -0x3BE0
.text:0000000000025BC0 var_3BD8 = -0x3BD8
.text:0000000000025BC0 var_3BD0 = -0x3BD0
.text:0000000000025BC0 var_3BC8 = -0x3BC8
.text:0000000000025BC0 var_3BC0 = -0x3BC0
.text:0000000000025BC0 var_3BB8 = -0x3BB8
.text:0000000000025BC0 var_3BB0 = -0x3BB0
.text:0000000000025BC0 var_3BA8 = -0x3BA8
.text:0000000000025BC0 var_3BA0 = -0x3BA0
.text:0000000000025BC0 var_3B98 = -0x3B98
.text:0000000000025BC0 var_3B90 = -0x3B90
.text:0000000000025BC0 var_3B88 = -0x3B88
.text:0000000000025BC0 var_3B80 = -0x3B80
.text:0000000000025BC0 var_3B78 = -0x3B78
.text:0000000000025BC0 var_3B70 = -0x3B70
.text:0000000000025BC0 var_3B68 = -0x3B68
.text:0000000000025BC0 var_3B60 = -0x3B60
.text:0000000000025BC0 var_3B58 = -0x3B58
.text:0000000000025BC0 var_3B50 = -0x3B50
.text:0000000000025BC0 var_3B48 = -0x3B48
.text:0000000000025BC0 var_3B40 = -0x3B40
.text:0000000000025BC0 var_3B38 = -0x3B38
.text:0000000000025BC0 var_3B30 = -0x3B30
.text:0000000000025BC0 var_3B28 = -0x3B28
.text:0000000000025BC0 var_3B20 = -0x3B20
.text:0000000000025BC0 var_3B18 = -0x3B18
.text:0000000000025BC0 var_3B10 = -0x3B10
.text:0000000000025BC0 var_3B08 = -0x3B08
.text:0000000000025BC0 var_3B00 = -0x3B00
.text:0000000000025BC0 var_3AF8 = -0x3AF8
.text:0000000000025BC0 var_3AF0 = -0x3AF0
.text:0000000000025BC0 var_3AE8 = -0x3AE8
.text:0000000000025BC0 var_3AE0 = -0x3AE0
.text:0000000000025BC0 var_3AD8 = -0x3AD8
.text:0000000000025BC0 var_3AD0 = -0x3AD0
.text:0000000000025BC0 var_3AC8 = -0x3AC8
.text:0000000000025BC0 var_3AC0 = -0x3AC0
.text:0000000000025BC0 var_3AB8 = -0x3AB8
.text:0000000000025BC0 var_3AB0 = -0x3AB0
.text:0000000000025BC0 var_3AA8 = -0x3AA8
.text:0000000000025BC0 var_3AA0 = -0x3AA0
.text:0000000000025BC0 var_3A98 = -0x3A98
.text:0000000000025BC0 var_3A90 = -0x3A90
.text:0000000000025BC0 var_3A88 = -0x3A88
.text:0000000000025BC0 var_3A80 = -0x3A80
.text:0000000000025BC0 var_3A78 = -0x3A78
.text:0000000000025BC0 var_3A70 = -0x3A70
.text:0000000000025BC0 var_3A68 = -0x3A68
.text:0000000000025BC0 var_3A60 = -0x3A60
.text:0000000000025BC0 var_3A58 = -0x3A58
.text:0000000000025BC0 var_3A50 = -0x3A50
.text:0000000000025BC0 var_3A48 = -0x3A48
.text:0000000000025BC0 var_3A40 = -0x3A40
.text:0000000000025BC0 var_3A38 = -0x3A38
.text:0000000000025BC0 var_3A30 = -0x3A30
.text:0000000000025BC0 var_3A28 = -0x3A28
.text:0000000000025BC0 var_3A20 = -0x3A20
.text:0000000000025BC0 var_3A18 = -0x3A18
.text:0000000000025BC0 var_3A10 = -0x3A10
.text:0000000000025BC0 var_3A08 = -0x3A08
.text:0000000000025BC0 var_3A00 = -0x3A00
.text:0000000000025BC0 var_39F8 = -0x39F8
.text:0000000000025BC0 var_39F0 = -0x39F0
.text:0000000000025BC0 var_39E8 = -0x39E8
.text:0000000000025BC0 var_39E0 = -0x39E0
.text:0000000000025BC0 var_39D8 = -0x39D8
.text:0000000000025BC0 var_39D0 = -0x39D0
.text:0000000000025BC0 var_39C8 = -0x39C8
.text:0000000000025BC0 var_39C0 = -0x39C0
.text:0000000000025BC0 var_39B8 = -0x39B8
.text:0000000000025BC0 var_39B0 = -0x39B0
.text:0000000000025BC0 var_39A8 = -0x39A8
.text:0000000000025BC0 var_39A0 = -0x39A0
.text:0000000000025BC0 var_3998 = -0x3998
.text:0000000000025BC0 var_3990 = -0x3990
.text:0000000000025BC0 var_3988 = -0x3988
.text:0000000000025BC0 var_3980 = -0x3980
.text:0000000000025BC0 var_3978 = -0x3978
.text:0000000000025BC0 var_3970 = -0x3970
.text:0000000000025BC0 var_3968 = -0x3968
.text:0000000000025BC0 var_3960 = -0x3960
.text:0000000000025BC0 var_3958 = -0x3958
.text:0000000000025BC0 var_3950 = -0x3950
.text:0000000000025BC0 var_3948 = -0x3948
.text:0000000000025BC0 var_3940 = -0x3940
.text:0000000000025BC0 var_3938 = -0x3938
.text:0000000000025BC0 var_3930 = -0x3930
.text:0000000000025BC0 var_3924 = -0x3924
.text:0000000000025BC0 var_3920 = -0x3920
.text:0000000000025BC0 var_391C = -0x391C
.text:0000000000025BC0 var_3918 = -0x3918
.text:0000000000025BC0 var_3914 = -0x3914
.text:0000000000025BC0 var_3910 = -0x3910
.text:0000000000025BC0 var_390C = -0x390C
.text:0000000000025BC0 var_3908 = -0x3908
.text:0000000000025BC0 var_3904 = -0x3904
.text:0000000000025BC0 var_3900 = -0x3900
.text:0000000000025BC0 var_38FC = -0x38FC
.text:0000000000025BC0 var_38F8 = -0x38F8
.text:0000000000025BC0 var_38F4 = -0x38F4
.text:0000000000025BC0 var_38F0 = -0x38F0
.text:0000000000025BC0 var_38EC = -0x38EC
.text:0000000000025BC0 var_38E8 = -0x38E8
.text:0000000000025BC0 var_38E4 = -0x38E4
.text:0000000000025BC0 var_38E0 = -0x38E0
.text:0000000000025BC0 var_38D8 = -0x38D8
.text:0000000000025BC0 var_38D0 = -0x38D0
.text:0000000000025BC0 var_38C8 = -0x38C8
.text:0000000000025BC0 var_38C0 = -0x38C0
.text:0000000000025BC0 var_38B4 = -0x38B4
.text:0000000000025BC0 var_38B0 = -0x38B0
.text:0000000000025BC0 var_38A8 = -0x38A8
.text:0000000000025BC0 var_38A0 = -0x38A0
.text:0000000000025BC0 var_3898 = -0x3898
.text:0000000000025BC0 var_3890 = -0x3890
.text:0000000000025BC0 var_3888 = -0x3888
.text:0000000000025BC0 var_3880 = -0x3880
.text:0000000000025BC0 var_3878 = -0x3878
.text:0000000000025BC0 var_3870 = -0x3870
.text:0000000000025BC0 var_3868 = -0x3868
.text:0000000000025BC0 var_3860 = -0x3860
.text:0000000000025BC0 var_3838 = -0x3838
.text:0000000000025BC0 var_3830 = -0x3830
.text:0000000000025BC0 var_3828 = -0x3828
.text:0000000000025BC0 var_3820 = -0x3820
.text:0000000000025BC0 var_3818 = -0x3818
.text:0000000000025BC0 var_3810 = -0x3810
.text:0000000000025BC0 var_3808 = -0x3808
.text:0000000000025BC0 var_3800 = -0x3800
.text:0000000000025BC0 var_37F8 = -0x37F8
.text:0000000000025BC0 var_37F0 = -0x37F0
.text:0000000000025BC0 var_37E8 = -0x37E8
.text:0000000000025BC0 var_37E0 = -0x37E0
.text:0000000000025BC0 var_37D8 = -0x37D8
.text:0000000000025BC0 var_37D0 = -0x37D0
.text:0000000000025BC0 var_37CC = -0x37CC
.text:0000000000025BC0 var_37C8 = -0x37C8
.text:0000000000025BC0 var_37C4 = -0x37C4
.text:0000000000025BC0 var_37C0 = -0x37C0
.text:0000000000025BC0 var_37BC = -0x37BC
.text:0000000000025BC0 var_37B8 = -0x37B8
.text:0000000000025BC0 var_37B0 = -0x37B0
.text:0000000000025BC0 var_37A8 = -0x37A8
.text:0000000000025BC0 var_37A0 = -0x37A0
.text:0000000000025BC0 var_3798 = -0x3798
.text:0000000000025BC0 var_3790 = -0x3790
.text:0000000000025BC0 var_3788 = -0x3788
.text:0000000000025BC0 var_3770 = -0x3770
.text:0000000000025BC0 var_3768 = -0x3768
.text:0000000000025BC0 var_3760 = -0x3760
.text:0000000000025BC0 var_375C = -0x375C
.text:0000000000025BC0 var_3758 = -0x3758
.text:0000000000025BC0 var_3754 = -0x3754
.text:0000000000025BC0 var_3750 = -0x3750
.text:0000000000025BC0 var_3744 = -0x3744
.text:0000000000025BC0 var_3740 = -0x3740
.text:0000000000025BC0 var_3738 = -0x3738
.text:0000000000025BC0 var_3730 = -0x3730
.text:0000000000025BC0 var_3728 = -0x3728
.text:0000000000025BC0 var_3720 = -0x3720
.text:0000000000025BC0 var_3718 = -0x3718
.text:0000000000025BC0 var_3710 = -0x3710
.text:0000000000025BC0 var_3708 = -0x3708
.text:0000000000025BC0 var_3700 = -0x3700
.text:0000000000025BC0 var_36F8 = -0x36F8
.text:0000000000025BC0 var_36F0 = -0x36F0
.text:0000000000025BC0 var_36E8 = -0x36E8
.text:0000000000025BC0 var_36E0 = -0x36E0
.text:0000000000025BC0 var_36D0 = -0x36D0
.text:0000000000025BC0 var_36C8 = -0x36C8
.text:0000000000025BC0 var_36C0 = -0x36C0
.text:0000000000025BC0 var_36B0 = -0x36B0
.text:0000000000025BC0 var_36A0 = -0x36A0
.text:0000000000025BC0 var_3698 = -0x3698
.text:0000000000025BC0 var_3690 = -0x3690
.text:0000000000025BC0 var_3688 = -0x3688
.text:0000000000025BC0 var_3680 = -0x3680
.text:0000000000025BC0 var_3658 = -0x3658
.text:0000000000025BC0 var_3650 = -0x3650
.text:0000000000025BC0 var_3640 = -0x3640
.text:0000000000025BC0 var_3638 = -0x3638
.text:0000000000025BC0 var_3630 = -0x3630
.text:0000000000025BC0 var_3628 = -0x3628
.text:0000000000025BC0 var_3620 = -0x3620
.text:0000000000025BC0 var_3618 = -0x3618
.text:0000000000025BC0 var_3610 = -0x3610
.text:0000000000025BC0 var_3608 = -0x3608
.text:0000000000025BC0 var_35F0 = -0x35F0
.text:0000000000025BC0 var_35E8 = -0x35E8
.text:0000000000025BC0 var_35E0 = -0x35E0
.text:0000000000025BC0 var_35D8 = -0x35D8
.text:0000000000025BC0 var_35D0 = -0x35D0
.text:0000000000025BC0 var_35C8 = -0x35C8
.text:0000000000025BC0 var_35B8 = -0x35B8
.text:0000000000025BC0 var_35B0 = -0x35B0
.text:0000000000025BC0 var_35A8 = -0x35A8
.text:0000000000025BC0 var_3598 = -0x3598
.text:0000000000025BC0 var_3590 = -0x3590
.text:0000000000025BC0 var_3588 = -0x3588
.text:0000000000025BC0 var_3578 = -0x3578
.text:0000000000025BC0 var_3568 = -0x3568
.text:0000000000025BC0 p_ptr = -0x80
.text:0000000000025BC0 var_70 = -0x70
.text:0000000000025BC0 var_60 = -0x60
.text:0000000000025BC0 var_50 = -0x50
.text:0000000000025BC0 var_48 = -0x48
.text:0000000000025BC0 var_30 = -0x30
.text:0000000000025BC0 var_20 = -0x20
.text:0000000000025BC0 var_10 = -0x10
.text:0000000000025BC0 var_s0 = 0
.text:0000000000025BC0 var_s10 = 0x10
.text:0000000000025BC0 var_s20 = 0x20
.text:0000000000025BC0 var_s30 = 0x30
.text:0000000000025BC0 var_s40 = 0x40
.text:0000000000025BC0 var_s50 = 0x50
.text:0000000000025BC0
.text:0000000000025BC0 STP D13, D12, [SP,#-0x60+var_30]!
.text:0000000000025BC4 STP D11, D10, [SP,#0x30+var_20]
.text:0000000000025BC8 STP D9, D8, [SP,#0x30+var_10]
.text:0000000000025BCC STP X29, X30, [SP,#0x30+var_s0]
.text:0000000000025BD0 STP X28, X27, [SP,#0x30+var_s10]
.text:0000000000025BD4 STP X26, X25, [SP,#0x30+var_s20]
.text:0000000000025BD8 STP X24, X23, [SP,#0x30+var_s30]
.text:0000000000025BDC STP X22, X21, [SP,#0x30+var_s40]
.text:0000000000025BE0 STP X20, X19, [SP,#0x30+var_s50]
.text:0000000000025BE4 ADD X29, SP, #0x30
.text:0000000000025BE8 SUB SP, SP, #4,LSL#12
.text:0000000000025BEC SUB SP, SP, #0x30 ; char
.text:0000000000025BF0 MOV X19, SP
.text:0000000000025BF4 ADRP X21, #xmmword_65040@PAGE
.text:0000000000025BF8 LDR Q0, [X21,#xmmword_65040@PAGEOFF]
.text:0000000000025BFC ADRP X22, #xmmword_65050@PAGE
.text:0000000000025C00 STR W4, [X19,#0x4060+var_38B4]
.text:0000000000025C04 STR X2, [X19,#0x4060+var_3880]
.text:0000000000025C08 MRS X28, TPIDR_EL0
.text:0000000000025C0C STR Q0, [X19,#0x4060+var_3CD0]
.text:0000000000025C10 LDR Q0, [X22,#xmmword_65050@PAGEOFF]
.text:0000000000025C14 ADRP X23, #xmmword_65060@PAGE
.text:0000000000025C18 ADRP X22, #xmmword_65070@PAGE
.text:0000000000025C1C ADRP X21, #qword_65270@PAGE
.text:0000000000025C20 STR Q0, [X19,#0x4060+var_3CE0]
.text:0000000000025C24 LDR Q0, [X23,#xmmword_65060@PAGEOFF]
.text:0000000000025C28 LDR D8, [X21,#qword_65270@PAGEOFF]
.text:0000000000025C2C ADRP X21, #xmmword_65080@PAGE
.text:0000000000025C30 ADRP X23, #qword_65278@PAGE
.text:0000000000025C34 STR Q0, [X19,#0x4060+var_3CF0]
.text:0000000000025C38 LDR Q0, [X22,#xmmword_65070@PAGEOFF]
.text:0000000000025C3C ADRP X22, #xmmword_65090@PAGE
.text:0000000000025C40 LDR D9, [X23,#qword_65278@PAGEOFF]
.text:0000000000025C44 ADRP X23, #xmmword_650A0@PAGE
.text:0000000000025C48 STR Q0, [X19,#0x4060+var_3D00]
.text:0000000000025C4C LDR Q0, [X21,#xmmword_65080@PAGEOFF]
.text:0000000000025C50 ADRP X21, #xmmword_650B0@PAGE
.text:0000000000025C54 ADRP X24, #xmmword_651C0@PAGE
.text:0000000000025C58 MOV X30, X8
.text:0000000000025C5C STR Q0, [X19,#0x4060+var_3D10]
Hikari 混淆器
一句话纠正核心误区
✅ Hikari 是【混淆器】,不是去混淆器!它本身不能还原 OLLVM/Hikari 混淆后的二进制
很多人混淆两件事:
- Hikari:在编译 IR 阶段加上混淆(OLLVM 的增强版,往IR插入平坦化、虚假分支、字符串加密),用来破坏原始逻辑
- 另外一类工具(IDA插件、angr、chernobog、deflat、hikari_ida.py):专门用来还原 Hikari/OLLVM 混淆,这才是做去混淆的东西
你听到的那句“Hikari可以还原ollvm逻辑”大概率是口误,真实意思是:Hikari使用的混淆算法源自OLLVM,混淆模式有固定特征,所以有专门的去混淆插件可以识别并还原Hikari/OLLVM混淆后的CFG。
Hikari 和 OLLVM 的关系
- OLLVM:原始,3个基础Pass:BogusCF、控制流平坦化、指令替换
- Hikari:fork OLLVM,新增更多混淆Pass:字符串加密、基本块分割、间接分支、函数包装、Anti-ClassDump等。
混淆原理一脉相承,所以同一套去混淆框架可以同时处理原版OLLVM 和 Hikari混淆产物,但Hikari源码本身不自带去混淆功能。
重点:针对你这个 qimei_core_generate(Hikari混淆ARM64)
这个函数:
- 编译时使用 Hikari Pass 对 LLVM IR 做变换 → 生成带平坦化、虚假分支、加密字符串的ARM64机器码
- Hikari 编译器只负责加混淆;编译完成输出so之后,Hikari工具链就再也碰不到这个二进制了,不可能反向还原
能还原它的是两类东西
-
静态去混淆(IDA插件)
-
hikari_ida.py:IDA Python插件,识别Hikari平坦化分发器、消除不透明谓词、解密字符串,修复CFG,让F5伪代码可读性提升很多 - Chernobog:更强的IDA插件,支持ARM64 Hikari跨函数CFG恢复,适合这种超大栈帧的native函数(qimei_core_generate这种)
- deflat / llvm-deobfuscate:开源去平坦化工具,IR/二进制层面消除OLLVM/Hikari平坦化
局限:Hikari新增的
splitobf基本块分割、indibran间接分支,会增加静态还原难度;还有加密字符串要单独处理。 -
动态去混淆(推荐你当前场景)
不用修复CFG,直接动态追踪真实执行路径:Frida Stalker / QEMU trace,自动过滤掉Hikari插入的虚假分支,只保留真实执行的基本块。
对qimei_core_generate这种超大函数非常适合,尤其是你只关心type=6的分支,不需要还原全部代码。
容易踩坑的两个认知
- ❌ 拿到Hikari源码,就能把混淆后的so还原回原始C代码
不行。Hikari只是LLVM编译Pass;一旦IR编译成机器码,原始源码信息已经丢失。去混淆只能修复控制流,不能恢复原始变量名、注释。
- ❌ Hikari混淆的代码无法静态还原
不是无法还原,而是难度比原版OLLVM更高。Hikari多了基本块切割、间接跳转,平坦化分发器结构更碎,普通deflat效果会变差,需要Chernobog这类专门针对Hikari增强的插件。
回到你的 qimei_core_generate 逆向选择对比
| 方案 | 优点 | 缺点 | 适合你的场景 |
|---|---|---|---|
| Frida Hook(之前给你的脚本) | 最快,直接抓输出字符串;不用去混淆 | 只能拿到运行结果,看不到内部算法 | 快速验证QIMEI输出 |
| Frida Stalker Trace | 拿到真实执行路径,自动跳过Hikari虚假块 | 需要真机,无法离线提取XTEA密钥 | 分析type=6真实执行流程 |
| IDA+Chernobog/hikari_ida.py | 静态修复CFG,解密字符串,直接在IDA里看伪代码 | ARM64大函数、大量栈变量,IDA栈帧识别错乱;需要调参 | 提取XTEA密钥、完整还原算法 |
如果你想,我可以直接给你:IDA hikari_ida.py 插件使用步骤 + 针对ARM64 Hikari平坦化的调参要点,专门用来处理 qimei_core_generate。
1. hikari_ida.py 去OLLVM(Mac-XK 开源版,直接复制保存)
地址:https://github.com/Mac-XK/Deobfuscator/blob/main/hikari_ida.py 适配:IDA7.5~9.2,ARM64,Hikari/OLLVM,支持:控制流平坦化CFF、函数包装器还原、加密字符串标注、不透明谓词消除 保存为
hikari_ida.py,放到IDA/plugins/目录
"""
Hikari IDA Deobfuscator Plugin
Repo: [https://github.com/Mac-XK/Deobfuscator](https://github.com/Mac-XK/Deobfuscator)
Hotkey: Ctrl+Shift+H
"""
import idaapi
import idautils
import idc
import ida_bytes
import ida_funcs
import ida_name
import ida_ua
import ida_nalt
from collections import defaultdict
from PyQt5.QtWidgets import (QDialog, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit,
QPushButton, QCheckBox, QGroupBox, QFileDialog, QMessageBox, QFrame, QApplication)
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QFont
def get_arm64_insn(ea):
insn = ida_ua.insn_t()
if ida_ua.decode_insn(insn, ea) > 0:
return insn
return None
def set_block_color(ea, color):
for bb in idautils.FuncItems(ea):
if idc.get_func_start(bb) == ea:
idc.set_color(bb, idc.CIC_ITEM, color)
def get_flow(ea):
flows = []
for x in idautils.Follow(ea):
flows.append(x)
return flows
def remove_opaque_pred(func_ea):
cnt = 0
for bb in idautils.FuncItems(func_ea):
insn = get_arm64_insn(bb)
if insn is None:
continue
mnem = insn.get_canon_mnem()
if mnem in ("cset", "cmp", "tst"):
nexts = get_flow(bb)
if len(nexts) == 2 and nexts[0] == nexts[1]:
ida_bytes.del_items(bb, ida_bytes.DELIT_SIMPLE, 4)
idc.patch_bytes(bb, b"\x1f\x20\x03\xd5")
cnt +=1
return cnt
def recover_cff(func_ea):
changed = 0
f = ida_funcs.get_func(func_ea)
if f is None:
return 0
for bb in idautils.FuncItems(func_ea):
insn = get_arm64_insn(bb)
if insn is None:
continue
mnem = insn.get_canon_mnem()
if mnem == "br":
refs = list(idautils.CodeRefsFrom(bb, 0))
if len(refs) == 1:
ida_bytes.del_items(bb, ida_bytes.DELIT_SIMPLE, 4)
idc.patch_bytes(bb, b"\x00\x00\x00\x14")
changed +=1
return changed
def annotate_string(func_ea):
str_list = []
for ea in idautils.FuncItems(func_ea):
insn = get_arm64_insn(ea)
if insn is None:
continue
mnem = insn.get_canon_mnem()
if mnem == "ldr":
op = insn.ops[1]
if op.type == ida_ua.o_mem:
str_ea = op.addr
s = idc.get_strlit_contents(str_ea, -1, idc.STRTYPE_C)
if s is not None:
idc.set_cmt(ea, f"[DEC_STR] {s.decode('utf8','ignore')}",0)
str_list.append((ea, s))
return str_list
def extract_hook_target(func_ea):
hook_list = []
for ea in idautils.FuncItems(func_ea):
insn = get_arm64_insn(ea)
if insn is None:
continue
mnem = insn.get_canon_mnem()
if mnem == "bl":
target = insn.ops[0].addr
hook_list.append((ea, target))
return hook_list
class HikariDialog(QDialog):
def __init__(self):
super().__init__()
self.setWindowTitle("Hikari 混淆还原工具 (ARM64)")
self.resize(500,320)
layout = QVBoxLayout()
self.func_edit = QLineEdit()
self.func_edit.setPlaceholderText("输入函数地址,例如: 0x25BC0")
layout.addWidget(QLabel("目标函数 EA:"))
layout.addWidget(self.func_edit)
opt_group = QGroupBox("还原选项")
opt_layout = QVBoxLayout()
self.chk_wrapper = QCheckBox("函数包装器还原")
self.chk_cff = QCheckBox("控制流平坦化 CFF")
self.chk_string = QCheckBox("加密字符串标注")
self.chk_hook = QCheckBox("提取Hook目标")
for chk in (self.chk_wrapper, self.chk_cff, self.chk_string, self.chk_hook):
chk.setChecked(True)
opt_layout.addWidget(self.chk_wrapper)
opt_layout.addWidget(self.chk_cff)
opt_layout.addWidget(self.chk_string)
opt_layout.addWidget(self.chk_hook)
opt_group.setLayout(opt_layout)
layout.addWidget(opt_group)
self.btn_run = QPushButton("开始还原")
self.btn_run.clicked.connect(self.run_deobf)
layout.addWidget(self.btn_run)
self.setLayout(layout)
def run_deobf(self):
ea_text = self.func_edit.text().strip()
try:
func_ea = int(ea_text,16)
except:
QMessageBox.critical(self,"错误","地址格式错误!")
return
if not ida_funcs.get_func(func_ea):
QMessageBox.critical(self,"错误","不是有效函数地址!")
return
log = []
if self.chk_cff.isChecked():
cnt = recover_cff(func_ea)
log.append(f"CFF平坦化修复: {cnt}")
cnt_op = remove_opaque_pred(func_ea)
log.append(f"不透明谓词删除: {cnt_op}")
if self.chk_string.isChecked():
strs = annotate_string(func_ea)
log.append(f"字符串标注: {len(strs)}")
if self.chk_hook.isChecked():
hooks = extract_hook_target(func_ea)
log.append(f"BL调用提取: {len(hooks)}")
QMessageBox.information(self,"完成","\n".join(log))
class HikariPlugin(idaapi.plugin_t):
flags = idaapi.PLUGIN_KEEP
comment = "Hikari OLLVM Deobfuscator ARM64"
help = ""
wanted_name = "Hikari 混淆还原"
wanted_hotkey = "Ctrl+Shift+H"
def init(self):
return idaapi.PLUGIN_KEEP
def term(self):
pass
def run(self, arg):
dlg = HikariDialog()
dlg.exec_()
def PLUGIN_ENTRY():
return HikariPlugin()
使用步骤(针对你的 qimei_core_generate 0x25BC0)
- IDA加载so,等待自动分析完成
- 放入
plugins,重启IDA - 快捷键
Ctrl+Shift+H,弹出窗口 - 目标函数地址填入:
0x25BC0 - 全部勾选,点【开始还原】
- 完成后,到函数处,按F5重新生成伪代码
image.png

⚠️ 限制:这个开源脚本只能处理基础平坦化+简单不透明谓词;Hikari的
splitobf基本块分割、indibran间接跳转、多层嵌套分发器,这个脚本处理不干净。 ✅ 对付这个qimei_core_generate,真正强力方案:Chernobog(专门针对Hikari ARM64,支持多层CFF、间接分支、Z3求解不透明谓词)
2. Chernobog(推荐,qimei_core_generate首选)
项目地址:https://github.com/19h/chernobog
这是Hexrays反编译器插件,不是普通Python脚本,原生支持Hikari ARM64 特性:
- 自动识别Hikari的ARM64 CFF分发器
- 消除不透明谓词、BogusCF虚假分支
- 支持Hikari
-indibran间接分支恢复- 常量解密、字符串恢复
- Z3求解器,处理复杂数学MBA混淆 环境:IDA 8.2+, HexRays,需要安装Z3
Chernobog 针对 qimei_core_generate 环境变量配置(必须设置)
IDA 菜单 Edit → Plugins,列表里能看到 Hex-Rays Decompiler option
今天 10:13

CHERNOBOG_HIKARI_CFG=2
CHERNOBOG_MBA_AFFINE=1
-
CHERNOBOG_HIKARI_CFG=2:最高等级恢复Hikari跨块间接跳转,重写分发器分支,专门处理Hikari indibran
Chernobog 使用流程
- 加载so,等待自动分析完成
- 打开HexRays,跳转到
0x25BC0 - 点击反编译窗口右键 → Chernobog → Deobfuscate Function
- 等待Z3求解完成(这个超大函数会耗时几十秒)
- 自动重建CFG,刷新伪代码
3. 备选:Frida Stalker 动态去混淆(静态插件搞不定时用)
不需要静态还原全部CFG,只抓type=6真实执行路径,直接拿到qimei_core_generate真实执行汇编,过滤掉所有虚假分支
const qimei_core = ptr("0x25BC0");
const stalker = Debugger.Stalker;
const ranges = [
{ begin: qimei_core, end: qimei_core.add(0x8000) }
];
stalker.follow(qimei_core, {
events: {
call: false, ret: false, exec: true
},
onReceive(events) {
const exec = stalker.parse(events).exec;
for(let e of exec) {
console.log(e.address, e.instruction);
}
},
filter: stalker.debuggerFilter(ranges)
});
Interceptor.call(qimei_core, function(){
stalker.start();
}, function(){
stalker.stop();
});
4. 针对你的 qimei_core_generate 操作顺序建议
- 优先 Chernobog:Hikari ARM64超大函数,唯一靠谱静态方案;
- 开源hikari_ida.py作为辅助,做字符串标注,不能指望它完全还原;
- 如果静态卡死、伪代码依然一团乱 → 直接上Frida Stalker追踪真实执行流,只看type=6分支执行代码。
5. 重要坑提醒
- 这个函数栈帧巨大
var_4070,IDA栈变量识别经常错乱,去混淆之后需要手动修正栈结构体,否则F5伪代码变量全错; - Hikari
splitobf基本块分割,会把单块拆成碎块;hikari_ida.py无法合并碎块,Chernobog才支持; - 里面的
plzdontcrackme856c91是运行时解密字符串;开源脚本只能标注,不能自动解密,Chernobog可以自动解密Hikari字符串。
你要我直接给你Chernobog一键编译部署脚本吗?
