本帖最后由 Ericky 于 2015-12-8 13:19 编辑
第二届MSC第一题分析
1.BackToSmali分析代码发现关键函数的smali代码有4W行 先搜索return发现有两处源头: [Asm] 纯文本查看 复制代码 36102行 goto/16 :goto_0
38164行 goto/16 :goto_0 定位到 一处v4 和v10两个Long型整数比较的地方。 2.插入Smali代码打log,插入代码如下: [Asm] 纯文本查看 复制代码 if-nez v4, :cond_3//原有代码
invoke-static {v4}, Ljava/lang/Long;->toString(J)Ljava/lang/String;//以下为插入的代码
move-result-object v3
invoke-static {v3,v3}, Landroid/util/Log;->v(Ljava/lang/String;Ljava/lang/String;)I
invoke-static {v10}, Ljava/lang/Long;->toString(J)Ljava/lang/String;
move-result-object v3
invoke-static {v3,v3}, Landroid/util/Log;->v(Ljava/lang/String;Ljava/lang/String;)I
重打包后打印log,输入555555,555545,尝试两次后计算出答案为:395926
第二届MSC第二题分析
1.Java分析代码要想触发到关键的native方法,修改java层代码: 在Lk2015/a2/Ch这个类里修改smali,修改后为: [Asm] 纯文本查看 复制代码 # direct methods
.method static constructor <clinit>()V
.locals 1
const-string v0, "wbox"
invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V
return-void
.end method
.method public static a()V
.locals 2
const-string v0, "YT"
const-string v1, ".-- --- .--- .. ..- ... .... .. -.. .- .- -."
invoke-static {v0, v1}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I
return-void
.end method
.method public static a(Landroid/content/Context;Ljava/lang/String;)Z
.locals 2
invoke-static {p1}, Lk2015/a2/Ch;->ch(Ljava/lang/String;)Z
move-result v0
return v0
.end method
.method private static native ch(Ljava/lang/String;)Z
.end method Java层: 2.反调试检测了tracepid以及一些tricks。 Tracepid可以用多种方法来绕过,可以把睡的时间设置成很长很长,也可以挂起线程,也可以直接return。 有大的无用的循环直接跳过,不然出错: 这样的 直接改成非,也可以把出错的语句nop掉。 Nop前出错: Nop后如下: 这样就可以开始调试了。 3.算法分析嵌套了几层,找到最后比较16bytes的地方: 可以在Hex窗口找到,正确答案加密后对应的bytes如下: Key Answer: 0x5C, 0xDA, 0x77, 0x2F, 0xA3, 0xC6, 0x3E, 0x39, 0xB6, 0xF0, 0xF3, 0xED, 0x51, 0x5A, 0x99, 0x86
找到最后一层算法 F5之后 猜测是AES算法。 在Hex窗口找到: 红框内的是Expantion Key,外面的是4个Key。这里卡了很久,用的github上的一个库,老是不对,后来换了一个库,算对了: 解出来为: 8a 1f 4b 6e 59 ca f2 52 05 ca 27 de 04 c2 e9 db 所做变化函数字节码为: 1F BC DA FF E6 4C BC 44 F5 B8 13 C8 EC A8 CD BD
两式一减得到:
6B 63 71 6F 73 7E 36 E 10 12 14 16 18 1A 1C 1E 第8位为补充的长度,后面的为填充的数值。
再根据之前分析的与Index变换,变换后的bytes为: 6B 62 6F 6C 6F 79 30 7
查表,答案即为: kboloy0
第二届MSC第三题分析
1.Java层调用了一个native的Check函数,所有算法等数据关键信息都在native层,java层只是一个UI。
2.so层
SO 用IDA看不到函数,修改SO的头部,在IDA中效果如下: 3.Check函数首地址用修改过的ROM来打印dvmRegisterJniMethod这个函数中的fnPtr计算后得知Check函数的地址为:0x19C39。如图:
图中首地址为0x19c38。 4.下断,动态调试下好断点,打开程序。附加,F9。 程序断下来,可以单步走,于是就可以调试了。 5.程序的保护手段
分析一段时间后发现,程序大概结构组成如下: a.执行代码片段
图中给R0赋值决定了下一个调用的代码片段的偏移。
b.”整个函数总指挥部”--控制代码片段的流程
(1)
(2)
(3)
(4)
每次执行的代码寥寥几行汇编,确实让人难以调试,用010Editor查看代码片段一共5000多个。加上经常进代码片段的时候第一时间是呈现出这样的代码: 可见混淆得很严重。此时F8直接跑飞,我的方法是F7,显示出真实的代码片段如下: 由此可推断为O-LLVM混淆的保护。 6.反调试实话实说,反调试并没有遇到。F9直接可以跑通整个程序。倒是有时候单步走时间间隔了很久会出现一个错误:
我想可能是手机自身的问题 或者是一个反调试?如果是反调试的话,这个可以忽略。 7.代码追踪。好的方法是还原整个被混淆过的程序,把程序还原成线性,易读懂也容易调试。 大量的代码,利用IDA的TRACING INSTRUCTIONS 如下:
附件里有原文件。 分析后发现,被混淆的代码片段识别不出来。但是却给了一个思路,在 下断点。 8.算法函数一路上踏着荆棘来到0x17CB0(未加载),然后一直到0x18006,这里应该就是关键的算法函数的起始地址了。 0x18006: 断在0x18006,可以看见取了输入的密码,如图中红框所示: 然后在这里有0XFF次对数据的加密,一次一字节。这是我判断是算法函数的依据。 清空5位密码,图中开头5个00 所示。再利用距离0X5C的一个块与密码进行或运算,加密并且填充了一个块。 加密填充的块如图所示: 这里存放的是输入密码的长度: 9.猜想一开始我想到既然混淆得如此严重,有可能是简单变化之后的字符串的直接对比吗,于是我找到了最靠近结尾的一个函数,地址为0x1AFB0 内存中加载后如图: 往后一点就进入了dvm,return到java层了,但是走了很多次,依旧未发现字符串对比,于是我感觉不好弄了。
由于没找到最简洁的方法,逆向的过程太耗时间和精力,我这里猜测一下: 答案的字符长度:8位 KEY:16位 80 74 C4 BE 3D 59 39 75 18 74 C4 BE 45 4B 39 75。 算法类型:TEA
10.总结代码片段多,混淆严重,没找到对的方法就会吃力又不讨好。平时也要多积累,才能厚积薄发。总的来说此次比赛让自己意识到了不足之处,同时各方面收获很大,最后要感谢阿里的工作人员出题以及举行比赛,你们辛苦了。
2015.10.18 By Ericky
PS:谢谢提醒 加上了题目 见附件
|