native hook mechanism in android bionic linker

90
Android Dynamic Framework : Native Hook Mechanism in Bionic Linker Mai-Hsuan Chia Shih-Wei Liao Department of Computer Science and Information Engineering National Taiwan University

Upload: mai-hsuan-chia

Post on 17-Feb-2017

204 views

Category:

Engineering


7 download

TRANSCRIPT

Page 1: Native hook mechanism in Android Bionic linker

Android Dynamic Framework : Native Hook Mechanism in Bionic Linker

Mai-Hsuan ChiaShih-Wei Liao

Department of Computer Science and Information EngineeringNational Taiwan University

Page 2: Native hook mechanism in Android Bionic linker

Outline● Background● Motivation● Native Hook Mechanism● Experiment● Applications● Future works● Conclusion

Page 3: Native hook mechanism in Android Bionic linker

Background● JNI● Android Dynamic Framework● Bionic

Page 4: Native hook mechanism in Android Bionic linker

JNI● Enable Java code can call or can be called by native applications

Page 5: Native hook mechanism in Android Bionic linker

JNI

Java method

JNI

Native functionC/C++

Java

Page 6: Native hook mechanism in Android Bionic linker

Java calls nativeclass HelloWorld { private native void print(); // print() is native function public static void main(String[] args) { new HelloWorld().print(); } static { System.loadLibrary("hello"); // This loads libhello.so }}

Page 7: Native hook mechanism in Android Bionic linker

● A framework which is able to dynamically replace Java methods in ART Runtime without modifying APKs.

Android Dynamic Framework

Page 8: Native hook mechanism in Android Bionic linker

Android Dynamic Framework

Class A Class B

HookTable

...class linker

Method A1

Method A2

Method B1

Method B2

Page 9: Native hook mechanism in Android Bionic linker

Android Dynamic Framework

Class A Class B

HookTable

...class linker

Method A1

Method A2

Method B1

Method B2

0. Do linking

Page 10: Native hook mechanism in Android Bionic linker

Android Dynamic Framework

Class A Class B

HookTable

...class linker

Method A1

Method A2

Method B1

Method B2

1. Query HookTable

Page 11: Native hook mechanism in Android Bionic linker

Android Dynamic Framework

Class A Class B

HookTable

...class linker

Method A1

Method A2

Method B1

Method B2

Replace ClassA::A1 with ClassB::B1

1. Query HookTable

Page 12: Native hook mechanism in Android Bionic linker

Android Dynamic Framework

Class A Class B

HookTable

...class linker

Method A2

Method B1

Method B2

Method B1

2. Do method hooking

Page 13: Native hook mechanism in Android Bionic linker

● C library in Android● Forked from BSDs rather than from GNU/Linux

○ To avoid license problems● Smaller● Faster

Bionic

Page 14: Native hook mechanism in Android Bionic linker

● Components○ libc○ libm○ libdl (written from scratch)○ dynamic linker

■ /system/bin/linker (written from scratch)

Bionic

Page 15: Native hook mechanism in Android Bionic linker

Motivation● Only Java methods can be replaced in Android Dynamic

Framework

Page 16: Native hook mechanism in Android Bionic linker

Class A

Method A2

Method B1

Class B

Method B1

Method B2

JNI

libd.so

Func D1

Func D2

libe.so

Func E1

Func E2

(1) method hook

Method A3

libc.so

Func C1

Func C2

native call

hooking path

Page 17: Native hook mechanism in Android Bionic linker

Class A

Method A2

Method B1

Class B

Method B1

Method B2

JNI

libd.so

Func D1

Func D2

libe.so

Func E1

Func E2

(1) method hook

Method A3

libc.so

Func C1

Func C2

native call

hooking path

Page 18: Native hook mechanism in Android Bionic linker

Class A

Method A2

Method B1

Class B

Method B1

Method B2

JNI

libd.so

Func D1

Func D2

libe.so

Func E1

Func E2

(1) method hook

Method A3

libc.so

Func D1

Func C2

native call

hooking path

(2) dlopen native hook

(1) method hook

Page 19: Native hook mechanism in Android Bionic linker

Class A

Method A2

Method B1

Class B

Method B1

Method B2

JNI

libd.so

Func D1

Func D2

libe.so

Func E1

Func E2

(1) method hook

Method A3

libc.so

Func D1

Func C2

native call

hooking path

(2) dlopen native hook

(1) method hook

(2) dlopen native hook

Page 20: Native hook mechanism in Android Bionic linker

Class A

Method A2

Method B1

Class B

Method B1

Method B2

JNI

libd.so

Func D1

Func E2

libe.so

Func E1

Func E2

(1) method hook

Method A3

libc.so

Func D1

Func C2

native call

hooking path

(2) dlopen native hook

(1) method hook

(2) dlopen native hook

(3) native to native hook

Page 21: Native hook mechanism in Android Bionic linker

Motivation● (1) method hook can be done in the existing Android Dynamic

Framework● However, (2) dlopen native hook and (3) native to native hook

cannot not be done.

Page 22: Native hook mechanism in Android Bionic linker

Motivation● Native hook mechanism can do both (2) dlopen native hook and

(3) native to native hook

Page 23: Native hook mechanism in Android Bionic linker

MotivationWith Native hook mechanism integrated,

Android Dynamic Framework can be more complete and powerful

Page 24: Native hook mechanism in Android Bionic linker

Native hook mechanism● Implemented in Bionic Linker

Page 25: Native hook mechanism in Android Bionic linker

Review● How Bionic Linker loads an executable● Dynamic linking flow● Dynamic loading flow

Page 26: Native hook mechanism in Android Bionic linker

How Bionic Linker loads an executable

Page 27: Native hook mechanism in Android Bionic linker

OS creates a process image● Based on the interpreter’s segments. high

low

Memory space

/system/bin/linker

linker

Page 28: Native hook mechanism in Android Bionic linker

Linker links itself● __linker_init() high

low

Memory space

/system/bin/linker

Page 29: Native hook mechanism in Android Bionic linker

Load the executable● __linker_init_post_relocation()

/system/bin/linker

high

low

Memory space

exe

executable

Page 30: Native hook mechanism in Android Bionic linker

Get needed libraries names ● __linker_init_post_relocation()

/system/bin/linker

high

low

Memory space

executable

exe

.dynamic

DT_NEEDEDptr_to_liba1.so_nameDT_NEEDEDptr_to_liba2.so_name…DT_NULL

Page 31: Native hook mechanism in Android Bionic linker

Get needed libraries names ● __linker_init_post_relocation()

/system/bin/linker

high

low

Memory space

executable

exe

DT_NEEDEDptr_to_liba1.so_nameDT_NEEDEDptr_to_liba2.so_name…DT_NULL

.dynamic

char needed_libraries_names[] = {“liba1.so”, “liba2.so”

}

Page 32: Native hook mechanism in Android Bionic linker

Load needed libraries● find_libaries(exe, needed_libraries_names)

○ step 1 : load libraries and build dependencies tree

Page 33: Native hook mechanism in Android Bionic linker

Load needed libraries● find_libaries(exe, needed_libraries_names)

○ step 1 : load libraries and build dependencies tree

exe

liba1.so

liba2.so Loaded NotLoaded

p.s.

Page 34: Native hook mechanism in Android Bionic linker

Load needed libraries● find_libaries(exe, needed_libraries_names)

○ step 1 : load libraries and build dependencies tree

exe

liba1.so

liba2.so Loaded NotLoaded

p.s.

Page 35: Native hook mechanism in Android Bionic linker

Load needed libraries● find_libaries(exe, needed_libraries_names)

○ step 1 : load libraries and build dependencies tree

exe

liba1.so

liba2.so

libb1.so

libb2.so

libb3.solibb4.so

...

...

Loaded NotLoaded

p.s.

Page 36: Native hook mechanism in Android Bionic linker

Load needed libraries● find_libaries(exe, needed_libraries_names)

○ step 1 : load libraries and build dependencies tree

exe

liba1.so

liba2.so

libb2.so

libb3.solibb4.so

...

...

Loaded NotLoaded

p.s.

libb1.so

Page 37: Native hook mechanism in Android Bionic linker

Load needed libraries● find_libaries(exe, needed_libraries_names)

○ step 1 : load libraries and build dependencies tree

exe

liba1.so

liba2.so

libb2.so

libb3.solibb4.so

...

...

...

...

...

...

... Loaded NotLoaded

p.s.

libb1.so

Page 38: Native hook mechanism in Android Bionic linker

Load needed libraries

liba1.soexe liba2.so libb1.so libb2.so ...

● find_libaries(exe, needed_libraries_names)○ step 2 : turn dependencies tree into libraries_list in

Breadth First Search(BFS) order

libraries_listdependencies tree

Page 39: Native hook mechanism in Android Bionic linker

Link the application and all libraries● find_libaries(exe, needed_libraries_names)

○ step 3 : relocate all to-be-relocated symbols in the application and libraries

foreach lib in libraries_list { foreach rel in lib.dynamic_relocation_table { symbol = rel.sym; soinfo_do_lookup(symbol, lib, libraries_list); }}

Page 40: Native hook mechanism in Android Bionic linker

Link the application and all libraries● find_libaries(exe, needed_libraries_names)

○ step 3 : relocate all to-be-relocated symbols in the application and libraries

liba1.soexe liba2.so libb1.so libb2.so ...

libraries_list

exe

sym_1

sym_n

...

if sym_1 is defined in lib: sym_1 = lib.find(sym)else: lib = lib->next;

Page 41: Native hook mechanism in Android Bionic linker

Link the application and all libraries● find_libaries(exe, needed_libraries_names)

○ step 3 : relocate all to-be-relocated symbols in the application and libraries

liba1.soexe liba2.so libb1.so libb2.so ...

libraries_list

exe

sym_1

sym_n

...

if sym_1 is defined in lib: sym_1 = lib.find(sym)else: lib = lib->next;

NOT FOUND

Page 42: Native hook mechanism in Android Bionic linker

Link the application and all libraries● find_libaries(exe, needed_libraries_names)

○ step 3 : relocate all to-be-relocated symbols in the application and libraries

liba1.soexe liba2.so libb1.so libb2.so ...

libraries_list

exe

sym_1

sym_n

...

if sym_1 is defined in lib: sym_1 = lib.find(sym)else: lib = lib->next;

NOT FOUND

Page 43: Native hook mechanism in Android Bionic linker

Link the application and all libraries● find_libaries(exe, needed_libraries_names)

○ step 3 : relocate all to-be-relocated symbols in the application and libraries

liba1.soexe liba2.so libb1.so libb2.so ...

libraries_list

exe

sym_1

sym_n

...

if sym_1 is defined in lib: sym_1 = lib.find(sym)else: lib = lib->next;

FOUND

ok

Page 44: Native hook mechanism in Android Bionic linker

Link the application and all libraries● find_libaries(exe, needed_libraries_names)

○ step 3 : relocate all to-be-relocated symbols in the application and libraries

liba1.soexe liba2.so libb1.so libb2.so ...

libraries_list

exe

sym_1

sym_n

...

if sym_k is defined in lib: sym_k = lib.find(sym)else: lib = lib->next;

ok

Page 45: Native hook mechanism in Android Bionic linker

Link the application and all libraries● find_libaries(exe, needed_libraries_names)

○ step 3 : relocate all to-be-relocated symbols in the application and libraries

liba1.soexe liba2.so libb1.so libb2.so ...

libraries_list

exe

sym_1

sym_n

...

ok

ok

Page 46: Native hook mechanism in Android Bionic linker

Link the application and all libraries● find_libaries(exe, needed_libraries_names)

○ step 3 : relocate all to-be-relocated symbols in the application and libraries

liba1.soexe liba2.so libb1.so libb2.so ...

libraries_list

liba1.so

sym_1

sym_n

...

if sym_1 is defined in lib: sym_1 = lib.find(sym)else: lib = lib->next;

Page 47: Native hook mechanism in Android Bionic linker

Link the application and all libraries● find_libaries(exe, needed_libraries_names)

○ step 3 : relocate all to-be-relocated symbols in the application and libraries

liba1.soexe liba2.so libb1.so libb2.so ...

libraries_list

...

sym_1

sym_n

...

if sym_1 is defined in lib: sym_1 = lib.find(sym)else: lib = lib->next;

Page 48: Native hook mechanism in Android Bionic linker

Link the application and all libraries● find_libaries(exe, needed_libraries_names)

○ step 3 : relocate all to-be-relocated symbols in the application and libraries

liba1.soexe liba2.so libb1.so libb2.so ...

libraries_list

...

sym_1

sym_n

...

if sym_1 is defined in lib: sym_1 = lib.find(sym)else: lib = lib->next;

It is DONE until all libraries are linked

Page 49: Native hook mechanism in Android Bionic linker

Jump to the application’s entry

/system/bin/linker

high

low

Memory space

executable

liba1.so

liba2.so

libb1.so

...

● jump to executable’s _start.

Page 50: Native hook mechanism in Android Bionic linker

The executable is loaded successfully● And start to execute

/system/bin/linker

high

low

Memory space

liba1.so

liba2.so

libb1.so

...

.text section

_start:….….

executable

Page 51: Native hook mechanism in Android Bionic linker

Bionic linker linking & loading flow● Dynamic linking flow● Dynamic loading flow

Page 52: Native hook mechanism in Android Bionic linker

__linker_init_post_relocation

Dynamic linking

dlopen_ext

do_dlopen

find_library

find_libraries

find_library_internal

load_library

Dynamic loading

...load all libraries…relocate all symbols

Page 53: Native hook mechanism in Android Bionic linker

Native hook mechanismModified codes are mainly in two parts

● Load hooking libraries in find_libraries()○ Init native_hook_table○ Look up native_hook_table○ Load hooking_library

● Replace hooked_symbol with hooking_symbol in soinfo_do_lookup()○ Look up native_hook_table○ Replace every hooked_symbol in hooked_library with hooking_symbol in

hooking_library

Page 54: Native hook mechanism in Android Bionic linker

Native hook file formatin /system/nh_file.txt

< hooked_lib_name:hooked_symbol:hooking_lib_name:hooking_symbol >

Page 55: Native hook mechanism in Android Bionic linker

System flow

hooking lib

nh_file

ROM

/system/bin/linker

__linker_init_post_relocation

find_libraries

init native_hook_table

look up native hook table

soinfo_do_lookup

look up native hook table

replace hooked symbol with hooking symbol

NewProcess

load hooking library

Page 56: Native hook mechanism in Android Bionic linker

Load hooking libraries

linkerexe

liba1.so

liba2.so Loaded NotLoaded

p.s.

liba1.so:hi:libhooking.so:ha...

Native Hook Table

Page 57: Native hook mechanism in Android Bionic linker

Load hooking libraries

linkerexe

liba1.so

liba2.so Loaded NotLoaded

p.s.

liba1.so:hi:libhooking.so:ha...

Native Hook Table

0. load liba1.so

Page 58: Native hook mechanism in Android Bionic linker

Load hooking libraries

linkerexe

liba1.so

liba2.so Loaded NotLoaded

p.s.

liba1.so:hi:libhooking.so:ha...

Native Hook Table

1. look up the native hook table

HOOKED LIB “liba1.so” FOUND

Page 59: Native hook mechanism in Android Bionic linker

Load hooking libraries

linkerexe

liba1.so

liba2.so Loaded NotLoaded

p.s.

liba1.so:hi:libhooking.so:ha...

Native Hook Table

2. load libhooking.so

libhooking.so

Page 60: Native hook mechanism in Android Bionic linker

Replace hooked_symbol with hooking_symbol

liba1.soexe liba2.so libhooking.so

libraries_list

liba1.so:hi:libhooking.so:ha...

Native Hook Table

exe

hi

hi halinker

0. relocate symbol

Page 61: Native hook mechanism in Android Bionic linker

Replace hooked_symbol with hooking_symbol

liba1.soexe liba2.so libhooking.so

libraries_list

liba1.so:hi:libhooking.so:ha...

Native Hook Table

exehi ha

linker

NOT FOUNDhi

Page 62: Native hook mechanism in Android Bionic linker

Replace hooked_symbol with hooking_symbol

liba1.soexe liba2.so libhooking.so

libraries_list

liba1.so:hi:libhooking.so:ha...

Native Hook Table

exehi ha

linker

FOUNDhi

Page 63: Native hook mechanism in Android Bionic linker

Replace hooked_symbol with hooking_symbol

liba1.soexe liba2.so libhooking.so

libraries_list

liba1.so:hi:libhooking.so:ha...

Native Hook Table

exehi ha

linker

FOUNDhi

1. look up native hook table

liba1.so:hi is to be hooked

Page 64: Native hook mechanism in Android Bionic linker

Replace hooked_symbol with hooking_symbol

liba1.soexe liba2.so libhooking.so

libraries_list

liba1.so:hi:libhooking.so:ha...

Native Hook Table

exehi ha

linker

hi

1. look up native hook table

2. find libhooking.so:ha

Page 65: Native hook mechanism in Android Bionic linker

Replace hooked_symbol with hooking_symbol

liba1.soexe liba2.so libhooking.so

libraries_list

liba1.so:hi:libhooking.so:ha...

Native Hook Table

exehi ha

linker

ha

3. relocate hooked_symbol “hi” with the hooking_symbol “ha”

Page 66: Native hook mechanism in Android Bionic linker

// in libnativehook.so

#include “native_hook.h”

void* find_lib_symbol(char* lib_name, char* symbol){

// Using dl_iterate_phdr() to get the symbol’s address// in the loaded library whose name is lib_name.…return ptr_to_symbol;

}

Before/After hook SDK

Page 67: Native hook mechanism in Android Bionic linker

How find_lib_symbol() works ?With the following facts, we can get the hooked_symbol in hooked_library with dl_iterate_phdr(callback, void* data)

● hooked_lib is loaded in the memory● dl_iterate_phdr()iterates all loaded libraries in the process, and get each

library’s program header and base address.● With library’s program header, we can get .dynamic segment, and therefore we get

.dynstr and .dynsym section● With .dynsym and .dynstr, we can find the offset of hooked_symbol in hooked_lib.● hooked_symbol_addr = base address + offset

Page 68: Native hook mechanism in Android Bionic linker

// in libmine.so#include “native_hook.h”

double my_sin(double x){

char hooked_lib[] = "/system/lib/libm.so";char hooked_symbol[] = "sin";double (*hooked_sin)(double) = find_lib_symbol(hooked_lib, hooked_symbol);

/* before hook : you can do something before calling hooked_func */

double result = hooked_sin(x);/*

after hook : you can do something after calling hooked_func */

result += 5566;

return result;}

After hook example

Page 69: Native hook mechanism in Android Bionic linker

After hook example// in main.c

#include <math.h>#include <stdio.h>#define PI 3.14159265

int main(void){

double angle = 30.0;double result = sin((angle * PI) /

180);printf(“sin(%lf) = %lf\n”, angle,

result);return 0;

}

libm.so:sin:libmine.so:my_sin...

Native Hook Table

$ ./mainsin(30.000000) = 5566.500000

Page 70: Native hook mechanism in Android Bionic linker

double my_sin(double x){

char hooked_lib[] = "/system/lib/libm.so";char hooked_symbol[] = "sin";static void* cache_ptr = NULL;double (*hooked_sin)(double) = NULL;if (cache_ptr) {

hooked_sin = cache_ptr;} else {

hooked_sin = find_lib_symbol(hooked_lib, hooked_symbol);}if (hooked_sin) {

cache_ptr = (void*)hooked_sin;}double result = hooked_sin(x);result += 5566;return result;

}

Before/After hook with cache

Page 71: Native hook mechanism in Android Bionic linker

Experiment1,000 100,000 1,000,000 10,000,000

Baseline 0.10 0.14 0.52 4.07

Normal hook 0.20 0.23 0.60 4.15

Before/After hook without cache 0.25 1.9 17.12 169.03

Before/After hook with cache 0.22 0.24 0.69 4.77

iterations

Page 72: Native hook mechanism in Android Bionic linker

Experiment169.03

Page 73: Native hook mechanism in Android Bionic linker

Applications● Profiling● Boosting apps performance● Security sandbox

Page 74: Native hook mechanism in Android Bionic linker

Profiling

Target function

Before hook

After hook

● Input Distribution Analysis

● Function call Analysis

● Output Analysis

Page 75: Native hook mechanism in Android Bionic linker

● Hook functions that affect the performance of applications in Android

● Scenario○ Functions in libm.so are not good enough for some special

purpose, we can hook the function with the optimized one.

Boosting apps performance

Page 76: Native hook mechanism in Android Bionic linker

libm_opt.so

optimized_sin:...

libbenchmark.so

getScore:…call <sin>

App

libm.so

sin:...

JNI

Page 77: Native hook mechanism in Android Bionic linker

libm_opt.so

optimized_sin:...

libbenchmark.so

getScore:…call <sin>

App

libm.so

sin:...

JNI

Replace ‘sin’ with ‘optimized_sin’

Page 78: Native hook mechanism in Android Bionic linker

Security sandbox● Use “before hook” to hook the open()in libc● Examine the filename and other parameters in advance

○ If the to-be-written file is a critical file, we let the app open another file to write without consciousness.

Page 79: Native hook mechanism in Android Bionic linker

Security sandbox

f = open(“/data/critical.txt”, ‘w’);...

modifying critical.txt ...

...

App

Sandbox

Page 80: Native hook mechanism in Android Bionic linker

Security sandbox

f = open(“/data/critical.txt”, ‘w’);...

modifying critical.txt ...

...

App

Sandbox

/data/critical.txt should not be modified.

Page 81: Native hook mechanism in Android Bionic linker

Security sandbox

f = open(“/data/critical.txt”, ‘w’);...

modifying critical.txt ...

...

App

Sandbox

f = open(“/data/another.txt”, ‘w’);

In the sandbox, app is deceived to write to “/data/another.txt” instead of

“/data/critical.txt”.

Page 82: Native hook mechanism in Android Bionic linker

Security sandbox

App

Sandbox

f = open(“/data/another.txt”, ‘w’);

f = open(“/data/another.txt”, ‘w’);...

modifying another.txt ...

...

Page 83: Native hook mechanism in Android Bionic linker

● Provide more easy-to-use API for Native Hook in Android○ Native Hook SDK

Future works

Page 84: Native hook mechanism in Android Bionic linker

● Completely integrate Native Hook into Android Dynamic Framework○ Provide hooking between Java method and native functions.

Future works

Integrated Hook Table

liba.so:funca:libb.so:funcb # hook native to nativeclassA:methoda:classB:methodb # hook java to javaclassA:methoda:libb.so:funcb # hook java to nativelibb.so:funcb:classA:methoda # hook native to java

...

Page 85: Native hook mechanism in Android Bionic linker

Conclusion● Native Hook mechanism is a strong and useful framework in

Android allowing developers to replace native functions at runtime without modifying the existing functions.

● Native Hook is more powerful than Java method hook mechanisms because it is implemented in Bionic Linker.

● With Before/After hook mechanism, you can do whatever you want before/after any existing function.

● With Native Hook enabled, it suffers only little overhead to load nh_file and hooking libraries.

Page 86: Native hook mechanism in Android Bionic linker

Q & A

Page 87: Native hook mechanism in Android Bionic linker

Thank you for your listening

Page 88: Native hook mechanism in Android Bionic linker

Backup slides

Page 89: Native hook mechanism in Android Bionic linker

void* find_lib_symbol(char* lib_name, char* symbol){

// Using dl_iterate_phdr() to get the symbol’s address// in the loaded library whose name is lib_name.static void* unordered_map<std::string, void*> cache = nullptr;std::string lib_symbol = std::string(lib_name) + symbol;if (cache) {

unordered_map<std::string, void*>::iterator it = cache.find(lib_symbol);if (it != cache.end()) {

return it->second;}

}…// find ptr_to_symbolif (ptr_to_symbol) {

cache[lib_symbol] = ptr_to_symbol;}return ptr_to_symbol;

}

Before/After hook with cache in find_lib_symbol

Page 90: Native hook mechanism in Android Bionic linker

Replace hooked_symbol with hooking_symbol

liba1.soexe liba2.so libhooking.so

libraries_list

liba1.so:hi:libhooking.so:ha...

Native Hook Table

exehi ha

linker

FOUNDhi

1. look up native hook table

liba1.so:hi is to be hooked

2. find libhooking.so:ha