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

EFI Byte Code Virtual Machine for Fun and Profit

8dc3958dc2480bd681e4b5c197817047?s=47 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.

8dc3958dc2480bd681e4b5c197817047?s=128

Akira Moroo

November 10, 2018
Tweet

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