最近在学加固,做了点笔记,前面分享过一篇Dalvik 虚拟机代码加载简析
这篇是Art版,基于android-5.0.0_r2
懒得画图了,art其他版本后续有空再更吧(逃
java层和android-4.4.4_r1好像区别不大
android5的mCookie 类型由int 变成了long
android4 native层和java层(好像?)是通过brige连接
android5 开始才是JNI标准
支持多multidex
其实这里可以看到关键脱壳点OpenMemory函数,Android6,Android7也是这个函数,通过源码代码执行的分析,可以帮助我们去更好地理解脱壳。
这里附上基于Android5的不落地加载代码:
注:仅学习笔记,如有理解错误的地方还望包涵~
xref: libcore
/
dalvik
/
src
/
main
/
java
/
dalvik
/
system
/
DexClassLoader.java
extends BaseDexClassLoader
xref: libcore
/
dalvik
/
src
/
main
/
java
/
dalvik
/
system
/
DexClassLoader.java
extends BaseDexClassLoader
dexPath:dex文件源码目录
optimizedDirectory:优化以后odex生成目录
librarySearchPath:需要的本地so库的搜索路径
parent:父加载器
public DexClassLoader(String dexPath, String optimizedDirectory,
String libraryPath, ClassLoader parent) {
super
(dexPath, new
File
(optimizedDirectory), libraryPath, parent);
}
dexPath:dex文件源码目录
optimizedDirectory:优化以后odex生成目录
librarySearchPath:需要的本地so库的搜索路径
parent:父加载器
public DexClassLoader(String dexPath, String optimizedDirectory,
String libraryPath, ClassLoader parent) {
super
(dexPath, new
File
(optimizedDirectory), libraryPath, parent);
}
xref: libcore
/
dalvik
/
src
/
main
/
java
/
dalvik
/
system
/
BaseDexClassLoader.java
extends ClassLoader
private final DexPathList pathList;
xref: libcore
/
dalvik
/
src
/
main
/
java
/
dalvik
/
system
/
BaseDexClassLoader.java
extends ClassLoader
private final DexPathList pathList;
public BaseDexClassLoader(String dexPath,
File
optimizedDirectory,
String libraryPath, ClassLoader parent) {
super
(parent);
this.pathList
=
new DexPathList(this, dexPath, libraryPath, optimizedDirectory);
}
public BaseDexClassLoader(String dexPath,
File
optimizedDirectory,
String libraryPath, ClassLoader parent) {
super
(parent);
this.pathList
=
new DexPathList(this, dexPath, libraryPath, optimizedDirectory);
}
xref:
/
libcore
/
dalvik
/
src
/
main
/
java
/
dalvik
/
system
/
DexPathList.java
private final Element[] dexElements;
xref:
/
libcore
/
dalvik
/
src
/
main
/
java
/
dalvik
/
system
/
DexPathList.java
private final Element[] dexElements;
public DexPathList(ClassLoader definingContext, String dexPath,
String libraryPath,
File
optimizedDirectory) {
...
this.dexElements
=
makeDexElements(splitDexPath(dexPath),
optimizedDirectory,suppressedExceptions);
}
public DexPathList(ClassLoader definingContext, String dexPath,
String libraryPath,
File
optimizedDirectory) {
...
this.dexElements
=
makeDexElements(splitDexPath(dexPath),
optimizedDirectory,suppressedExceptions);
}
private static Element[] makeDexElements(ArrayList<
File
> files,
File
optimizedDirectory,
ArrayList<IOException> suppressedExceptions) {
ArrayList<Element> elements
=
new ArrayList<Element>();
...
for
(
File
file
: files) {
DexFile dex
=
loadDexFile(
file
, optimizedDirectory);
}
if
((
zip
!
=
null) || (dex !
=
null)) {
elements.add(new Element(
file
, false,
zip
, dex));
}
return
elements.toArray(new Element[elements.size()]);
/
/
返回赋值给dexElements
}
private static Element[] makeDexElements(ArrayList<
File
> files,
File
optimizedDirectory,
ArrayList<IOException> suppressedExceptions) {
ArrayList<Element> elements
=
new ArrayList<Element>();
...
for
(
File
file
: files) {
DexFile dex
=
loadDexFile(
file
, optimizedDirectory);
}
if
((
zip
!
=
null) || (dex !
=
null)) {
elements.add(new Element(
file
, false,
zip
, dex));
}
return
elements.toArray(new Element[elements.size()]);
/
/
返回赋值给dexElements
}
private static DexFile loadDexFile(
File
file
,
File
optimizedDirectory)
throws IOException {
...
return
DexFile.loadDex(
file
.getPath(), optimizedPath,
0
);
}
private static DexFile loadDexFile(
File
file
,
File
optimizedDirectory)
throws IOException {
...
return
DexFile.loadDex(
file
.getPath(), optimizedPath,
0
);
}
xref:
/
libcore
/
dalvik
/
src
/
main
/
java
/
dalvik
/
system
/
DexFile.java
private
long
mCookie;
xref:
/
libcore
/
dalvik
/
src
/
main
/
java
/
dalvik
/
system
/
DexFile.java
private
long
mCookie;
static public DexFile loadDex(String sourcePathName, String outputPathName,
int
flags) throws IOException {
return
new DexFile(sourcePathName, outputPathName, flags);
}
static public DexFile loadDex(String sourcePathName, String outputPathName,
int
flags) throws IOException {
return
new DexFile(sourcePathName, outputPathName, flags);
}
private DexFile(String sourceName, String outputName,
int
flags) throws IOException {
...
mCookie
=
openDexFile(sourceName, outputName, flags);
}
private DexFile(String sourceName, String outputName,
int
flags) throws IOException {
...
mCookie
=
openDexFile(sourceName, outputName, flags);
}
private static
long
openDexFile(String sourceName, String outputName,
int
flags) throws IOException {
return
openDexFileNative(new
File
(sourceName).getCanonicalPath(),
(outputName
=
=
null) ? null : new
File
(outputName).getCanonicalPath(),
flags);
}
private static
long
openDexFile(String sourceName, String outputName,
int
flags) throws IOException {
return
openDexFileNative(new
File
(sourceName).getCanonicalPath(),
(outputName
=
=
null) ? null : new
File
(outputName).getCanonicalPath(),
flags);
}
native private static
long
openDexFileNative(String sourceName, String outputName,
int
flags) throws IOException;
native private static
long
openDexFileNative(String sourceName, String outputName,
int
flags) throws IOException;
DexPathList pathList
Element[] dexElements
DexFile dex
/
/
new Element(
file
, false,
zip
, dex)
long
mCookie
BaseDexClassLoader中有pathList变量
pathList中有dexElements变量,dexElements中每一个Element由dex初始化
每个DexFile中最关键的就是mCookie,也就是native层的dex_files指针
DexPathList pathList
Element[] dexElements
DexFile dex
/
/
new Element(
file
, false,
zip
, dex)
long
mCookie
BaseDexClassLoader中有pathList变量
pathList中有dexElements变量,dexElements中每一个Element由dex初始化
每个DexFile中最关键的就是mCookie,也就是native层的dex_files指针
xref:
/
art
/
runtime
/
native
/
dalvik_system_DexFile.cc
std::unique_ptr<std::vector<const DexFile
*
>> dex_files(new std::vector<const DexFile
*
>());
xref:
/
art
/
runtime
/
native
/
dalvik_system_DexFile.cc
std::unique_ptr<std::vector<const DexFile
*
>> dex_files(new std::vector<const DexFile
*
>());
static jlong DexFile_openDexFileNative(JNIEnv
*
env, jclass, jstring javaSourceName, jstring javaOutputName, jint) {
...
ClassLinker
*
linker
=
Runtime::Current()
-
>GetClassLinker();
std::unique_ptr<std::vector<const DexFile
*
>> dex_files(new std::vector<const DexFile
*
>());
bool
success
=
linker
-
>OpenDexFilesFromOat(sourceName.c_str(), outputName.c_str(), &error_msgs,dex_files.get());
if
(success || !dex_files
-
>empty()) {
/
/
In the case of non
-
success, we have
not
found
or
could
not
generate the oat
file
.
/
/
But we may still have found a dex
file
that we can use.
return
static_cast<jlong>(reinterpret_cast<uintptr_t>(dex_files.release()));
}
}
static jlong DexFile_openDexFileNative(JNIEnv
*
env, jclass, jstring javaSourceName, jstring javaOutputName, jint) {
...
ClassLinker
*
linker
=
Runtime::Current()
-
>GetClassLinker();
std::unique_ptr<std::vector<const DexFile
*
>> dex_files(new std::vector<const DexFile
*
>());
bool
success
=
linker
-
>OpenDexFilesFromOat(sourceName.c_str(), outputName.c_str(), &error_msgs,dex_files.get());
if
(success || !dex_files
-
>empty()) {
/
/
In the case of non
-
success, we have
not
found
or
could
not
generate the oat
file
.
/
/
But we may still have found a dex
file
that we can use.
return
static_cast<jlong>(reinterpret_cast<uintptr_t>(dex_files.release()));
}
}
xref:
/
art
/
runtime
/
class_linker.cc
xref:
/
art
/
runtime
/
class_linker.cc
bool
ClassLinker::OpenDexFilesFromOat(const char
*
dex_location, const char
*
oat_location,
std::vector<std::string>
*
error_msgs,
std::vector<const DexFile
*
>
*
dex_files) {
if
(!DexFile::GetChecksum(dex_location, dex_location_checksum_pointer, &checksum_error_msg)) {
...
}
/
/
检查是否我们有一个已经打开的oatfile(内存中)
const OatFile::OatDexFile
*
oat_dex_file
=
FindOpenedOatDexFile(oat_location, dex_location,dex_location_checksum_pointer);
std::unique_ptr<const OatFile> open_oat_file(
oat_dex_file !
=
nullptr ? oat_dex_file
-
>GetOatFile() : nullptr);
/
/
检查是否我们有一个可以使用的的oatfile(磁盘上),通过oat_location字符串
if
(open_oat_file.get()
=
=
nullptr) {
open_oat_file.reset(FindOatFileInOatLocationForDexFile(dex_location, dex_location_checksum,oat_location, &error_msg));
...
needs_registering
=
true;
}
/
/
如果我们有一个oat文件,检查所有包含的multidex文件以确定我们的dex位置
bool
success
=
LoadMultiDexFilesFromOatFile(open_oat_file.get(), dex_location,
dex_location_checksum_pointer,
false, error_msgs, dex_files);
if
(success) {
const OatFile
*
oat_file
=
open_oat_file.release();
/
/
Avoid deleting it.
if
(needs_registering) {
/
/
We opened the oat
file
, so we must register it.
RegisterOatFile(oat_file);
}
return
oat_file
-
>IsExecutable();
}
/
/
如果不是这样(要么没有oat文件,要么不匹配),重新生成并加载oat,通过dex_location字符串
if
(Runtime::Current()
-
>IsDex2OatEnabled() && has_flock && scoped_flock.HasFile()) {
/
/
Create the oat
file
.
open_oat_file.reset(CreateOatFileForDexLocation(dex_location, scoped_flock.GetFile()
-
>Fd(),oat_location, error_msgs));
}
/
/
Failed, bail.art模式下的解析模式,以上都是编译成oat的编译模式
if
(open_oat_file.get()
=
=
nullptr) {
std::string error_msg;
/
/
dex2oat was disabled
or
crashed. Add the dex
file
in
the
list
of dex_files to make progress.
DexFile::
Open
(dex_location, dex_location, &error_msg, dex_files);
error_msgs
-
>push_back(error_msg);
return
false;
}
/
/
Try to load again, but stronger checks.
success
=
LoadMultiDexFilesFromOatFile(open_oat_file.get(), dex_location,
dex_location_checksum_pointer,
true, error_msgs, dex_files);
if
(success) {
RegisterOatFile(open_oat_file.release());
return
true;
}
}
bool
ClassLinker::OpenDexFilesFromOat(const char
*
dex_location, const char
*
oat_location,
std::vector<std::string>
*
error_msgs,
std::vector<const DexFile
*
>
*
dex_files) {
if
(!DexFile::GetChecksum(dex_location, dex_location_checksum_pointer, &checksum_error_msg)) {
...
}
/
/
检查是否我们有一个已经打开的oatfile(内存中)
const OatFile::OatDexFile
*
oat_dex_file
=
FindOpenedOatDexFile(oat_location, dex_location,dex_location_checksum_pointer);
std::unique_ptr<const OatFile> open_oat_file(
oat_dex_file !
=
nullptr ? oat_dex_file
-
>GetOatFile() : nullptr);
/
/
检查是否我们有一个可以使用的的oatfile(磁盘上),通过oat_location字符串
if
(open_oat_file.get()
=
=
nullptr) {
open_oat_file.reset(FindOatFileInOatLocationForDexFile(dex_location, dex_location_checksum,oat_location, &error_msg));
...
needs_registering
=
true;
}
/
/
如果我们有一个oat文件,检查所有包含的multidex文件以确定我们的dex位置
bool
success
=
LoadMultiDexFilesFromOatFile(open_oat_file.get(), dex_location,
dex_location_checksum_pointer,
false, error_msgs, dex_files);
if
(success) {
const OatFile
*
oat_file
=
open_oat_file.release();
/
/
Avoid deleting it.
if
(needs_registering) {
/
/
We opened the oat
file
, so we must register it.
RegisterOatFile(oat_file);
}
return
oat_file
-
>IsExecutable();
}
/
/
如果不是这样(要么没有oat文件,要么不匹配),重新生成并加载oat,通过dex_location字符串
if
(Runtime::Current()
-
>IsDex2OatEnabled() && has_flock && scoped_flock.HasFile()) {
/
/
Create the oat
file
.
open_oat_file.reset(CreateOatFileForDexLocation(dex_location, scoped_flock.GetFile()
-
>Fd(),oat_location, error_msgs));
}
/
/
Failed, bail.art模式下的解析模式,以上都是编译成oat的编译模式
if
(open_oat_file.get()
=
=
nullptr) {
std::string error_msg;
/
/
dex2oat was disabled
or
crashed. Add the dex
file
in
the
list
of dex_files to make progress.
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)