Skip to content

Commit

Permalink
hook integration
Browse files Browse the repository at this point in the history
  • Loading branch information
rk700 committed Mar 31, 2017
1 parent 6f32d33 commit 5c530ee
Show file tree
Hide file tree
Showing 48 changed files with 627 additions and 29 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,6 @@ captures/

# Keystore files
*.jks

*.swp
.externalNativeBuild
2 changes: 2 additions & 0 deletions VirtualApp/YAHFA/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/build
.externalNativeBuild
38 changes: 38 additions & 0 deletions VirtualApp/YAHFA/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
apply plugin: 'com.android.library'

android {
compileSdkVersion 25
buildToolsVersion "25.0.2"

defaultConfig {
minSdkVersion 14
targetSdkVersion 23
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
ndk {
// Specifies the ABI configurations of your native
// libraries Gradle should build and package with your APK.
abiFilters 'armeabi', 'armeabi-v7a', 'x86'
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
externalNativeBuild {
ndkBuild {
path 'src/main/jni/Android.mk'
}
}
}

dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
testCompile 'junit:junit:4.12'
}
25 changes: 25 additions & 0 deletions VirtualApp/YAHFA/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /usr/local/opt/android-sdk-macosx/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# Add any project specific keep options here:

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package lab.galaxy.yahfa;

import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;

import org.junit.Test;
import org.junit.runner.RunWith;

import static org.junit.Assert.*;

/**
* Instrumentation test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() throws Exception {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getTargetContext();

assertEquals("lab.galaxy.yahfa.test", appContext.getPackageName());
}
}
10 changes: 10 additions & 0 deletions VirtualApp/YAHFA/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"

package="lab.galaxy.yahfa">

<application android:allowBackup="true" android:label="@string/app_name"
android:supportsRtl="true">

</application>

</manifest>
77 changes: 77 additions & 0 deletions VirtualApp/YAHFA/src/main/java/lab/galaxy/yahfa/HookMain.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package lab.galaxy.yahfa;

import android.app.Application;
import android.util.Log;

import java.lang.reflect.Method;

import dalvik.system.DexClassLoader;

/**
* Created by liuruikai756 on 28/03/2017.
*/

public class HookMain {
private static final String TAG = "YAHFA";

static {
System.loadLibrary("yahfa");
}

public HookMain() {
init(android.os.Build.VERSION.SDK_INT);
}

public void doHookDefault(ClassLoader patchClassLoader, ClassLoader originClassLoader) {
try {
Class<?> hookInfoClass = Class.forName("lab.galaxy.yahfa.HookInfo", true, patchClassLoader);
String[] hookItemNames = (String[])hookInfoClass.getField("hookItemNames").get(null);
for(String hookItemName : hookItemNames) {
doHookItemDefault(patchClassLoader, hookItemName, originClassLoader);
}
}
catch (Exception e) {
e.printStackTrace();
}
}

public void doHookItemDefault(ClassLoader patchClassLoader, String hookItemName, ClassLoader originClassLoader) {
try {
Log.i(TAG, "Start hooking with item "+hookItemName);
Class<?> hookItem = Class.forName(hookItemName, true, patchClassLoader);
String className = (String)hookItem.getField("className").get(null);
String methodName = (String)hookItem.getField("methodName").get(null);
String methodSig = (String)hookItem.getField("methodSig").get(null);

if(className == null || className.equals("")) {
Log.w(TAG, "No target class. Skipping...");
return;
}
Class<?> clazz = Class.forName(className, true, originClassLoader);

Method hook = null;
Method backup = null;
for (Method method : hookItem.getDeclaredMethods()) {
if (method.getName().equals("hook")) {
hook = method;
} else if (method.getName().equals("origin")) {
backup = method;
}
}
if (hook == null) {
Log.e(TAG, "Cannot find hook for "+methodName);
return;
}
findAndBackupAndHook(clazz, methodName, methodSig, hook, backup);
}
catch (Exception e) {
e.printStackTrace();
}
}


public native void findAndBackupAndHook(Class targetClass, String methodName, String methodSig,
Method hook, Method backup);

private native void init(int SDK_version);
}
14 changes: 14 additions & 0 deletions VirtualApp/YAHFA/src/main/jni/Android.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

ifeq "$(TARGET_ARCH_ABI)" "x86"
LOCAL_SRC_FILES:= HookMain.c entrypoints_x86.S
else
LOCAL_SRC_FILES:= HookMain.c entrypoints_arm.S
endif

LOCAL_LDLIBS := -llog

LOCAL_MODULE:= yahfa

include $(BUILD_SHARED_LIBRARY)
1 change: 1 addition & 0 deletions VirtualApp/YAHFA/src/main/jni/Application.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
APP_ABI := armeabi armeabi-v7a x86
132 changes: 132 additions & 0 deletions VirtualApp/YAHFA/src/main/jni/HookMain.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
#include "jni.h"
#include <android/log.h>
#include <string.h>

#define LOG_TAG "YAHFA-Native"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)

void hook_new_entry_23();
void hook_new_entry_22();

static int OFFSET_dex_cache_resolved_methods_in_ArtMethod;
static int OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod;
static int OFFSET_entry_point_from_jni_in_ArtMethod;
static int OFFSET_dex_method_index_in_ArtMethod;
static int OFFSET_array_in_PointerArray;
static int OFFSET_ArtMehod_in_Object;
static size_t pointer_size;
static size_t ArtMethodSize;
static void *hook_new_entry;

static unsigned int read32(void *addr) {
return *((unsigned int*)addr);
}

static unsigned long read64(void *addr) {
return *((unsigned long*)addr);
}

static unsigned long readAddr(void *addr) {
if(pointer_size == 4) {
return read32(addr);
}
else if(pointer_size == 8) {
return read64(addr);
}
else {
LOGE("unknown pointer size %d", pointer_size);
return 0;
}
}

void Java_lab_galaxy_yahfa_HookMain_init(JNIEnv *env, jclass clazz, jint sdkVersion) {
switch(sdkVersion) {
case 23:
LOGI("init to SDK %d", sdkVersion);
OFFSET_dex_cache_resolved_methods_in_ArtMethod = 4;
OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod = 36;
OFFSET_entry_point_from_jni_in_ArtMethod = 32;
OFFSET_dex_method_index_in_ArtMethod = 20;
OFFSET_array_in_PointerArray = 12;
OFFSET_ArtMehod_in_Object = 0;
pointer_size = sizeof(void *);
ArtMethodSize = 40;
hook_new_entry = (void *)hook_new_entry_23;
break;
case 22:
LOGI("init to SDK %d", sdkVersion);
OFFSET_dex_cache_resolved_methods_in_ArtMethod = 12;
OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod = 44;
OFFSET_entry_point_from_jni_in_ArtMethod = 40;
OFFSET_dex_method_index_in_ArtMethod = 28;
OFFSET_array_in_PointerArray = 12;
OFFSET_ArtMehod_in_Object = 8;
pointer_size = sizeof(void *);
ArtMethodSize = 48;
hook_new_entry = (void *)hook_new_entry_22;
break;
default:
LOGE("not compatible with SDK %d", sdkVersion);
break;
}
}

static void doBackupAndHook(void *originMethod, void *hookMethod, void *backupMethod) {
if(!backupMethod) {
LOGW("backup method is null");
}
else { //do method backup
void *dexCacheResolvedMethods = (void *)readAddr((void *)((char *)backupMethod+OFFSET_dex_cache_resolved_methods_in_ArtMethod));
int methodIndex = read32((void *)((char *)backupMethod+OFFSET_dex_method_index_in_ArtMethod));
//first update the cached method manually
memcpy((void *)((char *)dexCacheResolvedMethods+OFFSET_array_in_PointerArray+pointer_size*methodIndex), (void *)(&backupMethod), pointer_size);
//then replace the placeholder with original method
memcpy((void *)((char *)backupMethod+OFFSET_ArtMehod_in_Object),
(void *)((char *)originMethod+OFFSET_ArtMehod_in_Object),
ArtMethodSize-OFFSET_ArtMehod_in_Object);
}
//do method replacement
//save the hook method at entry_point_from_jni_
memcpy((void *)((char *)originMethod+OFFSET_entry_point_from_jni_in_ArtMethod), (void *)(&hookMethod), pointer_size);
//update the entrypoint
memcpy((void *)((char *)originMethod+OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod), (void *)(&hook_new_entry), pointer_size);
LOGI("hook and backup done");
}

void Java_lab_galaxy_yahfa_HookMain_findAndBackupAndHook(JNIEnv *env, jclass clazz,
jclass targetClass, jstring methodName, jstring methodSig, jobject hook, jobject backup) {
if(!methodName || !methodSig) {
LOGE("empty method name or signature");
return;
}
const char *c_methodName = (*env)->GetStringUTFChars(env, methodName, NULL);
const char *c_methodSig = (*env)->GetStringUTFChars(env, methodSig, NULL);
if(c_methodName == NULL || c_methodSig == NULL) {
LOGE("failed to get c string");
return;
}
void *targetMethod = NULL;
LOGI("Start findAndBackupAndHook for method %s%s", c_methodName, c_methodSig);
if(pointer_size == 0) {
LOGE("Not initialized");
goto end;
}
targetMethod = (void *)(*env)->GetMethodID(env, targetClass, c_methodName, c_methodSig);
if((*env)->ExceptionCheck(env)) {
(*env)->ExceptionClear(env); //cannot find non-static method
targetMethod = (void *)(*env)->GetStaticMethodID(env, targetClass, c_methodName, c_methodSig);
if((*env)->ExceptionCheck(env)) {
(*env)->ExceptionClear(env); //cannot find static method
LOGE("Cannot find target method %s%s", c_methodName, c_methodSig);
goto end;
}
}
doBackupAndHook(targetMethod, (void *)(*env)->FromReflectedMethod(env, hook),
backup==NULL ? NULL : (void *)(*env)->FromReflectedMethod(env, backup));

end:
(*env)->ReleaseStringUTFChars(env, methodName, c_methodName);
(*env)->ReleaseStringUTFChars(env, methodSig, c_methodSig);
}
10 changes: 10 additions & 0 deletions VirtualApp/YAHFA/src/main/jni/common.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.macro BEGIN_ENTRY eName
.globl \eName
.type \eName, %function
.balign 16
\eName:
.endm

.macro END_ENTRY eName
.size \eName, .-\eName
.endm
12 changes: 12 additions & 0 deletions VirtualApp/YAHFA/src/main/jni/entrypoints_arm.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#include "common.S"

.text
BEGIN_ENTRY hook_new_entry_23
ldr r0, [r0, #32]
ldr pc, [r0, #36]
END_ENTRY hook_new_entry_23

BEGIN_ENTRY hook_new_entry_22
ldr r0, [r0, #40]
ldr pc, [r0, #44]
END_ENTRY hook_new_entry_22
15 changes: 15 additions & 0 deletions VirtualApp/YAHFA/src/main/jni/entrypoints_x86.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#include "common.S"

.text
BEGIN_ENTRY hook_new_entry_23
mov 32(%eax), %eax
push 36(%eax)
ret
END_ENTRY hook_new_entry_23


BEGIN_ENTRY hook_new_entry_22
mov 40(%eax), %eax
push 44(%eax)
ret
END_ENTRY hook_new_entry_22
3 changes: 3 additions & 0 deletions VirtualApp/YAHFA/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<resources>
<string name="app_name">YAHFA</string>
</resources>
Loading

0 comments on commit 5c530ee

Please sign in to comment.