原文出處——>[Xposed源碼剖析——hook具體實現](http://blog.csdn.net/yzzst/article/details/47913867)
承接上文[Xposed源碼剖析——Xposed初始化](http://blog.csdn.net/yzzst/article/details/47834077)
之前我們看到了xposed各種初始化的工作,其實都是完成了針對系統中各種method的hook和替換工作。
那么具體如何替換,其實都是調用了其中的。XposedBridge_hookMethodNative函數。這里,我們詳細的看看XposedBridge_hookMethodNative函數中,做了一些什么操作。
~~~
/**
*
* 將輸入的Class中的Method方法的nativeFunc替換為xposedCallHandler
*
* @param env JniEnv
* @param reflectedMethodIndirect 待反射的函數
* @param declaredClassIndirect 定義的class
* @param slot 函數偏移量
* @param additionalInfoIndirect 添加的函數
*
*/
void XposedBridge_hookMethodNative(JNIEnv* env, jclass clazz, jobject reflectedMethodIndirect,
jobject declaredClassIndirect, jint slot, jobject additionalInfoIndirect) {
// 容錯
if (declaredClassIndirect == NULL || reflectedMethodIndirect == NULL) {
dvmThrowIllegalArgumentException("method and declaredClass must not be null");
return;
}
// 根據函數的偏移量,從classloader中找到準備替換的函數。
ClassObject* declaredClass = (ClassObject*) dvmDecodeIndirectRef(dvmThreadSelf(), declaredClassIndirect);
Method* method = dvmSlotToMethod(declaredClass, slot);
if (method == NULL) {
dvmThrowNoSuchMethodError("Could not get internal representation for method");
return;
}
if (isMethodHooked(method)) {
// already hooked
return;
}
// 保存替換前的數據信息
XposedHookInfo* hookInfo = (XposedHookInfo*) calloc(1, sizeof(XposedHookInfo));
memcpy(hookInfo, method, sizeof(hookInfo->originalMethodStruct));
hookInfo->reflectedMethod = dvmDecodeIndirectRef(dvmThreadSelf(), env->NewGlobalRef(reflectedMethodIndirect));
hookInfo->additionalInfo = dvmDecodeIndirectRef(dvmThreadSelf(), env->NewGlobalRef(additionalInfoIndirect));
// 替換函數方法 , 讓nativeFunction指向本地的hookedMethodCallback
SET_METHOD_FLAG(method, ACC_NATIVE);
method->nativeFunc = &hookedMethodCallback;
method->insns = (const u2*) hookInfo;
method->registersSize = method->insSize;
method->outsSize = 0;
if (PTR_gDvmJit != NULL) {
// reset JIT cache
char currentValue = *((char*)PTR_gDvmJit + MEMBER_OFFSET_VAR(DvmJitGlobals,codeCacheFull));
if (currentValue == 0 || currentValue == 1) {
MEMBER_VAL(PTR_gDvmJit, DvmJitGlobals, codeCacheFull) = true;
} else {
ALOGE("Unexpected current value for codeCacheFull: %d", currentValue);
}
}
}
~~~
對vm不熟悉的,解釋一下幾個不怎么常用的函數。
|名稱 |說明|
| --- | --- |
|dvmDecodeIndirectRef| 將間接引用jobject轉換為對象引用Object*|
|dvmSlotToMethod |根據偏移量,從ClassLoader中獲取函數指針|
~~~
/**
* hook方法調用時的回調
*/
void hookedMethodCallback(const u4* args, JValue* pResult, const Method* method, ::Thread* self) {
if (!isMethodHooked(method)) {
dvmThrowNoSuchMethodError("Could not find Xposed original method - how did you even get here?");
return;
}
XposedHookInfo* hookInfo = (XposedHookInfo*) method->insns;
Method* original = (Method*) hookInfo;
Object* originalReflected = hookInfo->reflectedMethod;
Object* additionalInfo = hookInfo->additionalInfo;
// convert/box arguments
const char* desc = &method->shorty[1]; // [0] is the return type.
Object* thisObject = NULL;
size_t srcIndex = 0;
size_t dstIndex = 0;
// for non-static methods determine the "this" pointer
if (!dvmIsStaticMethod(original)) {
thisObject = (Object*) args[0];
srcIndex++;
}
ArrayObject* argsArray = dvmAllocArrayByClass(objectArrayClass, strlen(method->shorty) - 1, ALLOC_DEFAULT);
if (argsArray == NULL) {
return;
}
while (*desc != '\0') {
char descChar = *(desc++);
JValue value;
Object* obj;
switch (descChar) {
case 'Z':
case 'C':
case 'F':
case 'B':
case 'S':
case 'I':
value.i = args[srcIndex++];
obj = (Object*) dvmBoxPrimitive(value, dvmFindPrimitiveClass(descChar));
dvmReleaseTrackedAlloc(obj, self);
break;
case 'D':
case 'J':
value.j = dvmGetArgLong(args, srcIndex);
srcIndex += 2;
obj = (Object*) dvmBoxPrimitive(value, dvmFindPrimitiveClass(descChar));
dvmReleaseTrackedAlloc(obj, self);
break;
case '[':
case 'L':
obj = (Object*) args[srcIndex++];
break;
default:
ALOGE("Unknown method signature description character: %c", descChar);
obj = NULL;
srcIndex++;
}
setObjectArrayElement(argsArray, dstIndex++, obj);
}
// 調用Java中的對應方法,即之前我們用到,的handleHookedMethod
JValue result;
dvmCallMethod(self, xposedHandleHookedMethod, NULL, &result,
originalReflected, (int) original, additionalInfo, thisObject, argsArray);
dvmReleaseTrackedAlloc(argsArray, self);
// exceptions are thrown to the caller
if (dvmCheckException(self)) {
return;
}
// return result with proper type
ClassObject* returnType = dvmGetBoxedReturnType(method);
if (returnType->primitiveType == PRIM_VOID) {
// ignored
} else if (result.l == NULL) {
if (dvmIsPrimitiveClass(returnType)) {
dvmThrowNullPointerException("null result when primitive expected");
}
pResult->l = NULL;
} else {
if (!dvmUnboxPrimitive(result.l, returnType, pResult)) {
dvmThrowClassCastException(result.l->clazz, returnType);
}
}
}
~~~
- 前言
- Android系統的體系結構
- Dalvik VM 和 JVM 的比較
- Android 打包應用程序并安裝的過程
- Android ADB工具
- Android應用開發
- Android UI相關知識總結
- Android 中window 、view、 Activity的關系
- Android應用界面
- Android中的drawable和bitmap
- AndroidUI組件adapterView及其子類和Adapter的關系
- Android四大組件
- Android 數據存儲
- SharedPreference
- Android應用的資源
- 數組資源
- 使用Drawable資源
- Material Design
- Android 進程和線程
- 進程
- 線程
- Android Application類的介紹
- 意圖(Intent)
- Intent 和 Intent 過濾器(Google官網介紹)
- Android中關于任務棧的總結
- 任務和返回棧(官網譯文)
- 總結
- Android應用安全現狀與解決方案
- Android 安全開發
- HTTPS
- 安卓 代碼混淆與打包
- 動態注入技術(hook技術)
- 一、什么是hook技術
- 二、常用的Hook 工具
- Xposed源碼剖析——概述
- Xposed源碼剖析——app_process作用詳解
- Xposed源碼剖析——Xposed初始化
- Xposed源碼剖析——hook具體實現
- 無需Root也能Hook?——Depoxsed框架演示
- 三、HookAndroid應用
- 四、Hook原生應用程序
- 五、Hook 檢測/修復
- Android 應用的逆向與加固保護技術
- OpenCV在Android中的開發
- Android高級開發進階
- 高級UI
- UI繪制流程及原理
- Android新布局ConstraintLayout約束布局
- 關鍵幀動畫
- 幀動畫共享元素變換
- Android異步消息處理機制完全解析,帶你從源碼的角度徹底理解
- Android中為什么主線程不會因為Looper.loop()里的死循環卡死?
- 為什么 Android 要采用 Binder 作為 IPC 機制?
- JVM 中一個線程的 Java 棧和寄存器中分別放的是什么?
- Android源碼的Binder權限是如何控制?
- 如何詳解 Activity 的生命周期?
- 為什么Android的Handler采用管道而不使用Binder?
- ThreadLocal,你真的懂了嗎?
- Android屏幕刷新機制