apk的拆包重構(gòu)以及反編

前言

還是之前痛徹心扉的出包經(jīng)歷,出一點(diǎn)小問題就要重新出包,驗(yàn)證問題及其麻煩,浪費(fèi)了大量的非必要時(shí)間。所以這里想盡可能的優(yōu)化步驟,提升效率。文檔如正文,并且將下述步驟集成為shell文件,掛在附件,需要的話自取。

包體拆包重構(gòu)

工具下載

1. apktool,用于包體的拆解與構(gòu)建,從apk中提取圖片和布局資源。apktool下載
2. dex2jar,將可運(yùn)行文件classes.dex反編譯為jar源碼文件,版本選擇上要選2.1,2.0以及2.0之前的不支持MultiDex。dex2jar_2.1下載
3. jd-gui,查看jar源碼文件。jd-gui下載

工具安裝

apktool安裝

1. 根據(jù)apktool網(wǎng)站提示的下載方法,右擊wrapper script,鏈接存儲(chǔ)為apktool,不要帶拓展名
2. 下載apktool.jar,選擇第一個(gè)下載最新版本
3. 把a(bǔ)pktool_2.3.3.jar重命名為apktool.jar,然后把a(bǔ)pktool.jar和apktool一起拷貝到/usr/local/bin路徑下
4. 打開終端,輸入apktool命令,看到相應(yīng)輸出及為安裝成功

dex2jar && jd-gui

下載完dex2jar和 jd-gui解壓一下就可以了,復(fù)制到工作目錄方便操作。(順便對(duì)dex2jar提一下權(quán)限,不然會(huì)報(bào)權(quán)限問題)

拆包與重構(gòu)

1. 終端輸入cd path..... 進(jìn)入到測試apk所在目錄
2. test.apk 將包體拆解

apktool.bat d -o <output_dir> 

3. 根據(jù)各自需求,對(duì)文件夾內(nèi)的內(nèi)容進(jìn)行替換和修改
4. 將包體重構(gòu),此時(shí)包體未重簽過,所以是安裝不了的。

apktool.bat b -o <output.apk> <input_dir>

包體重簽

1. 將簽名文件移植到apk目錄下,方便操作
2. 確保機(jī)器上安裝了java環(huán)境
3. 終端進(jìn)入apk目錄下,執(zhí)行命令:

jarsigner -verbose -keystore [your_key_store_path] -signedjar [signed_apk_name] [usigned_apk_name] [your_key_store_alias] -digestalg SHA1 -sigalg MD5withRSA -storepass [StorePass]

****字段說明:****

  • [your_key_store_path]:密鑰所在位置的路徑
  • [signed_apk_name]:簽名后安裝包名稱
  • [usigned_apk_name]:未簽名的安裝包名稱
  • [your_key_store_alias]:密鑰的別名
  • [StorePass]:keystore的密碼

重簽之后的apk包就是可以用的了

java代碼的抽取

代碼的抽取只是一句命令行:

sh dex2jar-2.1/d2j-dex2jar.sh apk_path

這里著重說下運(yùn)行過程中遇到的問題:

問題一:資源包超兩個(gè)G

報(bào)錯(cuò)如下:

Exception in thread "main" java.lang.OutOfMemoryError: Required array size too large
    at java.nio.file.Files.readAllBytes(Files.java:3156)
    at com.googlecode.dex2jar.tools.Dex2jarCmd.doCommandLine(Dex2jarCmd.java:108)
    at com.googlecode.dex2jar.tools.BaseCmd.doMain(BaseCmd.java:290)
    at com.googlecode.dex2jar.tools.Dex2jarCmd.main(Dex2jarCmd.java:33)

出現(xiàn)原因: Files.readAllBytes 方法最大支持 Integer.MAX_VALUE - 8 大小的文件,也就是最大2GB的文件。一旦超過了這個(gè)限度,java 原生的方法就不能直接使用了。所以伴隨這個(gè)報(bào)錯(cuò)的往往是游戲閃退。
解決辦法: 把文件分成多個(gè)子區(qū)域分多次讀取,這就會(huì)有多種方法可以使用。

問題二:java堆空間溢出

報(bào)錯(cuò)如下:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at java.nio.file.Files.read(Files.java:3099)
    at java.nio.file.Files.readAllBytes(Files.java:3158)
    at com.googlecode.dex2jar.tools.Dex2jarCmd.doCommandLine(Dex2jarCmd.java:108)
    at com.googlecode.dex2jar.tools.BaseCmd.doMain(BaseCmd.java:290)
    at com.googlecode.dex2jar.tools.Dex2jarCmd.main(Dex2jarCmd.java:33)

出現(xiàn)原因: 運(yùn)行的java程序需要較大的內(nèi)存時(shí),可能會(huì)造成堆空間溢出。
解決方法: 將dex2jar-2.1/d2j-dex2jar.sh下的Xmx1024m改為Xmx4096m。Xmx表示jvm所需最大內(nèi)存,這里我們可以根據(jù)實(shí)際需要自己調(diào)整設(shè)置。
即:

java -Xms512m -Xmx1024m -classpath "${_classpath}" "com.googlecode.dex2jar.tools.Dex2jarCmd" "$@"

改為:

java -Xms512m -Xmx4096m -classpath "${_classpath}" "com.googlecode.dex2jar.tools.Dex2jarCmd" "$@"

問題三:dex2jar不支持MultiDex

出現(xiàn)原因: dex2jar版本為v2.1之前的版本,那么dex2jar就會(huì)默認(rèn)轉(zhuǎn)化第一個(gè)dex文件而忽略其他dex文件. 2.1版本開始支持multidex,會(huì)直接執(zhí)行
解決辦法: 下載2.1版本即可

shell腳本如下,只需將.sh與apk放在一起即可,具體操作請(qǐng)看注釋:

#!/bin/sh
#默認(rèn)填入數(shù)據(jù),不填可以不用管

# dex=1,拆解包體,需付上apk路徑;
# dex=2,重構(gòu)包體,需付上keystore的文件名,Alias,簽名密碼,鑒于每個(gè)項(xiàng)目只有一個(gè)keystore,所以也可以寫死在文件內(nèi);
# dex=3,反編譯java代碼,這里會(huì)生成.jar文件,可以方便程序復(fù)查代碼

dex=None
oldApkPath=None;
keystore_name=None;
Alias=None;
StorePass=None;

if [ "$1" ]
then
dex="$1"
fi

if [ "$2" ]
then
    if [ ${dex} = 2 ] ; then 
        keystore_name="$2"
        echo "keystore_name~~~~~~~"
    else
        oldApkPath="$2"
        echo "oldApkPath~~~~~~~"
    fi
fi

if [ "$3" ]
then
Alias="$3"
fi

if [ "$4" ]
then
StorePass="$4"
fi


#當(dāng)前apk的絕對(duì)或相對(duì)路徑
APK_PATH=${oldApkPath}
#獲取當(dāng)前文件所在的絕對(duì)路徑
SHELL_FOLDER=$(cd "$(dirname "$0")";pwd)
#操作類型
DEX=${dex}

echo "APK_PATH:", ${APK_PATH}
echo "SHELL_FOLDER:", ${SHELL_FOLDER}
echo "dex:", ${DEX}
time=$(date "+%Y_%m_%d_%H_%M_%S")
echo "${time}"


if [ ${APK_PATH} = None -a ${DEX} = 1 ] ; then
echo "apk沒傳,退出~~~"
exit 0
fi

if [ ${keystore_name} = None -a ${DEX} = 2  ] ; then
echo "keystore_name沒有,無法重簽~~"
exit 0
fi

if [ ${Alias} = None -a ${DEX} = 2  ] ; then
echo "Alias無,無法重簽~~~"
exit 0
fi

if [ ${StorePass} = None -a ${DEX} = 2  ] ; then
echo "簽名密碼沒有,無法重簽~~~"
exit 0
fi

if [ -x  "usigned" -a ${DEX} = 1 ]
then
echo "Remove file usigned"
rm -rf "usigned"
fi

if [ -x  "usigned.apk" -a ${DEX} = 2 ]
then
echo "Remove file usigned.apk"
rm -rf "usigned.apk"
fi

if [ ${DEX} = 1 ]; then
echo "開始拆解包體~~~"
apktool d -o usigned ${APK_PATH}
fi

if [ ${DEX} = 2 ]; then
echo "開始重構(gòu)包體~~~"
apktool b -o "usigned.apk" ${SHELL_FOLDER}"/usigned"
echo "開始重簽apk包體~~~~"
jarsigner -verbose -keystore ${keystore_name} -signedjar ${time}"_resign.apk" usigned.apk ${Alias} -digestalg SHA1 -sigalg MD5withRSA -storepass ${StorePass}
fi

if [ ${DEX} = 3 ]; then
echo "開始解析包體內(nèi)的Java代碼~~"
sh dex2jar-2.1/d2j-dex2jar.sh ${APK_PATH}
fi
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 早在4年前我曾發(fā)表過一篇關(guān)于《Android開發(fā)之反編譯與防止反編譯》的文章,在該文章中我對(duì)如何在Windows平...
    CrazyCodeBoy閱讀 5,006評(píng)論 3 10
  • 轉(zhuǎn)載https://blog.csdn.net/s13383754499/article/details/7891...
    甄姝兒閱讀 1,321評(píng)論 2 9
  • 前言 處理反編譯,首先先要了解apk文件的結(jié)構(gòu),然后是編譯過程,最后是反編譯。反編譯Apk的目的就是Apk拆成我們...
    yzzCool閱讀 5,890評(píng)論 0 8
  • 一、準(zhǔn)備必要工具 反編譯的前提 首先要配置jdk 環(huán)境變量 否則無法編譯 如果已經(jīng)配置好環(huán)境了可以忽略配置流程 ...
    冰封漠_閱讀 887評(píng)論 0 0
  • 舊文改編,留給曾經(jīng)年輕的自己。 我是一個(gè)不怎么愛走路的人。都說女人愛逛街,而我是個(gè)例外。不管和誰去逛街我能...
    笨學(xué)徒閱讀 360評(píng)論 0 0

友情鏈接更多精彩內(nèi)容