美文网首页
AndroidNDK入门

AndroidNDK入门

作者: MagicalGuy | 来源:发表于2018-10-11 00:18 被阅读0次

Android NDK 入门
Android NDK 安装
Android NDK 实例-静态方式函数
Android NDK 实例-动态方式函数
Android so 文件格式-ELF 格式
so 文件加载执行流程
Android so 文件动态调试

Android NDK 入门
NDK 就是 Android 平台下的 C++软件开发包。
NDK Native Delvpment Kit 原生开发包,这里包括常用库、编译工具、构建工具
NDK 中逆向分析中最需要了解和熟悉的是 JNI 接口,JNI - Java Native Interface (Java
原生接口)。JNI 是 Java 语言提供的 Java 与 C++交互的接口。
NDK 中使用编译器有 gcc,clang(基于 LLVM)

Android NDK 安装

image.png

Android NDK 实例-静态方式函数
Android 中 NDK 应用其实就是 C++的动态库,所以只要我们想要调用 C++的动态库,
就需要在 Java 代码中添加以下代码:

System.loadLibrary("native-lib");

一般来说,我们都会定义一个静态域,让其运行时自动加载。
static {
System.loadLibrary("native-lib");
}

在 Java 中我们可以声明原生函数,无需实现,使用关键字 native
public native String stringFromJNI();

同时在 C++中实现,实现的函数名称需要遵循一定的规则

  1. 需要 extern "C"
  2. 函数的名称:Java+包名+类名+函数名,用下划线连接
    Java_com_类名_hello13ndk_MainActivity_stringFromJNI
  3. 函数的参数:有两个固定的
    第一个参数是 JNI 环境指针
    第二个参数是对象的 this 指针(成员函数)或是对象的类型(静态函数)
    从第三个参数是 Java 中声明函数时定义的参数

extern "C"
jstring
Java_com_类名_hello13ndk_MainActivity_stringFromJNI(
JNIEnv env,
jobject /
this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}

image.png

NDK 中常用基本类型
typedef unsigned char jboolean; /* unsigned 8 bits /
typedef signed char jbyte; /
signed 8 bits /
typedef unsigned short jchar; /
unsigned 16 bits /
typedef short jshort; /
signed 16 bits /
typedef int jint; /
signed 32 bits /
typedef long long jlong; /
signed 64 bits /
typedef float jfloat; /
32-bit IEEE 754 /
typedef double jdouble; /
64-bit IEEE 754 */

对象类型
typedef _jobject* jobject;
typedef _jclass* jclass;
typedef _jstring* jstring;

注意写代码时,别忘记 extern “C”,如果不加,导出函数会将参数之类一并导出,名称粉碎

image.png

有 extern “C”的导出

image.png

Android NDK 实例-动态方式函数
NDK 中 C++通常生成的是动态库,其实动态有一个入口函数 JNI_Onload,可以在入口
函数进行动态注册对应的类的导出函数。

// 需要动态注册的函数
extern "C"
JNIEXPORT jstring JNICALL
stringFromJNI1(JNIEnv *env, jobject instance,
 jint i) {
 // TODO
 return env->NewStringUTF("hello 15PB!");
}
// 注册的结构体
const JNINativeMethod method = {
 "stringFromJNI1",
 "(I)Ljava/lang/String;", // 函数的签名
 (void*)stringFromJNI1
};
extern "C"
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
{
 // 获取 JNI 环境指针
 JNIEnv* env = NULL;
 jint jRet = vm->GetEnv((void**)&env, JNI_VERSION_1_6);

if (jRet != JNI_OK){
 __android_log_print(ANDROID_LOG_DEBUG,
 "native-lib",
 "获取环境指针 发生错误"
 );
 return JNI_ERR;
 }
 // 通过 JNI 接口调用注册原生函数
 // 获取类的类型 FindClass 参数是 类描述符,间隔符应该是/ 而不是.
 jclass jclass1 = env->FindClass("com/bluelesson/hellondk/MainActivity");
 // 动态注册函数
 jRet = env->RegisterNatives(jclass1, // 类的类型
 &method, // 数组基址
 1); // 数组元素个数
 if (jRet != JNI_OK){
 __android_log_print(ANDROID_LOG_DEBUG,
 "native-lib",
 "动态注册原生函数 发生错误"
 );
 return JNI_ERR;
 }
 return JNI_VERSION_1_6;
}

需要注意的两点:
函数签名
与 Dalvik 字节码中的类型描述符是一样的


image.png

举例: 函数类型 int fun(int,String); -> 签名 (ILjava/lang/String;)I
函数类型 boolean fun2(char,char) -》 (CC)Z

FindClass 的参数-类描述符
类描述符,间隔符应该是/ 而不是.
举例: com/bluelesson/hellondk/MainActivity

Android so 文件格式-ELF 格式
和 PE 文件类似,比 PE 文件简单,我们可以用 NDK 中提供的一个工具 readelf 去查看 ELF
文件主要表信息。
目录:D:\Android\sdk\ndk-bundle\toolchains\x86-4.9\prebuilt\windows-x86_64\bin

image.png

常见命令:
-h 查看文件头
-S 查看 Section header Table
-l 查看程序头表 Progrm Header Table
-s 查看符号表
-r 查看重定位表
-d 查看动态加载信息

image.png

文件头信息

image.png

段表信息,段表信息描述的是文件中每个区段的信息

image.png

程序头表信息
表示的是在内存中的区段信息。LOAD 类型区段会被加载到内存中。一般对齐方式 0x1000.

image.png

so 文件加载执行流程

image.png

① Init 段的 init_proc 函数(linker)
② Init_array 段的构造数组函数(linker)
③ Jni_Onload(libdvm.so)
使用 readelf 可以查看 init 段和 init_array 段的地址

image.png

Android so 文件动态调试
工具:IDA Pro , Android monitor、adb
① 上传 IDA 调试服务端

image.png
  1. 上传到 android 机器中
    adb push android_server /data/local/tmp/ands

  2. 修改文件权限,测试运行


    image.png
  3. 带参数,修改端口运行


    image.png

    ② 打开 monitor,以调试方式启动 apk

  4. 打开 monitor,待程序启动之后,选中调试进程


    image.png
  5. 以调试方式启动 apk
    adb shell am start -D -n 包名/入口类名


    image.png
  6. 设置端口转发
    adb forward tcp:23456 tcp:23456
    ③ 启动 IDA,附加调试 apk


    image.png
    image.png
    image.png
    image.png

④ 启动 jdb,附加 apk,启动 APK
jdb -connect com.sun.jdi.SocketAttach:hostname=localhost,port=8700

相关文章

网友评论

      本文标题:AndroidNDK入门

      本文链接:https://www.haomeiwen.com/subject/pdmeaftx.html