首页
社区
课程
招聘
[原创]360无线攻防第三题详细分析
2014-6-7 18:29 36941

[原创]360无线攻防第三题详细分析

2014-6-7 18:29
36941
来看雪混了快一年了,由一年前的“不会汇编,不会android”的超级新手,慢慢变成了新手,这不得不感谢看雪各位大牛的无私分享!前几天偶然见到“风随雨行”大大的360无线攻防第三题粗解,很是手痒,就断断续续花了6天的时间进行了详细分析。处女贴,有什么不对的地方望大家指正!
    分析文档,代码和apk均在附件中。

360crackme分析

1 概述

该crackme的核心验证程序在libqihoo.so中。这个动态库经过了加密、清除elf文件的节区信息、花指令等处理,无法直接使用IDA进行静态分析。所以需要使用动态调试。不过如果仅仅使用动态跟踪的话,是很难分析出最后结果的。所以应当想法获得正确的libqihoo.so文件,然后结合动态调试、静态分析,最终分析出验证机制。

2 破解方法

2.1 获取较为正确的libqihoo.so文件

这里之所以使用较为正确,是因为我从内存dump出来的libqihoo.so文件并不完全正确,不过核心代码均有了,只是IDA没能自动识别出export函数(malloc,memset等),需要我们分析的时候自己加以判断,只要熟悉这些函数就很容易判断出来。

获取so文件的方法很简单:使用动态调试附加上crackme之后,运行几次确保so已经加载到内存,然后ctrl+s查看so在内存中的起始位置,再到hex-view窗口中dump出这段内存,另存为libqihoo.so,然后另起一个IDA静态分析即可。IDA分析后的可以发现在Function widows有了我们关心的JNI_OnLoad和verify函数:

如图所示:


2 开始分析

通过分析发现JNI_OnLoad函数将JAVA层的verify函数同so中的verify函数进行了关联。所以我们直接开始分析verify函数即可。Ps:方便大家查看,我将我分析过程中提取的关键代码也放出来,在360crackmeARMcode.c中,大家可以参照着看,那里面有详细注释。其中逻辑简单的我保留了汇编代码,逻辑复杂的就手工转换成了c代码。

2.1 JAVA层传递的参数

JAVA层传递三个参数username, emailaddr, serialNum。这三个参数均为String类型。

2.2 so文件的花指令模式

Libqihoo.so中加入了大量的花指令,这无疑增加了逆向分析的工作量。不过只要理清了它的花指令模式,我们完全可以一劳永逸地解决这个麻烦。它的花指令模式如下:

    LDMFD SP!, {R0}
    真正指令
    STMFD SP!, {R0}
    ADRL R0, LOC_XXX
    SUB R0, R0, #4
    BX R0
    为了方便分析,我是手工将花指令代码中的真正指令提取出来,然后进行分析的。看起来很费劲,其实是大大缩减了分析时间。


解决了花指令问题,就开始真正分析了。

2.3 本地验证流程

1)在verify函数中调用__GNU_Unwind_8,将三个参数(String型的字符串)转换为native层的char* username, * emailaddr, * serialNum。

2)在verify函数中调用__GNU_Unwind_6。此函数完成验证的核心功能。
下面开始对__GNU_Unwind_6函数进行分析:

①新建一个结构体(命名为inputinfo),该结构体如下:
typedef struct inputInfo{
	char *username;
	char *emailaddr;
	char *serialNum;
}inputInfo;


然后给inputInfo内的三个成员赋值。

②判断serialNum长度是否为8,是就继续,否则退出。

③调用__GNU_Unwind_1。在__GNU_Unwind_1中依次调用__GNU_Unwind_2、__GNU_Unwind_3、__GNU_armfini_29、__GNU_Unwind_4、__GNU_Unwind_11、__GNU_Unwind_10。下面对这几个函数加以说明:

__GNU_Unwind_2: 此函数主要调用__GNU_armfini_25和__GNU_armfini_23两个函数来获取com/qihoo/qhcrackme/MainActivity;->show(Ljava/lang/String;)V方法id。__GNU_armfini_25是一个解密函数,解密出一个base64字符串,__GNU_armfini_23是一个base64解码函数,将__GNU_armfini_25解出的字符串转换成明文。

__GNU_Unwind_3:完成一个功能:sprintf(info, "%s%s", input.username, input.emailaddr);

★__GNU_armfini_29:这是本程序中最重要的两个函数之一。该函数首先将username和emailaddr连接在一起(这里为方便称之为info),然后调用__arm_aeabi_6和__gnu_arm_message完成对info信息的变换。__arm_aeabi_6用于构造一个0x102字节的转换表 ,__gnu_arm_message用于将input的前4字节进行变换(使用前面生成的转换表)。这里需要特别说明:由于程序固定转换info的前4字节,所以如果我们输入的username+emailaddr的字节数小于4的话就会发生预料不到的错误,因此一定要确保两者长度之和大于4。

__GNU_Unwind_4:sha1_hash函数,对变换后的info进行hash,得到sha1_result
★__GNU_Unwind_11:本程序最重要的两个函数之二。该函数功能如下:

        serialNum[0] = sha1_result[0];
        serialNum [1] = sha1_result [2];
        serialNum [2] = sha1_result [5];
        serialNum [3] = sha1_result [9];
        serialNum [4] = sha1_result [14];
        serialNum [5] = sha1_result [20];
        serialNum [6] = sha1_result [27];
        serialNum [7] = sha1_result [35];

依次进行对比。

__GNU_Unwind_10:根据__GNU_Unwind_11的对比结果来进行不同处理,如果对比成功,就调用前面获得的show方法,显示”you passed…”,否则就什么都不做。

至此整个程序的验证逻辑分析完毕。下面开始编写注册机代码:

呃…算了,时间有限…大家直接看附件createSerialNum中的代码吧~~

Ps:这个crackme有两个版本,我分析的是最新的版本(现今官方指定版)。听说第一个版本对sha1进行了部分变异,原帖参考http://bbs.pediy.com/showthread.php?t=187906。不过最新版本并没有进行变异,在这里就偷个懒,直接将“风随雨行”大大的sha1代码copy过来,再把变异代码改成正常代码即可~()

附一组验证通过的序列号:

Username:wanchouchou

Emaildaar:1024@qq.com

SerialNum: 56c0e1fb

3 总结

以前都是静态分析,这是我第一次动态分析so,第一次遇到花指令,第一次搞这么复杂的代码,断断续续花了6天的时间才搞定….不过收获还是很大的,通过360的第一个题,学习了jni的编写,第3个题初识了so的动态调试。不过还是有一个疑惑,360是如何清除elf的节区信息,使得直接IDA静态分析失效的呢?清除过后,又是如何在加载这个so文件的时候,还原的呢?望大牛们不吝赐教啊!谢谢!

转换表:

 5  4b  e1  9f  78  eb  90  98  a5  a8  2c  dd  af  a0  46   1  43  49  c1  79
d4  70  4d  3b  28  d7  19  37  da  30  15  e5  9b  10  c8  2f  59  bb  3d   3
e4  45  ee  fc  be  b3  6b  31  2d  a2  b7  93  96  ae  17  a9  a4   a  c0  e2
53  82  1f  e0  61  5e  c2  68  d6  67  e9  86  94  ce  47   8  14   b  de  6f
55  4a  58  52   c  3c  32  27  74  e8  62  95  c3  f5  c4  97  7e  1c  64  38
bd  22  57  84  2b  ad  80  b5  e7  8c  36  cf  89  65  c9  6a  f9  d2  25   0
2a   4  ca  1a  8d  ff  c5  b6  4c  b8  f3  df  2e  ec  5f  fd  6d  7d   7  5d
9e  35  8b  8a  b9  d1  56  69  29  cd  60  d9  ed  54  81  40  d5  8e  d3  e6
cb  a3  b1  9c  dc  9d  24  f0   9  1b  77  b2  26  db  71   2  83  a1  39  b4
72  fe  4e  d8  3f  f6  fb  50  21  18   6  23  bf  1e  85  87  6c  fa  d0  16
bc  42  9a  76  51  13  92  34  44  7f  a7  ea  b0  ba  5b  f7  cc  63  75  41
 e  7c  73  f4  12  48  11  3e  5c  8f  99  66  c6  3a   f  a6  5a  6e  7b  f1
7a  f2  aa  91  f8  ac  33  88  20  e3  1d  ab  ef  c7   d  4f   0   0   


注:本帖由看雪论坛志愿者PEstone 重新将文档整理排版,若和原文有出入,以原作者附件为准

360crackme.rar

[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

上传的附件:
收藏
点赞1
打赏
分享
最新回复 (38)
雪    币: 31
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
笨多多 2014-6-7 21:41
2
0
支持...
雪    币: 35
活跃值: (139)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
JoyFei 2 2014-6-7 23:16
3
0
围观....
雪    币: 7268
活跃值: (3189)
能力值: ( LV8,RANK:138 )
在线值:
发帖
回帖
粉丝
zhighest 2014-6-8 00:54
4
0
膜拜………………
雪    币: 29
活跃值: (499)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
万抽抽 2 2014-6-8 10:57
5
0
哈哈,处女贴竟然得了个优秀,值了!
开始分析的时候还是很困难的,不过越到后面就越熟练,只要有耐心,大家都能破出来。
ps:话说,没有大牛帮忙解释下360是如何使得这个so无法进行ida分析的么?或者给个相关资料链接也行啊~
雪    币: 188
活跃值: (366)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
唐某某 2014-6-8 14:58
6
0
楼主分析的不错,分析文档后面两个问题提的很到位。
雪    币: 7
活跃值: (35)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
小飞学IT 2014-6-9 09:46
7
0
感谢分享,学习下
雪    币: 230
活跃值: (106)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zrhai 2014-6-10 22:29
8
0
多谢分享!
雪    币: 59
活跃值: (25)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
crespoage 2014-6-11 10:36
9
0
请问一下,里面的so是用什么工具动态调试的,我用ida6.1一直断不下来
雪    币: 29
活跃值: (499)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
万抽抽 2 2014-6-11 16:15
10
0
我使用的ida6.1加小米2s,动态调试完全没问题。你可以参考非虫大大的《Android软件安全于逆向分析》8.5.2中的介绍来操作。
雪    币: 59
活跃值: (25)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
crespoage 2014-6-11 21:20
11
0
今天下午实验了一下,发现可以动态调试,只是在ida上寻找关键断点时,因为对设置ARM指令还是Thumb指令不是很清楚,断点没设置好,这方面还得学习一下。顺便想请教一下,在程序加载so文件以后,将所需so dump回来以后,是不是还得做一些还原的工作,才能恢复正常的elf文件,用以反汇编分析,这方面您是怎么做到呢
雪    币: 36
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
fastback 2014-7-8 13:47
12
0
赞,学习了
雪    币: 250
活跃值: (251)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
OnlyEnd 2014-7-15 18:10
13
0
楼主分析解决了 最后的两个问题吗?
雪    币: 6
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Avkiki 2014-7-15 18:12
14
0
前排支持
雪    币: 230
活跃值: (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
lasvegas 2014-7-22 14:46
15
0
看楼主这么卖力的,俺凑个热闹

先上个修复图,不明白的看下elf文件结构。



其实这个修不修复没啥影响。就未修复的来说,ida 静态加载虽然会弹错,但导出函数能正确识别,只是不能区分有些section。看jni_onload, verify就知道是被加密了,那前面肯定有个解密函数。翻翻ida能识别的代码,大概齐__gnu_armfini_26就是你想要的解密。

当然修复了更直观,直接可以看到 __gnu_armfini_26x 在.init_array section。

再说下另外一个问题,动态加载的时候根本木有还原。section header table没被破坏,所以加载器能够正确识别。
上传的附件:
雪    币: 29
活跃值: (499)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
万抽抽 2 2014-7-22 23:24
16
0
感谢指点。我先消化消化~
雪    币: 181
活跃值: (45)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
duoniduoni 2014-7-24 09:06
17
0
高端 咱也学习学习 我竟然不知道IDA可以静态调试的~~~~~
雪    币: 29
活跃值: (499)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
万抽抽 2 2014-7-24 10:12
18
0
按照您的指点,成功修复了elf。也发现了so加密函数就在__gnu_armfini_26(init.array节中)。不过这部分代码过于复杂,静态分析起来难度太大,需要结合动态分析才能弄清它的加密算法。
现在问题又来了:鉴于init.array只有在so初次加载的时候执行,所以必须在so刚加载的时候就下断点,然后才能动态跟踪init.array中的函数。
大牛你看下能不能在init.array下断点。望告知方法,不胜感激!
ps:我也使用了am start -D这种方式,但IDA始终不能断在libraries load处。我的调试环境是小米2s和IDA6.1,不知是不是IDA的问题。
雪    币: 29
活跃值: (499)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
万抽抽 2 2014-7-24 16:16
19
0
额,我静态分析搞定部分了 ~~就是有点费时费力~ 不过还是跪求下断点方法~
雪    币: 270
活跃值: (234)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
wule 2 2014-7-25 13:56
20
0
期待楼主脱壳!!!
雪    币: 230
活跃值: (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
lasvegas 2014-7-26 18:09
21
0
1, 还用am start, 换个新款的ida
2,patch so (p14) 替换原来的。
雪    币: 29
活跃值: (499)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
万抽抽 2 2014-7-26 22:11
22
0
[QUOTE=lasvegas;1303851]1, 还用am start, 换个新款的ida
2,patch so (p14) 替换原来的。[/QUOTE]
  新款IDA~等我肾长出来了再说吧~
雪    币: 250
活跃值: (251)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
OnlyEnd 2014-7-30 11:35
23
0
[QUOTE=lasvegas;1303851]1, 还用am start, 换个新款的ida
2,patch so (p14) 替换原来的。[/QUOTE]

6.4的可以断下来吗?
雪    币: 188
活跃值: (167)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
cacorothuo 2014-8-5 19:52
24
0
至于最后一个问题: 节头信息和一些节名字符串是在elf文件中完全没有用的。完全可以抹掉。对于链接试图的文件中,linker是根据段进行加载的。section header是没有用处的
雪    币: 3
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
ulike 2014-8-21 20:27
25
0
lz知道它native函数是怎么注册的吗,感觉找到了注册的地方,调用了libvm.so中的方法,但原理不太明白
游客
登录 | 注册 方可回帖
返回