前言

Xposed是一款强大的hook框架,是时候该学习一下如何开发它的模块了。刚开始也是比较懵,因此记录一下。Xposed相关的链接

我的开发环境如下:

  • 已Root并且安装了Xposed Installer的Nexus 5, Android版本4.4.4
  • Android Studio,API Level 25
  • XposedBridgeApi-54.jar

开发流程

  1. 新建Android Studio工程,选择no Activity
    2.把XposedBridgeApi-54.jar加到 libs 文件夹,然后修改build.gradle中的一个地方。
    compile fileTree(dir: ‘libs’, include: [‘.jar’]) 改为 provided fileTree(dir: ‘libs’, include: [‘.jar’])

build.gradle

3.在AndroidManifest.xml文件的application标签中增加下面的内容

1
2
3
4
5
6
7
8
9
<meta-data
android:name="xposedmodule"
android:value="true" />
<meta-data
android:name="xposeddescription"
android:value="First Xpoesd Module Test" />
<meta-data
android:name="xposedminversion"
android:value="54" />

xposeddescription下面的value填写xposed模块的相关描述,xposedminversion下面的value是我们使用XposedBridge jar包的版本号。

4.新建一个java文件,写一个简单的example

1
2
3
4
5
6
7
8
9
10
11
package com.seven.xposedtest;
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.callbacks.XC_LoadPackage;
public class XModule implements IXposedHookLoadPackage {
public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
XposedBridge.log("Seven Loaded app:" + lpparam.packageName);
}
}

5.新建一个assets目录

assets

6.在assets目录新建一个文件 xposed_init ,里面写上hook类的完整路径。比如我的包名是com.seven.xposedtest,类名是XModule,那么就写上com.seven.xposedtest.XModule

7.Build Apk,然后install到手机。在Xposed installer的模块里找到这个模块,勾选上,接着重启手机。就可以在logcat看到效果啦。如果能看到有Seven Loaded app:的text,说明我们的模块安装成功了。

最近做项目的时候遇到了一个比较无语的问题,出bug了,但是给出的出错信息只有一条Android的权限信息,无法得知出错的代码位置在哪,排查起来工作量就变大了。除了项目本身的问题,就是自己没有注意使用try catch来捕获异常,加上平时写的捕获异常信息也比较模糊,这个会给后面的排查工作带来一定的影响,经过师兄的提醒后,发现可以trackback来获得更详细的异常信息。

简单的异常处理

简单的异常处理比如:

1
2
3
4
try:
pass
except Exception, e:
print e

这样捕获到的异常信息的信息量实际上不足以满足项目的需求,我们不能得知具体出错的代码是哪一行。因此,需要一个打印更详细的异常信息的办法,这就引出了traceback。

traceback

1
2
3
4
5
6
7
8
9
10
11
import traceback
....
try:
i = int('a')
except Exception, e:
print 'str(Exception):\t', str(Exception)
print 'str(e):\t\t', str(e)
print 'repr(e):\t', repr(e)
print 'e.message:\t', e.message
print 'traceback.print_exc():'; traceback.print_exc()
print 'traceback.format_exc():\n%s' % traceback.format_exc()

traceback.print_exc() 会直接打印出异常信息, traceback.format_exc() 会返回异常信息的字符串。根据项目原先的代码结构,我使用了traceback.format_exc()配合logging.error()来打印异常信息。这个返回的异常信息包括了发生异常的详细信息,比如定位代码行数,异常的原因。这个可以帮助开发者较快的发现问题所在。

由于工作问题,换了一台电脑,发现win7没法自动更新找到Nexus5的驱动,这样就没法使用测试机了。上网找了一下资料,发现这个做法是有用的,虽然是繁体字。

  1. https://wazai.net/3190/google-nexus-7-2013-%E7%89%88%E6%9C%AC-usb-driver-%E5%AE%89%E8%A3%9D

  2. https://developer.android.com/studio/run/win-usb.html?hl=zh-cn

步骤:

  1. 首先可以去Android Studio下载驱动程序,从Android SDK Manager获取,操作如下所示:

(1)在 Android Studio 中,点击Tools > Android > SDK Manager。

(2)点击SDK Tools标签。

(3)选择Google USB Driver package并点击Install。

(4)安装完成后,驱动程序文件将下载到\extras\google\usb_driver\目录中。前面接上SDK的安全目录,比如我的是C:\Users\\AppData\Local\Android\sdk\extras\google\usb_driver

2.接着就按繁体字教程那样安装

(1)找到“设备管理器”,“Nexus5”的那一项

(2)右键->“更新驱动程序软件”->点击“浏览计算机以查找驱动程序软件”

(3)点击“从计算机的设备驱动程序列表中选择”->“显示所有装置”->“从磁盘中安装”->选择刚刚driver文件夹下的“android_winusb.inf”->接着选“Android ADB Interface”


2017的实习生春招投了几家公司,把面试的经过记录一下吧。

移动安天

3月初就投了简历到招聘邮箱(campus@antiy.cn),结果一直没回复。后来有听一些面试安天的小伙伴说,在实习僧上投的简历或者直接找那边的负责人,后来都有面试。可能是我的简历直接挂了。

阿里(offer)

也是3月初,在AFSRC的帽子群看到自来发的内推实习生的消息,于是就发简历过去了,3.7晚投的简历,没想到很快就有了回复。接着3.9在系统上填资料,第二天就收到了一面的电话。(当时真没想到阿里的面试战线拉得那么长…)

一面(3.10, 电面,1h24min)

算是实习季的第一通面试电话,刚接到的时候很紧张,幸好面试官听起来还是挺nice的。开头就说了今天的面试按照简历上写的东西顺序来了解了解(后来才知道这大概是简历评估面),先是说了自己去年暑假实习做的东西,问了做什么工作(我做的是Android应用的安全检测)、最后发现了什么漏洞等等,接着开始聊做过的项目,先是介绍项目是干嘛的、自己做了什么、怎么做、有什么成果,基本都是按照这个模板来介绍。当时写简历的时候把最有把握的一个项目放在了第一个,于是第一个项目也是聊得最久的,中途面试官也会插播问一些问题,这就考验了自己对简历项目的熟悉度。到后面,时间不太够,因为也是时候吃午饭了,所以感觉面试官问题不多,基本都是自己在说,论文和竞赛都一笔带过了。

总结:由于是第一面,实际上自己对简历的内容还没有准备好(没想到一面那么快就来了),所以回答的时候有一些点回答得比较含糊,幸好面试官不是很介意,事实上聊得还算比较愉快的,毕竟第一次面试那么久,后面嗓子都干了。所以在投简历之前还是要对自己的简历内容要有比较充分的把握和了解,因为你不知道明天和面试电话哪个会先来 - -||

二面(3.13, 46min)

一面完之后的第二天是周六,早上在宿舍整理内务的时候,快到中午的时候收到了昨天的面试电话,当时一惊,因为自己完全没预料到那么快会有二面电话。结果是跟我预约面试时间的,于是约了下周一。有了一面的经验,周末两天都在准备面试的内容。3.13电话如期而至,不过这次面试没有上次那么轻松。面试官问了挺多问题,基本上没有问简历的东西,大多是跟业务相关以及跟问题的延伸和扩展,考验平时是否有思考的习惯以及面试者的思路。而其中有两个问题我都没有理解面试官想问的是什么,只能请面试官再问一遍..印象比较深刻的是面试官一上来就说“我看过你的博客(简历上有留博客地址),那篇思维导图的..(中间省略),为什么漏洞要这么分类,你怎么能确保这样分类的漏洞可以覆盖所有的问题?”(大概是这样一个意思,具体问法不记得了)。接着问了漏洞挖掘、安全测试自己怎么做的;是否了解系统层面的安全问题;给定一个业务场景,讲讲里面包含的安全问题(AR抢红包),这个问题和面试官讨论得比较久,适当的时侯面试官会有些引导,不过感觉自己还是回答得不太好。

总结:二面的时候感觉自己回答得一般,面试官可能会偏业务安全那块多些,和面试官的交流也意识到自己的不足。

hr面(4.19, 20min)

由于前两面紧凑的面试,让我对阿里的面试产生了期待,事实上发现这种期待才是最磨人的。二面过后一个月还是没消息,官网上的进度还是“面试中”,心里实际上觉得自己应该是已经挂了,但官网上的状态又给了自己一些希望。4.18的时候下午去打球,错过了一个阿里的电话,内心是崩溃的..结果吃完晚饭发现又错过了一个阿里电话(嗯,欲哭无泪,手机问题没响铃)。幸好第二天中午终于接到了,是hr的电话,约了当天晚上。当时心里想,时隔那么久,而且第三面就接到了hr面的电话,不知道是什么情况。晚上去打球,hr来电话,激动地跑去比较安静的地方,结果因为自己跑太猛,接电话的时候一直在喘气= =。hr跟我说的时候才发现自己从蚂蚁被调到菜鸟去了,hr跟我解释了一下为什么会发生这样的变动,接着就开始正式的hr面。自我介绍、职业规划、最有成就感的事、最挫败的事等等。后面两个问题实际上被问的时候有点懵逼,到了这个4月下旬其实基本没什么面试了,加上自己没有考虑到会问这个,于是停了挺久思考的,中途hr还问了我一声还在吗(尴尬),最后我居然傻傻的回答了最有成就感和最挫败的是同一件事,解释了一下..但感觉糟透了,快结束的时候,hr问我有什么问题,于是我问了关于菜鸟的问题,hr小姐姐在回答的时候还不知道什么原因电话挂了..幸好后来hr还是打回来继续说了。

到了周五统一发offer的时候,虽然hr面感觉一般,但心里还是有些底的。果然,晚上十点半的时候状态变成待跟进offer了,开心~

腾讯

内推一面(3.20,电面)

感觉是简历评估面,问了一些简历上的实习经历和项目经历,可以感觉到面试官是懂行的,问的问题也比较深入,有问到应用漏洞挖掘、自动化扫描的问题。

晚上师兄就告诉我挂了,自己反省了一下,有挺多东西面试的时候没有展现出来,还有挺多东西要学习。面试官给的建议是可以继续扩展知识面,挖一些有价值的漏洞。

初试(4.11,现场面)

清明在家做的笔试,笔试完没抱太大希望,因为笔试考察的范围很广,安全很多方向都考了。

后来接到通知,现场面试,想着也是个机会,就去试一试了。

初试的时候面试官也没让我自我介绍,盯着我的简历似乎不知道应该从何问起,跟我解释了一下他们是windows游戏反外挂团队的,我当时万脸懵逼,简历上的都是Android安全相关的,怎么会跟windows扯上关系..面试官先是问了我,你觉得自己笔试得怎样,我回答一般般,他说确实不太好,不过这份考卷也考的比较广。接着问了我的基本情况,后来说搞他们那一块的现在人比较少,所以不得不考虑其他方向的人,从面试过程来看,我的学习能力还可以,但是要综合考虑其他面试者的情况,今晚才有答复,于是我就默默回去等消息了。

晚上,收到了复试的消息,但我也不知道自己能准备什么,于是平常心对待。

复试(4.13)

复试的面试官看上去有些资深,但我说的话他都很认真地在听。问了一些底层、加固脱壳的问题,以及我项目的细节、实验室的情况,可以看得出面试官在从多方面考察我,评估是否适合他们的岗位,后面面试官也有说到,他主要考察面试者的思路。最后出了一道编程题,跪了。腾讯面试就这样结束了。

网易(offer)

网易笔试没报多大希望,因为有三道编程题,实习季的时候就没有准备过数据结构、coding方面的东西,大概也就过了半道编程题吧。结果清明前顺手查结果,居然有面试机会,哈哈。不过面试要去杭州现场面试,考虑了很久,决定还是去吧,于是买了机票、订酒店、查路线..假装自己去杭州旅游。

现场面试(4.6):

只身来到杭州,早上11点的面试,比预定时间来早了一个钟。去前台签到,扫了一下周围,网易的办公环境还是不错的。找了个地方坐下等,十分钟左右就叫号了。

一面

具体忘了面试官问什么了,主要是了解我的基本情况,简历问,对Android安全掌握到什么程度。一面完之后,让我回去等待。结果没5分钟,又叫号了。

二面

二面问了加固脱壳的问题比较多。比如,常见的反调试有哪些手段;加固脱壳的原理;dex2jar这些反编译工具有什么Bug..还有其他也是问了自己挖的漏洞,讲讲自己印象最深的一个漏洞。最后面试官让我提问。当时脑子不知道怎么了,我居然问了,你觉得网易的饭堂怎么样?面试官也一本正经地回答我这个问题,嗯。

又回去等消息,过了十几分钟,跑去前台问结果,说有hr面,不过要等到下午,待会会被领去吃饭的。抱着一丝希望,去吃猪厂的饭堂,人好多,饭菜还可以啦。

hr面

等到两点多,hr面终于来了。hr小姐姐好nice,问了有没有男朋友、工作地点、工作选择、职业规划、最近看的一本书等等。愉快地结束了网易的面试之后,本来打算去西湖看看,结果居然开始下大雨T T。于是去附近吃了一碗鳗鱼饭,心满意足地回酒店去了。第二天5点多起床,然后打飞的回我大广州咯。

360

投360安全岗都要参加一个安全星的计划,实际上就是在i春秋学习一些课程,然后参加笔试,通过之后才能面试。因为i春秋上的学习进度据闻也是参与考核的,所以在这个安全星计划上花的时间也是蛮多的,但是他的判定课程进度的方式有点反人类..不能跳,必须进度条全部跑完才算,但是正常看课程多少都会跳着看,比如说有些地方没听清然后回看,结果到最后我没有一门课是听完的,总是缺百分之几。笔试时间原本限定2个小时,但实际只有20道选择题,十几分钟就做完了。做完可以看到笔试排名,当时看到排名是第二的时候,想着还有戏,结果最后连面试机会都没有,泪。

原本的想法是想实操绕过反调试的,刚好以前这道移动安全挑战赛的第二题是有反调试的,于是拿来练手,过程中也对动态调试有了更深的一些理解。

方法一

1.反编译apk可以看到securityCheck是校验的函数,但是在so里

2.用ida打开so文件,分析securityCheck方法,主要实现的逻辑是比较字符串

找到一个字符串wojiushidaan,输入但是不正确,于是打算动态调试。如果直接在该函数下断点,然后进行调试,应用会直接退出,说明在这个函数之前可能存在着反调试的工作。

通常反调试可能在JNI_Onload或.init段的位置,因此我们在JNI_Onload下断点,进行调试。

3.开始动态调试,绕过反调试。调试的步骤如同上一篇文章的方法二所写。
(0)在JNI_Onload下断点
(1)启动android_server
(2)转发端口23946
(3)以调试模式启动应用,adb shell am start -D -n com.yaotong.crackme/.MainActivity
(4)ida挂载,process option,attach process
(5)启动ddms,jdb -connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8700
注:如果这里ddms上没有显示该进程,那么说明可能应用没有允许调试,可以修改Androidmanifest文件中的application标签,添加android:debuggable=”true”,重编译签名,重新安装应用。
(6)ida按运行,跳到JNI_Onload的地方了

(7)F8单步跟踪,直到PC走到C58这个位置,出现了警告,并且应用也退出了调试模式

(8)根据上述的反馈,可以判断BLX跳进去的这个地方可能有问题,于是我们重新挂载调试一遍。到R7这里,我们F7进入该函数,看到这里开了个线程,是做了检测反调试的工作

(9)再一次重新挂载动态调试,在单步跟踪到C58之前,nop掉C58这个地方。按F2(或右键->edit)修改为0000A0E1,在按一次F2应用修改。这一次平安无事地过了C58.

(10)按运行,然后在应用的输入框内输入,点击按钮。就跳到了securityCheck方法

(11)继续F8.根据之前静态分析的结果,可以定位这个地方。R0地址存的是我们输入的值,R2地址就是我们想要的flag.

(12)其中,过反调试的方法除了nop掉反调试检测的地方。网上还有大神提出使用Kill调试技巧。

该技巧是QEver 在《MSC的伪解题报告》中提到的。利用kill我们可以让程序挂起,然后用ida挂载上去,获取有用的信息,然后可以再用kill将程序恢复运行。我们还是拿自毁程序密码这个应用举例,具体实行方法如下:
1 首先用ps获取运行的app的pid。

2 然后用kill -19 [pid] 就可以将这个app挂起了。

3 随后我们用ida attach上这个app。因为整个进程都挂起了,所以这次ida挂载后app并没有闪退。然后就可以在内存中找到答案了。

4 如果想要恢复app的运行,需要将ida退出,然后再使用kill -18 [pid]即可。

方法二

在分析securityCheck方法时候,我们发现有一个android_log_print的方法,该方法会打印一些调试信息,那么我们尝试通过该log方法将flag的值输出来。具体方法如下:

  • 将从0x1284到0x129C处都用NOP改写(NOP为空操作)
  • 在0x12AC处调用android_log_print函数
  • 为了不影响R1的值,把0x12A0处的R1改成R3
  • 将0x12A4处的R1改成R3
  • 将0x12A8处指令改成MOV R0,#4
    因为so为二进制文件,所以我们修改的也是二进制。
  • NOP对应的二进制值为00 00 A0 E1
  • android_log_print对应的二进制值为88 FF FF EB
  • 0x12A0处的值应改为60 30 9F E5
  • 0x12A4处的值应改为07 20 93 E7
  • MOV R0,#4的值为04 00 A0 E3

在ida上直接修改只是会保存到相应的数据库中,而我们实际修改要通常十六进制编辑器直接对so文件进行修改。修改完后,重打包apk,运行,观察log信息。