记录一下在BUUCTF Mobile方向中做过的题。
1. 相册(四大组件)
Android四大组件之一——Service
启动M2服务,注册内容。读取短信收件箱中以消息序号降序的第一条消息序号(猜测是最新的)、手机号、短信内容,并且监听短信数据库变化。
Content Provider
短信操作
BroadCast Receiver详解
AlarmManager的setRepeating的用法-闹钟/定时器
android 4.4 设置默认短信 和来电短信拒接
设置本应用为默认短信应用,向通讯录里的所有号码发送钓鱼短信。
用ContentProvider获取通讯录联系人
TelephonyManager
向某个号码(病毒开发者)发送本机设备id短信,表示这台手机已安装了本应用。
将本机的所有短信记录发送到某个邮箱当中。
回到C1.class
看MailTask,将本机的所有联系人备注及手机号发送到某个邮箱中。
继续看check()
,获取设备管理权限,加载WebView页面。
Android设备管理器DevicePolicyManager的使用和理解
但这个WebView页面现在已经无了。分析到这里,发现flag就是病毒开发者邮箱。
2. PixelShooter
这个是Assembly-CSharp.dll
类的unity3D游戏。将APK直接用jeb打开,在Assembly-CSharp.dll
中搜索关键字符串即可。
具体如何分析一个unity3D游戏再说吧…
3. Strange apk(加固APK的执行流程)
查看sctf.demo.myapplication.c
发现继承了Application类,并重写了Application.attachBaseContext()
和Application.onCreate()
方法。
Android app的启动流程
对于整体加密壳,它在运行时解密,在Application.attchBaseContext()
和Application.onCreate()
中必须要完成对加密Dex的动态加载和解密,得到源Dex,才能保证源APK的正常运行。
将解密函数拷贝下来,运行一下得到解密Dex。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| import java.io.File; import java.io.FileOutputStream; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream;
public class datong{ public static byte[] __(String fileName) throws IOException { InputStream in = new FileInputStream(fileName); int lenght = in.available(); byte[] buffer = new byte[lenght]; in.read(buffer); in.close(); return buffer; }
private static byte[] _0_(byte[] srcdata) { for (int i = 0; i < srcdata.length; i++) { srcdata[i] = (byte) ("syclover".charAt(i % "syclover".length()) ^ srcdata[i]); }
return srcdata; }
private static void _(byte[] apkdata) throws IOException { byte[] apkdata2 = _0_(apkdata); File file = new File("srcdata.apk"); try { FileOutputStream localFileOutputStream = new FileOutputStream(file); localFileOutputStream.write(apkdata2); localFileOutputStream.close(); } catch (IOException localIOException) { throw new RuntimeException(localIOException); } }
public static void main(String[] args) throws IOException{ byte[] bytes = __("data"); _(bytes); } }
|
分析脱壳后的APK:
已知flag一部分为sctf{W3lc0me
,剩下那部分与key进行加密。根据encode()
函数编写decode()
函数。
所以完整flag为sctf{W3lc0me~t0_An4r0id-w0rld}
。
4. app-debug(TEA加密)
java层,简单。
So,在.init_array()
中做了TracerPid反调试。
再看关键的check()
函数:
看wp说这是TEA加密,属于分组加密算法。想要逆向,就必须要知道其DELTA值与key,以及加密后的密文。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| from ctypes import * def encrypt(v,k): v0=c_uint32(v[0]) v1=c_uint32(v[1]) sum1=c_uint32(0) delta = 0x458BCD42 for i in range(32): sum1.value+=delta v0.value+=((v1.value<<4)+k[0])^(v1.value+sum1.value)^((v1.value>>5)+k[1]) v1.value+=((v0.value<<4)+k[2])^(v0.value+sum1.value)^((v0.value>>5)+k[3]) return v0.value,v1.value def decrypt(v,k): v0=c_uint32(v[0]) v1=c_uint32(v[1]) delta = 0x458BCD42 sum1=c_uint32(delta*32) for i in range(32): v1.value-=((v0.value<<4)+k[2])^(v0.value+sum1.value)^((v0.value>>5)+k[3]) v0.value-=((v1.value<<4)+k[0])^(v1.value+sum1.value)^((v1.value>>5)+k[1]) sum1.value-=delta return v0.value,v1.value if __name__=='__main__': a=[0xF5A98FF3,0xA21873A3] k=[9,3,2,1] print("加密前数据:",a) res=encrypt(a,k) print("加密后的数据:",res) res=decrypt(res,k) print("解密后数据:",res)
|
发现并不是可输入字符串,说明在解密过程中出错了。由于delta值固定,所以猜测是key的问题。查看交叉调用,发现在.init_array()
中不仅做了反调试操作,还改变了key值。
又由于每个数都是小端存储,所以正确input应该是GKcTFg0
,回到Java层看到提示,对其进行MD5加密为77bca47fe645ca1bd1ac93733171c9c4
。
1
| flag{77bca47fe645ca1bd1ac93733171c9c4}
|
5. [FlareOn2]Android
查看Native层函数,如果v7能整除v14,则v16[j]++。
sorry看不懂。
6. [WMCTF2020]easy_apk
查看Java层:
Android 关于ApplicationInfo flags
查看So层,.init_array()
做了一个Frida检测:
Native层的stringFromJNI()
函数的作用是设置字符串“check”。进入JNI_OnLoad()
:
我们发现Class类名被加密了,查看String窗口其实很多字符串都被加密了,都是用这个函数加密。由于本人实在看不懂,这道题GG