虚拟摄像头/无人直播效果分析,可替抖音/微信

虚拟摄像头/无人直播效果分析,可替抖音/微信

一、可实现方案

VCAM + Magisk + Lsposed

android_virtual_cam 基于 Xposed 的虚拟摄像头,采用 hook 方式去勾住系统 Camera 相关 API,然后读取本地指定视频文件进行替换

Magisk 用于 root 系统,刷入系统 boot.img,然后再安装 Riru 和 LSPosed 模块

Riru 模块

LSPosed 模块

二、效果图

三、实现过程和难点

难点一、Magisk 预装并烧写完成替换 boot

熟悉 Magisk 的伙计都知道,要想成功刷入修补后 boot.img ,需要将设备解锁才行。

以前我的认知都是解锁需要重启进入 BootLoader 模式配合音量键操作才能成功,这样如果

批量生产这种需要默认解锁的特殊设备岂不是要麻烦到家了。后来仔细阅读了 lk 源码,发现

MTK 已经考虑到这种情况了,提供两特殊宏 MTK_BUILD_DEFAULT_UNLOCK 和 MTK_SECURITY_SW_SUPPORT

将其打开后再次编译烧写设备已经是解锁状态,这样就省去了手动解锁麻烦。

配置路径 vendor/mediatek/proprietary/bootable/bootloader/lk/project/xxxx.mk

vendor\mediatek\proprietary\bootable\bootloader\lk\platform\common\boot\avb20\load_vfy_boot.c

int load_vfy_boot(uint32_t bootimg_type, uint32_t addr)

{

#ifdef MTK_SEC_FASTBOOT_UNLOCK_SUPPORT

#if defined(MTK_DM_VERITY_OFF) || defined(MTK_BUILD_DEFAULT_UNLOCK) || !defined(MTK_SECURITY_SW_SUPPORT)

/* This feature is for test purpose only.

* we unlock device without wiping userdata, which should not

* happen for MP product. We do this because after userdata

* has been wiped, Android will fail to mount userdata and reboot

* to recovery to format userdata, and then reboot. If we always

* wipe userdata in boot process, Android will never get a properly

* formatted userdata.

*/

#ifdef MTK_SECURITY_SW_SUPPORT

/* unlock device */

if (sec_set_device_lock(0) != 0) {

ret = ERR_AVB_UNLOCK_DEVICE_FAILED;

goto end;

}

#endif

解锁后开机时间明显变长了且主屏幕有警告文字提示,这很明显是需要我们避免的。

vendor/mediatek/proprietary/bootable/bootloader/lk/platform/common/boot/vboot_state.c

+ /*video_set_cursor(video_get_rows() / 2, 0);

video_printf("Orange State\n\n");

video_printf("Your device has been unlocked and can't be trusted\n");

video_printf("Your device will boot in 5 seconds\n");

mtk_wdt_restart();

+ mdelay(5000);*/

mtk_wdt_restart();

虽然这样处理系统后,烧写开机还是免不了要做一次修补提取 boot.img 操作,然后就可以再次直接刷入提取 boot

重启后 Magsik 可正常工作。对于最终要发放系统版本,发放人员可这样操作,先刷机后开机进行修补提取 boot.img,

将修补后 boot 替换原来编译后 boot, 整个刷机包就是最终烧写固件。

难点二、Magsik 安装依赖模块 Riru 和 LSPosed 需要再次重启

Magisk 成功安装后,底部会多出 4 按钮菜单

传统做法手动点击模块按钮,跳转安装页面,从手机 sdcard 下选择预制的 Riruxxx.zip LSPosedxxx.zip

模块的安装顺序必须先 riru 然后再 lsposed,这样操作起来又是更麻烦。好在 Magisk 是开源的,那我们就来自己定制一个

Magisk,实现自动安装模块。源码下载编译可参考之前写的 Magisk 最新版本 V24.1 源码编译踩坑集锦

编译成功后来修改代码吧,虽然是 kotlin 问题不大,盘它。修改思路如下

1、先判断是否成功安装 Magsik,没安装自动跳转然后直接安装

刷机完修补后的boot,开机后需要选推荐安装一次 Magisk 才能正常使用(底部工具栏)

2、安装成功后拷贝 assert 目录下的 riru.zip 和 LSPosed.zip 到 sdcard 根目录

3、跳转安装模块界面先安装 riru 模块,再安装 LSPosed 模块,安装成功重启

这部分的逻辑比较简单就不贴了,直接放个最终的 Magisk.apk

难点三、高版本预装 APK 可卸载

之前也写过参考这篇 android11.0® data分区节点加密控制分析

修改

system/core/init/util.cpp

system/core/rootdir/init.rc

新建 package/app/MagiskAPP 文件夹

Android.mk

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := Magisk

LOCAL_MODULE_TAGS := optional

LOCAL_SRC_FILES := $(LOCAL_MODULE).apk

LOCAL_MODULE_CLASS := APPS

LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)

# LOCAL_PRIVILEGED_MODULE := true

LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)

# LOCAL_CERTIFICATE := PRESIGNED

LOCAL_DEX_PREOPT := false

LOCAL_CERTIFICATE := platform

include $(BUILD_PREBUILT)

include $(CLEAR_VARS)

LOCAL_MODULE := VCAM

LOCAL_MODULE_TAGS := optional

LOCAL_SRC_FILES := $(LOCAL_MODULE).apk

LOCAL_MODULE_CLASS := APPS

LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)

# LOCAL_PRIVILEGED_MODULE := true

LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)

LOCAL_CERTIFICATE := PRESIGNED

LOCAL_DEX_PREOPT := false

# LOCAL_CERTIFICATE := platform

include $(BUILD_PREBUILT)

经过测试 微信视频通话使用 Camera1

抖音直播使用 Camera2

四、准备替换视频

抖音替换路径 /sdcard/DCIM/Camera1/virtual.mp4

微信替换路径 /sdcard/Android/data/com.tencent.mm/files/Camera1/virtual.mp4

virtual.mp4 用系统相机直接随便录制一个即可,主要是看其具体分辨率。

2022-02-09 14:39:19.398 2179-3231/com.mediatek.ims I/LSPosed-Bridge: 【VCAM】1位参数初始化相机,类:class com.mediatek.ims.internal.VTSource$DeviceHandler$1 2022-02-09 14:39:19.465 2179-3232/com.mediatek.ims I/LSPosed-Bridge: 【VCAM】重建垃圾场 2022-02-09 14:39:19.472 2179-3232/com.mediatek.ims I/LSPosed-Bridge: 【VCAM】打开相机C2 2022-02-09 14:39:19.663 2179-3231/com.mediatek.ims I/LSPosed-Bridge: 【VCAM】surfaceInfo=Surface(name=android.graphics.SurfaceTexture@3131cdf)/@0x6b39b1f 2022-02-09 14:39:19.663 2179-3231/com.mediatek.ims I/LSPosed-Bridge: 【VCAM】获取 c2_preview_Surfcae 2022-02-09 14:39:19.664 2179-3231/com.mediatek.ims I/LSPosed-Bridge: 【VCAM】添加目标:Surface(name=android.graphics.SurfaceTexture@3131cdf)/@0x6b39b1f 2022-02-09 14:39:19.665 2179-3231/com.mediatek.ims I/LSPosed-Bridge: 【VCAM】开始build请求 2022-02-09 14:39:19.672 2179-3231/com.mediatek.ims I/LSPosed-Bridge: 【VCAM】c2_player.setDataSource 2022-02-09 14:39:19.734 2179-3231/com.mediatek.ims I/LSPosed-Bridge: 【VCAM】处理过程完全执行 2022-02-09 14:39:21.105 2179-3231/com.mediatek.ims I/LSPosed-Bridge: 【VCAM】surfaceInfo=Surface(name=android.graphics.SurfaceTexture@3131cdf)/@0xd964558 2022-02-09 14:39:21.106 2179-3231/com.mediatek.ims I/LSPosed-Bridge: 【VCAM】获取 c2_preview_Surfcae_1 2022-02-09 14:39:21.106 2179-3231/com.mediatek.ims I/LSPosed-Bridge: 【VCAM】添加目标:Surface(name=android.graphics.SurfaceTexture@3131cdf)/@0xd964558 2022-02-09 14:39:21.109 2179-3231/com.mediatek.ims I/LSPosed-Bridge: 【VCAM】开始build请求 2022-02-09 14:39:21.191 2179-3231/com.mediatek.ims I/LSPosed-Bridge: 【VCAM】c2_player.setDataSource 2022-02-09 14:39:21.249 2179-3231/com.mediatek.ims I/LSPosed-Bridge: 【VCAM】c2_player_1.setDataSource 2022-02-09 14:39:21.276 2179-3231/com.mediatek.ims I/LSPosed-Bridge: 【VCAM】[c2player1][ Surface(name=android.graphics.SurfaceTexture@3131cdf)/@0xd964558]java.lang.IllegalStateException 2022-02-09 14:39:21.276 2179-3231/com.mediatek.ims I/LSPosed-Bridge: 【VCAM】处理过程完全执行

2022-02-11 13:01:59.107 695-1207/? E/Camera3-OutputStream: configureConsumerQueueLocked: Unable to connect to native window for stream 0 2022-02-11 13:01:59.107 695-1207/? E/Camera3-Stream: finishConfiguration: Unable to configure stream 0 queue: Invalid argument (-22) 2022-02-11 13:01:59.107 695-1207/? E/Camera3-Device: Camera 1: configureStreamsLocked: Can’t finish configuring output stream 0: Invalid argument (-22) 2022-02-11 13:01:59.107 695-1207/? E/CameraDeviceClient: endConfigure: Camera 1: Unsupported set of inputs/outputs provided 2022-02-11 13:01:59.108 769-4340/? I/MtkCam/StreamingPipe/MDPWrapper: [MDPWrapper][p2s] out port count=2, mUseIONFD=0 2022-02-11 13:01:59.108 769-4340/? I/MtkCam/StreamingPipe/MDPWrapper: [MDPWrapper][p2s] out port count=2, mUseIONFD=0 2022-02-11 13:01:59.108 769-4339/? I/MtkCam/fdNodeImp: [config] is FD in secure mode : 0 2022-02-11 13:01:59.108 2200-4306/com.mediatek.ims W/CameraDevice-JV-1: Stream configuration failed due to: endConfigure:505: Camera 1: Unsupported set of inputs/outputs provided 2022-02-11 13:01:59.109 769-4340/? I/MtkCam/StreamingPipe/MDPWrapper: [MDPWrapper][p2s] out port count=2, mUseIONFD=0 2022-02-11 13:01:59.109 2200-4306/com.mediatek.ims E/CameraCaptureSession: Session 0: Failed to create capture session; configuration failed 2022-02-11 13:01:59.109 769-4340/? I/MtkCam/StreamingPipe/MDPWrapper: [MDPWrapper][fpipe.helper] out port count=2, mUseIONFD=0 Dialer: DialerCall.onCameraError - Camera session error: 8003, Call: [DialerCall_1, INCOMING, [Capabilities: rsp_v_txt mut], [Properties: m_volte], children:[], parent:null, conferenceable:[], videoState:Audio Tx Rx, mSessionModificationState:0, CameraDir:-1]

在看雪论坛发现有大佬直接修改 framework 层可实现此功能,后来实操了,发现只能 hook camera1 微信,抖音就不行了,也算是一种思路

在lineageOS16.0 小米6 上 复现无人直播应用

🎀 相关推荐

试图的解释
🎯 365bet中文比分

试图的解释

📅 06-29 👀 9712
人这一辈子,一定要去一趟三亚!
🎯 365体育备用网站

人这一辈子,一定要去一趟三亚!

📅 06-29 👀 9592
淘宝代付怎么操作
🎯 365bet中文比分

淘宝代付怎么操作

📅 06-28 👀 9481