rev.ng A unified static binary analysis framework Alessandro Di - - PowerPoint PPT Presentation

rev ng
SMART_READER_LITE
LIVE PREVIEW

rev.ng A unified static binary analysis framework Alessandro Di - - PowerPoint PPT Presentation

rev.ng A unified static binary analysis framework Alessandro Di Federico PhD student at Politecnico di Milano LLVM developers meeting 2016 November 3, 2016 Index Introduction A peek inside Recovery of switch cases Function detection


slide-1
SLIDE 1

rev.ng

A unified static binary analysis framework Alessandro Di Federico PhD student at Politecnico di Milano

LLVM developers meeting 2016

November 3, 2016

slide-2
SLIDE 2

Index

Introduction A peek inside Recovery of switch cases Function detection Results Conclusions

slide-3
SLIDE 3

What is rev.ng?

rev.ng is a unified suite of tools for static binary analysis

slide-4
SLIDE 4

Features

  • Static binary translation
  • Recovery of the control-flow graph
  • Recovery of function boundaries
slide-5
SLIDE 5

revamb: the static binary translator

1 Parse the binary and load it in memory 2 Identify all the basic blocks in a binary 3 Lift them using QEMU’s tiny code generator 4 Translate the output to a single LLVM IR function 5 Recompile it

slide-6
SLIDE 6

QEMU IR Alpha ARM AArch64 RISC V Hexagon x86 x86-64 MicroBlaze OpenRISC MIPS64 MIPS XCore PowerPC64 PowerPC SystemZ SuperH SPARC SPARC64 Unicore CRIS

slide-7
SLIDE 7

LLVM IR Alpha ARM AArch64 RISC V Hexagon x86 x86-64 MicroBlaze OpenRISC MIPS64 MIPS XCore PowerPC64 PowerPC SystemZ SuperH SPARC SPARC64 Unicore CRIS

slide-8
SLIDE 8

revamb Alpha ARM AArch64 RISC V Hexagon x86 x86-64 MicroBlaze OpenRISC MIPS64 MIPS XCore PowerPC64 PowerPC SystemZ SuperH SPARC SPARC64 Unicore CRIS

slide-9
SLIDE 9

revamb Alpha ARM AArch64 RISC V Hexagon x86 x86-64 MicroBlaze OpenRISC MIPS64 MIPS XCore PowerPC64 PowerPC SystemZ SuperH SPARC SPARC64 Unicore CRIS

slide-10
SLIDE 10

Concept mapping

Input assembly revamb CPU register LLVM GlobalVariable

slide-11
SLIDE 11

Concept mapping

Input assembly revamb CPU register LLVM GlobalVariable direct branch direct branch

slide-12
SLIDE 12

Concept mapping

Input assembly revamb CPU register LLVM GlobalVariable direct branch direct branch indirect branch jump to the dispatcher

slide-13
SLIDE 13

Dispatcher example

%0 = load i32 , i32* @pc switch i32 %0 , label %abort [ i32 0x10074 , label %bb.0 x10074 i32 0x10080 , label %bb.0 x10080 i32 0x10084 , label %bb.0 x10084 ... ]

slide-14
SLIDE 14

Concept mapping

Input assembly revamb CPU register LLVM GlobalVariable direct branch direct branch indirect branch jump to the dispatcher

slide-15
SLIDE 15

Concept mapping

Input assembly revamb CPU register LLVM GlobalVariable direct branch direct branch indirect branch jump to the dispatcher complex instruction QEMU helper function

slide-16
SLIDE 16

Concept mapping

Input assembly revamb CPU register LLVM GlobalVariable direct branch direct branch indirect branch jump to the dispatcher complex instruction QEMU helper function syscalls QEMU Linux subsystem

slide-17
SLIDE 17

We statically link all the necessary QEMU helper functions

slide-18
SLIDE 18

Example: original assembly

ldr r3 , [fp , #-8] bl 0x1234

slide-19
SLIDE 19

Example: QEMU’s IR

ldr r3 , [fp , #-8] bl 0x1234 mov_i32 tmp5 ,fp movi_i32 tmp6 ,$0xfffffff8 add_i32 tmp5 ,tmp5 ,tmp6 qemu_ld_i32 tmp6 ,tmp5 mov_i32 r3 ,tmp6 movi_i32 tmp5 ,$0x10088 mov_i32 lr ,tmp5 movi_i32 pc ,$0x1234 exit_tb $0x0

slide-20
SLIDE 20

Example: LLVM IR

ldr r3 , [fp , #-8] bl 0x1234 %1 = load i32 , i32* @fp %2 = add i32 %1 , -8 %3 = inttoptr i32 %2 to i32* %4 = load i32 , i32* %3 store i32 %4 , i32* @r3 store i32 0x10088 , i32* @lr store i32 0x1234 , i32* @pc br label %bb.0 x1234

slide-21
SLIDE 21

System overview

md5sum.arm Collect JTs1 from global data Lift to QEMU IR Collect JTs from direct jumps Translate to LLVM IR

new JT

Collect JTs from indirect jumps

new JT

Identify function boundaries Link runtime functions md5sum.x86-64

1JT: a jump target, i.e., a basic block starting address

slide-22
SLIDE 22

Index

Introduction A peek inside Recovery of switch cases Function detection Results Conclusions

slide-23
SLIDE 23

Index

Introduction A peek inside Recovery of switch cases Function detection Results Conclusions

slide-24
SLIDE 24

Typical lowering of a switch on ARM

1000: cmp r1 , #5 1004: addls pc , pc , r1 , lsl #2 1008: ... 100c: ...

slide-25
SLIDE 25

OSR Analysis

  • A data-flow analysis to handle switch
  • It considers each SSA value
  • Tracks of it can be expressed w.r.t. x:
  • plus an offset a
  • and a factor b
  • For each basic block it tracks:
  • the boundaries of x
  • the signedness of x
slide-26
SLIDE 26

An Offset Shifted Range (OSR)

Given two SSA values x and y: y = a + b · x, with

  • x : x ∈ [c, d]

x / ∈ [c, d] and x is signed unsigned

slide-27
SLIDE 27

Example: the input

1000: cmp r1 , #5 1004: addls pc , pc , r1 , lsl #2 1008: ... 100c: ...

slide-28
SLIDE 28

Pseudo C LLVM IR OSRA

a = r1 b = a - 4 c = (b >= 4) if (c) { d = (b == 0) if (!d) return } e = a << 2 f = e + 0x100c pc = f BB1: %1 = load i32 , i32* @r1 %2 = sub i32 %1 , 4 %3 = icmp uge i32 %1 , 4 br i1 %3 , %BB2 , %BB3 BB2: %4 = icmp eq i32 %2 , 0 br i1 %4 , %BB3 , %exit BB3: %5 = shl i32 %1 , 2 %6 = add i32 0x100c , %5 store i32 %6 , i32* @pc

slide-29
SLIDE 29

Pseudo C LLVM IR OSRA

a = r1 b = a - 4 c = (b >= 4) if (c) { d = (b == 0) if (!d) return } e = a << 2 f = e + 0x100c pc = f BB1: %1 = load i32 , i32* @r1 %2 = sub i32 %1 , 4 %3 = icmp uge i32 %1 , 4 br i1 %3 , %BB2 , %BB3 BB2: %4 = icmp eq i32 %2 , 0 br i1 %4 , %BB3 , %exit BB3: %5 = shl i32 %1 , 2 %6 = add i32 0x100c , %5 store i32 %6 , i32* @pc ; [x]

slide-30
SLIDE 30

Pseudo C LLVM IR OSRA

a = r1 b = a - 4 c = (b >= 4) if (c) { d = (b == 0) if (!d) return } e = a << 2 f = e + 0x100c pc = f BB1: %1 = load i32 , i32* @r1 %2 = sub i32 %1 , 4 %3 = icmp uge i32 %1 , 4 br i1 %3 , %BB2 , %BB3 BB2: %4 = icmp eq i32 %2 , 0 br i1 %4 , %BB3 , %exit BB3: %5 = shl i32 %1 , 2 %6 = add i32 0x100c , %5 store i32 %6 , i32* @pc ; [x] ; [x - 4]

slide-31
SLIDE 31

Pseudo C LLVM IR OSRA

a = r1 b = a - 4 c = (b >= 4) if (c) { d = (b == 0) if (!d) return } e = a << 2 f = e + 0x100c pc = f BB1: %1 = load i32 , i32* @r1 %2 = sub i32 %1 , 4 %3 = icmp uge i32 %1 , 4 br i1 %3 , %BB2 , %BB3 BB2: %4 = icmp eq i32 %2 , 0 br i1 %4 , %BB3 , %exit BB3: %5 = shl i32 %1 , 2 %6 = add i32 0x100c , %5 store i32 %6 , i32* @pc ; [x] ; [x - 4] ; (x >= 4, u)

slide-32
SLIDE 32

Pseudo C LLVM IR OSRA

a = r1 b = a - 4 c = (b >= 4) if (c) { d = (b == 0) if (!d) return } e = a << 2 f = e + 0x100c pc = f BB1: %1 = load i32 , i32* @r1 %2 = sub i32 %1 , 4 %3 = icmp uge i32 %1 , 4 br i1 %3 , %BB2 , %BB3 BB2: %4 = icmp eq i32 %2 , 0 br i1 %4 , %BB3 , %exit BB3: %5 = shl i32 %1 , 2 %6 = add i32 0x100c , %5 store i32 %6 , i32* @pc ; [x] ; [x - 4] ; (x >= 4, u) ; (x >= 4, u)

slide-33
SLIDE 33

Pseudo C LLVM IR OSRA

a = r1 b = a - 4 c = (b >= 4) if (c) { d = (b == 0) if (!d) return } e = a << 2 f = e + 0x100c pc = f BB1: %1 = load i32 , i32* @r1 %2 = sub i32 %1 , 4 %3 = icmp uge i32 %1 , 4 br i1 %3 , %BB2 , %BB3 BB2: %4 = icmp eq i32 %2 , 0 br i1 %4 , %BB3 , %exit BB3: %5 = shl i32 %1 , 2 %6 = add i32 0x100c , %5 store i32 %6 , i32* @pc ; [x] ; [x - 4] ; (x >= 4, u) ; (x >= 4, u) ; (x < 4, u)

slide-34
SLIDE 34

Pseudo C LLVM IR OSRA

a = r1 b = a - 4 c = (b >= 4) if (c) { d = (b == 0) if (!d) return } e = a << 2 f = e + 0x100c pc = f BB1: %1 = load i32 , i32* @r1 %2 = sub i32 %1 , 4 %3 = icmp uge i32 %1 , 4 br i1 %3 , %BB2 , %BB3 BB2: %4 = icmp eq i32 %2 , 0 br i1 %4 , %BB3 , %exit BB3: %5 = shl i32 %1 , 2 %6 = add i32 0x100c , %5 store i32 %6 , i32* @pc ; [x] ; [x - 4] ; (x >= 4, u) ; (x >= 4, u) ; (x - 4 == 0, u) ; (x < 4, u)

slide-35
SLIDE 35

Pseudo C LLVM IR OSRA

a = r1 b = a - 4 c = (b >= 4) if (c) { d = (b == 0) if (!d) return } e = a << 2 f = e + 0x100c pc = f BB1: %1 = load i32 , i32* @r1 %2 = sub i32 %1 , 4 %3 = icmp uge i32 %1 , 4 br i1 %3 , %BB2 , %BB3 BB2: %4 = icmp eq i32 %2 , 0 br i1 %4 , %BB3 , %exit BB3: %5 = shl i32 %1 , 2 %6 = add i32 0x100c , %5 store i32 %6 , i32* @pc ; [x] ; [x - 4] ; (x >= 4, u) ; (x >= 4, u) ; (x == 4, u) ; (x < 4, u)

slide-36
SLIDE 36

Pseudo C LLVM IR OSRA

a = r1 b = a - 4 c = (b >= 4) if (c) { d = (b == 0) if (!d) return } e = a << 2 f = e + 0x100c pc = f BB1: %1 = load i32 , i32* @r1 %2 = sub i32 %1 , 4 %3 = icmp uge i32 %1 , 4 br i1 %3 , %BB2 , %BB3 BB2: %4 = icmp eq i32 %2 , 0 br i1 %4 , %BB3 , %exit BB3: %5 = shl i32 %1 , 2 %6 = add i32 0x100c , %5 store i32 %6 , i32* @pc ; [x] ; [x - 4] ; (x >= 4, u) ; (x >= 4, u) ; (x == 4, u) ; (x < 4, u) ; (x == 4, u)

slide-37
SLIDE 37

Pseudo C LLVM IR OSRA

a = r1 b = a - 4 c = (b >= 4) if (c) { d = (b == 0) if (!d) return } e = a << 2 f = e + 0x100c pc = f BB1: %1 = load i32 , i32* @r1 %2 = sub i32 %1 , 4 %3 = icmp uge i32 %1 , 4 br i1 %3 , %BB2 , %BB3 BB2: %4 = icmp eq i32 %2 , 0 br i1 %4 , %BB3 , %exit BB3: %5 = shl i32 %1 , 2 %6 = add i32 0x100c , %5 store i32 %6 , i32* @pc ; [x] ; [x - 4] ; (x >= 4, u) ; (x >= 4, u) ; (x == 4, u) ; (x <= 4, u)

slide-38
SLIDE 38

Pseudo C LLVM IR OSRA

a = r1 b = a - 4 c = (b >= 4) if (c) { d = (b == 0) if (!d) return } e = a << 2 f = e + 0x100c pc = f BB1: %1 = load i32 , i32* @r1 %2 = sub i32 %1 , 4 %3 = icmp uge i32 %1 , 4 br i1 %3 , %BB2 , %BB3 BB2: %4 = icmp eq i32 %2 , 0 br i1 %4 , %BB3 , %exit BB3: %5 = shl i32 %1 , 2 %6 = add i32 0x100c , %5 store i32 %6 , i32* @pc ; [x] ; [x - 4] ; (x >= 4, u) ; (x >= 4, u) ; (x == 4, u) ; (x <= 4, u) ; [4 * x]

slide-39
SLIDE 39

Pseudo C LLVM IR OSRA

a = r1 b = a - 4 c = (b >= 4) if (c) { d = (b == 0) if (!d) return } e = a << 2 f = e + 0x100c pc = f BB1: %1 = load i32 , i32* @r1 %2 = sub i32 %1 , 4 %3 = icmp uge i32 %1 , 4 br i1 %3 , %BB2 , %BB3 BB2: %4 = icmp eq i32 %2 , 0 br i1 %4 , %BB3 , %exit BB3: %5 = shl i32 %1 , 2 %6 = add i32 0x100c , %5 store i32 %6 , i32* @pc ; [x] ; [x - 4] ; (x >= 4, u) ; (x >= 4, u) ; (x == 4, u) ; (x <= 4, u) ; [4 * x] ; [0 x100c + 4 * x]

slide-40
SLIDE 40

Possible jump targets

[0x100c + 4 * x] with (x <= 4, u): 0x100c + 4 * 0 = 0x100c 0x100c + 4 * 1 = 0x1010 0x100c + 4 * 2 = 0x1014 0x100c + 4 * 3 = 0x1018 0x100c + 4 * 4 = 0x101c

slide-41
SLIDE 41

Index

Introduction A peek inside Recovery of switch cases Function detection Results Conclusions

slide-42
SLIDE 42

Generality of function detection

We don’t use any architecture-specific heuristic

slide-43
SLIDE 43

The function detection process

1 Identify function calls and return instructions 2 Create a set of candidate function entry points (CFEP): 1 called basic blocks 2 unused code pointers in global data (e.g., not jump tables) 3 code pointers embedded in the code 3 Compute the basic blocks reachable from each CFEP 4 Keep a CFEP only if: 1 it’s a called basic block, or 2 it’s reached by a skipping jump instruction

slide-44
SLIDE 44

noreturn functions

abort, exit We identify syscalls killing the process and trivial infinite loops longjmp Any instruction overwriting the stack pointer with a value different from sp + value or loaded from such an address.

slide-45
SLIDE 45

noreturn functions

abort, exit We identify syscalls killing the process and trivial infinite loops longjmp Any instruction overwriting the stack pointer with a value different from sp + value or loaded from such an address.

1 Mark all these basic blocks as killer basic blocks 2 Set their successor to a common basic block, the sink 3 Compute the set of basic blocks it post-dominates 4 Mark as noreturn CFEPs in this set

slide-46
SLIDE 46

Index

Introduction A peek inside Recovery of switch cases Function detection Results Conclusions

slide-47
SLIDE 47

Coreutils test suite results

rev.ng QEMU Passed Failed due to missing code Passed MIPS 90.5% 0.7% 92.0% ARM 80.6% 0.0% 92.7% x86-64 92.5% 0.0% 94.6%

slide-48
SLIDE 48

Function detection

Matched functions (%) Jaccard index ARM MIPS x86-64 ARM MIPS x86-64 IDA 85.31 93.38 94.47 97.75 93.64 99.69 rev.ng 87.91 95.08 95.66 97.08 92.89 95.72 BAP 80.26 N/A 83.51 75.37 N/A 69.91 angr 97.54 92.56 93.75 51.15 63.71 83.86

slide-49
SLIDE 49

Index

Introduction A peek inside Recovery of switch cases Function detection Results Conclusions

slide-50
SLIDE 50

Current status

Tested on:

  • statically linked ELF binaries
  • ARM, MIPS, x86-64
  • uClibc and musl
slide-51
SLIDE 51

Future works

  • Calling convention detection and stack analysis
  • Multithreading
  • Try to upstream our changes to QEMU
  • Measure our performance vs QEMU vs native
  • Experiment with instrumentation (fuzzing?)
slide-52
SLIDE 52

Thanks for your attention! https://rev.ng

slide-53
SLIDE 53

License

This work is licensed under the Creative Commons Attribution-ShareAlike 3.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative Commons, 444 Castro Street, Suite 900, Mountain View, California, 94041, USA.