Commit 36230c71 authored by swift_gan's avatar swift_gan Committed by ganyao114

Fix: fix case when hook some method in class not inited

parent 6b1a533a
......@@ -12,6 +12,7 @@ android {
}
buildTypes {
debug {
debuggable false
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
......
......@@ -13,6 +13,7 @@ import android.widget.TextView;
import com.swift.sandhook.test.Inter;
import com.swift.sandhook.test.InterImpl;
import com.swift.sandhook.test.PendingHookTest;
import com.swift.sandhook.test.TestClass;
import java.lang.reflect.Field;
......@@ -82,6 +83,9 @@ public class MainActivity extends AppCompatActivity {
inter.dosth();
testPluginHook(str);
MyApp.initedTest = true;
PendingHookTest.test();
}
public static Field getField(Class topClass, String fieldName) throws NoSuchFieldException {
......
......@@ -5,6 +5,7 @@ import android.app.Application;
import android.os.Build;
import android.util.Log;
import com.swift.sandhook.test.PendingHookTest;
import com.swift.sandhook.test.TestClass;
import com.swift.sandhook.testHookers.ActivityHooker;
import com.swift.sandhook.testHookers.CtrHook;
......@@ -16,7 +17,6 @@ import com.swift.sandhook.testHookers.ObjectHooker;
import com.swift.sandhook.wrapper.HookErrorException;
import com.swift.sandhook.xposedcompat.XposedCompat;
import dalvik.system.DexClassLoader;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedHelpers;
......@@ -24,6 +24,8 @@ public class MyApp extends Application {
//if you want test Android Q, please Set true, because SDK_INT of Android Q is still 28
public final static boolean testAndroidQ = false;
//for test pending hook case
public volatile static boolean initedTest = false;
@Override
public void onCreate() {
......@@ -95,18 +97,17 @@ public class MyApp extends Application {
}
});
try {
ClassLoader classLoader = getClassLoader();
DexClassLoader dexClassLoader = new DexClassLoader("/sdcard/hookers-debug.apk",
getCacheDir().getAbsolutePath(), null, classLoader);
Class absHookerClass = Class.forName("com.swift.sandhook.hookers.AbsHooker", true, dexClassLoader);
Class pluginHookerClass = Class.forName("com.swift.sandhook.hookers.PluginHooker", true, dexClassLoader);
SandHook.addHookClass(getClassLoader(), absHookerClass, pluginHookerClass);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (HookErrorException e) {
e.printStackTrace();
}
XposedHelpers.findAndHookMethod(PendingHookTest.class, "test", new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
param.returnEarly = true;
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
}
});
}
}
package com.swift.sandhook.test;
import android.util.Log;
import com.swift.sandhook.MyApp;
public class PendingHookTest {
static {
if (!MyApp.initedTest) {
throw new RuntimeException("PendingHookTest.class may can not init this time!");
}
}
public static void test() {
Log.e("PendingHookTest", "hook failure!");
}
}
......@@ -7,7 +7,7 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.1.3'
classpath 'com.android.tools.build:gradle:3.5.0'
classpath 'com.novoda:bintray-release:0.8.1'
// NOTE: Do not place your application dependencies here; they belong
......
......@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
......@@ -9,15 +9,14 @@ android {
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
arguments '-DBUILD_TESTING=OFF'
cppFlags "-frtti -fexceptions"
abiFilters 'armeabi-v7a', 'arm64-v8a'
arguments "-DCMAKE_BUILD_TYPE=Release"
}
}
ndk {
abiFilters 'armeabi-v7a', "arm64-v8a"
}
}
externalNativeBuild {
......
......@@ -3,6 +3,8 @@ project(sandhook)
ENABLE_LANGUAGE(ASM)
add_definitions(-std=c++11)
set(${PROJECT_NAME}_SOURCES
sandhook.cpp
trampoline/trampoline.cpp
......@@ -23,8 +25,6 @@ set(${PROJECT_NAME}_SOURCES
nativehook/native_hook.cpp
)
add_definitions(-std=c++11)
add_library(${PROJECT_NAME}
SHARED
${${PROJECT_NAME}_SOURCES})
......
......@@ -37,6 +37,10 @@ extern "C" {
bool forceProcessProfiles();
bool hookClassInit(void(*callback)(void*));
JNIEnv *attachAndGetEvn();
}
#endif //SANDHOOK_HIDE_API_H
......@@ -324,7 +324,7 @@ Java_com_swift_sandhook_SandHook_skipAllSafeCheck(JNIEnv *env, jclass type, jboo
extern "C"
JNIEXPORT jboolean JNICALL
Java_com_swift_sandhook_SandHook_is64Bit(JNIEnv *env, jclass type) {
return BYTE_POINT == 8;
return static_cast<jboolean>(BYTE_POINT == 8);
}
extern "C"
......@@ -361,6 +361,23 @@ Java_com_swift_sandhook_SandHook_setNativeEntry(JNIEnv *env, jclass type, jobjec
return JNI_TRUE;
}
static jclass class_pending_hook = nullptr;
static jmethodID method_class_init = nullptr;
extern "C"
JNIEXPORT jboolean JNICALL
Java_com_swift_sandhook_SandHook_initForPendingHook(JNIEnv *env, jclass type) {
class_pending_hook = static_cast<jclass>(env->NewGlobalRef(
env->FindClass("com/swift/sandhook/PendingHookHandler")));
method_class_init = env->GetStaticMethodID(class_pending_hook, "onClassInit", "(J)V");
auto class_init_handler = [](void *clazz_ptr) {
attachAndGetEvn()->CallStaticVoidMethod(class_pending_hook, method_class_init, (jlong) clazz_ptr);
attachAndGetEvn()->ExceptionClear();
};
return static_cast<jboolean>(hookClassInit(class_init_handler));
}
extern "C"
JNIEXPORT void JNICALL
Java_com_swift_sandhook_ClassNeverCall_neverCallNative(JNIEnv *env, jobject instance) {
......@@ -477,6 +494,11 @@ static JNINativeMethod jniSandHook[] = {
"setNativeEntry",
"(Ljava/lang/reflect/Member;Ljava/lang/reflect/Member;J)Z",
(void *) Java_com_swift_sandhook_SandHook_setNativeEntry
},
{
"initForPendingHook",
"()Z",
(void *) Java_com_swift_sandhook_SandHook_initForPendingHook
}
};
......
......@@ -35,6 +35,12 @@ extern "C" {
JavaVM* jvm;
void *(*hook_native)(void* origin, void *replace) = nullptr;
void (*class_init_callback)(void*) = nullptr;
void (*backup_fixup_static_trampolines)(void *, void *) = nullptr;
bool fileExits(const char* path) {
int fd = open(path, O_RDONLY);
if (fd < 0) {
......@@ -125,6 +131,15 @@ extern "C" {
profileSaver_ForceProcessProfiles = reinterpret_cast<void (*)()>(getSymCompat(art_lib_path, "_ZN3art12ProfileSaver20ForceProcessProfilesEv"));
}
//init native hook lib
void* native_hook_handle = dlopen("libsandhook-native.so", RTLD_LAZY | RTLD_GLOBAL);
if (native_hook_handle) {
hook_native = reinterpret_cast<void *(*)(void *, void *)>(dlsym(native_hook_handle, "SandInlineHook"));
} else {
hook_native = reinterpret_cast<void *(*)(void *, void *)>(getSymCompat(
"libsandhook-native.so", "SandInlineHook"));
}
}
bool canCompile() {
......@@ -250,5 +265,40 @@ extern "C" {
return true;
}
void replaceFixupStaticTrampolines(void *thiz, void *clazz_ptr) {
backup_fixup_static_trampolines(thiz, clazz_ptr);
if (class_init_callback) {
class_init_callback(clazz_ptr);
}
}
bool hookClassInit(void(*callback)(void*)) {
void* symFixupStaticTrampolines = getSymCompat(art_lib_path, "_ZN3art11ClassLinker22FixupStaticTrampolinesENS_6ObjPtrINS_6mirror5ClassEEE");
if (symFixupStaticTrampolines == nullptr || hook_native == nullptr)
return false;
backup_fixup_static_trampolines = reinterpret_cast<void (*)(void *, void *)>(hook_native(
symFixupStaticTrampolines, (void *) replaceFixupStaticTrampolines));
if (backup_fixup_static_trampolines) {
class_init_callback = callback;
return true;
} else {
return false;
}
}
JNIEnv *getEnv() {
JNIEnv *env;
jvm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6);
return env;
}
JNIEnv *attachAndGetEvn() {
JNIEnv *env = getEnv();
if (env == nullptr) {
jvm->AttachCurrentThread(&env, nullptr);
}
return env;
}
}
package com.swift.sandhook;
import android.util.Log;
import com.swift.sandhook.wrapper.HookErrorException;
import com.swift.sandhook.wrapper.HookWrapper;
import java.util.Map;
import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;
// Pending for hook static method
// When Init class error!
public class PendingHookHandler {
private static Map<Class, Vector<HookWrapper.HookEntity>> pendingHooks = new ConcurrentHashMap<>();
private static boolean canUsePendingHook;
static {
//init native hook
canUsePendingHook = SandHook.initForPendingHook();
}
public static boolean canWork() {
return canUsePendingHook && SandHook.canGetObject() && !SandHookConfig.DEBUG;
}
public static synchronized void addPendingHook(HookWrapper.HookEntity hookEntity) {
Vector<HookWrapper.HookEntity> entities = pendingHooks.get(hookEntity.target.getDeclaringClass());
if (entities == null) {
entities = new Vector<>();
pendingHooks.put(hookEntity.target.getDeclaringClass(), entities);
}
entities.add(hookEntity);
}
public static void onClassInit(long clazz_ptr) {
if (clazz_ptr == 0)
return;
Class clazz = (Class) SandHook.getObject(clazz_ptr);
if (clazz == null)
return;
Vector<HookWrapper.HookEntity> entities = pendingHooks.get(clazz);
if (entities == null)
return;
for (HookWrapper.HookEntity entity:entities) {
HookLog.w("do pending hook for method: " + entity.target.toString());
try {
SandHook.hook(entity);
} catch (HookErrorException e) {
HookLog.e("Pending Hook Error!", e);
}
}
pendingHooks.remove(clazz);
}
}
......@@ -4,6 +4,7 @@ import android.os.Build;
import com.swift.sandhook.annotation.HookMode;
import com.swift.sandhook.blacklist.HookBlackList;
import com.swift.sandhook.utils.ClassStatusUtils;
import com.swift.sandhook.utils.FileUtils;
import com.swift.sandhook.utils.ReflectionUtils;
import com.swift.sandhook.utils.Unsafe;
......@@ -68,10 +69,6 @@ public class SandHook {
HookWrapper.addHookClass(hookWrapperClass);
}
public static void addHookClass(ClassLoader classLoader, Class... hookWrapperClass) throws HookErrorException {
HookWrapper.addHookClass(classLoader, hookWrapperClass);
}
public static synchronized void hook(HookWrapper.HookEntity entity) throws HookErrorException {
if (entity == null)
......@@ -90,8 +87,16 @@ public class SandHook {
if (HookBlackList.canNotHook(target))
throw new HookErrorException("method <" + entity.target.toString() + "> can not hook, because of in blacklist!");
resolveStaticMethod(target);
if (SandHookConfig.delayHook && PendingHookHandler.canWork() && ClassStatusUtils.isStaticAndNoInited(entity.target)) {
PendingHookHandler.addPendingHook(entity);
return;
} else {
resolveStaticMethod(target);
}
resolveStaticMethod(backup);
if (backup != null && entity.resolveDexCache) {
SandHookMethodResolver.resolveMethod(hook, backup);
}
......@@ -193,17 +198,21 @@ public class SandHook {
}
}
public static void resolveStaticMethod(Member method) {
public static boolean resolveStaticMethod(Member method) {
//ignore result, just call to trigger resolve
if (method == null)
return;
return true;
try {
if (method instanceof Method && Modifier.isStatic(method.getModifiers())) {
((Method) method).setAccessible(true);
((Method) method).invoke(new Object(), getFakeArgs((Method) method));
}
} catch (ExceptionInInitializerError classInitError) {
//may need hook later
return false;
} catch (Throwable throwable) {
}
return true;
}
private static Object[] getFakeArgs(Method method) {
......@@ -367,6 +376,8 @@ public class SandHook {
public static native boolean setNativeEntry(Member origin, Member hook, long nativeEntry);
public static native boolean initForPendingHook();
@FunctionalInterface
public interface HookModeCallBack {
int hookMode(Member originMethod);
......
......@@ -8,10 +8,13 @@ import com.swift.sandhook.lib.BuildConfig;
public class SandHookConfig {
public volatile static int SDK_INT = Build.VERSION.SDK_INT;
public volatile static boolean DEBUG = BuildConfig.DEBUG;
//Debug status of hook target process
public volatile static boolean DEBUG = true;
//Enable compile with jit
public volatile static boolean compiler = true;
public volatile static ClassLoader initClassLoader;
public volatile static int curUse = 0;
public volatile static boolean delayHook = true;
public volatile static String libSandHookPath;
public volatile static LibLoader libLoader = new LibLoader() {
......
package com.swift.sandhook.utils;
import com.swift.sandhook.SandHookConfig;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Modifier;
public class ClassStatusUtils {
static Field fieldStatusOfClass;
static {
try {
fieldStatusOfClass = Class.class.getDeclaredField("status");
fieldStatusOfClass.setAccessible(true);
} catch (NoSuchFieldException e) {
}
}
public static int getClassStatus(Class clazz, boolean isUnsigned) {
if (clazz == null) {
return 0;
}
int status = 0;
try {
status = fieldStatusOfClass.getInt(clazz);
} catch (Throwable e) {
}
if (isUnsigned) {
status = (int) (toUnsignedLong(status) >> (32 - 4));
}
return status;
}
public static long toUnsignedLong(int x) {
return ((long) x) & 0xffffffffL;
}
/**
* 5.0-8.0: kInitialized = 10 int
* 8.1: kInitialized = 11 int
* 9.0: kInitialized = 14 uint8_t
*/
public static boolean isInitialized(Class clazz) {
if (fieldStatusOfClass == null)
return true;
if (SandHookConfig.SDK_INT >= 28) {
return getClassStatus(clazz, true) == 14;
} else if (SandHookConfig.SDK_INT == 27) {
return getClassStatus(clazz, false) == 11;
} else {
return getClassStatus(clazz, false) == 10;
}
}
public static boolean isStaticAndNoInited(Member hookMethod) {
if (hookMethod == null || hookMethod instanceof Constructor) {
return false;
}
Class declaringClass = hookMethod.getDeclaringClass();
return Modifier.isStatic(hookMethod.getModifiers())
&& !ClassStatusUtils.isInitialized(declaringClass);
}
}
......@@ -24,7 +24,7 @@ android {
externalNativeBuild {
cmake {
path "CMakeLists.txt"
path "src/main/cpp/CMakeLists.txt"
}
}
......
......@@ -11,26 +11,26 @@ cmake_minimum_required(VERSION 3.4.1)
# Gradle automatically packages shared libraries with your APK.
if(${CMAKE_ANDROID_ARCH_ABI} STREQUAL "arm64-v8a")
set(OS_DEPENDENDED_SRC
src/main/cpp/archs/arm/arm64/assembler/assembler_arm64.cpp
src/main/cpp/archs/arm/arm64/inst/inst_arm64.cpp
src/main/cpp/archs/arm/arm64/register/register_arm64.cpp
src/main/cpp/archs/arm/arm64/register/register_list_arm64.cpp
src/main/cpp/archs/arm/arm64/decoder/decoder_arm64.cpp
src/main/cpp/archs/arm/arm64/relocate/code_relocate_arm64.cpp
src/main/cpp/archs/arm/arm64/hook/hook_arm64.cpp)
archs/arm/arm64/assembler/assembler_arm64.cpp
archs/arm/arm64/inst/inst_arm64.cpp
archs/arm/arm64/register/register_arm64.cpp
archs/arm/arm64/register/register_list_arm64.cpp
archs/arm/arm64/decoder/decoder_arm64.cpp
archs/arm/arm64/relocate/code_relocate_arm64.cpp
archs/arm/arm64/hook/hook_arm64.cpp)
elseif (${CMAKE_ANDROID_ARCH_ABI} STREQUAL "armeabi-v7a")
set(OS_DEPENDENDED_SRC
src/main/cpp/archs/arm/arm32/inst/inst_arm32.cpp
src/main/cpp/archs/arm/arm32/inst/inst_t32.cpp
src/main/cpp/archs/arm/arm32/inst/inst_t16.cpp
src/main/cpp/archs/arm/arm32/register/register_arm32.cpp
src/main/cpp/archs/arm/arm32/register/register_list_arm32.cpp
src/main/cpp/archs/arm/arm32/assembler/assembler_arm32.cpp
src/main/cpp/archs/arm/arm32/decoder/decoder_arm32.cpp
src/main/cpp/archs/arm/arm32/hook/hook_arm32.cpp
src/main/cpp/archs/arm/arm32/hook/breakpoint_shellcode.S
src/main/cpp/archs/arm/arm32/relocate/code_relocate_arm32.cpp)
archs/arm/arm32/inst/inst_arm32.cpp
archs/arm/arm32/inst/inst_t32.cpp
archs/arm/arm32/inst/inst_t16.cpp
archs/arm/arm32/register/register_arm32.cpp
archs/arm/arm32/register/register_list_arm32.cpp
archs/arm/arm32/assembler/assembler_arm32.cpp
archs/arm/arm32/decoder/decoder_arm32.cpp
archs/arm/arm32/hook/hook_arm32.cpp
archs/arm/arm32/hook/breakpoint_shellcode.S
archs/arm/arm32/relocate/code_relocate_arm32.cpp)
endif()
add_library( # Sets the name of the library.
......@@ -40,37 +40,37 @@ add_library( # Sets the name of the library.
SHARED
# Provides a relative path to your source file(s).
src/main/cpp/sandhook_native.cpp
src/main/cpp/decoder/decoder.cpp
src/main/cpp/relocate/code_relocate.cpp
src/main/cpp/elf/elf.cpp
src/main/cpp/assembler/assembler.cpp
src/main/cpp/buffer/code_buffer.cpp
src/main/cpp/utils/platform.cpp
src/main/cpp/hook/hook.cpp
sandhook_native.cpp
decoder/decoder.cpp
relocate/code_relocate.cpp
elf/elf.cpp
assembler/assembler.cpp
buffer/code_buffer.cpp
utils/platform.cpp
hook/hook.cpp
${OS_DEPENDENDED_SRC})
include_directories(
src/main/cpp/asm
src/main/cpp/decoder
src/main/cpp/elf
src/main/cpp/utils
src/main/cpp/includes
src/main/cpp/buffer
src/main/cpp/archs/arm
src/main/cpp/archs/arm/arm64/inst
src/main/cpp/archs/arm/arm64/register
src/main/cpp/archs/arm/arm64/decoder
src/main/cpp/archs/arm/arm64/assembler
src/main/cpp/archs/arm/arm64/relocate
src/main/cpp/archs/arm/arm64/hook
src/main/cpp/archs/arm/arm32/inst
src/main/cpp/archs/arm/arm32/register
src/main/cpp/archs/arm/arm32/assembler
src/main/cpp/archs/arm/arm32/decoder
src/main/cpp/archs/arm/arm32/hook
src/main/cpp/archs/arm/arm32/relocate
asm
decoder
elf
utils
includes
buffer
archs/arm
archs/arm/arm64/inst
archs/arm/arm64/register
archs/arm/arm64/decoder
archs/arm/arm64/assembler
archs/arm/arm64/relocate
archs/arm/arm64/hook
archs/arm/arm32/inst
archs/arm/arm32/register
archs/arm/arm32/assembler
archs/arm/arm32/decoder
archs/arm/arm32/hook
archs/arm/arm32/relocate
src/main/cpp/antihook
)
......
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