之前将Fart8.0的代码编译到Android13下,运行发现在将Java的Method对象转换成C的ArtMethod对象时报错,没找到原因。再加上AOSP的系统太素了,就琢磨是否可以用LineageOS来编译,所以就有了这篇文章。
先罗列一下我的环境吧,编译环境是Kali2022,用的r0ysue大佬的集成版,手机是Pixel6,选择的系统是LineageOS20版(基于AOSP13)的,原本想用基于AOSP10的Lineage17的,但是官网同步源码后发现缺少device blob,遂决定就用20版。
我的虚拟机设置了32G内存,8核CPU,500G的硬盘,实际下载编译完成占用了快300G空间。这里坑的地方在于同样的配置,我的AOSP能顺利编译完成,但在编译LineageOS时中途报错,检查原因发现是因为swap只有1G大小,在设置了swap为20G后,才编译成功。
安装好git和 platform-tools 并配置环境变量
创建源码所需目录(默认在kali root账户下)
安装repo命令行工具
将bin目录添加进环境变量。
使用下面的命令打开~/.bashrc文件,
在文件最后添加下面的代码:
配置git
查看git lfs是否安装
配置缓存,加快编译速度
可将其加入到~/.bashrc文件中,并在命令行执行下行
初始化LineageOS source repository
这里最好不要换成国内源,因为国内源同步出来的代码,我在编译时碰到浏览器app编译失败的问题,重新从官方源同步才解决,查看清华的issue发现有同样的问题,坑死了。
下载源码
上面的-j8是启动8个线程下载,可以不要,默认是4个线程。取决于你的虚拟机cpu内核数。由于网络问题,如果同步完成后报错,可根据提示,将线程数减为1,重新执行该命令即可。
下载设备内核代码
确保你在源码根目录下 ( <font color='red'>cd ~/android/lineage</font> )
下载源码整个过程根据网速会有1段时间,我自己搭建了科学上网的软路由,整个时间有3个小时左右。
下载完kernel源码后会报如下的错误,这是因为还没有下载device blob的缘故,暂时不用管,下载完device blob后再重新执行上面的命令即可
这里是个大坑。我按照官方推荐的方式直接从已经安装了LineageOS的piexl6手机上提取blob,结果有几千个文件没有找到,害的我折腾了2天。总算使用官方镜像提取成功。下面是过程。
创建提取目录
下载官方镜像 LineageOS Downloads
从zip文件中解压出 payload.bin文件
安装 python-protobuf
下载官方提供的导出脚本,然后用python运行脚本,注意脚本目录路径
成功运行后,应该能在system_dump目录下看到如下一些.img文件
然后使用mout命令挂载这些img文件
进入<font color='red'>~/android/lineage/device/google/oriole</font>文件夹 运行如下命令 导出blob文件
重新执行如下命令
编译时间在2小时左右,尤其最后阶段编译kernel会持续50多分钟,这里即使我的内存设置到了32G,也不够用,需要设置swap,而且每次修改源码再编译 都会要重新编译这个kernel,很耗费时间,暂时没找到不重复编译的办法,在XDA上看到可以下载prebuild的内核,避免重复编译,实在懒折腾了,所以没尝试。
编译成功后会在/root/android/lineage/out/target/product/oriole目录下生成boot.img 和 lineage-20.0****.zip文件。按照官方文档替换官方镜像刷机即可。
按照官方文档操作即可。实在懒翻译了
Install LineageOS on oriole | LineageOS Wiki
为了方便修改源码,减少报错,可以将源码中的Java代码导入AndroidStudio,C语言代码导入CLionAS导入Android源码
先成功编译一次,再使用以下方法导入
在ubuntu系统下,进入源码根目录,运行如下命令, 会在源码目录下的out/host/linux-x86/framework目录下生成了idegen.jar文件
在源码根目录下继续执行如下命令,会在根目录下生成android.iml和android.ipr两个文件,这两个文件是AndroidStudio的工程配置文件
安装并打开AndroidStudio,选择Open an existing Android Studio project,找到源码根目录,点击Android.ipr
具体参考:https://wuxiaolong.me/2018/08/15/AOSP3/
我在AOSP中成功导入了AS,但在LineageOS源码中在执行到第3步时长时间卡住,等了30个小时不动,没辙只好放弃。改用VSCode编辑java代码。
C/C++代码导入CLion
CMakeLists.txt会生成在out/development/ide/clion/art/runtime/libart-arm64-android/CMakeLists.txt
用Clion打开CMakeLists.txt
tools--->cmake-->Change Project Root
选择aosp源码根路径,等解析完毕即可
Java代码可按上面导入的步骤,用AS编辑
修改LineageOS源码的/root/android/lineage/frameworks/base/core/java/android/app/ActivityThread.java文件,将Fart8.0对应文件中添加的部分复制到该文件中,并导入对应的包,为了防止加固厂商的检测,修改了函数名和日志输出。
在文件中的performLaunchActivity方法最后添加 wayneThread()方法的调用。
修改源码 /root/android/lineage/libcore/dalvik/src/main/java/dalvik/system/DexFile.java文件,将Fart8.0中添加的方法定义复制过来,并修改方法命名,
SO层的c\c++代码可按上面的步骤导入CLion编辑。
修改该文件最开始的art命名空间
在该文件最末尾添加saveMethodCode函数的函数名命名定义,<font color='red'>注意在上一行末尾添加逗号</font>
编辑 /root/android/lineage/art/runtime/native/java_lang_reflect_Method.cc文件,添加上面用到的jobject2ArtMethod函数
编辑/root/android/lineage/art/runtime/art_method.cc文件,将Fart8.0源码同名文件中添加的代码复制到该代码中,并修改函数名和日志输出内容。
为了防止加固厂商的检测,修改了dex文件保存的目录,由原来的sdcard目录全部改为 "/data/data/%s/wayne/%d_classlist.txt",szProcName,size_int_);"
同时修改了invoke脱壳点的脱壳函数saveArtMethod和Execute脱壳点的脱壳函数saveDexFileByExeMethod中提示错误的部分,如下所列
打开文件添加O_CREATE方式
修改文件是否存在的判断方式
修改类型定义变化的出错
修改saveArtMethod函数中计算codeItem长度的方式
在该文件最开始添加gettidv1()的宏定义
导入需要的.h文件
在Invoke函数中添加对saveArtMethod函数的调用
在该文件最前面的art命名空间添加脱壳函数的引入:
刷机完毕,将待脱壳的apk安装后运行,等待一会,进入/data/data/包名/XXX目录下可看到脱壳下来的dex文件和方法的bin文件,copy到/sdcard目录
再使用adb pull命令拖到虚拟机中修复即可。 测试发现Execute脱壳点没有生效,需要进一步查找原因。
swapoff -a
dd
if
=
/dev/zero
of=
/var/swapfile
bs=1M count=20480
mkswap
/var/swapfile
swapon
/var/swapfile
free
-m --查看当前分区
swapoff -a
dd
if
=
/dev/zero
of=
/var/swapfile
bs=1M count=20480
mkswap
/var/swapfile
swapon
/var/swapfile
free
-m --查看当前分区
apt-get update
apt-get
install
bc
bison build-essential ccache curl flex g++-multilib gcc-multilib git git-lfs gnupg gperf imagemagick
lib32ncurses5-dev lib32readline-dev lib32z1-dev libelf-dev liblz4-tool libncurses5 libncurses5-dev
libsdl1.2-dev libssl-dev libxml2 libxml2-utils lzop pngcrush
rsync
schedtool squashfs-tools xsltproc zip zlib1g-dev m4
apt-get update
apt-get
install
bc
bison build-essential ccache curl flex g++-multilib gcc-multilib git git-lfs gnupg gperf imagemagick
lib32ncurses5-dev lib32readline-dev lib32z1-dev libelf-dev liblz4-tool libncurses5 libncurses5-dev
libsdl1.2-dev libssl-dev libxml2 libxml2-utils lzop pngcrush
rsync
schedtool squashfs-tools xsltproc zip zlib1g-dev m4
mkdir
-p ~
/bin
mkdir
-p ~
/android/lineage
mkdir
-p ~
/bin
mkdir
-p ~
/android/lineage
curl https:
//storage
.googleapis.com
/git-repo-downloads/repo
> ~
/bin/repo
chmod
a+x ~
/bin/repo
curl https:
//storage
.googleapis.com
/git-repo-downloads/repo
> ~
/bin/repo
chmod
a+x ~
/bin/repo
vim ~/.bashrc
if
[ -d
"$HOME/bin"
] ;
then
PATH=
"$HOME/bin:$PATH"
fi
if
[ -d
"$HOME/bin"
] ;
then
PATH=
"$HOME/bin:$PATH"
fi
git config --global user.email
"you@example.com"
git config --global user.name
"Your Name"
git config --global user.email
"you@example.com"
git config --global user.name
"Your Name"
curl
-
s https:
/
/
packagecloud.io
/
install
/
repositories
/
github
/
git
-
lfs
/
script.deb.sh | sudo bash
apt
-
get install git
-
lfs
git lfs install
curl
-
s https:
/
/
packagecloud.io
/
install
/
repositories
/
github
/
git
-
lfs
/
script.deb.sh | sudo bash
apt
-
get install git
-
lfs
git lfs install
export USE_CCACHE
=
1
export CCACHE_EXEC
=
/
usr
/
bin
/
ccache
export USE_CCACHE
=
1
export CCACHE_EXEC
=
/
usr
/
bin
/
ccache
ccache
-
M
50G
cd ~
/
android
/
lineage
repo init
-
u https:
/
/
github.com
/
LineageOS
/
android.git
-
b lineage
-
20.0
-
-
git
-
lfs
cd ~
/
android
/
lineage
repo init
-
u https:
/
/
github.com
/
LineageOS
/
android.git
-
b lineage
-
20.0
-
-
git
-
lfs
repo sync
-
j8
source build
/
envsetup.sh
breakfast oriole
source build
/
envsetup.sh
breakfast oriole
mkdir ~
/
android
/
system_dump
/
cd ~
/
android
/
system_dump
/
mkdir ~
/
android
/
system_dump
/
cd ~
/
android
/
system_dump
/
unzip
/path/to/lineage-
*.zip payload.bin
unzip
/path/to/lineage-
*.zip payload.bin
apt-get
install
python-protobuf
apt-get
install
python-protobuf
git clone https:
//github
.com
/LineageOS/scripts
python scripts
/update-payload-extractor/extract
.py payload.bin --output_dir ./
git clone https:
//github
.com
/LineageOS/scripts
python scripts
/update-payload-extractor/extract
.py payload.bin --output_dir ./
mkdir system
/
sudo mount
-
o ro system.img system
/
sudo mount
-
o ro vendor.img system
/
vendor
/
sudo mount
-
o ro product.img system
/
product
/
sudo mount
-
o ro system_ext.img system
/
system_ext
/
mkdir system
/
sudo mount
-
o ro system.img system
/
sudo mount
-
o ro vendor.img system
/
vendor
/
sudo mount
-
o ro product.img system
/
product
/
sudo mount
-
o ro system_ext.img system
/
system_ext
/
cd
~
/android/lineage/device/google/oriole
.
/extract-files
.sh ~
/android/system_dump/
cd
~
/android/lineage/device/google/oriole
.
/extract-files
.sh ~
/android/system_dump/
source
build
/envsetup
.sh
breakfast oriole
source
build
/envsetup
.sh
breakfast oriole
croot
brunch oriole
source
build
/envsetup
.sh
mmm development
/tools/idegen/
source
build
/envsetup
.sh
mmm development
/tools/idegen/
development
/tools/idegen/idegen
.sh
development
/tools/idegen/idegen
.sh
source build
/
envsetup.sh
export SOONG_GEN_CMAKEFILES
=
1
export SOONG_GEN_CMAKEFILES_DEBUG
=
1
breakfast oriole
source build
/
envsetup.sh
export SOONG_GEN_CMAKEFILES
=
1
export SOONG_GEN_CMAKEFILES_DEBUG
=
1
breakfast oriole
public
static
Field getClassField(ClassLoader classloader, String class_name,
String filedName) {
try
{
Class obj_class = classloader.loadClass(class_name);
Field field = obj_class.getDeclaredField(filedName);
field.setAccessible(
true
);
return
field;
}
catch
(SecurityException e) {
e.printStackTrace();
}
catch
(NoSuchFieldException e) {
e.printStackTrace();
}
catch
(IllegalArgumentException e) {
e.printStackTrace();
}
catch
(ClassNotFoundException e) {
e.printStackTrace();
}
return
null
;
}
public
static
Object getClassFieldObject(ClassLoader classloader, String class_name, Object obj,
String filedName) {
try
{
Class obj_class = classloader.loadClass(class_name);
Field field = obj_class.getDeclaredField(filedName);
field.setAccessible(
true
);
Object result =
null
;
result = field.get(obj);
return
result;
}
catch
(SecurityException e) {
e.printStackTrace();
}
catch
(NoSuchFieldException e) {
e.printStackTrace();
}
catch
(IllegalArgumentException e) {
e.printStackTrace();
}
catch
(ClassNotFoundException e) {
e.printStackTrace();
}
catch
(IllegalAccessException e) {
e.printStackTrace();
}
return
null
;
}
public
static
Object invokeStaticMethod(String class_name,
String method_name, Class[] pareTyple, Object[] pareVaules) {
try
{
Class obj_class = Class.forName(class_name);
Method method = obj_class.getMethod(method_name, pareTyple);
return
method.invoke(
null
, pareVaules);
}
catch
(SecurityException e) {
e.printStackTrace();
}
catch
(IllegalArgumentException e) {
e.printStackTrace();
}
catch
(IllegalAccessException e) {
e.printStackTrace();
}
catch
(NoSuchMethodException e) {
e.printStackTrace();
}
catch
(InvocationTargetException e) {
e.printStackTrace();
}
catch
(ClassNotFoundException e) {
e.printStackTrace();
}
return
null
;
}
public
static
Object getFieldOjbect(String class_name, Object obj,
String filedName) {
try
{
Class obj_class = Class.forName(class_name);
Field field = obj_class.getDeclaredField(filedName);
field.setAccessible(
true
);
return
field.get(obj);
}
catch
(SecurityException e) {
e.printStackTrace();
}
catch
(NoSuchFieldException e) {
e.printStackTrace();
}
catch
(IllegalArgumentException e) {
e.printStackTrace();
}
catch
(IllegalAccessException e) {
e.printStackTrace();
}
catch
(ClassNotFoundException e) {
e.printStackTrace();
}
catch
(NullPointerException e) {
e.printStackTrace();
}
return
null
;
}
public
static
ClassLoader getClassloader() {
ClassLoader resultClassloader =
null
;
Object currentActivityThread = invokeStaticMethod(
"android.app.ActivityThread"
,
"currentActivityThread"
,
new
Class[]{},
new
Object[]{});
Object mBoundApplication = getFieldOjbect(
"android.app.ActivityThread"
, currentActivityThread,
"mBoundApplication"
);
Application mInitialApplication = (Application) getFieldOjbect(
"android.app.ActivityThread"
,
currentActivityThread,
"mInitialApplication"
);
Object loadedApkInfo = getFieldOjbect(
"android.app.ActivityThread$AppBindData"
,
mBoundApplication,
"info"
);
Application mApplication = (Application) getFieldOjbect(
"android.app.LoadedApk"
, loadedApkInfo,
"mApplication"
);
resultClassloader = mApplication.getClassLoader();
return
resultClassloader;
}
public
static
void
loadClassAndCall(ClassLoader appClassloader, String eachclassname, Method saveMethodCode) {
Class resultclass =
null
;
Log.i(
"wayne"
,
"go into loadClassAndCall->"
+
"classname:"
+ eachclassname);
try
{
resultclass = appClassloader.loadClass(eachclassname);
}
catch
(Exception e) {
e.printStackTrace();
return
;
}
catch
(Error e) {
e.printStackTrace();
return
;
}
if
(resultclass !=
null
) {
try
{
Constructor<?> cons[] = resultclass.getDeclaredConstructors();
for
(Constructor<?> constructor : cons) {
if
(saveMethodCode !=
null
) {
try
{
saveMethodCode.invoke(
null
, constructor);
}
catch
(Exception e) {
e.printStackTrace();
continue
;
}
catch
(Error e) {
e.printStackTrace();
continue
;
}
}
else
{
Log.e(
"wayne"
,
"saveMethodCode is null "
);
}
}
}
catch
(Exception e) {
e.printStackTrace();
}
catch
(Error e) {
e.printStackTrace();
}
try
{
Method[] methods = resultclass.getDeclaredMethods();
if
(methods !=
null
) {
for
(Method m : methods) {
if
(saveMethodCode !=
null
) {
try
{
saveMethodCode.invoke(
null
, m);
}
catch
(Exception e) {
e.printStackTrace();
continue
;
}
catch
(Error e) {
e.printStackTrace();
continue
;
}
}
else
{
Log.e(
"wayne"
,
"saveMethodCode is null "
);
}
}
}
}
catch
(Exception e) {
e.printStackTrace();
}
catch
(Error e) {
e.printStackTrace();
}
}
}
public
static
void
wayne() {
ClassLoader appClassloader = getClassloader();
ClassLoader tmpClassloader=appClassloader;
ClassLoader parentClassloader=appClassloader.getParent();
if
(appClassloader.toString().indexOf(
"java.lang.BootClassLoader"
)==-
1
)
{
wayneDoWithClassloader(appClassloader);
}
while
(parentClassloader!=
null
){
if
(parentClassloader.toString().indexOf(
"java.lang.BootClassLoader"
)==-
1
)
{
wayneDoWithClassloader(parentClassloader);
}
tmpClassloader=parentClassloader;
parentClassloader=parentClassloader.getParent();
}
}
public
static
void
wayneDoWithClassloader(ClassLoader appClassloader) {
List<Object> dexFilesArray =
new
ArrayList<Object>();
Field pathList_Field = (Field) getClassField(appClassloader,
"dalvik.system.BaseDexClassLoader"
,
"pathList"
);
Object pathList_object = getFieldOjbect(
"dalvik.system.BaseDexClassLoader"
, appClassloader,
"pathList"
);
Object[] ElementsArray = (Object[]) getFieldOjbect(
"dalvik.system.DexPathList"
, pathList_object,
"dexElements"
);
Field dexFile_fileField =
null
;
try
{
dexFile_fileField = (Field) getClassField(appClassloader,
"dalvik.system.DexPathList$Element"
,
"dexFile"
);
}
catch
(Exception e) {
e.printStackTrace();
}
catch
(Error e) {
e.printStackTrace();
}
Class DexFileClazz =
null
;
try
{
DexFileClazz = appClassloader.loadClass(
"dalvik.system.DexFile"
);
}
catch
(Exception e) {
e.printStackTrace();
}
catch
(Error e) {
e.printStackTrace();
}
Method _getClassNameList =
null
;
Method _saveMethodCode =
null
;
for
(Method field : DexFileClazz.getDeclaredMethods()) {
if
(field.getName().equals(
"getClassNameList"
)) {
_getClassNameList = field;
_getClassNameList.setAccessible(
true
);
}
if
(field.getName().equals(
"saveMethodCode"
)) {
_saveMethodCode = field;
_saveMethodCode.setAccessible(
true
);
}
}
Field mCookiefield = getClassField(appClassloader,
"dalvik.system.DexFile"
,
"mCookie"
);
Log.e(
"wayne->methods"
,
"dalvik.system.DexPathList.ElementsArray.length:"
+ ElementsArray.length);
for
(
int
j =
0
; j < ElementsArray.length; j++) {
Object element = ElementsArray[j];
Object dexfile =
null
;
try
{
dexfile = (Object) dexFile_fileField.get(element);
}
catch
(Exception e) {
e.printStackTrace();
}
catch
(Error e) {
e.printStackTrace();
}
if
(dexfile ==
null
) {
Log.e(
"ActivityThread"
,
"dexfile is null"
);
continue
;
}
if
(dexfile !=
null
) {
dexFilesArray.add(dexfile);
Object mcookie = getClassFieldObject(appClassloader,
"dalvik.system.DexFile"
, dexfile,
"mCookie"
);
if
(mcookie ==
null
) {
Object mInternalCookie = getClassFieldObject(appClassloader,
"dalvik.system.DexFile"
, dexfile,
"mInternalCookie"
);
if
(mInternalCookie!=
null
)
{
mcookie=mInternalCookie;
}
else
{
Log.e(
"wayne->err"
,
"get mInternalCookie is null"
);
continue
;
}
}
String[] classnames =
null
;
try
{
classnames = (String[]) _getClassNameList.invoke(dexfile, mcookie);
}
catch
(Exception e) {
e.printStackTrace();
continue
;
}
catch
(Error e) {
e.printStackTrace();
continue
;
}
if
(classnames !=
null
) {
for
(String eachclassname : classnames) {
loadClassAndCall(appClassloader, eachclassname, _saveMethodCode);
}
}
}
}
return
;
}
public
static
void
wayneThread() {
new
Thread(
new
Runnable() {
@Override
public
void
run() {
try
{
Log.e(
"wayne"
,
"start sleep......"
);
Thread.sleep(
1
*
60
*
1000
);
}
catch
(InterruptedException e) {
e.printStackTrace();
}
Log.e(
"wayne"
,
"sleep over and start myshell"
);
wayne();
Log.e(
"wayne"
,
"myshell run over"
);
}
}).start();
}
public
static
Field getClassField(ClassLoader classloader, String class_name,
String filedName) {
try
{
Class obj_class = classloader.loadClass(class_name);
Field field = obj_class.getDeclaredField(filedName);
field.setAccessible(
true
);
return
field;
}
catch
(SecurityException e) {
e.printStackTrace();
}
catch
(NoSuchFieldException e) {
e.printStackTrace();
}
catch
(IllegalArgumentException e) {
e.printStackTrace();
}
catch
(ClassNotFoundException e) {
e.printStackTrace();
}
return
null
;
}
public
static
Object getClassFieldObject(ClassLoader classloader, String class_name, Object obj,
String filedName) {
try
{
Class obj_class = classloader.loadClass(class_name);
Field field = obj_class.getDeclaredField(filedName);
field.setAccessible(
true
);
Object result =
null
;
result = field.get(obj);
return
result;
}
catch
(SecurityException e) {
e.printStackTrace();
}
catch
(NoSuchFieldException e) {
e.printStackTrace();
}
catch
(IllegalArgumentException e) {
e.printStackTrace();
}
catch
(ClassNotFoundException e) {
e.printStackTrace();
}
catch
(IllegalAccessException e) {
e.printStackTrace();
}
return
null
;
}
public
static
Object invokeStaticMethod(String class_name,
String method_name, Class[] pareTyple, Object[] pareVaules) {
try
{
Class obj_class = Class.forName(class_name);
Method method = obj_class.getMethod(method_name, pareTyple);
return
method.invoke(
null
, pareVaules);
}
catch
(SecurityException e) {
e.printStackTrace();
}
catch
(IllegalArgumentException e) {
e.printStackTrace();
}
catch
(IllegalAccessException e) {
e.printStackTrace();
}
catch
(NoSuchMethodException e) {
e.printStackTrace();
}
catch
(InvocationTargetException e) {
e.printStackTrace();
}
catch
(ClassNotFoundException e) {
e.printStackTrace();
}
return
null
;
}
public
static
Object getFieldOjbect(String class_name, Object obj,
String filedName) {
try
{
Class obj_class = Class.forName(class_name);
Field field = obj_class.getDeclaredField(filedName);
field.setAccessible(
true
);
return
field.get(obj);
}
catch
(SecurityException e) {
e.printStackTrace();
}
catch
(NoSuchFieldException e) {
e.printStackTrace();
}
catch
(IllegalArgumentException e) {
e.printStackTrace();
}
catch
(IllegalAccessException e) {
e.printStackTrace();
}
catch
(ClassNotFoundException e) {
e.printStackTrace();
}
catch
(NullPointerException e) {
e.printStackTrace();
}
return
null
;
}
public
static
ClassLoader getClassloader() {
ClassLoader resultClassloader =
null
;
Object currentActivityThread = invokeStaticMethod(
"android.app.ActivityThread"
,
"currentActivityThread"
,
new
Class[]{},
new
Object[]{});
Object mBoundApplication = getFieldOjbect(
"android.app.ActivityThread"
, currentActivityThread,
"mBoundApplication"
);
Application mInitialApplication = (Application) getFieldOjbect(
"android.app.ActivityThread"
,
currentActivityThread,
"mInitialApplication"
);
Object loadedApkInfo = getFieldOjbect(
"android.app.ActivityThread$AppBindData"
,
mBoundApplication,
"info"
);
Application mApplication = (Application) getFieldOjbect(
"android.app.LoadedApk"
, loadedApkInfo,
"mApplication"
);
resultClassloader = mApplication.getClassLoader();
return
resultClassloader;
}
public
static
void
loadClassAndCall(ClassLoader appClassloader, String eachclassname, Method saveMethodCode) {
Class resultclass =
null
;
Log.i(
"wayne"
,
"go into loadClassAndCall->"
+
"classname:"
+ eachclassname);
try
{
resultclass = appClassloader.loadClass(eachclassname);
}
catch
(Exception e) {
e.printStackTrace();
return
;
}
catch
(Error e) {
e.printStackTrace();
return
;
}
if
(resultclass !=
null
) {
try
{
Constructor<?> cons[] = resultclass.getDeclaredConstructors();
for
(Constructor<?> constructor : cons) {
if
(saveMethodCode !=
null
) {
try
{
saveMethodCode.invoke(
null
, constructor);
}
catch
(Exception e) {
e.printStackTrace();
continue
;
}
catch
(Error e) {
e.printStackTrace();
continue
;
}
}
else
{
Log.e(
"wayne"
,
"saveMethodCode is null "
);
}
}
}
catch
(Exception e) {
e.printStackTrace();
}
catch
(Error e) {
e.printStackTrace();
}
try
{
Method[] methods = resultclass.getDeclaredMethods();
if
(methods !=
null
) {
for
(Method m : methods) {
if
(saveMethodCode !=
null
) {
try
{
saveMethodCode.invoke(
null
, m);
}
catch
(Exception e) {
e.printStackTrace();
continue
;
}
catch
(Error e) {
e.printStackTrace();
continue
;
}
}
else
{
Log.e(
"wayne"
,
"saveMethodCode is null "
);
}
}
}
}
catch
(Exception e) {
e.printStackTrace();
}
catch
(Error e) {
e.printStackTrace();
}
}
}
public
static
void
wayne() {
ClassLoader appClassloader = getClassloader();
ClassLoader tmpClassloader=appClassloader;
ClassLoader parentClassloader=appClassloader.getParent();
if
(appClassloader.toString().indexOf(
"java.lang.BootClassLoader"
)==-
1
)
{
wayneDoWithClassloader(appClassloader);
}
while
(parentClassloader!=
null
){
if
(parentClassloader.toString().indexOf(
"java.lang.BootClassLoader"
)==-
1
)
{
wayneDoWithClassloader(parentClassloader);
}
tmpClassloader=parentClassloader;
parentClassloader=parentClassloader.getParent();
}
}
public
static
void
wayneDoWithClassloader(ClassLoader appClassloader) {
List<Object> dexFilesArray =
new
ArrayList<Object>();
Field pathList_Field = (Field) getClassField(appClassloader,
"dalvik.system.BaseDexClassLoader"
,
"pathList"
);
Object pathList_object = getFieldOjbect(
"dalvik.system.BaseDexClassLoader"
, appClassloader,
"pathList"
);
Object[] ElementsArray = (Object[]) getFieldOjbect(
"dalvik.system.DexPathList"
, pathList_object,
"dexElements"
);
Field dexFile_fileField =
null
;
try
{
dexFile_fileField = (Field) getClassField(appClassloader,
"dalvik.system.DexPathList$Element"
,
"dexFile"
);
}
catch
(Exception e) {
e.printStackTrace();
}
catch
(Error e) {
e.printStackTrace();
}
Class DexFileClazz =
null
;
try
{
DexFileClazz = appClassloader.loadClass(
"dalvik.system.DexFile"
);
}
catch
(Exception e) {
e.printStackTrace();
}
catch
(Error e) {
e.printStackTrace();
}
Method _getClassNameList =
null
;
Method _saveMethodCode =
null
;
for
(Method field : DexFileClazz.getDeclaredMethods()) {
if
(field.getName().equals(
"getClassNameList"
)) {
_getClassNameList = field;
_getClassNameList.setAccessible(
true
);
}
if
(field.getName().equals(
"saveMethodCode"
)) {
_saveMethodCode = field;
_saveMethodCode.setAccessible(
true
);
}
}
Field mCookiefield = getClassField(appClassloader,
"dalvik.system.DexFile"
,
"mCookie"
);
Log.e(
"wayne->methods"
,
"dalvik.system.DexPathList.ElementsArray.length:"
+ ElementsArray.length);
for
(
int
j =
0
; j < ElementsArray.length; j++) {
Object element = ElementsArray[j];
Object dexfile =
null
;
try
{
dexfile = (Object) dexFile_fileField.get(element);
}
catch
(Exception e) {
e.printStackTrace();
}
catch
(Error e) {
e.printStackTrace();
}
if
(dexfile ==
null
) {
Log.e(
"ActivityThread"
,
"dexfile is null"
);
continue
;
}
if
(dexfile !=
null
) {
dexFilesArray.add(dexfile);
Object mcookie = getClassFieldObject(appClassloader,
"dalvik.system.DexFile"
, dexfile,
"mCookie"
);
if
(mcookie ==
null
) {
Object mInternalCookie = getClassFieldObject(appClassloader,
"dalvik.system.DexFile"
, dexfile,
"mInternalCookie"
);
if
(mInternalCookie!=
null
)
{
mcookie=mInternalCookie;
}
else
{
Log.e(
"wayne->err"
,
"get mInternalCookie is null"
);
continue
;
}
}
String[] classnames =
null
;
try
{
classnames = (String[]) _getClassNameList.invoke(dexfile, mcookie);
}
catch
(Exception e) {
e.printStackTrace();
continue
;
}
catch
(Error e) {
e.printStackTrace();
continue
;
}
if
(classnames !=
null
) {
for
(String eachclassname : classnames) {
loadClassAndCall(appClassloader, eachclassname, _saveMethodCode);
}
}
}
}
return
;
}
public
static
void
wayneThread() {
new
Thread(
new
Runnable() {
@Override
public
void
run() {
try
{
Log.e(
"wayne"
,
"start sleep......"
);
Thread.sleep(
1
*
60
*
1000
);
}
catch
(InterruptedException e) {
e.printStackTrace();
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)