本帖最后由 昨夜星辰恰似你 于 2020-6-23 10:02 编辑
java层
首先把apk拖到jeb或者其他java反编译工具查看
可以看到onClick和checkFlag是native方法
so层
看下init段有没有初始化函数
知道so加载的时候init_array数组中的函数会先于jni_onload方法执行,原理就去看看安卓linker源码吧(不熟悉安卓)
看到定义了一个sub_4DF0函数
初始化了一些全局变量就没了,基本没啥用,忽视
看jni_onload函数
很多符号和全局变量我都做了重命名,方便理解
其中函数sub_6A04作用是初始化和创建后面需要用到的j一些java类
这些符号我都做了对应的重命名
其实上面说的这些和解出这道题关系不大,只是刚接触安卓为了搞懂这些东西的作用
看onclick方法
获取了编辑框输入然后调用checkFlag方法验证
checkFlag算法首先把下面这个字符串分为三个部分
thisiskey52pojie_2020_happy_chinese_new_year20200125
用伪代码表示
StringBuilder s1=new StringBuilder("thisiskey");
StringBuilder s2=new StringBuilder("52pojie_2020_happy_chinese_new_year");
StringBuilder s3=new StringBuilder("20200125");
然后利用s2和s3计算出另一个中间字符串
具体算法是循环35次,每次循环取一个字符,如果本次计数器是能被4整除就从s3中亦或取字符,如果不是就s2中取字符
for (int i=0;i<35;i++){
if ((i%4==0)&&(i!=0)){
int index=((i>>2)-1);
System.out.println(i);
char c=s3.charAt(index);
tmp1.append(c);
}else {
tmp1.append(s2.charAt(i));
}
}
最后计算tmp1的md5值,注意的是并不是已经转换成16进制字符串的32位字符MD5,而是经过md5运算得到的长度为16的byte数组,然后把md5字节数组和s1字符串取余亦或得到16字节的数组,在转换成32位16进制字符串T,取中间第二位到倒数第二位字符串,也就是T[1:31]共30位字符串和输入字符串比较
完整Java代码如下
static void PrintHex(byte[] buff){
System.out.print("char data[]={");
for (int i=0;i<buff.length;i++){
System.out.printf("0x%x,",buff[i]^0xFF);
}
System.out.print("}\n");
}
static void ctf(){
StringBuilder s1=new StringBuilder("thisiskey");
StringBuilder s2=new StringBuilder("52pojie_2020_happy_chinese_new_year");
StringBuilder s3=new StringBuilder("20200125");
StringBuilder tmp1=new StringBuilder();
for (int i=0;i<35;i++){
if ((i%4==0)&&(i!=0)){
int index=((i>>2)-1);
System.out.println(i);
char c=s3.charAt(index);
tmp1.append(c);
}else {
tmp1.append(s2.charAt(i));
}
}
System.out.println(tmp1.toString());
try {
byte[] buff=tmp1.toString().getBytes();
System.out.println(buff.length);
MessageDigest md5=MessageDigest.getInstance("MD5");
byte[] md5Bytes=md5.digest(buff);
System.out.println(toHex(md5Bytes));
byte[] s1_bytes=s1.toString().getBytes();
for (int i=0;i<md5Bytes.length;i++){
md5Bytes[i]^=s1_bytes[i%9];
}
PrintHex(md5Bytes);
PrintHex(s1_bytes);
System.out.println(toHex(md5Bytes));
System.out.println(toHex(md5Bytes).substring(1,31));
}catch (Exception se){
se.printStackTrace();
}
}
这道题就是用了java2C,Java层逻辑全部用NDK实现而已,如果有调试设备完全可以不用逆向什么算法,一步到位,动态跟踪也行,hook也行,因为最后出现了明文比较,算是这道题比较弱的地方。可惜回家没有带安卓调试机器,电脑上也没有安卓开发环境(懒得去折腾了),不然可以写xposed 插件+VirtulXposed免Root搞定,还是太菜了,刚学安卓,环境什么的折腾起来太费劲了
|