Skip to content

hidetag/CheckIn

Repository files navigation

我不想我不想我不想迟到~

公司使用的是xxapp打卡。要想自己打卡, 那么我抓包获取接口和参数,自己组装,自己访问接口即可。 说干就干,我开始在登录界面进行抓包:


Expand to collapse animation

从图上可以发现:

  • 在请求的时候,herades 里面有一些参数,包括了custom-device-idcustom-versioncustom-oscustom-company-idx-json-web-token等,这些内容是自定义header加上去的,后期调用接口时可能会用到
  • 采用了https连接

既然XXX采用https方式,我们没有证书,就无法拦截获取信息,接口调用基本行不通了,那么我们采用AccessibilityService辅助功能的方式进行打卡如何呢?

思路是:将一台手机放到公司,连接网络,另一台手机远程QQ发送消息,公司这台手机接收到消息,点亮屏幕,向上滑动解锁,打开XXX,此时我们的打开app是在运行的,然后通过AccessibilityService进行辅助点击从而进行打卡。或者直接设置定时器,时间到之后自动触发以上过程并打卡。但这种思路对进程保活有相当高的要求,不太好实现。


使用https之前的XXX,肯定是http,那么http接口今安在?

Expand to collapse animation

居然200,而且从返回的json来看,登录接口对于服务器的逻辑来说是没问题的,应该是在使用中,那么下一步我们只需要拿到入参就行。


下一步,反编译xxxx.apk,用到的工具是AndroidCrakTool

Expand to collapse animation

这里要提一下,反编译后我们能拿到资源文件们,资源文件对于定位页面,控件,以及此控件接下来的逻辑是至关重要很有帮助的。

  • 反编译后,将AndroidManifest.xmlres文件夹留下,其他的删除即可,因为我们此次不对smali进行分析
  • 另外,反编译后我们发现XXX并没有对代码进行加壳,只是单纯的混淆了。所以这就更加轻松简单

接下来,我们将XXX.apk后缀名改为zip,然后解压,得到如下内容:

Expand to collapse animation

可以看到,得到了两个dex文件,一个classes.dexclasses2.dex,这是因为他的方法数超过了65536,进行multidex的结果。现在我们使用AndroidCrakTool对这两个dex进行dex2jar,目的是将dex转成jar包,方便我们阅读源码。

Expand to collapse animation

得到jar包之后,我们用JD-GUI打开阅读,也可以使用AS或者IDEA进行源码阅读。这里采用JD-GUI


打开这两个jar如下图:

Expand to collapse animation

现在来理一理思路,我们刚才测试的是登录接口,我们目的是打卡,那么我们就需要登录后,得到token,然后带上token和一大堆参数进行打卡接口的访问,所以第一步,我们需要得到登录接口的参数。


我们通过使用TopActivity,在手机上找到登录界面的Activity名字。

从设备左上角可以知道这个界面的名字和包名,所以我们在JD-GUI中找到对应的包名进入寻找登录界面。由于我们有两个jar,所以就先挨个找吧。但从顺序来说,这个登录界面一般会在dex1中,当然这也是猜测,不过一般按照代码量和顺序来看的话是这样的。果不其然,如下图:

Expand to collapse animation

从界面上看,我们是点击了button之后进行网络请求的,所以我们看成员变量,发现一个button,变量名i,然后紧接着下面有个b()方法,内部将i初始化了,findviewbyid()内部传入的正是这个buttonidR文件中的静态常量值。这里插一句,如果有需要对界面和id进行分析的话,就需要从这些dex中找到R文件,然后将这个id的数值拿去寻找匹配,就能在R文件中反向得到这个控件的id,然后将这个id拿到之前反编译后的res文件夹中搜索匹配,从而得到布局文件,控件id等。当然也能通过ASDDMS进行布局分析,从而得到id,不过那个id是混淆后的,在jar中是无法找到的,因为jar中使用的idint静态常量。

接下来我们将i变量的id2131362755用来进行搜索,得到设置点击事件的地方。这里为何不直接用变量i呢?因为i是混淆后的,搜出来可能会有很多,不好排除。

Expand to collapse animation

从图上可以看到,我们找到了onClick()回调,并且找到了点击后的逻辑。图中有个方法,叫executeOnExecutor(),看起来像是AsyncTask的线程池执行方法,我们看看是不是,这时候点击前面new b(),看看这个b对象是啥,如下图:

Expand to collapse animation

可以看到果然是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()

Expand to collapse animation


现在回过头来分析doInBackground()

    this.b = b.w(this.d, this.e);

我们点击w()进入看看:

Expand to collapse animation

可以看到,这个b对象的w()方法,就是组装登录接口所需参数的,登录接口需要2个参数,最下面那个是接口地址,红色部分是一串字符串。而通过大码部分的字符串,我们可以知道第二个参数是密码,那么后面跟一串字符串是什么呢?是不是加密?,我们点击e.a()中的a()方法去看看:

Expand to collapse animation

从图上可以看到a()方法接收一个参数,联系刚才组装数据的地方,可以知道,密码是由明文加后面红色部分字符串,再整体经过MD5加密之后的。至于为何知道是明文密码,我们返回到LoginActivity,在AsyncTask实例化的时候传入了两个参数,后者就是密码。这个密码字符串的获取方式是反推出来的,如下图:

Expand to collapse animation

所以,现在我们有了接口地址,参数,加密方式,我们试试看能否访问成功。

经过调试,登陆成功,server返回了一堆数据,其中包括了token,id等:

Expand to collapse animation

我们现在相当于完成了50%

接下来的步骤要比之前简单太多了。通过抓包,获取到打卡接口的大概路径,然后在刚才组装登录接口参数的b类中,查询匹配这个接口地址,于是得到了打卡的完整接口地址。并且得到了入参。剩下的就是慢慢组装数据了。我们需要打卡,那么就需要经纬度。通过反编译发现他是用的是高德地图,于是我们使用高德的地理位置反编码,将我们想打卡的位置的经纬度得到,然后传入参数体,从而实现登录并打卡。


其实整个过程走下来,最主要的几个点:

  • 在替换成https后,原http接口未关闭,可能是为了兼容老版本
  • apk未进行更深层的保护,仅仅只是混淆
  • 密码加密的关键信息未进行有效保护,直接暴露了出来

最后,这次尝试主要是利用了http接口未关闭的漏洞,其实说到底也就是一次抓包分析数据的过程。


  • 以上敏感信息均做打码处理
  • app名字也替换成了XXX
  • 请勿用作商业用途和非法途径,仅供学习参考
  • 如有侵权,联系我删除

联系我

About

A process to decompile xxapp for checkIn

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages