assembly 如何在UEFI中获取当前运行映像的设备路径?

7xzttuei  于 11个月前  发布在  其他
关注(0)|答案(1)|浏览(86)

作为我正在编写的UEFI应用程序的一部分,我希望我的应用程序在与此应用程序相同的文件夹中加载第二个应用程序。然而,要做到这一点,我需要知道当前运行文件的完整文件路径,并且我可以访问的固件中没有一个包含SIMPLE_FILE_SYSTEM_PROTOCOL示例(使用locateHandleBuffer)。
我的解决方案是获取正在运行的应用程序的LOADED_IMAGE_PROTOCOL,从那里获取设备路径(希望它是一个文件路径媒体设备路径),然后从那里开始。
问题是,我的应用程序的每次运行都会给出不同的设备路径。在某些固件上,只有设备路径的长度会改变,但在其他固件上,设备路径类型会改变。此外,在我尝试过的所有固件中,没有一个设备类型是有效的设备类型。

**我如何获得我试图加载的文件的设备路径?**是这段代码被破坏了,还是我做错了,或者两者兼而有之?

下面是来自应用程序的消息的一些截图。第一个是QEMU,第二个是来自我的笔记本电脑:
100d1x

的字符串
下面是执行设备路径打印的主程序流部分:

;Get the loaded image protocol for this handle
mov rcx, [EFI_HANDLE]
mov rdx, GUID_EFI_LOADED_IMAGE_PROTOCOL
call getProtocolFromHandle

;If getting the protocol failed, exit
cmp rax, [RETURN_SUCCESS]
je print

cmp rax, [RETURN_UNSUPPORTED]
jne error

mov rcx, [CONERR]
mov rdx, protocolNotFound
call printString
jmp printFinalString

print:
;If we have a loaded image protocol, then print information about the device path
add rcx, [OFFSET_LOADED_IMAGE_DEVICE_PATH_PROTOCOL]
mov r8, [rcx]
mov r9, [rcx]
mov r10, [rcx]
and r8, [MASK_FIRST_BYTE]
shr r8, 56
and r9, [MASK_SECOND_BYTE]
shr r9, 48
and r10, [MASK_THIRD_FOURTH_BYTES]
shr r10, 32
mov rcx, [CONOUT]
mov rdx, devicePathOne
call printString
mov rdx, r8
call printNumber
mov rdx, devicePathTwo
call printString
mov rdx, r9
call printNumber
mov rdx, devicePathThree
call printString
mov rdx, r10
call printNumber
mov rdx, newLine
call printString

字符串
下面是从给定句柄获取协议的代码部分:

;****************************************************
;*** getProtocolFromHandle [BOOT FUNCTION ONLY]   ***
;*** Definition: Gets the address of the protocol ***
;*** of the specified GUID from the image handle  ***
;*** Input: rcx is the image handle               ***
;***        rdx is the protocol's GUID            ***
;*** Output: rcx is a pointer to the protocol     ***
;***         interface installed on that handle   ***
;*****************************************************
getProtocolFromHandle:
    ;Save registers
    push rdx
    push r8
    push r9
    push r10
    push r11
    
    ;Call the function
    mov r8, ADDRESS_OPEN_PROTOCOL
    mov r9, [EFI_HANDLE]
    mov r10, 0
    mov r11, [CONSTANT_OPEN_PROTOCOL_GET_PROTOCOL]
    push r11 ;Arguments to the stack must be pushed in reverse order
    push r10 
    sub rsp, 0x20
    call [BOOT_SERVICES_OPEN_PROTOCOL]

    ;Restore registers
    add rsp, 0x20
    pop r10
    pop r11
    pop r11
    pop r10
    pop r9
    pop r8
    pop rdx
    
    ;Prepare return values and return
    mov rcx, [ADDRESS_OPEN_PROTOCOL]
    ret


下面是我认为对理解代码有用的数据的副本:

OFFSET_LOADED_IMAGE_DEVICE_PATH_PROTOCOL dq 28
ADDRESS_OPEN_PROTOCOL dq 0
MASK_FIRST_BYTE dq 0xff00000000000000
MASK_SECOND_BYTE dq 0x00ff000000000000
MASK_THIRD_FOURTH_BYTES dq 0x0000ffff00000000

**编辑:**今天运行这个应用程序的一个示例,在尝试获取值时崩溃了。这表明我的地址完全错误,但我不知道它是如何错误的:

2ekbmq32

2ekbmq321#

我已经发现了这个问题。这里的主要问题是加载的图像设备路径的偏移量需要是32而不是28。即使协议以UINT 32(4字节)开始,它似乎在64位系统上填充了零以占用8字节。
另外,上面的代码的其余部分将无法工作,因为它有很多错误,需要大量的更改,但至少现在你可以得到指向设备路径协议的指针!
这样的东西会起作用:

getImageProtocol:
;Get the loaded image protocol for this handle
mov rcx, [EFI_HANDLE]
mov rdx, GUID_EFI_LOADED_IMAGE_PROTOCOL
call getProtocolFromHandle
cmp rax, [RETURN_SUCCESS]
jne exitWithError
mov [ADDRESS_LOADED_IMAGE], rcx

;Get an instance of the device path utilities protocol
mov rcx, GUID_EFI_DEVICE_PATH_UTILITIES_PROTOCOL
call locateProtocol
cmp rax, [RETURN_SUCCESS]
jne exitWithError
mov [ADDRESS_DEVICE_PATH_UTILITIES_PROTOCOL], rcx
mov rcx, [rcx]
mov [ADDRESS_DEVICE_PATH_UTILITIES_PROTOCOL_GET_DEVICE_PATH_SIZE], rcx

;Print the size of the loaded image device path
mov rcx, [ADDRESS_LOADED_IMAGE]
add rcx, [OFFSET_LOADED_IMAGE_DEVICE_PATH]
mov rcx, [rcx]
call getDevicePathSize
cmp rax, [RETURN_SUCCESS]
jne exitWithError
mov r9, rcx
mov rcx, [ADDRESS_CONOUT]
mov rdx, sizeString
call printString
mov rdx, r9
call printNumber
mov rdx, newLine
call printString

字符串
这些函数看起来像这样(我使用的是tab宽度8,所以SO中的星号对齐可能看起来很奇怪,因为它的tab宽度是4):

;******************************************************************
;*** getProtocolFromHandle [BOOT FUNCTION ONLY]     ***
;*** Definition: Gets an instance of the protocol which is  ***
;***         registered to the given image.     ***
;*** Input: rcx is the image handle             ***
;***        rdx is a pointer to the protocol's GUID     ***
;*** Output: rcx is a pointer to the protocol's interface   ***
;***         installed on that handle.              ***
;******************************************************************
getProtocolFromHandle:
    ;Save registers
    push rdx
    push r8
    push r9
    push r10
    push r11
    
    ;Call the function
    mov r8, BUFFER_OPENED_PROTOCOL
    mov r9, [EFI_HANDLE]
    mov r10, 0
    mov r11, [CONSTANT_OPEN_PROTOCOL_GET_PROTOCOL]
    push r11 ;Arguments to the stack must be pushed in reverse order
    push r10 
    sub rsp, 0x20
    call [ADDRESS_BOOT_SERVICES_OPEN_PROTOCOL]

    ;Restore registers
    add rsp, 0x20
    pop r10
    pop r11
    pop r11
    pop r10
    pop r9
    pop r8
    pop rdx
    
    ;Prepare return values and return
    mov rcx, [BUFFER_OPENED_PROTOCOL]
    ret
    
;**************************************************************************
;*** locateProtocol [BOOT FUNCTION ONLY]                ***
;*** Definition: provides an interface to the requested protocol.   ***
;*** Input: rcx is the address of the protocol GUID         ***
;*** Output: rcx holds a pointer to the interface           ***
;**************************************************************************
locateProtocol:
    ;Save registers
    push rdx
    push r8
    push r9
    push r10
    push r11
    
    ;Call the function
    mov rdx, 0
    mov r8, BUFFER_LOCATED_PROTOCOL
    sub rsp, 0x20
    call [ADDRESS_BOOT_SERVICES_LOCATE_PROTOCOL]

    ;Restore registers
    add rsp, 0x20
    pop r11
    pop r10
    pop r9
    pop r8
    pop rdx
    
    ;Prepare return values and return
    mov rcx, [BUFFER_LOCATED_PROTOCOL]
    ret

;**************************************************************************
;*** getDevicePathSize                          ***
;*** Definition: gets the total size of all nodes in the device ***
;***         path, including the end-of-path tag            ***
;*** Input: rcx is the address of the device path           ***
;*** Output: rcx is the size of the device path         ***
;**************************************************************************
getDevicePathSize:
    ;Save registers
    push rdx
    push r8
    push r9
    push r10
    push r11
    
    ;Call the function
    sub rsp, 0x20
    call [ADDRESS_DEVICE_PATH_UTILITIES_PROTOCOL_GET_DEVICE_PATH_SIZE] ;My gosh that's a long pointer name!

    ;Restore registers
    add rsp, 0x20
    pop r11
    pop r10
    pop r9
    pop r8
    pop rdx
    
    ;Return
    mov rcx, rax
    cmp rax, 0
    jne GDPSgood
    mov rax, [RETURN_INVALID_ARGUMENT] ;DevicePath is either null or something else, so it's invalid :(
    ret
    
    GDPSgood:
    mov rax, [RETURN_SUCCESS]
    ret

相关问题