在anndroid studio 2.2 后,用它编写native代码只支持用CMake
进行,然后我正在准备用Cydia Substrate 来 hook native代码的时候,发现网上没有用CMake
方法来编写cydia脚本的,然后就只有自己动手了,下面用一个小案例记一下大致流程,也方便后来的朋友。
创建一个目标程序
1. 用android studio创建一个ndk程序,这里很简单,我们在创建的时候选择include c++ support即可,后面流程就和普通程序一样,然后等待它创建完成,完成后的目录结构如下:
注:你们的cpp文件夹里cpp文件的名字可能不是这个,这没影响,我这个是我自己创建的
2.我们修改一下native-lib.cpp里面的代码,方便后面hook,native-lib.cpp中代码如下:
//
// Created by Blinger on 2018/7/3.
//
#include <jni.h>
#include <string>
//加上extern "C"是因为c++11后的编译器为了方便重载,会更改函数名,加上这个就不会,方便后面hook,不然还得用IDA PRO打开so文件查找,如果是自己创建的.c文件就不用
extern "C"
{
char *getHello(void) {
return "hello native";
}
//函数名记得做相应的修改
JNIEXPORT jstring JNICALL Java_blinger_com_dumpdex_MainActivity_getFromNativeString(
JNIEnv *env,
jobject jobject1) {
return env->NewStringUTF(getHello());
}
}
3.编译运行
目标程序写好了,接下来就写我们的cydia脚本了
Cydia脚本编写
1.和传统JNI一样,先下载cydia sdk与apk文件
2.新建一个NDK项目,步骤同上
3.将cydia sdk的两个.so
放入libs文件夹相应的ABI目录中,没有ABI路径的话就自己建一个吧,然后在cpp文件夹中创建include文件夹,将sdk的头文件放进去,最后生成的目录如下
注:路径也不一定要像我这样配置,如果改了,后面的配置文件也要做相应的改变
4.编写cydia脚本,内容如下,并将其后缀改为.cy.cpp,如上图最后一行:
#include <jni.h>
#include <android/log.h>
#include "include/substrate.h"
#define LOG(...) __android_log_print(ANDROID_LOG_DEBUG,"blinger",__VA_ARGS__)
extern "C"
//这是HOOK程序的写法,像hook livdvm.so应该这样写:MSConfig(MSFilterLibrary, "libdvm.so");
MSConfig(MSFilterExecutable,"/system/bin/app_process")
//旧的函数地址,为了保留就函数入口,有时候会用到,当然我们这个例子简单,就不用了
char * (* getFromNativeString) (void);
char * newhello(void)
{
return "hello better tomorrow";
}
//通过so库的绝对路径和函数名,找到其函数的映射地址
void * lookup_symbol(char* libraryname,char* symbolname)
{
void *handle = dlopen(libraryname,RTLD_GLOBAL | RTLD_NOW);
if(handle != NULL){
void *symbol = dlsym(handle,symbolname);
if(symbol != NULL){
return symbol;
} else{
LOG("dl error: %s",dlerror());
return NULL;
}
} else{
return NULL;
}
}
MSInitialize
{
//文件路径记得改为自己的路径
void *symbol = lookup_symbol("/data/data/blinger.com.dumpdex/lib/libhello.so","getHello");
//这里将旧函数的入口(参数一)指向hello(参数三),然后执行新函数(参数二)
MSHookFunction(symbol,(void *)&newhello,(void **)&getFromNativeString);
};
这里注意一下,记得修改MainActivity里面的内容,将native相关的删掉,不然等会编译肯定是会报错的
5.配置CMakeLists文件,这也是最重要的一步,文件内容如下:
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html
# Sets the minimum version of CMake required to build the native library.
cmake_minimum_required(VERSION 3.4.1)
add_library( # 这里记得改为脚本相应的名字.
native-lib.cy
# Sets the library as a shared library.
SHARED
# 改为相应的路径
src/main/cpp/native-lib.cy.cpp )
# sdk头文件路径
include_directories(src/main/cpp/include/substrate)
#在添加第三方库进项目时,所添加的东西包括add_library与set_target_properties与在target_link_libraries添加相应的文件名,如果sdk文件放置的目录和我不一致,记得添加为自己的
#添加三方库名的时候记得把lib前缀去掉,比如:libtest.so,就应该写为test,但输入路径的时候不变,其他CMakeLists的配置方法就不多说了,可以去官网查阅
add_library(substrate SHARED IMPORTED)
set_target_properties(substrate
PROPERTIES IMPORTED_LOCATION
${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI}/libsubstrate.so)
add_library(substrate-dvm SHARED IMPORTED)
set_target_properties(substrate-dvm
PROPERTIES IMPORTED_LOCATION
${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI}/libsubstrate-dvm.so)
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log )
#特别注意,记得在这里添加你说添加的三方库
target_link_libraries( # Specifies the target library.
native-lib.cy
# Links the target library to the log library
# included in the NDK.
substrate
substrate-dvm
${log-lib} )
6.在模块的build.gradle添加配置文件,添加到android版块中,内容如下(这里如果你的sdk文件放到了其他地方,应该做相应的修改):
sourceSets.main {
jni.srcDirs = [] // This prevents the auto generation of Android.mk
jniLibs.srcDir 'libs'
}
7.修改AndroidManifest.xml文件,在相应的地方做修改就行,内容如下:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:installLocation="internalOnly">
<application android:hasCode="false">
</application>
<uses-permission android:name="cydia.permission.SUBSTRATE"/>
</manifest>
8.编译运行,记得先安装cydia的apk,给了root权限后重启,再安装cydia脚本后重启,如果打开我们的脚本apk可能会闪退,但这没影响,hook成功就行
说了这么多,是不是感觉比传统的JNI方法方便了许多,主要是修改CMakeLists中的内容,其他都和传统的JNI方法差不多。在我看了还是比传统方法好很多,不知道各位看官怎么看待。有什么问题就留言吧。