-
-
[原创]android JNI静态注册和动态注册
-
发表于: 2021-9-28 20:46 9452
-
这几天在摸android的题目, 在XCTF里面做了一个ONLOAD来动态注册native的题目, 但是本身ida的export能够找到对应native函数名. 想找找ONLOAD注册方法和直接调用的区别, 就仔细去翻了一些相关的帖子.
这个OnLoad注册了一个名为CheckFlag的方法.
native方法分为静态注册和动态注册两种.(我的环境是java16)
因为注册的过程不太好调, 可能会有问题, 如果有错误请师傅们提出来, 我好及时改进.
java的每个方法都会有一个Method对象, 而这个Method对象有两个成员:nativeFunc和insns.
当java构建这个native方法时, 会将该方法对应的Method对象的nativeFunc成员设置为dvmResolveNativeMethod, dvmResolveNativeMethod方法会按照方法的名称去查找对应的C方法.
lookupSharedLibMethod函数用来查找SO层里面的方法, 再看下lookupSharedLibMethod代码
dvmHashForeach的注释是
findMethodInLib:
最终通过调用dlsym来查找so文件里面的方法, 这和windows的GetProAddress()很类似了.
在dvmResolveNativeMethod找到对应的方法后, 会对native方法对应的方法对象进行再一次赋值,
nativeFunc = dvmCallJNIMethod, insns = 找到的so中的方法地址.
dvmCallJNIMethod方法是一个bridge方法, 这个方法的作用就是调用insns对应的方法
当native方法对象构建好了之后, nativeFunc中已经有值, 这样就会直接执行nativeFunc方法
动态注册是将RegisterNatives放在OnLoad方法里面, 在加载库的时候, 会通过dlsym调用Onload方法.
System.java:
Runtime.class:
ClassLoader.loadLibrary:
libs.loadLibrary():
findFromPaths():
loadLibrary():
然后发现居然最后调用了一个native :
NativeLibraries.c:
findJniFunction:
buildJniFunctionName:
JVM_FindLibraryEntry中调用了dlsym()
然后在Onload里面写RegisterNatives方法就可以进行方法注册:
RegisterNatives的第二个参数为JNINativeMethod类型, 这个类型的定义为:
最后对native方法对应的方法对象进行赋值, 和静态注册类似
nativeFunc = dvmCallJNIMethod, insns = 找到的so中的方法地址.
最后可以总结一些, 在静态注册的时候,感觉和windows的iat加载有点类似, 一个是通过GetProAddress()查找DLL的EAT来实现,一个是通过通过dlsym寻找动态符号表.动态注册的时候, 是事先对结构体中的函数指针进行赋值, 通过RegisterNatives进行注册.当注册好了之后, native方法对应的方法对象的成员nativeFunc==dvmCallJNIMethod, 就不会在再设置为dvmResolveNativeMethod, 而是直接执行vmCallJNIMethod, 调用insns的方法.
void dvmResolveNativeMethod(const u4
*
args, JValue
*
pResult,
const Method
*
method, Thread
*
self
)
{
ClassObject
*
clazz
=
method
-
>clazz;
/
*
*
If this
is
a static method, it could be called before the
class
*
has been initialized.
*
/
if
(dvmIsStaticMethod(method)) {
if
(!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
assert
(dvmCheckException(dvmThreadSelf()));
return
;
}
}
else
{
assert
(dvmIsClassInitialized(clazz) ||
dvmIsClassInitializing(clazz));
}
/
*
start with our internal
-
native methods
*
/
DalvikNativeFunc infunc
=
dvmLookupInternalNativeMethod(method);
if
(infunc !
=
NULL) {
/
*
resolution always gets the same answer, so no race here
*
/
IF_LOGVV() {
char
*
desc
=
dexProtoCopyMethodDescriptor(&method
-
>prototype);
LOGVV(
"+++ resolved native %s.%s %s, invoking"
,
clazz
-
>descriptor, method
-
>name, desc);
free(desc);
}
if
(dvmIsSynchronizedMethod(method)) {
ALOGE(
"ERROR: internal-native can't be declared 'synchronized'"
);
ALOGE(
"Failing on %s.%s"
, method
-
>clazz
-
>descriptor, method
-
>name);
dvmAbort();
/
/
harsh, but this
is
VM
-
internal problem
}
DalvikBridgeFunc dfunc
=
(DalvikBridgeFunc) infunc;
dvmSetNativeFunc((Method
*
) method, dfunc, NULL);
dfunc(args, pResult, method,
self
);
return
;
}
/
*
now scan
any
DLLs we have loaded
for
JNI signatures
*
/
void
*
func
=
lookupSharedLibMethod(method);
if
(func !
=
NULL) {
/
*
found it, point it at the JNI bridge
and
then call it
*
/
dvmUseJNIBridge((Method
*
) method, func);
(
*
method
-
>nativeFunc)(args, pResult, method,
self
);
return
;
}
IF_ALOGW() {
char
*
desc
=
dexProtoCopyMethodDescriptor(&method
-
>prototype);
ALOGW(
"No implementation found for native %s.%s:%s"
,
clazz
-
>descriptor, method
-
>name, desc);
free(desc);
}
dvmThrowUnsatisfiedLinkError(
"Native method not found"
, method);
}
void dvmResolveNativeMethod(const u4
*
args, JValue
*
pResult,
const Method
*
method, Thread
*
self
)
{
ClassObject
*
clazz
=
method
-
>clazz;
/
*
*
If this
is
a static method, it could be called before the
class
*
has been initialized.
*
/
if
(dvmIsStaticMethod(method)) {
if
(!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
assert
(dvmCheckException(dvmThreadSelf()));
return
;
}
}
else
{
assert
(dvmIsClassInitialized(clazz) ||
dvmIsClassInitializing(clazz));
}
/
*
start with our internal
-
native methods
*
/
DalvikNativeFunc infunc
=
dvmLookupInternalNativeMethod(method);
if
(infunc !
=
NULL) {
/
*
resolution always gets the same answer, so no race here
*
/
IF_LOGVV() {
char
*
desc
=
dexProtoCopyMethodDescriptor(&method
-
>prototype);
LOGVV(
"+++ resolved native %s.%s %s, invoking"
,
clazz
-
>descriptor, method
-
>name, desc);
free(desc);
}
if
(dvmIsSynchronizedMethod(method)) {
ALOGE(
"ERROR: internal-native can't be declared 'synchronized'"
);
ALOGE(
"Failing on %s.%s"
, method
-
>clazz
-
>descriptor, method
-
>name);
dvmAbort();
/
/
harsh, but this
is
VM
-
internal problem
}
DalvikBridgeFunc dfunc
=
(DalvikBridgeFunc) infunc;
dvmSetNativeFunc((Method
*
) method, dfunc, NULL);
dfunc(args, pResult, method,
self
);
return
;
}
/
*
now scan
any
DLLs we have loaded
for
JNI signatures
*
/
void
*
func
=
lookupSharedLibMethod(method);
if
(func !
=
NULL) {
/
*
found it, point it at the JNI bridge
and
then call it
*
/
dvmUseJNIBridge((Method
*
) method, func);
(
*
method
-
>nativeFunc)(args, pResult, method,
self
);
return
;
}
IF_ALOGW() {
char
*
desc
=
dexProtoCopyMethodDescriptor(&method
-
>prototype);
ALOGW(
"No implementation found for native %s.%s:%s"
,
clazz
-
>descriptor, method
-
>name, desc);
free(desc);
}
dvmThrowUnsatisfiedLinkError(
"Native method not found"
, method);
}
static void
*
lookupSharedLibMethod(const Method
*
method)
{
if
(gDvm.nativeLibs
=
=
NULL) {
ALOGE(
"Unexpected init state: nativeLibs not ready"
);
dvmAbort();
}
return
(void
*
) dvmHashForeach(gDvm.nativeLibs, findMethodInLib,
(void
*
) method);
}
static void
*
lookupSharedLibMethod(const Method
*
method)
{
if
(gDvm.nativeLibs
=
=
NULL) {
ALOGE(
"Unexpected init state: nativeLibs not ready"
);
dvmAbort();
}
return
(void
*
) dvmHashForeach(gDvm.nativeLibs, findMethodInLib,
(void
*
) method);
}
int
dvmHashForeach(HashTable
*
pHashTable, HashForeachFunc func, void
*
arg);
/
*
*
Execute
"func"
on every entry
in
the
hash
table.
*
*
If
"func"
returns
1
detach the entry
from
the
hash
table. Does
not
invoke
*
the
"free"
function.
*
*
Returning values other than
0
or
1
from
"func"
will abort the routine.
*
/
int
dvmHashForeach(HashTable
*
pHashTable, HashForeachFunc func, void
*
arg);
/
*
*
Execute
"func"
on every entry
in
the
hash
table.
*
*
If
"func"
returns
1
detach the entry
from
the
hash
table. Does
not
invoke
*
the
"free"
function.
*
*
Returning values other than
0
or
1
from
"func"
will abort the routine.
*
/
static
int
findMethodInLib(void
*
vlib, void
*
vmethod)
{
const SharedLib
*
pLib
=
(const SharedLib
*
) vlib;
const Method
*
meth
=
(const Method
*
) vmethod;
char
*
preMangleCM
=
NULL;
char
*
mangleCM
=
NULL;
char
*
mangleSig
=
NULL;
char
*
mangleCMSig
=
NULL;
void
*
func
=
NULL;
int
len
;
if
(meth
-
>clazz
-
>classLoader !
=
pLib
-
>classLoader) {
ALOGV(
"+++ not scanning '%s' for '%s' (wrong CL)"
,
pLib
-
>pathName, meth
-
>name);
return
0
;
}
else
ALOGV(
"+++ scanning '%s' for '%s'"
, pLib
-
>pathName, meth
-
>name);
/
*
*
First, we
try
it without the signature.
*
/
preMangleCM
=
createJniNameString(meth
-
>clazz
-
>descriptor, meth
-
>name, &
len
);
if
(preMangleCM
=
=
NULL)
goto bail;
mangleCM
=
mangleString(preMangleCM,
len
);
if
(mangleCM
=
=
NULL)
goto bail;
ALOGV(
"+++ calling dlsym(%s)"
, mangleCM);
func
=
dlsym(pLib
-
>handle, mangleCM);
if
(func
=
=
NULL) {
mangleSig
=
createMangledSignature(&meth
-
>prototype);
if
(mangleSig
=
=
NULL)
goto bail;
mangleCMSig
=
(char
*
) malloc(strlen(mangleCM)
+
strlen(mangleSig)
+
3
);
if
(mangleCMSig
=
=
NULL)
goto bail;
sprintf(mangleCMSig,
"%s__%s"
, mangleCM, mangleSig);
ALOGV(
"+++ calling dlsym(%s)"
, mangleCMSig);
func
=
dlsym(pLib
-
>handle, mangleCMSig);
if
(func !
=
NULL) {
ALOGV(
"Found '%s' with dlsym"
, mangleCMSig);
}
}
else
{
ALOGV(
"Found '%s' with dlsym"
, mangleCM);
}
bail:
free(preMangleCM);
free(mangleCM);
free(mangleSig);
free(mangleCMSig);
return
(
int
) func;
}
static
int
findMethodInLib(void
*
vlib, void
*
vmethod)
{
const SharedLib
*
pLib
=
(const SharedLib
*
) vlib;
const Method
*
meth
=
(const Method
*
) vmethod;
char
*
preMangleCM
=
NULL;
char
*
mangleCM
=
NULL;
char
*
mangleSig
=
NULL;
char
*
mangleCMSig
=
NULL;
void
*
func
=
NULL;
int
len
;
if
(meth
-
>clazz
-
>classLoader !
=
pLib
-
>classLoader) {
ALOGV(
"+++ not scanning '%s' for '%s' (wrong CL)"
,
pLib
-
>pathName, meth
-
>name);
return
0
;
}
else
ALOGV(
"+++ scanning '%s' for '%s'"
, pLib
-
>pathName, meth
-
>name);
/
*
*
First, we
try
it without the signature.
*
/
preMangleCM
=
createJniNameString(meth
-
>clazz
-
>descriptor, meth
-
>name, &
len
);
if
(preMangleCM
=
=
NULL)
goto bail;
mangleCM
=
mangleString(preMangleCM,
len
);
if
(mangleCM
=
=
NULL)
goto bail;
ALOGV(
"+++ calling dlsym(%s)"
, mangleCM);
func
=
dlsym(pLib
-
>handle, mangleCM);
if
(func
=
=
NULL) {
mangleSig
=
createMangledSignature(&meth
-
>prototype);
if
(mangleSig
=
=
NULL)
goto bail;
mangleCMSig
=
(char
*
) malloc(strlen(mangleCM)
+
strlen(mangleSig)
+
3
);
if
(mangleCMSig
=
=
NULL)
goto bail;
sprintf(mangleCMSig,
"%s__%s"
, mangleCM, mangleSig);
ALOGV(
"+++ calling dlsym(%s)"
, mangleCMSig);
func
=
dlsym(pLib
-
>handle, mangleCMSig);
if
(func !
=
NULL) {
ALOGV(
"Found '%s' with dlsym"
, mangleCMSig);
}
}
else
{
ALOGV(
"Found '%s' with dlsym"
, mangleCM);
}
bail:
free(preMangleCM);
free(mangleCM);
free(mangleSig);
free(mangleCMSig);
return
(
int
) func;
}
public static void loadLibrary(String libname) {
Runtime.getRuntime().loadLibrary0(Reflection.getCallerClass(), libname);
}
public static void loadLibrary(String libname) {
Runtime.getRuntime().loadLibrary0(Reflection.getCallerClass(), libname);
}
void loadLibrary0(Class<?> fromClass, String libname) {
SecurityManager security
=
System.getSecurityManager();
if
(security !
=
null) {
security.checkLink(libname);
}
if
(libname.indexOf((
int
)
File
.separatorChar) !
=
-
1
) {
throw new UnsatisfiedLinkError(
"Directory separator should not appear in library name: "
+
libname);
}
ClassLoader.loadLibrary(fromClass, libname);
}
void loadLibrary0(Class<?> fromClass, String libname) {
SecurityManager security
=
System.getSecurityManager();
if
(security !
=
null) {
security.checkLink(libname);
}
if
(libname.indexOf((
int
)
File
.separatorChar) !
=
-
1
) {
throw new UnsatisfiedLinkError(
"Directory separator should not appear in library name: "
+
libname);
}
ClassLoader.loadLibrary(fromClass, libname);
}
static NativeLibrary loadLibrary(Class<?> fromClass, String name) {
ClassLoader loader
=
(fromClass
=
=
null) ? null : fromClass.getClassLoader();
if
(loader
=
=
null) {
NativeLibrary nl
=
BootLoader.getNativeLibraries().loadLibrary(fromClass, name);
if
(nl !
=
null) {
return
nl;
}
throw new UnsatisfiedLinkError(
"no "
+
name
+
" in system library path: "
+
StaticProperty.sunBootLibraryPath());
}
NativeLibraries libs
=
loader.libraries;
/
/
First load
from
the
file
returned
from
ClassLoader::findLibrary,
if
found.
String libfilename
=
loader.findLibrary(name);
if
(libfilename !
=
null) {
File
libfile
=
new
File
(libfilename);
if
(!libfile.isAbsolute()) {
throw new UnsatisfiedLinkError(
"ClassLoader.findLibrary failed to return an absolute path: "
+
libfilename);
}
NativeLibrary nl
=
libs.loadLibrary(fromClass, libfile);
if
(nl !
=
null) {
return
nl;
}
throw new UnsatisfiedLinkError(
"Can't load "
+
libfilename);
}
/
/
Then load
from
system library path
and
java library path
NativeLibrary nl
=
libs.loadLibrary(fromClass, name);
if
(nl !
=
null) {
return
nl;
}
/
/
Oops, it failed
throw new UnsatisfiedLinkError(
"no "
+
name
+
" in java.library.path: "
+
StaticProperty.javaLibraryPath());
}
static NativeLibrary loadLibrary(Class<?> fromClass, String name) {
ClassLoader loader
=
(fromClass
=
=
null) ? null : fromClass.getClassLoader();
if
(loader
=
=
null) {
NativeLibrary nl
=
BootLoader.getNativeLibraries().loadLibrary(fromClass, name);
if
(nl !
=
null) {
return
nl;
}
throw new UnsatisfiedLinkError(
"no "
+
name
+
" in system library path: "
+
StaticProperty.sunBootLibraryPath());
}
NativeLibraries libs
=
loader.libraries;
/
/
First load
from
the
file
returned
from
ClassLoader::findLibrary,
if
found.
String libfilename
=
loader.findLibrary(name);
if
(libfilename !
=
null) {
File
libfile
=
new
File
(libfilename);
if
(!libfile.isAbsolute()) {
throw new UnsatisfiedLinkError(
"ClassLoader.findLibrary failed to return an absolute path: "
+
libfilename);
}
NativeLibrary nl
=
libs.loadLibrary(fromClass, libfile);
if
(nl !
=
null) {
return
nl;
}
throw new UnsatisfiedLinkError(
"Can't load "
+
libfilename);
}
/
/
Then load
from
system library path
and
java library path
NativeLibrary nl
=
libs.loadLibrary(fromClass, name);
if
(nl !
=
null) {
return
nl;
}
/
/
Oops, it failed
throw new UnsatisfiedLinkError(
"no "
+
name
+
" in java.library.path: "
+
StaticProperty.javaLibraryPath());
}
public NativeLibrary loadLibrary(Class<?> fromClass, String name) {
assert
name.indexOf(
File
.separatorChar) <
0
;
NativeLibrary lib
=
findFromPaths(LibraryPaths.SYS_PATHS, fromClass, name);
if
(lib
=
=
null && searchJavaLibraryPath) {
lib
=
findFromPaths(LibraryPaths.USER_PATHS, fromClass, name);
}
return
lib;
}
public NativeLibrary loadLibrary(Class<?> fromClass, String name) {
assert
name.indexOf(
File
.separatorChar) <
0
;
NativeLibrary lib
=
findFromPaths(LibraryPaths.SYS_PATHS, fromClass, name);
if
(lib
=
=
null && searchJavaLibraryPath) {
lib
=
findFromPaths(LibraryPaths.USER_PATHS, fromClass, name);
}
return
lib;
}
private NativeLibrary findFromPaths(String[] paths, Class<?> fromClass, String name) {
for
(String path : paths) {
File
libfile
=
new
File
(path, System.mapLibraryName(name));
NativeLibrary nl
=
loadLibrary(fromClass, libfile);
if
(nl !
=
null) {
return
nl;
}
libfile
=
ClassLoaderHelper.mapAlternativeName(libfile);
if
(libfile !
=
null) {
nl
=
loadLibrary(fromClass, libfile);
if
(nl !
=
null) {
return
nl;
}
}
}
return
null;
}
private NativeLibrary findFromPaths(String[] paths, Class<?> fromClass, String name) {
for
(String path : paths) {
File
libfile
=
new
File
(path, System.mapLibraryName(name));
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
赞赏
- [原创]SCTF low_re出题思路 14324
- [原创]l3hctf两道re的wp 8956
- [原创]强网拟态线上mobile的两道wp 22212
- [原创]android JNI静态注册和动态注册 9453
- [原创]inctf-noodes 9766