├── README.md ├── LICENSE ├── ZLJPrinter.h ├── .gitignore └── ZLJPrinter.m /README.md: -------------------------------------------------------------------------------- 1 | # ZLJBlockPrinter 2 | Print MethodSignature And VMAddr of Blocks! 3 | Article:http://iosre.com/t/zljblockprinter-block/15231 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 zljkevin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /ZLJPrinter.h: -------------------------------------------------------------------------------- 1 | // 2 | // ZLJPrinter.h 3 | // SMS 4 | // 5 | // Created by Mu on 2019/8/1. 6 | // 7 | 8 | #import 9 | #import 10 | #import 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @interface ZLJPrinter : NSObject 15 | 16 | + (NSString *)printBlock:(id)aBlock; 17 | + (NSString *)callStackSymbolsLocateInImages:(NSArray *)images; 18 | 19 | @end 20 | 21 | NS_ASSUME_NONNULL_END 22 | 23 | 24 | /* block 内存结构 25 | struct Block_literal_1 { 26 | void *isa; //16byte initialized to &_NSConcreteStackBlock or &_NSConcreteGlobalBlock 27 | int flags; //8byte 28 | int reserved; //8byte 29 | void (*invoke)(void *, ...); //16byte 30 | struct Block_descriptor_1 { //16byte 31 | unsigned long int reserved; //16byte NULL 32 | unsigned long int size; //16byte sizeof(struct Block_literal_1) 33 | // optional helper functions 34 | void (*copy_helper)(void *dst, void *src); //16byte IFF (1<<25) 35 | void (*dispose_helper)(void *src); //16byte IFF (1<<25) 36 | // required ABI.2010.3.16 37 | const char *signature; //16byte IFF (1<<30) 38 | } *descriptor; 39 | // imported variables 40 | }; 41 | 42 | struct BlockLiteral { 43 | void *isa; 44 | int flags; 45 | int reserved; 46 | void (*invoke)(void *, ...); 47 | struct BlockDescriptor *descriptor; 48 | }; 49 | 50 | struct BlockDescriptor { 51 | unsigned long int reserved; 52 | unsigned long int size; 53 | void (*copy_helper)(void *dst, void *src); 54 | void (*dispose_helper)(void *src); 55 | const char *signature; 56 | }; 57 | 58 | */ 59 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | # CocoaPods 32 | # 33 | # We recommend against adding the Pods directory to your .gitignore. However 34 | # you should judge for yourself, the pros and cons are mentioned at: 35 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 36 | # 37 | # Pods/ 38 | 39 | # Carthage 40 | # 41 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 42 | # Carthage/Checkouts 43 | 44 | Carthage/Build 45 | 46 | # fastlane 47 | # 48 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 49 | # screenshots whenever they are needed. 50 | # For more information about the recommended setup visit: 51 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 52 | 53 | fastlane/report.xml 54 | fastlane/Preview.html 55 | fastlane/screenshots/**/*.png 56 | fastlane/test_output 57 | 58 | # Code Injection 59 | # 60 | # After new code Injection tools there's a generated folder /iOSInjectionProject 61 | # https://github.com/johnno1962/injectionforxcode 62 | 63 | iOSInjectionProject/ 64 | -------------------------------------------------------------------------------- /ZLJPrinter.m: -------------------------------------------------------------------------------- 1 | // 2 | // ZLJPrinter.m 3 | // SMS 4 | // 5 | // Created by Mu on 2019/8/1. 6 | // 7 | 8 | #import "ZLJPrinter.h" 9 | 10 | @implementation ZLJPrinter 11 | 12 | + (NSString *)callStackSymbolsLocateInImages:(NSArray *)images{ 13 | 14 | NSArray *preSetImages = [@[ 15 | @"libdyld.dylib", 16 | @"UIKit", 17 | @"GraphicsServices", 18 | @"CoreFoundation", 19 | @"Foundation", 20 | @"CoreTelephony", 21 | ] mutableCopy]; 22 | 23 | NSMutableDictionary *baseAddrDic = [[NSMutableDictionary alloc]init]; 24 | 25 | for(int i = 0; i < _dyld_image_count(); i++) 26 | { 27 | intptr_t base_addr = _dyld_get_image_vmaddr_slide(i); 28 | const char *name = _dyld_get_image_name(i); 29 | NSString *nameStr = [NSString stringWithUTF8String:name]; 30 | 31 | if ([images containsObject:[nameStr lastPathComponent]] || 32 | [preSetImages containsObject:[nameStr lastPathComponent]]) { 33 | [baseAddrDic setObject:@(base_addr) forKey:[nameStr lastPathComponent]]; 34 | } 35 | } 36 | 37 | NSArray *syms = [NSThread callStackSymbols]; 38 | 39 | NSMutableString *retStr = [[NSMutableString alloc]init]; 40 | [retStr appendString:@"\n\n/***ZLJ CallStackSymbols Start***/\n"]; 41 | for (NSString *sym in syms) { 42 | 43 | NSMutableArray *symUnits = [[sym componentsSeparatedByString:@" "] mutableCopy]; 44 | while ([symUnits containsObject:@""]) { 45 | [symUnits removeObject:@""]; 46 | } 47 | 48 | if (symUnits.count >= 3 && [symUnits[2] hasPrefix:@"0x"]) { 49 | 50 | char *symVMAddrStr = (char *)symUnits[2].UTF8String; 51 | char *endPtr; 52 | NSInteger symVMAddr = strtol(symVMAddrStr, &endPtr, 16); 53 | 54 | if ([baseAddrDic.allKeys containsObject:symUnits[1]]) { 55 | NSInteger symFileAddr = symVMAddr - [baseAddrDic objectForKey:symUnits[1]].integerValue; 56 | if (symFileAddr <= 0) { 57 | [retStr appendFormat:@"%@ = 0x%lx ≈ symFileAddr\n", sym, symUnits.lastObject.integerValue]; 58 | }else{ 59 | [retStr appendFormat:@"%@ symFileAddr 0x%lx\n", sym, symFileAddr]; 60 | } 61 | }else{ 62 | [retStr appendFormat:@"%@\n", sym]; 63 | } 64 | 65 | }else{ 66 | [retStr appendFormat:@"%@\n", sym]; 67 | } 68 | } 69 | [retStr appendString:@"/***ZLJ CallStackSymbols End***/\n\n"]; 70 | 71 | NSLog(@"%@",retStr); 72 | 73 | return retStr; 74 | } 75 | 76 | 77 | + (NSString *)printBlock:(id)aBlock{ 78 | 79 | if (!([aBlock isKindOfClass:NSClassFromString(@"__NSGlobalBlock__")] || 80 | [aBlock isKindOfClass:NSClassFromString(@"__NSMallocBlock__")] || 81 | [aBlock isKindOfClass:NSClassFromString(@"__NSStackBlock__")] )) { 82 | return @"ZLJBlockPrinter Error: Not A Block!"; 83 | } 84 | 85 | uint64_t blockInMemory[4]; //block 在内存中的前4个uint64_t 86 | uint64_t descriptor[5]; //block的descriptor 在内存中的前5个uint64_t 87 | char *signatureCStr; 88 | NSMethodSignature *blockSignature; 89 | 90 | void *aBlockPtr = (__bridge void *)(aBlock); 91 | memcpy(blockInMemory, (void *)aBlockPtr, sizeof(blockInMemory)); 92 | memcpy(descriptor, (void *)blockInMemory[3], sizeof(descriptor)); 93 | 94 | BOOL hasSignature = ((blockInMemory[1] & 0x00000000FFFFFFFF) & (1 << 30)) != 0; 95 | if (!hasSignature) { 96 | return @"ZLJBlockPrinter: Block Do Not Have Signature!"; 97 | } 98 | 99 | BOOL hasCopyDisposeHelper = ((blockInMemory[1] & 0x00000000FFFFFFFF) & (1 << 25)) != 0; 100 | 101 | if (hasCopyDisposeHelper) { 102 | signatureCStr = (char *)descriptor[4]; 103 | }else{ 104 | signatureCStr = (char *)descriptor[2]; 105 | } 106 | blockSignature = [NSMethodSignature signatureWithObjCTypes:signatureCStr]; 107 | 108 | NSString *retStr = [NSString stringWithFormat:@"\n%@\nBlockVmaddrSlide:0x%llx\nBlockSignature:%@", 109 | aBlock, 110 | blockInMemory[2], 111 | blockSignature.debugDescription]; 112 | NSLog(@"%@",retStr); 113 | 114 | return retStr; 115 | } 116 | 117 | //+ (NSString *)printBlock:(id)aBlock inImage:(nullable NSString *)imageName{ 118 | // 119 | // if (!([aBlock isKindOfClass:NSClassFromString(@"__NSGlobalBlock__")] || 120 | // [aBlock isKindOfClass:NSClassFromString(@"__NSMallocBlock__")] || 121 | // [aBlock isKindOfClass:NSClassFromString(@"__NSStackBlock__")] )) { 122 | // return @"ZLJBlockPrinter Error: Not A Block!"; 123 | // } 124 | // 125 | // uint64_t blockInMemory[4]; //block 在内存中的前4个uint64_t 126 | // uint64_t descriptor[5]; //block的descriptor 在内存中的前5个uint64_t 127 | // char *signatureCStr; 128 | // NSMethodSignature *blockSignature; 129 | // 130 | // void *aBlockPtr = (__bridge void *)(aBlock); 131 | // memcpy(blockInMemory, (void *)aBlockPtr, sizeof(blockInMemory)); 132 | // memcpy(descriptor, (void *)blockInMemory[3], sizeof(descriptor)); 133 | // 134 | // BOOL hasSignature = ((blockInMemory[1] & 0x00000000FFFFFFFF) & (1 << 30)) != 0; 135 | // if (!hasSignature) { 136 | // return @"ZLJBlockPrinter: Block Do Not Have Signature!"; 137 | // } 138 | // 139 | // 140 | // BOOL hasCopyDisposeHelper = ((blockInMemory[1] & 0x00000000FFFFFFFF) & (1 << 25)) != 0; 141 | // 142 | // if (hasCopyDisposeHelper) { 143 | // signatureCStr = (char *)descriptor[4]; 144 | // }else{ 145 | // signatureCStr = (char *)descriptor[2]; 146 | // } 147 | // blockSignature = [NSMethodSignature signatureWithObjCTypes:signatureCStr]; 148 | // 149 | // 150 | // uint64_t block_file_slide = 0; 151 | // if (imageName.length && [aBlock isKindOfClass:NSClassFromString(@"__NSGlobalBlock__")]) { 152 | // NSInteger image_vmaddr_slide = 0; 153 | // for(int i = 0; i < _dyld_image_count(); i++) 154 | // { 155 | // const char *name = _dyld_get_image_name(i); 156 | // NSString *nameStr = [NSString stringWithUTF8String:name]; 157 | // if ([nameStr containsString:imageName]) { 158 | // image_vmaddr_slide = _dyld_get_image_vmaddr_slide(i); 159 | // break; 160 | // } 161 | // } 162 | // block_file_slide = blockInMemory[2] - image_vmaddr_slide; 163 | // } 164 | // 165 | // NSString *ret = nil; 166 | // if (imageName.length && [aBlock isKindOfClass:NSClassFromString(@"__NSGlobalBlock__")]) { 167 | // ret = [NSString stringWithFormat:@"\n%@\nBlockVmaddrSlide(Check This Address In LLDB):0x%llx\nBlockFileSlide(Jump To This Address In IDA):0x%llx\nBlockSignature:%@", [aBlock class], blockInMemory[2], block_file_slide, blockSignature.debugDescription]; 168 | // }else{ 169 | // ret = [NSString stringWithFormat:@"\n%@\nBlockVmaddrSlide(Check This Address In LLDB):0x%llx\nBlockSignature:%@", aBlock, blockInMemory[2], blockSignature.debugDescription]; 170 | // } 171 | // 172 | // return ret; 173 | //} 174 | 175 | 176 | @end 177 | --------------------------------------------------------------------------------