你在问一个有点奇怪的事情。如果您只想使逆向工程更难 - 那么最好只混淆代码并且不要试图隐藏您的崩溃,至少因为它:
- 使得在开发过程中调试应用程序变得更加困难
- 无法通过 Google Play 控制台从最终用户那里获取崩溃报告
- 以不可预知的方式干扰系统范围的故障报告机制和应用程序框架
如果你还想尝试一下 - 试试这个 sn-p:
#include <signal.h>
#include <stddef.h>
#include <unistd.h>
#include <sys/syscall.h>
void makeCrashesSilent() {
struct sigaction sa;
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = [] (int signo, siginfo_t*, void*) {
_exit(1);
};
int signals[] = {
SIGSEGV,
SIGBUS,
SIGFPE,
SIGABRT,
SIGILL,
SIGINT,
};
for (size_t i = 0; i < sizeof signals / sizeof signals[0]; i++) {
syscall(__NR_sigaction, signals[i], &sa, nullptr);
}
}
此函数为所有 UNIX 信号安装自定义处理程序,这些信号在通常情况下会导致本机崩溃和 logcat 中的相关转储。调用此函数一次以抑制 logcat 中的调试输出。但尽管如此,logcat 中的少量消息仍然可以检测到每次崩溃:
10-06 21:24:01.214 945-2236/? I/ActivityManager: Process com.example.sergik.test2 (pid 7682) has died: fore TOP
10-06 21:24:01.214 632-632/? I/Zygote: Process 7682 exited cleanly (1)
仅此而已。没有崩溃转储,没有额外的信息。请注意,系统可能会立即重新启动您的应用程序,因为它看不到发生崩溃,最好推迟重新启动,直到用户明确请求。同样正如我之前所说的 - 这很可能会混淆 android 运行时,尤其是在现代系统上,ART 为某些信号安装了自己的处理程序链。
所以最好专注于混淆。 AFAIK 有一些基于 LLVM 的混淆器可能适合您的需求。但是您甚至可以在没有任何额外工具的情况下开始 - 作为第一步,您可以从二进制文件中隐藏所有不必要的符号信息,只留下 JNI 所需的导出,例如通过每个 .so 文件的版本脚本:
{
global:
JNI_OnLoad; Java_*;
local:
*;
};
这样的脚本将隐藏所有导出,除了在 Java 领域使用您的代码所需的导出。