我们继续之前的话题:在一个已经编译成功的 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 的大小需要更新)。