首页
社区
课程
招聘
[原创]全国大学生软件安全攻防赛初赛wp
发表于: 2025-1-11 18:46 8560

[原创]全国大学生软件安全攻防赛初赛wp

2025-1-11 18:46
8560

base64一长串一看就不正常,大概是个文件,cybercgef解码下然后保存为文件。

010看了下

PK头,zip吧。。。

解压发现需要密码,找了个工具按纯数字试了下,爆出密码,不记得了,好几天前了。

总之解压出一个exe。

exe加壳,动调了一会,看规律大概是upx,于是直接esp大法dump。

字符串找了一会没有发现像ip端口的字符串,于是尝试wireshark抓包。

这里直接在主机运行了现在有点后怕。。。

在java层看了一下,有控制流平坦化混淆(我不太清楚,看的很像那种native层加的ollvm混淆)

好像jeb可以写脚本去除,但是我还没有研究过,有时间再说叭。

字符串采取标准base64加密

不过稍微扫几眼还是能看出点东西的,大概加载了一个dex,里面应该有一些关键逻辑。

HOOK了一下dexloader函数发现加载的是check类,对这个类的cmp方法HOOK也是可以HOOK到的。

但是用frida-dump无法dump出有效的dex。

于是打算直接HOOK到的同时dump一下,这里直接让gpt写了一个脚本。

然后成功dump了下来

但是还是无法正常分析。

看到了native方法的字样,于是想着native层确实还没看,这里因为native层的字符串也有加密,我记得是有来着,所以我采取的是直接用frida_dump-master dump so。

哦,然后看完就知道它在干什么了,说来惭愧,确实这么久了还没看脱壳是一款我的问题。。

所以这里就稍微详细点说吧。

这里直接看JNI_ONLOAD函数。主要调用了三个函数,一个一个分析。

126A8虽然一开始看不出来在干什么,但是看到最后的字符串就明白了,这是shadowhook的初始化。

同时从这里得到的信息去查找shadowhook,明白这是一个关于inlinehook的项目。

ef3K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6T1P5i4c8W2k6r3q4F1j5$3g2Q4x3V1k6S2L8X3c8J5L8$3W2V1i4K6u0V1K9h3&6D9K9h3&6W2i4K6u0V1K9r3!0G2K9#2)9J5c8X3u0D9L8$3u0Q4x3V1k6E0j5h3W2F1i4K6u0r3f1V1g2m8c8p5#2q4i4K6u0W2P5X3S2Q4x3X3c8o6e0W2)9J5k6h3#2V1

接着看第二个函数12300

看到这么简短的操作,以及函数的参数,大致能猜到这是一个HOOK的过程。

至于具体的操作,则是HOOK了libcso中的execve,这是一个创建新进程的函数。

而替换它的函数是根据判断是否是有dex2oat字符串来决定是否执行原来的execve函数。

接着往下看,最后一个函数sub_12324。

首先是调用了sub_1216C。

判断版本号返回不同字符串。

所以它返回的实际上应该是loadmethod这个方法。

然后在下一步再进行HOOK。

然后去搜索了一下对loadmethod进行HOOK的这个操作,明白了这是在实现函数抽取壳,也就是二代壳。

这里也明白了前面对execve HOOK的原因。

文章:dd3K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6G2L8X3g2B7j5h3&6W2i4K6u0W2k6$3W2@1K9s2g2T1i4K6u0W2K9h3!0Q4x3V1j5J5x3o6t1I4i4K6u0r3x3o6y4Q4x3V1j5J5y4g2)9J5c8W2)9J5y4f1f1#2i4K6t1#2z5p5q4Q4x3U0g2m8x3q4)9J5y4f1f1#2i4K6t1#2b7e0y4Q4x3U0g2n7x3#2)9J5y4f1f1@1i4K6t1#2b7U0S2Q4x3U0f1^5c8g2)9J5y4f1f1^5i4K6t1#2z5o6c8Q4x3U0g2n7x3g2)9J5y4f1f1#2i4K6t1#2b7e0y4Q4x3U0g2n7x3#2)9J5y4f1f1@1i4K6t1#2b7U0W2Q4x3U0f1^5b7W2)9J5y4f1f1@1i4K6t1#2b7V1q4Q4x3U0f1^5b7#2)9J5y4f1f1@1i4K6t1#2b7V1u0Q4x3U0g2m8x3#2)9J5y4f1f1#2i4K6t1#2b7e0y4Q4x3U0g2n7x3#2)9J5y4f1f1#2i4K6t1#2z5o6N6Q4x3U0g2n7c8q4)9J5y4f1f1$3i4K6t1#2z5e0g2Q4x3U0g2n7x3q4)9J5y4f1f1$3i4K6t1#2z5p5q4Q4x3U0g2n7c8q4)9J5y4f1f1#2i4K6t1#2z5p5k6Q4x3U0f1&6y4W2)9J5c8W2)9J5x3#2)9J5y4f1f1$3i4K6t1#2b7V1q4Q4x3U0f1&6x3q4)9J5y4f1f1%4i4K6t1#2b7e0m8Q4x3U0f1^5x3g2)9J5y4f1f1#2i4K6t1#2z5o6S2Q4x3U0f1^5y4W2)9J5y4f1f1$3i4K6t1#2z5f1g2Q4x3U0f1&6x3l9`.`.

再看下替换成的函数。

唔,这里看到memcpy再结合函数抽取壳的思想就突然明白它在干什么了,它在把字节填充回去。

用010看一下之前dump的dex。

发现果然有一连串0,然后长度就是152.

所以填充回去即可。

以及下面的12345678也替换为Crackme!

实际的比较函数。

解出flag。已经是赛后了,不清楚对不对。

分析代码逻辑,多次调试大致明白他的思路,有一个结构部分收录了要用到的函数,然后再从中取来调用,完成rc4的加密和比较。


最终比较的密文

很多函数都加了花指令,nop即可,范围的判断是push rax到pop rax。

两个比较关键的函数,上面那个是密钥的S盒生成,byte数组就是key,14位。

然后对byte交叉引用的时候发现有第二个调用的地方,猜测是反调试,于是只取静态下的值。

然后大概有点异或之类的魔改,看了下主要的加密逻辑,

最后加密的那一句有一个异或0x23.

解密脚本:

得出flag:

都不是很难的题叭,附件超大小了,放云盘了,师傅们感兴趣的可以自己试试水。
其实这个发看雪感觉有点水。。但是我自己也太懒了没搭博客所以就发这里叭呜呜。
通过网盘分享的文件:软件安全攻防赛.zip
链接: 5a2K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6H3j5h3&6Q4x3X3g2T1j5h3W2V1N6g2)9J5k6h3y4G2L8g2)9J5c8Y4y4Q4x3V1j5I4y4e0b7@1h3i4g2V1M7Y4t1#2f1K6N6o6y4r3N6S2f1s2N6D9P5g2W2G2b7g2)9K6c8Y4m8%4k6q4)9K6c8s2u0W2j5e0p5`. 提取码: rea1
--来自百度网盘超级会员v4的分享

Java.perform(function () {
    console.log("[*] Frida 脚本已加载,开始 Hook DexClassLoader 并尝试dump dex文件...");
 
    try {
        // 获取 DexClassLoader 类
        var DexClassLoader = Java.use("dalvik.system.DexClassLoader");
        console.log("[+] 找到 dalvik.system.DexClassLoader 类");
 
        // Hook DexClassLoader 的构造函数
        DexClassLoader.$init.overload(
            'java.lang.String',    // dexPath
            'java.lang.String',    // optimizedDirectory
            'java.lang.String',    // libraryPath
            'java.lang.ClassLoader'// parent
        ).implementation = function (dexPath, optimizedDirectory, libraryPath, parent) {
            console.log("[*] DexClassLoader 构造函数被调用 >>>");
            console.log("    dexPath: " + dexPath);
            console.log("    optimizedDirectory: " + optimizedDirectory);
            console.log("    libraryPath: " + libraryPath);
            console.log("    parent: " + parent);
 
            // ========== 关键:尝试dump dex文件 ==========
            // 如果 dexPath 实际上在磁盘上存在,我们可以尝试复制它
            // 注意:某些应用可能会瞬时删除或仅在内存中解密dex,这种情况下物理文件可能并不存在
 
            dumpDexToExternal(dexPath);
 
            // 调用原始构造函数
            return this.$init(dexPath, optimizedDirectory, libraryPath, parent);
        };
 
        // Hook DexClassLoader 的 loadClass 方法(可选,用于观察加载的类)
        DexClassLoader.loadClass.overload('java.lang.String').implementation = function (className) {
            console.log("[*] DexClassLoader.loadClass 被调用,加载的类名: " + className);
 
            // 调用原始 loadClass 方法
            var result = this.loadClass(className);
 
            // 可以在此处添加更多逻辑,如记录加载的类或执行其他操作
            return result;
        };
 
        console.log("[*] DexClassLoader 的构造函数和 loadClass 方法已成功 Hook");
    } catch (err) {
        console.error("[-] Hook DexClassLoader 失败: " + err.message);
    }
 
    // 简单枚举以确认 DexClassLoader 是否已加载
    Java.enumerateLoadedClasses({
        onMatch: function(className) {
            if (className === "dalvik.system.DexClassLoader") {
                console.log("[+] dalvik.system.DexClassLoader 已加载");
            }
        },
        onComplete: function() {
            console.log("[*] 已完成类的枚举");
        }
    });
 
    // ========== 文件复制函数 ==========
    // ========== 文件复制函数,修正后的示例 ==========
function dumpDexToExternal(dexPath) {
    if (!dexPath) {
        console.log("[-] dexPath为空,无法dump");
        return;
    }
 
    var File = Java.use("java.io.File");
    var FileInputStream = Java.use("java.io.FileInputStream");
    var FileOutputStream = Java.use("java.io.FileOutputStream");
    var Arrays = Java.use("java.util.Arrays");
 
    try {
        var dexFile = File.$new(dexPath);
        if (!dexFile.exists()) {
            console.log("[-] 目标 dex 文件不存在: " + dexPath);
            return;
        }
 
        var fis = FileInputStream.$new(dexFile);
 
        // 目标输出目录,可自行修改
        var outDirPath = "/sdcard/Download/dump_dex";
        var outDir = File.$new(outDirPath);
        if (!outDir.exists()) {
            var created = outDir.mkdirs();
            if (!created) {
                console.log("[-] 创建目录失败: " + outDirPath);
                fis.close();
                return;
            }
        }
 
        var timestamp = Date.now();
        var outDexPath = outDirPath + "/dump_" + timestamp + "_classes.dex";
        console.log("[*] 准备将 dex 复制到: " + outDexPath);
 
        var outFile = File.$new(outDexPath);
        var fos = FileOutputStream.$new(outFile);
 
        var chunkSize = 4096;
        // 正确创建长度为 chunkSize 的 byte[]
        function newByteArray(size) {
            var tmp = [];
            for (var i = 0; i < size; i++) {
                tmp.push(0);
            }
            return Java.array('byte', tmp);
        }
 
        var buffer = newByteArray(chunkSize);
        var bytesRead = 0;
 
        while (true) {
            bytesRead = fis.read(buffer, 0, parseInt(chunkSize));
            if (bytesRead <= 0) break// EOF
 
            // 若 read 返回的大小小于 chunkSize,需要截断写入
            if (bytesRead < chunkSize) {
                var actualData = Arrays.copyOf(buffer, bytesRead);
                fos.write(actualData, 0, parseInt(bytesRead));
            } else {
                fos.write(buffer, 0, parseInt(bytesRead)); // chunkSize 也是 int
            }
        }
 
        fis.close();
        fos.close();
 
        console.log("[+] Dex 文件已成功复制到: " + outDexPath);
    } catch (e) {
        console.log("[-] dumpDexToExternal 异常: " + e.message);
    }
}
 
});
Java.perform(function () {
    console.log("[*] Frida 脚本已加载,开始 Hook DexClassLoader 并尝试dump dex文件...");
 
    try {
        // 获取 DexClassLoader 类
        var DexClassLoader = Java.use("dalvik.system.DexClassLoader");
        console.log("[+] 找到 dalvik.system.DexClassLoader 类");
 
        // Hook DexClassLoader 的构造函数
        DexClassLoader.$init.overload(
            'java.lang.String',    // dexPath
            'java.lang.String',    // optimizedDirectory
            'java.lang.String',    // libraryPath
            'java.lang.ClassLoader'// parent
        ).implementation = function (dexPath, optimizedDirectory, libraryPath, parent) {
            console.log("[*] DexClassLoader 构造函数被调用 >>>");
            console.log("    dexPath: " + dexPath);
            console.log("    optimizedDirectory: " + optimizedDirectory);
            console.log("    libraryPath: " + libraryPath);
            console.log("    parent: " + parent);
 
            // ========== 关键:尝试dump dex文件 ==========
            // 如果 dexPath 实际上在磁盘上存在,我们可以尝试复制它
            // 注意:某些应用可能会瞬时删除或仅在内存中解密dex,这种情况下物理文件可能并不存在
 
            dumpDexToExternal(dexPath);
 
            // 调用原始构造函数
            return this.$init(dexPath, optimizedDirectory, libraryPath, parent);
        };
 
        // Hook DexClassLoader 的 loadClass 方法(可选,用于观察加载的类)
        DexClassLoader.loadClass.overload('java.lang.String').implementation = function (className) {
            console.log("[*] DexClassLoader.loadClass 被调用,加载的类名: " + className);
 
            // 调用原始 loadClass 方法
            var result = this.loadClass(className);
 
            // 可以在此处添加更多逻辑,如记录加载的类或执行其他操作
            return result;
        };
 
        console.log("[*] DexClassLoader 的构造函数和 loadClass 方法已成功 Hook");
    } catch (err) {
        console.error("[-] Hook DexClassLoader 失败: " + err.message);
    }
 
    // 简单枚举以确认 DexClassLoader 是否已加载
    Java.enumerateLoadedClasses({
        onMatch: function(className) {
            if (className === "dalvik.system.DexClassLoader") {
                console.log("[+] dalvik.system.DexClassLoader 已加载");
            }
        },
        onComplete: function() {
            console.log("[*] 已完成类的枚举");
        }
    });
 
    // ========== 文件复制函数 ==========
    // ========== 文件复制函数,修正后的示例 ==========
function dumpDexToExternal(dexPath) {
    if (!dexPath) {
        console.log("[-] dexPath为空,无法dump");
        return;
    }
 
    var File = Java.use("java.io.File");
    var FileInputStream = Java.use("java.io.FileInputStream");
    var FileOutputStream = Java.use("java.io.FileOutputStream");
    var Arrays = Java.use("java.util.Arrays");
 
    try {
        var dexFile = File.$new(dexPath);
        if (!dexFile.exists()) {
            console.log("[-] 目标 dex 文件不存在: " + dexPath);
            return;
        }

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2025-1-11 19:27 被螺丝兔编辑 ,原因:
收藏
免费 15
支持
分享
最新回复 (3)
雪    币: 1019
活跃值: (323)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
学习一下
2025-4-4 22:06
0
雪    币: 335
活跃值: (666)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
多谢楼主分享技术!
2025-4-7 19:38
0
雪    币: 214
活跃值: (42)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
多谢楼主!
2025-4-8 20:50
0
游客
登录 | 注册 方可回帖
返回