树洞剪藏#剪藏#树洞剪藏

替换未加固 APK 中的特定字符串

2024 年 12 月 2 日1 分钟
分享Twitter / XTelegram微博

同步来源:树洞剪藏 源站剪藏 ID:159 原文地址:https://mp.weixin.qq.com/s/bH1DMLxjkgxjTYCu1PqywA

打开原文 · 打开源站剪藏快照


替换未加固 APK 中的特定字符串

替换未加固 APK 中的特定字符串

原创

杨浦老苏

各种折腾

2024年11月06日 19:00 上海

各种折腾 聚沙成塔,集腋成裘 764篇原创内容

公众号 ,

本文纯粹是为了弥补缺憾,而做的技术可行性验证,但如果对你有所启发,老苏会觉得非常欣慰,不感兴趣的朋友可以忽略 前言 2023 的最后一天,老苏发了一篇《将群晖IPTV后台管理套件docker化》,原本是想着通过 docker ,让其他平台的用户也能使用,结果只存活了几个小时就挂了 当时只完成了后台部分,配套的 Android 客户端还需要用户自己用 MT 管理器来修改 apk 中的后台地址。修改方法网上能找到教程,不过对于大部分用户来说,还是有门槛的。 而原本的套件安装完成时,会自动生成对应后台地址的安卓客户端文件。原理老苏大概是明白的,只是因为文章被下架,所以也就没了心情。 最近有点闲,重新研究了一下 Apktool 的编译和反编译,为了不搞乱环境,老苏还是习惯性的封装成了镜像。 原理 其实原理不复杂,第一步将未加固的 apk 文件进行反编译,第二步进行字符串替换,第三步重新编译,第四步重新签名。 思路理顺了,能少走点弯路。一开始老苏忘记了给编译出来的 apk 重新签名,结果导致生成的 apk 不能安装。加入了 Apksigner 之后, Dockerfile 几乎又重新重写了一遍,白白浪费了好几个小时。 构建镜像

如果你不想自己构建,可以跳过,直接阅读下一章节 先要准备三个文件,分别是 Dockerfile 、 entrypoint.sh 和 generate-keystore.sh ,这三个文件放在同一个目录中,用于镜像的构建

文件都放在 Github 上,地址:https://github.com/wbsu2003/Dockerfile/tree/main/apktool generate-keystore.sh generate-keystore.sh 是用于生成签名证书的脚本

生成私钥

openssl genrsa -out my-release-key.pem 2048

生成自签名证书

openssl req -new -x509 -key my-release-key.pem -out my-release-cert.pem -days 365 -subj "/CN=MyApp/C=US"

将私钥和证书合并为 PKCS#12 文件

openssl pkcs12 - export -out " $KEYSTORE_PATH " -inkey my-release-key.pem - in my-release-cert.pem -name "my-key-alias" -passout pass: " $KEYSTORE_PASSWORD "

检查生成的 keystore 文件

if [ -f $KEYSTORE_PATH ]; then echo "Keystore successfully created at $KEYSTORE_PATH " else echo "Failed to create keystore." fi

清理临时文件

rm my-release-key.pem my-release-cert.pem

entrypoint.sh entrypoint.sh 则完成了整个原理中描述的的 4 步流程

!/bin/bash

生成证书

if [ "$GENERATE_KEYSTORE" = "true" ]; then echo "生成 keystore..." if [ -z "$KEYSTORE_PASSWORD" ]; then echo "请设置 KEYSTORE_PASSWORD 环境变量。" exit 1 fi /usr/local/bin/generate-keystore.sh fi

检查 keystore 文件是否存在

if [ ! -f "$KEYSTORE_PATH" ]; then echo "Error: Keystore file $KEYSTORE_PATH does not exist." exit 1 else echo "Keystore file found: $KEYSTORE_PATH" fi

检查 apksigner 是否可用

if ! command -v apksigner &> /dev/null; then echo "apksigner 未找到,请检查 Android SDK 是否正确安装。" exit 1 fi

检查环境变量是否设置

if [[ -z "$APP_URL" || -z "$NEW_APP_URL" || -z "$ORIGINAL_APK_NAME" ]]; then echo "请设置环境变量 APP_URL、NEW_APP_URL 和 ORIGINAL_APK_NAME" exit 1 fi

定义输入和输出路径

INPUT_DIR="/app/input" OUTPUT_DIR="/app/output" ORIGINAL_APK="$INPUT_DIR/$ORIGINAL_APK_NAME"

创建 decompiled 目录

DECOMPILED_DIR="/app/decompiled" if [ -d "$DECOMPILED_DIR" ]; then rm -rf "$DECOMPILED_DIR" fi

提取原 APK 的签名信息

SIGNATURE_INFO=$(apksigner verify --print-signature "$ORIGINAL_APK") echo "原 APK 签名信息:" echo "$SIGNATURE_INFO"

反编译 APK

apktool d "$ORIGINAL_APK" -o "$DECOMPILED_DIR"

替换字符串

find "$DECOMPILED_DIR" -type f -exec sed -i "s|$APP_URL|$NEW_APP_URL|g" {} +

重新编译 APK

apktool b "$DECOMPILED_DIR" -o "$OUTPUT_DIR/${ORIGINAL_APK_NAME%.apk}_new.apk"

使用 PKCS #12 keystore 对新 APK 进行签名

if apksigner sign --ks "$KEYSTORE_PATH" --ks-type PKCS12 --ks-pass pass:"$KEYSTORE_PASSWORD" --key-pass pass:"$KEYSTORE_PASSWORD" --out "$OUTPUT_DIR/${ORIGINAL_APK_NAME%.apk}_new_signed.apk" "$OUTPUT_DIR/${ORIGINAL_APK_NAME%.apk}_new.apk"; then echo "新 APK 已生成并输出到 $OUTPUT_DIR/${ORIGINAL_APK_NAME%.apk}_new_signed.apk" else echo "签名失败,未生成新 APK。" exit 1 fi

Dockerfile Dockerfile 完成整个运行环境的搭建

使用基础镜像

FROM openjdk: 8 -jdk-slim

安装必要的工具

RUN apt-get update && apt-get install -y
wget
unzip
openssl
&& apt-get clean

下载并安装 Android SDK

RUN wget -q https://dl.google.com/android/repository/sdk-tools-linux-3859397.zip -O sdk-tools.zip
&& unzip sdk-tools.zip -d /android-sdk
&& rm sdk-tools.zip

设置环境变量

ENV ANDROID_SDK_ROOT=/android-sdk ENV PATH=$PATH:$ANDROID_SDK_ROOT/tools/bin:$ANDROID_SDK_ROOT/build-tools/ 29.0 . 3

设置 keystore 别名和密码

ENV GENERATE_KEYSTORE= "true" ENV KEY_ALIAS= "my-key-alias" ENV KEYSTORE_PASSWORD= "123456" ENV KEYSTORE_PATH= "/app/my-release-key.keystore"

安装 Android SDK Build Tools 和 Platform Tools

RUN yes | /android-sdk/tools/bin/sdkmanager --licenses
&& /android-sdk/tools/bin/sdkmanager "build-tools;29.0.3" "platform-tools"
&& apt-get remove --purge -y wget unzip
&& apt-get autoremove -y
&& rm -rf /var/lib/apt/lists/*

将 apktool.jar 复制到容器中

COPY apktool_2.10.0.jar /usr/local/bin/apktool.jar

在线下载 apktool

#RUN wget -q https://github.com/iBotPeaches/Apktool/releases/download/v2.10.0/apktool_2.10.0.jar -O /usr/local/bin/apktool.jar \ RUN apt-get update && apt-get install -y curl
&& curl -L -o /usr/ local /bin/apktool.jar https://github.com/iBotPeaches/Apktool/releases/download/v2.10.0/apktool_2.10.0.jar
&& echo -e '#!/bin/sh exec java -jar /usr/local/bin/apktool.jar "$@"' > /usr/ local /bin/apktool
&& chmod +x /usr/ local /bin/apktool

设置工作目录

WORKDIR /app

复制证书生成脚本

COPY generate-keystore.sh /usr/ local /bin/generate-keystore.sh RUN chmod +x /usr/ local /bin/generate-keystore.sh

复制 entrypoint 脚本

COPY entrypoint.sh /usr/ local /bin/entrypoint.sh RUN chmod +x /usr/ local /bin/entrypoint.sh

设置默认命令

ENTRYPOINT [ "/usr/local/bin/entrypoint.sh" ]

构建镜像和容器运行的基本命令如下👇

新建文件夹 apktool

mkdir -p apktool

进入 apktool 目录

cd apktool

将 Dockerfile、entrypoint.sh 和 generate-keystore.sh 放入目录

构建镜像

docker build -t wbsu2003/apktool:v1 .

使用

这个镜像是命令行运行的,没有 Web 界面 还是以在群晖上运行为例 在 docker 文件夹中,创建一个新文件夹 apktool ,并在其中建两个子文件夹 input 和 output

文件夹 装载路径 说明 docker/apktool/input /app/input 存放待处理的 apk 文件 docker/apktool/output /app/output 存放处理之后的 apk 文件

新建文件夹 apktool 和 子目录

mkdir -p /volume1/docker/apktool/{input,output}

进入 apktool 目录

cd /volume1/docker/apktool

将需要处理的 apk 文件放入到 input 目录中

示例文件老苏放在了:https://github.com/wbsu2003/Dockerfile/raw/refs/heads/main/apktool/QHTV.apk,用手机安装会提示风险,可能是因为签名是 V1 的缘故; 现在可以在当前目录中执行下面的命令了

运行容器(全部参数)

docker run --rm
-v $( pwd )/input:/app/input
-v $( pwd )/output:/app/output
-e APP_URL= "http://192.168.0.199/iptv"
-e NEW_APP_URL= "http://192.168.0.197:3332"
-e ORIGINAL_APK_NAME= "QHTV.apk"
-e GENERATE_KEYSTORE= "true"
-e KEYSTORE_PASSWORD= "123456"
-e KEYSTORE_PATH= "/app/my-release-key.keystore"
wbsu2003/apktool

第一次运行,会需要下载镜像

可变 值 APP_URL 指程序中原来的后台地址 NEW_APP_URL 指用于替换的新的后台地址 ORIGINAL_APK_NAME 指需要替换的 apk 的文件名,该文件应该被放在 input 目录中 GENERATE_KEYSTORE 是否要生成证书,默认为 true KEYSTORE_PASSWORD 用于保护 keystore 的密码,脚本会使用这个密码生成和访问 keystore KEYSTORE_PATH 证书的路径,默认为 /app/my-release-key.keystore ,不建议改

前 3 个为必填项,后 3 个为可选项 当然也可以省掉 KEYSTORE 相关的三个变量,因为老苏在 Dockerfile 中赋了默认值

运行容器(必要参数)

docker run --rm
-v $( pwd )/input:/app/input
-v $( pwd )/output:/app/output
-e APP_URL= "http://192.168.0.199/iptv"
-e NEW_APP_URL= "http://192.168.0.197:3332"
-e ORIGINAL_APK_NAME= "QHTV.apk"
wbsu2003/apktool

但 GENERATE_KEYSTORE 如果赋值为 false ,是不会往下执行的

运行容器(错误示例)

docker run --rm
-v $( pwd )/input:/app/input
-v $( pwd )/output:/app/output
-e APP_URL= "http://192.168.0.199/iptv"
-e NEW_APP_URL= "http://192.168.0.197:3332"
-e ORIGINAL_APK_NAME= "QHTV.apk"
-e GENERATE_KEYSTORE= "false"
wbsu2003/apktool

如果没有出错的话 可以在 output 目录看到两个文件 其中 QHTV_new_signed.apk 就是我们用来安装的文件,它的签名状态已经改为了 V1+V2+V3 其他 目前老苏发现的问题:

如果你先安装了 QHTV.apk 文件,再安装 QHTV_new_signed.apk 会提示安装不了,必须先卸载 QHTV.apk 才行,这是因为签名文件变了。老苏采用的是动态生成签名,所以每次执行,签名都是不一样的;

生成的 QHTV_new_signed.apk 在 HarmonyOS 2.0.0 和电视盒子上运行正常,但是在另一台 Android 14 上,则卡在首界面,后台授权中查不到上线信息,因此也就无法授权,这个已经超出了本文的范围; 另外请不要问关于 《将群晖IPTV后台管理套件docker化》的问题,当时就是为了不想做技术支持,专门设置成了付费文章,谢谢~ 参考文档

Apktool | Apktool 地址:https://apktool.org/ iBotPeaches/Apktool: A tool for reverse engineering Android apk files 地址:https://github.com/iBotPeaches/Apktool 群晖NAS安装IPTV管理系统套件 图文教程 – WANG 地址:https://www.oureiq.top:8812/2023/01/29/群晖nas安装iptv管理系统套件-图文教程/

各种折腾 聚沙成塔,集腋成裘 764篇原创内容

公众号 , @所有人:写文不易,如果你都看到了这里,请点个 赞 和 在看 ,分享给更多的朋友;为确保你能收到每一篇文章,请主页右上角设置星标。

预览时标签不可点

群晖 668 docker 675 工具 33 字符串 1

群晖 · 目录

上一篇 Docker可视化管理面板DPanel的安装 下一篇 IPTV直播源自动检测和更新工具

阅读原文 修改于 2024年12月01日

关闭

更多

小程序 广告

搜索「undefined」网络结果

微信扫一扫 关注该公众号

当前内容可能存在未经审核的第三方商业营销信息,请确认是否继续访问。

继续访问 取消 微信公众平台广告规范指引

: , 。

视频 小程序 赞 ,轻点两下取消赞 在看 ,轻点两下取消在看 分享 留言 收藏

相关文章