/ Tweak.xm
Tweak.xm
1 #import <Foundation/Foundation.h> 2 #import <CommonCrypto/CommonHMAC.h> 3 #import <substrate.h> 4 #import <dlfcn.h> 5 6 typedef void (*CCHmacType)(CCHmacAlgorithm algorithm, const void *key, size_t keyLength, const void *data, size_t dataLength, void *macOut); 7 typedef int (*CCHmacUpdateType)(CCHmacContext *ctx, const void *data, size_t dataLength); 8 typedef int (*CCHmacInitType)(CCHmacContext *ctx, CCHmacAlgorithm algorithm, const void *key, size_t keyLength); 9 typedef int (*CCHmacFinalType)(void *macOut, CCHmacContext *ctx); 10 11 static CCHmacType original_CCHmac = NULL; 12 static CCHmacUpdateType original_CCHmacUpdate = NULL; 13 static CCHmacInitType original_CCHmacInit = NULL; 14 static CCHmacFinalType original_CCHmacFinal = NULL; 15 16 void writeLog(NSString *message) { 17 NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]; 18 NSString *logFilePath = [documentsDirectory stringByAppendingPathComponent:@"CCHmacLogger.log"]; 19 20 // add timestamp to the log message 21 NSString *logEntry = [NSString stringWithFormat:@"%@: %@\n", [NSDate date], message]; 22 23 // write to file 24 NSFileHandle *fileHandle = [NSFileHandle fileHandleForWritingAtPath:logFilePath]; 25 if (fileHandle) { 26 [fileHandle seekToEndOfFile]; 27 [fileHandle writeData:[logEntry dataUsingEncoding:NSUTF8StringEncoding]]; 28 [fileHandle closeFile]; 29 } 30 else { 31 [logEntry writeToFile:logFilePath atomically:YES encoding:NSUTF8StringEncoding error:nil]; 32 } 33 } 34 35 NSString* algorithmToString(CCHmacAlgorithm algorithm) { 36 switch (algorithm) { 37 case kCCHmacAlgMD5: return @"MD5"; 38 case kCCHmacAlgSHA1: return @"SHA1"; 39 case kCCHmacAlgSHA224: return @"SHA224"; 40 case kCCHmacAlgSHA256: return @"SHA256"; 41 case kCCHmacAlgSHA384: return @"SHA384"; 42 case kCCHmacAlgSHA512: return @"SHA512"; 43 default: return @"Unknown Algorithm"; 44 } 45 } 46 47 size_t CCHmacOutputSize(CCHmacAlgorithm algorithm) { 48 switch (algorithm) { 49 case kCCHmacAlgMD5: return CC_MD5_DIGEST_LENGTH; 50 case kCCHmacAlgSHA1: return CC_SHA1_DIGEST_LENGTH; 51 case kCCHmacAlgSHA224: return CC_SHA224_DIGEST_LENGTH; 52 case kCCHmacAlgSHA256: return CC_SHA256_DIGEST_LENGTH; 53 case kCCHmacAlgSHA384: return CC_SHA384_DIGEST_LENGTH; 54 case kCCHmacAlgSHA512: return CC_SHA512_DIGEST_LENGTH; 55 default: return 0; 56 } 57 } 58 59 void hooked_CCHmac(CCHmacAlgorithm algorithm, const void *key, size_t keyLength, const void *data, size_t dataLength, void *macOut) { 60 original_CCHmac(algorithm, key, keyLength, data, dataLength, macOut); 61 62 NSMutableString *macOutput = [NSMutableString string]; 63 // length of the output is determined by the algorithm 64 for (size_t i = 0; i < CCHmacOutputSize(algorithm); i++) { 65 [macOutput appendFormat:@"%02x", ((unsigned char *)macOut)[i]]; 66 } 67 68 NSMutableString *keyString = [NSMutableString string]; 69 for (size_t i = 0; i < keyLength; i++) { 70 [keyString appendFormat:@"%02x", ((unsigned char *)key)[i]]; 71 } 72 73 NSMutableString *dataString = [NSMutableString string]; 74 for (size_t i = 0; i < dataLength; i++) { 75 [dataString appendFormat:@"%02x", ((unsigned char *)data)[i]]; 76 } 77 78 NSString *algorithmString = algorithmToString(algorithm); 79 80 writeLog([NSString stringWithFormat:@"CCHmac called: Algorithm=%@, KeyLength=%zu, InputLength=%zu", algorithmString, keyLength, dataLength]); 81 writeLog([NSString stringWithFormat:@"Key: %@", keyString]); 82 writeLog([NSString stringWithFormat:@"Input: %@", dataString]); 83 writeLog([NSString stringWithFormat:@"Output: %@", macOutput]); 84 } 85 86 int hooked_CCHmacUpdate(CCHmacContext *ctx, const void *data, size_t dataLength) { 87 int result = original_CCHmacUpdate(ctx, data, dataLength); 88 writeLog([NSString stringWithFormat:@"CCHmacUpdate called: InputLength=%zu", dataLength]); 89 90 NSMutableString *dataString = [NSMutableString string]; 91 for (size_t i = 0; i < dataLength; i++) { 92 [dataString appendFormat:@"%02x", ((unsigned char *)data)[i]]; 93 } 94 95 writeLog([NSString stringWithFormat:@"Input: %@", dataString]); 96 return result; 97 } 98 99 // store algorithm for use in CCHmacFinal 100 static CCHmacAlgorithm currentAlgorithm; 101 102 int hooked_CCHmacInit(CCHmacContext *ctx, CCHmacAlgorithm algorithm, const void *key, size_t keyLength) { 103 currentAlgorithm = algorithm; 104 105 NSString *algorithmString = algorithmToString(algorithm); 106 int result = original_CCHmacInit(ctx, algorithm, key, keyLength); 107 writeLog([NSString stringWithFormat:@"CCHmacInit called: Algorithm=%@, KeyLength=%zu", algorithmString, keyLength]); 108 109 NSMutableString *keyString = [NSMutableString string]; 110 for (size_t i = 0; i < keyLength; i++) { 111 [keyString appendFormat:@"%02x", ((unsigned char *)key)[i]]; 112 } 113 114 writeLog([NSString stringWithFormat:@"Key: %@", keyString]); 115 return result; 116 } 117 118 int hooked_CCHmacFinal(void *macOut, CCHmacContext *ctx) { 119 int result = original_CCHmacFinal(macOut, ctx); 120 writeLog(@"CCHmacFinal called"); 121 122 NSMutableString *macOutput = [NSMutableString string]; 123 // length of the output is determined by the algorithm 124 for (size_t i = 0; i < CCHmacOutputSize(currentAlgorithm); i++) { 125 [macOutput appendFormat:@"%02x", ((unsigned char *)macOut)[i]]; 126 } 127 128 writeLog([NSString stringWithFormat:@"Output: %@", macOutput]); 129 return result; 130 } 131 132 // entry point where we hook all functions 133 __attribute__((constructor)) static void init() { 134 original_CCHmac = (CCHmacType)dlsym(RTLD_DEFAULT, "CCHmac"); 135 if (original_CCHmac) MSHookFunction((void *)original_CCHmac, (void *)&hooked_CCHmac, (void **)&original_CCHmac); 136 else writeLog(@"Failed to find CCHmac"); 137 138 original_CCHmacUpdate = (CCHmacUpdateType)dlsym(RTLD_DEFAULT, "CCHmacUpdate"); 139 if (original_CCHmacUpdate) MSHookFunction((void *)original_CCHmacUpdate, (void *)&hooked_CCHmacUpdate, (void **)&original_CCHmacUpdate); 140 else writeLog(@"Failed to find CCHmacUpdate"); 141 142 original_CCHmacInit = (CCHmacInitType)dlsym(RTLD_DEFAULT, "CCHmacInit"); 143 if (original_CCHmacInit) MSHookFunction((void *)original_CCHmacInit, (void *)&hooked_CCHmacInit, (void **)&original_CCHmacInit); 144 else writeLog(@"Failed to find CCHmacInit"); 145 146 original_CCHmacFinal = (CCHmacFinalType)dlsym(RTLD_DEFAULT, "CCHmacFinal"); 147 if (original_CCHmacFinal) MSHookFunction((void *)original_CCHmacFinal, (void *)&hooked_CCHmacFinal, (void **)&original_CCHmacFinal); 148 else writeLog(@"Failed to find CCHmacFinal"); 149 }