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

xposed曾经是android平台上最好的java层hook调试工具,但是已经不再更新,android系统版本目前只能支持到6.0,故已经逐渐落伍。目前android上最广泛使用的hook工具是frida,这是另一个话题,详见:https://blog.csdn.net/m0_37567738/article/details/135714090?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522171435816916800180610376%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=171435816916800180610376&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2blogfirst_rank_ecpm_v1~rank_v31_ecpm-1-135714090-null-null.nonecase&utm_term=frida&spm=1018.2226.3001.4450

本文不涉及xposed的原理和底层实现,只是基于雷电模拟器和eclipse,对xposed的使用方法做一个简单说明,以期能达到实际上手使用的目的。至于为什么是eclipse,因为过去一段时间内,android主流开发工具就是eclipse adt,android studio在国内的广泛使用是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包XposedBridgeApi-54.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输出:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值