目的
能快速,简单(主要是指脱离AndroidStudio)的把c/c++ 源码进行交叉编译成Android上的动态库,静态库,或者可执行文件。从而为逆向分析构建demo节省时间。
编译环境配置
电脑:Mac OS 10.13.4
NDK:官网下载,目前最新的好像android-ndk-r17 我用的是 android-ndk-r14b,ndk不需要安装官网下载后解压就行。
测试机: 华为EVA-AL00 Android7.0
配置环境变量
为了方便使用ndk的命令行工具,我们配置环境变量
在 ~/.bash_profile
文件中添加如下配置
export ANDROID_NDK_HOME=/Users/user01/Development/android-ndk-r14b
export PATH=${PATH}:${ANDROID_NDK_HOME}:${ANDROID_NDK_HOME}/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin
然后命令行运行如下命令:
$ source ~/.bash_profile
然后命令行运行:
$ ndk-build -h
如果能打印出 ndk-build 这个工具的帮助文档说明环境变量配置成功
测试简单的例子
创建如下目录结构(注意jni这层目录很重要,名字不要随便取):
~/Desktop/test/
└── jni/
├── Android.mk
├── Application.mk
└── test.c
主要有三个文件,其中Android.mk和Application.mk 是辅助ndk-build进行编译的,test.c是我们的c测试用例
- Application.mk
主要指定生成哪些cpu架构的动态库,这里只生成armeabi 和armeabi-v7a架构的库
APP_ABI := armeabi armeabi-v7a
APP_PLATFORM := android-14
- Android.mk
具体Android.mk的更详细的配置自行Google
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# 生成的so库的名字为libdemo.so
LOCAL_MODULE := demo
# 用于编译的c文件
LOCAL_SRC_FILES := test.c
# 生成库的类型,是动态库,静态库还是可执行文件,这里先来生成一个动态库
include $(BUILD_SHARED_LIBRARY)
# 下面这么写是生成可执行文件
#include $(BUILD_EXECUTABLE)
- test.c
很简单就是打印一句 hello world!
#include <stdio.h>
int main(const int argc,const char* args[]){
const char* str = "hello world!";
printf("%s\n",str);
return 0;
}
然后命令行进入到test目录下面:
$ cd ~/Desktop/test
$ ndk-build -C ./jni
然后会生成如下目录结构,obj目录下是生成动态库的中间文件,libs里面是最终生成的不同CPU架构的动态库:
test
├── jni
│ ├── Android.mk
│ ├── Application.mk
│ └── test.c
├── libs
│ ├── armeabi
│ │ └── libdemo.so
│ └── armeabi-v7a
│ └── libdemo.so
└── obj
└── local
├── armeabi
│ ├── libdemo.so
│ └── objs
│ └── demo
│ ├── test.o
│ └── test.o.d
└── armeabi-v7a
├── libdemo.so
└── objs
└── demo
├── test.o
└── test.o.d
为什么非要有jni那一层目录
约定优于配置,没有不行吗?行,但是要改点东西。去掉jni那层目录再编译一次,当前目录结构如下:
test/
├── Android.mk
├── Application.mk
└── test.c
命令行执行
$ cd ~/Desktop/test
$ ndk-build
结果报错如下:
Android NDK: Could not find application project directory !
Android NDK: Please define the NDK_PROJECT_PATH variable to point to it.
错误日志上说什么路径找不到错误,需要定义一个xx变量,我们只需要把编译命令改成如下就可以了:
ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=./Android.mk NDK_APPLICATION_MK=./Application.mk
编译一个可以运行的文件
修改Android.mk 文件如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := demo
LOCAL_SRC_FILES := test.c
#include $(BUILD_SHARED_LIBRARY)
# Android4.4 以后 调用的可执行文件不是基于PIE方式编译的,则无法运行
LOCAL_CFLAGS += -pie -fPIE
LOCAL_LDFLAGS += -pie -fPIE
# 编译一个可执行文件
include $(BUILD_EXECUTABLE)
这个可执行文件在电脑上是没法执行的,只能放到手机里面执行,执行如下命令,我们把刚生成的文件放到手机上:
- push 文件到手机
$ adb push libs/armeabi-v7a/demo /data/local/tmp
- 为手机中的demo文件添加可执行权限(为了方便直接给予所有权限了)
$ adb shell 'chmod 777 /data/local/tmp/demo'
- 用手机环境运行demo这个文件
$ adb shell '/data/local/tmp/demo'
运行结果会打印一行
hello world!