Cydia Substrate出了android版本的hook框架,不仅能hook java层函数,还能hook so中的函数,其核心原理是函数的inline hook,与xposed有着十分大的差别(xposed主要通过hookMethodNative将java层函数替换成native层函数而完成hook)。
合理使用Cydia Substrate可以有效绕过反调试,签名校验还可以制作脱壳机等,大大加快分析APK的效率。这篇文章主要介绍使用Cydia Substrate Android框架进行so层的hook。
1.安装apk并下载SDK
在官网(http://www.cydiasubstrate.com/)中下载substrate的android版apk并安装(需要root权限)。
在官网中下载SDK(http://www.cydiasubstrate.com/id/73e45fe5-4525-4de7-ac14-6016652cc1b8/):。so层hook只需要用到SDK中的libsubstrate.so,libsubstrate-dvm.so,substrate.h。
2.新建Android工程
so层hook并不需要界面(作为Cydia Substrate的扩展模块),所以在新建工程时无需建activity。接下来在工程目录下新建jni文件夹,并将libsubstrate.so,libsubstrate-dvm.so,substrate.h三个文件拷贝至jni文件夹下。
在AndroidManifest.xml中添加权限:
1
|
<
uses
-
permission
android
:
name
=
"cydia.permission.SUBSTRATE"
/
>
|
3.编写hook模块
本次演示实例hook了libc.so中的fopen函数,完整代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
|
#include <stdio.h>
#include <android/log.h>
#include <unistd.h>
#include "substrate.h"
#define TAG "CydiaHook"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG ,__VA_ARGS__) // 定义LOGI类型
#define GETLR(store_lr) \
__asm__
__volatile__
(
\
"mov %0, lr\n\t"
\
:
"=r"
(
store_lr
)
\
)
//指明要hook的lib
MSConfig
(
MSFilterLibrary
,
"/system/lib/libc.so"
)
int
(
*
oldfopen
)
(
const
char
*
path
,
const
char
*
mode
)
;
int
newfopen
(
const
char
*
path
,
const
char
*
mode
)
{
LOGI
(
"call my fopen!!:%d"
,
getpid
(
)
)
;
unsigned
lr
;
GETLR
(
lr
)
;
if
(
strstr
(
path
,
"status"
)
!=
NULL
)
{
LOGI
(
"[*] Traced-fopen Call function: 0x%x\n"
,
lr
)
;
if
(
strstr
(
path
,
"task"
)
!=
NULL
)
{
LOGI
(
"[*] Traced-anti-task/status"
)
;
}
else
LOGI
(
"[*] Traced-anti-status"
)
;
}
else
if
(
strstr
(
path
,
"wchan"
)
!=
NULL
)
{
LOGI
(
"[*] Traced-fopen Call function: 0x%x\n"
,
lr
)
;
LOGI
(
"[*] Traced-anti-wchan"
)
;
}
return
oldfopen
(
path
,
mode
)
;
}
/*
* Substrate entry point
*/
//初始化时进行hook
MSInitialize
{
// Let the user know that the extension has been
// extension has been registered
LOGI
(
"Substrate initialized."
)
;
MSImageRef
image
;
image
=
MSGetImageByName
(
"/system/lib/libc.so"
)
;
if
(
image
!=
NULL
)
{
void
*
hookfopen
=
MSFindSymbol
(
image
,
"fopen"
)
;
if
(
hookfopen
==
NULL
)
{
LOGI
(
"error find fopen "
)
;
}
else
{
MSHookFunction
(
hookfopen
,
(
void
*
)
&
newfopen
,
(
void
*
*
)
&
oldfopen
)
;
}
}
else
{
LOGI
(
"ERROR FIND LIBC"
)
;
}
}
|
注意:在初始配置MSConfig中第一个参数是MSFilterLibrary,表示要hook lib,如果要hook可执行文件的话,这个参数为MSFilterExecutable。
本实例实现的效果为:在调用fopen时打印调用这pid,如果发现打开特殊文件(/proc/pid/status等)则打印出调用这地址,arm汇编中lr寄存器保存了函数返回地址,所以在进入函数时打印该值就表示调用者的虚拟地址。
4.编写makefile
在jni文件夹下新建Android.mk文件,内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
|
LOCAL_PATH
:
=
$
(
call
my
-
dir
)
include
$
(
CLEAR_VARS
)
LOCAL_MODULE
:
=
substrate
-
dvm
LOCAL_SRC_FILES
:
=
libsubstrate
-
dvm
.
so
include
$
(
PREBUILT_SHARED_LIBRARY
)
include
$
(
CLEAR_VARS
)
LOCAL_MODULE
:
=
hooktest
.
cy
#生成的模块名
LOCAL_SRC_FILES
:
=
hooktest
.
cy
.
cpp
#源文件名
LOCAL_LDLIBS
:
=
-
L
$
(
LOCAL_PATH
)
-
lsubstrate
-
lsubstrate
-
dvm
-
llog
#加入substrate模块
include
$
(
BUILD_SHARED_LIBRARY
)
|
接下来通过ndk-build编译生成hooktest.cy模块,再运行安装apk,在substrate中点击Link Substrate Files,最后软重启即可看到hook的效果:
5.后记
本次演示实例只是简单hook了fopen函数,反调试时经常会读取关键文件,hook了fopen就可以很方便的知道它的调用点,当然还可以进行重定向等直接绕过;几个月前ThomasKing牛在看雪上发表的《基于HOOK的Anti-debug调用点trace和Anti-anti》,就是通过cydia substrate完成的,当然还有很早之前空道牛发表的《过百分之八十的签名校验模块》也是基于substrate,所以说如果能用好substrate,可以大大简化apk破解的难度,当然这对于移动安全而言也是一个很大的挑战。
http://burningcodes.net/cydia-substrate-android-so-hook/