注入安卓进程,并hook java世界的方法
说明:
安卓系统的可执行对象有两个世界,一个是Linux Native世界,一个是Java世界.两个世界能够通过jvm产生交互,具体来说就是通过jni技术进行互相干涉.但是在正常情况下,只能在Java世界通过jni调用native方法,二native不能在没有任何java上的支持下干涉java世界.
在一些应用中,我们需要对一个app的java世界进行干涉.再说到linux上的进程注入技术,已不用我多讲,但是传统的linux进程注入技术在安卓上只能进入目标进程的native世界.
于是本教程是要注入别的进程,并hook java世界的java 方法!
条件:
1) 手机已root
2) 布置好了的ndk环境
3) 网友贡献的inject代码
由于安卓上的进程注入网上已经有很多方案了,这里就不列举了,这里就假设读者已经能够将so注入到别的进程并顺利运行了.
首先贴一下这次的目标
package com.example.testar;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import dalvik.system.DexClassLoader;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.text.GetChars;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
public class MainActivity extends Activity {
private final Map<String, ClassLoader> mLoaders = new HashMap<String, ClassLoader>();
@Override
protected void onCreate(BundlesavedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btn = (Button) findViewById(R.id.button1);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
WifiInfo info = wifi.getConnectionInfo();
System.out.println("Wifi mac:" + info.getMacAddress());
System.out.println("return " + test());
}
});
}
@Override
public booleanonCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to theaction bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
private String test() {
return "real";
}
}
我们的目标是上面的test()方法,我们要改变其返回值.
接下来看看我们要注入到目标进程的so.cpp, MethodHooker.cpp
so.cpp:
#include "jni.h"
#include"android_runtime/AndroidRuntime.h"
#include "android/log.h"
#include "stdio.h"
#include "stdlib.h"
#include "MethodHooker.h"
#include <utils/CallStack.h>
#include "art.h"
#define log(a,b)__android_log_write(ANDROID_LOG_INFO,a,b); // LOG Ѝ:info
#define log_(b)__android_log_write(ANDROID_LOG_INFO,"JNI_LOG_INFO",b); // LOG Ѝ:info
extern "C" void InjectInterface(char*arg){
log_("*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*");
log_("*-*-*-*-*-*Injected so *-*-*-*-*-*-*-*");
log_("*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*");
Hook();
log_("*-*-*-*-*-*-*-End -*-*-*-*-*-*-*-*-*-*");
}
extern "C" JNIEXPORT jstring JNICALL Java_com_example_testar_InjectApplication_test(JNIEnv *env, jclass clazz)
{
Abort_();
return env->NewStringUTF("haha ");;
}
MethodHooker.cpp:
#include "MethodHooker.h"
#include "jni.h"
#include"android_runtime/AndroidRuntime.h"
#include "android/log.h"
#include "stdio.h"
#include "stdlib.h"
#include "native.h"
#include <dlfcn.h>
#define ANDROID_SMP 0
#include "Dalvik.h"
#include "alloc/Alloc.h"
#include "art.h"
#define ALOG(...)__android_log_print(ANDROID_LOG_VERBOSE, __VA_ARGS__)
static bool g_bAttatedT;
static JavaVM *g_JavaVM;
void init()
{
g_bAttatedT = false;
g_JavaVM = android::AndroidRuntime::getJavaVM();
}
static JNIEnv *GetEnv()
{
int status;
JNIEnv *envnow = NULL;
status = g_JavaVM->GetEnv((void **)&envnow, JNI_VERSION_1_4);
if(status < 0)
{
status = g_JavaVM->AttachCurrentThread(&envnow, NULL);
if(status < 0)
{
return NULL;
}
g_bAttatedT = true;
}
return envnow;
}
static void DetachCurrent()
{
if(g_bAttatedT)
{
g_JavaVM->DetachCurrentThread();
}
}
static int computeJniArgInfo(const DexProto* proto)
{
const char* sig = dexProtoGetShorty(proto);
int returnType, jniArgInfo;
u4hints;
/* The first shorty character is the return type. */
switch (*(sig++)) {
case 'V':
returnType = DALVIK_JNI_RETURN_VOID;
break;
case 'F':
returnType = DALVIK_JNI_RETURN_FLOAT;
break;
case 'D':
returnType = DALVIK_JNI_RETURN_DOUBLE;
break;
case 'J':
returnType = DALVIK_JNI_RETURN_S8;
break;
case 'Z':
case 'B':
returnType = DALVIK_JNI_RETURN_S1;
break;
case 'C':
returnType = DALVIK_JNI_RETURN_U2;
break;
case 'S':
returnType = DALVIK_JNI_RETURN_S2;
break;
default:
returnType = DALVIK_JNI_RETURN_S4;
break;
}
jniArgInfo = returnType << DALVIK_JNI_RETURN_SHIFT;
hints = dvmPlatformInvokeHints(proto);
if (hints &DALVIK_JNI_NO_ARG_INFO) {
jniArgInfo |= DALVIK_JNI_NO_ARG_INFO;
} else {
assert((hints & DALVIK_JNI_RETURN_MASK) == 0);
jniArgInfo |= hints;
}
return jniArgInfo;
}
int ClearException(JNIEnv *jenv){
jthrowable exception = jenv->ExceptionOccurred();
if (exception != NULL) {
jenv->ExceptionDescribe();
jenv->ExceptionClear();
return true;
}
return false;
}
bool isArt(){
return true;
}
static jclass findAppClass(JNIEnv *jenv,const char *apn){
//