20220701更新 4.14.0-4.20.0破解1. 修复EVP_VerifyDigestFinal地址获取2. 修复错误SGUProFeatureDefine unlockTime整体流程初始化(入口)网络请求检查license - Refresh请求破解Hook网络请求Payload生成hook sign校验函数记录历程
20220701更新 4.14.0-4.20.0破解
1. 修复EVP_VerifyDigestFinal地址获取
- 4.14.0 之后Surge改为使用独立的OpenSSL.framework
- 使用MSGetImageByName + MSFindSymbol
2. 修复错误SGUProFeatureDefine unlockTime
- 由于不明原因,- [SGUProFeatureDefine unlockTime]始终返回94665600000(和下图相比少一个0)
- 直接hook掉这个函数返回0,可以正常绕过
整体流程
初始化(入口)
在加载主界面Feature列表、授权管理、开启Tunnel等UI操作,以及Tunnel和主程序的Timer会调用refresh接口来定期检查lic
网络请求
所有的请求都会经过一个callSurgeLicServer函数,符合传递DeviceID等公用参数
这个函数支持ac,refresh,activate,deactivate,migratev2等接口
其中ac、refresh为定期检查调用,其他则为授权管理相关
检查license - Refresh请求
curl --insecure -H 'User-Agent:' -v -X POST 'https://www.surge-activation.com/ios/v3/refresh' -H 'Content-Type: application/json' -d '{"system":"iOS","build":1966,"bundle":"com.nssurge.inc.surge-ios","deviceName":"iPad","deviceID":"485987D7C875","testflight":true,"systemVersion":"Version 14.2 (Build 18B92)","jailbroken":true,"metadata":{"InitDeviceID":"ADE568FA6F3F"},"deviceModel":"iPad11,4"}'
{"license":{"policy":"eyJkZXZpY2VJRCI6IjQ4NTk4N0Q3Qzg3NSIsImV4cGlyYXRpb25EYXRlIjoxNjI5NDIwMDgzLCJmdXNEYXRlIjoxNTk2MDIwMjA3LCJ0eXBlIjoibGljZW5zZWQiLCJpc3N1ZURhdGUiOjE2MjgxMjQwODMsInAiOiJlNVBZTm9HOWhLUUhBL0licEtsRzhRPT0ifQ==","sign":"Uxv//O3zOFJs40ML1cugN9PAaCqLFxr7y4oi2z4/J7JFFQ1oNkMkYAmu0hroubKQqo7bQL4SbN4zhvFLL//OSScihQrgI6s8JON5QMeE6SRTkKauZdNvxGqQ6DM3KeTW1XTIz/gxGWZRKoUTA2NV2vkF4jZLtA86GvJL+8Iubqx0DGRM11dK+vzYVrYkKqb6qqKvhN9yAFU6Pse00Q7pRJcBb8fzF2Ei4K5OEjUWl1cSRa8wpssCcVr02ckgEsk503w7LpuPlCGbA16JR8RB5VKkuAT3miy7mUdXBckGABlbtkuAiuc/IxZUdV5v3AdtK+KX1JrPNE4f7SlFmDT+9Q=="}}
服务器返回的license中policy如下,sign则由内置的证书验证签名
{"deviceID":"485987D7C875","expirationDate":1629420083,"fusDate":1596020207,"type":"licensed","issueDate":1628124083,"p":"e5PYNoG9hKQHA/IbpKlG8Q=="}
程序检查sign正确后,对比deviceID,并进一步取出fusDate、expirationDate,用于判断license状态,expirationDate代表这个request的过期时间,而fusDate则代表订阅过期时间
订阅过期时间fusDate与每个FeatureDefine中定义的unlockTime比对,从而判断是否解锁
p则在NE Plugin中解密,得到由SHA256(deviceID)[0:32]做密钥,SHA256(deviceID)[16:32]做iv,AES-CBC的结果,内容为:
00000000 03 04 02 4e 53 45 78 74 65 6e 73 69 6f 6e 00 |...NSExtension.| [0] = 3, 为固定header [1] = 4, 控制VMess加密 [2] = 2, 控制TCP、SS的端口字节数 [3:] = "NSExtension", 控制TE plugin加载
破解
切入点:虚拟license服务器
Hook网络请求
所有的激活请求全部都走的
SGNSARequestHelper - (id)request:(NSMutableURLRequest *)req completeBlock:(void (^)(NSData *body, NSURLResponse *resp, NSError *err))completeBlock
Payload生成
比对url格式后,针对性生成payload
- 篡改后的License信息
NSDictionary *licInfo = @{ @"deviceID": deviceID, @"expirationDate": @4070880000, // 2099-01-01 00:00:00 @"fusDate": @4070880000, @"type": @"licensed", @"issueDate": [NSNumber numberWithInt:(long)[[NSDate date] timeIntervalSince1970]], @"p": p, };
- 生成p并base64:
AES_CBC_256( input: "\x03\x04\x02NSExtension", key: SHA256(deviceID), iv: SHA256(deviceID)[16:32], options: PKCS7Padding)
- 组合成最终payload
{"license":{"policy":"base64(licInfo)","sign":""}}
hook sign校验函数
校验中间并没有检查每个函数的返回值,只检查了最后EVP_DigestVerifyFinal的返回值,而EVP_DigestVerifyFinal正好具有极强的pattern可以直接由Lumina识别,直接memmem即可找到对应函数地址,返回1即可
记录历程
- 收集其他人的Patch:Flex上有hook SGUPro类的,cydia上有Surge增强版hook,都下载下来了
- 寻找关键点:直接用Flexing从SGUPro开头的类开始找,发现只有SGUPro相关的View Controller
- 逆向SGUProViewController,找到License校验起始函数
- 快速浏览逻辑,并确认Surge在竭尽全力使用网络校验
- 使用License的位置极多,爆破太傻
- 如果没有完全爆破掉,可能会导致license检查时发送错误的数据,导致license被吊销
- 决定直接hook网络请求
- 检查了所有网络请求函数调用的来源,发现了大量暗桩
- 编写Hook