Commit d577c5a6 authored by swift_gan's avatar swift_gan

fix crash when hook replacement

parent a7924ae8
......@@ -51,6 +51,14 @@ bool ArtMethod::isCompiled() {
return getQuickCodeEntry() != SandHook::CastArtMethod::quickToInterpreterBridge;
}
bool ArtMethod::isThumbCode() {
#if defined(__arm__)
return (reinterpret_cast<Size>(getQuickCodeEntry()) & 0x1) == 0x1;
#else
return false;
#endif
}
void ArtMethod::setAccessFlags(uint32_t flags) {
CastArtMethod::accessFlag->set(this, flags);
}
......@@ -84,6 +92,10 @@ void* ArtMethod::getInterpreterCodeEntry() {
return CastArtMethod::entryPointFormInterpreter->get(this);
}
void* ArtMethod::getDeclaringClassPtr() {
return CastArtMethod::declaringClass->get(this);
}
void ArtMethod::setQuickCodeEntry(void *entry) {
CastArtMethod::entryPointQuickCompiled->set(this, entry);
}
......@@ -103,6 +115,10 @@ void ArtMethod::setDexCacheResolveItem(uint32_t index, void* item) {
CastArtMethod::dexCacheResolvedMethods->setElement(this, index, item);
}
void ArtMethod::setDeclaringClassPtr(void *classPtr) {
CastArtMethod::declaringClass->set(this, classPtr);
}
bool ArtMethod::compile(JNIEnv* env) {
if (isCompiled())
return true;
......
......@@ -101,6 +101,13 @@ namespace SandHook {
}
};
class CastShadowClass : public IMember<art::mirror::ArtMethod, void*> {
protected:
Size calOffset(JNIEnv *jniEnv, mirror::ArtMethod *p) override {
return 0;
}
};
class CastDexMethodIndex : public IMember<art::mirror::ArtMethod, uint32_t> {
protected:
......@@ -148,6 +155,9 @@ namespace SandHook {
dexMethodIndex = new CastDexMethodIndex();
dexMethodIndex->init(env, m1, size);
declaringClass = new CastShadowClass();
declaringClass->init(env, m1, size);
jclass neverCallTestClass = env->FindClass("com/swift/sandhook/ClassNeverCall");
art::mirror::ArtMethod *neverCall = reinterpret_cast<art::mirror::ArtMethod *>(env->GetMethodID(
neverCallTestClass, "neverCall", "()V"));
......@@ -173,6 +183,7 @@ namespace SandHook {
ArrayMember<art::mirror::ArtMethod, void *> *CastArtMethod::dexCacheResolvedMethods = nullptr;
IMember<art::mirror::ArtMethod, uint32_t> *CastArtMethod::dexMethodIndex = nullptr;
IMember<art::mirror::ArtMethod, uint32_t> *CastArtMethod::accessFlag = nullptr;
IMember<art::mirror::ArtMethod, void*> *CastArtMethod::declaringClass = nullptr;
void *CastArtMethod::quickToInterpreterBridge = nullptr;
void *CastArtMethod::genericJniStub = nullptr;
void *CastArtMethod::staticResolveStub = nullptr;
......
......@@ -48,6 +48,7 @@ public:
bool isAbstract();
bool isNative();
bool isCompiled();
bool isThumbCode();
void setAccessFlags(uint32_t flags);
void disableCompilable();
......@@ -61,11 +62,13 @@ public:
void setInterpreterCodeEntry(void* entry);
void setDexCacheResolveList(void* list);
void setDexCacheResolveItem(uint32_t index, void* item);
void setDeclaringClassPtr(void* classPtr);
void* getQuickCodeEntry();
void* getInterpreterCodeEntry();
uint32_t getAccessFlags();
uint32_t getDexMethodIndex();
void* getDeclaringClassPtr();
bool compile(JNIEnv* env);
void flushCache();
......
......@@ -18,6 +18,7 @@ namespace SandHook {
static ArrayMember<art::mirror::ArtMethod,void*>* dexCacheResolvedMethods;
static IMember<art::mirror::ArtMethod, uint32_t>* dexMethodIndex;
static IMember<art::mirror::ArtMethod, uint32_t>* accessFlag;
static IMember<art::mirror::ArtMethod, void*>* declaringClass;
static void* quickToInterpreterBridge;
static void* genericJniStub;
static void* staticResolveStub;
......
//
// Created by SwiftGan on 2019/2/15.
//
#ifndef SANDHOOK_LOG_H
#define SANDHOOK_LOG_H
#include "android/log.h"
#define TAG "SandHook-Native"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
#endif //SANDHOOK_LOG_H
......@@ -2,6 +2,7 @@
#include "includes/cast_art_method.h"
#include "includes/trampoline_manager.h"
#include "includes/hide_api.h"
#include "includes/log.h"
SandHook::TrampolineManager trampolineManager;
......@@ -13,6 +14,8 @@ enum HookMode {
REPLACE = 2
};
HookMode gHookMode = AUTO;
extern "C"
JNIEXPORT jboolean JNICALL
Java_com_swift_sandhook_SandHook_initNative(JNIEnv *env, jclass type, jint sdk) {
......@@ -50,18 +53,29 @@ void ensureMethodCached(art::mirror::ArtMethod *hookMethod, art::mirror::ArtMeth
}
}
void ensureMethodDeclaringClass(art::mirror::ArtMethod *origin, art::mirror::ArtMethod *backup) {
if (origin->getDeclaringClassPtr() != backup->getDeclaringClassPtr()) {
LOGW("backup method declaringClass is out to date due to Moving GC!");
backup->setDeclaringClassPtr(origin->getDeclaringClassPtr());
backup->flushCache();
}
}
bool doHookWithReplacement(JNIEnv* env,
art::mirror::ArtMethod *originMethod,
art::mirror::ArtMethod *hookMethod,
art::mirror::ArtMethod *backupMethod) {
if (!hookMethod->isCompiled()) {
hookMethod->compile(env);
if (!backupMethod->isCompiled()) {
backupMethod->compile(env);
}
if (SDK_INT >= ANDROID_N) {
originMethod->disableCompilable();
hookMethod->disableCompilable();
}
originMethod->tryDisableInline();
if (backupMethod != nullptr) {
originMethod->backup(backupMethod);
if (SDK_INT >= ANDROID_N) {
......@@ -71,13 +85,13 @@ bool doHookWithReplacement(JNIEnv* env,
backupMethod->disableInterpreterForO();
}
backupMethod->tryDisableInline();
backupMethod->setPrivate();
backupMethod->flushCache();
}
if (SDK_INT >= ANDROID_O) {
if (SDK_INT >= ANDROID_O && SDK_INT < ANDROID_P) {
originMethod->disableInterpreterForO();
}
SandHook::HookTrampoline* hookTrampoline = trampolineManager.installReplacementTrampoline(originMethod, hookMethod, backupMethod);
if (hookTrampoline != nullptr) {
originMethod->setQuickCodeEntry(hookTrampoline->replacement->getCode());
......@@ -130,7 +144,6 @@ bool doHookWithInline(JNIEnv* env,
backupMethod->disableInterpreterForO();
}
backupMethod->tryDisableInline();
backupMethod->setPrivate();
backupMethod->flushCache();
}
return true;
......@@ -164,9 +177,14 @@ Java_com_swift_sandhook_SandHook_hookMethod(JNIEnv *env, jclass type, jobject or
goto label_hook;
}
if (origin->isAbstract()) {
isInlineHook = false;
} else if (gHookMode != AUTO) {
if (gHookMode == INLINE) {
isInlineHook = origin->compile(env);
} else {
isInlineHook = false;
}
} else if (!origin->isCompiled()) {
if (SDK_INT >= ANDROID_N) {
isInlineHook = origin->compile(env);
......@@ -180,8 +198,10 @@ Java_com_swift_sandhook_SandHook_hookMethod(JNIEnv *env, jclass type, jobject or
label_hook:
if (isInlineHook && trampolineManager.canSafeInline(origin)) {
LOGD("method hook by inline!");
return static_cast<jboolean>(doHookWithInline(env, origin, hook, backup));
} else {
LOGW("method hook by replacement!");
return static_cast<jboolean>(doHookWithReplacement(env, origin, hook, backup));
}
......@@ -196,6 +216,28 @@ Java_com_swift_sandhook_SandHook_ensureMethodCached(JNIEnv *env, jclass type, jo
ensureMethodCached(hookeMethod, backupMethod);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_swift_sandhook_SandHook_ensureMethodDeclaringClass(JNIEnv *env, jclass type,
jobject originMethod,
jobject backupMethod) {
if (backupMethod == NULL || originMethod == NULL)
return;
art::mirror::ArtMethod* origin = reinterpret_cast<art::mirror::ArtMethod *>(env->FromReflectedMethod(originMethod));
art::mirror::ArtMethod* backup = reinterpret_cast<art::mirror::ArtMethod *>(env->FromReflectedMethod(backupMethod));
ensureMethodDeclaringClass(origin, backup);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_swift_sandhook_SandHook_setHookMode(JNIEnv *env, jclass type, jint mode) {
// TODO
gHookMode = static_cast<HookMode>(mode);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_swift_sandhook_test_TestClass_jni_1test(JNIEnv *env, jobject instance) {
......
......@@ -4,6 +4,7 @@
#include "../includes/trampoline_manager.h"
#include "../includes/trampoline.h"
#include "../includes/inst.h"
#include "../includes/log.h"
extern int SDK_INT;
#define SWITCH_SETX0 false
......@@ -108,8 +109,10 @@ namespace SandHook {
replacementHookTrampoline = new ReplacementHookTrampoline();
replacementHookTrampoline->init();
replacementHookTrampolineSpace = allocExecuteSpace(replacementHookTrampoline->getCodeLen());
if (replacementHookTrampolineSpace == 0)
if (replacementHookTrampolineSpace == 0) {
LOGE("hook error due to can not alloc execute space!");
goto label_error;
}
replacementHookTrampoline->setExecuteSpace(replacementHookTrampolineSpace);
replacementHookTrampoline->setEntryCodeOffset(quickCompileOffset);
replacementHookTrampoline->setHookMethod(reinterpret_cast<Code>(hookMethod));
......@@ -164,8 +167,10 @@ namespace SandHook {
checkThumbCode(inlineHookTrampoline, getEntryCode(originMethod));
inlineHookTrampoline->init();
inlineHookTrampolineSpace = allocExecuteSpace(inlineHookTrampoline->getCodeLen());
if (inlineHookTrampolineSpace == 0)
if (inlineHookTrampolineSpace == 0) {
LOGE("hook error due to can not alloc execute space!");
goto label_error;
}
inlineHookTrampoline->setExecuteSpace(inlineHookTrampolineSpace);
inlineHookTrampoline->setEntryCodeOffset(quickCompileOffset);
inlineHookTrampoline->setOriginMethod(reinterpret_cast<Code>(originMethod));
......@@ -183,6 +188,7 @@ namespace SandHook {
directJumpTrampoline->init();
originEntry = getEntryCode(originMethod);
if (!memUnprotect(reinterpret_cast<Size>(originEntry), directJumpTrampoline->getCodeLen())) {
LOGE("hook error due to can not write origin code!");
goto label_error;
}
......@@ -200,8 +206,10 @@ namespace SandHook {
checkThumbCode(callOriginTrampoline, getEntryCode(originMethod));
callOriginTrampoline->init();
callOriginTrampolineSpace = allocExecuteSpace(callOriginTrampoline->getCodeLen());
if (callOriginTrampolineSpace == 0)
if (callOriginTrampolineSpace == 0) {
goto label_error;
}
callOriginTrampoline->setExecuteSpace(callOriginTrampolineSpace);
callOriginTrampoline->setOriginMethod(reinterpret_cast<Code>(originMethod));
Code originCode = nullptr;
......
......@@ -17,6 +17,7 @@ import java.util.concurrent.ConcurrentHashMap;
public class SandHook {
static Map<Member,HookWrapper.HookEntity> globalHookEntityMap = new ConcurrentHashMap<>();
static Map<Method,HookWrapper.HookEntity> globalBackupMap = new ConcurrentHashMap<>();
public static Class artMethodClass;
......@@ -69,6 +70,9 @@ public class SandHook {
}
Log.d("SandHook", "method <" + entity.target.getName() + "> hook success!");
globalHookEntityMap.put(entity.target, entity);
if (entity.backup != null) {
globalBackupMap.put(entity.backup, entity);
}
}
}
......@@ -91,6 +95,24 @@ public class SandHook {
return res;
}
public static void ensureBackupDelaringClass(Method backupMethod) {
if (backupMethod == null)
return;
HookWrapper.HookEntity hookEntity = globalBackupMap.get(backupMethod);
if (hookEntity == null)
return;
ensureMethodDeclaringClass(hookEntity.target, backupMethod);
}
public static void ensureBackupDelaringClassByOrigin(Member originMethod) {
if (originMethod == null)
return;
HookWrapper.HookEntity hookEntity = globalHookEntityMap.get(originMethod);
if (hookEntity == null || hookEntity.backup == null)
return;
ensureMethodDeclaringClass(originMethod, hookEntity.backup);
}
private static void resolveStaticMethod(Member method) {
//ignore result, just call to trigger resolve
try {
......@@ -182,8 +204,12 @@ public class SandHook {
private static native boolean initNative(int sdk);
public static native void setHookMode(int hookMode);
private static native boolean hookMethod(Member originMethod, Method hookMethod, Method backupMethod, int hookMode);
public static native void ensureMethodCached(Method hook, Method backup);
public static native void ensureMethodDeclaringClass(Member originMethod, Method backupMethod);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment