反编译竞品借鉴其功能

竞品分析

Posted by JovenHe on May 29, 2019

很长时间没发文章,一个是工作忙,另一个是写了几篇文章后感觉虎头蛇尾的,不想献丑。所以磨蹭到现在分享个平时经验出来。

本文分享的是我在做项目的时候,经常会用到的方法,因为app嘛,大多数都是你抄我,我抄你,产品设计上很大程度上也是借鉴竞品的功能,有时候产品经理描述不清,直接让他把竞品发过来就OK了,所以在功能上,因为有些功能自己实现也能实现,但找轮子、调样式等一系列过程下来,还不如直接拿到竞品来借鉴一下。

严重声明 本文的意图只有一个就是通过分析app学习更多的逆向技术,如果有人利用本文知识和技术进行非法操作进行牟利,带来的任何法律责任都将由操作者本人承担,和本文作者无任何关系,最终还是希望大家能够秉着学习的心态阅读此文。

本文竞品是一款数据分析的app,BDP个人版,主要是把网站上建立的数据图表模型在手机app上展示出来,app上主要功能就是图表,我的目标是把它里面的图表功能模块和手势密码功能拿出来借鉴一下。

1.反编译apk

使用apktool.jar反编译得到相关资源文件

使用jadx -d out反编译得到所有java文件

使用jadx-gui查看源代码,结构如下:

反编译后文件目录.png

可以看到主要功能为图表库,其他都是开源可用的组件,至于为什么它要自己实现图表功能,而不使用开源最为广泛的hellocharts-androidMPAndroidChart,可能主要是开源图表框架并不满足需求吧,bdp主要有以下几种类型图表:

所有图表.png

开源图表框架并不能实现需求,所以我们直接拿来主义吧

2.编译mcchart

自己新建一个项目,然后选择File->New->New Module->Android Library,命名也为mcchart

  • 复制java文件

    直接复制反编译mcchart文件夹中的所有文件到mcchart Library中,点开一个文件, 就可以看到java文件中import的都报错了,然后根据反编译mcchart中的java文件的包名修改这个库的java路径名

  • 引入资源文件与第三方支持

    还是有不少报错,有的是缺少第三方支持库,有的缺少R.drawable等资源文件,缺少的一一引入即可,例如:

    缺少第三方库.png

    可见是缺少nineoldandroids这个开源动画库,直接在 GitHub 下载jar包引入即可。

    第三方支持库主要有百度地图和nineoldandroids的jar包,SVGMapView的library。

  • 修改代码错误

    在代码中还是有不少错误的,毕竟是从反编译成java代码的,错误中主要有父类错误、for循环错误、JADX WARNING这大致三种。

    父类错误

    这类错误是反编译后发现程序中应该声明的变量类型是父类,导致不能使用子类的某些属性和方法,比如Object i=0;switch(i){case 0:break}就会报错。

    例如:

    引用父类错误.png

    这种错误很常见,直接把父类修改为子类即可

    for循环错误

    反编译得到的java代码中是没有for循环的,因为for循环在Smali中是类似while循环,满足条件后break,所以反编译成java后得到的是while循环,所以循环语句都是又臭又长,还有可能有多个break出错,所以应该根据语义重写。

    JADX WARNING

    这个是反编译中很常见的错误,是jadx在把Smali转化为java的过程中方法内语句错误,方法就会变成这样:

    JADX WARNING.jpg

    解决方法是把jadx-gui中文件->设置->显示不一致的代码 勾选后保存,然后就可以看到jadx-gui中代码变成这样:

    JADX WARNING-true.png

    这样处理后的代码是伪代码,可能会有错误,所以还是需要对该方法的功能有整体的了解,并阅读Smali后进行适当修改。

经过上述修改后,mcchart基本可用了。当然,图表的使用方法就有待摸索了,如果用过hellocharts-android或MPAndroidChart,图表的使用上还是很容易上手的。

3.手势密码功能

开启 验证 关闭
开启手势.png 验证手势.png 关闭手势.png

可以看到这三个页面实现了手势密码的开启、验证与关闭。所以很容易拿到这三个页面的相关代码实现。

先新建Library,选择File->New->New Module->Android Library,命名为gestures

  • 复制java文件

    jadx搜索SetupLockActivity,根据包名路径修改Library,在对应位置新建class SetupLockActivity,复制jadx中的java代码,注意这次是和mcchart步骤不同的,是复制的jadx-gui中的java代码,并不是直接复制文件到Library中,因为mcchart中并不会混淆其中的类名、变量名以及方法名,而手势密码功能只是几个activity,所以其中大量类都是被混淆的,使用中有大量同名变量和类,非常不方便,但jadx-gui中开启了反混淆,例如:public class b 会变成public class C1712b,在使用中减少很多报错。

    例如在方法中有一个临时int变量b,在调用另一个类b中方法时,会认为b是这个临时int变量b,所以报错。

    没有反混淆-方法中的报错.png

    在 jadx-gui中开启了反混淆后不会出现该问题:

    反混淆后方法不报错.png

    开启方法如下:

    jadx反混淆.png

  • 引入资源文件和相关类

    看界面就知道手势密码功能引入了自定义的View,所以需要根据activity中的报错,引入layout、drawable、string、color等资源文件和自定义view类。

  • 解决报错

    分析主要功能

    有不少人看到没有引入文件报错了就开始找文件并引入,这并没有错,但在反编译他人项目的时候并不妥当,我们要从功能出发,不能只会Control +C/V,与功能无关的直接先注释掉。

    类似继承的BaseActivity相关的方法代码,成功或者失败后要保存的数据或者跳转都是无关的代码,应该根据运行结果再理清方法代表含义

    匿名内部类

    我们平时写的匿名内部类,在编译后其实会生成一个类。所以new Runnable或者new OnClickListener等匿名内部类会报错,例如:

    匿名内部类报错.png

    该类其实就是new Runnable实现的:

    匿名内部类.png

    直接修改即可:

    重写匿名内部类.png

经过修改后,SetupLockActivity页面就可以运行了。根据相应步骤可以实现其它页面的功能。

效果如下:

手势密码.gif

本文没什么技术难点,只是讲讲自己的项目心得,希望大家一起进步。