Android Hook程序,对库函数进行HOOK

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, "<init>", "([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
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

互联网极客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值