过签名校验(2) -- MT 的 IO 重定向
本来是想照着敲一遍 MT 的 github 上面的代码 ,但个人c ++ 以及 arm 汇编 实在有点吃力。说白了就是个人水平不够。
所以砸门的目标就变成了.
- 能看懂就行
- 可以编译 mt github源码 成 apk
- 复制 so 和 classX.dex 到我们要去签名的应用上
运行 MT 的 去签名的 github 源码
- 先从github下下来
网络差的建议通过油猴转到网盘下载
- 导入到android studio
导入后您可以看到两个模块
app (测试demo) killer(去签模块)
运行后 app 您应该能够得到
使用zip 解压 其中重要的就是
app-debug.apk/lib/ 里面的 so hook 的 IO 重定向
classesXXX.dex 这个得看 KillerApplication 在哪里了
了解Killer 模块
我们主要目的是看 killer 去签的那个模块 , 先从 KillerApplication 看
public class KillerApplication extends Application {
static {
String packageName = "bin.mt.signature";
killOpen(packageName);
}
private static void killOpen(String packageName) {
try {
//1.加载 so 层 hook
System.loadLibrary("SignatureKiller");
} catch (Throwable e) {
System.err.println("Load SignatureKiller library failed");
return;
}
//2. 通过 当前 /proc/self/maps 获取apk路径
String apkPath = getApkPath(packageName);
if (apkPath == null) {
System.err.println("Get apk path failed");
return;
}
//3. 获取的路径是 /data/app/{PackageName}-xxx/base.apk 这个是当前 apk文件
File apkFile = new File(apkPath);
//4.将当前 apk 中 origin.apk 文件提取出去 作为我们的 IO重定向文件
File repFile = new File("/data/data/" + packageName + "/origin.apk");
//5. 由于 apk实际是个 zip 所以我们可以解压缩 提取 origin.apk
try (ZipFile zipFile = new ZipFile(apkFile)) {
//6. apkFile 抽取 origin.apk 到 repFile变量 指定的位置
String name = "assets/SignatureKiller/origin.apk";
ZipEntry entry = zipFile.getEntry(name);
if (entry == null) {
System.err.println("Entry not found: " + name);
return;
}
//7.把 /data/app/{PackageName}-xxx/base.apk/origin.apk 转换到 /data/data/packageName/origin.apk
if (!repFile.exists() || repFile.length() != entry.getSize()) {
try (InputStream is = zipFile.getInputStream(entry); OutputStream os = new FileOutputStream(repFile)) {
byte[] buf = new byte[102400];
int len;
while ((len = is.read(buf)) != -1) {
os.write(buf, 0, len);
}
}
}
} catch (IOException e) {
throw new RuntimeException(e);
}
//8. 传入到 底层 so hook
hookApkPath(apkFile.getAbsolutePath(), repFile.getAbsolutePath());
}
private static native void hookApkPath(String apkPath, String repPath);
}
KillerApplication Java层 主要是 获取 当前 app 里面 我们放入的原始的 origin.apk 文件 , origin.apk 是没有改过签的正常 app
在我们编译的apk 的 : app-debug.apk/assets/SignatureKiller/origin.apk
但是我们 android 安装后 路径会变成: /data/app/{包名}-XXX/ base.apk
获取apk 路径 通过 /proc/self/maps 获取 。
# ps -ef|grep mt
u0_a63 7864 1464 0 20:10:12 ? 00:00:00 bin.mt.signature
# cat /proc/7864/maps | grep base.apk
7ffff4080000-7ffff4082000 r--s 00009000 08:12 919883 /data/app/bin.mt.signature-zJwiS40NJvMBt5AUPmgKRA==/base.apk
7ffff7a88000-7ffff7a89000 r--s 00019000 08:12 919883 /data/app/bin.mt.signature-zJwiS40NJvMBt5AUPmgKRA==/base.apk
/data/app/bin.mt.signature-zJwiS40NJvMBt5AUPmgKRA==/base.apk 就是 安装包的路径了
为了方便, MT 将 base.apk 里面的 origin.apk 提取到 /data/data/包名 下面
# cd /data/data/包名
# ll
drwxrws--x 2 u0_a63 u0_a63_cache 4096 2023-01-04 19:36 cache
drwxrws--x 2 u0_a63 u0_a63_cache 4096 2023-01-04 19:36 code_cache
drwxrwxr-x 5 u0_a63 u0_a63 4096 2023-01-04 19:47 lldb
-rw------- 1 u0_a63 u0_a63 22989 2023-01-04 19:38 origin.apk
然后传到 hookApkPath 进行 HOOK
XHook 分析
xhook 是针对 so 层 拦截的一种框架。
github 在 :
https://github.com/iqiyi/xHook/blob/master/README.zh-CN.md
//注册hook
xhook_register(".*\\.so$", "hook的函数", 到我们自定义的 , NULL);
//执行 hook!
xhook_refresh(1);
咋们只用看 mt_jni.c 就行了
``` c++
//1. 从 java 层传入的
// apkPath 是 原来的路径
const char apkPath__;
// repPath 要重定向的路径
const char repPath__;
//2. hook open 函数
int (old_open)(const char , int, mode_t);
static int openImpl(const char *pathname, int flags, mode_t mode) {
//如果 打开是原路径 就替换成 repPath
if (strcmp(pathname, apkPath__) == 0){
return old_open(repPath__, flags, mode);
}
return old_open(pathname, flags, mode);
}
//3. hook openat 函数
int (old_openat)(int, const char, int, mode_t);
static int openatImpl(int fd, const char *pathname, int flags, mode_t mode) {
//如果 打开是原路径 就替换成 repPath
if (strcmp(pathname, apkPath__) == 0){
return old_openat(fd, repPath__, flags, mode);
}
return old_openat(fd, pathname, flags, mode);
}
JNIEXPORT void JNICALL
Java_bin_mt_signature_KillerApplication_hookApkPath(JNIEnv env, attribute((unused)) jclass clazz, jstring apkPath, jstring repPath) {
//4. 获取从 java传入来的 原路径和重定向路径
apkPath__ = (env)->GetStringUTFChars(env, apkPath, 0);
repPath__ = (*env)->GetStringUTFChars(env, repPath, 0);
//5. 使用 xhook 进行 重定向 hook
xhook_register(".*\\.so$", "openat64", openat64Impl, (void **) &old_openat64);
xhook_register(".*\\.so$", "openat", openatImpl, (void **) &old_openat);
xhook_register(".*\\.so$", "open64", open64Impl, (void **) &old_open64);
xhook_register(".*\\.so$", "open", openImpl, (void **) &old_open);
xhook_refresh(0);
}
# 应用去签名
我就直接用 之前 有点遗憾的 七猫小说 做为这次的示例。
之前说过,但我们签名后,七猫就会显示网络异常
所以我们步骤如下:
1. 根据 mt 中 获取 原始包的路径, 我们在 **assets/SignatureKiller/** 创建我们的原始 apk
```java
private static void killOpen(String packageName) {
....
File repFile = new File("/data/data/" + packageName + "/origin.apk");
//5. 由于 apk实际是个 zip 所以我们可以解压缩 提取 origin.apk
try (ZipFile zipFile = new ZipFile(apkFile)) {
//6. apkFile 抽取 origin.apk 到 repFile变量 指定的位置
String name = "assets/SignatureKiller/origin.apk";
....
}
- 我们通过 jadx 看下 编译的 KillerApplication 在哪个 xxxx.dex 中,顺带用 mt 把 包名和签名都成 原始七猫的
- 移动到 七猫里面去
(注意还有个 lsposed 的 dex 依赖 也得弄进去,这个就交给你们自己找了)
- 看看 androidManifest.xml 文件 ,看看 application 在哪里
记住这个 SophixStubApplication 我们待会会用到
- 复制 so文件,先把 arm64 的删掉,咋们就留一份arm32,免得不兼容。
在 app-debug.apk/lib/armeabi-v7a 里面找到我们得so 复制到 七猫里面去
- 在 com.km.sophix.SophixStubApplication 中加入我们的 KillerApplication
(在上篇 PM 过签中我是通过 static 代码块插入的) 但在 正己大佬 视频里 MT 一键是通过 继承的方式, 这种需要面向对象基础才能理解。 但这种更为简单,但是得一直找父类最上层 就如下图,最上层父类是 SophixApplication
可以看到这个继承 最终的 Application
咋们修改成 super KillerApplication 让他继承我们过签名的 MT 的 application
转换成 java 看看
至此算是完毕了。
不过跟PM管理器一样,模拟器不行,但是 手机可以。
个人觉得应该是 hook 不支持 x86_64 android 内部的 hook 。 不让我实在不理解为啥,管他的,谁又会用模拟器看小说呢。
尾言
其实说这么多,也就是MT 一键过签的事情。不过实践一下感觉也不错,起码知道了思路,下次这一方法不行,来了个新家伙,砸门也可以尝试上手改改。不至于只能等待 工具的 更新
在大佬树下乘凉就是不错,168 直接开通 MT 会员 感觉也能接受了。
c++ 和 so 对我来说还是过于困难,感觉我的android 逆向之路会被这两座大山给拦住。
不过算了,要是什么都会,那还要大佬干什么,跟着大佬混饭吃也不错。