Implementing an LLVM based D ynamic B inary I nstrumentation - - PowerPoint PPT Presentation

implementing an llvm based d ynamic b inary i
SMART_READER_LITE
LIVE PREVIEW

Implementing an LLVM based D ynamic B inary I nstrumentation - - PowerPoint PPT Presentation

Implementing an LLVM based D ynamic B inary I nstrumentation framework Charles Hubain Cdric Tessier Introduction to Instrumentation 34c3 - Implementing an LLVM based DBI framework 2 What is Instrumentation? Transformation of a program


slide-1
SLIDE 1

Implementing an LLVM based Dynamic Binary Instrumentation framework

Charles Hubain Cédric Tessier

slide-2
SLIDE 2

Introduction to Instrumentation

34c3 - Implementing an LLVM based DBI framework

2

slide-3
SLIDE 3

What is Instrumentation?

  • “Transformation of a program into its own measurement tool”
  • Observe any state of a program anytime during runtime
  • Automate the data collection and processing

34c3 - Implementing an LLVM based DBI framework

3

slide-4
SLIDE 4

Use Cases

  • Finding memory bugs:
  • Track memory allocations / deallocations
  • Track memory accesses
  • Fuzzing:
  • Measure code coverage
  • Build symbolic representation of code
  • Recording execution traces
  • Replay them for “timeless” debugging
  • Software side-channel attacks against crypto

34c3 - Implementing an LLVM based DBI framework

4

slide-5
SLIDE 5

“Why not … debuggers?”

  • Debuggers are awesome but slooooooooow

Debugger Kernel Target

Resume Schedule Trap interrupt Signal + schedule

34c3 - Implementing an LLVM based DBI framework

5

slide-6
SLIDE 6

https://asciinema.org/a/17nynlopg5a18e1qps3r9ou7g

slide-7
SLIDE 7

“Why not … debuggers?”

  • Debuggers are awesome but slooooooooow

Debugger Kernel Target

Resume Schedule Trap interrupt Signal + schedule

  • Solution? Get rid of the kernel
  • How? Run the instrumentation inside the target

34c3 - Implementing an LLVM based DBI framework

7

slide-8
SLIDE 8

Instrumentation Techniques

  • From source code:
  • Manually, you know … printf(…)
  • At compile time
  • From binary:
  • Static binary patching & hooking
  • Dynamic Binary Instrumentation

BORING

Crude and barbaric

This talk

34c3 - Implementing an LLVM based DBI framework

8

slide-9
SLIDE 9

Existing Frameworks

  • Valgrind since 2000
  • Open source, only *nix platforms, very complex
  • DynamoRIO since 2002
  • Open source, cross-platforms, very raw
  • Intel Pin since 2004
  • Closed source, only Intel platforms, user friendly

34c3 - Implementing an LLVM based DBI framework

9

slide-10
SLIDE 10

“Why we made our own”

  • Cross-platform and cross-architecture
  • Mobile and embedded targets support
  • Simpler and modular design
  • Focus on “heavy” instrumentation

What we wanted from a DBI framework in 2015

34c3 - Implementing an LLVM based DBI framework

10

slide-11
SLIDE 11

Introduction to DBI

34c3 - Implementing an LLVM based DBI framework

11

slide-12
SLIDE 12

Dynamic Binary Instrumentation

  • Dynamically insert the instrumentation at runtime

Original Binary Code

Disassemble Generate Instrumentation Insert Execute

Instru PAC-MAN for scale 34c3 - Implementing an LLVM based DBI framework

12

slide-13
SLIDE 13

Disassembling

  • What part of the binary is the code is unknown

➡ Disassembling the whole binary in advance is

impossible

  • We need to discover the code as we go

34c3 - Implementing an LLVM based DBI framework

13

slide-14
SLIDE 14

Code Discovery

  • How?
  • Execute a block of code
  • Discover where the execution flow after the block
  • Execute the next block of code
  • This forms a short execution cycle

34c3 - Implementing an LLVM based DBI framework

14

slide-15
SLIDE 15

No Free Space

Instruction Instruction Instruction … COND JUMP Instruction Instruction Instruction … JUMP Instruction Instruction Instruction … JUMP

FALSE TRUE

  • The instrumented code is larger than

the original code

  • Binaries are usually tightly packed with

little free space

➡ The instrumentation cannot be

inserted in-place

➡ It needs to be “relocated”

34c3 - Implementing an LLVM based DBI framework

15

slide-16
SLIDE 16

Relocating

  • Code contains relative reference to memory addresses
  • These become invalid once we move the code
  • We need to completely rewrite the code to fix those

references

➡ This is what we call “patching”

34c3 - Implementing an LLVM based DBI framework

16

slide-17
SLIDE 17

The “Cycle of Life”

34c3 - Implementing an LLVM based DBI framework

17

slide-18
SLIDE 18

Designing a DBI:

  • 1. Low Level Abstractions

34c3 - Implementing an LLVM based DBI framework

18

slide-19
SLIDE 19

Instruction Instruction Instruction … Instruction Instruction Instruction … Instruction Instruction Instruction … Instruction Instruction Instruction …

Basic Blocks

34c3 - Implementing an LLVM based DBI framework

19

slide-20
SLIDE 20

Instruction Instruction Instruction … Instruction Instruction Instruction … Instruction Instruction Instruction … Instruction Instruction Instruction … JUMP JUMP JUMP JUMP

Control Flow

34c3 - Implementing an LLVM based DBI framework

20

slide-21
SLIDE 21

Under Control Flow

Instruction Instruction Instruction … JUMP Instruction Instruction Instruction … JUMP Instruction Instruction Instruction … JUMP Instruction Instruction Instruction … JUMP

DBI

Guest Host

34c3 - Implementing an LLVM based DBI framework

21

slide-22
SLIDE 22

Under Control

DBI is all about keeping control of the execution

34c3 - Implementing an LLVM based DBI framework

22

slide-23
SLIDE 23

Under Control

  • Keeping control of the execution
  • requires modifying original instructions…
  • …without modifying original behaviour

34c3 - Implementing an LLVM based DBI framework

23

slide-24
SLIDE 24

What We Need

  • A multi-architecture disassembler
  • A multi-architecture assembler
  • A generic intermediate representation to apply

modifications on

34c3 - Implementing an LLVM based DBI framework

24

slide-25
SLIDE 25

We Don't Want

  • To implement a multi-architecture disassembler and

assembler

  • To abstract every single instruction semantic
  • Architectures Developer Manuals are not that fun…

Actually we don’t have 10 years and unlimited ressources

34c3 - Implementing an LLVM based DBI framework

25

slide-26
SLIDE 26

Here Be Dragons

This has nothing to do with 26C3

34c3 - Implementing an LLVM based DBI framework

26

slide-27
SLIDE 27

To the rescue

  • LLVM already has everything
  • It supports all major architectures
  • It provides a disassembler and an assembler…
  • …and both work on the same intermediate

representation

  • LLVM Machine Code (aka MC) to the rescue

34c3 - Implementing an LLVM based DBI framework

27

slide-28
SLIDE 28

LLVM MC

<MCInst #1670 MOV64mr <MCOperand Reg:0> <MCOperand Imm:1> <MCOperand Reg:0> <MCOperand Imm:42> <MCOperand Reg:0> <MCOperand Reg:35>>

movq rax, 42

[0x48,0x89,0x04,0x25,0x2a,0x00,0x00,0x00] Binary Instruction LLVM MC

34c3 - Implementing an LLVM based DBI framework

28

slide-29
SLIDE 29

LLVM MC

  • It’s minimalist
  • It’s totally generic
  • still encodes a lot of things about an instruction
  • But very raw
  • genericness means some heavy compromises
  • doesn’t encode everything about an instruction

34c3 - Implementing an LLVM based DBI framework

29

slide-30
SLIDE 30

Creation

movq [rip+0x2600], rax

<MCInst #1139 MOV64mr <MCOperand Reg:41> <MCOperand Imm:1> <MCOperand Reg:0> <MCOperand Imm:0x2600> <MCOperand Reg:0> <MCOperand Reg:35>>

Every instruction is encoded using the same representation… … but in a different way

34c3 - Implementing an LLVM based DBI framework

30

slide-31
SLIDE 31

Modification

<MCInst #1141 JMP_1 <MCOperand Imm: 0x41424242>> <MCInst #1139 JMP64m <MCOperand Reg:41> <MCOperand Imm:1> <MCOperand Reg:0> <MCOperand Imm:0x2600> <MCOperand Reg:0>>

jmp 0x41424242 jmp [rip+0x2600]

34c3 - Implementing an LLVM based DBI framework

31

slide-32
SLIDE 32

Patch

mov r0, [r0+pc]

; Load a value relative to PC

0x410000:

34c3 - Implementing an LLVM based DBI framework

32

slide-33
SLIDE 33

0x7f10000:

; Load a value relative to R1

mov r0, [r0+r1]

Patch

mov r1, 0x410000 mov [pc+0x2600], r1 mov r1, [pc+0x2600]

; Set original instruction address ; Backup R1 ; Restore R1

34c3 - Implementing an LLVM based DBI framework

33

slide-34
SLIDE 34

Abstractions

  • MCInst encoding make transformations painful
  • Patches can be really complex
  • Many transformations are composed of generic steps

we need abstractions

34c3 - Implementing an LLVM based DBI framework

34

slide-35
SLIDE 35

Patch Engine

Patch Engine

MCInst MCInst MCInst MCInst

Abstractions Inside™

34c3 - Implementing an LLVM based DBI framework

35

slide-36
SLIDE 36

36

slide-37
SLIDE 37

Patch DSL

  • Identify transformation steps required to patch instructions
  • Regroup and integrate them as a domain-specific language
  • Instructions are architecture specifics…
  • …DSL should be generic (as much as possible)

Abstractions you said?

34c3 - Implementing an LLVM based DBI framework

37

slide-38
SLIDE 38

Patch DSL

Registry Memory Program QBDI Reg Context T emp Shadows, Metadata Copy Load/Save W r i t e Get/Set

34c3 - Implementing an LLVM based DBI framework

38

slide-39
SLIDE 39

Patch DSL

Temp(0)

mov [pc+0x2600], r1 mov r1, 0x410000 […] mov r1, [pc+0x2600]

34c3 - Implementing an LLVM based DBI framework

39

slide-40
SLIDE 40

Patch DSL

SubstituteWithTemp(Reg(REG_PC), Temp(0))

mov [pc+0x2600], r1 mov r1, 0x410000 mov r0, [r0+r1] mov r1, [pc+0x2600]

34c3 - Implementing an LLVM based DBI framework

40

slide-41
SLIDE 41

Patch DSL

  • Modifications are defined in rules
  • A rule is composed of
  • one (or several) condition(s)
  • one (or several) action(s)
  • Actions can modify or replace an instruction

34c3 - Implementing an LLVM based DBI framework

41

slide-42
SLIDE 42

Patch DSL

/* Rule #3: Generic RIP patching. * Target: Any instruction with RIP as operand, e.g. LEA RAX, [RIP + 1] * Patch: Temp(0) := rip * LEA RAX, [RIP + IMM] --> LEA RAX, [Temp(0) + IMM] */ PatchRule( UseReg(Reg(REG_PC)), { GetPCOffset(Temp(0), Constant(0)), ModifyInstruction({ SubstituteWithTemp(Reg(REG_PC), Temp(0)) }) } );

34c3 - Implementing an LLVM based DBI framework

42

slide-43
SLIDE 43

Patch DSL

/* Rule #0: Simulating BX instructions. * Target: BX REG * Patch: Temp(0) := Operand(0) * DataOffset[Offset(PC)] := Temp(0) */ PatchRule( Or({ OpIs(llvm::ARM::BX), OpIs(llvm::ARM::BX_pred) }), { GetOperand(Temp(0), Operand(0)), WriteTemp(Temp(0), Offset(Reg(REG_PC))) } );

34c3 - Implementing an LLVM based DBI framework

43

slide-44
SLIDE 44

Lessons Learned

  • LLVM provides robust foundations for modifying binary

code

  • Abstractions on top of it are:
  • vital to make quite a simple intermediate

representation do complex things

  • very (very) hard to conceptualise

34c3 - Implementing an LLVM based DBI framework

44

slide-45
SLIDE 45

Designing a DBI:

  • 2. Cross-Architecture Support

34c3 - Implementing an LLVM based DBI framework

45

slide-46
SLIDE 46

Host and Guest

Process Host

DBI Engine Instrumentation Tool

Guest

Original Binary Instrumented Code

34c3 - Implementing an LLVM based DBI framework

46

slide-47
SLIDE 47

Context Switch

  • They share the same memory and the same CPU

context

  • We need to switch between those two contexts at every

cycle

  • No help from the kernel or the CPU

34c3 - Implementing an LLVM based DBI framework

47

slide-48
SLIDE 48

Context Switch

  • Save / restore CPU context from guest / host
  • Avoid any side effects on the guest
  • We can’t modify its stack
  • We can’t erase any register

➡ We need to relatively address host memory from the

guest

34c3 - Implementing an LLVM based DBI framework

48

slide-49
SLIDE 49

Relative Addressing

  • Constrained by CPU architecture capabilities
  • Limited to +/- 4096 under ARM

➡ We need host memory next to guest code

  • We want to play nice with Data Execution Prevention

➡ Allocate 2 contiguous memory pages:

  • Code block in Read eXecute
  • Data block in Read Write

34c3 - Implementing an LLVM based DBI framework

49

slide-50
SLIDE 50

ExecBlock

Code Block RX

Prologue Instrumented Code Epilogue

Data Block RW

Guest Context Host Context

34c3 - Implementing an LLVM based DBI framework

50

slide-51
SLIDE 51

ExecBlock

  • Bind instrumented code and instrumentation data
  • Data is guaranteed to be directly addressable
  • 4 KB pages give us a lot of space…
  • We can put multiple instrumented basic blocks in the code

block

  • We can put more than just context in the data block

34c3 - Implementing an LLVM based DBI framework

51

slide-52
SLIDE 52

Things Got More Complex …

Code Block RX

Prologue

JMP selector

Basic Block 0 Epilogue

Data Block RW

Guest Context Host Context

selector

Basic Block 1 Constants & Shadows

34c3 - Implementing an LLVM based DBI framework

52

slide-53
SLIDE 53

Making 4K Useful

  • Instrumentation constants
  • used in the same way as ARM’s literal pool
  • Instruction shadows
  • “instruction analog” to Valgrind's memory shadow
  • instrumentation variable abstraction
  • can be used to record memory accesses

34c3 - Implementing an LLVM based DBI framework

53

slide-54
SLIDE 54

What We Need

  • A cross-platform memory management abstraction
  • allocating memory pages
  • changing page permissions
  • A cross-architecture assembler working in-memory
  • It’s not just about building binary objects in-memory

34c3 - Implementing an LLVM based DBI framework

54

slide-55
SLIDE 55

Guess What?

34c3 - Implementing an LLVM based DBI framework

55

slide-56
SLIDE 56

LLVM JIT

  • LLVM already has several JIT engine
  • They are very well designed…
  • …but none of them fitted our strict constraints
  • LLVM provides everything to create a custom one
  • cross-architecture memory management abstraction
  • powerful in-memory assembler (LLVM MC)

34c3 - Implementing an LLVM based DBI framework

56

slide-57
SLIDE 57

Lessons learned

  • LLVM is perfect for creating a JIT
  • Designing a JIT engine for DBI is hard
  • Really easy to make a design locked down on a particular CPU

architecture

  • Portability need to be taken into account from the start

34c3 - Implementing an LLVM based DBI framework

57

slide-58
SLIDE 58

QBDI

  • Linux, macOS, Windows, Android and iOS
  • User friendly
  • easy to use C/C++ APIs
  • extensive documentation
  • binary packages for all major OS
  • Modular design (Unix philosophy)

QuarkslaB Dynamic binary Instrumentation is a modular, cross-platform and cross-architecture DBI framework

34c3 - Implementing an LLVM based DBI framework

58

slide-59
SLIDE 59

QBDI

  • Modularity stands for:
  • core only provides what is essential
  • don’t force users to do thing in your way
  • easy integration everywhere
  • Fun and flexible Python bindings
  • Full featured integration with Frida

34c3 - Implementing an LLVM based DBI framework

59

slide-60
SLIDE 60

Roadmap

  • Improve ARM architecture support
  • Thumb-2
  • Memory Access information
  • ARMv8 (AArch64)
  • Add SIMD memory access
  • Multithreading and exceptions
  • probably not as part of the core engine (KISS)

34c3 - Implementing an LLVM based DBI framework

60

slide-61
SLIDE 61

Demo time!

34c3 - Implementing an LLVM based DBI framework

61

slide-62
SLIDE 62

pyQBDI

import pyqbdi; def printInstruction(vm, gpr, fpr, data): inst = vm.getInstAnalysis() print "0x%x %s" % (inst.address, inst.disassembly) return pyqbdi.CONTINUE def pyqbdipreload_on_run(vm, start, stop): state = vm.getGPRState() success, addr = pyqbdi.allocateVirtualStack(state, 0x100000) funcPtr = ctypes.cast(aLib.aFunction, ctypes.c_void_p).value vm.addInstrumentedModuleFromAddr(funcPtr) vm.addCodeCB(pyqbdi.PREINST, printInstruction, None) vm.call(funcPtr, [42])

34c3 - Implementing an LLVM based DBI framework

62

slide-63
SLIDE 63

Frida / QBDI

34c3 - Implementing an LLVM based DBI framework

63

slide-64
SLIDE 64

Give it a try

  • https://qbdi.quarkslab.com/
  • https://github.com/quarkslab/QBDI
  • Free software under permissive license (Apache 2)
  • All suggestions / pull requests are most welcome
  • #qbdi on freenode

Many thanks to Paul and djo for their major contributions to this release!

slide-65
SLIDE 65

Any questions?