├── .gitignore ├── APNS ├── README.md └── apnsPem.sh ├── B&A&D ├── README.md ├── archive.config ├── build.sh └── exportOptions │ ├── ad-hoc.plist │ ├── app-store.plist │ ├── development.plist │ └── enterprise.plist ├── LICENSE ├── README.md ├── autoResign ├── README.md ├── aUtoReSiGn.sh └── resign │ ├── EnterPrise_Development.mobileprovision │ ├── EnterPrise_Distribution.mobileprovision │ ├── Entitlements │ ├── developer │ │ └── Entitlements.plist │ ├── free │ │ └── Entitlements.plist │ └── production │ │ └── Entitlements.plist │ ├── Free.mobileprovision │ ├── certificate.png │ ├── provisioning profiles.png │ ├── resign.config │ └── resign.sh ├── class_dump ├── README.md ├── class-dump └── dumpdecrypted.dylib ├── crashMe ├── README.md └── sourcecode.png ├── cydia.md ├── inject_with_jailbreaking ├── AsyncSocket.h ├── AsyncSocket.m ├── Xtrace.h ├── Xtrace.mm ├── build_inject.sh ├── wspx_inject.mm └── wspx_inject.plist ├── isWKoUI ├── README.md └── iswkoui.png ├── jailBreak └── README.md ├── nextDay └── README.md └── pRoxY ├── README.md ├── crontabScript.sh └── proxy_demo.py /.gitignore: -------------------------------------------------------------------------------- 1 | # https://github.com/MrChens/iOS_Tools 2 | 3 | .DS_Store 4 | -------------------------------------------------------------------------------- /APNS/README.md: -------------------------------------------------------------------------------- 1 | 推送证书的生成: 2 | ================ 3 | 4 | 1. 在identifiers-->App IDs中找到对应的appid 5 | 2. 点击edit-->Create Certificate... 6 | 3. 制作CSR文件:打开钥匙串-->证书助理-->从证书颁发机构请求证书(填写账号的邮箱和存储到磁盘) 7 | 4. 返回到刚才的Create Certificate中点击Choose File选择刚才生成的CSR文件然后点击Continue 8 | 5. 下载证书并双击打开钥匙串访问,在左边的证书中选择刚刚弄的好的证书,右键导出为p12文件 9 | 6. 然后使用apnsPem.sh来创建pem文件。(提示输入密码,输入刚才导出p12时的密码) 10 | 11 | Generate apns pem file 12 | ====================== 13 | 14 | 1. Login you apple Developer account in https://developer.apple.com/ 15 | 2. In `Identifiers` click `App IDs` then Choose you `iOS App IDs` which you wanna create apns pem file. 16 | 3. Expanding it and click `edit` 17 | 4. Before you click `Create Certificate...`, you need generate CSR file. 18 | 5. In the `Push Notifications` section click `Create Certificate...` then click `Choose File` upload the CSR file which you created a moment ago. 19 | 6. Then click `Continue` and download the `xx.cer` file. 20 | 7. Double click the `xx.cer` file, and then choose the certificates which you just download amoment ago. 21 | 8. Export the `xx.cer` file as p12 file.(important:remember your password, we will use it in the follow steps.) 22 | 9. Then use the tool `apnsPem.sh` to create apns pem file. 23 | 24 | Generate CSR file(CertificateSigningRequest) 25 | ============================================ 26 | 27 | 1. open `Keychain Access` > `Certificate Assistant` > `Request a Certificate from a Certificate Authority`. 28 | - In the User Email Address field, enter your email address. 29 | - In the Common Name field, create a name for your private key (e.g., John Doe Dev Key). 30 | - The CA Email Address field should be left empty. 31 | - In the "Request is" group, select the "Saved to disk" option. 32 | 2. Click Continue within Keychain Access to complete the CSR generating process. 33 | -------------------------------------------------------------------------------- /APNS/apnsPem.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | if [ $# -lt 2 ]; then 3 | echo "" 4 | echo "\t Usage:" 5 | echo "\t\t ./apnsPem.sh xxx.p12 xxx.pem" 6 | echo "\t\t the xxx.p12 is the file which you export from Keychain Access." 7 | echo "\t\t the xxx.pme is the file name which you generate from xxx.p12." 8 | exit 0 9 | fi 10 | 11 | INAPNSCERTP12=$1 12 | OUTANPSCERTPEM=$2 13 | echo "\t Please enter your password when the p12 file is generated." 14 | openssl pkcs12 -in $INAPNSCERTP12 -out $OUTANPSCERTPEM -nodes 15 | -------------------------------------------------------------------------------- /B&A&D/README.md: -------------------------------------------------------------------------------- 1 | # 环境要求: 2 | 1. OSX 10.8以上. 3 | 2. Xcode8.0以上. 4 | 5 | # 使用方式: 6 | 1. 将`exportOptions`,`build.sh`,`archive.config`放入你项目的根目录 7 | 2. 修改`build.sh`中`ARCHIVE_SCHEME_NAME`,`ARCHIVE_PROJECT_NAME`,`ApplicationLoader_UserName`,`ApplicationLoader_Password`为你对应的 8 | 3. 执行`build.sh archive.config` 9 | 10 | 11 | ### 在使用过程中如果有任何问题或者改良的方案欢迎提issue和pr. 12 | -------------------------------------------------------------------------------- /B&A&D/archive.config: -------------------------------------------------------------------------------- 1 | # TYPE=enterprise appstore ad-hoc development 2 | # Last RELEASE ENTERPRISE BUILDVERSION 100 TODO: 这里的时间用脚本生成 3 | # Last RELEASE APPSTORE BUILDVERSION 130 TODO: 这里的时间用脚本生成. 4 | # RELEASE: indicate whether is need upload dSYMs and ipa to SVN. 5 | # DELIVER_TO_APPSTORE: indicate whether is need upload to AppStore. 6 | 7 | TYPE=enterprise 8 | VERSION=1 9 | EP_BUILDVERSION=0 10 | AS_BUILDVERSION=0 11 | DE_BUILDVERSION=0 12 | DELIVER_TO_APPSTORE=false 13 | RELEASE=true 14 | -------------------------------------------------------------------------------- /B&A&D/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # https://developer.apple.com/library/content/technotes/tn2215/_index.html 3 | # https://itunesconnect.apple.com/docs/UsingApplicationLoader.pdf 4 | # http://www.matrixprojects.net/p/xcodebuild-export-options-plist/ 5 | # http://www.voidcn.com/blog/potato512/article/p-6165228.html 6 | # http://www.jianshu.com/p/bd4c22952e01 7 | # ``有返回值 8 | # ''不做格式化 9 | # ""做格式化 10 | # 0标准输入(stdin),1标准输出(stdout), 2标准错误(stderr) 11 | # error: exportArchive: No applicable devices found. solution: https://github.com/bitrise-io/steps-xcode-archive/issues/37 rvm use system 12 | # xcodebuild exit code :https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man3/sysexits.3.html#//apple_ref/doc/man/3/sysexits 13 | 14 | ALTOOL_DIR="/Applications/Xcode.app/Contents/Applications/Application Loader.app/Contents/Frameworks/ITunesSoftwareService.framework/Versions/A/Support/altool" 15 | ARCHIVE_SCHEME_NAME="wsyun" 16 | ARCHIVE_PROJECT_NAME="wsyun.xcodeproj" 17 | ApplicationLoader_UserName="zhengluff@chinanetcenter.com" 18 | ApplicationLoader_Password="iTunes Producer: zhengluff@chinanetcenter.com" 19 | 20 | 21 | BUGTRACKER_URL="svn://chenshilong@192.168.24.144:8888/tm/flow_browser/BugTracker" 22 | BUGTRACKER_DIR="$HOME/Documents" 23 | BUGTRACKER="BugTracker" 24 | IPA_PREFIX_APPSTORE="${ARCHIVE_SCHEME_NAME}_AppStore_" 25 | IPA_PREFIX_ENTERPRISE="${ARCHIVE_SCHEME_NAME}_ENT_" 26 | CUR_PATH="$PWD" 27 | PROJECT_DIR="${CUR_PATH}" 28 | 29 | BUILD_TIME=`date "+%m-%d-%y, %l.%M %p"` 30 | BUILD_DATE=`date "+%Y-%m-%d"` 31 | EXPORT_TIME=`date "+%Y%m%d%H_%M"` 32 | APP_VERSION="agvtool what-marketing-version -terse1" 33 | 34 | ARCHIVE_FILE_NAME="$ARCHIVE_SCHEME_NAME $BUILD_TIME.xcarchive" 35 | ARCHIVE_FILE_PATH="$HOME/Library/Developer/Xcode/Archives/${BUILD_DATE}/${ARCHIVE_FILE_NAME}" 36 | ARCHIVE_LOG_FILE_NAME="archive.log" 37 | # ARCHIVE_FILE_PATH="$HOME/Library/Developer/Xcode/Archives/2017-06-06/UOne 06-06-17, 3.56 PM.xcarchive" 38 | 39 | 40 | OUTPUT_IPA_APPSTORE="$HOME/Desktop/ipa/${ARCHIVE_SCHEME_NAME}_AppStore/$ARCHIVE_SCHEME_NAME" 41 | OUTPUT_IPA_ENTERPRISE="$HOME/Desktop/ipa/${ARCHIVE_SCHEME_NAME}_EnterPrise/$ARCHIVE_SCHEME_NAME" 42 | 43 | APPSTORE_RESPONED_FILE_NAME="respon.plist" 44 | 45 | function set_publish_mode() { 46 | echo "set UOneConfig.plist to publish mode ${PROJECT_DIR}" 47 | cd "${PROJECT_DIR}/WSPXBrowser" 48 | plutil -p UOneConfig.plist 49 | plutil -replace PMSServiceType -integer 0 UOneConfig.plist 50 | plutil -replace UOneServiceType -integer 0 UOneConfig.plist 51 | plutil -replace CrashMonitor -bool true UOneConfig.plist 52 | plutil -replace NSLogToFile -bool false UOneConfig.plist 53 | plutil -p UOneConfig.plist 54 | sed -i.bak 's/kWspxTest (1)/kWspxTest (0)/g' WSPXUOneDefine.h 55 | sed -i.bak 's/wspxUILog (1)/wspxUILog (0)/g' WSPXUOneDefine.h 56 | sed -i.bak 's/kWspxCustomPhoneTest (1)/kWspxCustomPhoneTest (0)/g' WSPXUOneDefine.h 57 | sed -i.bak 's/kSwitchToLocalJsFile (1)/kSwitchToLocalJsFile (0)/g' WSPXUOneDefine.h 58 | 59 | rm WSPXUOneDefine.h.bak 60 | echo 'set WSPXUOneDefine.h to RELEASE DONE' 61 | } 62 | 63 | function build_enterprise() { 64 | echo -e "构建企业版${ARCHIVE_SCHEME_NAME} build at: ${BUILD_TIME}" 65 | echo -e "" 66 | set_publish_mode 67 | cd $PROJECT_DIR 68 | echo "arguments $* " 69 | CONFIGURATION_TYPE=$4 70 | 71 | agvtool what-marketing-version # update CFBundleShortVersionString 72 | agvtool new-marketing-version $1 73 | 74 | agvtool what-version # update CFBundleVersion 75 | agvtool new-version -all $[ $2+1 ] 76 | echo 'clear...' 77 | xcodebuild clean -project "$ARCHIVE_PROJECT_NAME" -configuration "$CONFIGURATION_TYPE" -quiet 78 | echo -e "xcodebuild clean exit code:$?" 79 | 80 | echo 'archive...' 81 | if [[ -e "${ARCHIVE_LOG_FILE_NAME}" ]]; then 82 | rm $ARCHIVE_LOG_FILE_NAME 83 | fi 84 | xcodebuild archive -project ./"$ARCHIVE_PROJECT_NAME" -scheme "$ARCHIVE_SCHEME_NAME" -configuration "$CONFIGURATION_TYPE" -archivePath "$ARCHIVE_FILE_PATH" PROVISIONING_PROFILE="Automatic"#CODE_SIGN_IDENTITY="iPhone Developer" -quiet > $ARCHIVE_LOG_FILE_NAME #PROVISIONING_PROFILE="Automatic" #-quiet > /dev/null #貌似不指定provisioning_profile才是真的automatic 85 | checkXcodebuildExitCode 86 | rm -r "build" 87 | echo 'exportArchive...' 88 | xcodebuild -exportArchive -archivePath "$ARCHIVE_FILE_PATH" -exportPath "$CUR_PATH" -exportOptionsPlist ./exportOptions/$3.plist 89 | 90 | echo -e "move ipa file to :$OUTPUT_IPA_ENTERPRISE`$APP_VERSION`/" 91 | if [[ ! -e "$OUTPUT_IPA_ENTERPRISE`$APP_VERSION`" ]]; then 92 | echo -e "create ipa directory.:$OUTPUT_IPA_ENTERPRISE`$APP_VERSION`" 93 | mkdir $OUTPUT_IPA_ENTERPRISE`$APP_VERSION` 94 | fi 95 | 96 | rm -i -f "$OUTPUT_IPA_ENTERPRISE`$APP_VERSION`/"*.ipa 97 | 98 | cp -i "$ARCHIVE_SCHEME_NAME.ipa" "$OUTPUT_IPA_ENTERPRISE`$APP_VERSION`/${IPA_PREFIX_ENTERPRISE}${EXPORT_TIME}.ipa" 99 | if [[ -e "$OUTPUT_IPA_ENTERPRISE`$APP_VERSION`/${IPA_PREFIX_ENTERPRISE}${EXPORT_TIME}.ipa" ]]; then 100 | echo "open directory===>$OUTPUT_IPA_ENTERPRISE`$APP_VERSION`/" 101 | open "$OUTPUT_IPA_ENTERPRISE`$APP_VERSION`/" 102 | fi 103 | } 104 | 105 | function build_appStore() { 106 | echo -e "构建商店版${ARCHIVE_SCHEME_NAME} build at: ${BUILD_TIME}" 107 | echo -e "" 108 | set_publish_mode 109 | cd "$PROJECT_DIR/AppStore" 110 | echo "arguments $*" 111 | 112 | agvtool what-marketing-version 113 | agvtool new-marketing-version $1 114 | 115 | agvtool what-version 116 | agvtool new-version -all $[ $2+2 ] 117 | echo 'clear...' 118 | xcodebuild clean -project "$ARCHIVE_PROJECT_NAME" -configuration Release -quiet 119 | echo -e "xcodebuild clean exit code:$?" 120 | 121 | echo 'archive...' 122 | if [[ -e "${ARCHIVE_LOG_FILE_NAME}" ]]; then 123 | rm $ARCHIVE_LOG_FILE_NAME 124 | fi 125 | xcodebuild archive -project ./"$ARCHIVE_PROJECT_NAME" -scheme "$ARCHIVE_SCHEME_NAME" -configuration Release -archivePath "$ARCHIVE_FILE_PATH" CODE_SIGN_IDENTITY="iPhone Developer" -quiet > $ARCHIVE_LOG_FILE_NAME #PROVISIONING_PROFILE="Automatic" -quiet > /dev/null #貌似不指定provisioning_profile才是真的automatic 126 | 127 | checkXcodebuildExitCode 128 | 129 | rm -r "build" 130 | echo 'exportArchive...' 131 | xcodebuild -exportArchive -archivePath "$ARCHIVE_FILE_PATH" -exportPath "$OUTPUT_IPA_APPSTORE`$APP_VERSION`" -exportOptionsPlist ../exportOptions/$3.plist 132 | 133 | echo -e "move ipa file to :$OUTPUT_IPA_APPSTORE`$APP_VERSION`/" 134 | if [[ ! -e "$OUTPUT_IPA_APPSTORE`$APP_VERSION`" ]]; then 135 | echo -e "create ipa directory.:$OUTPUT_IPA_APPSTORE`$APP_VERSION`" 136 | mkdir $OUTPUT_IPA_APPSTORE`$APP_VERSION` 137 | 138 | fi 139 | 140 | mv -i "$OUTPUT_IPA_APPSTORE`$APP_VERSION`/$ARCHIVE_SCHEME_NAME.ipa" "$OUTPUT_IPA_APPSTORE`$APP_VERSION`/${IPA_PREFIX_APPSTORE}${EXPORT_TIME}.ipa" 141 | if [[ -e "$OUTPUT_IPA_APPSTORE`$APP_VERSION`/${IPA_PREFIX_APPSTORE}${EXPORT_TIME}.ipa" ]]; then 142 | echo "open directory===>$OUTPUT_IPA_APPSTORE`$APP_VERSION`/" 143 | open "$OUTPUT_IPA_APPSTORE`$APP_VERSION`/" 144 | fi 145 | } 146 | 147 | function deliver_appStore() { 148 | echo -e "Uploading Your Application Binary Files with altool..." 149 | "$ALTOOL_DIR" --upload-app -f "$OUTPUT_IPA_APPSTORE`$APP_VERSION`/${IPA_PREFIX_APPSTORE}${EXPORT_TIME}.ipa" -u "$ApplicationLoader_UserName" -p @keychain:"$ApplicationLoader_Password" --output-format xml > $APPSTORE_RESPONED_FILE_NAME 150 | } 151 | 152 | function echoSVNStatus() { 153 | echo -e "" 154 | echo -e "Time:`date "+%m-%d-%y, %l.%M.%S %p"`" 155 | echo -e "SVN STATUS:" 156 | svn status 157 | } 158 | 159 | function bugTracker() { 160 | echo -e "checkout BugTracker..." 161 | svn checkout ${BUGTRACKER_URL} ${BUGTRACKER_DIR}/${BUGTRACKER} 1> /dev/null 162 | 163 | if [[ ! -e "${BUGTRACKER_DIR}/${BUGTRACKER}" ]]; then 164 | echo -e "create BugTracker directory." 165 | mkdir ${BUGTRACKER_DIR}/$BUGTRACKER 166 | svn mkdir -m "create BugTracker directory." ${BUGTRACKER_URL} 167 | svn checkout ${BUGTRACKER_URL} ${BUGTRACKER_DIR}/${BUGTRACKER} 1> /dev/null 168 | fi 169 | 170 | dSYMsFile=`ls "${ARCHIVE_FILE_PATH}"/dSYMs/` 171 | BaseString=`xcrun dwarfdump --uuid "${ARCHIVE_FILE_PATH}/dSYMs/${dSYMsFile}" | sed -n -e '/UUID:/p' | grep "UUID:.*" | awk '{split( $0, a, " "); print a[2]}' ` 172 | commitMessage=`echo $BaseString | sed 's/ /;/g'` 173 | UUIDFile=`echo $BaseString | sed 's/-//g' | sed 's/ //g' ` 174 | echo -e "UUIDFILE:${UUIDFile}" 175 | 176 | filePath=${BUGTRACKER_DIR}/${BUGTRACKER}/${ARCHIVE_SCHEME_NAME}/`$APP_VERSION`/${UUIDFile} 177 | mkdir -p $filePath 178 | 179 | echo -e "copy dSYMsFile:${dSYMsFile} to BugTracker..." 180 | cp -R "${ARCHIVE_FILE_PATH}/dSYMs/${dSYMsFile}" "${filePath}/${UUIDFile}.dSYM" 181 | if [[ $? -gt 0 ]]; then 182 | echo "cp dSYMsFile:${dSYMsFile} failed" 183 | fi 184 | 185 | if [[ $1 == 'enterprise' ]]; then 186 | echo -e "copy enterprise ipa to BugTracker..." 187 | cp -R "$OUTPUT_IPA_ENTERPRISE`$APP_VERSION`/${IPA_PREFIX_ENTERPRISE}${EXPORT_TIME}.ipa" "${filePath}" 188 | if [[ $? -gt 0 ]]; then 189 | echo -e "copy ipa failed:$OUTPUT_IPA_ENTERPRISE`$APP_VERSION`/${IPA_PREFIX_ENTERPRISE}${EXPORT_TIME}.ipa" 190 | fi 191 | else 192 | echo -e "copy app-store ipa to BugTracker..." 193 | cp -R "$OUTPUT_IPA_APPSTORE`$APP_VERSION`/${IPA_PREFIX_APPSTORE}${EXPORT_TIME}.ipa" "${filePath}" 194 | if [[ $? -gt 0 ]]; then 195 | echo -e "copy ipa failed:$OUTPUT_IPA_APPSTORE`$APP_VERSION`/${IPA_PREFIX_APPSTORE}${EXPORT_TIME}.ipa" 196 | fi 197 | fi 198 | 199 | cd $BUGTRACKER_DIR/$BUGTRACKER 200 | echoSVNStatus 201 | 202 | echo -e "SVN ADD" 203 | svn add ${ARCHIVE_SCHEME_NAME} --force 204 | 205 | echo "SVN COMMIT" 206 | svn commit -m "version:${APP_VERSION} $1=>${commitMessage}" 207 | 208 | echoSVNStatus 209 | } 210 | 211 | SUCCESS_MESSAGE="success-message" 212 | PRODUCT_ERRORS="product-errors" 213 | 214 | function checkResponse() { 215 | 216 | if [[ ! -e $APPSTORE_RESPONED_FILE_NAME ]]; then 217 | echo -e "" 218 | echo -e "file -->$APPSTORE_RESPONED_FILE_NAME not exist!!!" 219 | exit 1 220 | fi 221 | 222 | echo -e "---------------------------->check response<----------------------------" 223 | 224 | RETURN=`plutil -p $1 | grep "$SUCCESS_MESSAGE"` 225 | if [[ $RETURN == *"$SUCCESS_MESSAGE"* ]]; then 226 | STATUS=`plutil -p $1 | sed -n -e "/$SUCCESS_MESSAGE/,/dev-tools/p"` 227 | echo -e "response message:" 228 | echo -e "$STATUS" 229 | rm $1 230 | return 0 231 | fi 232 | 233 | RETURN=`plutil -p $1 | grep "$PRODUCT_ERRORS"` 234 | if [[ $RETURN == *"$PRODUCT_ERRORS"* ]]; then 235 | STATUS=`plutil -p $1 | sed -n -e "/$PRODUCT_ERRORS/,/]/p"` 236 | echo -e "response message:" 237 | echo -e "$STATUS" 238 | return 1 239 | fi 240 | 241 | return 1 242 | } 243 | 244 | function checkXcodebuildExitCode() { 245 | XcodebuildExitCode=$? 246 | echo -e "xcodebuild archive exit code:${XcodebuildExitCode}" 247 | 248 | if [[ $XcodebuildExitCode == 0 ]]; then 249 | echo -e "xcodebuild archive succed!" 250 | rm $ARCHIVE_LOG_FILE_NAME 251 | else 252 | echo -e "xocodebuild archive failed, please see ${ARCHIVE_LOG_FILE_NAME}" 253 | echo -e "open ${ARCHIVE_LOG_FILE_NAME}" 254 | open $ARCHIVE_LOG_FILE_NAME 255 | exit 1 256 | fi 257 | } 258 | 259 | function usage() { 260 | echo -e "" 261 | echo -e "build.sh command" 262 | echo -e "command:" 263 | echo -e " ./build.sh reset reset wscloudConfig.plist,WSPXUOneDefine.h to the publish mode." 264 | echo -e " ./build.sh archive.config reset wscloudConfig.plist,WSPXUOneDefine.h and archive project then output ipa." 265 | echo -e "" 266 | } 267 | 268 | function faq() { 269 | echo -e "系统要求:Xcode 8.1 " 270 | echo -e "使用该脚本之前请确保已经在本机安装了对应的证书和描述文件." 271 | echo -e "error: exportArchive: No applicable devices found. solution: https://github.com/bitrise-io/steps-xcode-archive/issues/37 rvm use system" 272 | 273 | } 274 | 275 | if [ $# != 1 ] ; then 276 | usage 277 | exit 0 278 | fi 279 | 280 | faq 281 | 282 | if [[ $1 == 'reset' ]]; then 283 | set_publish_mode 284 | elif [[ $1 == *"config"* ]]; then 285 | source ./$1 286 | if [[ $TYPE == 'enterprise' ]]; then 287 | build_enterprise $VERSION $EP_BUILDVERSION enterprise Release 288 | if [[ $RELEASE == 'true' ]]; then 289 | bugTracker $TYPE 290 | fi 291 | elif [[ $TYPE == 'appstore' ]]; then 292 | build_appStore $VERSION $AS_BUILDVERSION app-store 293 | if [[ $DELIVER_TO_APPSTORE == 'true' ]]; then 294 | deliver_appStore 295 | checkResponse $APPSTORE_RESPONED_FILE_NAME 296 | result=$? 297 | echo -e "---------------------------- checkResponse return value:$result ----------------------------" 298 | if [[ $result == 0 ]]; then 299 | bugTracker $TYPE 300 | fi 301 | fi 302 | 303 | elif [[ $TYPE == 'ad-hoc' ]]; then 304 | build_appStore $VERSION $BUILDVERSION ad-hoc 305 | elif [[ $TYPE == 'development' ]]; then 306 | build_enterprise $VERSION $DE_BUILDVERSION development Debug 307 | fi 308 | else 309 | usage 310 | fi 311 | -------------------------------------------------------------------------------- /B&A&D/exportOptions/ad-hoc.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | stripSwiftSymbols 6 | 7 | signingStyle 8 | automatic 9 | thinning 10 | <none> 11 | compileBitcode 12 | 13 | method 14 | ad-hoc 15 | uploadBitcode 16 | 17 | teamID 18 | xxxxxx 19 | uploadSymbols 20 | 21 | manifest 22 | 23 | appURL 24 | http://xxxx/UOne-free-2.2.6.ipa?t=1472549634827 25 | displayImageURL 26 | http://xxxx.UOne_AppIcon_57x57.png 27 | fullSizeImageURL 28 | http://xxxx.UOne_AppIcon_512x512.png 29 | subtitle 30 | XXXX 31 | title 32 | XXXX 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /B&A&D/exportOptions/app-store.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | stripSwiftSymbols 6 | 7 | signingStyle 8 | automatic 9 | thinning 10 | <none> 11 | compileBitcode 12 | 13 | method 14 | app-store 15 | uploadBitcode 16 | 17 | teamID 18 | xxxxxx 19 | uploadSymbols 20 | 21 | manifest 22 | 23 | appURL 24 | http://cache.default.server.matocloud.com:39900/static.server.matocloud.com:8080/staticresource/static/cert/bms/app/package/UOne-free-2.2.6.ipa?t=1472549634827 25 | displayImageURL 26 | http://static.server.matocloud.com:8080/staticresource/static/cert/bms/app/package/com.chinanetcenter.UOne_AppIcon_57x57.png 27 | fullSizeImageURL 28 | http://static.server.matocloud.com:8080/staticresource/static/cert/bms/app/package/com.chinanetcenter.UOne_AppIcon_512x512.png 29 | subtitle 30 | XXXX 31 | title 32 | XXXX 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /B&A&D/exportOptions/development.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | thinning 6 | <none> 7 | signingStyle 8 | automatic 9 | stripSwiftSymbols 10 | 11 | compileBitcode 12 | 13 | method 14 | development 15 | uploadBitcode 16 | 17 | teamID 18 | xxxxxx 19 | provisioningProfiles 20 | 21 | com.xxxx.yyyy 22 | provisioningProfilesName_dev 23 | 24 | manifest 25 | 26 | appURL 27 | http://cache.default.server.matocloud.com:39900/static.server.matocloud.com:8080/staticresource/static/cert/bms/app/package/UOne-free-2.2.6.ipa?t=1472549634827 28 | displayImageURL 29 | http://static.server.matocloud.com:8080/staticresource/static/cert/bms/app/package/com.chinanetcenter.UOne_AppIcon_57x57.png 30 | fullSizeImageURL 31 | http://static.server.matocloud.com:8080/staticresource/static/cert/bms/app/package/com.chinanetcenter.UOne_AppIcon_512x512.png 32 | subtitle 33 | U玩 34 | title 35 | U玩 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /B&A&D/exportOptions/enterprise.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | thinning 6 | <none> 7 | signingStyle 8 | automatic 9 | stripSwiftSymbols 10 | 11 | compileBitcode 12 | 13 | method 14 | enterprise 15 | uploadBitcode 16 | 17 | teamID 18 | xxxxx 19 | provisioningProfiles 20 | 21 | com.xxxx.yyyy 22 | provisioningProfilesName 23 | 24 | manifest 25 | 26 | appURL 27 | http://xxxx/UOne-free-2.2.6.ipa?t=1472549634827 28 | displayImageURL 29 | http://xxxx.UOne_AppIcon_57x57.png 30 | fullSizeImageURL 31 | http://xxxx.UOne_AppIcon_512x512.png 32 | subtitle 33 | XXXX 34 | title 35 | XXXX 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2017, ShiLong Chen 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # iOS_Tools 2 | 3 | 放一些在iOS开发中自己写的垃圾脚本工具[传送门][iOS_Tools] 4 | 5 | - `aUtoReSiGn` 是使用企业签名来做ipa包的自动重签名+自动安装重签名后的ipa包到测试设备中[传送门][aUtoReSiGn] 6 | - `inject_with_jailbreaking` 用来在越狱设备中hook某些app做些调研什么的[传送门][jailbreaking] 7 | - `class_dump` 对ipa文件进行头文件的导出[传送门][class_dump] 8 | - `codeObfuscated` 改良版的代码混淆[传送门][codeObfuscated] 9 | - `B&A&D` 构建,打包,并提交Itunesconnect上传dsym文件到svn以供后续Debug使用[传送门][B&A&D] 10 | - `isWKoUI` 检测app内的页面是`WKWebview`还是`UIWebview`[传送门][isWKoUI] 11 | - `crashMe` 演示如何通过`crash`文件排查`app`崩溃的问题[ 传送门][crashMe] 12 | - `nextDay` 演示什么叫做永远没空研究系列[传送门][nextDay] 13 | - `jailBreak` 记录越狱笔记[传送门][jailBreak] 14 | 15 | ### 在使用过程中如果有任何问题或者改良的方案欢迎提issue和pr. 16 | 17 | [jailbreaking]:https://github.com/MrChens/iOS_Tools/tree/master/inject_with_jailbreaking 18 | [class_dump]:https://github.com/MrChens/iOS_Tools/tree/master/class_dump 19 | [codeObfuscated]:https://github.com/MrChens/codeObfuscated 20 | [aUtoReSiGn]:https://github.com/MrChens/iOS_Tools/tree/master/autoResign 21 | [iOS_Tools]:https://github.com/MrChens/iOS_Tools 22 | [B&A&D]:https://github.com/MrChens/iOS_Tools/tree/master/B%26A%26D 23 | [isWKoUI]:https://github.com/MrChens/iOS_Tools/tree/master/isWKoUI 24 | [crashMe]:https://github.com/MrChens/iOS_Tools/tree/master/crashMe 25 | [nextDay]:https://github.com/MrChens/iOS_Tools/tree/master/nextDay 26 | [jailBreak]:https://github.com/MrChens/iOS_Tools/tree/master/jailBreak 27 | -------------------------------------------------------------------------------- /autoResign/README.md: -------------------------------------------------------------------------------- 1 | # 1. 环境要求: 2 | 3 | 4 | 1. OSX 10.8以上. 5 | 2. Xcode8.0以上. 6 | 7 | # 2. 使用方式: 8 | 9 | 1. 直接在终端运行`aUtoReSiGn.sh`. 10 | 2. 将要需要企业重签名的`ipa`放入`input文件夹`中. 11 | 3. 企业重签名后的`ipa`文件会自动放入`output文件夹`中. 12 | 4. 默认情况下重签名的是Distribution版的,如需重签名`Development`版的请修改`resign.config`中的`GET_TASK_ALLOW`为`true` 13 | 5. 如若不需要自动重签名,请直接运行`resign.sh`脚本 14 | 6. 如若需要自动安装`ipa`到手机上,请修改`resign.config`中的`AUTO_INSTALL_IPA`为`true` 15 | 16 | # 3. 重要的: 17 | 18 | 在使用该脚本前您需要确保做了以下几件事: 19 | 20 | **P.S.:请看完全文后再配置,后面附有文件的详细获取/修改步骤** Development和Distribution的区别在于Development的重签名是可以`get-task-allow` 21 | 22 | ## 3.1.1 Development配置 23 | 24 | - 配置`Development`的企业证书在本地的电脑中(钥匙串中) 25 | - 将您下载的`Development`版的`xx.mobileprovision`放入`resign`目录中并重命名为`EnterPrise_Development.mobileprovision`,文件结构如下图`文件结构`所示 26 | - 修改`resign`中`Entitlements/developer/Entitlements.plist`的配置 27 | - 在`resign.config`文件中修改`CODESIGN_IDENTITIES_DEV`的值为您`Development`版的企业证书名字 28 | 29 | ## 3.1.2 Distribution配置 30 | 31 | - 配置`Distribution`的企业证书在本地的电脑中(钥匙串中) 32 | - 将您下载的`Distribution`版的`yy.mobileprovision`放入`resign`目录中并重命名为`EnterPrise_Distribution.mobileprovision`,文件结构如下图`文件结构`所示 33 | - 修改`resign`中`Entitlements/production/Entitlements.plist`的配置 34 | - 在`resign.config`文件中修改`CODESIGN_IDENTITIES`的值为您`Distribution`版的企业证书名字 35 | 36 | ## 3.1.3 free配置 37 | 38 | - 配置`free`的企业证书在本地的电脑中(钥匙串中) 39 | - 将您下载的`free`版的`yy.mobileprovision`放入`resign`目录中并重命名为`Free.mobileprovision`,文件结构如下图`文件结构`所示 40 | - 修改`resign`中`Entitlements/free/Entitlements.plist`的配置 41 | - 在`resign.config`文件中修改`CODESIGN_IDENTITIES_FREE`的值为您`Free`版的证书名字 42 | 43 | ## 3.2 如何修改对应的`Entitlements.plist` 44 | 45 | - 假设你的`teamID`为:`yourTeamID` 46 | - 假设你的`application-identifier`:为`yourTeamID.com.xxx.xxx` 47 | - 将`application-identifier`中的`yyyy.com.xxx.xxx`改为`yourTeamID.com.xxx.xxx` 48 | - 将`keychain-access-groups`的中的`yyyy.*`改为`yourTeamID.*` 49 | 50 | 如果看不懂上面说的是什么鬼. 51 | - Development配置 52 | - 将`Entitlements/developer/Entitlements.plist`中的`application-identifier`的值,改为`EnterPrise_Development.mobileprovision`文件中`application-identifier`中对应的值 53 | - 将`Entitlements/developer/Entitlements.plist`中的`keychain-access-groups`的值,改为`EnterPrise_Development.mobileprovision`文件中`keychain-access-groups`中对应的值 54 | 55 | - Distribution配置 56 | - 将`Entitlements/production/Entitlements.plist`中的`application-identifier`的值,改为`EnterPrise_Distribution.mobileprovision`文件中`application-identifier`中对应的值 57 | - 将`Entitlements/production/Entitlements.plist`中的`keychain-access-groups`的值,改为`EnterPrise_Distribution.mobileprovision`文件中`keychain-access-groups`中对应的值 58 | 59 | - Free配置 60 | - 将`Entitlements/free/Entitlements.plist`中的`application-identifier`的值,改为`Free.mobileprovision`文件中`application-identifier`中对应的值 61 | - 将`Entitlements/free/Entitlements.plist`中的`keychain-access-groups`的值,改为`Free.mobileprovision`文件中`keychain-access-groups`中对应的值 62 | 63 | ## 3.3 如何获取对应的`xx.mobileprovision` 64 | 65 | - Development 66 | - 登陆你的企业开发者账号,选择`Provisioning Profiles`下的`Development`下载`Type`为`iOS Development`的`Provisioning Profiles`文件(P.S.:没试过`Type`为`iOS UniversalDistribution`的) 67 | - Distribution 68 | - 登陆你的企业开发者账号,选择`Provisioning Profiles`下的`Distribution`下载`Type`为`iOS Distribution`的`Provisioning Profiles`文件(P.S.:没试过`Type`为`iOS UniversalDistribution`的) 69 | - Free 70 | - 在Xcode中登录你的Apple ID,然后利用Xcode下载 71 | - PS:目前处于实验阶段,等有空了再来补充完善free版本的签名文档 72 | 73 | ## 3.4 如何获取您证书的名字 74 | - Development 75 | - 打开电脑中的`Keychain Access` 76 | - 找到您的`Development`企业证书,并双击 77 | - 复制证书`Common Name`中对应的值到`resign.config`的`CODESIGN_IDENTITIES_DEV` 78 | - Distribution 79 | - 打开电脑中的`Keychain Access` 80 | - 找到您的`Distribution`企业证书,并双击 81 | - 复制证书`Common Name`中对应的值到`resign.config`的`CODESIGN_IDENTITIES` 82 | - Free 83 | - 打开电脑中的`Keychain Access` 84 | - 找到您的`Free`证书,并双击 85 | - 复制证书`Common Name`中对应的值到`resign.config`的`CODESIGN_IDENTITIES_FREE` 86 | 87 | ## 3.5 如何使用自动安装重签名后的ipa到手机 88 | - 先使用数据连接线将手机和Mac连接 89 | - 修改`resign.config`中的`AUTO_INSTALL_IPA`为`true` 90 | - 运行`aUtoReSiGn.sh`脚本 91 | 92 | ### 如果不想使用自动重签名,可以将`xx.ipa`放在`resign`目录下,并执行脚本`resign.sh` 93 | 94 | --- 95 | 96 | # 文件结构: 97 | 98 | 99 | ``` 100 | autoResign 101 | ├── README.md 102 | ├── aUtoReSiGn.sh 103 | ├── input 104 | ├── output 105 | └── resign 106 | ├── EnterPrise_Development.mobileprovision 107 | ├── EnterPrise_Distribution.mobileprovision 108 | ├── Entitlements 109 | │   ├── developer 110 | │   ├── free 111 | │   └── production 112 | ├── Free.mobileprovision 113 | ├── certificate.png 114 | ├── provisioning\ profiles.png 115 | ├── resign.config 116 | └── resign.sh 117 | ``` 118 | 119 | ### 在使用过程中如果有任何问题或者改良的方案欢迎提issue和pr. 120 | 121 | --> 122 | -------------------------------------------------------------------------------- /autoResign/aUtoReSiGn.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | OUTPUT_DIR="output" 3 | INPUT_DIR="input" 4 | RESIGN_DIR="resign" 5 | MYPATH=$(dirname "$0") 6 | INPUT_PATH="${MYPATH}/${INPUT_DIR}" 7 | OUTPUT_PATH="${MYPATH}/${OUTPUT_DIR}" 8 | RESIGN_PATH="${MYPATH}/${RESIGN_DIR}" 9 | source ./resign/resign.config 10 | PROVISIONING_PROFILE=$NEW_MOBILEPROVISION 11 | CURRENT_TIME_FORMAT="+%m-%d-%y, %l.%M.%S %p" 12 | 13 | WHICH_BREW=`which brew` 14 | WHICH_FSWATCH=`which fswatch` 15 | WHICH_IDEVICEINSTALLER=`which ideviceinstaller` 16 | 17 | SCAN_TITME=1 #扫描文件变化的间隔 1/秒 18 | 19 | function installHomebrew() { 20 | echo "auto install Homebrew:" 21 | echo "if any Error shows, you may need this:" 22 | echo "https://brew.sh" 23 | /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" 24 | } 25 | 26 | function checkPathExist() { 27 | if [[ ! -e $INPUT_PATH ]]; then 28 | echo "MKDIR ${INPUT_PATH}" 29 | mkdir $INPUT_PATH 30 | fi 31 | 32 | if [[ ! -e $OUTPUT_PATH ]]; then 33 | echo "MKDIR ${OUTPUT_PATH}" 34 | mkdir $OUTPUT_PATH 35 | fi 36 | } 37 | 38 | function checkFswatch() { 39 | # echo -e "MYPATH:$MYPATH" 40 | # echo -e "INPUT_PATH:$INPUT_PATH" 41 | # exit 1 42 | echo "checking fswatch status ..." 43 | if [[ ${WHICH_FSWATCH} == *"fswatch"* ]]; then 44 | echo "fswatch is installed." 45 | else 46 | if [[ ${WHICH_BREW} == *"brew"* ]]; then 47 | echo "brew has installed." 48 | echo "auto install fswatch, please wait I'm working on:" 49 | brew install fswatch 50 | else 51 | installHomebrew 52 | fi 53 | fi 54 | } 55 | 56 | 57 | function checkIdeviceinstaller() { 58 | echo "checking ideviceinstaller status ..." 59 | if [[ ${WHICH_IDEVICEINSTALLER} == *"ideviceinstaller"* ]]; then 60 | echo "ideviceinstaller is installed." 61 | else 62 | if [[ ${WHICH_BREW} == *"brew"* ]]; then 63 | echo "" 64 | echo "brew has installed." 65 | echo "auto install ideviceinstaller, please wait I'm working on:" 66 | echo "if any Error shows, mybe you can use following command:" 67 | echo " 68 | brew update 69 | brew uninstall --ignore-dependencies libimobiledevice 70 | brew uninstall --ignore-dependencies usbmuxd 71 | brew install --HEAD usbmuxd 72 | brew unlink usbmuxd 73 | brew link usbmuxd 74 | brew install --HEAD libimobiledevice 75 | or 76 | brew uninstall ideviceinstaller 77 | brew uninstall libimobiledevice 78 | brew install --HEAD libimobiledevice 79 | brew link --overwrite libimobiledevice 80 | brew install ideviceinstaller 81 | brew link --overwrite ideviceinstaller 82 | " 83 | brew install ideviceinstaller 84 | else 85 | installHomebrew 86 | fi 87 | fi 88 | } 89 | 90 | function doInstall() { 91 | echo "call doInstall with:$1" 92 | if [[ -f "${OUTPUT_PATH}/${1}" ]]; then 93 | echo "READY TO INSTALL ${1} TO IPHONE" 94 | ideviceinstaller -g "${OUTPUT_PATH}/${1}" 95 | else 96 | echo "${1} NOT EXIST" 97 | fi 98 | } 99 | 100 | function doResignWork() { 101 | echo "call doResignWork with:$1" 102 | if [[ -f "${INPUT_PATH}/${1}" ]]; then 103 | echo "READY TO RESIGN ${1}" 104 | APP_NAME=${1} 105 | # echo "@1CurrentPath:$PWD" 106 | cp "$INPUT_PATH/${APP_NAME}" "${RESIGN_PATH}/" 107 | # echo "@2CurrentPath:$PWD" 108 | cd "${RESIGN_PATH}/" 109 | # echo "@3CurrentPath:$PWD" 110 | "./resign.sh" $APP_NAME $GET_TASK_ALLOW 111 | cd "-" 112 | # echo "@4CurrentPath:$PWD" 113 | rm -rf "${RESIGN_PATH}/${APP_NAME}" 114 | FINAL_FILE=`ls ${RESIGN_PATH} | grep "ipa"` 115 | if [[ -f "${RESIGN_PATH}/${FINAL_FILE}" ]]; then 116 | mv "${RESIGN_PATH}/${FINAL_FILE}" "${OUTPUT_PATH}" 117 | else 118 | echo "failed: file not exist" 119 | fi 120 | echo "TIME:`date "${CURRENT_TIME_FORMAT}"`" 121 | else 122 | echo "${1} NOT EXIST" 123 | fi 124 | 125 | } 126 | 127 | function monitor_ipa() { 128 | fswatch -l $SCAN_TITME -v --monitor=fsevents_monitor -0 "${INPUT_PATH}/" "${OUTPUT_PATH}/" | while read -d "" event 129 | do 130 | echo "FINE HAS CHANGED EVENT:${event}" 131 | if [[ ${event} == *"${INPUT_DIR}"* && ${event} == *"ipa" && ${event} != *"TM.ipa" ]]; then 132 | echo "HANDLE INPUT_DIR EVENT:" 133 | IFS='/' read -ra array <<< ${event} 134 | for i in ${array[@]}; do 135 | if [[ ${i} == *"ipa" ]]; then 136 | doResignWork "${i}" 137 | fi 138 | done 139 | elif [[ ${event} == *"${OUTPUT_DIR}"* ]]; then 140 | echo "HANDLE OUTPUT_DIR EVNET:" 141 | IFS='/' read -ra array <<< ${event} 142 | for i in ${array[@]}; do 143 | if [[ ${i} == *"TM.ipa" ]]; then 144 | doInstall "${i}" 145 | fi 146 | done 147 | fi 148 | done 149 | } 150 | 151 | 152 | checkPathExist 153 | checkFswatch 154 | checkIdeviceinstaller 155 | monitor_ipa 156 | -------------------------------------------------------------------------------- /autoResign/resign/EnterPrise_Development.mobileprovision: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrChens/iOS_Tools/54715f6e51467838ff6a549bb8f6e5bd44a1d72e/autoResign/resign/EnterPrise_Development.mobileprovision -------------------------------------------------------------------------------- /autoResign/resign/EnterPrise_Distribution.mobileprovision: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrChens/iOS_Tools/54715f6e51467838ff6a549bb8f6e5bd44a1d72e/autoResign/resign/EnterPrise_Distribution.mobileprovision -------------------------------------------------------------------------------- /autoResign/resign/Entitlements/developer/Entitlements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | application-identifier 6 | yyyy.com.xxx.xxx 7 | com.apple.developer.team-identifier 8 | yyyy 9 | com.apple.developer.associated-domains 10 | * 11 | aps-environment 12 | development 13 | get-task-allow 14 | 15 | keychain-access-groups 16 | 17 | yyyy.* 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /autoResign/resign/Entitlements/free/Entitlements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | application-identifier 6 | yyyy.com.xxx.xxx 7 | com.apple.developer.team-identifier 8 | yyyy 9 | aps-environment 10 | development 11 | com.apple.developer.associated-domains 12 | * 13 | get-task-allow 14 | 15 | keychain-access-groups 16 | 17 | yyyy.* 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /autoResign/resign/Entitlements/production/Entitlements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | application-identifier 6 | yyyy.com.xxx.xxx 7 | aps-environment 8 | production 9 | get-task-allow 10 | 11 | keychain-access-groups 12 | 13 | yyyy.* 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /autoResign/resign/Free.mobileprovision: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrChens/iOS_Tools/54715f6e51467838ff6a549bb8f6e5bd44a1d72e/autoResign/resign/Free.mobileprovision -------------------------------------------------------------------------------- /autoResign/resign/certificate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrChens/iOS_Tools/54715f6e51467838ff6a549bb8f6e5bd44a1d72e/autoResign/resign/certificate.png -------------------------------------------------------------------------------- /autoResign/resign/provisioning profiles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrChens/iOS_Tools/54715f6e51467838ff6a549bb8f6e5bd44a1d72e/autoResign/resign/provisioning profiles.png -------------------------------------------------------------------------------- /autoResign/resign/resign.config: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | NEW_MOBILEPROVISION="EnterPrise_Distribution.mobileprovision" # Distribution配置文件 3 | CODESIGN_IDENTITIES="iPhone Distribution: xxxx yyyy & Technology Co., Ltd." # Distribution版证书的名字 4 | ENTITLEMENTS="Entitlements/production/Entitlements.plist" # 授权文件 不需要修改该字段 5 | 6 | NEW_MOBILEPROVISION_DEV="EnterPrise_Development.mobileprovision" # Developer配置文件 7 | CODESIGN_IDENTITIES_DEV="iPhone Developer: xxxx Funny (KxxxxxFP)" # Developer版证书的名字 8 | ENTITLEMENTS_DEV="Entitlements/developer/Entitlements.plist" # 授权文件 不需要修改该字段 9 | GET_TASK_ALLOW=false #是否打包Developer true重签名为Developer的包 false重签名为Distribution的包 10 | AUTO_INSTALL_IPA=false #是否自动将重签名后的app安装到手机上 11 | 12 | NEW_MOBILEPROVISION_FREE="person.mobileprovision" # Distribution配置文件 13 | CODESIGN_IDENTITIES_FREE="Apple Development: 13777726110@139.com (R3X24X6L99)" # 个人版证书的名字 14 | ENTITLEMENTS_FREE="Entitlements/free/Entitlements.plist" # 授权文件 不需要修改该字段 15 | 16 | 17 | MINIMUMOSVERSION="10.0" #ipa最低支持的iOS版本 18 | -------------------------------------------------------------------------------- /autoResign/resign/resign.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | 4 | if [ $# -lt 1 ]; then 5 | echo "" 6 | echo "resign.sh Usage:" 7 | echo "\t required: ./resign.sh APP_NAME.ipa true/free" 8 | echo "\t true is optional feature which allow you set get-task-allow to true" 9 | echo "\t free is optional feature which allow you codesign ipa with free apple id" 10 | 11 | exit 0 12 | fi 13 | 14 | echo "read cofig from resign.config" 15 | source resign.config 16 | 17 | 18 | TARGET_IPA_PACKAGE_NAME=$1 19 | TM_IPA_PACKAGE_NAME="${TARGET_IPA_PACKAGE_NAME%.*}_MC.ipa" # resigned ipa name 20 | PAYLOAD_DIR="Payload" 21 | APP_DIR="" 22 | PROVISION_FILE=$NEW_MOBILEPROVISION 23 | CODESIGN_KEY=$CODESIGN_IDENTITIES 24 | ENTITLEMENTS_FILE=$ENTITLEMENTS 25 | 26 | 27 | if [[ $2 == 'true' ]]; then 28 | echo "resign with development type" 29 | PROVISION_FILE=$NEW_MOBILEPROVISION_DEV 30 | CODESIGN_KEY=$CODESIGN_IDENTITIES_DEV 31 | ENTITLEMENTS_FILE=$ENTITLEMENTS_DEV 32 | fi 33 | 34 | if [[ $2 == 'free' ]]; then 35 | echo "resign with free developer type" 36 | PROVISION_FILE=$NEW_MOBILEPROVISION_FREE 37 | CODESIGN_KEY=$CODESIGN_IDENTITIES_FREE 38 | ENTITLEMENTS_FILE=$ENTITLEMENTS_FREE 39 | fi 40 | 41 | echo -e "" 42 | echo -e "the new ipa named:${TM_IPA_PACKAGE_NAME}" 43 | echo -e "use provision file:${PROVISION_FILE}" 44 | echo -e "use entitlements file:${ENTITLEMENTS_FILE}" 45 | echo -e "use codesign:${CODESIGN_KEY}" 46 | 47 | OLD_MOBILEPROVISION="embedded.mobileprovision" 48 | DEVELOPER=`xcode-select -print-path` 49 | TARGET_APP_FRAMEWORKS_PATH="" 50 | 51 | SDK_DIR="${DEVELOPER}/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk" 52 | echo -e "SDK_DIR*$SDK_DIR" 53 | 54 | if [ ! -e $TARGET_IPA_PACKAGE_NAME ]; then 55 | echo "ipa file ($TARGET_IPA_PACKAGE_NAME) not exist" 56 | exit 0 57 | fi 58 | 59 | if [ ! -e $PROVISION_FILE ]; then 60 | echo "provision file ($PROVISION_FILE) not exist" 61 | exit 0 62 | fi 63 | 64 | if [ -e $TM_IPA_PACKAGE_NAME ]; then 65 | echo "rm $TM_IPA_PACKAGE_NAME" 66 | rm $TM_IPA_PACKAGE_NAME 67 | fi 68 | 69 | if [ -d $PAYLOAD_DIR ]; then 70 | echo "delete old ipa:$PAYLOAD_DIR" 71 | rm -rf $PAYLOAD_DIR 72 | fi 73 | 74 | echo "" 75 | echo "1. unzip $TARGET_IPA_PACKAGE_NAME" 76 | unzip $TARGET_IPA_PACKAGE_NAME > /dev/null 77 | 78 | if [ ! -d $PAYLOAD_DIR ]; then 79 | echo "unzip $TARGET_IPA_PACKAGE_NAME fail" 80 | fi 81 | 82 | APP_DIR="Payload/fuck.app" 83 | 84 | FUCK_APP_DIR=$(find ${PAYLOAD_DIR} -type d | grep ".app$" | head -n 1) 85 | 86 | # incase of some app name with white space 87 | # eg. "hello world.app" 88 | echo "rename ${FUCK_APP_DIR} to ${APP_DIR}" 89 | mv -i "$FUCK_APP_DIR" "$APP_DIR" 90 | 91 | echo "set Minimum support os version:${MINIMUMOSVERSION}" 92 | plutil -replace MinimumOSVersion -string $MINIMUMOSVERSION $APP_DIR/Info.plist 93 | # plutil -insert UISupportedDevices.4 -string "iPhone11,6" $APP_DIR/Info.plist 94 | # we don't need the this feature 95 | echo "delete UISupportedDevices keypath in Info.plist" 96 | plutil -remove UISupportedDevices $APP_DIR/Info.plist 97 | 98 | if [ -d "$APP_DIR/_CodeSignature" ]; then 99 | echo "" 100 | echo "rm $APP_DIR/_CodeSignature" 101 | rm -rf $APP_DIR/_CodeSignature 102 | 103 | echo "" 104 | echo "cp $SDK_DIR/ResourceRules.plist $APP_DIR/" 105 | cp $SDK_DIR/ResourceRules.plist $APP_DIR/ 106 | echo "" 107 | echo "cp $PROVISION_FILE $APP_DIR/$OLD_MOBILEPROVISION" 108 | cp $PROVISION_FILE $APP_DIR/$OLD_MOBILEPROVISION 109 | echo "" 110 | echo "*************start codesign*************" 111 | 112 | #codesign frameworks 113 | TARGET_APP_FRAMEWORKS_PATH="$APP_DIR/Frameworks" 114 | if [[ -d "$TARGET_APP_FRAMEWORKS_PATH" ]]; then 115 | for FRAMEWORK in "$TARGET_APP_FRAMEWORKS_PATH/"*; do 116 | FILENAME=$(basename $FRAMEWORK) 117 | /usr/bin/codesign -f -s "$CODESIGN_KEY" "$FRAMEWORK" 118 | done 119 | fi 120 | echo "codesign frameworks done." 121 | 122 | #codesign plugins 123 | TARGET_APP_PLUGINS_PATH="$APP_DIR/PlugIns" 124 | if [[ -d "$TARGET_APP_PLUGINS_PATH" ]]; then 125 | for PLUGIN in "$TARGET_APP_PLUGINS_PATH/"*; do 126 | FILENAME=$(basename $PLUGIN) 127 | /usr/bin/codesign -f -s "$CODESIGN_KEY" "$PLUGIN" 128 | done 129 | fi 130 | echo "codesign plugins done." 131 | 132 | #codesign the fuck dylib 133 | for FDYLIB in "$APP_DIR/"*; do 134 | #statements 135 | DYLIB=${FDYLIB##*.} 136 | if [[ $DYLIB == dylib ]]; then 137 | #statements 138 | echo "codesign ${FDYLIB}" 139 | /usr/bin/codesign -f -s "$CODESIGN_KEY" "$FDYLIB" 140 | fi 141 | done 142 | echo "codesign dylibs done." 143 | 144 | echo "codesign ${APP_DIR} with entitlements file" 145 | /usr/bin/codesign -f -s "$CODESIGN_KEY" --entitlements $ENTITLEMENTS_FILE $APP_DIR 146 | 147 | echo "*************end codesign*************" 148 | 149 | if [ -d $APP_DIR/_CodeSignature ]; then 150 | echo "" 151 | echo "zip -r $TARGET_IPA_PACKAGE_NAME $APP_DIR/" 152 | zip -r $TM_IPA_PACKAGE_NAME $APP_DIR/ > /dev/null 153 | echo "delete ${APP_DIR}" 154 | rm -rf $APP_DIR 155 | echo " @@@@@@@ resign success !!! @@@@@@@ " 156 | exit 0 157 | fi 158 | fi 159 | 160 | echo "oops! resign fail !!!" 161 | -------------------------------------------------------------------------------- /class_dump/README.md: -------------------------------------------------------------------------------- 1 | # 导出头文件操作流程文档 2 | 3 | [class-dump](http://stevenygard.com/projects/class-dump/) 4 | 5 | [砸壳(破解)工具](https://github.com/stefanesser/dumpdecrypted.git) 6 | 7 | ### 砸壳时遇见如下 8 | dyld: could not load inserted library 'dumpdecrypted.dylib' because no suitable image found. Did find: 9 | dumpdecrypted.dylib: required code signature missing for 'dumpdecrypted.dylib' 10 | 11 | security find-identity -v -p codesigning 12 | codesign --force --verify --verbose --sign "iPhone Developer: xxx xxxx (xxxxxxxxxx)" dumpdecrypted.dylib 13 | 14 | ### 本目录下已经预先放置好了需要使用的工具,如果不能使用请从上面的网址去download新的工具来。 15 | 16 | 从App Store下载的ipa是需要先砸壳然后再使用`class-dump`才能导出头文件. 17 | 如果是自己打包的企业app直接把ipa解压后的xx.app用`class-dump`就能导出头文件. 18 | 19 | ### 针对App Store下载的ipa进行的`class-dump`(需要越狱的设备) 20 | - 先从ituness上下载xxx.ipa 21 | - 然后将ipa安装到越狱的手机中 22 | - 将`dumpdecrypted.dylib`拷贝到手机的`(iOS8)/var/mobile/Containers/Data/Application/xxx-xxx/Documents`目录下,在iOS7中是`/var/mobile/Applications/xxx-xxx/Documents` 23 | - iOS8然后再cd到3中的目录下执行:`DYLD_INSERT_LIBRARIES=dumpdecrypted.dylib /var/mobile/Containers/Bundle/Application/xxx-xxx/yyy.app/yyy` 24 | iOS7然后再cd到3中的目录下执行:`DYLD_INSERT_LIBRARIES=dumpdecrypted.dylib /var/mobile/Applications/xxx-xxx/yyy.app/yyy` 25 | - 然后就会生成`yyy.decrypted` 26 | - 使用`scp`将`yyy.decrypted`传输到电脑上 27 | - `./class-dump -H yyy.decrypted -o outputs` 28 | - 然后就能在`outputs`中看到导出的头文件 29 | 30 | ### 针对不需要砸壳的ipa进行的class-dump(不需要越狱的设备) 31 | - 将xxx.ipa解压到`class-dump`同个目录下,然后使用下面的命令将头文件导出到`outputs`目录下: 32 | - `./class-dump -H xx.app -o outputs` 33 | - 然后就能在`outputs`中看到导出的头文件 34 | 35 | 36 | ### 在使用过程中如果有任何问题或者改良的方案欢迎提issue和pr. 37 | 38 | -------------------------------------------------------------------------------- /class_dump/class-dump: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrChens/iOS_Tools/54715f6e51467838ff6a549bb8f6e5bd44a1d72e/class_dump/class-dump -------------------------------------------------------------------------------- /class_dump/dumpdecrypted.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrChens/iOS_Tools/54715f6e51467838ff6a549bb8f6e5bd44a1d72e/class_dump/dumpdecrypted.dylib -------------------------------------------------------------------------------- /crashMe/README.md: -------------------------------------------------------------------------------- 1 | # app崩溃时排查步骤 2 | > 在app崩溃时所生成的`.crash`文件,默认情况下该文件显示的都是十六进制数无法分析。所以我们需要对这些文件进行分析。 3 | ## 需要的工具: 4 | - `Xcode` 5 | - `app`崩溃时生成的`.crash`文件,可通过`Xcode`--> `Window`--> `Devices and Simulators`--> `View Device Logs`从iPhone中提取出来 6 | - `dsym`文件(符号表文件) 7 | - `symbolicatecrash`(可通过执行`find /Applications/Xcode.app/ -name symbolicatecrash`找到该文件的所在位置) 8 | 9 | ## 使用方式: 10 | 1. 打开`.crash`文件找到其中的`uuid` 11 | 2. 找到对应的`dysm`文件.(可通过`dwarfdump --uuid xxx.dsym`查看`uuid`是否和1的一致) 12 | 3. 将`.crash`,`dysm`,`symbolicatecrash`这3个文件放在同一个文件夹下方便处理 13 | 4. 执行命令`./symbolicatecrash xxxx.crash xxxx.dSYM/ > output.crash`就可以看到符号化以后的崩溃堆栈信息 14 | 5. 若报错`Error: "DEVELOPER_DIR" is not defined at ./symbolicatecrash`,则在终端执行一次后面的命令`export DEVELOPER_DIR="/Applications/XCode.app/Contents/Developer"`,然后再执行一次`4`的命令. 15 | 16 | ps:最后生成的`.crash`文件只会解析当前项目的代码,其余的还是十六进制数据 17 | 18 | ## 实际操作 19 | 1. 从`iPhone`中获取`wspxDemo 2018-11-5, 2-42 PM.crash.crash`文件如下(只保留需要的关键信息) 20 | 21 | ``` 22 | Incident Identifier: 211AB31B-F097-47DC-83ED-3AC6B3AC6B05 23 | CrashReporter Key: 991d9b4c57cf7b9c00c2cabc05f20cb4812ea851 24 | Hardware Model: iPhone10,3 25 | Process: wspxDemo [1214] 26 | Path: /private/var/containers/Bundle/Application/DF7AAB28-9FF0-99EC-4EA1-16B5C50EB87C/wspxDemo.app/wspxDemo 27 | Identifier: com.crash.CrashMe 28 | Version: 2222 (22.22.222) 29 | Code Type: ARM-64 (Native) 30 | Role: Foreground 31 | Parent Process: launchd [1] 32 | Coalition: com.crash.CrashMe [738] 33 | 34 | Date/Time: 2018-11-05 14:42:17.6018 +0800 35 | Launch Time: 2018-11-05 14:42:17.3303 +0800 36 | OS Version: iPhone OS 12.1 (16B5089b) 37 | Baseband Version: 3.11.00 38 | Report Version: 104 39 | 40 | Exception Type: EXC_CRASH (SIGABRT) 41 | Exception Codes: 0x0000000000000000, 0x0000000000000000 42 | Exception Note: EXC_CORPSE_NOTIFY 43 | Triggered by Thread: 0 44 | 45 | Application Specific Information: 46 | abort() called 47 | 48 | Last Exception Backtrace: 49 | (0x1dcfcfea0 0x1dc1a1a40 0x1dcede054 0x102ceb9b4 0x209fda3c8 0x209fdbb30 0x209fe157c 0x20987ea18 0x209887698 0x20987e694 0x20987f034 0x20987d134 0x20987cde0 0x209881fa0 0x209882f00 0x209881e58 0x209886d44 0x209fdfa74 0x209bca088 0x1dfa049d4 0x1dfa0f79c 0x1dfa0ee94 0x1dca0a484 0x1dc9e13f0 0x1dfa43a9c 0x1dfa43728 0x1dfa43d44 0x1dcf601cc 0x1dcf6014c 0x1dcf5fa30 0x1dcf5a8fc 0x1dcf5a1cc 0x1df1d1584 0x209fe3328 0x102cebaf0 0x1dca1abb4) 50 | 51 | Thread 0 name: Dispatch queue: com.apple.main-thread 52 | Thread 0 Crashed: 53 | 0 libsystem_kernel.dylib 0x00000001dcb67104 0x1dcb44000 + 143620 54 | 1 libsystem_pthread.dylib 0x00000001dcbe6998 0x1dcbe0000 + 27032 55 | 2 libsystem_c.dylib 0x00000001dcabed78 0x1dca67000 + 359800 56 | 3 libc++abi.dylib 0x00000001dc188f78 0x1dc187000 + 8056 57 | 4 libc++abi.dylib 0x00000001dc189120 0x1dc187000 + 8480 58 | 5 libobjc.A.dylib 0x00000001dc1a1e48 0x1dc19b000 + 28232 59 | 6 libc++abi.dylib 0x00000001dc1950fc 0x1dc187000 + 57596 60 | 7 libc++abi.dylib 0x00000001dc195188 0x1dc187000 + 57736 61 | 8 libdispatch.dylib 0x00000001dca0a498 0x1dc9a9000 + 398488 62 | 9 libdispatch.dylib 0x00000001dc9e13f0 0x1dc9a9000 + 230384 63 | 10 FrontBoardServices 0x00000001dfa43a9c 0x1df9f8000 + 309916 64 | 11 FrontBoardServices 0x00000001dfa43728 0x1df9f8000 + 309032 65 | 12 FrontBoardServices 0x00000001dfa43d44 0x1df9f8000 + 310596 66 | 13 CoreFoundation 0x00000001dcf601cc 0x1dceb4000 + 704972 67 | 14 CoreFoundation 0x00000001dcf6014c 0x1dceb4000 + 704844 68 | 15 CoreFoundation 0x00000001dcf5fa30 0x1dceb4000 + 703024 69 | 16 CoreFoundation 0x00000001dcf5a8fc 0x1dceb4000 + 682236 70 | 17 CoreFoundation 0x00000001dcf5a1cc 0x1dceb4000 + 680396 71 | 18 GraphicsServices 0x00000001df1d1584 0x1df1c6000 + 46468 72 | 19 UIKitCore 0x0000000209fe3328 0x2096fc000 + 9335592 73 | 20 wspxDemo 0x0000000102cebaf0 0x102ce4000 + 31472 74 | 21 libdyld.dylib 0x00000001dca1abb4 0x1dca1a000 + 2996 75 | 76 | Thread 1: 77 | 0 libsystem_pthread.dylib 0x00000001dcbeece8 0x1dcbe0000 + 60648 78 | 79 | Thread 2: 80 | 0 libsystem_pthread.dylib 0x00000001dcbeece8 0x1dcbe0000 + 60648 81 | 82 | Thread 3: 83 | 0 libsystem_pthread.dylib 0x00000001dcbeece8 0x1dcbe0000 + 60648 84 | 85 | Thread 4: 86 | 0 libsystem_pthread.dylib 0x00000001dcbeece8 0x1dcbe0000 + 60648 87 | 88 | Thread 5 name: com.apple.uikit.eventfetch-thread 89 | Thread 5: 90 | 0 libsystem_kernel.dylib 0x00000001dcb5bed0 0x1dcb44000 + 98000 91 | 1 libsystem_kernel.dylib 0x00000001dcb5b3a8 0x1dcb44000 + 95144 92 | 2 CoreFoundation 0x00000001dcf5fbc4 0x1dceb4000 + 703428 93 | 3 CoreFoundation 0x00000001dcf5aa60 0x1dceb4000 + 682592 94 | 4 CoreFoundation 0x00000001dcf5a1cc 0x1dceb4000 + 680396 95 | 5 Foundation 0x00000001dd94f404 0x1dd947000 + 33796 96 | 6 Foundation 0x00000001dd94f2b0 0x1dd947000 + 33456 97 | 7 UIKitCore 0x000000020a0d0430 0x2096fc000 + 10306608 98 | 8 Foundation 0x00000001dda821ac 0x1dd947000 + 1290668 99 | 9 libsystem_pthread.dylib 0x00000001dcbeb2ac 0x1dcbe0000 + 45740 100 | 10 libsystem_pthread.dylib 0x00000001dcbeb20c 0x1dcbe0000 + 45580 101 | 11 libsystem_pthread.dylib 0x00000001dcbeecf4 0x1dcbe0000 + 60660 102 | 103 | Thread 0 crashed with ARM Thread State (64-bit): 104 | x0: 0x0000000000000000 x1: 0x0000000000000000 x2: 0x0000000000000000 x3: 0x000000028248b4b7 105 | x4: 0x00000001dc198b81 x5: 0x000000016d11a570 x6: 0x000000000000006e x7: 0xffffffff00000500 106 | x8: 0x0000000000000800 x9: 0x00000001dcbe6870 x10: 0x00000001dcbe1ef4 x11: 0x0000000000000003 107 | x12: 0x0000000000000069 x13: 0x0000000000000000 x14: 0x0000000000000010 x15: 0x0000000000000016 108 | x16: 0x0000000000000148 x17: 0x0000000000000000 x18: 0x0000000000000000 x19: 0x0000000000000006 109 | x20: 0x00000001030aeb80 x21: 0x000000016d11a570 x22: 0x0000000000000303 x23: 0x00000001030aec60 110 | x24: 0x0000000000001903 x25: 0x0000000000002103 x26: 0x0000000000000000 x27: 0x0000000000000000 111 | x28: 0x00000002836bc408 fp: 0x000000016d11a4d0 lr: 0x00000001dcbe6998 112 | sp: 0x000000016d11a4a0 pc: 0x00000001dcb67104 cpsr: 0x00000000 113 | 114 | Binary Images: 115 | 0x102ce4000 - 0x102ceffff wspxDemo arm64 /var/containers/Bundle/Application/DF7AAB28-9FF0-99EC-4EA1-16B5C50EB87C/wspxDemo.app/wspxDemo``` 116 | 117 | 2. 从`Binary Images: 118 | 0x102ce4000 - 0x102ceffff wspxDemo arm64 /var/containers/Bundle/Application/DF7AAB28-9FF0-99EC-4EA1-16B5C50EB87C/wspxDemo.app/wspxDemo`中我们拿到`b0ffd72fc5c33a59bf97c79556430202` 119 | 3. 在终端执行`dwarfdump --uuid wspxDemo.app.dSYM/`后得到如下的输出: 120 | 121 | 122 | ```Mero:wspxDemo 2018-11-05 12-56-20 dc$ dwarfdump --uuid wspxDemo.app.dSYM/ 123 | UUID: 43C734F8-405F-3970-8B8D-D58575672912 (armv7) wspxDemo.app.dSYM/Contents/Resources/DWARF/wspxDemo 124 | UUID: B0FFD72F-C5C3-3A59-BF97-C79556430202 (arm64) wspxDemo.app.dSYM/Contents/Resources/DWARF/wspxDemo``` 125 | 126 | 4. 对比步骤2和3的结果会发现:`b0ffd72fc5c33a59bf97c79556430202`和`B0FFD72F-C5C3-3A59-BF97-C79556430202`是一致的,所以该`wspxDemo 2018-11-5, 2-42 PM.crash.crash`对应的`dysm`就是`wspxDemo.app.dSYM` 127 | 5. 在终端执行命令:`./symbolicatecrash wspxDemo\ \ 2018-11-5\,\ 2-42\ PM.crash wspxDemo.app.dSYM/ > output.crash`得到如下的输出: 128 | 129 | ``` 130 | Mero:wspxDemo 2018-11-05 12-56-20 dc$ ./symbolicatecrash wspxDemo\ \ 2018-11-5\,\ 2-42\ PM.crash wspxDemo.app.dSYM/ > output.crash 131 | Error: "DEVELOPER_DIR" is not defined at ./symbolicatecrash line 69.``` 132 | 133 | 6. 报错:`Error: "DEVELOPER_DIR" is not defined at ./symbolicatecrash line 69.` 134 | 7. 执行如下命令:`export DEVELOPER_DIR="/Applications/XCode.app/Contents/Developer"`然后再执行`5`的命令.执行结果如下: 135 | 136 | ``` 137 | Mero:wspxDemo 2018-11-05 12-56-20 dc$ export DEVELOPER_DIR="/Applications/XCode.app/Contents/Developer" 138 | Mero:wspxDemo 2018-11-05 12-56-20 dc$ ./symbolicatecrash wspxDemo\ \ 2018-11-5\,\ 2-42\ PM.crash wspxDemo.app.dSYM/ > output.crash``` 139 | 140 | 8. 如果没有报任何其他错误,则说明你已经成功把`crash`符号了,这时打开`output.crash`开始查看崩溃堆栈吧 141 | 9. 如下是符号化后的`output.crash`文件的内容: 142 | 143 | ``` 144 | Incident Identifier: 211AB31B-F097-47DC-83ED-3AC6B3AC6B05 145 | CrashReporter Key: 991d9b4c57cf7b9c00c2cabc05f20cb4812ea851 146 | Hardware Model: iPhone10,3 147 | Process: wspxDemo [1214] 148 | Path: /private/var/containers/Bundle/Application/DF7AAB28-9FF0-99EC-4EA1-16B5C50EB87C/wspxDemo.app/wspxDemo 149 | Identifier: com.crash.CrashMe 150 | Version: 2222 (22.22.222) 151 | Code Type: ARM-64 (Native) 152 | Role: Foreground 153 | Parent Process: launchd [1] 154 | Coalition: com.crash.CrashMe [738] 155 | 156 | Date/Time: 2018-11-05 14:42:17.6018 +0800 157 | Launch Time: 2018-11-05 14:42:17.3303 +0800 158 | OS Version: iPhone OS 12.1 (16B5089b) 159 | Baseband Version: 3.11.00 160 | Report Version: 104 161 | 162 | Exception Type: EXC_CRASH (SIGABRT) 163 | Exception Codes: 0x0000000000000000, 0x0000000000000000 164 | Exception Note: EXC_CORPSE_NOTIFY 165 | Triggered by Thread: 0 166 | 167 | Application Specific Information: 168 | abort() called 169 | 170 | Last Exception Backtrace: 171 | 0 CoreFoundation 0x1dcfcfea0 __exceptionPreprocess + 228 172 | 1 libobjc.A.dylib 0x1dc1a1a40 objc_exception_throw + 55 173 | 2 CoreFoundation 0x1dcede054 -[__NSSingleObjectArrayI objectAtIndex:] + 127 174 | 3 wspxDemo 0x102ceb9b4 -[AppDelegate application:didFinishLaunchingWithOptions:] + 31156 (AppDelegate.m:150) 175 | 4 UIKitCore 0x209fda3c8 -[UIApplication _handleDelegateCallbacksWithOptions:isSuspended:restoreState:] + 411 176 | 5 UIKitCore 0x209fdbb30 -[UIApplication _callInitializationDelegatesForMainScene:transitionContext:] + 3339 177 | 6 UIKitCore 0x209fe157c -[UIApplication _runWithMainScene:transitionContext:completion:] + 1551 178 | 7 UIKitCore 0x20987ea18 __111-[__UICanvasLifecycleMonitor_Compatability _scheduleFirstCommitForScene:transition:firstActivation:completion:]_block_invoke + 783 179 | 8 UIKitCore 0x209887698 +[_UICanvas _enqueuePostSettingUpdateTransactionBlock:] + 159 180 | 9 UIKitCore 0x20987e694 -[__UICanvasLifecycleMonitor_Compatability _scheduleFirstCommitForScene:transition:firstActivation:completion:] + 239 181 | 10 UIKitCore 0x20987f034 -[__UICanvasLifecycleMonitor_Compatability activateEventsOnly:withContext:completion:] + 1075 182 | 11 UIKitCore 0x20987d134 __82-[_UIApplicationCanvas _transitionLifecycleStateWithTransitionContext:completion:]_block_invoke + 771 183 | 12 UIKitCore 0x20987cde0 -[_UIApplicationCanvas _transitionLifecycleStateWithTransitionContext:completion:] + 431 184 | 13 UIKitCore 0x209881fa0 __125-[_UICanvasLifecycleSettingsDiffAction performActionsForCanvas:withUpdatedScene:settingsDiff:fromSettings:transitionContext:]_block_invoke + 219 185 | 14 UIKitCore 0x209882f00 _performActionsWithDelayForTransitionContext + 111 186 | 15 UIKitCore 0x209881e58 -[_UICanvasLifecycleSettingsDiffAction performActionsForCanvas:withUpdatedScene:settingsDiff:fromSettings:transitionContext:] + 247 187 | 16 UIKitCore 0x209886d44 -[_UICanvas scene:didUpdateWithDiff:transitionContext:completion:] + 367 188 | 17 UIKitCore 0x209fdfa74 -[UIApplication workspace:didCreateScene:withTransitionContext:completion:] + 539 189 | 18 UIKitCore 0x209bca088 -[UIApplicationSceneClientAgent scene:didInitializeWithEvent:completion:] + 363 190 | 19 FrontBoardServices 0x1dfa049d4 -[FBSSceneImpl _didCreateWithTransitionContext:completion:] + 443 191 | 20 FrontBoardServices 0x1dfa0f79c __56-[FBSWorkspace client:handleCreateScene:withCompletion:]_block_invoke_2 + 259 192 | 21 FrontBoardServices 0x1dfa0ee94 __40-[FBSWorkspace _performDelegateCallOut:]_block_invoke + 63 193 | 22 libdispatch.dylib 0x1dca0a484 _dispatch_client_callout + 15 194 | 23 libdispatch.dylib 0x1dc9e13f0 _dispatch_block_invoke_direct$VARIANT$armv81 + 215 195 | 24 FrontBoardServices 0x1dfa43a9c __FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK__ + 39 196 | 25 FrontBoardServices 0x1dfa43728 -[FBSSerialQueue _performNext] + 415 197 | 26 FrontBoardServices 0x1dfa43d44 -[FBSSerialQueue _performNextFromRunLoopSource] + 55 198 | 27 CoreFoundation 0x1dcf601cc __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 23 199 | 28 CoreFoundation 0x1dcf6014c __CFRunLoopDoSource0 + 87 200 | 29 CoreFoundation 0x1dcf5fa30 __CFRunLoopDoSources0 + 175 201 | 30 CoreFoundation 0x1dcf5a8fc __CFRunLoopRun + 1039 202 | 31 CoreFoundation 0x1dcf5a1cc CFRunLoopRunSpecific + 435 203 | 32 GraphicsServices 0x1df1d1584 GSEventRunModal + 99 204 | 33 UIKitCore 0x209fe3328 UIApplicationMain + 211 205 | 34 wspxDemo 0x102cebaf0 main + 31472 (main.m:14) 206 | 35 libdyld.dylib 0x1dca1abb4 start + 3 207 | 208 | 209 | Thread 0 name: Dispatch queue: com.apple.main-thread 210 | Thread 0 Crashed: 211 | 0 libsystem_kernel.dylib 0x00000001dcb67104 __pthread_kill + 8 212 | 1 libsystem_pthread.dylib 0x00000001dcbe6998 pthread_kill$VARIANT$armv81 + 296 213 | 2 libsystem_c.dylib 0x00000001dcabed78 abort + 140 214 | 3 libc++abi.dylib 0x00000001dc188f78 __cxa_bad_cast + 0 215 | 4 libc++abi.dylib 0x00000001dc189120 default_unexpected_handler+ 8480 () + 0 216 | 5 libobjc.A.dylib 0x00000001dc1a1e48 _objc_terminate+ 28232 () + 124 217 | 6 libc++abi.dylib 0x00000001dc1950fc std::__terminate(void (*)+ 57596 ()) + 16 218 | 7 libc++abi.dylib 0x00000001dc195188 std::terminate+ 57736 () + 84 219 | 8 libdispatch.dylib 0x00000001dca0a498 _dispatch_client_callout + 36 220 | 9 libdispatch.dylib 0x00000001dc9e13f0 _dispatch_block_invoke_direct$VARIANT$armv81 + 216 221 | 10 FrontBoardServices 0x00000001dfa43a9c __FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK__ + 40 222 | 11 FrontBoardServices 0x00000001dfa43728 -[FBSSerialQueue _performNext] + 416 223 | 12 FrontBoardServices 0x00000001dfa43d44 -[FBSSerialQueue _performNextFromRunLoopSource] + 56 224 | 13 CoreFoundation 0x00000001dcf601cc __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 24 225 | 14 CoreFoundation 0x00000001dcf6014c __CFRunLoopDoSource0 + 88 226 | 15 CoreFoundation 0x00000001dcf5fa30 __CFRunLoopDoSources0 + 176 227 | 16 CoreFoundation 0x00000001dcf5a8fc __CFRunLoopRun + 1040 228 | 17 CoreFoundation 0x00000001dcf5a1cc CFRunLoopRunSpecific + 436 229 | 18 GraphicsServices 0x00000001df1d1584 GSEventRunModal + 100 230 | 19 UIKitCore 0x0000000209fe3328 UIApplicationMain + 212 231 | 20 wspxDemo 0x0000000102cebaf0 main + 31472 (main.m:14) 232 | 21 libdyld.dylib 0x00000001dca1abb4 start + 4 233 | 234 | Thread 1: 235 | 0 libsystem_pthread.dylib 0x00000001dcbeece8 start_wqthread + 0 236 | 237 | Thread 2: 238 | 0 libsystem_pthread.dylib 0x00000001dcbeece8 start_wqthread + 0 239 | 240 | Thread 3: 241 | 0 libsystem_pthread.dylib 0x00000001dcbeece8 start_wqthread + 0 242 | 243 | Thread 4: 244 | 0 libsystem_pthread.dylib 0x00000001dcbeece8 start_wqthread + 0 245 | 246 | Thread 5 name: com.apple.uikit.eventfetch-thread 247 | Thread 5: 248 | 0 libsystem_kernel.dylib 0x00000001dcb5bed0 mach_msg_trap + 8 249 | 1 libsystem_kernel.dylib 0x00000001dcb5b3a8 mach_msg + 72 250 | 2 CoreFoundation 0x00000001dcf5fbc4 __CFRunLoopServiceMachPort + 236 251 | 3 CoreFoundation 0x00000001dcf5aa60 __CFRunLoopRun + 1396 252 | 4 CoreFoundation 0x00000001dcf5a1cc CFRunLoopRunSpecific + 436 253 | 5 Foundation 0x00000001dd94f404 -[NSRunLoop+ 33796 (NSRunLoop) runMode:beforeDate:] + 300 254 | 6 Foundation 0x00000001dd94f2b0 -[NSRunLoop+ 33456 (NSRunLoop) runUntilDate:] + 148 255 | 7 UIKitCore 0x000000020a0d0430 -[UIEventFetcher threadMain] + 136 256 | 8 Foundation 0x00000001dda821ac __NSThread__start__ + 1040 257 | 9 libsystem_pthread.dylib 0x00000001dcbeb2ac _pthread_body + 128 258 | 10 libsystem_pthread.dylib 0x00000001dcbeb20c _pthread_start + 48 259 | 11 libsystem_pthread.dylib 0x00000001dcbeecf4 thread_start + 4 260 | 261 | Thread 0 crashed with ARM Thread State (64-bit): 262 | x0: 0x0000000000000000 x1: 0x0000000000000000 x2: 0x0000000000000000 x3: 0x000000028248b4b7 263 | x4: 0x00000001dc198b81 x5: 0x000000016d11a570 x6: 0x000000000000006e x7: 0xffffffff00000500 264 | x8: 0x0000000000000800 x9: 0x00000001dcbe6870 x10: 0x00000001dcbe1ef4 x11: 0x0000000000000003 265 | x12: 0x0000000000000069 x13: 0x0000000000000000 x14: 0x0000000000000010 x15: 0x0000000000000016 266 | x16: 0x0000000000000148 x17: 0x0000000000000000 x18: 0x0000000000000000 x19: 0x0000000000000006 267 | x20: 0x00000001030aeb80 x21: 0x000000016d11a570 x22: 0x0000000000000303 x23: 0x00000001030aec60 268 | x24: 0x0000000000001903 x25: 0x0000000000002103 x26: 0x0000000000000000 x27: 0x0000000000000000 269 | x28: 0x00000002836bc408 fp: 0x000000016d11a4d0 lr: 0x00000001dcbe6998 270 | sp: 0x000000016d11a4a0 pc: 0x00000001dcb67104 cpsr: 0x00000000 271 | 272 | Binary Images: 273 | 0x102ce4000 - 0x102ceffff wspxDemo arm64 /var/containers/Bundle/Application/DF7AAB28-9FF0-99EC-4EA1-16B5C50EB87C/wspxDemo.app/wspxDemo``` 274 | 275 | 10. 从`crash`文件中我们很容易定位到`app`挂在了`AppDelegate.m`文件中的`第150行`这里.并且可能是因为数组越界导致崩溃。从源码截图中看确实是在`AppDelegate.m`的`150行`有问题. 276 | 11. 得到符号化`crash`文件后就可以进一步排查问题,之前有写过相关的博客[传送门][debug-with-crashlog]在这里就不再详细说明. 277 | 278 | ![源码][sourceCode] 279 | 280 | [debug-with-crashlog]:https://mrchens.github.io/2018/07/26/debug-with-crashlog 281 | [sourceCode]:https://github.com/MrChens/iOS_Tools/blob/master/crashMe/sourcecode.png 282 | -------------------------------------------------------------------------------- /crashMe/sourcecode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrChens/iOS_Tools/54715f6e51467838ff6a549bb8f6e5bd44a1d72e/crashMe/sourcecode.png -------------------------------------------------------------------------------- /cydia.md: -------------------------------------------------------------------------------- 1 | # 越狱开发中有用的软件 2 | - OpenSSH:建立ssh连接,记得修改默认root密码(alpine) 3 | - 安装后可以使用scp 4 | - APT 0.6 Transitional: apt-get包管理工具 5 | - Gawk: 支持awk编程,awk是一种强大的文本处理及模式匹配语言 6 | - Core Utilities (/bin):提供了dirname,kill,mktemp,su 7 | - top:动态查看系统状态,如CPU负载 8 | - inetutils: ping, ftp客户端/服务端 9 | - cURL: 10 | - ReRpovision:app自动续签 11 | - tcpdump: 抓包工具 12 | - network Commands: 网络管理工具, ifconfig, netstat, arp, route, traceroute 13 | - readline: 方便命令行移动 14 | - `ctrl+r` 搜索 15 | - `ctrl+a/e` 移动到行首/尾 16 | - `ctrl+u/k` 删除到行首/尾 17 | - `ctrl+l` 清屏 18 | - open:通过命令行打开应用 19 | - ipainstaller: 通过命令行安装ipa应用 20 | - plutil (com.Erica.Utilities): 支持设备上对plist文件进行操作 21 | - strings(Binutils): 打印某个文件的可打印字符串,便于了解一些非文本文件的内容。比如可用来查找浏览器Cokkies内容 22 | - cycript: TBD 通过`ctrl+d`退出 23 | - AppSync: 安装未经过认证的软件 24 | # 命令示例子 25 | - APT 0.6 Transitional 26 | - apt-cache search 查找软件包 27 | - apt-cache show 显示软件包信息 28 | - apt-get update 从APT源更新软件包列表 29 | - apt-get updrade 更新软件包 30 | - apt-get remove 删除已安装的软件包 31 | - apt-get purge 删除已安装的软件包及配置文件 32 | - apt-get autoremove 删除不需要的软件包(通常是由于依赖关系而安装) 33 | - apt-get autoclean 删除已卸载的软件包的.deb档 34 | - dpkg --get-selections | grep 搜索已安装的软件包 35 | - dpkg -s/-L 查看已安装的包信息/路径 36 | 37 | 38 | 39 | # 常用命令行 40 | - `python tcprelay.py -t 2222:2244` 41 | - `uicache //refresh ui` 42 | - `ssh root@ip -p 2222` 43 | - `scp -P root@: ` 44 | - `tcpdump -i lo0 -s0 -w xxxx.pcapng //抓lo0接口的包` 45 | - `ifconfig lo0` 46 | - `rvictl -s uuid [Getting a Packet Trace]:https://developer.apple.com/library/content/qa/qa1176/_index.html#//apple_ref/doc/uid/DTS10001707-CH1-SECRVI` 47 | - `defaults write ~/Desktop/config_Xcode/plistfiletst key value` 48 | - `sudo xcode-select -s /Applications/Xcode.app/Contents/Developer` 49 | - `curl - I "http://ssxxx/hhh.txt"` 50 | - `wget -c "http://sssxxx/hhh.txt"` 51 | - `nscurl --ats-diagnostics --verbose https://127.0.0.1:443 //诊断app对于https的plist设置是否正确` 52 | - `dig cache.default.server.matocloud.com` 53 | - `telnet 123.103.23.219` 54 | - `nm //display name list (symbol table)` 55 | - `dpkg -i xxxx.deb (use apt-get install -f command tries to fix this broken package by installing the missing dependency)` 56 | - `https://unix.stackexchange.com/questions/159094/how-to-install-a-deb-file-by-dpkg-i-or-by-apt` 57 | - `grep -rnw headOutPuts -e 'requestByRemovingPostCheckKey' //查找指定字符串的文件` 58 | - `otool -l xxxx | grep crypt // 0为脱过壳` 59 | - `codesign -d --ent :- /path/to/the.app //Inspect the entitlements of a built app` 60 | # 常用文件路径 61 | - `host文件 /private/etc/` 62 | - `cydia下载的deb文件 /private/var/cache/apt/archives 2014年11月,iOS8越狱后的deb包的变化: /User/Library/Caches/com.saurik.Cydia/archives/` 63 | 64 | # 自动安装deb文件 65 | - 将deb文件放入/private/var/root/Media/Cydia/AutoInstall,然后重启设备 66 | 67 | # 常用的源 68 | - http://apt.saurik.com/ 69 | - http://apt.thebigboss.org/repofiles/cydia/ 70 | - https://cydia.angelxwind.net/ 71 | - http://rpetri.ch/repo/ 72 | - applist 73 | - http://www.saurik.com/id/1 74 | - http://xsf1re.github.io 75 | -flyjb 76 | 77 | # iPhone相关的网站 78 | - https://www.theiphonewiki.com/wiki/Models 79 | # 越狱可用的网站 80 | 1. https://checkra.in 81 | 2. https://frida.re/docs/installation/ 82 | 3. 83 | # 忘记ssh的密码 84 | 1. 使用iFiles或者Filza打开'/private/etc/master.password',找到下面这行 85 | 86 | root:xxxxxxxxxxxxx:0:0::0:0:System Administrator:/var/root:/bin/sh 87 | mobile:xxxxxxxxxxxxx:501:501::0:0:Mobile User:/var/mobile:/bin/sh 88 | 89 | 2. 将root:及mobile:后面的13个x字符处修改成 90 | 91 | root:/smx7MYTQIi2M:0:0::0:0:System Administrator:/var/root:/bin/sh 92 | mobile:/smx7MYTQIi2M:501:501::0:0:Mobile User:/var/mobile:/bin/sh 93 | 3. 修改后保存此文件,你越狱机的ssh密码就重新回到默认的:'alpine' 94 | 95 | # cydia can't access network 96 | 1. cd /var/preferences 97 | 2. backup 98 | 3. rm -rf com.apple.networkextension.plist 99 | 4. rm -rf com.apple.networkextension.cache.plist 100 | 5. rm -rf com.apple.networkextension.necp.plist 101 | 6. 提醒: 如果你是第一次使用的同学cydia启用网络之后 会搜索到cydia的更新 更新之后 的cydia又会无法联网.请再去删一次 3个文件然后再重启 即可. 102 | 103 | # Reveal V4 fix "The operation couldn’t be completed. The app is linked against an older version of the Reveal library. You may need to update the Reveal library in your app." 104 | 0. `install Reveal2Loader_1.0-3_iphoneos-arm.deb or put deb in Device/var/root` 105 | 1. `copy RevealServer.framework to /Library/Frameworks` 106 | 2. `killall SpringBoard` 107 | 108 | # ifunbox can see root 109 | 1. install "Apple File Conduit "2" (64位)" 110 | 111 | # 方便的调试他人app的工具 112 | - flexible 113 | - woodpecker 114 | - lookin 115 | 116 | # IPA2Deb 117 | - mkdir tmp 118 | - cd tmp 119 | - mkdir DEBIAN Applications 120 | - touch DEBIAN/control 121 | - vim DEBIAN/control 122 | - 输入如下的文本: 123 | Package: com.sharedream.test 124 | Name: test 125 | Version: 0.1 126 | Description: test 127 | Section: test 128 | Depends: firmware (>= 4.3) 129 | Priority: optional 130 | Architecture: iphoneos-arm 131 | Author: test 132 | Homepage: test 133 | Maintainer: test 134 | - cp text.app Applications 135 | - cd .. 136 | - dpkg-deb -b tmp test.deb 137 | - dpkg-scanpackages -m debs >Packages 138 | - bzip2 -zkf Packages 139 | 140 | # homebrew 141 | ## 中科大镜像 142 | 替换brew.git: 143 | cd "$(brew --repo)" 144 | git remote set-url origin https://mirrors.ustc.edu.cn/brew.git 145 | 146 | 替换homebrew-core.git: 147 | cd "$(brew --repo)/Library/Taps/homebrew/homebrew-core" 148 | git remote set-url origin https://mirrors.ustc.edu.cn/homebrew-core.git 149 | 150 | ## 阿里镜像 151 | 152 | - cd "$(brew --repo)" 153 | 154 | - git remote set-url origin https://mirrors.aliyun.com/homebrew/brew.git 155 | 156 | - cd "$(brew --repo)/Library/Taps/homebrew/homebrew-core" 157 | 158 | - git remote set-url origin https://mirrors.aliyun.com/homebrew/homebrew-core.git 159 | 160 | ## 更新 161 | 162 | - brew update 163 | - brew config 164 | 165 | ## 重置 166 | - cd "$(brew --repo)" 167 | - git remote set-url origin https://github.com/Homebrew/brew.git 168 | 169 | - cd "$(brew --repo)/Library/Taps/homebrew/homebrew-core" 170 | - git remote set-url origin https://github.com/Homebrew/homebrew-core.git 171 | 172 | ## 更换 homebrew-bottles 173 | - echo $SHELL 174 | 175 | - echo 'export HOMEBREW_BOTTLE_DOMAIN=https://mirrors.aliyun.com/homebrew/homebrew-bottles' >> ~/.zshrc 176 | 177 | - source ~/.zshrc 178 | 179 | - echo 'export HOMEBREW_BOTTLE_DOMAIN=https://mirrors.aliyun.com/homebrew/homebrew-bottles' >> ~/.bash_profile 180 | 181 | - source ~/.bash_profile 182 | 183 | 184 | -------------------------------------------------------------------------------- /inject_with_jailbreaking/AsyncSocket.h: -------------------------------------------------------------------------------- 1 | // 2 | // AsyncSocket.h 3 | // 4 | // This class is in the public domain. 5 | // Originally created by Dustin Voss on Wed Jan 29 2003. 6 | // Updated and maintained by Deusty Designs and the Mac development community. 7 | // 8 | // http://code.google.com/p/cocoaasyncsocket/ 9 | // 10 | 11 | #import 12 | 13 | @class AsyncSocket; 14 | @class AsyncReadPacket; 15 | @class AsyncWritePacket; 16 | 17 | extern NSString *const AsyncSocketException; 18 | extern NSString *const AsyncSocketErrorDomain; 19 | 20 | enum AsyncSocketError 21 | { 22 | AsyncSocketCFSocketError = kCFSocketError, // From CFSocketError enum. 23 | AsyncSocketNoError = 0, // Never used. 24 | AsyncSocketCanceledError, // onSocketWillConnect: returned NO. 25 | AsyncSocketConnectTimeoutError, 26 | AsyncSocketReadMaxedOutError, // Reached set maxLength without completing 27 | AsyncSocketReadTimeoutError, 28 | AsyncSocketWriteTimeoutError 29 | }; 30 | typedef enum AsyncSocketError AsyncSocketError; 31 | 32 | @interface NSObject (AsyncSocketDelegate) 33 | 34 | /** 35 | * In the event of an error, the socket is closed. 36 | * You may call "unreadData" during this call-back to get the last bit of data off the socket. 37 | * When connecting, this delegate method may be called 38 | * before"onSocket:didAcceptNewSocket:" or "onSocket:didConnectToHost:". 39 | **/ 40 | - (void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err; 41 | 42 | /** 43 | * Called when a socket disconnects with or without error. If you want to release a socket after it disconnects, 44 | * do so here. It is not safe to do that during "onSocket:willDisconnectWithError:". 45 | * 46 | * If you call the disconnect method, and the socket wasn't already disconnected, 47 | * this delegate method will be called before the disconnect method returns. 48 | **/ 49 | - (void)onSocketDidDisconnect:(AsyncSocket *)sock; 50 | 51 | /** 52 | * Called when a socket accepts a connection. Another socket is spawned to handle it. The new socket will have 53 | * the same delegate and will call "onSocket:didConnectToHost:port:". 54 | **/ 55 | - (void)onSocket:(AsyncSocket *)sock didAcceptNewSocket:(AsyncSocket *)newSocket; 56 | 57 | /** 58 | * Called when a new socket is spawned to handle a connection. This method should return the run-loop of the 59 | * thread on which the new socket and its delegate should operate. If omitted, [NSRunLoop currentRunLoop] is used. 60 | **/ 61 | - (NSRunLoop *)onSocket:(AsyncSocket *)sock wantsRunLoopForNewSocket:(AsyncSocket *)newSocket; 62 | 63 | /** 64 | * Called when a socket is about to connect. This method should return YES to continue, or NO to abort. 65 | * If aborted, will result in AsyncSocketCanceledError. 66 | * 67 | * If the connectToHost:onPort:error: method was called, the delegate will be able to access and configure the 68 | * CFReadStream and CFWriteStream as desired prior to connection. 69 | * 70 | * If the connectToAddress:error: method was called, the delegate will be able to access and configure the 71 | * CFSocket and CFSocketNativeHandle (BSD socket) as desired prior to connection. You will be able to access and 72 | * configure the CFReadStream and CFWriteStream in the onSocket:didConnectToHost:port: method. 73 | **/ 74 | - (BOOL)onSocketWillConnect:(AsyncSocket *)sock; 75 | 76 | /** 77 | * Called when a socket connects and is ready for reading and writing. 78 | * The host parameter will be an IP address, not a DNS name. 79 | **/ 80 | - (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port; 81 | 82 | /** 83 | * Called when a socket has completed reading the requested data into memory. 84 | * Not called if there is an error. 85 | **/ 86 | - (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag; 87 | 88 | /** 89 | * Called when a socket has read in data, but has not yet completed the read. 90 | * This would occur if using readToData: or readToLength: methods. 91 | * It may be used to for things such as updating progress bars. 92 | **/ 93 | - (void)onSocket:(AsyncSocket *)sock didReadPartialDataOfLength:(CFIndex)partialLength tag:(long)tag; 94 | 95 | /** 96 | * Called when a socket has completed writing the requested data. Not called if there is an error. 97 | **/ 98 | - (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag; 99 | 100 | /** 101 | * Called when a socket has written some data, but has not yet completed the entire write. 102 | * It may be used to for things such as updating progress bars. 103 | **/ 104 | - (void)onSocket:(AsyncSocket *)sock didWritePartialDataOfLength:(CFIndex)partialLength tag:(long)tag; 105 | 106 | /** 107 | * Called if a read operation has reached its timeout without completing. 108 | * This method allows you to optionally extend the timeout. 109 | * If you return a positive time interval (> 0) the read's timeout will be extended by the given amount. 110 | * If you don't implement this method, or return a non-positive time interval (<= 0) the read will timeout as usual. 111 | * 112 | * The elapsed parameter is the sum of the original timeout, plus any additions previously added via this method. 113 | * The length parameter is the number of bytes that have been read so far for the read operation. 114 | * 115 | * Note that this method may be called multiple times for a single read if you return positive numbers. 116 | **/ 117 | - (NSTimeInterval)onSocket:(AsyncSocket *)sock 118 | shouldTimeoutReadWithTag:(long)tag 119 | elapsed:(NSTimeInterval)elapsed 120 | bytesDone:(CFIndex)length; 121 | 122 | /** 123 | * Called if a write operation has reached its timeout without completing. 124 | * This method allows you to optionally extend the timeout. 125 | * If you return a positive time interval (> 0) the write's timeout will be extended by the given amount. 126 | * If you don't implement this method, or return a non-positive time interval (<= 0) the write will timeout as usual. 127 | * 128 | * The elapsed parameter is the sum of the original timeout, plus any additions previously added via this method. 129 | * The length parameter is the number of bytes that have been written so far for the write operation. 130 | * 131 | * Note that this method may be called multiple times for a single write if you return positive numbers. 132 | **/ 133 | - (NSTimeInterval)onSocket:(AsyncSocket *)sock 134 | shouldTimeoutWriteWithTag:(long)tag 135 | elapsed:(NSTimeInterval)elapsed 136 | bytesDone:(CFIndex)length; 137 | 138 | /** 139 | * Called after the socket has successfully completed SSL/TLS negotiation. 140 | * This method is not called unless you use the provided startTLS method. 141 | * 142 | * If a SSL/TLS negotiation fails (invalid certificate, etc) then the socket will immediately close, 143 | * and the onSocket:willDisconnectWithError: delegate method will be called with the specific SSL error code. 144 | **/ 145 | - (void)onSocketDidSecure:(AsyncSocket *)sock; 146 | 147 | @end 148 | 149 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 150 | #pragma mark - 151 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 152 | 153 | @interface AsyncSocket : NSObject 154 | { 155 | CFSocketNativeHandle theNativeSocket4; 156 | CFSocketNativeHandle theNativeSocket6; 157 | 158 | CFSocketRef theSocket4; // IPv4 accept or connect socket 159 | CFSocketRef theSocket6; // IPv6 accept or connect socket 160 | 161 | CFReadStreamRef theReadStream; 162 | CFWriteStreamRef theWriteStream; 163 | 164 | CFRunLoopSourceRef theSource4; // For theSocket4 165 | CFRunLoopSourceRef theSource6; // For theSocket6 166 | CFRunLoopRef theRunLoop; 167 | CFSocketContext theContext; 168 | NSArray *theRunLoopModes; 169 | 170 | NSTimer *theConnectTimer; 171 | 172 | NSMutableArray *theReadQueue; 173 | AsyncReadPacket *theCurrentRead; 174 | NSTimer *theReadTimer; 175 | NSMutableData *partialReadBuffer; 176 | 177 | NSMutableArray *theWriteQueue; 178 | AsyncWritePacket *theCurrentWrite; 179 | NSTimer *theWriteTimer; 180 | 181 | id theDelegate; 182 | UInt16 theFlags; 183 | 184 | long theUserData; 185 | } 186 | 187 | - (id)init; 188 | - (id)initWithDelegate:(id)delegate; 189 | - (id)initWithDelegate:(id)delegate userData:(long)userData; 190 | 191 | /* String representation is long but has no "\n". */ 192 | - (NSString *)description; 193 | 194 | /** 195 | * Use "canSafelySetDelegate" to see if there is any pending business (reads and writes) with the current delegate 196 | * before changing it. It is, of course, safe to change the delegate before connecting or accepting connections. 197 | **/ 198 | - (id)delegate; 199 | - (BOOL)canSafelySetDelegate; 200 | - (void)setDelegate:(id)delegate; 201 | 202 | /* User data can be a long, or an id or void * cast to a long. */ 203 | - (long)userData; 204 | - (void)setUserData:(long)userData; 205 | 206 | /* Don't use these to read or write. And don't close them either! */ 207 | - (CFSocketRef)getCFSocket; 208 | - (CFReadStreamRef)getCFReadStream; 209 | - (CFWriteStreamRef)getCFWriteStream; 210 | 211 | // Once one of the accept or connect methods are called, the AsyncSocket instance is locked in 212 | // and the other accept/connect methods can't be called without disconnecting the socket first. 213 | // If the attempt fails or times out, these methods either return NO or 214 | // call "onSocket:willDisconnectWithError:" and "onSockedDidDisconnect:". 215 | 216 | // When an incoming connection is accepted, AsyncSocket invokes several delegate methods. 217 | // These methods are (in chronological order): 218 | // 1. onSocket:didAcceptNewSocket: 219 | // 2. onSocket:wantsRunLoopForNewSocket: 220 | // 3. onSocketWillConnect: 221 | // 222 | // Your server code will need to retain the accepted socket (if you want to accept it). 223 | // The best place to do this is probably in the onSocket:didAcceptNewSocket: method. 224 | // 225 | // After the read and write streams have been setup for the newly accepted socket, 226 | // the onSocket:didConnectToHost:port: method will be called on the proper run loop. 227 | // 228 | // Multithreading Note: If you're going to be moving the newly accepted socket to another run 229 | // loop by implementing onSocket:wantsRunLoopForNewSocket:, then you should wait until the 230 | // onSocket:didConnectToHost:port: method before calling read, write, or startTLS methods. 231 | // Otherwise read/write events are scheduled on the incorrect runloop, and chaos may ensue. 232 | 233 | /** 234 | * Tells the socket to begin listening and accepting connections on the given port. 235 | * When a connection comes in, the AsyncSocket instance will call the various delegate methods (see above). 236 | * The socket will listen on all available interfaces (e.g. wifi, ethernet, etc) 237 | **/ 238 | - (BOOL)acceptOnPort:(UInt16)port error:(NSError **)errPtr; 239 | 240 | /** 241 | * This method is the same as acceptOnPort:error: with the additional option 242 | * of specifying which interface to listen on. So, for example, if you were writing code for a server that 243 | * has multiple IP addresses, you could specify which address you wanted to listen on. Or you could use it 244 | * to specify that the socket should only accept connections over ethernet, and not other interfaces such as wifi. 245 | * You may also use the special strings "localhost" or "loopback" to specify that 246 | * the socket only accept connections from the local machine. 247 | * 248 | * To accept connections on any interface pass nil, or simply use the acceptOnPort:error: method. 249 | **/ 250 | - (BOOL)acceptOnInterface:(NSString *)interface port:(UInt16)port error:(NSError **)errPtr; 251 | 252 | /** 253 | * Connects to the given host and port. 254 | * The host may be a domain name (e.g. "deusty.com") or an IP address string (e.g. "192.168.0.2") 255 | **/ 256 | - (BOOL)connectToHost:(NSString *)hostname onPort:(UInt16)port error:(NSError **)errPtr; 257 | 258 | /** 259 | * This method is the same as connectToHost:onPort:error: with an additional timeout option. 260 | * To not time out use a negative time interval, or simply use the connectToHost:onPort:error: method. 261 | **/ 262 | - (BOOL)connectToHost:(NSString *)hostname 263 | onPort:(UInt16)port 264 | withTimeout:(NSTimeInterval)timeout 265 | error:(NSError **)errPtr; 266 | 267 | /** 268 | * Connects to the given address, specified as a sockaddr structure wrapped in a NSData object. 269 | * For example, a NSData object returned from NSNetservice's addresses method. 270 | * 271 | * If you have an existing struct sockaddr you can convert it to a NSData object like so: 272 | * struct sockaddr sa -> NSData *dsa = [NSData dataWithBytes:&remoteAddr length:remoteAddr.sa_len]; 273 | * struct sockaddr *sa -> NSData *dsa = [NSData dataWithBytes:remoteAddr length:remoteAddr->sa_len]; 274 | **/ 275 | - (BOOL)connectToAddress:(NSData *)remoteAddr error:(NSError **)errPtr; 276 | 277 | /** 278 | * This method is the same as connectToAddress:error: with an additional timeout option. 279 | * To not time out use a negative time interval, or simply use the connectToAddress:error: method. 280 | **/ 281 | - (BOOL)connectToAddress:(NSData *)remoteAddr withTimeout:(NSTimeInterval)timeout error:(NSError **)errPtr; 282 | 283 | /** 284 | * Disconnects immediately. Any pending reads or writes are dropped. 285 | * If the socket is not already disconnected, the onSocketDidDisconnect delegate method 286 | * will be called immediately, before this method returns. 287 | * 288 | * Please note the recommended way of releasing an AsyncSocket instance (e.g. in a dealloc method) 289 | * [asyncSocket setDelegate:nil]; 290 | * [asyncSocket disconnect]; 291 | * [asyncSocket release]; 292 | **/ 293 | - (void)disconnect; 294 | 295 | /** 296 | * Disconnects after all pending reads have completed. 297 | * After calling this, the read and write methods will do nothing. 298 | * The socket will disconnect even if there are still pending writes. 299 | **/ 300 | - (void)disconnectAfterReading; 301 | 302 | /** 303 | * Disconnects after all pending writes have completed. 304 | * After calling this, the read and write methods will do nothing. 305 | * The socket will disconnect even if there are still pending reads. 306 | **/ 307 | - (void)disconnectAfterWriting; 308 | 309 | /** 310 | * Disconnects after all pending reads and writes have completed. 311 | * After calling this, the read and write methods will do nothing. 312 | **/ 313 | - (void)disconnectAfterReadingAndWriting; 314 | 315 | /* Returns YES if the socket and streams are open, connected, and ready for reading and writing. */ 316 | - (BOOL)isConnected; 317 | 318 | /** 319 | * Returns the local or remote host and port to which this socket is connected, or nil and 0 if not connected. 320 | * The host will be an IP address. 321 | **/ 322 | - (NSString *)connectedHost; 323 | - (UInt16)connectedPort; 324 | 325 | - (NSString *)localHost; 326 | - (UInt16)localPort; 327 | 328 | /** 329 | * Returns the local or remote address to which this socket is connected, 330 | * specified as a sockaddr structure wrapped in a NSData object. 331 | * 332 | * See also the connectedHost, connectedPort, localHost and localPort methods. 333 | **/ 334 | - (NSData *)connectedAddress; 335 | - (NSData *)localAddress; 336 | 337 | /** 338 | * Returns whether the socket is IPv4 or IPv6. 339 | * An accepting socket may be both. 340 | **/ 341 | - (BOOL)isIPv4; 342 | - (BOOL)isIPv6; 343 | 344 | // The readData and writeData methods won't block. 345 | // 346 | // You may optionally set a timeout for any read/write operation. (To not timeout, use a negative time interval.) 347 | // If a read/write opertion times out, the corresponding "onSocket:shouldTimeout..." delegate method 348 | // is called to optionally allow you to extend the timeout. 349 | // Upon a timeout, the "onSocket:willDisconnectWithError:" method is called, followed by "onSocketDidDisconnect". 350 | // 351 | // The tag is for your convenience. 352 | // You can use it as an array index, step number, state id, pointer, etc., just like the socket's user data. 353 | 354 | /** 355 | * This will read a certain number of bytes into memory, and call the delegate method when those bytes have been read. 356 | * 357 | * If the length is 0, this method does nothing and the delegate is not called. 358 | * If the timeout value is negative, the read operation will not use a timeout. 359 | **/ 360 | - (void)readDataToLength:(CFIndex)length withTimeout:(NSTimeInterval)timeout tag:(long)tag; 361 | 362 | /** 363 | * This reads bytes until (and including) the passed "data" parameter, which acts as a separator. 364 | * The bytes and the separator are returned by the delegate method. 365 | * 366 | * If you pass nil or zero-length data as the "data" parameter, 367 | * the method will do nothing, and the delegate will not be called. 368 | * If the timeout value is negative, the read operation will not use a timeout. 369 | * 370 | * To read a line from the socket, use the line separator (e.g. CRLF for HTTP, see below) as the "data" parameter. 371 | * Note that this method is not character-set aware, so if a separator can occur naturally as part of the encoding for 372 | * a character, the read will prematurely end. 373 | **/ 374 | - (void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag; 375 | 376 | /** 377 | * Same as readDataToData:withTimeout:tag, with the additional restriction that the amount of data read 378 | * may not surpass the given maxLength (specified in bytes). 379 | * 380 | * If you pass a maxLength parameter that is less than the length of the data parameter, 381 | * the method will do nothing, and the delegate will not be called. 382 | * 383 | * If the max length is surpassed, it is treated the same as a timeout - the socket is closed. 384 | * 385 | * Pass -1 as maxLength if no length restriction is desired, or simply use the readDataToData:withTimeout:tag method. 386 | **/ 387 | - (void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout maxLength:(CFIndex)length tag:(long)tag; 388 | 389 | /** 390 | * Reads the first available bytes that become available on the socket. 391 | * 392 | * If the timeout value is negative, the read operation will not use a timeout. 393 | **/ 394 | - (void)readDataWithTimeout:(NSTimeInterval)timeout tag:(long)tag; 395 | 396 | /** 397 | * Writes data to the socket, and calls the delegate when finished. 398 | * 399 | * If you pass in nil or zero-length data, this method does nothing and the delegate will not be called. 400 | * If the timeout value is negative, the write operation will not use a timeout. 401 | **/ 402 | - (void)writeData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag; 403 | 404 | /** 405 | * Returns progress of current read or write, from 0.0 to 1.0, or NaN if no read/write (use isnan() to check). 406 | * "tag", "done" and "total" will be filled in if they aren't NULL. 407 | **/ 408 | - (float)progressOfReadReturningTag:(long *)tag bytesDone:(CFIndex *)done total:(CFIndex *)total; 409 | - (float)progressOfWriteReturningTag:(long *)tag bytesDone:(CFIndex *)done total:(CFIndex *)total; 410 | 411 | /** 412 | * Secures the connection using SSL/TLS. 413 | * 414 | * This method may be called at any time, and the TLS handshake will occur after all pending reads and writes 415 | * are finished. This allows one the option of sending a protocol dependent StartTLS message, and queuing 416 | * the upgrade to TLS at the same time, without having to wait for the write to finish. 417 | * Any reads or writes scheduled after this method is called will occur over the secured connection. 418 | * 419 | * The possible keys and values for the TLS settings are well documented. 420 | * Some possible keys are: 421 | * - kCFStreamSSLLevel 422 | * - kCFStreamSSLAllowsExpiredCertificates 423 | * - kCFStreamSSLAllowsExpiredRoots 424 | * - kCFStreamSSLAllowsAnyRoot 425 | * - kCFStreamSSLValidatesCertificateChain 426 | * - kCFStreamSSLPeerName 427 | * - kCFStreamSSLCertificates 428 | * - kCFStreamSSLIsServer 429 | * 430 | * Please refer to Apple's documentation for associated values, as well as other possible keys. 431 | * 432 | * If you pass in nil or an empty dictionary, the default settings will be used. 433 | * 434 | * The default settings will check to make sure the remote party's certificate is signed by a 435 | * trusted 3rd party certificate agency (e.g. verisign) and that the certificate is not expired. 436 | * However it will not verify the name on the certificate unless you 437 | * give it a name to verify against via the kCFStreamSSLPeerName key. 438 | * The security implications of this are important to understand. 439 | * Imagine you are attempting to create a secure connection to MySecureServer.com, 440 | * but your socket gets directed to MaliciousServer.com because of a hacked DNS server. 441 | * If you simply use the default settings, and MaliciousServer.com has a valid certificate, 442 | * the default settings will not detect any problems since the certificate is valid. 443 | * To properly secure your connection in this particular scenario you 444 | * should set the kCFStreamSSLPeerName property to "MySecureServer.com". 445 | * If you do not know the peer name of the remote host in advance (for example, you're not sure 446 | * if it will be "domain.com" or "www.domain.com"), then you can use the default settings to validate the 447 | * certificate, and then use the X509Certificate class to verify the issuer after the socket has been secured. 448 | * The X509Certificate class is part of the CocoaAsyncSocket open source project. 449 | **/ 450 | - (void)startTLS:(NSDictionary *)tlsSettings; 451 | 452 | /** 453 | * For handling readDataToData requests, data is necessarily read from the socket in small increments. 454 | * The performance can be much improved by allowing AsyncSocket to read larger chunks at a time and 455 | * store any overflow in a small internal buffer. 456 | * This is termed pre-buffering, as some data may be read for you before you ask for it. 457 | * If you use readDataToData a lot, enabling pre-buffering will result in better performance, especially on the iPhone. 458 | * 459 | * The default pre-buffering state is controlled by the DEFAULT_PREBUFFERING definition. 460 | * It is highly recommended one leave this set to YES. 461 | * 462 | * This method exists in case pre-buffering needs to be disabled by default for some unforeseen reason. 463 | * In that case, this method exists to allow one to easily enable pre-buffering when ready. 464 | **/ 465 | - (void)enablePreBuffering; 466 | 467 | /** 468 | * When you create an AsyncSocket, it is added to the runloop of the current thread. 469 | * So for manually created sockets, it is easiest to simply create the socket on the thread you intend to use it. 470 | * 471 | * If a new socket is accepted, the delegate method onSocket:wantsRunLoopForNewSocket: is called to 472 | * allow you to place the socket on a separate thread. This works best in conjunction with a thread pool design. 473 | * 474 | * If, however, you need to move the socket to a separate thread at a later time, this 475 | * method may be used to accomplish the task. 476 | * 477 | * This method must be called from the thread/runloop the socket is currently running on. 478 | * 479 | * Note: After calling this method, all further method calls to this object should be done from the given runloop. 480 | * Also, all delegate calls will be sent on the given runloop. 481 | **/ 482 | - (BOOL)moveToRunLoop:(NSRunLoop *)runLoop; 483 | 484 | /** 485 | * Allows you to configure which run loop modes the socket uses. 486 | * The default set of run loop modes is NSDefaultRunLoopMode. 487 | * 488 | * If you'd like your socket to continue operation during other modes, you may want to add modes such as 489 | * NSModalPanelRunLoopMode or NSEventTrackingRunLoopMode. Or you may simply want to use NSRunLoopCommonModes. 490 | * 491 | * Accepted sockets will automatically inherit the same run loop modes as the listening socket. 492 | * 493 | * Note: NSRunLoopCommonModes is defined in 10.5. For previous versions one can use kCFRunLoopCommonModes. 494 | **/ 495 | - (BOOL)setRunLoopModes:(NSArray *)runLoopModes; 496 | 497 | /** 498 | * Returns the current run loop modes the AsyncSocket instance is operating in. 499 | * The default set of run loop modes is NSDefaultRunLoopMode. 500 | **/ 501 | - (NSArray *)runLoopModes; 502 | 503 | /** 504 | * In the event of an error, this method may be called during onSocket:willDisconnectWithError: to read 505 | * any data that's left on the socket. 506 | **/ 507 | - (NSData *)unreadData; 508 | 509 | /* A few common line separators, for use with the readDataToData:... methods. */ 510 | + (NSData *)CRLFData; // 0x0D0A 511 | + (NSData *)CRData; // 0x0D 512 | + (NSData *)LFData; // 0x0A 513 | + (NSData *)ZeroData; // 0x00 514 | 515 | @end 516 | -------------------------------------------------------------------------------- /inject_with_jailbreaking/Xtrace.h: -------------------------------------------------------------------------------- 1 | // 2 | // Xtrace.h 3 | // Xtrace 4 | // 5 | // Created by John Holdsworth on 28/02/2014. 6 | // Copyright (c) 2014 John Holdsworth. All rights reserved. 7 | // 8 | // Repo: https://github.com/johnno1962/Xtrace 9 | // 10 | // $Id: //depot/Xtrace/Xtrace.h#2 $ 11 | // 12 | // Class to intercept messages sent to a class or object. 13 | // Swizzles generic logging implemntation in place of the 14 | // original which is called after logging the message. 15 | // 16 | // Implemented as category on NSObject so message the 17 | // class or instance you want to log for example: 18 | // 19 | // Log all messages of the navigation controller class 20 | // and it's superclasses: 21 | // [UINavigationController xtrace] 22 | // 23 | // Log all messages sent to objects instance1/2 24 | // [instance1 xtrace]; 25 | // [instance2 xtrace]; 26 | // 27 | // Instance tracing takes priority. 28 | // 29 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 30 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 31 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 32 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 33 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 34 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 35 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 36 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 37 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 38 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 | // 40 | 41 | #ifdef DEBUG 42 | #ifdef __OBJC__ 43 | #import 44 | #import 45 | 46 | #ifdef __clang__ 47 | #if __has_feature(objc_arc) 48 | #define XTRACE_ISARC 49 | #endif 50 | #endif 51 | 52 | #ifdef XTRACE_ISARC 53 | #define XTRACE_UNSAFE __unsafe_unretained 54 | #define XTRACE_BRIDGE(_type) (__bridge _type) 55 | #define XTRACE_RETAINED __attribute((ns_returns_retained)) 56 | #else 57 | #define XTRACE_UNSAFE 58 | #define XTRACE_BRIDGE(_type) (_type) 59 | #define XTRACE_RETAINED 60 | #endif 61 | 62 | #define XTRACE_EXCLUSIONS "^(initWithCoder:|_UIAppearance_|"\ 63 | "_(initializeFor|performUpdatesForPossibleChangesOf)Idiom:|"\ 64 | "timeIntervalSinceReferenceDate)|(WithObjects(AndKeys)?|Format):$" 65 | 66 | // for use with "XcodeColours" plugin 67 | // https://github.com/robbiehanson/XcodeColors 68 | 69 | #define XTRACE_FG "\033[fg" 70 | #define XTRACE_BG "\033[bg" 71 | 72 | #define XTRACE_RED XTRACE_FG"255,0,0;" 73 | #define XTRACE_GREEN XTRACE_FG"0,255,0;" 74 | #define XTRACE_BLUE XTRACE_FG"0,0,255;" 75 | 76 | // internal information 77 | #define XTRACE_ARGS_SUPPORTED 10 78 | 79 | typedef void (*XTRACE_VIMP)( XTRACE_UNSAFE id obj, SEL sel, ... ); 80 | typedef void (^XTRACE_BIMP)( XTRACE_UNSAFE id obj, SEL sel, ... ); 81 | 82 | struct _xtrace_arg { 83 | const char *name, *type; 84 | int stackOffset; 85 | }; 86 | 87 | // information about original implementations 88 | struct _xtrace_info { 89 | int depth; 90 | void *caller; 91 | void *lastObj; 92 | const char *color; 93 | 94 | XTRACE_VIMP before, original, after; 95 | XTRACE_UNSAFE XTRACE_BIMP beforeBlock, afterBlock; 96 | 97 | Method method; 98 | const char *name, *type, *mtype; 99 | struct _xtrace_arg args[XTRACE_ARGS_SUPPORTED+1]; 100 | 101 | struct _stats { 102 | NSTimeInterval entered, elapsed; 103 | unsigned callCount; 104 | } stats; 105 | BOOL callingBack; 106 | }; 107 | 108 | @interface NSObject(Xtrace) 109 | 110 | // dump class 111 | + (void)xdump; 112 | 113 | // intercept before method is called 114 | + (void)beforeSelector:(SEL)sel callBlock:callback; 115 | 116 | // after intercept block replaces return value 117 | + (void)afterSelector:(SEL)sel callBlock:callback; 118 | 119 | // avoid a class 120 | + (void)notrace; 121 | 122 | // trace class or.. 123 | + (void)xtrace; 124 | 125 | // trace instance 126 | - (void)xtrace; 127 | 128 | // stop tacing "" 129 | - (void)notrace; 130 | 131 | @end 132 | 133 | // logging delegate 134 | @protocol XtraceDelegate 135 | - (void)xtrace:(NSString *)trace forInstance:(void *)obj indent:(int)indent; 136 | @end 137 | 138 | // implementing class 139 | @interface Xtrace : NSObject { 140 | @public 141 | Class aClass; 142 | struct _xtrace_info *info; 143 | NSTimeInterval elapsed; 144 | int callCount; 145 | } 146 | 147 | // delegate for callbacks 148 | + (void)setDelegate:delegate; 149 | 150 | // show caller on entry 151 | + (void)showCaller:(BOOL)show; 152 | 153 | // show class implementing 154 | + (void)showActual:(BOOL)show; 155 | 156 | // show log of return values 157 | + (void)showReturns:(BOOL)show; 158 | 159 | // attempt log of call arguments 160 | + (void)showArguments:(BOOL)show; 161 | 162 | // log values's "description" 163 | + (void)describeValues:(BOOL)desc; 164 | 165 | // property methods filtered out by default 166 | + (void)includeProperties:(BOOL)include; 167 | 168 | // include/exclude methods matching pattern 169 | + (BOOL)includeMethods:(NSString *)pattern; 170 | + (BOOL)excludeMethods:(NSString *)pattern; 171 | + (BOOL)excludeTypes:(NSString *)pattern; 172 | 173 | // color subsequent traces 174 | + (void)useColor:(const char *)color; 175 | 176 | // finer grain control of color 177 | + (void)useColor:(const char *)color forSelector:(SEL)sel; 178 | + (void)useColor:(const char *)color forClass:(Class)aClass; 179 | 180 | // don't trace this class e.g. [UIView notrace] 181 | + (void)dontTrace:(Class)aClass; 182 | 183 | // trace class down to NSObject 184 | + (void)traceClass:(Class)aClass; 185 | 186 | // trace class down to "levels" of superclases 187 | + (void)traceClass:(Class)aClass levels:(int)levels; 188 | 189 | // trace all classes in app/bundle/framework 190 | + (void)traceBundleContainingClass:(Class)aClass; 191 | 192 | // "kitchen sink" trace all classes matching pattern 193 | + (void)traceClassPattern:(NSString *)pattern excluding:(NSString *)exclusions; 194 | 195 | // trace instance but only for methods in aClass 196 | + (void)traceInstance:(id)instance class:(Class)aClass; 197 | 198 | // trace all messages sent to an instance 199 | + (void)traceInstance:(id)instance; 200 | 201 | // stop tracing messages to instance 202 | + (void)notrace:(id)instance; 203 | 204 | // dump runtime class info 205 | + (void)dumpClass:(Class)aClass; 206 | 207 | // before, replacement and after callbacks to delegate 208 | + (void)forClass:(Class)aClass before:(SEL)sel callback:(SEL)callback; 209 | + (void)forClass:(Class)aClass replace:(SEL)sel callback:(SEL)callback; 210 | + (void)forClass:(Class)aClass after:(SEL)sel callback:(SEL)callback; 211 | 212 | // block based callbacks as an alternative 213 | + (void)forClass:(Class)aClass before:(SEL)sel callbackBlock:callback; 214 | + (void)forClass:(Class)aClass after:(SEL)sel callbackBlock:callback; 215 | 216 | // get parsed argument info and recorded stats 217 | + (struct _xtrace_info *)infoFor:(Class)aClass sel:(SEL)sel; 218 | 219 | // name the caller of the specified method 220 | + (const char *)callerFor:(Class)aClass sel:(SEL)sel; 221 | 222 | // simple profiling interface 223 | + (NSArray *)profile; 224 | + (void)dumpProfile:(unsigned)count dp:(int)decimalPlaces; 225 | 226 | @end 227 | #endif 228 | #endif 229 | -------------------------------------------------------------------------------- /inject_with_jailbreaking/Xtrace.mm: -------------------------------------------------------------------------------- 1 | // 2 | // Xtrace.mm 3 | // Xtrace 4 | // 5 | // Created by John Holdsworth on 28/02/2014. 6 | // Copyright (c) 2014 John Holdsworth. All rights reserved. 7 | // 8 | // Repo: https://github.com/johnno1962/Xtrace 9 | // 10 | // $Id: //depot/Xtrace/Xtrace.mm#8 $ 11 | // 12 | // The above copyright notice and this permission notice shall be 13 | // included in all copies or substantial portions of the Software. 14 | // 15 | // Your milage will vary.. This is definitely a case of: 16 | // 17 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 21 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 24 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | 29 | #ifdef DEBUG 30 | 31 | #pragma clang diagnostic push 32 | #pragma clang diagnostic ignored "-Wold-style-cast" 33 | #pragma clang diagnostic ignored "-Wcstring-format-directive" 34 | #pragma clang diagnostic ignored "-Wgnu-conditional-omitted-operand" 35 | #pragma clang diagnostic ignored "-Wdisabled-macro-expansion" 36 | #pragma clang diagnostic ignored "-Wobjc-interface-ivars" 37 | #pragma clang diagnostic ignored "-Wglobal-constructors" 38 | #pragma clang diagnostic ignored "-Wdirect-ivar-access" 39 | #pragma clang diagnostic ignored "-Wclass-varargs" 40 | #pragma clang diagnostic ignored "-Wc++98-compat" 41 | #pragma clang diagnostic ignored "-Wfloat-equal" 42 | #pragma clang diagnostic ignored "-Wpadded" 43 | 44 | #import "Xtrace.h" 45 | #import 46 | 47 | #ifdef __IPHONE_OS_VERSION_MIN_REQUIRED 48 | #import 49 | #endif 50 | 51 | #import 52 | #import 53 | 54 | @implementation NSObject(Xtrace) 55 | 56 | + (void)xdump { 57 | [Xtrace dumpClass:self]; 58 | } 59 | 60 | + (void)beforeSelector:(SEL)sel callBlock:callback { 61 | [Xtrace forClass:self before:sel callbackBlock:callback]; 62 | } 63 | 64 | + (void)afterSelector:(SEL)sel callBlock:callback { 65 | [Xtrace forClass:self after:sel callbackBlock:callback]; 66 | } 67 | 68 | + (void)notrace { 69 | [Xtrace dontTrace:self]; 70 | } 71 | 72 | + (void)xtrace { 73 | [Xtrace traceClass:self]; 74 | } 75 | 76 | - (void)xtrace { 77 | [Xtrace traceInstance:self]; 78 | } 79 | 80 | - (void)notrace { 81 | [Xtrace notrace:self]; 82 | } 83 | 84 | @end 85 | 86 | @implementation Xtrace 87 | 88 | // Not sure this is even C.. 89 | static struct { BOOL showCaller = YES, showActual = YES, showReturns = YES, showArguments = YES, 90 | showSignature = NO, includeProperties = NO, describeValues = NO, logToDelegate; } params; 91 | static int indentScale = 2; 92 | static id delegate; 93 | 94 | template 95 | static inline bool exists( const _M &map, const _K &key ) { 96 | return map.find(key) != map.end(); 97 | } 98 | 99 | + (void)setDelegate:aDelegate { 100 | delegate = aDelegate; 101 | params.logToDelegate = [delegate respondsToSelector:@selector(xtrace:forInstance:indent:)]; 102 | } 103 | int printf(const char * __restrict format, ...) 104 | { 105 | va_list args; 106 | va_start(args,format); 107 | NSLogv([NSString stringWithUTF8String:format], args) ; 108 | va_end(args); 109 | return 1; 110 | } 111 | // callback delegate can implement as instance method 112 | + (void)xtrace:(NSString *)trace forInstance:(void *)obj indent:(int)indent { 113 | printf( "| %s\n", [trace UTF8String] ); 114 | } 115 | 116 | + (void)showCaller:(BOOL)show { 117 | params.showCaller = show; 118 | } 119 | 120 | + (void)showActual:(BOOL)show { 121 | params.showActual = show; 122 | } 123 | 124 | + (void)showReturns:(BOOL)hide { 125 | params.showReturns = hide; 126 | } 127 | 128 | + (void)includeProperties:(BOOL)include { 129 | params.includeProperties = include; 130 | } 131 | 132 | + (void)showArguments:(BOOL)show { 133 | params.showArguments = show; 134 | } 135 | 136 | + (void)describeValues:(BOOL)desc { 137 | params.describeValues = desc; 138 | } 139 | 140 | static std::map > originals; 141 | static std::map tracedClasses; // trace color 142 | static std::map swizzledClasses, excludedClasses; 143 | static std::map tracingInstances; 144 | static std::map tracedInstances; 145 | static std::map selectorColors; 146 | 147 | + (void)dontTrace:(Class)aClass { 148 | Class metaClass = object_getClass(aClass); 149 | excludedClasses[metaClass] = 1; 150 | excludedClasses[aClass] = 1; 151 | } 152 | 153 | + (void)traceClass:(Class)aClass { 154 | [self traceClass:aClass levels:99]; 155 | } 156 | 157 | + (void)traceClass:(Class)aClass levels:(int)levels { 158 | if ( aClass == [Xtrace class] ) 159 | return; 160 | if ( aClass == [NSObject class] ) { 161 | NSLog( @"Xtrace: Tracing NSObject will not trace all classes" ); 162 | return; 163 | } 164 | #ifdef __arm64__ 165 | #warning Xtrace will not work on an ARM64 build. Rebuild for $(ARCHS_STANDARD_32_BIT). 166 | NSLog( @"Xtrace will not work on an ARM64 build. Rebuild for $(ARCHS_STANDARD_32_BIT)." ); 167 | #else 168 | Class metaClass = object_getClass(aClass); 169 | [self traceClass:metaClass mtype:"+" levels:levels]; 170 | [self traceClass:aClass mtype:"" levels:levels]; 171 | #endif 172 | } 173 | 174 | + (void)traceBundleContainingClass:(Class)aClass { 175 | Dl_info info; 176 | if ( !dladdr( XTRACE_BRIDGE(const void *)(aClass ?: self), &info ) ) 177 | NSLog( @"Xtrace: Could not find load address" ); 178 | 179 | #ifndef __LP64__ 180 | uint32_t size = 0; 181 | char *referencesSection = getsectdatafromheader((struct mach_header *)info.dli_fbase, 182 | "__DATA", "__objc_classlist", &size ); 183 | #else 184 | uint64_t size = 0; 185 | char *referencesSection = getsectdatafromheader_64((struct mach_header_64 *)info.dli_fbase, 186 | "__DATA", "__objc_classlist", &size ); 187 | #endif 188 | 189 | if ( referencesSection ) 190 | { 191 | Class *classReferences = (Class *)(void *)((char *)info.dli_fbase+((uintptr_t)referencesSection&0xffffffff)); 192 | 193 | for ( unsigned long i=0 ; ibeforeBlock = XTRACE_BRIDGE(XTRACE_BIMP)CFRetain( XTRACE_BRIDGE(CFTypeRef)callback ); 238 | } 239 | 240 | + (void)forClass:(Class)aClass after:(SEL)sel callbackBlock:callback { 241 | [self intercept:aClass method:class_getInstanceMethod(aClass, sel) mtype:NULL 242 | depth:[self depth:aClass]]->afterBlock = XTRACE_BRIDGE(XTRACE_BIMP)CFRetain( XTRACE_BRIDGE(CFTypeRef)callback ); 243 | } 244 | 245 | + (XTRACE_VIMP)forClass:(Class)aClass intercept:(SEL)sel callback:(SEL)callback { 246 | return [self intercept:aClass method:class_getInstanceMethod(aClass, sel) mtype:NULL 247 | depth:[self depth:aClass]] ? (XTRACE_VIMP)[delegate methodForSelector:callback] : NULL; 248 | } 249 | 250 | + (int)depth:(Class)aClass { 251 | int depth = 0; 252 | for ( Class nsObject = [NSObject class], nsObjectMeta = object_getClass( nsObject ) ; 253 | aClass && aClass != nsObject && aClass != nsObjectMeta ; aClass = class_getSuperclass( aClass ) ) 254 | depth++; 255 | return depth; 256 | } 257 | 258 | static NSRegularExpression *includeMethods, *excludeMethods, *excludeTypes; 259 | 260 | + (BOOL)includeMethods:(NSString *)pattern { 261 | return (includeMethods = [self getRegexp:pattern]) != NULL; 262 | } 263 | 264 | + (BOOL)excludeMethods:(NSString *)pattern { 265 | return (excludeMethods = [self getRegexp:pattern]) != NULL; 266 | } 267 | 268 | + (BOOL)excludeTypes:(NSString *)pattern { 269 | return (excludeTypes = [self getRegexp:pattern]) != NULL; 270 | } 271 | 272 | + (NSRegularExpression *)getRegexp:(NSString *)pattern { 273 | if ( !pattern ) 274 | return nil; 275 | NSError *error = nil; 276 | NSRegularExpression *regexp = [[NSRegularExpression alloc] initWithPattern:pattern options:0 error:&error]; 277 | if ( error ) 278 | NSLog( @"Xtrace: Filter compilation error: %@, in pattern: \"%@\"", [error localizedDescription], pattern ); 279 | return regexp; 280 | } 281 | 282 | static const char *noColor = "", *traceColor = noColor; 283 | 284 | + (void)useColor:(const char *)color { 285 | if ( !color ) color = noColor; 286 | traceColor = color; 287 | } 288 | 289 | + (void)useColor:(const char *)color forSelector:(SEL)sel { 290 | if ( !color ) color = noColor; 291 | selectorColors[sel] = color; 292 | } 293 | 294 | + (void)useColor:(const char *)color forClass:(Class)aClass { 295 | if ( !color ) color = noColor; 296 | Class metaClass = object_getClass(aClass); 297 | tracedClasses[metaClass] = color; 298 | tracedClasses[aClass] = color; 299 | } 300 | 301 | + (void)traceClass:(Class)aClass mtype:(const char *)mtype levels:(int)levels { 302 | 303 | if ( !tracedClasses[aClass] ) 304 | tracedClasses[aClass] = traceColor; 305 | swizzledClasses[aClass] = NO; 306 | 307 | // yes, this is a hack 308 | if ( !excludeMethods ) 309 | [self excludeMethods:@XTRACE_EXCLUSIONS]; 310 | 311 | Class nsObject = [NSObject class], nsObjectMeta = object_getClass( nsObject ); 312 | NSMutableString *nameStr = [NSMutableString new]; 313 | int depth = [self depth:aClass]; 314 | 315 | for ( int l=0 ; l 382 | 383 | + (const char *)callerFor:(void *)caller { 384 | static std::map callers; 385 | 386 | if ( !exists( callers, caller ) ) { 387 | Dl_info info; 388 | if ( dladdr(caller, &info) && info.dli_sname ) 389 | callers[caller] = strdup(info.dli_sname); 390 | } 391 | 392 | return callers[caller]; 393 | } 394 | 395 | + (const char *)callerFor:(Class)aClass sel:(SEL)sel { 396 | return [self callerFor:originals[aClass][sel].caller]; 397 | } 398 | 399 | // should really be per-thread but can deadlock 400 | static struct { int indent; BOOL describing; } state; 401 | 402 | #define APPEND_TYPE( _enc, _fmt, _type ) case _enc: [args appendFormat:_fmt, va_arg(*argp,_type)]; return YES; 403 | 404 | static BOOL formatValue( const char *type, void *valptr, va_list *argp, NSMutableString *args ) { 405 | switch ( type[0] == 'r' ? type[1] : type[0] ) { 406 | case 'V': case 'v': 407 | return NO; 408 | 409 | #pragma clang diagnostic push 410 | #pragma clang diagnostic ignored "-Wvarargs" 411 | // warnings here are necessary evil 412 | APPEND_TYPE( 'B', @"%d", bool ) 413 | APPEND_TYPE( 'c', @"%d", char ) 414 | APPEND_TYPE( 'C', @"%d", unsigned char ) 415 | APPEND_TYPE( 's', @"%d", short ) 416 | APPEND_TYPE( 'S', @"%d", unsigned short ) 417 | APPEND_TYPE( 'i', @"%d", int ) 418 | APPEND_TYPE( 'I', @"%u", unsigned ) 419 | APPEND_TYPE( 'f', @"%f", float ) 420 | #pragma clang diagnostic pop 421 | APPEND_TYPE( 'd', @"%f", double ) 422 | APPEND_TYPE( '^', @"%p", void * ) 423 | APPEND_TYPE( '*', @"\"%.100s\"", char * ) 424 | #ifndef __LP64__ 425 | APPEND_TYPE( 'q', @"%lldLL", long long ) 426 | #else 427 | case 'q': 428 | #endif 429 | APPEND_TYPE( 'l', @"%ldL", long ) 430 | #ifndef __LP64__ 431 | APPEND_TYPE( 'Q', @"%lluLL", unsigned long long ) 432 | #else 433 | case 'Q': 434 | #endif 435 | APPEND_TYPE( 'L', @"%luL", unsigned long ) 436 | case ':': 437 | [args appendFormat:@"@selector(%s)", sel_getName(va_arg(*argp,SEL))]; 438 | return YES; 439 | case '#': case '@': { 440 | XTRACE_UNSAFE id obj = va_arg(*argp,XTRACE_UNSAFE id); 441 | if ( [obj isKindOfClass:[NSString class]] ) 442 | [args appendFormat:@"@\"%@\"", obj]; 443 | else if ( params.describeValues ) { 444 | state.describing = YES; 445 | [args appendString:obj?[obj description]:@""]; 446 | state.describing = NO; 447 | } 448 | else 449 | [args appendFormat:@"<%s %p>", class_getName(object_getClass(obj)), obj]; 450 | return YES; 451 | } 452 | case '{': 453 | #ifdef __IPHONE_OS_VERSION_MIN_REQUIRED 454 | if ( strncmp(type,"{CGRect=",8) == 0 ) 455 | [args appendString:NSStringFromCGRect( va_arg(*argp,CGRect) )]; 456 | else if ( strncmp(type,"{CGPoint=",9) == 0 ) 457 | [args appendString:NSStringFromCGPoint( va_arg(*argp,CGPoint) )]; 458 | else if ( strncmp(type,"{CGSize=",8) == 0 ) 459 | [args appendString:NSStringFromCGSize( va_arg(*argp,CGSize) )]; 460 | else if ( strncmp(type,"{CGAffineTransform=",19) == 0 ) 461 | [args appendString:NSStringFromCGAffineTransform( va_arg(*argp,CGAffineTransform) )]; 462 | else if ( strncmp(type,"{UIEdgeInsets=",14) == 0 ) 463 | [args appendString:NSStringFromUIEdgeInsets( va_arg(*argp,UIEdgeInsets) )]; 464 | else if ( strncmp(type,"{UIOffset=",10) == 0 ) 465 | [args appendString:NSStringFromUIOffset( va_arg(*argp,UIOffset) )]; 466 | #else 467 | if ( strncmp(type,"{_NSRect=",9) == 0 || strncmp(type,"{CGRect=",8) == 0 ) 468 | [args appendString:NSStringFromRect( va_arg(*argp,NSRect) )]; 469 | else if ( strncmp(type,"{_NSPoint=",10) == 0 || strncmp(type,"{CGPoint=",9) == 0 ) 470 | [args appendString:NSStringFromPoint( va_arg(*argp,NSPoint) )]; 471 | else if ( strncmp(type,"{_NSSize=",9) == 0 || strncmp(type,"{CGSize=",8) == 0 ) 472 | [args appendString:NSStringFromSize( va_arg(*argp,NSSize) )]; 473 | #endif 474 | else if ( strncmp(type,"{_NSRange=",10) == 0 ) 475 | [args appendString:NSStringFromRange( va_arg(*argp,NSRange) )]; 476 | else 477 | break; 478 | return YES; 479 | } 480 | 481 | [args appendFormat:@"", type]; 482 | return NO; 483 | } 484 | 485 | struct _xtrace_depth { 486 | XTRACE_UNSAFE id obj; SEL sel; int depth; 487 | }; 488 | 489 | static id nullImpl( XTRACE_UNSAFE __unused id obj, __unused SEL sel, ... ) { 490 | return nil; 491 | } 492 | 493 | // find original implmentation for message and log call 494 | static struct _xtrace_info &findOriginal( struct _xtrace_depth *info, SEL sel, ... ) { 495 | va_list argp; va_start(argp, sel); 496 | Class aClass = object_getClass( info->obj ); 497 | const char *className = class_getName( aClass ); 498 | 499 | while ( aClass && (!exists( originals[aClass], sel ) || 500 | originals[aClass][sel].depth != info->depth) ) 501 | aClass = class_getSuperclass( aClass ); 502 | 503 | struct _xtrace_info &orig = originals[aClass][sel]; 504 | orig.lastObj = XTRACE_BRIDGE(void*)info->obj; 505 | orig.caller = __builtin_return_address(1); 506 | 507 | if ( !aClass ) { 508 | NSLog( @"Xtrace: could not find original implementation for [%s %s]", className, sel_getName(sel) ); 509 | orig.original = (XTRACE_VIMP)nullImpl; 510 | } 511 | 512 | static char KVO_prefix[] = "NSKVONotifying_"; 513 | while ( aClass && strncmp( class_getName(aClass), KVO_prefix, sizeof(KVO_prefix)-1 ) == 0 ) 514 | aClass = class_getSuperclass(aClass); 515 | 516 | Class implementingClass = aClass; 517 | aClass = object_getClass( info->obj ); 518 | 519 | // add custom filtering of logging here.. 520 | if ( !state.describing && orig.mtype && 521 | (exists( tracingInstances, aClass ) ? 522 | exists( tracedInstances, info->obj ) : 523 | tracedClasses[aClass] != nil) ) 524 | orig.color = exists( selectorColors, sel ) ? 525 | selectorColors[sel] : tracedClasses[aClass]; 526 | else 527 | orig.color = NULL; 528 | 529 | if ( orig.color ) { 530 | NSMutableString *args = [NSMutableString string]; 531 | 532 | const char *symbol; 533 | if ( params.showCaller && state.indent == 0 && 534 | (symbol = [Xtrace callerFor:orig.caller]) && symbol[0] != '<' ) { 535 | [args appendFormat:@"From: %s", symbol]; 536 | [params.logToDelegate ? delegate : [Xtrace class] xtrace:args forInstance:orig.lastObj indent:-2]; 537 | [args setString:@""]; 538 | } 539 | 540 | if ( orig.color && orig.color[0] ) 541 | [args appendFormat:@"%s", orig.color]; 542 | 543 | if ( orig.mtype[0] == '+' ) 544 | [args appendFormat:@"%*s%s[%s", 545 | state.indent++*indentScale, "", orig.mtype, className]; 546 | else 547 | [args appendFormat:@"%*s%s[<%s %p>", 548 | state.indent++*indentScale, "", orig.mtype, className, info->obj]; 549 | 550 | if ( params.showActual && implementingClass != aClass ) 551 | [args appendFormat:@"/%s", class_getName(implementingClass)]; 552 | 553 | if ( !params.showArguments ) 554 | [args appendFormat:@" %s", orig.name]; 555 | else { 556 | const char *frame = (char *)(void *)&info+sizeof info; 557 | void *valptr = NULL; 558 | 559 | BOOL typesKnown = YES; 560 | for ( struct _xtrace_arg *aptr = orig.args ; *aptr->name ; aptr++ ) { 561 | [args appendFormat:@" %.*s", (int)(aptr[1].name-aptr->name), aptr->name]; 562 | if ( !aptr->type ) 563 | break; 564 | 565 | valptr = (void *)(frame+aptr[1].stackOffset); 566 | typesKnown = typesKnown && 567 | formatValue( aptr->type, valptr, &argp, args ); 568 | } 569 | } 570 | 571 | [args appendString:@"]"]; 572 | if ( params.showSignature ) 573 | [args appendFormat:@" %.100s %p", orig.type, orig.original]; 574 | if ( orig.color && orig.color[0] ) 575 | [args appendString:@"\033[;"]; 576 | [params.logToDelegate ? delegate : [Xtrace class] xtrace:args forInstance:orig.lastObj indent:state.indent]; 577 | } 578 | 579 | orig.stats.entered = [NSDate timeIntervalSinceReferenceDate]; 580 | orig.stats.callCount++; 581 | return orig; 582 | } 583 | 584 | // log returning value 585 | static void returning( struct _xtrace_info *orig, ... ) { 586 | va_list argp; va_start(argp, orig); 587 | if ( state.indent > 0 ) 588 | state.indent--; 589 | 590 | orig->stats.elapsed += [NSDate timeIntervalSinceReferenceDate] - orig->stats.entered; 591 | 592 | if ( orig->color && params.showReturns ) { 593 | NSMutableString *val = [NSMutableString string]; 594 | [val appendFormat:@"%s%*s-> ", orig->color, state.indent*indentScale, ""]; 595 | if ( formatValue(orig->type, NULL, &argp, val) ) { 596 | [val appendFormat:@" (%s)", orig->name]; 597 | if ( orig->color && orig->color[0] ) 598 | [val appendString:@"\033[;"]; 599 | [params.logToDelegate ? delegate : [Xtrace class] xtrace:val forInstance:orig->lastObj indent:-1]; 600 | } 601 | } 602 | } 603 | 604 | #define ARG_SIZE (sizeof(id) + sizeof(SEL) + sizeof(void *)*9) // approximate to say the least.. 605 | #ifndef __LP64__ 606 | #define ARG_DEFS void *a0, void *a1, void *a2, void *a3, void *a4, void *a5, void *a6, void *a7, void *a8, void *a9 607 | #define ARG_COPY a0, a1, a2, a3, a4, a5, a6, a7, a8, a9 608 | #else 609 | #define ARG_DEFS void *a0, void *a1, void *a2, void *a3, void *a4, void *a5, void *a6, void *a7, void *a8, void *a9, double d0, double d1, double d2, double d3, double d4, double d5, double d6, double d7 610 | #define ARG_COPY a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, d0, d1, d2, d3, d4, d5, d6, d7 611 | #endif 612 | 613 | // replacement implmentations "swizzled" onto class 614 | // "_depth" is number of levels down from NSObject 615 | // (used to detect calls to super) 616 | template 617 | static void xtrace( XTRACE_UNSAFE id obj, SEL sel, ARG_DEFS ) { 618 | struct _xtrace_depth info = { obj, sel, _depth }; 619 | struct _xtrace_info &orig = findOriginal( &info, sel, ARG_COPY ); 620 | 621 | if ( !orig.callingBack ) { 622 | if ( orig.before ) { 623 | orig.callingBack = YES; 624 | orig.before( delegate, sel, obj, ARG_COPY ); 625 | orig.callingBack = NO; 626 | } 627 | if ( orig.beforeBlock ) { 628 | orig.callingBack = YES; 629 | orig.beforeBlock( obj, sel, ARG_COPY ); 630 | orig.callingBack = NO; 631 | } 632 | } 633 | 634 | orig.original( obj, sel, ARG_COPY ); 635 | 636 | if ( !orig.callingBack ) { 637 | if ( orig.after ) { 638 | orig.callingBack = YES; 639 | orig.after( delegate, sel, obj, ARG_COPY ); 640 | orig.callingBack = NO; 641 | } 642 | if ( orig.afterBlock ) { 643 | orig.callingBack = YES; 644 | orig.afterBlock( obj, sel, ARG_COPY ); 645 | orig.callingBack = NO; 646 | } 647 | } 648 | 649 | returning( &orig ); 650 | } 651 | 652 | template 653 | static _type XTRACE_RETAINED xtrace_t( XTRACE_UNSAFE id obj, SEL sel, ARG_DEFS ) { 654 | struct _xtrace_depth info = { obj, sel, _depth }; 655 | struct _xtrace_info &orig = findOriginal( &info, sel, ARG_COPY ); 656 | 657 | if ( !orig.callingBack ) { 658 | if ( orig.before ) { 659 | orig.callingBack = YES; 660 | orig.before( delegate, sel, obj, ARG_COPY ); 661 | orig.callingBack = NO; 662 | } 663 | if ( orig.beforeBlock ) { 664 | orig.callingBack = YES; 665 | orig.beforeBlock( obj, sel, ARG_COPY ); 666 | orig.callingBack = NO; 667 | } 668 | } 669 | 670 | typedef _type (*TIMP)( XTRACE_UNSAFE id obj, SEL sel, ... ); 671 | TIMP impl = (TIMP)orig.original; 672 | _type out = impl( obj, sel, ARG_COPY ); 673 | 674 | if ( !orig.callingBack ) { 675 | if ( orig.after ) { 676 | orig.callingBack = YES; 677 | impl = (TIMP)orig.after; 678 | out = impl( delegate, sel, out, obj, ARG_COPY ); 679 | orig.callingBack = NO; 680 | } 681 | if ( orig.afterBlock ) { 682 | typedef _type (^BTIMP)( XTRACE_UNSAFE id obj, SEL sel, _type out, ... ); 683 | orig.callingBack = YES; 684 | BTIMP timpl = (BTIMP)orig.afterBlock; 685 | out = timpl( obj, sel, out, ARG_COPY ); 686 | orig.callingBack = NO; 687 | } 688 | } 689 | 690 | returning( &orig, out ); 691 | return out; 692 | } 693 | 694 | + (struct _xtrace_info *)intercept:(Class)aClass method:(Method)method mtype:(const char *)mtype depth:(int)depth { 695 | if ( !method ) 696 | NSLog( @"Xtrace: unknown method" ); 697 | 698 | SEL sel = method_getName(method); 699 | const char *name = sel_getName(sel); 700 | const char *className = class_getName(aClass); 701 | const char *type = method_getTypeEncoding(method); 702 | if ( !type ) 703 | return NULL; 704 | 705 | IMP newImpl = NULL; 706 | switch ( type[0] == 'r' ? type[1] : type[0] ) { 707 | 708 | #define IMPL_COUNT 10 709 | #define IMPLS( _func, _type ) \ 710 | switch ( depth%IMPL_COUNT ) { \ 711 | case 0: newImpl = (IMP)_func<_type,0>; break; \ 712 | case 1: newImpl = (IMP)_func<_type,1>; break; \ 713 | case 2: newImpl = (IMP)_func<_type,2>; break; \ 714 | case 3: newImpl = (IMP)_func<_type,3>; break; \ 715 | case 4: newImpl = (IMP)_func<_type,4>; break; \ 716 | case 5: newImpl = (IMP)_func<_type,5>; break; \ 717 | case 6: newImpl = (IMP)_func<_type,6>; break; \ 718 | case 7: newImpl = (IMP)_func<_type,7>; break; \ 719 | case 8: newImpl = (IMP)_func<_type,8>; break; \ 720 | case 9: newImpl = (IMP)_func<_type,9>; break; \ 721 | } 722 | case 'V': 723 | case 'v': IMPLS( xtrace, void ); break; 724 | 725 | case 'B': IMPLS( xtrace_t, bool ); break; 726 | case 'C': 727 | case 'c': IMPLS( xtrace_t, char ); break; 728 | case 'S': 729 | case 's': IMPLS( xtrace_t, short ); break; 730 | case 'I': 731 | case 'i': IMPLS( xtrace_t, int ); break; 732 | case 'Q': 733 | case 'q': 734 | #ifndef __LP64__ 735 | IMPLS( xtrace_t, long long ); break; 736 | #endif 737 | case 'L': 738 | case 'l': IMPLS( xtrace_t, long ); break; 739 | case 'f': IMPLS( xtrace_t, float ); break; 740 | case 'd': IMPLS( xtrace_t, double ); break; 741 | case '#': 742 | case '@': IMPLS( xtrace_t, id ) break; 743 | case '^': IMPLS( xtrace_t, void * ); break; 744 | case ':': IMPLS( xtrace_t, SEL ); break; 745 | case '*': IMPLS( xtrace_t, char * ); break; 746 | case '{': 747 | if ( strncmp(type,"{_NSRange=",10) == 0 ) 748 | IMPLS( xtrace_t, NSRange ) 749 | #ifndef __IPHONE_OS_VERSION_MIN_REQUIRED 750 | else if ( strncmp(type,"{_NSRect=",9) == 0 ) 751 | IMPLS( xtrace_t, NSRect ) 752 | else if ( strncmp(type,"{_NSPoint=",10) == 0 ) 753 | IMPLS( xtrace_t, NSPoint ) 754 | else if ( strncmp(type,"{_NSSize=",9) == 0 ) 755 | IMPLS( xtrace_t, NSSize ) 756 | #endif 757 | else if ( strncmp(type,"{CGRect=",8) == 0 ) 758 | IMPLS( xtrace_t, CGRect ) 759 | else if ( strncmp(type,"{CGPoint=",9) == 0 ) 760 | IMPLS( xtrace_t, CGPoint ) 761 | else if ( strncmp(type,"{CGSize=",8) == 0 ) 762 | IMPLS( xtrace_t, CGSize ) 763 | else if ( strncmp(type,"{CGAffineTransform=",19) == 0 ) 764 | IMPLS( xtrace_t, CGAffineTransform ) 765 | break; 766 | default: 767 | NSLog(@"Xtrace: Unsupported return type: %s for: %s[%s %s]", type, mtype, className, name); 768 | } 769 | 770 | const char *frameSize = type+1; 771 | while ( !isdigit(*frameSize) ) 772 | frameSize++; 773 | 774 | if ( atoi(frameSize) > (int)ARG_SIZE ) 775 | NSLog( @"Xtrace: Stack frame too large to trace method: %s[%s %s]", mtype, className, name ); 776 | 777 | else if ( newImpl ) { 778 | 779 | struct _xtrace_info &orig = originals[aClass][sel]; 780 | 781 | orig.name = name; 782 | orig.type = type; 783 | orig.method = method; 784 | orig.depth = depth%IMPL_COUNT; 785 | if ( mtype ) 786 | orig.mtype = mtype; 787 | 788 | [self extractSelector:name into:orig.args maxargs:XTRACE_ARGS_SUPPORTED]; 789 | [self extractOffsets:type into:orig.args maxargs:XTRACE_ARGS_SUPPORTED]; 790 | 791 | IMP impl = method_getImplementation(method); 792 | if ( impl != newImpl ) { 793 | orig.original = (XTRACE_VIMP)impl; 794 | method_setImplementation(method,newImpl); 795 | //NSLog( @"%d %s%s %s %s", depth, mtype, className, name, type ); 796 | } 797 | 798 | return &orig; 799 | } 800 | 801 | return NULL; 802 | } 803 | 804 | // break up selector by argument 805 | + (int)extractSelector:(const char *)name into:(struct _xtrace_arg *)args maxargs:(int)maxargs { 806 | 807 | for ( int i=0 ; iname = name; 809 | const char *next = index( name, ':' ); 810 | if ( next ) { 811 | name = next+1; 812 | args++; 813 | } 814 | else { 815 | args[1].name = name+strlen(name); 816 | return i; 817 | } 818 | } 819 | 820 | return -1; 821 | } 822 | 823 | // parse method encoding for call stack offsets (replaced by varargs) 824 | 825 | #if 1 // original version using information in method type encoding 826 | 827 | + (int)originalExtractOffsets:(const char *)type into:(struct _xtrace_arg *)args maxargs:(int)maxargs { 828 | int frameLen = -1; 829 | 830 | for ( int i=0 ; itype = type; 832 | while ( !isdigit(*type) || type[1] == ',' ) 833 | type++; 834 | args->stackOffset = -atoi(type); 835 | if ( i==0 ) 836 | frameLen = args->stackOffset; 837 | while ( isdigit(*type) ) 838 | type++; 839 | if ( i>2 ) 840 | args++; 841 | else 842 | args->type = NULL; 843 | if ( !*type ) { 844 | args->stackOffset = frameLen; 845 | return i; 846 | } 847 | } 848 | 849 | return -1; 850 | } 851 | 852 | #else // alternate "NSGetSizeAndAlignment()" version 853 | 854 | + (int)extractOffsets:(const char *)type into:(struct _xtrace_arg *)args maxargs:(int)maxargs { 855 | NSUInteger size, align, offset = 0; 856 | 857 | type = NSGetSizeAndAlignment( type, &size, &align ); 858 | 859 | for ( int i=0 ; itype = type; 863 | type = NSGetSizeAndAlignment( type, &size, &align ); 864 | if ( !*type ) { 865 | args->type = NULL; 866 | return i; 867 | } 868 | offset -= size; 869 | offset &= ~(align-1 | sizeof(void *)-1); 870 | args[1].stackOffset = (int)offset; 871 | if ( i>1 ) 872 | args++; 873 | else 874 | args->type = NULL; 875 | } 876 | 877 | return -1; 878 | } 879 | 880 | #endif // Extract types using NSMethodSignature - can give unsuppported type error 881 | 882 | + (int)extractOffsets:(const char *)type into:(struct _xtrace_arg *)args maxargs:(int)maxargs { 883 | @try { 884 | NSMethodSignature *sig = [NSMethodSignature signatureWithObjCTypes:type]; 885 | int acount = (int)[sig numberOfArguments]; 886 | 887 | for ( int i=2 ; i", (int)(end-type), type]; 1005 | else 1006 | return [NSString stringWithFormat:@"%.*s%s", (int)(end-type), type, star]; 1007 | } 1008 | 1009 | + (NSArray *)profile { 1010 | NSMutableArray *profile = [NSMutableArray array]; 1011 | 1012 | for ( auto &byClass : originals ) 1013 | for ( auto &bySel : byClass.second ) { 1014 | Xtrace *trace = [Xtrace new]; 1015 | trace->aClass = byClass.first; 1016 | trace->info = &bySel.second; 1017 | trace->callCount = trace->info->stats.callCount; 1018 | trace->elapsed = trace->info->stats.elapsed; 1019 | trace->info->stats.callCount = 0; 1020 | trace->info->stats.elapsed = 0; 1021 | [profile addObject:trace]; 1022 | } 1023 | 1024 | [profile sortUsingSelector:@selector(compareElapsed:)]; 1025 | return profile; 1026 | } 1027 | 1028 | + (void)dumpProfile:(unsigned)count dp:(int)decimalPlaces { 1029 | NSArray *profile = [self profile]; 1030 | for ( unsigned i=0 ; iinfo->color ) 1033 | trace->info->color = noColor; 1034 | printf( "%s%.*f/%-4d %s[%s %s]%s\n", 1035 | trace->info->color, decimalPlaces, trace->elapsed, trace->callCount, 1036 | trace->info->mtype, class_getName(trace->aClass), trace->info->name, 1037 | trace->info->color[0] ? "\033[;" : "" ); 1038 | } 1039 | } 1040 | 1041 | - (NSComparisonResult)compareElapsed:(Xtrace *)other { 1042 | return self->elapsed > other->elapsed ? NSOrderedAscending : self->elapsed == other->elapsed ? NSOrderedSame : NSOrderedDescending; 1043 | } 1044 | 1045 | @end 1046 | 1047 | #pragma clang diagnostic pop 1048 | #endif 1049 | -------------------------------------------------------------------------------- /inject_with_jailbreaking/build_inject.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang -x objective-c++ -arch arm64 -arch armv7 -fmessage-length=0 -fdiagnostics-show-note-include-stack -fmacro-backtrace-limit=0 -std=gnu++11 -fobjc-arc -Wno-trigraphs -fpascal-strings -O0 -Wno-missing-field-initializers -Wno-missing-prototypes -Wno-implicit-atomic-properties -Wno-receiver-is-weak -Wno-arc-repeated-use-of-weak -Wno-non-virtual-dtor -Wno-overloaded-virtual -Wno-exit-time-destructors -Wduplicate-method-match -Wno-missing-braces -Wparentheses -Wswitch -Wno-unused-function -Wno-unused-label -Wno-unused-parameter -Wunused-variable -Wunused-value -Wempty-body -Wuninitialized -Wno-unknown-pragmas -Wno-shadow -Wno-four-char-constants -Wno-conversion -Wno-constant-conversion -Wno-int-conversion -Wno-bool-conversion -Wno-enum-conversion -Wshorten-64-to-32 -Wno-newline-eof -Wno-selector -Wno-strict-selector-match -Wno-undeclared-selector -Wno-deprecated-implementations -Wno-c++11-extensions -DDEBUG=1 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk -fstrict-aliasing -Wprotocol -Wdeprecated-declarations -Winvalid-offsetof -g -Wno-sign-conversion -miphoneos-version-min=7.0 -c wspx_inject.mm -o wspx_inject.o 4 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang -x objective-c++ -arch arm64 -arch armv7 -fmessage-length=0 -fdiagnostics-show-note-include-stack -fmacro-backtrace-limit=0 -std=gnu++11 -fobjc-arc -Wno-trigraphs -fpascal-strings -O0 -Wno-missing-field-initializers -Wno-missing-prototypes -Wno-implicit-atomic-properties -Wno-receiver-is-weak -Wno-arc-repeated-use-of-weak -Wno-non-virtual-dtor -Wno-overloaded-virtual -Wno-exit-time-destructors -Wduplicate-method-match -Wno-missing-braces -Wparentheses -Wswitch -Wno-unused-function -Wno-unused-label -Wno-unused-parameter -Wunused-variable -Wunused-value -Wempty-body -Wuninitialized -Wno-unknown-pragmas -Wno-shadow -Wno-four-char-constants -Wno-conversion -Wno-constant-conversion -Wno-int-conversion -Wno-bool-conversion -Wno-enum-conversion -Wshorten-64-to-32 -Wno-newline-eof -Wno-selector -Wno-strict-selector-match -Wno-undeclared-selector -Wno-deprecated-implementations -Wno-c++11-extensions -DDEBUG=1 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk -fstrict-aliasing -Wprotocol -Wdeprecated-declarations -Winvalid-offsetof -g -Wno-sign-conversion -miphoneos-version-min=7.0 -c Xtrace.mm -o Xtrace.o 5 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld -arch arm64 -arch armv7 -dylib -lsystem -lobjc -lc++ -syslibroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk -ios_version_min 7.0 -framework SystemConfiguration -framework QuartzCore -framework CoreGraphics -lresolv -lstdc++.6.0.9 -lz -framework Security -framework CFNetwork -framework CoreTelephony -framework Foundation -framework AVFoundation -framework UIKit -framework CoreFoundation wspx_inject.o Xtrace.o -o wspx_inject.dylib 6 | 7 | #### /Library/MobileSubstrate/DynamicLibraries/ 8 | # -framework SystemConfiguration -framework QuartzCore -framework CoreGraphics -lresolv -lstdc++.6.0.9 -lz -framework Security -framework CFNetwork -framework CoreTelephony 9 | -------------------------------------------------------------------------------- /inject_with_jailbreaking/wspx_inject.mm: -------------------------------------------------------------------------------- 1 | 2 | #import 3 | #import 4 | #import 5 | #import "Xtrace.h" 6 | // exchange Class Method and Instance Method 7 | static void __exchangeClassMethod(Class oldClass, SEL oldSEL, Class newClass, SEL newSEL) 8 | { 9 | Method oldMethod = class_getClassMethod(oldClass, oldSEL); 10 | assert(oldMethod); 11 | Method newMethod = class_getClassMethod(newClass, newSEL); 12 | assert(newMethod); 13 | method_exchangeImplementations(oldMethod, newMethod); 14 | NSLog(@"替换方法成功"); 15 | } 16 | 17 | static void __exchangeInstanceMethod(Class oldClass, SEL oldSEL, Class newClass, SEL newSEL) 18 | { 19 | Method oldMethod = class_getInstanceMethod(oldClass, oldSEL); 20 | assert(oldMethod); 21 | Method newMethod = class_getInstanceMethod(newClass, newSEL); 22 | assert(newMethod); 23 | method_exchangeImplementations(oldMethod, newMethod); 24 | } 25 | 26 | @interface UIViewController (Hooked) 27 | - (void)hooked_viewDidLoad; 28 | - (void)hooked_viewWillAppear:(BOOL)animated; 29 | + (void)hook; 30 | @end 31 | @implementation UIViewController (Hooked) 32 | - (void)hooked_viewDidLoad { 33 | NSLog(@" Test:%@ \nTestfunc:%s", NSStringFromClass([self class]), __PRETTY_FUNCTION__); 34 | static BOOL finish = NO; 35 | if ([NSStringFromClass([self class]) isEqualToString:@"UCMovieRootController"] && !finish) { 36 | finish = YES; 37 | Class asClass = NSClassFromString(@"UCMoviePlayerToolController");//UCMovieRootController 38 | SEL sel = @selector(xtrace); 39 | NSMethodSignature *signature = [asClass methodSignatureForSelector:sel]; 40 | if(!signature) { 41 | NSLog(@"csl test signature nil"); 42 | signature = [asClass methodSignatureForSelector:sel]; 43 | } 44 | 45 | NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; 46 | invocation.target = asClass; 47 | invocation.selector = sel; 48 | 49 | if([asClass respondsToSelector:sel]){ 50 | NSLog(@"csl test invokeWithTarget"); 51 | [invocation invokeWithTarget:asClass]; 52 | } else { 53 | NSLog(@"csl test invoke"); 54 | [invocation invoke]; 55 | } 56 | } 57 | [self hooked_viewDidLoad]; 58 | } 59 | - (void)hooked_viewWillAppear:(BOOL)animated { 60 | NSLog(@" Test:%@ \nTestfunc:%s", NSStringFromClass([self class]), __PRETTY_FUNCTION__); 61 | [self hooked_viewWillAppear:animated]; 62 | } 63 | 64 | + (void)hook { 65 | Class oldClass = NSClassFromString(@"UIViewController"); 66 | Class newClass = NSClassFromString(@"UIViewController_Hooked"); 67 | if (oldClass == nil && newClass == nil) { 68 | NSLog(@"oldClass or newClass is nil"); 69 | return; 70 | } 71 | 72 | __exchangeInstanceMethod(oldClass, @selector(viewDidLoad), oldClass, @selector(hooked_viewDidLoad)); 73 | __exchangeInstanceMethod(oldClass, @selector(viewWillAppear:), oldClass, @selector(hooked_viewWillAppear:)); 74 | } 75 | @end 76 | @interface NSURLSession(Hooked) 77 | 78 | + (NSData *)readTVConfig; 79 | - (NSURLSessionDataTask *)hooked_dataTaskWithRequest:(NSURLRequest *)request; 80 | - (NSURLSessionDataTask *)hooked_dataTaskWithURL:(NSURL *)url; 81 | 82 | - (NSURLSessionDataTask *)hooked_dataTaskWithRequest:(NSURLRequest *)request completionHandler:(void (^)(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error))completionHandler; 83 | - (NSURLSessionDataTask *)hooked_dataTaskWithURL:(NSURL *)url completionHandler:(void (^)(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error))completionHandler; 84 | 85 | + (void) hook; 86 | 87 | @end 88 | 89 | @implementation NSURLSession(Hooked) 90 | 91 | + (NSData *) readTVConfig { 92 | NSData * data = nil; 93 | NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, 94 | NSUserDomainMask, YES) objectAtIndex:0]; 95 | 96 | NSString *configFile = [docPath stringByAppendingPathComponent:@"tvconfig.txt"]; 97 | NSLog(@"configFile: %@\n",configFile); 98 | NSFileManager *fileManager = [NSFileManager defaultManager]; 99 | if([fileManager fileExistsAtPath:configFile]) { 100 | data = [NSData dataWithContentsOfFile:configFile]; 101 | } 102 | return data; 103 | } 104 | 105 | + (void) hook { 106 | 107 | Class oldClass = NSClassFromString(@"NSURLSession"); 108 | Class newClass = NSClassFromString(@"NSURLSession_Hooked"); 109 | if (oldClass == nil && newClass == nil) { 110 | NSLog(@"oldClass or newClass is nil"); 111 | return; 112 | } 113 | 114 | __exchangeInstanceMethod(oldClass, @selector(dataTaskWithRequest:), oldClass, @selector(hooked_dataTaskWithRequest:)); 115 | __exchangeInstanceMethod(oldClass, @selector(dataTaskWithURL:), oldClass, @selector(hooked_dataTaskWithURL:)); 116 | 117 | __exchangeInstanceMethod(oldClass, @selector(dataTaskWithRequest:completionHandler:), oldClass, @selector(hooked_dataTaskWithRequest:completionHandler:)); 118 | __exchangeInstanceMethod(oldClass, @selector(dataTaskWithURL:completionHandler:), oldClass, @selector(hooked_dataTaskWithURL:completionHandler:)); 119 | return; 120 | } 121 | 122 | 123 | - (NSURLSessionDataTask *)hooked_dataTaskWithRequest:(NSURLRequest *)request { 124 | //NSLog(@"hooked_dataTaskWithRequest -> \n %@\n", request.URL.absoluteString); 125 | return [self hooked_dataTaskWithRequest:request]; 126 | } 127 | 128 | - (NSURLSessionDataTask *)hooked_dataTaskWithURL:(NSURL *)url { 129 | //NSLog(@"hooked_dataTaskWithURL -> \n %@ \n", url.absoluteString); 130 | return [self hooked_dataTaskWithURL:url]; 131 | } 132 | 133 | - (NSURLSessionDataTask *)hooked_dataTaskWithRequest:(NSURLRequest *)request completionHandler:(void (^)(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error))completionHandler { 134 | //NSLog(@"hooked_dataTaskWithRequest:completionHandler: -> \n %@\n", request.URL.absoluteString); 135 | NSURLSessionDataTask * task = nil; 136 | if (request != nil && [request.URL.absoluteString hasPrefix: @"https://static.api.m.panda.tv/index.php?method=clientconf.tvconf"]) { 137 | task = [self hooked_dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { 138 | NSData * newData = [NSURLSession readTVConfig]; 139 | if (newData == nil) { 140 | NSLog(@"tvconfig.txt is empty"); 141 | newData = data; 142 | } 143 | NSString * strData = [[NSString alloc] initWithData: newData encoding:NSUTF8StringEncoding]; 144 | NSLog(@"%@ \n\n %@ \noo\n", request.URL.absoluteString, strData); 145 | if (completionHandler) { 146 | completionHandler(newData, response, error); 147 | } 148 | }]; 149 | } else { 150 | task = [self hooked_dataTaskWithRequest:request completionHandler:completionHandler]; 151 | } 152 | return task; 153 | } 154 | 155 | - (NSURLSessionDataTask *)hooked_dataTaskWithURL:(NSURL *)url completionHandler:(void (^)(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error))completionHandler { 156 | //NSLog(@"hooked_dataTaskWithURL:completionHandler: -> \n %@ \n", url.absoluteString); 157 | NSURLSessionDataTask * task = nil; 158 | if (url != nil && [url.absoluteString hasPrefix: @"https://static.api.m.panda.tv/index.php?method=clientconf.tvconf"]) { 159 | task = [self hooked_dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { 160 | NSData * newData = [NSURLSession readTVConfig]; 161 | if (newData == nil) { 162 | NSLog(@"tvconfig.txt is empty"); 163 | newData = data; 164 | } 165 | NSString * strData = [[NSString alloc] initWithData: newData encoding:NSUTF8StringEncoding]; 166 | NSLog(@"%@ \n\n %@ \noo\n", url.absoluteString, strData); 167 | if (completionHandler) { 168 | completionHandler(newData, response, error); 169 | } 170 | }]; 171 | } else { 172 | task = [self hooked_dataTaskWithURL:url completionHandler:completionHandler]; 173 | } 174 | return task; 175 | } 176 | 177 | 178 | @end 179 | 180 | @interface wspxHooks : NSObject 181 | + (void)hookAppProxy; 182 | + (void)hookAsynSocket; 183 | @end 184 | 185 | @implementation wspxHooks 186 | 187 | + (void)hookAppProxy { 188 | Class oldClass = NSClassFromString(@"AppProxy"); 189 | SEL sel = @selector(setLogEnabled:); 190 | 191 | NSMethodSignature *signature = [oldClass methodSignatureForSelector:sel]; 192 | 193 | if(!signature) { 194 | NSLog(@"csl test signature nil"); 195 | signature = [oldClass instanceMethodSignatureForSelector:sel]; 196 | } 197 | 198 | 199 | NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; 200 | invocation.target = oldClass; 201 | invocation.selector = sel; 202 | int enable = 1; 203 | 204 | [invocation setArgument:&enable atIndex:2]; 205 | if([oldClass respondsToSelector:sel]){ 206 | NSLog(@"csl test invokeWithTarget"); 207 | [invocation invokeWithTarget:oldClass]; 208 | } else { 209 | NSLog(@"csl test invoke"); 210 | [invocation invoke]; 211 | } 212 | } 213 | 214 | + (void)hookAsynSocket { 215 | Class oldClass = NSClassFromString(@"AsyncSocket"); 216 | SEL sel = @selector(createStreamsToHost:onPort:error:); 217 | 218 | NSMethodSignature *signature = [oldClass methodSignatureForSelector:sel]; 219 | 220 | if(!signature) { 221 | NSLog(@"csl test signature nil"); 222 | signature = [oldClass instanceMethodSignatureForSelector:sel]; 223 | } 224 | 225 | 226 | NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; 227 | invocation.target = oldClass; 228 | invocation.selector = sel; 229 | 230 | NSLog(@"csl test invoke with AsynSocket"); 231 | } 232 | 233 | @end 234 | 235 | // MobileSubstrace dynamic library initialize 236 | static void __attribute__((constructor)) initialize(void) 237 | { 238 | NSLog(@"======================= csl WspxInject Initialize at Date:%@========================",[NSDate dateWithTimeIntervalSinceNow:0]); 239 | // [NSURLSession hook]; 240 | [UIViewController hook]; 241 | // [wspxHooks hookAppProxy]; 242 | // [wspxHooks hookAsynSocket]; 243 | //Hooked AppProxy Log 244 | /* 245 | Class oldClass = NSClassFromString(@"AppProxy"); 246 | SEL sel = @selector(setLogEnabled:); 247 | 248 | NSMethodSignature *signature = [oldClass methodSignatureForSelector:sel]; 249 | 250 | if(!signature) { 251 | NSLog(@"csl test signature nil"); 252 | signature = [oldClass instanceMethodSignatureForSelector:sel]; 253 | } 254 | 255 | 256 | NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; 257 | invocation.target = oldClass; 258 | invocation.selector = sel; 259 | int enable = 1; 260 | 261 | [invocation setArgument:&enable atIndex:2]; 262 | if([oldClass respondsToSelector:sel]){ 263 | NSLog(@"csl test invokeWithTarget"); 264 | [invocation invokeWithTarget:oldClass]; 265 | } else { 266 | NSLog(@"csl test invoke"); 267 | [invocation invoke]; 268 | } 269 | */ 270 | 271 | NSLog(@"======================= WspxInject Initialize at Date:%@========================",[NSDate dateWithTimeIntervalSinceNow:0]); 272 | } 273 | -------------------------------------------------------------------------------- /inject_with_jailbreaking/wspx_inject.plist: -------------------------------------------------------------------------------- 1 | { 2 | Filter = { 3 | Bundles = ( 4 | "com.PandaTV.Live-iPhone", 5 | "com.chinanetcenter.UOne", 6 | "com.ucweb.iphone.lowversion", 7 | ); 8 | }; 9 | } 10 | -------------------------------------------------------------------------------- /isWKoUI/README.md: -------------------------------------------------------------------------------- 1 | # 如何通过Safari检测第三方app的某个页面是WKWebview还是UIWebview 2 | 3 | ## 使用方法: 4 | 1. 使用这里的[传送门][aUtoReSiGn]脚本对app进行重签名. 5 | - PS:要选择Development的配置来进行重签名 6 | 2. 重签名后将app安装到手机并使用闪电转USB连接线连接Mac电脑 7 | 3. 打开app到你想要验证的页面 8 | 4. 打开Mac电脑上的Safari浏览器 9 | 4. 打开Safari菜单栏上的`开发`选项.如果没找到开发选项,请依次点击`Safari浏览器`->`偏好设置`->`高级`->`在菜单栏中显示“开发”菜单`将勾勾选中. 10 | - PS:实在不明白请百度:Safari打开开发者选项 11 | 5. 然后按如下图操作: 12 | - 点击`Develop`.(PS:中文里面是叫做`开发`) 13 | - 选择`devmatocloud的iPhone`, 这时会有个`WSPXDemo`下面会显示app内webview加载的网址.(PS:如果没有网址出现在里面,那么该页面并不是webview做的) 14 | - `devmatocloud的iPhone`对应你的手机;`WSPXDemo`对应你app的名字 15 | - 选择其中一个网址,会弹出对应的`Web Inspector`.(PS:中文应该叫web检查器) 16 | - 然后在`Console`中输入`window.statusbar.visible`并按回车键,如果输出`true`那么就是`wkwebview`,相反则为`uiwebview`. 17 | 18 | ![传说中的下图][iswkoui] 19 | 20 | # Trick 21 | - 一般使用`WKWebview`都会在native这边通过`- (void)addScriptMessageHandler:(id )scriptMessageHandler name:(NSString *)name;`添加一个script消息的handler,那么就可以通过在`Web Inspector`中输入`window.webkit.messageHandlers`查看是否有输出对应的输出来判断是哪个`webview` 22 | - `UIWebview`中的输出为:`TypeError: undefined is not an object (evaluating 'window.webkit.messageHandlers')` 23 | - `WKWebview`中的输出为:`UserMessageHandlersNamespace {}` 24 | 25 | # TODO: 26 | - 弄个网址直接弹窗显示检测结果 27 | 28 | ### 在使用过程中如果有任何问题或者改良的方案欢迎提issue和pr. 29 | 30 | [iswkoui]:https://github.com/MrChens/iOS_Tools/blob/master/isWKoUI/iswkoui.png 31 | [aUtoReSiGn]:https://github.com/MrChens/iOS_Tools/tree/master/autoResign 32 | -------------------------------------------------------------------------------- /isWKoUI/iswkoui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrChens/iOS_Tools/54715f6e51467838ff6a549bb8f6e5bd44a1d72e/isWKoUI/iswkoui.png -------------------------------------------------------------------------------- /jailBreak/README.md: -------------------------------------------------------------------------------- 1 | # iPhone越狱步骤 2 | 3 | ## 1. 查看当前设备是否能越狱 4 | - [canjailbreak][canjailbreak] 5 | 6 | ## 2. 选取合适的越狱工具 7 | - 从1中的网站点击对应的越狱工具网站 8 | 9 | ## 3. 下载越狱app 10 | - 从2中的越狱工具网站下载app 11 | 12 | ## 4. 添加特殊权限 13 | - 比如`Electra`需要`com.apple.developer.networking.multipath`权限 14 | - 创建一个`app identifiers`,并勾选需要的权限`Multipath` 15 | - 创建`AdHoc`的`ProvisioningProfile` 16 | 17 | ## 4. 使用工具对app进行重签名 18 | - [appsigner][appsigner] 19 | 20 | ## 5. 将app安装到手机 21 | - Apple Configurator 2 22 | - 同步推 23 | - ideviceinstaller 24 | 25 | 26 | # iOS11越狱 27 | ## 下载越狱app 28 | - `https://coolstar.org/electra/`下载`Electra1141-1.3.2.ipa`or`https://github.com/coolstar/electra-ipas` 29 | - `https://app.ignition.fun`下载`uncOver.ipa`or`https://github.com/pwn20wndstuff/Undecimus` 30 | - 按照设备系统下载上面对应的清除工具 IPA 安装包,然后通过电脑进行自签名操作 31 | - ElectraRemover_v1.0 支持 iOS 11.0-iOS 11.1.2 清除工具,去除越狱状态`electraRemover_v1.0.ipa` 32 | - JB Remover_4.6 支持 iOS 11.2-11.4 清除工具`JB Remover-4.6 (iOS 11.2~11.4).ipa` 33 | 34 | 35 | 36 | ## 添加frida的软件源 37 | - `https://build.frida.re`, 38 | - 测试是否安装成功,在mac运行`frida-ps -U` 39 | 40 | # iOS11,增加iPhoneX的手势 41 | - 下载`Filza iOS11.3.x` 42 | 43 | 44 | [appsigner]:https://dantheman827.github.io/ios-app-signer 45 | [canjailbreak]:https://canijailbreak.com 46 | -------------------------------------------------------------------------------- /nextDay/README.md: -------------------------------------------------------------------------------- 1 | # 有空去研究一下(~~永远都没有空~~) 2 | - 让自己写的库也能使用尖括号来引用 3 | - http://stackoverflow.com/questions/749027/how-to-add-a-global-include-path-for-xcode 4 | - http://stackoverflow.com/questions/3162030/difference-between-angle-bracket-and-double-quotes-while-including-heade 5 | - http://stackoverflow.com/questions/1044360/import-using-angle-brackets-and-quote-marks 6 | 7 | - ARC相关 8 | - https://fuller.li/posts/memory-management-arc/#retainable-object-pointers 9 | 10 | - ConfiguringYourApp 11 | - https://developer.apple.com/library/content/documentation/IDEs/Conceptual/AppDistributionGuide/ConfiguringYourApp/ConfiguringYourApp.html 12 | 13 | - crul 14 | - https://ec.haxx.se/ 15 | 16 | - Debug/Hack 17 | - `Xtrace` 让它支持64位的 18 | - `itracker` 19 | 20 | - 修改`Webview`中获取`title`和`url`的方式 21 | 将js获取的方式改为https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/DisplayWebContent/Tasks/LocationChanges.html#//apple_ref/doc/uid/20002027-CJBEHAAG 中提到的几个代理方案,为以后将webview切换到wkwebview做准备。 22 | - 获取手机安装的`app`列表:https://github.com/lanvsblue/AppBrowser 23 | 24 | - `iOS`也试试使用`jekins`?还是用现在的自动打包脚本?使用`jekins`可能说以后用`xpms`就能实现打包的发布的动作。 25 | - 调试时打印视图层次 26 | - http://blog.csdn.net/duanyipeng/article/details/50523018 27 | 28 | - apple的标记 29 | - https://developer.apple.com/library/content/documentation/Xcode/Reference/xcode_markup_formatting_ref/index.html 30 | - iOS加固 31 | - http://www.blogfshare.com/ios-protect.html 32 | - http://www.cocoachina.com/ios/20170324/18955.html 33 | - 好用的工具 34 | fauxpas 静态分析工具 35 | - http://blog.csdn.net/duanyipeng/article/details/50523018 36 | 37 | - 中间人攻击:`mitmproxy` 38 | - http://docs.mitmproxy.org/en/stable/install.html 39 | - https://blog.heckel.xyz/2013/07/01/how-to-use-mitmproxy-to-read-and-modify-https-traffic-of-your-phone/ 40 | - 针对iOS10系统需要在设置->通用->关于本机->证书信任设置->开启针对根证书启用完全信任 41 | - 中间人攻击:`SSLsplit` 42 | - http://www.roe.ch/SSLsplit 43 | - https://blog.heckel.xyz/2013/08/04/use-sslsplit-to-transparently-sniff-tls-ssl-connections/ 44 | 45 | - 使用`AVAssetResourceLoaderDelegate`来实现播放器的缓冲以及设置代理的局限性 46 | - http://msching.github.io/blog/2016/05/24/audio-in-ios-9/ 47 | - 开启未定义行为监测 48 | - https://developer.apple.com/documentation/code_diagnostics/undefined_behavior_sanitizer/enabling_the_undefined_behavior_sanitizer 49 | 50 | - 文档处理 51 | - https://www.gnu.org/software/gawk/manual/gawk.html 52 | - 网络数据抓包处理(命令行工具,可以用脚本来) 53 | - https://www.wireshark.org/docs/man-pages/tshark.html 54 | 55 | - `Xcode`打包 56 | - https://developer.apple.com/library/content/technotes/tn2339/_index.html#//apple_ref/doc/uid/DTS40014588-CH1-MY_APP_HAS_MULTIPLE_BUILD_CONFIGURATIONS__HOW_DO_I_SET_A_DEFAULT_BUILD_CONFIGURATION_FOR_XCODEBUILD_ 57 | - 隐藏符号表 58 | - https://developer.apple.com/library/content/documentation/DeveloperTools/Conceptual/CppRuntimeEnv/CPPRuntimeEnv.html#//apple_ref/doc/uid/TP40001675-SW1 59 | -------------------------------------------------------------------------------- /pRoxY/README.md: -------------------------------------------------------------------------------- 1 | 2 | # 代理使用指南 3 | ## 背景 4 | 因较多CP的测试人员或开发人员不具备抓包能力,且获取uuid的办法较复杂,每次根据CP的专业程度可能需花费2-3h用以指导CP操作.所以弄了这个代理使用指南,旨在减少和CP的沟通成本. 5 | ## 使用步骤 6 | ### 1. 给手机设置代理 7 | > 以下描述都是在Wi-Fi环境下进行的 8 | #### iPhone 9 | - 打开`设置`--->`无线局域网`--->点击你所连接的Wi-Fi里的感叹号--->`HTTP代理`--->`手动`--->在`服务器`中输入`deafchen.com`--->在`端口`中输入`8080` 10 | - 如果不懂请百度/谷歌:`iPhone如何设置代理` 11 | - 友情链接:[iPhone设置代理][iPhone proxy] 12 | 13 | #### Android 14 | - 如果不懂请百度/谷歌:`Android设置代理` 15 | - 友情链接:[Android设置代理][Android proxy] 16 | 17 | ### 2. 给手机安装根证书 18 | - 使用手机自带的浏览器打开这个网站[网址][certSite]链接:http://mitm.it 19 | - 点击对应的图标就行下载,比如iPhone的手机就点击那个苹果的图标 20 | - 友情链接:[参考链接1][mitmproxy en],[参考链接2][mitmproxy zh].(PS:仅看如何安装证书部分就行,从有苹果,Android的图标开始) 21 | - 如果你的iOS系统是大于等于10.3的还需点击`设置`--->`通用`--->`关于本机`--->`证书信任设置`--->把`mitmproxy`开关打开弄成绿色的就行 22 | 23 | ### 3.到这里您的工作已经完成了,这时候联系QA人员等待他们下一步安排(如果等不及,可以自己完成下面4这个的操作) 24 | 25 | ### 4.上面的设置好以后,建议用电脑浏览器打开[查看界面][proxy GUI] 26 | > 流程是这样子的:`查看界面`连接正常没问题,再打开app 27 | 28 | - 打开手机上要测试的app,等待5秒(主要是等它触发SDK的`getBaseConfigInfo`的请求) 29 | - 如果在`查看界面`的右上角显示了红色的`connection lost`或者没有页面显示出来,请刷新一下页面如果还是不行,请联系我方人员 30 | - 在`查看界面`这里的`Search`框框中输入`~u getBaseConfigInfo` 31 | - `~u getBaseConfigInfo`解释:`~u`是对`url`进行匹配,`getBaseConfigInfo`是匹配`url`中含有`getBaseConfigInfo` 32 | - 点击最后一条符合搜索条件的请求,这时在右边会显示请求相关的参数(如果对显示格式有要求可选择View:auto中进行调整) 33 | - 复制这些参数给测试人员就行 34 | - 友情提示:如若对`mitmproxy`不了解的话请误乱点,否则可能不可预料的问题,增加沟通测试的成本 35 | 36 | ## 进阶使用指南 37 | > 以上是给CP使用的教程,以下是给我方的Server开发&QA人员的指南 38 | 39 | ### QA人员 40 | - 过滤log:在[查看界面][proxy GUI]中点击`Options`--->勾选`Display Event Log`,然后再去掉`info`,`web`,`warn`的显示等级,就留下`error`的(因为打印的就是`error`级别的`log`,量少),则能看到上面的那头牛,每个请求的`host`为`base.micro.server.matocloud.com`都会打印一次 41 | - 42 | - `Time`,参数表示该log打印的时间,可以和cp那的app发起请求的时间有大致的对应关系 43 | - `Request`请求相关的,可以用来查看是否是感兴趣的url 44 | - `param`请求带上来的参数,这里的就是我们想要的东西 45 | 46 | ### Server开发 47 | - 部署该代理GUI界面的大致步骤 48 | - 下载安装`mitmweb`[installation][mitmproxy doc] 49 | - 下载安装`caddy`[installation][caddy doc](也可以使用nginx):用来将外网的访问代理到内网的`mitmweb`中 50 | - 安装`screen`:应该也可以不用 51 | - 编辑配置`Caddyfile`文件:注意使用`nginx`需要配置`websocket`的代理(没用过nginx可能需要自己去google一下) 52 | ``` 53 | http://deafchen.com:8083 { 54 | proxy / http://127.0.0.1:8081 { 55 | websocket 56 | header_upstream -Origin 57 | } 58 | } 59 | ``` 60 | 61 | - 编辑配置`matocloud_proxy.py` 62 | ``` 63 | """ 64 | This example shows two ways to redirect flows to another server. 65 | """ 66 | from mitmproxy import http 67 | from mitmproxy import ctx 68 | import time 69 | 70 | def request(flow: http.HTTPFlow) -> None: 71 | # pretty_host takes the "Host" header of the request into account, 72 | # which is useful in transparent mode where we usually only have the IP 73 | # otherwise. 74 | if flow.request.pretty_host == "base.micro.server.matocloud.com": 75 | ctx.log.error(''' 76 | -------------------------------- 77 | \ ^__^ 78 | \ (oo)\_______ 79 | (__)\ )\/ 80 | ||----w | 81 | || || 82 | 83 | Time: %s 84 | Request:%s 85 | param:%s 86 | --------------------------------\n''' % (time.strftime('%Y.%m.%d %H:%M:%S',time.localtime(time.time())), flow.request, flow.request.text)) 87 | ``` 88 | 89 | - 先运行`caddy -conf Caddyfile &` 90 | 91 | 92 | ## 可配合使用的选项 93 | - 1. 配合`screen`使用 94 | - 运行`SCREEN -S mitmproxy ./mitmweb --set web_port=8081 --set block_global=false -s matocloud_proxy.py` 95 | 96 | - 2. 配合`crontab`使用 97 | - 将目录下的`crontabScript.sh`拷贝到`matocloud_proxy.py`同目录下, 98 | - 运行`crontab -e` 99 | - 输入`2 */1 * * * /root/sourceCode/mitmproxy/mitmproxy-4.0.4-linux/crontabScript.sh >/dev/null 2>&1`用来防止`mitmweb`挂掉后没人去重启 100 | - 输入`3 */1 * * * /root/sourceCode/mitmproxy/mitmproxy-4.0.4-linux/mitmproxy.sh >/dev/null 2>&1`让`mitmproxy.sh`脚本 101 | ### 关于`screen`的用法 102 | 103 | - [crontab][crontab] 104 | - [screen][screen] 105 | - [screen trik][screen trik] 106 | 107 | 108 | ### 关于`crontab`的用法 109 | 110 | - [crontab1][crontab1] 111 | - [crontab2][crontab2] 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | [crontab]:https://crontab.guru 132 | [crontab1]:https://www.ibm.com/support/knowledgecenter/zh/ssw_aix_71/com.ibm.aix.cmds1/crontab.htm 133 | [crontab2]:http://einverne.github.io/post/2017/03/crontab-schedule-task.html 134 | [iPhone proxy]:https://jingyan.baidu.com/article/dca1fa6f620442f1a4405202.html 135 | [Android proxy]:https://jingyan.baidu.com/article/fd8044faebfaa85030137a72.html 136 | [certSite]:http://mitm.it 137 | [mitmproxy en]:https://mrchens.github.io/2017/07/05/mitmproxy-for-iOS-app-usage 138 | [mitmproxy zh]:https://www.jianshu.com/p/032eb87aa7e0 139 | [proxy GUI]:http://deafchen.com:8083 140 | [mitmproxy doc]:https://docs.mitmproxy.org/stable/overview-installation/ 141 | [caddy doc]:https://github.com/mholt/caddy 142 | [screen]:https://linux.cn/article-8215-1.html 143 | [screen trik]:https://www.ibm.com/developerworks/cn/linux/l-cn-screen/index.html 144 | -------------------------------------------------------------------------------- /pRoxY/crontabScript.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | source /etc/profile 3 | PID=`ps aux | grep mitmweb | grep -v "grep" | wc -l` 4 | while [[ $PID -eq 0 ]]; do 5 | cm="mitmweb --set web_port=8081 --set block_global=false -s /root/sourceCode/mitmproxy/mitmproxy-4.0.4-linux/matocloud_uuid.py" 6 | eval "$cm" 7 | echo `date` > /root/sourceCode/mitmproxy/mitmproxy-4.0.4-linux/xx.txt 8 | sleep 1 9 | exit 0 10 | done 11 | 12 | -------------------------------------------------------------------------------- /pRoxY/proxy_demo.py: -------------------------------------------------------------------------------- 1 | """ 2 | This example shows two ways to redirect flows to another server. 3 | """ 4 | from mitmproxy import http 5 | from mitmproxy import ctx 6 | import time 7 | 8 | def request(flow: http.HTTPFlow) -> None: 9 | # pretty_host takes the "Host" header of the request into account, 10 | # which is useful in transparent mode where we usually only have the IP 11 | # otherwise. 12 | if flow.request.pretty_host == "base.micro.server.matocloud.com": 13 | ctx.log.error(''' 14 | -------------------------------- 15 | \ ^__^ 16 | \ (oo)\_______ 17 | (__)\ )\/ 18 | ||----w | 19 | || || 20 | 21 | Time: %s 22 | Request:%s 23 | param:%s 24 | --------------------------------\n''' % (time.strftime('%Y.%m.%d %H:%M:%S',time.localtime(time.time())), flow.request, flow.request.text)) 25 | flow.request.host = "base.micro.server.matocloud.com" 26 | elif flow.request.pretty_host == "mitm.it": 27 | flow.request.host = "mitm.it" 28 | else: 29 | flow.kill() 30 | --------------------------------------------------------------------------------