app攻防-校验签名对抗&IO重定向&PM篇

admin 2024年12月3日13:53:13评论46 views字数 4378阅读14分35秒阅读模式

作者:yueji0j1anke

首发于公号:剑客古月的安全屋

字数:1720

阅读时间:    5min

声明:请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,文章作者不为此承担任何责任。合法渗透,本文章内容纯属虚构,如遇巧合,纯属意外

目录

  • 前言

  • 前置知识

  • PMSHook

  • IO重定向

  • 总结

0x01 前言

本来在整理校验签名对抗的实战部分,突然发现存在一部分底层汇编以及操作需要详细讲解,加入进去显然太过冗杂,遂干脆新开辟一个专题。

本期依旧偏向逆向,有兴趣的师傅可以看看

0x02 前置知识

校验签名对抗现有方案

防重打包以及绕过一向是app攻防的重点。红极一时的过签工具很多->MT,NP,再配合现在诸多的dex内存dump工具,可以无视诸多壳成功重打包运行。

其中最核心的技术就是PMSHook与IO重定向

下面就来着重讲讲这两种技术

0x03 PMSHook

其主要利用反射和动态代理技术去修改apk中dex文件的signature,依靠PMS获取的攻击者构造后的正确签名信息signature,完成apk的签名检验

以下是一个testdemo,可以通过PM获取包的很多信息

public class MainActivity extends AppCompatActivity {
    private byte[] signatureFromAPI() {
        try {
            PackageInfo info = getPackageManager().getPackageInfo(getPackageName(),                                                 PackageManager.GET_SIGNATURES);
            Log.i("签名数量:", info.signatures.length + "");
            return info.signatures[0].toByteArray();
        } catch (PackageManager.NameNotFoundException e) {
            throw new RuntimeException(e);
        }
   }
}    

包括PM命令,实则也是通过类似的接口实现命令的调用

app攻防-校验签名对抗&IO重定向&PM篇

那getPackageManager()如何从MainActivity获取的呢

app攻防-校验签名对抗&IO重定向&PM篇

通过ContextWrapper子类接口获取实现->而Context本身便是Activity的产物,具体接口就是hook住android.app.ActivityThread

这里实现一个简单的testdemo

public class ServiceManagerWraper {

    public final static String ZJ = "ZJ595";

   public static void hookPMS(Context context, String signed, String appPkgName, int hashCode) {
       try {
           // 获取全局的ActivityThread对象
           Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
           Method currentActivityThreadMethod =
                   activityThreadClass.getDeclaredMethod("currentActivityThread");
           Object currentActivityThread = currentActivityThreadMethod.invoke(null);
           // 获取ActivityThread里面原始的sPackageManager
           Field sPackageManagerField = activityThreadClass.getDeclaredField("sPackageManager");
           sPackageManagerField.setAccessible(true);
           Object sPackageManager = sPackageManagerField.get(currentActivityThread);
           // 准备好代{过}{滤}理对象, 用来替换原始的对象
           Class<?> iPackageManagerInterface = Class.forName("android.content.pm.IPackageManager");
           Object proxy = Proxy.newProxyInstance(
                   iPackageManagerInterface.getClassLoader(),
                   new Class<?>[]{iPackageManagerInterface},
                   new PmsHookBinderInvocationHandler(sPackageManager, signed, appPkgName, 0));
           // 1. 替换掉ActivityThread里面的 sPackageManager 字段
           sPackageManagerField.set(currentActivityThread, proxy);
           // 2. 替换 ApplicationPackageManager里面的 mPM对象
           PackageManager pm = context.getPackageManager();
           Field mPmField = pm.getClass().getDeclaredField("mPM");
           mPmField.setAccessible(true);
           mPmField.set(pm, proxy);
      } catch (Exception e) {
           Log.d(ZJ, "hook pms error:" + Log.getStackTraceString(e));
      }
  }

   public static void hookPMS(Context context) {
       String Sign = "原包的签名信息";
       hookPMS(context, Sign, "com.zj.hookpms", 0);
  }
}
public class PmsHookBinderInvocationHandler implements InvocationHandler{
   //应用正确的签名信息
   private String SIGN;

    @Override
   public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
       Log.i(SHARK, method.getName());
       //查看是否是getPackageInfo方法
       if("getPackageInfo".equals(method.getName())){
           String pkgName = (String)args[0];
           Integer flag = (Integer)args[1];
           //是否是获取我们需要hook apk的签名
           if(flag == PackageManager.GET_SIGNATURES && appPkgName.equals(pkgName)){
               //将构造方法中传进来的新的签名覆盖掉原来的签名
               Signature sign = new Signature(SIGN);
               PackageInfo info = (PackageInfo) method.invoke(base, args);
               info.signatures[0] = sign;
               return info;
          }
      }
       return method.invoke(base, args);
  }    
}    

那对于mt管理器,它会对packageinfo内置过滤信息进行处理

app攻防-校验签名对抗&IO重定向&PM篇

对应的过滤代码是这一段

app攻防-校验签名对抗&IO重定向&PM篇

主要功能是通过伪造签名(Fake Signature)*和*修改系统的内存缓存,劫持PackageInfo类中签名信息的获取过程,从而在应用程序内部伪装某个包(packageName)的签名数据。

app攻防-校验签名对抗&IO重定向&PM篇

对应只需在此处修改包名与原包签名,即可完成PM绕过

编译,找dex文件

app攻防-校验签名对抗&IO重定向&PM篇

app攻防-校验签名对抗&IO重定向&PM篇

找到dex文件后,移入apk文件内部

app攻防-校验签名对抗&IO重定向&PM篇

查看AndoridManifest.xml文件是否拥有自己的application

比如说这里存在,就不用去使用我们的Application

有的话直接插入代码

寻找MainApplication.smali

插入代码

.method static <clinit>()V
    .registers 1

     .line 37
     new-instance        v0, Lcom/example/nativelib/KillerApplication; # type@0013
     invoke-direct       {v0}, Lcom/example/nativelib/KillerApplication;-><init>()V # method@001c
     .line 38
     return-void         

.end method

app攻防-校验签名对抗&IO重定向&PM篇

完成PMS校验绕过

0x04 IO重定向

什么是IO重定向呢

简而言之,就是本来该读取a应用的信息,你替换成b,类似于pwn中的execve(),从而实现

路径替换
签名绕过
检测绕过

在新来的mt一键过签名校验中,具体代码如下

app攻防-校验签名对抗&IO重定向&PM篇

获取app原包,放入对应origin.apk实现路径重定向

随后传到

hookApkPath(apkFile.getAbsolutePath(), repFile.getAbsolutePath());

该方法进行安卓底层的hook

具体来说,就是hook底层几个打开文件的命令操作接口

app攻防-校验签名对抗&IO重定向&PM篇

具体实操如下:

编译一下,把testapp的so文件和dex文件拿出来,放入至你要绕过的apk,从而实现IO重定向(记得做个继承)

app攻防-校验签名对抗&IO重定向&PM篇

这个lsposed模块的dex文件也要拿过来,

app攻防-校验签名对抗&IO重定向&PM篇

该文件也得放入hook apk中

app攻防-校验签名对抗&IO重定向&PM篇

找到对应Application随后反编译即可

0x05 总结

直接用一键过签工具很方便,but了解原理也是很重要的一部分,以后安全开发也可以根据学习这个写出一些框架应用

 

原文始发于微信公众号(剑客古月的安全屋):app攻防-校验签名对抗&IO重定向&PM篇

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年12月3日13:53:13
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   app攻防-校验签名对抗&IO重定向&PM篇https://cn-sec.com/archives/3442714.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息