Cydia Substrate是一个代码修改平台,它可以修改任何主进程的代码,不管是用Java还是C/C++(native代码)编写的。但hook三方库总是失败,原因不明。暂只支持到Android4.4
Xposed只支持HOOK app_process中的java函数,因此Cydia Substrate是一款强大而实用的HOOK工具。
Substrate框架的使用:
Java层hook:
1、首先就是在Android设备中安装Cydia Substrate框架的本地服务应用substrate.apk。
2、创建一个空的Android工程。由于创建的工程将以插件的形式被加载,所以不需要activity。拷贝cydia sdk包中的substrate-api.jar到libs目录,右键点击,“add as library” ,app模块下的 build.gradle文件会添加:
dependencies{
...
implementation files('libs/substrate-api.jar')
}
3、修改AndroidManiFest.xml,增加cydia相关内容
<permission
android:name="cydia.permission.SUBSTRATE"
android:label="modify code from other packages"
android:permissionGroup="android.permission-group.DEVELOPMENT_TOOLS"
android:protectionLevel="dangerous" />
<uses-permission android:name="cydia.permission.SUBSTRATE"/>
<application
.....>
<meta-data android:name="com.saurik.substrate.main"
android:value=".Main"/><!--自己写的hook类名-->
</application>
4、编写hook类
public class Main {
static void initialize(){//在模块安装后, Cydia会自动调用initialize函数
MS.hookClassLoad("xxxxxxx", new MS.ClassLoadHook() {
public void classLoaded(Class<?> _class) {
Constructor method = null;
method method = _class.getConstructor(...) //反射得到方法
if (method != null) {
MS.hookMethod(_class, method, new MS.MethodAlteration() {
public Object invoked(Object _this, Object... args) throws Throwable {
//_this是当前类
//args是参数,可以修改参数后调用老类
args[0]=...
return invoke(_this, host, port);
}
});
}
}
});
}
}
So层hook:
1、新建工程,使用空Activity即可
2、新建jni目录,把cydia sdk中的substrate.h、libsubstrate.so和libsubstrate-dvm.so拷贝到jni目录下;前者是c函数hook依赖库,后者是dvm函数hook依赖库.
3、新建module.cy.cpp,格式如下
#include <android/log.h>
#include <substrate.h>
#include <stdio.h>
#define LOG_TAG "XLZH"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
void cigi_hook(void *orig_fcn, void* new_fcn, void **orig_fcn_ptr)
{
MSHookFunction(orig_fcn, new_fcn, orig_fcn_ptr);
}
MSConfig(MSFilterExecutable, "/system/bin/app_process")
int (*original_getAge)(void);
int replaced_getAge(void) {
return 99;
}
int (*original_arc4random)(void);
int replaced_arc4random(void)
{
return 1234;
}
void* lookup_symbol(char* libraryname,char* symbolname)
{
void *imagehandle = dlopen(libraryname, RTLD_GLOBAL | RTLD_NOW);
if (imagehandle != NULL){
void * sym = dlsym(imagehandle, symbolname);
if (sym != NULL){
return sym;
}
else{
LOGI("(lookup_symbol) dlsym didn't work");
return NULL;
}
}
else{
LOGI("(lookup_symbol) dlerror: %s",dlerror());
return NULL;
}
}
void * get_base_of_lib_from_maps(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[200] = {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[i] == ' ' || tok[i] == '\r' || tok[i] == '\n' || tok[i] == '\t'))
break;
tok[i] = 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;
}
void * get_base_of_lib_from_soinfo(char *soname)
{
if (soname == NULL)
return NULL;
void *imagehandle = dlopen(soname, RTLD_LOCAL | RTLD_LAZY);
if (imagehandle == NULL){
return NULL;
}
char *basename;
char *searchname;
int i;
void * libdl_ptr=dlopen("libdl.so",3);
basename = strrchr(soname,'/');
searchname = basename ? basename +1 : soname;
for(i =(int) libdl_ptr; i!=NULL; i=*(int*)(i+164)){
if(!strcmp(searchname,(char*)i)){
unsigned int *lbase= (unsigned int*)i+140;
void * baseaddr = (void*)*lbase;
return baseaddr;
}
}
return NULL;
}
MSInitialize {//模块安装后, Cydia会自动调用这里的代码,你可以在这里进行hook,也可以以后手动hook
cigi_hook((void *)arc4random,(void*)&replaced_arc4random,(void**)&original_arc4random);
// // void * getAgeSym = lookup_symbol("/data/data/com.example.targetapp/lib/libtargetlib.so","getAge");
// void* lib_base = get_base_of_lib_from_maps("/data/data/com.example.cydiahooktarget/lib/libtargetLib.so");
//// void* lib_base = get_base_of_lib_from_soinfo("/data/data/com.example.cydiahooktarget/lib/libtargetLib.so");
// LOGI("lib base is %p",lib_base);
// if (lib_base!=NULL){
// void * getAgeSym = (unsigned char *)lib_base + 0xE49;
// LOGI("getAge() should be at %p. Let's hook it",getAgeSym);
// cigi_hook(getAgeSym,(void*)&replaced_getAge,(void**)&original_getAge);
// }
void * getAgeSym = lookup_symbol("/data/data/com.example.cydiahooktarget/lib/libtargetLib.so","getAge");
cigi_hook(getAgeSym,(void*)&replaced_getAge,(void**)&original_getAge);
}
4、编写Android.mk文件,内容如下
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE:= substrate-dvm
LOCAL_SRC_FILES := libsubstrate-dvm.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE:= substrate
LOCAL_SRC_FILES := libsubstrate.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := module.cy #生成的模块名
LOCAL_SRC_FILES := module.cy.cpp #源文件名
LOCAL_LDLIBS += -L$(LOCAL_PATH) -llog -lsubstrate -lsubstrate-dvm
include $(BUILD_SHARED_LIBRARY)
5、终端进入jni目录,执行ndk-build APP_ABI="armeabi";
6、修改local.properties,指定sdk目录,如下
sdk.dir=D\:\\sdk
ndk.dir=D\:\\android-ndk-r13b
7、修改gradle.properties文件,增加内容如下
android.useDeprecatedNdk=true
8、修改build.gradle文件,增加在defaultConfig中增加ndk选项,同级增加sourceSet,如下
apply plugin: 'com.android.application'
android {
compileSdkVersion 25
buildToolsVersion "25.0.2"
defaultConfig {
applicationId "com.example.cydianativehook"
minSdkVersion 15
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
ndk{
moduleName "module.cy"
ldLibs "substrate"
ldLibs "substrate-dvm"
ldLibs "log"
}
}
sourceSets{
main{
jni.srcDirs = []
jniLibs.srcDirs=['src/main/libs']
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.3.0'
testCompile 'junit:junit:4.12'
}
9、编译成apk,安装即可.