JNI编程笔记AndroidStudio3.0下的JNI编程

特别说明

当前博客平台账号已废弃,如果有使用细节问题请前往我新博客平台进行讨论交流。

个人博客平台 HuRuWo的技术小站

文章首发于个人博客HuRuWo的技术小站,如果本文非vip用户无法完全浏览或者图片无法打开,可前往个人博客文章地址查看文章并留言讨论。

个人博客文章地址JNI编程笔记AndroidStudio3.0下的JNI编程

更多技术文章访问本人博客HuRuWo的技术小站,包括 Electron从零开发 Android 逆向 app 微信数据抓取 抖音数据抓取 闲鱼数据抓取 小红书数据抓取 其他软件爬虫 等技术文章

JNI介绍

官方介绍:

在编程领域,JNI (Java Native Interface,Java本地接口)是一种编程框架,使得Java虚拟机中的Java程序可以调用本地应用/或库,也可以被其他程序调用。 本地程序一般是用其它语言(C、C++或汇编语言等)编写的,并且被编译为基于本机硬件和操作系统的程序。

总的来说呢,就是一个框架,可以使得java调用c/c++代码。在Android中谷歌提供了NDK工具,用于移动下的JNI开发。

Android NDK 是一套允许您使用 C 和 C++ 等语言,以原生代码实现部分应用的工具集。在开发某些类型的应用时,这有助于您重复使用以这些语言编写的代码库

NDK下载和教程地址:https://developer.android.com/ndk/?hl=zh-cn

JNI对于Android安全的意义

做过逆向工程的小伙伴都知道。所谓的java层代码是非常容易被解开的。即使加上混淆,加上签名校验什么的,依然十分脆弱。而真正的大厂都会把真正的加密安全相关的信息放在so文件里面。

使用jni开发的so文件是一个二进制文件,无法轻易被读取。极大的增加破解难度。再配合加固等技术一般都能做到软件的安全防护。

使用AndroidStudio3.0进行JNI开发

这里强调AS3.0呢,主要是在3.0之后的JNI编程和之前有很大的区别。

众所周知,混合编译需要一个配置文件来说明编译的过程。在3.0之前使用的配置文件是makefile。而在3.0之后官方直接默认了CMake.txt。所以我们要习惯CMake文件的使用。

CMake介绍

CMake文件官网https://cmake.org/

官网首页的介绍如下(谷歌翻译):

CMake是一个开源的跨平台工具系列,旨在构建,测试和打包软件。CMake用于使用简单的平台和独立于编译器的配置文件来控制软件编译过程,并生成可在您选择的编译器环境中使用的本机makefile和工作空间。CMake工具套件由Kitware创建,以满足对ITK和VTK等开源项目的强大跨平台构建环境的需求。

总之就是一个混合编译配置文件,它有自己的语法包括版本。如果你想知道更多可以仔细的学习他的文档。

新建工程

新建安卓工程,点上Include C++ support

image.png

一路next到finish,系统就会自动配置一个带JNI的工程。

查看工程

实际上这个工程已经是一个标准的JNI工程了,直接运行就可以了。
不过在运行钱可以查看下工程目录,看看和平常的安卓工程有什么区别。

区别1:MainActivity.java的so文件导入和本地方法

image.png

引用so文件native-lib
调用本地方法stringFromJNI()
本地方法public native String stringFromJNI();

区别2:app build.gradle 文件配置
可以看到和平常的build.gradle有两处不同

image.png

可以看到有两个externalNativeBuild节点

defaultConfig内部的externalNativeBuild节点用于配置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节点用于配置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"
        }
    }
}

区别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 了一个字符串 ,具体这里怎么生成的我下一节讲。

区别4:CMakeLists.txt文件

非常有意思这个文件,我把内容复制出来分析:

# 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库(系统库)

# 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库 系统库

# 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");
    }
    
    //调用c层方法
    public static native System sayHello();
}

2.利用javac 命令生成.class文件

转到myJNI.java目录下,右键当前打开命令行:

image.png

会生成一个myJNI.class文件

image.png

3.javah命令生成.h头文件

转到java目录下(即com同层目录下)

命令如下: javah -jni 包名+文件名

image.png

生成新的.h文件

image.png

打开里面的内容如下:

/* 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同层级

image.png

新建main.c文件(这个命名可以随意) 把之前生成的.h文件内容拷贝过来

然后改动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

编译工程 其他配置

为了节省空间,避免包太大。通常我们配置NDK 支持的CPU架构。
百度一搜可能就会出现以下代码:

ndk{
            moduleName "helloJni"//*生成的so文件名,必填
            abiFilters "armeabi", "armeabi-v7a", "x86" //配置输出的abi体系结构下的so库,
        }

你兴奋的复制上去,shit 报错了。

image.png

显然这些配置需要出现在CMake节点里面 就想这样

externalNativeBuild {
            cmake {
                cppFlags ""
                abiFilters 'arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64'
            }
        }

运行起来:

image.png

没毛病哦老铁,数据请求成功。

我们可以看到生成的so文件,build文件后解压apk:

image.png

总结

本次了解了AS3.0的JNI基础编程,可以提高安全性。

一份参考资料奉上 http://wiki.jikexueyuan.com/project/jni-ndk-developer-guide/workflow.html

最后是项目地址:

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容