首页
社区
课程
招聘
[原创]2015移动安全挑战赛-第3题破解思路
2015-1-26 19:52 4923

[原创]2015移动安全挑战赛-第3题破解思路

2015-1-26 19:52
4923
首先反编译classes.dex文件,结果如下:

只有Application类,显然是核心dex文件被保护了。
第一反应是拿出zjdroid进行动态backsmali,但一执行命令
adb shell am broadcast -a com.myzjdroid.invoke --ei target 2282 --es cmd "{\"action\":\"dump_dexinfo\"}"
程序就退出了,显然针对zjdroid做了防护,那么下一步就是看看是否有可能去掉防护。

用IDA看了看so,发现so加入了大量的垃圾代码,看起来好费劲。得慢慢来了。
使用AXMLPrinter2.jar反编译AndroidManifest.xml,发现了搞鬼的代码:
                <receiver
                        android:name="com.zjdroid.invoke"
                        >
                        <intent-filter
                                >
                                <action
                                        android:name="com.zjdroid.invoke"
                                        >
                                </action>
                        </intent-filter>
                </receiver>

注册了与zjdroid相同的广播,尝试修改zjdroid源代码,把广播换个名字。结果是:
虽然程序不退出了,但zjdroid始终收不到广播,命令不执行。那就对zjdroid进行个大换血。我的做法是新建了个xposed工程,将zjdroid的dump代码移置到新工程中,这个工作大概消耗了半天的时间。最后hook了android.app.Application的onCreate方法,在这个点进行dex的dump。
首先打印所有的dex信息。发现有2个,如下:
dexFile:/data/app/crackme.a3-1.apk cookie:1565641824
dexFile:/data/data/crackme.a3/lib/libmobisecy.so cookie:1552628144

第1个是classes.dex,第2个就是核心dex了

最终成功dump出核心dex文件。截图如下:

下面的工作就是java逆向了。
使用JAD查看代码,得到代码逻辑如下:
(1)        将输入的字符通过密码表转化,密码表如下:
  static
  {
    a("a", ". _");
    a("b", "_ . . .");
    a("c", "_ . _ .");
    a("d", "_ . .");
    a("e", ".");
    a("f", ". . _ .");
    a("g", "_ _ .");
    a("h", ". . . .");
    a("i", ". .");
    a("j", ". _ _ _");
    a("k", "_ . _");
    a("l", ". _ . .");
    a("m", "_ _");
    a("n", "_ .");
    a("o", "_ _ _");
    a("p", ". _ _ .");
    a("q", "_ _ . _");
    a("r", ". _ .");
    a("s", ". . .");
    a("t", "_");
    a("u", ". . _");
    a("v", ". . . _");
    a("w", ". _ _");
    a("x", "_ . . _");
    a("y", "_ . _ _");
    a("z", "_ _ . .");
    a("2", ". _ _ _ _");
    a("1", ". . _ _ _");
    a("3", ". . . _ _");
    a("4", ". . . . _");
    a("0", ". . . . .");
    a("6", "_ . . . .");
    a("9", "_ _ . . .");
    a("8", "_ _ _ . .");
    a("7", "_ _ _ _ .");
    a("5", "_ _ _ _ _");
  }

(2)        将转换后的字符交于b类的public void run()函数处理,加入了大量的混淆代码,其中调用的CRC32、sha1、AES,但都是骗人的,出题人真是太坏了,我一直怀疑自己的dump代码是否有问题,但最后还是找到了真正的代码逻辑。
核心代码片段如下:
        ac = s.toCharArray();
        i = s.substring(0, 2).hashCode();
        if(i <= 3904)
首先头两个字符的hashCode要小于3904

if(i != 3618) goto _L8; else goto _L7
确切的就是要等于3618

if(ac[0] + ac[1] != 168) goto _L8; else goto _L9
字符之和为168,通过枚举确定前2个字符为“s5”

L9:
        abyte1 = (new StringBuilder()).append(((f)e.getAnnotation(f)).a()).append(((f)a.getAnnotation(f)).a()).toString().getBytes();
        if(-2 + ac.length != abyte1.length) goto _L11; else goto _L10

下面的逻辑就是剩余的字符要等于(f)e.getAnnotation(f)).a()和(f)a.getAnnotation(f)).a()的字符串拼接。查看e和a这两个类,找到了@f(a="7e")和@f(a="1p")
那么字符串就是s57e1p

(3)        通过密码表转化,得到答案:... _____ ____. . ..___ .__.

[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。

上传的附件:
  • 1.png (152.51kb,21次下载)
  • 2.png (191.75kb,4次下载)
收藏
点赞0
打赏
分享
最新回复 (2)
雪    币: 51
活跃值: (213)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
gestic 2015-4-7 09:56
2
0
"最后hook了android.app.Application的onCreate方法,在这个点进行dex的dump。"
这个地方有点疑问,是如何做的hook呢,也是用的zjoid hook的吗?
雪    币: 200
活跃值: (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
iprowq 2015-4-14 16:03
3
0
用Xposed
游客
登录 | 注册 方可回帖
返回