第二届Alictf-初赛第四题

本文详细介绍了对一款CTF木马的逆向分析过程,包括脱壳、空间定位、字符串资源文件获取等关键步骤。通过调试和逆向工程,作者揭示了其中的加密和混淆手法,并最终成功解码。文章强调了耐心和细节对于逆向分析的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上月的ctf木有机会参加,不过技术比较菜,不献丑也好。。。废话不多说,拿来看看。

--------------------------------------------------------------------------------

0x01 脱壳

脱壳方法和年初的MSC相同,看雪有各路大牛的技巧。 脱壳修复dex之后,用jd查看。

0x02 分析

从入口函数看起,根据布局文件,结合apk界面,可以知道基本的空间。关注btn的listerner:

其中:

    try {
            你好中国.__Db(this.b.c, 2130968577);//故意赋值不相同的空间类型,进入异常流程。
        }
        catch(Exception v0) {
            try {
                byte[] v0_1 = 你好中国.__Lb(你好中国.__Ib(你好中国.__m(this.a)), "UTF-8");  // 直接获取bytes
            }
            catch(Exception v0) {
                goto label_39;
            }


            try {
                if(v0_1.length >= 1 && (你好中国.__bb(v0_1))) {
                    你好中国.__Bb(你好中国.__Eb(this.b), 0);  //这里可以断定为成功流程,结果字符串资源文件的GO!!!可以确定。
                    return;
                }

                你好中国.__Bb(你好中国.__Eb(this.b), 1);
            }
            catch(Exception v0) {
                try {
                    你好中国.__Bb(你好中国.__Eb(this.b), 1);
                }
                catch(Exception v0) {
                label_39:
                    throw new RuntimeException();
                }
            }
        }

关键点就是__bb方法做了什么。oops拿起Indroid圣剑就开搞。

小弟木有圣剑,拿着补刀斧上了。反正不是比赛,也不用担心时间问题。

...

调试之后,找到各种Native函数地址。

...

再接着调试__bb方法,然后发现问题:

经常反射调用tn的a,b无用方法干扰我们。

输入数据经过__p方法后,进行了变换。 dd出内存,这个方法f5看得也是醉了:

跟踪之后,逆出一下代码:(JAVA)

    public static void __p(byte[] arg3) {
        int v0;
        for(v0 = 0; v0 < arg3.length; ++v0) {
            arg3[v0] = ((byte)(arg3[v0] + v0 * 3));    //经过3轮,每轮数值加上i,这里直接合并
        }
    }   

再调试之后,发现还调用了s的a方法变换

....

调试发现,其反射调用了H的a方法:

   public static byte[] a(byte[] arg7) {
        你好中国.__n(你好中国.__Q());
        Cipher v0 = 你好中国.__Fb("AES");
        你好中国.__Zb("h01aJiqQsF/dl3g6LaZi7g==", 0);//base64字串,调试其反射调用了decode方法
        你好中国.__Zb("h01aJiqQSF/dl3g6Lazi7g==", 0);
        你好中国.__Zb("h01aJiqQSF/dI3g6LaZi7g==", 0);
        你好中国.__Ab(v0, 1, new SecretKeySpec(你好中国.__Zb("h01aJiqQSF/dl3g6LaZi7g==", 0), "AES"));
        你好中国.__Zb("h01aJiqQSF/pl3g6LaZi7g==", 0);
        return 你好中国.__Vb(v0, arg7);//aes加密,密钥就是解密base64后的值
    }

...

再调用了R的a方法,获得checkCode值.

    public static byte[] a() {
        你好中国.__n(你好中国.__Q());
        int v0 = 0;
        你好中国.__Zb("+by7eL4gwrnnaW3z3lPbbA==", 0);
        byte[] v1 = 你好中国.__Zb("+by7eL4gwrmnaW3z3lPbbA==", 0);
        你好中国.__Zb("+by7eL4gwrmnaW3z31PbbA==", 0);
        你好中国.__Zb("+by7eL4gvrmnaW3z31PbbA==", 0);
        while(v0 < v1.length) {
            v1[v0] = ((byte)(v1[v0] ^ 5));
            ++v0;
        }
        return v1;
    }

最后调用__x方法,返回比较结果。

猜测就是直接比较返回结果,故内存修改输入的code,结果不正确。

。。。再动态调试了__x方法,发现在java里面执行a()方法得出的checkCode与apk运行的checkCode不匹配。

fc b9 be 7d bb 25 c7 bc a2 6c 68 f6 da 56 de 69
fc b9 be 7d bb 25 c7 bc a2 6c 68 f6 [db] 56 de 69

真是要跪了。。。

根据逆过程,写下代码,得到正确结果。。。

------------------------------------------------------------

总的来说,调试要耐心,细节决定成败。




评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值