如何确保Java程序分发后不被篡改?使用JNI对Java程序进行安全校验

前言

众所周知,Java/Kotlin编译后会编译成smali,使用Jadx这类的反编译工具或者Hook工具就能很轻松的把我们的软件安全校验给破解了。

为了防止这种情况发生,我们一般会将核心代码使用C++编写,然后使用JNI技术,使用Java调用C++,因为C++编译后就成为了机器语言,反编译难度提高了可不止一倍两倍,但同时,如果我们的安全校验只在Java层面进行检查就很容易被去除。为此,我们可以使用C++来对Java程序进行安全检查,在发现被修改后就直接退出,因为核心逻辑是C++写的,如果C++的代码没有被

加载那么软件的壳被破解了也就毫无用途。

初步实现

初步实现可以看我之前写的:JNI的入门教程

在so加载时进行检查

cpp 复制代码
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
    JNIEnv* env;
    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
        return JNI_ERR;
    }

#ifdef _RELEASE
	// 
    if (!xxxx.checkLicenceKey(env)) {
        std::cerr << "Licence key validation failed. Terminating execution." << std::endl;
        return JNI_ERR;  // 验证失败,停止执行
    }
    #endif
    return JNI_VERSION_1_6;  // 验证通过,继续执行
}

其中的ifdef _RELEASE是一个宏,代表被包裹的代码,仅在RELEASE编译模式下才会被执行,如果你没有这个宏可以在CMake中加入

txt 复制代码
# 在 Release 模式下定义 _RELEASE 宏
if(CMAKE_BUILD_TYPE STREQUAL "Release")
    add_definitions(-D_RELEASE)
endif()

它调用了其他C++方法进行内部检查,这块的检查可以根据你的实际情况来操作,我这里是封装了checkLicenceKey方法来检查许可证授权。

比如我是在C++中获取到程序的文件,然后进行签名检查,判断是否与程序正式对外发布的RELEASE签名相同,如果不相同直接在JNI_OnLoad这个方法返回错误就行了,(切记不要在RELEASE中输出任何的调试日志不然很容易被定位破解的)

JNI_OnLoad方法是当System.load()时会被触发的方法

这样,当你程序外发的时候so文件每次加载都会检查文件完整性,并且破解者也不能取消加载这个so,因为一旦取消,程序就完全成了壳了。

这样,如果有人想要破解我们的程序,在加载后就会遇到这个错误:

(同样也是千万别直接说明原因,那样不是给破解者找问题原因的吗,你应该返回一个毫不相干的Exception)

版权所有:XuanRan

相关推荐
米羊12111 分钟前
fastjson (3修复)
网络·网络协议·安全
Wang15302 小时前
jdk内存配置优化
java·计算机网络
0和1的舞者3 小时前
Spring AOP详解(一)
java·开发语言·前端·spring·aop·面向切面
Wang15303 小时前
Java多线程死锁排查
java·计算机网络
小小星球之旅3 小时前
CompletableFuture学习
java·开发语言·学习
jiayong234 小时前
知识库概念与核心价值01
java·人工智能·spring·知识库
皮皮林5514 小时前
告别 OOM:EasyExcel 百万数据导出最佳实践(附开箱即用增强工具类)
java
weixin_462446234 小时前
exo + tinygrad:Linux 节点设备能力自动探测(NVIDIA / AMD / CPU 安全兜底)
linux·运维·python·安全
Da Da 泓5 小时前
多线程(七)【线程池】
java·开发语言·线程池·多线程
To Be Clean Coder5 小时前
【Spring源码】getBean源码实战(三)
java·mysql·spring