第二届MSC分析
本帖最后由 Ericky 于 2015-12-8 13:19 编辑第二届MSC第一题分析
1.BackToSmali分析代码发现关键函数的smali代码有4W行先搜索return发现有两处源头:36102行 goto/16 :goto_0
38164行 goto/16 :goto_0定位到 一处v4 和v10两个Long型整数比较的地方。2.插入Smali代码打log,插入代码如下: 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,修改后为:# 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 methodJava层: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 5205 ca 27 de 04 c2 e9 db所做变化函数字节码为:1F BC DA FF E6 4C BC 44F5 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 7518 74 C4 BE 45 4B 39 75。算法类型:TEA
10.总结代码片段多,混淆严重,没找到对的方法就会吃力又不讨好。平时也要多积累,才能厚积薄发。总的来说此次比赛让自己意识到了不足之处,同时各方面收获很大,最后要感谢阿里的工作人员出题以及举行比赛,你们辛苦了。
2015.10.18By Ericky
PS:谢谢提醒加上了题目见附件
第一题打log:
invoke-static {v4}, Ljava/lang/Long;->toString(J)Ljava/lang/String;
修改为
invoke-static {v4, v5}, Ljava/lang/Long;->toString(J)Ljava/lang/String;
不然老是出错,累坏了我这小菜 世事繁华皆成空 发表于 2015-12-8 18:40
你竟然又发了一遍,还以为这次会增加点东西呢,不就是比赛时的writeup么
居然偷看我的writeup死罪啊。。。 感觉好厉害啊{:1_903:} 不明觉厉 前排留名!! 然而看都看不懂得我竟然看完了 前排前排露脸 谢谢谢谢 本帖最后由 冰楓丶殘瀷 于 2015-12-7 17:31 编辑
膜拜
前排出售酒鬼花生、奶油瓜子、农夫山泉、可口可乐、爆米花、哈根达斯、各种烧烤 前排膜拜 看完了,虽然不懂{:1_903:}