美文网首页
python代码混淆

python代码混淆

作者: Maj_sunshine | 来源:发表于2020-03-20 09:52 被阅读0次

    由于近期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。

    相关文章

      网友评论

          本文标题:python代码混淆

          本文链接:https://www.haomeiwen.com/subject/femdyhtx.html