文章目錄
1.新進程啓動流程
以com.hgy.ndk
新安裝在VA上的app啓動爲例:
LaunchpadAdapter.onBindViewHolder
設置了點擊VA已安裝app監聽事件,如下代碼:
public void onBindViewHolder(ViewHolder holder, int position) {
...
holder.itemView.setOnClickListener(v -> {
if (mAppClickListener != null) {
mAppClickListener.onAppClick(position, data);
}
});
...
}
—>在HomeActivity
中設置了mAppClickListener
,如下代碼:
mLaunchpadAdapter.setAppClickListener((pos, data) -> {
if (!data.isLoading()) {
...
mPresenter.launchApp(data);
}
});
—>調用到HomePresenterImpl.launchApp
函數,傳入參數爲AppData
(實際爲PackageAppData
), AppData
可能包含以下參數:
icon
name = "ndk"
packageName = "com.hgy.ndk"
isFirstOpen = true
isLoading = false
userid默認爲0
—>這內部可能涉及到權限申請等延遲操作,但最後都會調用到VActivityManager.launchApp
函數,它主要是構造一個intent
, intent
的主要內容差不多如下:
Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
intentToResolve.setPackage("com.hgy.ndk");
intentToResolve.addCategory(Intent.CATEGORY_LAUNCHER);
final Intent intent = new Intent(intentToResolve);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setClassName("com.hgy.ndk", "com.hgy.ndk.MainActivity"); // intent.setClassName(info.packageName, info.name);
很明顯,是增加以下兩個屬性:
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
—>然後跨進程從VPMS
中取得ActivityInfo
數據,並和intent
一起傳到VAMS
的startActivity
中,代碼如下:
public int startActivity(Intent intent, int userId) {
// ...
ActivityInfo info = VirtualCore.get().resolveActivityInfo(intent, userId);
return startActivity(intent, info, null, null, null, 0, userId);
}
---> VAMS的startActivity:
public int startActivity(Intent intent, ActivityInfo info, ...) {
return mActivityStack.startActivityLocked(userId, intent, info, resultTo, options, resultWho, requestCode, VBinder.getCallingUid());
}
上面的參數除了ActivityInfo
數據和intent
,其餘全爲null或0。
—>傳入ActivityStack.startActivityLocked
中還有個參數是callingUid
,默認是9999, 代碼如下:
// eg: 第一次點擊 callingUid = Constants.OUTSIDE_APP_UID 9999
int startActivityLocked(int userId, Intent intent, ActivityInfo info, IBinder resultTo, Bundle options,
String resultWho, int requestCode, int callingUid) { // 173
synchronized (mHistory) {
// 把不存活的task從mHistory中幹掉
optimizeTasksLocked();
}
...
if (reuseTask == null || reuseTask.isFinishing()) { // eg: 新的app啓動task會走這個條件
return startActivityInNewTaskLocked(mLauncherFlags, userId, intent, info, options, callingUid);
}
...
其中ActivityStack.mHistory
保存了正在運行的TaskRecord
記錄, 對應系統ActivityStack
中 ArrayList<TaskRecord> mTaskHistory = new ArrayList<>();
。
—> 上面函數有一堆邏輯判斷,但都是查找最近有沒有打開過這個app。
新的app啓動可以忽略這個函數,直接進入ActivityStack.startActivityInNewTaskLocked
,其中mLauncherFlags = 0
, 代碼如下:
private int startActivityInNewTaskLocked(...) {
ActivityRecord targetRecord = newActivityRecord(intent, info, null); // 1
final Intent destIntent = startActivityProcess(userId, targetRecord, intent, info, callingUid); // 2
...
}
- 創建一個
ActivityRecord targetRecord
,targetRecord
內部存儲了前面提到的ActivityInfo
數據和intent
,並設置了targetRecord.component=ComponentInfo{com.hgy.ndk/com.hgy.ndk.MainActivity}
。 - 調用
ActivityStack.startActivityProcess
, 它主要調用兩個函數, 代碼如下:
private Intent startActivityProcess(int userId, ActivityRecord targetRecord, Intent intent, ActivityInfo info, int callingUid) {
// 3
ProcessRecord targetApp = mService.startProcessIfNeedLocked(info.processName, userId, info.packageName, -1, callingUid);
// 4
return getStartStubActivityIntentInner(intent, targetApp.is64bit, targetApp.vpid, userId, targetRecord, info);
}
- 調用
VAMS.startProcessIfNeedLocked
VAMS.startProcessIfNeedLocked
根據包名首先取得 PackageSetting ps
和 ApplicationInfo info
數據, 這些數據在安裝時就會被保存。
然後創建一個新的ProcessRecord app
,ProcessRecord
記錄了 ApplicationInfo info
和vuid
等信息。並通過mProcessNames
和mPidsSelfLocked
記錄app
, 最後調用initProcess
創建新進程, 關鍵代碼如下:
app = new ProcessRecord(info, processName, vuid, vpid, callingUid, is64bit);
mProcessNames.put(app.processName, app.vuid, app);
mPidsSelfLocked.add(app);
if (initProcess(app)) {
return app;
—>由VAMS
的initProcess
發起的啓動新進程:p0
(第一個啓動是:p0
,依次+1), 代碼如下:
private boolean initProcess(ProcessRecord app) {
...
Bundle extras = new Bundle();
extras.putParcelable("_VA_|_client_config_", app.getClientConfig());
Bundle res = ProviderCall.callSafely(app.getProviderAuthority(), "_VA_|_init_process_", null, extras);
app.getProviderAuthority()
對應AndroidManifest.xml
中:p0-:p99
的100個provider
。
它會先進入VirtualCore.startup
流程,做一些hook系統函數設置,這個在後續分析。
之後進入ShadowContentProvider
的call
初始化, 取得由ProcessRecord
轉換的clientConfig
,並設置到VClient
中, 同時把VClient
對象和pid
綁定到Bundle返回到VAMS
中, 代碼如下:
public Bundle call(String method, String arg, Bundle extras) {
if ("_VA_|_init_process_".equals(method)) {
return initProcess(extras);
}
}
--->
private Bundle initProcess(Bundle extras) {
VirtualCore.get().waitStartup(); // 等街startup完成
extras.setClassLoader(ClientConfig.class.getClassLoader());
ClientConfig clientConfig = extras.getParcelable("_VA_|_client_config_");// 取得由ProcessRecord轉換的clientConfig
VClient client = VClient.get();
client.initProcess(clientConfig); // 將clientConfig設置到VClient中
Bundle res = new Bundle();
BundleCompat.putBinder(res, "_VA_|_client_", client.asBinder()); // 將"_VA_|_client_"和client綁定
res.putInt("_VA_|_pid_", Process.myPid()); // 將"_VA_|_pid_"和pid綁定
return res;
}
---->返回到VAMS
中的initProcess
函數, 此函數後續把:po
傳過來的pid
, IVClient
,IApplicationThread
都賦值給ProcessRecord
, 代碼如下:
app.pid = res.getInt("_VA_|_pid_"); // 得到pid
IBinder clientBinder = BundleCompat.getBinder(res, "_VA_|_client_");// 得到IClient.IBinder對象
return attachClient(app, clientBinder);
--->attachClient實現如下:
private boolean attachClient(final ProcessRecord app, final IBinder clientBInder) { // 734
IVClient client = IVClient.Stub.asInterface(clientBInder);
...
app.client = client;
// 對應IApplicationThread
app.appThread = ApplicationThreadCompat.asInterface(client.getAppThread());
...
return true;
}
其中client.getAppThread()
是跨進程在po
中調用。
- 調用
ActivityThread.getStartStubActivityIntentInner
---->返回後調用getStartStubActivityIntentInner
, 設置targetIntent
, targetIntent
設置的代碼如下:
Intent targetIntent = new Intent();
targetIntent.setClassName("io.busniess.va", "com.lody.virtual.client.stub.ShadowActivity$P0")
targetIntent.setType("com.hgy.ndk/com.hgy.ndk.MainActivity")
StubActivityRecord saveInstance = new StubActivityRecord(intent, info, userId, targetRecord);
saveInstance.saveToIntent(targetIntent); // 把saveInstance中數據保存到targetIntent
可以看出targetIntent
記錄了 前面提到的intent
, ActivityInfo info
, userId
,targetRecord
所有數據。
繼續回到上層函數startActivityInNewTaskLocked
, 它會繼續對返回的targetIntent
增加flags
,主要內容差不多如下:
private int startActivityInNewTaskLocked(...) {
ActivityRecord targetRecord = newActivityRecord(intent, info, null);
// destIntent即前面提到的targetIntent
final Intent destIntent = startActivityProcess(userId, targetRecord, intent, info, callingUid);
destIntent.addFlags(0);// launcherFlags = 0
destIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
destIntent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
destIntent.addFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
destIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
destIntent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
VirtualCore.get().getContext().startActivity(destIntent);
}
最後進入系統的startActivity
,因爲targetIntent.setClassName("io.busniess.va", "com.lody.virtual.client.stub.ShadowActivity$P0")
,所以它會在po
進程中啓動startActivity
。
但是這裏有個問題,因爲設置的是 "com.lody.virtual.client.stub.ShadowActivity$P0"
,那理論上啓動的是ShadowActivity
,而不是我們原始的com.hgy.ndk.MainActivity
了,這裏可以提前解釋下,在後面的HCallbackStub
的LAUNCH_ACTIVITY
中有如下代碼:
ActivityThread.ActivityClientRecord.intent.set(r, intent);
ActivityThread.ActivityClientRecord.activityInfo.set(r, info);
其中intent
是原始的,這裏可以貼下改變前面的值:
調用 ActivityThread.ActivityClientRecord.intent.set(r, intent)
改變後:
也就是在啓動activity
前,又換回原始的intent
和info
數據,從而正常啓動。
在lulubox4.3的插件化中有類似的實現: 位於plugin-base-cmplugin-host-library中AndroidHack.java。
這時VA中設置的hook函數開始準備攔截了。
2.hook 函數處理
hook函數框架可以參考InvocationStubManager相關
2.0 預先處理的hook函數
在startActivity
後到HCallbackStub
的LAUNCH_ACTIVITY
之前要處理幾個函數的hook:
2.0.1 addPackageDependency
在 mInitialApplication = LoadedApk.makeApplication
中會調用getClassLoader
,getClassLoader
內部會調用addPackageDependency
,如下圖:
將參數args
從"com.hgy.ndk
"換成“io.busniess.va
”再傳入調用:
public Object call(Object who, Method method, Object... args) throws Throwable {
MethodParameterUtils.replaceFirstAppPkg(args); // args由原始的包名轉換成io.busniess.va
return method.invoke(who, args);
}
2.0.2 startService
如果是va自身的service
就直接使用系統的,否則和VAMS
中startActivity
類似,使用VAMS
中的startService
,先自己起一個子進程p0(如果p0被佔用就依此類推),再 intent.setClassName(com.lody.virtual.client.stub.ShadowService$P0, serviceName);
綁定到子進程。
2.0.3 getContentProvider
根據名字判斷如果是va自身的contentprovider
就直接使用系統的,否則和前面的一樣,使用VAMS
中的initProcess
,先自己起一個子進程p0(如果p0被佔用就依此類推), 然後把getContentProvider
的第二個參數name
設置爲io.busniess.vatools.virtual_stub_${vpid}
。
2.0.4 getRunningAppProcesses
首先取得運行進程list, 遍歷, 如果是va的app進程,則更新RunningAppProcessInfo
中的數據爲va變化的數據:
if (processName != null) {
info.importanceReasonCode = 0;
info.importanceReasonPid = 0;
info.importanceReasonComponent = null;
info.processName = processName;
}
info.pkgList = pkgList.toArray(new String[0]);
info.uid = vuid;
2.1 client進程的HCallbackStub
ActivityThread
有個很重要的變量,final H mH = new H();
, 它的實現如下:
private class H extends Handler {
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
case LAUNCH_ACTIVITY: {
...
}
}
簡單的說就是處理各種消息, HCallbackStub
就是設置了ActivityThread.H
的callback
函數,實現handleMessage
攔截。
2.1.1 LAUNCH_ACTIVITY消息
首先到達的LAUNCH_ACTIVITY
消息,其中 Msg.object
就是ActivityClientRecord r
對象
Intent stubIntent;
if (BuildCompat.isPie()) {
stubIntent = LaunchActivityItem.mIntent.get(r);
} else {
stubIntent = ActivityThread.ActivityClientRecord.intent.get(r);
}
這裏得到的stubIntent
就是我們前面VAMS
中startActivity
傳出的destIntent
, 如下所示:
所以就可以在這裏把VAMS
中綁定的StubActivityRecord
,intent(原始的)
, ActivityInfo info
都取出來,前面流程提到過如何綁定, 代碼如下:
StubActivityRecord saveInstance = new StubActivityRecord(stubIntent);
// intent是原始的,沒有調用setClassName改變的
Intent intent = saveInstance.intent;
IBinder token;
if (BuildCompat.isPie()) { //android 9.0
token = ClientTransaction.mActivityToken.get(msg.obj);
} else {
token = ActivityThread.ActivityClientRecord.token.get(r);
}
ActivityInfo info = saveInstance.info;
這時還會判斷:p0
進程是否已初始化,如果沒有就嘗試重啓p0進程,代碼如下:
if (VClient.get().getClientConfig() == null) { // 理論上不會成立,除非px進程掛了,因爲clientConfig會在call時賦值給VClient
InstalledAppInfo installedAppInfo = VirtualCore.get().getInstalledAppInfo(info.packageName, 0);
// 讓VAMS再次initProcess,重啓:px進程
VActivityManager.get().processRestarted(info.packageName, info.processName, saveInstance.userId);
getH().sendMessageAtFrontOfQueue(Message.obtain(msg));// 重發消息
return false;
}
繼續就會進行到比較重要的一步,調用 VClient.get().bindApplication
,然後重新觸發LAUNCH_ACTIVITY
消息。之後調用
2.1.1.1 bindApplication初始化
VClient.get().bindApplication
總是在主UI線程中調用bindApplicationNoCheck
,bindApplicationNoCheck
主要完成了以下任務:
setupUncaughtHandler
設置異常捕獲,由外部VCore
設置CrashHandler
,內部默認沒有設置。fixInstalledProviders
會檢查我們的provider
,如果authority
不是io.busniess.va.virtual_stub_
開頭,則利用ProviderHook
生成provider代理
取代原始的provider
。理論上都是以io.busniess.va.virtual_stub_
開頭。VDeviceManager.get().applyBuildProp
設置虛擬的設備信息。- 把
VirtualCore.mainThread
的mInitialApplication
變量設置爲null。 - 設置
InstalledAppInfo
,ApplicationInfo
,List<ProviderInfo>
等基礎數據到VClient
中。 - 通過
VirtualRuntime.setupRuntime
改變進程的argv[0]
參數爲進程名(com.hgy.ndk
), 設置app名字爲進程名(com.hgy.ndk
)。
原始的app名字爲io.busniess.va:p0
。 - 設置
AlarmManager.mTargetSdkVersion
爲被安裝apk的targetSdkVersion
,原始值爲va的targetSdkVersion
。 - 設置系統緩存的臨時目錄爲
/data/data/io.busniess.vatools/virtual/data/user/userId/packageName/cache
, userId爲0,1,…。 - 調用
startIORelocater
,startIORelocater
的作用就是可以在java層設置路徑白名單,黑名單,要替換的名單,然後把這些路徑列表傳到NDK層,並hook
所有的帶路徑的libc
函數以及linker
下的dlopen
函數,並在hook
函數中對路徑做相應放過,禁止,替換。 - 調用
launchEngine
替換java native函數對應的NDK jni函數。 - 設置
codeCacheDir
爲/data/data/io.busniess.va/virtual/data/user/0/com.hgy.ndk/code_cache
。 - 把
AppBindData mBoundApplication
傳入ActivityThread.mBoundApplication
對象,即 設置appInfo
,processName
,instrumentationName
,info
等到對象, 其中info
由臨時創建的context
獲取。 - 設置
LoadedApk.mSecurityViolation
爲false
。 - 調用
VMRuntime.setTargetSdkVersion
設置targetSdkVersion
。 - 調用
AppCallback.beforeStartApplication
對外接口,可以看出傳出的context
爲前面臨時創建的。 - 利用
LoadedApk.makeApplication
創建mInitialApplication
,並設置到ActivityThread.mInitialApplication
中。 - 利用
ContextFixer
把ContextImpl.mBasePackageName
,ContextImplKitkat.mOpPackageName
,ContentResolverJBMR2.mPackageName
的包名(原始爲com.hgy.ndk
)改爲io.busniess.va
。 - 調用
AppCallback.beforeApplicationCreate
對外接口。 - 調用
mInstrumentation.callApplicationOnCreate
會首先把ActivityThread.mInstrumentation
替換成VClient的mInstrumentation
。 - 調用
AppCallback.afterApplicationCreate
對外接口。
2.1.1.2 startIORelocater重定位
仍以com.hgy.ndk
爲例,邏輯:
在deviceConfig.enable時觸發
NativeEngine.redirectFile("/sys/class/net/wlan0/address",“/data/data/io.busniess.va/virtual/data/user/0/system/wifiMacAddress”);
NativeEngine.redirectFile("/sys/class/net/eth0/address",“/data/data/io.busniess.va/virtual/data/user/0/system/wifiMacAddress”);
NativeEngine.redirectFile("/sys/class/net/wifi/address",“/data/data/io.busniess.va/virtual/data/user/0/system/wifiMacAddress”);
NativeEngine.redirectFile("/proc/stat", "/data/data/io.busniess.vatools/virtual/proc/stat");
NativeEngine.forbid("/proc/" + info.pid + "/maps", true);
NativeEngine.forbid("/proc/" + info.pid + "/cmdline", true);
NativeEngine.redirectDirectory("/tmp/", "/data/data/io.busniess.va/virtual/data/user/0/com.hgy.ndk/cache/");
NativeEngine.redirectDirectory("/data/data/com.hgy.ndk","/data/data/io.busniess.va/virtual/data/user/0/com.hgy.ndk/");
NativeEngine.redirectDirectory("/data/user/0/com.hgy.ndk","/data/data/io.busniess.va/virtual/data/user/0/com.hgy.ndk/");
// user_de在android7.0以後
NativeEngine.redirectDirectory("/data/user_de/0/com.hgy.ndk","/data/data/io.busniess.va/virtual/data/user_de/0/com.hgy.ndk/");
if (appLibConfig == SettingConfig.AppLibConfig.UseOwnLib) {// 默認不成立
NativeEngine.redirectDirectory("/data/data/com.hgy.ndk/lib/","/data/data/io.busniess.va/virtual/data/app/com.hgy.ndk/lib/");
NativeEngine.redirectDirectory("/data/user/0/com.hgy.ndk/lib/","/data/data/io.busniess.va/virtual/data/app/com.hgy.ndk/lib/");
}
NativeEngine.redirectDirectory("/data/data/io.busniess.va/virtual/data/user/0/com.hgy.ndk/lib","/data/data/io.busniess.va/virtual/data/app/com.hgy.ndk/lib/");
NativeEngine.whitelist("/data/data/io.busniess.va/virtual/data/app/com.hgy.ndk/lib");
NativeEngine.whitelist("/data/user/0/com.hgy.ndk/lib/");
最後調用NativeEngine.enableIORedirect()
。
關鍵函數是NativeEngine.redirectFile
及NativeEngine.redirectDirectory
及NativeEngine.forbid
及NativeEngine.whitelist
及NativeEngine.enableIORedirect
。
四者 用於區分傳入的是文件和文件夾在於路徑最後有沒有/
。
NativeEngine.forbid
最終調到NDK的jni_nativeIOForbid
, jni_nativeIOForbid
會把傳入的路徑統一加入到forbidden_items
數組中,forbidden_items
數組由PathItem
構成, 代碼如下:
typedef struct PathItem {
char *path;
bool is_folder;
size_t size;
} PathItem;
--->
PathItem &item = forbidden_items[forbidden_item_count];
item.path = strdup(path);
item.size = strlen(path);
item.is_folder = (path[strlen(path) - 1] == '/'); // 根據最後有沒有斜槓判斷是否爲文件夾
NativeEngine.whitelist
最終調到NDK的jni_nativeIOWhitelist
, jni_nativeIOWhitelist
把傳入的路徑統一加入到keep_items
數組中,forbidden_items
數組同樣由PathItem
構成,和上面的加入類似。
NativeEngine.redirectFile
及NativeEngine.redirectDirectory
都是把原始文件(夾)和要重定位的文件(夾)路徑放在REDIRECT_LISTS
列表中。
最後由NativeEngine.enableIORedirect
來觸發:
NativeEngine.enableIORedirect
首先會把REDIRECT_LISTS
排序(第一個字符串從長到短), 然後遍歷REDIRECT_LISTS
,並調用NativeEngine.nativeIORedirect
,再調到NDK的jni_nativeIORedirect
把傳入的原始路徑和要替換的路徑統一加入到replace_items
數組中, 代碼如下:
typedef struct ReplaceItem {
char *orig_path;
size_t orig_size;
char *new_path;
size_t new_size;
bool is_folder;
} ReplaceItem;
--->
ReplaceItem &item = replace_items[replace_item_count];
item.orig_path = strdup(orig_path);
item.orig_size = strlen(orig_path);
item.new_path = strdup(new_path);
item.new_size = strlen(new_path);
item.is_folder = (orig_path[strlen(orig_path) - 1] == '/');
最後調用NDK的jni_nativeEnableIORedirect
, 傳入參數基本如下:
soPath = /data/app/io.busniess.va-2/lib/x86/libv++.so
soPath64 = /data/app/io.busniess.va-2/lib/x86/libv++_64.so
nativePath = /data/data/io.busniess.va/virtual/.native 或 /data/data/io.busniess64.va/virtual/.native
jni_nativeEnableIORedirect
在內部調用IOUniformer::startUniformer
,先把前面傳入參數使用setenv
保存,再調用startIOHook
來hook
所有的包含路徑的c庫函數,這些函數在調用的時候,可能會替換路徑爲新路徑。由於hook
的是libc
的函數,java層和虛擬機的文件訪問最終也會調用到這裏,從而受到影響, 代碼如下:
void startIOHook(int api_level) {
void *handle = dlopen("libc.so", RTLD_NOW);
if (handle) {
...
HOOK_SYMBOL(handle, faccessat);
HOOK_SYMBOL(handle, __openat);
HOOK_SYMBOL(handle, fchmodat);
...
#ifdef __arm__
if (!relocate_linker()) {
findSyscalls("/system/bin/linker", on_found_linker_syscall_arm);
}
#endif
#endif
dlclose(handle);
}
}
HOOK_SYMBOL
內部調用了MSHookFunction
,也就是著名的Cydia
的hook庫, 代碼如下:
#define HOOK_SYMBOL(handle, func) hook_function(handle, #func, (void*) new_##func, (void**) &orig_##func)
--->
void hook_function(void *handle, const char *symbol, void *new_func, void **old_func) {
void *addr = dlsym(handle, symbol);
MSHookFunction(addr, new_func, old_func);
}
以faccessat
爲例,代碼如下:
HOOK_DEF(int, faccessat, int dirfd, const char *pathname, int mode, int flags) {
char temp[PATH_MAX];
const char *relocated_path = relocate_path(pathname, temp, sizeof(temp));
if (relocated_path && !(mode & W_OK && isReadOnly(relocated_path))) {
return syscall(__NR_faccessat, dirfd, relocated_path, mode, flags);
}
errno = EACCES;
return -1;
}
內部relocate_path
是關鍵的替換路徑函數,代碼如下:
const char *relocate_path(const char *path, char *const buffer, const size_t size) {
const char *result = relocate_path_internal(path, buffer, size);
return result;
}
--->relocate_path_internal代碼:
relocate_path_internal
邏輯如下:
- 使用
canonicalize_path
把路徑轉成規範的路徑,比如傳入的路徑可能有//
這種重複斜槓或./
。 - 從
keep_items
(白名單,對應上層的NativeEngine.whitelist
)中遍歷,看是否符合,如符合,直接返回原始路徑。 - 從
forbidden_items
(黑名單,對應上層的NativeEngine.forbid
)中遍歷,看是否符合,如符合,直接返回NULL
。 - 從
replace_items
(替換名單, 對應上層的NativeEngine.redirectFile
和NativeEngine.redirectDirectory
)中遍歷,看是否符合,如符合,這裏會分幾種情況,不過最後總是返回被替換的路徑。一般會把被替換的路徑保存到前面傳入的temp
中。
比較函數代碼如下:
bool match_path(bool is_folder, size_t size, const char *item_path, const char *path, size_t path_len) {
if (is_folder) {
if (path_len < size) {
// ignore the last '/'
return strncmp(item_path, path, size - 1) == 0;
} else {
return strncmp(item_path, path, size) == 0;
}
} else {
return strcmp(item_path, path) == 0;
}
}
relocate_linker
的作用是:從/proc/self/maps
中取得/system/bin/linker
的基地址,再遍歷/system/bin/linker
文件的symbol
查找dlopen
的文件偏移,再加上基地址做hook
, 不同版本的linker
的dlopen
對應的symbol
不同,這個可以通過IDA
來查看確認。
startIORelocater
的作用是可以在java層設置路徑白名單,黑名單,要替換的名單,然後把這些路徑列表傳到NDK層,並hook
所有的帶路徑的libc
函數以及linker
下的dlopen
函數,並在hook
中對路徑做相應放過,禁止,替換。
2.1.1.3 launchEngine
NativeEngine.launchEngine
會調用jni_nativeLaunchEngine
, 傳入參數如下:
1> method
:java層的native函數列表:
gOpenDexFileNative
: DexFile.java中openDexFileNative
函數地址gCameraNativeSetup
: Camera.java中native_setup
函數地址gAudioRecordNativeCheckPermission
: AudioRecord.java中native_check_permission
函數地址gMediaRecorderNativeSetup
: MediaRecorder.java中native_setup
函數地址gAudioRecordNativeSetup
: AudioRecord.java中native_setup
函數地址
2> VirtualCore.get().getHostPkg
:va的包名io.busniess.va
3> isArt
:是否爲art
4> Build.VERSION.SDK_INT
: 設備版本號
5> gCameraMethodType
: gCameraNativeSetup
函數參數列表中String參數的位置 + 0x10
6> gAudioRecordMethodType
: 區分gAudioRecordNativeSetup
的版本,9個參數爲1,10個參數爲2
jni_nativeLaunchEngine
內部做了一套hook native
函數的封裝, 邏輯如下:
- 自定義一個空的hook函數
mark
, 並RegisterNatives
綁定NativeEngine.nativeMark
到mark
。然後遍歷計算NativeEngine.nativeMark
到mark
的偏移,參考函數measureNativeOffset
:
void measureNativeOffset(JNIEnv *env, bool isArt) {
jmethodID markMethod = env->GetStaticMethodID(nativeEngineClass, "nativeMark", "()V");
size_t start = (size_t) markMethod;
size_t target = (size_t) mark;
int offset = 0;
bool found = false;
while (true) {
if (*((size_t *) (start + offset)) == target) {
found = true;
break;
}
offset += 4;
if (offset >= 100) {
ALOGE("Error: Cannot find the jni function offset.");
break;
}
}
if (found) {
patchEnv.native_offset = offset;
}
}
- 以hook
getCallingUid
爲例,首先取得原始的getCallingUid
地址
public static final native int getCallingUid()
--->得到native函數getCallingUid的地址
jclass binderClass = env->FindClass("android/os/Binder");
jmethodID getCallingUid = env->GetStaticMethodID(binderClass, "getCallingUid", "()I");
然後調用hookJNIMethod
做hook, vmGetJNIFunction
通過相同的偏移量得到ndk層中原始jni函數地址, vmUseJNIFunction
替換爲新的jni函數地址。
hookJNIMethod(getCallingUid,
(void *) new_getCallingUid,
(void **) &patchEnv.orig_getCallingUid
--->
void hookJNIMethod(jmethodID method, void *new_jni_func, void **orig_jni_func) {
*orig_jni_func = vmGetJNIFunction(method);
vmUseJNIFunction(method, new_jni_func);
}
---> vmGetJNIFunction得到原始的jni函數地址
void *vmGetJNIFunction(jmethodID method) {
void **funPtr = (void **) (reinterpret_cast<size_t>(method) + patchEnv.native_offset);
return *funPtr;
}
--->vmUseJNIFunction替換爲新的jni函數地址
void vmUseJNIFunction(jmethodID method, void *jniFunction) {
void **funPtr = (void **) (reinterpret_cast<size_t>(method) + patchEnv.native_offset);
*funPtr = jniFunction;
}
jni_nativeLaunchEngine
主要完成了以下任務:
- hook Binder.java中
getCallingUid
,調用NativeEngine. onGetCallingUid
返回自定義的Uid - hook DexFile.java中
openDexFileNative
, 調用NativeEngine. onOpenDexFileNative
- hook Camera.java中
native_setup
, 替換它的String參數爲傳入的包名 - hook MediaRecorder.java中
native_setup
, 替換它的String參數爲傳入的包名 - hook AudioRecord.java中
native_setup
, 替換它的String參數爲傳入的包名 - hook Runtime.java中的
nativeLoad
, 替換它的文件路徑
launchEngine
的作用是替換java native函數對應的ndk層jni函數,具體如上所述。
2.2.x進程中hook 函數處理
2.2.1. IActivityManager.overridePendingTransition
在VClient.bindApplication
調用之前,默認返回0,之後判斷va中是否使用系統已安裝的apk進行安裝(默認是),如果是,則放過
public Object call(Object who, Method method, Object... args) throws Throwable {
if (!VClient.get().isAppUseOutsideAPK()) {
return 0;
}
return super.call(who, method, args);
}
2.2.2. IActivityManager.getRecentTasks
判斷取得的 List<ActivityManager.RecentTaskInfo>
是否有我們自定義的TaskInfo
,如果有,就強制修改List,再返回, 修改如下:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
info.topActivity = taskInfo.topActivity;
info.baseActivity = taskInfo.baseActivity;
}
info.origActivity = taskInfo.baseActivity;
info.baseIntent = taskInfo.baseIntent;
2.2.3. IActivityManager.getContentProvider
這個函數首次觸發是在前面提到的initProcess
中ProviderCall.callSafely
創建新進程:p0
, 這時默認是直接返回的:
public Object call(Object who, Method method, Object... args) throws Throwable {
int nameIdx = getProviderNameIndex(); // nameIndex = 1
String name = (String) args[nameIdx]; // name = io.busniess.va.virtual_stub_0
if ((name.startsWith(StubManifest.STUB_CP_AUTHORITY)
|| name.startsWith(StubManifest.STUB_CP_AUTHORITY_64BIT)
|| name.equals(getConfig().get64bitHelperAuthority()))
|| name.equals(getConfig().getBinderProviderAuthority())) {
return method.invoke(who, args);
...
// todo,待續.
之後進入了新進程:p0
的相關hook
2.3.Os.getuid
取得原始系統分配的uid
,初始使用系統分配的uid
,在初始化完成後,使用ProcessRecord
中的vuid
, 這個也可以從後面打印的日誌看出。
public Object afterCall(Object who, Method method, Object[] args, Object result) throws Throwable {
int uid = (int) result;
return NativeEngine.onGetUid(uid);
}
-->
public static int onGetUid(int uid) {
if (!VClient.get().isAppRunning()) {// 在點擊啓動va中的apk開始時,isAppRunning=false
return uid;
}
return VClient.get().getBaseVUid();// 取得ProcessRecord中的vuid
}
2.1. IPackageManager.getApplicationInfo
默認返回我們VPMS
中創建的ApplicationInfo
, 如果我們沒有安裝過,但是屬於以下三類:
- va自身
- 系統app
- 使用外部包的app, 其中3的解釋如下
比如內部微信調用QQ分享,但是內部沒有QQ,如果沒用addVisibleOutsidePackage
,那麼提示沒有安裝QQ,如果用了addVisibleOutsidePackage
,則屬於外部包,啓動外部的QQ
這三類都會通過ComponentFixer.fixOutsideApplicationInfo
把ApplicationInfo.uid
設置爲9999。
public Object call(Object who, Method method, Object... args) throws Throwable {
String pkg = (String) args[0]; // eg: com.hgy.ndk
int flags = (int) args[0]; // 1024
if (getHostPkg().equals(pkg)) { // getHostPkg = io.busniess.va
return method.invoke(who, args);
}
int userId = VUserHandle.myUserId(); // eg: userId = 0
ApplicationInfo info = VPackageManager.get().getApplicationInfo(pkg, flags, userId);
if (info != null) {
return info; // 默認返回我們VPMS中創建的ApplicationInfo
}
info = (ApplicationInfo)method.invoke(who, args);
// isVisiblePackage表明了三類可見app,1.va自身 2.系統app 3.使用外部包的app, 其中3的解釋如下
// 外部安裝了應用,但是內部沒有安裝(雙開),內部應用在調用外面的應用,需要先addVisibleOutsidePackage,否則會相當於沒有安裝
if (info == null || !isVisiblePackage(info)) {
return null;
}
ComponentFixer.fixOutsideApplicationInfo(info);
return info;
}
3. 打印hook的函數
我們可以把HookInvocationHandler.invoke
稍改造下,讓它所有的hook函數都打印出日誌:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodProxy methodProxy = getMethodProxy(method.getName());
if (methodProxy != null) {
methodProxy.setInvocationloggingCondition(LogInvocation.Condition.ALWAYS);
}
在VirtualCore.startup
中加入等待斷點:
public void startup(Context context, SettingConfig config) throws Throwable {
...
detectProcessType();
if (isVAppProcess()) {
VLog.e(TAG, "startup0");
android.os.Debug.waitForDebugger();
VLog.e(TAG, "startup1");
}
}
點擊VA中安裝的APK啓動,附加斷點,把Logcat切到當前的io.busniess.va:px
日誌,觀察它的整個hook函數列表:
在附加之前,我們的:x
服務進程,它的日誌如下:
08-26 02:24:13.594 3006-3006/io.busniess.va:x I/MethodInvocationStub: IActivityManager.getActivityDisplayId(android.os.BinderProxy@640bff7) => 0
08-26 02:24:13.603 3006-3006/io.busniess.va:x I/MethodInvocationStub: IActivityManager.setTaskDescription(android.os.BinderProxy@640bff7, TaskDescription Label: null Icon: null colorPrimary: -1644826) => void
08-26 02:24:13.605 3006-3006/io.busniess.va:x I/MethodInvocationStub: IActivityManager.overridePendingTransition(android.os.BinderProxy@640bff7, io.busniess.va, 0, 0) => void
08-26 02:24:13.616 3006-3006/io.busniess.va:x I/MethodInvocationStub: IActivityManager.getActivityOptions(android.os.BinderProxy@640bff7) => null
08-26 02:24:13.620 3006-3006/io.busniess.va:x I/MethodInvocationStub: IActivityManager.getActivityOptions(android.os.BinderProxy@640bff7) => null
08-26 02:24:13.622 3006-3006/io.busniess.va:x I/MethodInvocationStub: IActivityManager.checkPermission(android.permission.INTERACT_ACROSS_USERS, 3006, 10058) => -1
08-26 02:24:13.623 3006-3006/io.busniess.va:x I/MethodInvocationStub: IActivityManager.checkPermission(android.permission.INTERACT_ACROSS_USERS_FULL, 3006, 10058) => -1
08-26 02:24:13.646 3006-3006/io.busniess.va:x I/MethodInvocationStub: IActivityManager.activityResumed(android.os.BinderProxy@640bff7) => void
08-26 02:24:13.825 3006-3006/io.busniess.va:x I/MethodInvocationStub: IActivityManager.activityIdle(android.os.BinderProxy@640bff7, {1.0 310mcc260mnc en_US ldltr sw392dp w392dp h713dp 440dpi nrml long port finger -keyb/v/h dpad/v s.6}, false) => void
08-26 02:24:13.992 3006-3030/io.busniess.va:x I/MethodInvocationStub: IActivityManager.getRecentTasks(2147483647, 3, 0) => [android.app.ActivityManager$RecentTaskInfo@4d02da, android.app.ActivityManager$RecentTaskInfo@644d30b, android.app.ActivityManager$RecentTaskInfo@91d65e8]
附加後,它的新增日誌爲:
08-26 02:25:22.163 3006-3030/io.busniess.va:x I/MethodInvocationStub: IActivityManager.getContentProvider(android.app.ActivityThread$ApplicationThread@b14e927, io.busniess.va.virtual_stub_0, 0, false) => android.app.IActivityManager$ContentProviderHolder@14401
08-26 02:25:23.659 3006-3006/io.busniess.va:x I/MethodInvocationStub: IActivityManager.removeContentProvider(android.os.BinderProxy@1eb94e7, false) => void
08-26 02:25:23.714 3006-3030/io.busniess.va:x I/MethodInvocationStub: IActivityManager.startActivity(android.app.ActivityThread$ApplicationThread@b14e927, io.busniess.va, Intent { typ=com.hgy.ndk/com.hgy.ndk.MainActivity flg=0x18290000 cmp=io.busniess.va/com.lody.virtual.client.stub.ShadowActivity$P0 (has extras) }, com.hgy.ndk/com.hgy.ndk.MainActivity, null, null, -1, 0, null, null) => 0
08-26 02:25:23.726 3006-3006/io.busniess.va:x I/MethodInvocationStub: IActivityManager.activityPaused(android.os.BinderProxy@640bff7) => void
08-26 02:25:23.728 3006-3018/io.busniess.va:x I/MethodInvocationStub: IActivityManager.getRecentTasks(2147483647, 3, 0) => [android.app.ActivityManager$RecentTaskInfo@d3d1f3d, android.app.ActivityManager$RecentTaskInfo@8b91332, android.app.ActivityManager$RecentTaskInfo@5529883, android.app.ActivityManager$RecentTaskInfo@6f50a00]
08-26 02:25:23.743 3006-3018/io.busniess.va:x I/MethodInvocationStub: IActivityManager.startActivity(android.app.ActivityThread$ApplicationThread@b14e927, io.busniess.va, Intent { typ=com.hgy.ndk/com.hgy.ndk.MainActivity flg=0x18290000 cmp=io.busniess.va/com.lody.virtual.client.stub.ShadowActivity$P0 (has extras) }, com.hgy.ndk/com.hgy.ndk.MainActivity, null, null, -1, 0, null, null) => 0
08-26 02:25:23.779 3006-3031/io.busniess.va:x I/MethodInvocationStub: IActivityManager.getRecentTasks(2147483647, 3, 0) => [android.app.ActivityManager$RecentTaskInfo@b617239, android.app.ActivityManager$RecentTaskInfo@a61307e, android.app.ActivityManager$RecentTaskInfo@79c39df, android.app.ActivityManager$RecentTaskInfo@8a0c62c]
08-26 02:25:23.780 3006-3031/io.busniess.va:x I/MethodInvocationStub: IActivityManager.broadcastIntent(android.app.ActivityThread$ApplicationThread@b14e927, Intent { act=virtual.intent.action.APP_LAUNCHED (has extras) }, null, null, -1, null, null, null, -1, null, false, false, 0) => 0
08-26 02:25:23.895 3006-3018/io.busniess.va:x I/MethodInvocationStub: IActivityManager.getRecentTasks(2147483647, 3, 0) => [android.app.ActivityManager$RecentTaskInfo@addf8f5, android.app.ActivityManager$RecentTaskInfo@4dbd68a, android.app.ActivityManager$RecentTaskInfo@5b494fb, android.app.ActivityManager$RecentTaskInfo@86a1918]
08-26 02:25:24.031 3006-3030/io.busniess.va:x I/MethodInvocationStub: IActivityManager.getRecentTasks(2147483647, 3, 0) => [android.app.ActivityManager$RecentTaskInfo@9622f71, android.app.ActivityManager$RecentTaskInfo@ba8d156, android.app.ActivityManager$RecentTaskInfo@52d85d7, android.app.ActivityManager$RecentTaskInfo@e73aec4, android.app.ActivityManager$RecentTaskInfo@61951ad]
08-26 02:25:24.033 3006-3030/io.busniess.va:x I/MethodInvocationStub: IActivityManager.broadcastIntent(android.app.ActivityThread$ApplicationThread@b14e927, Intent { act=virtual.intent.action.APP_LAUNCHED (has extras) }, null, null, -1, null, null, null, -1, null, false, false, 0) => 0
08-26 02:25:24.079 3006-3018/io.busniess.va:x I/MethodInvocationStub: IActivityManager.getRecentTasks(2147483647, 3, 0) => [android.app.ActivityManager$RecentTaskInfo@878ace2, android.app.ActivityManager$RecentTaskInfo@8daa873, android.app.ActivityManager$RecentTaskInfo@5ef330, android.app.ActivityManager$RecentTaskInfo@da65ba9, android.app.ActivityManager$RecentTaskInfo@d78b52e]
08-26 02:25:24.316 3006-3006/io.busniess.va:x I/MethodInvocationStub: IActivityManager.finishActivity(android.os.BinderProxy@640bff7, 0, null, false) => true
08-26 02:25:24.328 3006-3006/io.busniess.va:x I/MethodInvocationStub: IActivityManager.activityStopped(android.os.BinderProxy@640bff7, Bundle[{android:viewHierarchyState=Bundle[{android:views={16908290=android.view.AbsSavedState$1@32d58cf}}]}], null, null) => void
對於被啓動的進程com.hgy.ndk(io.busniess.va:p0)
,它的日誌如下:
08-26 02:25:22.150 3032-3032/io.busniess.va:p0 I/MethodInvocationStub: Os.getuid(ul) => 10058
08-26 02:25:22.161 3032-3032/io.busniess.va:p0 I/MethodInvocationStub: Os.getuid(ul) => 10058
08-26 02:25:22.163 3032-3032/io.busniess.va:p0 I/MethodInvocationStub: IActivityManager.publishContentProviders(android.app.ActivityThread$ApplicationThread@6fbd30e, [android.app.IActivityManager$ContentProviderHolder@e5b512f]) => void
08-26 02:25:22.165 3032-3032/io.busniess.va:p0 I/MethodInvocationStub: IActivityManager.removeContentProvider(android.os.BinderProxy@2ec0c41, false) => void
08-26 02:25:23.746 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.getRunningAppProcesses(ul) => [android.app.ActivityManager$RunningAppProcessInfo@446f18, android.app.ActivityManager$RunningAppProcessInfo@b8ccd71, android.app.ActivityManager$RunningAppProcessInfo@7f21756]
08-26 02:25:23.755 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:23.757 3032-3032/com.hgy.ndk I/MethodInvocationStub: IPackageManager.getApplicationInfo(com.hgy.ndk, 1024, 0) => ApplicationInfo{d0c4bde com.hgy.ndk}
08-26 02:25:23.757 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:23.757 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:23.757 3032-3032/com.hgy.ndk I/MethodInvocationStub: IPackageManager.performDexOptIfNeeded(com.hgy.ndk, x86) => false
08-26 02:25:23.757 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.addPackageDependency(com.hgy.ndk) => void
08-26 02:25:23.758 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.stat(/data/app/com.hgy.ndk-1/base.apk) => StructStat[st_atime=1566480905,st_blksize=4096,st_blocks=3512,st_ctime=1566480906,st_dev=64800,st_gid=1000,st_ino=16584,st_mode=33188,st_mtime=1566480905,st_nlink=1,st_rdev=0,st_size=1796475,st_uid=1000]
08-26 02:25:23.758 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.stat(/data/app/com.hgy.ndk-1/base.apk) => StructStat[st_atime=1566480905,st_blksize=4096,st_blocks=3512,st_ctime=1566480906,st_dev=64800,st_gid=1000,st_ino=16584,st_mode=33188,st_mtime=1566480905,st_nlink=1,st_rdev=0,st_size=1796475,st_uid=1000]
08-26 02:25:23.759 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.stat(/vendor/lib) => StructStat[st_atime=1499889343,st_blksize=4096,st_blocks=8,st_ctime=1499889343,st_dev=64768,st_gid=2000,st_ino=1583,st_mode=16877,st_mtime=1499889343,st_nlink=4,st_rdev=0,st_size=4096,st_uid=0]
08-26 02:25:23.759 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.stat(/system/lib) => StructStat[st_atime=1499889365,st_blksize=4096,st_blocks=16,st_ctime=1566472418,st_dev=64768,st_gid=0,st_ino=889,st_mode=16877,st_mtime=1566472418,st_nlink=5,st_rdev=0,st_size=8192,st_uid=0]
08-26 02:25:23.759 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.stat(/data/app/com.hgy.ndk-1/lib/x86) => StructStat[st_atime=1566480905,st_blksize=4096,st_blocks=8,st_ctime=1566480906,st_dev=64800,st_gid=1000,st_ino=16586,st_mode=16877,st_mtime=1566480905,st_nlink=2,st_rdev=0,st_size=4096,st_uid=1000]
08-26 02:25:23.759 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.stat(/vendor/lib) => StructStat[st_atime=1499889343,st_blksize=4096,st_blocks=8,st_ctime=1499889343,st_dev=64768,st_gid=2000,st_ino=1583,st_mode=16877,st_mtime=1499889343,st_nlink=4,st_rdev=0,st_size=4096,st_uid=0]
08-26 02:25:23.760 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.stat(/system/lib) => StructStat[st_atime=1499889365,st_blksize=4096,st_blocks=16,st_ctime=1566472418,st_dev=64768,st_gid=0,st_ino=889,st_mode=16877,st_mtime=1566472418,st_nlink=5,st_rdev=0,st_size=8192,st_uid=0]
08-26 02:25:23.761 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.stat(/data/app/com.hgy.ndk-1/base.apk) => StructStat[st_atime=1566480905,st_blksize=4096,st_blocks=3512,st_ctime=1566480906,st_dev=64800,st_gid=1000,st_ino=16584,st_mode=33188,st_mtime=1566480905,st_nlink=1,st_rdev=0,st_size=1796475,st_uid=1000]
08-26 02:25:23.768 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:23.769 3032-3032/com.hgy.ndk I/MethodInvocationStub: IPackageManager.getPackageInfo(com.hgy.ndk, 0, 0) => PackageInfo{a3889b7 com.hgy.ndk}
08-26 02:25:23.769 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:23.778 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.getTaskForActivity(android.os.BinderProxy@a58f8af, false) => 19
08-26 02:25:23.780 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:23.780 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:23.782 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.fstat(FileDescriptor[26]) => StructStat[st_atime=1566480905,st_blksize=4096,st_blocks=3512,st_ctime=1566480906,st_dev=64800,st_gid=1000,st_ino=16584,st_mode=33188,st_mtime=1566480905,st_nlink=1,st_rdev=0,st_size=1796475,st_uid=1000]
08-26 02:25:23.782 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.fstat(FileDescriptor[26]) => StructStat[st_atime=1566480905,st_blksize=4096,st_blocks=3512,st_ctime=1566480906,st_dev=64800,st_gid=1000,st_ino=16584,st_mode=33188,st_mtime=1566480905,st_nlink=1,st_rdev=0,st_size=1796475,st_uid=1000]
08-26 02:25:23.783 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.fstat(FileDescriptor[26]) => StructStat[st_atime=1566480905,st_blksize=4096,st_blocks=3512,st_ctime=1566480906,st_dev=64800,st_gid=1000,st_ino=16584,st_mode=33188,st_mtime=1566480905,st_nlink=1,st_rdev=0,st_size=1796475,st_uid=1000]
08-26 02:25:23.787 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.getActivityDisplayId(android.os.BinderProxy@a58f8af) => 0
08-26 02:25:23.787 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:23.788 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:23.788 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:23.789 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:23.789 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:23.791 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:23.791 3032-3032/com.hgy.ndk I/MethodInvocationStub: IUserManager.getProfiles(0, false) => []
08-26 02:25:23.793 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.setTaskDescription(android.os.BinderProxy@a58f8af, TaskDescription Label: null Icon: null colorPrimary: -16743049) => void
08-26 02:25:23.795 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.getTaskForActivity(android.os.BinderProxy@a58f8af, true) => 19
08-26 02:25:23.795 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:23.796 3032-3032/com.hgy.ndk I/MethodInvocationStub: IUserManager.getProfiles(0, false) => []
08-26 02:25:23.796 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.setTaskDescription(android.os.BinderProxy@a58f8af, TaskDescription Label: ndk Icon: android.graphics.Bitmap@800eaa1 colorPrimary: 0) => void
08-26 02:25:23.797 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.getRequestedOrientation(android.os.BinderProxy@a58f8af) => -1
08-26 02:25:23.809 3032-3032/com.hgy.ndk I/MethodInvocationStub: IPackageManager.getActivityInfo(ComponentInfo{com.hgy.ndk/com.hgy.ndk.MainActivity}, 128, 0) => ActivityInfo{dda98f1 com.hgy.ndk.MainActivity}
08-26 02:25:23.812 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:23.812 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:23.813 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.checkPermission(android.permission.INTERACT_ACROSS_USERS, 3032, 10001) => -1
08-26 02:25:23.813 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:23.814 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.checkPermission(android.permission.INTERACT_ACROSS_USERS_FULL, 3032, 10001) => -1
08-26 02:25:23.814 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:23.814 3032-3032/com.hgy.ndk I/MethodInvocationStub: IAccessibilityManager.addClient(android.view.accessibility.AccessibilityManager$1@76ed32d, 0) => 0
08-26 02:25:23.872 3032-3032/com.hgy.ndk I/MethodInvocationStub: IPackageManager.getPackageInfo(com.dts.freefireth, 0, 0) => null
08-26 02:25:23.874 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.getActivityOptions(android.os.BinderProxy@a58f8af) => null
08-26 02:25:23.874 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.getActivityOptions(android.os.BinderProxy@a58f8af) => null
08-26 02:25:23.876 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:23.880 3032-3032/com.hgy.ndk I/MethodInvocationStub: IWindowManager.openSession(android.view.WindowManagerGlobal$1@ee7b73a, android.view.inputmethod.InputMethodManager$1@358dfeb, android.view.inputmethod.InputMethodManager$ControlledInputConnectionWrapper@bd32148) => android.view.IWindowSession$Stub$Proxy@69dc51d
08-26 02:25:23.886 3032-3032/com.hgy.ndk I/MethodInvocationStub: IGraphicsStats.requestBufferForProcess(com.hgy.ndk, android.os.Binder@97f6163) => {ParcelFileDescriptor: FileDescriptor[32]}
08-26 02:25:23.894 3032-3032/com.hgy.ndk I/MethodInvocationStub: IWindowSession.addToDisplay(android.view.ViewRootImpl$W@7ad160, 0, WM.LayoutParams{(0,0)(fillxfill) ty=1 fl=#81810100 wanim=0x103045b needsMenuKey=2}, 4, 0, Rect(0, 0 - 0, 0), Rect(0, 0 - 0, 0), Rect(0, 0 - 0, 0), uninitialized) => 3
08-26 02:25:23.896 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.activityResumed(android.os.BinderProxy@a58f8af) => void
08-26 02:25:23.897 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:23.901 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.activityPaused(android.os.BinderProxy@a58f8af) => void
08-26 02:25:23.920 3032-3032/com.hgy.ndk I/MethodInvocationStub: IWindowSession.relayout(android.view.ViewRootImpl$W@7ad160, 0, WM.LayoutParams{(0,0)(fillxfill) sim=#20 ty=1 fl=#81810100 wanim=0x103045b needsMenuKey=2}, 1080, 2028, 0, 0, Rect(0, 0 - 0, 0), Rect(0, 0 - 0, 0), Rect(0, 66 - 0, 132), Rect(0, 0 - 0, 0), Rect(0, 66 - 0, 132), Rect(0, 0 - 0, 0), {1.0 ?mcc?mnc ?locale ?layoutDir ?swdp ?wdp ?hdp ?density ?lsize ?long ?orien ?uimode ?night ?touch ?keyb/?/? ?nav/?}, Surface(name=null)/@0xbbb6953) => 7
08-26 02:25:24.030 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.getTaskForActivity(android.os.BinderProxy@d9c3789, false) => 20
08-26 02:25:24.033 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:24.034 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:24.034 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.getActivityDisplayId(android.os.BinderProxy@d9c3789) => 0
08-26 02:25:24.035 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:24.037 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:24.038 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:24.042 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:24.042 3032-3032/com.hgy.ndk I/MethodInvocationStub: IUserManager.getProfiles(0, false) => []
08-26 02:25:24.042 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.setTaskDescription(android.os.BinderProxy@d9c3789, TaskDescription Label: null Icon: null colorPrimary: -16743049) => void
08-26 02:25:24.043 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.getTaskForActivity(android.os.BinderProxy@d9c3789, true) => 20
08-26 02:25:24.043 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:24.043 3032-3032/com.hgy.ndk I/MethodInvocationStub: IUserManager.getProfiles(0, false) => []
08-26 02:25:24.044 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.setTaskDescription(android.os.BinderProxy@d9c3789, TaskDescription Label: ndk Icon: android.graphics.Bitmap@90947af colorPrimary: 0) => void
08-26 02:25:24.059 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.getRequestedOrientation(android.os.BinderProxy@d9c3789) => -1
08-26 02:25:24.061 3032-3032/com.hgy.ndk I/MethodInvocationStub: IPackageManager.getActivityInfo(ComponentInfo{com.hgy.ndk/com.hgy.ndk.MainActivity}, 128, 0) => ActivityInfo{887c345 com.hgy.ndk.MainActivity}
08-26 02:25:24.072 3032-3032/com.hgy.ndk I/MethodInvocationStub: IPackageManager.getPackageInfo(com.dts.freefireth, 0, 0) => null
08-26 02:25:24.073 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.getActivityOptions(android.os.BinderProxy@d9c3789) => null
08-26 02:25:24.074 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.getActivityOptions(android.os.BinderProxy@d9c3789) => null
08-26 02:25:24.074 3032-3032/com.hgy.ndk I/MethodInvocationStub: Os.getuid(ul) => 10001
08-26 02:25:24.078 3032-3032/com.hgy.ndk I/MethodInvocationStub: IWindowSession.addToDisplay(android.view.ViewRootImpl$W@35f9e4a, 0, WM.LayoutParams{(0,0)(fillxfill) ty=1 fl=#81810100 wanim=0x103045b needsMenuKey=2}, 4, 0, Rect(0, 0 - 0, 0), Rect(0, 0 - 0, 0), Rect(0, 0 - 0, 0), uninitialized) => 3
08-26 02:25:24.079 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.activityResumed(android.os.BinderProxy@d9c3789) => void
08-26 02:25:24.188 3032-3032/com.hgy.ndk I/MethodInvocationStub: IWindowSession.relayout(android.view.ViewRootImpl$W@35f9e4a, 0, WM.LayoutParams{(0,0)(fillxfill) sim=#20 ty=1 fl=#81810100 wanim=0x103045b needsMenuKey=2}, 1080, 2028, 0, 0, Rect(0, 0 - 0, 0), Rect(0, 0 - 0, 0), Rect(0, 66 - 0, 132), Rect(0, 0 - 0, 0), Rect(0, 66 - 0, 132), Rect(0, 0 - 0, 0), {1.0 ?mcc?mnc ?locale ?layoutDir ?swdp ?wdp ?hdp ?density ?lsize ?long ?orien ?uimode ?night ?touch ?keyb/?/? ?nav/?}, Surface(name=null)/@0x3f9d511) => 7
08-26 02:25:24.252 3032-3032/com.hgy.ndk I/MethodInvocationStub: IInputMethodManager.windowGainedFocus(android.view.inputmethod.InputMethodManager$1@358dfeb, android.view.ViewRootImpl$W@35f9e4a, 260, 32, -2122252032, android.view.inputmethod.EditorInfo@c711676, null) => InputBindResult{null com.android.inputmethod.latin/.LatinIME sequence:29 userActionNotificationSequenceNumber:1}
08-26 02:25:24.270 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.activityIdle(android.os.BinderProxy@d9c3789, {1.0 310mcc260mnc en_US ldltr sw392dp w392dp h713dp 440dpi nrml long port finger -keyb/v/h dpad/v s.6}, false) => void
08-26 02:25:24.271 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.activityIdle(android.os.BinderProxy@a58f8af, {1.0 310mcc260mnc en_US ldltr sw392dp w392dp h713dp 440dpi nrml long port finger -keyb/v/h dpad/v s.6}, false) => void
08-26 02:25:24.306 3032-3032/com.hgy.ndk I/MethodInvocationStub: IWindowSession.relayout(android.view.ViewRootImpl$W@7ad160, 0, null, 1080, 2160, 8, 0, Rect(0, 0 - 1080, 2160), Rect(0, 0 - 0, 0), Rect(0, 66 - 0, 132), Rect(0, 66 - 0, 132), Rect(0, 66 - 0, 132), Rect(0, 0 - 0, 0), {1.0 310mcc260mnc en_US ldltr sw392dp w392dp h713dp 440dpi nrml long port finger -keyb/v/h dpad/v}, Surface(name=null)/@0xbbb6953) => 5
08-26 02:25:24.326 3032-3032/com.hgy.ndk I/MethodInvocationStub: IActivityManager.activityStopped(android.os.BinderProxy@a58f8af, Bundle[{android:viewHierarchyState=Bundle[{android:views={16908290=android.view.AbsSavedState$1@9ae7868, 2131165190=android.support.v7.widget.Toolbar$SavedState@692481, 2131165192=android.view.AbsSavedState$1@9ae7868, 2131165198=android.view.AbsSavedState$1@9ae7868, 2131165232=android.view.AbsSavedState$1@9ae7868}}], android:fragments=android.app.FragmentManagerState@2aa0926}], null, null) => void
其中參數爲
null
會被截取打印成ul
,如Os.getuid(ul) => 10058