Android Hook (2) Java2java

Frida安卓逆向实战:从环境搭建到Java/Native层Hook Frida是一种基于动态插桩的移动应用安全分析技术,其核心原理是通过注入JavaScript逻辑到目标Android进程,实时劫持Java方法调用与Native函数执行流。该技术具备高灵活性和低侵入性,广泛应用于App安全审计、加固方案验证、SDK行为监控及竞品逻辑分析等工程场景。在Android 12+系统中,Frida的稳定运行高度依赖Zygisk启用、SELinux策略适配、v2/v3签名重打包及ABI架构匹配等底层环境协同。本文聚焦真实项目中高频出现的frida-ps无进程、hook失败、so加载异 阅读详情

原文地址:http://www.zhaoxiaodan.com/android/Android-Hook(2)-java2java.html

之前学习了如何做一个简单android的函数勾子, 而这个勾子是用native 的函数去hook java函数, 现在来学习如何封装让他可以实现java hook java

不过不管怎么说, 这里已经不算是原理了, 因为原理就是改accessFlags并设置nativeFunc, 实际的hook 函数还是个native函数, 所以说这个是用这个原理来封装

我们一般要hook一个方法, 有可能希望在三个时间点进行处理:

  • 原方法执行前
  • 替换原方法
  • 原方法执行后

先来做个最简单的, 在原方法执行之前 执行, 那么就需要如下的Handler 用来hook 原函数, 并且这个java层的hook 可以获得原函数所在类的对象实例和所有参数值

public interface Handler
{
    /**
     * 在原方法执行之前执行
     * @param params 原方法参数
     */
    public void before(Object instance, Object[] params);
}

所以在jni 函数hook 里将原函数的nativeFunc 修改为 forwardToHander, 然后forwardToHander里 解析原函数的参数值等信息之后, 再调用 Handler的before方法, 将原函数所在类实例和参数值传递给handler的before回调方法

具体代码:

#include <jni.h>
#include "log.h"
#include "Dalvik.h"

/**
 * dvmCallMethod 需要的是 ArrayObject*, 而 nativeFunction 传入的参数是 const u4*
 * 做个转换
 */
ArrayObject* argsToArrayObject(const char* argsTypeDesc, const u4* args)
{
    //全部参数都转成Object型
    ClassObject* objectArrayClass = dvmFindArrayClass("[Ljava/lang/Object;", NULL);

    // 参数个数, 类型描述符都是一个字符, 所以 argsTypeDesc 字符串长度就是参数个数
    int argsSize = strlen(argsTypeDesc);

    // 分配空间
    ArrayObject* argArray = dvmAllocArrayByClass(objectArrayClass,argsSize ,ALLOC_DEFAULT);

    // 挨个赋值
    // 因为 args 并不是一个真正意义上的"数组", 当long 或者 double 形, 会占用 args[i]和args[i+1]
    // 所以需要多一个下标来指向args内存
    int pArgs = 0;
    for(int i=0;i<argsSize;i++)
    {
        // 当前参数类型描述符
        const char descChar = argsTypeDesc[i];

        JValue value;
        Object* obj;

        switch(descChar)
        {

            case 'Z':
            case 'C':
            case 'F':
            case 'B':
            case 'S':
            case 'I':

                //如果是基本数据类型, 则使用java的"自动装配", 也就是 int 转 Integer, long 转 Long, 这样就都转成Object了
                value.i = args[pArgs++];
                obj = (Object*) dvmBoxPrimitive(value, dvmFindPrimitiveClass(descChar));
                dvmReleaseTrackedAlloc(obj, dvmThreadSelf());
                break;
            case 'D':
            case 'J':

                // 基本数据类型中, double 和 long 占用两个字节, 所以 pArgs 需要 +2
                value.j = dvmGetArgLong(args, pArgs++);
                pArgs++;
                obj = (Object*) dvmBoxPrimitive(value, dvmFindPrimitiveClass(descChar));
                dvmReleaseTrackedAlloc(obj, dvmThreadSelf());
                break;
            case '[':
            case 'L':
                obj  = (Object*) args[pArgs++];
                break;
            default:
                LOGE("Unknown method signature description character: %c\n", descChar);
                obj = NULL;
        }

        // 塞到ArrayObject 中
        dvmSetObjectArrayElement(argArray,i,obj);
    }

    return argArray;
}

/**
 * 被hook的函数统一调用这个native方法, 由他来装配之后跳转到Handler
 */
static void forwardToHander(const u4* args, JValue* pResult,
                          const Method* method, struct Thread* self) {

    // 之前放进去的 "附加参数"
    Object* handlerObject = const_cast<Object*>(reinterpret_cast<const Object*>(method->insns));

    // 在原方法执行之前, 我们是要调用 Handler 的 before 这个hook
    Method* handlerBeforeMethod = dvmFindInterfaceMethodHierByDescriptor(handlerObject->clazz,"before","(Ljava/lang/Object;[Ljava/lang/Object;)V");

    if(nullptr != handlerBeforeMethod)
    {
        LOGD("handlerBeforeMethod name:%s,desc:%s",handlerBeforeMethod->name,handlerBeforeMethod->shorty);
        JValue* result = new JValue();

        // method->shorty[0] 表示返回值类型, 比如"ILJ" 说明原函数有一个Object型参数和一个long型参数, 返回值为 整形
        // 注意自动装配类型, int long double, 如果是Integer, Long, Double, 则描述符为Ljava/lang/Integer,Ljava/lang/Long和Ljava/lang/Double
        const char returnTypeDesc = method->shorty[0];
        const char* argsTypeDesc = &(method->shorty[1]);

        // 转一下参数格式
        ArrayObject* argsArray ;
        Object* originalInstance;

        // 同样的, 如果原函数不是static 的, args[0] 函数是所在类的实例
        if(dvmIsStaticMethod(method))
        {
            argsArray = argsToArrayObject(argsTypeDesc,&(args[0]));
            originalInstance = nullptr;
        }else{
            argsArray = argsToArrayObject(argsTypeDesc,&(args[1]));
            originalInstance = (Object*)(args[0]);
        }


        dvmCallMethod(self,handlerBeforeMethod, handlerObject, result, originalInstance ,argsArray);
    }else{
        LOGE("method no found....");
    }

    // before 前置调用先不修改原返回值了
    pResult->l = nullptr;


}


/**
 * 设置hook, 将原函数调用转发给nativeFunc forwardToHander 进行处理
 */
extern "C" JNIEXPORT void JNICALL
Java_com_zhaoxiaodan_hookdemo_Demo2_hook(JNIEnv *env, jobject instance, jobject clazzToHook,
                                                 jstring methodName_, jstring methodSig_,
                                                 jobject handler) {
    const char *methodName = env->GetStringUTFChars(methodName_, 0);
    const char *methodSig = env->GetStringUTFChars(methodSig_, 0);

    jmethodID methodIDToHook = env->GetMethodID((jclass) clazzToHook,methodName,methodSig);

    // 找不到有可能是个static
    if(nullptr == methodIDToHook){
        env->ExceptionClear();
        methodIDToHook = env->GetStaticMethodID((jclass) clazzToHook,methodName,methodSig);
    }


    if(methodIDToHook != nullptr)
    {
        Method* method = reinterpret_cast<Method*>(methodIDToHook);

        LOGD("hook function %s, args desc:%s",method->name,method->shorty);

        SET_METHOD_FLAG(method, ACC_NATIVE);
        //转发
        method->nativeFunc = &forwardToHander;
        method->registersSize=method->insSize;
        method->outsSize=0;

        // "附加参数" 功能
        // 在hook 的时候传进来的 handler 实现实例, 我们放到Method 结构体的insns 属性中
        // 到时候dvm 调用 nativeFunc 的时候会带回到 nativeFunc 中, 我们就能取到了
        method->insns = reinterpret_cast<const u2*>(dvmDecodeIndirectRef(dvmThreadSelf(),handler));
    }

    env->ReleaseStringUTFChars(methodName_, methodName);
    env->ReleaseStringUTFChars(methodSig_, methodSig);
}

使用代码为:

public class Demo2
{
    String TAG = "===[hookdemo]===";

    public interface Handler
    {
        /**
         * 在原方法执行之前执行
         * @param params 原方法参数
         */
        public void before(Object instance, Object[] params);
    }

    public String test(String param1, long param2, int[] param3)
    {
        return param1;
    }

    public static String staticTest(String param1, Long param2, int[] param3)
    {
        return param1;
    }
    public void demo()
    {
        String param1 = "param1";

        /**
         * 设置hook
         * hook 住Demo2 这个类的 test 方法
         * 实现一个Handler类来实现 回调函数 before
         */
        hook(Demo2.class, "test", "(Ljava/lang/String;J[I)Ljava/lang/String;", new Handler()
        {
            @Override
            public void before(Object instance, Object[] params)
            {
                Log.d(TAG, "===========Handler before,param len: "+params.length+",instance:"+instance);
                for (int i = 0; i < params.length; i++)
                {
                    Log.d(TAG, "p" + i + "=" + params[i]);
                }
            }
        });
        Log.d(TAG, "===========call test" + this.test(param1,999L,new int[]{1,2,3}));


        /**
         * 测试静态函数的hook, 则回调函数参数中 instance 为 null
         */
        hook(Demo2.class, "staticTest", "(Ljava/lang/String;Ljava/lang/Long;[I)Ljava/lang/String;", new Handler()
        {
            @Override
            public void before(Object instance, Object[] params)
            {
                Log.d(TAG, "===========Handler before,param len: "+params.length+",instance:"+instance);
                for (int i = 0; i < params.length; i++)
                {
                    Log.d(TAG, "p" + i + "=" + params[i]);
                }
            }
        });
        Log.d(TAG, "===========call test" + this.staticTest(param1, 999L, new int[]{1, 2, 3}));
    }

    /**
     * hook 函数, 是个jni 函数
     * @param clazzToHook
     * @param methodName
     * @param methodSig
     * @param handler
     */
    private native void hook(Class<?> clazzToHook, String methodName, String methodSig, Handler handler);
}

但是这个封装其实也不好, 只是学习如何在nativeFunc 通过dvm 调用回java层代码而已

它并没有真正的转发处理, 还是native来调用具体的方法; 也就是说如果hooker 需要做其他逻辑的话, 比如, 我是不是设置了before是不是有replace之类的, native代码就多了

最好的就是, 我把原函数改掉, 然后获取信息, 然后转发给一个java层处理器, 告诉它, 被hook的是这个函数, 对象是这个, 参数是这些, 然后勾子是这个, 就可以了, Handler 勾子的调用都由这个java层处理器来做, 而不是natviceFunc里, native里不需要做太多逻辑

具体实现就不在做了, 因为alibaba/dexposed项目已经做的很好了, 具体可以看它的实现

我自己也做了些注释:

pangliang/dexposed

安卓HTTPS抓包实战:Xposed+JustTrustMe绕过SSL Pinning HTTPS作为保障网络通信安全的核心协议,通过SSL/TLS加密防止数据在传输过程中被窃听或篡改。其原理基于非对称加密和证书体系,确保客户端与服务器之间的身份认证和信道安全。在移动应用开发和安全测试中,分析HTTPS流量对于调试接口、评估安全性至关重要。然而,现代安卓应用广泛采用SSL Pinning(证书绑定)技术,将应用只信任预设的特定证书,导致常规抓包工具无法解密流量。为解决这一难题,可以借助Xposed框架的动态代码注入能力,配合JustTrustMe模块,在运行时Hook证书验证的关键方法,从而绕 阅读详情

相关推荐

安卓APK逆向工程实战:从解密、分析到修改与重签名的完整指南

逆向工程是软件工程与安全领域的一项关键技术,指通过分析已编译程序来理解其内部结构与运行逻辑。其核心原理在于将机器码或字节码转换为更易理解的高级语言表示,从而揭示程序的设计思路与数据流。这项技术的价值不仅体现在安全审计与漏洞挖掘上,还能助力开发者进行竞品分析、算法学习与软件兼容性研究。在安卓生态中,APK文件作为应用分发格式,其逆向分析具有广泛的应用场景,例如应用安全评估、功能定制化、遗留系统维护与学术研究。本文聚焦于APK逆向的完整工作流,详细介绍了如何利用JADX、Apktool、Frida等工具链进行高

weixin_30522095的博客 439

Android Hook 机制之简单实战

简介 什么是 Hook Hook 又叫“钩子”,它可以在事件传送的过程中截获并监控事件的传输,将自身的代码与系统方法进行融入。这样当这些方法被调用时,也就可以执行我们自己的代码,这也是面向切面编程的思想(AOP)。 Hook 分类 1.根据Android开发模式,Native模式(C/C++)和Java模式(Java)区分,在Android平台上 Java层级的Hook; ...

徐公,微信公众号同名 6万+

从‘Hello World’到Hook实战:用Frida-Tools 17.3.2在Android模拟器上写你的第一个脚本

本文详细介绍了如何使用Frida-Tools 17.3.2在Android模拟器上编写和运行第一个Hook脚本。从环境配置验证到实际Hook实战,逐步引导读者掌握Frida的基本用法,包括Hook Java方法、修改返回值等核心技巧,适合Android逆向工程初学者入门。

weixin_30335575的博客 492

Android Hook(2) Java2java

原文地址:http://www.zhaoxiaodan.com/android/Android-Hook(2)-java2java.html 之前学习了如何做一个简单android的函数勾子, 而这个勾子是用native 的函数去hook java函数, 现在来学习如何封装让他可以实现java hook java 不过不管怎么说, 这里已经不算是原理了, 因为原理就是改accessFl

Omnictech的专栏 476

Frida Hook入门指南:如何修改APK方法返回值(Android逆向小白必看)

本文为Android逆向新手提供了一份详细的Frida Hook入门指南,通过一个修改APK方法返回值的实战案例,手把手教你从环境搭建、靶场应用创建到编写Hook脚本的全过程。文章深入浅出地讲解了Frida的核心原理,并演示了如何让一个简单的加法方法返回指定值(如将1+2的结果改为88),是掌握动态调试和运行时修改技术的绝佳起点。

red88的博客 676

注入安卓进程,并hook java世界的方法

看雪大牛写的

Android Hook(1) Dexposed原理

原文地址:http://www.zhaoxiaodan.com/android/Android-Hook(1)-dexposed%E5%8E%9F%E7%90%86.html dexposed 这个项目相当不错, 之前就想着怎么动态替换jvm中的代码, 一直没有思路; 现在好好学习一下 准备源码库 因为dexposed其实是用了dvm和art调用class的方式来做的, 而dvm

Omnictech的专栏 1072

目标检测之Mask R-CNN(Pytorch):小白动手实现项目

目标检测之Mask R-CNN:小白动手实现项目Pytorch引言Mask R-CNN原理简述代码、注释及详细解释 引言 首先声明本项目的运行环境。操作系统为Windows,编写环境为Anaconda3 + Jupyter Notebook。Pytorch版本为 torch 1.7.1+cu110 、torchvision版本为 0.8.2+cu110,cuda版本为cu100,显卡为Nvidia 2060。 我是目标检测领域的小白,刚刚完成了Pytorch的相关入门学习任务,所以我认为学习本篇博客的基础

dzc_go的博客 1万+

Android Hook框架Xposed详解

1 Introduction 1.1  概述 Xposed 是 GitHUB 上 rovo89 大大设计的一个针对 Android 平台的动态劫持项目,通过替换 /system/bin/app_process 程序控制 zygote 进程,使得 app_process 在启动过程中会加载 XposedBridge.jar 这个 jar 包,从而完成对系统应用的劫持。

我的专栏 1万+

ITK-snap医学图像标注方法(超级详细)——保姆级

医学3D图像标注方法,非常详细,保姆级

jialiyk的博客 3万+

中心对数比变换(Centered Log Ratio Transformation,CLR)的原理及scikit-bio介绍

中心对数比变换(Centered Log Ratio Transformation,CLR)是一种数据预处理方法,常用于成分数据分析领域。在成分数据中,各成分之间通常存在一定的约束关系,比如它们的和为固定值等,中心对数比变换可以有效地处理这种具有特殊约束的数据。官方文档scikit-bio是一个在Python3中处理生物数据的库成分统计 (skbio.stats.composition )模块中的,此函数将组合从Aitchison几何体转换到真实空间。这个clr。

RECORD LEARN PROGRESS 1万+

android java层hook_Android Hook——Java2Java

之前学习了如何做一个简单android的函数勾子, 而这个勾子是用native 的函数去hook java函数, 现在来学习如何封装让他可以实现java hook java不过不管怎么说, 这里已经不算是原理了, 因为原理就是改accessFlags并设置nativeFunc, 实际的hook 函数还是个native函数, 所以说这个是用这个原理来封装我们一般要hook一个方法, 有可能希望在三个...

weixin_39861255的博客 544

STM32实现薄膜压力传感器数据采集(标准库和HAL库实现)

薄膜压力传感器采集压力数据

XiaoCaiDaYong的博客 3万+

LSPlant安卓HOOK框架安装与配置完全攻略

**基础介绍:** LSPlant,一款专为Android运行时(ART)设计的强大HOOK库,由LSPosed团队维护,并在GNU Lesser General Public License V3.0协议下发布。它支持广泛的Android版本(从5.0到15 Beta2,API级别21至35),并兼容多种CPU架构。此框架允许开发者实现Java方法的HOOK与解除HOOK,以及进行内联反优化,非...

gitblog_01258的博客 2154

SAP-HR 模块 PPOSE 的详细信息标签页增强

步骤1:T-CODE : SE11 创建一个名为 HRI9106 的结构 命名:HRI + 91 + 两位数字。人事管理 - 组织管理 - 集成新信息类型 - 将信息类型添加为明细范围中的标签页。步骤6:SE51 查看 7000屏幕,修改屏幕属性 让其更美观。步骤3:T-CODE : SM30维护 T777I 表。步骤5:PPCI 新建 7000屏幕用于显示。标签页 IT 开头 + 信息类型 9106。步骤2:T-CODE : PPCI。步骤4:T-CODE : SPRO。

常回来看看呀!! 1627

利用autojs制作抢购支付宝消费劵的手机脚本

前期准备工作 1.打开支付宝,点击中间的抢消费券的广告 2.点击左上角,将抢购页面添加到首页 3.查看支付宝首页是否出现消费劵 . autojs代码 "auto"; functiontaskstart(){ sleep(1000); launchApp('支付宝'); toast("正在打开支付宝应用"); sleep(1000); varxf=textContains("消费").findOne().bounds(); ...

洛阳泰山的博客 1万+

Hook Java的的一个改进版本

Hook Java的的一个改进版本 《注入安卓进程,并Hook java世界的方法》这篇好文相信大家都看这,里面所提到的方法估计大家也都试过。不过里面的所用的方法,我发现有两个可以改进的地方。 改进点一:更简单地修改java方法为本地方法 ... // hook method int argsSize = calcMethodArgsSize(method->sh

简行之旅 2万+

基于YOLOv8的智能肿瘤检测系统:从图像到诊断的深度学习应用——含代码和论文

本文提出了一种基于YOLOv8深度学习的智能肿瘤检测系统,用于医学影像(CT/MRI/X光)的自动分析与诊断。针对传统人工阅片效率低、主观性强的问题,系统采用最新的YOLOv8目标检测算法,通过改进的C2F骨干网络、Anchor-Free检测头和解耦头等创新设计,实现高效精准的肿瘤定位。文章详细阐述了模型架构、数据处理流程、训练优化方法及PyQt5用户界面开发,为临床提供可靠的AI辅助诊断工具。实验结果表明,该系统在速度和准确率上达到良好平衡,有望提升肿瘤早期筛查效率。

FJN110的博客 196

33.安卓逆向2-frida hook技术-逆向分析加密方式(一)(api-sign java层)

安卓逆向 安卓协议分析 app协议分析 保姆级攻略 app逆向 Android apk逆向

计算机王的博客 2249

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

android hook工具,Android Native Hook 工具实践

作者:GToad作者博客:GToad Blog本文章所对应项目长期维护与更新,因为在我自己的几台测试机上用得还挺顺手的。本项目作为作者本人的一个学习项目将会长期更新以修复当前可能存在的Bug以及跟进以后Android NDK可能出现的主流汇编模式。前言在目前的安卓APP测试中对于Native Hook的需求越来越大,越来越多的APP开始逐渐使用NDK来开发核心或者敏感代码逻辑。个人认为原因如下:安...

weixin_35436969的博客 1330

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

Android平台dalvik模式下java Hook框架ddi的分析(2)--dex文件的注入和调用

本文博客地址:http://blog.youkuaiyun.com/qq1084283172/article/details/77942585 前面的博客《Android平台dalvik模式下java Hook框架 ddi 的分析(1)》中,已经分析了dalvik模式下 ddi 框架Hook java方法的原理和流...

墨鱼菜鸡 403

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

终极指南:LSPlant安卓Hook框架快速上手教程

LSPlant是一款专为Android运行时(ART)设计的强大Hook框架,由LSPosed团队精心打造。作为目前最受欢迎的安卓Hook工具之一,LSPlant能够帮助开发者轻松实现Java方法的Hook与解除Hook操作,支持从Android 5.0到最新的Android 15 Beta2版本,覆盖API级别21至35,兼容多种CPU架构。 ## 🎯 为什么选择LSPlant? **核心

gitblog_00108的博客 802

LSPlant安卓HOOK框架终极指南:从入门到实战

在Android应用开发和逆向工程领域,Java方法拦截一直是一个技术难点。传统的HOOK方案往往面临兼容性差、稳定性低的问题。今天,我将为大家详细介绍LSPlant安卓HOOK框架,这是一个专门为Android运行时(ART)设计的高性能HOOK库,能够帮助开发者轻松实现Java方法的拦截和修改。 ## 为什么选择LSPlant? LSPlant作为LSPosed团队维护的开源项目,具有以下

gitblog_00319的博客 458

java上传ddi_Android平台dalvik模式下java Hook框架ddi的分析(2)--dex文件的注入和调用...

前面的博客《Android平台dalvik模式下java Hook框架ddi 的分析(1)》中,已经分析了dalvik模式下 ddi 框架Hook java方法的原理和流程,这里来学习一下ddi框架代码中涉及到的 dex文件的注入和调用。将一个Android的so库文件跨进程注入到另一个进程中,在so库文件的实现里,我们可以做很多的事情,例如:inline Hook,java方法的Hook,dex...

weixin_39832727的博客 307
上一篇: Android Hook (1) Dexposed原理
下一篇: 从Android运行时出发,打造我们的脱壳神器
Omni-Space
博客等级 码龄11年 2158粉丝 23原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值