2016976438 发表于 2023-1-5 23:46

过签名校验(2) -- MT 的 IO 重定向实践

本帖最后由 2016976438 于 2023-1-6 00:13 编辑

# 过签名校验(2) -- MT 的 IO 重定向

本来是想照着敲一遍 MT 的 github 上面的代码 ,但个人c ++ 以及 arm 汇编 实在有点吃力。说白了就是个人水平不够。

所以砸门的目标就变成了.

1.**能看懂就行**
2.**可以编译 mt github源码 成 apk**
3.**复制 so 和 classX.dex 到我们要去签名的应用上**

​               



#运行 MT 的 去签名的 github 源码

1.先从github下下来





网络差的建议通过油猴转到网盘下载

2. 导入到android studio



导入后您可以看到两个模块

**app (测试demo)killer(去签模块)**



运行后 app 您应该能够得到





使用zip 解压 其中重要的就是

**app-debug.apk/lib/**里面的 so hook 的 IO 重定向

**classesXXX.dex**   这个得看 **KillerApplication** 在哪里了

   

# 了解Killer 模块

我们主要目的是看 **killer** 去签的那个模块 , 先从 **KillerApplication** 看



``` java
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;
                  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** 获取 。

```cmake
# ps -ef|grep mt
u0_a63      78641464 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_cache4096 2023-01-04 19:36 cache
drwxrws--x 2 u0_a63 u0_a63_cache4096 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
```

```cpp
//注册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";
        ....   
}
```



   

2.我们通过 **jadx** 看下 编译的 **KillerApplication** 在哪个 **xxxx.dex** 中,顺带用 **mt** 把 包名和签名都成 原始七猫的



3. 移动到 七猫里面去



(注意还有个 lsposed 的 dex 依赖 也得弄进去,这个就交给你们自己找了)




4. 看看 **androidManifest.xml**文件 ,看看 **application** 在哪里




记住这个 **SophixStubApplication** 我们待会会用到

5. 复制 so文件,先把 arm64 的删掉,咋们就留一份arm32,免得不兼容。





在 **app-debug.apk/lib/armeabi-v7a** 里面找到我们得so 复制到 七猫里面去







6. 在 **com.km.sophix.SophixStubApplication** 中加入我们的 **KillerApplication**

(在上篇 PM 过签中我是通过 **static** 代码块插入的) 但在 **正己大佬** 视频里 **MT 一键**是通过 继承的方式, 这种需要面向对象基础才能理解。 但这种更为简单,但是得一直找父类最上层 就如下图,最上层父类是 **SophixApplication**



可以看到这个继承 最终的 **Application**







咋们修改成 **superKillerApplication**让他继承我们过签名的 **MT 的 application**



转换成 java 看看





至此算是完毕了。

**不过跟PM管理器一样,模拟器不行,但是 手机可以。**

个人觉得应该是 hook 不支持 x86_64 android 内部的hook 。 不让我实在不理解为啥,管他的,谁又会用模拟器看小说呢。




#尾言

其实说这么多,也就是MT 一键过签的事情。不过实践一下感觉也不错,起码知道了思路,下次这一方法不行,来了个新家伙,砸门也可以尝试上手改改。不至于只能等待 工具的 更新

在大佬树下乘凉就是不错,168 直接开通 MT 会员 感觉也能接受了。



c++ 和 so 对我来说还是过于困难,感觉我的android逆向之路会被这两座大山给拦住。

不过算了,要是什么都会,那还要大佬干什么,跟着大佬混饭吃也不错。

yun520530 发表于 2023-1-6 09:11

谢谢分享,学习学习啦

Poorwood 发表于 2023-1-6 09:45

这个工具的原理,有大佬讲讲吗?我看,就是不停地替换dex和so文件?

BAllen007 发表于 2023-1-30 12:05

小学徒来学习了

sopcast 发表于 2023-1-6 07:53

感谢分析学习了

aa2923821a 发表于 2023-1-6 08:45

感谢分享!!

aonima 发表于 2023-1-6 08:54

不错,学习了

怜渠客 发表于 2023-1-6 08:56

感谢分享,其实mt的hook支持x86_64,用AS自带的虚拟机加上Bin的demo apk试试就行,应该是七猫不兼容,或者二者混合发生了奇怪反应。

markdik31 发表于 2023-1-6 09:00

谢谢大神分享,小弟来学习学习

大大连连 发表于 2023-1-6 09:02

zkq970413 发表于 2023-1-6 09:04

感谢分享~我记得我买的时候MT永久会员还不是168,没想到现在这么贵了啊。
页: [1] 2 3 4 5
查看完整版本: 过签名校验(2) -- MT 的 IO 重定向实践