#!/usr/bin/env python#coding=utf8
importosimportreimportrandom#规避文件夹
exclude_dirs = ["JBSDKOtherFrames"]#规避文件
exclude_files =[]#属性名
property_name_list =[]#普通属性名
normal_pro_name_list =[]#类名
class_name_list =[]#字典key值
dict_key_list =[]#方法名提取
method_name_list =[]#随机字符串 (此处采取随机8位小写字母进行混淆,每次混淆后加入到此list,方便之后混淆查重)
define_rand_list =[]
#工作目录
confound_path= "/xxx/xxx/xxx/xxx"
#获取路径下的所有需要混淆的文件
defget_all_files():
path =confound_pathprint "获取文件夹内容"
if notos.path.isdir(path):print "非文件夹路径"
return
#过滤相关文件夹后的文件夹
confound_dirs =[]for root, dirs, list inos.walk(path):
confound_dirs.append(root)#过滤相关文件后的所有文件
confound_files =[]for item_path inconfound_dirs:for root, dirs, list inos.walk(item_path):for item_file inlist:if (os.path.splitext(item_file)[1] == '.h' or os.path.splitext(item_file)[1] == '.m' or os.path.splitext(item_file)[1] == '.mm') and not item_file inexclude_files:
file_path= root + '/' +item_fileif not file_path inconfound_files:iflen(exclude_dirs):
item_include=Falsefor exc_item inexclude_dirs:if exc_item infile_path:
item_include=Truebreak
if item_include ==False:
confound_files.append(file_path)returnconfound_files#查找混淆内容 正则匹配所需混淆内容
deffind_variable_name(file_path):
with open(file_path) as file:
lines=file.readlines()for line_content inlines:if "@property" in line_content: #@property 变量名
find_list= re.search("^@property\s*\(.+?\)\s*\w+\s*\*?\s*(\w+?);", line_content)if not find_list ==None:if not find_list.group(1) ==None:#print '属性名',find_list.group(1)
if not find_list.group(1) inproperty_name_list:
property_name_list.append(find_list.group(1))elif '@interface' in line_content: #类名 @interface JBSDKPopOption : UIView
find_list = re.search("^@interface\s+(\w+?)\s*:\s*\w+$", line_content)if not find_list ==None:if not find_list.group(1) ==None:#print '类名',find_list.group(1)
if not find_list.group(1) inclass_name_list:
class_name_list.append(find_list.group(1))else:#普通属性 UIImageView *arrowView;
find_list = re.search("^\s*(\w+?)\s*\*\s*(\w+?);$", line_content)if not find_list ==None:if not find_list.group(1) == None and not find_list.group(2) ==None:if not find_list.group(1) == 'return':
normal_pro_name= find_list.group(2)if normal_pro_name[0] == '_':
normal_pro_name= normal_pro_name.replace('_','')if not normal_pro_name innormal_pro_name_list:
normal_pro_name_list.append(normal_pro_name)#查字典key值
find_list = re.search("@\"([\w\d]+?)\"", line_content)if not find_list ==None:if not find_list.group(1) ==None:if not find_list.group(1) indict_key_list:
dict_key_list.append(find_list.group(1))#方法名 无参数或一个参数 - (void)JBSDKLoginCallBack;
find_list = re.search("^\s*-\s*\(\w+?\)\s*(\w+)", line_content)if not find_list ==None:if not find_list.group(1) ==None:if not find_list.group(1) inmethod_name_list:
method_name_list.append(find_list.group(1))#方法名 两个参数 - (void)JBSDKLoginCallBack:(BOOL)loginState uid:(NSString *)uid token:(NSString *)token;
find_list = re.search("^\s*-\s*\(.+?\)\s*\w+?\s*:\s*\(\w+?\)\s*\w+?\s+?(\w+?):\(.*?\)\s*\w+?\s*[;{]$", line_content)if not find_list ==None:if not find_list.group(1) ==None:if not find_list.group(1) inmethod_name_list:
method_name_list.append(find_list.group(1))#换行后的方法名
#+ (void)phoneRegister:(NSString *)phoneNum
#password:(NSString *)password
#code:(NSString *)code
find_list = re.search("^\s*(\w+?)\s*:\s*\(.+?\)\s*\w+\s*;?$",line_content)if not find_list ==None:if not find_list.group(1) ==None:if not find_list.group(1) inmethod_name_list:
method_name_list.append(find_list.group(1))#将参数写入宏文件
defwriteDefineFile():
write_file_path= 'xxx/xxx/xxx/xxx/ConfuseDefine.h'define_ok_list=[]
#一下混淆过滤内容除系统外,只略微写几个(意思一下)。针对不同工程需自行调整#系统方法 过滤系统方法名(需要根据自己的工程添加)
ex_clude_list = ['allocWithZone','copyWithZone','dealloc','viewDidLoad','shouldAutorotate','supportedInterfaceOrientations','preferredInterfaceOrientationForPresentation','didReceiveMemoryWarning','prefersStatusBarHidden','viewDidAppear','textFieldShouldReturn','touchesBegan','viewWillAppear','viewWillDisappear','alertView','tableView','initWithStyle','reuseIdentifier','numberOfSectionsInTableView','layoutSubviews','setSelected','animated','setValue','numberOfComponentsInPickerView','layout','initWithFrame','init','textFieldWillEditing','webViewDidFinishLoad','image','show','webView','webViewDidStartLoad','length','charset','srcLen','destBytes','destLen','textViewShouldBeginEditing','option_setupPopOption','_setupParams','_tapGesturePressed','JSONObject','password','description','pickView','pickerView','state','array','rightView','leftViewRectForBounds','rightViewRectForBounds','textRectForBounds']#自定义方法 (因为我的工程是SDK,所以暴露的方法不能混淆,需要过滤掉)
ex_clude_list += ['xxx','xxx','xxx','xxx','xxx']#变量 (有些自定义变量和系统变量冲突需要过滤,例如:UIButton 的 titleLabel 我们自定义时很可能会出现同名的变量,当你在设置UIButton.titleLabel时会报错,因为titleLabel已经被混淆掉了)
ex_clude_list += ['imageView','titleLabel']#私有变量 (同上)
ex_clude_list += ['font','leftView','error','scrollView','label']#类名 (SDK对外暴露的类名不能混淆,需过滤掉。非SDK应该可以忽略掉)
ex_clude_list += ['xxx','xxx','xxx','xxx','xxx']ifos.path.exists(write_file_path):
os.remove(write_file_path)
with open(write_file_path,'w+') as define_file:#property 变量
for property_name inproperty_name_list:if not property_name in ex_clude_list and not property_name in dict_key_list and not property_name indefine_ok_list:print "混淆property 变量 ==", property_name
define_ok_list.append(property_name)
define_ok_list.append('_' +property_name)
rand_name=randString()
define_content= "# ifndef" + property_name + "\n" + "# define" + property_name + " " + rand_name + "\n" + "# endif" + "\n"define_content+= "# ifndef" + '_' + property_name + "\n" + "# define" + '_' + property_name + ' ' + "_" + rand_name + "\n" + "# endif" + "\n"property_name=uperFirstString(property_name)
rand_name=uperFirstString(rand_name)
define_ok_list.append('set' +property_name)
define_content+= "# ifndef" + 'set' + property_name + "\n" + "# define" + 'set' + property_name + " " + 'set' + rand_name + "\n" + "# endif" + "\n\r"define_file.write(define_content)#私有变量
for private_name innormal_pro_name_list:if not private_name in ex_clude_list and not private_name in dict_key_list and not private_name indefine_ok_list:print "私有变量 ==", private_name
define_ok_list.append(private_name)
define_content= "# ifndef" + private_name + "\n" + "# define" + private_name + " " + randString() + "\n" + "# endif" + "\n\r"define_file.write(define_content)#类名
for class_name inclass_name_list:if not class_name in ex_clude_list and not class_name in dict_key_list and not class_name indefine_ok_list:print "类名 ==", class_name
define_ok_list.append(class_name)
rand_name=randString()
define_content= "# ifndef" + class_name + "\n" + "# define" + class_name + " " + rand_name + "\n" + "# endif" + "\n\r"define_content+= "# ifndef" + '_' + class_name + "\n" + "# define" + '_' + class_name + ' ' + "_" + rand_name + "\n" + "# endif" + "\n\r"define_file.write(define_content)#方法名
for method_name inmethod_name_list:if not method_name in ex_clude_list and not method_name in dict_key_list and not method_name indefine_ok_list:print "混淆方法 ==", method_name
define_content= "# ifndef" + method_name + "\n" + "# define" + method_name + " " + randString() + "\n" + "# endif" + "\n\r"define_file.write(define_content)#随机字符串(此处随机8位字母,根据自身需求进行调整)
defrandString():
rand_list= ['a','b','c','d','e','f','g','h','i','z','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z']
ran_str= ''.join(random.sample(rand_list, 8))while ran_str indefine_rand_list:
ran_str= ''.join(random.sample(rand_list, 8))
define_rand_list.append(ran_str)returnran_str#首字母转大写 (公开变量混淆 set 方法时,变量首字母需大写)
defuperFirstString(up_string):
first_zm=up_string[0]
up_string= first_zm.upper() + up_string[1:]returnup_string#.m文件混淆 (.m文件重命名为无意义字符,因为翻遍后可以清楚看到.m文件的名字) 注意:.h 文件无需重命名,.m 文件什么名字无所谓,只要其中引入对应的.h文件,就不会产生任何影响(只是多了一很多文件名不匹配的警告)
defconfoundMFile():
all_m_files=get_all_files()
new_file_index= 1old_name_list=[]
new_name_list=[]
file_count=0for m_file inall_m_files:if os.path.splitext(m_file)[1] == '.m' or os.path.splitext(m_file)[1] == '.mm':if not 'Test' inm_file:
file_count+= 1old_file_name= re.search("/(\w+?\+?\w+?)\.m{1,2}$", m_file)if not old_file_name ==None:
old_re_name= old_file_name.group(1) +'.m'new_name= "aaaaaaaa" + str(new_file_index) +'.m'old_name_list.append(old_re_name)
new_name_list.append(new_name)
new_file_name=m_file.replace(old_re_name, new_name)try:
os.rename(os.path.join(m_file), os.path.join(new_file_name))except:print '重命名失败',m_fileprintnew_file_nameprintold_re_nameprintnew_name
new_file_index+= 1
else:print '正则未匹配',m_file#修改配置文件 (当文件重命名后,打开工程时,.m文件会变红,指配置文件中的文件不存在,所以需要根据重命名后的文件名对配置文件进行修改)
find_file =False
config_file= ''
for root, dirs, files inos.walk(confound_path):for dir_item indirs:if dir_item == 'JBSDK.xcodeproj':
value_dir=os.path.join(root, dir_item)
config_file= value_dir + '/project.pbxproj'find_file=Truebreak
if find_file ==True:breakwith open(config_file) as config_content_file:
config_content=config_content_file.read()for index, old_name inenumerate(old_name_list):print 'old_name',old_nameprint 'new_name',new_name_list[index]
config_content=config_content.replace(old_name, new_name_list[index])
file_object= open(config_file, 'w')
file_object.write(config_content)
file_object.close()if __name__ == "__main__":
file_list=get_all_files()for path infile_list:#print path
find_variable_name(path)
writeDefineFile()#print '属性名'
#print property_name_list
#print len(property_name_list)
# #print '私有属性名'
#print normal_pro_name_list
#print len(normal_pro_name_list)
# #print '类名'
#print class_name_list
#print len(class_name_list)
# #print '字典key值'
#print dict_key_list
#print len(dict_key_list)
# #print '方法名'
#print method_name_list
#print len(method_name_list)
confoundMFile()