SMJobBless是苹果官方提供的用于“MacOS app获取root权限”的demo。
使用Security.framework和ServiceManagement.framework两个库,把需要root权限的操作封装成一个进程,作为项目的子Target,把该子进程注册LaunchdDaemon。
成为LaunchdDaemon后:
/Library/PrivilegedHelperTools
.plist
被放在/Library/LaunchDaemons
,Launchd加载该子进程会需要读取该配置文件更多介绍请见”参考资料1”
从官网下载SMJobBless源码(下面”参考资料3”也有链接),具体操作Demo里的ReadMe.txt也讲述得比较清楚,只是由于新版本Xcode的编译产物不再放在项目目录里,所以ReadMe.txt里有一些步骤的路径要做一些调整
在xcode先编译项目
用终端进入项目根目录,运行下面命令
./SMJobBlessUtil.py setreq <path-to-SMJobBlessApp.app> SMJobBlessApp/SMJobBlessApp-Info.plist SMJobBlessHelper/SMJobBlessHelper-Info.plist
其中<path-to-SMJobBlessApp.app>
可以在xcode左边的Navigator的product下的编译产物APP”右击-Show in Finder”的到编译产物的路径。
脚本运行成功后会输出
SMJobBlessApp/SMJobBlessApp-Info.plist: updated
SMJobBlessHelper/SMJobBlessHelper-Info.plist: updated
在Xcode对项目Clean,然后再Build
终端在项目根目录下执行
./SMJobBlessUtil.py check <path-to-SMJobBlessApp.app>
没有输出任何东西即说明check通过。
Run编译产物APP,会弹出输入账号密码的认证窗口,提示要”Install Helper”;输入密码后,若Xcode打印出”Job is available!”的log,已经App的UI上有”The Helper Tool is available!”,即说明Demo成功运行。
Apple官方Demo: EvenBetterAuthorizationSample
这个是SMJobBless进一步的Demo,结合Sand-box的特性。
StackOverflow: AuthorizationExecuteWithPrivileges is deprecated
StackOverflow: Writing a privileged helper tool with SMJobBless()
Jacob Pan ( jacobpan3g.github.io/cn )
在MacOS App开发中,有一些操作需要管理员权限,需要弹出认证对话框让用户输入账号和密码,这个过程就是MacOS App提权的过程,主要有下面几种方式:
使用这个接口最有代表的库是STPrivilegedTask,这是一个封装得很好得App提权库,接口与NSTask十分像,使用起来十分方便。
可惜得是AuthorizationExecuteWithPrivileges()接口在MacOS 10.7开始deprecated,据说在10.12的版本该接口就关闭了。
因此,若要兼容10.12以后的MacOS版本,就不得不放弃使用STPrivilegedTask库了。
这是Apple官方目前推荐的提权方式,官方有一个SMJobBless的Demo,是用来有点复杂,具体请见另一篇文档”SMJobBless官方Demo笔记”
该方法有一个几个小缺点:
/Library
下的,当用户把App卸载后会不会存在”残留问题”?do shell script "..." with administrator privileges
省略号部分填入shell脚本,任何可执行文件都需要写全路径,如/bin/ls
。
以上是AppleScript脚本,通过这种方式提权有以下有点:
AppleScript脚本在objective-c中有两种执行方式:
方法1有两个缺点:
do shell script
会在所有shell执行完成后再把所有stdout返回,因此当启动的是Daemon进程,就算使用NSTask的fileHandle Notification,也无法把stdout分次读取出来。
这种方法的认证窗口提示信息是”osascript wants to make changes.”,对于小白用户来说会不会有一种这样的感觉”我明明安装的是XXX.app,怎么来了一个osascript让我输入账号密码?会不会是恶意程序?”
而使用NSAppleScript方法时,认证窗口的提示信息是”APP_NAME wants to make changes.”,感觉这样的提示更加友好。但也有一些缺点:
NSAppleScript执行Daemon进程的话会直到Daemon退出才退出,即会一直占用线程
解法:建议在子线程使用NSAppleScript,以免UI无法响应
也存在stdout只能等待Daemon退出才全部打印的问题
Jacob Pan ( jacobpan3g.github.io/cn )
ps [-Aax]
-A
显示所有进程,包括GUI进程-a
显示所有终端进程,包括其它用户-x
显示所有没有控制终端的进程top
动态显示各进程的资源使用情况,ctrl-c可退出。
在mac下sed与GNU sed差别有点大,要使用后者的话需要安装。
brew install gnu-sed --with-defult-names
后面的--with-defult-names
选项是让安装后依然叫sed,不然默认是叫gsed,以与系统本来的sed做区分。
安装后还需要设置一下PATH,打开~/.bash_profile
,添加下面设置
export PATH="/usr/local/opt/gnu-sed/libexec/gnubin:$PATH"
重新打开终端即可使用gnu sed了。
右击pdf文件 - Get Info - 在Open with:选择阅读器 - 点击下面的”Change All…“按钮
sudo /Applications/Xcode/Content/MacOS/Xcode
不能以sudo open /Applications/Xcode
打开,前者编译运行后的App才是处于root权限下,不过Xcode里不能用复制粘贴。
Jacob Pan ( jacobpan3g.github.io/cn )
ADB(Android Debug Bridge)是一款很有用的调试工具,可以模拟很多用户的操作。adb一般是安装在sdk目录下的platform-tools目录内,需要把这个目录先添加到环境变量$PATH
中, 在mac下,可以下面语句添加到~/.bash_profile
中:
export PATH=${PATH}:~/Library/Android/sdk/platform-tools
当然,也可以进入这个目录后再使用adb命令。
adb shell input tap 50 100
模拟点击(50, 100)的点。不同分辨率的屏幕点的坐标会有所不同,可以通过手机里”设置” - “开发者选项” - 在”输入”栏下开启”指针位置”,就可以在手机屏幕中得知手指所在位置的坐标
adb input keyevent <keyCode>
其中<keyCode>
可以代表各种按键,如电源键,音量键,这里列出几个keyCode
3 home键
4 back键
24 增加音量
25 降低音量
26 电源键
使用adb input keyevent 25
命令就可以降低音量。
更多keyCode信息可参见adb模拟按键与输入。
adb devices
通过上面命令可以看到每个已连接设备的序列号(serial number),adb的所有命令都可以通过-s <serial number>
参数来指定某一台设备,如
adb -s XXXXXXX pull data/data/com.android.xxx/xxx ~/xxx
上述pull命令可以从设备里把文件导出到PC。
adb shell dumpsys window displays | head -n 3
Jacob Pan ( jacobpan3g.github.io/cn )
codesign -v -d XXX.app
spctl -v -a XXX.app
ps: 以上两条命令都可以对app或者命令行可执行文件进行检测,使用-vvv
替代-v
可看到更多信息。
对macOS命令好工具的工程签名,不需要制定Bundle identity(即com.xxx.xxx)和provisioning profile,只需要填写Code Signing Identity(证书)即可。
若输入了provisioning profile签名,run时会提示”error: ::posix_spawnp (…) err = Permission denied (0x0000000d)”错误
codesign -f -s "XXX" -v "XXX.app" --deep
其中-s
后面跟的时证书
下载并安装好相关证书,在Xcode里签名有以下步骤
在Navigation窗口打开项目文件Image.xcassets
,就会看到AppIcon的配置,把不同大小的八张图片拉进去,编译即可。
ps: 关于如何制作这8种不同大小的icon,下面有一小节专门说明。
在Navigation窗口点击最上面的项目名字,在PROJECT或者TARGETS栏设置Build Setting - Code Signing (ps: 前者是全局的,后者是针对单个Target的)
- 先在Provisioning选择相应的provision,provision文件也分”Mac应用商店发布”和”开发者ID发布”两种,均需要在Apple开发者账号里申请,证书安装好后会自动下载到Mac中
完成上面两步后,尝试编译项目(ps: 这里需要连接外网),若APP没有提示错误,并能成功运行,说明Debug版本签名成功
完成上面配置后,点击顶层菜单Project - Archive,在弹出的窗口先点击”Validate…“来验证一下发布APP是否签名成功,若成功会提示
Validation Successful
Your app successfully passed all validation checks.
然后点击”Export…“,选择相应路径导出即可。
Jacob Pan ( jacobpan3g.github.io/cn )
在c中,当一些函数出错时,会有相应的errno,这是一个错误码,每个错误码对应一个错误描述,对于一些文件操作,socket操作,在打印错误信息时,附上这些错误码相应的信息对调试非常有帮助,围绕errno,有下面两个接口:
#include <stdio.h>
extern int errno;
char * strerror(int errno)
void perror(const char *s)
fprintf(stderr, "%s: %s", s, strerror(errno))
errno其实是一个全局变量,在多线程环境使用时要注意,因为这个errno随时都有可能被其它线程修改。
Jacob Pan ( jacobpan3g.github.io/cn )