#!/bin/bash #set -e表示一旦脚本中有命令的返回值为非0,则脚本立即退出,后续命令不再执行; #set -o pipefail表示在管道连接的命令序列中,只要有任何一个命令返回非0值,则整个管道返回非0值,即使最后一个命令返回0. export setCmd="set -eo pipefail" $setCmd #导出环境变量 export PATH=/opt/MonkeyDev/bin:/usr/local/bin:/usr/bin:/usr/sbin:/bin:/sbin:$PATH #脚本名称和版本 export scriptName="${0##*/}" export scriptVer="2.0" #本地存储文件的目录 export MonkeyDevPath="/opt/MonkeyDev" export backupFileExt=".MonkeyDev" #获取用户名、用户组、用户目录、和profile文件 export userName="${SUDO_USER-$USER}" export userGroup=`id -g $userName` export userHome=`eval echo ~$userName` #用户可能存在的profile文件 export bashProfileFiles=("$userHome/.zshrc" "$userHome/.bash_profile" "$userHome/.bashrc" "$userHome/.bash_login" "$userHome/.profile") #获取临时文件名 export tempDirsFile="`mktemp -d -t $scriptName`/tempdirs" touch "$tempDirsFile" #把LANG变量从当前环境中删除 unset LANG #出错退出 function cleanup() { local exitCode=$? set +e trap - $signals removeTempData exit $exitCode } function panic() { local exitCode=$1 set +e shift [[ "$@" == "" ]] || echo "$@" >&2 exit $exitCode } export signals="0 1 2 3 15" #当shell接收到signals指定的信号时,执行cleanup命令 trap cleanup $signals function removeTempData() { local tempDirs if [[ -f "$tempDirsFile" ]]; then tempDirs=(`cat "$tempDirsFile"`) for td in "${tempDirs[@]}"; do rm -rf "$td" || true done rm -rf "`dirname $tempDirsFile`" || true fi } function getTempDir() { $setCmd local tempDir tempDir=`mktemp -d -t $scriptName` || \ panic $? "Failed to create temporary directory" echo "$tempDir" >> "$tempDirsFile" || \ panic $? "Failed to echo into $tempDirsFile" echo "$tempDir" } function copyFile() { cp -f "$1" "$2" || \ panic $? "Failed to copy file $1 to $2" } #备份原文件 function requireBackup() { [[ ! -f "$1" || -f "${1}${backupFileExt}" ]] || \ copyFile "$1" "${1}${backupFileExt}" } #获取SDK信息 function getSdkProperty() { $setCmd local sdk="$1" local propertyName="$2" propertyValue=`xcodebuild -version -sdk $sdk $propertyName` || \ panic $? "Failed to get $sdk SDK property $propertyName" [[ $propertyValue != "" ]] || \ panic 1 "Value of $sdk SDK property $propertyName cannot be empty" # return # echo "$propertyValue" } #下载文件 function downloadFile() # args: sourceUrl, targetPath { local sourceUrl="$1" local targetPath="$2" local curlPath mkdir -p "${targetPath%/*}" || \ panic $? "Failed to make directory: ${targetPath%/*}" curlPath=`which curl` || \ panic $? "Failed to get curl path" "$curlPath" --output "$targetPath" "$sourceUrl" || \ panic $? "Failed to download $sourceUrl to $targetPath" } #解压文件 function extractTar() # args: tarPath, outputPath { local tarPath="$1" local outputPath="$2" tar -C "$outputPath" -zxf "$tarPath" || \ panic $? "Failed to extract $tarPath to $outputPath" } #下载github文件 function downloadGithubTarball() # args: url, outputDir, title { $setcmd local url="$1" local outputDir="$2" local title="$3" local tempDirForTar local tempDirForFiles local untardDir local tarFile="file.tar.gz" echo "Downloading $title from Github..." tempDirForTar=`getTempDir` tempDirForFiles=`getTempDir` downloadFile "$url" "$tempDirForTar/$tarFile" extractTar "$tempDirForTar/$tarFile" "$tempDirForFiles" untardDir=`find "$tempDirForFiles/"* -type d -depth 0` || \ panic $? "Failed to get untar'ed directory name of $tempDirForTar/$tarFile" mkdir -p "$outputDir" || \ panic $? "Failed to make directory: $outputDir" cp -fR "$untardDir/"* "$outputDir/" } #修改文件权限 function changeMode() { local mode="$1" local target="$2" local recursive="$3" local options [[ $recursive != "true" ]] || \ options="-R" if [[ -e "$target" ]]; then chmod $options "$mode" "$target" || \ panic $? "Failed to change mode to $mode on $target" fi } #获取用户profile文件 function determineUserBashProfileFile() { $setCmd local f local filePath for f in "${bashProfileFiles[@]}"; do if [[ -f "$f" ]]; then filePath="$f" echo "" >> "$f" || \ panic $? "Failed to echo into $f" break fi done if [[ $filePath == "" ]]; then filePath="$bashProfileFiles" touch "$filePath" || \ panic $? "Failed to touch $filePath" chown "$userName:$userGroup" "$filePath" || \ panic $? "Failed to change owner-group of $filePath" changeMode 0600 "$filePath" fi # return # echo "$filePath" } #验证是否存在文件 function requireFile() # args: filePath [, touchFileIfNotFound] { local filePath="$1" local touchFileIfNotFound="$2" if [[ ! -f "$filePath" ]]; then if [[ $touchFileIfNotFound == "true" ]]; then touch "$filePath" || \ panic $? "Failed to touch $filePath" else panic 1 "File $filePath not found" fi fi } #增加内容到文件 function addToFileIfMissing() # args: filePath, pattern, value { local filePath="$1" local pattern="$2" local value="$3" local doesContain doesContain=`doesFileContain "$filePath" "$pattern"` [[ $doesContain == "true" ]] || \ echo "$value" >> "$filePath" || \ panic $? "Failed to echo into $filePath" } #判断文件是否包含内容 function doesFileContain() # args: filePath, pattern { $setCmd local filePath="$1" local pattern="$2" local perlValue local funcReturn perlValue=`perl -ne 'if (/'"$pattern"'/) { print "true"; exit; }' "$filePath"` || \ panic $? "Failed to perl" if [[ $perlValue == "true" ]]; then funcReturn="true" else funcReturn="false" fi # return # echo $funcReturn } #从spec读取内容 function readXcodeSpecificationById(){ #args: filePath, id local filePath="$1" local id="$2" content=`/usr/libexec/PlistBuddy -x -c Print "$filePath"` || \ panic $? "Failed to get $filePath content" for (( i=0; i<=1; i++)); do dict=`/usr/libexec/PlistBuddy -x -c "Print $i" "$filePath"` if echo $dict | grep -qE "$id"; then echo "$dict" fi done } #往spec文件写入内容 function writeDictToSpecification(){ #args: filePath, content local filePath="$1" local content="$2" tempfile=`getTempDir`/dictfile echo "$content" >> $tempfile /usr/libexec/PlistBuddy -x -c 'add 0 dict' "$filePath" > /dev/null /usr/libexec/PlistBuddy -x -c "merge $tempfile 0" "$filePath" > /dev/null } # start it # 创建/opt/MonkeyDev mkdir -p "$MonkeyDevPath" || \ panic $? "Failed to make directory: $MonkeyDevPath" branch="master" if [[ "$1" ]]; then branch="$1" fi #下载一些基础文件和模板文件 downloadGithubTarball "https://codeload.github.com/AloneMonkey/MonkeyDev/tar.gz/$branch" "$MonkeyDevPath" "MonkeyDev base" downloadGithubTarball "https://codeload.github.com/AloneMonkey/MonkeyDev-Xcode-Templates/tar.gz/$branch" "$MonkeyDevPath/templates" "Xcode templates" #下载frida-ios-dump echo "Downloading frida-ios-dump from Github..." downloadFile "https://raw.githubusercontent.com/AloneMonkey/frida-ios-dump/3.x/dump.py" "$MonkeyDevPath/bin/dump.py" downloadFile "https://raw.githubusercontent.com/AloneMonkey/frida-ios-dump/3.x/dump.js" "$MonkeyDevPath/bin/dump.js" chmod +x "$MonkeyDevPath/bin/dump.py" #创建符号链接 echo "Creating symlink to Xcode templates..." #$userHome/Library/Developer/Xcode/Templates/MonkeyDev linkto $MonkeyDevPath/templates userDevDir="$userHome/Library/Developer" userTemplatesDir="$userDevDir/Xcode/Templates" if [[ ! -d "$userTemplatesDir" ]]; then mkdir -p "$userTemplatesDir" || \ panic $? "Failed to make directory: $userTemplatesDir" chown -R "$userName:$userGroup" "$userDevDir" || \ panic $? "Failed to change ownership-group of $userDevDir" fi ln -fhs "$MonkeyDevPath/templates" "$userTemplatesDir/MonkeyDev" #修改用户profile文件 echo "Modifying Bash personal initialization file..." userBashProfileFile=`determineUserBashProfileFile` addToFileIfMissing "$userBashProfileFile" "^(export)? *MonkeyDevPath=.*" "export MonkeyDevPath=$MonkeyDevPath" addToFileIfMissing "$userBashProfileFile" "^(export)? *MonkeyDevDeviceIP=.*" "export MonkeyDevDeviceIP=" addToFileIfMissing "$userBashProfileFile" "^(export)? *PATH=.*(\\\$MonkeyDevPath\\/bin|${MonkeyDevPath//\//\\/}\\/bin).*" "export PATH=$MonkeyDevPath/bin:\$PATH" #支持iphoneos command line tools iosSdkPlatformPath=`getSdkProperty iphoneos PlatformPath` macosSdkPlatformPath=`getSdkProperty macosx PlatformPath` specificationFile=$(cd $iosSdkPlatformPath/../../.. && pwd)/PlugIns/IDEiOSSupportCore.ideplugin/Contents/Resources/Embedded-Device.xcspec requireFile "$specificationFile" false #backup requireBackup "$specificationFile" hasPackageTypeForCommandLineTool=`doesFileContain "$specificationFile" 'com.apple.package-type.mach-o-executable'` hasProductTypeForCommandLineTool=`doesFileContain "$specificationFile" 'com.apple.product-type.tool'` macosxSDKSpecificationsPath=$macosSdkPlatformPath/Developer/Library/Xcode/Specifications packageTypesForMacOSXPath="$macosxSDKSpecificationsPath/MacOSX Package Types.xcspec" productTypesForMacOSXPath="$macosxSDKSpecificationsPath/MacOSX Product Types.xcspec" requireFile "$packageTypesForMacOSXPath" false requireFile "$productTypesForMacOSXPath" false if [[ $hasPackageTypeForCommandLineTool != "true" ]]; then machoDict=`readXcodeSpecificationById "$packageTypesForMacOSXPath" "com.apple.package-type.mach-o-executable"` writeDictToSpecification "$specificationFile" "$machoDict" fi if [[ $hasProductTypeForCommandLineTool != "true" ]]; then toolDict=`readXcodeSpecificationById "$productTypesForMacOSXPath" "com.apple.product-type.tool"` writeDictToSpecification "$specificationFile" "$toolDict" fi exit 0