本帖最后由 nanaqilin 于 2024-3-3 09:31 编辑
今年第一次参加这个活动,感觉题目分析起来对我来说还是有难度的,并且也遇到了好多困惑,同时看别的大神的解题思路,感觉收获还是很多的
解题方法有很多种,比如下断点,直接跟,就会出正确答案,但是,那不是我的目的,我的目的就是想分析代码
箭头部分明显看上去像一个加密后的字串,并且长度0x24转成10进制是36,跟下边字串的长度也是一致的。
其中我遇到的第一个坑就是,sub_401FE0这个函数,分析出来它应是一个关键的函数,但是IDA第一次加载程序,转C代码的时候,这个函数没有传值,当时瞬间懵逼,这怎么搞,明明里面还用到参数了。
瞬间放弃了,等第二天再次打开IDA,加载以前的数据时,神奇的是有传参了,心情突然就又好了。于是乎可以继续分析。
好加伙,上来就一堆这个,这是啥算法,这么复杂,瞬间又蒙圈了。往后边啪啦啪啦,突然间看到了希望
我神奇的发现,原来下面还有一段上面代码的重新实现,马上心情又好了,这样回头看上面的代码,发现那堆_mm的函数其实是simd失量寄存器的优化代码。
这里,__m128i 类型的变量将在 16 字节边界上自动对齐。
若是16字节的short数据,一次可以并行8个数据运算处理,32字节的int数据,可以同时运算4个。
这样可以成倍的提高运算速度,默认的情况编译器应该不会用SIMD来优化代码,很有可能是作者故意加的。
由于都是一组一组的进行运算,要么4的倍数,要么8的倍数,,作者这个看上去像是8。这样剩余的部分就得用正常的方法来运算,也就出现了咱们想要看到的代码。
于是乎,开始编代码解密,这里就遇到了一个新的坑。
#include <cstdio>
#include <cstring>
unsigned char aIocjKcssBq6zbh[] = {
0x69, 0x6F, 0x43, 0x6A, 0x7E, 0x4B, 0x43, 0x73, 0x73, 0x7C, 0x62, 0x51,
0x36, 0x7A, 0x62, 0x68, 0x43, 0x75, 0x24, 0x35, 0x72, 0x35, 0x37, 0x24,
0x49, 0x6C, 0x6A, 0x6B, 0x77, 0x6C, 0x71, 0x6A, 0x24, 0x24, 0x24, 0x80,
0x00, 0x00, 0x00, 0x00, 0xA1, 0xBE, 0x32, 0x30, 0x32, 0x34, 0xB4, 0xBA};
int main(int argc, char *argv[]) {
const char *encode ="ioCj~KCss|bQ6zbhCu$5r57$Iljkwlqj$$$?" ;
char decode[200];
memset(decode, 0x00, sizeof(decode));
int len = 36;
for (int i = 0; i < len; i++) {
decode[i] = encode[i] + (-3 % 26);
}
printf("%s\n", decode);
printf("\n============\n");
memset(decode, 0x00, sizeof(decode));
for (int i = 0; i < len; i++) {
decode[i] = aIocjKcssBq6zbh[i] + (-3 % 26);
}
printf("%s\n", decode);
return 0;
}```
直接把字符串解码竟然乱码了,抓狂,只能用我新学的复制Shift+E,复制16进制字串到C大法,重新来了一个,终于出来结果了,真是要了半条命了。
从来没逆过Android的我,现学现卖吧,还好JEB够强大,直接反编译出源码
还好懂点JAVA代码,这段代码的大致意思就是,在ys.mp4那个文件中的最后30个字节(s1)处,找到v2,即"flag{"打头的字串索引,然后得出s2,以“flag{”开头,以“}”结尾。
用JEB直接打开mp4文件,即可找到答案,不得不说,这是我最顺利的一次,很开心,然后立即下一题。
直接复制前面的经验,JEB走起,找到位置
看上去比上一题还要简单一些,然后我就准备解密,于是乎又掉坑里了。
Signature[] arr_signature = this.getPackageManager().getPackageInfo("com.kbtx.redpack_simple", 0x40).signatures;
这句代码就是获取包的签名,需要找到这个签名,这玩艺儿去哪里找啊,于是乎就各种试,先是用签名文件的MD5,然后就SHA1,还有HEX,发现都不对
后来查了查说是用签名文件本体字串就行,于是乎就用本体字串,发现还是不行。然后就卡了一天。
第二次,再看时,发现这个APK里有两个文件,还有一个V2的
我的那个亲娘啊,现在APK都玩的这么花了吗?话不多说,上代码吧
#include <stdint.h>
#include <cstdint>
#include <cstdio>
int8_t code[] = {86, -18, 98, 103, 75, -73, 51, -104, 104,
94, 73, 81, 0x7D, 0x76, 0x70, 100, -29, 0x3F,
-33, -110, 108, 0x73, 51, 59, 55, 52, 77};
uint8_t sig[] = {0x30, 0x82, 0x03, 0x00, 0x30, 0x82, 0x01, 0xE8, 0x02, 0x01,
0x01, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7,
0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, 0x30, 0x46, 0x31, 0x10,
0x30, 0x0E, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0C, 0x07, 0x6B,
0x62, 0x74, 0x78, 0x77, 0x65, 0x72, 0x31, 0x10, 0x30, 0x0E,
0x06, 0x03, 0x55, 0x04, 0x0B, 0x0C, 0x07};
int main(int argc, char *argv[]) {
int len = sizeof(code);
int sig_len = sizeof(sig);
for (int i = 0; i < len; i++) {
uint8_t c = (uint8_t)code[i] ^ sig[i % sig_len];
printf("%c ", c);
}
printf("\n");
return 0;
}
到这里我的答题之旅就结束了,但不得不说,Android中级题才是我遇到的更大的坑,结果没公布之前,一直没搞明白作者到底想做啥,因为总报classdex出错。
我就想啊,是不是我手机问题,于是乎我就上模拟器,找别的手机,反正就是各种试,结果就总是一个样。
然后我就用JEB各种看源码,看逻辑,我神奇的找到了1234这个初始密码,当时心理别说有多开心,赶紧试一哈。
结果,锁是绿了一下,但玄天帝似乎真的睡死了,没反应,5555
这让我寝食难安,苦啊,玄天帝命苦啊,我就想啊,要是荒仙帝在的话,会不会能解锁呢,5555后记:
按版主的意思,继续找我寻找的机缘。。。
然后继续遇坑,既然作者就是让咱们把那个classdex给修复,首先我的思路就是把JAVA代码复制出来,然后自动修复一下,导出来分析。说干就干
分析部分就不讲了,好多大佬都已经讲过了,我直接上我的小白版代码
public static File fix(ByteBuffer byteBuffer0, int v, int v1, int v2, Context context0) throws Exception {
try {
//File file0 = context0.getDir("data", 0);
File file0 = new File("/sdcard/Download");
int v3 = (int)(((Integer)D.[i]getClassDefData(byteBuffer0, v).get("class_data_off")));
HashMap hashMap0 = D.[i]getClassData(byteBuffer0, v3);
((int[][])hashMap0.get("direct_methods"))[v1][2] = v2;
byte[] arr_b = D.[i]encodeClassData(hashMap0);
byteBuffer0.position(v3);
byteBuffer0.put(arr_b);
byteBuffer0.position(0x20);
byte[] arr_b1 = new byte[byteBuffer0.capacity() - 0x20];
byteBuffer0.get(arr_b1);
byte[] arr_b2 = Utils.[i]getSha1(arr_b1);
byteBuffer0.position(12);
byteBuffer0.put(arr_b2);
int v4 = Utils.[i]checksum(byteBuffer0);
byteBuffer0.position(8);
byteBuffer0.putInt(Integer.[i]reverseBytes(v4));
byte[] arr_b3 = byteBuffer0.array();
File file1 = new File(file0, "2.dex");
FileOutputStream fileOutputStream0 = new FileOutputStream(file1);
fileOutputStream0.write(arr_b3);
fileOutputStream0.close();
return file1;
}
catch(Exception exception0) {
exception0.printStackTrace();
return null;
}
}
public static ByteBuffer read(String filename) {
try {
//File file0 = new File(context0.getDir("data", 0), "decode.dex");
File file0 = new File("/sdcard/Download",filename);
if(!file0.exists()) {
Log.[i]e([i]TAG,file0.getAbsolutePath().toString()+" does not exit");
return null;
}
FileInputStream fileInputStream0 = new FileInputStream(file0);
byte[] arr_b = new byte[fileInputStream0.available()];
fileInputStream0.read(arr_b);
ByteBuffer byteBuffer0 = ByteBuffer.[i]wrap(arr_b);
fileInputStream0.close();
return byteBuffer0;
}
catch(Exception unused_ex) {
Log.[i]e([i]TAG,unused_ex.toString());
return null;
}
}
// 这个是调用上面的方法
binding.fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.[i]make(view, "Replace with your own action", Snackbar.[i]LENGTH_LONG)
.setAnchorView(R.id.[i]fab)
.setAction("Action", null).show();
try {
//C.fix(C.read("classes.dex"),0,3,7908,MainActivity.this);
C.[i]fix(C.[i]read("classes.dex"),1,1,8108,MainActivity.this);
} catch (Exception e) {
Log.[i]e("zj",e.toString());
}
}
});
我的代码主要思路就是,将classes.dex传到Dowload文件夹中,然后执行修复,然后把2.dex给拉回来反向分析。
上传classes.dex可以用工具,也可以用命令
adb push classes.dex /sdcard/Download
```
拉取的命令为
adb pull /sdcard/Download/2.dex
运行上面的代码段,需要注意的问题是,首先测试的App需要有存储的权限,注意现在的Android版本都需要动态获取权限才行的。
还有就是需要用到反编译出来的D.java和Utils.java,其中Utils.java有一个MD5函数有问题,需要手动修复一下。
public static String md5(byte[] arr_b) {
int v;
try {
String s = new BigInteger(1, MessageDigest.[i]getInstance("md5").digest(arr_b)).toString(16);
v = 0;
while(true) {
if(v >= 0x20 - s.length()) {
return s;
}
s = "0" + s;
++v;
}
}
catch(NoSuchAlgorithmException unused_ex) {
throw new RuntimeException("ops!!");
}
}
这回子玄天帝应该就醒了吧,可但是看一下结果
再一次哭了,看来我不是荒,我可能真的没有大道机缘,55555
试了好几次,依旧如此,莫说大道机缘,咋给点小道消息也不往我写了一天的代码啊,55555
冷静,一定要冷静,看了一眼smali是对的,那就说明只是缘份还没到,那就再等等吧
话说,又过了一天,睡了一觉,继续寻找我的机缘。
其实结合smali来仔细琢磨一下玄帝给的机缘,看上去好好像是已经直接算好了。
还是玄帝对我好啊,怕我不会算,直接帮我算出来了,还好时机已过,要不我非得拿这个提交上去,然后结果不对,找管理理论{:1_918:}
既然玄帝如此不靠谱,咱们还是自己来找方案吧。
在这个地方,右键,选择第二项,点进去
把这个改成disable,这个选择就是实现自动解密的功能,这里我们需要关掉它,避免影响机缘大道
然后再进行反编译,这时候真实的大道机缘就出现啦
所以,机关算计太聪明,反害了卿卿性命。谢了,玄天帝! |