Step to UEFI (295)手工给 EFI 文件插入代码的试验 (下)

我们继续之前的话题:在一个已经编译成功的 SimpleTest.EFI 中,加入另外一个 Hello.EFI 程序,最终实现Shell 下输入 SimpleTest.EFI, 实际上运行了SimpleTest.EFI 和 Hello.EFI。

前面的代码我们已经实现了大部分,还有一些细节需要处理。

第一个需要注意的是,我们Hello.EFI 是 NASM 生成的,其中有很多对于寄存器和堆栈的操作,这个操作会破坏SimpleTest.efi 需要的运行环境,导致无法跳入后执行出错。

仔细观察 SimpleTest.EFI 反编译结果,在开始处从 Shell 下收到的参数需是放在 rbx 和 rsi 寄存器中的,我们必须妥善保存这两个寄存器才能保证后续的正确运行。

代码头部修改如下:

_start:
	push rdx
	push rcx
	push rdi
	
    push rbx
	push rsi
	
    push rax    ;ConOut requires a push here. I don't know why
 
    ; reserve space for 4 arguments
    sub rsp, 4 * 8

代码尾部修改如下:
    add rsp, 4 * 8
    pop rax     

	pop rsi
	pop rbx
	
	pop rdi
	pop rcx
	pop rdx

	times 20 nop

再次生成一个新的 hello.efi(注意,这样修改之后的代码无法像之前的 EFI Application一样运行了), 用HXD 打开后拷贝代码区放置到 SimpleText.EFI 中。

此外,还有两个位置需要修改:

1.在拷贝到到 SimpleTest.EFI 的带末尾放上 mov  [rsp+0x08],rbx/mov [rsp+x010],rsi 两个操作;

2.跳转回文件头部的指令:

经过这样的改造,在模拟器中测试可以看到:

执行 SimpleTest.EFI 得到了2个输出,这个说明确实运行了2个EFI 。

修改后的 Hello.ASM 相关程序:

修改后的 SimpleTestM.EFI 文件

本文特别感谢Windows 专家天杀提供帮助。他对于 WinPE 结构的非常了解,帮助解决了修改EFI后, 使用模拟器测试崩溃的问题(Section Header 中 .TEXT 的大小需要更新)。