1、Hook原理
Hook技术,其本质就是劫持函数的调用,但是由于处于Linux用户态,每个进程都有自己独立的进程空间,所以必须先注入到所要Hook的进程空间,修改其内存中的进程代码,替换其过程表的符号地址。在Android中,一般是通过ptrace函数附加进程,然后向进程注入so库,从而达到监控以及远程进程关键函数挂钩。
Hook技术的难点,并不在Hook技术,如何找到函数的入口点、替换函数,这就涉及了理解函数的连接与加载机制。
2、HOOK小程序
在写HOOK例子前,需要对先写JNI小程序,可以参考上篇博客:JNI小程序
下面的hook例子是我对C语言库函数进行的hook操作。
2.1:在安卓程序中设置了Button按钮来产生事件,事件中调用hook函数,及readHook函数

btnHook.setOnClickListener(new OnClickListener(){            public void onClick(View v){                hookFunc();                Toast.makeText(MainActivity.this,"Hook成功"+hook("str1","str2"),Toast.LENGTH_SHORT).show();            }        });

下面是声明的两个native函数,在C程序中进行实现;

/**     * 该方法为native方法,hook内容     * @return     */    public static native String hook(String str1,String str2);    /**     * 该方法为native ,hookFun()     */    public static native void hookFunc();

加载so文件

/**     * 载入JNI生成so库文件     */    static{        System.loadLibrary("hookFun");    }

下面是我在hook.cpp文件中实现的hook关键代码,将C库函数strcpy()进行hook,修改为自定义的函数功能

extern "C" {JNIEXPORT jstring JNICALL hook(JNIEnv *env, jclass tis, jstring str1,        jstring str2) {    char *str1_ch = jstringTostring(env,str1); //这个函数是将jstring转化为char*    char *str2_ch = jstringTostring(env,str2);    char *str = strcpy(str1_ch, str2_ch); //hook后进行的调用    //将char *转化为java字符串    jclass clsstr = env->FindClass("java/lang/String");    jmethodID ctorID = env->GetMethodID(clsstr, "", "([B)V");    jbyteArray bytes = env->NewByteArray(strlen(str));    env->SetByteArrayRegion(bytes, 0, strlen(str), (jbyte*) str);    jstring jdes = (jstring) env->NewObject(clsstr, ctorID, bytes);    return jdes;}}

将jstring转化为指针的函数jstringTostring()

char* jstringTostring(JNIEnv* env, jstring jstr) { //将jstring转换为char*    char* rtn = NULL;    jclass clsstring = env->FindClass("java/lang/String");    jstring strencode = env->NewStringUTF("utf-8");    jmethodID mid = env->GetMethodID(clsstring, "getBytes",            "(Ljava/lang/String;)[B");    jbyteArray barr = (jbyteArray) env->CallObjectMethod(jstr, mid, strencode);    jsize alen = env->GetArrayLength(barr);    jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);    if (alen > 0) {        rtn = (char*) malloc(alen + 1);        memcpy(rtn, ba, alen);        rtn[alen] = 0;    }    env->ReleaseByteArrayElements(barr, ba, 0);    return rtn;}

下面是对hookFun()函数进行的实现,

typedef char* (*fnread)(char *str1,char *str2);fnread ori_strcpy = NULL;char *hook_read(char *str1, char *str2) { //定义为自己设置的转化规则    char *str_hook = NULL;    str_hook = ori_strcpy(str2,str1);    return str_hook;}extern "C" void hookFunc(JNIEnv *env, jclass tis) {//中的getTargetSI,replaceFunc可以看后面    void* libcom_hook = getTargetSI("libHookFun.so");    if (libcom_hook == NULL) {        LOGI("-----------hook-----------NULL------");    }    LOGI("%p, %d", libcom_hook, sdkVersion);    replaceFunc(libcom_hook, "strcpy", (void*)hook_read,(void **)&ori_strcpy,            sdkVersion);    if (ori_strcpy == NULL) {        LOGI("-------------ori_strcpy--------NULL--------");    }}

后面的是JNI的注册函数

static JNINativeMethod getMethods[] = {        { "hook", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",                (void*) hook } ,                {"hookFunc","()V",(void*) hookFunc}};static int registerNativeMethods(JNIEnv* env, const char* className,        JNINativeMethod* gMethods, int numMethods) {    jclass clazz;    jclass temp = env->FindClass(className);    clazz = (jclass) env->NewGlobalRef(temp);    if (clazz == NULL) {        return 0;    }    if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) {        return 0;    }    return 1;}static int registerNatives(JNIEnv* env) {    if (!registerNativeMethods(env, "com/example/jnihook/MainActivity",            getMethods, sizeof(getMethods) / sizeof(getMethods[0])))        return JNI_FALSE;    return JNI_TRUE;}JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void *reserved) {    jint result = -1;    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK)        return -1;    if (!registerNatives(env))        return -1;    char sdkchar[16];    memset(sdkchar, 0, 16);    __system_property_get("ro.build.version.sdk", sdkchar);    sdkVersion = atoi(sdkchar);    return JNI_VERSION_1_4;}

HookUtil.cpp可以参考下面这个文件;
hookutil.cpp
文中还有好多头文件,配置信息Android.mk,及安卓源程序没有列出来,重要的点都列出了。

更多相关文章

  1. android在JNI_OnLoad入口函数下断点动态调试so库
  2. COCOS2D-X在LINUX下的IDE
  3. android源代码framework取消apk强制翻转
  4. 退出程序时尚未finish的activity出现问题
  5. Android内存原理
  6. 腾讯、网易云、字节跳动面试点总结—AMS在Android起到什么作用?
  7. Android(安卓)如何从应用深入到Framework (一)
  8. Kotlin系列——在Android中使用协程以及协程源码分析
  9. Android(安卓)TV (三)(创建电视页面布局)

随机推荐

  1. Android sd卡读取数据库实例代码
  2. Android运行过程中一点小问题
  3. android--------根据文件路径使用File类
  4. android页面管理器。可以实现完整退出and
  5. Android中添加布局和初始化布局总结
  6. Android图片缩放效果代码
  7. android IOC框架学习记录
  8. Android SDK Manager更新版慢解决办法
  9. cocos2d-x eclipse android 配置注意项(
  10. ubuntu10.04上android环境安装 “org.ecl