Skip to content

Instantly share code, notes, and snippets.

@NikolaRusakov
Created September 9, 2022 20:39
Show Gist options
  • Select an option

  • Save NikolaRusakov/73a21f7391b6a309232ea40772ede269 to your computer and use it in GitHub Desktop.

Select an option

Save NikolaRusakov/73a21f7391b6a309232ea40772ede269 to your computer and use it in GitHub Desktop.
sketchcrapp url patched
#!/bin/bash
# RUP Review every time when new verison update part.
# Latest supported version
latestVersion="v71.2"
# Support version list.
declare -a version_list
# RUP Review every time when new verison update part.
# Address parameter array and other parameters for each version.
# Version 53
declare -a address_param_513
version_list+=("51.3")
address_param_513+=("3bc0e7")
address_param_513+=("3bab6d")
address_param_513+=("3bacbc")
exe_hash_513="21aed0fe8e29e9eaf9a1194b316ae6ee0ec342f7"
# Version 53
declare -a address_param_530
version_list+=("53")
address_param_530+=("4143c2")
address_param_530+=("412f2d")
address_param_530+=("413079")
address_param_530+=("4d2f09")
exe_hash_530="f8a7efc0814bbd26c591dcb8b2922cdf17016c04"
# Version 58
declare -a address_param_580
version_list+=("58")
address_param_580+=("3912bf")
address_param_580+=("3912c2")
address_param_580+=("38ff2e")
address_param_580+=("39007d")
exe_hash_580="5669dd6d7452a96ac3523ea8fa1a41d9ce70f50f"
# Version 63.1
declare -a address_param_631
version_list+=("63.1")
address_param_631+=("4a2a4f")
address_param_631+=("4a2a52")
address_param_631+=("4a173a")
address_param_631+=("4a1879")
exe_hash_631="db9b88f3aa6abc484be104660fa911275d9f2515"
# Version 64
declare -a address_param_640
version_list+=("64")
address_param_640+=("4cde6f")
address_param_640+=("4cde72")
address_param_640+=("4ccb5a")
address_param_640+=("4ccc99")
exe_hash_640="a4d16224ebb8caf84c94a6863db183fd306002da"
# Version 65.1
declare -a address_param_651
version_list+=("65.1")
address_param_651+=("4db4ff")
address_param_651+=("4db502")
address_param_651+=("4da1ea")
address_param_651+=("4da329")
exe_hash_651="0e7cad9b81284d127d652b3a8c962315770cd905"
# Version 66.1
declare -a address_param_661
version_list+=("66.1")
address_param_661+=("4f374f")
address_param_661+=("4f3752")
address_param_661+=("4f243a")
address_param_661+=("4f2579")
exe_hash_661="97d6273be93546a9b3caa7c8e1f97fe2246e673b"
# Version 67 & 67.1
declare -a address_param_670
version_list+=("67")
address_param_670+=("50a6cf")
address_param_670+=("50a6d2")
address_param_670+=("5093aa")
address_param_670+=("5094e9")
exe_hash_670="b9866183ded9573aea6be0a004f31c8941059f3f"
version_list+=("67.1")
exe_hash_671="708e9203a8628c5cee767eb75546c6145b69df57"
# Version 67.2
declare -a address_param_672
version_list+=("67.2")
address_param_672+=("50a78f")
address_param_672+=("50a792")
address_param_672+=("50946a")
address_param_672+=("5095a9")
exe_hash_672="9762906ced4d5589e27b297012ce862665e65a29"
# Version 68
declare -a address_param_680
version_list+=("68")
address_param_680+=("54d2af")
address_param_680+=("54d2b2")
address_param_680+=("54bf8a")
address_param_680+=("54c0c9")
exe_hash_680="ad9ccdce3ac270b2441f0efb8f3233935fb1900a"
# Version 68.1 & 68.2
declare -a address_param_681
version_list+=("68.1")
address_param_681+=("54d34f")
address_param_681+=("54d352")
address_param_681+=("54c02a")
address_param_681+=("54c169")
exe_hash_681="bc22987f7b3a7580aba1ac260c59d66d0a3622e7"
version_list+=("68.2")
exe_hash_682="651f3263305e004133253c2706fcdf5b16e20558"
# Version 69
declare -a address_param_690
version_list+=("69")
address_param_690+=("5cf76f")
address_param_690+=("5cf772")
address_param_690+=("5ce44a")
address_param_690+=("5ce589")
exe_hash_690="2d4027890e2b72175c4a562f59c5d1adb2655b8c"
# Version 69.1 & 69.2
declare -a address_param_691
version_list+=("69.1")
address_param_691+=("5d09df")
address_param_691+=("5d09e2")
address_param_691+=("5cf57e")
address_param_691+=("5cf6ae")
exe_hash_691="4ce06aa34c40040244c60608a02c152186f23c32"
version_list+=("69.2")
exe_hash_692="a7ba7ddf8e15e1e03ae88c00ab5070dabecc06b2"
# Version 70.2
declare -a address_param_702
version_list+=("70.2")
address_param_702+=("5861bf")
address_param_702+=("5861c2")
address_param_702+=("584e0e")
address_param_702+=("584f3e")
address_param_702+=("66d03f")
address_param_702+=("66d04f")
address_param_702+=("dcd72c")
address_param_702+=("dcd730")
address_param_702+=("dcc3a4")
address_param_702+=("dcc4c7")
address_param_702+=("ed1031")
address_param_702+=("ed1041")
exe_hash_702="e3376ad6f58bdf1e24306bf6d94ee67b082a94db"
# Version 70.3
declare -a address_param_703
version_list+=("70.3")
address_param_703+=("58619f")
address_param_703+=("5861a2")
address_param_703+=("584dee")
address_param_703+=("584f1e")
address_param_703+=("66d058")
address_param_703+=("66d068")
address_param_703+=("dcd574")
address_param_703+=("dcd578")
address_param_703+=("dcc1ec")
address_param_703+=("dcc30f")
address_param_703+=("ed0fd7")
address_param_703+=("ed0fe7")
exe_hash_703="9a0e6b7721c275b75e1fb6b70b55cda7ab99c4a8"
# Version 70.4
declare -a address_param_704
version_list+=("70.4")
address_param_704+=("58606f")
address_param_704+=("586072")
address_param_704+=("584cbe")
address_param_704+=("584dee")
address_param_704+=("66cffb")
address_param_704+=("66d00b")
address_param_704+=("dcd484")
address_param_704+=("dcd488")
address_param_704+=("dcc0fc")
address_param_704+=("dcc21f")
address_param_704+=("ed0fa5")
address_param_704+=("ed0fb5")
exe_hash_704="6adf7ee4c29bb1a61739b8804c7ce6d94c791f36"
# Version 70.5 & 70.6
declare -a address_param_705
version_list+=("70.5")
address_param_705+=("585eef")
address_param_705+=("585ef2")
address_param_705+=("584b3e")
address_param_705+=("584c6e")
address_param_705+=("66ce63")
address_param_705+=("66ce73")
address_param_705+=("dcd404")
address_param_705+=("dcd408")
address_param_705+=("dcc07c")
address_param_705+=("dcc19f")
address_param_705+=("ed0fbc")
address_param_705+=("ed0fcc")
exe_hash_705="2f1f2fff46d692f2ffe67cec150da4d5d67218eb"
version_list+=("70.6")
exe_hash_706="33d438d86cbb81bf945f30d0906395522680a03f"
# Version 71.1
declare -a address_param_711
version_list+=("71.1")
address_param_711+=("5d904f")
address_param_711+=("5d9052")
address_param_711+=("5d7c9e")
address_param_711+=("5d7dce")
address_param_711+=("6cb001")
address_param_711+=("6cb011")
address_param_711+=("e95d84")
address_param_711+=("e95d88")
address_param_711+=("e949f4")
address_param_711+=("e94b17")
address_param_711+=("fa6458")
address_param_711+=("fa6468")
exe_hash_711="abd3ce2193b113c28d1bf5e28739bb303b52a556"
# Version 71.2
declare -a address_param_712
version_list+=("71.2")
address_param_712+=("5dccbf")
address_param_712+=("5dccc2")
address_param_712+=("5db90e")
address_param_712+=("5dba3e")
address_param_712+=("6cef41")
address_param_712+=("6cef51")
address_param_712+=("e9992c")
address_param_712+=("e99930")
address_param_712+=("e9859c")
address_param_712+=("e986bf")
address_param_712+=("faa308")
address_param_712+=("faa318")
exe_hash_712="35d64aa153bca44a4325b47211ae19ae2bf16fac"
# Value old parameter array.
declare -a value_ancient_param
value_ancient_param+=("\00")
value_ancient_param+=("\00\00")
value_ancient_param+=("\165")
# Value old parameter array.
declare -a value_old_param
value_old_param+=("\00")
value_old_param+=("\00\00")
value_old_param+=("\165")
value_old_param+=("\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00") # x86_remove_register
# Value parameter array.
declare -a value_legacy_param
value_legacy_param+=("\00")
value_legacy_param+=("\00")
value_legacy_param+=("\00\00")
value_legacy_param+=("\165")
declare -a value_param
value_param+=("\00") # x86_1
value_param+=("\00") # x86_2
value_param+=("\00\00") # x86_3
value_param+=("\165") # x86_4
value_param+=("\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00") # x86_remove_register
value_param+=("\40\123\153\145\164\143\150\103\162\141\160\160\40") # x86_modified_day_left
value_param+=("\01") # aarch_1
value_param+=("\24") # aarch_2
value_param+=("\165\00") # aarch_3
value_param+=("\64") # aarch_4
value_param+=("\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00") # aarch_remove_register
value_param+=("\40\123\153\145\164\143\150\103\162\141\160\160\40") # aarch_modified_day_left
declare -a nametag_ancient_ver
nametag_ancient_ver+=("51.3")
declare -a nametag_old_ver
nametag_old_ver+=("53")
# OpenSSL configuration.
CONFIG="
[ req ]
distinguished_name=name
[ name ]
[ self ]
keyUsage = critical,digitalSignature
extendedKeyUsage = codeSigning
subjectKeyIdentifier = hash
basicConstraints = critical,CA:false
"
downloadURLString=""
# Banner block
banner() {
cat <<"EOF"
__ __ __
___ / /_____ / /_____/ / ___________ ____ ___
( _-</ '_/ -_) __/ __/ _ \/ __/ __/ _ `/ _ \/ _ \
/___/_/\_\\__/\__/\__/_//_/\__/_/ \_,_/ .__/ .__/
/_/ /_/
Sketch.App Patch Tool (https://github.com/duraki/SketchCrapp)
by @duraki & @elijahtsai
EOF
}
# RUP Review every time when new verison update part.
# Last function to run before exit.
finally() {
local status="$1"
local pds="2021-10-16 serial 002"
printf "[+] SketchCrapp last published date: \e[38;5;14m$pds\e[0m\n"
exit $status
}
# RUP Review every time when new verison update part.
# Help messages block.
usage() {
echo "Usage:"
echo "./sketchcrapp [-h] [-a] <applicationPath> [-m] [-g] <version>"
echo "Supported versions: v51.3, v53, v58, v63.1, v64.0, v65.1, v66.1, v67"
echo "v67.1, v67.2, v68, v68.1, v68.2, v69, v69.1, v69.2, v70.2, v70.3, v70.4"
echo "v70.5, v70.6, v71.1, v71.2"
finally 0;
}
# Clean up all related files.
clean() {
printf "[+] Cleaning up file(s) ... "
if [ -f pk.pem ]; then
rm -f pk.pem
fi
if [ -f crt.pem ]; then
rm -f crt.pem
fi
if [ -f pkcs.p12 ]; then
rm -f pkcs.p12
fi
if [ -f "/tmp/app.zip" ]; then
rm -f "/tmp/app.zip"
if ! [ "$?" -eq "0" ]; then
printf "\e[38;5;9mError\e[0m\n"
echo "[-] Fail to remove zip file of latest application. remove by yourself."
finally 1
fi
fi
if [ -f "/tmp/Sketch.app" ]; then
rm -f "/tmp/Sketch.app"
if ! [ "$?" -eq "0" ]; then
printf "\e[38;5;9mError\e[0m\n"
echo "[-] Fail to remove application bundle. remove by yourself."
finally 1
fi
fi
if [ -f "/tmp/select.swift" ]; then
rm -f "/tmp/select.swift"
if ! [ "$?" -eq "0" ]; then
printf "\e[38;5;9mError\e[0m\n"
echo "[-] Fail to remove swift script file. remove by yourself."
finally 1
fi
fi
if [ -f "/tmp/list.xml" ]; then
rm -f "/tmp/list.xml"
if ! [ "$?" -eq "0" ]; then
printf "\e[38;5;9mError\e[0m\n"
echo "[-] Fail to remove list xml file. remove by yourself."
finally 1
fi
fi
printf "\e[38;5;10mCleaned\e[0m\n"
}
# Generate self-signed certificate for codesign. Required for pass-tru
# code-signature detection by Sketch. Built-in via MacOS openssl library.
genSelfSignCert() {
echo "[+] Generating self-signed certificate ..."
openssl req -new -newkey ec:<(openssl ecparam -name secp521r1) \
-config <(echo "$CONFIG") \
-extensions self -days 3650 -nodes -x509 \
-subj "/CN=sketchcrapp"\
-keyform pem -keyout pk.pem \
-outform pem -out crt.pem
echo "[+] Creating pkcs package..."
openssl pkcs12 -export -out pkcs.p12 -in crt.pem -inkey pk.pem \
-name "sketchcrapp" -nodes -passout pass:1234
}
# Import code-signature certificate to keychain. Must be included and trusted
# by the OS internals.
# - First: The default keychain that under the user profile.
importSelfSignCert() {
local userDefaultKeychain="$1"
echo "[+] Importing private key and self-signed certificate"
security import pkcs.p12 -k "$userDefaultKeychain" -f pkcs12 -P 1234
}
# Equivalent to code-signature application in Sketch.
# Sign Sketch with generated certificate.
# - Parameters:
# - First: The application bundle path.
# - Second: The default keychain that under the user profile.
signApplication() {
local appPath="$1"
local userDefaultKeychain="$2"
echo "[+] Signing the patched *.app bundle. This may require root privilege."
echo "[+] If asked, enter your login password. Choose \"Always Allow\" to \
not be asked again."
codesign --deep --force -s "sketchcrapp" "$appPath" --verbose --keychain "$userDefaultKeychain"
if ! [ "$?" -eq "0" ]; then
echo "[-] Failed to sign Sketch bundle."
echo "[+] Automatic fix process started."
echo "[+] Removing certificate ..."
security delete-certificate -c "sketchcrapp" "$userDefaultKeychain"
if ! [ "$?" -eq "0" ]; then
echo "[-] Unable to delete <sketchcrapp> certificate from Keychain"
clean
finally 1
fi
echo "[+] Re-creating signature identity ..."
genSelfSignCert
echo "[+] Re-importing signature identity ..."
importSelfSignCert "$userDefaultKeychain"
echo "[+] Resigning application bundle again using signature identity ..."
codesign --deep --force -s "sketchcrapp" "$appPath" --verbose --keychain "$userDefaultKeychain"
if ! [ "$?" -eq "0" ]; then
printf "[\e[38;5;9mERR\e[0m] Failed to sign Sketch bundle. Automatic method failed.\n"
printf "[\e[38;5;11mINFO\e[0m] Copy the full log and open a new issue on GitHub \
repository: https://github.com/duraki/SketchCrapp\n"
clean
finally 1
fi
fi
}
checkVersionSupported() {
local versionString="$1"
for versionElement in "${version_list[@]}"
do
if [ "$versionString" = "$versionElement" ]; then
return 0
fi
done
return 1
}
generateSelectVersionScript(){
echo "[+] Generating swift script: target Version ..."
cat <<'EOF' > /tmp/select.swift
import Foundation
var testString = ""
while let line = readLine() {
testString += "\(line)\n"
}
let pattern = #"v?(?:(\d\.\d\.\d)|(\d\d?\d?\.\d)|(\d\d))"#
let regex = try! NSRegularExpression(pattern: pattern)
let stringRange = NSRange(location: 0, length: testString.utf16.count)
let matches = regex.matches(in: testString, range: stringRange)
var versions: String
versions="(null)"
for match in matches {
var groups: String = ""
for rangeIndex in 1 ..< match.numberOfRanges {
if match.range(at: rangeIndex).location > testString.utf16.count {
continue
}
groups = (testString as NSString).substring(with: match.range(at: rangeIndex))
}
versions=groups
}
print(versions)
EOF
}
generateSelectURLScript(){
echo "[+] Generating swift script: target URL ..."
cat <<'EOF' > /tmp/select.swift
import Foundation
var testString = ""
while let line = readLine() {
testString += "\(line)\n"
}
let pattern = #".*<enclosure url[^"]"(.*)" len.*\/>.*"#
let regex = try! NSRegularExpression(pattern: pattern)
let stringRange = NSRange(location: 0, length: testString.utf16.count)
let matches = regex.matches(in: testString, range: stringRange)
var urls: [String] = []
for match in matches {
var groups: String = ""
for rangeIndex in 1 ..< match.numberOfRanges {
if match.range(at: rangeIndex).location > testString.utf16.count {
continue
}
groups = (testString as NSString).substring(with: match.range(at: rangeIndex))
}
urls.append(groups)
}
for u in urls {
print(u)
}
EOF
}
getURLFromVersionString() {
local versionString="$1"
local testVersionString=""
echo "[+] Checking if version $versionString is supported ..."
if [ -z "$versionString" ]; then
versionString="(null)"
else
generateSelectVersionScript
testVersionString=$(echo $versionString | swift "/tmp/select.swift")
checkVersionSupported "$testVersionString"
fi
if ! [ "$?" -eq "0" ] || [ -z $testVersionString ]; then
printf "[\e[38;5;9mERR\e[0m] Version $testVersionString is not supported, \
please carefully review README file again.\n"
printf "[\e[38;5;11mINFO\e[0m] Copy the details below and open a new issue on GitHub \
repository: https://github.com/duraki/SketchCrapp\n"
echo "+==================================================================="
echo "+ Issue details ‹s:sketchcrapp:VersionUserEnter›"
echo "+ Passed version : $versionString"
echo "+ Normalize version : $testVersionString"
echo "+ Error : Version $testVersionString is not supported."
echo "+==================================================================="
clean
finally 1
fi
local versionListXMLURL="https://download.sketch.com/sketch-versions.xml"
echo "[+] Fetching $versionListXMLURL ... "
curl -L "$versionListXMLURL" --output "/tmp/list.xml"
if ! [ "$?" -eq "0" ]; then
printf "[\e[38;5;9mERR\e[0m] Failed while downloading version list xml file!\n"
printf "[\e[38;5;11mINFO\e[0m] Are you connected to the internet? Check your network connection.\n"
clean
finally 1
fi
generateSelectURLScript
if ! [ -f "/tmp/select.swift" ]; then
echo "[-] Swift script does not exists under the /tmp folder."
printf "[\e[38;5;9mERR\e[0m] Couldn't find select.swift at /tmp/select.swift\n"
printf "[\e[38;5;11mINFO\e[0m] We don't know what's going on, try to use -m to get latest patch.\n"
clean
finally 1
fi
LANG=en_GB.UTF-8
OIFS=$IFS
IFS=$'\n'
testURL=$(cat /tmp/list.xml | \
sed -e 's/^[[:space:]]*//g' | \
sed -e 's/[[:space:]]*$//g'| \
tr -d '\n' | \
sed -e $'s/<enclos/\\\n<enclos/g' | \
swift "/tmp/select.swift" | \
grep "\-$testVersionString\-")
IFS=$OIFS
downloadURLString="$testURL"
if [ -z "$downloadURLString" ]; then
printf "[\e[38;5;9mERR\e[0m] Version $versionString is not supported, \
please carefully review README file again.\n"
printf "[\e[38;5;11mINFO\e[0m] Copy the details below and open a new issue on GitHub \
repository: https://github.com/duraki/SketchCrapp\n"
echo "+==================================================================="
echo "+ Issue details ‹s:sketchcrapp:UnknowDownloadURLString"
echo "+ Passed version : $versionString"
echo "+ Normalize version : $testVersionString"
echo "+ Error : Version $versionString is not supported."
echo "+==================================================================="
clean
finally 1
fi
echo "[+] Download URL set to: $downloadURLString"
}
# Get binary hash from CFBundleShortVersionString
# - Parameters:
# - First: The application bundle CFBundleShortVersionString.
getHashFromVersionString() {
local bundleVersionString="$1"
# RUP Review every time when new verison update part.
case "$bundleVersionString" in
"51.3")
echo "$exe_hash_513"
;;
"53")
echo "$exe_hash_530"
;;
"58")
echo "$exe_hash_580"
;;
"63.1")
echo "$exe_hash_631"
;;
"64")
echo "$exe_hash_640"
;;
"65.1")
echo "$exe_hash_651"
;;
"66.1")
echo "$exe_hash_661"
;;
"67")
echo "$exe_hash_670"
;;
"67.1")
echo "$exe_hash_671"
;;
"67.2")
echo "$exe_hash_672"
;;
"68")
echo "$exe_hash_680"
;;
"68.1")
echo "$exe_hash_681"
;;
"68.2")
echo "$exe_hash_682"
;;
"69")
echo "$exe_hash_690"
;;
"69.1")
echo "$exe_hash_691"
;;
"69.2")
echo "$exe_hash_692"
;;
"70.2")
echo "$exe_hash_702"
;;
"70.3")
echo "$exe_hash_703"
;;
"70.4")
echo "$exe_hash_704"
;;
"70.5")
echo "$exe_hash_705"
;;
"70.6")
echo "$exe_hash_706"
;;
"71.1")
echo "$exe_hash_711"
;;
"71.2")
echo "$exe_hash_712"
;;
*)
echo "Input version string invaild, cannot lookup correct hash value."
esac
}
# Verify the application by using hash value.
# - Parameters:
# - First: The application bundle path.
analysisApplication() {
echo "[+] Analysing application bundle ... Starting"
local appPath="$1"
printf "[+] Finding executable file ... "
# Get the path of application executable.
local execPath="$appPath/Contents/MacOS/Sketch"
if ! [ -f "$execPath" ]; then
printf "\e[38;5;9mError\e[0m\n"
echo "[-] Executable file does not exists under the given application folder."
printf "[\e[38;5;9mERR\e[0m] Couldn't find executable file at $execPath\n"
printf "[\e[38;5;11mINFO\e[0m] Please make sure you pass clean app to script.\n"
finally 1
fi
printf "\e[38;5;10mOK\e[0m\n"
printf "[+] Finding Info.plist ... "
# Get the path of application info plist.
local infoPath="$appPath/Contents/Info"
if ! [ -f "$infoPath.plist" ]; then
printf "\e[38;5;9mError\e[0m\n"
echo "[-] Info file does not exists under the given application folder."
printf "[\e[38;5;9mERR\e[0m] Couldn't find Info.plist at $infoPath.plist\n"
printf "[\e[38;5;11mINFO\e[0m] Please make sure you pass clean app to script.\n"
finally 1
fi
printf "\e[38;5;10mOK\e[0m\n"
printf "[+] Checking Info.plist for CFBundleShortVersionString ... "
# Get the CFBundleShortVersionString from info plist.
local bundleVersionString="$(defaults read $infoPath CFBundleShortVersionString)"
if [ -z "$bundleVersionString" ]; then
printf "\e[38;5;9mError\e[0m\n"
printf "[\e[38;5;9mERR\e[0m] Couldn't find value of CFBundleShortVersionString\n"
printf "[\e[38;5;11mINFO\e[0m] Please make sure you pass clean app to script.\n"
finally 1
fi
printf "\e[38;5;10mOK\e[0m\n"
# Get the hash of application executable
local appSHA1="$(shasum -a 1 "$execPath" | cut -f 1 -d ' ')"
checkVersionSupported "$bundleVersionString"
if ! [ "$?" -eq "0" ]; then
printf "[\e[38;5;9mERR\e[0m] Version $bundleVersionString is not supported, \
please carefully review README file again.\n"
printf "[\e[38;5;11mINFO\e[0m] Copy the details below and open a new issue on GitHub \
repository: https://github.com/duraki/SketchCrapp\n"
echo "+==================================================================="
echo "+ Issue details ‹s:sketchcrapp›"
echo "+ Application Path : $appPath"
echo "+ Application Binary: $execPath"
echo "+ Passed version : $bundleVersionString"
echo "+ Binary SHA1 : $appSHA1"
echo "+ Error : Version $bundleVersionString is not supported."
echo "+==================================================================="
finally 1
fi
printf "[+] Validating executable file ... "
local testBundleVersionString=""
# RUP Review every time when new verison update part.
case "$appSHA1" in
"$exe_hash_513")
testBundleVersionString="51.3"
;;
"$exe_hash_530")
testBundleVersionString="53"
;;
"$exe_hash_580")
testBundleVersionString="58"
;;
"$exe_hash_631")
testBundleVersionString="63.1"
;;
"$exe_hash_640")
testBundleVersionString="64"
;;
"$exe_hash_651")
testBundleVersionString="65.1"
;;
"$exe_hash_661")
testBundleVersionString="66.1"
;;
"$exe_hash_670")
testBundleVersionString="67"
;;
"$exe_hash_671")
testBundleVersionString="67.1"
;;
"$exe_hash_672")
testBundleVersionString="67.2"
;;
"$exe_hash_680")
testBundleVersionString="68"
;;
"$exe_hash_681")
testBundleVersionString="68.1"
;;
"$exe_hash_682")
testBundleVersionString="68.2"
;;
"$exe_hash_690")
testBundleVersionString="69"
;;
"$exe_hash_691")
testBundleVersionString="69.1"
;;
"$exe_hash_692")
testBundleVersionString="69.2"
;;
"$exe_hash_702")
testBundleVersionString="70.2"
;;
"$exe_hash_703")
testBundleVersionString="70.3"
;;
"$exe_hash_704")
testBundleVersionString="70.4"
;;
"$exe_hash_705")
testBundleVersionString="70.5"
;;
"$exe_hash_706")
testBundleVersionString="70.6"
;;
"$exe_hash_711")
testBundleVersionString="71.1"
;;
"$exe_hash_712")
testBundleVersionString="71.2"
;;
*)
testBundleVersionString="binaryerr››"
printf "\e[38;5;9mError\e[0m\n"
printf "[\e[38;5;9mERR\e[0m] Can't find Sketch with that signature. Hash is invalid.\n"
printf "[\e[38;5;11mINFO\e[0m] Carefully review README file again\n"
printf "[\e[38;5;11mINFO\e[0m] If you still have problem copy the details below and open a new issue\n"
printf "[\e[38;5;11mINFO\e[0m] on GitHub repository: https://github.com/duraki/SketchCrapp\n"
echo "+==================================================================="
echo "+ Application Path : $appPath"
echo "+ Application Binary: $execPath"
echo "+ Passed version : $bundleVersionString"
echo "+ Correct hash : $(getHashFromVersionString "$bundleVersionString")"
echo "+ Binary SHA1 : $appSHA1"
echo "+ Error : Can't find Sketch with that signature. Hash is invalid."
echo "+==================================================================="
finally 1
esac
if [ "$bundleVersionString" = "$testBundleVersionString" ]; then
printf "\e[38;5;10mOK\e[0m\n"
engin "$bundleVersionString" "$appPath" "$execPath"
else
printf "\e[38;5;9mError\e[0m\n"
printf "[\e[38;5;9mFATAL\e[0m] Executable SHA1 hash returned version value does not \
equal to the CFBundleShortVersionString\n"
printf "[\e[38;5;11mINFO\e[0m] Carefully review README file again, if you still have problem\n"
printf "[\e[38;5;11mINFO\e[0m] open a new issue on GitHub repository: https://github.com/duraki/SketchCrapp\n"
finally 1
fi
}
# Patch ancient process.
# - Parameters:
# - First: An array of address of specific version.
# - Second: A path of application executable to patch.
patchAncient() {
echo "Starting ancient arch patch via bash&seek ..."
local addressArray=(${1})
local execPath=${2}
for i in {0..2}; do
echo "[+] Patching address at offset: 0x${addressArray[$i]} \
with value: ${value_ancient_param[$i]}"
printf "${value_ancient_param[$i]}" | dd seek="$((0x${addressArray[$i]}))" conv=notrunc bs=1 of="$execPath"
if ! [ "$?" -eq "0" ]; then
printf "[\e[38;5;9mFATAL\e[0m] Patch process resulted in failure. That's all we know.\n"
printf "[\e[38;5;11mINFO\e[0m] Open a new issue and tell us about this \
on GitHub repository: https://github.com/duraki/SketchCrapp\n"
finally 1
fi
done
}
# Patch old process.
# - Parameters:
# - First: An array of address of specific version.
# - Second: A path of application executable to patch.
patchOld() {
echo "Starting old arch patch via bash&seek ..."
local addressArray=(${1})
local execPath=${2}
for i in {0..3}; do
echo "[+] Patching address at offset: 0x${addressArray[$i]} \
with value: ${value_old_param[$i]}"
printf "${value_old_param[$i]}" | dd seek="$((0x${addressArray[$i]}))" conv=notrunc bs=1 of="$execPath"
if ! [ "$?" -eq "0" ]; then
printf "[\e[38;5;9mFATAL\e[0m] Patch process resulted in failure. That's all we know.\n"
printf "[\e[38;5;11mINFO\e[0m] Open a new issue and tell us about this \
on GitHub repository: https://github.com/duraki/SketchCrapp\n"
finally 1
fi
done
}
# Patch legacy process.
# - Parameters:
# - First: An array of address of specific version.
# - Second: A path of application executable to patch.
patchLegacy() {
echo "Starting legacy arch patch via bash&seek ..."
local addressArray=(${1})
local execPath=${2}
for i in {0..3}; do
echo "[+] Patching address at offset: 0x${addressArray[$i]} \
with value: ${value_legacy_param[$i]}"
printf "${value_legacy_param[$i]}" | dd seek="$((0x${addressArray[$i]}))" conv=notrunc bs=1 of="$execPath"
if ! [ "$?" -eq "0" ]; then
printf "[\e[38;5;9mFATAL\e[0m] Patch process resulted in failure. That's all we know.\n"
printf "[\e[38;5;11mINFO\e[0m] Open a new issue and tell us about this \
on GitHub repository: https://github.com/duraki/SketchCrapp\n"
finally 1
fi
done
}
# Patch process.
# - Parameters:
# - First: An array of address of specific version.
# - Second: A path of application executable to patch.
patch() {
echo "Starting patch via bash&seek ..."
local addressArray=(${1})
local execPath=${2}
for i in {0..11}; do
echo "[+] Patching address at offset: 0x${addressArray[$i]} \
with value: ${value_param[$i]}"
printf "${value_param[$i]}" | dd seek="$((0x${addressArray[$i]}))" conv=notrunc bs=1 of="$execPath"
if ! [ "$?" -eq "0" ]; then
printf "[\e[38;5;9mFATAL\e[0m] Patch process resulted in failure. That's all we know.\n"
printf "[\e[38;5;11mINFO\e[0m] Open a new issue and tell us about this \
on GitHub repository: https://github.com/duraki/SketchCrapp\n"
finally 1
fi
done
}
# Install and register cracktag + credits for ancient version
nameTagAncient() {
local appPath="$1"
local LangPath="$appPath/Contents/Resources/"
if ! [ -d "$LangPath" ]; then
if [ -d "$appPath" ]; then
rm -rf "$appPath"
clean
finally 1
fi
fi
local LangFilePath="$LangPath/Localizable.strings"
if ! [ -f "$LangFilePath" ]; then
if [ -d "$appPath" ]; then
rm -rf "$appPath"
clean
finally 1
fi
fi
local LangFilePathBak="$LangPath/Localizable.strings.bak"
mv "$LangFilePath" "$LangFilePathBak"
cat "$LangFilePathBak" | iconv -f UTF-16LE -t UTF-8 | sed -e "s/1 Day Left/SketchCrapp/g" -e "s/ - Register Now//g" | iconv -f UTF-8 -t UTF-16LE > "$LangFilePath"
rm -f "$LangFilePathBak"
}
# Install and register cracktag + credits for older version
nameTagOld() {
local appPath="$1"
local LangPath="$appPath/Contents/Resources/en.lproj"
if ! [ -d "$LangPath" ]; then
if [ -d "$appPath" ]; then
rm -rf "$appPath"
clean
finally 1
fi
fi
local LangFilePath="$LangPath/Localizable.stringsdict"
if ! [ -f "$LangFilePath" ]; then
if [ -d "$appPath" ]; then
rm -rf "$appPath"
clean
finally 1
fi
fi
local LangFilePathBak="$LangPath/Localizable.stringsdict.bak"
mv "$LangFilePath" "$LangFilePathBak"
cat "$LangFilePathBak" | iconv -f UTF-16LE -t UTF-8 | sed -e "s/1 Day Left/SketchCrapp/g" | iconv -f UTF-8 -t UTF-16LE > "$LangFilePath"
rm -f "$LangFilePathBak"
}
# Install and register cracktag + credits
nameTag() {
local appPath="$1"
local engLangPath="$appPath/Contents/Resources/en.lproj"
local zhLangPath="$appPath/Contents/Resources/zh-Hans.lproj"
if ! [ -d "$engLangPath" ] || ! [ -d "$zhLangPath" ]; then
if [ -d "$appPath" ]; then
rm -rf "$appPath"
clean
finally 1
fi
fi
echo '"gWf-Nl-VLs.title" = "Sketch Cloud is currently not supported by SketchCrapp. Sorry :(";
"h0z-lo-HfZ.ibShadowedIsNilPlaceholder" = "@0xduraki & @elijahtsai";
"h1X-KO-1Ed.title" = "Name";
"Ja3-jS-bo6.title" = "Crack It";
"kCf-Hg-sTQ.ibShadowedIsNilPlaceholder" = "Cracked by @0xduraki & @elijahtsai";
"kUG-6E-w0F.ibShadowedIsNilPlaceholder" = "sketchcrapp@github.com";
"mSb-kZ-v2e.ibShadowedLabels[0]" = "SketchCrapp";
"mSb-kZ-v2e.ibShadowedLabels[1]" = "github.com/duraki/SketchCrapp";
"oEr-Dw-WUj.title" = "Forgot to crack it?";
"pfs-Mp-bgn.title" = "Wh00ps, what did you do :)";
"yfB-jh-Is0.placeholderString" = "Cracked by @0xduraki & @elijahtsai";' > "$engLangPath/MSRegistrationWindow.strings"
if ! [ -f "$zhLangPath/MSRegistrationWindow.strings" ]; then
if [ -d "$appPath" ]; then
rm -rf "$appPath"
clean
finally 1
fi
fi
/usr/bin/sed -i -e 's/"gWf-Nl-VLs.title"\ =\ [^;]*/"gWf-Nl-VLs.title" = "SketchCrapp 還沒支援 Sketch Cloud, 再等等吧 :("/g' "$zhLangPath/MSRegistrationWindow.strings"
/usr/bin/sed -i -e 's/"h0z-lo-HfZ.ibShadowedIsNilPlaceholder"\ =\ [^;]*/"h0z-lo-HfZ.ibShadowedIsNilPlaceholder" = "@0xduraki \& @elijahtsai"/g' "$zhLangPath/MSRegistrationWindow.strings"
/usr/bin/sed -i -e 's/"h1X-KO-1Ed.title"\ =\ [^;]*/"h1X-KO-1Ed.title" = "名稱"/g' "$zhLangPath/MSRegistrationWindow.strings"
/usr/bin/sed -i -e 's/"Ja3-jS-bo6.title"\ =\ [^;]*/"Ja3-jS-bo6.title" = "破解"/g' "$zhLangPath/MSRegistrationWindow.strings"
/usr/bin/sed -i -e 's/"kCf-Hg-sTQ.ibShadowedIsNilPlaceholder"\ =\ [^;]*/"kCf-Hg-sTQ.ibShadowedIsNilPlaceholder" = "由 @0xduraki \& @elijahtsai 破解"/g' "$zhLangPath/MSRegistrationWindow.strings"
/usr/bin/sed -i -e 's/"kUG-6E-w0F.ibShadowedIsNilPlaceholder"\ =\ [^;]*/"kUG-6E-w0F.ibShadowedIsNilPlaceholder" = "sketchcrapp@github.com"/g' "$zhLangPath/MSRegistrationWindow.strings"
/usr/bin/sed -i -e 's/"mSb-kZ-v2e.ibShadowedLabels\[0\]"\ =\ [^;]*/"mSb-kZ-v2e.ibShadowedLabels[0]" = "SketchCrapp"/g' "$zhLangPath/MSRegistrationWindow.strings"
/usr/bin/sed -i -e 's/"mSb-kZ-v2e.ibShadowedLabels\[1\]"\ =\ [^;]*/"mSb-kZ-v2e.ibShadowedLabels[1]" = "github.com\/duraki\/SketchCrapp"/g' "$zhLangPath/MSRegistrationWindow.strings"
/usr/bin/sed -i -e 's/"oEr-Dw-WUj.title"\ =\ [^;]*/"oEr-Dw-WUj.title" = "忘記破解了嗎?"/g' "$zhLangPath/MSRegistrationWindow.strings"
/usr/bin/sed -i -e 's/"pfs-Mp-bgn.title"\ =\ [^;]*/"pfs-Mp-bgn.title" = "哇!您做了什麼!"/g' "$zhLangPath/MSRegistrationWindow.strings"
/usr/bin/sed -i -e 's/"yfB-jh-Is0.placeholderString"\ =\ [^;]*/"yfB-jh-Is0.placeholderString" = "由 @0xduraki \& @elijahtsai 破解"/g' "$zhLangPath/MSRegistrationWindow.strings"
}
# All the code and logic flow to patch the Sketch.app binary, do a code-signature
# and link-resolve the patched Sketch.app.
# - Parameters:
# - First: A version of current application bundle.
# - Second: An array of address of specific version.
# - Third: A path of application executable to patch.
engin() {
local appVersion="$1"
local appPath="$2"
local execPath="$3"
# Version Selector.
echo "[+] Selected Sketch.app version is $appVersion ... SketchCrapp starting ... OK"
echo "[+] Patching offsets for $appVersion ... "
# RUP Review every time when new verison update part.
case "$appVersion" in
"51.3")
patchAncient "${address_param_513[*]}" "$execPath"
;;
"53")
patchOld "${address_param_530[*]}" "$execPath"
;;
"58")
patchLegacy "${address_param_580[*]}" "$execPath"
;;
"63.1")
patchLegacy "${address_param_631[*]}" "$execPath"
;;
"64")
patchLegacy "${address_param_640[*]}" "$execPath"
;;
"65.1")
patchLegacy "${address_param_651[*]}" "$execPath"
;;
"66.1")
patchLegacy "${address_param_661[*]}" "$execPath"
;;
"67"|"67.1")
patchLegacy "${address_param_670[*]}" "$execPath"
;;
"67.2")
patchLegacy "${address_param_672[*]}" "$execPath"
;;
"68")
patchLegacy "${address_param_680[*]}" "$execPath"
;;
"68.1")
patchLegacy "${address_param_681[*]}" "$execPath"
;;
"68.2")
patchLegacy "${address_param_681[*]}" "$execPath"
;;
"69")
patchLegacy "${address_param_690[*]}" "$execPath"
;;
"69.1")
patchLegacy "${address_param_691[*]}" "$execPath"
;;
"69.2")
patchLegacy "${address_param_691[*]}" "$execPath"
;;
"70.2")
patch "${address_param_702[*]}" "$execPath"
;;
"70.3")
patch "${address_param_703[*]}" "$execPath"
;;
"70.4")
patch "${address_param_704[*]}" "$execPath"
;;
"70.5")
patch "${address_param_705[*]}" "$execPath"
;;
"70.6")
patch "${address_param_705[*]}" "$execPath"
;;
"71.1")
patch "${address_param_711[*]}" "$execPath"
;;
"71.2")
patch "${address_param_712[*]}" "$execPath"
;;
*)
printf "[\e[38;5;9mERR\e[0m] Something went wrong, this line should never execute.\n"
printf "[\e[38;5;11mINFO\e[0m] Copy the details below and open a new issue on GitHub repository: \
https://github.com/duraki/SketchCrapp\n"
echo "+==================================================================="
echo "+ Issue details ‹s:sketchcrapp›"
echo "+ Application Path : $appPath"
echo "+ Application Binary: $execPath"
echo "+ Passed version : $bundleVersionString"
echo "+ Binary SHA1 : $appSHA1"
echo "+ Error : patcherr››"
echo "+==================================================================="
finally 1
esac
# Install name tag
if [[ "${nametag_ancient_ver[*]}" =~ "$appVersion" ]]; then
nameTagAncient "$appPath"
elif [[ "${nametag_old_ver[*]}" =~ "$appVersion" ]]; then
nameTagOld "$appPath"
else
nameTag "$appPath"
fi
# Get the path of user default keychain.
userKeyChain="$(security default-keychain -d user | sed -e 's/^[ ]*//g' -e 's/\"//g')"
printf "[+] Checking user default keychain ... "
if ! [ -f "$userKeyChain" ]; then
printf "\e[38;5;9mNot exist\e[0m\n"
echo "[-] User default Keychain does not exist: $userKeyChain"
clean
finally 1
fi
printf "\e[38;5;10mExist\e[0m\n"
# CodeSigning area.
# Check if sketchcrapp certificate already exist.
printf "[+] Checking SketchCrapp identity ... "
security find-identity -p codesigning | grep sketchcrapp >/dev/null
if ! [ "$?" -eq "0" ]; then
printf "\e[38;5;11mNot exist\e[0m\n"
# Certificate does not exist, generate one.
genSelfSignCert
# Import the certificate.
importSelfSignCert "$userKeyChain"
else
printf "\e[38;5;10mExist\e[0m\n"
echo "[+] Skipping certificate creation"
fi
# Sign the application.
signApplication "$appPath" "$userKeyChain"
# Call cleaner to do some housekeeping.
clean
printf "[+] SketchCrapp process \e[38;5;10mcompleted\e[0m. Sketch.app has been patched :)\n"
printf "[+] \e[38;5;11m-- Notice: \e[0m\n"
echo "[+] If a dialogue shows up with message: “Sketch 3.app” can’t be opened"
echo "[+] please right-click the application and select open, "
echo "[+] or go to Settings -› Security and allow opening Sketch.app application."
echo "[+] "
echo "[+] If you are using an old version and a dialogue shows up asking for password"
echo "[+] about \"com.bohemiancoding.sketch3.HockeySDK\""
echo "[+] please enter your login password. Choose \"Always Allow\" to not be asked again."
echo ""
echo "[+] SketchCrapp (A Sketch.app cracking tool)"
echo "[+] https://github.com/duraki/SketchCrapp [by @duraki & @elijahtsai]"
}
# An auto function to patch latest app.
magic() {
local testVersionString="$1"
if [ -z "$testVersionString" ]; then
testVersionString="$latestVersion"
fi
echo "[+] Hello, The magic show is about to start! Are you ready?"
getURLFromVersionString "$testVersionString"
# Check if missing cURL
if ! command -v curl &> /dev/null; then
echo "cURL is not installed on your system."
echo "This should not happen, macOS have cURL built-in."
printf "[\e[38;5;11mFIX\e[0m] Try: brew install curl\n"
printf "[\e[38;5;11mFIX\e[0m] Try: port install curl\n"
printf "[\e[38;5;11mFIX\e[0m] Try: install cURL manually\n"
finally 1;
fi
# Check if missing UNZIP
if ! command -v unzip &> /dev/null; then
echo "UNZIP is not installed on your system."
echo "This should not happen, macOS have UNZIP built-in."
printf "[\e[38;5;11mFIX\e[0m] Try: brew install unzip\n"
printf "[\e[38;5;11mFIX\e[0m] Try: port install unzip\n"
printf "[\e[38;5;11mFIX\e[0m] Try: install UNZIP manually\n"
finally 1;
fi
printf "[+] Checking directory tmp existence ... "
if ! [ -d /tmp ]; then
printf "\e[38;5;9mError\e[0m\n"
echo "Directory tmp does not exist."
finally 1
fi
printf "\e[38;5;10mOK\e[0m\n"
echo "[+] Fetching $downloadURLString ... "
curl "$downloadURLString" --output "/tmp/app.zip"
if ! [ "$?" -eq "0" ]; then
echo "[-] Failed while downloading latest application version!"
echo "[-] Are you connected to the internet? Check your network connection."
clean
finally 1
fi
echo -n "[+] Checking if Sketch.app exist in /tmp ... "
if [ -d "/tmp/Sketch.app" ]; then
echo "Exist. Removing."
rm -rf "/tmp/Sketch.app"
if ! [ "$?" -eq St"0" ]; then
echo "[-] Can't remove existing Sketch.app from /tmp directory."
clean
finally 1
fi
else
echo "Not exist. Continuous."
fi
unzip -q "/tmp/app.zip" -d "/tmp"
if ! [ "$?" -eq "0" ]; then
echo "[-] Can't unzip downloaded archived file of the latest application version."
clean
finally 1
fi
echo -n "[+] Checking if Sketch.app exist in /Applications ... "
if [ -d "/Applications/Sketch.app" ]; then
echo "Exist. Removing."
rm -rf "/Applications/Sketch.app"
if ! [ "$?" -eq "0" ]; then
echo "Fail to remove exist Sketch.app in /Applications directory."
clean
finally 1
fi
else
echo "Not exist. Continuous."
fi
printf "[+] Moving Sketch.app to /Applications directory ... "
reason="$(mv "/tmp/Sketch.app" "/Applications" 2>&1)"
if ! [ "$?" -eq "0" ]; then
printf "\e[38;5;9mFail\e[0m\n"
echo "[-] Failed while moving /tmp/Sketch.app to /Applications directory."
printf "[\e[38;5;11mINFO\e[0m] Reason: $reason\n"
clean
finally 1
fi
printf "\e[38;5;10mSuccessfully.\e[0m\n"
analysisApplication "/Applications/Sketch.app"
}
# Command Line Interface initialization.
# Script startup point. How about we start from banner shell we?
banner
# Check if missing UNZIP
if ! command -v sed &> /dev/null; then
echo "SED is not installed on your system."
echo "This should not happen, macOS have sed built-in."
printf "[\e[38;5;11mFIX\e[0m] Try: brew install sed\n"
printf "[\e[38;5;11mFIX\e[0m] Try: port install sed\n"
printf "[\e[38;5;11mFIX\e[0m] Try: install SED manually\n"
finally 1;
fi
# Check if missing OpenSSL library
if ! command -v openssl &> /dev/null; then
echo "OpenSSL is not installed on your system."
echo "This should not happen, macOS have OpenSSL built-in."
printf "[\e[38;5;11mFIX\e[0m] Try: brew install openssl\n"
printf "[\e[38;5;11mFIX\e[0m] Try: port install openssl\n"
printf "[\e[38;5;11mFIX\e[0m] Try: install openssl manually\n"
finally 1;
fi
# If no option was given by default search /Application or ~/Application .
if [ $# -eq 0 ]; then
echo "SketchCrapp is finding application bundle path ..."
if [ -d "/Applications/Sketch.app" ]; then
# Sketch is found in /Application .
echo "[+] Selected Sketch.app path is </Applications> (auto-detected) ... OK"
analysisApplication "/Applications/Sketch.app"
elif [ -d "$HOME/Applications/Sketch.app" ]; then
# Sketch is found in ~/Application .
echo "[+] Selected Sketch.app path is <$HOME/Applications> (auto-detected) ... OK"
analysisApplication "$HOME/Applications/Sketch.app"
else
printf "[\e[38;5;9mERR\e[0m] Application not found in /Applications or ~/Applications\n"
echo "Try: ./sketchcrapp -a /Custom/Path/For/Applications/Sketch.app"
echo "To get the latest supported version of Sketch"
echo "Try: ./sketchcrapp -m"
finally 1
fi
finally 0
fi
# Option filter (Command-Line Interface parser).
while getopts "ha:mg:" argv; do
case "${argv}" in
h)
usage
;;
a)
appPath="${OPTARG}"
if [ -d "$appPath" ]; then
analysisApplication "$appPath"
else
printf "[\e[38;5;9mERR\e[0m] Given directory is either invaild or not exist.\n"
finally 1
fi
;;
m)
magic
;;
g)
version="${OPTARG}"
magic "$version"
;;
*)
echo "Use -h for more information."
finally 0
;;
esac
done
finally 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment