Tower-9.0-342 MacOS漏洞分析
这是一款MacOS下面的GIT客户端,这里是一些分析日记,若有侵权,请联系我,秒删。
先安装,直接用Hopper Disassember调试,主要的模块是Tower/FNLicensing/FNFoundation。首先可以找到[GTProductConfig licenseCodeValidationPattern],这个函数校验了license格式,最终可以知道格式应该是这样:
TOWR(-[A-Z]{4}){4} TOWR-ABCD-ABCD-ABCD-ABCD
另外还有一系列的函数是关键点,可以从中获取各种重要信息:
模块:FNLicensing FNMachineIdentifier::obfuscatedMachineUUID FNLicensingFileHelpers::licenseFileURLForLicenseType FNLicenseStoreManager::readProductLicense read license file FNLicenseValidator::initWithProductConfig FNLicenseValidator::validateProductLicense FNProductLicense::licenseWithValuesFromDictionary FNLicenseHashGenerator::generateHashForDictionary FNLicenseHashGenerator::hashSourceForDictionary // see never is not expired... FNExpirationDateStringValueToExpirationDateTransformer::transformedValue
模块:Tower
[GTProductConfig defaultConfig]
[FNLicensingHelpers obfuscatedUserName]
[FNLicensingHelpers obfuscatedMachineUUID]
[FNLicensingHelpers machineName]
模块:FNFoundation
NSString::MD5String
还有一些用于加料的数据:
macuuid salt : S842!kJoqsoS(2kS(l2)=1100JkloAs2
key salt : JuD324AiNyS89oTtS10sVyJoUaAgNv1q
下面是一些关键字符串对应的名称,这些名称是dictionary的键,这些值的来源都可以通过前面的函数逆向分析得到。
// function name to string _FNLicenseKeyKey keys _FNLicenseKeyIdentifier uuid _FNLicenseKeyMachineID machine _FNLicenseKeyUserID user _FNLicenseKeyEmail email _FNLicenseKeyLicenseName name _FNLicenseKeyCode code _FNLicenseKeyMaskedLicenseCod license_code _FNLicenseKeyLicenseRevoked revoked _FNLicenseKeyExpirationDate expiration_date _FNLicenseKeyFeatures plan_features _FNLicenseKeyPlan plan _FNLicenseKeyPlanID plan_uuid _FNLicenseKeyProductName product _FNLicenseKeyLicenseType type _FNLicenseFeatureEnterpriseServices
如:
self.productName = @"tower"; self.productVersion = @"9.0"; self.machineUUID = [FNProductConfig ObfuscateMachineUUID]; self.userName = [FNProductConfig ObfuscateUserUUID]; self.licensesDirectory = [[NSURL URLWithString:[NSString stringWithFormat:@"%@com.fournova.Tower3/%@", [FNProductConfig ApplicationSupportDirectory], self.machineUUID]] path]; self.licensesFilePath = [NSString stringWithFormat:@"%@/license.plist", self.licensesDirectory]; // format is regex pattern : TOWR(-[A-Z]{4}){4} self.licenseCode = @"TOWR-ABCD-ABCD-ABCD-ABCD"; self.licensesUUID = [[NSUUID UUID] UUIDString];
+ (NSString*) ObfuscateMachineUUID { NSMutableString* hardwareID = [NSMutableString stringWithString:[self HardwareUUID]]; // add this salt [hardwareID appendString:@"S842!kJoqsoS(2kS(l2)=1100JkloAs2"]; NSString* md5 = [self MD5String:hardwareID]; return md5; } + (NSString*) ObfuscateUserUUID { NSString* username = NSUserName(); return [FNProductConfig MD5String:username]; }
在调试过程中,可以直接将这些数据调试输出出来:
// input license dictionary po $rax { code = code; email = email; "expiration_date" = never; "license_code" = "license_code"; machine = machine; plan = plan; "plan_features" = "plan_features"; "plan_uuid" = "plan_uuid"; product = product; revoked = false; type = type; user = user; uuid = uuid; } // all keys po $rax <__NSArrayI_Transfer 0x600000223b40>( uuid, expiration_date, user, machine, plan_uuid, product, type, code, revoked, plan, plan_features, license_code, email ) // all used keys , remove "code" po $rax <__NSFrozenArrayM 0x600000c58330>( uuid, expiration_date, user, machine, plan_uuid, product, type, revoked, plan, plan_features, license_code, email ) // sort ... po $rax <__NSArrayI_Transfer 0x600000249b00>( email, expiration_date, license_code, machine, plan, plan_features, plan_uuid, product, revoked, type, user, uuid ) // get values... po $rbx <__NSArrayM 0x600000c46a30>( email, never, license_code, cfbb84998c388b71a5ed275ae3aedf26, plan, plan_features, plan_uuid, product, false, type, f93d290deeda70e6270537a58d01d8a1, uuid )
在计算最终的license字符串时,将这些值使用都好分割组合成一个字符串,再将这个字符串计算MD5,这个MD5值就是目标序列号:
// join by "," po $rax email,never,license_code,cfbb84998c388b71a5ed275ae3aedf26,plan,plan_features,plan_uuid,product,false,type,f93d290deeda70e6270537a58d01d8a1,uuid // + salt , calc md5string // this is the license key. po $rbx fabc35e08c01c552248f659a888464c8
如:
// FNLicensing FNLicenseHashGenerator::hashSourceForDictionary + (NSString*) GenerateHashSourceForDictionary:(NSDictionary *)dict { // get all keys from dictionary NSArray* keys = [dict allKeys]; NSMutableArray* validKeys = [NSMutableArray arrayWithArray:keys]; // sort by alphabet // FNLicense sub_2518 [validKeys sortUsingComparator:^(NSString* l, NSString* r) { return [l compare:r]; }]; NSMutableArray* values = [NSMutableArray new]; for(int i=0; i<validKeys.count; ++i) { NSObject* value = [dict objectForKeyedSubscript:validKeys[i]]; if(![value isKindOfClass:[NSArray class]]) { [values addObject:value]; } } NSString* result = [values componentsJoinedByString:@","]; return result; }
- (NSString*) genHashSourceString { NSMutableDictionary* dict = [NSMutableDictionary dictionaryWithDictionary:[self genDictionary]]; NSString* baseHashSource = [FNProductConfig GenerateHashSourceForDictionary:dict]; NSString* salt = @"JuD324AiNyS89oTtS10sVyJoUaAgNv1q"; return [NSString stringWithFormat:@"%@%@", baseHashSource, salt]; } - (NSString*) genHashString { return [FNProductConfig MD5String:[self genHashSourceString]]; }
所以只要你能把这些东西都搞清楚,就可以搞一个注册机出来了。