apktool,dex2jar,jd-gui简单使用与实战

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/luoyanglizi/article/details/50482426

前言

最近项目里要实现一个TimePicker,类似于这样的

我一看,瞬间想起了手机上的某APP,他上面就刚好有类似的效果

本来项目时间就有点赶,自己慢慢写这个控件时间上也有点来不及了,而且他又那么的像,于是,嘿嘿嘿…

正文

下载安装apktool,dex2jar以及jd-gui

这三个软件都是免费的,下载地址Google一下也能轻易的搜到,这里还是简单都是汇一下总。

apktool下载地址
dex2jar下载地址
jd-gui下载地址

dex2jar在sourceforge上面,建议代理开全局访问。

OK,下载好了之后就开始安装。
首先是apktool。运行apktool是需要Java环境的,不过我相信需要用到这个软件的人电脑里肯定是有JDK的,这个就不赘叙了。

  1. 在下载apktool压缩包的同一个文件夹里新建一个文本文件,写入
@echo off
if "%PATH_BASE%" == "" set PATH_BASE=%PATH%
set PATH=%CD%;%PATH_BASE%;
java -jar -Duser.language=en "%~dp0\apktool.jar" %1 %2 %3 %4 %5 %6 %7 %8 %9

并将这个文件命名为apktool.bat。
2. 将刚刚下载的apktool的压缩包更名为apktool.jar(刚下载的时候名字里应该有版本号,干掉他)。
3. 成功。

dex2jar和jd-gui都是绿色版的,不需要安装,下载之后直接解压就好了。

使用apktool得到Android apk的资源文件

一般来说拿到一个apk文件之后想要得到自己想要的部分的代码一个很重要的突破口就是图片和xml文件,尤其是在你想要得到的部分是一个自定义控件的时候。因为图片和xml文件的名字是不会被混淆的,如果编写这个程序的人秉承了良好的代码规范的话,你就可以很容易的猜出你想要的界面使用的那些图片的名字,甚至猜出那个界面或者控件的xml文件的名字,继而找到控件的包名——幸运的是,包名也是不会被混淆的。继而就可以找到相应的Java文件——这是像我这样的小偷的幸运也是像我这样的开发者的悲哀。

ok,接下来该怎么用apktool得到apk的资源文件呢?我们知道,想要看到apk里面的图片是很简单的,直接用WinRAR之类的解压器直接打开apk文件就可以得到图片——也可以看到布局文件或者Manifest文件等,但是他们是被混淆过的,打开是一堆乱码。这个时候就要用到apktool了。

  1. 将想要反编译的apk文件,假设apk文件的名字是base.apk,放到apktool的文件夹下。
  2. 打开控制台,进入apktool所在的文件夹。
  3. 输入apktool d base.apk,敲回车。

然后等一会儿你就会发现在apktool所在的文件夹里面多了一个叫做base的文件夹,进去之后是这样的

这个时候res里面的xml文件就都是可读的了。可以看到,还有一些奇奇怪怪的文件夹,比如smali和unknown,其中smail是apk中的Java文件转换过去的,Android采用的是java语言进行开发,但是Android系统有自己的虚拟机Dalvik,代码编译最终不是采用的java的class,而是使用的smali。我们反编译得到的代码,jar的话可能很多地方无法正确的解释出来,如果我们反编译的是smali则可以正确的理解程序的意思。但是smali有自己的一套语法,而且比较的晦涩难懂,所以虽然他要比反编译出来的jar文件准确一些,但是在大多数情况下我还是更倾向于看反编译出的jar文件。

既然都已经得到了布局文件,那么现在就来找目标界面所在的xml。很显然我的目标名字里含有time或者picker这类的单词,我很快就找到了我的目标——一个叫做time_picker.xml的文件——也许原来的APP里面这个控件在多个地方都有出现,所以原作者把它单独抽取出来了。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center_horizontal"
    android:gravity="center"
    android:orientation="horizontal">

    <net.simonvt.calendarview.CalendarView
        android:id="@id/calendar_view"
        android:layout_width="245.0dip"
        android:layout_height="280.0dip"
        android:layout_marginLeft="16.0dip"
        android:layout_marginRight="16.0dip"
        android:layout_weight="1.0"
        android:focusable="true"
        android:focusableInTouchMode="true"/>

    <LinearLayout
        android:id="@id/pickers"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1.0"
        android:gravity="center"
        android:orientation="horizontal">

        <net.simonvt.numberpicker.NumberPicker
            android:id="@id/month"
            android:layout_width="48.0dip"
            android:layout_height="wrap_content"
            android:layout_marginLeft="6.0dip"
            android:layout_marginRight="6.0dip"
            android:focusable="true"
            android:focusableInTouchMode="true"/>

        <net.simonvt.numberpicker.NumberPicker
            android:id="@id/day"
            android:layout_width="48.0dip"
            android:layout_height="wrap_content"
            android:layout_marginLeft="6.0dip"
            android:layout_marginRight="6.0dip"
            android:focusable="true"
            android:focusableInTouchMode="true"/>

        <net.simonvt.numberpicker.NumberPicker
            android:id="@id/year"
            android:layout_width="42.0dip"
            android:layout_height="wrap_content"
            android:layout_marginLeft="6.0dip"
            android:layout_marginRight="6.0dip"
            android:focusable="true"
            android:focusableInTouchMode="true"/>

        <net.simonvt.numberpicker.NumberPicker
            android:id="@id/hour"
            android:layout_width="48.0dip"
            android:layout_height="wrap_content"
            android:layout_marginLeft="16.0dip"
            android:layout_marginRight="5.0dip"
            android:focusable="true"
            android:focusableInTouchMode="true"/>

        <TextView
            android:id="@id/colon"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text=":"
            android:textColor="#ff000000"
            android:textSize="16.0sp"
            android:textStyle="bold"/>

        <net.simonvt.numberpicker.NumberPicker
            android:id="@id/min"
            android:layout_width="48.0dip"
            android:layout_height="wrap_content"
            android:layout_marginLeft="5.0dip"
            android:layout_marginRight="10.0dip"
            android:focusable="true"
            android:focusableInTouchMode="true"/>
    </LinearLayout>
</LinearLayout>

我们可以很清晰的看到,我最终希望的效果是五个NumberPicker拼凑出来的,而且我还知道了他的包名是net.simonvt.numberpicker,那么接下来几乎可以直接动手粗暴的获取apk反编译之后的jar文件了。

使用dex2jar获取jar文件

在用dex2jar的时候我还出了一点问题,试了好几次都不能成功的搞定,等我将正确的方式说了之后一会儿再分享坑爹的经历。

  1. 首先将目标apk文件的后缀改为.rar,比如base.apk改为base.rar,方便解压。
  2. 解压刚刚得到base.rar文件。可以看到解压出来的文件里面有一个的后缀名是.dex,名字一般来说是classes.dex,反正他是什么一会儿就输入什么。没错,dex2jar就是对他起作用的。
  3. 进入dex2jar的那一堆bat命令所在的文件夹,找到那个名字里面带有dex2jar.bat的bat命令,我的这个版本是这个

  4. 打开控制台,进入dex2jar所在的文件夹,注意,是那个有一大堆bat命令的地方,那才是终点。

  5. 输入命令 d2j-dex2jar.bat classes.dex的全路径(比如:E:\lypeer\classes.dex),敲回车。

然后稍等一会儿就可以看到在dex2jar的文件夹里多了一个jar包,像这样的

这是正确的流程。然而一开始我用dex2jar的时候踩到了好多的地雷:(。
有可能是dex2jar的版本不一样的原因,有好多地方都和网上搜到的教程不一样。比如我看到的教程他输入的命令是 dex2jar.bat %class.dex的地址%class.dex 简直坑啊…这命令一共就两部分,两部分都是错的。第一部分根本就没有那个命令,人家包里的命令是d2j-dex2jar.bat,第二部分明明是classes.dex他写成了class.dex……不过这有可能是由于版本的原因,大家要善于自己找这些命令的正确书写方式。

使用jd-gui查看得到的jar包

然后怎么看这个jar包呢?这个时候jd-gui就起作用了。
先前说过将下载来的jd-gui解压就好了,解压之后会有一个叫做jd-gui.exe的可执行文件,双击点开,然后根据目录打开刚刚得到的jar包或者直接将jar包拖进去,就可以看到反编译之后的结果了。

可以看到,jar包里面的文件是根据包结构排列的像这样

而我之前已经知道了我的目标的包名,所以很容易我就找到了我的目标

点进去就是目标代码了,当然具体的代码肯定是经过混淆的,比如参数都是aa,bb,cc啦,方法名都是a,b,c,d啦,都很常见,这个时候就取不得巧了,慢慢研读吧,读得多了掌握了一些技巧之后其实还是很快的。

后记

到最后,其实我发现我的目标是一个开源库:)

猜你喜欢

转载自blog.csdn.net/luoyanglizi/article/details/50482426