研究了一下在Winload和grub2中都是怎么实现控制权到内核的转移的。
winload
在winload中负责这一操作的主要是OslExecuteTransition函数,其中调用了两个关键函数:OslFwpKernelSetupPhase1和OslArchTransferToKernel。
OslFwpKernelSetupPhase1调用ExitBootService来结束启动服务,将控制权从UEFI转移给OS Loader。
执行完gBS->ExitBootServices之后,EFI_BOOT_SERVICES表和控制器设备句柄将会清零,同时EfiBootServicesCode和EfiBootServicesData类型的内存资源将被释放。保留运行时服务、EFI_Configuration_Table以及固件版本号和固件开发商名称字符串以供OS Loader和操作系统使用。

而之后调用OslArchTransferToKernel则是为了将控制权从OS Loader转移到内核入口点KiSystemStartup,通过Hook该函数可以在调用KiSystemStartup之前获得控制权,并借此注入恶意代码。

Grub2
在grub2里主要由grub_relocator32_boot()来实现跳转到内核执行。
grub_err_t
grub_relocator32_boot (struct grub_relocator *rel,
struct grub_relocator32_state state,
int avoid_efi_bootservices)
{
grub_err_t err;
void *relst;
grub_relocator_chunk_t ch;
/* Specific memory range due to Global Descriptor Table for use by payload
that we will store in returned chunk. The address range and preference
are based on "THE LINUX/x86 BOOT PROTOCOL" specification. */
err = grub_relocator_alloc_chunk_align_safe (rel, &ch, 0x1000, 0x9a000,
RELOCATOR_SIZEOF (32), 16,
GRUB_RELOCATOR_PREFERENCE_LOW,
avoid_efi_bootservices);
if (err)
return err;
grub_relocator32_eax = state.eax;
grub_relocator32_ebx = state.ebx;
grub_relocator32_ecx = state.ecx;
grub_relocator32_edx = state.edx;
grub_relocator32_eip = state.eip;
grub_relocator32_esp = state.esp;
grub_relocator32_ebp = state.ebp;
grub_relocator32_esi = state.esi;
grub_relocator32_edi = state.edi;
grub_memmove (get_virtual_current_address (ch), &grub_relocator32_start,
RELOCATOR_SIZEOF (32));
err = grub_relocator_prepare_relocs (rel, get_physical_target_address (ch),
&relst, NULL);
if (err)
return err;
asm volatile ("cli");
((void (*) (void)) relst) ();
/* Not reached. */
return GRUB_ERR_NONE;
}首先将state的各个寄存器复制到ch指向的地址。
再调用grub_relocator_prepare_relocs将ch内容转换为重定位的指令,由relst指向该重定位的指令地址。
asm volatile ("cli")关闭外部中断。
((void (*) (void)) relst) ();执行跳转到内核的入口点。

近期评论