Bash玩转脚本4之搞一套完整的Android反编译与分包工具

一、前言


正在搞IOS的微信支付和支付宝支付,焦头烂额之时,天上掉下来一个Android分包工具的需求,觉得还蛮有意思,其实之前一直想搞一个类似的东西,正好趁着这次机会实践一下。

[原文地址]

(http://blog.csdn.net/yang8456211/article/details/52513354 )

(先说清楚需求,这个分包工具要干什么)

从产品角度

拿到一个apk安装包,然后用这个包去生成n个包,这n个包需要有特定的标示,能够根据包的标示去收集信息,而且这个n个包彼此不能覆盖安装。

从技术角度

对于这个需求,关键点在于三个点

1. 怎么去生成n个包?

2. 怎么修改apk的标示?

3. 怎么使得这n个包不能覆盖安装?

二、Just do it

2.1 首先我们自己制作一个简单的apk包

这个apk包包含两个功能点:

  • 获取一些包的基本信息,例如应用包名
  • 获取一些Meta信息,用来区分我们所打的包

因为这篇文章主要在讲bash和apk打包,对于Android代码就不赘述了,贴出来参考。

(获取应用包名)

        PackageInfo info = null;
        try {
            // 获取包名
            info = this.getPackageManager()
                    .getPackageInfo(this.getPackageName(), 0);
        } catch (NameNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        // 当前版本的包名
        pgName = info.packageName;

(获取Meta信息)

        PackageManager pm = this.getPackageManager();

        ApplicationInfo appInfo = null;
        try {
            appInfo = pm.getApplicationInfo(this.getPackageName(),
                    PackageManager.GET_META_DATA);
        } catch (NameNotFoundException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        // 读取meta的内容
        msg.append(appInfo.metaData.getString("SDK_CHANNEL"));

这里我们读取了SDK_CHANNEL这个信息作为包的标示,需要在Android Manifest中配置好相关的Meta data。

    <meta-data android:name="SDK_CHANNEL" android:value="天降正义" />

运行时截图

可以看到现在的包名是com.example.testmultipac,渠道是天降正义~

接下来我们就开始着手一个一个解决问题

三、开始处理我们的包

3.1 怎么去生成这个n个包?

想要生成多个包,必须涉及到需要把apk进行反编译,然后重新生成apk包的过程,因此我使用了apktool这个工具。

注:apktool 有1和2两个版本,两者语法有些许不同,在这里使用了apktool_2.1.0这个jar,当然你也可以使用apktool1;window可以直接调用apktool.bat的批处理,事实上也是调用了apktool.jar。

apktool指令:

解开apk包:

java -jar apktool d -f 输入的apk路径 -o 输出的文件夹路径

重新生成apk包:

java -jar apktool b 上一步解出的文件夹路径 -o 输出apk路径

注:这里使用的apktool2,因此有-o这个参数,apktool是没有的,请注意。

了解了apktool的指令后,我们便可以方便的实现apk的解包和组包,在组包的会后通过修改包的名称,就可以生成多个不同名的包了。

例如:

do_repac(){

    outapk=$apkpacpath"/"$game_package_name".apk"

    # apktool重新回包 以免apktool的一些临时改动
    java -jar ./tool/apktool/$APKTOOL_JAR b $unpacpath -o $outapk
}

上面的outapk即为 $apkpacpath”/”$game_package_name”.apk”

game_package_name为当前包的包名。(如果能做到包名不同,则生成的apk的名字便不同)

3.2 怎么修改apk的标示?

目前例子来说,我们apk的标示是”SDK_CHANNEL”这个Meta字段,我们可以通过修改这个字段来实现我们对包的区分。当客户端对服务器发起请求的时候,带上这个字段,服务器便可以方便的知道是哪个包进行的请求了。

那我们要怎么修改这个字段呢?

在此我使用了sed,一个方便替换的文本的指令。

(想要见识sed对字符串的替换,可以看我的这篇文章)

Bash玩转脚本3之几个指令有趣的筛选京东评价

指令为:

sed -i ‘‘ "s~^.*<meta-data android:name=\"SDK_CHANNEL\".*~        <meta-data android:name=\"SDK_CHANNEL\" android:value=\""$game_channel"\"/>~g" $manifest

在此我稍作解释,如果有兴趣的朋友可以去google或者百度才能系统的学习。

1)sed "s~原字符串~新字符串~g" 文件路径 这是sed最基本的指令, “~”符号可以换成很多符号,三个”~”对应更换即可.

2)sed -i

通过 man sed 可以查到sed的基本指令(OSX 系统)

意思是不备份,直接在原文件上面进行操作。

注:在linux上可以直接使用 sed -i,而在Unix上需要sed -i ""

3) ^.*<meta-data android:name=\"SDK_CHANNEL\".*

这一段是正则匹配,用于匹配到SDK_CHANNEL那一行,sed是一行一行进行扫描的,如果遇到能够匹配的就会进行替换。

4)"$game_channel"这个是bash的取值,相当于一个变量,这里我是取game_channel这个变量

到现在,我们已经能够把包解出来,然后使用sed去修改里面的标示,看样子已经成功了一半了。

3.3 怎么使得这n个包不能覆盖安装?

涉及到这个问题,我们需要对Android的基本知识进行一个简单回顾。

Android通过什么来保证应用的唯一性?

答案是包名和签名。

  • 如果两个apk,包名相同,签名也相同,则会根据versionCode的值来决定是否会覆盖,如果后一个apk的versionCode比较大,才能够覆盖安装。
  • 如果包名相同,签名不同,则会被识别为不安全的应用,会给予提示,安装的结果会是后一个apk会删掉前一个apk,然后进行安装。
  • 如果包名不同,签名相同,则代表着同一个开发者的应用,被识别为不同的应用。(看来这样就可以实现我们的不覆盖安装了)

在修改包名的时候,我同样是用了一系列指令。(下意识写的指令,并没有考虑到是否最好,如果有更好的指令可以给我留言)

    old_pacname=`cat $manifest | grep "package=" | head -n 1 | awk -F ‘package=\"‘ ‘{print $2}‘ | awk -F ‘\"‘ ‘{print $1}‘ |  xargs echo `
    echo "==>"$old_pacname
    sed -i ‘‘ "s~package=\""$old_pacname\""~package="\"$game_package_name\""~g" $manifest

讲一下思路:

1. 先把”package=”关键字的那一行抓出来(这里是为了抓包名)

2. 使用两次awk取出 package=后面的包名(得到当前的包名)

3. 当前的包名赋值给old_pacname

4 .使用sed替换旧的包名为新包名,新的包名为game_package_name这个变量的值。

至此我们已经弄清楚了其中的知识点,对于一些难点也有了一定处理办法,接下来我们便要开始做一个脚本去自动化实现Android的反编译和分包了。

3.4 来看看我们的流程

Created with Rapha?l 2.1.0开始获得参数apk解包修改包内参数和包名apk组包签名结束

可以发现,在这个流程的最后一步,还有个签名的过程,那怎么进行签名呢?

3.5 签名过程

我们是通过jarsigner这个工具对apk进行签名的,如果不签名的应用可是无法安装的~

那个这个jarsigner是什么呢?其实这个是jdk自带的对jar包进行签名的工具,我们可以在安装的java指令的同级目录找到它。

通过直接输入jarsigner指令,可以得到提示

用法:

    #         显示信息              签名文件                   签名密码                生成apk                                            未签名apk        alias
    jarsigner -verbose -keystore $keystore_name -storepass $SIGN_PASS -signedjar $sign_apkname -digestalg SHA1 -sigalg MD5withRSA $unsign_apkname $SIGN_ALIAS

每个参数的意思注释都标志的很清楚了~

四、make Auto

下面讲讲脚本的思路

4.1 实现两个调用模式

第一种)所有的参数从外部传递调用,Mode为1时

第二种)读取本地的配置文件,Mode为0时,可以实现批处理生成多个包

功能说明:

help_info() {
cat << ENTER
     ============= Auto pac For game =============
     Version: 1.0
     Date: 20160907
     Usage: Auto repackage For the game, modify package name and subchannel
     e.g.:
        Mode0: sh autopac.sh inputApkPath gamename
        Mode1: sh autopac.sh inputApkPath gamename channel outputApkPath
            inputApkPath: 待分包的apk路径
            gamename: 游戏名称英文首字母小写
            channel: 渠道号
            outputApkPath: 完成输出apk的路径
     ============= Auto pac For game =============
ENTER
}

参数由外部输入就不赘述了,简单的赋值即可。

对于Mode=0时的读取配置文件一般是通过awk来实现的。

4.2 使用awk读取配置文件

例如配置文件的内容是这样

[package]
package1=d101
package2=d102

我们通过awk取出对应的d101,和102出来

read_config() {
    inifile=$1 #$1为配置文件的位置
    _readIni=`awk -F ‘=‘ ‘$1~/‘package[d]*‘/{print $2}‘ $inifile`
    echo $_readIni
}

稍微解释一下:

1. awk -F ‘=’ 为按照’=’,进行字符串分割

2. package[d]*为正则表达式,用来匹配package1,package2这种类型的一行,所以配置文件中可以有很多个package

3. {print $2} 就是打印出用’=’分割的第二个字符串,即’=’号后面的内容。

(假如我的标示不止1个怎么办?)

例如我的标示有三个,channel、subchannel、payway分别对应着渠道号、子渠道、支付渠道,那这个时候怎么办呢?

我们可以把配置文件写成这样:

package1=d101:subchannel101:1
package1=d102:subchannel102:2

然后在按照上面的做法,我们取出了 ‘=’ 右边的值,例如d101:subchannel101:1

我们便可以通过bash的字符串分割来做:

    game_payway=${1##*:}
    temp=${1%:*}
    game_subchannel=${temp##*:}
    game_channel=${temp%:*}

这样便可以取出payway等值了,关于bash的字符串分割,可以自行百度

基本的东西都讲完了,我们来看看最终的效果:

五、实现效果

以mode为1的批处理为例子:

1)配置文件配置了4个不同channel的包:

[package]

package1=yingxiongbuxiu:英雄不朽
package2=wushiyidao:午时已到
package3=laidianyinyue:来点音乐
package4=ronghuohexin:熔火核心

2)执行脚本:

sh autopac.sh ./TestMultiPac.apk mszl

TestMutiPac.apk就是我们最开始生成的一个apk,mszl为游戏的名称

3)执行效果:

看到已经生成了4个包:

4)安装效果:

如图生成了5个包

随便选取一个包的效果

源码地址:

https://github.com/yang8456211/AutoPacAndroid

杨光(atany)原创,转载请注明博主与博文链接,未经博主允许,禁止任何商业用途。

博文地址:http://blog.csdn.net/yang8456211/article/details/52513354

博客地址:http://blog.csdn.net/yang8456211

本文遵循“署名-非商业用途-保持一致”创作公用协议

时间: 2024-08-06 03:20:04

Bash玩转脚本4之搞一套完整的Android反编译与分包工具的相关文章

Bash玩转脚本3之几个指令有趣的筛选京东评价

Bash玩转脚本3之几个指令有趣的筛选京东评价 今天在工作中遇到了一个筛选和去重问题,饶有兴致祭出Mac(为了跟公司同步,写Android一直用Win-),三两个指令搞定了去重复筛选问题,回到家中意犹未尽,决定总结一下这些年使用bash做数据筛选和去重的经验. 传送门: Bash玩转脚本文章系列 一.数据 找数据是个头疼的问题,不过在百度过程中缺找到了一个蛮好的网站,推荐给大家http://www.datatang.com/,我从中下载了一个京东手机评价的数据,随便找了一组数据,命名为data.

Bash玩转脚本1之自己的脚本安装程序

Bash之打造自己的脚本安装器 前言 还是理所当然的前言,我一直想找一套管理脚本的"框架",能让自己杂乱的脚本有点规整.无奈眼界尚浅,未能找到. 因此萌生自己写一点优化脚本的工具来.新手可学习.高手请指正.今天先写一个脚本的安装器,目的在于写完并新脚本之后能够在shell的不论什么位置都能够便捷使用. 安装器干了啥? 一.配置文件 config.ini主要用于配置两个文件夹. 脚本的读取文件夹 生成软链接的存放文件夹 二.读取脚本 递归遍历读取scriptPath文件夹下的脚本文件,排

手把手教你搞懂 Android 反编译

我们知道,Android的程序打包后会生成一个APK文件,这个文件可以直接安装到任何Android手机上,因此,反编译就是对这个APK进行反编译.Android的反编译分成两个部分: 一个是对代码反编译,也就是java文件的反编译. 一个是对资源反编译,也就是res文件的反编译. 所需的工具 Android Studio:安卓开发IDE下载地址:https://developer.android.com/studio/index.html 反编译代码的工具: dex2jar: 把dex文件转成j

source、sh、bash、./执行脚本的区别

source.sh.bash../执行脚本的区别 source命令用法: source FileName 作用:在当前bash环境下读取并执行FileName中的命令.该filename文件可以无"执行权限" 注:该命令通常用命令"."来替代. 如:source .bash_profile . .bash_profile两者等效. source(或点)命令通常用于重新执行刚修改的初始化文档. source命令(从 C Shell 而来)是bash shell的内置命

shell命令中用source 和sh(或者bash)执行脚本的区别,以及export的作用

用户登录到Linux系统后,系统将启动一个用户shell,我们暂且称这个shell为shell父. 在这个shell父中,可以使用shell命令或声明变量,也可以创建并运行shell脚本程序. 当使用sh或者bash运行shell脚本程序时,系统将创建一个子shell,我们暂且称为shell子. 此时,系统中将有两个shell,一个是登录时系统启动的shell父,另一个是系统为运行脚本程序创建 的shell子.当一个脚本程序运行完毕,脚本shell子将终止,返回到执行该脚本之前的shell父.

详解shell中source、sh、bash、./执行脚本的区别

复制文章:https://www.jb51.net/article/128918.htm 这篇文章主要介绍了shell中source.sh.bash../执行脚本的区别,需要的朋友可以参考下 1.source命令用法: source FileName 作用:在当前bash环境下读取并执行FileName中的命令.该filename文件可以无"执行权限" 注:该命令通常用命令“.”来替代. 如:source .bash_profile . .bash_profile两者等效. sourc

linux bash启动停止脚本,第二弹

本文是之前的watchdate的shell脚本的改进wdate,同样先上图: 1)脚本加入chkconfig管理  head -5 /etc/init.d/wdate #!/bin/bash #auth:[email protected] # #wdate         Start/Stop the watchdate daemon # # chkconfig: 2345 71 55 chkconfig --add wdate 2)开始贴代码 #!/bin/bash #auth:[email 

bash小小小脚本

1.编写脚本/root/bin/systeminfo.sh,显示当前主机系统信息,包括主机名,IPv4地址,操作系统版本,内核版本,CPU型号,内存大小,硬盘大小. [[email protected] scripts]# cat systeminfo.sh #!/bin/bash HostName=`uname -n` Ipv4=`ifconfig |sed -nr '2s#.*addr:(.*)  Bca.*$#\1#gp'` Cpu=`lscpu|sed -n '13p'|tr -s ' 

bash编程练习脚本

1.写一个脚本,判断当前系统上所有用户的shell是否为可登录shell(即用户的shell不是/sbin/nologin): 分别这两类用户的个数:通过字符串比较来实现: 通过while循环遍历来实现. while循环的特殊用法(遍历文件的行): while  read VARIABLE; do 循环体: done  < /PATH/FROM/SOMEFILE 依次读取/PATH/FROM/SOMEFILE文件中的每一行,且将基赋值给VARIABLE变量: [[email protected]