转载 : https://blog.csdn.net/ganyao939543405/article/details/76177392

在这之前,我们还是要先了解一下 VA Client Framework 和 VAService 之间的通讯方式

VAService 与通讯

VAService

首先 VAService 是指 VA 仿造 Android 原生 frameworkService 实现的一套副本,举例有 VActivityManagerService ,它和系统 AMS 一样,只不过他管理的是 VA 内部 Client App 的组件会话。

阅读全文 »

转载 : https://blog.csdn.net/ganyao939543405/article/details/76150725

VA 初始化

VirtualCore.startup

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
public void startup(Context context) throws Throwable {
if (!isStartUp) {
// 确保 MainThread
if (Looper.myLooper() != Looper.getMainLooper()) {
throw new IllegalStateException("VirtualCore.startup() must called in main thread.");
}
VASettings.STUB_CP_AUTHORITY = context.getPackageName() + "." + VASettings.STUB_DEF_AUTHORITY;
ServiceManagerNative.SERVICE_CP_AUTH = context.getPackageName() + "." + ServiceManagerNative.SERVICE_DEF_AUTH;
this.context = context;
// 获取 ActivityThread 实例
mainThread = ActivityThread.currentActivityThread.call();
unHookPackageManager = context.getPackageManager();
hostPkgInfo = unHookPackageManager.getPackageInfo(context.getPackageName(), PackageManager.GET_PROVIDERS);
detectProcessType();
// hook 系统类
InvocationStubManager invocationStubManager = InvocationStubManager.getInstance();
invocationStubManager.init();
invocationStubManager.injectAll();
// 修复权限管理
ContextFixer.fixContext(context);
isStartUp = true;
if (initLock != null) {
initLock.open();
initLock = null;
}
}
}

整个 VA 会运行在四种进程, 分别是前面提到的 VAService 进程、Client App 进程、 VA 自身的 App 主进程、子进程。

阅读全文 »

转载:https://github.com/mzlogin/awesome-adb

基本用法

命令语法

adb 命令的基本语法如下:

阅读全文 »

转载 : https://blog.csdn.net/ganyao939543405/article/details/76146760

最近发现了一个非常好的开源项目,基本实现了一个 Android 上的沙箱环境,不过应用场景最多的还是应用双开。

本文主要是分析一下项目的整体结构。

包结构

阅读全文 »

最近有点时间就尝试着移植 FART 到 Android 9.0 ,本文记录一下的整个过程。

获取 cloassloader 执行主动调用

首先修改 frameworks/base/core/java/android/app/ActivityThread.java 文件,添加以下内容。其中主要思想就是获取 apk 的 classloader 然后通过反射获取 dumpMethodCode 方法,执行主动调用,下面添加 dumpMethodCode 方法。

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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
// add start
import android.os.Build;
import android.util.ArrayMap;
import android.util.Log;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.lang.reflect.Constructor;
import dalvik.system.BaseDexClassLoader;
import dalvik.system.DexClassLoader;
// add end


// add start
public static String CKCatTAG = "CKCatUnPack";
public static Field getClassField(ClassLoader classloader, String className,
String fieldName){
try{
Class clazz = classloader.loadClass(className);
Field field = clazz.getDeclaredField(fieldName);
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 className,
Object obj, String fieldName){
try {
Class clazz = classloader.loadClass(className);
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
Object result = null;
result = field.get(obj);
return result;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}

public static Object invokeStaticMethod(String className, String methodName,
Class[] pareType, Object[] pareValues){
try {
Class clazz = Class.forName(className);
Method method = clazz.getMethod(methodName, pareType);
return method.invoke(null, pareValues);
} catch(Exception e){
e.printStackTrace();
}
return null;
}

public static Object getFieldObject(String className, Object obj,
String fieldName){
try {
Class clazz = Class.forName(className);
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(obj);
} catch (Exception e) {
e.printStackTrace();
}
return null;

}

public static ClassLoader getClassLoader(){
ClassLoader classloader = null;
Object currentActivityThread = invokeStaticMethod("android.app.ActivityThread",
"currentActivityThread", new Class[]{}, new Object[]{});
Object mBoundApplication = getFieldObject("android.app.ActivityThread",
currentActivityThread, "mBoundApplication");
Object loadedApkInfo = getFieldObject("android.app.ActivityThread$AppBindData",
mBoundApplication, "info");
Application mApplication = (Application)getFieldObject("android.app.loadedApk",
loadedApkInfo, "mApplication");
classloader = mApplication.getClassLoader();
return classloader;
}

public static void loadClassAndInvoke(ClassLoader appClassloader, String eachClassName,
Method dumpMethodCode_method){
Log.i(CKCatTAG, "go into loadClassAndInvoke->" + "classname:" + eachClassName);

Class retClass = null;
try {
retClass = appClassloader.loadClass(eachClassName);
} catch (Exception e) {
e.printStackTrace();
return;
} catch (Error e) {
e.printStackTrace();
return;
}

if (retClass != null) {
try {
Constructor<?> cons[] = retClass.getDeclaredConstructors();
for (Constructor<?> constructor : cons){
if (dumpMethodCode_method != null) {
try {
dumpMethodCode_method.invoke(null, constructor);
} catch (Exception e) {
e.printStackTrace();
continue;
} catch (Error e) {
e.printStackTrace();
continue;
}
} else {
Log.e(CKCatTAG, "dumpMethodCode_method is null ");
}
}
} catch (Exception e) {
e.printStackTrace();
} catch (Error e) {
e.printStackTrace();
}

try {
Method[] methods = retClass.getDeclaredMethods();
if (methods != null) {
for (Method m : methods) {
if (dumpMethodCode_method != null) {
try {
dumpMethodCode_method.invoke(null, m);
} catch (Exception e) {
e.printStackTrace();
continue;
} catch (Error e) {
e.printStackTrace();
continue;
}
} else {
Log.e(CKCatTAG, "dumpMethodCode_method is null ");
}
}
}
} catch (Exception e) {
e.printStackTrace();
} catch (Error e) {
e.printStackTrace();
}
}
}

public static void fart(){
//获取当前 classloader
ClassLoader appClassloader = getClassLoader();
List<Object> dexFieldsArray = new ArrayList<Object>();

// 获取 pathList 字段
Field pathList_Field = (Field)getClassField(appClassloader,
"dalvik.system.BaseDexClassLoader", "pathList");
Object pathList_object = getFieldObject("dalvik.system.BaseDexClassLoader",
appClassloader, "pathList");

// 获取 dexElements
Object[] dexElements = (Object[]) getFieldObject("dalvik.system.DexPathList",
pathList_object, "dexElements");

Field dexFile_Field = null;
try {
dexFile_Field = (Field)getClassField(appClassloader,
"dalvik.system.DexPathList$Element", "dexFile");
} catch (Exception e) {
e.printStackTrace();
}

Class dexFileClazz = null;
try {
dexFileClazz = appClassloader.loadClass("dalvik.system.DexFile");
} catch (Exception e) {
e.printStackTrace();
}

Method getClassNameList_Method = null;
Method defineClass_Method = null;
Method dumpMethodCode_Method = null;
// 通过反射获取获取 dumpMethodCode
for (Method method : dexFileClazz.getDeclaredMethods()){
if (method.getName().equals("getClassNameList")) {
getClassNameList_Method = method;
getClassNameList_Method.setAccessible(true);
}
if (method.getName().equals("defineClassNative")) {
defineClass_Method = method;
defineClass_Method.setAccessible(true);
}
if (method.getName().equals("dumpMethodCode")) {
dumpMethodCode_Method = method;
dumpMethodCode_Method.setAccessible(true);
}
}

// 获取 mCookie
Field mCookieField = getClassField(appClassloader, "dalvik.system.DexFile", "mCookie");
for (int i = 0; i < dexElements.length; i++) {
Object element = dexElements[i];
Object dexfile = null;
try {
dexfile = (Object)dexFile_Field.get(element);
} catch (Exception e) {
e.printStackTrace();
}

if (dexfile == null) {
continue;
}

if(dexfile != null){
dexFieldsArray.add(dexfile);
Object mCookie = getClassFieldObject(appClassloader,
"dalvik.system.DexFile", dexfile, "mCookie");
if (mCookie == null) {
continue;
}

String[] classNames = null;
try {
classNames = (String[])getClassNameList_Method.invoke(dexfile, mCookie);
} catch (Exception e) {
e.printStackTrace();
continue;
} catch (Error e) {
e.printStackTrace();
continue;
}

if (classNames != null) {
for(String eachClassName: classNames){
// 执行主动调用
loadClassAndInvoke(appClassloader, eachClassName, dumpMethodCode_Method);
}
}
}
}

}

public static void fartthread(){
new Thread(new Runnable(){

@Override
public void run(){
try{
Log.e(CKCatTAG, "start sleep,wait for fartthread start......");
Thread.sleep(1*60*1000);
}catch(InterruptedException e){
e.printStackTrace();
}
Log.e(CKCatTAG, "sleep over and start fartthread");
fart();
Log.e(CKCatTAG, "fart run over");
}
});
}
// add end

/** Core implementation of activity launch. */
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {

...
// add start
fartthread();
// add end
return activity;
}

添加 dumpMethodCode 方法

阅读全文 »

最近准备学习一下 FART 的源码及其相关文章的过程中发现绕不开 Android 应用的启动过程,所以准备阅读一下 android 的源码,了解一下相关知识。

本文研究的源码为 Android 9 。

ActivityThread.main

ActivityThread.main 方法中对 ActivityThread 进行了初始化,创建了主线程的 Looper 对象并调用 Looper.loop() 方法启动 Looper,把自定义 Handler 类 H 的对象作为主线程的 handler 。接下来跳转到 ActivityThread.attach 方法。

阅读全文 »

什么是 CMake

CMake 是一个开源、跨平台的工具系列,可用于构建、测试和打包软件。它通过一个名为 CMakeLists.txt 的配置文件来管理软件的编译流程,并根据用户所选择的目标平台生成构建软件所需的本地化 makefile 或 workspace。通俗来讲,使用 CMake 可以生成 UNIX-like 上构建软件所需的 Makefile 和 Windows 上构建软件所需的 vcxproj,而无需为它们单独写一份 Makefile/vcxproj

CMake 官方文档中有详细的使用手册,可以帮助用户更深入地了解 CMake。另外,还有一个详细的使用教程:CMake Tutorial

入门案例

单个源文件

阅读全文 »

最近看到很多大佬对于wsl2的推崇,于是就想体验一番,将系统升级到2004,下面记录以下折腾过程。

1. 系统升级

1.1. 问题:我们无法更新系统保留的分区

首先进行系统升级就出现了问题“我们无法更新系统保留的分区”,对于这个问题,网上很多人给的答案是 MSR(Microsoft Reserved)分区太小的问题,然而实际问题是ESP(EFI System Partition)分区 “EFI系统分区” 太小的原因,微软在这里所提示的系统保留的分区实际上是指“EFI系统分区”。

阅读全文 »

ART的函数运行机制

类的加载

dalvik 的类加载的主要过程如下:

  1. app_process 作为 zygote server 通过 local socket 处理进程创建请求,zygote server 是在 ZygoteInit.main 函数里调用 ZygoteInit.runSelectLoop 监听。

  2. 接收到 zygote clientfork 请求之后,调用 ZygoteConnection.runOnce ,调用 Zygote.forkAndSpecialize 创建新进程

  3. 进程创建之后,由 ZygoteConnection.handleParentProc 来初始化进程,最终会调用 ActivityThread.main 函数

  4. ActivityThread.main -> ActivityThread.attach ->  ActivityThread.bindApplication -> Activity.handleBindApplication,handleBindApplication 会初始化 BaseDexClassLoader

  5. 类的加载经过了 ClassLoader.loadClass->BaseDexClassLoader.findClass->DexPathList.findClass->DexFile.loadClassBinaryName->DexFile.defineClassNative->DexFile_defineClassNative (runtime/native/dalvik_system_DexFile.cc) 。

这个初始化过程, artdalvik 都是一样的。 artDexFile_defineClassNativeClassLinkerDefineClass 来加载类。

阅读全文 »
0%