diff --git a/README.md b/README.md index 826a45e..7e487ab 100644 --- a/README.md +++ b/README.md @@ -2,23 +2,22 @@ ## 0 前言 - 最近有了个需求:免 root 实现任意位置点击和静默安装。这个做过的小伙伴应该都知道正常情况下是不可能实现的。无障碍只能实现对已知控件的点击,并不能指定坐标。但是确实有人另辟蹊径做出来了,譬如做游戏手柄的飞智,他们是用一个激活器,手机开 usb 调试,然后插在激活器上并授权,飞智游戏厅就被「激活」了,然后可以实现任意位置点击。如果不了解的可以去他们官网了解下,在这里不多赘述了。无独有偶,黑域也使用了类似的手段,也可以用电脑的usb调试激活。我们知道,任意位置坐标xy点击是可以在 pc 上通过 shell 命令「input tap x y」来实现的,也不需要 root 权限。但是在应用内通过「Runtime.getRuntime().exec」执行这个 shell 命令却提示「permission denied」也就是权限不足。但是飞智或者黑域却好像使用了某种魔法,提升了自己的权限,那么问题来了:如何用 usb 调试给 app 提权? +最近有了个需求:免 root 实现任意位置点击和静默安装。这个做过的小伙伴应该都知道正常情况下是不可能实现的。无障碍只能实现对已知控件的点击,并不能指定坐标。但是确实有人另辟蹊径做出来了,譬如做游戏手柄的飞智,他们是用一个激活器,手机开 usb 调试,然后插在激活器上并授权,飞智游戏厅就被「激活」了,然后可以实现任意位置点击。如果不了解的可以去他们官网了解下,在这里不多赘述了。无独有偶,黑域也使用了类似的手段,也可以用电脑的usb调试激活。我们知道,任意位置坐标xy点击是可以在 pc 上通过 shell 命令「input tap x y」来实现的,也不需要 root 权限。但是在应用内通过「Runtime.getRuntime().exec」执行这个 shell 命令却提示「permission denied」也就是权限不足。但是飞智或者黑域却好像使用了某种魔法,提升了自己的权限,那么问题来了:如何用 usb 调试给 app 提权? ## 1 原理揭晓 - 「如何用 usb 调试给 app 提权」这个问题乍一看确实没问题,但是知乎有个回答是「先问是不是,再问为什么」我觉得说的很好。我被这个问题给困扰了很久,最后发现我问错了。先放出结论「并不是给 app 提权,而是运行了一个由设立了权限的新程序」 - - 刚才的问题先放一边,我来问大家个新问题,怎样让 app 获取 root 权限?这个问题答案已经有不少了,网上一查便可知其实是获取「Runtime.getRuntime().exec」的流,在里面用su提权,然后就可以执行需要 root 权限的 shell 命令,比如挂载 system 读写,访问 data 分区,用 shell 命令静默安装,等等。话说回来,是不是和我们今天的主题有点像,如何使 app 获取 shell 权限?嗯,其实差不多,思路也类似,因为本来 root 啦, shell 啦,根本就不是 Android 应用层的名词呀,他们本来就是 Linux 里的名词,只不过是 Android 框架运行于 Linux 层之上, 我们可以调用 shell 命令,也可以在shell 里调用 su 来使shell 获取 root 权限,来绕过 Android 层做一些被限制的事。然而在 app 里调用 shell 命令,其进程还是 app 的,权限还是受限。所以就不能在 app 里运行 shell 命令,那么问题来了,不在 app 里运行在哪运行?答案是在 pc 上运行。当然不可能是 pc 一直连着手机啦,而是 pc 上在 shell 里运行独立的一个 java 程序,这个程序因为是在 shell 里启动的,所以具有 shell 权限。我们想一下,这个 Java 程序在 shell 里运行,建立本地 socket 服务器,和 app 通信,远程执行 app 下发的代码。因为即使拔掉了数据线,这个 Java 程序也不会停止,只要不重启他就一直活着,执行我们的命令,这不就是看起来 app 有了 shell 权限?现在真相大白,飞智和黑域用 usb 调试激活的那一下,其实是启动那个 Java 程序,飞智是执行模拟按键,黑域是监听系统事件,你想干啥就任你开发了。「注:黑域和飞智由于进程管理的需要,其实是先用 shell 启动一个 so ,然后再用 so 做跳板启动 Java 程序,而且 so 也充当守护进程,当 Java 意外停止可以重新启动,读着有兴趣可以自行研究,在此不多做说明」 +「如何用 usb 调试给 app 提权」这个问题乍一看确实没问题,但是知乎有个回答是「先问是不是,再问为什么」我觉得说的很好。我被这个问题给困扰了很久,最后发现我问错了。先放出结论「并不是给 app 提权,而是运行了一个由设立了权限的新程序」 +刚才的问题先放一边,我来问大家个新问题,怎样让 app 获取 root 权限?这个问题答案已经有不少了,网上一查便可知其实是获取「Runtime.getRuntime().exec」的流,在里面用su提权,然后就可以执行需要 root 权限的 shell 命令,比如挂载 system 读写,访问 data 分区,用 shell 命令静默安装,等等。话说回来,是不是和我们今天的主题有点像,如何使 app 获取 shell 权限?嗯,其实差不多,思路也类似,因为本来 root 啦, shell 啦,根本就不是 Android 应用层的名词呀,他们本来就是 Linux 里的名词,只不过是 Android 框架运行于 Linux 层之上, 我们可以调用 shell 命令,也可以在shell 里调用 su 来使shell 获取 root 权限,来绕过 Android 层做一些被限制的事。然而在 app 里调用 shell 命令,其进程还是 app 的,权限还是受限。所以就不能在 app 里运行 shell 命令,那么问题来了,不在 app 里运行在哪运行?答案是在 pc 上运行。当然不可能是 pc 一直连着手机啦,而是 pc 上在 shell 里运行独立的一个 java 程序,这个程序因为是在 shell 里启动的,所以具有 shell 权限。我们想一下,这个 Java 程序在 shell 里运行,建立本地 socket 服务器,和 app 通信,远程执行 app 下发的代码。因为即使拔掉了数据线,这个 Java 程序也不会停止,只要不重启他就一直活着,执行我们的命令,这不就是看起来 app 有了 shell 权限?现在真相大白,飞智和黑域用 usb 调试激活的那一下,其实是启动那个 Java 程序,飞智是执行模拟按键,黑域是监听系统事件,你想干啥就任你开发了。「注:黑域和飞智由于进程管理的需要,其实是先用 shell 启动一个 so ,然后再用 so 做跳板启动 Java 程序,而且 so 也充当守护进程,当 Java 意外停止可以重新启动,读着有兴趣可以自行研究,在此不多做说明」 ## 2 好耶!是 app_process - 那么如何具体用 shell 运行 Java 程序呢?肯定不是「java xxx.jar」啦,Android 能运行的格式是 dex 。没错,就是apk 里那个 dex 。然后我们可以通过「app_process」开启动 Java 。app_process 的参数如下 +那么如何具体用 shell 运行 Java 程序呢?肯定不是「java xxx.jar」啦,Android 能运行的格式是 dex 。没错,就是apk 里那个 dex 。然后我们可以通过「app_process」开启动 Java 。app_process 的参数如下 ```shell app_process [vm-options] cmd-dir [options] start-class-name [main-options] ``` - 这个诡异又可怕的东西是没有 -help 的。我们要么看源码,要么看别人分析好的。本人水平有限,这里选择看别人分析好的: +这个诡异又可怕的东西是没有 -help 的。我们要么看源码,要么看别人分析好的。本人水平有限,这里选择看别人分析好的: ```shell vm-options – VM 选项