Intel Brand Verification Tool

最近一直在和Intel BVT 作战。

Intel BVT 工具的全称是 Intel Brand Verification Tool。 是一款用来测试vPro然后生成报告的工具。测试通过之后,客户通过提交报告即可获得贴vPro Logo的资格。这个工具并不是进行功能性检查,而只是检查配置。例如:报告上说TLS已经Ready,但是实际上软件只是测试标志位是否已经设置起来,但是并不表示这个功能没有问题。如果想确认功能好用,那么需要使用 PETS 之类的进行测试。

BVT 还有一个很大的坑就是关于 Wireless Lan 的设定,如果你没有设定那么测试会提示 “CLink interface to Wi-Fi adapter tests FAILED”。而解决方法是令人匪夷所思的从 Gbe 的Lan登录AMT 的WebUI (Http://IP:16992), 然后找到 Wireless 的设定部分随便写一个AP 设定。

===============================================

2019年1月22日 更新

关于最后一点,如果使用特定的Intel WireLess Driver ,可以在不通过 Gbe Lan的情况下通过 http://127.0.0.1:16992 的方式登录到 WebUI 进行设定。但是从测试结果上来看这样的方法并不稳定(经常会出现无法找到页面,需要再次刷新才能进去的情况)。

===============================================

2020年5月22日 更新

AMT 默认密码是 admin ,第一次进入之后会要求你重设一个密码,你可以使用 “Admin98#” 这个符合密码规则。

参考:

https://wenku.baidu.com/view/a09d33bd960590c69ec376b4.html

Intel主动管理技术(Intel AMT)设置指南

https://blog.51cto.com/lzlutao/1218077

如何使用Intel AMT 8.0技术远程管理PC

 

【图解】替换 Windows ACPI Table的方法

本文介绍一种在没有BIOS代码的情况下,修改 ACPI Table 的方法。实际上这种方法已经使用很多很多年了,作为一种测试的方法是非常有效的。
使用到的工具一个是asl 这是微软 wdk 里面带的,用来 dump 和 load 系统acpi table 的;另外一个是 iasl, 这是 acpica 提供的工具,用来编译和反编译 asl 。特别需要注意的问题是,我在实践中发现 iasl 不同版本之间差别很大,如果你在使用中发现编译或者反编译错误非常多,那么最好多尝试几个版本,如果有条件最好直接使用Build 你BIOS的版本。
原理:Windows每次使用的 ACPI table 不是直接从内存读取的,而是缓冲在系统注册表上,因此替换这个注册表里面的就可以取得替换 ACPI Table的效果。
操作:

1. 在 console 下面(需要 Administrator权限),使用命令 asl.exe /tab=DSDT /c

2. 反编译抓下来的 DSDT0000.bin ,使用命令 iasl2016 –ve DSDT0000.bin

虽然报错了,但是还是生成了 dsdt0000.dsl

3. 将生成的 DSDT0000.DSL 改名为 dsdt.dsl,再重新编译之 ,命令是 Iasl2016.exe –ve DSDT.dsl

编译直接出错,修改这个错误(单纯来说,我这次碰到的问题是因为 extern 了 BNUM 和 RTIP,但是后面又重新定义了这两个名字所以会有冲突,修改方法是去掉 extern 的 BNUM和RTIP)

修改之后就可以正常编译了
4. 加入一个我们自定义的设备做为标记,加入的位置在 EC 下面,这样便于观看。加入的代码如下:

            Device (LABZ)
            {
                Name (_HID, EisaId ("LAB33D6") /* Intel Virtual Buttons Device */)  // _HID: Hardware ID
                Method (_STA, 0, Serialized)  // _STA: Status
                {
                    Return (0x0F)
                }

            }

再次编译,

5. 将编译后的结果加入系统中,命令是 asl /loadtable dsdt.aml

6. 重启之后,设备管理器中还是没有变化。需要再设置打开TestMode。 方法是在 console 下面使用
Bcdedit /set testsigning on

7.重启之后就可以在设备管理器中看到我们加入的设备了
加入之前

修改之后

上面的 Unknown device就是我们新加入的设备,设备属性

8. 删除加载的 dsdt 的方法是 asl /loadtable dsdt.aml –d 重启之后即可恢复

changeacpi

从原理上说,Windows会将 DSDT Table “缓存” 在注册表中,在开机的过程中不会去内存解析DSDT而是直接使用缓存的。因此,我们可以通过上面的方法来加入我们需要的代码。

=====================================================

2024年5月20日 在 Windows 11 的虚拟机上测试过,上述方法仍然有效。

Step to UEFI (153)用GetFirmwareEnvironmentVariable修改Setup选项

高考结束很多年了,班主任的音容笑貌仍然会出现在噩梦中,我仍然记得他在讲述虚数i的时候特别强调过时时刻刻牢记 i^2=-1,因为这是虚数和实数相互转换的门。

对于BIOS工程师来说SMI 就是当下OS和BIOS代码之间门。前面研究过了 gRT->GetVariable的Windows实现,因此,这里也可以作为非常简单的门。这次我们的目标是:在Shell 和 Windows下修改 Setup 的取值。比如说,我们当前的设计上需要更改四个Setup item才能去掉刷写BIOS的保护,这着实很麻烦,如果能自动修改就方便多了。
前文已经找到了BIOS对于Setup 限制访问的位置,经过研究,VarCheckLib.c 中的VarCheckLibSetVariableCheck() 函数会在 PlatformVarCheckLibNullClass.c 中的 mSetupVariableList[] 中查找 GUID 和 名称,对得上就会 Write Protect。为此,将 gSetupVariableGuid,L”Setup” 的定义去掉即可突破这个限制。

接下来,有2种实现的方法:

方法一:Windows Application直接对 Setup 变量的写入。这里选择 Setup 中的第二个UINT8 实验,对应的是 FastBoot 选项。

#define VariableGuidStr1     "{EC87D643-EBA4-4BB5-A1E5-3F3E36B20DA9}"
#define TestStr2             "Setup"

	printf("Check Setup");
	dwRet = GetFirmwareEnvironmentVariable(
		_T(TestStr2),
		_T(VariableGuidStr1),
		pBuffer,
		iBufferSize);
	printf("GetFirmwareEnvironmentVariable again, return value:%x\n", dwRet);
	Buffer[1] = 1;
	dwRet = SetFirmwareEnvironmentVariable(
		_T(TestStr2),
		_T(VariableGuidStr1),
		pBuffer,
		dwRet);
	printf("SetFirmwareEnvironmentVariable return value:%x\n", dwRet);
	printf("GetLastError:%x\n", GetLastError());

	printf("Check Setup again\n");

	dwRet = GetFirmwareEnvironmentVariable(
		_T(TestStr2),
		_T(VariableGuidStr1),
		pBuffer,
		iBufferSize);
	printf("GetFirmwareEnvironmentVariable again, return value:%x\n", dwRet);

 

运行结果:

再进入 Setup检查,可以看到 Fast Boot 已经设置为 Disabled。

方法二:在代码中根据输入的 GUID 来判断,然后做出设定的动作。在 VariableSmmRuntimeDxe.c 中的 RuntimeGerviceGetVariable() 函数中加入对GUID 的判断,如果是我们期望的,那么就先取出 Setup Variable,修改之后再用 RuntimeServiceSetVariable()放回去。

/**
  This code finds variable in storage blocks (Volatile or Non-Volatile).

  Caution: This function may receive untrusted input.
  The data size is external input, so this function will validate it carefully to avoid buffer overflow.

  @param[in]      VariableName       Name of Variable to be found.
  @param[in]      VendorGuid         Variable vendor GUID.
  @param[out]     Attributes         Attribute value of the variable found.
  @param[in, out] DataSize           Size of Data found. If size is less than the
                                     data, this value contains the required size.
  @param[out]     Data               Data pointer.

  @retval EFI_INVALID_PARAMETER      Invalid parameter.
  @retval EFI_SUCCESS                Find the specified variable.
  @retval EFI_NOT_FOUND              Not found.
  @retval EFI_BUFFER_TO_SMALL        DataSize is too small for the result.

**/
EFI_STATUS
EFIAPI
RuntimeServiceGetVariable (
  IN      CHAR16                            *VariableName,
  IN      EFI_GUID                          *VendorGuid,
  OUT     UINT32                            *Attributes OPTIONAL,
  IN OUT  UINTN                             *DataSize,
  OUT     VOID                              *Data
  )
{
  EFI_STATUS                                Status;
  UINTN                                     PayloadSize;
  SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE  *SmmVariableHeader;
  UINTN                                     TempDataSize;
  UINTN                                     VariableNameSize;

//LABZ_Start
  SETUP_DATA                   SetupData;
  UINTN                        VariableSize;
  UINT32                       VariableAttributes;
  
  if (CompareGuid (VendorGuid, &gLabZTestGuid)) { // 比较查看参数是否要触发
          
  VariableSize = sizeof (SETUP_DATA);
  Status = RuntimeServiceGetVariable (  //取Setup变量
                  L"Setup",
                  &gSetupVariableGuid,
                  &VariableAttributes,
                  &VariableSize,
                  &SetupData
                  );
  if (EFI_ERROR (Status)) {
    return Status;
  }
  SetupData.WakeOnRTCS5=1;  //修改选项值
  Status = RuntimeServiceSetVariable ( //将修改之后的结果回写
                  L"Setup",
                  &gSetupVariableGuid,
                  VariableAttributes,
                  VariableSize,
                  &SetupData
                  );
  ASSERT_EFI_ERROR(Status);
              
  }
//LABZ_End

  if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {
    return EFI_INVALID_PARAMETER;
  }

 

在 KBL-R HDK 平台上实验,首先在Shell 中,为了便于实验编写一个测试程序,最主要的功能就是调用 gRT->GetVariable 发送gLabZTestGuid 来触发函数。
在 Windows下运行编译后的 Shell Application ,再进入 Setup查看是能够看到选项已经成功修改。

#define TestGuidStr          "{11111111-1111-1111-1111-111111111111}" //用这个定义只是方便

	dwRet = GetFirmwareEnvironmentVariable(
		_T(TestStr2),
		_T(TestGuidStr),
		pBuffer,
		iBufferSize);
	printf("GetFirmwareEnvironmentVariable again, return value:%x\n", dwRet);

 

仍然是成功的。

从上面可以看到,这个方法无论在 Shell 下还是 Windows下都能正常工作(虽然没有实验,但是我也相信支持 UEFI 的Linux也是可以使用的)。此外,作为参数的 GUID 足够多,能让我们灵活的处理各种情况。