我们可以为Android应用程序编写如下获取密钥的方法方法1和方法2
两个方法是否具有相同的安全强度?或者在反编译/逆向工程或其他应用程序破解过程中,以下方法之一是否存在任何安全漏洞?
方法1
在lib.cpp文件中的方法中声明/assign key
lib.cpp文件
extern "C"
JNIEXPORT jstring JNICALL
Java_com_app_keytest_KeyHelper_getKey(JNIEnv *env, jobject) {
std::string API_KEY = "YOUR_API_KEY";
return env->NewStringUTF(API_KEY.c_str());
}
方法2
在与lib.cpp相同目录下的单独keys.h文件中声明/分配密钥,并导入到lib.cpp文件
keys.h文件
std::string API_KEY = "YOUR_API_KEY";
lib.cpp文件
#include "keys.h"
extern "C"
JNIEXPORT jstring JNICALL
Java_com_app_keytest_KeyHelper_getKey(JNIEnv *env, jobject) {
return env->NewStringUTF(API_KEY.c_str());
}
这两个片段编译成几乎完全相同的代码。在这两种情况下,API密钥都以明文形式存在于编译库中。即使您煞费苦心地混淆了本机代码,攻击者也可以附加一个调试器并捕获getKey
的返回值。
你需要重新考虑你的方法,并决定它是否真的值得你付出努力。
你可以用另一种方法取得好成绩:
- 你必须混淆JNI函数名,因为"getKey()"在逆向工程中过于自我解释和容易理解
- 将未使用的参数添加到getKey()"使其在滚动时更复杂,同时查看反向代码
- getKey()还没有返回键但必须调用Java方法或设置特定的Java变量
关于#3:我在JNI上使用专用线程来接收"命令";和一个"回调"对于其结果:
- Java调用JNI的getKey(fakeArg1, fakeArg2, fn_callback, fakeArg3)">
- getKey()发送一个请求JNI专用线程甚至通过"fn_callback"作为请求的一部分
- 专用线程处理请求然后调用Java回调
在这种情况下,在正常的调试过程中,很难遵循流程,因为调试不会进入专用线程内自动使用StepInto/Over键/按钮。
Update: callback是第一种方法,但是在调用者和结果之间创建了一个链接。为了避免这种情况,您可以从JNI中调用一个完全分离的Java方法,将变量传递给。