Chain load Grub from Windows Boot Manager?
On last post I got Windows Boot Manager to load GRUB (or what seems like it) on QEMU. Since then I was trying to cross-compile a newer version of GRUB for ARM and then load this newer version, instead of the original EFI partition I used when writing that post. That was harder than I first thought.
I didn’t get it to work. For now I’ll stick with that original GRUB imagine, knowing that the though of it will bug for a while - I got really curious to know how that image was made. I thought of recording whatever I found so far, in case I decide to continue investigating this in the future, or someone else is trying the same thing.
UEFI loaders are PE files. So I first started to compare the PE headers from the RoL’s GRUB image (from the last post) with the one I built:
RoL’s image headers
DOS Header
Magic number: 0x5a4d (MZ)
Bytes in last page: 144
Pages in file: 3
Relocations: 0
Size of header in paragraphs: 4
Minimum extra paragraphs: 0
Maximum extra paragraphs: 65535
Initial (relative) SS value: 0
Initial SP value: 0xb8
Initial IP value: 0
Initial (relative) CS value: 0
Address of relocation table: 0x40
Overlay number: 0
OEM identifier: 0
OEM information: 0
PE header offset: 0xd8
COFF/File header
Machine: 0x1c4 IMAGE_FILE_MACHINE_ARMV7
Number of sections: 7
Date/time stamp: 1471559823 (Thu, 18 Aug 2016 22:37:03 UTC)
Symbol Table offset: 0
Number of symbols: 0
Size of optional header: 0xe0
Characteristics: 0x122
Characteristics names
IMAGE_FILE_EXECUTABLE_IMAGE
IMAGE_FILE_LARGE_ADDRESS_AWARE
IMAGE_FILE_32BIT_MACHINE
Optional/Image header
Magic number: 0x10b (PE32)
Linker major version: 11
Linker minor version: 0
Size of .text section: 0x3a00
Size of .data section: 0x2e00
Size of .bss section: 0
Entrypoint: 0x1691
Address of .text section: 0x1000
Address of .data section: 0x6000
ImageBase: 0x400000
Alignment of sections: 0x1000
Alignment factor: 0x200
Major version of required OS: 0
Minor version of required OS: 0
Major version of image: 0
Minor version of image: 0
Major version of subsystem: 1
Minor version of subsystem: 0
Size of image: 0xc000
Size of headers: 0x400
Checksum: 0xd560
Subsystem required: 0x10 (IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION)
DLL characteristics: 0
DLL characteristics names
Size of stack to reserve: 0x100000
Size of stack to commit: 0x1000
Size of heap space to reserve: 0x100000
Size of heap space to commit: 0x1000
My GRUB image headers
DOS Header
Magic number: 0x5a4d (MZ)
Bytes in last page: 144
Pages in file: 3
Relocations: 0
Size of header in paragraphs: 4
Minimum extra paragraphs: 0
Maximum extra paragraphs: 65535
Initial (relative) SS value: 0
Initial SP value: 0xb8
Initial IP value: 0
Initial (relative) CS value: 0
Address of relocation table: 0x40
Overlay number: 0
OEM identifier: 0
OEM information: 0
PE header offset: 0x80
COFF/File header
Machine: 0x1c2 IMAGE_FILE_MACHINE_THUMB
Number of sections: 4
Date/time stamp: 1420070400 (Thu, 01 Jan 2015 00:00:00 UTC)
Symbol Table offset: 0
Number of symbols: 0
Size of optional header: 0xe0
Characteristics: 0x30e
Characteristics names
IMAGE_FILE_EXECUTABLE_IMAGE
IMAGE_FILE_LINE_NUMS_STRIPPED
IMAGE_FILE_LOCAL_SYMS_STRIPPED
IMAGE_FILE_32BIT_MACHINE
IMAGE_FILE_DEBUG_STRIPPED
Optional/Image header
Magic number: 0x10b (PE32)
Linker major version: 0
Linker minor version: 0
Size of .text section: 0xb800
Size of .data section: 0xa99a00
Size of .bss section: 0
Entrypoint: 0x400
Address of .text section: 0x400
Address of .data section: 0xbc00
ImageBase: 0
Alignment of sections: 0x200
Alignment factor: 0x200
Major version of required OS: 0
Minor version of required OS: 0
Major version of image: 0
Minor version of image: 0
Major version of subsystem: 0
Minor version of subsystem: 0
Size of image: 0xaa5e00
Size of headers: 0x400
Checksum: 0
Subsystem required: 0xa (IMAGE_SUBSYSTEM_EFI_APPLICATION)
DLL characteristics: 0
DLL characteristics names
Size of stack to reserve: 0x10000
Size of stack to commit: 0x10000
Size of heap space to reserve: 0x10000
Size of heap space to commit: 0x10000
I used the PEV toolkit to get those headers.
Some things are quite obvious. I’ll go through them. To begin with, the machine header are different. Both are ARM, but one is ARMv7 and the other is Thumb. I couldn’t really compile GRUB such to match ARMv7, even passing -march=armv7 to GCC. I am probably doing something wrong.
It is curious though. When you compile GRUB, you get a set of tools like grub-mkstandalone. Those tools are compile to your BUILD platform, that is, the platform you are building on (x86 in my case). This makes sense, because you will use these tools to then generate the final GRUB image. This image is generate, as far as I understood, from the modules that are build as part of GRUB. However, those modules are ELF files, according to /bin/file:
acpi.mod: ELF 32-bit LSB relocatable, ARM, EABI5 version 1 (SYSV), not stripped
So I imagine that grub-mkstandalone actually concatenates all the modules required and transform them in a PE file when building the final imagine. So would be it the responsible to set the PE machine header to ARMV7 and my cross-compilation doesn’t really matter? I have no clue :(
Here’s how I cross-compile GRUB, should you need to do something similar:
./autoconfig
./configure --with-platform=efi --prefix=/usr --target=arm-none-eabi
make CFLAGS="-march=armv7 -Wno-unused-value"
make DESTDIR=/tmp/grub install
cd /tmp/grub
/tmp/grub/usr/bin/grub-mkstandalone -o boot.img -O arm-efi -d /tmp/grub/usr/lib/grub/arm-efi
Long story short, I am not sure how much a problem that is, after all. If I bypass Windows Boot Manager and makes UEFI load my GRUB image directly, it works. So I don’t really know how much Windows Boot Manager cares about this header.
The other two red flags were the headers Checksum and Subsystem required. This forum post was the closed I came to a solution. It talks about how the Subsystem required needs to be set to IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION. I tried manually changing that header to match it, along side with fixing the checksum (using this code that seemed to give valid checksum when I compared with valid PE files I have). None of that helped.
Another interesting point discussed on that forum thread and that also caught my eye was the fact that the entry point for both PE files differed. Not quite sure how much that could be because of the different instruction set (if at all), but that may indicate that the RoL’s GRUB was generated in a very different way than I am doing, and fiddling with headers might not be enough.
Anyways, that’s how far I got. If you have any points on the topic, do let me know!