特別說明
當前博客平臺賬號已廢棄,如果有使用細節(jié)問題請前往我新博客平臺進行討論交流脂信。
個人博客平臺 HuRuWo的技術小站
文章首發(fā)于個人博客HuRuWo的技術小站,如果本文非vip用戶無法完全瀏覽或者圖片無法打開癣蟋,可前往個人博客文章地址查看文章并留言討論。
個人博客文章地址JNI編程筆記AndroidStudio3.0下的JNI編程
更多技術文章訪問本人博客HuRuWo的技術小站狰闪,包括 Electron從零開發(fā) Android 逆向 app 微信數(shù)據(jù)抓取 抖音數(shù)據(jù)抓取 閑魚數(shù)據(jù)抓取 小紅書數(shù)據(jù)抓取 其他軟件爬蟲 等技術文章
JNI介紹
官方介紹:
在編程領域疯搅,JNI (Java Native Interface,Java本地接口)是一種編程框架,使得Java虛擬機中的Java程序可以調(diào)用本地應用/或庫埋泵,也可以被其他程序調(diào)用幔欧。 本地程序一般是用其它語言(C、C++或匯編語言等)編寫的丽声,并且被編譯為基于本機硬件和操作系統(tǒng)的程序礁蔗。
總的來說呢,就是一個框架,可以使得java調(diào)用c/c++代碼恒序。在Android中谷歌提供了NDK工具瘦麸,用于移動下的JNI開發(fā)。
Android NDK 是一套允許您使用 C 和 C++ 等語言歧胁,以原生代碼實現(xiàn)部分應用的工具集滋饲。在開發(fā)某些類型的應用時,這有助于您重復使用以這些語言編寫的代碼庫
NDK下載和教程地址:https://developer.android.com/ndk/?hl=zh-cn
JNI對于Android安全的意義
做過逆向工程的小伙伴都知道喊巍。所謂的java層代碼是非常容易被解開的屠缭。即使加上混淆,加上簽名校驗什么的崭参,依然十分脆弱呵曹。而真正的大廠都會把真正的加密安全相關的信息放在so文件里面。
使用jni開發(fā)的so文件是一個二進制文件何暮,無法輕易被讀取奄喂。極大的增加破解難度。再配合加固等技術一般都能做到軟件的安全防護海洼。
使用AndroidStudio3.0進行JNI開發(fā)
這里強調(diào)AS3.0呢跨新,主要是在3.0之后的JNI編程和之前有很大的區(qū)別。
眾所周知,混合編譯需要一個配置文件來說明編譯的過程坏逢。在3.0之前使用的配置文件是makefile
域帐。而在3.0之后官方直接默認了CMake.txt
赘被。所以我們要習慣CMake文件的使用。
CMake介紹
CMake文件官網(wǎng)https://cmake.org/
官網(wǎng)首頁的介紹如下(谷歌翻譯):
CMake是一個開源的跨平臺工具系列肖揣,旨在構(gòu)建民假,測試和打包軟件。CMake用于使用簡單的平臺和獨立于編譯器的配置文件來控制軟件編譯過程龙优,并生成可在您選擇的編譯器環(huán)境中使用的本機makefile和工作空間羊异。CMake工具套件由Kitware創(chuàng)建,以滿足對ITK和VTK等開源項目的強大跨平臺構(gòu)建環(huán)境的需求陋率。
總之就是一個混合編譯配置文件球化,它有自己的語法包括版本秽晚。如果你想知道更多可以仔細的學習他的文檔瓦糟。
新建工程
新建安卓工程,點上Include C++ support
一路next到finish赴蝇,系統(tǒng)就會自動配置一個帶JNI的工程菩浙。
查看工程
實際上這個工程已經(jīng)是一個標準的JNI工程了,直接運行就可以了句伶。
不過在運行錢可以查看下工程目錄劲蜻,看看和平常的安卓工程有什么區(qū)別。
區(qū)別1:MainActivity.java的so文件導入和本地方法
引用so文件native-lib
調(diào)用本地方法stringFromJNI()
本地方法public native String stringFromJNI();
區(qū)別2:app build.gradle
文件配置
可以看到和平常的build.gradle
有兩處不同
可以看到有兩個externalNativeBuild
節(jié)點
defaultConfig
內(nèi)部的externalNativeBuild
節(jié)點用于配置cmake
的配置
可選配置有下面這些文檔地址:
android {
// Similar to other properties in the defaultConfig block, you can override
// these properties for each product flavor you configure.
defaultConfig {
// This block is different from the one you use to link Gradle
// to your CMake or ndk-build script.
externalNativeBuild {
// For ndk-build, instead use the ndkBuild block.
cmake {
// Passes optional arguments to CMake.
arguments "-DANDROID_ARM_NEON=TRUE", "-DANDROID_TOOLCHAIN=clang"
// Sets a flag to enable format macro constants for the C compiler.
cFlags "-D__STDC_FORMAT_MACROS"
// Sets optional flags for the C++ compiler.
cppFlags "-fexceptions", "-frtti"
// Specifies the library and executable targets from your CMake project
// that Gradle should build.
targets "libexample-one", "my-executible-demo"
}
}
}
}
defaultConfig
外部的externalNativeBuild
節(jié)點用于配置cmake
的文件地址考余,如果CMake.txt放在根目錄先嬉,配置如下:
android {
externalNativeBuild {
// Encapsulates your CMake build configurations.
// For ndk-build, instead use the ndkBuild block.
cmake {
// Specifies a path to your CMake build script that's
// relative to the build.gradle file.
path "CMakeLists.txt"
}
}
}
區(qū)別3:main目錄下的cpp文件夾以及里面的native-lib.cpp
文件
這個不解釋了,就是c層文件目錄了
代碼如下:
#include <jni.h>
#include <string>
extern "C" JNIEXPORT jstring
JNICALL
Java_com_huruwo_as3_1jni_1demo_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
這里就是return 了一個字符串 ,具體這里怎么生成的我下一節(jié)講楚堤。
區(qū)別4:CMakeLists.txt
文件
非常有意思這個文件疫蔓,我把內(nèi)容復制出來分析:
# 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)
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
add_library( # Sets the name of the library.
native-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
src/main/cpp/native-lib.cpp)
# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
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)
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library.
native-lib
# Links the target library to the log library
# included in the NDK.
${log-lib})
通過里面的英文說明我們可以知道每一段文字的意義:
設置最小的CMake版本
# Sets the minimum version of CMake required to build the native library.
cmake_minimum_required(VERSION 3.4.1)
設置生成so文件信息 源代碼地址
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
add_library( # Sets the name of the library.
native-lib # 設置so文件名稱 也就是我們在mainactivity里面引用的名稱
# Sets the library as a shared library.
SHARED #設置為分享庫
# Provides a relative path to your source file(s).
src/main/cpp/native-lib.cpp) # 設置代碼的地址 有多少寫多少
導入一些而外的庫,比如這里的log庫(系統(tǒng)庫)
# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
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)
把前面的所有庫連接起來 包括三方庫 so庫 系統(tǒng)庫
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library.
native-lib
# Links the target library to the log library
# included in the NDK.
${log-lib})
如何生成native-lib.cpp
文件
步驟如下:
1.新建myJNI.java文件
代碼如下:
public class myJNI {
//加載so文件
static {
System.loadLibrary("JniTest");
}
//調(diào)用c層方法
public static native System sayHello();
}
2.利用javac 命令生成.class文件
轉(zhuǎn)到myJNI.java目錄下身冬,右鍵當前打開命令行:
會生成一個myJNI.class文件
3.javah命令生成.h頭文件
轉(zhuǎn)到java目錄下(即com同層目錄下)
命令如下: javah -jni 包名+文件名
生成新的.h文件
打開里面的內(nèi)容如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_huruwo_hellosoworld_myJNI */
#ifndef _Included_com_huruwo_hellosoworld_myJNI
#define _Included_com_huruwo_hellosoworld_myJNI
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_huruwo_hellosoworld_myJNI
* Method: sayHello
* Signature: ()Ljava/lang/System;
*/
JNIEXPORT jobject JNICALL Java_com_huruwo_hellosoworld_myJNI_sayHello
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif
4.編寫c層代碼
新建文件夾jni衅胀,在main下與java同層級
新建main.c文件(這個命名可以隨意) 把之前生成的.h文件內(nèi)容拷貝過來
然后改動JNIEXPORT jobject JNICALL Java_com_huruwo_hellosoworld_myJNI_sayHello
這個方法,讓其返回一段文字酥筝。
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_huruwo_hellosoworld_myJNI */
#ifndef _Included_com_huruwo_hellosoworld_myJNI
#define _Included_com_huruwo_hellosoworld_myJNI
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_huruwo_hellosoworld_myJNI
* Method: sayHello
* Signature: ()Ljava/lang/System;
*/
JNIEXPORT jobject JNICALL Java_com_huruwo_hellosoworld_myJNI_sayHello
(JNIEnv *, jclass){
return (*env)->NewStringUTF(env,"hello 52pojie!");
}
#ifdef __cplusplus
}
#endif
#endif
編譯工程 其他配置
為了節(jié)省空間,避免包太大滚躯。通常我們配置NDK 支持的CPU架構(gòu)。
百度一搜可能就會出現(xiàn)以下代碼:
ndk{
moduleName "helloJni"http://*生成的so文件名嘿歌,必填
abiFilters "armeabi", "armeabi-v7a", "x86" //配置輸出的abi體系結(jié)構(gòu)下的so庫掸掏,
}
你興奮的復制上去,shit 報錯了宙帝。
顯然這些配置需要出現(xiàn)在CMake節(jié)點里面 就想這樣
externalNativeBuild {
cmake {
cppFlags ""
abiFilters 'arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64'
}
}
運行起來:
沒毛病哦老鐵丧凤,數(shù)據(jù)請求成功。
我們可以看到生成的so文件茄唐,build文件后解壓apk:
總結(jié)
本次了解了AS3.0的JNI基礎編程息裸,可以提高安全性蝇更。
一份參考資料奉上 http://wiki.jikexueyuan.com/project/jni-ndk-developer-guide/workflow.html
最后是項目地址: