├── CommonDefines.m ├── CommonFunctions.m ├── Makefile ├── ParsingFunctions.m ├── classdumpdyldlib ├── Makefile ├── classdumpdyld.cy └── classdumpdyldlib.xm ├── control ├── ent.plist ├── iphoneos └── classdump-dyld ├── macosx └── usr │ └── local │ ├── bin │ └── classdump-dyld │ └── lib │ └── libclassdumpdyld.dylib ├── main.xm └── readme.md /CommonDefines.m: -------------------------------------------------------------------------------- 1 | #define RESET "\033[0m" 2 | #define BOLDWHITE "\033[1m\033[37m" 3 | #define CLEARSCREEN "\e[1;1H\e[2J" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | static BOOL addHeadersFolder=NO; 18 | static BOOL shouldImportStructs=0; 19 | static NSMutableArray *allStructsFound=nil; 20 | static NSMutableArray *classesInStructs=nil; 21 | static NSMutableArray *classesInClass=nil; 22 | static NSMutableArray *processedImages=nil; 23 | NSString *classID=nil; 24 | NSString *onlyOneClass=nil; 25 | 26 | @interface NSArray (extras) 27 | -(id)reversedArray; 28 | @end 29 | 30 | 31 | const struct dyld_all_image_infos *dyld_all_image_infos; 32 | //extern "C" struct dyld_all_image_infos* _dyld_get_all_image_infos(); 33 | NSString * propertyLineGenerator(NSString *attributes,NSString *name); 34 | NSString * commonTypes(NSString *atype,NSString **inName,BOOL inIvarList); 35 | 36 | 37 | -------------------------------------------------------------------------------- /CommonFunctions.m: -------------------------------------------------------------------------------- 1 | static NSMutableArray *forbiddenClasses=nil; 2 | NSMutableArray *forbiddenPaths=nil; 3 | 4 | 5 | 6 | 7 | struct cache_header { 8 | char version[16]; 9 | uint32_t baseaddroff; 10 | uint32_t unk2; 11 | uint32_t startaddr; 12 | uint32_t numlibs; 13 | uint64_t dyldaddr; 14 | }; 15 | 16 | 17 | BOOL isMachOExecutable(const char *image){ 18 | 19 | FILE *machoFile = fopen (image, "rb"); 20 | if (machoFile == 0){ 21 | return NO; 22 | } 23 | //#ifdef __LP64__ 24 | mach_header_64 machHeader; 25 | //#else 26 | //mach_header machHeader; 27 | //#endif 28 | 29 | int n = fread (&machHeader, sizeof (machHeader), 1, machoFile); 30 | if (n != 1 ){ 31 | fclose(machoFile); 32 | return NO; 33 | } 34 | BOOL isExec = machHeader.filetype == MH_EXECUTE; 35 | 36 | fclose(machoFile); 37 | return isExec; 38 | 39 | } 40 | 41 | BOOL is64BitMachO(const char *image){ 42 | 43 | FILE *machoFile = fopen (image, "rb"); 44 | if (machoFile == 0){ 45 | fclose(machoFile); 46 | return NO; 47 | } 48 | mach_header_64 machHeader; 49 | int n = fread (&machHeader, sizeof (machHeader), 1, machoFile); 50 | if (n != 1){ 51 | 52 | fclose(machoFile); 53 | return NO; 54 | } 55 | BOOL is64=machHeader.magic!=MH_MAGIC; // instead of ==MH_MAGIC_64 56 | fclose(machoFile); 57 | return is64; 58 | 59 | } 60 | 61 | BOOL fileExistsOnDisk(const char *image){ 62 | 63 | FILE *aFile = fopen (image, "r"); 64 | BOOL exists=aFile != 0; 65 | fclose(aFile); 66 | return exists; 67 | 68 | } 69 | 70 | BOOL arch64(){ 71 | 72 | //size_t size; 73 | //sysctlbyname("hw.cpu64bit_capable", NULL, &size, NULL, 0); 74 | //BOOL cpu64bit; 75 | //sysctlbyname("hw.cpu64bit_capable", &cpu64bit, &size, NULL, 0); 76 | //return cpu64bit; 77 | 78 | #ifdef __LP64__ 79 | return YES; 80 | #endif 81 | return NO; 82 | 83 | } 84 | 85 | 86 | 87 | static BOOL priorToiOS7(){ 88 | 89 | return ![objc_getClass("NSProcessInfo") instancesRespondToSelector:@selector(endActivity:)]; 90 | 91 | } 92 | 93 | 94 | NSMutableArray * generateForbiddenClassesArray(BOOL isRecursive){ 95 | 96 | BOOL IOS11=[[[NSProcessInfo processInfo] operatingSystemVersionString] rangeOfString:@"Version 11"].location==0; 97 | BOOL IOS12=[[[NSProcessInfo processInfo] operatingSystemVersionString] rangeOfString:@"Version 12"].location==0; 98 | 99 | forbiddenClasses=[[NSMutableArray alloc] init]; 100 | 101 | if (priorToiOS7()){ 102 | [forbiddenClasses addObject:@"VKRoadGroup"]; 103 | [forbiddenClasses addObject:@"SBApplication"]; 104 | [forbiddenClasses addObject:@"SBSMSApplication"]; 105 | [forbiddenClasses addObject:@"SBFakeNewsstandApplication"]; 106 | [forbiddenClasses addObject:@"SBWebApplication"]; 107 | [forbiddenClasses addObject:@"SBNewsstandApplication"]; 108 | } 109 | 110 | if (isRecursive){ 111 | [forbiddenClasses addObject:@"UIScreen"]; 112 | [forbiddenClasses addObject:@"UICollectionViewData"]; 113 | } 114 | 115 | //iWork related crashing classes 116 | [forbiddenClasses addObject:@"KNSlideStyle"]; 117 | [forbiddenClasses addObject:@"TSWPListStyle"]; 118 | [forbiddenClasses addObject:@"TSWPColumnStyle"]; 119 | [forbiddenClasses addObject:@"TSWPCharacterStyle"]; 120 | [forbiddenClasses addObject:@"TSWPParagraphStyle"]; 121 | [forbiddenClasses addObject:@"TSTTableStyle"]; 122 | [forbiddenClasses addObject:@"TSTCellStyle"]; 123 | [forbiddenClasses addObject:@"TSDMediaStyle"]; 124 | [forbiddenClasses addObject:@"TSDShapeStyle"]; 125 | [forbiddenClasses addObject:@"TSCHStylePasteboardData"]; 126 | [forbiddenClasses addObject:@"OABShapeBaseManager"]; 127 | [forbiddenClasses addObject:@"TSCH3DGLRenderProcessor"]; 128 | [forbiddenClasses addObject:@"TSCH3DAnimationTimeSlice"]; 129 | [forbiddenClasses addObject:@"TSCH3DBarChartDefaultAppearance"]; 130 | [forbiddenClasses addObject:@"TSCH3DGenericAxisLabelPositioner"]; 131 | [forbiddenClasses addObject:@"TSCHChartSeriesNonStyle"]; 132 | [forbiddenClasses addObject:@"TSCHChartAxisNonStyle"]; 133 | [forbiddenClasses addObject:@"TSCHLegendNonStyle"]; 134 | [forbiddenClasses addObject:@"TSCHChartNonStyle"]; 135 | [forbiddenClasses addObject:@"TSCHChartSeriesStyle"]; 136 | [forbiddenClasses addObject:@"TSCHChartAxisStyle"]; 137 | [forbiddenClasses addObject:@"TSCHLegendStyle"]; 138 | [forbiddenClasses addObject:@"TSCHChartStyle"]; 139 | [forbiddenClasses addObject:@"TSCHBaseStyle"]; 140 | 141 | //other classes that crash on opening outside their process 142 | [forbiddenClasses addObject:@"LineServiceManager"]; 143 | [forbiddenClasses addObject:@"GKBubbleFlowBubbleControl"]; 144 | [forbiddenClasses addObject:@"AXBackBoardGlue"]; 145 | [forbiddenClasses addObject:@"TMBackgroundTaskAgent"]; 146 | [forbiddenClasses addObject:@"PLWallpaperAssetAccessibility"]; 147 | [forbiddenClasses addObject:@"MPMusicPlayerController"]; 148 | [forbiddenClasses addObject:@"PUAlbumListCellContentView"]; 149 | [forbiddenClasses addObject:@"SBAXItemChooserTableViewCell"]; 150 | [forbiddenClasses addObject:@"WebPreferences"]; 151 | [forbiddenClasses addObject:@"WebFrameView"]; 152 | [forbiddenClasses addObject:@"VMServiceClient"]; 153 | [forbiddenClasses addObject:@"VKClassicGlobeCanvas"]; 154 | [forbiddenClasses addObject:@"VKLabelModel"]; 155 | [forbiddenClasses addObject:@"UICTFont"]; 156 | [forbiddenClasses addObject:@"UIFont"]; 157 | [forbiddenClasses addObject:@"NSFont"]; 158 | [forbiddenClasses addObject:@"PLImageView"]; 159 | [forbiddenClasses addObject:@"PLPolaroidImageView"]; 160 | [forbiddenClasses addObject:@"MFSMTPConnection"]; 161 | [forbiddenClasses addObject:@"MFConnection"]; 162 | [forbiddenClasses addObject:@"AXSpringBoardSettingsLoader"]; 163 | [forbiddenClasses addObject:@"AXUIActiveWindow"]; 164 | [forbiddenClasses addObject:@"VolumeListener"]; 165 | [forbiddenClasses addObject:@"VKTransitLineMarker"]; 166 | [forbiddenClasses addObject:@"VKLabelMarkerShield"]; 167 | [forbiddenClasses addObject:@"VKImageSourceKey"]; 168 | [forbiddenClasses addObject:@"MMSDK"]; 169 | [forbiddenClasses addObject:@"MDLAsset"]; 170 | [forbiddenClasses addObject:@"MDLCamera"]; 171 | [forbiddenClasses addObject:@"SCNMetalResourceManager"]; 172 | [forbiddenClasses addObject:@"SCNRenderContextImp"]; 173 | [forbiddenClasses addObject:@"SUICFlamesView"]; 174 | [forbiddenClasses addObject:@"WAMediaPickerAsset"]; 175 | [forbiddenClasses addObject:@"FBSDKAppLinkResolver"]; 176 | [forbiddenClasses addObject:@"BFTaskCompletionSource"]; 177 | [forbiddenClasses addObject:@"FilterContext"]; 178 | [forbiddenClasses addObject:@"GMSZoomTable"]; 179 | [forbiddenClasses addObject:@"CardIOCardScanner"]; 180 | [forbiddenClasses addObject:@"LineServiceManager"]; 181 | [forbiddenClasses addObject:@"WAServerProperties"]; 182 | [forbiddenClasses addObject:@"FBGroupPendingStream"]; 183 | [forbiddenClasses addObject:@"FBConsoleGetTagStatuses_result"]; 184 | [forbiddenClasses addObject:@"CLLocationProviderAdapter"]; 185 | [forbiddenClasses addObject:@"AXBackBoardGlue"]; 186 | [forbiddenClasses addObject:@"TMBackgroundTaskAgent"]; 187 | [forbiddenClasses addObject:@"TSCHReferenceLineNonStyle"]; 188 | [forbiddenClasses addObject:@"TSTTableInfo"]; 189 | [forbiddenClasses addObject:@"TSCHReferenceLineStyle"]; 190 | [forbiddenClasses addObject:@"AZSharedUserDefaults"]; 191 | [forbiddenClasses addObject:@"NSLeafProxy"]; 192 | [forbiddenClasses addObject:@"FigIrisAutoTrimmerMotionSampleExport"]; 193 | [forbiddenClasses addObject:@"RCDebugRecordingController"]; 194 | [forbiddenClasses addObject:@"CoreKnowledge.CKInMemoryKnowledgeStorage"]; 195 | [forbiddenClasses addObject:@"CoreKnowledge.CKUserDefaultsKnowledgeStorage"]; 196 | [forbiddenClasses addObject:@"CoreKnowledge.CKSQLKnowledgeStorage"]; 197 | [forbiddenClasses addObject:@"CoreKnowledge.CKEntity"]; 198 | [forbiddenClasses addObject:@"CoreKnowledge.CKKnowledgeStore"]; 199 | [forbiddenClasses addObject:@"JSExport"]; 200 | [forbiddenClasses addObject:@"SBClockApplicationIconImageView"]; 201 | if (IOS11 || IOS12){ 202 | [forbiddenClasses addObject:@"SKTransformNode"]; 203 | [forbiddenClasses addObject:@"OZFxPlugParameterHandler"]; 204 | [forbiddenClasses addObject:@"OZFxPlugParameterHandler_v4"]; 205 | [forbiddenClasses addObject:@"PAETransitionDefaultBase"]; 206 | [forbiddenClasses addObject:@"PAEGeneratorDefaultBase"]; 207 | [forbiddenClasses addObject:@"PAEFilterDefaultBase"]; 208 | [forbiddenClasses addObject:@"MTLToolsDevice"]; 209 | [forbiddenClasses addObject:@"CMMTLDevice"]; 210 | [forbiddenClasses addObject:@"SBReachabilityManager"]; 211 | [forbiddenClasses addObject:@"IGRTCBroadcastSession"]; 212 | [forbiddenClasses addObject:@"FBVideoBroadcastSwitchableSession"]; 213 | [forbiddenClasses addObject:@"FBVideoBroadcastSessionBase"]; 214 | [forbiddenClasses addObject:@"NFSecureElementWrapper"]; 215 | 216 | [forbiddenClasses addObject:@"JTImageView"]; 217 | [forbiddenClasses addObject:@"PNPWizardScratchpadInkView"]; 218 | [forbiddenClasses addObject:@"PFMulticasterDistributionMethods"]; 219 | [forbiddenClasses addObject:@"PFEmbeddedMulticasterImplementation"]; 220 | [forbiddenClasses addObject:@"AAJSON"]; 221 | 222 | } 223 | [forbiddenClasses addObject:@"_UISearchBarVisualProviderIOS"]; 224 | [forbiddenClasses addObject:@"_UISearchBarVisualProviderLegacy"]; 225 | [forbiddenClasses addObject:@"VNFaceObservation"]; 226 | [forbiddenClasses addObject:@"CMMTLDevice"]; 227 | [forbiddenClasses addObject:@"SKTransformNode"]; 228 | [forbiddenClasses addObject:@"AASession"]; 229 | [forbiddenClasses addObject:@"TeaFoundation.DynamicLocale"]; 230 | [forbiddenClasses addObject:@"CoreKnowledge.SRIngestor"]; 231 | [forbiddenClasses addObject:@"CKHistoricEvent"]; 232 | [forbiddenClasses addObject:@"SUICFlamesViewLegacy"]; 233 | [forbiddenClasses addObject:@"SUICFlamesViewMetal"]; 234 | [forbiddenClasses addObject:@"JTImageView"]; 235 | [forbiddenClasses addObject:@"MTLToolsDevice"]; 236 | [forbiddenClasses addObject:@"PNPWizardScratchpadInkView"]; 237 | [forbiddenClasses addObject:@"OZFxPlugParameterHandler"]; 238 | [forbiddenClasses addObject:@"OZFxPlugParameterHandler_v4"]; 239 | [forbiddenClasses addObject:@"PAETransitionDefaultBase"]; 240 | [forbiddenClasses addObject:@"PAEGeneratorDefaultBase"]; 241 | [forbiddenClasses addObject:@"PAEFilterDefaultBase"]; 242 | [forbiddenClasses addObject:@"USKData"]; 243 | [forbiddenClasses addObject:@"USKProperty"]; 244 | [forbiddenClasses addObject:@"NTKPrideLinearQuad"]; 245 | [forbiddenClasses addObject:@"NTKPrideCircularQuad"]; 246 | [forbiddenClasses addObject:@"NTKPrideSplinesQuad"]; 247 | [forbiddenClasses addObject:@"Highlights.FallbackHighlightViewModel"]; 248 | [forbiddenClasses addObject:@"HighlightsHeavy.FallbackHighlightViewModel"]; 249 | 250 | 251 | return forbiddenClasses; 252 | } 253 | 254 | static NSString * copyrightMessage(char *image){ 255 | 256 | NSAutoreleasePool *pool =[[NSAutoreleasePool alloc] init]; 257 | NSString *version = [NSProcessInfo processInfo ].operatingSystemVersionString; 258 | NSLocale *loc=[NSLocale localeWithLocaleIdentifier: @"en-us"]; 259 | NSString *date=[NSDate.date descriptionWithLocale: loc]; 260 | 261 | NSString *message=[[NSString alloc] initWithFormat:@"/*\n\ 262 | * This header is generated by classdump-dyld 1.0\n\ 263 | * on %@\n\ 264 | * Operating System: %@\n\ 265 | * Image Source: %s\n\ 266 | * classdump-dyld is licensed under GPLv3, Copyright \u00A9 2013-2016 by Elias Limneos.\n\ 267 | */\n\n",date,version,image]; 268 | 269 | [pool drain]; 270 | 271 | return message; 272 | 273 | } 274 | 275 | 276 | void printHelp(){ 277 | 278 | printf("\nclassdump-dyld v1.0. Licensed under GPLv3, Copyright \u00A9 2013-2014 by Elias Limneos.\n\n"); 279 | printf("Usage: classdump-dyld [] \n"); 280 | printf(" or\n"); 281 | printf(" classdump-dyld [] -r \n\n"); 282 | 283 | printf("Options:\n\n"); 284 | 285 | 286 | printf(" Structure:\n"); 287 | printf(" -g Generate symbol names file\n"); 288 | printf(" -b Build original directory structure in output dir\n"); 289 | printf(" -h Add a \"Headers\" directory to place headers in\n"); 290 | printf(" -u Do not include framework when importing headers (\"Header.h\" instead of )\n\n"); 291 | 292 | printf(" Output:\n"); 293 | printf(" -o Save generated headers to defined path\n\n"); 294 | 295 | printf(" Mass dumping: (requires -o)\n"); 296 | printf(" -c Dump all images found in dyld_shared_cache\n"); 297 | printf(" -r Recursively dump any compatible Mach-O file found in the given path\n"); 298 | printf(" -s In a recursive dump, skip header files already found in the same output directory\n\n"); 299 | 300 | printf(" Single Class:\n"); 301 | printf(" -j Dump only the specified class name. (Does not work with -c or -r )\n"); 302 | printf(" This might also dump additional imported or required headers.\n\n"); 303 | 304 | printf(" Miscellaneous\n"); 305 | printf(" -D Enable debug printing for troubleshooting errors\n"); 306 | printf(" -e dpopen 32Bit executables instead of injecting them (iOS 5+, use if defaults fail.This will skip any 64bit executable) \n"); 307 | printf(" -a In a recursive dump, include 'Applications' directories (skipped by default) \n\n"); 308 | 309 | printf(" Examples:\n"); 310 | printf(" Example 1: classdump-dyld -o outdir /System/Library/Frameworks/UIKit.framework\n"); 311 | printf(" Example 2: classdump-dyld -o outdir /usr/libexec/backboardd\n"); 312 | printf(" Example 3 (recursive): classdump-dyld -o outdir -c (Dumps all files residing in dyld_shared_cache)\n"); 313 | printf(" Example 4 (recursive): classdump-dyld -o outdir -r /System/Library/\n"); 314 | printf(" Example 5 (recursive): classdump-dyld -o outdir -r / -c (Mass-dumps almost everything on device)\n\n"); 315 | 316 | } 317 | 318 | 319 | static NSString * print_free_memory () { 320 | 321 | mach_port_t host_port; 322 | mach_msg_type_number_t host_size; 323 | vm_size_t pagesize; 324 | 325 | host_port = mach_host_self(); 326 | host_size = sizeof(vm_statistics_data_t) / sizeof(integer_t); 327 | host_page_size(host_port, &pagesize); 328 | 329 | vm_statistics_data_t vm_stat; 330 | 331 | if (host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stat, &host_size) != KERN_SUCCESS){ 332 | //Failed to fetch vm stats 333 | } 334 | natural_t mem_free = vm_stat.free_count * pagesize; 335 | 336 | if (mem_free<10000000){ // break if less than 10MB of RAM 337 | printf("Error: Out of memory. You can repeat with -s option to continue from where left.\n\n"); 338 | exit(0); 339 | } 340 | if (mem_free<20000000){ // warn if less than 20MB of RAM 341 | return [NSString stringWithFormat:@"Low Memory: %u MB free. Might exit to prevent system hang",(mem_free/1024/1024)] ; 342 | } 343 | else{ 344 | return [NSString stringWithCString:"" encoding:NSASCIIStringEncoding]; 345 | //return [NSString stringWithFormat:@"Memory: %u MB free",(mem_free/1024/1024)] ; 346 | } 347 | 348 | } 349 | 350 | 351 | // A nice loading bar. Credits: http://www.rosshemsley.co.uk/2011/02/creating-a-progress-bar-in-c-or-any-other-console-app/ 352 | static inline void loadBar(int x, int n, int r, int w,const char *className) 353 | { 354 | // return; 355 | // Only update r times. 356 | if ((n/r)<1){ 357 | return; 358 | } 359 | if ( x % (n/r) != 0 ) return; 360 | 361 | // Calculuate the ratio of complete-to-incomplete. 362 | float ratio = x/(float)n; 363 | int c = ratio * w; 364 | 365 | // Show the percentage complete. 366 | printf("%3d%% [", (int)(ratio*100) ); 367 | 368 | // Show the load bar. 369 | for (int x=0; x\n\033[F\033[J",[print_free_memory() UTF8String],x,n,className); 378 | } 379 | 380 | 381 | 382 | NSMutableArray * generateForbiddenPathsArray(BOOL isRecursive){ 383 | 384 | forbiddenPaths=[[NSMutableArray alloc] init]; 385 | // The following paths are skipped for known issues that arise when their symbols are added to the flat namespace 386 | 387 | [forbiddenPaths addObject:@"/usr/bin"]; 388 | [forbiddenPaths addObject:@"/Developer"]; 389 | [forbiddenPaths addObject:@"/Library/Switches"]; 390 | [forbiddenPaths addObject:@"SBSettings"]; 391 | [forbiddenPaths addObject:@"Activator"]; 392 | [forbiddenPaths addObject:@"launchd"]; 393 | if (priorToiOS7()){ 394 | [forbiddenPaths addObject:@"/System/Library/Frameworks/PassKit.framework/passd"]; 395 | } 396 | [forbiddenPaths addObject:@"AGXMetal"]; 397 | [forbiddenPaths addObject:@"PhotosUI"]; 398 | [forbiddenPaths addObject:@"AccessibilityUIService"]; 399 | [forbiddenPaths addObject:@"CoreSuggestionsInternals"]; 400 | [forbiddenPaths addObject:@"GameCenterPrivateUI"]; 401 | [forbiddenPaths addObject:@"GameCenterUI"]; 402 | [forbiddenPaths addObject:@"LegacyGameKit"]; 403 | [forbiddenPaths addObject:@"IMAP.framework"]; 404 | [forbiddenPaths addObject:@"POP.framework"]; 405 | [forbiddenPaths addObject:@"Parsec"]; 406 | [forbiddenPaths addObject:@"ZoomTouch"]; 407 | [forbiddenPaths addObject:@"VisualVoicemailUsage"]; 408 | if (isRecursive){ 409 | [forbiddenPaths addObject:@"braille"]; 410 | [forbiddenPaths addObject:@"QuickSpeak"]; 411 | [forbiddenPaths addObject:@"HearingAidUIServer"]; 412 | [forbiddenPaths addObject:@"Mail.siriUIBundle"]; 413 | [forbiddenPaths addObject:@"TTSPlugins"]; 414 | } 415 | [forbiddenPaths addObject:@"AppAnalytics"]; 416 | [forbiddenPaths addObject:@"CoreKnowledge"]; 417 | 418 | 419 | return forbiddenPaths; 420 | } 421 | 422 | 423 | int locationOfString(const char *haystack, const char *needle){ 424 | const char * found = strstr( haystack, needle ); 425 | int anIndex=-1; 426 | if (found != NULL){ 427 | anIndex = found - haystack; 428 | } 429 | return anIndex; 430 | } -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | DEBUG=0 2 | GO_EASY_ON_ME=1 3 | #TARGET = simulator:clang:11.0 4 | #TARGET = macosx 5 | #TARGET = iphone:clang::6.0 6 | export TARGET = iphone:clang:11.2:9.3 7 | export ARCHS=armv7 arm64 arm64e 8 | #export ARCHS=x86_64 9 | include $(THEOS_MAKE_PATH)/common.mk 10 | TOOL_NAME = classdump-dyld 11 | classdump-dyld_FILES = main.xm 12 | classdump-dyld_LDFLAGS = -Wl,-segalign,0x4000 13 | classdump-dyld_CODESIGN_FLAGS = -Sent.plist 14 | include theos/makefiles/tool.mk 15 | include theos/makefiles/library.mk 16 | SUBPROJECTS += classdumpdyldlib 17 | include $(THEOS_MAKE_PATH)/aggregate.mk 18 | -------------------------------------------------------------------------------- /ParsingFunctions.m: -------------------------------------------------------------------------------- 1 | /* Note: NSMethodSignature does not support unions or unknown structs on input. 2 | // However, using NSMethodSignature to break ObjC types apart for parsing seemed to me very convenient. 3 | // My implementation below encodes the unknown structs 4 | // and unions as a special, impossible to conflict struct that is accepted on input. 5 | // They are then decoded back in the output of getArgumentTypeAtIndex: 6 | // This actually adds support for unions and undefined structs. */ 7 | 8 | 9 | @implementation NSMethodSignature (classdump_dyld_helper) 10 | 11 | +(id)cd_signatureWithObjCTypes:(const char *)types{ 12 | 13 | 14 | __block NSString *text=[NSString stringWithCString:types encoding:NSUTF8StringEncoding]; 15 | 16 | while ([text rangeOfString:@"("].location!=NSNotFound){ 17 | 18 | NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"\\(([^\\(\\)]+)\\)" options:nil error:nil]; 19 | 20 | // test if the anticipated union (embraced in parentheseis) is actually a function definition rather than a union 21 | 22 | NSRange range=[text rangeOfString:@"\\(([^\\(\\)]+)\\)" options:NSRegularExpressionSearch]; 23 | NSString *rep=[text substringWithRange:range]; 24 | NSString *testUnion=[rep stringByReplacingOccurrencesOfString:@"(" withString:@"{"]; //just to test if it internally passes as a masqueraded struct 25 | testUnion=[testUnion stringByReplacingOccurrencesOfString:@")" withString:@"}"]; 26 | if ([testUnion rangeOfString:@"="].location==NSNotFound){ 27 | // its a function! 28 | text=[text stringByReplacingOccurrencesOfString:@"(" withString:@"__FUNCTION_START__"]; 29 | text=[text stringByReplacingOccurrencesOfString:@")" withString:@"__FUNCTION_END__"]; 30 | continue; 31 | } 32 | 33 | [regex enumerateMatchesInString:text options:0 34 | range:NSMakeRange(0, [text length]) 35 | usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) 36 | { 37 | 38 | for (int i = 1; i< [result numberOfRanges] ; i++) { 39 | NSString *textFound=[text substringWithRange:[result rangeAtIndex:i]]; 40 | text=[text stringByReplacingOccurrencesOfString:[NSString stringWithFormat:@"(%@)",textFound] withString:[NSString stringWithFormat:@"{union={%@}ficificifloc}",textFound]]; //add an impossible match of types 41 | *stop=YES; 42 | } 43 | }]; 44 | 45 | } 46 | 47 | if ([text rangeOfString:@"{"].location!=NSNotFound){ 48 | 49 | BOOL FOUND=1; 50 | NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"(? *" withString:@">"]; 147 | if ([type rangeOfString:@"<"].location==0){ 148 | type=[@"id" stringByAppendingString:type]; 149 | } 150 | else{ 151 | type=[type stringByReplacingOccurrencesOfString:@"<" withString:@"*<"]; 152 | } 153 | } 154 | } 155 | else if ([type rangeOfString:@"@"].location==0 && [type rangeOfString:@"\""].location==NSNotFound){ 156 | type=@"id"; 157 | } 158 | else{ 159 | type=commonTypes(type,&name,NO); 160 | } 161 | if ([type rangeOfString:@"="].location!=NSNotFound){ 162 | type=[type substringToIndex:[type rangeOfString:@"="].location]; 163 | if ([type rangeOfString:@"_"].location==0){ 164 | 165 | type=[type substringFromIndex:1]; 166 | } 167 | } 168 | 169 | type=[type stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; 170 | attrArr=[NSMutableArray arrayWithArray:attrArr]; 171 | [attrArr removeObjectAtIndex:0]; 172 | NSMutableArray *newPropsArray=[NSMutableArray array]; 173 | NSString *synthesize=@""; 174 | for (NSString *attr in attrArr){ 175 | 176 | NSString *vToClear=nil; 177 | 178 | if ([attr rangeOfString:@"V_"].location==0){ 179 | vToClear=attr; 180 | attr=[attr stringByReplacingCharactersInRange:NSMakeRange(0,2) withString:@""] ; 181 | synthesize=[NSString stringWithFormat:@"\t\t\t\t//@synthesize %@=_%@ - In the implementation block",attr,attr]; 182 | } 183 | 184 | if ([attr length]==1){ 185 | 186 | NSString *translatedProperty = attr; 187 | if ([attr isEqual:@"R"]){ translatedProperty = @"readonly"; } 188 | if ([attr isEqual:@"C"]){ translatedProperty = @"copy"; } 189 | if ([attr isEqual:@"&"]){ translatedProperty = @"retain"; } 190 | if ([attr isEqual:@"N"]){ translatedProperty = @"nonatomic";} 191 | //if ([attr isEqual:@"D"]){ translatedProperty = @"@dynamic"; } 192 | if ([attr isEqual:@"D"]){ continue; } 193 | if ([attr isEqual:@"W"]){ translatedProperty = @"__weak"; } 194 | if ([attr isEqual:@"P"]){ translatedProperty = @"t";} 195 | 196 | 197 | [newPropsArray addObject:translatedProperty]; 198 | } 199 | 200 | if ([attr rangeOfString:@"G"].location==0){ 201 | attr=[attr stringByReplacingCharactersInRange:NSMakeRange(0,1) withString:@""] ; 202 | attr=[NSString stringWithFormat:@"getter=%@",attr]; 203 | [newPropsArray addObject:attr]; 204 | } 205 | 206 | if ([attr rangeOfString:@"S"].location==0){ 207 | attr=[attr stringByReplacingCharactersInRange:NSMakeRange(0,1) withString:@""] ; 208 | attr=[NSString stringWithFormat:@"setter=%@",attr]; 209 | [newPropsArray addObject:attr]; 210 | } 211 | 212 | } 213 | 214 | if ([newPropsArray containsObject:@"nonatomic"] && ![newPropsArray containsObject:@"assign"] && ![newPropsArray containsObject:@"readonly"] && ![newPropsArray containsObject:@"copy"] && ![newPropsArray containsObject:@"retain"]){ 215 | [newPropsArray addObject:@"assign"]; 216 | } 217 | 218 | newPropsArray=[newPropsArray reversedArray]; 219 | 220 | NSString *rebuiltString=[newPropsArray componentsJoinedByString:@","]; 221 | NSString *attrString=[newPropsArray count]>0 ? [NSString stringWithFormat:@"(%@)",rebuiltString] : @"(assign)"; 222 | 223 | 224 | return [[NSString alloc] initWithFormat:@"\n%@%@ %@ %@; %@",@"@property ",attrString,type,name,synthesize]; 225 | 226 | } 227 | 228 | 229 | 230 | 231 | /****** Properties Combined Array (for fixing non-matching types) ******/ 232 | 233 | static NSMutableArray * propertiesArrayFromString(NSString *propertiesString){ 234 | 235 | NSMutableArray *propertiesExploded=[[propertiesString componentsSeparatedByString:@"\n"] mutableCopy]; 236 | NSMutableArray *typesAndNamesArray=[NSMutableArray array]; 237 | 238 | for (NSString *string in propertiesExploded){ 239 | 240 | if (string.length<1){ 241 | continue; 242 | } 243 | 244 | int startlocation=[string rangeOfString:@")"].location; 245 | int endlocation=[string rangeOfString:@";"].location; 246 | if ([string rangeOfString:@";"].location==NSNotFound || [string rangeOfString:@")"].location==NSNotFound){ 247 | continue; 248 | } 249 | 250 | NSString *propertyTypeFound=[string substringWithRange:NSMakeRange(startlocation+1,endlocation-startlocation-1)]; 251 | int firstSpaceLocationBackwards=[propertyTypeFound rangeOfString:@" " options:NSBackwardsSearch].location; 252 | if ([propertyTypeFound rangeOfString:@" " options:NSBackwardsSearch].location==NSNotFound){ 253 | continue; 254 | } 255 | 256 | NSMutableDictionary *typesAndNames=[NSMutableDictionary dictionary]; 257 | 258 | NSString *propertyNameFound=[propertyTypeFound substringFromIndex:firstSpaceLocationBackwards+1]; 259 | propertyTypeFound=[propertyTypeFound substringToIndex:firstSpaceLocationBackwards]; 260 | //propertyTypeFound=[propertyTypeFound stringByReplacingOccurrencesOfString:@" " withString:@""]; 261 | if ([propertyTypeFound rangeOfString:@" "].location==0){ 262 | propertyTypeFound=[propertyTypeFound substringFromIndex:1]; 263 | } 264 | propertyNameFound=[propertyNameFound stringByReplacingOccurrencesOfString:@" " withString:@""]; 265 | 266 | [typesAndNames setObject:propertyTypeFound forKey:@"type"]; 267 | [typesAndNames setObject:propertyNameFound forKey:@"name"]; 268 | [typesAndNamesArray addObject:typesAndNames]; 269 | 270 | } 271 | [propertiesExploded release]; 272 | return typesAndNamesArray; 273 | } 274 | 275 | 276 | 277 | /****** Protocol Parser ******/ 278 | 279 | NSString * buildProtocolFile(Protocol *currentProtocol){ 280 | 281 | NSMutableString * protocolsMethodsString=[[NSMutableString alloc] init]; 282 | 283 | 284 | NSString *protocolName=[NSString stringWithCString:protocol_getName(currentProtocol) encoding:NSUTF8StringEncoding]; 285 | [protocolsMethodsString appendString:[NSString stringWithFormat:@"\n@protocol %@",protocolName]]; 286 | NSMutableArray *classesInProtocol=[[NSMutableArray alloc] init]; 287 | 288 | unsigned int outCount=0; 289 | Protocol ** protList=protocol_copyProtocolList(currentProtocol,&outCount); 290 | 291 | if (outCount>0){ 292 | [protocolsMethodsString appendString:@" <"]; 293 | } 294 | for (int p=0; p0){ 300 | [protocolsMethodsString appendString:@">"]; 301 | } 302 | free(protList); 303 | 304 | NSMutableString *protPropertiesString=[[NSMutableString alloc] init]; 305 | unsigned int protPropertiesCount; 306 | 307 | objc_property_t * protPropertyList=protocol_copyPropertyList(currentProtocol,&protPropertiesCount); 308 | 309 | for (int xi=0; xi1 && [protocolsMethodsString rangeOfString:@"@required"].location==NSNotFound){ 357 | [protocolsMethodsString appendString:@"\n@required\n"]; 358 | } 359 | NSString *startSign=isInstanceMethod==NO ? @"+" : @"-"; 360 | objc_method_description selectorsAndTypes=protMeths[gg]; 361 | SEL selector=selectorsAndTypes.name; 362 | char *types=selectorsAndTypes.types; 363 | NSString *protSelector=NSStringFromSelector(selector); 364 | NSString *finString=@""; 365 | //CDLog(@"\t\t\t\tAbout to call cd_signatureWithObjCTypes of current protocol with types: %s",types); 366 | NSMethodSignature *signature=[NSMethodSignature cd_signatureWithObjCTypes:types]; 367 | //CDLog(@"\t\t\t\tGot cd_signatureWithObjCTypes of current protocol"); 368 | 369 | NSString *returnType=commonTypes([NSString stringWithCString:[signature methodReturnType] encoding:NSUTF8StringEncoding],nil,NO); 370 | 371 | NSArray *selectorsArray=[protSelector componentsSeparatedByString:@":"]; 372 | if (selectorsArray.count>1){ 373 | int argCount=0; 374 | for (unsigned ad=2;ad<[signature numberOfArguments]; ad++){ 375 | argCount++; 376 | NSString *space=ad==[signature numberOfArguments]-1 ? @"" : @" "; 377 | 378 | finString=[finString stringByAppendingString:[NSString stringWithFormat:@"%@:(%@)arg%d%@" ,[selectorsArray objectAtIndex:ad-2],commonTypes([NSString stringWithCString:[signature cd_getArgumentTypeAtIndex:ad] encoding:NSUTF8StringEncoding],nil,NO),argCount,space]]; 379 | } 380 | } 381 | else{ 382 | finString=[finString stringByAppendingString:[NSString stringWithFormat:@"%@" ,[selectorsArray objectAtIndex:0]] ]; 383 | } 384 | finString=[finString stringByAppendingString:@";"]; 385 | [protocolsMethodsString appendString:[NSString stringWithFormat:@"%@(%@)%@\n",startSign,returnType,finString]]; 386 | } 387 | free(protMeths); 388 | 389 | } 390 | 391 | //FIX EQUAL TYPES OF PROPERTIES AND METHODS 392 | NSArray *propertiesArray=propertiesArrayFromString(protPropertiesString); 393 | [protPropertiesString release]; 394 | NSArray *lines=[protocolsMethodsString componentsSeparatedByString:@"\n"]; 395 | NSMutableString *finalString=[[NSMutableString alloc] init]; 396 | for (NSString *line in lines){ 397 | 398 | if (line.length>0 && ([line rangeOfString:@"-"].location==0 || [line rangeOfString:@"+"].location==0)){ 399 | NSString *methodInLine=[line substringFromIndex:[line rangeOfString:@")"].location+1]; 400 | methodInLine=[methodInLine substringToIndex:[methodInLine rangeOfString:@";"].location]; 401 | for (NSDictionary *dict in propertiesArray){ 402 | NSString *propertyName=[dict objectForKey:@"name"]; 403 | if ([methodInLine rangeOfString:@"set"].location!=NSNotFound){ 404 | NSString *firstCapitalized=[[propertyName substringToIndex:1] capitalizedString]; 405 | NSString *capitalizedFirst=[firstCapitalized stringByAppendingString:[propertyName substringFromIndex:1]]; 406 | if ([methodInLine isEqual:[NSString stringWithFormat:@"set%@",capitalizedFirst] ]){ 407 | // replace setter 408 | NSString *newLine=[line substringToIndex:[line rangeOfString:@":("].location+2]; 409 | newLine=[newLine stringByAppendingString:[dict objectForKey:@"type"]]; 410 | newLine=[newLine stringByAppendingString:[line substringFromIndex:[line rangeOfString:@")" options:4].location]]; 411 | line=newLine; 412 | } 413 | } 414 | if ([methodInLine isEqual:propertyName]){ 415 | NSString *newLine=[line substringToIndex:[line rangeOfString:@"("].location+1]; 416 | newLine=[newLine stringByAppendingString:[NSString stringWithFormat:@"%@)%@;",[dict objectForKey:@"type"],[dict objectForKey:@"name"]]]; 417 | line=newLine; 418 | } 419 | } 420 | 421 | } 422 | [finalString appendString:[line stringByAppendingString:@"\n"]]; 423 | 424 | } 425 | 426 | 427 | if ([classesInProtocol count]>0){ 428 | 429 | NSMutableString *classesFoundToAdd=[[NSMutableString alloc] init]; 430 | [classesFoundToAdd appendString:@"@class "]; 431 | for (int f=0; f?:\"|}{"] invertedSet]; 1109 | 1110 | if ([aString rangeOfCharacterFromSet:set].location != NSNotFound) { 1111 | stringContainingType=aString; 1112 | break; 1113 | } 1114 | } 1115 | 1116 | [numberOfArray removeObject:stringContainingType]; 1117 | NSCharacterSet * set =[NSCharacterSet characterSetWithCharactersInString:@"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLKMNOPQRSTUVWXYZ@#$%^&*()!<>?:\"|}{"]; 1118 | int letterLocation=[stringContainingType rangeOfCharacterFromSet:set].location==NSNotFound ? -1 : [stringContainingType rangeOfCharacterFromSet:set].location; 1119 | NSString *outtype=letterLocation==-1 ? stringContainingType : [stringContainingType substringFromIndex:letterLocation]; 1120 | outtype=[outtype stringByReplacingOccurrencesOfString:@"]" withString:@""]; 1121 | stringContainingType=[stringContainingType stringByReplacingOccurrencesOfString:outtype withString:@""]; 1122 | for (NSString *subarr in numberOfArray){ 1123 | stringContainingType=[subarr stringByAppendingString:stringContainingType]; 1124 | } 1125 | atype=outtype; 1126 | if ([atype isEqual:@"v"]){ 1127 | atype=@"void*"; 1128 | } 1129 | if (inName!=nil){ 1130 | *inName=[*inName stringByAppendingString:stringContainingType]; 1131 | } 1132 | } 1133 | } 1134 | 1135 | 1136 | 1137 | if ([atype rangeOfString:@"=}"].location!=NSNotFound && [atype rangeOfString:@"{"].location==0 && [atype rangeOfString:@"?"].location==NSNotFound && [atype rangeOfString:@"\""].location==NSNotFound){ 1138 | shouldImportStructs=1; 1139 | NSString *writeString=[atype stringByReplacingOccurrencesOfString:@"{" withString:@""]; 1140 | writeString=[writeString stringByReplacingOccurrencesOfString:@"}" withString:@""]; 1141 | writeString=[writeString stringByReplacingOccurrencesOfString:@"=" withString:@""]; 1142 | NSString *constString=isConst ? @"const " : @""; 1143 | writeString=[NSString stringWithFormat:@"typedef %@struct %@* ",constString,writeString]; 1144 | 1145 | 1146 | 1147 | atype=[atype stringByReplacingOccurrencesOfString:@"{__" withString:@""] ; 1148 | atype=[atype stringByReplacingOccurrencesOfString:@"{" withString:@""] ; 1149 | atype=[atype stringByReplacingOccurrencesOfString:@"=}" withString:@""] ; 1150 | 1151 | if ([atype rangeOfString:@"_"].location==0){ 1152 | 1153 | atype=[atype substringFromIndex:1]; 1154 | } 1155 | 1156 | BOOL found=NO; 1157 | for (NSDictionary *dict in allStructsFound){ 1158 | if ([[dict objectForKey:@"name"] isEqual:atype] ){ 1159 | found=YES; 1160 | break; 1161 | } 1162 | } 1163 | 1164 | if (!found){ 1165 | writeString=[writeString stringByAppendingString:[NSString stringWithFormat:@"%@Ref;\n\n",representedStructFromStruct(atype,nil,0,NO)]]; 1166 | [allStructsFound addObject:[NSDictionary dictionaryWithObjectsAndKeys:[NSArray arrayWithObject:@""],@"types",writeString,@"representation",atype,@"name",nil]]; 1167 | } 1168 | 1169 | isRef=YES; 1170 | isPointer=NO; // -> Ref 1171 | } 1172 | 1173 | 1174 | 1175 | if ([atype rangeOfString:@"{"].location==0){ 1176 | 1177 | 1178 | if (inName!=nil){ 1179 | atype=representedStructFromStruct(atype,*inName,inIvarList,YES); 1180 | } 1181 | else{ 1182 | atype=representedStructFromStruct(atype,nil,inIvarList,YES); 1183 | } 1184 | if ([atype rangeOfString:@"_"].location==0){ 1185 | atype=[atype substringFromIndex:1]; 1186 | } 1187 | shouldImportStructs=1; 1188 | } 1189 | 1190 | 1191 | if ([atype rangeOfString:@"b"].location==0 && atype.length>1){ 1192 | 1193 | NSCharacterSet *numberSet=[NSCharacterSet characterSetWithCharactersInString:@"0123456789"]; 1194 | if ([atype rangeOfCharacterFromSet:numberSet].location==1){ 1195 | NSString *bitValue=[atype substringFromIndex:1]; 1196 | atype= @"unsigned"; 1197 | if (inName!=nil){ 1198 | *inName=[*inName stringByAppendingString:[NSString stringWithFormat:@" : %@",bitValue]]; 1199 | } 1200 | } 1201 | } 1202 | 1203 | if ([atype rangeOfString:@"N"].location==0 && ![commonTypes([atype substringFromIndex:1],nil,NO) isEqual:[atype substringFromIndex:1]]){ 1204 | 1205 | atype = commonTypes([atype substringFromIndex:1],nil,NO); 1206 | atype=[NSString stringWithFormat:@"inout %@",atype]; 1207 | } 1208 | 1209 | if ([atype isEqual: @"d"]){ atype = @"double"; } 1210 | if ([atype isEqual: @"i"]){ atype = @"int"; } 1211 | if ([atype isEqual: @"f"]){ atype = @"float"; } 1212 | 1213 | if ([atype isEqual: @"c"]){ atype = @"char"; } 1214 | if ([atype isEqual: @"s"]){ atype = @"short"; } 1215 | if ([atype isEqual: @"I"]){ atype = @"unsigned"; } 1216 | if ([atype isEqual: @"l"]){ atype = @"long"; } 1217 | if ([atype isEqual: @"q"]){ atype = @"long long"; } 1218 | if ([atype isEqual: @"L"]){ atype = @"unsigned long"; } 1219 | if ([atype isEqual: @"C"]){ atype = @"unsigned char"; } 1220 | if ([atype isEqual: @"S"]){ atype = @"unsigned short"; } 1221 | if ([atype isEqual: @"Q"]){ atype = @"unsigned long long"; } 1222 | //if ([atype isEqual: @"Q"]){ atype = @"uint64_t"; } 1223 | 1224 | if ([atype isEqual: @"B"]){ atype = @"BOOL"; } 1225 | if ([atype isEqual: @"v"]){ atype = @"void"; } 1226 | if ([atype isEqual: @"*"]){ atype = @"char*"; } 1227 | if ([atype isEqual: @":"]){ atype = @"SEL"; } 1228 | if ([atype isEqual: @"?"]){ atype = @"/*function pointer*/void*"; } 1229 | if ([atype isEqual: @"#"]){ atype = @"Class"; } 1230 | if ([atype isEqual: @"@"]){ atype = @"id"; } 1231 | if ([atype isEqual: @"@?"]){ atype = @"/*^block*/id"; } 1232 | if ([atype isEqual: @"Vv"]){ atype = @"void"; } 1233 | if ([atype isEqual: @"rv"]){ atype = @"const void*"; } 1234 | 1235 | 1236 | 1237 | 1238 | if (isRef){ 1239 | if ([atype rangeOfString:@"_"].location==0){ 1240 | atype=[atype substringFromIndex:1]; 1241 | } 1242 | atype=[atype isEqual:@"NSZone"] ? @"NSZone*" : [atype stringByAppendingString:@"Ref"]; 1243 | } 1244 | 1245 | if (isPointer){ 1246 | atype=[atype stringByAppendingString:@"*"]; 1247 | } 1248 | 1249 | if (isConst){ 1250 | atype=[@"const " stringByAppendingString:atype]; 1251 | } 1252 | 1253 | if (isCArray && inName!=nil){ //more checking to do, some framework were crashing if not nil, shouldn't be nil 1254 | 1255 | *inName=[*inName stringByAppendingString:[NSString stringWithFormat:@"[%d]",arrayCount]]; 1256 | } 1257 | 1258 | if (isOut){ 1259 | atype=[@"out " stringByAppendingString:atype]; 1260 | } 1261 | 1262 | if (isByCopy){ 1263 | atype=[@"bycopy " stringByAppendingString:atype]; 1264 | } 1265 | 1266 | if (isByRef){ 1267 | atype=[@"byref " stringByAppendingString:atype]; 1268 | } 1269 | 1270 | if (isOneWay){ 1271 | atype=[@"oneway " stringByAppendingString:atype]; 1272 | } 1273 | 1274 | 1275 | return atype; 1276 | 1277 | } 1278 | 1279 | /****** Methods Parser ******/ 1280 | 1281 | NSString * generateMethodLines(Class someclass,BOOL isInstanceMethod,NSMutableArray *propertiesArray){ 1282 | 1283 | unsigned int outCount; 1284 | 1285 | NSString *returnString=@""; 1286 | Method * methodsArray=class_copyMethodList(someclass,&outCount); 1287 | 1288 | for (unsigned x=0; x2){ 1319 | NSArray *selValuesArray=[SelectorNameNS componentsSeparatedByString:@":"]; 1320 | for (unsigned i=2; itm_mon], 48 | timeptr->tm_mday, timeptr->tm_hour, 49 | timeptr->tm_min, timeptr->tm_sec,getprogname(),getpid()); 50 | 51 | char logtxt[strlen(sdf)+strlen(timestr)+4]; 52 | sprintf(logtxt,"%s %s\n",timestr,sdf); 53 | fwrite(logtxt,strlen(logtxt),1,p); 54 | fclose(p); 55 | } 56 | 57 | 58 | } 59 | 60 | #define NSLog(...) mylog([[NSString stringWithFormat:__VA_ARGS__] UTF8String]) 61 | 62 | 63 | static const struct dyld_all_image_infos *(*my_dyld_get_all_image_infos)(); 64 | static MSImageRef (*_MSGetImageByName)(const char* name); 65 | static void * (*_MSFindSymbol)(MSImageRef ref,const char* name); 66 | 67 | static void findDyldGetAllImageInfosSymbol(){ 68 | 69 | if (dlsym(RTLD_DEFAULT,"_dyld_get_all_image_infos")){ 70 | 71 | my_dyld_get_all_image_infos=(const struct dyld_all_image_infos*(*)(void))dlsym(RTLD_DEFAULT,"_dyld_get_all_image_infos"); 72 | } 73 | else{ 74 | 75 | unsigned int count; 76 | const char *dyldImage=NULL; 77 | const char **names=objc_copyImageNames(&count); 78 | 79 | for (unsigned int i=0; iinfoArrayCount; i++) { 124 | if (dyld_all_image_infos->infoArray[i].imageLoadAddress!=NULL){ 125 | char *currentImage=(char *)dyld_all_image_infos->infoArray[i].imageFilePath; 126 | if (strlen(currentImage)>0 && strstr(currentImage,image)){ 127 | image=currentImage; 128 | break; 129 | } 130 | } 131 | } 132 | */ 133 | 134 | unsigned int imageCount=0; 135 | const char **imageNames=objc_copyImageNames(&imageCount); 136 | for (int i=0; i0 && strstr(imageName,image)){ 139 | image=(char *)imageName; 140 | break; 141 | } 142 | } 143 | 144 | 145 | 146 | NSMutableString *returnString=[[NSMutableString alloc] init]; 147 | 148 | 149 | BOOL isFramework=NO; 150 | NSMutableString *dumpString=[[NSMutableString alloc] initWithString:@""]; 151 | unsigned int count; 152 | CDLog(@"Getting class count for %s",image); 153 | const char **names = objc_copyClassNamesForImage(image,&count); 154 | CDLog(@"Did return class count %d",count); 155 | if (count){ 156 | printf(" Dumping "BOLDWHITE"%s"RESET"...(%d classes) %s (injected with libclassdumpdyld.dylib) \n",image ,count,[print_free_memory() UTF8String]); 157 | } 158 | 159 | 160 | 161 | BOOL hasWrittenCopyright=NO; 162 | allStructsFound=nil; 163 | allStructsFound=[NSMutableArray array]; 164 | classesInStructs=nil; 165 | classesInStructs=[NSMutableArray array]; 166 | 167 | 168 | NSMutableArray *protocolsAdded=[NSMutableArray array]; 169 | 170 | NSString *imageName=[[NSString stringWithCString:image encoding:NSUTF8StringEncoding] lastPathComponent]; 171 | NSString *fullImageNameInNS=[NSString stringWithCString:image encoding:NSUTF8StringEncoding]; 172 | 173 | 174 | NSString *seeIfIsBundleType=[fullImageNameInNS stringByDeletingLastPathComponent]; 175 | NSString *lastComponent=[seeIfIsBundleType lastPathComponent]; 176 | NSString *targetDir=nil; 177 | if ([lastComponent rangeOfString:@"."].location==NSNotFound){ 178 | targetDir=fullImageNameInNS; 179 | 180 | } 181 | else{ 182 | targetDir=[fullImageNameInNS stringByDeletingLastPathComponent]; 183 | isFramework=YES; 184 | } 185 | NSString *headersFolder=addHeadersFolder ? @"/Headers" : @""; 186 | NSString *writeDir=buildOriginalDirs ? (isFramework ? [NSString stringWithFormat:@"%@/%@%@",outputDir,targetDir,headersFolder] : [NSString stringWithFormat:@"%@/%@",outputDir,targetDir]) : outputDir; 187 | writeDir=[writeDir stringByReplacingOccurrencesOfString:@"///" withString:@"/"]; 188 | writeDir=[writeDir stringByReplacingOccurrencesOfString:@"//" withString:@"/"]; 189 | 190 | [writeDir retain]; 191 | 192 | [processedImages addObject:[NSString stringWithCString:image encoding:NSUTF8StringEncoding]]; 193 | CDLog(@"Beginning class loop (%d classed) for %s",count,image); 194 | if (inCycript){ 195 | NSLog(@"Beginning class loop (%d classed) for %s",count,image); 196 | } 197 | NSMutableString *classesToImport=[[NSMutableString alloc] init]; 198 | 199 | int actuallyProcesssedCount=0; 200 | 201 | for (unsigned i=0; i"]; 308 | } 309 | } 310 | 311 | 312 | 313 | if ( writeToDisk || (!writeToDisk && !hasWrittenCopyright )){ 314 | NSString *copyrightString=copyrightMessage(image); 315 | [dumpString appendString:copyrightString]; 316 | [copyrightString release]; 317 | hasWrittenCopyright=YES; 318 | } 319 | 320 | 321 | if (writeToDisk && superclassString.length>0 && ![superclassString isEqual:@" : NSObject"]){ 322 | NSString *fixedSuperclass=[superclassString stringByReplacingOccurrencesOfString:@" : " withString:@""]; 323 | NSString *importSuper=@""; 324 | if (!simpleHeader){ 325 | NSString *imagePrefix=[imageName substringToIndex:2]; 326 | 327 | NSString *superclassPrefix=[superclassString rangeOfString:@"_"].location==0 ? [[superclassString substringFromIndex:1] substringToIndex:2] : [superclassString substringToIndex:2]; 328 | const char *imageNameOfSuper=[imagePrefix isEqual:superclassPrefix] ? [imagePrefix UTF8String] : class_getImageName(objc_getClass([fixedSuperclass UTF8String])); 329 | if (imageNameOfSuper){ 330 | NSString *imageOfSuper=[NSString stringWithCString:imageNameOfSuper encoding:NSUTF8StringEncoding]; 331 | imageOfSuper=[imageOfSuper lastPathComponent]; 332 | importSuper=[NSString stringWithFormat:@"#import <%@/%@.h>\n",imageOfSuper,fixedSuperclass]; 333 | } 334 | 335 | } 336 | else{ 337 | importSuper=[NSString stringWithFormat:@"#import \"%@.h\"\n",fixedSuperclass]; 338 | } 339 | [dumpString appendString:importSuper]; 340 | } 341 | 342 | 343 | for (unsigned d=0; d\n",imageOfProtocol,protocolNSString]]; 368 | } 369 | 370 | } 371 | if ([protocolsAdded containsObject:protocolNSString]){ 372 | continue; 373 | } 374 | [protocolsAdded addObject:protocolNSString]; 375 | 376 | NSString *protocolHeader=buildProtocolFile(protocol); 377 | 378 | if (strcmp(names[i],protocolName)==0){ 379 | [dumpString appendString:protocolHeader]; 380 | 381 | } 382 | else{ 383 | if (writeToDisk){ 384 | NSString *copyrightString=copyrightMessage(image); 385 | protocolHeader=[copyrightString stringByAppendingString:protocolHeader] ; 386 | [copyrightString release]; 387 | 388 | NSString *targetSaveString=[NSString stringWithFormat:@"@@@@@%@/%s.h&&&&&",writeDir,protocolName]; 389 | [returnString appendString:targetSaveString]; 390 | [returnString appendString:protocolHeader]; 391 | } 392 | else{ 393 | [dumpString appendString:protocolHeader]; 394 | 395 | } 396 | } 397 | 398 | } 399 | free(protocolArray); 400 | 401 | 402 | [dumpString appendString:[NSString stringWithFormat:@"\n@interface %s%@%@",names[i],superclassString,inlineProtocolsString]]; 403 | [inlineProtocolsString release]; 404 | 405 | unsigned int ivarOutCount; 406 | Ivar * ivarArray=class_copyIvarList(currentClass, &ivarOutCount); 407 | if (ivarOutCount>0){ 408 | [dumpString appendString:@" {\n"]; 409 | for (unsigned x=0;x" withString:@""]; 438 | protocolToAdd=[protocolToAdd stringByReplacingOccurrencesOfString:@"*" withString:@""]; 439 | if (![inlineProtocols containsObject:protocolToAdd]){ 440 | [inlineProtocols addObject:protocolToAdd]; 441 | } 442 | 443 | } 444 | else{ 445 | [classesInClass addObject:classFoundInIvars]; 446 | } 447 | } 448 | if ([ivarTypeString rangeOfString:@"<"].location!=NSNotFound){ 449 | ivarTypeString=[ivarTypeString stringByReplacingOccurrencesOfString:@">*" withString:@">"]; 450 | if ([ivarTypeString rangeOfString:@"<"].location==0){ 451 | ivarTypeString=[@"id" stringByAppendingString:ivarTypeString]; 452 | } 453 | else{ 454 | ivarTypeString=[ivarTypeString stringByReplacingOccurrencesOfString:@"<" withString:@"*<"]; 455 | } 456 | } 457 | } 458 | 459 | NSString *formatted=[NSString stringWithFormat:@"\n\t%@ %@;",ivarTypeString,ivarNameNS]; 460 | [dumpString appendString:formatted]; 461 | 462 | } 463 | [dumpString appendString:@"\n\n}"]; 464 | 465 | } 466 | free(ivarArray); 467 | 468 | if ([inlineProtocols count]>0){ 469 | 470 | NSMutableString *inlineProtocolsString=[[NSMutableString alloc] init]; 471 | [inlineProtocolsString appendString:@"@protocol "]; 472 | for (int g=0; glongestLocation){ 520 | longestLocation=location; 521 | } 522 | 523 | } 524 | 525 | NSMutableArray *newStrings=[NSMutableArray array]; 526 | for (NSString *string in synthesized){ 527 | int synthesizeLocation=[string rangeOfString:@"//@synth"].location; 528 | if ([string rangeOfString:@"//@synth"].location==NSNotFound){ 529 | [newStrings addObject:string]; 530 | continue; 531 | } 532 | 533 | NSString *copyString=[string substringFromIndex:synthesizeLocation]; 534 | int location=[string rangeOfString:@";"].location; 535 | string=[string substringToIndex:location+1]; 536 | string=[string stringByPaddingToLength:longestLocation+15 withString:@" " startingAtIndex:0]; 537 | string=[string stringByAppendingString:copyString]; 538 | [newStrings addObject:string]; 539 | } 540 | if (propLenght>0){ 541 | propertiesString=[[[@"\n" stringByAppendingString:[newStrings componentsJoinedByString:@"\n"]] mutableCopy] retain]; 542 | } 543 | 544 | 545 | [dumpString appendString:propertiesString]; 546 | NSString *finalClassMethodLines=generateMethodLines(object_getClass(currentClass),NO,nil); 547 | [dumpString appendString:finalClassMethodLines]; 548 | NSString *finalMethodLines=generateMethodLines(currentClass,YES,propertiesArrayFromString(propertiesString)); 549 | [propertiesString release]; 550 | [dumpString appendString:finalMethodLines]; 551 | [finalClassMethodLines release]; 552 | [finalMethodLines release]; 553 | [dumpString appendString:@"\n@end\n\n"]; 554 | 555 | 556 | 557 | 558 | 559 | if (shouldImportStructs && writeToDisk){ 560 | int firstImport=[dumpString rangeOfString:@"#import"].location!=NSNotFound ? [dumpString rangeOfString:@"#import"].location : [dumpString rangeOfString:@"@interface"].location; 561 | NSString *structImport=simpleHeader ? [NSString stringWithFormat:@"#import \"%@-Structs.h\"\n",imageName] : [NSString stringWithFormat:@"#import <%@/%@-Structs.h>\n",imageName,imageName]; 562 | [dumpString insertString:structImport atIndex:firstImport]; 563 | 564 | } 565 | 566 | if (writeToDisk && [classesInClass count]>0){ 567 | 568 | [classesInClass removeObject:[NSString stringWithCString:names[i] encoding:NSUTF8StringEncoding]]; 569 | if ([classesInClass count]>0){ 570 | int firstInteface=[dumpString rangeOfString:@"@interface"].location; 571 | NSMutableString *classesFoundToAdd=[[NSMutableString alloc] init]; 572 | [classesFoundToAdd appendString:@"@class "]; 573 | for (int f=0; f\n",imageName,names[i]]; 612 | [classesToImport appendString:importStringFrmt]; 613 | } 614 | 615 | objc_destructInstance(currentClass); 616 | if (inCycript && onlyOneClass){ 617 | return [dumpString autorelease]; 618 | } 619 | [dumpString release]; 620 | dumpString=[[NSMutableString alloc] init]; 621 | [pool drain]; 622 | 623 | } 624 | 625 | 626 | if (actuallyProcesssedCount==0 && onlyOneClass){ 627 | printf("\r\n"BOLDWHITE"\t\tlibclassdump-dyld:"RESET" Class \""BOLDWHITE"%s"RESET"\" not found"RESET" in %s\r\n\r\n",[onlyOneClass UTF8String],image); 628 | } 629 | 630 | if (writeToDisk && classesToImport.length>2){ 631 | 632 | NSString *targetSaveString=[NSString stringWithFormat:@"@@@@@%@/%@.h&&&&&",writeDir,imageName]; 633 | [returnString appendString:targetSaveString]; 634 | [returnString appendString:classesToImport]; 635 | 636 | } 637 | [classesToImport release]; 638 | 639 | 640 | CDLog(@"Finished class loop for %s",image); 641 | 642 | 643 | 644 | 645 | 646 | if ([allStructsFound count]>0){ 647 | CDLog(@"Found %lu structs, processing...",(unsigned long)[allStructsFound count]); 648 | NSMutableString *structsString=[[NSMutableString alloc] init]; 649 | if (writeToDisk){ 650 | NSString *copyrightString=copyrightMessage(image); 651 | [structsString appendString:copyrightString]; 652 | [copyrightString release]; 653 | } 654 | 655 | if ([classesInStructs count]>0){ 656 | 657 | [structsString appendString:@"\n@class "]; 658 | for (NSString *string in classesInStructs){ 659 | [structsString appendString:[NSString stringWithFormat:@"%@, ",string]]; 660 | } 661 | structsString=[[[structsString substringToIndex:structsString.length-2] mutableCopy] retain]; 662 | [structsString appendString:@";\n\n"]; 663 | } 664 | 665 | 666 | for (NSDictionary *dict in allStructsFound){ 667 | [structsString appendString:[dict objectForKey:@"representation"]]; 668 | } 669 | if (writeToDisk){ 670 | 671 | NSString *targetSaveString=[NSString stringWithFormat:@"@@@@@%@/%@-Structs.h&&&&&",writeDir,imageName]; 672 | [returnString appendString:targetSaveString]; 673 | [returnString appendString:structsString]; 674 | 675 | } 676 | else{ 677 | printf("\n%s\n",[structsString UTF8String]); 678 | } 679 | CDLog(@"Finished processing structs..."); 680 | [structsString release]; 681 | } 682 | 683 | 684 | 685 | 686 | 687 | if (getSymbols){ 688 | 689 | CDLog(@"In Symbols -> Fetching symbols for %s",image); 690 | 691 | struct mach_header * mh=nil; 692 | struct mach_header_64 * mh64=nil; 693 | 694 | 695 | BOOL is64BitImage=is64BitMachO(image); 696 | 697 | 698 | if (!my_dyld_get_all_image_infos){ 699 | findDyldGetAllImageInfosSymbol(); 700 | } 701 | dyld_all_image_infos = my_dyld_get_all_image_infos(); 702 | for(int i=0; iinfoArrayCount; i++) { 703 | if (dyld_all_image_infos->infoArray[i].imageLoadAddress!=NULL){ 704 | char *currentImage=(char *)dyld_all_image_infos->infoArray[i].imageFilePath; 705 | if (strlen(currentImage)>0 && !strcmp(currentImage,image)){ 706 | 707 | if (is64BitImage){ 708 | mh64 = (struct mach_header_64 *)dyld_all_image_infos->infoArray[i].imageLoadAddress; 709 | } 710 | else{ 711 | mh = (struct mach_header *)dyld_all_image_infos->infoArray[i].imageLoadAddress; 712 | } 713 | break; 714 | } 715 | } 716 | } 717 | 718 | if ((is64BitImage && mh64==nil) | (!is64BitImage && mh==nil)){ 719 | CDLog(@"Currently dlopened image %s not found in _dyld_image_count (?)",image); 720 | } 721 | else{ 722 | 723 | unsigned int file_slide; 724 | NSMutableString *symbolsString=nil; 725 | 726 | 727 | if (!is64BitImage){ 728 | CDLog(@"In Symbols -> Got mach header OK , filetype %d",mh->filetype); 729 | 730 | 731 | 732 | struct segment_command *seg_linkedit = NULL; 733 | struct segment_command *seg_text = NULL; 734 | struct symtab_command *symtab = NULL; 735 | struct load_command *cmd = (struct load_command*)((char*)mh + sizeof(struct mach_header)); 736 | CDLog(@"In Symbols -> Iterating header commands for %s",image); 737 | for (uint32_t index = 0; index < mh->ncmds; index++, cmd = (struct load_command*)((char*)cmd + cmd->cmdsize)) 738 | { 739 | 740 | switch(cmd->cmd) 741 | { 742 | case LC_SEGMENT: 743 | { 744 | 745 | struct segment_command *segmentCommand = (struct segment_command*)(cmd); 746 | if (strncmp(segmentCommand->segname, "__TEXT", sizeof(segmentCommand->segname)) == 0) 747 | { 748 | seg_text = segmentCommand; 749 | 750 | } else if (strncmp(segmentCommand->segname, "__LINKEDIT", sizeof(segmentCommand->segname)) == 0) 751 | { 752 | seg_linkedit = segmentCommand; 753 | } 754 | break; 755 | } 756 | 757 | case LC_SYMTAB: 758 | { 759 | 760 | symtab = (struct symtab_command*)(cmd); 761 | break; 762 | } 763 | 764 | default: 765 | { 766 | break; 767 | } 768 | 769 | } 770 | } 771 | 772 | 773 | if (mh->filetype==MH_DYLIB){ 774 | file_slide = ((unsigned long)seg_linkedit->vmaddr - (unsigned long)seg_text->vmaddr) - seg_linkedit->fileoff; 775 | } 776 | else{ 777 | file_slide = 0; 778 | } 779 | CDLog(@"In Symbols -> Got symtab for %s",image); 780 | struct nlist *symbase = (struct nlist*)((unsigned long)mh + (symtab->symoff + file_slide)); 781 | char *strings = (char*)((unsigned long)mh + (symtab->stroff + file_slide)); 782 | struct nlist *sym; 783 | sym = symbase; 784 | 785 | symbolsString=[[NSMutableString alloc] init]; 786 | NSAutoreleasePool *pp = [[NSAutoreleasePool alloc] init]; 787 | 788 | CDLog(@"In Symbols -> Iteraring symtab"); 789 | for (uint32_t index = 0; index < symtab->nsyms; index += 1, sym += 1) 790 | { 791 | 792 | if ((uint32_t)sym->n_un.n_strx > symtab->strsize) 793 | { 794 | break; 795 | 796 | } else { 797 | 798 | const char *strFound = (char*) (strings + sym->n_un.n_strx); 799 | char *str= strdup(strFound); 800 | if (strcmp(str,"") && strlen(str)>0){ 801 | if (!symbolsString){ 802 | NSString *copyrightString=copyrightMessage(image); 803 | [symbolsString appendString:[copyrightString stringByReplacingOccurrencesOfString:@"This header" withString:@"This output"]]; 804 | [copyrightString release]; 805 | 806 | [symbolsString appendString :[NSString stringWithFormat:@"\nSymbols found in %s:\n%@\n",image,[NSString stringWithCString:str encoding:NSUTF8StringEncoding]]] ; 807 | } 808 | else{ 809 | [symbolsString appendString : [NSString stringWithFormat:@"%s\n",str]] ; 810 | } 811 | 812 | } 813 | free (str); 814 | 815 | } 816 | 817 | } 818 | [pp drain]; 819 | } 820 | 821 | else{ 822 | 823 | CDLog(@"In Symbols -> Got mach header64 OK , filetype %d",mh64->filetype); 824 | 825 | struct segment_command_64 *seg_linkedit = NULL; 826 | struct segment_command_64 *seg_text = NULL; 827 | struct symtab_command *symtab = NULL; 828 | struct load_command *cmd = (struct load_command*)((char*)mh64 + sizeof(struct mach_header_64)); 829 | CDLog(@"In Symbols -> Iterating header64 commands for %s",image); 830 | 831 | for (uint32_t index = 0; index < mh64->ncmds; index++, cmd = (struct load_command*)((char*)cmd + cmd->cmdsize)) 832 | { 833 | 834 | switch(cmd->cmd) 835 | { 836 | case LC_SEGMENT_64: 837 | { 838 | 839 | struct segment_command_64 *segmentCommand = (struct segment_command_64*)(cmd); 840 | if (strncmp(segmentCommand->segname, "__TEXT", sizeof(segmentCommand->segname)) == 0) 841 | { 842 | seg_text = segmentCommand; 843 | 844 | } else if (strncmp(segmentCommand->segname, "__LINKEDIT", sizeof(segmentCommand->segname)) == 0) 845 | { 846 | seg_linkedit = segmentCommand; 847 | } 848 | break; 849 | } 850 | 851 | case LC_SYMTAB: 852 | { 853 | 854 | symtab = (struct symtab_command*)(cmd); 855 | break; 856 | } 857 | 858 | default: 859 | { 860 | break; 861 | } 862 | 863 | } 864 | } 865 | 866 | if (mh64->filetype==MH_DYLIB){ 867 | file_slide = ((unsigned long)seg_linkedit->vmaddr - (unsigned long)seg_text->vmaddr) - seg_linkedit->fileoff; 868 | } 869 | else{ 870 | file_slide = 0; 871 | } 872 | CDLog(@"In Symbols -> Got symtab for %s",image); 873 | struct nlist_64 *symbase = (struct nlist_64*)((unsigned long)mh64 + (symtab->symoff + file_slide)); 874 | char *strings = (char*)((unsigned long)mh64 + (symtab->stroff + file_slide)); 875 | struct nlist_64 *sym; 876 | sym = symbase; 877 | [symbolsString release]; 878 | symbolsString=[[NSMutableString alloc] init]; 879 | NSAutoreleasePool *pp = [[NSAutoreleasePool alloc] init]; 880 | 881 | CDLog(@"In Symbols -> Iteraring symtab"); 882 | for (uint32_t index = 0; index < symtab->nsyms; index += 1, sym += 1) 883 | { 884 | 885 | if ((uint32_t)sym->n_un.n_strx > symtab->strsize) 886 | { 887 | break; 888 | 889 | } else { 890 | 891 | const char *strFound = (char*) (strings + sym->n_un.n_strx); 892 | char *str= strdup(strFound); 893 | if (strcmp(str,"") && strlen(str)>0){ 894 | if (!symbolsString){ 895 | NSString *copyrightString=copyrightMessage(image); 896 | [symbolsString appendString:[copyrightString stringByReplacingOccurrencesOfString:@"This header" withString:@"This output"]]; 897 | [copyrightString release]; 898 | 899 | [symbolsString appendString :[NSString stringWithFormat:@"\nSymbols found in %s:\n%@\n",image,[NSString stringWithCString:str encoding:NSUTF8StringEncoding]]] ; 900 | } 901 | else{ 902 | [symbolsString appendString : [NSString stringWithFormat:@"%s\n",str]] ; 903 | } 904 | 905 | } 906 | free (str); 907 | 908 | } 909 | 910 | } 911 | [pp drain]; 912 | } 913 | 914 | 915 | 916 | CDLog(@"Finished fetching symbols for %s\n: %@",image,symbolsString); 917 | if ([symbolsString length]>0){ 918 | if (writeToDisk){ 919 | 920 | NSString *targetSaveString=[NSString stringWithFormat:@"@@@@@%@/%@-Symbols.h&&&&&",writeDir,imageName]; 921 | [returnString appendString:targetSaveString]; 922 | [returnString appendString:symbolsString]; 923 | 924 | } 925 | else{ 926 | printf("\n%s\n",[symbolsString UTF8String]); 927 | } 928 | } 929 | [symbolsString release]; 930 | } 931 | } 932 | [writeDir release]; 933 | 934 | 935 | free(names); 936 | 937 | return returnString; 938 | 939 | 940 | } 941 | 942 | @interface classdumpdyld : NSObject 943 | @end 944 | 945 | @implementation classdumpdyld 946 | static NSString *parsedResult=nil; 947 | +(id)printResult{ 948 | return parsedResult; 949 | } 950 | @end 951 | 952 | NSString *imagePathForClassName(NSString *className){ 953 | 954 | NSString *imagePath=NULL; 955 | unsigned int count=0; 956 | /*if (!my_dyld_get_all_image_infos){ 957 | findDyldGetAllImageInfosSymbol(); 958 | } 959 | dyld_all_image_infos = my_dyld_get_all_image_infos(); 960 | dyld_all_image_infos = my_dyld_get_all_image_infos(); 961 | for(int i=0; iinfoArrayCount; i++) { 962 | if (dyld_all_image_infos->infoArray[i].imageLoadAddress!=NULL){ 963 | char *currentImage=(char *)dyld_all_image_infos->infoArray[i].imageFilePath; 964 | const char **names = objc_copyClassNamesForImage((const char *)currentImage,&count); 965 | for (int i=0; i2){ 1061 | 1062 | NSLog(@"libclassdumpdyld: Writing headers to disk..."); 1063 | 1064 | } 1065 | 1066 | for (unsigned i=0; i<[things count]; i++){ 1067 | 1068 | @autoreleasepool{ 1069 | 1070 | NSString *thing=[things objectAtIndex:i]; 1071 | 1072 | if (thing.length>0){ 1073 | NSError *createError=nil; 1074 | 1075 | NSString *filePath=[thing substringToIndex:[thing rangeOfString:@"&&&&&"].location]; 1076 | thing=[thing substringFromIndex:[thing rangeOfString:@"&&&&&"].location+5]; 1077 | NSString *dirtosave=[filePath stringByDeletingLastPathComponent]; 1078 | 1079 | 1080 | [[NSFileManager defaultManager] createDirectoryAtPath:dirtosave withIntermediateDirectories:YES attributes:nil error:&createError]; 1081 | FILE * pFile; 1082 | pFile = fopen ([filePath UTF8String],"w"); 1083 | 1084 | if (pFile!=NULL){ 1085 | fputs ([thing UTF8String],pFile); 1086 | fclose (pFile); 1087 | } 1088 | else{ 1089 | 1090 | } 1091 | } 1092 | 1093 | } 1094 | 1095 | } 1096 | 1097 | [things release]; 1098 | 1099 | 1100 | return [NSString stringWithFormat:@"Wrote all headers to %@",outputDir]; 1101 | 1102 | 1103 | } 1104 | 1105 | 1106 | extern "C" NSString * dumpBundle(NSBundle *aBundle){ 1107 | 1108 | onlyOneClass=nil; 1109 | 1110 | if (![aBundle isKindOfClass:objc_getClass("NSBundle")]){ 1111 | return [NSString stringWithFormat:@"Not a bundle '%@'",aBundle]; 1112 | } 1113 | if (![aBundle isLoaded]){ 1114 | BOOL loaded=[aBundle load]; 1115 | if (!loaded){ 1116 | return [NSString stringWithFormat:@"Can't load bundle '%@'",[aBundle bundleIdentifier]]; 1117 | } 1118 | } 1119 | 1120 | generateForbiddenClassesArray(NO); 1121 | NSString *imagePath=[aBundle executablePath]; 1122 | NSString *savePath=[[NSFileManager defaultManager] isWritableFileAtPath:@"/tmp"] ? @"/tmp" : [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]; 1123 | NSString *outputDir=[NSString stringWithFormat:@"%@/%@",savePath,[[[aBundle bundlePath] lastPathComponent] stringByDeletingPathExtension] ?: [aBundle principalClass]]; 1124 | NSError *error=NULL; 1125 | BOOL isDir=NO; 1126 | [[NSFileManager defaultManager] fileExistsAtPath:outputDir isDirectory:&isDir]; 1127 | if (!isDir){ 1128 | [[NSFileManager defaultManager] createDirectoryAtPath:outputDir withIntermediateDirectories:NO attributes:nil error:&error]; 1129 | if (error){ 1130 | return [error description]; 1131 | } 1132 | } 1133 | 1134 | NSString *result=parseImage((char *)[imagePath UTF8String],YES,outputDir,NO,NO,NO,NO,NO); 1135 | 1136 | NSArray *things=[[result componentsSeparatedByString:@"@@@@@"] retain]; 1137 | [result release]; 1138 | 1139 | int total=[things count]; 1140 | 1141 | if (total>2){ 1142 | 1143 | NSLog(@"libclassdumpdyld: Writing headers to disk..."); 1144 | 1145 | } 1146 | 1147 | for (unsigned i=0; i<[things count]; i++){ 1148 | 1149 | @autoreleasepool{ 1150 | 1151 | NSString *thing=[things objectAtIndex:i]; 1152 | 1153 | if (thing.length>0){ 1154 | NSError *createError=nil; 1155 | 1156 | NSString *filePath=[thing substringToIndex:[thing rangeOfString:@"&&&&&"].location]; 1157 | thing=[thing substringFromIndex:[thing rangeOfString:@"&&&&&"].location+5]; 1158 | NSString *dirtosave=[filePath stringByDeletingLastPathComponent]; 1159 | 1160 | 1161 | [[NSFileManager defaultManager] createDirectoryAtPath:dirtosave withIntermediateDirectories:YES attributes:nil error:&createError]; 1162 | FILE * pFile; 1163 | pFile = fopen ([filePath UTF8String],"w"); 1164 | 1165 | if (pFile!=NULL){ 1166 | fputs ([thing UTF8String],pFile); 1167 | fclose (pFile); 1168 | } 1169 | else{ 1170 | 1171 | } 1172 | } 1173 | 1174 | } 1175 | 1176 | } 1177 | 1178 | [things release]; 1179 | 1180 | 1181 | return [NSString stringWithFormat:@"Wrote all headers to %@",outputDir]; 1182 | 1183 | 1184 | } 1185 | 1186 | 1187 | 1188 | 1189 | 1190 | 1191 | 1192 | 1193 | 1194 | 1195 | 1196 | 1197 | 1198 | 1199 | 1200 | 1201 | 1202 | 1203 | 1204 | 1205 | 1206 | 1207 | 1208 | 1209 | @interface MyThing : NSObject 1210 | @end 1211 | 1212 | @implementation MyThing 1213 | +(void)dumpAllFrameworks{ 1214 | 1215 | NSString *frameworks=[[NSBundle bundleWithIdentifier:@"com.apple.UIKit"] bundlePath]; 1216 | frameworks=[frameworks substringToIndex:[frameworks rangeOfString:@"UIKit.framework"].location]; 1217 | NSString *privateFrameworks=[frameworks stringByReplacingOccurrencesOfString:@"/Frameworks" withString:@"/PrivateFrameworks"]; 1218 | 1219 | NSArray *frameworksList=[[NSFileManager defaultManager] contentsOfDirectoryAtPath:frameworks error:nil]; 1220 | NSArray *privateFrameworksList=[[NSFileManager defaultManager] contentsOfDirectoryAtPath:privateFrameworks error:nil]; 1221 | 1222 | for (NSString *currentFramework in frameworksList){ 1223 | NSString *currentBundlePath=[frameworks stringByAppendingString:[NSString stringWithFormat:@"/%@",currentFramework]]; 1224 | currentBundlePath=[currentBundlePath stringByReplacingOccurrencesOfString:@"//" withString:@"/"]; 1225 | dumpBundle([NSBundle bundleWithPath:currentBundlePath]); 1226 | } 1227 | for (NSString *currentFramework in privateFrameworksList){ 1228 | NSString *currentBundlePath=[privateFrameworks stringByAppendingString:[NSString stringWithFormat:@"/%@",currentFramework]]; 1229 | currentBundlePath=[currentBundlePath stringByReplacingOccurrencesOfString:@"//" withString:@"/"]; 1230 | dumpBundle([NSBundle bundleWithPath:currentBundlePath]); 1231 | } 1232 | } 1233 | @end 1234 | 1235 | 1236 | static __attribute__((constructor)) void xs3dax3dax(){ 1237 | 1238 | //dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.05 * NSEC_PER_SEC),dispatch_get_main_queue(),^{ 1239 | 1240 | NSLog(@"INSIDE PROCESS..."); 1241 | 1242 | 1243 | @autoreleasepool { 1244 | 1245 | char * image=nil; 1246 | BOOL writeToDisk=NO; 1247 | BOOL buildOriginalDirs=NO; 1248 | BOOL skipAlreadyFound=NO; 1249 | BOOL simpleHeader=NO; 1250 | BOOL getSymbols=NO; 1251 | BOOL isRecursive=NO; 1252 | 1253 | 1254 | NSString *outputDir=nil; 1255 | 1256 | //NSLog(@"INSIDE PROCESS... argc %d argv[0] %s",argc,argv[0]); 1257 | 1258 | /*findDyldGetAllImageInfosSymbol(); 1259 | 1260 | dyld_all_image_infos = my_dyld_get_all_image_infos(); 1261 | for(int i=0; iinfoArrayCount; i++) { 1262 | if (dyld_all_image_infos->infoArray[i].imageLoadAddress!=NULL){ 1263 | char *currentImage=(char *)dyld_all_image_infos->infoArray[i].imageFilePath; 1264 | if (strlen(currentImage)>0 && strstr(currentImage,"libcycript")){ 1265 | inCycript=YES; 1266 | break; 1267 | } 1268 | } 1269 | }*/ 1270 | unsigned int imageCount=0; 1271 | const char **imageNames=objc_copyImageNames(&imageCount); 1272 | for (int i=0; i0 && (strstr(imageName,"libcycript") || strstr(imageName,"liblimshell"))){ 1275 | inCycript=YES; 1276 | break; 1277 | } 1278 | } 1279 | 1280 | 1281 | inCycript=inCycript && image==nil; 1282 | 1283 | NSString *currentDir=[[[NSProcessInfo processInfo] environment] objectForKey:@"PWD"]; 1284 | 1285 | if (!inCycript){ 1286 | 1287 | 1288 | 1289 | 1290 | 1291 | NSMutableArray *arguments=[[[NSProcessInfo processInfo] arguments] mutableCopy]; 1292 | 1293 | 1294 | if (!image){ 1295 | // we're probably inside a process by post-running injection 1296 | 1297 | image=(char*)[[[NSBundle mainBundle] executablePath] UTF8String]; 1298 | [arguments removeObject:@"-o"]; 1299 | [arguments addObject:@"-o"]; 1300 | NSString *docs=NULL; 1301 | 1302 | docs=[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]; 1303 | docs=[docs stringByAppendingString:[NSString stringWithFormat:@"/%@-classdump-dyld",[[[NSBundle mainBundle] executablePath] lastPathComponent] ]]; 1304 | 1305 | //[arguments addObject:[NSString stringWithFormat:@"/var/mobile/Library/Logs/awd/%@-classdump-dyld",[[[NSBundle mainBundle] executablePath] lastPathComponent] ]]; 1306 | [arguments addObject:docs]; 1307 | [arguments addObject:@"-D"]; 1308 | } 1309 | 1310 | 1311 | 1312 | NSMutableArray *argumentsToUse=[arguments mutableCopy]; 1313 | 1314 | int argCount=[arguments count]; 1315 | 1316 | if (argCount<1){ 1317 | printHelp(); 1318 | exit(0); 1319 | } 1320 | 1321 | for (NSString *arg in arguments){ 1322 | 1323 | if ([arg isEqual:@"-o"]){ 1324 | 1325 | int argIndex=[arguments indexOfObject:arg]; 1326 | 1327 | if (argIndex==argCount-1){ 1328 | printHelp(); 1329 | exit(0); 1330 | } 1331 | 1332 | outputDir=[arguments objectAtIndex:argIndex+1]; 1333 | 1334 | if ([outputDir rangeOfString:@"-"].location==0){ 1335 | printHelp(); 1336 | exit(0); 1337 | } 1338 | writeToDisk=YES; 1339 | [argumentsToUse removeObject:arg]; 1340 | [argumentsToUse removeObject:outputDir]; 1341 | 1342 | 1343 | } 1344 | 1345 | if ([arg isEqual:@"-j"]){ 1346 | 1347 | int argIndex=[arguments indexOfObject:arg]; 1348 | 1349 | if (argIndex==argCount-1){ 1350 | printHelp(); 1351 | exit(0); 1352 | } 1353 | 1354 | onlyOneClass=[[arguments objectAtIndex:argIndex+1] retain]; 1355 | 1356 | if ([onlyOneClass rangeOfString:@"-"].location==0){ 1357 | printHelp(); 1358 | exit(0); 1359 | } 1360 | 1361 | [argumentsToUse removeObject:arg]; 1362 | [argumentsToUse removeObject:onlyOneClass]; 1363 | 1364 | 1365 | } 1366 | 1367 | 1368 | if ([arg isEqual:@"-b"]){ 1369 | buildOriginalDirs=YES; 1370 | [argumentsToUse removeObject:arg]; 1371 | 1372 | } 1373 | 1374 | if ([arg isEqual:@"-r"]){ 1375 | isRecursive=YES; 1376 | [argumentsToUse removeObject:arg]; 1377 | 1378 | } 1379 | 1380 | if ([arg isEqual:@"-g"]){ 1381 | getSymbols=YES; 1382 | [argumentsToUse removeObject:arg]; 1383 | 1384 | } 1385 | 1386 | if ([arg isEqual:@"-u"]){ 1387 | simpleHeader=YES; 1388 | [argumentsToUse removeObject:arg]; 1389 | } 1390 | 1391 | if ([arg isEqual:@"-h"]){ 1392 | addHeadersFolder=YES; 1393 | [argumentsToUse removeObject:arg]; 1394 | } 1395 | if ([arg isEqual:@"-s"]){ 1396 | skipAlreadyFound=YES; 1397 | [argumentsToUse removeObject:arg]; 1398 | } 1399 | if ([arg isEqual:@"-D"]){ 1400 | inDebug=YES; 1401 | [argumentsToUse removeObject:arg]; 1402 | } 1403 | 1404 | if ([arg isEqual:@"-x"]){ 1405 | 1406 | int argIndex=[arguments indexOfObject:arg]; 1407 | 1408 | if (argIndex==argCount-1){ 1409 | printHelp(); 1410 | exit(0); 1411 | } 1412 | 1413 | int nextEntriesCount=[arguments count]-argIndex-1; 1414 | int next=1; 1415 | while (nextEntriesCount){ 1416 | NSString *forbiddenClassAdd=[arguments objectAtIndex:argIndex+next]; 1417 | next++; 1418 | nextEntriesCount--; 1419 | if ([forbiddenClassAdd rangeOfString:@"-"].location==0){ 1420 | nextEntriesCount=0; 1421 | break; 1422 | } 1423 | if (!forbiddenClasses){ 1424 | generateForbiddenClassesArray(isRecursive); 1425 | } 1426 | [forbiddenClasses addObject:forbiddenClassAdd]; 1427 | [argumentsToUse removeObject:forbiddenClassAdd]; 1428 | 1429 | } 1430 | 1431 | [argumentsToUse removeObject:arg]; 1432 | 1433 | } 1434 | 1435 | 1436 | } 1437 | 1438 | if (addHeadersFolder && !outputDir){ 1439 | printHelp(); 1440 | exit(0); 1441 | } 1442 | 1443 | 1444 | if ([argumentsToUse count]>0){ 1445 | image=(char *)[[argumentsToUse objectAtIndex:0] UTF8String]; 1446 | } 1447 | else{ 1448 | printHelp(); 1449 | // exit(0); 1450 | } 1451 | 1452 | 1453 | if (!forbiddenClasses){ 1454 | generateForbiddenClassesArray(isRecursive); 1455 | } 1456 | 1457 | if (image){ 1458 | 1459 | NSError *error=nil; 1460 | NSFileManager *fileman=[[NSFileManager alloc ] init]; 1461 | NSString *imageString=nil; 1462 | if (outputDir){ 1463 | 1464 | [fileman createDirectoryAtPath:outputDir withIntermediateDirectories:YES attributes:nil error:&error]; 1465 | if (error){ 1466 | NSLog(@"Could not create directory %@. Check permissions.",outputDir); 1467 | outputDir=@"/tmp/classdump-dyld"; 1468 | error=NULL; 1469 | [fileman createDirectoryAtPath:outputDir withIntermediateDirectories:YES attributes:nil error:&error]; 1470 | if (error){ 1471 | NSLog(@"Could not create directory %@. Check permissions. Exiting...",outputDir); 1472 | exit(EXIT_FAILURE); 1473 | } 1474 | } 1475 | [fileman changeCurrentDirectoryPath:currentDir]; 1476 | 1477 | [fileman changeCurrentDirectoryPath:outputDir]; 1478 | 1479 | outputDir=[fileman currentDirectoryPath]!=nil ? [fileman currentDirectoryPath] : outputDir; 1480 | 1481 | if (![fileman currentDirectoryPath]){ 1482 | printf(" Error: Injected application cannot write to %s, please change your output directory (you can use your user directory, e.g. /var/root/%s )",[outputDir UTF8String],[[outputDir lastPathComponent] UTF8String]); 1483 | exit(0); 1484 | } 1485 | imageString=[NSString stringWithCString:image encoding:NSUTF8StringEncoding]; 1486 | 1487 | if ([imageString rangeOfString:@"/"].location!=0){ 1488 | 1489 | [fileman changeCurrentDirectoryPath:currentDir]; 1490 | NSString *append=[imageString lastPathComponent]; 1491 | NSString *source=[imageString stringByDeletingLastPathComponent]; 1492 | [fileman changeCurrentDirectoryPath:source]; 1493 | imageString=[[fileman currentDirectoryPath] stringByAppendingString:[NSString stringWithFormat:@"/%@",append]]; 1494 | image=(char *)[imageString UTF8String]; 1495 | 1496 | } 1497 | } 1498 | 1499 | NSString *result=parseImage(image,writeToDisk,outputDir,getSymbols,NO,buildOriginalDirs,simpleHeader,skipAlreadyFound); 1500 | 1501 | 1502 | 1503 | if (writeToDisk){ 1504 | 1505 | 1506 | NSArray *things=[[result componentsSeparatedByString:@"@@@@@"] retain]; 1507 | [result release]; 1508 | 1509 | int total=[things count]; 1510 | 1511 | if (total>2){ 1512 | 1513 | printf(" Writing "BOLDWHITE"%s"RESET" headers to disk...\n",image); 1514 | 1515 | } 1516 | 1517 | for (unsigned i=0; i<[things count]; i++){ 1518 | 1519 | @autoreleasepool{ 1520 | 1521 | NSString *thing=[things objectAtIndex:i]; 1522 | 1523 | if (thing.length>0){ 1524 | NSError *createError=nil; 1525 | 1526 | NSString *filePath=[thing substringToIndex:[thing rangeOfString:@"&&&&&"].location]; 1527 | thing=[thing substringFromIndex:[thing rangeOfString:@"&&&&&"].location+5]; 1528 | NSString *dirtosave=[filePath stringByDeletingLastPathComponent]; 1529 | 1530 | loadBar(i,total, 100, 50,[[filePath lastPathComponent] UTF8String]); 1531 | [[NSFileManager defaultManager] createDirectoryAtPath:dirtosave withIntermediateDirectories:YES attributes:nil error:&createError]; 1532 | FILE * pFile; 1533 | pFile = fopen ([filePath UTF8String],"w"); 1534 | 1535 | if (pFile!=NULL){ 1536 | fputs ([thing UTF8String],pFile); 1537 | fclose (pFile); 1538 | } 1539 | else{ 1540 | 1541 | } 1542 | } 1543 | 1544 | } 1545 | 1546 | } 1547 | 1548 | [things release]; 1549 | 1550 | } 1551 | printf(" All done for "BOLDWHITE"%s"RESET"\n",image); 1552 | 1553 | [fileman release]; 1554 | } 1555 | 1556 | exit(0); 1557 | 1558 | } 1559 | 1560 | 1561 | } 1562 | 1563 | //}); 1564 | 1565 | 1566 | 1567 | } 1568 | 1569 | 1570 | 1571 | -------------------------------------------------------------------------------- /control: -------------------------------------------------------------------------------- 1 | Package: net.limneos.classdump-dyld 2 | Name: classdump-dyld 3 | Version: 1.1 4 | Architecture: iphoneos-arm 5 | Description: Class-dump most images on device or shared cache 6 | Author: Elias Limneos 7 | Section: System 8 | Tag: purpose::extension, role::developer 9 | dev: limneos 10 | -------------------------------------------------------------------------------- /ent.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | platform-application 6 | 7 | com.apple.springboard-ui.client 8 | 9 | com.apple.private.skip-library-validation 10 | 11 | com.apple.springboard.remote-alert 12 | 13 | com.apple.springboard.manageicons 14 | 15 | com.apple.private.security.container-required 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /iphoneos/classdump-dyld: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limneos/classdump-dyld/31b6f9d897ed12065d9d30cc3aba548c892407f5/iphoneos/classdump-dyld -------------------------------------------------------------------------------- /macosx/usr/local/bin/classdump-dyld: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limneos/classdump-dyld/31b6f9d897ed12065d9d30cc3aba548c892407f5/macosx/usr/local/bin/classdump-dyld -------------------------------------------------------------------------------- /macosx/usr/local/lib/libclassdumpdyld.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limneos/classdump-dyld/31b6f9d897ed12065d9d30cc3aba548c892407f5/macosx/usr/local/lib/libclassdumpdyld.dylib -------------------------------------------------------------------------------- /main.xm: -------------------------------------------------------------------------------- 1 | /* 2 | classdump-dyld is free software: you can redistribute it and/or modify 3 | it under the terms of the GNU General Public License as published by 4 | the Free Software Foundation, either version 3 of the License, or 5 | any later version. 6 | 7 | classdump-dyld is distributed in the hope that it will be useful, 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | GNU General Public License for more details. 11 | */ 12 | 13 | static BOOL inDebug=NO; 14 | static BOOL isIOS11=NO; 15 | 16 | #define CDLog(...) if (inDebug)NSLog(@"classdump-dyld : %@", [NSString stringWithFormat:__VA_ARGS__] ) 17 | 18 | #include "CommonDefines.m" 19 | 20 | extern "C" int parseImage(char *image,BOOL writeToDisk,NSString *outputDir,BOOL getSymbols,BOOL isRecursive,BOOL buildOriginalDirs,BOOL simpleHeader,BOOL skipAlreadyFound,BOOL skipApplications,int percent); 21 | 22 | static void list_dir(const char *dir_name,BOOL writeToDisk,NSString *outputDir,BOOL getSymbols,BOOL recursive,BOOL simpleHeader,BOOL skipAlreadyFound,BOOL skipApplications); 23 | static NSMutableArray *allImagesProcessed; 24 | static uint8_t *_cacheData; 25 | static struct cache_header *_cacheHead; 26 | static BOOL shouldDLopen32BitExecutables=NO; 27 | 28 | 29 | /****** Helper Functions ******/ 30 | #include "CommonFunctions.m" 31 | 32 | /****** Parsing Functions ******/ 33 | #include "ParsingFunctions.m" 34 | 35 | 36 | 37 | 38 | typedef void *MSImageRef; 39 | //#include "substrate.h" 40 | 41 | static const struct dyld_all_image_infos *(*my_dyld_get_all_image_infos)(); 42 | static MSImageRef (*_MSGetImageByName)(const char* name); 43 | static void * (*_MSFindSymbol)(MSImageRef ref,const char* name); 44 | 45 | static void findDyldGetAllImageInfosSymbol(){ 46 | if (dlsym(RTLD_DEFAULT,"_dyld_get_all_image_infos")){ 47 | my_dyld_get_all_image_infos=(const struct dyld_all_image_infos*(*)(void))dlsym(RTLD_DEFAULT,"_dyld_get_all_image_infos"); 48 | } 49 | else{ 50 | // find libdyld.dylib ... 51 | unsigned int count; 52 | const char *dyldImage=NULL; 53 | const char **names=objc_copyImageNames(&count); 54 | for (unsigned int i=0; id_type == DT_LNK){ 107 | entry = readdir (d); 108 | 109 | } 110 | if (! entry) { 111 | break; 112 | } 113 | 114 | printf(" Scanning dir: %s...",dir_name); 115 | printf("\n\033[F\033[J"); 116 | 117 | while (entry && (entry->d_type & DT_DIR) && ( locationOfString(dir_name,[outputDir UTF8String])==0 || ((locationOfString(dir_name,"/private/var")==0 || locationOfString(dir_name,"/var")==0 || locationOfString(dir_name,"//var")==0 || locationOfString(dir_name,"//private/var")==0) && (skipApplications || (!skipApplications && !strstr(dir_name,"Application")))) || locationOfString(dir_name,"//dev")==0 || locationOfString(dir_name,"//bin")==0 || locationOfString(dir_name,"/dev")==0 || locationOfString(dir_name,"/bin")==0 )) { 118 | entry = readdir (d); 119 | } 120 | 121 | 122 | if (! entry) { 123 | break; 124 | } 125 | d_name = entry->d_name; 126 | 127 | if (strcmp(d_name,".") && strcmp(d_name,"..")){ 128 | 129 | NSAutoreleasePool *p=[[NSAutoreleasePool alloc] init]; 130 | if (!dir_name){ 131 | printf("\n stringWithCString dir_name empty \n"); 132 | } 133 | NSString *currentPath=[NSString stringWithCString:dir_name encoding:NSUTF8StringEncoding]; 134 | currentPath=[currentPath stringByReplacingOccurrencesOfString:@"//" withString:@"/"]; 135 | if (!d_name){ 136 | printf("\n stringWithCString d_name empty \n"); 137 | } 138 | 139 | NSString *currentFile=[NSString stringWithCString:d_name encoding:NSUTF8StringEncoding]; 140 | NSString *imageToPass=[NSString stringWithFormat:@"%@/%@",currentPath,currentFile]; 141 | 142 | if ([imageToPass rangeOfString:@"classdump-dyld"].location==NSNotFound && [imageToPass rangeOfString:@"/dev"].location!=0 && [imageToPass rangeOfString:@"/bin"].location!=0){ 143 | 144 | NSString *imageWithoutLastPart=[imageToPass stringByDeletingLastPathComponent]; 145 | 146 | if ([[imageWithoutLastPart lastPathComponent] rangeOfString:@".app"].location!=NSNotFound || [[imageWithoutLastPart lastPathComponent] rangeOfString:@".framework"].location!=NSNotFound || [[imageWithoutLastPart lastPathComponent] rangeOfString:@".bundle"].location!=NSNotFound){ 147 | NSString *skipString=[imageWithoutLastPart lastPathComponent]; 148 | //skipString=[skipString stringByDeletingPathExtension]; 149 | skipString=[skipString stringByReplacingOccurrencesOfString:@".framework" withString:@""]; 150 | skipString=[skipString stringByReplacingOccurrencesOfString:@".bundle" withString:@""]; 151 | skipString=[skipString stringByReplacingOccurrencesOfString:@".app" withString:@""]; 152 | 153 | if ([skipString isEqualToString:[imageToPass lastPathComponent]]){ 154 | parseImage((char *)[imageToPass UTF8String ],writeToDisk,outputDir,getSymbols,recursive,YES,simpleHeader,skipAlreadyFound,skipApplications,0); 155 | 156 | } 157 | 158 | } 159 | 160 | else{ 161 | 162 | parseImage((char *)[imageToPass UTF8String ],writeToDisk,outputDir,getSymbols,recursive,YES,simpleHeader,skipAlreadyFound,skipApplications,0); 163 | } 164 | } 165 | 166 | [p drain]; 167 | } 168 | 169 | if (entry->d_type & DT_DIR ) { 170 | 171 | if (strcmp(d_name, "..")!= 0 && strcmp(d_name, ".")!=0) { 172 | 173 | int path_length; 174 | char path[PATH_MAX]; 175 | 176 | path_length = snprintf (path, PATH_MAX,"%s/%s", dir_name, d_name); 177 | 178 | if (path_length >= PATH_MAX) { 179 | //Path length has gotten too long 180 | exit (EXIT_FAILURE); 181 | } 182 | 183 | list_dir (path,writeToDisk,outputDir,getSymbols,recursive,simpleHeader,skipAlreadyFound,skipApplications); 184 | } 185 | } 186 | } 187 | 188 | closedir (d); 189 | 190 | } 191 | 192 | 193 | 194 | /****** The actual job ******/ 195 | 196 | extern "C" int parseImage(char *image,BOOL writeToDisk,NSString *outputDir,BOOL getSymbols,BOOL isRecursive,BOOL buildOriginalDirs,BOOL simpleHeader, BOOL skipAlreadyFound,BOOL skipApplications,int percent){ 197 | 198 | 199 | if (!image){ 200 | return 3; 201 | } 202 | 203 | // applications are skipped by default in a recursive, you can use -a to force-dump them recursively 204 | if (skipApplications){ 205 | if (isRecursive && strstr(image,"/var/stash/Applications/")){ //skip Applications dir 206 | return 4; 207 | } 208 | 209 | if (isRecursive && strstr(image,"/var/mobile/Applications/")){ //skip Applications dir 210 | return 4; 211 | } 212 | if (isRecursive && strstr(image,"/var/mobile/Containers/Bundle/Application/")){ //skip Applications dir 213 | return 4; 214 | } 215 | if ((isRecursive && strstr(image,"SubstrateBootstrap.dylib") ) || (isRecursive && strstr(image,"CydiaSubstrate.framework"))){ //skip Applications dir 216 | return 4; 217 | } 218 | 219 | } 220 | if (isIOS11 && strstr(image,"SpringBoardUI")){ 221 | dlopen("/System/Library/PrivateFrameworks/SearchUI.framework/SearchUI",RTLD_NOW); //rdar://problem/26143166 222 | } 223 | 224 | NSString *imageAsNSString=[[NSString alloc] initWithCString:image encoding:NSUTF8StringEncoding]; 225 | for (NSString *forbiddenPath in forbiddenPaths){ 226 | if ([imageAsNSString rangeOfString:forbiddenPath].location!=NSNotFound){ 227 | NSLog(@"Image %@ cannot be parsed due to known crashing issues.",imageAsNSString); 228 | [imageAsNSString release]; 229 | return 5; 230 | } 231 | } 232 | 233 | [imageAsNSString release]; 234 | 235 | 236 | 237 | NSAutoreleasePool *xd=[[NSAutoreleasePool alloc] init]; 238 | 239 | if (!image){ 240 | printf("\n stringWithCString image empty \n"); 241 | } 242 | 243 | if (isRecursive && ([[NSString stringWithCString:image encoding:NSUTF8StringEncoding] rangeOfString:@"/dev"].location==0 || [[NSString stringWithCString:image encoding:NSUTF8StringEncoding] rangeOfString:@"/bin"].location==0 || (skipApplications && [[NSString stringWithCString:image encoding:NSUTF8StringEncoding] rangeOfString:@"/var"].location==0))){ 244 | [xd drain]; 245 | return 4; 246 | } 247 | [xd drain]; 248 | 249 | 250 | NSAutoreleasePool *xdd=[[NSAutoreleasePool alloc] init]; 251 | 252 | 253 | if ([allImagesProcessed containsObject:[NSString stringWithCString:image encoding:NSUTF8StringEncoding]]){ 254 | [xdd drain]; 255 | return 5; 256 | } 257 | 258 | NSString *imageEnd=[[NSString stringWithCString:image encoding:NSUTF8StringEncoding] lastPathComponent]; 259 | imageEnd=[imageEnd stringByReplacingOccurrencesOfString:@".framework/" withString:@""]; 260 | imageEnd=[imageEnd stringByReplacingOccurrencesOfString:@".framework" withString:@""]; 261 | imageEnd=[imageEnd stringByReplacingOccurrencesOfString:@".bundle/" withString:@""]; 262 | imageEnd=[imageEnd stringByReplacingOccurrencesOfString:@".bundle" withString:@""]; 263 | imageEnd=[imageEnd stringByReplacingOccurrencesOfString:@".app/" withString:@""]; 264 | imageEnd=[imageEnd stringByReplacingOccurrencesOfString:@".app" withString:@""]; 265 | NSString *containedImage=[[NSString stringWithCString:image encoding:NSUTF8StringEncoding] stringByAppendingString:[NSString stringWithFormat:@"/%@",imageEnd]]; 266 | 267 | if ([allImagesProcessed containsObject:containedImage]){ 268 | [xdd drain]; 269 | return 5; 270 | } 271 | [xdd drain]; 272 | 273 | 274 | // check if image is executable 275 | dlopen_preflight(image); 276 | BOOL isExec=NO; 277 | if (dlerror()){ 278 | if (fileExistsOnDisk(image)){ 279 | isExec=isMachOExecutable(image); 280 | } 281 | } 282 | 283 | 284 | void * ref=nil; 285 | BOOL opened=dlopen_preflight(image); 286 | const char *dlopenError=dlerror(); 287 | if (opened){ 288 | CDLog(@"Will dlopen %s",image); 289 | ref=dlopen(image, RTLD_LAZY ); 290 | CDLog(@"Did dlopen %s",image); 291 | } 292 | else{ 293 | 294 | if (!isExec || shouldDLopen32BitExecutables){ 295 | 296 | if (!dlopenError || (dlopenError && !strstr(dlopenError,"no matching architecture in universal wrapper") && !strstr(dlopenError,"out of address space") && !strstr(dlopenError,"mach-o, but wrong architecture"))){ 297 | NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init]; 298 | NSString *imageString=[[NSString alloc] initWithCString:image encoding:NSUTF8StringEncoding]; 299 | NSString *lastComponent=[imageString lastPathComponent]; 300 | 301 | if ([lastComponent rangeOfString:@".framework"].location==NSNotFound && [lastComponent rangeOfString:@".bundle"].location==NSNotFound && [lastComponent rangeOfString:@".app"].location==NSNotFound){ 302 | if (!isRecursive){ 303 | dlopen_preflight(image); 304 | printf("\nNot a suitable image: %s\n(%s)\n",image,dlerror()); 305 | } 306 | return 3; 307 | } 308 | NSBundle *loadedBundle=[NSBundle bundleWithPath:imageString]; 309 | [imageString release]; 310 | [pool drain]; 311 | char *exec=(char *)[[loadedBundle executablePath] UTF8String]; 312 | image=(char *)exec; 313 | if (image){ 314 | 315 | if (!dlopen_preflight(image)){ 316 | // cleanup dlerror: 317 | dlerror(); 318 | isExec=isMachOExecutable(image); 319 | } 320 | //opened=dlopen_preflight(image); 321 | opened=dlopen_preflight([[loadedBundle executablePath] UTF8String]); 322 | dlopenError=dlerror(); 323 | } 324 | else{ 325 | opened=NO; 326 | } 327 | if (opened && (!isExec || shouldDLopen32BitExecutables)){ 328 | ref=dlopen(image, RTLD_LAZY); 329 | } 330 | } 331 | 332 | } 333 | } 334 | 335 | if (image!=nil && ![allImagesProcessed containsObject:[NSString stringWithCString:image encoding:2]] && ((dlopenError && (strstr(dlopenError,"no matching architecture in universal wrapper") || strstr(dlopenError,"not macOS") || strstr(dlopenError,"out of address space") || strstr(dlopenError,"mach-o, but wrong architecture"))) || (isExec && !shouldDLopen32BitExecutables))){ 336 | @autoreleasepool{ 337 | 338 | /*if (fileExistsOnDisk(image) && isExec){ 339 | NSString *exec=[NSString stringWithFormat:@"/usr/bin/ldid -e %s > /tmp/entitlements/%@",image,[[NSString stringWithCString:image encoding:NSUTF8StringEncoding] lastPathComponent]]; 340 | system([exec UTF8String]); 341 | }*/ 342 | 343 | #if defined (__x86_64__) || defined (__i386__) 344 | NSString *tryWithLib=[NSString stringWithFormat:@"DYLD_INSERT_LIBRARIES=/usr/local/lib/libclassdumpdyld.dylib %s",image]; 345 | 346 | #else 347 | NSString *tryWithLib=[NSString stringWithFormat:@"DYLD_INSERT_LIBRARIES=/usr/lib/libclassdumpdyld.dylib %s",image]; 348 | 349 | #endif 350 | 351 | 352 | if (writeToDisk){ 353 | tryWithLib=[tryWithLib stringByAppendingString:[NSString stringWithFormat:@" -o %@",outputDir]]; 354 | } 355 | if (buildOriginalDirs){ 356 | tryWithLib=[tryWithLib stringByAppendingString:@" -b"]; 357 | } 358 | if (getSymbols){ 359 | tryWithLib=[tryWithLib stringByAppendingString:@" -g"]; 360 | } 361 | if (simpleHeader){ 362 | tryWithLib=[tryWithLib stringByAppendingString:@" -u"]; 363 | } 364 | if (addHeadersFolder){ 365 | tryWithLib=[tryWithLib stringByAppendingString:@" -h"]; 366 | } 367 | if (inDebug){ 368 | tryWithLib=[tryWithLib stringByAppendingString:@" -D"]; 369 | } 370 | if (isRecursive){ 371 | tryWithLib=[tryWithLib stringByAppendingString:@" -r"]; 372 | } 373 | if (onlyOneClass){ 374 | tryWithLib=[tryWithLib stringByAppendingString:[NSString stringWithFormat:@" -j %@",onlyOneClass]]; 375 | } 376 | 377 | [allImagesProcessed addObject:[NSString stringWithCString:image encoding:2]]; 378 | int(*_my_system)(const char *)=(int(*)(const char *))dlsym(RTLD_DEFAULT,"system"); 379 | _my_system([tryWithLib UTF8String]); 380 | } 381 | if (!isRecursive){ 382 | return 1; 383 | } 384 | } 385 | 386 | if (!opened || ref==nil || image==NULL){ 387 | if (!isRecursive){ 388 | printf("\nCould not open: %s\n",image); 389 | } 390 | return 3; 391 | } 392 | 393 | if (image!=nil && [allImagesProcessed containsObject:[NSString stringWithCString:image encoding:2]]){ 394 | return 5; 395 | } 396 | 397 | 398 | 399 | CDLog(@"Dlopen complete, proceeding with class info for %s",image); 400 | // PROCEED 401 | BOOL isFramework=NO; 402 | NSMutableString *dumpString=[[NSMutableString alloc] initWithString:@""]; 403 | unsigned int count; 404 | CDLog(@"Getting class count for %s",image); 405 | const char **names = objc_copyClassNamesForImage(image,&count); 406 | CDLog(@"Did return class count %d",count); 407 | if (count){ 408 | 409 | if (percent){ 410 | printf(" Dumping "BOLDWHITE"%s"RESET"...(%d classes) (%d%%) %s \n",image ,count, percent, [print_free_memory() UTF8String]); 411 | } 412 | else{ 413 | printf(" Dumping "BOLDWHITE"%s"RESET"...(%d classes) %s \n",image ,count,[print_free_memory() UTF8String]); 414 | } 415 | } 416 | 417 | while ([outputDir rangeOfString:@"/" options:NSBackwardsSearch].location==outputDir.length-1){ 418 | outputDir=[outputDir substringToIndex:outputDir.length-1]; 419 | } 420 | 421 | BOOL hasWrittenCopyright=NO; 422 | allStructsFound=nil; 423 | allStructsFound=[NSMutableArray array]; 424 | classesInStructs=nil; 425 | classesInStructs=[NSMutableArray array]; 426 | 427 | 428 | NSMutableArray *protocolsAdded=[NSMutableArray array]; 429 | 430 | NSString *imageName=[[NSString stringWithCString:image encoding:NSUTF8StringEncoding] lastPathComponent]; 431 | NSString *fullImageNameInNS=[NSString stringWithCString:image encoding:NSUTF8StringEncoding]; 432 | [allImagesProcessed addObject:fullImageNameInNS]; 433 | 434 | NSString *seeIfIsBundleType=[fullImageNameInNS stringByDeletingLastPathComponent]; 435 | NSString *lastComponent=[seeIfIsBundleType lastPathComponent]; 436 | NSString *targetDir=nil; 437 | if ([lastComponent rangeOfString:@"."].location==NSNotFound){ 438 | targetDir=fullImageNameInNS; 439 | 440 | } 441 | else{ 442 | targetDir=[fullImageNameInNS stringByDeletingLastPathComponent]; 443 | isFramework=YES; 444 | } 445 | NSString *headersFolder=addHeadersFolder ? @"/Headers" : @""; 446 | NSString *writeDir=buildOriginalDirs ? (isFramework ? [NSString stringWithFormat:@"%@/%@%@",outputDir,targetDir,headersFolder] : [NSString stringWithFormat:@"%@/%@",outputDir,targetDir]) : outputDir; 447 | writeDir=[writeDir stringByReplacingOccurrencesOfString:@"///" withString:@"/"]; 448 | writeDir=[writeDir stringByReplacingOccurrencesOfString:@"//" withString:@"/"]; 449 | 450 | [processedImages addObject:[NSString stringWithCString:image encoding:NSUTF8StringEncoding]]; 451 | CDLog(@"Beginning class loop (%d classed) for %s",count,image); 452 | NSMutableString *classesToImport=[[NSMutableString alloc] init]; 453 | 454 | int actuallyProcesssedCount=0; 455 | 456 | for (unsigned i=0; i"] retain] ; 548 | } 549 | } 550 | 551 | 552 | if ( writeToDisk || (!writeToDisk && !hasWrittenCopyright )){ 553 | NSString *copyrightString=copyrightMessage(image); 554 | [dumpString appendString:copyrightString]; 555 | [copyrightString release]; 556 | hasWrittenCopyright=YES; 557 | } 558 | 559 | 560 | if (writeToDisk && superclassString.length>0 && ![superclassString isEqual:@" : NSObject"]){ 561 | NSString *fixedSuperclass=[superclassString stringByReplacingOccurrencesOfString:@" : " withString:@""]; 562 | NSString *importSuper=@""; 563 | if (!simpleHeader){ 564 | NSString *imagePrefix=[imageName substringToIndex:2]; 565 | 566 | NSString *superclassPrefix=[superclassString rangeOfString:@"_"].location==0 ? [[superclassString substringFromIndex:1] substringToIndex:2] : [superclassString substringToIndex:2]; 567 | const char *imageNameOfSuper=[imagePrefix isEqual:superclassPrefix] ? [imagePrefix UTF8String] : class_getImageName(objc_getClass([fixedSuperclass UTF8String])); 568 | if (imageNameOfSuper){ 569 | NSString *imageOfSuper=[NSString stringWithCString:imageNameOfSuper encoding:NSUTF8StringEncoding]; 570 | imageOfSuper=[imageOfSuper lastPathComponent]; 571 | importSuper=[NSString stringWithFormat:@"#import <%@/%@.h>\n",imageOfSuper,fixedSuperclass]; 572 | } 573 | 574 | } 575 | else{ 576 | importSuper=[NSString stringWithFormat:@"#import \"%@.h\"\n",fixedSuperclass]; 577 | } 578 | [dumpString appendString:importSuper]; 579 | } 580 | 581 | 582 | for (unsigned d=0; d\n",imageOfProtocol,protocolNSString]]; 614 | } 615 | 616 | } 617 | if ([protocolsAdded containsObject:protocolNSString]){ 618 | continue; 619 | } 620 | [protocolsAdded addObject:protocolNSString]; 621 | NSString *protocolHeader=buildProtocolFile(protocol); 622 | if (strcmp(names[i],protocolName)==0){ 623 | [dumpString appendString:protocolHeader]; 624 | 625 | } 626 | else{ 627 | if (writeToDisk){ 628 | NSString *copyrightString=copyrightMessage(image); 629 | protocolHeader=[copyrightString stringByAppendingString:protocolHeader] ; 630 | [copyrightString release]; 631 | 632 | [[NSFileManager defaultManager] createDirectoryAtPath:writeDir withIntermediateDirectories:YES attributes:nil error:nil]; 633 | 634 | 635 | if ( ![protocolHeader writeToFile:[NSString stringWithFormat:@"%@/%s.h",writeDir,protocolName] atomically:YES encoding:NSUTF8StringEncoding error:nil]){ 636 | printf(" Failed to save protocol header to directory \"%s\"\n",[writeDir UTF8String]); 637 | } 638 | } 639 | else{ 640 | [dumpString appendString:protocolHeader]; 641 | 642 | } 643 | } 644 | 645 | } 646 | free(protocolArray); 647 | 648 | 649 | [dumpString appendString:[NSString stringWithFormat:@"\n@interface %s%@%@",names[i],superclassString,inlineProtocolsString]]; 650 | // Get Ivars 651 | unsigned int ivarOutCount; 652 | Ivar * ivarArray=class_copyIvarList(currentClass, &ivarOutCount); 653 | if (ivarOutCount>0){ 654 | [dumpString appendString:@" {\n"]; 655 | for (unsigned x=0;x" withString:@""]; 693 | protocolToAdd=[protocolToAdd stringByReplacingOccurrencesOfString:@"*" withString:@""]; 694 | if (![inlineProtocols containsObject:protocolToAdd]){ 695 | [inlineProtocols addObject:protocolToAdd]; 696 | } 697 | 698 | } 699 | else{ 700 | [classesInClass addObject:classFoundInIvars]; 701 | } 702 | } 703 | if ([ivarTypeString rangeOfString:@"<"].location!=NSNotFound){ 704 | ivarTypeString=[ivarTypeString stringByReplacingOccurrencesOfString:@">*" withString:@">"]; 705 | if ([ivarTypeString rangeOfString:@"<"].location==0){ 706 | ivarTypeString=[@"id" stringByAppendingString:ivarTypeString]; 707 | } 708 | else{ 709 | ivarTypeString=[ivarTypeString stringByReplacingOccurrencesOfString:@"<" withString:@"*<"]; 710 | } 711 | } 712 | } 713 | } 714 | else{ 715 | ivarTypeString=@"???"; 716 | } 717 | NSString *formatted=[NSString stringWithFormat:@"\n\t%@ %@;",ivarTypeString,ivarNameNS]; 718 | [dumpString appendString:formatted]; 719 | 720 | } 721 | [dumpString appendString:@"\n\n}"]; 722 | 723 | } 724 | free(ivarArray); 725 | 726 | if ([inlineProtocols count]>0){ 727 | 728 | NSMutableString *inlineProtocolsString=[[NSMutableString alloc] init]; 729 | [inlineProtocolsString appendString:@"@protocol "]; 730 | for (int g=0; glongestLocation){ 784 | longestLocation=location; 785 | } 786 | 787 | } 788 | 789 | NSMutableArray *newStrings=[NSMutableArray array]; 790 | for (NSString *string in synthesized){ 791 | int synthesizeLocation=[string rangeOfString:@"//@synth"].location; 792 | if ([string rangeOfString:@"//@synth"].location==NSNotFound){ 793 | [newStrings addObject:string]; 794 | continue; 795 | } 796 | 797 | NSString *copyString=[string substringFromIndex:synthesizeLocation]; 798 | int location=[string rangeOfString:@";"].location; 799 | string=[string substringToIndex:location+1]; 800 | string=[string stringByPaddingToLength:longestLocation+15 withString:@" " startingAtIndex:0]; 801 | string=[string stringByAppendingString:copyString]; 802 | [newStrings addObject:string]; 803 | } 804 | if (propLenght>0){ 805 | propertiesString=[@"\n" stringByAppendingString:[newStrings componentsJoinedByString:@"\n"]]; 806 | } 807 | 808 | // Gather All Strings 809 | [dumpString appendString:propertiesString]; 810 | [dumpString appendString:[generateMethodLines(object_getClass(currentClass),NO,nil) autorelease]]; 811 | [dumpString appendString:[generateMethodLines(currentClass,YES,propertiesArrayFromString(propertiesString)) autorelease]]; 812 | [dumpString appendString:@"\n@end\n\n"]; 813 | 814 | 815 | 816 | 817 | 818 | if (shouldImportStructs && writeToDisk){ 819 | int firstImport=[dumpString rangeOfString:@"#import"].location!=NSNotFound ? [dumpString rangeOfString:@"#import"].location : [dumpString rangeOfString:@"@interface"].location; 820 | NSString *structImport=simpleHeader ? [NSString stringWithFormat:@"#import \"%@-Structs.h\"\n",imageName] : [NSString stringWithFormat:@"#import <%@/%@-Structs.h>\n",imageName,imageName]; 821 | [dumpString insertString:structImport atIndex:firstImport]; 822 | 823 | } 824 | 825 | if (writeToDisk && [classesInClass count]>0){ 826 | 827 | if (!names[i]){ 828 | printf("\n stringWithCString names[i] empty \n"); 829 | } 830 | 831 | 832 | [classesInClass removeObject:[NSString stringWithCString:names[i] encoding:NSUTF8StringEncoding]]; 833 | if ([classesInClass count]>0){ 834 | int firstInteface=[dumpString rangeOfString:@"@interface"].location; 835 | NSMutableString *classesFoundToAdd=[[NSMutableString alloc] init]; 836 | [classesFoundToAdd appendString:@"@class "]; 837 | for (int f=0; f\n",imageName,names[i]]; 878 | [classesToImport appendString:importStringFrmt]; 879 | } 880 | 881 | objc_destructInstance(currentClass); 882 | 883 | [dumpString release]; 884 | dumpString=[[NSMutableString alloc] init]; 885 | [pool drain]; 886 | 887 | } 888 | // END OF PER-CLASS LOOP 889 | 890 | if (actuallyProcesssedCount==0 && onlyOneClass){ 891 | printf("\r\n"BOLDWHITE"\t\tlibclassdump-dyld:"RESET" Class \""BOLDWHITE"%s"RESET"\" not found"RESET" in %s\r\n\r\n",[onlyOneClass UTF8String],image); 892 | } 893 | 894 | if (writeToDisk && classesToImport.length>2){ 895 | [[NSFileManager defaultManager] createDirectoryAtPath:writeDir withIntermediateDirectories:YES attributes:nil error:nil]; 896 | if (![classesToImport writeToFile:[NSString stringWithFormat:@"%@/%@.h",writeDir,imageName] atomically:YES encoding:NSUTF8StringEncoding error:nil]){ 897 | printf(" Failed to save header list to directory \"%s\"\n",[writeDir UTF8String]); 898 | 899 | } 900 | } 901 | [classesToImport release]; 902 | 903 | 904 | CDLog(@"Finished class loop for %s",image); 905 | 906 | // Compose FrameworkName-Structs.h file 907 | 908 | NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init]; 909 | 910 | if ([allStructsFound count]>0){ 911 | 912 | NSString *structsString=@""; 913 | if (writeToDisk){ 914 | NSString *copyrightString=copyrightMessage(image); 915 | structsString=[[[structsString autorelease] stringByAppendingString:copyrightString] retain]; 916 | [copyrightString release]; 917 | } 918 | NSError *writeError; 919 | if ([classesInStructs count]>0){ 920 | 921 | structsString=[[[structsString autorelease] stringByAppendingString:@"\n@class "] retain]; 922 | for (NSString *string in classesInStructs){ 923 | structsString=[[[structsString autorelease] stringByAppendingString:[NSString stringWithFormat:@"%@, ",string]] retain]; 924 | } 925 | structsString=[[[structsString autorelease] substringToIndex:structsString.length-2] retain]; 926 | structsString=[[[structsString autorelease] stringByAppendingString:@";\n\n"] retain]; 927 | } 928 | 929 | 930 | for (NSDictionary *dict in allStructsFound){ 931 | structsString=[[[structsString autorelease] stringByAppendingString:[dict objectForKey:@"representation"]] retain]; 932 | } 933 | if (writeToDisk){ 934 | [[NSFileManager defaultManager] createDirectoryAtPath:writeDir withIntermediateDirectories:YES attributes:nil error:nil]; 935 | 936 | if (![structsString writeToFile:[NSString stringWithFormat:@"%@/%@-Structs.h",writeDir,imageName] atomically:YES encoding:NSUTF8StringEncoding error:&writeError]){ 937 | printf(" Failed to save structs to directory \"%s\"\n",[writeDir UTF8String]); 938 | if (writeError!=nil){ 939 | printf(" %s\n",[[writeError description] UTF8String]); 940 | } 941 | } 942 | } 943 | else{ 944 | printf("\n%s\n",[structsString UTF8String]); 945 | } 946 | 947 | } 948 | 949 | [pool drain]; 950 | 951 | 952 | // Compose FrameworkName-Symbols.h file (more like nm command's output not an actual header anyway) 953 | if (getSymbols){ 954 | 955 | CDLog(@"In Symbols -> Fetching symbols for %s",image); 956 | 957 | struct mach_header * mh=nil; 958 | struct mach_header_64 * mh64=nil; 959 | 960 | if (!my_dyld_get_all_image_infos){ 961 | findDyldGetAllImageInfosSymbol(); 962 | } 963 | dyld_all_image_infos = my_dyld_get_all_image_infos(); 964 | for(int i=0; iinfoArrayCount; i++) { 965 | if (dyld_all_image_infos->infoArray[i].imageLoadAddress!=NULL){ 966 | char *currentImage=(char *)dyld_all_image_infos->infoArray[i].imageFilePath; 967 | if (strlen(currentImage)>0 && !strcmp(currentImage,image)){ 968 | 969 | if (arch64()){ 970 | mh64 = (struct mach_header_64 *)dyld_all_image_infos->infoArray[i].imageLoadAddress; 971 | } 972 | else{ 973 | mh = (struct mach_header *)dyld_all_image_infos->infoArray[i].imageLoadAddress; 974 | } 975 | 976 | break; 977 | } 978 | } 979 | } 980 | 981 | if ((arch64() && mh64==nil) | (!arch64() && mh==nil)){ 982 | CDLog(@"Currently dlopened image %s not found in _dyld_image_count (?)",image); 983 | } 984 | else{ 985 | 986 | unsigned int file_slide; 987 | NSMutableString *symbolsString=nil; 988 | 989 | 990 | if (!arch64()){ 991 | CDLog(@"In Symbols -> Got mach header OK , filetype %d",mh->filetype); 992 | 993 | // Thanks to FilippoBiga for the code snippet below 994 | 995 | struct segment_command *seg_linkedit = NULL; 996 | struct segment_command *seg_text = NULL; 997 | struct symtab_command *symtab = NULL; 998 | struct load_command *cmd = (struct load_command*)((char*)mh + sizeof(struct mach_header)); 999 | CDLog(@"In Symbols -> Iterating header commands for %s",image); 1000 | for (uint32_t index = 0; index < mh->ncmds; index++, cmd = (struct load_command*)((char*)cmd + cmd->cmdsize)) 1001 | { 1002 | //CDLog(@"I=%d",index); 1003 | switch(cmd->cmd) 1004 | { 1005 | case LC_SEGMENT: 1006 | { 1007 | //CDLog(@"FOUND LC_SEGMENT"); 1008 | struct segment_command *segmentCommand = (struct segment_command*)(cmd); 1009 | if (strncmp(segmentCommand->segname, "__TEXT", sizeof(segmentCommand->segname)) == 0) 1010 | { 1011 | seg_text = segmentCommand; 1012 | 1013 | } else if (strncmp(segmentCommand->segname, "__LINKEDIT", sizeof(segmentCommand->segname)) == 0) 1014 | { 1015 | seg_linkedit = segmentCommand; 1016 | } 1017 | break; 1018 | } 1019 | 1020 | case LC_SYMTAB: 1021 | { 1022 | //CDLog(@"FOUND SYMTAB"); 1023 | symtab = (struct symtab_command*)(cmd); 1024 | break; 1025 | } 1026 | 1027 | default: 1028 | { 1029 | break; 1030 | } 1031 | 1032 | } 1033 | } 1034 | 1035 | 1036 | if (mh->filetype==MH_DYLIB){ 1037 | file_slide = ((unsigned long)seg_linkedit->vmaddr - (unsigned long)seg_text->vmaddr) - seg_linkedit->fileoff; 1038 | } 1039 | else{ 1040 | file_slide = 0; 1041 | } 1042 | CDLog(@"In Symbols -> Got symtab for %s",image); 1043 | struct nlist *symbase = (struct nlist*)((unsigned long)mh + (symtab->symoff + file_slide)); 1044 | char *strings = (char*)((unsigned long)mh + (symtab->stroff + file_slide)); 1045 | struct nlist *sym; 1046 | sym = symbase; 1047 | 1048 | symbolsString=[[NSMutableString alloc] init]; 1049 | NSAutoreleasePool *pp = [[NSAutoreleasePool alloc] init]; 1050 | 1051 | CDLog(@"In Symbols -> Iteraring symtab"); 1052 | for (uint32_t index = 0; index < symtab->nsyms; index += 1, sym += 1) 1053 | { 1054 | 1055 | if ((uint32_t)sym->n_un.n_strx > symtab->strsize) 1056 | { 1057 | break; 1058 | 1059 | } else { 1060 | 1061 | const char *strFound = (char*) (strings + sym->n_un.n_strx); 1062 | char *str= strdup(strFound); 1063 | if (strcmp(str,"") && strlen(str)>0){ 1064 | if (!symbolsString){ 1065 | NSString *copyrightString=copyrightMessage(image); 1066 | [symbolsString appendString:[copyrightString stringByReplacingOccurrencesOfString:@"This header" withString:@"This output"]]; 1067 | [copyrightString release]; 1068 | if (!str){ 1069 | printf("\n stringWithCString str empty \n"); 1070 | } 1071 | 1072 | [symbolsString appendString :[NSString stringWithFormat:@"\nSymbols found in %s:\n%@\n",image,[NSString stringWithCString:str encoding:NSUTF8StringEncoding]]] ; 1073 | } 1074 | else{ 1075 | [symbolsString appendString : [NSString stringWithFormat:@"%s\n",str]] ; 1076 | } 1077 | 1078 | } 1079 | free (str); 1080 | 1081 | } 1082 | 1083 | } 1084 | [pp drain]; 1085 | } 1086 | 1087 | else{ 1088 | 1089 | CDLog(@"In Symbols -> Got mach header OK , filetype %d",mh64->filetype); 1090 | 1091 | struct segment_command_64 *seg_linkedit = NULL; 1092 | struct segment_command_64 *seg_text = NULL; 1093 | struct symtab_command *symtab = NULL; 1094 | struct load_command *cmd = (struct load_command*)((char*)mh64 + sizeof(struct mach_header_64)); 1095 | CDLog(@"In Symbols -> Iterating header commands for %s",image); 1096 | 1097 | for (uint32_t index = 0; index < mh64->ncmds; index++, cmd = (struct load_command*)((char*)cmd + cmd->cmdsize)) 1098 | { 1099 | //CDLog(@"I=%d",index); 1100 | switch(cmd->cmd) 1101 | { 1102 | case LC_SEGMENT_64: 1103 | { 1104 | //CDLog(@"FOUND LC_SEGMENT_64"); 1105 | struct segment_command_64 *segmentCommand = (struct segment_command_64*)(cmd); 1106 | if (strncmp(segmentCommand->segname, "__TEXT", sizeof(segmentCommand->segname)) == 0) 1107 | { 1108 | seg_text = segmentCommand; 1109 | 1110 | } else if (strncmp(segmentCommand->segname, "__LINKEDIT", sizeof(segmentCommand->segname)) == 0) 1111 | { 1112 | seg_linkedit = segmentCommand; 1113 | } 1114 | break; 1115 | } 1116 | 1117 | case LC_SYMTAB: 1118 | { 1119 | //CDLog(@"FOUND SYMTAB"); 1120 | symtab = (struct symtab_command*)(cmd); 1121 | break; 1122 | } 1123 | 1124 | default: 1125 | { 1126 | break; 1127 | } 1128 | 1129 | } 1130 | } 1131 | 1132 | if (mh64->filetype==MH_DYLIB){ 1133 | file_slide = ((unsigned long)seg_linkedit->vmaddr - (unsigned long)seg_text->vmaddr) - seg_linkedit->fileoff; 1134 | } 1135 | else{ 1136 | file_slide = 0; 1137 | } 1138 | CDLog(@"In Symbols -> Got symtab for %s",image); 1139 | struct nlist_64 *symbase = (struct nlist_64*)((unsigned long)mh64 + (symtab->symoff + file_slide)); 1140 | char *strings = (char*)((unsigned long)mh64 + (symtab->stroff + file_slide)); 1141 | struct nlist_64 *sym; 1142 | sym = symbase; 1143 | 1144 | symbolsString=[[NSMutableString alloc] init]; 1145 | NSAutoreleasePool *pp = [[NSAutoreleasePool alloc] init]; 1146 | 1147 | CDLog(@"In Symbols -> Iteraring symtab"); 1148 | for (uint32_t index = 0; index < symtab->nsyms; index += 1, sym += 1) 1149 | { 1150 | 1151 | if ((uint32_t)sym->n_un.n_strx > symtab->strsize) 1152 | { 1153 | break; 1154 | 1155 | } else { 1156 | 1157 | const char *strFound = (char*) (strings + sym->n_un.n_strx); 1158 | char *str= strdup(strFound); 1159 | if (strcmp(str,"") && strlen(str)>0){ 1160 | if (!symbolsString){ 1161 | NSString *copyrightString=copyrightMessage(image); 1162 | [symbolsString appendString:[copyrightString stringByReplacingOccurrencesOfString:@"This header" withString:@"This output"]]; 1163 | [copyrightString release]; 1164 | if (!str){ 1165 | printf("\n stringWithCString str empty \n"); 1166 | } 1167 | 1168 | [symbolsString appendString :[NSString stringWithFormat:@"\nSymbols found in %s:\n%@\n",image,[NSString stringWithCString:str encoding:NSUTF8StringEncoding]]] ; 1169 | } 1170 | else{ 1171 | [symbolsString appendString : [NSString stringWithFormat:@"%s\n",str]] ; 1172 | } 1173 | 1174 | } 1175 | free (str); 1176 | 1177 | } 1178 | 1179 | } 1180 | [pp drain]; 1181 | } 1182 | 1183 | 1184 | NSError *error2; 1185 | CDLog(@"Finished fetching symbols for %s\n",image); 1186 | if ([symbolsString length]>0){ 1187 | if (writeToDisk){ 1188 | [[NSFileManager defaultManager] createDirectoryAtPath:writeDir withIntermediateDirectories:YES attributes:nil error:&error2]; 1189 | if (![symbolsString writeToFile:[NSString stringWithFormat:@"%@/%@-Symbols.h",writeDir,imageName] atomically:YES encoding:NSUTF8StringEncoding error:&error2]){ 1190 | printf(" Failed to save symbols to directory \"%s\"\n",[writeDir UTF8String]); 1191 | if (error2!=nil){ 1192 | printf(" %s\n",[[error2 description] UTF8String]); 1193 | } 1194 | } 1195 | } 1196 | else{ 1197 | printf("\n%s\n",[symbolsString UTF8String]); 1198 | } 1199 | } 1200 | [symbolsString release]; 1201 | } 1202 | } 1203 | 1204 | 1205 | free(names); 1206 | 1207 | return 1; 1208 | 1209 | } 1210 | 1211 | 1212 | 1213 | /****** main ******/ 1214 | 1215 | int main(int argc, char **argv, char **envp) { 1216 | 1217 | isIOS11=[[[NSProcessInfo processInfo] operatingSystemVersionString] rangeOfString:@"Version 11"].location==0 || [[[NSProcessInfo processInfo] operatingSystemVersionString] rangeOfString:@"Version 12"].location==0; 1218 | 1219 | @autoreleasepool { 1220 | 1221 | 1222 | char * image=nil; 1223 | BOOL writeToDisk=NO; 1224 | BOOL buildOriginalDirs=NO; 1225 | BOOL recursive=NO; 1226 | BOOL simpleHeader=NO; 1227 | BOOL getSymbols=NO; 1228 | BOOL skipAlreadyFound=NO; 1229 | BOOL isSharedCacheRecursive=NO; 1230 | BOOL skipApplications=YES; 1231 | 1232 | 1233 | 1234 | NSString *outputDir=nil; 1235 | NSString *sourceDir=nil; 1236 | 1237 | // Check and apply arguments 1238 | 1239 | NSString *currentDir=[[[NSProcessInfo processInfo] environment] objectForKey:@"PWD"]; 1240 | NSArray *arguments=[[NSProcessInfo processInfo] arguments]; 1241 | NSMutableArray *argumentsToUse=[arguments mutableCopy]; 1242 | [argumentsToUse removeObjectAtIndex:0]; 1243 | 1244 | int argCount=[arguments count]; 1245 | 1246 | if (argCount<2){ 1247 | printHelp(); 1248 | exit(0); 1249 | } 1250 | 1251 | 1252 | 1253 | for (NSString *arg in arguments){ 1254 | 1255 | 1256 | if ([arg isEqual:@"-D"]){ 1257 | inDebug=1; 1258 | [argumentsToUse removeObject:arg]; 1259 | } 1260 | 1261 | 1262 | 1263 | if ([arg isEqual:@"-o"]){ 1264 | 1265 | int argIndex=[arguments indexOfObject:arg]; 1266 | 1267 | if (argIndex==argCount-1){ 1268 | printHelp(); 1269 | exit(0); 1270 | } 1271 | 1272 | outputDir=[arguments objectAtIndex:argIndex+1]; 1273 | //outputDir=[NSString stringWithFormat:@"\"%@\"",outputDir]; 1274 | if ([outputDir rangeOfString:@"-"].location==0){ 1275 | printHelp(); 1276 | exit(0); 1277 | } 1278 | writeToDisk=YES; 1279 | [argumentsToUse removeObject:arg]; 1280 | [argumentsToUse removeObject:outputDir]; 1281 | 1282 | 1283 | } 1284 | 1285 | if ([arg isEqual:@"-j"]){ 1286 | 1287 | int argIndex=[arguments indexOfObject:arg]; 1288 | 1289 | if (argIndex==argCount-1){ 1290 | printHelp(); 1291 | exit(0); 1292 | } 1293 | 1294 | onlyOneClass=[[arguments objectAtIndex:argIndex+1] retain]; 1295 | 1296 | if ([onlyOneClass rangeOfString:@"-"].location==0){ 1297 | printHelp(); 1298 | exit(0); 1299 | } 1300 | 1301 | [argumentsToUse removeObject:arg]; 1302 | [argumentsToUse removeObject:onlyOneClass]; 1303 | 1304 | 1305 | } 1306 | 1307 | 1308 | 1309 | if ([arg isEqual:@"-r"]){ 1310 | 1311 | int argIndex=[arguments indexOfObject:arg]; 1312 | 1313 | if (argIndex==argCount-1){ 1314 | printHelp(); 1315 | exit(0); 1316 | } 1317 | 1318 | sourceDir=[arguments objectAtIndex:argIndex+1]; 1319 | BOOL isDir; 1320 | if ([sourceDir rangeOfString:@"-"].location==0 || ![[NSFileManager defaultManager] fileExistsAtPath:sourceDir] || ([[NSFileManager defaultManager] fileExistsAtPath:sourceDir isDirectory:&isDir] && !isDir)){ 1321 | printf("classdump-dyld: error: Directory %s does not exist\n",[sourceDir UTF8String]); 1322 | exit(0); 1323 | } 1324 | recursive=YES; 1325 | [argumentsToUse removeObject:arg]; 1326 | [argumentsToUse removeObject:sourceDir]; 1327 | 1328 | } 1329 | 1330 | 1331 | 1332 | if ([arg isEqual:@"-a"]){ 1333 | skipApplications=NO; 1334 | [argumentsToUse removeObject:arg]; 1335 | } 1336 | 1337 | if ([arg isEqual:@"-e"]){ 1338 | shouldDLopen32BitExecutables=YES; 1339 | [argumentsToUse removeObject:arg]; 1340 | } 1341 | 1342 | 1343 | if ([arg isEqual:@"-s"]){ 1344 | skipAlreadyFound=YES; 1345 | [argumentsToUse removeObject:arg]; 1346 | 1347 | } 1348 | 1349 | if ([arg isEqual:@"-b"]){ 1350 | buildOriginalDirs=YES; 1351 | [argumentsToUse removeObject:arg]; 1352 | 1353 | } 1354 | 1355 | if ([arg isEqual:@"-g"]){ 1356 | getSymbols=YES; 1357 | [argumentsToUse removeObject:arg]; 1358 | 1359 | } 1360 | 1361 | if ([arg isEqual:@"-u"]){ 1362 | simpleHeader=YES; 1363 | [argumentsToUse removeObject:arg]; 1364 | } 1365 | if ([arg isEqual:@"-c"]){ 1366 | isSharedCacheRecursive=YES; 1367 | [argumentsToUse removeObject:arg]; 1368 | } 1369 | if ([arg isEqual:@"-h"]){ 1370 | addHeadersFolder=YES; 1371 | [argumentsToUse removeObject:arg]; 1372 | } 1373 | 1374 | 1375 | if ([arg isEqual:@"-x"]){ 1376 | 1377 | int argIndex=[arguments indexOfObject:arg]; 1378 | 1379 | if (argIndex==argCount-1){ 1380 | printHelp(); 1381 | exit(0); 1382 | } 1383 | 1384 | int nextEntriesCount=[arguments count]-argIndex-1; 1385 | int next=1; 1386 | while (nextEntriesCount){ 1387 | NSString *forbiddenClassAdd=[arguments objectAtIndex:argIndex+next]; 1388 | next++; 1389 | nextEntriesCount--; 1390 | if ([forbiddenClassAdd rangeOfString:@"-"].location==0){ 1391 | nextEntriesCount=0; 1392 | break; 1393 | } 1394 | if (!forbiddenClasses){ 1395 | generateForbiddenClassesArray(recursive); 1396 | } 1397 | [forbiddenClasses addObject:forbiddenClassAdd]; 1398 | [argumentsToUse removeObject:forbiddenClassAdd]; 1399 | 1400 | } 1401 | 1402 | [argumentsToUse removeObject:arg]; 1403 | 1404 | } 1405 | 1406 | 1407 | } 1408 | 1409 | if (onlyOneClass && (recursive || isSharedCacheRecursive)){ 1410 | printHelp(); 1411 | exit(0); 1412 | } 1413 | 1414 | if (addHeadersFolder && !outputDir){ 1415 | printHelp(); 1416 | exit(0); 1417 | } 1418 | 1419 | if ((recursive || isSharedCacheRecursive) && !outputDir){ 1420 | printHelp(); 1421 | exit(0); 1422 | } 1423 | if ((recursive || isSharedCacheRecursive) && [argumentsToUse count]>0){ 1424 | printHelp(); 1425 | exit(0); 1426 | } 1427 | if ([argumentsToUse count]>2){ 1428 | printHelp(); 1429 | exit(0); 1430 | } 1431 | if (!recursive && !isSharedCacheRecursive){ 1432 | if ([argumentsToUse count]>1){ 1433 | printHelp(); 1434 | exit(0); 1435 | } 1436 | else{ 1437 | if ([argumentsToUse count]>0){ 1438 | image=(char *)[[argumentsToUse objectAtIndex:0] UTF8String]; 1439 | } 1440 | else{ 1441 | printHelp(); 1442 | exit(0); 1443 | } 1444 | } 1445 | } 1446 | 1447 | if (recursive && isSharedCacheRecursive){ 1448 | skipAlreadyFound=YES; 1449 | } 1450 | 1451 | // Begin 1452 | 1453 | int RESULT=1; 1454 | 1455 | allImagesProcessed=[NSMutableArray array]; 1456 | if (!forbiddenClasses){ 1457 | generateForbiddenClassesArray(recursive); 1458 | } 1459 | generateForbiddenPathsArray(recursive); 1460 | 1461 | NSString *inoutputDir=outputDir; 1462 | 1463 | if (isSharedCacheRecursive){ 1464 | const char *filename="/System/Library/Caches/com.apple.dyld/dyld_shared_cache_armv6"; 1465 | FILE* fp=fopen(filename,"r"); 1466 | if (fp==NULL){ 1467 | if ([[NSFileManager defaultManager] fileExistsAtPath:@"/private/var/db/dyld/dyld_shared_cache_x86_64"]){ 1468 | filename="/private/var/db/dyld/dyld_shared_cache_x86_64"; 1469 | } 1470 | else if ([[NSFileManager defaultManager] fileExistsAtPath:@"/private/var/db/dyld/dyld_shared_cache_i386"]){ 1471 | filename="/private/var/db/dyld/dyld_shared_cache_i386"; 1472 | } 1473 | else if ([[NSFileManager defaultManager] fileExistsAtPath:@"/System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64"]){ 1474 | filename="/System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64"; 1475 | } 1476 | else if ([[NSFileManager defaultManager] fileExistsAtPath:@"/System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64e"]){ 1477 | filename="/System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64e"; 1478 | } 1479 | else if([[NSFileManager defaultManager] fileExistsAtPath:@"/System/Library/Caches/com.apple.dyld/dyld_shared_cache_armv7s"]){ 1480 | filename="/System/Library/Caches/com.apple.dyld/dyld_shared_cache_armv7s"; 1481 | } 1482 | else{ 1483 | filename="/System/Library/Caches/com.apple.dyld/dyld_shared_cache_armv7"; 1484 | } 1485 | } 1486 | fclose(fp); 1487 | printf("\n Now dumping "BOLDWHITE"%s..."RESET"\n\n",filename); 1488 | // Thanks to DHowett & KennyTM~ for dyld_shared_cache listing codes 1489 | struct stat filebuffer; 1490 | stat(filename, &filebuffer); 1491 | unsigned long long filesize = filebuffer.st_size; 1492 | int fd = open(filename, O_RDONLY); 1493 | _cacheData = (uint8_t *)mmap(NULL, filesize, PROT_READ, MAP_PRIVATE, fd, 0); 1494 | _cacheHead = (struct cache_header *)_cacheData; 1495 | uint64_t curoffset = _cacheHead->startaddr; 1496 | 1497 | for (unsigned i = 0; i < _cacheHead->numlibs; ++ i) { 1498 | uint64_t fo = *(uint64_t *)(_cacheData + curoffset + 24); 1499 | curoffset += 32; 1500 | char *imageInCache=(char*)_cacheData + fo; 1501 | 1502 | // a few blacklisted frameworks that crash 1503 | if ( strstr(imageInCache,"Powerlog") || strstr(imageInCache,"Parsec") || strstr(imageInCache,"WebKitLegacy") || strstr(imageInCache,"VisualVoicemail") || strstr(imageInCache,"/System/Library/Frameworks/CoreGraphics.framework/Resources/") || strstr(imageInCache,"JavaScriptCore.framework") || strstr(imageInCache,"GameKitServices.framework") || strstr(imageInCache,"VectorKit")){ 1504 | continue; 1505 | } 1506 | 1507 | NSMutableString *imageToNSString=[[NSMutableString alloc] initWithCString:imageInCache encoding:NSUTF8StringEncoding]; 1508 | [imageToNSString replaceOccurrencesOfString:@"///" withString:@"/" options:nil range:NSMakeRange(0, [imageToNSString length])]; 1509 | [imageToNSString replaceOccurrencesOfString:@"//" withString:@"/" options:nil range:NSMakeRange(0, [imageToNSString length])]; 1510 | double prct=(double)((double)i/(double)_cacheHead->numlibs)*(double)100; 1511 | CDLog(@"Current Image %@",imageToNSString); 1512 | parseImage((char *)[imageToNSString UTF8String],writeToDisk,outputDir,getSymbols,YES,YES,simpleHeader,skipAlreadyFound,skipApplications,(int)prct); 1513 | [imageToNSString release]; 1514 | 1515 | } 1516 | munmap(_cacheData, filesize); 1517 | close(fd); 1518 | printf("\n Finished dumping "BOLDWHITE"%s..."RESET"\n\n",filename); 1519 | } 1520 | if (recursive){ 1521 | 1522 | NSFileManager *fileman=[[NSFileManager alloc ] init]; 1523 | NSError *error = nil; 1524 | if (![fileman fileExistsAtPath:outputDir]) { 1525 | [fileman createDirectoryAtPath:outputDir withIntermediateDirectories:YES attributes:nil error:&error]; 1526 | if (error){ 1527 | NSLog(@"Could not create directory %@. Check permissions.",outputDir); 1528 | exit(EXIT_FAILURE); 1529 | } 1530 | } 1531 | [fileman changeCurrentDirectoryPath:currentDir]; 1532 | [fileman changeCurrentDirectoryPath:outputDir]; 1533 | outputDir=[fileman currentDirectoryPath]; 1534 | [fileman changeCurrentDirectoryPath:currentDir]; 1535 | [fileman changeCurrentDirectoryPath:sourceDir]; 1536 | sourceDir=[fileman currentDirectoryPath]; 1537 | [fileman release]; 1538 | const char* dir_name=[sourceDir UTF8String]; 1539 | list_dir(dir_name,writeToDisk,outputDir,getSymbols,recursive,simpleHeader,skipAlreadyFound,skipApplications); 1540 | 1541 | 1542 | } 1543 | else{ 1544 | if (image){ 1545 | 1546 | NSError *error = nil; 1547 | NSFileManager *fileman=[[NSFileManager alloc ] init]; 1548 | NSString *imageString=nil; 1549 | if (outputDir){ 1550 | if (![fileman fileExistsAtPath:outputDir]) { 1551 | [fileman createDirectoryAtPath:outputDir withIntermediateDirectories:YES attributes:nil error:&error]; 1552 | if (error){ 1553 | NSLog(@"Could not create directory %@. Check permissions.",outputDir); 1554 | exit(EXIT_FAILURE); 1555 | } 1556 | } 1557 | [fileman changeCurrentDirectoryPath:currentDir]; 1558 | [fileman changeCurrentDirectoryPath:outputDir]; 1559 | outputDir=[fileman currentDirectoryPath]; 1560 | 1561 | imageString=[NSString stringWithCString:image encoding:NSUTF8StringEncoding]; 1562 | 1563 | if ([imageString rangeOfString:@"/"].location!=0){ // not an absolute path 1564 | 1565 | [fileman changeCurrentDirectoryPath:currentDir]; 1566 | NSString *append=[imageString lastPathComponent]; 1567 | NSString *source=[imageString stringByDeletingLastPathComponent]; 1568 | [fileman changeCurrentDirectoryPath:source]; 1569 | imageString=[[fileman currentDirectoryPath] stringByAppendingString:[NSString stringWithFormat:@"/%@",append]]; 1570 | image=(char *)[imageString UTF8String]; 1571 | 1572 | } 1573 | } 1574 | RESULT = parseImage(image,writeToDisk,outputDir,getSymbols,NO,buildOriginalDirs,simpleHeader,NO,skipApplications,0); 1575 | [fileman release]; 1576 | } 1577 | } 1578 | 1579 | if (RESULT){ 1580 | if (RESULT==4){ 1581 | printf(" %s cannot be dumped with classdump-dyld.\n",image); 1582 | exit(1); 1583 | } 1584 | else if (RESULT==2){ 1585 | printf(" %s does not implement any classes.\n",image); 1586 | exit(1); 1587 | } 1588 | else if (RESULT==3){ 1589 | exit(1); 1590 | } 1591 | else{ 1592 | if (writeToDisk){ 1593 | printf(" Done. Check \"%s\" directory.\n",[inoutputDir UTF8String]); 1594 | } 1595 | } 1596 | } 1597 | 1598 | } 1599 | 1600 | exit(0); 1601 | 1602 | } 1603 | 1604 | 1605 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | classdump-dyld 2 | ============== 3 | 4 | Major update 5 | ------------ 6 | 7 | As of February 5 2016, I have added cycript integration. 8 | 9 | You can now dlopen /usr/lib/libclassdumpdyld.dylib in cycript after injecting any application, 10 | 11 | and dlsym the dumpClass and dumpBundle functions. 12 | 13 | extern "C" NSString * dumpClass(Class *aClass); 14 | 15 | extern "C" NSString * dumpBundle(NSBundle *aBundle); 16 | 17 | extern "C" NSString * dumpBundleForClass(Class *aClass); 18 | 19 | 20 | This is extremely useful in cases when classdump-dyld cannot inject and dump applications. 21 | 22 | (This makes weak_classdump project obsolete) 23 | 24 | A typical usage in cycript would be: 25 | 26 | #cycript -p SpringBoard 27 | 28 | @import net.limneos.classdumpdyld; 29 | 30 | classdumpdyld.dumpClass(SpringBoard); 31 | @"Wrote file /tmp/SpringBoard.h" 32 | 33 | classdumpdyld.dumpBundle([NSBundle mainBundle]); 34 | @"Wrote all headers to /tmp/SpringBoard" 35 | 36 | // Dump any bundle other than the main bundle 37 | classdumpdyld.dumpBundle([NSBundle bundleWithIdentifier:@"com.apple.UIKit"]); 38 | @"Wrote all headers to /tmp/UIKit" 39 | 40 | // Dump any image loaded in the process using any class name it contains 41 | classdumpdyld.dumpBundleForClass(CallBarControllerModern); 42 | @"Wrote all headers to /tmp/CallBar7" 43 | 44 | ----------------------------- 45 | 46 | General Info 47 | ------------ 48 | Added 64bit executables dumping and single class dumping 49 | 50 | A class dumping command line tool that generates header files from app binaries, libraries, frameworks, bundles or the whole dyld_shared_cache. 51 | 52 | Eliminates the need to extract files from the dyld_shared_cache in order to class-dump them or get symbols. 53 | 54 | Mass-dumps whole dyld_shared_cache or directories containing any mach-o file recursively. 55 | 56 | You can instantly classdump any compatible Mach-o file, either if it is physically stored on disk or it resides in the dyld_shared_cache. 57 | 58 | Features and options: 59 | 60 | * Classdump files that appear malformed to the usual tools on device. 61 | * Classdump files or frameworks on runtime without extracting them from dyld_shared_cache. 62 | * Classdump files that reside on disk as usual 63 | * Recursively search for compatible files and dump them (e.g. whole directory of "/System/Library", "/Applications" or "/" ) 64 | * Recursively dump all the images stored in dyld_shared_cache 65 | * Generate symbols list for files that are stored in dyld_shared_cache without extracting them. 66 | * Generation of all structs, symbols and necessary #imports to correctly fill up each header file. (I pray for that) 67 | 68 | 69 | You can find a recursive sample output on this project under iphoneheaders. 70 | It also works on a Mac for dyld_shared_cache and some libraries 71 | 72 | 73 | ------------------------------- 74 | 75 | Usage: classdump-dyld [] 76 | 77 | classdump-dyld [] -r 78 | 79 | 80 | Options: 81 | 82 | Structure: 83 | -g Generate symbol names 84 | -h Add a \"Headers\" directory to place headers in 85 | -b Build original directory structure in output dir 86 | -u Do not include framework when importing headers ("Header.h" instead of ) 87 | 88 | Output: 89 | -o Save generated headers to defined path 90 | 91 | Single Class: 92 | -j Dump only the specified class name. (Does not work with -c or -r ) 93 | This might also dump additional imported or required headers. 94 | 95 | Mass dumping: (requires -o) 96 | -c Dump all images found in dyld_shared_cache 97 | -r Recursively dump any compatible Mach-O file found in the given path (requires -o) 98 | -s In a recursive dump, skip header files already found in the same output directory 99 | 100 | Miscellaneous: 101 | -D Enable debug printing for troubleshooting errors 102 | -e dpopen 32Bit executables instead of injecting them (iOS 5+, use if defaults fail.This will skip any 64bit executable) 103 | -a In a recursive dump, include 'Applications' directories (skipped by default) 104 | Examples: 105 | Example 1: classdump-dyld -o outdir /System/Library/Frameworks/UIKit.framework 106 | Example 2: classdump-dyld -o outdir /usr/libexec/backboardd 107 | Example 3 (recursive): classdump-dyld -o outdir -c (Dumps all files residing in dyld_shared_cache) 108 | Example 4 (recursive): classdump-dyld -o outdir -r /Applications 109 | Example 5 (recursive): classdump-dyld -o outdir -r / -c (Mass-dumps almost everything on device) 110 | 111 | 112 | Usage limitations 113 | ---------------- 114 | classdump-dyld works with Mach-o files only. 115 | Some files have protection against being dynamically loaded from a different process. 116 | In those cases, you can use weak_classdump or other tools. 117 | 118 | 119 | by Elias Limneos 120 | ---------------- 121 | web: limneos.net 122 | 123 | twitter: @limneos 124 | 125 | 126 | Licence 127 | ----------- 128 | 129 | classdump-dyld is Copyright (c) 2013-2016 Elias Limneos, licensed under GPLv3. 130 | 131 | 132 | Environment 133 | ----------- 134 | classdump-dyld works in a command line shell on any iOS 5+ device and Mac OS X. Tested from iOS 5.x to iOS 8.x and Mac OSX 10.8+. 135 | 136 | 137 | 138 | --------------------------------------------------------------------------------