CydiaSubtrateHook——Native注册混淆破解(更新版)
本帖最后由 一夜梦惊人 于 2019-1-3 21:39 编辑前言:今天是2019年1月1号,首先祝大家新年快乐!然后前段时间我在看了姜维大佬的文章后,也觉得必须要搞个这样子的东西,于是就有了本文。
准备工具:海马玩模拟器、CydiaSubtrate(以下简称CS)、AS3.2
一、资金贫穷所以没有用真机,只能用模拟器。<请注意,模拟器必须用海马玩模拟器,其他的模拟器基本都是不可以的>,安装CS自行百度,想必对于各位都是So easy!
二、AS上编写Hook代码。首先下载CS的SDK,文件我会给出。打开AS新建一个project,由于我们不需要activity,所以就No Activity咯。在main目录下新建个jni目录,把SDK中的so和h文件复制到下面。
其中Android.mk的代码如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := substrate
LOCAL_SRC_FILES := libsubstrate.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := substrate-dvm
LOCAL_SRC_FILES := libsubstrate-dvm.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := CydiaHook.cy
LOCAL_SRC_FILES := CydiaNativeHook.cpp
LOCAL_LDLIBS += -L$(SYSROOT)/usr/lib -llog
LOCAL_LDLIBS += -L$(LOCAL_PATH) -lsubstrate-dvm -lsubstrate
include $(BUILD_SHARED_LIBRARY)
大家可以根据自己的不同进行修改,其中需要注意的是你写的CS代码必须要以.cy结尾。然后还要修改build.gradle。
由于我只在模拟器上进行运行,所以我只生成x86的。环境基本配置就是这样子了。
三、大家都知道Native注册函数是RegisterNatives,而RegisterNatives方法在libdvm.so里面,实现代码则是jni.cpp。而libdvm.so一般在system/lib下,但是请注意可能会有所不同,比如海马玩模拟器就有两个libdvm.so文件,经过我的查看,system/lib/arm下的才能使用。IDA打开libdvm.so,直接查找RegisterNatives。PS:未更新版中使用的AndroidRuntime:RegisterNativeMethod,但是当时查询的资料没有说明,这个方法是系统自带的服务的Native注册方法,而非系统服务APP调用的Native注册方法则是不同的。最后会给出资料给大家看。
但是呢很抱歉,没有。经过我的寻找,最终经过确认是sub_668c4方法。这个方法是没有EXPORT的,那么只能曲线救国,而我选用的就是Hook其他方法,然后计算偏移量转到Native注册方法sub_668c4方法就行。sub_668c4方法的参数和返回值这些东西则是可以通过查看Android源码来得到。我选用的方法就是dexFileParse方法,而他的EXPORT则是_Z12dexFileParsePKhji(这里不讲解,给出的资料会说)
接下来我就贴上我写的代码吧!
//
// Created by Poity on 2019/1/1.
//
#include <jni.h>
#include "substrate.h"
#include <android/log.h>
#include <unistd.h>
#include <dirent.h>
#define TAG "CydiaHook"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
MSConfig(MSFilterLibrary, "/system/lib/arm/libdvm.so");
void * get_base_of_lib_from_maps(const char *SoName)
{
void * imagehandle = dlopen(SoName, RTLD_LOCAL | RTLD_LAZY);
if (SoName == NULL)
return NULL;
if (imagehandle == NULL){
return NULL;
}
uintptr_t * irc = NULL;
FILE *f = NULL;
char line = {0};
char *state = NULL;
char *tok = NULL;
char * baseAddr = NULL;
if ((f = fopen("/proc/self/maps", "r")) == NULL)
return NULL;
while (fgets(line, 199, f) != NULL)
{
tok = strtok_r(line, "-", &state);
baseAddr = tok;
tok = strtok_r(NULL, "\t ", &state);
tok = strtok_r(NULL, "\t ", &state); // "r-xp" field
tok = strtok_r(NULL, "\t ", &state); // "0000000" field
tok = strtok_r(NULL, "\t ", &state); // "01:02" field
tok = strtok_r(NULL, "\t ", &state); // "133224" field
tok = strtok_r(NULL, "\t ", &state); // path field
if (tok != NULL) {
int i;
for (i = (int)strlen(tok)-1; i >= 0; --i) {
if (!(tok == ' ' || tok == '\r' || tok == '\n' || tok == '\t'))
break;
tok = 0;
}
{
size_t toklen = strlen(tok);
size_t solen = strlen(SoName);
if (toklen > 0) {
if (toklen >= solen && strcmp(tok + (toklen - solen), SoName) == 0) {
fclose(f);
return (uintptr_t*)strtoll(baseAddr,NULL,16);
}
}
}
}
}
fclose(f);
return NULL;
}
jint (*old_RegiserNatives)(JNIEnv *env, jclass clazz, const JNINativeMethod* methods,jint nMethods) = NULL;
jint new_RegiserNatives(JNIEnv *env, jclass clazz, const JNINativeMethod* methods,jint nMethods){
//传入你想Hookd的So文件的绝对地址
void * Soaddress = get_base_of_lib_from_maps("");
if (Soaddress != (void *) env){
//去掉你不想要的,如果有多个就自己修改把 LOGD("exclude So address %p",Soaddress);
return old_RegiserNatives(env,clazz,methods,nMethods);
}
LOGD("------------------------------------------------");
LOGD("env:%p,class:%p,methods:%p,methods_num:%d",env,clazz,methods,nMethods);
LOGD("------------------------------------------------");
for (int i = 0;i < nMethods;i++){
LOGD("name:%s,sign:%s,address:%p",methods.name,methods.signature,methods.fnPtr);
}
LOGD("------------------------------------------------");
return old_RegiserNatives(env,clazz,methods,nMethods);
}
void * Hook_Symbol(const char * LibraryName, const char * SymbolName){
void * handle = dlopen(LibraryName,RTLD_GLOBAL | RTLD_NOW);
if (handle != NULL){
LOGD("Hook so %s success",LibraryName);
void * symbol = dlsym(handle,SymbolName);
if (symbol != NULL){
LOGD("Hook function %s success",SymbolName);
return symbol;
} else{
LOGD("error find functicon:%s",SymbolName);
LOGD("dl error:%s",dlerror());
return NULL;
}
} else{
LOGD("error find so : %s",LibraryName);
return NULL;
}
}
MSInitialize{
LOGD("CydiaHook MSinitialize.");
MSImageRef image = MSGetImageByName("/system/lib/arm/libdvm.so");
if (image != NULL){
LOGD("Hook so libdvm.so success");
void * function_address = MSFindSymbol(image,"_Z12dexFileParsePKhji");
if (function_address != NULL){
LOGD("get _Z12dexFileParsePKhji address success");
LOGD("begin hook funvtion sub_668c4");
void * RegiserNatives = (void *)((uint32_t)function_address - 0x43f0); //function_address:lib_base+0xc4990 差值:43f0
LOGD("RegiserNatives address:%p",RegiserNatives);
MSHookFunction(RegiserNatives,(void*)&new_RegiserNatives, (void **)&old_RegiserNatives);
} else{
LOGD("error find functicon _Z12dexFileParsePKhji");
}
} else{
LOGD("error find so : libdvm.so");
}
}
代码中有个Hook_Symbol方法,这个方法看代码大家就知道其实跟MSGetImageByName和MSFindSymbol的方法是重复的,但是为什么我还会保留呢?因为其实大家Hook的可能Hook的时候还没有加载到进程空间里面,你用CS自带的是Hook不到的。所以为了方便大家我就保留下来了!代码大家自己看吧,我就不讲解了(还有一些需要改进,大家根据自己需求来改进吧)。
贴一下模拟器的log吧。
最后希望大家多多评分,谢谢!
资料链接:
1.https://www.52pojie.cn/thread-540077-1-1.html(Hook Android C代码(Cydia Substrate)
2.https://www.androidos.net.cn/android/4.2.2_r1/xref/dalvik/vm/Jni.cpp (Android 中jni.cpp代码)
3.https://www.androidos.net.cn/article/fmJJxVeqqg.html (Dalvik虚拟机JNI方法的注册过程分析)4.https://www.52pojie.cn/thread-800279-1-1.html (Android中-抖音火山视频的Native注册混淆函数获取方法)3.CS的SDK下载链接:http://asdk.cydiasubstrate.com/zips/cydia_substrate-r2.zip
本文有些Bug。通过pid获取APP名字,但是pid是Android_runtime的,所以一旦用pid排除是不可能的。有大佬的说下解决思路。我将会重新编辑 大神牛逼 大神牛逼 这是什么原理??还是没说清楚呀 一语惊醒梦中人 感谢分享技术{:1_893:}
感谢分享技术,虽然我不明白 不明觉厉 厉害啊 大神
页:
[1]
2