本篇博文参考了非虫大大的Android软件安全与逆向分析,这真的是一本好书,里面涵盖的内容比较全也比较基础。下面开始我们的学习。
Android为了提高效率、安全性等,提供了NDK(原生开发套件),现在我们来看看如何编译原生程序。
原生程序的编译有三种方法:
1、使用gcc手动编译
2、使用ndk-build手动编译
3、使用eclipse自动编译
我们分别使用这三种方式来分别编译看看。
准备工作:
1、下载对应版本的ndk,我所使用的平台是windows,解压到指定位置即可。ndk下载链接:https://developer.android.com/ndk/downloads/index.html
我的路径为F:\android\android-ndk-r11b,那么工具链的完整路径为F:\android\android-ndk-r11b\toolchains\arm-linux-androideabi-4.9\prebuilt\windows-x86_64\bin,大家可以看到该目录有很多前缀为arm-linux-androideabi-的exe文件,代表它们使用与arm架构的android程序开发。
现在,就开始动手啦。
首先,新建hello.c程序,代码如下:
1、gcc手动编译
使用这种方式需要首先编写makefile文件。为了之后的方便,我们先将adb 和make工具加入环境变量,环境变量设置方式这里就不细说了。不知道的可以参考这篇文章:
http://jingyan.baidu.com/article/17bd8e52f514d985ab2bb800.html,make.exe工具路径为F:\android\android-ndk-r11b\prebuilt\windows-x86_64\bin,将该路径添加到环境变量中,注意与adb路径用分号隔开。
现在,我们开始编写我们的makefile文件。新建makefile文件,无后缀名,内容如下:
1、如果仔细看的话,就会发现这个文件定义了一系列的变量,然后又使用拼接的方式将值赋给另一个变量。
2、前六行定义了路径变量,$(NDK_ROOT)就是取该变量值,在这里可能需要对应版本修改你的对应路径。
3、MODULE_NAME这个变量定义了我们编译完成的名称为hello
4、FLAGS变量增加了一些头文件和库文件的搜索路径和编译选项。在这里我们主要提两个选项,第一个是-nostdlib,android没有采用glibc作为c库,而是采用Google自己开发的Bionic C库,因此需要加入该选项;第二个是-pie -fPIE,在android4.4之后添加了新的保护机制,可执行文件必须是采用PIE编译的,我们加入该行参数,就可以避免报错。
5、all便签指定了编译程序时需要执行的命令。
6、clean标签用于清理生成的目标文件。
7、install标签将我们生成的最终文件安装到手机上,就可以看到c程序输出的结果了。(该标签下的命令就是我们为什么要设置adb环境变量,方便在makefile中编写该命令)
将我们的makefile文件与hello.c放到同一目录下,打开命令行,进入该目录,依次执行以下命令:
同时,我们打开刚才的目录,可以看到里面生成了一些.o和.S文件。假设我们想删除其中后缀为.o的文件,执行make clean命令,再打开目录就会看到.o文件已经被删除。。如果想修改删除规则,修改makefile中clean标签内容即可。
2、ndk-build编译
首先,我们先将ndk-build命令加入环境变量,该命令一般位于ndk安装目录下,我安在F:\android下,因此我的ndk-build命令路径为F:\android\android-ndk-r11b,参考gcc编译方式中的adb环境变量设置,将此路径加入到android变量中即可,注意用分号隔开。
使用ndk-build工具,必须先有一个Android工程。我们可以使用sdk开发包中的tools目录下的android脚本来生成。首先我们列出Android SDK中所有已经按照的SDK平台版本。在sdk\toos目录下执行以下命令:
接下来创建Android工程,执行以下命令:
执行完以上命令后,会看到tools目录下生成了hello2的工程。
下一步,进入工程根目录,新建jni文件夹,并将我们最开始编写的hello.c文件复制进去。接着编写ndk-build所需要的脚本文件,主要是Android.mk与Application.mk两个脚本,Application.mk可选,我们暂时不使用,这里我们只使用Android.mk文件,该文件是工程的编译脚本,描述了编译原生程序所需的编译选项,头文件,源文件及依赖库等。
新建Android.mk,文件内容如下:
1、LOCAL_PATH:定义本地源码路径
2、CLEAR_VARS:让编译系统清除掉一些已经定义过的宏
3、LOCAL_ARM_MODE:指定生成的原生程序使勇的ARM指定模式
4、LOCAL_MODULE:指定模块名称,即原生程序生成后的文件名
5、LOCAL_SRC_FILES:指定C或C++源列表。示例中使用的只有一个hello.c文件。
6、BUILD_EXECUTABLE:指定生成可执行文件。
Android.mk文件编写完后,将它与hello.c一同放在jni目录下,然后进入命令行切换到hello2根目录,执行ndk-build命令,执行效果如下:
Android.mk文件编写完后,将它与hello.c一同放在jni目录下,然后进入命令行切换到hello2根目录,执行ndk-build命令,执行效果如下:
此时,我们看执行结果的最后一行即我们生成文件的位置。因此,我们进入hello2目录下的libs/armeabi下,将hello文件复制到模拟器或手机中,执行过程参考gcc手动编译。其实主要也就是以下三条命令即可:
说明:1、adb需要配置环境变量。
2、传入的hello必须修改权限为可执行文件
此时,可以看到,控制台命令行输出"Hello ARM!"。
3、Eclipse创建工程并自动编译
使用eclipse自动编译原生程序的原理依然是使用ndk-build工具。
1、打开eclilpse,新建Android工程,取名为hello3。
2、新建Build,当代码修改保存后,eclipse会自动编译生成原生程序,新建Build流程如下:
在hello3工程上右键选择Properties,点击Builders选项,再点击右侧New按钮,然后双击Program打开Edit Configuration,在对话框的Name一栏中设置Builder名称,Location输入ndk-build命令路径,Working Drrectory右侧的Browser Workspace选择hello3工程,点击Apply按钮。点击Refresh标签,勾选“Refresh resource upon completion”复选框。点击Build Options标签,勾选“During auto builds”和"Specify working set of relevant resources"复选框。点击“Specify Resources”按钮,勾选hello3工程的jni目录,点击finish按钮,点击Ok关闭Edit Configuration对话框。点击OK关闭Properties对话框。
3、此时hello3自动编译,并在libs/armeabi目录下省hello可执行文件。
结果如下:
以后在Eclipse中对jni目录下任何文件进行修改保存操作,都会触发JNI_Builder执行来重新编译工程。
至此,我们已经将三种编译方式完全讲述完毕。