/ 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  }