开篇之前,我一直考虑这算不算侵权?只是兴趣,如果有人告知侵权的话,立马删除。

我所说的数据不是指拿别人app中的图片资源。而是程序运行所需要的数据。

App中的数据无非两种,一种是网络数据,一种是本地数据。网络请求我们一般用抓包工具(Mac上的Charles 或者Windows上的Fiddler)来获取Api,然后再用程序循环请求,获取所有的数据。而另一种是app存储到本地的数据,一种是存储到文件中的,一种是存储到数据库中的。

快快查汉语词典

一次偶然的机会,发现快快查汉语词典这个app作为汉语词典来说,还算是比较良心的app,免费,而且界面还是比较干净的。而且词库比较全。所以我想获取这个词典的所有数据,作为自己的词库使用。像这种词典,一般汉字都用拼音散列开了。所以我想获取汉字和拼音的映射。好吧,用了一个周的时间,边学习,边反编译,并且学习了Smali语法。最终还是把数据解析出来了。

大体流程:数据解密--->数据格式化--->格式化后的数据

汉字查询结果页面

作为一个词典来说,我感觉这个app做的相当不错。有很多值得我们学习的地方。so,我给反编译了。

首先确定数据来源。

分析一下数据到底来源于网络呢,还是本地数据存储呢。这个很容易判断,第一次安装好app之后,断开网络,如果仍然能查询,说明本地有数据缓存,如果不能查询,说明必须要访问网络。好,测试之后我们发现能查询,说明本地可定有一份可供查询的数据存储。

有些app会做双重数据存储。也就是说数据源,既有网络也有本地,比如有道词典,会做一部分本地存储,详细信息要从网络查询。所以还要做,有网和无网情况下查询详情是不是一样,来判断本地是否存有所有的数据。经过比较发现本地确实有完整的数据存储

如果数据存储在本地,存在哪了?

猜测: 本地数据

理由: 像字--拼音--解释这种数据结构,一般不适合存放到文件中。

实践:数据库存放无非三个位置,一个是/data/data/包名目录下,一个是/sdcard/Android/data/包名,最后一个就是SD卡了,随便建个文件夹就可以存储。参考,Android文件存放位置,那么如何判断数据库文件存放在这三个位置中的那个呢?我们来一个个排除:

要访问真机的/data/data目录必须要root权限。当然我的测试机是root了的。发现里面并没有任何有价值的数据库。

/sdcard/Android/data/包名这个目录是可以访问的,adb shell的方式访问之后也没有发现任何有价值的数据。

那就剩下最后一个sd卡了。这个比较麻烦,因为这个路径不固定,可以任意创建文件夹。如果是测试机,那么sd卡上没有几个文件夹比价好排查。这里可以用一些小技巧。比如我们app的包名为com.kk.dict 所以按照一般程序员命名规则,这个文件夹如果真的在SD卡上的话,那么有很大的可能性和kk或者dict有关,哈哈,经过查找,在sd卡上有个叫kkdict的文件夹,最后发现所有的离线数据库都在这里面/sdcard/kkdict/dict/

其实上面的三种排查方式比较大众化,也就是可以用于所有的情况下的排查,但是在分析别人的app的时候,我们的方法还是比较灵活的,不拘泥于这么几种,比如我们要分析的这个快快查词典。并不需要这么麻烦。这个app在我的-->设置-->功能包下载里面能够设置离线的数据库的存储路径。

Paste_Image.png

由上图可以发现,在这之前的所有分析,都不用了,从离线路径可以分析出来,这数据查询就保存在本地,而且保存路径都可以看到了。

结果: 和我们猜想的一样。

好那接下来我们就从数据库中拿数据了哦~

可以看到/sdcard/kkdict/dict/目录下主要有以下数据库:

快快查词典包含的主要数据库

从名字结合app的界面可以大体分析出数据库中存储的内容。我们来看详解这个库,应该存储的是每个字的详细解释。用数据库查看软件查看一下我用的Navicate(在Mac上没发现什么好用的sqlite3可视化查看软件)。打开数据库,找到里面主要的表,这下懵逼了。表里的数据是用二进制Blob存储的。

xiangjie.db/xiangjie表

下面的主要任务就是把这个zhujie的字段表示的数据解析出来:how?这种分析主要从哪下手、我一般主要从两方面下手:直接分析数据库;从界面反编译代码后,从代码查询。显然后者难度很大,如果代码混淆了,读起来相当困难。我们先来实验第一种方式,看是否能够成功。也就是直接解析zhujie字段的二进制,翻译成字符串。

猜测这个二进制是什么:有这么几种可能,对象,直接把数据所对应的对象存到数据库,以二进制的方式;字符串,把字符串转换成二进制数据写入数据库;加密,这也是最头疼的方式,如果真的加密了,必须去源码中找到加密算法和相应的解密密钥。

试验:试着猜想一下,这种数据库中可能存放对象吗?我感觉以我的经验来说不大可能,这种存对象的方式,平台适用性太低。如果使用java存的对象,只能用java读出来,那么这个库完全无法在别的平台(如:IOS)上使用。这种不是不行只是不太理想,极少有程序员这么做。当时我猜测的最大可能是字符串的二进制格式,因为我一直以为这种数据没必要加密。所以,我就试着验证了一下。如何读数据库就不说了,参考;

从数据库以二进制的方式读入,然后用String解码。一运行,额。。。乱码??

测试代码及运行结果

从上图看出,以我多年解决乱码的经验(瞎搞),出现乱码大多数是由于编码方式不正确引起的。好,编码不对那我改还不行吗?

于是有了下图的测试代码:

对二进制进行不同的字符编码

额。。。全是乱码,从查词的结果来看一定包含中文,我知道的能处理中文的常用编码也就这么三种,你说全是乱码。这。。。

结果:上面猜想错误,0.0,只能继续猜测呗。

继续猜测: 会不会数据库存放的是Base64的二进制方式,作者会不会用Base64的方式对数据进行了简单的加密? 但是仔细一想,Base64主要作用是把二进制转换成字符来显示和表达的。把一个字符串,转换成二进制在转换成Base64再换成二进制,再存储。好像能有这种想法的人有点,那啥吧??既然没有别的办法也只能试试喽。测试代码就不给了,就是Base64的基本操作,就是流程绕了点,后来测试发现也是乱码。(:-

继续猜想:看了数据库的这个字段的数据真的加密了。只从数据库入手好像无法解决。加密有难有易,但是无论如何,他既然会显示到界面的数据是正常的明文,说明即使加密了,apk源码中也有解密代码。看了现在找到这个解密的代码是非常关键的。这个解密的代码也有难有易,如果做的简单点就是一个java的Util类。如果做的难了,用jni做到so文件中。但愿他在java中吧。这样反编译起来还简单些。

测试:要把apk中的dex拿出来反编译成jar,然后查看这个jar中的源文件。具体如何反编译拿到jar,不再给出,可以参考这个。参考 至于查看浏览这个jar包中的java代码,我主要借助两个工具jd-gui-1.3.0.jar和jadx-0.6.0为什么要接着两个,我能力有限,查看反编译后的java代码,如果这个代码被混淆了,读起来相当困难,而这两个tool反编译后的java代码各有优缺点。前者有代码跟进功能,后者的代码反编译的可读性比较好,但是后者代码综合性比较强,比如能简写的他会简写。这样读起来也比价困难。结合来看就轻松多了。

好,我们可以看到最终数据会被现实到,汉字查询结果页面。如下:

汉字查询结果页面2

那么我们找到这个页面,然后就可以进行数据分析了,接下来的问题,这个页面怎么找??

猜测:这是个Activity,既然是详情页面,那么根据中国程序员的英语水平命名的话,应该和Detail 和 Activity有关。好找一下。

jd-gui显示jar包文件

如图所示,可以看到,这个jar里面大多数是没有用的,都是些第三方的引入。被打包进来的。真正我们写的代码在如图箭头指向的包中。是主要的Activity。找来找去,还真找到了一个叫DetailActivity.class的类。哈哈...

打开一看彻底懵逼:全是a啊b啊的。这特么怎么看。没办法,反编译比人的工程代码,需要极大的耐心。慢慢来看,有些小技巧在里面,我们并不需要全看,要想理解大体思路,也需要一定的代码基础。至少自己独立架构过一个项目。或者参与过很多项目。

思路:接下来要做的就是找到显示着段文字的View--->找到这个View的赋值过程--->找到这个值得来源--->这个来源中一定包含解密过程这个思路想起了简单,但是操作起来想当复制,我们可以看到这个DetailActivity.class类大约有几千行代码啊。如何找?

猜测:据我所知,在Android常用的显示文本的控件也就那么三个TextView,EditText,WebView。到底是哪个,我们要借助于一个工具叫Android Device Monitor 这是分析比人程序布局的利器啊。如何使用?这个地方先空一下,改天补上 因为用起来不难,但是描述起来很烦人。来看分析截图:

字典详情页面分析截图

从红色箭头标出的部分看,6不6,这界面用了什么View,View的层级关系,View的Id都能得到。拿到了这些再去DetailActivity.class中分析是不是就简单多了。可以确定这个就是为WebView赋值而已嘛。找到WebView的赋值的地方,也就找到了数据源了。这时候就兴奋的去DetailActivity.class中找WevView了,我去,没有???why?

猜测:页面用了Fragment,数据在Fragment中,界面用了组合View,WebView在组合View中。分析到这里似乎难以用一种固定的方式分析了,好像要凭感觉?怎么办,转向layout 的xml文件,找点突破口。这时候就用到jadx出厂了,为啥?自己对比。

jadx

从图片中可以看到,我们很容易拿到了,这个activity的布局文件。打开它。

detail.xml

分析后发现果然,主要的数据都放到了ViewPager中。好啊,接下来的主要工作就转战这个ViewPager,在这个DetailActivity中可定有这个Viewpager的引用。继续用jadx。搜索这个ViewPager的id找到,他的引用。如下图。

查找ViewPager的引用

好嘛,兄弟,你在Activity中的引用叫this.B啊,让我这个好找啊。既然找到了ViewPager,我们想要ViewPager中的每一个Pager的数据,怎么找,找啥?找Adapter不论是啥,一定会有setAdapter这个方法。继续搜索。this.B.setAdapter

查找Adapter的设置方法。

一切如上图。其实感觉好的可以看到我们的方框框起来的就是我们最终要找的。好这个PagerAdapter的名字竟然叫j。Adapter有两种方式存在,一种是单独的文件,另一种是匿类的方式,这就是我们的开发常识了。先猜测就在本文件中吧。搜索Adapter.如下图:

Adapter搜索。

从上图中我们可以分析出ViewPager的View集合了,this.a.C认真读下代码,这个this指的是j也即是PagerAdapter的实例对象。而a,指的是DetailActivity.this,好了,集合对象找到了就是DetailActivity中的C,搜索this.C,结果如下图:

搜索this.C ViewPager的Pager页

图片中包含唯一的自定义View就是DetailContentView,打开它看看。哈,果然WebView就在这里面。如下图:

DetailContentView

这货对外暴露的设置内容的方法为a(string),好。在DetailActivity中可以看到:

this.U = (DetailContentView) inflate.findViewById(R.id.detail_zhujie_id);

this.V = (DetailContentView) inflate.findViewById(R.id.detail_xiangjie);

this.W = (DetailContentView) inflate.findViewById(R.id.detail_guhanyu);

this.X = (DetailContentView) inflate.findViewById(R.id.detail_kangxi);

this.Y = (DetailContentView) inflate.findViewById(R.id.detail_shuowen);

this.Z = (DetailContentView) inflate.findViewById(R.id.detail_wys_id);

我们从这里面随便拿一个分析就行。我就选this.W吧。这个对应详情页的古汉语展开的详情。

那么这个this.W要想设置数据可定调用了a方法。搜索this.W 大小写敏感。注意自己过滤一些无关的搜索。结果可以看到唯一符合条件的是:

搜索赋值方法

可以看到,这个p.c(this,this.aX.c)+this.aX.c)就是获取数据源的方法。猜测,这个p.c方法可能是某个帮助类。对数据进行处理,也可能是某个查询类根据传入的参数来查询,到底是什么呢?我们用jd-gui来帮助我们跟进代码。来跟进参数this.aX.c打这个东西。(P.S.这个p.c也是相当有用的。剧透一下用于字符串的格式化)如下图:

数据库查询类

可以看到 aX就是上图中a这个类的对象,而c就是这个对象的成员,在结合上面的拼音,我们断定,这个a类是和数据库表结构对应的Bean类。进而我断定这个a的外部类就是数据库表的查询类。查询方法在上面。数据库表结构如下图:

古汉语的表结构

从上上个图中,我们从a类的定义往上看,猜我看到了啥。哈哈,getBlob方法,很多时候感觉还是很重要的。一种熟悉的感觉有木有。一开始的时候我们就是用他读的数据的那个二进制字段。从这行代码往下读,看不懂?我也看不懂。但是我读出来,这个a类中的c字段就是我们要的东西。继续看这个c是怎么获取来的?

locala.c = q.a(paramList,i) //paramlist 就是我们的二进制byte数组,是数组的长度,哈哈,这个方法就是解密方法喽。

我们要做的就是找到,这个方法,把他提取出来,就能解密数据所有的二进制了。这是个静态方法,是比较独立的工具类。所以提取没有什么难度?但是也遇到很多问题,关键是有些加密代码看不懂。

万里长征走一半了?No,才刚刚开始。还记得我们要干嘛嘛?要拿到解密后数据的数据。继续吧:

用jd-gui跟进代码。q.a(byte[],int)。反编译查找方法时候一定注意方法签名。有可能都是特么的a 但都是重载,别找错了。这个方法传递一个加密后的二进制数据和他的长度进去,返回一个解密后的字符串。

我发现不能再往下写了,再写人家的加密算法就给拿出来了。

来看这个方法的签名:

解密方法签名

P.S.看反编译后的代码要学会自动过滤无关代码

这个方法有用的即使三行。而这三行中唯一不知道的就是d也就是d.getBytes()中的d,继续分析这个类看看这个d是如何获取的。a(byte[],int)是个静态方法,所以d不可能在构造方法中初始化,一定在这个方法内初始化的,为啥找不到???对比jadx,效果如下图:

jadx反编译a方法

从上图可以看到,jadx的反编译结果,比jd-gui多了一个调用a()a的空方法,这才符合我的猜想嘛。接下来看看这个a()的定义,只要能拿到d的值。这个解密过程就算完成了。哈哈,这个不能贴了,这是人家的密钥生成方式。不过这个方法我是真心看不懂,不过没关系,这个方法没有引用其他的东西,直接拷出来,引入生成一个d就行了。至此解密完成。如下图所示:

解密后的数据

这不太对啊。这数据格式太丑了,还包含什么乱七八糟的字符?要处理这些就是前面所说的字符串格式化。加入css样式和加入html标签。这个过程更是相当复杂。各种猜测和尝试,其中还借助了Smali文件,重新打包,打印log等。不过还好,最终成功了,我给封装成ExplainUtil,哈哈他的app中也是这么命名的,不过混淆过后就成了a,b,c。。。这种乱七八糟的东西了。

这篇文章写了五个小时~~~

app怎么调用mysql数据_教你如何拿别人APP中的数据相关推荐

  1. Python办公自动化实战 10 | Python-docx库:Python与Word的完美结合_教你如何管理Word表格中的数据?让你庖丁解牛游刃有余

    一.专题内容简介 本专题主要讲解了怎么删除Word文档中表格中的数据. 二.专题案例效果 三.专题内容 3.1 删除单元格数据 单元格数据的删除从本质上来说同赋值是一样的,只不过赋值为空字符串,即'' ...

  2. java如何向数据库中插入数据_如何控制Java代码向数据库中插入数据

    慕哥6287543 Java程序向数据库中插入数据,代码如下:123456789101112131415161718192021222324252627282930313233343536373839 ...

  3. 分批处理list中的数据_如何分批次处理List集合中的数据

    分批次处理list中的数据 package com.O0115; import java.util.ArrayList; import java.util.List; public class Lis ...

  4. java mysql 快速插入1000w条数据_教你88秒插入1000万条数据到mysql数据库表

    我用到的数据库为,mysql数据库5.7版本的 1.首先自己准备好数据库表 其实我在插入1000万条数据的时候遇到了一些问题,现在先来解决他们,一开始我插入100万条数据时候报错,控制台的信息如下: ...

  5. java将数据写入csv文件,从csv文件中读取数据

    全栈工程师开发手册 (作者:栾鹏) java教程全解 java将数据写入csv文件,从csv文件中读取数据 测试代码 public static void main(String[] arges){/ ...

  6. wpf mysql 框架_带有 WPF 和实体框架6的简单数据应用 - Visual Studio | Microsoft Docs

    使用 WPF 和 Entity Framework 6 创建简单的数据应用程序Create a simple data application with WPF and Entity Framewor ...

  7. spring批量写入mysql数据库_快速使用组件-spring batch(3)读文件数据到数据库

    tags: springbatch 1.引言 上一篇文章<快速了解组件-spring batch(2)之helloworld>对Spring Batch进行了入门级的开发,也对基本的组件有 ...

  8. php将excel数据导入mysql表中_【PHP】将EXCEL表中的数据轻松导入Mysql数据表

    在网络上有不较多的方法,在此介绍我已经验证的方法. 方法一.利用EXCEL表本身的功能生成SQL代码 ①.先在"phpmyadmin"中建立数据库与表(数据库:excel,数据表: ...

  9. mysql数据库中怎么删除一行_数据库教程_mysql如何删除表中一行数据?- 中国it教程网...

    mysql中使用DELETE语句删除表中一行数据,语句为"DELETE FROM 表名称 WHERE 列名称 = 值".删除所有行的语句为"DELETE FROM tab ...

最新文章

  1. AndroidStudio 生成Jar并混淆
  2. vscode如何及时提示flutter代码
  3. 1251: [蓝桥杯2015初赛]星系炸弹
  4. 如何在linux系统写程序文件,Linux应用程序使用写文件调试程序的方法
  5. 马库斯再谈AlphaGo Zero不是从零开始,AGI可能需要这十大先天机制
  6. IAR for stm8安装破解
  7. 通讯录管理软件Cardhop for Mac
  8. 央行二代征信系统即将上线 有哪些变化?
  9. Qt设计精美的登录注册界面(包含SQLite数据库应用)
  10. html datetime控件 到时分秒,日期控件:datepicker(bootstrap)支持时分秒
  11. 想进大厂必须要知道的Web安全问题
  12. Java学习day02-数据类型和运算符
  13. 十八家省级大数据管理局盘点
  14. 耦合器 功分器 合路器
  15. 西瓜视频 iOS Voice Over 无障碍适配实践
  16. JavaOO面向对象中的注意点(二)
  17. scrollY,scrollTo
  18. 什么是股票接口dde散户数量?
  19. PTA(每日一题)7-1 jmu-JavaPython-统计一段文字中的单词个数并按单词的字母顺序排序后输出
  20. 《创业家》杂志:警惕商业模式狂热症

热门文章

  1. 【Linux集群教程】07 块存储之 iSCSI 服务
  2. python目前版本强势英雄_王者荣耀S11赛季什么英雄强势 S11强势英雄推荐
  3. leetCode_Patching Array
  4. QTransform(图形平移旋转剪切变换)
  5. 第二篇:Haploview做单倍型教程2--分析教程
  6. 2019北航_夏令营
  7. 通俗易懂、简单粗暴地解决各类猴子分桃问题
  8. vmware和hyper-v的一个坑
  9. CSGO手套武器箱直接卖还是开了再卖?
  10. 把USB打印机映射到LPT端口