鸿蒙逆向 — SHCTF – Android?Harmony!

前言

第二次遇到鸿蒙逆向的题,感觉挺新奇,琢磨了一中午,虽然中间有些出题人疏忽的小插曲,不过修复的速度也挺快,也是顺利拿了个一血哈哈

分析

题目给了一个shctf.app文件,对于文件结构可以查看官方文档的描述 应用程序包基础知识
实际上同安卓类似,使用解压缩软件即可解压,得到一个.hap文件和一个pack.info

 

 

HAP(Harmony Ability Package)是应用安装和运行的基本单元。HAP包是由代码、资源、第三方库、配置文件等打包生成的模块包,其主要分为两种类型:entry和feature。
entry:应用的主模块,作为应用的入口,提供了应用的基础功能。
feature:应用的动态特性模块,作为应用能力的扩展,可以根据用户的需求和设备类型进行选择性安装。
应用程序包可以只包含一个基础的entry包,也可以包含一个基础的entry包和多个功能性的feature包。

然后继续解压hap文件

在etc目录下,可以看到一个module.abc文件

鸿蒙逆向 — SHCTF – Android?Harmony!插图

abc文件
方舟字节码(ArkCompiler Bytecode)文件,是ArkCompiler的编译工具链以源代码作为输入编译生成的产物,其文件后缀名为.abc。在发布时,abc文件会被打包到HAP中。

接下来就是想办法如何去反编译这个abc文件,最后在github上发现一个基于jadx的开源abc反编译工具 abc-decompiler,虽然反编译效果还不是很完美,期待大佬们的完善

分析page/Index,在构造函数中初始化了secretKey

 复制代码 隐藏代码
public Object Index(Object functionObject, Object newTarget, Index this, Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) {
        if ((0 == arg3 ? 1 : 0) != 0) {
            arg3 = -1;
        }
        if ((0 == arg4 ? 1 : 0) != 0) {
            arg4 = null;
        }
        Object obj = super(arg0, arg2, arg3, arg5);
        if (("function" == typeof(arg4) ? 1 : 0) != 0) {
            obj.paramsGenerator_ = arg4;
        }
        obj.__userInput = ObservedPropertySimplePU("", obj, "userInput");
        obj.secretKey = "[f#fLw)??Pz?#9w)Du[ks[q[#w4D?4P4UJf,kU[f.rDkfwrDtq...)?J.#rP4[qrPDJkkJ|.9J|qffU?k|D4P4P[wkk.)k?JUJ[k#9kww[r??wUfw|PkrPUf.P#f.P#.PwJ4f4q.PU4UPDr9.[9fJ#PqP)cDDffJPDrJ.J4qPP[r[.JfJ4f|?U9#";
        obj.setInitiallyProvidedValue(arg1);
        obj.finalizeConstruction();
        return obj;
    }

获取用户输入,并加密,和secretKey对比,如果校验通过则创建一个迷宫,然后写入What文件中

 复制代码 隐藏代码

public Object validateAndCreateMaze(Object functionObject, Object newTarget, Index this, Object arg0) {
        newlexenv(2);
        _lexenv_0_0_ = newTarget;
        _lexenv_0_1_ = this;
        Object newobjrange = import { encode } from "@bundle:com.welcome.shctf/entry/ets/model/encode"();
        if ((_lexenv_0_1_.secretKey == newobjrange.encode(arg0) ? 1 : 0) == 0) {
            Object promptAction = import { default as promptAction } from "@ohos:promptAction";
            promptAction.showToast(createobjectwithbuffer(["message", "口令错误!"]));
            return null;
        }
        Object newobjrange2 = import { maze } from "@bundle:com.welcome.shctf/entry/ets/model/maze"();
        r12 = getContext(_lexenv_0_1_).filesDir + "/What";
        try {
            Object fileIo = import { default as fileIo } from "@ohos:file.fs";
            Object openSync = fileIo.openSync(r12, import { default as fileIo } from "@ohos:file.fs".OpenMode.READ_WRITE | import { default as fileIo } from "@ohos:file.fs".OpenMode.CREATE);
            Object CreateMaze = newobjrange2.CreateMaze(arg0);
            Object map = CreateMaze.map(#11009740135539449431#);
            Object join = map.join("\n");
            Object fileIo2 = import { default as fileIo } from "@ohos:file.fs";
            fileIo2.writeSync(openSync.fd, join);
            Object promptAction2 = import { default as promptAction } from "@ohos:promptAction";
            Object obj = promptAction2.showToast;
            Object obj2 = createobjectwithbuffer(["message", 0, "duration", 5000]);
            obj2.message = "口令正确!\n等下!好像创建了什么东西?\n" + r12 + "";
            obj(obj2);
            return null;
        } catch (ExceptionI0 unused) {
            Object promptAction3 = import { default as promptAction } from "@ohos:promptAction";
            Object obj3 = promptAction3.showToast;
            Object obj4 = createobjectwithbuffer(["message", 0]);
            obj4.message = "文件操作失败: " + r12.message + "";
            obj3(obj4);
            return null;
        }
    }

先对model/encode方法进行分析,一些常规的运算,单字节加密

 复制代码 隐藏代码
public Object #9151489524504893103#encode(Object functionObject, Object newTarget, encode this, Object arg0) {
        Object obj = [Object];
        Object obj2 = obj;
        throw(obj);
        Object obj3 = getiterator(arg0);
        Object obj4 = obj3.next;
        while (true) {
            Object callthisN = obj4();
            throw.ifnotobject(callthisN);
            if (istrue(callthisN.done) != null) {
                break;
            }
            Object obj5 = callthisN.value;
            try {
                obj2.push(String.fromCharCode((((114514 * (obj5.charCodeAt(0) - 32)) + 1919810) % 95) + 32));
            } catch (ExceptionI0 unused) {
                if (istrue(0) == null) {
                    try {
                        obj2 = obj3.return;
                    } catch (ExceptionI0 unused2) {
                    }
                    if ((0 == obj2 ? 1 : 0) == 0) {
                        obj2();
                        throw(obj5);
                    }
                }
                throw(obj5);
            }
        }
        return obj2.join("");
    }

可以直接写个爆破脚本来解决

 复制代码 隐藏代码
s = "[f#fLw)??Pz?#9w)Du[ks[q[#w4D?4P4UJf,kU[f.rDkfwrDtq...)?J.#rP4[qrPDJkkJ|.9J|qffU?k|D4P4P[wkk.)k?JUJ[k#9kww[r??wUfw|PkrPUf.P#f.P#.PwJ4f4q.PU4UPDr9.[9fJ#PqP)cDDffJPDrJ.J4qPP[r[.JfJ4f|?U9#"
f = ""
for i in range(len(s)):
    for j in range(32, 128):
        tmp = ((114514*(j - 32)+1919810)%95)+32
        if s[i] == chr(tmp):
            f += chr(j)
            break
print(f)
# b4c4S20331H3cf208Cb9Tbebc2a83a1a6d4F96b45-8942-8{e55503d5c-1abe-18d99d75fd7e4463978a1a1b2995093d6db9cf922b-332642719-16451c451c512da4ae516a618-f5bf4dc1e10}8844d18-d5dae11b-b5d4da4736fc

由于手上没有鸿蒙的机子,也没有调试hap的方法,因此只能继续静态分析他是如何创建迷宫的
分析model/maze,在构造函数中初始化了迷宫数据

 复制代码 隐藏代码
public Object maze(Object functionObject, Object newTarget, maze this) {
        Object[] objArr = [Object];
         objArr[0] = createarraywithbuffer(["#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#"]);
        objArr[1] = createarraywithbuffer(["#", " ", "#", " ", " ", " ", " ", " ", "#", " ", " ", " ", " ", " ", " ", " ", " ", " ", "#", " ", " ", " ", " ", " ", " ", " ", "#", " ", " ", " ", " ", " ", "#", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "#", " ", " ", " ", " ", " ", " ", " ", "#", " ", " ", " ", "#", " ", " ", " ", "#", " ", " ", " ", "#", " ", " ", " ", "#", " ", " ", " ", " ", " ", " ", " ", " ", " ", "#"]);

        ......

        this.maze = objArr;
        return this;
    }

CreateMaze方法中设置了迷宫的起点(S)和终点(E),并将我们输入的内容填充在迷宫中

 复制代码 隐藏代码
public Object CreateMaze(Object functionObject, Object newTarget, maze this, Object arg0) {
        this.maze[77][1] = "E";
        this.maze[1][83] = "S";
        return this.FillF1ag(this.maze, arg0);
    }

FillF1ag方法遍历迷宫所有格子,判断是否为空格,然后调用CheckGround再判断,由于反编译工具还不完善,反编译结果看着还比较难懂,手动优化一下可以发现他进行了边界检查,以及返回四个方向空格的个数,当个数超过2时,FillFlag就会将输入内容填充进去

本站资源来自互联网收集,仅提供信息发布
一旦您浏览本站,即表示您已接受以下条约:
1.使用辅助可能会违反游戏协议,甚至违法,用户有权决定使用,并自行承担风险;
2.本站辅助严禁用于任何形式的商业用途,若被恶意贩卖,利益与本站无关;
3.本站为非营利性网站,但为了分担服务器等运营费用,收费均为赞助,没有任何利益收益。
死神科技 » 鸿蒙逆向 — SHCTF – Android?Harmony!

死神科技,因为专业,所以领先。

网站首页 24小时自动发卡
在线客服
24小时在线客服
阿里云自动发卡,购卡进群售后
12:01
您好,有任何疑问请与我们联系!

选择聊天工具: