在开赛前看到 app 分类 + 名字 vmp,就是很慌的。到手 apk,jadx 一开没啥看头,核心逻辑都在 native 的 libcrackme.so 里。虽然有 Java_armvmp_cn_crackme_hello 这个符号,但是似乎完全不能逆向,然后就开始了为期两天的各种奇妙却没用的操作,包括但不限于:
直到周日下午,在搜索安卓反调试的资料的时候,居然搜到一篇春季赛的 wp,一看出题人也是 ArmVMP。好家伙,这不得把 wp 和源码翻烂?尤其是作者的文章,其实已经解释了我好不容易才发现的事 & 一直在猜的坑,比如说 svc 实现的 read write 等。
从这篇 wp了解到了frida inline hook,适配一下,可以打印 read write 的参数,对比春季赛源码确认了校验都是在子进程。此外还可以把 PTRACE_CONT hook 成 PTRACE_DETTACH 等等,不过父进程会检查 /proc/self/status 的 TracerPid 得是子进程。当时看到两个进程的 Tracer 都是 0,只是觉得有些奇怪。想 hook open,把 pid 存进文件,竞争了才发现原来 frida hook 也会影响子进程。
但是好像没有啥效果,迷惑了半天才发现,js 的运算符优先级,==
比 &
居然要优先...然后就没有再管 ptrace 和 Tracer 了,因为只需要调试子进程,子进程不检查 Tracer。
gdb attach 子进程,刚好前面 inline hook 找到了 read write 的地址。
对 serial 之类的下 watchpoint 看了一会儿,放弃了,决定直接进行内存 diff:serial 的地址是容易得到的,在子进程断在 write 结果的时候,dump serial 所在的整个段。
变化中的“低 16 位”似乎能和 hzqmwne 春季赛的 wp 对上。于是提取 fbca8 的值,测试全 0 的输入,和只有一个 FF 在不同位置的输入,模仿一下算法,通过
1
2
data
=
[
0x000025a0
,
0x000024dc
,
0x0000244c
,
0x000024e4
,
0x00002556
,
0x0000243a
,
0x000025a4
,
0x0000253c
,
0x0000249e
,
0x0000244e
,
0x000025c6
,
0x000025f6
,
0x00002530
,
0x0000248e
,
0x00002618
,
0x00002428
,
0x000025fe
,
0x00002532
,
0x0000261a
,
0x0000256c
,
0x0000247c
,
0x0000256c
,
0x0000247c
,
0x0000242e
,
0x000025e0
,
0x00002602
,
0x0000249e
,
0x000024aa
,
0x00002516
,
0x00002586
,
0x000024ca
,
0x000024e8
,
0x00002604
,
0x000025ea
]
print
(bytes((
0x2525
-
x
+
0xff
)
/
/
2
for
x
in
data).
hex
().upper())
吐槽:感觉比起春季赛,反调试保护似乎并没有太多变化。算法大概是增强了,但是只有 name 做了非线性的运算,一通处理算出来的结果和 serial 用稀奇古怪的方法做一些线性比较,导致最后的解法也基本没有变,感觉几乎是原题了。搜 wp 搜晚了,再摆摆烂,分数就只有一半了5555