利用 Linux 信号机制(SIGTRAP)实现 Android 下的反调试

版权归作者所有,如有转发,请注明文章出处:cyrus-studio.github.io/blog/

利用 SIGTRAP 检测调试器

在 Linux 的进程管理中,信号(Signal) 是调试器与被调试进程沟通的核心机制。断点、单步执行、进程暂停与恢复等操作,背后都依赖于特定信号的传递。

其中,SIGTRAP (陷阱信号)尤为特殊。通常它由调试器在调试过程中触发,例如执行断点指令或单步运行时都会引发 SIGTRAP。

如果一个程序主动触发 SIGTRAP,并设置了对应的信号处理函数,就能实现一种"自检":

  • 若信号处理函数被成功调用,说明 SIGTRAP 没有被调试器截获,此时可以推断程序处于非调试状态

  • 若信号处理函数未被调用,反而被调试器捕获并消费,则意味着程序正被调试。

由此,利用 SIGTRAP 信号进行反调试检测 ,就成为 Android 应用中一种更隐蔽、更底层的安全防护手段。

常见 Linux 信号列表(基于 signal.h)

编号 名称 说明
1 SIGHUP 挂起信号,通常在控制终端关闭时发送给进程
2 SIGINT 中断信号,通常由 Ctrl+C 触发
3 SIGQUIT 退出信号,通常由 Ctrl+\ 触发,并生成 core dump
4 SIGILL 非法指令(非法 CPU 指令执行)
5 SIGTRAP 陷阱信号,主要用于调试(断点、单步)
6 SIGABRT 异常终止,通常由 abort() 触发
7 SIGBUS 总线错误(非法内存访问,例如未对齐访问)
8 SIGFPE 浮点异常(除零、溢出等算术错误)
9 SIGKILL 强制终止信号,无法被捕获或忽略
11 SIGSEGV 无效内存访问(段错误)
13 SIGPIPE 向无读端的管道写数据时触发
14 SIGALRM 定时器超时,由 alarm() 触发
15 SIGTERM 终止信号,可被捕获和处理
17 SIGCHLD 子进程状态发生变化时通知父进程
18 SIGCONT 继续执行(与 SIGSTOP 配合使用)
19 SIGSTOP 停止进程,无法被捕获或忽略
20 SIGTSTP 终端暂停信号,通常由 Ctrl+Z 触发
21 SIGTTIN 后台进程尝试从终端读输入时触发
22 SIGTTOU 后台进程尝试往终端写输出时触发
23 SIGURG socket 上的紧急数据到达
24 SIGXCPU 超过 CPU 时间限制
25 SIGXFSZ 文件大小超过限制
26 SIGVTALRM 虚拟时钟超时
27 SIGPROF profiling 定时器超时
28 SIGWINCH 窗口大小发生变化(终端调整大小)
29 SIGIO / SIGPOLL 异步 I/O 事件
30 SIGPWR 电源故障
31 SIGSYS 非法系统调用

此外,Linux 还支持 实时信号(Real-Time Signals) ,编号从 32 开始 ,具体上限依赖于系统实现(通常是 SIGRTMIN 到 SIGRTMAX),通常是用于用户自定义的信号,应用程序可根据需要使用这些信号。

Android 下利用 SIGTRAP 反调试流程

在 Android 环境中,利用 SIGTRAP 进行反调试的核心思路是:让程序主动触发 SIGTRAP,并观察信号是否能够进入我们自己定义的处理器。如果信号能被捕获,说明程序运行正常;如果信号被调试器拦截,则说明进程正处于被调试状态。

Android 下利用 SIGTRAP + 自定义 Handler 的反调试流程:

scss 复制代码
                ┌─────────────────────────────┐
                │   App 进程启动 (目标进程)   │
                └──────────────┬──────────────┘
                               │
                               ▼
                   ┌──────────────────────────┐
                   │ 注册 SIGTRAP Handler     │
                   │ sigaction(SIGTRAP, ...)  │
                   └───────────┬─────────────┘
                               │
                               ▼
                   ┌────────────────────┐
                   │ 调用 raise(SIGTRAP)│
                   └───────────┬────────┘
                               │
               ┌───────────────┼─────────────────┐
               │                                 │
   ┌───────────▼────────────┐        ┌───────────▼────────────┐
   │ 无调试器存在            │        │ 有调试器附加           │
   │ ──────────────          │        │ ──────────────         │
   │ 信号交由自定义 handler  │        │ 调试器捕获 SIGTRAP     │
   │ handler 正常执行        │        │ handler 未被调用       │
   └───────────┬────────────┘        └───────────┬────────────┘
               │                                 │
               ▼                                 ▼
       [App 判定未被调试]                [App 判定被调试]
               │                                 │
               ▼                                 ▼
 ┌───────────────────────────┐     ┌───────────────────────────┐
 │   正常运行 (继续业务逻辑) │     │ 采取对抗动作:             │
 │                           │     │  - exit() / 延时退出       │
 │                           │     │  - 触发异常崩溃           │
 │                           │     │  - 执行混淆/假逻辑        │
 └───────────────────────────┘     └───────────────────────────┘

Android 下利用 SIGTRAP 反调试实现

1. 定义信号处理器并检测调试器

首先,我们在 C 代码中编写反调试逻辑,核心是通过 raise(SIGTRAP) 触发 SIGTRAP 信号,并判断信号是否被捕获。

arduino 复制代码
#include <jni.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <android/log.h>

#define LOG_TAG "AntiDebug"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)

// 标志变量,判断 SIGTRAP 是否被捕获
volatile int sigtrap_caught = 0;

// SIGTRAP 信号处理函数
void sigtrap_handler(int sig) {
    LOGI("Caught SIGTRAP. No debugger present.");
    sigtrap_caught = 1; // 标记 SIGTRAP 被捕获
}

// JNI 方法,触发 SIGTRAP 信号并检测调试器
JNIEXPORT jboolean JNICALL
Java_com_cyrus_example_antidebug_AntiDebug_detectDebugger(JNIEnv *env, jobject instance) {
    // 注册 SIGTRAP 处理器
    signal(SIGTRAP, sigtrap_handler);

    // 触发 SIGTRAP 信号
    raise(SIGTRAP);

    // 检查信号是否被捕获
    if (sigtrap_caught) {
        LOGI("No debugger detected.");
        return JNI_FALSE; // 没有检测到调试器
    } else {
        // 如果信号未被捕获,说明有调试器
        LOGI("Debugger detected! The program will exit in 3 seconds...");
        sleep(3); // 等待 3 秒
        exit(EXIT_FAILURE); // 退出程序
        return JNI_TRUE; // 返回 true,表示检测到调试器
    }
}

配置 CMakeLists.txt 文件

perl 复制代码
cmake_minimum_required(VERSION 3.4.1)



find_library( # 查找 log 库
              log-lib

              # 库名
              log )

add_library( # 库名称
             antidebug

             # 库类型
             SHARED

             # 源文件
             anti_debug.c )

target_link_libraries( # 绑定库到 log 库
                       antidebug
                       ${log-lib} )

2. Kotlin 层调用 JNI 方法

在 Kotlin 层,我们通过 JNI 调用 detectDebugger 函数,以检测是否存在调试器。根据结果,程序可以作出不同的响应。

kotlin 复制代码
package com.cyrus.example.antidebug

import android.util.Log

object AntiDebug {

    init {
        // 加载 native 库
        System.loadLibrary("antidebug")
    }

    external fun detectDebugger(): Boolean

    fun isDebuggerDetected(): Boolean {
        val detected = detectDebugger()
        if (detected) {
            Log.i("AntiDebug", "Debugger detected!")
        } else {
            Log.i("AntiDebug", "No debugger detected.")
        }
        return detected
    }
}

3. 调用反调试功能

kotlin 复制代码
val debuggerDetected = AntiDebug.isDebuggerDetected()
if (debuggerDetected) {
    Toast.makeText(this, "Debugger Detected", Toast.LENGTH_SHORT).show()
} else {
    Toast.makeText(this, "No Debugger Detected", Toast.LENGTH_SHORT).show()
}

测试反调试

1. 无调试状态

无调式状态 App 中点击 "SIGTRAP 反调试" 按钮调用反调试功能,未检测到调试器,程序正常运行。

2. 调试状态下

通过 IDA Pro 附加到当前应用

相关文章:静态分析根本不够!IDA Pro 动态调试 Android 应用的完整实战

App 中点击 "SIGTRAP 反调试" 按钮调用反调试功能,SIGTRAP 信号 被 IDA Pro 调试器捕获。

触发程序反调试机制,程序在 3 秒后退出。

完整源码

开源地址:github.com/CYRUS-STUDI...

相关推荐
Android-Flutter36 分钟前
android 动画详解
android·kotlin
Bruce_Liuxiaowei1 小时前
基于微步在线威胁情报的公网 IP 攻击迹象监测:threatbook_query 脚本全解析与 BruceSec 平台整合实践
数据库·tcp/ip·安全·网络安全·智能体
ZJU_统一阿萨姆1 小时前
【DSH】如何将 DeepSeek Harness 嵌入生产环境?万字解构 DeepSeek Agent Harness 的运行机制与安全边界
前端·javascript·安全
明航咨询_贾老师1 小时前
CISP-AISE知识体系大纲深度解读:6大模块,国内首个AI安全应用官方认证
人工智能·安全
40岁资深老架构师尼恩2 小时前
工业级 AI问数 AST语法 + 知识图谱语义+ 质量规则 三层安全校验 架构设计与实现
人工智能·安全·知识图谱
数智大号4 小时前
从“芯“出发,筑牢文印安全防线——联想至像以全链路自主可控回应国家安全之问
arm开发·安全
小新讲网安4 小时前
安全运营中心(SOC)建设实战:从SIEM到威胁狩猎全流程指南
网络·安全·web安全·网络安全·网安
愚公搬代码5 小时前
【愚公系列】《Web应用安全》001-VMware的安装
前端·安全
anscos5 小时前
案例分享| Latitude AI × Parasoft:搭建 L2-L3 自动驾驶量产验证与功能安全完整链路
人工智能·安全·自动驾驶
小孔龙6 小时前
GraphicBuffer 跨进程共享
android