Sensor2Everything - 深入分析Android传感器数据拦截与修改技术

Sensor2Everything使用了Xposed、Dobby和原生代码注入实现了针对Android系统的传感器数据拦截与修改,通过Hook系统级传感器服务。

传感器数据流拦截

项目核心在于拦截Android系统的传感器数据流。Android传感器服务通常遵循以下路径:

硬件传感器 → 传感器驱动 → SensorService → SensorEventQueue → 应用层

Sensor2Everything通过在libsensorservice.so中Hook关键函数来截取这条数据流:

// Hook点1:传感器事件写入队列
sensorWrite = sensorService.getSymbolAddress<void*>(
    "_ZN7android16SensorEventQueue5writeERKNS_2spINS_7BitTubeEEEPK12ASensorEventm");

// Hook点2:传感器事件转换函数
convertToSensorEvent = sensorService.getSymbolAddress<void*>(
    "_ZN7android8hardware7sensors4V1_014implementation20convertToSensorEventERKNS2_5EventEP15sensors_event_t");

传感器数据结构解析

从代码中可以看到,项目处理多种传感器类型:

  • 加速度传感器 (TYPE_ACCELEROMETER = 1)

  • 陀螺仪传感器 (TYPE_GYROSCOPE = 4)

  • 地磁传感器 (TYPE_MAGNETIC_FIELD = 2)

  • 未校准传感器 (各类_uncalibrated类型)

传感器数据结构遵循Android标准定义:

typedef struct sensors_event_t {
    int32_t version;        // 结构体版本
    int32_t sensor;         // 传感器标识符
    int32_t type;           // 传感器类型
    int32_t reserved0;      // 保留字段
    int64_t timestamp;      // 时间戳(纳秒)
    union {
        float data[16];     // 传感器数据数组
        // 各类型传感器专用数据结构
        sensors_vec_t acceleration;
        sensors_vec_t magnetic;
        sensors_vec_t orientation;
        sensors_vec_t gyro;
        // ...其他类型
    };
    uint32_t flags;         // 标志位
    uint32_t reserved1[3];  // 保留字段
} sensors_event_t;

传感器数据处理

在Hook函数中,项目可以读取和修改传感器数据:

void ConvertToSensorEvent(void *src, void *dst) {
    if (enableSensorHook) {
        auto sensorType = *(int32_t *)((char*)src + 8); // 获取传感器类型
        
        // 根据不同类型处理数据
        if (sensorType == 1) { // 加速度计
            float accelX = *(float *)((char*)dst + 32);
            float accelY = *(float *)((char*)dst + 36);
            float accelZ = *(float *)((char*)dst + 40);
            // 可以在这里修改数据
        }
        else if (sensorType == 4) { // 陀螺仪
            // 处理陀螺仪数据
        }
    }
}

Xposed模块与ADB命令交互

通过Xposed模块拦截ADB shell命令:

MethodFinder.fromClass("com.android.server.input.InputShellCommand")
    .filterByName("onCommand")
    .onEach { it ->
        it.createHook {
            before {
                val cmd = it.args[0] as String
                if ("c2e" != cmd) return@before
                
                // 处理c2e命令
                val type = getNextArgRequired() as String
                when (type) {
                    "init" -> { /* 初始化hook */ }
                    "hook" -> { /* 启用hook */ }
                    "unhook" -> { /* 禁用hook */ }
                }
            }
        }
    }

Root权限管理与库加载

项目通过root权限将so库复制到系统可访问位置:

fun initC2eLibrary(context: Context): Boolean {
    if (!ShellUtils.hasRoot()) return false
    
    // 创建专用目录
    val soDir = File("/data/local/c2e-lib")
    ShellUtils.executeCommand("mkdir ${soDir.absolutePath}")
    
    // 复制库文件
    val apkSoFile = File(context.applicationInfo.nativeLibraryDir, "libcursor2everything.so")
    ShellUtils.executeCommand("cp ${apkSoFile.absolutePath} ${soFile.absolutePath}")
    
    // 设置权限
    ShellUtils.executeCommand("chmod 777 ${soFile.absolutePath}")
    return true
}

原项目:https://github.com/Party233/Sensor2Everything

这个是fork之后的仓库,原作者私有化仓库了