xxapp
打卡。要想本身打卡, 那么我抓包获取接口和参数,本身组装,本身访问接口便可。 说干就干,我开始在登陆界面进行抓包:从图上能够发现:web
herades
里面有一些参数,包括了custom-device-id
,custom-version
,custom-os
,custom-company-id
,x-json-web-token
等,这些内容是自定义header
加上去的,后期调用接口时可能会用到https
链接既然XXX采用https
方式,咱们没有证书,就没法拦截获取信息,接口调用基本行不通了,那么咱们采用AccessibilityService
辅助功能的方式进行打卡如何呢?json
思路是:将一台手机放到公司,链接网络,另外一台手机远程
app
是在运行的,而后经过AccessibilityService
进行辅助点击从而进行打卡。或者直接设置定时器,时间到以后自动触发以上过程并打卡。但这种思路对进程保活有至关高的要求,不太好实现。数组
使用https
以前的XXX,确定是http
,那么http
接口今安在?bash
竟然200
,并且从返回的json
来看,登陆接口对于服务器的逻辑来讲是没问题的,应该是在使用中,那么下一步咱们只须要拿到入参就行。服务器
下一步,反编译xxxx.apk
,用到的工具是AndroidCrakTool
:网络
这里要提一下,反编译后咱们能拿到资源文件们,资源文件对于定位页面,控件,以及此控件接下来的逻辑是相当重要颇有帮助的。app
AndroidManifest.xml
和res
文件夹留下,其余的删除便可,由于咱们这次不对smali
进行分析接下来,咱们将XXX.apk
后缀名改成zip
,而后解压,获得以下内容:ide
能够看到,获得了两个dex
文件,一个classes.dex
和classes2.dex
,这是由于他的方法数超过了65536
,进行multidex
的结果。如今咱们使用AndroidCrakTool
对这两个dex
进行dex2jar
,目的是将dex
转成jar
包,方便咱们阅读源码。工具
获得jar
包以后,咱们用JD-GUI
打开阅读,也可使用AS
或者IDEA
进行源码阅读。这里采用JD-GUI
。布局
打开这两个jar
以下图:
如今来理一理思路,咱们刚才测试的是登陆接口,咱们目的是打卡,那么咱们就须要登陆后,获得
token
,而后带上token
和一大堆参数进行打卡接口的访问,因此第一步,咱们须要获得登陆接口的参数。
咱们经过使用TopActivity
,在手机上找到登陆界面的Activity
名字:
从图中左上角能够知道这个界面的名字和包名,因此咱们在JD-GUI
中找到对应的包名进入寻找登陆界面。因为咱们有两个jar
,因此就先挨个找吧。但从顺序来讲,这个登陆界面通常会在dex1
中,固然这也是猜想,不过通常按照代码量和顺序来看的话是这样的。果不其然,以下图:
从界面上看,咱们是点击了
button
以后进行网络请求的,因此咱们当作员变量,发现一个button
,变量名i
,而后紧接着下面有个b()
方法,内部将i
初始化了,findviewbyid()
内部传入的正是这个button
的id
在R
文件中的静态常量值。这里插一句,若是有须要对界面和id
进行分析的话,就须要从这些dex
中找到R
文件,而后将这个id
的数值拿去寻找匹配,就能在R
文件中反向获得这个控件的id
,而后将这个id
拿到以前反编译后的res
文件夹中搜索匹配,从而获得布局文件,控件id
等。固然也能经过AS
的DDMS
进行布局分析,从而获得id
,不过那个id
是混淆后的,在jar
中是没法找到的,由于jar
中使用的id
是int
静态常量。
接下来咱们将i
变量的id
值2131362755
用来进行搜索,获得设置点击事件的地方。这里为什么不直接用变量i
呢?由于i
是混淆后的,搜出来可能会有不少,很差排除。
从图上能够看到,咱们找到了onClick()
回调,而且找到了点击后的逻辑。图中有个方法,叫executeOnExecutor()
,看起来像是AsyncTask
的线程池执行方法,咱们看看是否是,这时候点击前面new b()
,看看这个b
对象是啥,以下图:
能够看到果真是AsyncTask
。那么结果就显而易见了,这次请求使用AsyncTask
发起,因此咱们在AsynctTask
内部就能找到网络请求的相关内容了。先看第一个:
protected Void a(Void... paramVarArgs){
this.b = b.w(this.d, this.e);
return null;
}
复制代码
此方法一看就知道,他是doInBackground
方法混淆后的,由于他的返回值是Void
而不是void
。在这个AsyncTask
实现的时候,泛型定义以下:
private class b extends AsyncTask<Void, Void, Void>{}
复制代码
三个Void
,因此能够判定第一个a()
方法是doInBackground
。那么网络请求就在这里面了。再来看第二个a()
方法。
protected void a(Void paramVoid){}
复制代码
从返回值和参数来看,多是onCancelled()
和onPoseExcute()
,可是从总体代码和代码量来看,能够判定是onPoseExcute()
:
如今回过头来分析doInBackground()
。
this.b = b.w(this.d, this.e);
复制代码
咱们点击w()
进入看看:
能够看到,这个b
对象的w()
方法,就是组装登陆接口所需参数的,登陆接口须要2
个参数,最下面
那个是接口地址,红色部分
是一串字符串。而经过大码部分的字符串,咱们能够知道第二个参数是密码,那么后面跟一串字符串是什么呢?是否是加密?,咱们点击e.a()
中的a()
方法去看看:
从图上能够看到a()
方法接收一个参数,联系刚才组装数据的地方,能够知道,密码是由明文加后面红色部分字符串
,再总体通过MD5
加密以后的。至于为什么知道是明文密码,咱们返回到LoginActivity
,在AsyncTask
实例化的时候传入了两个参数,后者就是密码。这个密码字符串的获取方式是反推出来的,以下图:
因此,如今咱们有了接口地址,参数,加密方式,咱们试试看可否访问成功。
通过调试,登录成功,server
返回了一堆数据,其中包括了token
,id
等:
咱们如今至关于完成了50%
。
接下来的步骤要比以前简单太多了。经过抓包,获取到打卡接口的大概路径,而后在刚才组装登陆接口参数的
b
类中,查询匹配这个接口地址,因而获得了打卡的完整接口地址。而且获得了入参。剩下的就是慢慢组装数据了。咱们须要打卡,那么就须要经纬度。经过反编译发现他是用的是高德地图,因而咱们使用高德的地理位置反编码,将咱们想打卡的位置的经纬度获得,而后传入参数体,从而实现登陆并打卡。
其实整个过程走下来,最主要的几个点:
https
后,原http
接口未关闭,多是为了兼容老版本apk
未进行更深层的保护,仅仅只是混淆最后,此次尝试主要是利用了http
接口未关闭的漏洞,其实说到底也就是一次抓包分析数据的过程。
app
名字也替换成了XXX