如何在Android NDK(C++)中获取二进制文件的MD5值
问题分析与修复方案
嘿,我一眼就瞅到你代码里的核心问题了——计算MD5时传入的长度完全不对,这才导致哈希结果和其他方式不一致!
先看你这段关键代码:
md5.update(contents, sizeof(contents));
contents是个char*指针,sizeof(contents)拿到的是指针本身的字节数(32位系统是4,64位是8),根本不是你从zip里读出来的classes.dex的实际大小st.size。等于你只算了文件开头几个字节的MD5,结果当然和完整文件的哈希对不上。
另外,你调用joyee::md5(contents)的时候,这个函数估计是把contents当C字符串处理,遇到\0就停了——但.dex是二进制文件,里面肯定有不少空字节,这也会导致计算不完整。
修正后的完整代码
我给你改好了代码,不仅修复了MD5长度的问题,还优化了内存管理(避免泄漏)和错误检查:
#include <zip.h> #include <fstream> #include <memory> #include <string> #include "joyee_md5.h" // 替换成你的MD5头文件路径 int calculateDexMd5() { const char* apkPath = getBaseApkAbsolutePath(); int zipErr = 0; zip* zipHandle = zip_open(apkPath, 0, &zipErr); if (!zipHandle) { LOG("Failed to open APK: error code %d", zipErr); return -1; } const char* dexName = "classes.dex"; struct zip_stat dexStat; zip_stat_init(&dexStat); if (zip_stat(zipHandle, dexName, 0, &dexStat) != 0) { LOG("Could not get info for classes.dex"); zip_close(zipHandle); return -1; } // 用智能指针自动释放内存,避免泄漏 std::unique_ptr<char[]> dexBuffer(new char[dexStat.size]); zip_file* dexFile = zip_fopen(zipHandle, dexName, 0); if (!dexFile) { LOG("Failed to open classes.dex inside APK"); zip_close(zipHandle); return -1; } // 确保读取到完整的文件内容 ssize_t bytesRead = zip_fread(dexFile, dexBuffer.get(), dexStat.size); if (bytesRead != dexStat.size) { LOG("Incomplete read: got %zd bytes, expected %zd", bytesRead, dexStat.size); zip_fclose(dexFile); zip_close(zipHandle); return -1; } // 可选:如果需要保存文件到本地,确保用二进制模式 std::ofstream outputFile("/data/data/my.package/classes.dex", std::ios::binary); if (outputFile.is_open()) { outputFile.write(dexBuffer.get(), dexStat.size); outputFile.close(); } // 计算完整文件的MD5 joyee::MD5 md5Calculator; md5Calculator.update(dexBuffer.get(), dexStat.size); // 这里传入实际文件大小! md5Calculator.finalize(); std::string md5Result = md5Calculator.toString(); LOG("Correct MD5 Hash: %s", md5Result.c_str()); // 如果你想用joyee::md5函数,要确保它支持二进制长度参数 // 比如加个重载:std::string md5(const char* data, size_t length); // LOG("MD5 via function: %s", joyee::md5(dexBuffer.get(), dexStat.size).c_str()); // 清理资源 zip_fclose(dexFile); zip_close(zipHandle); return 0; }
额外要注意的点
- 二进制模式必须开:处理.dex这类二进制文件时,所有读写操作都要加
std::ios::binary(或std::ofstream::binary),不然Windows/Android某些环境下会自动转换换行符,导致文件内容变了,哈希自然不对。 - 内存别漏了:你原来用
new分配了内存但没delete,长期运行会内存泄漏,用std::unique_ptr或者std::vector<char>就省心多了。 - 读取要检查完整性:一定要验证
zip_fread的返回值,确保读够了预期的字节数,不然哈希还是错的。 - Android权限问题:Android 10及以上,直接写
/data/data/my.package/可能有问题,建议用应用的私有目录(比如调用getFilesDir()拿到的路径)来保存文件。
这样应该就能得到和md5sum一致的结果了!
内容的提问来源于stack exchange,提问作者Roman Svyatnenko
相关产品推荐
相关产品推荐

