首页 > 解决方案 > 如何在命令行上获取 macOS 应用程序的 csreq?

问题描述

我正在维护一个 github 项目,该项目旨在自动化干净的 macOS 安装、macOS 自定义(完整的系统首选项和更多设置)以及应用程序和系统的更新。

https://github.com/tiiecherle/osx_install_config

其中一个脚本在系统首选项 - 安全 - 隐私下设置首选项。

https://github.com/tiiiecherle/osx_install_config/blob/master/11_system_and_app_preferences/11a_system_preferences_privacy_sqlite_mojave.sh

每个 macOS 应用程序都有一个 csreq,这似乎是每个应用程序的指纹/校验和。在 macOS Mojave 之前,不需要显式设置值,它正在努力用“?”替换 csreq。例如允许访问终端:

DATABASE_SYSTEM="/Library/Application Support/com.apple.TCC/TCC.db"
INPUT_SERVICE=kTCCServiceAccessibility

APP_ID=com.apple.Terminal
PERMISSION_GRANTED=1
APP_CSREQ=X'FADE0C000000003000000001000000060000000200000012636F6D2E6170706C652E5465726D696E616C000000000003'

### working, but no csreq
sudo sqlite3 "$DATABASE_SYSTEM" "REPLACE INTO access VALUES('"$INPUT_SERVICE"','"$APP_ID"',0,$PERMISSION_GRANTED,1,NULL,NULL,NULL,?,NULL,0,?);"

### working with csreq
sqlite3 "$DATABASE_USER" "REPLACE INTO access VALUES('"$INPUT_SERVICE"','"$APP_ID"',0,$PERMISSION_GRANTED,1,$APP_CSREQ,NULL,NULL,?,NULL,NULL,?);"

这仍然有效,但 macOS Mojave 引入了更多安全设置,并且为了通过命令行正确设置自动化,需要两个应用程序的 csreqs,即自动化和自动化应用程序,例如允许终端自动化系统设置:

DATABASE_USER="/Users/"$USER"/Library/Application Support/com.apple.TCC/TCC.db"
SOURCE_APP_ID=com.apple.Terminal
SOURCE_APP_CSREQ=X'FADE0C000000003000000001000000060000000200000012636F6D2E6170706C652E5465726D696E616C000000000003'
PERMISSION_GRANTED=1
AUTOMATED_APP_ID=com.apple.systemevents
AUTOMATED_APP_CSREQ=X'FADE0C000000003400000001000000060000000200000016636F6D2E6170706C652E73797374656D6576656E7473000000000003'

sqlite3 "$DATABASE_USER" "REPLACE INTO access VALUES('kTCCServiceAppleEvents','"$SOURCE_APP_ID"',0,$PERMISSION_GRANTED,1,$SOURCE_APP_CSREQ,NULL,0,'"$AUTOMATED_APP_ID"',$AUTOMATED_APP_CSREQ,NULL,?);"

如果 csreq 被替换为问号“?”,则该条目有效,但根本不会显示在系统首选项的 GUI 中。

当您在请求权限时单击允许时,系统会生成 csreq,然后可以从数据库中读取。为了通过命令行进行正确的输入,我想在命令行上从应用程序读取/生成正确的 csreq,而不是从 tcc.db 读取它,因为它似乎随着应用程序的每个版本而变化。

感谢您提前提供任何帮助

编辑

非常感谢 Keith Johnson 的非常好的解释并在很大程度上解决了这个问题。按照他的回答,我能够在我的脚本的新配置文件中实现 csreq。

https://github.com/tiiecherle/osx_install_config/blob/master/_config_file/shellscriptsrc.sh

在函数env_set_apps_security_permissionsenv_set_apps_automation_permissions.

我还不能解决的是获取使用脚本编辑器或自动机创建的未签名小程序或液滴的 csreq。

PATH_TO_APP="/Applications/brew_casks_update.app"
codesign --detached "$PATH_TO_APP".sig -s - "$PATH_TO_APP"
SOURCE_APP_CSREQ_STRING=$(codesign -d -r- --detached "$PATH_TO_APP".sig "$PATH_TO_APP")
echo "$SOURCE_APP_CSREQ_STRING" | csreq -r- -b /tmp/csreq.bin
Executable=/Applications/brew_casks_update.app/Contents/MacOS/applet error: invalid or corrupted code requirement(s) Requirement syntax error(s): line 2:1: unexpected end of file

如果我手动添加它并从数据库中读取字符串,它就有一个有效的 csreq。如果这个问题也能弄清楚,这个问题就完全解决了。那真是太好了。

谢谢

标签: bashmacossqlite

解决方案


背景

csreq blob 本身的格式并不会显得太复杂,如果你想花哨的话,在 Security.Framework 中找到的源代码可以帮助解码含义。它基本上是一个魔术头(0xFADE0C00),后跟一个 32 位长度(blob 的大小),然后是一些不同的“操作”。

值得庆幸的是,我们已经可以使用一些实用程序来操作 csreq blob,因此我们不需要深入研究它。

解码 csreq blob,并找到它的来源

让我以你上面的例子为例Terminal.app。Apple 提供了一个名为的工具csreq,可用于将需求从二进制表示转换为文本表示(然后再转换回来)。

# Convert the hex string into a binary blob
$ BLOB="FADE0C000000003000000001000000060000000200000012636F6D2E6170706C652E5465726D696E616C000000000003"
$ echo "$BLOB" | xxd -r -p > terminal-csreq.bin

# Ask csreq to tell us what it means
$ csreq -r- -t < terminal-csreq.bin
identifier "com.apple.Terminal" and anchor apple

所以那个 csreq blob 只是说它想将应用程序与标识符“com.apple.Terminal”匹配并锚定苹果。我们可以检查 Terminal.app 并找到相同的要求字符串(在“指定”下)

$ codesign -d -r- /Applications/Utilities/Terminal.app
Executable=/Applications/Utilities/Terminal.app/Contents/MacOS/Terminal
designated => identifier "com.apple.Terminal" and anchor apple

让我们看另一个示例,这次是来自您的存储库的 virtualbox

# Convert the hex string into a binary blob
BLOB="FADE0C00000000AC0000000100000006000000020000001D6F72672E7669727475616C626F782E6170702E5669727475616C426F78000000000000060000000F000000060000000E000000010000000A2A864886F76364060206000000000000000000060000000E000000000000000A2A864886F7636406010D0000000000000000000B000000000000000A7375626A6563742E4F550000000000010000000A564235453254563936330000"
$ echo "$BLOB" | xxd -r -p > vbox-csreq.bin

# Ask csreq to tell us what it means
$ csreq -r- -t < vbox-csreq.bin
identifier "org.virtualbox.app.VirtualBox" and anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = VB5E2TV963

# ask codesign what the requirement text from the application itself is
$ codesign -d -r- /Applications/VirtualBox.app
Executable=/Applications/VirtualBox.app/Contents/MacOS/VirtualBox
designated => identifier "org.virtualbox.app.VirtualBox" and anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = VB5E2TV963

我们再次可以看到designatedcodesign 返回的字段与 csreq blob 包含的内容相同。

如果您对需求字符串的实际含义感到好奇,Apple 对此有一些文档


构建一个新的 csreq blob

现在我们知道 csreq blob 包含什么以及在哪里可以找到等效信息,我们需要将其转换为 tcc 数据库所需的二进制格式。csreq我们上面用于解码二进制 blob的工具也能够将文本表示转换为二进制。

# Get the requirement string from codesign
$ REQ_STR=$(codesign -d -r- /Applications/Utilities/Terminal.app/ 2>&1 | awk -F ' => ' '/designated/{print $2}')

# Convert the requirements string into it's binary representation(sadly it seems csreq requires the output to be a file; so we just throw it in /tmp)
$ echo "$REQ_STR" | csreq -r- -b /tmp/csreq.bin

# Convert the binary form to hex, and print it nicely for use in sqlite
$ REQ_HEX=$(xxd -p /tmp/csreq.bin  | tr -d '\n')
$ echo "X'$REQ_HEX'"
X'fade0c000000003000000001000000060000000200000012636f6d2e6170706c652e5465726d696e616c000000000003'

这个十六进制字符串与您上面从 tcc 数据库中得到的相同。


奖励:未签名的二进制文件

如果您想信任未签名的脚本/二进制文件并尝试使用上述方法,您会遇到一些问题:

$ codesign -d -r- ./hello.sh
./hello.sh: code object is not signed at all

阅读有关 Code Signing Requirement Language 的文档,下面有一个小注释Code Directory Hash(强调我的)

因为每当程序以非平凡方式发生变化时,代码目录都会发生变化,因此该测试可用于明确识别程序的一个特定版本。当操作系统签署其他未签署的程序时(例如,以便钥匙串或家长控制可以识别该程序),它使用此要求。

因此,对于未签名的程序,会生成一个临时签名并用于识别诸如 TCC(以及其他)之类的东西。

codesign工具可用于创建临时签名,我们可以从中获取需求字符串。

$ cat hello.sh 
#!/bin/bash
echo "Hello World"

# Create a detached signature(so as not to modify the original binary)
$ codesign --detached ./hello.sh.sig -s - ./hello.sh

# Display the designated identifier from the detached signature
$ codesign -d -r- --detached ./hello.sh.sig ./hello.sh 
Executable=/Users/keith/hello.sh
host => identifier "com.apple.bash" and anchor apple
# designated => cdhash H"70212a41efea9849e7a88afa946afa3e1b559cbe" or cdhash H"9044184bcced89d2f4bf1d75ec61a7537871eee7"

从这里我们可以继续上面给出的相同过程。



推荐阅读