首页
论坛
课程
招聘
[原创]非华为电脑安装华为电脑管家分析
2021-12-8 14:54 20518

[原创]非华为电脑安装华为电脑管家分析

2021-12-8 14:54
20518

非华为电脑安装华为电脑管家分析过程

前言

近期有使用手机投屏的需求,用过几个小工具感觉效果不是很理想。所以想着着手分析下,发现涉及到了三阶段的知识,目前在科锐学到了二阶段尾声,于是向老师请教,在老师的指点下,艰难的进行了一些分析。如有分析不对的地方烦请各位指正。

分析环境

软件版本 : 11.1.6.31 (PCManager_Setup_11.1.6.31(C233D005).exe)

 

虚拟机 :windows 10 21H2 x64

 

真机 : windows 10 21H1 x64

 

工具 :IDA 、VS 2019

 

测试手机 : 华为 Mate 30 5G

首次安装运行分析

华为电脑管家官网上下载最新版本的安装包后,给我的感觉是一个类似与msi的安装包。

 

将安装包拖入虚拟机,同时打开process monitor抓取一波安装时的行为,方便后续分析。

 

首先最直观的提示是

 

设备不兼容

 

同样是windows,华为电脑和其友商电脑有什么区别?我感觉最直观的体现在于下图

 

设备信息

 

有这个方向下一步就需要关注下针对主板或者系统信息的一次操作。

分析安装包

将安装包拖入到ida中,在入口函数处竟然发现了一个明显的提示

 

NSIS

 

这华为电脑管家安装包应该是通过NSIS打包生成的。之前使用过NSIS进行过打包,该工具主要通过编写一个脚本文件(*.nsi/*.ini等)完成一系列操作。例子如下:

 

NSIS

 

用7Z直接解压PCManager_Setup_11.1.6.31(C233D005).exe看看是否可能从修改脚本重打包的方式绕过对设备的检测。

 

安装包信息

 

但是在压缩包的根目录并没有找到相关的脚本文件,因此这个方法并不可行。

 

不过既然解压了就试下解压后的可执行文件是否能运行。在解压目录找到PCManager.exe运行。

 

解压后运行PCManager.exe

 

可以直接运行,难道就此结束吗?跟着窗口的各种提示一路点击"同意",但是还是有问题。

 

服务异常.exe

 

可能是跳过了安装过程没有给安装上服务的原因,点击"修复"。

 

连接手机并进入"多屏协同"。此时并不能正常识别到手机。

 

连接手机异常.exe

 

到此看来,似乎并不能通过解压的方式正常运行"华为电脑管家"。

分析安装流程中的模块

知道了安装包并不包含主要的逻辑代码,那么就需要从安装包中包含的模块入手分析。

 

回到开始时用process monitor抓取到的信息中,在日志中可以看到一条信息

 

启动子进程.exe

 

通过命令行参数可以大胆猜测下,这里可能就是验证设备兼容性的函数。在IDA中定位到MBAInstallPre.exe中对参数isSupportDevice判断的位置。

 

isSupportDevice判断位置

 

通过观察流程该函数Func_isSupportDevice主要有两个可能的返回值,分别是 : 1 或 2

 

Func_isSupportDevice内部

 

首先进入函数sub_1400162D0

 

sub_1400162D0内部

 

该函数在入口处调用了一次导入函数之后便进入到字符串的拼接环节。

 

这里主要看下导入函数的工作流程。

 

导入函数GetDeviceTypeEx

 

GetDeviceTypeExinner

 

GetDeviceTypeExinner

 

这里多次跟进ProductAdapt::MachineType::GetInstance后发现会进入到一个函数__int64 __fastcall ProductAdapt::MachineType::LoadConfig(ProductAdapt::MachineType *this)

 

在函数ProductAdapt::MachineType::LoadConfig再次发现了Func_isSupportDevice里用到的一个类实例SmBiosHelper::GetInstance()

 

LoadConfig函数

 

看来这个SmBiosHelper这个类才是真正干活的。该函数由HardwareHal.dll导出。

 

SmBiosHelper::GetInstance

 

在其初始化函数中发现了如下调用:

 

Call_GetSystemFirmwareTable

 

下面是函数sub_180032750的主要逻辑

 

通过WMI获取数据

 

通过MSDN GetSystemFirmwareTable发现该函数可以读取到SMBIOS固件表。同时该函数也提到了使用WMI也可以获取到。

 

通过GitHub代码 DumpSMBIOS尝试获取数据

 

dumpsmbios

 

通过wbemtest.exe打开ROOT\WMI并打开类MSSMBios_RawSMBiosTables找到SMBiosData

 

wmi

 

显示SMBiosData字段无数据。

 

这里不清楚为什么通过WMI GUI工具没有获取到数据,已经管理员方式运行了。

 

通过上图可以看出来使用GetSystemFirmwareTable确实可以拿到主板信息。由上图中可以知道,如果通过GetSystemFirmwareTable可以拿到信息之后则跳过了通过WMI方式获取数据。

 

在拿到SMBiosData字段或者说SMBIOSTableData字段后,程序进行了如下处理。

 

ProductNameCmp

 

主要对其中的5个字段进行了解析(文章结尾提供BIOS更多信息)。分别是

1
2
3
4
5
BIOS Information (Type 0)
System Information  (Type 1)
Baseboard (or Module) Information  (Type 2)
System Enclosure  (Type 3)
OEM Strings (Type 11)

回到函数sub_1400162D0内部,当函数ProductCheckSupport::GetDeviceTypeEx返回后,则会得到对应设备的GetProductName,通过返回的ProductName与软件Config中包含的ProductName进行比较

 

ProductNameCmp

 

如果与Config中的ProductName一致,则函数返回1否则返回0。

 

至此函数sub_1400162D0流程分析完毕。下面来看Func_isSupportDevice中的else分支。

 

Func_isSupportDevice内部

 

else分支直接通过SmBiosHelper::GetSysManufactor来获取主板制造商。并将字符串转换为大写后与HUAWEIXXXX进行比较。

 

isSupportDevice_SMBIOS

 

如果主板厂商是HUAWEI则函数返回1,否则函数返回2。

 

至此MBAInstallPre.exe中的Func_isSupportDevice函数分析完毕。

模块分析总结

通过上面的对其中的MBAInstallPre.exe->isSupportDevice流程的大概分析可以知道,模块HardwareHal.dll中的类SmBiosHelper会通过函数GetSystemFirmwareTable或者WMI来获取主板信息。

 

接下来则通过hook函数GetSystemFirmwareTable处理其返回值。

 

通过MSDN GetSystemFirmwareTable知道正确的函数调用方式如下。

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
DWORD error = ERROR_SUCCESS;
DWORD smBiosDataSize = 0;
RawSMBIOSData* smBiosData = NULL; // Defined in this link
DWORD bytesWritten = 0;
 
// Query size of SMBIOS data.
// 第一次调用时为了获取SMBIOSData的数据大小
smBiosDataSize = GetSystemFirmwareTable('RSMB', 0, NULL, 0);
 
// Allocate memory for SMBIOS data
smBiosData = (RawSMBIOSData*) HeapAlloc(GetProcessHeap(), 0, smBiosDataSize);
if (!smBiosData) {
    error = ERROR_OUTOFMEMORY;
    goto exit;
}
 
// Retrieve the SMBIOS table
// 第二次调用时为了获取SMBIOSData的数据
 
bytesWritten = GetSystemFirmwareTable('RSMB', 0, smBiosData, smBiosDataSize);
 
if (bytesWritten != smBiosDataSize) {
    error = ERROR_INVALID_DATA;
    goto exit;
}
 
// Process the SMBIOS data and free the memory under an exit label

主要代码如下(修改自GitHub代码 DumpSMBIOS)。
更多BIOS结构信息在文章结尾提供相关链接。

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
UINT WINAPI Hooked_GetSystemFirmwareTable(
 _In_ DWORD FirmwareTableProviderSignature,
 _In_ DWORD FirmwareTableID,
 _Out_writes_bytes_to_opt_(BufferSize, return) PVOID pFirmwareTableBuffer,
 _In_ DWORD BufferSize
)
{
    PTF_LOG_A("Hooked_GetSystemFirmwareTable.");
    UINT uRetValue = 0;
 
    uRetValue = g_FUNC_GetSystemFirmwareTable(FirmwareTableProviderSignature, FirmwareTableID, pFirmwareTableBuffer, BufferSize);
 
    if (FirmwareTableProviderSignature != 'RSMB')
    {
        PTF_LOG_A("Hooked_GetSystemFirmwareTable. Signature is not \'RSMB\'");
        return uRetValue;
    }
 
    if (pFirmwareTableBuffer != NULL && BufferSize > 0 && uRetValue <= BufferSize)
    {
        PTF_LOG_A("Hooked_GetSystemFirmwareTable. Modify Data.");
        const PRawSMBIOSData pDMIData = (PRawSMBIOSData)pFirmwareTableBuffer;
        //修改返回数据
        DumpSMBIOSStruct(pDMIData, pDMIData->Length);
        PTF_LOG_A("Hooked_GetSystemFirmwareTable. Modify Data Finish.");
    }
    return uRetValue;
}
 
void DumpSMBIOSStruct(void* pAddress, unsigned int Len)
{
    LPBYTE p = (LPBYTE)(pAddress);
    const LPBYTE lastAddress = p + Len;
    PSMBIOSHEADER pHeader;
 
    for (;;) {
        pHeader = (PSMBIOSHEADER)p;
 
        if (ModiySysInfo(pHeader) == true)
            break;
 
        if ((pHeader->Type == 127) && (pHeader->Length == 4))
            break; // last avaiable tables
        LPBYTE nt = p + pHeader->Length; // point to struct end
        while (0 != (*nt | *(nt + 1))) nt++; // skip string area
        nt += 2;
        if (nt >= lastAddress)
            break;
        p = nt;
    }
}
 
/*
ModiySysInfo 函数 为了防止格式识别错误,最好是删除当前System Information节。
自己重新构建一个节并添加到全部数据的尾部。
同时需要更新GetSystemFirmwareTable返回值的大小。
以上前提是提供给GetSystemFirmwareTable的输出缓冲区足够长。
*/
bool ModiySysInfo(PSMBIOSHEADER pHeader)
{
    if (pHeader->Type == 1)
    {
        /*https://consumer.huawei.com/cn/support/laptops/matebook-e/*/
        PSystemInfo pSystem = (PSystemInfo)pHeader;
        char* str = (char *)pHeader + pHeader->Length;
        const char* pszManufacturer = "HUAWEI";//主板厂商
        const char* pszProductName = "BLl-W19";//产品名
        const char* pszVersion = "1.0";//版本
        //https://consumer.huawei.com/cn/support/warranty-query/
        //这里的SerialNumber在测试中发现了个小问题
        //如果未提供一个可用的SN则不能在软件中使用某些联网功能
        //"玩机技巧" "快捷服务"
        const char* pszSerialNumber = "ASM51ASMASM51ASM";//16位主板序列号
 
        //获取原各字段信息
        const char* pszOldManufacturer = LocateStringA(str, pSystem->Manufacturer);
        const char* pszOldProductName = LocateStringA(str, pSystem->ProductName);
        const char* pszOldVersion = LocateStringA(str, pSystem->Version);
        const char* pszOldSerialNumber = LocateStringA(str, pSystem->SN);
 
        if (
            strlen(pszOldManufacturer) > strlen(pszManufacturer) &&
            strlen(pszOldProductName) > strlen(pszProductName)&&
            strlen(pszOldVersion) > strlen(pszVersion)&&
            strlen(pszOldSerialNumber) > strlen(pszSerialNumber)
            )
        {
            //如果原主板信息足够长则可以直接修改
            PTF_LOG_A("Data length enough.");
            str = ModiyStringData(str, pszManufacturer);
            str = ModiyStringData(str, pszProductName);
            str = ModiyStringData(str, pszVersion);
            str = ModiyStringData(str, pszSerialNumber);
            return true;
        }
        else
        {
            //原主板信息较短,则需要另辟蹊径
            //...
        }
    }
    return false;
}
 
char * ModiyStringData(char* pAddress, const char* pszTargetData)
{
    if (0 == *pAddress)
        return pAddress;
    int nTragetLen = strlen(pszTargetData) + 1;
    strcpy_s(pAddress, nTragetLen, pszTargetData);
    return (pAddress + nTragetLen);
}

最终效果

测试1

 

测试2

声明

以上内容如有侵权部分,敬请告知,将及时更改。

相关引用

BIOS有关更多信息

 

GitHub DumpSMBIOS

 

MSDN GetSystemFirmwareTable

 

华为 matebook


【看雪培训】目录重大更新!《安卓高级研修班》2022年春季班开始招生!

收藏
点赞4
打赏
分享
最新回复 (13)
雪    币: 6017
活跃值: 活跃值 (3512)
能力值: ( LV12,RANK:211 )
在线值:
发帖
回帖
粉丝
sunfishi 活跃值 3 2021-12-8 15:21
2
0
支持!市面上破解早有,但是缺乏分析文章,值得学习。
雪    币: 4527
活跃值: 活跃值 (1924)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
LeadroyaL 活跃值 1 2021-12-8 15:46
3
0
精彩,学习了
雪    币: 843
活跃值: 活跃值 (9573)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
kanxue 活跃值 8 2021-12-8 15:56
4
0
华为鸿蒙手机+普通电脑 用户的福利!
雪    币: 1089
活跃值: 活跃值 (246)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
shinratensei 活跃值 1 2021-12-8 15:58
5
1

安装工具会被defender标记为病毒。

遇到过安装失败的问题,所以里边有两个版本dll,具体在安装包中有描述。

上传的附件:
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
mb_kupcnjmw 活跃值 2021-12-8 21:13
6
0
 虽然看不懂,但是必须支持
雪    币: 2685
活跃值: 活跃值 (1457)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
欧阳休 活跃值 2021-12-9 02:50
7
0
官方不是提供了无限制版吗?
雪    币: 4518
活跃值: 活跃值 (764)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
logkiller 活跃值 2021-12-9 02:55
8
0
安装后老是被驱动蓝屏,试了几个版本都这样,难道老电脑不支持?
雪    币: 20
活跃值: 活跃值 (376)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
快乐的小跳蛙 活跃值 2021-12-20 10:29
9
0
厉害厉害
雪    币: 106
活跃值: 活跃值 (426)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
TeLeMan 活跃值 1 2021-12-21 12:46
10
1
不需要修改代码,只需要修改xml文件就行了。另外xml的解密这部分很有意思,使用了一个内置的vm来完成的,有兴趣的可以研究一下。
雪    币: 843
活跃值: 活跃值 (9573)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
kanxue 活跃值 8 2021-12-21 18:50
11
0
TeLeMan 不需要修改代码,只需要修改xml文件就行了。另外xml的解密这部分很有意思,使用了一个内置的vm来完成的,有兴趣的可以研究一下。
大牛来了!
雪    币: 98
活跃值: 活跃值 (30)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
williamsvw 活跃值 1 2021-12-21 19:55
12
0
感谢楼主精彩的分享,学到不一样的思路
雪    币: 200
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
空降猫咪 活跃值 2022-1-21 01:31
13
0
感谢楼主的分析 想请教一下Hook部分是怎么实现的 我试了很多hook的代码都没有成功
雪    币: 200
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
空降猫咪 活跃值 2022-1-21 17:04
14
0
我Hook的话只启动PCManager的话是可以伪装成功的,但是从服务启动PCManager服务的话就会崩掉,不知道什么问题
游客
登录 | 注册 方可回帖
返回