自动解锁手机抢购京东飞天茅台
每天定时抢购飞天茅台
-
Shizuku Apk
-
- 执行 adb shell sh /sdcard/Android/data/li.songe.gkd.debug/start.sh
-
copy 可执行文件
-
copy starter from /storage/emulated/0/Android/data/li.songe.gkd.debug/starter to /data/local/tmp/shizuku_starter
-
-
增加执行权限starter.ELF
-
执行文件starter.ELF
-
执行starter.cpp
-
创建守护进程 if (daemon(false, false) == 0)
-
运行java文件
rikka.shizuku.server.ShizukuService
进程名称shizuku_server
-
static void run_server(const char *dex_path, const char *main_class, const char *process_name) { if (setenv("CLASSPATH", dex_path, true)) { LOGE("can't set CLASSPATH\n"); exit(EXIT_FATAL_SET_CLASSPATH); } #define ARG(v) char **v = nullptr; \ char buf_##v[PATH_MAX]; \ size_t v_size = 0; \ uintptr_t v_current = 0; #define ARG_PUSH(v, arg) v_size += sizeof(char *); \ if (v == nullptr) { \ v = (char **) malloc(v_size); \ } else { \ v = (char **) realloc(v, v_size);\ } \ v_current = (uintptr_t) v + v_size - sizeof(char *); \ *((char **) v_current) = arg ? strdup(arg) : nullptr; #define ARG_END(v) ARG_PUSH(v, nullptr) #define ARG_PUSH_FMT(v, fmt, ...) snprintf(buf_##v, PATH_MAX, fmt, __VA_ARGS__); \ ARG_PUSH(v, buf_##v) #ifdef JAVA_DEBUGGABLE #define ARG_PUSH_DEBUG_ONLY(v, arg) ARG_PUSH(v, arg) #define ARG_PUSH_DEBUG_VM_PARAMS(v) \ if (android::GetApiLevel() >= 30) { \ ARG_PUSH(v, "-Xcompiler-option"); \ ARG_PUSH(v, "--debuggable"); \ ARG_PUSH(v, "-XjdwpProvider:adbconnection"); \ ARG_PUSH(v, "-XjdwpOptions:suspend=n,server=y"); \ } else if (android::GetApiLevel() >= 28) { \ ARG_PUSH(v, "-Xcompiler-option"); \ ARG_PUSH(v, "--debuggable"); \ ARG_PUSH(v, "-XjdwpProvider:internal"); \ ARG_PUSH(v, "-XjdwpOptions:transport=dt_android_adb,suspend=n,server=y"); \ } else { \ ARG_PUSH(v, "-Xcompiler-option"); \ ARG_PUSH(v, "--debuggable"); \ ARG_PUSH(v, "-agentlib:jdwp=transport=dt_android_adb,suspend=n,server=y"); \ } #else #define ARG_PUSH_DEBUG_VM_PARAMS(v) #define ARG_PUSH_DEBUG_ONLY(v, arg) #endif char lib_path[PATH_MAX]{0}; snprintf(lib_path, PATH_MAX, "%s!/lib/%s", dex_path, ABI); ARG(argv) ARG_PUSH(argv, "/system/bin/app_process") ARG_PUSH_FMT(argv, "-Djava.class.path=%s", dex_path) ARG_PUSH_FMT(argv, "-Dshizuku.library.path=%s", lib_path) ARG_PUSH_DEBUG_VM_PARAMS(argv) ARG_PUSH(argv, "/system/bin") ARG_PUSH_FMT(argv, "--nice-name=%s", process_name) ARG_PUSH(argv, main_class) ARG_PUSH_DEBUG_ONLY(argv, "--debug") ARG_END(argv) LOGD("exec app_process"); if (execvp((const char *) argv[0], argv)) { exit(EXIT_FATAL_APP_PROCESS); } }
-
-
- 通过上面的执行:进程shizuku_server 已经创建运行
-
进入loop循环模式
-
public static void main(String[] args) { DdmHandleAppName.setAppName("shizuku_server", 0); LOGGER.i("gzp_ShizukuService getProperty" + System.getProperty("shizuku.library.path")); RishConfig.setLibraryPath(System.getProperty("shizuku.library.path")); Looper.prepareMainLooper(); new ShizukuService(); Looper.loop(); }
-
-
- 将shizukuservice 发送给客户端(应用apk)sendBinderToClient
-
public ShizukuService() { super(); HandlerUtil.setMainHandler(mainHandler); LOGGER.i("starting server..."); waitSystemService("package"); waitSystemService(Context.ACTIVITY_SERVICE); waitSystemService(Context.USER_SERVICE); waitSystemService(Context.APP_OPS_SERVICE); ApplicationInfo ai = getManagerApplicationInfo(); if (ai == null) { System.exit(ServerConstants.MANAGER_APP_NOT_FOUND); } assert ai != null; managerAppId = ai.uid; configManager = getConfigManager(); clientManager = getClientManager(); ApkChangedObservers.start(ai.sourceDir, () -> { if (getManagerApplicationInfo() == null) { LOGGER.w("manager app is uninstalled in user 0, exiting..."); System.exit(ServerConstants.MANAGER_APP_NOT_FOUND); } }); BinderSender.register(this); mainHandler.post(() -> { sendBinderToClient(); sendBinderToManager(); }); }
-
调用 sendBinderToUserApp
-
static void sendBinderToUserApp(Binder binder, String packageName, int userId, boolean retry) { try { DeviceIdleControllerApis.addPowerSaveTempWhitelistApp(packageName, 30 * 1000, userId, 316/* PowerExemptionManager#REASON_SHELL */, "shell"); LOGGER.v("Add %d:%s to power save temp whitelist for 30s", userId, packageName); } catch (Throwable tr) { LOGGER.e(tr, "Failed to add %d:%s to power save temp whitelist", userId, packageName); } String name = packageName + ".shizuku"; IContentProvider provider = null; /* When we pass IBinder through binder (and really crossed process), the receive side (here is system_server process) will always get a new instance of android.os.BinderProxy. In the implementation of getContentProviderExternal and removeContentProviderExternal, received IBinder is used as the key of a HashMap. But hashCode() is not implemented by BinderProxy, so removeContentProviderExternal will never work. Luckily, we can pass null. When token is token, count will be used. */ IBinder token = null; try { provider = ActivityManagerApis.getContentProviderExternal(name, userId, token, name); if (provider == null) { LOGGER.e("provider is null %s %d", name, userId); return; } if (!provider.asBinder().pingBinder()) { LOGGER.e("provider is dead %s %d", name, userId); if (retry) { // For unknown reason, sometimes this could happens // Kill Shizuku app and try again could work ActivityManagerApis.forceStopPackageNoThrow(packageName, userId); LOGGER.e("kill %s in user %d and try again", packageName, userId); Thread.sleep(1000); sendBinderToUserApp(binder, packageName, userId, false); } return; } if (!retry) { LOGGER.e("retry works"); } Bundle extra = new Bundle(); extra.putParcelable("moe.shizuku.privileged.api.intent.extra.BINDER", new BinderContainer(binder)); Bundle reply = IContentProviderUtils.callCompat(provider, null, name, "sendBinder", null, extra); if (reply != null) { LOGGER.i("send binder to user app %s in user %d", packageName, userId); } else { LOGGER.w("failed to send binder to user app %s in user %d", packageName, userId); } } catch (Throwable tr) { LOGGER.e(tr, "failed send binder to user app %s in user %d", packageName, userId); } finally { if (provider != null) { try { ActivityManagerApis.removeContentProviderExternal(name, token); } catch (Throwable tr) { LOGGER.w(tr, "removeContentProviderExternal"); } } } }
-
binder被包装成BinderContainer,塞到Bundle 中,binder就是ShizukuService
-
-
- 将shizukuservice 发送给Shizuku (应用apk)
-
调用 sendBinderToManager
-
static void sendBinderToManger(Binder binder, int userId) { sendBinderToUserApp(binder, MANAGER_APPLICATION_ID, userId); } public static final String MANAGER_APPLICATION_ID = "moe.shizuku.privileged.api";
-
-
- 至此 应用客户端 和Shizuku 客户端都持有 shizukuService的binder
-
-
应用 Apk
-
- androidMainfest 清单文件申明shuzuku的ShizukuProvider
-
接受Shizuku的server (binder)
-
<provider android:name="rikka.shizuku.ShizukuProvider" android:authorities="${applicationId}.shizuku" android:enabled="true" android:exported="true" android:multiprocess="false" android:permission="android.permission.INTERACT_ACROSS_USERS_FULL" />
-
- 当shizuku的 shizuku_server 进程 创建以后,后发送shizukuserver 的 binder到ShizukuProvider;
-
- 解析Bundle,得到BinderContainer(得到shizhukuservice)
-
private void handleSendBinder(@NonNull Bundle extras) { if (Shizuku.pingBinder()) { Log.d(TAG, "sendBinder is called when already a living binder"); return; } BinderContainer container = extras.getParcelable(EXTRA_BINDER); if (container != null && container.binder != null) { Log.d(TAG, "binder received"); Shizuku.onBinderReceived(container.binder, getContext().getPackageName()); if (enableMultiProcess) { Log.d(TAG, "broadcast binder"); Intent intent = new Intent(ACTION_BINDER_RECEIVED) .putExtra(EXTRA_BINDER, container) .setPackage(getContext().getPackageName()); getContext().sendBroadcast(intent); } } }
-
- shizuku api 保存 Shizukuservice 的binder 应用进程中的Shizuku
-
@RestrictTo(LIBRARY_GROUP_PREFIX) public static void onBinderReceived(@Nullable IBinder newBinder, String packageName) { if (binder == newBinder) return; if (newBinder == null) { binder = null; service = null; serverUid = -1; serverApiVersion = -1; serverContext = null; scheduleBinderDeadListeners(); } else { if (binder != null) { binder.unlinkToDeath(DEATH_RECIPIENT, 0); } binder = newBinder; service = IShizukuService.Stub.asInterface(newBinder); try { binder.linkToDeath(DEATH_RECIPIENT, 0); } catch (Throwable e) { Log.i("ShizukuApplication", "attachApplication"); } try { if (!attachApplicationV13(binder, packageName) && !attachApplicationV11(binder, packageName)) { preV11 = true; } Log.i("ShizukuApplication", "attachApplication"); } catch (Throwable e) { Log.w("ShizukuApplication", Log.getStackTraceString(e)); } if (preV11) { binderReady = true; scheduleBinderReceivedListeners(); } } }
-
- 多进程 发送广播通知
-
通过上面步骤,应用客户端已经保留shizukuService的binder
-
-
应用 Apk bindService :
-
- 应用 Apk 发起 binderService
-
public static void bindUserService(@NonNull UserServiceArgs args, @NonNull ServiceConnection conn) { ShizukuServiceConnection connection = ShizukuServiceConnections.get(args); connection.addConnection(conn); try { requireService().addUserService(connection, args.forAdd()); } catch (RemoteException e) { throw rethrowAsRuntimeException(e); } }
-
- binder 跨应用进程到进程shizuku_server中ShizukuService
- ShizukuService 处理addUserservice
-
- 应用apk 收到连接回调,binder 就是应用apk 中的服务
-
private final ServiceConnection userServiceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder binder) { if (binder != null && binder.pingBinder()) { IUserService service = IUserService.Stub.asInterface(binder); try { service.doSomething(); } catch (RemoteException e) { e.printStackTrace(); } } } @Override public void onServiceDisconnected(ComponentName componentName) { } };
-
-
ShizukuService 处理addUserservice
-
- 解析参数并保存,生成 UserServiceRecord
-
public int addUserService(IShizukuServiceConnection conn, Bundle options, int callingApiVersion) { ... ComponentName componentName = Objects.requireNonNull(options.getParcelable(USER_SERVICE_ARG_COMPONENT), "component is null"); String packageName = Objects.requireNonNull(componentName.getPackageName(), "package is null"); PackageInfo packageInfo = ensureCallingPackageForUserService(packageName, appId, userId); String className = Objects.requireNonNull(componentName.getClassName(), "class is null"); String sourceDir = Objects.requireNonNull(packageInfo.applicationInfo.sourceDir, "apk path is null"); int versionCode = options.getInt(USER_SERVICE_ARG_VERSION_CODE, 1); String tag = options.getString(USER_SERVICE_ARG_TAG); String processNameSuffix = options.getString(USER_SERVICE_ARG_PROCESS_NAME); boolean debug = options.getBoolean(USER_SERVICE_ARG_DEBUGGABLE, false); boolean noCreate = options.getBoolean(USER_SERVICE_ARG_NO_CREATE, false); boolean daemon = options.getBoolean(USER_SERVICE_ARG_DAEMON, true); boolean use32Bits = options.getBoolean(USER_SERVICE_ARG_USE_32_BIT_APP_PROCESS, false); String key = packageName + ":" + (tag != null ? tag : className); synchronized (this) { UserServiceRecord record = getUserServiceRecordLocked(key); if (noCreate) { if (record != null) { record.callbacks.register(conn); if (record.service != null && record.service.pingBinder()) { record.broadcastBinderReceived(); if (callingApiVersion >= 13) { return record.versionCode; } else { return 0; } } } if (callingApiVersion >= 13) { return -1; } else { return 1; } } else { UserServiceRecord newRecord = createUserServiceRecordIfNeededLocked(record, key, versionCode, daemon, packageInfo); newRecord.callbacks.register(conn); if (newRecord.service != null && newRecord.service.pingBinder()) { newRecord.broadcastBinderReceived(); } else if (!newRecord.starting) { newRecord.setStartingTimeout(DateUtils.SECOND_IN_MILLIS * 30); Runnable runnable = () -> startUserService(newRecord, key, newRecord.token, packageName, className, processNameSuffix, uid, use32Bits, debug); executor.execute(runnable); return 0; } return 0; } } }
-
- 开启新的shell进程 UserServiceManager# startUserService ^^shell 进程 进程名称:packageName:service^^
-
- 开启新的shell进程
-
private void startUserService( UserServiceRecord record, String key, String token, String packageName, String classname, String processNameSuffix, int callingUid, boolean use32Bits, boolean debug) { LOGGER.v("Starting process for service record %s (%s)...", key, token); String cmd = getUserServiceStartCmd(record, key, token, packageName, classname, processNameSuffix, callingUid, use32Bits && AbiUtil.has32Bit(), debug); LOGGER.v("gzp cmd2: %s", cmd); int exitCode; try { java.lang.Process process = Runtime.getRuntime().exec("sh"); OutputStream os = process.getOutputStream(); os.write(cmd.getBytes()); os.flush(); os.close(); exitCode = process.waitFor(); } catch (Throwable e) { throw new IllegalStateException(e.getMessage()); } if (exitCode != 0) { throw new IllegalStateException("sh exited with " + exitCode); } }
-
- 执行cmd
-
CLASSPATH='/data/app/li.songe.gkd.debug-c8Yb_FO5PS8KaLmGcLVbYQ==/base.apk' /system/bin/app_process -Xcompiler-option --debuggable -XjdwpProvider:internal -XjdwpOptions:transport=dt_android_adb,suspend=n,server=y /system/bin --nice-name='li.songe.gkd.debug:service' moe.shizuku.starter.ServiceStarter --token='ff773c49-13f5-4c80-a0a4-3219e79c3e0c-1708244575836' --package='li.songe.gkd.debug' --class='gzp.mt.service.UserService' --uid=10380 --debug-name=li.songe.gkd.debug:service)&
-
- 执行ServiceStarter.main方法
-
public static void main(String[] args) { if (Looper.getMainLooper() == null) { Looper.prepareMainLooper(); } IBinder service; String token; UserService.setTag(TAG); Pair<IBinder, String> result = UserService.create(args); if (result == null) { System.exit(1); return; } service = result.first; token = result.second; if (!sendBinder(service, token)) { System.exit(1); } Looper.loop(); System.exit(0); Log.i(TAG, "service exited"); }
-
- 反射构造客户端service
-
public static Pair<IBinder, String> create(String[] args) { String name = null; String token = null; String pkg = null; String cls = null; int uid = -1; for (String arg : args) { if (arg.startsWith("--debug-name=")) { name = arg.substring(13); } else if (arg.startsWith("--token=")) { token = arg.substring(8); } else if (arg.startsWith("--package=")) { pkg = arg.substring(10); } else if (arg.startsWith("--class=")) { cls = arg.substring(8); } else if (arg.startsWith("--uid=")) { uid = Integer.parseInt(arg.substring(6)); } } int userId = uid / 100000; Log.i(TAG, String.format("starting service %s/%s...", pkg, cls)); IBinder service; try { Context systemContext = ActivityThread.systemMain().getSystemContext(); DdmHandleAppName.setAppName(name != null ? name : pkg + ":user_service", 0); //noinspection InstantiationOfUtilityClass UserHandle userHandle = Refine.unsafeCast( Build.VERSION.SDK_INT >= Build.VERSION_CODES.N ? UserHandleHidden.of(userId) : new UserHandleHidden(userId)); Context context = Refine.<ContextHidden>unsafeCast(systemContext).createPackageContextAsUser(pkg, Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY, userHandle); ClassLoader classLoader = context.getClassLoader(); Class<?> serviceClass = classLoader.loadClass(cls); Constructor<?> constructorWithContext = null; try { constructorWithContext = serviceClass.getConstructor(Context.class); } catch (NoSuchMethodException | SecurityException ignored) { } if (constructorWithContext != null) { service = (IBinder) constructorWithContext.newInstance(context); } else { service = (IBinder) serviceClass.newInstance(); } } catch (Throwable tr) { Log.w(TAG, String.format("unable to start service %s/%s...", pkg, cls), tr); return null; } return new Pair<>(service, token); }
-
- 发送客户端service 到Shizuku Apk的 ShizukuManagerProvider
-
private static boolean sendBinder(IBinder binder, String token, boolean retry) { String packageName = "moe.shizuku.privileged.api"; String name = packageName + ".shizuku"; int userId = 0; IContentProvider provider = null; try { provider = ActivityManagerApis.getContentProviderExternal(name, userId, null, name); if (provider == null) { Log.e(TAG, String.format("provider is null %s %d", name, userId)); return false; } if (!provider.asBinder().pingBinder()) { Log.e(TAG, String.format("provider is dead %s %d", name, userId)); if (retry) { // For unknown reason, sometimes this could happens // Kill Shizuku app and try again could work ActivityManagerApis.forceStopPackageNoThrow(packageName, userId); Log.e(TAG, String.format("kill %s in user %d and try again", packageName, userId)); Thread.sleep(1000); return sendBinder(binder, token, false); } return false; } if (!retry) { Log.e(TAG, "retry works"); } Bundle extra = new Bundle(); extra.putParcelable(EXTRA_BINDER, new BinderContainer(binder)); extra.putString(ShizukuApiConstants.USER_SERVICE_ARG_TOKEN, token); Bundle reply = IContentProviderCompat.call(provider, null, null, name, "sendUserService", null, extra); if (reply != null) { reply.setClassLoader(BinderContainer.class.getClassLoader()); Log.i(TAG, String.format("send binder to %s in user %d", packageName, userId)); BinderContainer container = reply.getParcelable(EXTRA_BINDER); if (container != null && container.binder != null && container.binder.pingBinder()) { shizukuBinder = container.binder; shizukuBinder.linkToDeath(() -> { Log.i(TAG, "exiting..."); System.exit(0); }, 0); return true; } else { Log.w(TAG, "server binder not received"); } } return false; } catch (Throwable tr) { Log.e(TAG, String.format("failed send binder to %s in user %d", packageName, userId), tr); return false; } finally { if (provider != null) { try { ActivityManagerApis.removeContentProviderExternal(name, null); } catch (Throwable tr) { Log.w(TAG, "removeContentProviderExternal", tr); } } } }
-
- Shizuku Apk的 ShizukuManagerProvider 将 应用客户端的binder 继续发送给shizuku_server进程中的ShizukuServer,并且CDL 等待返回,将返回结果返回;
-
Shizuku.attachUserService(binder, bundleOf( USER_SERVICE_ARG_TOKEN to token))
-
override fun call(method: String, arg: String?, extras: Bundle?): Bundle? { if (extras == null) return null return if (method == METHOD_SEND_USER_SERVICE) { try { extras.classLoader = BinderContainer::class.java.classLoader val token = extras.getString(USER_SERVICE_ARG_TOKEN) ?: return null val binder = extras.getParcelable<BinderContainer>(EXTRA_BINDER)?.binder ?: return null val countDownLatch = CountDownLatch(1) var reply: Bundle? = Bundle() val listener = object : Shizuku.OnBinderReceivedListener { override fun onBinderReceived() { try { Shizuku.attachUserService(binder, bundleOf( USER_SERVICE_ARG_TOKEN to token )) reply!!.putParcelable(EXTRA_BINDER, BinderContainer(Shizuku.getBinder())) } catch (e: Throwable) { LOGGER.e(e, "attachUserService $token") reply = null } Shizuku.removeBinderReceivedListener(this) countDownLatch.countDown() } } Shizuku.addBinderReceivedListenerSticky(listener, workerHandler) return try { countDownLatch.await(5, TimeUnit.SECONDS) reply } catch (e: TimeoutException) { LOGGER.e(e, "Binder not received in 5s") null } } catch (e: Throwable) { LOGGER.e(e, "sendUserService") null } } else { super.call(method, arg, extras) } }
-
- ShizukuServer 通知客户端建立链接
-
public void broadcastBinderReceived() { LOGGER.v("Broadcast binder received for service record %s", token); int count = callbacks.beginBroadcast(); for (int i = 0; i < count; i++) { try { callbacks.getBroadcastItem(i).connected(service); } catch (Throwable e) { LOGGER.w("Failed to call connected %s", token); } } callbacks.finishBroadcast(); }
-
- 客户端拿到 packageName:service 对应的binder
-
override fun onServiceConnected(name: ComponentName?, service: IBinder?) { if (service?.pingBinder() == true) { log(TAG, "onServiceConnected success") mUserService = IUserService.Stub.asInterface(service) } else { log(TAG, "onServiceConnected pingBinder is false") } } }
-
-
补充
-
包装成 ShizukuServiceConnection 发送给shizukuService
-
class ShizukuServiceConnection extends IShizukuServiceConnection.Stub
-
通过
newRecord.callbacks.register(conn);
-
RemoteCallbackList
RemoteCallbackList 是一个类似于列表的数据结构,它用于存储回调接口对象。每个回调接口对象都有一个唯一的 Binder 标识符,可以用来在不同进程之间进行传递和跟踪。RemoteCallbackList 的主要功能是提供了一组安全的 API,使得客户端可以注册、注销和通知回调接口对象,同时还提供了一些线程安全的方法,保证了并发操作的正确性。
-
RemoteCallbackList 的使用
在使用 RemoteCallbackList 时,我们通常需要实现一个 Binder 服务或者一个 AIDL 接口,并在其中创建一个 RemoteCallbackList 对象。这个对象会被用来存储客户端注册的回调接口对象。
-
register(T callback):注册一个回调接口对象。
-
unregister(T callback):注销一个回调接口对象。
-
beginBroadcast():开始通知客户端,返回客户端数量。
-
getBroadcastItem(int index):获取指定位置的回调接口对象。
-
finishBroadcast():通知客户端结束。
-
-
-
-
问题:
-
- 新进程中的context 如何构建创造
-
- hidden api的实现原理
-