forked from tbl00c/iOS-private-api-checker
/
iOS_private.py
192 lines (162 loc) · 6.32 KB
/
iOS_private.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
#coding=utf-8
'''
Created on 2015年10月27日
iOS private api检查入口
@author: hzwangzhiwei
'''
import os, shutil
from utils import report_utils, utils
from dump import otool_utils, codesign_utils
from api import app_utils, api_utils
from db import api_dbs
# from app.utils import IpaParse
from app.utils import checkipa
def get_executable_path(ipa_path, pid):
'''
info: unzip ipa, get execute app path
'''
if not os.path.exists(ipa_path):
#不存在,返回检查结果为空值
return False
cur_dir = os.getcwd()
dest = os.path.join(cur_dir, 'tmp/' + pid)
if not os.path.exists(dest):
os.mkdir(dest)
print dest
app_path = app_utils.unzip_ipa(ipa_path, dest) #解压ipa,获得xxx.app目录路径
app = app_utils.get_executable_file(app_path)
return app
#检查私有api,返回三个参数
def check_private_api(app, pid):
#print app
strings = app_utils.get_app_strings(app, pid) #一般是app中的一些可打印文本
#app中的私有库和公有库 .framework
private, _ = otool_utils.otool_app(app)
app_varibles = app_utils.get_app_variables(app, pid)
left = strings - app_varibles #去除一些关键字,剩余app中的一些关键词
api_set = api_dbs.get_private_api_list() #数据库中的私有api,去除了whitelist白名单
print 'private length:', len(api_set)
inter_api = api_utils.intersection_list_and_api(left, api_set) # app中的api和数据库中的私有api取交集,获得app中的私有api关键字数据
app_methods = app_utils.get_app_methods(app, pid) #app中的方法名
app_apis = []
for m in app_methods:
class_name = m["class"] if m["class"] != "ctype" else 'cur_app'
method_list = m["methods"]
m_type = m["type"]
for m in method_list:
tmp_api = {}
tmp_api['api_name'] = m
tmp_api['class_name'] = class_name
tmp_api['type'] = m_type
#tmp_api['header_file'] = ''
#tmp_api['sdk'] = ''
#tmp_api['framework'] = ''
app_apis.append(tmp_api)
methods_in_app = api_utils.intersection_api(app_apis, inter_api) #app中的私有方法
methods_not_in_app = inter_api # inter_method - methods_in_app # 不在app中的私有方法
return methods_in_app, methods_not_in_app, private
#检查架构,返回架构数组
def check_architectures(app):
arcs = app_utils.check_architectures(app)
return arcs
#检查xcode ghost,返回bool
def check_xcode_ghost(app):
return app_utils.check_xcode_ghost(app)
#检查info和provision文件,并获取建议和错误配置
def check_app_info_and_provision(ipa):
return checkipa.process_ipa(ipa)
#检查codesign信息
def check_codesign(app):
return codesign_utils.codesignapp(app)
#ipa的md5
def get_file_md5(ipa):
return app_utils.file_md5(ipa)
def batch_check(app_folder, excel_path):
'''
批量检测多个ipa,并产生excel报告
'''
#遍历folder,找出.ipa文件
if not app_folder or not excel_path:
return False
check_results = []
ipa_list = os.listdir(app_folder)
for ipa in ipa_list:
result = {} #每个app的检查结果
print 'start check :', ipa
if ipa.endswith('.ipa'):
ipa_path = os.path.join(app_folder, ipa)
pid = utils.get_unique_str()
#获得ipa信息和静态检查
# ipa_parse = IpaParse.IpaParse(ipa_path)
# result['name'] = ipa_parse.app_name()
# result['version'] = ipa_parse.version()
# result['bundle_id'] = ipa_parse.bundle_identifier()
# result['tar_version'] = ipa_parse.target_os_version()
# result['min_version'] = ipa_parse.minimum_os_version()
result['md5'] = get_file_md5(ipa_path)
print result['md5']
rsts = check_app_info_and_provision(ipa_path)
for key in rsts.keys():
result[key] = rsts[key]
#检查ios私有api
app = get_executable_path(ipa_path, pid)
methods_in_app, methods_not_in_app, private = check_private_api(app, pid)
result['private_apis'] = methods_in_app
result['private_frameworks'] = list(private)
#检查ipa 64支持情况
arcs = check_architectures(app)
result['arcs'] = arcs
#检查ghost情况
ghost = check_xcode_ghost(app)
result['ghost'] = ghost
#检查codesign
codesign = check_codesign(app)
result['codesign'] = codesign
check_results.append(result)
cur_dir = os.getcwd() #删除检查临时目录
dest_tmp = os.path.join(cur_dir, 'tmp/' + pid)
if os.path.exists(dest_tmp):
shutil.rmtree(dest_tmp)
#将结果转化成excel报告
report_utils.excel_report(check_results, excel_path)
return excel_path
if __name__ == '__main__':
#######
#check one app
# ipa_path = "/Users/summer-wj/code/svn/ljsg_for_netease_20150928_resign.ipa"
# private_1 = open("tmp/private_1.txt", "w")
# private_2 = open("tmp/private_2.txt", "w")
# #将strings内容输出到文件中
# pid = app_utils.get_unique_str()
# app = get_executable_path(ipa_path, pid)
# print app
# arcs = check_architectures(app)
# print arcs
# a, b, c = check_private_api(app, pid)
# print "=" * 50
# print len(a), "Private Methods in App:"
# print "*" * 50
# for aa in a:
# print aa
# print >>private_1, aa
# print "=" * 50
# print len(b), "Private Methods not in App, May in Framework Used:"
# print "*" * 50
# for bb in b:
# print >>private_2, bb
# print "=" * 50
# print len(c), "Private Framework in App:"
# print "*" * 50
##########
#test batch check ipa
cwd = os.getcwd()
excel_path = os.path.join(cwd, 'tmp/' + utils.get_unique_str() + '.xlsx')
# excel_path = os.path.join(cwd, 'tmp/test.xlsx') # for test
print excel_path
ipa_folder = '/Users/netease/Downloads/ipas/mg/'
print batch_check(ipa_folder, excel_path)
#########
#test check arcs
# app_path = '/Users/netease/Downloads/ipas/mg/Payload'
# app = app_utils.get_executable_file(app_path)
# print check_architectures(app)