【 2 - 人脸视频流注入攻防全史:AI时代人脸对抗,我们如何应对?】此文章归类为: 2 。
在AI时代,黑产攻防的边界正在被“生成式技术”彻底重构。 过去,我们对抗的是粗糙的视频重放和系统篡改;现在,随着 LivePortrait、SadTalker 等 AIGC 技术的开源,黑产已能通过单张照片实时生成配合指令的“活体视频”。当“眼见不再为实”,当注入攻击结合了 AI 的即时生成能力,传统的特征防御防线正面临降维打击。这篇文章,不仅是对过去攻防技术的复盘,更是为了在 AIGC 洪流中,构建一套基于“行为逻辑”与“物理约束”的全新防御体系。
随着人脸场景的摄像头视频流注入的对抗升级,早期我们还可以从“攻防视角”入手:看进程里有没有可疑 so、有没有 hook 点、有没有异常权限、有没有典型注入链路等。一直升级到现阶段:攻击不发生在 App 进程内,甚至会配合 BL 解锁绕过、Root 隐藏、环境伪装 等手段,把传统的检测点绕开。这样一来,单纯依赖进程/系统属性/运行环境去判断“有没有注入”,会越来越不稳、成本越来越高、误报也越来越多。于是引发了一个思考:
为什么要从“攻防识别”转向“行为检测”?
本文将深度复盘人脸视频流注入攻防的完整演进史——从早期的 App 进程内 Hook,演进至如今隐蔽性极高的系统级(CameraServer/定制 ROM)注入。面对传统“特征检测”手段的失效,文章重点阐述了人脸对抗的“下半场”策略:构建基于“多维行为一致性”的防御体系。我们将详细拆解如何利用传感器(IMU)协同、光学主动干扰(白平衡/曝光)、时空动态挑战(随机相框)以及时序特征(循环/拼接检测)来逼迫伪造流露出破绽,旨在为“系统级注入时代”提供一套可落地、可运营的系统化解决方案。
摄像头数据流程整体链路概要,便于理解后面的注入点和检测点:
Camera1(旧 API):
Camera.open → 设置 setPreviewCallback && setPreviewDisplay(Surface) → startPreviewPreviewCallback#onPreviewFrame 回调到应用(常见格式 NV21/YUV)Camera2(新 API):
CameraManager#openCamera → CameraDevice 回调 onOpenedCaptureRequest,通过 createCaptureSession 绑定输出 SurfaceImageReader(常见格式 NV21/YUV)和 Surface(直接预览渲染)对应关键链路(Android 13):
ICameraDevice.open(callback):打开设备,返回 ICameraDeviceSessionICameraDeviceSession.configureStreams():配置预览/拍照输出流ICameraDeviceSession.processCaptureRequest():提交请求ICameraDeviceCallback.processCaptureResult():回传预览帧与 metadata(核心回调,驱动 Camera2 的 CameraCaptureSession/ImageReader;Camera1 场景下间接转成 onPreviewFrame)上述流程是通用的链路说明。下面开始分析这条链路在过去几年是如何被逐步注入的。
整体可以分为四个阶段:
最早一批手法比较直接:直接分析app的代码逻辑,在找到人脸的关键函数以后,替换入参或者返回值,修改相机返回的数据。
这类方案特征:
对应的防守思路:
注入目标:CameraService → App回调(PreviewCallback或ImageReader)这段链路。
在第一阶段以后,黑产进化为在应用进程里对 PreviewCallback#onPreviewFrame 的回调做 Hook,把原本来自摄像头(经过系统服务转发)的帧数据替换为伪造/重放的内容。
这类方案的特征是:
对应的防守思路:
只要把本进程的摄像头调用链路梳理清楚,对关键方法与关键路径做完整性校验,就能覆盖大多数场景。
尤其是 Java 方法的 Hook,本质上绕不开“入口被改写/调用被劫持”的痕迹:
只要做了足够的进程内链路校验,通常都能发现异常。
原理概述:
setPreviewTexture/setPreviewDisplay 的目标 Surface,startPreview 时用 MediaPlayer 播放 virtual.mp4;同时 hook PreviewCallback#onPreviewFrame,把解码出的 NV21 数据写回回调 buffer。c2_virtual_surface),将 CaptureRequest 的目标改写为该 Surface;保留原 preview/ImageReader Surface,并用 MediaPlayer/VideoToFrames 把 virtual.mp4 推送到对应 Surface。onPictureTaken,把 YUV/JPEG 数据替换为本地 1000.bmp 转换结果,确保“拍照”也被伪造。关键 hook 方法:
android.hardware.Camera#setPreviewTexture、setPreviewDisplay、startPreviewandroid.hardware.Camera#setPreviewCallbackWithBuffer、setPreviewCallback、setOneShotPreviewCallback、addCallbackBuffer、android.hardware.Camera.PreviewCallback#onPreviewFrameandroid.hardware.Camera#takePicture、android.hardware.Camera.PictureCallback#onPictureTakenandroid.hardware.camera2.CameraManager#openCamera(两种重载)、android.hardware.camera2.CameraDevice.StateCallback#onOpened、android.hardware.camera2.CameraDevice#createCaptureSession*android.hardware.camera2.CaptureRequest.Builder#addTarget/removeTarget/build、android.media.ImageReader#newInstance、android.hardware.camera2.CameraCaptureSession.StateCallback#onConfigured/onConfigureFailed/onClosed核心思路就是检测app进程内的方法是否被hook,具体展开见基础检测章节
由于摄像头链路很长,除驱动层代码闭源无法修改外,其余层级的定制 ROM 都可以改,所以检测思路从 App 进程内注入转向自定义 ROM 识别:系统识别到风险 ROM 后,直接阻断人脸识别等高风险业务,达到拦截目的。
自定义 ROM 常见两类:
常见的自定义 ROM 检测思路:
/proc/cpuinfo 与 /sys/devices/system/cpu,核数/频率等应一致。自定义 ROM 的识别强依赖端云协同:端上只做基础数据采集,服务端做归一化与模型学习,沉淀机型环境指纹,多特征不匹配直接拉黑。本节不展开实现细节,重点是服务端的数据验证能力,客户端做到在隐私合规的情况下应采尽采即可精准识别定制ROM。
随着对抗升级,自定义ROM的漏洞太多,magisk及zygisk的root解决方案让系统进程注入更加方便,所以注入点开始从 App 进程下沉到 cameraserver / CameraService 的结果回传链路。典型思路是围绕 processCaptureResult 及其前后接口做注入,直接在系统进程替换视频流。
再配合环境伪装手段(例如 Root/BL 相关模块隐藏),系统进程的注入app无法检测,手机root被隐藏也无法检测。
但这种方案往往适配android10-13版本。
因为在Android 14,cameraserver的构建形态发生变化,绝大多数逻辑都inline到了cameraserver本身,不再动态加载so,导致这种方案大部分只适配10-13。
核心原理:
基于 frida 注入 cameraserver,在 libcameraservice.so 和回调链路里做关键拦截与 buffer 改写,核心实现要点如下:
libcameraservice.so 导出符号,定位 processCaptureResult(不同版本符号名可能带版本后缀)。Interceptor.attach(processCaptureResult),解析 CaptureResult 的 frame_number/metadata/output_buffers,对输出 buffer改写,实现画面替换/重放。核心流程:找到 processCaptureResult → 解析 camera3_capture_result_t → 遍历 output_buffers 找到 buffer_handle → lockYCbCr 改写buffer(mp4到nv21数据用ffmpg库即可,此处不展开) → unlock。
函数与符号对应关系(GBM 相关):
GraphicBufferMapper::getInstance → _ZN7android9SingletonINS_19GraphicBufferMapperEE11getInstanceEvGraphicBufferMapper::lockYCbCr → _ZN7android19GraphicBufferMapper9lockYCbCrEPK13native_handlejRKNS_4RectEP13android_ycbcrGraphicBufferMapper::unlock → _ZN7android19GraphicBufferMapper6unlockEPK13native_handle核心代码片段:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | // 1) hook processCaptureResult,读取输出 buffer 列表const SYM = "_ZN7android7camera320processCaptureResultERNS0_19CaptureOutputStatesEPK22camera3_capture_result";const addr = Module.findGlobalExportByName(SYM);// OFF: camera3_capture_result_t 的字段偏移(按 32/64 位区分)从源码找// frame = frame_number, num = num_output_buffers, out = output_buffersconst OFF = (Process.pointerSize === 8) ? { frame: 0x0, num: 0x10, out: 0x18 } : { frame: 0x0, num: 0x08, out: 0x0c };// SB: camera3_stream_buffer_t 的字段偏移与结构体大小从源码找// stream = camera3_stream_t*, buffer = buffer_handle_t*const SB = (Process.pointerSize === 8) ? { size: 0x30, stream: 0x00, buffer: 0x08 } : { size: 0x1c, stream: 0x00, buffer: 0x04 };Interceptor.attach(addr, { onEnter: function (args) { const res = args[1]; const frame = res.add(OFF.frame).readU32(); const num = res.add(OFF.num).readU32(); const out = res.add(OFF.out).readPointer(); for (let i = 0; i < num; i++) { const sb = out.add(i * SB.size); const stream = sb.add(SB.stream).readPointer(); const handle = sb.add(SB.buffer).readPointer(); if (stream.isNull() || handle.isNull()) continue; const w = stream.add(0x4).readU32(); const h = stream.add(0x8).readU32();lockAndModifyYCbCr(handle, w, h); } }}); |
1 2 3 4 5 6 7 8 | // 2) lockAndModifyYCbCr 通过 GraphicBufferMapper::lockYCbCr 改写 Y plane// gbmLockYCbCrFn/gbmUnlockFn 来自 libui.so 的符号解析const ycbcr = Memory.alloc(0x40);if (gbmLockYCbCrFn(gGbm, handlePtr, usage, rect, ycbcr) === 0) { const yPtr = ycbcr.readPointer(); Memory.writeU8(yPtr.add(0), 0x80); // 示例:改写一个像素 gbmUnlockFn(gGbm, handlePtr);} |
对应的防守思路:
当端侧无注入暴露的时候,机器和人终究不同,所以行为检测显得尤为重要,具体思路见后续的行为检测章节
如何检测虚拟相机:
1.0版本会暴露出一个特殊的系统服务,扫描即可。
2.0版本,系统服务做了随机化,也能识别,但这种方式终究是有局限性的,开发者完全可以做到全隐藏。
在转向"行为检测"之前,业界普遍采用的是"基础检测"方案,这些方案看似简单直接,但在黑产对抗下逐渐失效。本节深入分析这些基础防护的原理、局限与对抗。
这是对分析app侧逻辑,替换相机返回后的数据的直接防守。核心思想是:对"摄像头数据→人脸识别服务器"这个链路加入完整性标记。
实现思路:
App 每次收到每一桢回调时:
但这种方式对后面阶段的手法都无法生效,后面阶段进阶为在app收到帧数据之前替换
目前java层注入主要分为frida派和xposed派,核心流程如下:
ArtMethod 的入口指针,把方法跳转到 trampoline/stub,再转去自定义逻辑。/proc/self/maps 判断是否落在可信代码段(如oat/odex、libart)。思路分析:
Throwable 两个构造方法的地址差推算 ArtMethod 大小,进而推断 entry_point_offset/data_offset(Android M+)。ArtField 反射读出 entryPointFromQuickCompiledCode/entryPointFromInterpreter/entryPointFromJni 的精确偏移。SetEntryPoint/GetEntryPoint 里按偏移读写入口点指针。核心代码源码:
1 2 3 4 5 6 7 8 9 | // 反射拿 ArtMethod* 指针static art::ArtMethod *FromReflectedMethod(JNIEnv *env, jobject method) { if (art_method_field) [[likely]] { return reinterpret_cast<art::ArtMethod *>( JNI_GetLongField(env, method, art_method_field)); } else { return reinterpret_cast<art::ArtMethod *>(env->FromReflectedMethod(method)); }} |
1 2 3 4 5 6 7 8 9 | // 用两个构造方法地址差推算 ArtMethod 大小(M+)auto first_ctor = constructors[0];auto second_ctor = constructors[1];auto *first = FromReflectedMethod(env, first_ctor.get());auto *second = FromReflectedMethod(env, second_ctor.get());art_method_size = reinterpret_cast<uintptr_t>(second) - reinterpret_cast<uintptr_t>(first);entry_point_offset = art_method_size - kPointerSize;data_offset = entry_point_offset - kPointerSize; |
1 2 3 4 5 6 7 8 | // L 系列:通过 ArtField 反射直接拿偏移if (sdk_int == __ANDROID_API_L__) { entry_point_offset = get_offset_from_art_method("entryPointFromQuickCompiledCode", "J"); interpreter_entry_point_offset = get_offset_from_art_method("entryPointFromInterpreter", "J"); data_offset = get_offset_from_art_method("entryPointFromJni", "J");} |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | // 入口点读写void SetEntryPoint(void *entry_point) { *reinterpret_cast<void **>(reinterpret_cast<uintptr_t>(this) + entry_point_offset) = entry_point; if (interpreter_entry_point_offset) [[unlikely]] { *reinterpret_cast<void **>(reinterpret_cast<uintptr_t>(this) + interpreter_entry_point_offset) = reinterpret_cast<void *>(&art_interpreter_to_compiled_code_bridge_); }}void *GetEntryPoint() { return *reinterpret_cast<void **>(reinterpret_cast<uintptr_t>(this) + entry_point_offset);} |
端侧以 RGB 不同颜色按既定(随机)时序进行主动补光并同步采集多帧图像,算法在对应帧中提取人脸区域的颜色/光谱响应特征及其时域一致性(如通道比例变化、局部反射分布、阴影与高光随光序列的同步变化等)。服务端依据光序列标识与帧时间对齐进行校验,从而判别是否为真实人脸对主动光挑战的响应。
实现思路:
黑产对抗:
如何再对抗:
交互式活体属于典型的挑战应答(Challenge-Response):系统在识别过程中随机下发动作指令(如眨眼、张嘴、点头/摇头、看向指定方向等),端侧在限定时间窗内采集连续帧并检测动作是否发生、是否按指令顺序完成、时序是否匹配、运动模式是否符合真实人脸。服务端(或端侧)基于“指令序列标识 + 帧时间戳对齐 + 动作检测结果”进行一致性校验,从而对抗静态照片/静态帧注入与部分重放攻击。
核心思路:
实现思路:
下发随机指令序列:从动作集合中随机抽取(可随机顺序/随机次数/随机时间窗),例如“眨眼 → 张嘴 → 点头”。
端侧引导与采集:在 UI 上提示用户执行动作,同时采集连续帧并记录关键时间点(指令开始/结束、每帧时间戳)。
动作检测与打分:对每个动作提取特征(如眼部 EAR 变化检测眨眼、嘴部开合比例检测张嘴、头姿 yaw/pitch 变化检测转头/点头),并输出动作完成度与时序一致性分数。
结果上报:上报指令序列 ID、每步动作检测结果、关键帧/摘要特征及时间戳,用于服务端按序列校验(或端侧本地判定后仅上报结论)。
黑产对抗:
-黑产提前准备点头,眨眼等动作,在界面弹出动作指令时,切换对应视频,从而进行绕过。
| 防护方式 | 特点 | 主要弱点 |
|---|---|---|
| 链路标记校验 | 在 NV21 buffer 加标记,检查是否被篡改 | 只防 App 进程内注入;标记可复用;无法证明来源 |
| 炫彩 | 依赖光学特性位移 | 可被人工合成;无机型源头校验 |
| Hook 检测 | 检测内存中是否存在 Xposed/Frida 等注入框架的痕迹 | 无法应对系统进程的注入 |
根本原因:上述防护都是"本地生成、本地验证"的模式,攻击者只要能:
换句话说,黑产通常比防守更早知道防守的底线是什么。
基础防护的共同缺陷:可预测、可重放、无源头校验。
而"行为检测"的优势:
因此,接下来的第 3 章将详细展开"行为检测"的实现思路,这是当前对抗注入流最有效的方案。
本文方案从以下维度判断“视频是否像真实摄像头那样响应世界变化”:
最终建议采用 多因子打分,减少误报。误报是每个产品的痛点——每天前台就追着问"为什么有误报",因为误报直接吃投诉。通过多个维度的联合判断,既能提高检测精准度,又能控制误报率。
核心思路:通过动作下发引导用户手机左右反转,同时采集两份数据流:
原理:
实现细节:
整个过程分为三个阶段:
(1) 动作挑战下发
(2) 多源数据采集
(3) 多维度一致性验证
(4) 异常判定规则
防护优势:
核心思路:系统主动修改摄像头的白平衡(改变色温)和曝光补偿(改变亮度),观察捕捉到的画面是否实时发生了对应的颜色和亮度变化。真实摄像头会立即反映这些参数的变化,伪造视频则无法做出这种实时响应。
原理:
真实摄像头的响应机制:
伪造视频的致命弱点:
实现细节:
(1) 参数修改
params.setWhiteBalance(Camera.Parameters.WHITE_BALANCE_DAYLIGHT) 偏蓝 / WHITE_BALANCE_INCANDESCENT 偏红params.setExposureCompensation(value) value可以通过getMaxExposureCompensation()获取,让画面全白,再人脸识别结束设置,不影响用户体验(2) 画面变化捕捉
(3) 真实性验证
(4) 伪造视频的检测特征
防护优势:
踩坑点:
必须先通过光线传感器获取当前环境光,低环境光下此功能点有误报情况,基于此如果在弱光环境下但是采集到的人脸背景不符合弱光特征,也可以证明有视频注入
核心思路:在"时间维度"(4.1、4.2)和"空间维度"(本节)都对用户施加随机、不可预知的挑战,要求视频流能够自然响应这些挑战。随机相框通过在屏幕上生成随机移动的取景框,要求用户将人脸移入框内或跟随框移动,同时验证人脸与框的空间关系是否自然和连贯。
原理:
真实人脸对空间挑战的响应:
伪造视频的弱点:
实现细节:
(1) 随机相框轨迹生成
(2) 人脸与框的对齐度量化
(3) 对齐度动态的真实性验证
(4) 伪造的检测特征
防护优势:
踩坑点:
核心思路:黑产的一个常见做法是循环播放录制的视频,以降低成本。虽然循环播放看起来是连贯的,但在计算机视觉的帧级别分析上会暴露出周期性的重复。通过检测这种周期性,可以识别出重放视频。
原理:
循环视频的特征:
真实视频的特征:
实现细节:
(1) 多维特征提取
每一帧提取多个维度的特征,用于周期性检测:
(2) 周期性检测算法
(3) 特征相似度计算(加权融合)
防护优势:
踩坑点:
核心思路:攻击者在某些场景下可能不是一直播放同一个循环视频,而是根据不同的检测阶段手动切换或动态拼接不同的视频段。例如:
原理:
真实视频的连续性特征:
视频切换的弱点:
实现细节:
(1) 人脸生物指纹提取
从人脸图像中提取难以伪造的稳定特征:
(2) 相邻帧连续性检测
(3) 时间序列异常检测
(4) 元数据交叉验证
(5) 切换点的特征
防护优势:
踩坑点:
前面 4 章我们分别给出了 5 类“物理约束证据”。真正上线时,不要押宝于某一个维度稳定:弱光、抖动、遮挡、低端机 ISP、掉帧都会让单点策略误报/漏报。
因此最终方案必须满足两点:
本章给出一套可以工程落地的融合框架参考实现:
“每维打分 + 质量门控 + 加权 log-odds 融合 + 业务分流”。
五个维度分别输出统一结构,便于做融合与线上排障:
每个维度输出:
score_i ∈ [0, 1]:异常程度(越大越像 Fake)quality_i ∈ [0, 1]:该维度当前是否可信(弱光/遮挡/掉帧/抖动会降低)meta_i:诊断字段(用于解释与复盘,例如:相关系数、时延、周期长度、突变点等)工程建议:每个维度都要输出
quality_i及结合本身业务埋点,用于线上排障,可以感知误报原因
把每个维度理解成提供一条证据,证据强度用似然比(Likelihood Ratio, LR)表达最方便:
LR_i(score_i):该分数在 Fake 上出现的相对概率 / 在 Real 上出现的相对概率直接把 LR 连乘会遇到两个典型线上问题:
工程上更稳的做法:把所有证据转到 log-odds 空间加权相加。
先验风险 P0(可按业务/地区/黑名单等级设置,默认可用 0.1~0.2):
1 2 3 4 5 | logit(P0) = ln(P0 / (1 - P0))logit(P) = logit(P0) + Σ [ w_i * quality_i * log(LR_i(score_i)) ]P = 1 / (1 + exp(-logit(P))) |
参数说明:
w_i:该维度权重(处理“相关性/重复计票”的关键旋钮,也是你最重要的调参点)quality_i:质量门控,质量差时让该维度降低权重上线后需要时间采集足够数据拟合完整分布。所以可以用分桶查表:
score_i 划分为 5~10 个桶(例如 0-0.1, 0.1-0.2 ...) p_fake_bin = P(score 落在该桶 | Fake) p_real_bin = P(score 落在该桶 | Real)logLR_bin = ln( (p_fake_bin + eps) / (p_real_bin + eps) )线上运行时:
score_i → 找到桶 → 取 logLR_bin五个维度并非独立,典型相关组:
{D1 IMU, D3 相框}:都与用户动作强相关 {D4 循环, D5 连续性}:重放/拼接常同时异常 {D2 光学} 在弱光/ISP 剧烈调整时可能与 D4/D5 同步波动工程上至少做一种处理(推荐 A + B):
w_i w4, w5 不要都很大,否则重放时会“重复计分,4和5算法原理其实类似,容易一起误报”把相关维度组先聚合再进入融合:
1 2 | E_loop = max( logLR4, logLR5 ) // 重放/拼接组E_motion = max( logLR1, logLR3 ) // 动作一致性组(可选) |
然后:
1 2 3 4 | logit(P) = logit(P0) + w_loop * q_loop * E_loop + w_motion * q_motion * E_motion + w_light * q2 * logLR2 |
不要用“≥2维/≥3维异常”这种硬规则,就无法动态适应了,(此处有吐槽,很多产品白皮书所谓的设备指纹模型,相似度算法,最后往往还是强因子做决策)。
建议以 后验概率 P + 强证据触发 来分流:
满足任一即可 REJECT:
P ≥ 0.95 且存在任一维度 logLR_i ≥ T_strongE_loop ≥ T_loop_strong好处:攻击很“硬”的时候,不需要凑齐 2/3 个维度,也能稳定拦截。
P ≥ 0.85 且 有效证据数 ≥ 2 quality_i ≥ q_min 且 logLR_i 超过最小阈值0.60 ≤ P < 0.85 → UNCERTAIN(触发二次验证)二次验证建议谨慎,会影响用户体验,可以进入人工复核,后置处理,或者本次登陆降权,关键业务辅助其他验证:
P < 0.60 → ACCEPT登录/实名/支付/提额等业务的误拒成本不同,建议按业务线配置
P0与阈值。
融合想稳,必须根据不同环境给予不同权重,例如:
工程实现建议:
quality_i “需要线上数据支持后再打分”,让其是具有可解释的最小值/乘积 meta_i 带上 quality 下降原因(便于线上排障)融合能不能长期稳定,取决于监控与回归:
score_i 分布漂移都需要关注建议上线策略:
UNCERTAIN(只做二次验证,不直拒)→ 稳定后再开 REJECT攻击者要骗过的不再是“某个检测点”,而是一系列联动:
并且融合层通过 权重/组内聚合 限制“重复计票”,既保证对攻击敏感,又能把误报压住。
技术解决不了100%的问题,一个良好的运营策略,配合业务场景,才能让人脸场景的成本降到最低,对于用户画像良好的账户,出现一次异常,应该谨慎看待是误报还是注入,现阶段的黑产对抗,不是单一点的对抗,是看谁家对用户画像画的足够精准。
这就是"魔法打败魔法"——用算法对抗算法,用模型对抗模型。
如果说前四个阶段(Hook/ROM/注入)是**"系统级"的对抗,那么接下来的第五阶段,我们将进入"模型级"的博弈——即AIGC(生成式AI)与鉴伪AI的直接碰撞**。
目前的注入攻击多依赖“预录制视频”,在交互式挑战(如:随机相框、炫彩)面前容易露馅。但未来的威胁在于 “实时 AIGC 渲染”:
Challenge 信号,直接喂给 AI 模型生成对应的 Response 视频流。面对生成的完美图像,传统的 CV 算法(如 LBP、直方图)可能失效,我们需要用魔法打败魔法:
软件层面的“图灵测试”总有被绕过的一天。在 AI 攻防的尽头,信任锚点必须下沉:
这里的实现仅为抛砖引玉,涉及到图像深层次处理的模型或者算法仅基于个人能力实现,所以具体用到的模型及算法未展开讲究。大家如果有更合适的模型或者算法适用于这几个场景,希望大家评论区指正和分享经验,大家一起讨论,共同进步!
LSPlant
469K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6x3f1#2m8G2M7$3g2V1i4K6u0r3e0q4y4b7L8r3q4F1N6l9`.`.
LSPosed
d15K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6x3f1#2m8G2M7$3g2V1i4K6u0r3e0q4y4b7L8%4y4W2k6l9`.`.
Frida
b94K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6X3M7X3W2V1j5g2)9J5c8X3k6J5K9h3c8S2
android_virtual_cam
fa0K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6%4x3U0l9I4y4U0f1$3x3e0f1K6y4W2)9J5c8X3q4F1k6s2u0G2K9h3c8Q4y4h3k6$3K9i4u0@1N6h3q4D9i4K6g2X3j5$3q4E0
OpenCV
345K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6G2M7r3g2F1j5%4k6Q4x3V1k6G2M7r3g2F1j5%4j5`.
更多【
2
- 人脸视频流注入攻防全史:AI时代人脸对抗,我们如何应对?】相关视频教程:www.yxfzedu.com