吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 3414|回复: 26
上一主题 下一主题
收起左侧

[CTF] 2024年答题红包小白遇入坑记(补入坑后记)

[复制链接]
跳转到指定楼层
楼主
nanaqilin 发表于 2024-3-1 20:38 回帖奖励
本帖最后由 nanaqilin 于 2024-3-3 09:31 编辑

今年第一次参加这个活动,感觉题目分析起来对我来说还是有难度的,并且也遇到了好多困惑,同时看别的大神的解题思路,感觉收获还是很多的
  • 下面来看一下windows简单题一

解题方法有很多种,比如下断点,直接跟,就会出正确答案,但是,那不是我的目的,我的目的就是想分析代码

箭头部分明显看上去像一个加密后的字串,并且长度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,这个选择就是实现自动解密的功能,这里我们需要关掉它,避免影响机缘大道


然后再进行反编译,这时候真实的大道机缘就出现啦

所以,机关算计太聪明,反害了卿卿性命。谢了,玄天帝!

免费评分

参与人数 12威望 +1 吾爱币 +31 热心值 +10 收起 理由
基不洛基 + 1 热心回复!
chensir01 + 1 + 1 我很赞同!
局外人K + 1 + 1 我很赞同!
ingsston + 1 + 1 热心回复!
wang380006 + 1 + 1 我很赞同!
diaoes + 1 + 1 谢谢@Thanks!
seatop + 1 + 1 谢谢@Thanks!
mzmo + 1 用心讨论,共获提升!
kolt1911 + 1 + 1 我很赞同!
为之奈何? + 1 + 1 我很赞同!
peiki + 1 + 1 我很赞同!
正己 + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

推荐
 楼主| nanaqilin 发表于 2024-3-3 11:40 |楼主
fireshark 发表于 2024-3-3 11:28
俺成麻瓜了,怎么分析关键入口的

你说是windows程序,还是安卓的程序,windows程序的话,通过定位字符串,比如那个"success",还有一种方法,就是动态分析程序运行的过程。
说起来简单,其实真正调起来还是有难度的,由其是分析代码和找关键函数这块,这个就是多练习吧,因为程序的写法并不是都相同的。
安卓程序方法很多,不过大部分还是需要配一定的环境,比如MT,核心破解啥的,如果没有加混淆的话,看代码还是挺方便的,这毕竟直接可以反编成JAVA代码,不像汇编那么难读。
推荐
 楼主| nanaqilin 发表于 2024-3-1 23:00 |楼主
正己 发表于 2024-3-1 21:54
照葫芦画瓢,现在还是能唤醒沉睡的玄天帝的

照着做就算了吧。等有时间了,我研究研究。我的想法是把源码导出来,然后放在另一个工程跑,通过修改代码的方式,直接修复dex。或者照源码写点JAVA代码,直接把DEX修复了。我是程序员,还是用程序员的方式来解决吧

点评

那也很简单,扣出来就能跑,也没混淆  详情 回复 发表于 2024-3-1 23:27
沙发
正己 发表于 2024-3-1 21:54
照葫芦画瓢,现在还是能唤醒沉睡的玄天帝的

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
SVIP9大会员 + 1 + 1 用心讨论,共获提升!

查看全部评分

3#
yaojia 发表于 2024-3-1 22:53
谢谢楼主大人
5#
正己 发表于 2024-3-1 23:27
nanaqilin 发表于 2024-3-1 23:00
照着做就算了吧。等有时间了,我研究研究。我的想法是把源码导出来,然后放在另一个工程跑,通过修改代码 ...

那也很简单,扣出来就能跑,也没混淆
6#
爱飞的猫 发表于 2024-3-2 00:12
默认的情况编译器应该不会用SIMD来优化代码,很有可能是作者故意加的。


其实是编译器自动优化的。使用 Release 模式编译的基本上都会尝试(-O2 等级的优化)。这个函数的顶部有个全局变量是用来检测 CPU 是否支持这些指令,如果不支持也会直接跳到下面这个 for 循环里面。
7#
 楼主| nanaqilin 发表于 2024-3-2 06:10 |楼主
爱飞的猫 发表于 2024-3-2 00:12
其实是编译器自动优化的。使用 Release 模式编译的基本上都会尝试(-O2 等级的优化)。这个函数的顶部 ...

涨知识了,我做算法优化,都是手动改成simd
8#
zwtstc 发表于 2024-3-2 11:14
学到了,感谢
9#
fstgw 发表于 2024-3-2 11:46
学习了,感谢楼主。
10#
seatop 发表于 2024-3-2 14:34
学习学习,谢谢楼主
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-23 00:48

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表