android ctf 分析,[原创]记一道Android CTF题

一、题目

wmctf2020 reverse easy_apk

题目地址:

https://adworld.xctf.org.cn/match/contest_challenge?event=146&hash=684a58cc-1140-4937-99f2-ef347d777d9f.event

考查知识点:

1、算法识别

2、动态调试这道题之前有大佬在论坛发过,但是后来看不到了,这里记录一下个人做题的过程和遇到的问题,不喜勿喷。

二、解题过程

1、java层jadx

5d59d040440cadb8e23d6ec6d83b8371.png

jeb

f035165b6cf53149aa0af746cb841612.png

手机上有面具的可以新建个android工程,引入so进行调试

748d2670ca897bda9fbf95146dfaacc6.png

2、native层

(1)check方法定位方法一

静态分析 jnionload

修复前(未导入jni.h)

9f57c76478a848437867ee03318b73b4.png

修复后(导入jni.h)

579a0d107bab9cc31d97da196c6d59a6.png

查看methods

8653ef4bc924a5c7617eabf3b9e27fad.png

check->sub_10F00方法二

使用frida动态hook RegisterNatives

[RegisterNatives] java_class: com.WM.one.Native name: check sig: (Ljava/lang/String;)Z fnPtr: 0x72afe26f00 module_name: libnative-lib.so module_base: 0x72afe16000 offset: 0x10f00

(2)init_array

caa11ce49e39a66f4e53d72e23e6f520.png

sub_D994中会kill进程

unsigned __int64 __fastcall sub_D994(__pid_t a1, int a2)

{

unsigned __int64 result; // x0

unsigned __int8 v3; // cf

bool v4; // zf

result = linux_eabi_syscall(__NR_kill, a1, a2);

v3 = __CFADD__(result, 0x1000LL);

v4 = result == 0xFFFFFFFFFFFFF000LL;

if ( result > 0xFFFFFFFFFFFFF000LL )

result = !result;

if ( !v4 & v3 )

{

*(_DWORD *)__errno() = result;

result = 0xFFFFFFFFFFFFFFFFLL;

}

return result;

}这里需要path so 让kill不成功,使用 RET C0 03 5F D6 让方法不执行或者nop方法体

path前

2eaacaabee043ea50bd1ce950e4a7b0a.png

path后

33c8c7ba53453569347c7ab7fee5fcff.png

F5

dafd0d43162be8489ecca0714f98ded9.png

(3)算法识别

在sub_10F00中

65d000ef93c40e980bef1e369fb020a7.png

这里调试的时候有固定的组数赋值

7405b40b4fcead51a4da52ecf7ba9358.png

搜索了一下,百度告诉我们这是zuc算法

2165374e4743f4acfc177e25e9eec814.png

这是一个对称算法

(4)动态调试sub_10D24对应是zuc的解密算法,由于是对称加密,可以使用加密后的字节进行解密获得flag,在网上看了一下zuc算法的计算过程,这里有py的实现 https://baike.baidu.com/item/%E7%A5%96%E5%86%B2%E4%B9%8B%E7%AE%97%E6%B3%95%E9%9B%86/7177910?fr=aladdinif '__main__' == __name__:

key = [0x00] * 16

iv = [0x00] * 16

zuc = ZUC(key, iv)

# 加密过程

out = zuc.zuc_encrypt(b"i love u")

print("加密得到的字流", ["%08x" % e for e in out])

# 解密过程

zuc2 = ZUC(key, iv)

out2 = zuc2.zuc_encrypt(out)

print("解密得到的字流", ["%08x" % e for e in out2])

print(bytes(out2))

根据算法,需要找到 IV KEY 加密字节 就可以得到flag

IV

ee4e2ad68a407c8ffc8a5688123aa064.png

KEY

93267108586c3337626e4c52252b78cd.png

0000007FF0435C00 IV

0000007FF0435C10 KEYzuc_encrypt

91db51a48cbc576cc66badcdc705c830.png

zuc_encrypt(v7, (__int64)&key, 354339, 24, 1, 256, (unsigned __int64)&src, (unsigned __int64)&encode);

3ad67ef27e0d8f160ad8450355ce70d2.png

src 是 01234567890123456789012345678912

encode

75d59e28aeef12d610d26692bcc35a69.png

然后再调试一边,用encode替换src,看看是否是原来的src,但是结果不正确,经过反复调试,发现IV是固定的,但是KEY是变化的,看了一下key赋值的过程,发现TracerPid是生成key的一部分

3cf1583f2e7957bbc469bcbc276f7640.png

5558ae323fc40f4ff7a77a400fbf8223.png

调试的时候TracerPid 不为0,正确的KEY是TracerPid = 0的时候算出来的TracerPid 修改为0 得到正确的key

9875235d8ed81d17ad2854bd2e5dceef.png

F2修改内存值

bc32740dd3246f7b0d9211fa4fd7ad6e.png

而最后要对比的字节应该是

v11 = unk_296C0;

v12 = unk_296D0;

result = (unsigned int)sub_DB8C(&v11, &encode, 0x20LL) == 0;0x2B, 0x31, 0xA9, 0x7F, 0x7A, 0x85, 0x71, 0xED, 0x06, 0x83, 0x72, 0xDB, 0x52, 0xC5, 0xC9, 0xCD,

0xC2, 0x2A, 0x66, 0xF0, 0x46, 0xAF, 0x9A, 0x5F, 0xA6, 0x5F, 0x63, 0xB2, 0x3B, 0x2E, 0x8B, 0xCA按之前的思路,将加密字节当做src来调试

3f4b5ff512e22bfcd042412d2eddbcf0.png

获得flag W3lcomeT0WMCTF!_*Fu2^_AnT1_32E3$

adf2eadb3c43ead029d45963c30f1df7.png

三、总结

1、算法识别这块搜索大法

2、学习了zuc算法

最后于 2020-8-12 18:35

被neilwu编辑

,原因:

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值