Upgrade to Pro — share decks privately, control downloads, hide ads and more …

EFI Byte Code Virtual Machine for Fun and Profit

Akira Moroo
November 10, 2018

EFI Byte Code Virtual Machine for Fun and Profit

EFI Byte Code (EBC) is a byte code for EFI. Its aim is to implement platform- and processor-independent EFI device drivers. In this presentation, I introduce EBC and ebcvm, EBC Virtual Machine in userspace from scratch.

Akira Moroo

November 10, 2018
Tweet

More Decks by Akira Moroo

Other Decks in Technology

Transcript

  1. EFI Byte Code Virtual Machine for Fun and Profit November

    10, 2018 @kernelvm Hokuriku Part 4 @retrage
  2. 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
  3. 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
  4. 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
  5. 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
  6. 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
  7. 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
  8. 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
  9. 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
  10. 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
  11. 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
  12. 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]
  13. 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
  14. 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;
  15. 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
  16. 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”);
  17. 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
  18. 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
  19. 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
  20. 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
  21. 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
  22. 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