首页
论坛
课程
招聘
看雪 2022 KCTF 秋季赛 第三题 水患猖獗
2022-11-21 06:01 3193

看雪 2022 KCTF 秋季赛 第三题 水患猖獗

2022-11-21 06:01
3193

惊闻被 hzqmwne 大哥 cue 了一下,不甚惶恐。要不是拜读了您之前的 wp,这第三题应该是没我的(

 

先来碎碎念:第一次关注 KCTF + 第一次认真调试安卓,居然碰上这种硬茬子 orz

 

在开赛前看到 app 分类 + 名字 vmp,就是很慌的。到手 apk,jadx 一开没啥看头,核心逻辑都在 native 的 libcrackme.so 里。虽然有 Java_armvmp_cn_crackme_hello 这个符号,但是似乎完全不能逆向,然后就开始了为期两天的各种奇妙却没用的操作,包括但不限于:

  • 摆弄前几个月换掉的小米前主力机,想 root 才发现之前没绑定不给解锁
  • 捣鼓模拟器,发现模拟器都是 x86 的,就算打了补丁装上 apk 也跑不起,又不乐意装 Android Studio 用里面 qemu 的 arm
  • IDA 翻翻 Ghidra 看看,除了一堆没有引用的字符串,啥也看不出

周末回家里拿出 root 过的旧手机,又发现:

  • 动态调试怎么都 attach 不上
  • frida spawn 可以调试,现场开始 frida 的学,然后 hook 各种函数只能 hook 住两三个,或者 app 直接崩掉 / 卡死

当时的进展:

  • 发现是父子进程互相 ptrace
  • frida 可 hook 到 pipe 的创建,但是看不到读写
  • frida 可 hook pthread_create,判断函数属于 libcrackme 就干掉,这样可以调试子进程,但是验证会卡住

直到周日下午,在搜索安卓反调试的资料的时候,居然搜到一篇春季赛的 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 也会影响子进程。

 

至于我 hook pthread_create 的事儿,是因为子进程处理消息也是用 pthread_create 起的,我给他也干掉了。就改成按照地址做了判断:

1
2
3
if (func.toInt32() & 0xfff == 0xaa5) {
    ... // 只干掉它
}

但是好像没有啥效果,迷惑了半天才发现,js 的运算符优先级,==& 居然要优先...然后就没有再管 ptrace 和 Tracer 了,因为只需要调试子进程,子进程不检查 Tracer。

 

gdb attach 子进程,刚好前面 inline hook 找到了 read write 的地址。
对 serial 之类的下 watchpoint 看了一会儿,放弃了,决定直接进行内存 diff:serial 的地址是容易得到的,在子进程断在 write 结果的时候,dump serial 所在的整个段。

 

试各种 name serial 的组合,对比找到所有内存不同的地方,然后就可以发现一些有用或者没用的:

  • fbcb8 name 从例子换成 KCTF 之后差了 1 bit,应该不重要
  • fbca0 一个负数,高位 0xffff,每次低 16 位不同
  • fbca8 一个正数,高位 0x0000,每次低 16 位不同
    • 这两个数的和是固定的,0xab
    • 这两个数中间夹着一个固定的 0x15a9
    • 示例 fbca8 就是 0x15a9,看来找到目标了
  • fbcd8 有 0x19 字节不同,和 serial 直接相关
    • serial hex decode 之后,32 个字节,每个字节乘它的位置下标,溢出丢掉
    • 后来感觉知道这个用处不大
  • fbe80 存着返回值,0x13 对,0 错
  • fbe84 固定一个 0xab,对应上面两数之和
  • fbe88 与 fbca0 一致的
  • fbf98 有 0x14 字节不同,和 name serial 都有关,而且变化很大
    • 估计是从 des 出来的,不过无所谓
  • fbff0 是读写 pipe 的 buf
  • fc0f0 存放着 serial hex 原文

变化中的“低 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())

答案:42A4ECA067F54074C3EB2F177ACB06FE1379055CD4FB2211C3BD874FAD9E101D


 

吐槽:感觉比起春季赛,反调试保护似乎并没有太多变化。算法大概是增强了,但是只有 name 做了非线性的运算,一通处理算出来的结果和 serial 用稀奇古怪的方法做一些线性比较,导致最后的解法也基本没有变,感觉几乎是原题了。搜 wp 搜晚了,再摆摆烂,分数就只有一半了5555


看雪招聘平台创建简历并且简历完整度达到90%及以上可获得500看雪币~

最后于 2022-11-21 06:05 被tkmk编辑 ,原因:
收藏
点赞1
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回