APK重打包流程
一、说在前面的话。
在本篇文章中,我们将深入讲解如何对APK进行重打包
- 如何对APK进行反编译与重打包
- 如何修改包名
- 如何在Smali文件中插入自定义逻辑
🛠️ 所需工具
在操作过程中,将使用以下工具:
1、Apktool
用于对APK进行反编译(decode)与重新打包(build)
下载地址:https://github.com/iBotPeaches/Apktool/releases
2、 Zipalign 与 Apksigner
这两个工具是Android SDK中的构建工具,主要作用如下:
- zipalign :对 APK 进行对齐优化,提高运行效率。
- apksigner:对 APK 进行签名,使其可安装到 Android 设备上。
它们通常位于以下目录中:
$ANDROID_HOME/build-tools/<version>/
✅ 建议:选择与项目compileSdkVersion接近的build-tools版本,避免兼容性问题,一般不建议使用高于当前的compileSdkVersion的版本
二、进入正题
1、反编译APK
介绍如何使用apktool对APK进行反编译,获取Smali和资源文件。
apktool d. 原始.apk -o 接包目录
说明:
- d 表示decode(反编译)
- -o 后面跟输出目录
实例代码:
java -jar apktool_2.12.0.jar d zy.apk -o zy
2、修改包名
✅ A.修改AndroidManifest.xml的package属性
在上文的目录中,zy/AndroidManifest.xml中:
<manifest package="com.old.package.name" ...
修改为:
<manifest package="com.new.package.name" ...
✅ B.重命名Smali目录结构
假如原来是:
zy/smali/com/old/package/name/
你需要将它移动为:
zy/smali/com/new/package/name/
你可以用下面的命令辅助:
cd your_app_decoded/smali
mkdir -p com/new/package/name
mv com/old/package/name/* com/new/package/name/
rm -r com/old
✅ C.替换smali文件中的包名
使用sed或者脚本所有的.smali文件中的旧包名改为新的:
find . -type f -name "*.smali" -exec sed -i '' 's/com\/old\/package\/name/com\/new\/package\/name/g' {} +
注意:smali文件中的包名是用 / 分割的
如果遇到分包的就会比较麻烦了,如下图:
就像这样的,上面的命令就有点吃力了,所以最好采用脚本的形式
下面是一个Python 脚本,可以自动完成上述的任务:
✅它的主要功能:
- 遍历所有 smali_classes 目录
- 重命名包名路径
- 替换所有 .smali 文件中旧包名为新包名
- 替换所有 res/ 和 AndroidManifest.xml 中的旧包名
Python 脚本:rename_package.py
import os
import shutil# 配置旧包名和新包名
old_package = "com.location.gps"
new_package = "com.location.gzk"# 转换为路径形式
old_path = old_package.replace('.', '/')
new_path = new_package.replace('.', '/')# 要处理的文件夹前缀
smali_prefixes = [d for d in os.listdir() if d.startswith("smali_classes") or d == "smali"]def rename_package_dirs():for smali_dir in smali_prefixes:old_dir = os.path.join(smali_dir, old_path)new_dir = os.path.join(smali_dir, new_path)if os.path.exists(old_dir):os.makedirs(os.path.dirname(new_dir), exist_ok=True)print(f"[+] 移动目录: {old_dir} -> {new_dir}")shutil.move(old_dir, new_dir)# 清除空目录(防止重复打包问题)for smali_dir in smali_prefixes:for root, dirs, files in os.walk(smali_dir, topdown=False):if not os.listdir(root):os.rmdir(root)def replace_in_files(root_dir, file_exts, old_str, new_str):for root, dirs, files in os.walk(root_dir):for file in files:if any(file.endswith(ext) for ext in file_exts):file_path = os.path.join(root, file)try:with open(file_path, 'r', encoding='utf-8') as f:content = f.read()new_content = content.replace(old_str, new_str)if new_content != content:with open(file_path, 'w', encoding='utf-8') as f:f.write(new_content)print(f"[~] 替换文件: {file_path}")except Exception as e:print(f"[!] 跳过文件(编码问题): {file_path}")def main():print(">>> 开始修改包名 ...")# 1. 移动包名路径rename_package_dirs()# 2. 替换 smali 中的包名replace_in_files(".", [".smali"], "L" + old_path.replace('/', '/') + "/", "L" + new_path.replace('/', '/') + "/")# 3. 替换 Manifest 和 XML 中的包名replace_in_files(".", [".xml"], old_package, new_package)# 4. 替换 Manifest 文件中的主包名manifest_path = "AndroidManifest.xml"if os.path.exists(manifest_path):replace_in_files(".", ["AndroidManifest.xml"], old_package, new_package)print("✅ 包名修改完成!")if __name__ == "__main__":main()
把它放到apktools解包的目录里(例如 AndroidManifest.xml 和 smali_classes 所在目录)
在命令行运行:
python3 rename_package.py
3、在Smali文件中插入自定义逻辑
例如,你要在Application.onCreate()插入代码:
1、找到Application类
在AndroidManifest.xml中找到:
<application android:name="com.xxx.MyApp" ...>
对应的smali文件是:
smali/com/xxx/MyApp.smali
2、编辑.smali
找到onCreate方法(如何没有找到就添加)
.method public onCreate()V.locals 1invoke-super {p0}, Landroid/app/Application;->onCreate()V# 自定义代码开始const-string v0, "Hello Custom Code"invoke-static {v0}, Landroid/util/Log;->d(Ljava/lang/String;)I# 自定义代码结束return-void
.end method
你可以调用任意Java中支持的方法,但要注意调用路径和参数签名是否正确。
还有一点:如果新增了变量一定要记得修改locals的值,否则会报异常错误的。
.locals N 声明该方法最多用到了N个本地寄存器
4、重新打包APK
还是用到上文提到的:apktool
java -jar apktool_2.12.0.jar b zy -o new_app.apk
5、对 APK 签名
先 zipalign(必须):
$ANDROID_HOME/build-tools/<version>/zipalign -p -f 4 new_app.apk output.apk
需要注意的地方: 最好加上-p,不然很容易出现:
Serving...
Failure [INSTALL_FAILED_INTERNAL_ERROR: Failed to extract native libraries, res=-110]
Performing Streamed Install
adb: failed to install /Volumes/SD/soft/reapk/my_signed.apk: Failure [INSTALL_FAILED_INVALID_APK: Failed to extract native libraries, res=-2].
然后签名(使用 apksigner):
$ANDROID_HOME/build-tools/<version>/apksigner sign \--ks xx.jks \--ks-key-alias xx \--ks-pass pass:xx \--key-pass pass:xx \--out my_signed.apk \output.apk
如果你没有签名文件,可以先创建:
keytool -genkey -v -keystore xx.jks -alias alias_name -xx RSA -keysize 2048 -validity 10000
6、测试安装
adb install -r signed.apk
至此 基础的重打包的流程已完结