Step to UEFI (210)调用 ConOut 的条件(上)

前面的研究中提到了调用 ConOut 必须满足的2个条件,这次就研究一下其中的一个条件:

“实践发现在调用 SystemTable->ConOut 的时候会损坏堆栈,比如下面的调用方式(按道理2个参数的情况下是通过寄存器来进行参数传递的)

push rdx 
Call ConOut
pop rdx 

运行之后会发现 rdx 值发生了变化”

首先需要明确的是:堆栈生长方向是从高向低。比如:PUSH RAX执行之后,会将RSP=RSP-8, RAX值存放在 RSP 给出的位置,然后;POP 动作与之相反。

开始跟踪代码,首先在调用处停下来:

执行Call 命令之后,RSP=RSP-8, 然后将 call 后面的下一条指令地址存放在 [RSP ] 之中。此时堆栈如下(简单起见,认为下面是高地址,上面是低地址。当前的IP和堆栈IP 都记作2Bytes方便查看):

跳转到了我们的 ASM 代码中

继续运行 call qword ptr [rcx+8] 之后堆栈情况:

特别注意,这里有一个 mov qword ptr [rsp+8],rbx, 运行之后会将前面一个的返回地址覆盖掉(就是 call qword ptr [rbx+20h] 指令(RIP=989B)的下一条地址)。因此,无论后面如何,这里都不可能正常返回。再进一步,观察到每个函数进入之后都有 sub esp,xxx 这样的操作,咨询天杀他回复“64位的函数调用中,参数的传递,也是要通过栈传递的,call子函数前将数据放到栈中再调用。小于四个参数的情况,一般使用RCX、RDX、R8、R9传递,但是也需要在栈中保留相应的空间。”换句话说,小于4个参数的情况会直接使用寄存器传递参数,但是同样要在堆栈上预留出这几个参数的空间。经过研究在【参考1】有如下描述:

1.在调用函数之前,会申请参数预留空间.(rcx,rdx,r8,r9)

2.函数内部,会将寄存器传参的值(rcx,rdx,r8,r9)保存到我们申请的预留空间中.

上面这两步其实就相当于x86下的 push r9 push r8 push rdx,push rcx

3.调用约定是 __fastcall.传参有rcx rdx,平栈是按照c调用约定平栈. 也就是调用者平栈.

因此,我们之前编写调用  ConOut 的方法是错误的,必须按照规则在堆栈上预留2个参数的空间。 从前面可以看到,堆栈的生长方向是由高到低,因此用  sub rsp,16 即可预留2个8Bytes。

上面就是发生堆栈损坏的原因,本质是我们违反了编译器的约定导致的。

参考:

1. https://www.cnblogs.com/iBinary/p/10959444.html  x64汇编第三讲,64位调用约定与函数传参.

WinDBG 查看 ACPI Table 的操作

最近根据【参考1】研究了一下通过 WinDBG 查看 ACPI Table 的方法,需要特别注意的是,必须按照顺序执行才能取得需要查看的信息。

1.运行!rsdt命令,感觉是让 WinDBG 进行查找的动作

||0:6: kd> !rsdt
Sorry: Unable to get ACPI!AcpiInformation.
Searching for RSDP.*************************************************************************
***                                                                   ***
***                                                                   ***
***    Either you specified an unqualified symbol, or your debugger   ***
***    doesn't have full symbol information.  Unqualified symbol      ***
***    resolution is turned off by default. Please either specify a   ***
***    fully qualified symbol module!symbolname, or enable resolution ***
***    of unqualified symbols by typing ".symopt- 100". Note that     ***
***    enabling unqualified symbol resolution with network symbol     ***
***    server shares in the symbol path may cause the debugger to     ***
***    appear to hang for long periods of time when an incorrect      ***
***    symbol name is typed or the network symbol server is down.     ***
***                                                                   ***
***    For some commands to work properly, your symbol path           ***
***    must point to .pdb files that have full type information.      ***
***                                                                   ***
***    Certain .pdb files (such as the public OS symbols) do not      ***
***    contain the required information.  Contact the group that      ***
***    provided you with these symbols if you need this command to    ***
***    work.                                                          ***
***                                                                   ***
***    Type referenced: hal!_RSDT_32                                  ***
***                                                                   ***
*************************************************************************
.........................................0x0effe0: Read 0x000020 of 0x000024 bytes
Could not locate the RSDT pointer

2. !acpicache 命令,显示当前系统 Cache 的ACPI Table

||0:6: kd> !acpicache
Dumping cached ACPI tables...
  XSDT @(fffff7e200004018) Rev: 0x1 Len: 0x000104 TableID: CFL-ULT
  DBGP @(fffff7e200005018) Rev: 0x1 Len: 0x000034 TableID: CFL-ULT
  MCFG @(fffff7e200006018) Rev: 0x1 Len: 0x00003c TableID: CFL-ULT
  FACP @(fffff7e200050018) Rev: 0x6 Len: 0x000114 TableID: CFL-ULT
  APIC @(fffff7e200051018) Rev: 0x3 Len: 0x00012c TableID: CFL-ULT
  BOOT @(fffff7e200054018) Rev: 0x1 Len: 0x000028 TableID: TIANO   
  DMAR @(fffff7e200055018) Rev: 0x1 Len: 0x0000a8 TableID: CFL     
  HPET @(fffff7e20007e018) Rev: 0x1 Len: 0x000038 TableID: CFL-ULT
  FPDT @(ffffe3020d0fe9e8) Rev: 0x1 Len: 0x000044 TableID: CFL-ULT
  DSDT @(ffffe3020d400018) Rev: 0x2 Len: 0x045806 TableID: CFL-ULT
  SSDT @(ffffe3020d0a7018) Rev: 0x2 Len: 0x001b1c TableID: CpuSsdt
  SSDT @(ffffe3020f31f018) Rev: 0x2 Len: 0x0031c6 TableID: SaSsdt 
  SSDT @(ffffe3020f322208) Rev: 0x2 Len: 0x00045a TableID: Tpm2Tabl
  SSDT @(ffffe3020f322698) Rev: 0x2 Len: 0x000046 TableID: MeSsdt 
  TPM2 @(ffffe3020f322708) Rev: 0x3 Len: 0x000034 TableID: CFL     
  UEFI @(ffffe3020f322768) Rev: 0x1 Len: 0x000042 TableID: CFL-ULT
  SSDM @(ffffe3020f3227d8) Rev: 0x1 Len: 0x000055 TableID: 
  SSDT @(ffffe3020f322858) Rev: 0x2 Len: 0x000538 TableID: PerfTune
  ECDT @(ffffe3020f322db8) Rev: 0x1 Len: 0x000069 TableID: CFL-ULT
  SSDT @(ffffe3020d05e018) Rev: 0x2 Len: 0x002f5c TableID: CnlU_Rvp
  SSDT @(ffffe3020e7fa978) Rev: 0x2 Len: 0x000fae TableID: Ther_Rvp
  SSDT @(ffffe3020d05b018) Rev: 0x2 Len: 0x0029c5 TableID: xh_whld4
  SSDT @(ffffe3020d0a5018) Rev: 0x2 Len: 0x001b67 TableID: UsbCTabl
  LPIT @(ffffe3020d0a6ba8) Rev: 0x1 Len: 0x00005c TableID: CFL-ULT
  WSMT @(ffffe3020d0a6c38) Rev: 0x1 Len: 0x000028 TableID: CFL-ULT
  SSDT @(ffffe3020d058018) Rev: 0x2 Len: 0x0027de TableID: PtidDevc
  SSDT @(ffffe3020d0a3018) Rev: 0x2 Len: 0x00149f TableID: TbtTypeC
  DBG2 @(ffffe3020d0a4548) Rev: 000 Len: 0x000054 TableID: CFL-ULT
  NHLT @(ffffe3020d0a1018) Rev: 000 Len: 0x001783 TableID: CFL     
  BGRT @(ffffe3020d0a2908) Rev: 0x1 Len: 0x000038 TableID: CFL-ULT

3. !fadt 命令,显示 FADT 的信息

||0:6: kd> !fadt 
FADT -- fffff8036da7aee0
FADT revision is 6, which is not understood by this debugger
HEADER - fffff8036da7aee0
  Signature:               FACP
  Length:                  0x00000114
  Revision:                0x06
  Checksum:                0xa1
  OEMID:                   INTEL 
  OEMTableID:              CFL-ULT
  OEMRevision:             0x20170001
  CreatorID:               INTL
  CreatorRev:              0x20160422
FADT - BODY - fffff8036da7af04
  FACS:                    0x8ca12000
  DSDT:                    0x8cbb6000
  Int Model:               Dual PIC
  SCI Vector:              0x009
  SMI Port:                0x000000b2
  ACPI On Value:           0x0f0
  ACPI Off Value:          0x0f1
  SMI CMD For S4 State:    0x0f2
  PM1A Event Block:        0x00001800
  PM1B Event Block:        0x00000000
  PM1 Event Length:        0x004
  PM1A Control Block:      0x00001804
  PM1B Control Block:      0x00000000
  PM1 Control Length:      0x002
  PM2 Control Block:       0x00001850
  PM2 Control Length:      0x001
  PM Timer Block:          0x00001808
  PM Timer Length:         0x004
  GP0 Block:               0x00001860
  GP0 Length:              0x020
  GP1 Block:               0x00000000
  GP1 Length:              0x00000000
  GP1 Base:                0x00000010
  C2 Latency:              0x00065
  C3 Latency:              0x003e9
  Memory Flush Size:       0x00000
  Memory Flush Stride:     0x00000
  Duty Cycle Index:        0x001
  Duty Cycle Index Width:  0x003
  Day Alarm Index:         0x00d
  Month Alarm Index:       0x000
  Century byte (CMOS):     0x032
  Boot Architecture:       0x0001
    The machine does not contain a legacy i8042
  Flags:                   0x0020c4b5
    WRITEBACKINVALIDATE_WORKS .................. SET
    WRITEBACKINVALIDATE_DOESNT_INVALIDATE ...... CLEAR
    SYSTEM_SUPPORTS_C1 ......................... SET
    P_LVL2_UP_ONLY ............................. CLEAR
    PWR_BUTTON_GENERIC ......................... SET
    SLEEP_BUTTON_GENERIC ....................... SET
    RTC_WAKE_GENERIC ........................... CLEAR
    RTC_WAKE_FROM_S4 ........................... SET
    TMR_VAL_EXT ................................ CLEAR
    DCK_CAP .................................... CLEAR
    RESET_CAP .................................. SET
      RESET_VALUE: 6
      RESET_REG: System I/O - 0000000000000cf9
    SEALED_CASE_CAP ............................ CLEAR
    HEADLESS_CAP ............................... CLEAR
    CPU_SW_SLP_CAP ............................. CLEAR
    PCI_EXP_WAK ................................ SET
    USE_PLATFORM_CLOCK ......................... SET
    RTC_WAKE_VALID_FROM_S4 ..................... CLEAR
    REMOTE_POWER_ON_CAPABLE .................... CLEAR
    FADT_FORCE_CLUSTERED_APIC_MODE ............. CLEAR
    FADT_FORCE_APIC_PHYSICAL_DESTINATION_MODE .. CLEAR
    ACPI_HARDWARE_NOT_PRESENT .................. CLEAR
    AOAC_CAPABLE_PLATFORM ...................... SET

上述实验平台为 WHL HDK,有兴趣的朋友可以试试。

参考:

1. https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/other-acpi-debugging-extensions 

WinDBG访问硬件

前面对于 RU.EFI 的研究告诉我们对于 X86 来说,访问硬件信息需要的基本操作有:

1. PCI 信息的访问

2. 访问IO Port 直接访问

3. IO Port Index/Data 方式的访问

4. Memory 的访问

5. Memory Index/Data 方式的访问

6. MSR 的访问

掌握了上述的访问方法就可以访问到 X86 上的全部空间和寄存器。下面逐项介绍在 WinDBG 中的访问方法。因为大多数情况下,WinDBG 是用于调试 Windows 软件本身而不是硬件,因此很多操作都是来自个人总结如果有错误或者遗漏,恳请及时指出。

1.PCI的访问

a. !pcitree 命令可以用来查看当前系统中的PCI总线和设备信息【参考1】

实例如下

0: kd> !pcitree
SYMSRV:  BYINDEX: 0x5
         C:\ProgramData\Dbg\sym
         pci.pdb
         96732E11A7284081C982C9A015D949A81
SYMSRV:  UNC: C:\ProgramData\Dbg\sym\pci.pdb\96732E11A7284081C982C9A015D949A81\pci.pdb - path not found
SYMSRV:  UNC: C:\ProgramData\Dbg\sym\pci.pdb\96732E11A7284081C982C9A015D949A81\pci.pd_ - path not found
SYMSRV:  UNC: C:\ProgramData\Dbg\sym\pci.pdb\96732E11A7284081C982C9A015D949A81\file.ptr - path not found
SYMSRV:  RESULT: 0x80070003
SYMSRV:  BYINDEX: 0x6
         C:\ProgramData\Dbg\sym*https://msdl.microsoft.com/download/symbols
         pci.pdb
         96732E11A7284081C982C9A015D949A81
SYMSRV:  UNC: C:\ProgramData\Dbg\sym\pci.pdb\96732E11A7284081C982C9A015D949A81\pci.pdb - path not found
SYMSRV:  UNC: C:\ProgramData\Dbg\sym\pci.pdb\96732E11A7284081C982C9A015D949A81\pci.pd_ - path not found
SYMSRV:  UNC: C:\ProgramData\Dbg\sym\pci.pdb\96732E11A7284081C982C9A015D949A81\file.ptr - path not found
SYMSRV:  HTTPGET: /download/symbols/pci.pdb/96732E11A7284081C982C9A015D949A81/pci.pdb
SYMSRV:  HttpQueryInfo: 801900c8 - HTTP_STATUS_OK
SYMSRV:  pci.pdb from https://msdl.microsoft.com/download/symbols:copied      
SYMSRV:  PATH: C:\ProgramData\Dbg\sym\pci.pdb\96732E11A7284081C982C9A015D949A81\pci.pdb
SYMSRV:  RESULT: 0x00000000
DBGHELP: C:\ProgramData\Dbg\sym\pci.pdb\96732E11A7284081C982C9A015D949A81\pci.pdb cached to C:\ProgramData\Dbg\sym\pci.pdb\96732E11A7284081C982C9A015D949A81\pci.pdb
DBGHELP: pci - public symbols  
        C:\ProgramData\Dbg\sym\pci.pdb\96732E11A7284081C982C9A015D949A81\pci.pdb
Bus 0x0 (FDO Ext ffffb106414d5a20)
  (d=0,  f=0) 80863e34 devext 0xffffb1063bfef1b0 devstack 0xffffb1063bfef060 0600 Bridge/HOST to PCI
  (d=2,  f=0) 80863ea0 devext 0xffffb1063bfee1b0 devstack 0xffffb1063bfee060 0300 Display Controller/VGA
  (d=8,  f=0) 80861911 devext 0xffffb1063bfed1b0 devstack 0xffffb1063bfed060 0880 Base System Device/'Other' base system device
  (d=12, f=0) 80869df9 devext 0xffffb1063bfec1b0 devstack 0xffffb1063bfec060 1180 Unknown Base Class/Unknown Sub Class
  (d=13, f=0) 80869dfc devext 0xffffb1063bfeb1b0 devstack 0xffffb1063bfeb060 0700 Simple Serial Communications Controller/Serial Port
  (d=14, f=0) 80869ded devext 0xffffb1063bfea1b0 devstack 0xffffb1063bfea060 0c03 Serial Bus Controller/USB
  (d=14, f=2) 80869def devext 0xffffb1063bfe91b0 devstack 0xffffb1063bfe9060 0500 Memory Controller/RAM
  (d=15, f=0) 80869de8 devext 0xffffb1063b4751b0 devstack 0xffffb1063b475060 0c80 Serial Bus Controller/Unknown Sub Class
  (d=16, f=0) 80869de0 devext 0xffffb1063b4671b0 devstack 0xffffb1063b467060 0780 Simple Serial Communications Controller/'Other'
  (d=1d, f=0) 80869db0 devext 0xffffb1063b4691b0 devstack 0xffffb1063b469060 0604 Bridge/PCI to PCI
  Bus 0x1 (FDO Ext ffffb106414e1a20)
    (d=0,  f=0) 144da802 devext 0xffffb106415d81b0 devstack 0xffffb106415d8060 0108 Mass Storage Controller/Unknown Sub Class
  (d=1f, f=0) 80869d84 devext 0xffffb1063b47b740 devstack 0xffffb1063b47b5f0 0601 Bridge/PCI to ISA
  (d=1f, f=3) 80869dc8 devext 0xffffb106414d01b0 devstack 0xffffb106414d0060 0401 Multimedia Device/Audio
  (d=1f, f=4) 80869da3 devext 0xffffb106415c21b0 devstack 0xffffb106415c2060 0c05 Serial Bus Controller/Unknown Sub Class
  (d=1f, f=5) 80869da4 devext 0xffffb106415c91b0 devstack 0xffffb106415c9060 0c80 Serial Bus Controller/Unknown Sub Class
Total PCI Root busses processed = 1
Total PCI Segments processed = 1
如果运行时出现类似下面的提示,需要使用.reload pci.sys 加载一下对应的 symbol
0: kd> !pcitree
Error retrieving address of PciFdoExtensionListHead

b. !pci 命令,参数比较多,这里直接给出常用的命令【参考2】

!pci 2 ff  //列出当前系统中全部 PCI 设备

0: kd> !pci 2 ff  
PCI Segment 0 Bus 0
00:0  8086:3e34.0b  Cmd[0006:.mb...]  Sts[0090:c....]  Intel Host Bridge  SubID:8086:7270
02:0  8086:3ea0.00  Cmd[0400:......]  Sts[0010:c....]  Intel VGA Compatible Controller  SubID:8086:2212
08:0  8086:1911.00  Cmd[0000:......]  Sts[0010:c....]  Intel Other System Peripheral  SubID:8086:7270
12:0  8086:9df9.30  Cmd[0002:.m....]  Sts[0010:c....]  Intel Other Signal Processing Controller  SubID:8086:7270
13:0  8086:9dfc.30  Cmd[0000:......]  Sts[0010:c....]  Intel Serial Controller  SubID:8086:7270
14:0  8086:9ded.30  Cmd[0406:.mb...]  Sts[0290:c....]  Intel Class:c:3:30  SubID:8086:7270
14:2  8086:9def.30  Cmd[0006:.mb...]  Sts[0010:c....]  Intel RAM Controller
15:0  8086:9de8.30  Cmd[0400:......]  Sts[0010:c....]  Intel Class:c:80:0  SubID:8086:7270
16:0  8086:9de0.30  Cmd[0406:.mb...]  Sts[0010:c....]  Intel Other Communications Controller  SubID:8086:7270
1d:0  8086:9db0.f0  Cmd[0407:imb...]  Sts[0010:c....]  Intel PCI-PCI Bridge 0->0x1-0x1
1f:0  8086:9d84.30  Cmd[0407:imb...]  Sts[0000:.....]  Intel ISA Bridge  SubID:8086:7270
1f:3  8086:9dc8.30  Cmd[0406:.mb...]  Sts[0010:c....]  Intel Audio Device  SubID:8086:7270
1f:4  8086:9da3.30  Cmd[0000:......]  Sts[0280:.....]  Intel SMBus Controller  SubID:8086:7270
1f:5  8086:9da4.30  Cmd[0402:.m....]  Sts[0000:.....]  Intel Class:c:80:0  SubID:8086:7270
PCI Segment 0 Bus 0x1
00:0  144d:a802.01  Cmd[0406:.mb...]  Sts[0010:c....]  Class:1:8:2  SubID:144d:a801

!pci f 0 2 0 0 0x200 //查看Bus 0, Device 2,function 0 上从 0 到 0x200的寄存器

0: kd> !pci f 0 2 0 0 0x200
PCI Segment 0 Bus 0
02:0  8086:3ea0.00  Cmd[0400:......]  Sts[0010:c....]  Intel VGA Compatible Controller  SubID:8086:2212
      cf8:80001000  IntPin:1  IntLine:0  Rom:0  cis:0  cap:40
      MEM[0]:cf000004  MPF[2]:d000000c  IO[4]:ffc1       
      00000000:  3ea08086 00100400 03000000 00000000
      00000010:  cf000004 00000000 d000000c 00000000
      00000020:  0000ffc1 00000000 00000000 22128086
      00000030:  00000000 00000040 00000000 00000100
      00000040:  010c7009 7a6160b1 9615808c 00000000
      00000050:  000001c1 00008031 00000000 8e000001
      00000060:  00010000 00000000 00000000 00000000
      00000070:  0092ac10 10008000 00000000 00000000
      00000080:  00000000 00000000 00000000 00000000
      00000090:  00000000 00000000 00000000 00000000
      000000a0:  00000000 00000000 00000000 0000d005
      000000b0:  fee00358 00000000 00000000 00000000
      000000c0:  00000000 00000000 00000000 00000000
      000000d0:  00220001 00000003 00000000 00000000
      000000e0:  00000000 00000000 00008000 00000000
      000000f0:  00000000 00000000 00000000 8cb33018
      00000100:  2001001b 00001400 00000000 00000000
      00000110:  00000000 00000000 00000000 00000000
      00000120:  00000000 00000000 00000000 00000000
      00000130:  00000000 00000000 00000000 00000000
      00000140:  00000000 00000000 00000000 00000000
      00000150:  00000000 00000000 00000000 00000000
      00000160:  00000000 00000000 00000000 00000000
      00000170:  00000000 00000000 00000000 00000000
      00000180:  00000000 00000000 00000000 00000000
      00000190:  00000000 00000000 00000000 00000000
      000001a0:  00000000 00000000 00000000 00000000
      000001b0:  00000000 00000000 00000000 00000000
      000001c0:  00000000 00000000 00000000 00000000
      000001d0:  00000000 00000000 00000000 00000000
      000001e0:  00000000 00000000 00000000 00000000
      000001f0:  00000000 00000000 00000000 00000000
      00000200:  0001000f

2. IO Port 的访问

IO port to read and write【参考3】

Function Command Description / mnemonic
Read IO port ib, iw, id Input from port (byte, word, double word)
Write IO port ob, ow, od Output to port (byte, word, double word)

实例如下 :访问70/71 上面的 CMOS,这个位置是当前的Second 所以过了一段时间会有变化

0: kd> !ob 70 0
0: kd> !ib 71
00000071: 000000000059
0: kd> !ob 70 0
0: kd> !ib 71
00000071: 000000000004

3. Memory 的访问

对于我们来说关注点通常只是物理内存,可以通过 !d* 命令来访问到【参考1】

实例如下 :!db 0xFFFFFF00 l 0x100   //按照Byte访问0xFFFFFF00,长度为 0x100 字节

目标机上同时使用 RW Everything 查看,可以看到结果相同:

4. MSR 的访问

可以通过 rdmsr 和  wrmsr 来实现,例如:

0: kd> rdmsr 0x2ff
msr[2ff] = 00000000`00000c06

此外,CPUID也可以被看作是一种MSR 可以用 CPUID 指令进行访问【参考4】:

0: kd> !cpuid
CP  F/M/S  Manufacturer     MHz
 0  6,142,11 GenuineIntel    1992
 1  6,142,11 GenuineIntel    1992
 2  6,142,11 GenuineIntel    1992
 3  6,142,11 GenuineIntel    1992
 4  6,142,11 GenuineIntel    1992
 5  6,142,11 GenuineIntel    1992
 6  6,142,11 GenuineIntel    1992
 7  6,142,11 GenuineIntel    1992

不过看起来能够提供的信息还是比较有限的。

参考:

  1. https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/-pcitree
  2. https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/-pci
  3. https://www.cnblogs.com/jiangxueqiao/p/7418195.html 
  4. https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/-cpuid

Step to UEFI (209)subst 命令

Subst 命令是一个很老的 DOS命令,通过它可以将一个目录映射为一个盘符。

例如,我本机当前只有一个盘符c:

通过 subst d: 201903, 即可将 buildbs\201903 这个目录映射为 D:

再次查看会多出一个 d: 盘符

对于我们BIOS编译来说,有时候会发生BUILD Debug版本的时候 Code 爆掉了,超过容量大小的限制。其中很大原因是目录过长。代码中很多DEBUG宏使用了 __FILE__ 定义,在编译中会展开为当前文件的完整路径,凭空要多出十几个字节。累积下来数量可观。为此,可以将你的编路径映射为一个盘符然后进入盘符编译。这样编译过程中路径是 D: 这样可以减少尺寸:

使用完毕后,可以使用 subst 盘符 /d 来取消映射。

台湾宝工(Pro’sKit)真的是一家玩具公司了

前一段时间参加创客嘉年华,惊奇的发现他们在这个活动上有一个摊位,更惊奇的是他们的摊位主打竟然是玩具。然后和他们聊了两句发现他们这些年转型向玩具市场进军。

转过天,我修理东西,拿出了他们家生产的螺丝刀,发现竟然生锈了。

基本上每一个刀头都没有幸免…….
这套工具用的很少
外包装还是完好的

除了这一套螺丝刀,我还有一个游标卡尺也是他们家的

检查发现也是生锈的

工具一直存放在家里,看起他们他们用的材质是很有问题的。如果非要加一个条件的话那就是:宝工产品不适合南方地区使用(作为东北人,过了山海关都算是南方)。

Step to UEFI (208)谁改动了我的文件头?

前面介绍了如何使用汇编语言直接编写UEFI Application,这里我偶然发现一个问题:用汇编生成的EFI 文件中,DOS 头部看起来多了一些东西。比如十六进制查看之前的 NasmUEFI.EFI 文件:

对比 Hello.EFI:

可以看到有些内容被清空为0x00. 首先怀疑的是编译过程中有工具来完成这个动作。于是,重新编译 Hello.EFI 观察到在末期有下面的操作:

Generating code
Finished generating code
        "GenFw" -e UEFI_APPLICATION -o c:\buildbs\201903\Build\AppPkg\DEBUG_VS2015x86\X64\AppPkg\Applications\Hello\Hello\DEBUG\Hello.efi c:\buildbs\201903\Build\AppPkg\DEBUG_VS2015x86\X64\AppPkg\Applications\Hello\Hello\DEBUG\Hello.dll

这个操作输入的是hello.dll 输出为 hello.efi,观察发现DLL 中还存在一些字符串,到了EFI 中会消失。接下来在窗口中直接运行 GenFw 来从 DLL生成EFI文件,最终确认是这个工具来完成移除多余的字符工作的,准确的说只是用0xFF覆盖,并没有引起文件长度的变化。

接下来查看 GenFW 的代码, \BaseTools\Source\C\GenFw\GenFw.c 其中下面就是我们需要找到的位置:

//
  // Zero all unused fields of the DOS header
  //
  if (DosHdr != NULL) {
    memcpy (&BackupDosHdr, DosHdr, sizeof (EFI_IMAGE_DOS_HEADER));
    memset (DosHdr, 0, sizeof (EFI_IMAGE_DOS_HEADER));
    DosHdr->e_magic  = BackupDosHdr.e_magic;
    DosHdr->e_lfanew = BackupDosHdr.e_lfanew;
    for (Index = sizeof (EFI_IMAGE_DOS_HEADER); Index < (UINT32 ) DosHdr->e_lfanew; Index++) {
      FileBuffer[Index] = (UINT8) DosHdr->e_cp;
    }
  }

特别提醒:目前提供的编译辅助工具都是 X86 版本的,因此需要在 x86 Native Tools Command Prompt 窗口下编译,如果使用X64会出现编译报错。

本文只是为了简单试验,并没有考虑一些特殊情况。针对上面的代码进行修改,插入一句话即可:

strcpy(&FileBuffer[sizeof (EFI_IMAGE_DOS_HEADER)],"www.lab-z.com");

这样,再次使用 GenFw 来进行DLL到EFI的转换,可以看到 EFI 文件中DOS Header后面被插入了我们期望的字符串。

通过上述的方法可以在 EFI 文件中自动加入自定义的字符串,通过这样的方法可以制作一些特殊的 EFI 文件,比如只能在特别BIOS上运行的 EFI文件。