当前位置: 首页 > news >正文

营销的本质百度快速seo

营销的本质,百度快速seo,建设集团简介,网络营销策划案例一、Android 普通app获取root用户权限的原理 Android 普通程序执行su#xff0c;可以获取root权限。 该过程原理如下#xff1a; 1.1、手机环境要求#xff1a;手机已root 首先#xff0c;该手机已root。这意味着#xff0c;手机持有者已经完成了以下3步操作#xff1a; …一、Android 普通app获取root用户权限的原理 Android 普通程序执行su可以获取root权限。 该过程原理如下 1.1、手机环境要求手机已root 首先该手机已root。这意味着手机持有者已经完成了以下3步操作 1保证该手机的/system/bin/下面有su可执行文件 cp /data/local/tmp/su /system/bin/ #copy su 到/system/分区 2保证su的所有者是root用户 chown root:root su #su的所有者置成root 3保证su的权限位为4775即非root用户对su有执行权限且su文件有SUID权限位rws的s chmod 4775 /system/bin/su #把su置成-rwsrwxr-x rws的s保证了运行su的进程的EUID在运行su期间变成了su的所有者的UID。 Linux内核为每个进程维护的三个对应的UID值RUID、EUID、SUID。 每个值是某个用户的UID。 Linux中UID用于标识一个用户例如alicebobroot Android中UID用于标识一个应用程序 关于进程的EUID详情参考https://blog.csdn.net/qq_39441603/article/details/125013758 这里插入一个小问题 第一条命令cp /data/local/tmp/su /system/bin/直观上的作用是把su文件放到环境变量中这样shell在任意路径下执行命令su都能成功。 那么这个copy su文件的过程是必须的吗如果我不想copy我直接在/data下放置su文件并完成第2、3条命令需要su时直接在/data下执行可以吗不可以 因为/data分区在被mount时就被规定其中的可执行文件不能有SUID权限 如果非要这么搞需要重新挂载一次data分区 mount -o rw,seclabel,suid,nodev,noatime,background_gcon,discard,user_xattr,inline_xattr,acl,inline_data,inline_dentry,extent_cache,inline_encrypt,active_logs6,remount -t f2fs /data 详情见https://www.cnblogs.com/cqufengchao/p/6747167.html 1.2、app发起一个shell进程 app执行su命令在java层通常的实现方式是 process Runtime.getRuntime().exec(su); 这里的Runtime.getRuntime().exec底层原理是发起一个shell进程去执行su命令。 注意这里的shell进程很关键。后面将su源代码时会涉及这个。 su命令就是执行su文件。 1.3、shell进程运行su文件 一个进程有三个对应的UIDRUIDEUIDSUID 详情参考https://blog.csdn.net/qq_39441603/article/details/125013758 由于su文件的权限位中有rws所以运行su的进程的EUID在运行su期间变成了su的所有者的UID。 而上文已述su的所有者是root用户所以运行su的进程的EUID在运行su期间变成了root用户的UID。 需要特别注意的是当shell进程开始运行su的时候shell进程的EUID就已经是root用户的UID了。换言之此时的shell进程已经拥有root用户权限了。 但是这种EUID变为root用户UID的情况是有时效性的在su文件运行完毕后就失效了。 而之所以运行过一次su文件进程就能持久性地获得root用户权限归功于su文件的内容。 其实只要shell进程运行的是一个owner是root用户且权限位为4775的可执行文件shell进程都能获取到短暂的root用户权限。之所以必须要运行su文件而不是其他文件就是因为su文件中的代码能赋予shell进程持久性的root用户权限。 1.4、su中代码赋予shell进程持久性的root用户权限 这里需要解读su源代码。 这里对su源码的关键内容解释如下 1su检查当前进程的RUID发现其等于AID_SHELL故允许继续执行 AID_SHELL也就是Shell用户的UID su会检查当前进程的RUID只有当其是Root用户的UID或Shell用户的UID时才允许继续执行。 uid_t current_uid getuid(); //返回当前进程的RUID if (current_uid ! AID_ROOT current_uid ! AID_SHELL) error(1, 0, not allowed); 对于app发起的shell进程而言其RUID并不因su文件的rws权限位而变化rws权限位只影响进程的EUID所以shell进程的RUID仍是shell用户的UID而不是root用户的UID。 所以对于app发起的shell进程而言这里能执行下去是因为current_uid等于AID_SHELL而不是current_uid等于AID_ROOT。 2su检查参数列表发现无参数故默认切换当前进程到root用户状态 su是Switch User的简写用于各种用户切换并不只用于切换到root用户状态。 根据su的源码当su不加任何参数时默认切换当前进程到uid 0且gid 0的状态也就是root用户状态。 int main(int argc, char** argv) { ……// The default user is root.// 无参数时默认切换到rootuid_t uid 0;gid_t gid 0;……// If there are any arguments, the first argument is the uid/gid/supplementary groups.// 有参数时切换到参数argv指定的用户状态if (*argv) {……// 从argv中提取内容放入uid, gid, gids覆盖之前uid和gid的默认值extract_uidgids(*argv, uid, gid, gids, gids_count);……argv;}…… }3su调用setuid函数将当前shell进程的RUID设置为root用户进程的UID // 根据参数或缺省默认值设置当前进程的gid和uid if (setgid(gid)) error(1, errno, setgid failed); if (setuid(uid)) // 由于当前shell进程的EUID为AID_ROOT// 所以这里的setuid(uid)会按照setuid的情况(1)// 将当前shell进程的RUIDEUID和SUID均设置为uiderror(1, errno, setuid failed);这就是为什么su程序能让shell进程持久性地切换到root用户UID。 关于setuid函数参考https://blog.csdn.net/qq_39441603/article/details/125013758 概括而言 su文件的rws权限位让当前的shell进程的EUID成为了su所有者Root用户的UID也就是AID_ROOT也就是0 所以这里的setuid(uid)会按照setuid的情况1将当前进程的RUIDEUID和SUID都设置为uid并返回0。由于无参数所以这里的uid是缺省值AID_ROOT。 如果当前的shell进程的EUID!AID_ROOT则属于情况2当进程的SUIDAID_ROOT时或情况3当进程的SUID!AID_ROOT时则setuid(uid)至多只影响当前shell进程的EUID而不影响其RUID和SUID 之后shell进程会继续执行完su程序。su程序执行完毕后shell进程的RUIDEUID和SUID均为AID_ROOT意味着shell进程获得了持久性的Root用户权限。 二、su源码完整解读 下面给出su程序源码的完整解读。 部分参考https://zhuanlan.zhihu.com/p/47661378 2.1 Android版本 以android-12.0.0_r3为例 源码参考http://aospxref.com/android-12.0.0_r3/ 2.2 su 二进制源码位置 su二进制文件一般在/system/bin 目录或/system/xbin 目录 编译安卓系统源代码时编译好的su二进制文件在/out/target/product/vendor/system/xbin中 但system.img镜像文件中没有su二进制文件。 su的源代码在/system/extras/su 目录下 http://aospxref.com/android-12.0.0_r3/xref/system/extras/su/ 2.3 su 源码分析带注释 Android.mk LOCAL_PATH: $(call my-dir) include $(CLEAR_VARS)LOCAL_CFLAGS : -Wall -WerrorLOCAL_SRC_FILES: su.cppLOCAL_MODULE: su LOCAL_LICENSE_KINDS: SPDX-license-identifier-Apache-2.0 LOCAL_LICENSE_CONDITIONS: notice LOCAL_NOTICE_FILE: $(LOCAL_PATH)/NOTICELOCAL_HEADER_LIBRARIES : libcutils_headersLOCAL_MODULE_PATH : $(TARGET_OUT_OPTIONAL_EXECUTABLES)include $(BUILD_EXECUTABLE) su.cpp源码 #include errno.h #include error.h #include getopt.h #include paths.h #include pwd.h #include stdio.h #include stdlib.h #include string.h #include unistd.h#include private/android_filesystem_config.h// 根据用户名获取uid和gid void pwtoid(const char* tok, uid_t* uid, gid_t* gid) {// 根据用户名获取用户登录信息struct passwd* pw getpwnam(tok);if (pw) {if (uid) *uid pw-pw_uid;if (gid) *gid pw-pw_gid;} else {char* end;errno 0;uid_t tmpid strtoul(tok, end, 10);if (errno ! 0 || end tok) error(1, errno, invalid uid/gid %s, tok);if (uid) *uid tmpid;if (gid) *gid tmpid;} }// 调用pwtoid根据用户名获取uid和gid // arg1: main的argv[0]逗号分隔 void extract_uidgids(const char* uidgids, uid_t* uid, gid_t* gid, gid_t* gids, int* gids_count) {char *clobberablegids;char *nexttok;char *tok;int gids_found;if (!uidgids || !*uidgids) {*gid *uid 0;*gids_count 0;return;}clobberablegids strdup(uidgids);strcpy(clobberablegids, uidgids);nexttok clobberablegids;tok strsep(nexttok, ,);pwtoid(tok, uid, gid);tok strsep(nexttok, ,);if (!tok) {/* gid is already set above */*gids_count 0;free(clobberablegids);return;}pwtoid(tok, NULL, gid);gids_found 0;while ((gids_found *gids_count) (tok strsep(nexttok, ,))) {pwtoid(tok, NULL, gids);gids_found;gids;}if (nexttok gids_found *gids_count) {fprintf(stderr, too many group ids\n);}*gids_count gids_found;free(clobberablegids); }// su的用法 // su [WHO [COMMAND...]] // WHO要切换到的用户默认为root逗号分隔 // COMMAND切换到WHO之后要执行的命令 int main(int argc, char** argv) {uid_t current_uid getuid(); //返回当前进程的RUID// 当前进程的RUID必须是root用户UID 或shell用户UID// 关于shell用户// 安卓app 获取shell权限时通常使用// Process p Runtime.getRuntime().exec(su);// 这里的Runtime.getRuntime().exec// 底层原理是调用操作系统接口新建一个shell进程异步执行命令if (current_uid ! AID_ROOT current_uid ! AID_SHELL) error(1, 0, not allowed);// Handle -h and --help.argv;if (*argv (strcmp(*argv, --help) 0 || strcmp(*argv, -h) 0)) {fprintf(stderr,usage: su [WHO [COMMAND...]]\n\nSwitch to WHO (default root) and run the given COMMAND (default sh).\n\nWHO is a comma-separated list of user, group, and supplementary groups\nin that order.\n\n);return 0;}// The default user is root.// 无参数时默认切换到rootuid_t uid 0;gid_t gid 0;// su的核心部分由setgroups、setgid、setuid完成设置当前进程的附加组、gid和uid// If there are any arguments, the first argument is the uid/gid/supplementary groups.// 有参数时切换到参数argv指定的用户状态if (*argv) {gid_t gids[10];int gids_count sizeof(gids)/sizeof(gids[0]);// 从argv中提取内容放入uid, gid, gids覆盖之前uid和gid的默认值extract_uidgids(*argv, uid, gid, gids, gids_count);// 根据参数 设置当前进程的附加组if (gids_count) {// int setgroups(size_t size, const gid_t * list);// setgroups()用来 将 当前进程的附加组 设置为 参数2 list数组中所标明的group// setgroups()参数1 size 为list数组的gid_t 数目, 最大值为NGROUP(32)if (setgroups(gids_count, gids)) {error(1, errno, setgroups failed);}}argv;}// 根据参数或缺省默认值设置当前进程的gid和uidif (setgid(gid)) error(1, errno, setgid failed);if (setuid(uid)) // 由于当前shell进程的EUID为AID_ROOT// 所以这里的setuid(uid)会按照setuid的情况(1)// 将当前shell进程的RUIDEUID和SUID均设置为uid// 否则按照情况(2)或情况(3)至多只影响当前进程的EUIDerror(1, errno, setuid failed);// Reset parts of the environment.setenv(PATH, _PATH_DEFPATH, 1);unsetenv(IFS);struct passwd* pw getpwuid(uid);if (pw) {setenv(LOGNAME, pw-pw_name, 1);setenv(USER, pw-pw_name, 1);} else {unsetenv(LOGNAME);unsetenv(USER);}// Set up the arguments for exec.char* exec_args[argc 1]; // Having too much space is fine.size_t i 0;for (; *argv ! NULL; i) {exec_args[i] *argv;}// Default to the standard shell.if (i 0) exec_args[i] const_castchar*(/system/bin/sh);exec_args[i] NULL;execvp(exec_args[0], exec_args);error(1, errno, failed to exec %s, exec_args[0]); } 关于Supplementary group附加组 参见https://blog.csdn.net/qq_39441603/article/details/125010004 三、su daemon 模式 上述方案的核心是在 $PATH 环境变量(例如/system/bin:/system/xbin:/sbin:/vendor/bin:/vendor/xbin)下放置su可执行文件并给su文件以suid权限。 然而从Android 4.3开始很多分区例如/system 和 /data在一开始挂载时就被设置为nosuid因此上述方案自然行不通。 如果直接观察 su 文件的权限也是正常的0755权限并没有suid位 所以一个可行的方案是在设备启动时由init进程开启一个su daemon 守护进程当有程序调用su时就作为client与这个server通信由远程的server完成所有操作。由于init进程具有天然的root权限由它 fork 出的su daemon自然也是root身份这就实现了提权。 参考《Android su提权的简单实现》 https://www.jianshu.com/p/6bc251ee9026 四、Android系统对app进程root权限的进一步限制 1在 Android 4.3 之前app进程 可以直接借助 有SUID标志位的su二进制文件 来获取root用户权限。 2Android 4.3之后app进程基于SUID获取root权限的方案被禁用。主要措施是 /system 和 /data 分区以 nosuid option被挂载让文件的SUID标识失效。app进程是由zygote 进程 fork产生的。zygote进程设置了NO_NEW_PRIVS标志父进程的NO_NEW_PRIVS位会在父进程fork、clone和execve时被子进程继承 并且不能被撤销。NO_NEW_PRIVS标志会让当前进程在执行可执行文件时进程的EUID和EGID不受可执行文件的SUID和SGID位影响。 关于zygote进程fork出app进程的过程 参考https://www.toutiao.com/article/6777894692462789124/ Android 4.3之后/system 分区也被以 nosuid option被挂载 那么系统进程如何获取root权限呢 app进程是否可以使用同样的方式呢 3系统进程改用 Capability来获取root权限但app进程不行。 系统daemon可通过可执行文件的capability来获取进程的cap_effective 但app进程不能这样做因为app进程是由zygote 进程fork出来的而zygote进程设置了NO_NEW_PRIVS标志使得app进程无法通过可执行文件的capability来获取cap_effective。 P’(ambient) (file is privileged) ? 0 : P(ambient) P’(permitted) (P(inheritable) F(inheritable)) | (F(permitted) P(bounding))) | P’(ambient) P’(effective) F(effective) ? P’(permitted) : P’(ambient) 也就是 P’(effective) F(effective) ? ( (P(inheritable) F(inheritable)) | (F(permitted) P(bounding))) | ( (file is privileged) ? 0 : P(ambient) ) ) : ( (file is privileged) ? 0 : P(ambient) ) NO_NEW_PRIVS标志会使SUID和SGID位无法改变进程的 uid 或 gidfile capability也不会被添加到进程的capability中。也就是NO_NEW_PRIVS标志会使获取root权限的 SUID方案和file capability方案 失效。 参考https://www.kernel.org/doc/html/latest/translations/zh_CN/userspace-api/no_new_privs.html 4对app进程切换EUID的其他限制 仅当进程的cap_bset数组中有 SETUID/SETGID capability时进程才能切换 UID。而从Android 4.4开始zygote fork app进程时会对所有fork出来的子进程进行CAPBSET_DROP动作让子进程不具有任何capability。从Android Oreo开始OS通过SECCOMP过滤器阻止某些SYSCALLapp进程更改UID/GID的能力被进一步抑制。 5SELinux带来的约束 即使一个进程的euid变成了0或者拥有了所有capability 它也必须受到SELinux策略的约束。 也就是SELinux机制进一步约束了root权限进程的行为。 五、Android设备 具体root方案 前文已述一个shell进程要想获得root权限需要执行下列代码 cp /data/local/tmp/su /system/bin/ #copy su 到/system/分区 chown root:root su #su的所有者置成root chmod 4775 /system/bin/su #把su置成-rwsr-xr-x 但问题是上面的每一行代码都需要root用户权限才能执行。 而上述代码本身就是用于获取root用户权限的。所以再执行上述代码之前普通app发起的进程是无法获取root用户权限的。 那么这个逻辑闭环如何打破呢这就需要root技术。 5.1 使用提权漏洞 一个办法是找一个本身有root权限的进程来执行上述代码。这样普通app执行process Runtime.getRuntime().exec(su);就能获得root权限了。 但是有root权限的进程都是预装app发起的代码写死了普通app没法控制它去执行特定的代码。 这个时候就需要用提权漏洞来root手机。比如zergRush漏洞就利用了一个拥有root权限的进程的栈溢出漏洞。 5.2 修改ROM并刷机 1BootLoader 引导加载程序BootLoader是系统启动时自动运行的一个底层程序。 程序的主要目的是初始化硬件然后找到并启动主操作系统。 Android bootloader一般是锁定的,也就仅仅允许启动或安装一个被OEM签名的操作系统img。 2Fastboot Fastboot是一种手机状态的名称也是一个协议的名称。 当手机处于快速启动模式Fastboot模式时若PC与手机通过USB连接则两者可通过Fastboot协议进行通信。 具体而言PC上的fastboot命令行工具通过USB bulk与手机上的USB Client通信。 PC上的fastboot命令行工具位于Android SDK中 手机上的USB ClientBootloader Fastboot最初的作用是向BootLoader发送分区镜像来将镜像写入到特定的设备分区中实现分区清除或者覆盖以方便Android系统移植device bring-up和设备恢复出厂设置。 但是现在Fastboot多被用于解锁Bootloader。 3Recovery 功能相当于PC中的PE。 用于存放Recovery恢复模式的分区里面有一套Linux Kernel但并不是安卓系统里的那个Linux Kernel。 分为原生Recovery和定制Recovery例如TWRP提供的Recovery。 4Boot 启动顺序在bootloader之后与recovery同级。 用于存放安卓系统的Linux Kernel相关内容。 可以参考 https://blog.csdn.net/fmc088/article/details/90376116 5.2.1 Magisk patch boot.imgfastboot 刷入 patched boot.img线刷 整体思路 用Magisk app 对 ROM的boot.img进行patch并将patched boot.img存放至PC 手机重启进入Fastboot 使用PC上Fastboot工具通过数据线将patched boot.img刷入手机。 可以参见 https://blog.csdn.net/qq_39441603/article/details/124679514 1解BootLoader锁 未解锁的BootLoader不允许刷入非官方签名过的img镜像包括Recovery.imgBoot.img等 解锁之后就可以通过PC上的fastboot程序刷入Magisk patch过的boot.img 2Magisk对boot.img进行patch 获取到当前OS的线刷包的boot.img后使用Magisk app对boot.img进行patch。 线刷包通常是tgz格式例如https://xiaomirom.com/download/mi-8-dipper-weekly-9.8.22/#china-fastboot。 Magisk对boot.img进行patch的过程Magisk通过对boot.img的patch在boot启动阶段创建钩子把/data/magisk.img挂载到/magisk构建出一个在 system 基础上能够自定义替换增加以及删除的文件系统。 所有操作都在启动时完成实际上并不修改/system(即所谓systemless方案以不触动 /system 的方式修改 /system)。/magisk相当于android系统的另一个独立分区。 3fastboot 刷入 patched boot.img 重启进入fastboot并使用PC上的Fastboot命令行工具通过USB bulk基于fastboot协议与手机上的USB Client通信刷入 patched boot.img adb reboot bootloader fastboot flash boot magisk_patched-22100_LMHbQ.img fastboot reboot 5.2.2 TWRP刷入第三方Recovery Magisk.zip 详细过程可参考 使用ADB Sideload方案https://miuiver.com/install-magisk-via-twrp/ 格式化整个Data分区方案https://forum.butian.net/share/1068 1解BootLoader锁 2刷入定制Recovery 定制Recovery可从TWRP项目中获得 直接启动定制Recoveryfastboot boot custom-recovery.img 将定制Recovery永久写入设备fastboot flash custom-recovery.img 将定制Recovery永久写入设备并启动fastboot flash boot custom-recovery.img 3借助定制Recovery刷入Magisk.zip 从界面中的Log来看好像是在这个Magisk.zip的刷入过程中Magisk会去patch boot.img 使用ADB Sideload 格式化整个Data分区 线刷和卡刷区别主要在于 线刷没动Recovery在Fastboot模式下手刷入Magisk app提前patch好的boot.img 卡刷动了Recovery在Recovery模式下手通过customized Recovery来修改boot.img。 六、Magisk原理 参考https://www.zhihu.com/question/278585502 Magisk的原理大致是通过修改boot分区使得手机在启动时systemless中的文件先作为系统文件加载然后才加载真正的系统达到了不修改system分区而实现修改的效果。 比如修改机型或是字体只需要安装并启用相应的模块模块存放在systemless里面就会在手机启动时生效又因为system分区本身并没有被修改只需要禁用模块就可以还原无需备份原有的配置 而root也就是把root相关的一些文件放在systemless里取代掉手机系统原本的su文件SuperSU就是直接修改system里的su文件而magisk是把su放在systemless中手机启动时取代系统原有su Magisk通过启动时在 boot 中创建钩子把 /data/magisk.img 挂载到 /magisk在 system 基础上构建出了一个能够自定义替换、增加以及删除的文件系统。所有操作都在启动的时候完成实际上并没有对 /system 分区进行修改即 systemless方案以不触动 /system 的方式修改 /system。 转自【Android安全】Android root原理及方案 | Magisk原理-CSDN博客
http://www.laogonggong.com/news/136490.html

相关文章:

  • 销售类网站开发wordpress docx插件
  • 网站升级建设招标公告四川网站建设哪家好
  • 网站建设网络推广方案建筑网片钢筋网片
  • 网站开发的环境信息发布类网站模板
  • 做系统进化树的网站开发jsp网站
  • 黑河企业网站建设公司苏州手机关键词优化
  • 网站开发项目经验描述宁波网站设计
  • 北京网站制作招聘网站的seo是什么意思
  • 网站开发项目怎么接闸北做网站公司
  • 静态网页模板 网站模板做电影采集网站需要多大vps
  • 合肥市重点工程建设管理局网站网站原文件怎么上传空间
  • 辅助教学网站开发技术讨论采购管理软件免费版
  • pc 移动端网站建设中学网站模板
  • 网站建设的违约责任怎么写美味的树莓派wordpress
  • 如何给自己做的网站加上域名阿里云快速做网站
  • 南宁网站制作超薄网络成都大型网站建设
  • 均安建网站wordpress多个函数文件路径
  • 建设网站职业证书查询联合智慧旅游建设旅游门户网站
  • 南京做网站的有哪些本地企业网站建设模板
  • 加强主流网站建设阿里云营销网站建设
  • 网站建设 视频教程wordpress能制作视频网站吗
  • 网站建设 豫icp备为什么要网站建设
  • 如何用 python 做网站公众号开发公司排行榜
  • 免费网站建设有哪些策划案
  • 网站设计软件有哪些新闻头条最新消息摘抄
  • 福鼎网站建设培训注册一个公司大概要多少钱
  • 鞍山手机网站设计wordpress 3.8.2
  • 百度收录网站需要多久茶艺馆网站
  • 抚顺市+网站建设广网站建设
  • phpcms 做购物网站湖南建设人力资源网站