由于近期OEM厂家也会吃到4.3礼包, 迫使我们去做混淆. 网上的工具大部分都是付费的, 这里仅分享python去混淆iOS的工程, 不一定适合大家, 仅提供个代码思路
混淆头文件
import os, keyword
meariPath = "/Users/maj/Desktop/xxx-2.1.1-copy/Meari"
xcodeprojPath = "/Users/maj/Desktop/xxx-2.1.1-copy/Meari.xcodeproj/project.pbxproj"
oldKey = "WY"
newKey = "PG"
# 文件做递归, 拿到有用的.h, .m 文件
path1 = []
for i in os.listdir(meariPath):
tempPath1 = meariPath + "/" + i
if "." not in os.path.splitext(i)[0] and "SDK" not in os.path.splitext(i)[0] or "pch" in os.path.splitext(i)[0]:
path1.append(tempPath1)
tempList = []
def findLastFilePathList(file: list):
for i in file:
print(i);
if os.path.isfile(i):
if ".h" == os.path.splitext(i)[1] or ".m" == os.path.splitext(i)[1] or ".xib" == os.path.splitext(i)[1] or ".pch" == os.path.splitext(i)[1]:
# if (os.path.splitext(i)[0].split("/")[-1].startswith(oldKey)) :
tempList.append(i)
else:
tempPath = []
for j in os.listdir(i):
tempPath.append(i + "/" + j)
findLastFilePathList(tempPath)
findLastFilePathList(path1)
# print(tempList)
changeFileDict = {}; #保存改变的文件夹名称, 改变后名称
for i in tempList:
# 修改文件夹名称
if os.path.exists(i):
first = os.path.basename(os.path.dirname(i));
second = os.path.basename(i).split(".")[0];
if first in second: # .h .m xib 文件和文件夹名称重复
new = first.replace(oldKey, newKey)
os.rename(os.path.dirname(i),
os.path.dirname(os.path.dirname(i)) + "/" + new)
changeFileDict[first] = first.replace(oldKey, newKey)
for i in tempList:
index = tempList.index(i);
for (key, value) in changeFileDict.items():
if key in i.split("/")[-2] and i.split("/")[-1]: # 多次处理分类处理
i = i.replace(key, value, 1)
tempList[index] = i
# print(i)
break;
# print(tempList)
classNameList = []
for i in tempList:
className = i.split("/")[-1].split(".")[0]
classNameList.append(className)
for i in tempList:
with open(i, "r") as file:
str1 = file.read()
with open(i, "w") as file:
for name in classNameList:
newName = name.replace(oldKey,newKey)
str1 = str1.replace(name, newName)
# print(str1)
file.write(str1)
# 重命名 .m .h .xib
oriName = os.path.splitext(i)[0].split("/")[-1];
changeName = oriName.replace(oldKey, newKey);
fileName = changeName + os.path.splitext(i)[1]
os.rename(i, os.path.dirname(i) + "/" + fileName)
# 修改引用
with open(xcodeprojPath, "r") as file:
str1 = file.read()
with open(xcodeprojPath, "w") as file:
str2 = str1.replace(oriName, changeName)
file.write(str2)
混淆资源文件
import os
path = "/Users/maj/Desktop/xxx-2.1.1-copy/Meari"
xcodeprojPath = "/Users/maj/Desktop/xxx-2.1.1-copy/Meari.xcodeproj/project.pbxproj"
originStr = "1234567890qwertyuiopasdfghjklzxcvbnm" # 替换前的字符
replaceStr = "0987654321mnbvcxzasdfghjklpoiuytrewq" # 替换后的字符
# 图片路径数组
imagesetDict = {}; # 新:老 imageset 的名称
gifDict = {}; # gif资源文件
htmlDict = {}; # html资源文件
mp3Dict = {}; # mp3资源文件
# 修改文件夹名称
def renameFolder(filePath):
imagesetPath = os.path.dirname(filePath) # imageset路径
oldBaseName = os.path.basename(imagesetPath).split(".")[0]
newBaseName = oldBaseName.translate(str.maketrans(originStr, replaceStr)) # 改变后的imageset路径名称 //
changePath = os.path.dirname(imagesetPath) + "/" + newBaseName + os.path.splitext(imagesetPath)[1]
os.rename(imagesetPath, changePath)
# print(oldBaseName, newBaseName, filePath)
imagesetDict[oldBaseName] = newBaseName # 保存新老对应的key
# 修改文件名称
def renameFile(filePath):
oldBaseName = os.path.basename(filePath).split(".")[0]
newBaseName = oldBaseName.translate(str.maketrans(originStr, replaceStr)) # 改变后的imageset路径名称 //
changePath = os.path.dirname(filePath) + "/" + newBaseName + "." + \
os.path.basename(filePath).split(".")[1]
if ".gif" in filePath:
os.rename(filePath, changePath)
gifDict[oldBaseName] = newBaseName # 保存新老对应的key
if ".html" in filePath:
os.rename(filePath, changePath)
htmlDict[oldBaseName] = newBaseName
if ".mp3" in filePath:
mp3Right = os.path.basename(filePath).split("_")[-1];
oldBaseName = os.path.basename(filePath).replace("_" + mp3Right, "")
newBaseName = oldBaseName.translate(str.maketrans(originStr, replaceStr)) # 改变后的imageset路径名称 //
changePath = os.path.dirname(filePath) + "/" + newBaseName + "_" + mp3Right
os.rename(filePath, changePath)
mp3Dict[oldBaseName] = newBaseName
# 修改文件引用
def replaceQuote(oriName, changeName):
with open(xcodeprojPath, "r") as file:
str1 = file.read()
with open(xcodeprojPath, "w") as file:
str2 = str1.replace(oriName, changeName)
file.write(str2)
# 遍历修改名称
for dirpath, dirname, filenames in os.walk(path):
for filename in filenames:
filePath = os.path.join(dirpath, filename)
endName = os.path.splitext(filePath)[1]
if "imageset" in filePath:
if "Contents.json" in filePath:
renameFolder(filePath)
if ".html" == endName or ".gif" == endName or ".mp3" == endName:
renameFile(filePath)
print(mp3Dict)
# 修改其他需要修改引用资源文件 的引用
for key in gifDict.keys():
replaceQuote(key + ".gif", gifDict[key] + ".gif")
for key in htmlDict.keys():
replaceQuote(key + ".html", htmlDict[key] + ".html")
for key in mp3Dict.keys():
replaceQuote(key, mp3Dict[key])
# 二次遍历 修改图片@2x @3x的名称 和 图片json文件
for dirpath, dirname, filenames in os.walk(path):
for filename in filenames:
# print(filePath)
filePath = os.path.join(dirpath, filename)
if "imageset" in filePath:
if "png" in filePath or "jpg" in filePath: # 找到@2x @3x图片 进行重命名
imagesetPath = os.path.dirname(filePath) # 图片路径
if "@" in os.path.basename(filePath):
oldBaseName = os.path.basename(filePath).split("@")[0]
newBaseName = os.path.basename(imagesetPath).split(".")[0] # 新的图片名称
changePath = os.path.dirname(filePath) + "/" + newBaseName + "@" + \
os.path.basename(filePath).split("@")[1]
else:
oldBaseName = os.path.basename(filePath).split(".")[0]
newBaseName = os.path.basename(imagesetPath).split(".")[0] # 新的图片名称
changePath = os.path.dirname(filePath) + "/" + newBaseName + "." + \
os.path.basename(filePath).split(".")[1]
contentPath = os.path.dirname(filePath) + "/" + "Contents.json"
with open(contentPath, "r") as file: # 读取Contents.json文件
contents = file.read()
with open(contentPath, "w") as file: # 修改Contents.json文件
# print(file, newBaseName, oldBaseName)
contents = contents.replace(oldBaseName, newBaseName)
file.write(contents)
os.rename(filePath, changePath)
# 遍历xcode文件工程 ,替换使用资源文件的地方
for dirpath, dirname, filenames in os.walk(path):
for filename in filenames:
filePath = os.path.join(dirpath, filename)
endName = os.path.splitext(filePath)[1]
if ".h" == endName or ".m" == endName or ".xib" == endName:
with open(filePath, "r") as file:
contents = file.read()
with open(filePath, "w") as file:
for key in imagesetDict.keys():
if key in contents:
contents = contents.replace("\"" + key + "\"", "\"" + imagesetDict[key] + "\"")
for key in gifDict.keys():
mb1 = "\"" + key + "\""
mb2 = "\"" + key + "."
if mb2 in contents:
contents = contents.replace(mb2, "\"" + gifDict[key] + ".")
elif mb1 in contents:
contents = contents.replace(mb1, "\"" + gifDict[key] + "\"")
for key in htmlDict.keys():
mb1 = "\"" + key + "\""
mb2 = "\"" + key + "."
if mb2 in contents:
contents = contents.replace(mb2, "\"" + htmlDict[key] + ".")
elif mb1 in contents:
contents = contents.replace(mb1, "\"" + htmlDict[key] + "\"")
for key in mp3Dict.keys():
if key in contents:
contents = contents.replace(key, mp3Dict[key])
# print(contents)
file.write(contents)
混淆本地国际化文件
import os
path = "/Users/maj/Desktop/xxx-2.1.1-copy/Meari"
originStr = "1234567890qwertyuiopasdfghjklzxcvbnm" # 替换前的字符
replaceStr = "0987654321mnbvcxzasdfghjklpoiuytrewq" # 替换后的字符
# 读取Base.lproj 文件, 获取字符串数组
for dirpath, dirname, filenames in os.walk(path):
for filename in filenames:
filePath = os.path.join(dirpath, filename)
# endName = os.path.splitext(filePath)[1]
if "Localizable.strings" == os.path.basename(filePath): # 读取Base.lproj 文件
with open(filePath , "r") as file:
lines = file.readlines()
break;
# 获取翻译前后的key map
localDict = {}
for line in lines:
key = line.split("=")[0].split("\"")[1]
translateKey = key.translate(str.maketrans(originStr, replaceStr))
localDict[key] = translateKey
# 替换所有 Localizable.strings 中的 key
for dirpath, dirname, filenames in os.walk(path):
for filename in filenames:
filePath = os.path.join(dirpath, filename)
if "Localizable.strings" == os.path.basename(filePath):
with open(filePath , "r") as file:
content = file.read()
with open(filePath , "w") as file:
for key in localDict.keys():
mb1 = "\"" + key + "\""
if mb1 in content:
content = content.replace(mb1, "\"" + localDict[key] + "\"")
file.write(content)
# 替换所有在xcode中使用的 key
for dirpath, dirname, filenames in os.walk(path):
for filename in filenames:
filePath = os.path.join(dirpath, filename)
if filePath.endswith(".h") or filePath.endswith(".m"):
with open(filePath , "r") as file:
content = file.read()
with open(filePath , "w") as file:
for key in localDict.keys():
mb1 = "@\"" + key + "\""
if mb1 in content:
content = content.replace(mb1, "@\"" + localDict[key] + "\"")
file.write(content)
添加垃圾类, 并在原工程添加垃圾代码
import os, random
# 方法单词
headerName = "PG";
# 路径
# path = "/Users/maj/Desktop/xxx-2.1.1-copy/Meari/Classes"
path = "/Users/maj/Desktop/xxx-2.1.1-copy/Meari"
xcodeprojPath = "/Users/maj/Desktop/xxx-2.1.1-copy/Meari.xcodeproj/project.pbxproj"
fileCreateTime = "2019/9/20";
methodInsertTime = 2; # 一个.m文件的方法插入次数
classCreateTime = 2; # 一个文件夹中 创建类的个数
name = "saturationDeltaFactor,launchOptionsDirections,backButtonTitle,buttonItemAppearance,pageIndicatorTint,imageTypeFail,withTrainParticular,organizeCollectionView,viewContentSize,groupsWithTypes,backIndicatorImage,trackTintColor,effectColorAlpha,willLayoutSubviews,textBorderStyle,socialUserInfo,controlViewWill,postImageWith,loginMainView,cameraRollAlbum,showFullButton,handpickViewController,completeWithError,backButtonClick,locationHeaderView,cachingImageManager,appearSoundView,willResignActive,differenceBetweenRect,trainCommentView,readingMutableContainers,groupPurchaseOrder,courseParticularVideo,withControlPoints,businessCardView,centerViewModel,mainCommentModel,cancelCollectionChoiceness,encodedStringWith,progressTypeDefault,delegateMethodWith,swimFriendsView,photoPrevireView,withVertexShader,fromVideoView,imageViewWith,recordMovieBottom,showInputText,navigationViewController,playerStatePlaying,groupPurchaseView,accessoryDisclosureIndicator,datePickerMode,stadiumViewModel,mobileCoreServices,badgeMaximumBadge,photoHeightSelectable,navigantionItemWith,badgeDefaultFont,networkReachabilityStatus,couponsInfoData,numberWithString,fieldShouldBegin,currentPlayChapter,tweetCommentData,trainParticularComment,mallNavigationItems,withCollectionView,selectPhotoBlock,courseTableView,userInfoHeader,sendButtonStatus,textAlignmentCenter,noticeTypeLogin,applicationWillResign,itemTextColor,particularCommentTable,pushPhotoPicker,allowUserInteraction,gestureRecognizerDelegate,dailyTrainView,startCameraCapture,withCourseVideo,phoneWithPhone,keyboardTypeEmail,moreRecommendUser,imageProgressUpdate,reusableHeaderFooter,movieTestView,withTintColor,weekDateFormatter,selectPhotoBrowser,controlEventTouch,rangeAccessSupported,imageViewDelegate,messageWithText,linkWithTarget,timeUnclampedProp,collectionOriginalTable,collectionViewData,videoProcessingQueue,settingPassWord,trainTableView,commonViewModel,imageSourceThumbnail,discountCouponTable,downWithButton,imageSourceCopy,rankMedalHeader,photoScrollView,commentViewModel,roundCornerWith,maximumTrackImage,recordListWith,chooseViewDelegate,appendingPathComponent,bitmapContextCreate,styleBlackOpaque,managerWithDelegate,enumerationResultsBlock,tweetPhotoModel,shouldAutoClip,exerciseParticularView,activityListWith,organizeServiceModel,uploadCompletionBlock,courseChoicenessArticle,titleViewDelegate,sectionFooterHeight,transformRotationAngle,photoPickerController,assetsCurrentPage,coachDetailModel,numberIconImage,playerItemStatus,strokeArticleTable,tableFooterView,finishLoadWith,tableViewStyle,imageRequestOptions,integralRecordData,userTrackingMode,badgeStyleNumber,passWordWith,scrollViewContent,activityIndicatorView,timeFromDuration,sliderTouchBegan,textAlignmentRight,recordMovieConfig,sizeWithAttributes,birthdayPickerView,showLoginAlert,albumCloudShared,keywindowWithText,handpickViewModel,workStatusNofi,imageRetryFailed,imageRenderingMode,playerAnimationTime,swimCircleService,smartAlbumUser,natatoriumParticularTable,mutableTrackWith,itemTextFont,routeSearchDone,selectPhotoPicker,oscillatoryAnimationType,javaScriptText,withInfosHandle,receivedFirstFrame,imageAlphaBlend,selectTypeMyttention,metersTimeLabel,loginWithUser,longPressGesture,noticeTypeShare,titlePositionAdjustment,playViewDelegate,locationViewController,contentsUserReviews,mallViewModel,inviteAnswerNormal,playFinishIndex,colorSpaceCreate,medalKindModel,calendarUnitMonth,javaScriptAlert,identityLabelLeft,shareWebpageObject,orderDetailWith,couseFinishAlert,withVideosData,assetCollectionsWith,authorizationWithCompletion,loginViewModel,couponsScrollTable,recordModeNormal,imagePickerController,savedPhotosAlbum,imageWithData,discoveryViewModel,controlStateSelected,imageSourceContains,weekTimeInterval,teachPreviewData,deliveryModeHigh,delaysTouchesBegan,synchronizedEncodingUsing,assetResourceType,matchingReportProgress,userCommentModel,cellDefaultMargin,oscillatoryAnimationWith,affineTransformIdentity,resizeModeFast,availableSpaceBytes,controlStateNormal,pickerViewData,classFromString,titleViewWith,priousorLaterDate,likesViewController,mainFirstLogin,startProvisionalNavigation,discoverTableView,remoteNotificationsWith,mirrorFrontFacing,cancelContentTouches,noticeHeightArray,trackingWithTouch,itemStatusFailed,likesViewModel,autoresizingMaskInto,couponsInfoModel,userNotificationType,scriptMessageHandler,cellReuseIdentifier,timeRangeMake,discoverViewModel,selectPhotoDelegate,dataViewModel,locationStyleReuse,courseChapterModel,enterBackgroundNotification,withActionBlock,navigationControllerOperation,contentInsetAdjustment,differenceValueWith,offsetFromCenter,columnistChildData,withAlphaComponent,trainWithOffset,frameWithIndex,collectionViewScroll,timesFromSlider,lineWithProgress,courseVideoPlayed,trainFinishAlert,operationWithBlock,chooseStadiumTable,animatedImageView,imageFromType,pushNotificationTrigger,medalDetailFlow,withClickedButton,statusShowBottom,dailyCourseModel,withMediaType,updateStatuMandatory,textAttributedString,nodataViewDelegate,viewWithIdentifier,resizeAspectFill,ringRotationAnimation,medalDetailModel,textureWithVertices,assetMediaSubtype,listViewModel,imageCompressionRules,contentBackgroundColor,scrollOffsetWith,assetFromImage,suggestWithContent,blendModeDestination,sessionDownloadTask,photoPickerCollection,directionHorizontalMoved,badgeWithStyle,routeChangeListener,lineHeadIndent,statusBackgroundColor,activityTableView,strokeCourseHeader,trainDataWith,naviTitleFont,withSelectedAssets,asynchronouslyWithCompletion,itemWithAsset,withUserComment,cacheDailyCourse,groupWithVideos,viewCornerRadius,titleAutoConfig,swimMoviePlay,finishPickingVideo,transitRouteSearch,playerStreamInfo,coachDetailView,notificationPresentationOption,natatoriumParticularData,locationCollectionView,textFieldWith,keyboardWillChange,videoImageExtractor,buttonTypeCustom,settingTableView,assetExportPreset,thumbCollectionView,frameProcessingCompletion,tweetItemModel,stadiumParticularView,bytesUsingEncoding,panelWithMessage,conversationViewController,matchTableView,applicationLaunchOptions,commentObjectModel,previewCollectionView,dailyCourseTable,tableViewDelegate,taskCenterModel,mapsWithItems,locationViewModel,medalDetailHeader,receiveVideoLength,userInfoView,controlStateHighlighted,navigationControllerDelegate,judgeTheillegalCharacter,periodicTimeObserver,allowPickingVideo,refreshStatePulling,organzationViewModel,discountNodataView,cyclingCycleLayer,courseDetailView,streamStatusIdle,notificationCategoryOption,gradeCollectionView,userNotificationSettings,articleStrokeCourse,colorSpaceRelease,blendModeClear,couponTypeIntegral,zoomingScrollView,animatedImageFrames,scrollTimeInterval,adjustsScrollView,becomeActiveNotification,deepBlackColor,withUserData,playEnterBack,withGroupPurchase,recommendUserView,userContentController,natatoriumParticularView,videoWithAsset,withPreviewType,badgeTextColor,inputTextureUniform,stringUsingEncoding,spaceLabelHeight,courseVideoModel,saveEmojiDictionary,interfaceOrientationMask,actionWithIdentifier,videoPreviewCell,fragmentShaderString,calendarUnitYear,noticeTypeReady,frontFromBack,mutableUserNotification,pickerImageView,primaryStudyData,countTableView,collectionViewFlow,imageGeneratorWith,secondeMallView,foregroundColorAttribute,textInputNotification,moreTrainDara,fillModeForwards,authorizationStatusAuthorized,sliderFillColor,generatingDeviceOrientation,viewCellIdentifier,integralRecordTable,imageContainerView,textHighlightRange,viewControllerTransition,receiveScriptMessage,stringFromClass,recommendCellDelegate,courseVideoPlaying,refreshHeaderLayer,chooseCityCell,applicationNeedUpdate,numberHandlerWith,mainActivityModel,progressTypeNone,userNotificationCenter,playBecomeActive,pathCreateMutable,mediaTimingFunction,registerViewController,extraLightEffect,strokeCourseDaily,lineDashType,originBackgroundColor,integralMainData,bottomChartView,circleCropRadius,photoPickerPhoto,courseParticularTable,courseVideoPlayer,playerLayerGravity,swimingCommonSense,textureRetainCount,organizeListView,statusSavePhotos,withArticleOriginal,medalWallTable,assetsPhotoWith,inputButtonTitle,attentionUserTweet,maximumFractionDigits,sizeWithAsset,indicatorTintColor,taskWithRequest,buttonSystemItem,keyboardWillHide,deviceOrientationPortrait,receiveNotificationResponse,articleCommentView,discountCouponView,trackingWithEvent,withLocaleIdentifier,recognizerShouldBegin,withSwimParticular,videoPlayHeight,pageLabelPage,locationManagerDelegate,indicatorViewColor,alertViewDelegate,choicenessViewController,contextFillPath,collectionElementKind,medalViewModel,allowsBackForward,articleOriginalModel,gaussianBlurElement,userTweetTable,stringFromSelector,userIdentifyModel,organizationViewController,withRecommendCourse,integralRecordModel,photoProgressView,sectionHeaderHeight,fullScreenPlay,paragraphStyleAttribute,tableViewCell,assetImageGenerator,nameLeftLabel,textViewDelegate,listRequsetWith,integralMainHeader,natatoriumBasicInfo,gradeViewController,circleParticularView,imageOrientationRight,typeLivePhoto,assetResourceLoader,withMainComment,lineBreakMode,assetReferenceRestriction,exchangeViewDelegate,cyclingSpotAnimation,circleViewModel,photoViewIndex,scrollDirectionLeft,withJsonString,recognizeSimultaneouslyWith,imageWithImages,viewDataSource,commentSelectImage,taskCenterView,previousPerformRequests,playTestView,withRefreshingTarget,attentionViewController,pathWithRounded,circleTweetComment,commentWithOrder,alaphNavigationView,imageEdgeExtend,photoBrowserView,sheetWithData,progressTypeCycling,modalPresentationNone,videoCameraInterface,playerBeginInterruption,forgotPasswordView,withActivityIndicator,cardViewDelegate,trainParticularView,swimParticularModel,viewHeightPadding,viewWillShow,imageSharpenFilter,updateUserLocation,titleLabelSelecteded,maximumBadgeNumber,compatibleWithSaved,fieldEdeitingChanging,chatBindWith,strokeCourseView,collectionWithOffset,deviceOrientationChange,childViewController,arrayUsingDescriptors,audioSessionRoute,keyboardAnimationDuration,buttonSettingBlock,lightGrayColor,insetAdjustmentNever,textSimpleEmoticon,showsVerticalScroll,cyclingImageLayer,networkStatusReachablevia,availableTextureIndex,currentMediaTime,kernAttributeName,attentionViewModel,selectPhotoNavigation,taskCenterCell,organizationNoticeWith,profileDataWith,assetResourceLoading,orderGroupModel,groupPurchaseData,couponViewModel,assetMediaType,routeSearchResponse,currentDateString,rankMedalInfo,groupTableView,photoPreviewCell,photoButtonClick,selectPickerAssets,photosBytesWith,recordVideoError,infoViewModel,changePhoneView,viewControllerDelegate,taskNeedFinish,lightBlackColor,clippingWithView,pointerFunctionsZeroing,showingPhotoView,loginViewController,controlEventEditing,textViewContent,videoPreviewPlay,categoryChooseView,protocolViewController,haveUserEnabel,tableViewFooter,progressViewStyle,imageCropManager,concurrentOperationCount,textFiledDelegate,dataViewDelegate,playDailyCourse,organizeListTable,saveEmojiArray,withRootView,windowLevelAlert,monthTimeInterval,spinLockUnlock,trainViewModel,couponsViewController,trainParticularBottom,applicationIconBadge,assetFromFetch,playerStateBuffering,recordCompleteView,withRenderingMode,authorizationOptionBadge,affineTransformScale,animationRepeatTimes,discoverViewController,selectorFromString,caseInsensitiveSearch,articleOriginalView,blockCropMode,updatedTimeLabel,assetsGroupSaved,assetCreationRequest,leftNavigationItem,inputViewContent,affineTransformMake,changeFrameNotification,alertActionStyle,recentlyUsedEmoji,purchaseStandardData,activityIndicatorVisible,updateStatuOptional,audioSessionCategory,withCourseSecond,deviceLinkView,gradeLevelModel,videoPlayerController,chooseStadiumView,wechatTimeLine,failLoadWith,statusPhotoStream,footerCollectionReusable,sessionTaskState,lineFragmentOrigin,delaysTouchesEnded,groupPurchaseTable,sourceTypePhoto,contextDrawImage,vertexAttribPointer,deviceOrientationUnknown,alertViewStyle,badgeCenterOffset,userInfoBottom,reusableCellWith,playImageView,itemPhotoClick,cancelCollectionCourse,bitmapByteOrder,pickerViewDelegate,pickerCollectionView,firendsViewModel,orderWithPayment,adjustTrackColor,currentPageColor,imageWithColor,videoOutputPath,changePreviousRoute,circleItemShare,withStrokeCourse,friendsViewModel,resourceWithType,dataCollectionView,groupViewController,loginWithPerson,inviteAnswerView,nameRightLabel,uploadVideoBlock,choicenessTableView,fillModeBoth,downloadChapterModel,photoPreviewController,bindPhoneView,imagePickerConfig,strokeCourseModel,userModelFrom,finishLaunchingWith,characterLineLength,recordVideoQuality,cachingHighQuality,pathCloseSubpath,dateFormatterShort,assetCollectionType,playerStatePause,calendarIdentifierGregorian,collectionDataWith,playerStateStopped,photoSelectableWith,alipaySuccNotification,selectPhotoCommon,pickerViewShow,videoSendIcon,recommendCourseHeight,graphicsBeginImage,crashReportEnabled,whenInteractionEnds,assetsPickerDemo,resetControlView,swimRecordData,chatInputAble,trainViewController,inputTextureVertex,supportedWindowLevel,backFromFront,controlEventValue,assetsFromFetch,edgeInsetsZero,authorizationWithOptions,destinationFilePath,couponsAlertView,lightOraneColor,showPlayButton,circleItemPhoto,recoderSelectPicker,circleCommentTable,withGradientTint,assetsGroupEnumeration,chatInputText,frameCheckDisabled,listWithCity,rootViewController,addingPercentEscapes,assetsLibraryGroups,headerViewDelegate,streamStatusReady,deviceSettingsType,columnistViewController,withRoundCorner,interfaceOrientationLandscape,circleViewController,trainParticularHeader,pageScrollView,withContainerSize,imageNearIndex,photoPickerImage,commonToolVedio,assetCollectionSubtype,moviePlayTest,numberFormatterDecimal,medalWallView,assetPropertyType,reusableAnnotationView,cameraAutoSave,withCityName,separatorStyleSingle,linkViewModel,cacheCourseParticular,titleShowStatus,currentViewController,rankMedalModel,showShowSheet,pausesLocationUpdates,infoWithStatus,playViewModel,groupPhotosWith,collectionViewDelegate,viewWidthPadding,workWithOffset,connectionDataDelegate,drawImageView,sourceTypeAvailable,orderStepView,replayTypeNormal,recordMovieModel,orderGroupCell,compositionLayerInstruction,withCommentObject,styleLightContent,withDailyTrain,rankMedalBlock,hourTimeInterval,currentDownloadCount,titleEdgeInsets,mainViewModel,locationWithGeocoder,videoDealPoint,taskCenterTable,tableViewContent,particularViewModel,scrollDirectionRight,socialShareResponse,orderInfoTable,decimalNumberHandler,headerFooterView,columnistChildView,natatoriumListTable,portraitUpsideDown,assetPreviewCell,ringStrokeAnimation,imageWithName,badgeAnimType,mainScreenHeight,sendCommentView,selectedPhotoBytes,photoLoadingView,scaleAspectFill,trainGuideTable,originalPhotoWith,deviceOrientationFace,scrollViewDeceleration,verticalScrollIndicator,withTaskCenter,courseViewController,viewArrowLength,dataElseLoad,imageOrientationLeft,weekTimeLabel,alowGroupPurchase,recordVideoCamera,choicenessViewModel,blendModeOverlay,showPhotoPicker,selectTypeUser,timerWithTime,underlineStyleAttribute,animationRightTick,columnistCategoryModel,hidesWhenStopped,fillColorWith,articleCourseParticular,imageFromCurrent,hideControlView,alertControllerStyle,playChapterIndex,mutableAttributedString,requestReloadIgnoring,pointSaturationMatrix,receiveLocalNotification,textFieldView,pickerViewController,withCalendarIdentifier,thirdLoginFail,showControlView,gestureRecognizerState,integralNumberTable,registerViewModel,courseRecommendCell,recordMovieView,collectionTrainModel,courseChoicenessColumnist,videoWithScroll,viewAnimationOption,bytesFromData,imageMatrixMultiply,withPlayerItem,imageHandleCookies,assetsUsingBlock,articleDetailData,followWithHeading,allowWithController,cellWithIndex,rectWithSize,mediaTypeAudio,spinLockLock,strokeCourseParticular,downloadProgressBlock,circleScreenData,fetchLoginInfo,recordViewModel,springWithDamping,natatoriumListView,failWithError,preferredTrackTransform,stringFromDate,replayTypeSlider,playerStatusPlaying,levalInfoModel,regionDefaultHandler,assetResourceCreation,screenButtonClick,orderDetailCell,objectsHashTable,imageRotationSwaps,withRefreshingBlock,viewWillHidden,baseViewController,userCommentData,fieldValueDictionary,hiddenScreenView,videBeginPlay,customControlView,filterWithCode,sessionDataTask,couponAlertView,valueObservingOption,wallTableView,finishLoadingWith,pickingMultipleVideo,presetsCompatibleWith,pageTintColor,cancelLoadingRequest,medalDetailCell,trainInfoView,trainParticularData,titleWithStatus,rectCornerBottom,applicationStateActive,edgeInsetsMake,sliderValueChanged,authorizationOptionSound,startLoadWith,photoImageView,withLongLong,baseLoginView,bottomViewDelegate,userCommentTable,minimumTrackImage,guideBottomView,launchOptionsShows,blurWithRadius,selectPhotoAssets,materialDesignSpinner,minuteTimeInterval,swipeGestureRecognizer,minimumDismissTime,courseChooseCell,natatoriumAddressTable,subviewWithClass,naviTitleAppearance,sourceTypeCamera,articleOriginalData,sizePlayView,customPropertyMapper,moreColumnistChild,minimumTrackTint,viewContentMode,imageEdgeInsets,levelUserCollections,assetPreferPrecise,articleCommentData,viewControllerContext,loginWithOpen,dailyTrainDetail,firstFrontCamera,personDataView,recommendCollectionView,courseParticularView,purchaseStatusLabel,userNotificationActivation,movieFrameOpposite,strikethroughStyleAttribute,editUserInfo,imageSourceCreate,maskTypeClear,viewsAlongAxis,activeShaderProgram,withIntegralRecord,errorWithStatus,launchViewController,sliderTouchDown,replayUserNick,swimDataModel,cyclingLineLayer,beginFromCurrent,selectionStyleNone,withTimeInterval,rankMedalView,playerStatusReady,intergralStoreView,recommendCourseModel,backgroundLocationUpdates,alertWithTitle,doneButtonClick,bottomLineLabel,reusablePhotoView,timeModelData,tweetCommentModel,photoButtonBottom,blockWithPreview,pageContolAliment,yearTimeInterval,actualBadgeSuper,numberBadgeWith,answersTableView,applicationOpenSettings,groupWithPhotos,separatorStyleNone,modalTransitionStyle,rightBottomPoint,userTweetView,bottomPhotoView,maskViewFlag,downloadImageWith,playerControlView,objectsFromArray,circleScreenView,organizeTableView,courseScrollView,directionVerticalMoved,photoViewDelegate,underlineStyleSingle,shareImageObject,stringFromData,withSwimData,userInfoWith,imageProcessingContext,modalPresentationOver,finishPickingMedia,searchRequestWith,extractImageList,videoDetailData,ticketRightLabel,exerciseRecordTable,courseViewModel,fillRuleEven,swappableImageView,backGroundUser,viewWillBegin,integralRecordView,selectOriginalPhoto,messageWithUser,downVideoData,articleDailyTrain,orientationPortraitConstraint,bundleShortVersion,interfaceOrientationPortrait,zoomScaleWith,tableViewScroll,progressUpdateBlock,mutableVideoComposition,assetChangeRequest,imageOptionProgressive,trainsWithOffset,viewControllerDone,commentTweetSucc,gradeViewModel,authImageView,groupPurchaseModel,streamStatusConnecting,medalDetailView,recommendTableView,assetsWithOptions,withUserTweet,smartAlbumRecently,exerciseHistoryData,courseClassTable,withProgressView,drivingRouteSearch,fullScreenVideo,playerStatusPause,screenViewController,audioPlayerDelegate,titleViewExample,viewAnimatedColors,pickingOriginalPhoto,shrinkRightBottom,applicationWillEnter,secondTextureCoordinate,ticketLeftLabel,valueImageRect,sourceTypeSaved,buttonItemStyle,playerItemPlayback,courseParticularModel,likesTableView,playerStateFailed,autoAdjustTrack,playerDecodeError,blendModeSource,mainViewController,photoPickerView,defaultMaskType,pickerGroupTable,rectEdgeNone,blurredImageCompletion,readingMutableLeaves,userViewModel,largeTextFont,strokeCourseSecond,playerViewContent,collectionTrainView,guidePageControl,trainParticularProperty,sendTweetView,collectionViewCell,exportVideoWith,videoCameraDelegate,outsideImageView,assetsPickerChecked,suggestBackView,organizeNoticeModel,articleOriginalHeader,layerWithPlayer,withReuseIdentifier,priceMutableString,bindWithOpen,buttonClickBlock,withDailyCourse,withDataArray,titleTextAttributes,timeRangeFrom,uploadSuccBlock,sliderSeekTime,cacheUserInfo,viewFinishLoad,autoClipImage,currentItemWith,deleteTweetSucc,infoHeaderHeight,swimScrollView,userInterfaceIdiom,downLoadData,videoWithPath,refreshStateIdle,dailyTrainData,userInfoMedal,albumSyncedAlbum,rectIntersectsRect,assetReferenceRestrictions,settingViewController,cellPlayerFather,screehButtonClick,affineTransformTranslate,horizontalScrollIndicator,failProvisionalNavigation,finishPickingPhotos,deviceSettingsCamera,baseTableView,captureFlashMode,pathWithRect,userNotificationAction,fansWithUser,valueObservingOptions,backgroundLayerColor,weekdayCalendarUnit,pointerFunctionsWeak,pointerFunctionsObject,audioSessionPort,withVisualFormat,contextFillRect,navigateItemWith,modelWithAsset,trainPropertyTrain,partButtonAction,intervalSinceDate,imageCompressionWith,photoWidthSelectable,mainCommentTable,hiddenShowSheet,fontAttributeName,gradeUserModel,pickerColletionView,orderDetailView,userInfoModel,particularDescriptionTable,authorizationOptionAlert,assetGridThumbnail,imageOrientationDown,infoBottomView,withServiceArea,imageContentMode,succViewController,nameBottomLine,filterManagerDelegate,organizeListRequset,readingAllowFragments,guideViewController,collectionReusableView,underlinePatternSolid,interfaceOrientionChange,routeSearchBase,particularModelJson,backWithContent,imageGenerationError,imageTypeSuccess,mainScreenWidth,photoPickerGroup,tweetItemData,mainMessageView,customAnimateTransition,stringWithTime,zoneWithAbbreviation,mediaTypeVideo,mainCommentView,tweetViewModel,playWhileCell,dailyTrainClass,socialPlatformType,swimCircleItem,mainMessageData,chooseCellDelegate,cycleScrollView,saveTimePlay,integralStoreView,firstAlreadyLogged,objectsUsingBlock,photoWithAsset,orientationLandscapeConstraint,photoPreviewView,completeViewDelegate,moreDataWith,recommendUserData,withSessionConfiguration,showOrderStatus,organizeHeaderView,bottomCellDelegate,swimFriendsData,keyboardTypeNumber,videoRequestOptions,encodingWithLine,mutableCompositionTrack,scrollViewKeyboard,captureSessionPreset,withAssetTrack,receiveVideoData,downloadAlertView,cancelAutoFade,imageManagerMaximum,pickerClickTick,scrollViewDelegate,axisTypeHorizontal,dataWithUser,withLoadingRequest,withCourseChoiceness,unclampedDelayTime,actionSheetDelegate,photosDelegateWith,alertWithController,dataReadingMapped,photoPickerBrowser,requestReturnCache,collectionViewController,videoViewModel,refreshStateRefreshing,imageWithLeft,cropTypeWith,emojiTypeAction,rectContainsPoint,couponTypeActivity,indicatorViewStyle,trainCommentModel,countDownHelper,pointerFunctionsOptions,withCouponsInfo,childViewControllers,assetExportSession,backGroundColor,receiveRemoteNotification,articleContentModel,photoWithImage,coachDetailWith,cyclingLineAnimation,assetCameraCell,withSureBlock,cacheUserModel,authorizationStatusRestricted,edgeInsetsInset,assetFromVideo,gradeBottomView,originStatusBackground,customDismissAction,trainParticularModel,notificationActionOption,browserPhotoScroll,cellWithReuse,filterManagerInited,keyboardWillShow,objectWithData,courseParticularSection,discoveryViewController,userDomainMask,arrayUsingSelector,beautyParamWith,exerciseRecordView,mallViewController,successWithStatus,networkStatusUnknow,styleWhiteLarge,assetPropertyDuration,strokeCourseData,controlStateDisabled,apertureModeEncoded,viewNoticeDelegate,mutableParagraphStyle,tintEffectWith,baseTabbarView,withFileName,collectionOriginalModel,stateAlertView,loopCommonModes,authrizationStatusChange,natatoriumListData,sendTweetSucc,pathWithOval,blurredImageDefault,inputPanelWith,imageRotationMode,affineTransformRotate,currentShortDate,shaderFromString,saveVideoPath,particularDetailTable,honorTableView,socialMessageObject,thumbnailFromImage,commentTableView,settingViewModel,statusWithBlock,stringWithAttachment,albumPickerController,receivedSecondFrame,lineJoinMiter,pointerFunctionsStrong,secondFrameCheck,childViewModel,pictureImageName,stringDrawingUses,itemsSupplementBack,playerWithPath,willEnterForeground,swimRecordWith,particularNameData,assetModelMedia,imageCacheType,collectionTrainTable,reachabilityStatusChange,loginWithPhone,withCourseParticular,statusCameraRoll,answerViewModel,choicenessVideoView,writingPrettyPrinted,networkReachabilityManager,trainStadiumData,contextStrokePath,browserPhotoView,originalPhotoData,likeTweetSucc,openWindowsAutomatically,layerTintColor,mainCommentData,collectionViewLayout,moviePlayView,sliderTouchEnded,dataViewController,contentInformationRequest,senseViewModel,imageMovieWriter,shareViewDelegate,imageTextureDelegate,insetAdjustmentBehavior,assetsGroupProperty,buttonTitleColor,playerStatusFailed,changeReasonCategory,videoRequestTask,javaScriptConfirm,viewControllerAnimated,withTweetItem,swimCircleView,insideImageView,assetCellType,typeUserCenter,locationWithSuccess,playerStatusIdle,recommendDiscountTable,deliveryModeAutomatic,dateFormatterMedium,articleOriginalTable,allowPickingImage,buttonTypeSystem,enableVertexAttrib,layerVideoGravity,withPhoneNumber,assetsViewController,pageContolStyle,mainCourseModel,textAlignmentLeft,compositionWithAsset,honorTitleModel,objectWithTitle,walkingRouteSearch,fromVideoFile,guideCollectionView,dailyTrainHeader,normalTableView,showGuideWindow,valueTrackingSlider,receiveMemoryWarning,trainParticularStadium,backIndicatorTransition,browserPhotoImage,assetTypeVideo,tableViewData,minimumFractionDigits,dailyTrainChapter,timeRangeValue,numberFormatterRound,courseCachaData,textFieldDelegate,defaultImageName,progressDefaultSize,dailyCourseDetail,currentPhotoIndex,viewNavigationType,courseParticularHeader,bottomShrinkPlay,effectThumbImage,withRankMedal,trainCommentTable,pressEmojiAction,photoPickerAssets,failLoadingWith,notificationPresentationOptions,userTweetData,withMedalKind,retinaFilePath,editCommentView,withSessionPreset,couponTypeCourse,shareInfoView,viewContentOffset,controllerWithTitle,reusableSupplementaryView,timeMakeWith,commentArticleSucc,blockWithResult,deviceOrientationLandscape,rewardTypeNone,finishSavingWith,swimPlayStatus,imageWithImage,fileTypeQuick,regularExpressionCase,successWithJson,contextWithOptions,photoStreamAlbum,badgeDefaultMaximum,imageAlphaPremultiplied,firstFrameCheck,imageViewFrame,middleTextFont,attentionWithUser,authorizationStatusDenied,collectionOriginalView,assetPropertyAsset,medalExplainView,userCommentView,recommendUserTable,typeCreatePreferred,centerButtonClick,videoPlayView,viewCellDelegate,viewShouldBegin,beautyParameterWith,naviTitleColor,swimmingCommonSense,codeLoginView,arrayUsingComparator,buttonImageName,imageNamesGroup,bottomShareView,viewSettingBlock,viewAutoresizingFlexible,boardWithText,loginWithCompletion,viewImageFinish,integralMainView,bundleDisplayName,textureCoordinateAttribute,withCustomView,firstBackCamera,withFragmentShader,textLabelHidden";
nameList = name.split(",")
ocClassStrongList = ["UIImage", "UITableView", "UITextField", "UIFont", "UITextView", "NSData", "UIColor", "NSString", "UIButton", "UIImageView", "NSMutableArray", "NSArray", "UIView", "UILabel", "UISwitch", "UIActivityIndicatorView", "UIScrollView", "UISlider"]
ocClassAssignList = ["CGRect", "CGPoint", "UITableViewStyle", "NSRange", "UIButtonType", "UIEdgeInsets", "CGSize", "UITextFieldViewMode", "UITableViewCellSeparatorStyle", "NSLineBreakMode", "NSTextAlignment"]
ocSystemImport = ["UIKit", "WebKit"]
newFileNameList = []; # 新文件的名称
newFilePathList = []; # 新文件的路径全称
classMethodDic = {}; # 类的名称 : 类的实例方法数组 "
# 首字母大写, 其他不变
def capitalize(string, lower_rest=False):
return string[:1].upper() + (string[1:].lower() if lower_rest else string[1:])
def low(string, lower_rest=False):
return string[:1].lower() + (string[1:].lower() if lower_rest else string[1:])
# ocClass为return的类型 className为其他类的名称,用作创建和引用
def getOCClassString(ocClass: str, isReturn: bool):
index = random.randint(0, len(nameList) - 1)
randomName = low(nameList[index]) + str(random.randint(1,9))
returnStr = " "
if ocClass == "UIImage":
returnStr = returnStr + "UIImage *" + randomName + "= [UIImage imageNamed:@\"\"]; \n "
elif ocClass == "UITableView":
if random.randint(0, 1) == 1:
returnStr += "UITableView *" + randomName + "= [[UITableView alloc] initWithFrame:CGRectZero style: UITableViewStylePlain]; \n "
else:
returnStr += "UITableView *" + randomName + "= [[UITableView alloc] initWithFrame:" + "CGRectMake(" + str(random.randint(1, 255)) + "," + str(random.randint(1, 255)) + "," + str(random.randint(1, 255)) + "," + str(random.randint(1, 255)) + ") " + "style: UITableViewStylePlain]; \n "
returnStr += randomName + ".frame = CGRectZero; \n "
returnStr += randomName + ".showsVerticalScrollIndicator = NO; \n "
returnStr += randomName + ".showsHorizontalScrollIndicator = NO; \n "
returnStr += randomName + ".backgroundColor = [UIColor whiteColor]; \n "
returnStr += randomName + ".separatorColor = [UIColor whiteColor]; \n "
returnStr += randomName + ".tableFooterView = [UIView new]; \n "
returnStr += randomName + ".estimatedRowHeight =" + str(random.randint(0, 100)) + "; \n "
returnStr += randomName + ".estimatedSectionHeaderHeight =" + str(random.randint(0, 100)) + "; \n "
returnStr += randomName + ".estimatedSectionFooterHeight =" + str(random.randint(0, 100)) + "; \n "
returnStr += randomName + ".rowHeight =" + str(random.randint(0, 100)) + "; \n "
returnStr += randomName + ".sectionFooterHeight =" + str(random.randint(0, 100)) + "; \n "
returnStr += randomName + ".sectionHeaderHeight =" + str(random.randint(0, 100)) + "; \n "
returnStr += randomName + ".tableHeaderView = [[UIView alloc] initWithFrame:" + "CGRectMake(" + str(random.randint(1, 255)) + "," + str(random.randint(1, 255)) + "," + str(random.randint(1, 255)) + "," + str(random.randint(1, 255)) + ")];\n "
returnStr += randomName + ".tableFooterView = [[UIView alloc] initWithFrame:" + "CGRectMake(" + str(random.randint(1, 255)) + "," + str(random.randint(1, 255)) + "," + str(random.randint(1, 255)) + "," + str(random.randint(1, 255)) + ")];\n "
elif ocClass == "UITextField":
if random.randint(0, 1) == 1:
returnStr += "UITextField *" + randomName + "= [[UITextField alloc] initWithFrame:CGRectZero]; \n "
else:
returnStr += "UITextField *" + randomName + "= [[UITextField alloc] initWithFrame:" + "CGRectMake(" + str(random.randint(1, 255)) + "," + str(random.randint(1, 255)) + "," + str(random.randint(1, 255)) + "," + str(random.randint(1, 255)) + ")]; \n "
returnStr += randomName + ".clearButtonMode = UITextFieldViewModeNever; \n "
returnStr += randomName + ".textColor = [UIColor whiteColor]; \n "
returnStr += randomName + ".font = [UIFont boldSystemFontOfSize:20];\n "
returnStr += randomName + ".textAlignment = NSTextAlignmentNatural; \n "
returnStr += randomName + ".tintColor = [UIColor blackColor]; \n "
returnStr += randomName + ".leftView = [[UIView alloc] initWithFrame:" + "CGRectMake(" + str(random.randint(1, 255)) + "," + str(random.randint(1, 255)) + "," + str(random.randint(1, 255)) + "," + str(random.randint(1, 255)) + ")];\n "
returnStr += randomName + ".leftViewMode = UITextFieldViewModeAlways; \n "
elif ocClass == "UIFont":
returnStr = returnStr + "UIFont *" + randomName + "= [UIFont systemFontOfSize:" + str(random.randint(1, 255)) + "];\n "
elif ocClass == "UITextView":
if random.randint(0, 1) == 1:
returnStr += "UITextView *" + randomName + "= [[UITextView alloc] initWithFrame:CGRectZero]; \n "
else:
returnStr += "UITextView *" + randomName + "= [[UITextView alloc] initWithFrame:" + "CGRectMake(" + str(random.randint(1, 255)) + "," + str(random.randint(1, 255)) + "," + str(random.randint(1, 255)) + "," + str(random.randint(1, 255)) + ")]; \n "
returnStr += randomName + ".editable = NO; \n "
returnStr += randomName + ".font = [UIFont systemFontOfSize:" + str(random.randint(1, 255)) + "];\n "
returnStr += randomName + ".text = @\"" + nameList[random.randint(0, len(nameList) - 1)] + "\";\n "
elif ocClass == "NSData":
returnStr = returnStr + "NSData *" + randomName + "= [[NSData alloc] init]" + ";\n "
elif ocClass == "UIColor":
returnStr = returnStr + "UIColor *" + randomName + "= [UIColor redColor]" + ";\n "
elif ocClass == "NSString":
returnStr += "NSString *" + randomName + " = @\"" + nameList[random.randint(0, len(nameList) - 1)] + "\";\n "
elif ocClass == "UIButton":
returnStr += "UIButton *" + randomName + "= [UIButton buttonWithType:UIButtonTypeCustom]; \n "
returnStr += randomName + ".frame = CGRectZero; \n "
returnStr += randomName + ".exclusiveTouch = NO; \n "
returnStr += randomName + ".adjustsImageWhenHighlighted = NO; \n "
returnStr += randomName + ".reversesTitleShadowWhenHighlighted = NO; \n "
returnStr += randomName + ".frame = CGRectZero; \n "
elif ocClass == "UIImageView":
returnStr += "UIImageView * " + randomName + " = [[UIImageView alloc] initWithImage:[UIImage imageNamed:[NSString string]] highlightedImage:[[UIImage alloc] initWithData:[NSData data]]]; \n "
returnStr += randomName + ".contentMode = UIViewContentModeCenter; \n "
returnStr += randomName + ".clipsToBounds = NO; \n "
returnStr += randomName + ".multipleTouchEnabled = YES; \n "
returnStr += randomName + ".autoresizesSubviews = YES; \n "
returnStr += randomName + ".clearsContextBeforeDrawing = YES; \n "
elif ocClass == "NSMutableArray":
if random.randint(0, 1) == 1:
returnStr = returnStr + "NSMutableArray *" + randomName + "= [NSMutableArray arrayWithCapacity:0]" + ";\n "
else:
returnStr = returnStr + "NSMutableArray *" + randomName + "= [NSMutableArray array]" + ";\n "
elif ocClass == "NSArray":
if random.randint(0, 1) == 1:
returnStr = returnStr + "NSArray *" + randomName + "= [NSArray arrayWithObject:@\"\"]" + ";\n "
else:
returnStr = returnStr + "NSArray *" + randomName + "= [NSArray array]" + ";\n "
elif ocClass == "UIView":
if random.randint(0, 1) == 1:
returnStr += "UIView *" + randomName + "= [[UIView alloc] initWithFrame:CGRectZero]; \n "
else:
returnStr += "UIView *" + randomName + "= [[UIView alloc] initWithFrame:" + "CGRectMake(" + str(random.randint(1, 255)) + "," + str(random.randint(1, 255)) + "," + str(random.randint(1, 255)) + "," + str(random.randint(1, 255)) + ")]; \n "
returnStr += randomName + ".backgroundColor = [UIColor whiteColor]; \n "
returnStr += randomName + ".layer.cornerRadius = " + "" + "\n "
returnStr += randomName + ".layer.masksToBounds = YES; \n "
elif ocClass == "UILabel":
if random.randint(0, 1) == 1:
returnStr += "UILabel *" + randomName + "= [[UILabel alloc] initWithFrame:CGRectZero]; \n "
else:
returnStr += "UILabel *" + randomName + "= [[UILabel alloc] initWithFrame:" + "CGRectMake(" + str(random.randint(1, 255)) + "," + str(random.randint(1, 255)) + "," + str(random.randint(1, 255)) + "," + str(random.randint(1, 255)) + ")]; \n "
returnStr += randomName + ".text = @\"" + nameList[random.randint(0, len(nameList) -1)] + "\";\n "
returnStr += randomName + ".textColor = [UIColor whiteColor]; \n "
returnStr += randomName + ".font = [UIFont systemFontOfSize:" + str(random.randint(1, 255)) + "];\n "
returnStr += randomName + ".numberOfLines = 0; \n "
returnStr += randomName + ".textAlignment = NSTextAlignmentCenter; \n "
elif ocClass == "UISwitch":
if random.randint(0, 1) == 1:
returnStr += "UISwitch *" + randomName + "= [[UISwitch alloc] initWithFrame:CGRectZero]; \n "
else:
returnStr += "UISwitch *" + randomName + "= [[UISwitch alloc] initWithFrame:" + "CGRectMake(" + str(random.randint(1, 255)) + "," + str(random.randint(1, 255)) + "," + str(random.randint(1, 255)) + "," + str(random.randint(1, 255)) + ")]; \n "
returnStr += randomName + ".on = YES; \n "
returnStr += randomName + ".onTintColor = [UIColor whiteColor]; \n "
elif ocClass == "UIActivityIndicatorView":
returnStr += "UIActivityIndicatorView *" + randomName + "= [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; \n "
returnStr += randomName + ".hidden = YES; \n "
returnStr += randomName + ".hidesWhenStopped = YES; \n "
elif ocClass == "UIScrollView":
if random.randint(0, 1) == 1:
returnStr += "UIScrollView *" + randomName + "= [[UIScrollView alloc] initWithFrame:CGRectZero]; \n "
else:
returnStr += "UIScrollView *" + randomName + "= [[UIScrollView alloc] initWithFrame:" + "CGRectMake(" + str(random.randint(1, 255)) + "," + str(random.randint(1, 255)) + "," + str(random.randint(1, 255)) + "," + str(random.randint(1, 255)) + ")]; \n "
returnStr += randomName + ".showsHorizontalScrollIndicator = NO; \n "
returnStr += randomName + ".showsVerticalScrollIndicator = NO; \n "
returnStr += randomName + ".bounces = NO; \n "
returnStr += randomName + ".maximumZoomScale = 5; \n "
returnStr += randomName + ".minimumZoomScale = 1; \n "
elif ocClass == "UISlider":
if random.randint(0, 1) == 1:
returnStr += "UISlider *" + randomName + "= [[UISlider alloc] initWithFrame:CGRectZero]; \n "
else:
returnStr += "UISlider *" + randomName + "= [[UISlider alloc] initWithFrame:" + "CGRectMake(" + str(random.randint(1, 255)) + "," + str(random.randint(1, 255)) + "," + str(random.randint(1, 255)) + "," + str(random.randint(1, 255)) + ")]; \n "
returnStr += randomName + ".minimumValue = 0; \n "
returnStr += randomName + ".maximumValue = 100; \n "
returnStr += randomName + ".value =" + str(random.randint(1, 100)) + "; \n "
elif ocClass == "CGRect":
if random.randint(0, 1) == 1:
returnStr += "CGRect " + randomName + " = CGRectZero;\n "
else:
returnStr += "CGRect " + randomName + " = CGRectMake(" + str(random.randint(1, 255)) + "," + str(random.randint(1, 255)) + "," + str(random.randint(1, 255)) + "," + str(random.randint(1, 255)) + "); \n "
elif ocClass == "CGPoint":
if random.randint(0, 1) == 1:
returnStr += "CGPoint " + randomName + " = CGPointZero;\n "
else:
returnStr += "CGPoint " + randomName + " = CGPointMake(" + str(random.randint(1, 10)) + "," + str(random.randint(20, 255)) + "); \n "
elif ocClass == "NSRange":
returnStr += "NSRange " + randomName + " = NSMakeRange(" + str(random.randint(1, 10)) + "," + str(random.randint(20, 255)) + "); \n "
elif ocClass == "UIButtonType":
returnStr += "UIButtonType " + randomName + " = UIButtonTypeContactAdd;\n "
elif ocClass == "UIEdgeInsets":
if random.randint(0, 1) == 1:
returnStr += "UIEdgeInsets " + randomName + " = UIEdgeInsetsZero;\n "
else:
returnStr += "UIEdgeInsets " + randomName + " = UIEdgeInsetsMake(" + str(random.randint(1, 255)) + "," + str(random.randint(1, 255)) + "," + str(random.randint(1, 255)) + "," + str(random.randint(1, 255)) + "); \n "
elif ocClass == "CGSize":
if random.randint(0, 1) == 1:
returnStr += "CGSize " + randomName + " = CGSizeZero;\n "
else:
returnStr += "CGSize " + randomName + " = CGSizeMake(" + str(random.randint(1, 255)) + "," + str(random.randint(1, 255)) + "); \n "
elif ocClass == "UITextFieldViewMode":
returnStr += "UITextFieldViewMode " + randomName + " = UITextFieldViewModeAlways; \n "
elif ocClass == "UITableViewStyle":
returnStr += "UITableViewStyle " + randomName + " = UITableViewStylePlain; \n "
elif ocClass == "UITableViewCellSeparatorStyle":
returnStr += "UITableViewCellSeparatorStyle " + randomName + " = UITableViewCellSeparatorStyleNone; \n "
elif ocClass == "NSLineBreakMode":
returnStr += "NSLineBreakMode " + randomName + " = NSLineBreakByTruncatingTail; \n "
elif ocClass == "NSTextAlignment":
returnStr += "NSTextAlignment " + randomName + " = NSTextAlignmentCenter; \n "
elif ocClass == "":
pass
if isReturn:
returnStr += "return " + randomName + ";"
return [returnStr, randomName];
def getContent(hPath: str, mPath: str, hmPathName: str):
useClass = ""
methodNameList = [] # 方法数组
instanMethodNameList = [] # 实例方法数组
returnTypeList = [] # 方法数组
if len(newFileNameList) > 0:
r = random.randint(0, len(newFileNameList) -1)
useClass = newFileNameList[r]
# print("newFileNameList", newFileNameList)
with open(hPath, "w+") as file:
contents = "// \n //" + hmPathName + ".h\n " + "// Meari \n// \n// Created by maj on" + fileCreateTime + ". \n// Copyright © 2019 Meari. All rights reserved. \n // \n"
for i in ocSystemImport:
if random.randint(0, 1) == 1:
contents = contents + "@import " + i + ";\n"
contents = contents + "\n";
# 添加@class声明
for i in ocClassStrongList:
if random.randint(0, 2) == 1:
contents = contents + "@class " + i + ";\n"
if len(useClass) > 0:
contents = contents + "@class " + useClass + ";\n"
contents = contents + "\n";
contents = contents + "@interface " + hmPathName + " : NSObject\n\n" # 添加interface
# 添加属性
propertyList = nameList.copy()
for i in range(0, 3):
random1 = random.randint(0, len(ocClassStrongList) -1) # 随机下标
typeName = ocClassStrongList[random1]
random2 = random.randint(0, len(propertyList) -1) # 随机下标
propertyName = propertyList[random2];
propertyList.pop(random2) # 去除相同属性的可能
contents = contents + "@property (nonatomic, readwrite, strong) " + typeName + " *" + propertyName + ";\n"
for i in range(0, 2):
random1 = random.randint(0, len(ocClassAssignList) -1) # 随机下标
typeName = ocClassAssignList[random1]
random2 = random.randint(0, len(propertyList) -1) # 随机下标
propertyName = propertyList[random2];
propertyList.pop(random2) # 去除相同属性的可能
contents = contents + "@property (nonatomic, readwrite, assign) " + typeName + " *" + propertyName + ";\n"
contents = contents + "\n";
# 添加方法
for i in range(0, 5):
# 随机为1 添加类方法,返回值为strong类型'
if i < 2:
returnTypeName = ocClassStrongList[random.randint(0, len(ocClassStrongList) -1)]
returnTypeList.append(returnTypeName)
thisMethod = "+ " + "(" + returnTypeName + " *)" + headerName.lower() + "_" + low(
nameList[random.randint(0, len(nameList) - 1)]) + "With";
contents = contents + thisMethod;
# 方法名个数
methodNameCount = random.randint(1, 2)
for j in range(0, 3):
if random.randint(0, 1) == 1:
if len(useClass) > 0 and i == 1:
methodTypeName = useClass
else:
methodTypeName = ocClassStrongList[random.randint(0, len(ocClassStrongList) - 1)]
methodName = low(nameList[random.randint(0, len(nameList ) - 1)])
thisMethod = thisMethod + methodName + ":(" + methodTypeName + " *)a" + methodName;
contents = contents + methodName + ":(" + methodTypeName + " *)a" + methodName;
if j != 2:
thisMethod = thisMethod + " "
contents = contents + " ";
else:
if len(useClass) > 0 and i == 1:
methodTypeName = useClass
else:
methodTypeName = ocClassStrongList[random.randint(0, len(ocClassAssignList) - 1)]
methodName = low(nameList[random.randint(0, len(nameList) - 1)])
thisMethod = thisMethod + methodName + ":(" + methodTypeName + " *)a" + methodName
contents = contents + methodName + ":(" + methodTypeName + " *)a" + methodName
if j != 2:
thisMethod = thisMethod + " "
contents = contents + " ";
contents = contents + ";\n"
methodNameList.append(thisMethod)
# 添加实例方法, 返回值为assign类型
else:
returnTypeName = ocClassAssignList[random.randint(0, len(ocClassAssignList) -1)]
returnTypeList.append(returnTypeName)
thisMethod = "- " + "(" + returnTypeName + ")" + headerName.lower() + "_" + low(
nameList[random.randint(0, len(nameList) - 1)]) + "With"
contents = contents + thisMethod
# 方法名个数
for j in range(0, 2):
if random.randint(0, 1) == 1:
methodTypeName = ocClassStrongList[random.randint(0, len(ocClassStrongList) -1)]
methodName = low(nameList[random.randint(0, len(nameList) - 1)])
thisMethod = thisMethod + methodName + ":(" + methodTypeName + " *)a" + methodName
contents = contents + methodName + ":(" + methodTypeName + " *)a" + methodName
if j != 1:
thisMethod = thisMethod + " "
contents = contents + " ";
else:
methodTypeName = ocClassAssignList[random.randint(0, len(ocClassAssignList) -1)]
methodName = low(nameList[random.randint(0, len(nameList) - 1)])
thisMethod = thisMethod + methodName + ":(" + methodTypeName + ")a" + methodName
contents = contents + methodName + ":(" + methodTypeName + ")a" + methodName
if j != 1:
thisMethod = thisMethod + " "
contents = contents + " ";
contents = contents + ";\n"
methodNameList.append(thisMethod)
instanMethodNameList.append(thisMethod)
classMethodDic[hmPathName] = instanMethodNameList;
# print(classMethodDic)
contents = contents + "+ (void)instanceCreateMethod; \n"''
methodNameList.append("+ (void)instanceCreateMethod")
returnTypeList.append("void")
contents = contents + "\n"
contents = contents + "@end"
file.write(contents)
with open(mPath, "w+") as file:
contents = "// \n //" + hmPathName + ".h\n " + "// Meari \n// \n// Created by maj on" + fileCreateTime + ". \n// Copyright © 2019 Meari. All rights reserved. \n // \n"
contents += "#import \""+ hmPathName + ".h\"" + "\n"
contents += "@implementation " + hmPathName + "\n"
# print(returnTypeList)
for i in range(0, len(methodNameList)):
methodName = methodNameList[i]
returnTypeName = returnTypeList[i]
contents = contents + methodName + "{\n"
if returnTypeName == "void":
contents += returnCodeFromMethod(hmPathName)
else:
contents += getOCClassString(returnTypeName, True)[0]
contents += "\n}\n\n"
contents += "\n"
contents = contents + "@end"
file.write(contents)
def changeXcodeproj(hPath: str, mPath: str, hmPathName: str, mExistFile, hExistFile):
# print(os.path.dirname(hPath))
hIdMark = "2222" + "".join(random.sample("ABCDEFGHIJKLMNOPQRSTWXV", 20))
mIdMark1 = "3333" + "".join(random.sample("ABCDEFGHIJKLMNOPQRSTWXV", 20))
mIdMark2 = "4444" + "".join(random.sample("ABCDEFGHIJKLMNOPQRSTWXV", 20))
# print(mExistFile)
if len(mExistFile) > 0:
with open(xcodeprojPath, "r") as file:
allContents = file.readlines()
for i in range(0, len(allContents)):
line = allContents[i]
# 修改.h文件
if hExistFile in line:
newLine = line.replace(hExistFile, (hmPathName + ".h"))
oldID = newLine.split(" /*")[0]
newLine = newLine.replace(oldID, hIdMark)
# print(newLine)
allContents.insert( i + 1, newLine)
# 修改.m文件
if mExistFile in line:
if "PBXBuildFile" in line:
# print("line1", line)
newLine = line.replace(mExistFile, (hmPathName + ".m"))
oldID1 = newLine.split(" /*")[0]
oldID2 = newLine.split(" /*")[1].split("=")[-1]
newLine = newLine.replace(oldID1, mIdMark1).replace(oldID2, mIdMark2)
allContents.insert(i + 1, newLine)
elif len(line.split(" /*")) == 2 and "in Sources" in line:
# print("line2", line)
newLine = line.replace(mExistFile, (hmPathName + ".m"))
oldID1 = newLine.split(" /*")[0]
newLine = newLine.replace(oldID1, mIdMark1)
allContents.insert(i + 1, newLine)
else:
# print("line3", line)
newLine = line.replace(mExistFile, (hmPathName + ".m"))
oldID2 = newLine.split(" /*")[0]
newLine = newLine.replace(oldID2, mIdMark2)
allContents.insert(i + 1, newLine)
with open(xcodeprojPath, "w") as file:
file.write("".join(allContents))
def returnCodeFromMethod(className: str):
if len(classMethodDic[className]) == 0:
print("className", className)
return
method = classMethodDic[className][0]
contents = ""
returnType = method.split(")")[0].split("(")[1].split(" *")[0]
sendTypeList = []
instanceNameList = []
mylist = method.split(")")
for i in range(1, len(mylist)-1):
string = mylist[i].split("(")[1]
if "*" in string:
string = string.split(" *")[0]
sendTypeList.append(string)
# print(sendTypeList)
for methodStr in sendTypeList:
tempArray = getOCClassString(methodStr, False)
contents += tempArray[0]
instanceNameList.append(tempArray[1])
# print(nameList)
name1 = nameList[random.randint(0, len(nameList) - 1)]
contents += className + " *"+ name1 + "= [[" + className + " alloc] init];"
methodList = []
a = method.split(")")
for i in range(1, len(a) - 1):
methodList.append(a[i].split(":")[0].split(" ")[-1])
contents += "\n";
contents += "[" + name1 + " ";
for i in range(0, len(methodList)):
contents += (methodList[i] + ":")
contents += instanceNameList[i] + " "
contents += "];\n"
return contents;
# 循环创建新文件和引用
def createFile(pathSet: set):
for tempPath in pathSet:
random1 = random.randint(0, len(nameList) - 1) # 随机下标
hmPathName = headerName + capitalize(nameList[random1]); # 随机生成 .h .m的文件名称
nameList.pop(random1)
hPath1 = os.path.join(tempPath, hmPathName + ".h")
mPath1 = os.path.join(tempPath, hmPathName + ".m")
# print(path)
for file in os.listdir(os.path.dirname(hPath1)):
if file.endswith(".m"):
mExistFile = file;
hExistFile = mExistFile.split(".")[0] + ".h"
with open(xcodeprojPath, "r") as file:
allContents = file.read()
if mExistFile in allContents and hExistFile in allContents:
break
else:
mExistFile = ""
hExistFile = ""
# print(hPath1, mPath1, hmPathName)
if len(mExistFile) > 0:
changeXcodeproj(hPath1, mPath1, hmPathName, mExistFile, hExistFile)
getContent(hPath1, mPath1, hmPathName)
newFileNameList.append(hmPathName)
#获取创建代码的文件夹
pathSet = set()
for dirpath, dirname, filenames in os.walk(path):
for filename in filenames:
filePath = os.path.join(dirpath, filename)
if filePath.endswith(".h") and "SDK" not in filePath:
pathSet.add(os.path.dirname(filePath))
for i in range(0, classCreateTime):
createFile(pathSet)
# 寻找vc
vcPathSet = set()
print(path)
for dirpath, dirname, filenames in os.walk(path):
for filename in filenames:
filePath = os.path.join(dirpath, filename)
print("path", path)
print("filePath", filePath)
if filePath.endswith(".m"):
with open(filePath, "r") as file:
content = file.read()
# print(content)
if "@interface" in content or "viewDidLoad" in content:
# print(filePath)
vcPathSet.add(filePath)
# 循环往工程中添加垃圾代码
print("vcPathSet", vcPathSet)
for path in vcPathSet:
with open(path, "r") as file:
content = file.readlines()
with open(path, "w") as file:
# 随机import几个垃圾工程
importFile = random.choice(newFileNameList)
importLine = "#import \""+ importFile + ".h\"" + "\n"
content.insert(0, importLine)
# print("content", content)
print(importLine)
insertTime = 0
for i in range(0, len(content)):
line = content[i]
if line.startswith("- (void)") and line.endswith("{\n"):
# print(line)
if random.randint(0,methodInsertTime) == 1:
insertStr = "dispatch_async(dispatch_get_main_queue(), ^{\n" + returnCodeFromMethod(
importFile) + "});\n"
content.insert(i + 1, insertStr)
insertTime += 1
if insertTime == methodInsertTime:
break;
file.write("".join(content))
方法混淆(由于是同事写的代码不方便贴)
属性混淆 (工作量太大, 后面有机会在研究)
3.27号, 经过一周的审核, 上架成功. 后续公司采用了这套混淆代码方案, 已经成功上架10个左右OEM app。
网友评论