有一个安全实践说你不应该在启用调试模式的情况下发布你的 android 应用程序。
虽然攻击者可以使用 apktool 反编译您的应用程序,启用 AndroidManifest.xml 中的调试标志并重新编译它,但不以调试模式发布您的应用程序实际上有什么帮助?
它是否应该与反反编译技术相结合才能有用?
如果有的话,在调试模式下的应用程序中放入了哪些额外信息,当您以后反编译并启用调试标志时您将无法访问这些信息?
有一个安全实践说你不应该在启用调试模式的情况下发布你的 android 应用程序。
虽然攻击者可以使用 apktool 反编译您的应用程序,启用 AndroidManifest.xml 中的调试标志并重新编译它,但不以调试模式发布您的应用程序实际上有什么帮助?
它是否应该与反反编译技术相结合才能有用?
如果有的话,在调试模式下的应用程序中放入了哪些额外信息,当您以后反编译并启用调试标志时您将无法访问这些信息?
这可能与您不想发布带有-g标志的 C/C++ 程序的原因相同。不必要的符号可能会被剥离或混淆。构建系统可能会遗漏某些安全措施,这些措施将使调试应用程序变得更加容易。Pro-guard 构建脚本可能不包含在调试构建中。
以下是可以根据配置保存在调试版本中的不同类型的数据。希望您能明白为什么这些对希望对您的应用程序进行逆向工程的人有所帮助。
调试符号
调试符号是存储在调试二进制文件中的选定信息片段。所有函数名、文件名,有时甚至包括行号。这样当程序崩溃并附加调试器时,所有这些信息都可以包含在堆栈跟踪中。它允许程序员查明导致错误的代码行。调试堆栈跟踪可能如下所示(取自此答案):
Exception in thread "main" java.lang.NullPointerException
at com.example.myproject.Book.getTitle(Book.java:16)
at com.example.myproject.Author.getBookTitles(Author.java:25)
at com.example.myproject.Bootstrap.main(Bootstrap.java:14)
没有调试符号的程序只会知道库定义。如下所示:
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff7fd3700 (LWP 22532)]0x00007fffe10002b4 in ?? ()
(gdb) bt
#0 0x00007fffe10002b4 in ?? ()
#1 0x0000000000000202 in ?? ()
#2 0x00007fffe1000160 in ?? ()
#3 0x00007ffff66bd1a9 in execute_internal_vm_tests () at /home/bionix/Openjdk8/hotspot/src/share/vm/prims/jni.cpp:5128
#4 0x00007ffff7fd2550 in ?? ()
#5 0x00007ffff6b08bf8 in VM_Version::get_cpu_info_wrapper () at /home/bionix/Openjdk8/hotspot/src/cpu/x86/vm/vm_version_x86.cpp:395
Backtrace stopped: previous frame inner to this frame (corrupt stack?)
在 Android 构建脚本 (Gradle) 中,您会找到对 ProGuard 的引用。ProGuard 用于优化、减少二进制大小和混淆代码。因为 Java 可以完全反编译 Android 使用 ProGuard 来混淆代码。下面是一个使用 ProGruard 混淆的代码示例:
// Before
btnNew = changeButtonLabel(btnNew, language.getText("new"));
btnOpen = changeButtonLabel(btnOpen, language.getText("open"));
// After
d = a(d, n.a("new"));
e = a(e, n.a("open"));
您可以查看包含源代码链接的完整教程。
从上面链接的 Android 文档中:
ProGuard 已集成到 Android 构建系统中,因此您不必手动调用它。ProGuard 仅在您以发布模式构建应用程序时运行,因此当您以调试模式构建应用程序时,您不必处理混淆代码。
ProGuard 在技术上是可选的,但在使用 Android Studio 时,它默认为 Release 构建启用。
调试日志
你的代码中应该总是有一些机制来从你的发布应用程序中删除调试消息。调试消息在二进制文件中存储为字符串,并且不会被混淆。这意味着,如果您有消息,例如Log.d("Key " + super_secrey_key);分析二进制文件的人现在将知道"Key "引用的位置。您现在已经提供了上下文,以及开始分析的有趣位置。
有几种方法可以删除调试日志,其中之一是通过配置 ProGuard 为您删除它们。也有其他库,你可以用,也可以换你的日志。无论哪种方式,区分日志消息的调试和发布都很重要。
您不希望对您的应用程序进行逆向工程太容易。特别是如果它包含敏感数据,例如后端密码或私钥材料。我同意一个应用程序不应该包含这样的秘密,如果它是安全的,但现实有时是困难的。
你提到过:
虽然攻击者可以使用 apktool 反编译您的应用程序,启用 AndroidManifest.xml 中的调试标志并重新编译它,但不以调试模式发布您的应用程序实际上有什么帮助?
如果您的应用程序有适当的防篡改措施(例如,检查其自身的完整性),攻击者可能无法逃脱这样做。
因此,如果您在禁用调试模式的情况下发布应用程序,他们将无法在调试模式下运行应用程序,除非他们也可以破坏您的防篡改措施。