省流
该Patch仅限DevEco Studio这一个版本的包
DevEco Studio 5.0.1 Release
Build #DS-233.14475.28.36.505310
构建版本:5.0.5.310, built on December 11, 2024
#!/bin/sh
cp Emulator.test Emulator.test.bak
echo -n "3B0000143A0000142A000014FFC300D1FD7B02A9FD830091A0831FF8E10B00F9E20700F9E80B40F9E80300F9E90340F9283940F908ED6492283900F9A0835FF8E10B40F9E20740F957A16A94FD7B42A9FFC30091C0035FD6" | xxd -r -p | dd of=Emulator.test bs=1 seek=$((0xCD90)) conv=notrunc
echo -n "C068F197" | xxd -r -p | dd of=Emulator.test bs=1 seek=$((0x3B2A9C)) conv=notrunc
xml_content='<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.hypervisor</key>
<true/>
</dict>
</plist>'
echo "$xml_content" > /tmp/Emulator_entitlements.xml
sudo codesign -s - --entitlements /tmp/Emulator_entitlements.xml --force Emulator.test
rm /tmp/Emulator_entitlements.xml
参考:
qemu: disable SME for Apple Silicon · utmapp/UTM@acbf2ba
Use Apple silicon images on CI. by colinrtwhite · Pull Request #1793 · cashapp/redwood
详细分析
首先,分析可知鸿蒙的模拟器使用了qemu
启动崩溃之后,使用breakpad(google/breakpad: Mirror of Google Breakpad project) dump出详细的堆栈信息
注意breakpad最好使用depot获取软件源进行编译的方法,以方便在Mac下编译dump_syms工具,获取Emulator的调试信息
经过分析发现在如下调用逻辑中出现了Crash
11 Emulator!_error_handle_fatal + 0xec
12 Emulator!_error_propagate + 0x2c
13 Emulator!_error_propagator_cleanup + 0x20
14 Emulator!_glib_auto_cleanup_ErrorPropagator + 0x14
15 Emulator!_object_property_set + 0x140
16 Emulator!_object_property_set_qobject + 0x38
17 Emulator!_object_property_set_bool + 0x98
18 Emulator!_qdev_realize + 0x110
19 Emulator!_machvirt_init + 0x820
20 Emulator!_machine_run_board_init + 0x418
21 Emulator!_qemu_init_board + 0x3c
22 Emulator!_qmp_x_exit_preconfig + 0x48
23 Emulator!_qemu_init + 0x2128
24 Emulator!_RunQemuMain + 0x28
25 Emulator!EnterQemuMainLoop(int, char**) + 0x34
看不出太多的东西,搜索MacOS 15.2和qemu相关问题发现了这个可能的原因
但是在日志里没看出同款保存信息,不过还是先尝试打补丁
分析知这个版本的Emulator使用的是qemu7.1.0,所以拷贝源代码先进行编译
git clone --depth=1 https://github.com/qemu/qemu -b v7.1.0
cd qemu
mkdir build
cd build
../configure --target-list=aarch64-softmmu --enable-debug #尽量减少优化,使得函数尽可能多
make
构造一个如下类似的函数插入hvf_arm_get_host_cpu_features源码的合适位置编译
static void __attribute__ ((noinline)) patch (ARMISARegisters* dst, ARMISARegisters*src, size_t size)
{
src->id_aa64pfr1 &= ~R_ID_AA64PFR1_SME_MASK;
*dst = *src;
}
在反编译器里获取到一个可能的汇编,修改适配Emulator里的hvf_arm_get_host_cpu_features
SUB SP, SP, #0x30
STP X29, X30, [SP,#32]
ADD X29, SP, #0x20
STUR X0, [X29,#-8]
STR X1, [SP,#16]
STR X2, [SP,#8]
LDR X8, [SP,#16]
STR X8, [SP]
LDR X9, [SP]
LDR X8, [X9,#0x70]
AND X8, X8, #0xFFFFFFFFF0FFFFFF
STR X8, [X9,#0x70]
LDUR X0, [X29,#-8]
LDR X1, [SP,#16]
LDR X2, [SP,#8]
BL _memcpy
LDP X29, X30, [SP,#32]
ADD SP, SP, #0x30
RET
选择一个“看起来很空闲”的位置,将汇编打进去
我选择的是assert_hvf_ok这个函数,它的有些输出部分的代码对Emulator来说不是完全必要的
修改assert_hvf_ok函数的位置从0x10000CD90开始,dump下的16进制机器码如下
3B0000143A0000142A000014FFC300D1FD7B02A9FD830091A0831FF8E10B00F9E20700F9E80B40F9E80300F9E90340F9283940F908ED6492283900F9A0835FF8E10B40F9E20740F957A16A94FD7B42A9FFC30091C0035FD6
然后在hvf_arm_get_host_cpu_features,发现源码的这个部分代码
ahcf->isar = host_isar;
被编译器改写为了memcpy,所以替换此处的bl跳转的函数到我的patch函数位置即可
修改hvf_arm_get_host_cpu_features函数的位置从0x1003B2A9C开始,dump下的16进制机器码如下
C068F197
Patch好之后,一定要注意在重签名的时候添加一些hypervisor相关的东西,否则qemu在调用相关api的时候回报错HV_UNSUPPORTED(assert_hvf_ok这个函数打印出的日志里可能存在)