样本只作为脱壳学习的一个样本,样本的内部逻辑并没有仔细分析,且样本较为简单,通用性差。本帖仅作为学习记录,欢迎大家一同交流。
首先先来官网看一下免费版包括的内容
上传一个Demo用于加固,Demo反编译结果如下
加固只针对Dex进行,且对类进行抽取,其效果如下
首先Shell创建了Application获取程序的起始控制权,之后在attachBaseContext通过Helper类加载manxi.so文件
之后的步骤都是在So层进行,所以需要对So层进行分析
So通过ollvm进行混淆,首先我们先通过Qiling模拟执行去除最简单的字符串混淆
首先我们需要提取到init_array所有函数起始地址和结束地址,这里我通过IDAPython进行提取
提取到地址之后即可进行模拟执行,监听内存读写,由于字符串解密函数通过OLLVM进行混淆,所以存在对于状态变量的写入,这会导致对内存写入的Hook产生多余的结果,只需要通过判断偏移是否在.data段或者.rodata段即可判断是否对加密字符串进行写入,过滤掉不需要修改的内容后把解密内存写入文件中即可(如果某个函数不能模拟执行只需要从列表中去除即可)
解密之后就可以看到很多敏感字符串,但实际上该程序没有检测Root、Fart,只在程序启动时对Frida检测,也就是说可通过Attach来进行附加
首先需要绕过启动时的Frida检测,奇怪的是我Hook dlopen
和android_dlopen_ext
都无法获取到libmanxi.so的加载,但是通过Process.enumerateModules()
可以得到so,这也导致了后续难以定位到检测的位置和绕过。于是使用魔改Frida https://github.com/Ylarod/Florida/releases (可绕过检测)
简单Hook了一下程序中的SVC指令,通过Radare2
的/adj svc
可导出所有SVC指令的地址
其中addr是导出的结果,这里只针对openat进行过滤
发现其创建线程不断打开status文件进而查询TracerPID字段
首先尝试Hook LoadMethod进而进行脱壳
然而脱下来的壳依旧只有Shell代码,即便我们通过延迟脱壳(即首先获取DexFile的begin和size,之后通过命令行调用脱壳函数)依旧如此
所以尝试别的办法,首先我们知道整体加固的原理是替换ClassLoader来加载原Dex,而Shell Dex尾部恰好存在着大量数据,可以猜测这就是被加密的Dex。由于Shell加载完成之后会将程序控制权归还给原程序,所以我们可以Hook performLaunchActivity
,在Activity启动之前获取系统ClassLoader进而得到其加载的Dex文件进行Dump。经过测试,最后一个覆盖的Dex文件为原Dex
反编译结果如下,可以发现onCreate的方法内容未被填充
所以尝试延迟Dump的时机,通过Hook ArtMethod::Invoke
来Dump,最终代码如下
反编译效果如下
import
idaapi
import
lief
import
struct
from
pwn
import
elf, pack, unpack, u64
idaapi.msg_clear()
elf_raw
=
elf.ELF(
"D:/new/frida-agent-example-main/agent/node_modules/libmanxi_copy.so"
)
elf_patch
=
elf.ELF(
"D:/new/frida-agent-example-main/agent/node_modules/libmanxi_copy.so"
)
print
(elf_raw.entrypoint)
init_array
=
None
binary
=
lief.parse(
"D:/new/frida-agent-example-main/agent/node_modules/libmanxi_copy.so"
)
for
sec
in
binary.sections:
if
sec.name
=
=
".init_array"
:
init_array
=
sec
funcArray
=
[]
funcArray_Address
=
[]
index
=
0
while
index < init_array.size:
offset
=
u64(elf_raw.read(init_array.virtual_address
+
index,
8
))
funcArray.append(offset)
index
+
=
8
funcArray.pop()
for
func
in
funcArray:
function
=
[]
function.append(func)
function.append(idaapi.get_func(func).end_ea)
funcArray_Address.append(function)
print
(funcArray_Address)
import
idaapi
import
lief
import
struct
from
pwn
import
elf, pack, unpack, u64
idaapi.msg_clear()
elf_raw
=
elf.ELF(
"D:/new/frida-agent-example-main/agent/node_modules/libmanxi_copy.so"
)
elf_patch
=
elf.ELF(
"D:/new/frida-agent-example-main/agent/node_modules/libmanxi_copy.so"
)
print
(elf_raw.entrypoint)
init_array
=
None
binary
=
lief.parse(
"D:/new/frida-agent-example-main/agent/node_modules/libmanxi_copy.so"
)
for
sec
in
binary.sections:
if
sec.name
=
=
".init_array"
:
init_array
=
sec
funcArray
=
[]
funcArray_Address
=
[]
index
=
0
while
index < init_array.size:
offset
=
u64(elf_raw.read(init_array.virtual_address
+
index,
8
))
funcArray.append(offset)
index
+
=
8
funcArray.pop()
for
func
in
funcArray:
function
=
[]
function.append(func)
function.append(idaapi.get_func(func).end_ea)
funcArray_Address.append(function)
print
(funcArray_Address)
import
lief
from
qiling.os.const
import
POINTER, UINT, STRING
from
qiling
import
Qiling
from
qiling.const
import
QL_VERBOSE
from
qiling.const
import
QL_INTERCEPT
from
qiling
import
os
from
qiling.os.mapper
import
QlFsMappedObject
import
struct
from
pwn
import
elf, pack, unpack, u64
soData
=
lief.parse(
"libmanxi.so"
)
datasec
=
None
rodatasec
=
None
for
sec
in
soData.sections:
if
sec.name
=
=
".data"
:
datasec
=
sec
elif
sec.name
=
=
".rodata"
:
rodatasec
=
sec
data_str
=
""
elf_patch
=
elf.ELF(
"D:/new/frida-agent-example-main/agent/node_modules/libmanxi_copy.so"
)
def
write_hook(ql: Qiling, access:
int
, address:
int
, size:
int
, value:
int
):
Addr
=
address
-
base_addr
if
(
Addr >
=
datasec.virtual_address
and
Addr <
=
datasec.virtual_address
+
datasec.size
)
or
(
Addr >
=
rodatasec.virtual_address
and
Addr <
=
rodatasec.virtual_address
+
rodatasec.size
):
print
(
f
"Write Address: {hex(address-base_addr)} Value:{hex(value)} Size:{hex(size)}"
)
if
size
=
=
1
:
data
=
ql.pack8(value)
elif
size
=
=
2
:
data
=
ql.pack16(value)
elif
size
=
=
4
:
data
=
ql.pack32(value)
elif
size
=
=
8
:
data
=
ql.pack64(value)
elf_patch.write(Addr, data)
funcArray
=
[
[
22616
,
23116
],
[
28832
,
29460
],
[
39664
,
40264
],
[
42856
,
43124
],
[
43932
,
44020
],
[
46660
,
46664
],
[
55196
,
62940
],
[
63672
,
63756
],
[
63756
,
63840
],
[
63840
,
63924
],
[
73424
,
73428
],
[
73516
,
73600
],
[
87628
,
88064
],
[
122504
,
122588
],
[
123876
,
124208
],
[
124208
,
124292
],
[
125200
,
125288
],
[
127652
,
128176
],
[
131420
,
131828
],
[
135164
,
135876
],
[
153412
,
154708
],
[
164120
,
167816
],
[
175060
,
175332
],
[
183120
,
183124
],
[
183124
,
183128
],
[
186856
,
186940
],
[
193592
,
193732
],
[
215616
,
216696
],
[
219564
,
219648
],
[
232264
,
232352
],
[
232920
,
232924
],
[
233080
,
233352
],
[
244248
,
253964
],
[
255484
,
256504
],
[
258116
,
258424
],
[
259408
,
262080
],
[
262080
,
262432
],
[
264236
,
264696
],
[
268872
,
269224
],
[
269688
,
270484
],
[
274292
,
276648
],
[
283864
,
284264
],
[
286580
,
287280
],
[
288384
,
288656
],
[
291236
,
291596
],
[
292296
,
293676
],
[
294012
,
295272
],
[
295272
,
295520
],
[
295976
,
296248
],
[
299480
,
299788
],
[
300236
,
307192
],
[
307500
,
307504
],
[
311600
,
312672
],
[
313304
,
313308
],
[
316048
,
316052
],
[
324380
,
325624
],
[
378800
,
380220
],
[
382004
,
382008
],
[
389160
,
389520
],
[
390088
,
390092
],
[
392360
,
392444
],
[
407960
,
407964
],
[
410060
,
410064
],
[
414476
,
415160
],
[
448668
,
457116
],
[
464888
,
464972
],
[
469092
,
469444
],
[
471132
,
471388
],
[
472156
,
472160
],
[
472180
,
472264
],
[
472512
,
472596
],
[
472596
,
472680
],
[
472680
,
472684
],
[
472684
,
472772
],
[
485160
,
489068
],
[
491672
,
493608
],
[
493608
,
493692
],
[
506756
,
506988
],
[
520552
,
521200
],
[
523132
,
523532
],
[
528344
,
528576
],
[
533168
,
539904
],
[
548616
,
550592
],
[
568596
,
569860
],
[
573168
,
575808
],
[
579536
,
579792
],
[
589616
,
589620
],
[
610480
,
610484
],
[
626444
,
626916
],
[
636500
,
636504
],
[
641936
,
643184
],
[
644460
,
644464
],
[
644816
,
644820
],
[
42852
,
42856
],
]
ql
=
Qiling(
[
"D:/new/frida-agent-example-main/agent/node_modules/libmanxi.so"
],
r
"D:/new/rootfs/arm64_android"
,
verbose
=
QL_VERBOSE.DISASM,
)
base_addr
=
ql.mem.get_lib_base(
"libmanxi.so"
)
str
=
f
"Base Address: {hex(base_addr)}"
ql.hook_mem_write(write_hook)
for
func
in
funcArray:
ql.run(func[
0
]
+
base_addr, func[
1
]
+
base_addr
-
4
)
elf_patch.save(
"aaa.so"
)
import
lief
from
qiling.os.const
import
POINTER, UINT, STRING
from
qiling
import
Qiling
from
qiling.const
import
QL_VERBOSE
from
qiling.const
import
QL_INTERCEPT
from
qiling
import
os
from
qiling.os.mapper
import
QlFsMappedObject
import
struct
from
pwn
import
elf, pack, unpack, u64
soData
=
lief.parse(
"libmanxi.so"
)
datasec
=
None
rodatasec
=
None
for
sec
in
soData.sections:
if
sec.name
=
=
".data"
:
datasec
=
sec
elif
sec.name
=
=
".rodata"
:
rodatasec
=
sec
data_str
=
""
elf_patch
=
elf.ELF(
"D:/new/frida-agent-example-main/agent/node_modules/libmanxi_copy.so"
)
def
write_hook(ql: Qiling, access:
int
, address:
int
, size:
int
, value:
int
):
Addr
=
address
-
base_addr
if
(
Addr >
=
datasec.virtual_address
and
Addr <
=
datasec.virtual_address
+
datasec.size
)
or
(
Addr >
=
rodatasec.virtual_address
and
Addr <
=
rodatasec.virtual_address
+
rodatasec.size
):
print
(
f
"Write Address: {hex(address-base_addr)} Value:{hex(value)} Size:{hex(size)}"
)
if
size
=
=
1
:
data
=
ql.pack8(value)
elif
size
=
=
2
:
data
=
ql.pack16(value)
elif
size
=
=
4
:
data
=
ql.pack32(value)
elif
size
=
=
8
:
data
=
ql.pack64(value)
elf_patch.write(Addr, data)
funcArray
=
[
[
22616
,
23116
],
[
28832
,
29460
],
[
39664
,
40264
],
[
42856
,
43124
],
[
43932
,
44020
],
[
46660
,
46664
],
[
55196
,
62940
],
[
63672
,
63756
],
[
63756
,
63840
],
[
63840
,
63924
],
[
73424
,
73428
],
[
73516
,
73600
],
[
87628
,
88064
],
[
122504
,
122588
],
[
123876
,
124208
],
[
124208
,
124292
],
[
125200
,
125288
],
[
127652
,
128176
],
[
131420
,
131828
],
[
135164
,
135876
],
[
153412
,
154708
],
[
164120
,
167816
],
[
175060
,
175332
],
[
183120
,
183124
],
[
183124
,
183128
],
[
186856
,
186940
],
[
193592
,
193732
],
[
215616
,
216696
],
[
219564
,
219648
],
[
232264
,
232352
],
[
232920
,
232924
],
[
233080
,
233352
],
[
244248
,
253964
],
[
255484
,
256504
],
[
258116
,
258424
],
[
259408
,
262080
],
[
262080
,
262432
],
[
264236
,
264696
],
[
268872
,
269224
],
[
269688
,
270484
],
[
274292
,
276648
],
[
283864
,
284264
],
[
286580
,
287280
],
[
288384
,
288656
],
[
291236
,
291596
],
[
292296
,
293676
],
[
294012
,
295272
],
[
295272
,
295520
],
[
295976
,
296248
],
[
299480
,
299788
],
[
300236
,
307192
],
[
307500
,
307504
],
[
311600
,
312672
],
[
313304
,
313308
],
[
316048
,
316052
],
[
324380
,
325624
],
[
378800
,
380220
],
[
382004
,
382008
],
[
389160
,
389520
],
[
390088
,
390092
],
[
392360
,
392444
],
[
407960
,
407964
],
[
410060
,
410064
],
[
414476
,
415160
],
[
448668
,
457116
],
[
464888
,
464972
],
[
469092
,
469444
],
[
471132
,
471388
],
[
472156
,
472160
],
[
472180
,
472264
],
[
472512
,
472596
],
[
472596
,
472680
],
[
472680
,
472684
],
[
472684
,
472772
],
[
485160
,
489068
],
[
491672
,
493608
],
[
493608
,
493692
],
[
506756
,
506988
],
[
520552
,
521200
],
[
523132
,
523532
],
[
528344
,
528576
],
[
533168
,
539904
],
[
548616
,
550592
],
[
568596
,
569860
],
[
573168
,
575808
],
[
579536
,
579792
],
[
589616
,
589620
],
[
610480
,
610484
],
[
626444
,
626916
],
[
636500
,
636504
],
[
641936
,
643184
],
[
644460
,
644464
],
[
644816
,
644820
],
[
42852
,
42856
],
]
ql
=
Qiling(
[
"D:/new/frida-agent-example-main/agent/node_modules/libmanxi.so"
],
r
"D:/new/rootfs/arm64_android"
,
verbose
=
QL_VERBOSE.DISASM,
)
base_addr
=
ql.mem.get_lib_base(
"libmanxi.so"
)
str
=
f
"Base Address: {hex(base_addr)}"
ql.hook_mem_write(write_hook)
for
func
in
funcArray:
ql.run(func[
0
]
+
base_addr, func[
1
]
+
base_addr
-
4
)
elf_patch.save(
"aaa.so"
)
function
hook_svc() {
console.log(
"=====Hook SVC====="
)
var
base_addr = Module.findBaseAddress(
"libmanxi.so"
);
addr.forEach(
function
(svc) {
var
offset = `0x` + svc.offset.toString(16)
Interceptor.attach(base_addr.add(offset), {
onEnter:
function
(args) {
if
(
this
.context.x8 == 0x38) {
console.log(
"Openat:"
+ ptr(
this
.context.x1).readCString())
}
},
onLeave:
function
(retval) {
}
})
})
}
function
hook_svc() {
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2023-9-20 21:10
被Gift1a编辑
,原因: