Android Hook native初探

一、写在前面

作为一个Android UI Api调用工程师,在日常中我们接触的更多是java层,除非特殊需求,不然很少直接接触Native层,昨天逛社区的时候看到一篇大佬的文章,就点开看了下,发现监控图片不是hook Java层,是hook了native层,然后就pull了源码,顿时发现没接触过C++的人看起来真费劲啊,于是想写篇文章记录下。

申明一下本文只是针对怎么理解JNI的调用流程,做下梳理,适合初学者,大佬不要喷我。下面就开始吧!!!

二、餐前小吃

实战前先来个简单的例子,熟悉一下基本流程,下面是使用Jni的一个简单例子:

1、首先创建一个MainActivity:

 

scala

复制代码

public class MainActivity extends AppCompatActivity { static { System.loadLibrary("native-lib"); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TextView tv = findViewById(R.id.sample_text); tv.setText(stringFromJNI()); } public native String stringFromJNI(); }

MainActivity内部先试用静态代码块调用System.loadLibrary("native-lib"), 目的是先加载资源库,其中的“native-lib”是在CMakeLists文件中命名的。然后就是定义了一个native的stringFromJNI() 方法。

2、创建native-lib.cpp:

 

c

复制代码

#include <jni.h> #include <string> extern "C" JNIEXPORT jstring JNICALL Java_com_example_jniexample_MainActivity_stringFromJNI(JNIEnv* env, jclass clazz) { std::string hello = "Hello from C++"; return env->NewStringUTF(hello.c_str()); }

此文件就是上述stringFromJNI() 的native实现,可以看到方法如下:

Java_com_example_jniexample_MainActivity_stringFromJNI(Java_包名_java类名_方法名), 入参有(JNIEnv* env, jclass clazz) ,首先java层没有定义入参,native这个是必有得,一个是Jni环境的指针,一个是java层的类名,如果java层有其他的参数,native层也加在后面即可。

关于extern "C" JNIEXPORT jstring JNICALL:

  • extern "C" JNIEXPORT jstring JNICALL 是JNI接口函数的声明,它告诉编译器如何将C/C++代码编译成可以被Java调用的本地库。

  • 在C++中,函数名称是由函数名和参数列表组成的,编译器会将函数名称转换为一种叫做mangled name的符号表示方式。但是,在JNI中,Java需要能够通过函数名称来调用本地库中的函数,Java不支持mangled name,因此需要通过extern "C"来指定函数按照C语言方式进行编译,避免C++编译器将函数名称转换为mangled name。

  • JNIEXPORT指定了函数的链接属性,告诉编译器应该导出函数,以便在本地库中可以被其他模块或程序使用。

  • jstring指定了函数的返回类型,表示返回一个Java的String类型。

  • JNICALL指定了函数调用约定,在Windows平台上,JNI函数的调用约定为__stdcall,而在其他平台上通常是__cdecl,JNICALL会根据平台自动选择正确的调用约定。

因此,extern "C" JNIEXPORT jstring JNICALL是JNI接口函数的标准声明方式,它告诉编译器如何将C/C++代码编译成Java可调用的本地库。

3、创建CMakeLists

 

scss

复制代码

# 指定cmake的最小版本 cmake_minimum_required(VERSION 3.4.1) # 创建一个库 add_library( native-lib SHARED native-lib.cpp ) # 查找log库 find_library( log-lib log ) # 链接库到目标库 target_link_libraries( native-lib ${log-lib} )

关于CMakeLists:

CMakeLists是CMake构建系统时必需的文件,用于指定信息和依赖关系,文件由一系列命令组成,每个命令都由一个调用和一组参数组成。以下是一些常用的命令:

  • cmake_minimum_required(VERSION x) :指定CMake的最低版本,x为版本号。
  • project(name) :指定项目名称,可以包含项目的版本、描述等信息。
  • add_library(name type source1 source2 ...) :创建一个库,其中name为库的名称,type为库的类型(STATIC、SHARED或MODULE),source为库的源文件。
  • target_link_libraries(target library1 library2 ...) :将目标库与指定的库链接起来。target是目标库的名称,library是需要链接的库名称。
  • find_library(name path) :查找指定名称的库,并将其路径存储在变量中。name是库的名称,path是查找的路径。
  • include_directories(directory) :添加一个目录到包含路径中。
  • add_definitions(definition) :添加一个编译定义。

在Android JNI项目中,我们可以使用add_library命令创建一个动态库,使用find_library命令查找需要链接的库,使用target_link_libraries命令将它们链接到目标库中。我们还可以使用include_directories命令添加包含路径和add_definitions命令添加编译定义。

除了上述命令,还有其他命令可用于指定编译选项、设置环境变量、生成可执行文件等。CMakeLists文件的语法和命令非常灵活,开发者可以根据自己的需求和项目特点进行自定义。

我们创建的库是add_library(native-lib SHARED native-lib.cpp) 名称是“native-lib”,这个就跟MainActivity中 System.loadLibrary("native-lib") 对应。然后我们创建的是SHARED library,也称为动态库或共享库,是一种在程序运行时被动态加载的库,它与静态库(Static library)相对。静态库在编译时被链接到可执行文件中,因此可执行文件比较大,但是静态库的加载速度较快。动态库则可以在程序运行时动态地加载和卸载,因此可执行文件较小,但是加载速度较慢。

关于库类型:

  1. SHARED library(动态库) 在多个程序之间共享代码和数据ÿ
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值