目前 Android
上 Hook
的框架已经很多了,但是支持 Java Native
方法的 Hook
却很少,这些框架将 native
方法当普通方法 Hook
,适配不同架构复杂等等。本文介绍一种 Android
版本通用的 Java Native Hook
方法并实现代码很少,下面进入我们的分析。
目前 native
方法只有两种方式
根据上面两种方式很自然想到了两种 Hook
方法
RegisterNatives
最新源码实现位置在 art/runtime/jni/jni_internal.cc,其源码如下:
这个方法主要进行各种验证并查找方法对应的 ArtMethod
,其中 FastNative
在 Android8.0 以后已经采用注解的方式了,最终调用 class_linker->RegisterNative(soa.Self(), m, fnPtr)
来完成函数注册,接着分析
有关 JVMTI
大家可以网上搜索,通过它能做到很多黑科技并且这里也使用了它修改后的 new_native_method
,因此通过 JVMTI
也能达到 Hook
。 ,这里判断 CriticalNative
如果没有初始化类则先要初始化类,然后再注册。最终实现注册的是 method->SetEntryPointFromJni(new_native_method)
最终只是设置 ArtMethod
对象中的 jni
入口点指针为我们的注册函数,上面是主分支代码分析,Android 11
及以下都是调用的 ArtMethod::RegisterNative
方法
这里可以看到在 Android 9
以上直接调用即可覆盖掉,Android 9
以下需要清理 FastNative
标志
经过上面分析要 Hook
则只需要调用 RegisterNatives
方法,而我们还要备份原方法方便后面可以调用,而原方法的地址在 ArtMethod
对象中的 jni
入口指针中保存,因此需要查找 ArtMethod
,为了简单适配不同我们自己手动注册一个函数,然后再拿这个地址跟 ArtMethod
对象中去比较获取偏移量
在 Android 9
以下如果原方法是 FastNative
类型则还需要清除标志,因此还要查找 uint32_t accessFlags
成员的偏移,这里我们又采用查找的方式,来确定偏移,使用 uint32_t
对齐,我这里选择的是 0x109
标志也就是 public static native
,这里最好要有 public
标志 0x1
,因为正常指针都是 4/8 字节对齐的,这样避免误判
fake-linker 集成 JNI
,Java native
函数 Hook
,LD_PRELOAD
模式的 PLT Hook
,Android 7
以上绕过命名空间限制等等
数据滤镜 用于分析恶意软件,提供高度自由的数据过滤,文件重定向,maps 文件过滤,动态符号查找过滤等等
点击 这里
extern
"C"
JNIEXPORT void JNICALL Java_com_sanfengandroid_fakelinker_FakeLinker_setLogLevel(JNIEnv
*
env, jclass clazz, jint level) {
g_log_level
=
level;
}
extern
"C"
JNIEXPORT void JNICALL Java_com_sanfengandroid_fakelinker_FakeLinker_setLogLevel(JNIEnv
*
env, jclass clazz, jint level) {
g_log_level
=
level;
}
static jint RegisterNatives(JNIEnv
*
env,
jclass java_class,
const JNINativeMethod
*
methods,
jint method_count) {
if
(UNLIKELY(method_count <
0
)) {
JavaVmExtFromEnv(env)
-
>JniAbortF(
"RegisterNatives"
,
"negative method count: %d"
,
method_count);
return
JNI_ERR;
/
/
Not reached
except
in
unit tests.
}
CHECK_NON_NULL_ARGUMENT_FN_NAME(
"RegisterNatives"
, java_class, JNI_ERR);
ClassLinker
*
class_linker
=
Runtime::Current()
-
>GetClassLinker();
ScopedObjectAccess soa(env);
StackHandleScope<
1
> hs(soa.Self());
Handle<mirror::Class> c
=
hs.NewHandle(soa.Decode<mirror::Class>(java_class));
if
(UNLIKELY(method_count
=
=
0
)) {
LOG(WARNING) <<
"JNI RegisterNativeMethods: attempt to register 0 native methods for "
<< c
-
>PrettyDescriptor();
return
JNI_OK;
}
CHECK_NON_NULL_ARGUMENT_FN_NAME(
"RegisterNatives"
, methods, JNI_ERR);
for
(jint i
=
0
; i < method_count;
+
+
i) {
const char
*
name
=
methods[i].name;
const char
*
sig
=
methods[i].signature;
const void
*
fnPtr
=
methods[i].fnPtr;
if
(UNLIKELY(name
=
=
nullptr)) {
ReportInvalidJNINativeMethod(soa, c.Get(),
"method name"
, i);
return
JNI_ERR;
}
else
if
(UNLIKELY(sig
=
=
nullptr)) {
ReportInvalidJNINativeMethod(soa, c.Get(),
"method signature"
, i);
return
JNI_ERR;
}
else
if
(UNLIKELY(fnPtr
=
=
nullptr)) {
ReportInvalidJNINativeMethod(soa, c.Get(),
"native function"
, i);
return
JNI_ERR;
}
bool
is_fast
=
false;
if
(
*
sig
=
=
'!'
) {
is_fast
=
true;
+
+
sig;
}
/
/
上面是一些参数验证
ArtMethod
*
m
=
nullptr;
bool
warn_on_going_to_parent
=
down_cast<JNIEnvExt
*
>(env)
-
>GetVm()
-
>IsCheckJniEnabled();
for
(ObjPtr<mirror::Class> current_class
=
c.Get();
current_class !
=
nullptr;
current_class
=
current_class
-
>GetSuperClass()) {
/
/
查询方法对应的 ArtMethod 对象
m
=
FindMethod<true>(current_class, name, sig);
if
(m !
=
nullptr) {
break
;
}
/
/
Search again comparing to
all
methods, to find non
-
native methods that match.
m
=
FindMethod<false>(current_class, name, sig);
if
(m !
=
nullptr) {
break
;
}
if
(warn_on_going_to_parent) {
LOG(WARNING) <<
"CheckJNI: method to register \""
<< name <<
"\" not in the given class. "
<<
"This is slow, consider changing your RegisterNatives calls."
;
warn_on_going_to_parent
=
false;
}
}
if
(m
=
=
nullptr) {
c
-
>DumpClass(LOG_STREAM(ERROR), mirror::Class::kDumpClassFullDetail);
LOG(ERROR)
<<
"Failed to register native method "
<< c
-
>PrettyDescriptor() <<
"."
<< name << sig <<
" in "
<< c
-
>GetDexCache()
-
>GetLocation()
-
>ToModifiedUtf8();
ThrowNoSuchMethodError(soa, c.Get(), name, sig,
"static or non-static"
);
return
JNI_ERR;
}
else
if
(!m
-
>IsNative()) {
/
/
非 native 方法是不能注册的
LOG(ERROR)
<<
"Failed to register non-native method "
<< c
-
>PrettyDescriptor() <<
"."
<< name << sig
<<
" as native"
;
ThrowNoSuchMethodError(soa, c.Get(), name, sig,
"native"
);
return
JNI_ERR;
}
VLOG(jni) <<
"[Registering JNI native method "
<< m
-
>PrettyMethod() <<
"]"
;
if
(UNLIKELY(is_fast)) {
LOG(WARNING) <<
"!bang JNI is deprecated. Switch to @FastNative for "
<< m
-
>PrettyMethod();
is_fast
=
false;
/
/
TODO: make this a hard register error
in
the future.
}
/
/
最终调用 class_linker
-
>RegisterNative 来实际进行注册
const void
*
final_function_ptr
=
class_linker
-
>RegisterNative(soa.Self(), m, fnPtr);
UNUSED(final_function_ptr);
}
return
JNI_OK;
}
static jint RegisterNatives(JNIEnv
*
env,
jclass java_class,
const JNINativeMethod
*
methods,
jint method_count) {
if
(UNLIKELY(method_count <
0
)) {
JavaVmExtFromEnv(env)
-
>JniAbortF(
"RegisterNatives"
,
"negative method count: %d"
,
method_count);
return
JNI_ERR;
/
/
Not reached
except
in
unit tests.
}
CHECK_NON_NULL_ARGUMENT_FN_NAME(
"RegisterNatives"
, java_class, JNI_ERR);
ClassLinker
*
class_linker
=
Runtime::Current()
-
>GetClassLinker();
ScopedObjectAccess soa(env);
StackHandleScope<
1
> hs(soa.Self());
Handle<mirror::Class> c
=
hs.NewHandle(soa.Decode<mirror::Class>(java_class));
if
(UNLIKELY(method_count
=
=
0
)) {
LOG(WARNING) <<
"JNI RegisterNativeMethods: attempt to register 0 native methods for "
<< c
-
>PrettyDescriptor();
return
JNI_OK;
}
CHECK_NON_NULL_ARGUMENT_FN_NAME(
"RegisterNatives"
, methods, JNI_ERR);
for
(jint i
=
0
; i < method_count;
+
+
i) {
const char
*
name
=
methods[i].name;
const char
*
sig
=
methods[i].signature;
const void
*
fnPtr
=
methods[i].fnPtr;
if
(UNLIKELY(name
=
=
nullptr)) {
ReportInvalidJNINativeMethod(soa, c.Get(),
"method name"
, i);
return
JNI_ERR;
}
else
if
(UNLIKELY(sig
=
=
nullptr)) {
ReportInvalidJNINativeMethod(soa, c.Get(),
"method signature"
, i);
return
JNI_ERR;
}
else
if
(UNLIKELY(fnPtr
=
=
nullptr)) {
ReportInvalidJNINativeMethod(soa, c.Get(),
"native function"
, i);
return
JNI_ERR;
}
bool
is_fast
=
false;
if
(
*
sig
=
=
'!'
) {
is_fast
=
true;
+
+
sig;
}
/
/
上面是一些参数验证
ArtMethod
*
m
=
nullptr;
bool
warn_on_going_to_parent
=
down_cast<JNIEnvExt
*
>(env)
-
>GetVm()
-
>IsCheckJniEnabled();
for
(ObjPtr<mirror::Class> current_class
=
c.Get();
current_class !
=
nullptr;
current_class
=
current_class
-
>GetSuperClass()) {
/
/
查询方法对应的 ArtMethod 对象
m
=
FindMethod<true>(current_class, name, sig);
if
(m !
=
nullptr) {
break
;
}
/
/
Search again comparing to
all
methods, to find non
-
native methods that match.
m
=
FindMethod<false>(current_class, name, sig);
if
(m !
=
nullptr) {
break
;
}
if
(warn_on_going_to_parent) {
LOG(WARNING) <<
"CheckJNI: method to register \""
<< name <<
"\" not in the given class. "
<<
"This is slow, consider changing your RegisterNatives calls."
;
warn_on_going_to_parent
=
false;
}
}
if
(m
=
=
nullptr) {
c
-
>DumpClass(LOG_STREAM(ERROR), mirror::Class::kDumpClassFullDetail);
LOG(ERROR)
<<
"Failed to register native method "
<< c
-
>PrettyDescriptor() <<
"."
<< name << sig <<
" in "
<< c
-
>GetDexCache()
-
>GetLocation()
-
>ToModifiedUtf8();
ThrowNoSuchMethodError(soa, c.Get(), name, sig,
"static or non-static"
);
return
JNI_ERR;
}
else
if
(!m
-
>IsNative()) {
/
/
非 native 方法是不能注册的
LOG(ERROR)
<<
"Failed to register non-native method "
<< c
-
>PrettyDescriptor() <<
"."
<< name << sig
<<
" as native"
;
ThrowNoSuchMethodError(soa, c.Get(), name, sig,
"native"
);
return
JNI_ERR;
}
VLOG(jni) <<
"[Registering JNI native method "
<< m
-
>PrettyMethod() <<
"]"
;
if
(UNLIKELY(is_fast)) {
LOG(WARNING) <<
"!bang JNI is deprecated. Switch to @FastNative for "
<< m
-
>PrettyMethod();
is_fast
=
false;
/
/
TODO: make this a hard register error
in
the future.
}
/
/
最终调用 class_linker
-
>RegisterNative 来实际进行注册
const void
*
final_function_ptr
=
class_linker
-
>RegisterNative(soa.Self(), m, fnPtr);
UNUSED(final_function_ptr);
}
return
JNI_OK;
}
const void
*
ClassLinker::RegisterNative(
Thread
*
self
, ArtMethod
*
method, const void
*
native_method) {
CHECK(method
-
>IsNative()) << method
-
>PrettyMethod();
CHECK(native_method !
=
nullptr) << method
-
>PrettyMethod();
void
*
new_native_method
=
nullptr;
Runtime
*
runtime
=
Runtime::Current();
/
/
这里 JVMTI 响应注册事件
runtime
-
>GetRuntimeCallbacks()
-
>RegisterNativeMethod(method,
native_method,
/
*
out
*
/
&new_native_method);
if
(method
-
>IsCriticalNative()) {
MutexLock lock(
self
, critical_native_code_with_clinit_check_lock_);
/
/
Remove old registered method
if
any
.
auto it
=
critical_native_code_with_clinit_check_.find(method);
if
(it !
=
critical_native_code_with_clinit_check_.end()) {
critical_native_code_with_clinit_check_.erase(it);
}
/
/
To ensure correct memory visibility, we need the
class
to be visibly
/
/
initialized before we can
set
the JNI entrypoint.
if
(method
-
>GetDeclaringClass()
-
>IsVisiblyInitialized()) {
method
-
>SetEntryPointFromJni(new_native_method);
}
else
{
critical_native_code_with_clinit_check_.emplace(method, new_native_method);
}
}
else
{
method
-
>SetEntryPointFromJni(new_native_method);
}
return
new_native_method;
}
const void
*
ClassLinker::RegisterNative(
Thread
*
self
, ArtMethod
*
method, const void
*
native_method) {
CHECK(method
-
>IsNative()) << method
-
>PrettyMethod();
CHECK(native_method !
=
nullptr) << method
-
>PrettyMethod();
void
*
new_native_method
=
nullptr;
Runtime
*
runtime
=
Runtime::Current();
/
/
这里 JVMTI 响应注册事件
runtime
-
>GetRuntimeCallbacks()
-
>RegisterNativeMethod(method,
native_method,
/
*
out
*
/
&new_native_method);
if
(method
-
>IsCriticalNative()) {
MutexLock lock(
self
, critical_native_code_with_clinit_check_lock_);
/
/
Remove old registered method
if
any
.
auto it
=
critical_native_code_with_clinit_check_.find(method);
if
(it !
=
critical_native_code_with_clinit_check_.end()) {
critical_native_code_with_clinit_check_.erase(it);
}
/
/
To ensure correct memory visibility, we need the
class
to be visibly
/
/
initialized before we can
set
the JNI entrypoint.
if
(method
-
>GetDeclaringClass()
-
>IsVisiblyInitialized()) {
method
-
>SetEntryPointFromJni(new_native_method);
}
else
{
critical_native_code_with_clinit_check_.emplace(method, new_native_method);
}
}
else
{
method
-
>SetEntryPointFromJni(new_native_method);
}
return
new_native_method;
}
void SetEntryPointFromJni(const void
*
entrypoint)
REQUIRES_SHARED(Locks::mutator_lock_) {
/
/
The resolution method also has a JNI entrypoint
for
direct calls
from
/
/
compiled code to the JNI dlsym lookup stub
for
@CriticalNative.
DCHECK(IsNative() || IsRuntimeMethod());
SetEntryPointFromJniPtrSize(entrypoint, kRuntimePointerSize);
}
void SetEntryPointFromJni(const void
*
entrypoint)
REQUIRES_SHARED(Locks::mutator_lock_) {
/
/
The resolution method also has a JNI entrypoint
for
direct calls
from
/
/
compiled code to the JNI dlsym lookup stub
for
@CriticalNative.
DCHECK(IsNative() || IsRuntimeMethod());
SetEntryPointFromJniPtrSize(entrypoint, kRuntimePointerSize);
}
/
/
Android
9
~
11
const void
*
ArtMethod::RegisterNative(const void
*
native_method) {
CHECK(IsNative()) << PrettyMethod();
CHECK(native_method !
=
nullptr) << PrettyMethod();
void
*
new_native_method
=
nullptr;
Runtime::Current()
-
>GetRuntimeCallbacks()
-
>RegisterNativeMethod(this,
native_method,
/
*
out
*
/
&new_native_method);
SetEntryPointFromJni(new_native_method);
return
new_native_method;
}
/
/
Android
9
以下
const void
*
ArtMethod::RegisterNative(const void
*
native_method,
bool
is_fast) {
CHECK(IsNative()) << PrettyMethod();
/
/
多了一个 FastNative 检测,在已经注册为 FastNative 后不能再次注册
CHECK(!IsFastNative()) << PrettyMethod();
CHECK(native_method !
=
nullptr) << PrettyMethod();
if
(is_fast) {
AddAccessFlags(kAccFastNative);
}
void
*
new_native_method
=
nullptr;
Runtime::Current()
-
>GetRuntimeCallbacks()
-
>RegisterNativeMethod(this,
native_method,
/
*
out
*
/
&new_native_method);
SetEntryPointFromJni(new_native_method);
return
new_native_method;
}
/
/
Android
9
~
11
const void
*
ArtMethod::RegisterNative(const void
*
native_method) {
CHECK(IsNative()) << PrettyMethod();
CHECK(native_method !
=
nullptr) << PrettyMethod();
void
*
new_native_method
=
nullptr;
Runtime::Current()
-
>GetRuntimeCallbacks()
-
>RegisterNativeMethod(this,
native_method,
/
*
out
*
/
&new_native_method);
SetEntryPointFromJni(new_native_method);
return
new_native_method;
}
/
/
Android
9
以下
const void
*
ArtMethod::RegisterNative(const void
*
native_method,
bool
is_fast) {
CHECK(IsNative()) << PrettyMethod();
/
/
多了一个 FastNative 检测,在已经注册为 FastNative 后不能再次注册
CHECK(!IsFastNative()) << PrettyMethod();
CHECK(native_method !
=
nullptr) << PrettyMethod();
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)