Surge破解

大类
Util
技术标签
逆向-iOS
开发-HookPatch-iOS
优先级
Low
开始日期
Aug 5, 2021
状态
Monitoring
Public
Public
最后更新
Jul 1, 2022

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)
    • notion image
  • 直接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
  1. 篡改后的License信息
    1. 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, };
  1. 生成p并base64:
    1. AES_CBC_256( input: "\x03\x04\x02NSExtension", key: SHA256(deviceID), iv: SHA256(deviceID)[16:32], options: PKCS7Padding)
  1. 组合成最终payload
    1. {"license":{"policy":"base64(licInfo)","sign":""}}
 

hook sign校验函数

校验中间并没有检查每个函数的返回值,只检查了最后EVP_DigestVerifyFinal的返回值,而EVP_DigestVerifyFinal正好具有极强的pattern可以直接由Lumina识别,直接memmem即可找到对应函数地址,返回1即可

记录历程

  1. 收集其他人的Patch:Flex上有hook SGUPro类的,cydia上有Surge增强版hook,都下载下来了
  1. 寻找关键点:直接用Flexing从SGUPro开头的类开始找,发现只有SGUPro相关的View Controller
  1. 逆向SGUProViewController,找到License校验起始函数
  1. 快速浏览逻辑,并确认Surge在竭尽全力使用网络校验
    1. 使用License的位置极多,爆破太傻
    2. 如果没有完全爆破掉,可能会导致license检查时发送错误的数据,导致license被吊销
    3. 决定直接hook网络请求
  1. 检查了所有网络请求函数调用的来源,发现了大量暗桩
  1. 编写Hook