Slide 1

Slide 1 text

EFI Byte Code Virtual Machine for Fun and Profit November 10, 2018 @kernelvm Hokuriku Part 4 @retrage

Slide 2

Slide 2 text

Recap: UEFI • Unified Extensible Firmware Interface (UEFI) • Based on EFI, developed for IA-64 by Intel. • Standardized by UEFI Forum[1]. • You can find the specification online[2]. • Supporting many platforms. • IA-32, x64, ARM, ARM64, RISC-V etc. • A lot of features compared with Legacy BIOS. • => Almost all x86-based PCs are shipped with UEFI. 1

Slide 3

Slide 3 text

EFI Byte Code (EBC) • ”platform- and processor-independent mechanisms for loading and executing EFI device drivers” – UEFI Specification • Operating System Independece • Processor Independence • Byte Code for EFI device drivers • Used in PCIe OptionROM (OROM) • OROM is executables located on a PCI device[8] • To support multiple architectures • In reality, most of OROM are x64 native code 2

Slide 4

Slide 4 text

Documents and Tools about EBC • Documents • UEFI Specification[2] • TianoCore/EDK2 source code[3] • Some blog posts[4][5] • Tools • Intel C Compiler for EFI Byte Code[6] • $995!! • fasmg-ebc[7] • fasmg based EBC assembler • Partly supports EFI Runtimes • => No GCC/Clang support or disassembler 3

Slide 5

Slide 5 text

EBC VM Architecture • 64-bit little endian • 10 registers: IP, FLAGS, and 8 G.P. registers(R0-R7) • R0: Pointer to the top of stack • R7: Function return value 4 IP FLAGS R0 R1-R6 R7 RV2-RV7

Slide 6

Slide 6 text

EBC Binary Format • Portable Executable: PE32+ • Windows and UEFI use the format. • Fun fact: FileHeader->Machine is 0x0ebc • Relocatable Image 5 Machine: ebc Number of Section: 2 Time Stamp: 1541744287 Size of Optional Header: 240 This file is DLL. PE+ AddressOfEntryPoint: 1000 ImageBase: 400000 SectionAlignment: 1000 FileAlignment: 200 SizeOfImage: 3000 SizeOfHeaders: 200 Section 0 Name: .text VirtualSize: 1c VirtualAddress: 1000 SizeOfRawData: 200 PointerToRawData: 200 PointerToRelocations: 0 PointerToLinenumbers: 0 NumberOfRelocations: 0 NumberOfLinenumbers: 0 Characteristics: 60000020 r-x exec

Slide 7

Slide 7 text

EBC Calling Convention • CDECL • In x64 native code, UEFI uses Microsoft x64 Calling Convention • Example: func(arg0, arg1, arg2); 6 return address arg0 arg2 Low High Stack top arg1 arg2 arg2 base Low High Stack top arg2 base • Arguments are passed via stack • Caller pops arguments

Slide 8

Slide 8 text

Natural Indexing 7 N N-1...N-3 N-4...A A-1...0 sign bit () Bits assigned to natural units () Constant units () Natural units () • N can be 16, 32, 64-bits in size • A is a number from ( = ∗ / 8) • Offset represented in Natural Indexing is decoded: • = + ∗ ( ∗) ∗ • ( ∗) depends on the host

Slide 9

Slide 9 text

Natural Indexing: Example • Let’s decode 16-bit index 0xa048 8 1010000001001000 • b = -1, w = 4, c = 4, n = 8 • On 64-bit machine: • = 4 + 8 ∗ 8 ∗ −1 = −68 • On 32-bit machine: • = 4 + 8 ∗ 4 ∗ −1 = −36

Slide 10

Slide 10 text

Instruction Set • Variable-length, CISC-like instructions • 56 types of Instructions • Arithmetic ops (+, -, *, /, &, |, ^, <<, >>, ~, !) • MOV ops (MOV, MOVI, MOVIn, MOVREL, MOVn) • CMP ops (CMP, CMPI) • JMP ops (JMP, JMP8) • Stack ops (POP, POPn, PUSH, PUSHn) • LOADSP, STORESP • EXTND ops • CALL, RET, BREAK • => Few, but enough instructions 9

Slide 11

Slide 11 text

Instruction Operands • Form: INSTRUCTION Operand1, Operand2 • Direct • Example: ADD64 R1, R2 • Indirect • Example: ADD32 R1, @R2 • Indirect with Index • @R1 (+n, +c) • Example: ADD32 R1, @R2(+1, +8) • Immediate • Example: MOVIww R1, 0x1234 10

Slide 12

Slide 12 text

Instruction Example: XOR • XOR[32|64] {@}R1 , {@}R2 {Index16|Immed16} • Op1 <= Op1 XOR Op2 11 • Byte0-Bit7 = 1 && Byte1-Bit7 = 0 • R2 + Imm16 • Byte0-Bit7 = 1 && Byte1-Bit7 = 1 • [R2 + Idx16]

Slide 13

Slide 13 text

Call to Native Code • The CALL instruction supports: • Call to EBC/Native code (EXCALL) • To support native code execution: • Some instructions are for native code • Example: MOVn, MOVIn, MOVsn, POPn, PUSHn • Typical usage: • Execute platform-specific process • Calling Runtimes (RuntimeServices, BootServices etc.) 12

Slide 14

Slide 14 text

typedef struct EFI_SYSTEM_TABLE { EFI_TABLE_HEADER Hdr; VOID_PTR FirmwareVendor; UINT32 FirmwareRevision; EFI_HANDLE ConsoleInHandle; VOID_PTR ConIn; EFI_HANDLE ConsoleOutHandle; VOID_PTR ConOut; EFI_HANDLE StandardErrorHandle; VOID_PTR StdErr; VOID_PTR RuntimeServices; VOID_PTR BootServices; UINTN NumberOfTableEntries; VOID_PTR ConfigurationTable; } EFI_SYSTEM_TABLE; Runtimes 13 typedef struct EFI_MAIN_PARAMETERS { EFI_HANDLE ImageHandle; VOID_PTR SystemTable; } EFI_MAIN_PARAMETERS;

Slide 15

Slide 15 text

EBC VM Exceptions • EBC VM raises exceptions: • Divide By 0, Debug Break, Invalid Opcode, Stack Fault, Alignment, Instruction Encoding, Bad Break, Undefined • If debugger is attached to VM, exceptions are captured by debugger • Via EFI debug supprt protocol • If debugger is not attached: • display error message and halt the system • hang the system • ignore the exception and continue 14

Slide 16

Slide 16 text

EBC Assembly: Example section '.text' code executable readable EfiMain: MOVn R1, @R0(EFI_MAIN_PARAMETERS.SystemTable) MOVn R1, @R1(EFI_SYSTEM_TABLE.ConOut) MOVREL R2, Hello PUSHn R2 ; Push Pointer to Hello PUSHn R1 ; Push Pointer to SystemTable->ConOut CALLEX @R1(SIMPLE_TEXT_OUTPUT_INTERFACE.OutputString) MOV R0, R0(+2,0) RET section '.data' data readable writeable Hello: du "Hello EBC World!", 0x0D, 0x0A, 0x00 15 SystemTable->Conout->OutputString( SystemTable->ConOut, “Hello EBC World!\r\n”);

Slide 17

Slide 17 text

ebcvm • Motivation: • It is difficult to try EBC without QEMU or hardware. • There is only a few documents about EBC. • Can I write an emulator for EBC with UEFI Spec? • An EBC interpreter in userspace from scratch • It supports all the instructions • Few native code execution emulation (WIP) • Simple debugger support • Still work in progress: https://github.com/yabits/ebcvm 16

Slide 18

Slide 18 text

ebcvm: Overview 17 • Loader loads an EBC executable to memory. • VM executes the byte code. • VM traps EXCALLs and call EFI Native Code • VM traps exceptions and debugger handles them. Registers Memory Decoder Executor Loader EFI Native Code Simple Debugger

Slide 19

Slide 19 text

ebcvm: VM • Decoder: • Decoder decodes the instruction. • Well tested (test code: 2277 LoC) • Executor: • Executor executes the instruction. • read/write reg/mem • Well tested (test code: 8490 LoC) 18 Registers Memory Decoder Executor

Slide 20

Slide 20 text

Summary & Future work • EFI Byte Code (EBC) is a byte code which is platform-, processor-independent for EFI. • Natural Indexing is a mechanism for supporting 32-, 64-bit processor • EBC VM can call native code. • ebcvm: • userspace EBC interpreter from scratch. • Future work: • Support more native UEFI runtimes • Add disassembly for debugging 19

Slide 21

Slide 21 text

References • [1] https://uefi.org/ • [2] https://uefi.org/specifications • [3] https://github.com/tianocore/edk2 • [4] http://vzimmer.blogspot.com/2015/08/efi-byte-code.html • [5] https://habr.com/post/201954/ • [6] https://software.intel.com/en-us/articles/intel-c-compiler-for- efi-byte-code- purchase/?_ga=2.177917472.440178022.1541746062- 392223130.1541746062 • [7] https://github.com/pbatard/fasmg-ebc • [8] http://opensecuritytraining.info/IntroBIOS_files/Day1_06_Advanc ed%20x86%20-%20BIOS%20and%20SMM%20Internals%20- %20PCI%20XROMs.pdf 20

Slide 22

Slide 22 text

EBC Interpreter Protocol • CreateThunk • Create a thunk for an EBC entry point from EBC image. • UnloadImage • After an EBC image has exited, call this to unload image. • RegisterICacheFlush • “Register a callback function that the EBC interpreter calls to flush the processor instruction cache following creation of thunks” • GetVersion • ”Called to get the version of the interpreter” 21