来自 NDK/JNI 的 Android APK 篡改检测

Pro*_*mer 6 security android android-ndk apk dex

问题

我有一些钥匙,我想保证它的安全。目前,原生共享库按需生成它们。我的 apk 使用这个共享库来获取密钥。当前实现的问题是攻击者可能会提取 apk,复制共享库并调用生成密钥的函数并获取密钥。因此,我想确保共享库仅在我的 apk 调用时才生成有效密钥。

解决这个问题的方法

解决这个问题的方法涉及到 NDK 端的 apk 篡改检测。基本思想是在运行时从 JNI 获取调用 APK 的签名。如果签名有效,则库生成有效密钥,否则生成无效密钥。

这种方法的已知局限性

  • 据了解,并非100%万无一失。
  • 由于密钥在客户端的设备中并且客户端拥有硬件,因此专门的攻击者可以访问生成的密钥。

到目前为止我做了什么到目前为止 的实现是基于这个stackoverflow帖子中提到的想法

  • 读取存储在 /proc/self/maps 中的进程内存
  • 找到包含文本“.dex”的行。
  • 获取DEX文件区域的起止地址

    FILE *fp;    
    fp = fopen("/proc/self/maps", "r");    
    if(fp!=NULL){
        char line [ 2048 ];
        while ( fgets ( line, sizeof line, fp ) != NULL ) /* read a line */
        {
            if (strstr(line, ".dex") != NULL) {
    
                //This is the line we want
                __android_log_write(ANDROID_LOG_INFO,"DexFile",line);
                char * startingAddress;
                char * endingAddress;
                startingAddress = strtok (line," ,.-");
                endingAddress = strtok (NULL," ,.-");
                if(startingAddress!=NULL){
                    __android_log_write(ANDROID_LOG_INFO,"DexStart",startingAddress);
                }
                if(endingAddress!=NULL){
                __android_log_write(ANDROID_LOG_INFO,"DexEnd",endingAddress);
                }
                //Now, we have the starting and ending address
            }
    
        }
        fclose ( fp);
    }
    
    Run Code Online (Sandbox Code Playgroud)

我不明白的

  • 有了dex文件区域的起始地址和结束地址,如何获取签名呢?
  • 我不确定为什么首先需要阅读签名。我认为您需要以 dex 文件区域dex 文件格式读取 apk 的校验和,如果校验和不是您所期望的,则将 apk 视为被篡改。

  • 我如何以可移植的方式实现我想要做的事情(因为它涉及本机代码)?

注意:如果您可以提供示例实现,那就太好了,因为我一直在寻找这个特定的答案,而我只找到了抽象的答案。提前致谢。