本文转载自: http://www.52pojie.cn/thread-396793-1-1.html

原帖:http://drops.wooyun.org/tips/7488 作者:瘦蛟舞

模块基本开发流程
1.创建工程android4.0.3(api15,测试发现其他版本也可以),可以不用activity
2.修改AndroidManifest.xml
Java
<?xml version="1.0"encoding="utf-8"?>
   package="de.robv.android.xposed.mods.tutorial"
   android:versionCode="1"
   android:versionName="1.0" >
   <uses-sdk android:minSdkVersion="15" />
   <application
       android:icon="@drawable/ic_launcher"
       android:label="@string/app_name" >
       <meta-data
           android:name="xposedmodule"
           android:value="true" />
       <meta-data
           android:name="xposeddescription"
           android:value="Easy example" />
       <meta-data
           android:name="xposedminversion"
           android:value="54" />
   </application>
</manifest>
3.在工程目录下新建一个lib文件夹,将下载好的XposedBridgeApi-54.jar包放入其中.eclipse 在工程里 选中XposedBridgeApi-54.jar右键–Build Path–Add to Build Path.IDEA 鼠标右键点击工程,选择Open ModuleSettings,在弹出的窗口中打开Dependencies选项卡.把XposedBridgeApi这个jar包后面的Scope属性改成provided.
4.模块实现接口
packagede.robv.android.xposed.mods.tutorial;
importde.robv.android.xposed.IXposedHookLoadPackage;
importde.robv.android.xposed.XposedBridge;
importde.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam;
publicclassTutorial implementsIXposedHookLoadPackage{
   publicvoidhandleLoadPackage(finalLoadPackageParam lpparam)throwsThrowable {
       XposedBridge.log("Loaded app: "+ lpparam.packageName);
    }
}
5.入口assets/xposed_init配置,声明需要加载到XposedInstaller 的入口类:
de.robv.android.xposed.mods.tutorial.Tutorial  //完整类名:包名+类名
6.定位要hook的api ,反编译目标程序,查看Smali代码 ,直接在AOSP(android源码)中查看
7.XposedBridge to hook it,指定要 hook 的包名,判断当前加载的包是否是指定的包,指定要 hook 的方法名,实现beforeHookedMethod方法和afterHookedMethod方法
示例如下:
packagede.robv.android.xposed.mods.tutorial;
importstaticde.robv.android.xposed.XposedHelpers.findAndHookMethod;importde.robv.android.xposed.IXposedHookLoadPackage;importde.robv.android.xposed.XC\_MethodHook;importde.robv.android.xposed.callbacks.XC\_LoadPackage.LoadPackageParam;
publicclassTutorialimplementsIXposedHookLoadPackage {publicvoidhandleLoadPackage(finalLoadPackageParam lpparam) throwsThrowable {if(!lpparam.packageName.equals("com.android.systemui")) return;
       findAndHookMethod("com.android.systemui.statusbar.policy.Clock",lpparam.classLoader, "updateClock", newXC_MethodHook() {
           @Override
           protectedvoidbeforeHookedMethod(MethodHookParam param) throwsThrowable {
                // this will be called beforethe clock was updated by the original method
           }
           @Override
           protectedvoIDAfterHookedMethod(MethodHookParam param) throwsThrowable {
                // this will be called afterthe clock was updated by the original method
           }
   });
    }
}
重写XC_MethodHook的两个方法beforeHookedMethod和afterHookedMethod,这两个方法会在原始的方法的之前和之后执行.您可以使用beforeHookedMethod 方法来打印/篡改方法调用的参数(通过param.args) ,甚至阻止调用原来的方法(发送自己的结果).afterHookedMethod 方法可以用来做基于原始方法的结果的事情.您还可以用它来操纵结果 .当然,你可以添加自己的代码,它将会准确地在原始方法的前或后执行.
关键API

IXposedHookLoadPackage

handleLoadPackage : 这个方法用于在加载应用程序的包的时候执行用户的操作
调用示例
publicclassXposedInterfaceimplementsIXposedHookLoadPackage {
publicvoidhandleLoadPackage(finalLoadPackageParamlpparam) throwsThrowable {
XposedBridge.log("Kevin-Loaded app:"+ lpparam.packageName); }
}
参数说明|final LoadPackageParam lpparam 这个参数包含了加载的应用程序的一些基本信息。
XposedHelpers
findAndHookMethod ;这是一个辅助方法,可以通过如下方式静态导入:
importstaticde.robv.android.xposed.XposedHelpers.findAndHookMethod;
使用示例
findAndHookMethod("com.android.systemui.statusbar.policy.Clock",lpparam.classLoader, "handleUpdateClock", newXC_MethodHook() {
@Override
protectedvoidbeforeHookedMethod(MethodHookParamparam) throwsThrowable {
// this will be called before the clock wasupdated by the original method }
@Override
protectedvoidafterHookedMethod(MethodHookParamparam) throwsThrowable {
// this will be called after the clock wasupdated by the original method }
});
参数说明
findAndHookMethod(Class<?>clazz, //需要Hook的类名
ClassLoader, //类加载器,可以设置为 null
String methodName, //需要 Hook 的方法名
Object... parameterTypesAndCallback
该函数的最后一个参数集,包含了:
(1)Hook 的目标方法的参数,譬如:
"com.android.internal.policy.impl.PhoneWindow.DecorView"
是方法的参数的类。
(2)回调方法:
a.XC_MethodHook
b.XC_MethodReplacement
模块开发中的一些细节
1.Dalvik 孵化器 Zygote (Android系统中,所有的应用程序进程以及系统服务进程SystemServer都是由Zygote进程孕育/fork出来的)进程对应的程序是/system/bin/app_process. Xposed 框架中真正起作用的是对方法的 hook。
因为 Xposed 工作原理是在/system/bin 目录下替换文件,在 install 的时候需要 root 权限,但是运行时不需要 root 权限。
2.log 统一管理,tag 显示包名
Log.d(MYTAG+lpparam.packageName,"hello"+ lpparam.packageName);
3.植入广播接收器,动态执行指令
findAndHookMethod("android.app.Application",lpparam.classLoader, "onCreate", newXC_MethodHook() {
   @Override
   protectedvoidbeforeHookedMethod(MethodHookParam param) throwsThrowable {
       Context context = (Context) param.thisObject;
       IntentFilter filter = newIntentFilter(myCast.myAction);
       filter.addAction(myCast.myCmd);
       context.registerReceiver(newmyCast(), filter);
    }
   @Override
   protectedvoidafterHookedMethod(MethodHookParam param) throwsThrowable {
        super.afterHookedMethod(param);
    }
});
4.context 获取
fristApplication = (Application)param.thisObject;
5.注入点选择 applicationoncreate 程序真正启动函数而是 MainActivity 的 onCreate (该类有可能被重写,所以通过反射得到 oncreate 方法)
String appClassName = this.getAppInfo().className;
       if(appClassName == null) {
           Method hookOncreateMethod = null;
           try{
                hookOncreateMethod =Application.class.getDeclaredMethod("onCreate", newClass[] {});
           } catch(NoSuchMethodException e) {
                e.printStackTrace();
           }
           hookhelper.hookMethod(hookOncreateMethod, newApplicationOnCreateHook());
6.排除系统 app,排除自身,确定主线程
if(lpparam.appInfo == null||
               (lpparam.appInfo.flags &(ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)) !=0){
           return;
       }elseif(lpparam.isFirstApplication &&!ZJDROID_PACKAGENAME.equals(lpparam.packageName)){
7.hook method

Only methods and constructors can behooked,Cannot hook interfaces,Cannot hook abstractmethods

只能 hook 方法和构造方法,不能 hook 接口和抽象方法
抽象类中的非抽象方法是可以 hook的, 接口中的方法不能 hook (接口中的method默认是publicabstract抽象的.field 必须是publicstaticfinal)
8.参数中有 自定义类

publicvoidmyMethod(String a, MyClass b)

通过反射得到自定义类,也可以用[xposedhelpers](https://github.com/rovo89/Xposed ... class-xposedhelpers)封装好的方法findMethod/findConstructor/callStaticMethod....
9.注入后反射自定义类
Class<?> hookMessageListenerClass =null;
hookMessageListenerClass =lpparam.classLoader.loadClass("org.jivesoftware.smack.MessageListener");
findAndHookMethod("org.jivesoftware.smack.ChatManager",lpparam.classLoader, "createChat", String.class, hookMessageListenerClass,newXC_MethodHook() {
   @Override
   protectedvoidbeforeHookedMethod(MethodHookParam param) throwsThrowable {
       String sendTo = (String) param.args[0];
       Log.i(tag , "sendTo : + "+ sendTo );
    }
   @Override
   protectedvoidafterHookedMethod(MethodHookParam param) throwsThrowable {
       super.afterHookedMethod(param);
    }
});
10.hook 一个类的方法,该类是子类并且没有重写父类的方法,此时应该 hook 父类还是子类.(hook 父类方法后,子类若没重写,一样生效.子类重写方法需要另外 hook) (如果子类重写父类方法时候加上 spuer ,hook 父类依旧有效)
例如 java.net.HttpURLConnection extends URLConnection ,
方法在父类
   publicOutputStream getOutputStream() throwsIOException {
          thrownewUnknownServiceException("protocol doesn't supportoutput");
      }
org.apache.http.impl.client.AbstractHttpClientextendsCloseableHttpClient ,
方法在父类(注意,android的继承的 AbstractHttpClient implements org.apache.http.client.HttpClient)
   publicCloseableHttpResponse execute(
           finalHttpHost target,
           finalHttpRequest request,
           finalHttpContext context) throwsIOException, ClientProtocolException {
       returndoExecute(target, request, context);
    }
android.async.http复写HttpGet导致zjdroidhook org.apache.http.impl.client.AbstractHttpClient execute 无法获取到请求 url和method
11.hook 构造方法
publicstaticXC_MethodHook.UnhookfindAndHookConstructor(String className, ClassLoader classLoader, Object...parameterTypesAndCallback) {
   returnfindAndHookConstructor(findClass(className, classLoader),parameterTypesAndCallback);
}
12.承接4,application 的onCreate 方法被重写,例如阿里的壳,重写为原生 native 方法.
解1:通过反射到 application 类重写后的 onCreate 方法再对该方法进行hook
解2:hook 构造方法(构造方法被重写,继续解1)
13.native 方法可以 hook,不过是在 java 层调用时hook而不是 hook 动态链接库.
实战Hook Android 中可能的出现 HTTP 请求
首先确定http 请求的 api,大致分为:
apache 提供的 HttpClient
1) 创建 HttpClient 以及 GetMethod/ PostMethod, HttpRequest等对象;
2) 设置连接参数;
3) 执行 HTTP 操作;
4) 处理服务器返回结果.
java 提供的 HttpURLConnection
1) 创建 URL 以及URLConnection / HttpURLConnection 对象
2) 设置连接参数
3) 连接到服务器
4) 向服务器写数据
5) 从服务器读取数据
android 提供的 webview
第三方库:volley/android-async-http/xutils (本质是对前两种的方式的延伸,方法的重写可能对接下来的hook 产生影响)
不太了解 java 的 hook 前可以先看下基础的代码HttpClient以及HttpURLConnection的基本使用
对 HttpClient的 hook 可以参考贾志军大牛的Zjdroid
Method executeRequest =RefInvoke.findMethodExact("org.apache.http.impl.client.AbstractHttpClient",ClassLoader.getSystemClassLoader(),
       "execute", HttpHost.class, HttpRequest.class,HttpContext.class);
hookhelper.hookMethod(executeRequest, newAbstractBahaviorHookCallBack(){
   @Override
   publicvoiddescParam(HookParam param) {
       // TODO Auto-generated method stub
       Logger.log_behavior("Apache Connect to URL ->");
       HttpHost host = (HttpHost) param.args[0];
       HttpRequest request = (HttpRequest) param.args[1];
       if(request instanceoforg.apache.http.client.methods.HttpGet) {
           org.apache.http.client.methods.HttpGet httpGet =(org.apache.http.client.methods.HttpGet) request;
           Logger.log_behavior("HTTP Method : "+ httpGet.getMethod());
           Logger.log_behavior("HTTP GET URL : "+httpGet.getURI().toString());
           Header[] headers = request.getAllHeaders();
           if(headers != null) {
                for(inti = 0; i < headers.length;i++) {
                   Logger.log_behavior(headers.getName() + ":"+headers.getName());
                }
           }
       } elseif(request instanceofHttpPost) {
           HttpPost httpPost = (HttpPost) request;
           Logger.log_behavior("HTTP Method : "+ httpPost.getMethod());
           Logger.log_behavior("HTTP URL : "+httpPost.getURI().toString());
           Header[] headers = request.getAllHeaders();
           if(headers != null) {
                for(inti = 0; i <headers.length; i++) {
                   Logger.log_behavior(headers.getName() + ":"+headers.getValue());
                }
           }
           HttpEntity entity = httpPost.getEntity();
           String contentType = null;
           if(entity.getContentType() != null) {
                contentType =entity.getContentType().getValue();
               if(URLEncodedUtils.CONTENT_TYPE.equals(contentType)) {
                    try{
                        byte[] data =newbyte[(int) entity.getContentLength()];
                       entity.getContent().read(data);
                        String content =newString(data, HTTP.DEFAULT_CONTENT_CHARSET);
                       Logger.log_behavior("HTTP POST Content : "+ content);
                    }catch(IllegalStateException e) {
                        // TODO Auto-generatedcatch block
                        e.printStackTrace();
                    } catch(IOException e) {
                        // TODO Auto-generatedcatch block
                        e.printStackTrace();
                    }
                }elseif(contentType.startsWith(HTTP.DEFAULT_CONTENT_TYPE)) {
                    try{
                        byte[] data =newbyte[(int) entity.getContentLength()];
                       entity.getContent().read(data);
                        String content =newString(data, contentType.substring(contentType.lastIndexOf("=") +1));
                       Logger.log_behavior("HTTP POST Content : "+ content);
                    }catch(IllegalStateException e) {
                        // TODO Auto-generatedcatch block
                        e.printStackTrace();
                    } catch(IOException e) {
                        // TODO Auto-generatedcatch block
                        e.printStackTrace();
                    }
                }
           }else{
                byte[] data = newbyte[(int)entity.getContentLength()];
                try{
                   entity.getContent().read(data);
                    String content =newString(data, HTTP.DEFAULT_CONTENT_CHARSET);
                   Logger.log_behavior("HTTP POST Content : "+ content);
                } catch(IllegalStateException e){
                    // TODO Auto-generatedcatch block
                    e.printStackTrace();
                } catch(IOException e) {
                    // TODO Auto-generatedcatch block
                    e.printStackTrace();
                }
           }
       }
    }
   @Override
   publicvoidafterHookedMethod(HookParam param) {
       // TODO Auto-generated method stub
       super.afterHookedMethod(param);
       HttpResponse resp = (HttpResponse) param.getResult();
       if(resp != null) {
           Logger.log_behavior("Status Code = "+resp.getStatusLine().getStatusCode());
           Header[] headers = resp.getAllHeaders();
           if(headers != null) {
                for(inti = 0; i <headers.length; i++) {
                   Logger.log_behavior(headers.getName() + ":"+headers.getValue());
                }
           }
       }
    }
});
对 HttpURLConnection 的 hook Zjdroid 未能提供完美的解决方案,想要取得除了 URL 之外的 data 字段必须对I/O流操作.
Method openConnectionMethod =RefInvoke.findMethodExact("java.net.URL",ClassLoader.getSystemClassLoader(), "openConnection");
hookhelper.hookMethod(openConnectionMethod,newAbstractBahaviorHookCallBack() {
   @Override
   publicvoiddescParam(HookParam param) {
        // TODO Auto-generated method stub
       URL url = (URL) param.thisObject;
       Logger.log_behavior("Connect to URL ->");
       Logger.log_behavior("The URL = "+ url.toString());
    }
});
我采取的临时解决方法是对I/O 进行正则匹配,类似 url 的 data 字段就打印出来,代码如下(这段代码只能解决前文 HttpUtils而且会有误报,大家有啥好想法欢迎指点一二)
findAndHookMethod("java.io.PrintWriter",lpparam.classLoader, "print",String.class, newXC_MethodHook() {
   @Override
   protectedvoidbeforeHookedMethod(MethodHookParam param) throwsThrowable {
       String print = (String) param.args[0];
       Pattern pattern = Pattern.compile("(\\w+=.*)");
       Matcher matcher = pattern.matcher(print);
       if(matcher.matches())
           Log.i(tag+lpparam.packageName,"data : "+ print);
       //Log.d(tag,"A :" + print);
    }
});
因为Android-async-http重写了 HttpGet 导致 Zjdroidhook 失败(未进入 HttpGet 和 HttpPost 的判读),加入一个else 语句就可以解决这个问题
else{
                   HttpEntityEnclosingRequestBase httpGet =(HttpEntityEnclosingRequestBase) request;
                    HttpEntity entity =httpGet.getEntity();
                   Logger.log_behavior("HttpRequestBase URL : "+httpGet.getURI().toString());
                    Header[] headers =request.getAllHeaders();
                    if(headers != null) {
                        for(inti = 0; i <headers.length; i++) {
                           Logger.log_behavior(headers.getName() + ":"+headers.getName());
                        }
                    }
                    if(entity!= null){
                                try{
                                    String content = EntityUtils
                                           .toString(entity);
                                   Logger.log_behavior("HTTP entity Content : "
                                            +content);
                               }catch(IllegalStateException e) {
                                    // TODOAuto-generated catch block
                                   e.printStackTrace();
                                }catch(IOException e) {
                                    // TODO Auto-generated catchblock
                                   e.printStackTrace();
                                }
                    }

[转载] Android.Hook框架xposed开发篇的更多相关文章

  1. 【转】Android Hook框架Xposed详解

    1 Introduction 1.1  概述 Xposed 是 GitHUB 上 rovo89 大大设计的一个针对 Android 平台的动态劫持项目,通过替换 /system/bin/app_pro ...

  2. Android Hook框架Xposed详解

    1 Introduction 1.1  概述 Xposed 是 GitHUB 上 rovo89 大大设计的一个针对 Android 平台的动态劫持项目,通过替换 /system/bin/app_pro ...

  3. android hook 框架 xposed 如何实现挂钩

    Android so注入-libinject2 简介.编译.运行 Android so注入-libinject2  如何实现so注入 Android so注入-Libinject 如何实现so注入 A ...

  4. android hook 框架 xposed 如何实现注入

    Android so注入-libinject2 简介.编译.运行 Android so注入-libinject2  如何实现so注入 Android so注入-Libinject 如何实现so注入 A ...

  5. android hook 框架 ADBI 如何实现dalvik函数挂钩

    Android so注入-libinject2 简介.编译.运行 Android so注入-libinject2  如何实现so注入 Android so注入-Libinject 如何实现so注入 A ...

  6. android hook 框架 libinject2 如何实现so注入

    Android so注入-libinject2 简介.编译.运行 Android so注入-libinject2  如何实现so注入 Android so注入-Libinject 如何实现so注入 A ...

  7. android hook 框架 libinject2 简介、编译、运行

    Android so注入-libinject2 简介.编译.运行 Android so注入-libinject2  如何实现so注入 Android so注入-Libinject 如何实现so注入 A ...

  8. Android网络框架Volley(体验篇)

    Volley是Google I/O 2013推出的网络通信库,在volley推出之前我们一般会选择比较成熟的第三方网络通信库,如: android-async-http retrofit okhttp ...

  9. Android网络框架Volley(实战篇)

      之前讲了ym—— Android网络框架Volley(体验篇),大家应该了解了volley的使用,接下来我们要看看如何把volley使用到实战项目里面,我们先考虑下一些问题: 从上一篇来看 mQu ...

随机推荐

  1. Linux下获得系统时间的C语言实现

    Linux下获得系统时间的C语言的实现方法 #include<time.h> //C语言的头文件#include<stdio.h> //C语言的I/O   int main() ...

  2. 职责链模式(chain of responsibility Pattern)

    职责链模式:使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系.将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理他为止. •Handler: 抽象处理者:定义出一个 ...

  3. ps颜色模式

    HSB(hue.saturation.bright)  基于人眼 RGB 基于光 CMYK 基于色 LAB 基于大自然颜色库(理论)

  4. php 单引号 双引号 ,php字符串/ hmtl / 数据库显示/ 及php的几个转化函数

    * 以单引号为定界符的php字符串,支持两个转义\'和\\* 以双引号为定界符的php字符串,支持下列转义(\'会直接输出\' ,也会转义 \\):    \n 换行(LF 或 ASCII 字符 0x ...

  5. Python decode与encode

      字符串在Python内部的表示是unicode编码(8-bit string),因此,在做编码转换时,通常需要以unicode作为中间编码,即先将其他编码的字符串解码(decode)成unicod ...

  6. nokogiri如何使用

    直接来个简单的代码实例就明白啦! require 'nokogiri' xml_data=<<XML <library> <NAME><![CDATA[Fav ...

  7. CDN的实现原理

    在描述CDN的实现原理,让我们先看传统的未加缓存服务的访问过程,以便了解CDN缓存访问方式与未加缓存访问方式的差别: 用户提交域名→浏览器对域名进行解释→得到目的主机的IP地址→根据IP地址访问发出请 ...

  8. ADF_Desktop Integration系列3_ADF桌面集成入门之重定义ADF Desktop Excel

    2013-05-01 Created By BaoXinjian

  9. 虚拟机Ubuntu16,caffe环境搭建

    虚拟机下的Ubuntu16.04+caffe+onlycup 官网的step很重要,要跟着官网,的步骤来:http://caffe.berkeleyvision.org/installation.ht ...

  10. Hihocoder 1035 [树形dp]

    /* 题意: 不要低头,不要放弃,不要气馁,不要慌张. PS:人生第一道自己独立做出来的树形dp... 给一棵树,标号1到n,每条边有两个权值,步行时间和驾车时间.车在1号点. 给m个必须访问的关键点 ...