Android java层hook------xposed框架的使用

news2024/12/26 23:05:47

xposed曾经是android平台上最好的java层hook和调试工具,由于已经不再更新,当前支持的android系统版本比较老旧,目前只能支持到android6.0,故已经逐渐落伍,目前android上最广泛使用的hook工具是frida,这是另一个话题。本文不涉及xposed的原理和底层实现,只是基于雷电模拟器和eclipse,对xposed的使用方法做一个简单说明,以期能达到熟练使用的目的。至于为什么是eclipse,因为过去一段实践内,android的主流开发工具就是eclipse加adt,android studio的广泛使用是2015、2016年之后的事了。

雷电模拟器下载地址:点击下载

本文代码工程例子下载地址:点击下载

(一)使用方法

雷电模拟器安装后如下如所示(模拟器中安装的android版本是5.1):
在这里插入图片描述

搜索xposed并安装:
在这里插入图片描述
安装xposed后,点击左上角菜单中的“框架”按钮,然后点击”version89",选择“直接安装”后,会自动下载安装xposed框架,框架安装完成后如下所示:
在这里插入图片描述
在左上角的按钮中点击”模块“按钮,可以看到安装的xopsed模块:

在这里插入图片描述
下面开始介绍插件开发。

(二)插件开发

eclipse是一个强大的多平台、多语言开发工具,到目前为止仍然有很多项目是基于此工具维护和开发的,插件开发基于古老的eclipse。

首先编写一个android程序test,包名为com.example.test,主类名为com.example.test.MainActivity,然后再该工程上右键”run as“–>“Android Application”,将其安装到模拟器中。

接下来,编写xposed插件来hook该程序主类中的onCreaete函数。
在eclipse中创建一个Android项目,包名为com.xposedtest ,接下来的项目选项一路点击"确定"。创建好项目后,在包中创建一个主类,名为XposedTest。

  1. Androidmanifest.xml中Application节区插入如下代码:
        <meta-data 
            android:name="xposedmodule" 
            android:value="true" />
        <meta-data 
            android:name="xposedminversion" 
            android:value="30" />
        <meta-data 
            android:name="xposeddescription" 
            android:value="xposed_hook_test"/>

该节区是xposed插件的版本和描述信息。

  1. assets文件夹下新建文件xposed_init文件,其内容为xposed插件的主类名,比如当前为com.xposedtest.XposedTest。
  2. 导入XposedBridgeApi-54.jar包。该包是xposed插件开发必不可少的支持包。在eclipse中点击"project"按钮–>“properties”–>“Java build path” -->“Libraries”–>“Add External Jars”,然后在选择框内选中jar包。
  3. 在xposed插件的主类XposedTest中,如下编写hook代码
package com.xposedtest;

import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Method;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Environment;
import android.text.Editable;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Toast;
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XC_MethodHook.Unhook;
import de.robv.android.xposed.XposedHelpers;
//import de.robv.android.xposed.callbacks.XC_InitPackageResources.Unhook;
import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam;



public class XposedTest implements IXposedHookLoadPackage {
	
	public final static String LOG_FILE_PATH = "/storage/sdcard0/XposedLog/"; 
	public final static String LOG_FILE_NAME = "XposedLog.txt";
	public final static int START_FLAG = 0;
	
	public static String TAG = "XposedTest";
	
	public void handleLoadPackage(LoadPackageParam lpparam) throws Throwable {
		
		if (lpparam.packageName.equals("com.example.test") == true )
		{
			Log.e(TAG,"handleLoadPackage");
			Context context = getContext();
			if(context!=null){
				Toast.makeText(context, "handleLoadPackage", Toast.LENGTH_LONG).show();
			}
			
	
			XposedHelpers.findAndHookMethod("com.example.test.MainActivity", 
					lpparam.classLoader, "onCreate", Bundle.class,new XC_MethodHook() {
				@SuppressLint("ShowToast") 
				@Override
				protected void afterHookedMethod(MethodHookParam param) throws Throwable {
					XposeWriteLogFile(" after param\r\n");

					Context context = getContext();
					Toast.makeText(context, "after onCreate", Toast.LENGTH_LONG).show();
					
					Log.e(TAG,"after onCreate");
					
					XposeWriteLogFile("after result:\r\n");
				}
				
				@SuppressLint("ShowToast") @Override
				protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
					XposeWriteLogFile(" before param\r\n");

					Context context = getContext();
					Toast.makeText(context, "before onCreate", Toast.LENGTH_LONG).show();
					
					Log.e(TAG,"before onCreate");
				}
			});
		}
	}
	
	
    public static Context getContext(){
        try {
            Class<?> ActivityThread = Class.forName("android.app.ActivityThread");
            Method methodcat = ActivityThread.getMethod("currentActivityThread");
            Object currentActivityThread = methodcat.invoke(ActivityThread);
            Method methodga = currentActivityThread.getClass().getMethod("getApplication");
            Context context =(Context)methodga.invoke(currentActivityThread);
            if (context == null) {
                Log.e(TAG, "context null");
            }else{
                Log.e(TAG, "get context ok,package name:" + context.getPackageName()+"/class name:" + context.getClass().getName());
                return context;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }
	
    public void XposeWriteLogFile(byte [] bytestr) 
    {   
        String sdStatus = Environment.getExternalStorageState();   
        if(!sdStatus.equals(Environment.MEDIA_MOUNTED)) 
        {   
            return;   
        }   
        try 
        {   
            String pathName=LOG_FILE_PATH;   
            String fileName=LOG_FILE_NAME;   
            File path = new File(pathName);   
            File file = new File(pathName + fileName);   
            if( !path.exists()) 
            {   
                path.mkdir();   
            }   
            if( !file.exists() ) 
            {   
                file.createNewFile();   
            }   
            FileOutputStream stream = new FileOutputStream(file,true);   
            
            if(bytestr.length > 0)
            {
            	stream.write(bytestr);
            }
            stream.write("\r\n".getBytes());
            stream.close();    
        } 
        catch(Exception e) 
        {   
            e.printStackTrace();   
        }   
    }
	
	
    public void XposeWriteLogFile(String str) 
    {   
        String sdStatus = Environment.getExternalStorageState();   
        if(!sdStatus.equals(Environment.MEDIA_MOUNTED)) 
        {   
            return;   
        }   
        try 
        {   
            String pathName=LOG_FILE_PATH;   
            String fileName=LOG_FILE_NAME;   
            File path = new File(pathName);   
            File file = new File(pathName + fileName);   
            if( !path.exists()) 
            {   
                path.mkdir();   
            }   
            if( !file.exists() ) 
            {   
                file.createNewFile();   
            }   
            FileOutputStream stream = new FileOutputStream(file,true);   

            if(str.length() > 0)
            {
            	stream.write(str.getBytes());
            }
            stream.write("\r\n".getBytes());
            stream.close();    
        } 
        catch(Exception e) 
        {   
            e.printStackTrace();   
        }   
    }
    
}


可以看到,该类继承自IXposedHookLoadPackage 类,在方法handleLoadPackage中,通过XposedHelpers.findAndHookMethod接口实现对android中任意其他包的方法的hook。该函数的原型如下:
在这里插入图片描述
其第一个参数是要hook的类名,第二个参数是lpparam.classLoader,第三个参数是方法名,第4个参数是hook的方法的参数,第5个参数是如下回调接口:

new XC_MethodHook() {
				@Override
				protected void afterHookedMethod(MethodHookParam param) throws Throwable {
						//do something after hook
				}
				
				@Override
				protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
						//do something before hook
				}
			}

其中的afterHookedMethod是被hook函数执行完后执行的,beforeHookedMethod在被hook函数执行前执行。函数体中实现具体的hook功能,当前例子里,是在hook函数前后分别在/storage/sdcard0/XposedLog/XposedLog.txt文件中输出一行记录,以及输出toast和log。

编写完后,同样右键工程,点击"run as"–>“Android Application”,将插件安装到模拟器中。同时在xposed中,点击"模块"菜单,并在右边的选项中选中该模块,然后将模拟器重启后,插件即可生效。

此时,点击test程序,在test启动和退出时,可以看到Toast输出、sd卡中的文件记录输出、log输出:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/563584.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据结构《链表》无头单向非循环-动图详解

前言 前面学习了顺序表发现&#xff0c;顺序表虽然好&#xff0c;但也有很多不足的地方&#xff0c;比方说&#xff0c;顺序表是一块连续的物理空间&#xff0c;如果头插或者头删&#xff0c;那么整个数组的数据都要移动。但是链表不一样&#xff0c;链表是通过指针访问或者调…

昨天面了个腾讯拿 48K 出来的,让我见识到了基础的天花板

今年的春招基本已经进入大规模的开奖季了&#xff0c;很多小伙伴收获不错&#xff0c;拿到了心仪的 offer。 各大论坛和社区里也看见不少小伙伴慷慨地分享了常见的面试题和八股文&#xff0c;为此咱这里也统一做一次大整理和大归类&#xff0c;这也算是划重点了。 俗话说得好&a…

ESP8266获取天气预报信息,并使用CJSON解析天气预报数据

一、实现功能 当前文章介绍如何使用ESP8266和STM32微控制器&#xff0c;搭配OLED显示屏&#xff0c;制作一个能够实时显示天气预报的智能设备。将使用心知天气API来获取天气数据&#xff0c;并使用MQTT协议将数据传递给STM32控制器&#xff0c;最终在OLED显示屏上显示。 心知…

Python篇——数据结构与算法(第二部分)

目录 二、排序算法&#xff08;承接第一部分&#xff09; 1、堆排序算法——树的基础知识补充 2、树的基本概念 3、二叉树基础知识 &#xff08;1&#xff09;满二叉树 &#xff08;2&#xff09;完全二叉树 &#xff08;3&#xff09;二叉树的存储方式&#xff08;表示方式…

Python基础教程:第九章_Python异常模块与包

从现在开始&#xff0c;让我们来进入到新的章节&#xff0c; Python 异常模块与包的内容学习。本章节我们主要分为 6 部分进行讲解&#xff0c;包含了 Python 异常的相关操作以及 Python 的模块操作&#xff0c; Python 的包操作和安装第三方 Python 包的相关操作。 了解异常 …

【Netty】Netty ChannelHandler(四)

文章目录 前言一、ChannelHandler二、ChannelInboundHandler三、ChannelOutboundHandler四、ChannelDuplexHandler总结 前言 前两篇文章我们已经对Netty进行了简单的了解和架构设计原理的剖析。 相关文章链接如下&#xff1a; Netty 概述&#xff08;一&#xff09;Netty 架构…

在互联网寒冬,我们应届生应如何提高竞争力?

前言 在当前就业形势下&#xff0c;如何提高应届生在职场中的竞争力&#xff1f;具有哪些有效的方法和策略可供选择&#xff1f;这是一个备受关注的热点话题。哪些方面会对应届生的职场发展起到关键的推动和支撑作用呢&#xff1f;我也来讲一下我是打算如何提升自己的职场竞争力…

移动应用架构解析:用户界面层、业务逻辑层、数据访问层

移动应用的成功离不开一个良好的架构设计&#xff0c;在移动应用开发过程中&#xff0c;合理的层次结构对于应用的可维护性、可扩展性和可测试性至关重要。 移动应用的常见层次结构包括用户界面层、业务逻辑层、数据访问层&#xff0c;但是随着跨平台开发框架的不断发展&#…

【低压配电漏电继电器660V/LLJ-100H/AC220V 中性点漏电保护 JOSEF】

LLJ-F(S)系列漏电继电器 系列型号&#xff1a; LLJ-10F(S)漏电继电器LLJ-15F(S)漏电继电器LLJ-16F(S)漏电继电器 LLJ-25F(S)漏电继电器LLJ-30F(S)漏电继电器LLJ-32F(S)漏电继电器 LLJ-60F(S)漏电继电器LLJ-63F(S)漏电继电器LLJ-80F(S)漏电继电器 LLJ-100F(S)漏电继电器LLJ-120…

医学影像检测方法(B超、DR、CT、MRI)

医学影像检测方法 当涉及到医学影像学时&#xff0c;B超&#xff08;超声波检查&#xff09;、DR&#xff08;数字X射线摄影&#xff09;、CT&#xff08;计算机断层扫描&#xff09;和MRI&#xff08;磁共振成像&#xff09;是常见的诊断工具。以下是对这四种影像技术的基本概…

智能门锁揭开新方案:NV340D芯片打造更智能安全的语音解锁体验

智能门锁可以实现一键开锁、实时监控等功能&#xff0c;带来了更便捷、智能的门禁管理体验&#xff0c;逐渐成为人们生活中必不可少的一部分。近年来&#xff0c;随着人工智能技术的不断进步&#xff0c;越来越多的智能门锁开始集成语音控制系统&#xff0c;以提供更加方便的门…

人民大学与加拿大女王大学金融硕士项目——职场不会拒绝一个优秀的金融人才

在金融行业摸爬滚打多年的金融人&#xff0c;通过多年的拼搏与积累&#xff0c;已身处于一个相对舒适、从容的阶段&#xff0c;能沉淀下来再学习的金融人更是令人钦佩。在繁忙的工作之余他们依然保持对学业的热情&#xff0c;以应对瞬息万变的环境发展。人民大学与加拿大女王大…

Unity AssetBundle资源热更插件

Unity AssetBundle资源热更插件 CatAssetManager运行模式 - Package Only新建一个AssetBundle更改AssetBundle的Group分类更改AssetBundle的打包方式 构建规则 加密方式输出AssetBundle 运行模式 - Updateable查看我们热更的Bundle输出目录WebServer目录上传到服务器上选择热更…

u盘数据不见了能恢复吗?可以试试这3种方法

U盘通常体积小巧&#xff0c;存储容量较大&#xff0c;在现代社会中广泛使用。用户可以将各种类型的数据存储到U盘中&#xff0c;如照片、音乐、视频、文档等。但是使用过程中U盘数据无故消失了怎么办呢&#xff1f;在未备份u盘数据的情况下&#xff0c;u盘数据不见了能恢复吗&…

Jenkins发送邮件、定时执行、持续部署

集成Allure报告只需要配置构建后操作即可。但如果是web自动化&#xff0c;或是用HTMLTestRunner生成报告&#xff0c;构建后操作要选择Publish HTML reports&#xff0c;而构建中还要添加Execute system Groovy script插件&#xff0c;内容&#xff1a; System.setProperty(&q…

FT2000+ openEuler 20.03 LTS SP3 NUMA关闭 numa=off 对应用程序申请内存大小的影响,NUMA开关作用

测试程序 编写内存消耗程序 eatMemory.c #define _GNU_SOURCE#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <string.h> #include <unistd.h> #include <sys/time.h> #include <sched.h> #include <…

k8s入门实战(Pod-Label-Deployment)

k8s入门实战(Pod-Label-Deployment) Pod Pod 是可以在 Kubernetes 中创建和管理的、最小的可部署的计算单元。 k8s架构图&#xff1a; k8s集群启动后&#xff0c;集群中各个组件也是以pod方式运行 [rootmaster ~]# kubectl get pod -n kube-system NAME …

RAR压缩文件如何转换成ZIP格式?

压缩文件有多种不同的格式&#xff0c;有时候因为需求不同&#xff0c;我们需要把RAR压缩文件转换成ZIP格式&#xff0c;那要如何操作呢&#xff1f;下面小编分享2种简单的方法。 方法一&#xff1a; 如果需要转换的RAR压缩包不是很多&#xff0c;我们可以直接把文件名字后缀“…

Spring Boot日志系统大揭秘:从零开始学习Spring Boot日志:常见问题解答和最佳实践

一. 关于 Spring Boot 日志的使用 Spring Boot 日志机制和工具用于记录应用程序的日志信息和追踪应用程序的执行过程。它集成了常用的日志框架&#xff0c;如 Log4j、logback、Java Util Logging等&#xff0c;并提供简单易用的配置方式&#xff0c;让开发人员可以方便地监控应…

【web基础与HTTP协议】

目录 一、Web基础1、域名1.1、域名的概述1.2、域名空间结构1.3、域名注册 2、网页的概念2.1、网页的概述2.2、网址的概述1、URI和URL的区别 二、HTML概述1、HTML 基本标签2、HTML 文件结构如下3、头标签中常用标签4、内容标签中常用标签 三、静态网页与动态网页3.1、目前常用的…