├── README.md └── okhttp-sslunpinning.js /README.md: -------------------------------------------------------------------------------- 1 | # okhttp-sslunpinning 2 | 3 | 一个简单的frida脚本来过okhttp-sslpinning,主要针对被混淆过的okhttp框架,由于样本过少,就只根据手上的样本框架特征进行识别,大家可以自行添加特征点来做更好的混淆识别 4 | 5 | # 使用方法 6 | - frida -U -f packagename -l okhttp-sslunpining.js --no-pause 7 | - frida -UF -l okhttp-sslunpining.js 8 | 9 | # 注意 10 | 11 | 在使用spawn模式的时候,要注意OkhttpClient已加载到内存。如果没有加载,可以先用attach模式,识别到类名,然后使用Java.use("xxx")来主动加载 12 | 13 | -------------------------------------------------------------------------------- /okhttp-sslunpinning.js: -------------------------------------------------------------------------------- 1 | var classesNames = new Array() 2 | var OkhttpClientClassName = "" 3 | var CertificatePinnerClassName = "" 4 | var prefix = "" 5 | 6 | function initConsole(){ 7 | var Color = {RESET: "\x1b[39;49;00m", Black: "0;01", Blue: "4;01", Cyan: "6;01", Gray: "7;11", "Green": "2;01", Purple: "5;01", Yellow: "3;01", Red: "1;01"} 8 | var LightColor = {RESET: "\x1b[39;49;00m", Black: "0;11", Blue: "4;11", Cyan: "6;11", Gray: "7;01", "Green": "2;11", Purple: "5;11", Red: "1;11", Yellow: "3;11"} 9 | var colorPrefix = '\x1b[3' 10 | var colorSuffix = 'm' 11 | Object.keys(Color).forEach(function(c){ 12 | if (c == "RESET") 13 | return 14 | console[c] = function(message){ 15 | console.log(colorPrefix + Color[c] + colorSuffix + message + Color.RESET) 16 | } 17 | console["Light" + c] = function(message){ 18 | console.log(colorPrefix + LightColor[c] + colorSuffix + message + Color.RESET) 19 | } 20 | }) 21 | } 22 | 23 | function loadOkhttpClient(){ 24 | Java.perform(function (){ 25 | try{ 26 | Java.use("okhttp3.OkHttpClient") 27 | }catch(e){ 28 | //console.error(e) 29 | } 30 | }) 31 | 32 | } 33 | 34 | function loadClasses(){ 35 | Java.perform(function (){ 36 | Java.enumerateLoadedClasses({ 37 | onMatch: function(clsName, handle){ 38 | classesNames.push(clsName) 39 | }, 40 | onComplete: function(){ 41 | console.Green("Search Class Completed!") 42 | } 43 | }) 44 | }) 45 | } 46 | 47 | function findOkhttpClass(){ 48 | Java.perform(function (){ 49 | var Modifier = Java.use("java.lang.reflect.Modifier") 50 | function isOkhttpClient(clsName){ 51 | if(clsName.split('.').length != 2){ 52 | return false; 53 | } 54 | 55 | try{ 56 | var cls = Java.use(clsName) 57 | var interfaces = cls.class.getInterfaces() 58 | const count = interfaces.length 59 | if(count < 2){ 60 | return false 61 | } 62 | var flag = false 63 | for(var i = 0; i < count; i++){ 64 | var interface_ = interfaces[i] 65 | var interface_name = interface_.getName() 66 | 67 | if(interface_name.indexOf("Cloneable") > 0){ 68 | flag = true 69 | }else{ 70 | if(interface_name.indexOf("$") <= 0){ 71 | return false 72 | } 73 | } 74 | } 75 | if(!flag) return false; 76 | 77 | if(cls.class.getDeclaredClasses().length < 1){ 78 | return false 79 | } 80 | 81 | if(cls.class.getSuperclass().getName() != 'java.lang.Object'){ 82 | return false 83 | } 84 | 85 | }catch(e){ 86 | return false 87 | } 88 | return true; 89 | } 90 | 91 | function isCertificatePinner(clsName,prefix){ 92 | 93 | if(!clsName.startsWith(prefix)){ 94 | return false 95 | } 96 | 97 | if(clsName.indexOf("$") > 0){ 98 | return false 99 | } 100 | 101 | if(clsName.split('.').length != 2){ 102 | return false; 103 | } 104 | 105 | var cls = Java.use(clsName) 106 | if(cls.class.isInterface()){ 107 | return false 108 | } 109 | 110 | 111 | if(cls.class.getInterfaces().length > 0){ 112 | return false 113 | } 114 | 115 | 116 | if(cls.class.getDeclaredClasses().length < 1){ 117 | return false 118 | } 119 | 120 | if(cls.class.getSuperclass().getName() != "java.lang.Object"){ 121 | return false 122 | } 123 | 124 | if(!Modifier.isFinal(cls.class.getModifiers())){ 125 | return false 126 | } 127 | var flag = false 128 | var methods = cls.class.getDeclaredMethods() 129 | for(var i = 0; i < methods.length; i++){ 130 | var method = methods[i] 131 | if(method.getParameterCount() < 1){ 132 | continue 133 | } 134 | if(method.getParameterTypes()[0].getName() == "java.security.cert.Certificate"){ 135 | flag = true 136 | break 137 | } 138 | } 139 | if(!flag) return false 140 | 141 | flag = false 142 | var fields = cls.class.getDeclaredFields() 143 | for(var k = 0; k < fields.length; k++){ 144 | var field = fields[k]; 145 | if(field.getType().getName() == "java.util.Set"){ 146 | flag = true 147 | break 148 | } 149 | } 150 | if(!flag) return false 151 | return true 152 | } 153 | 154 | for(var i = 0; i < classesNames.length; i++){ 155 | if(isOkhttpClient(classesNames[i])){ 156 | OkhttpClientClassName = classesNames[i] 157 | var prefix = classesNames[i].split('.')[0]+'.' 158 | } 159 | } 160 | 161 | for(var i = 0; i < classesNames.length; i++){ 162 | if(isCertificatePinner(classesNames[i],prefix)){ 163 | CertificatePinnerClassName = classesNames[i] 164 | } 165 | } 166 | 167 | var printOut 168 | if(OkhttpClientClassName == "" || CertificatePinnerClassName == "" || prefix == ""){ 169 | printOut = console.Red 170 | printOut("Can't find the okhttp class") 171 | }else{ 172 | printOut = console.Green 173 | } 174 | printOut("Found Class: "+classesNames.length) 175 | printOut("Okhttp's package prefix: "+prefix) 176 | printOut("Found the OkhttpClient: "+OkhttpClientClassName) 177 | printOut("Found the OkhttpCertificatePinner: "+CertificatePinnerClassName) 178 | }) 179 | } 180 | 181 | function hook(){ 182 | Java.perform(function (){ 183 | var Modifier = Java.use("java.lang.reflect.Modifier") 184 | //TrustAllManager 185 | var TrustAllManagerClass = Java.registerClass({ 186 | name: "TrustAllManager", 187 | implements:[Java.use("javax.net.ssl.X509TrustManager")], 188 | methods: { 189 | checkClientTrusted(chain, authType) { 190 | console.Cyan("checkClientTrusted Called!!") 191 | }, 192 | checkServerTrusted(chain, authType) { 193 | console.Cyan("checkServerTrusted Called!!") 194 | }, 195 | getAcceptedIssuers() { 196 | return []; 197 | }, 198 | } 199 | }) 200 | var trustAllManagerHandle = TrustAllManagerClass.$new() 201 | 202 | var sslContext = Java.use("javax.net.ssl.SSLContext").getInstance("TLS") 203 | sslContext.init(null,Java.array("Ljavax.net.ssl.X509TrustManager;",[trustAllManagerHandle]),null) 204 | var sslSocketFactory = sslContext.getSocketFactory() 205 | 206 | //HostnameVerify 207 | var MyHostnameVerify = Java.registerClass({ 208 | name: "MyHostnameVerify", 209 | implements:[Java.use("javax.net.ssl.HostnameVerifier")], 210 | methods: { 211 | verify(hostname, session){ 212 | console.log(hostname) 213 | return true 214 | } 215 | } 216 | }) 217 | var myHostnameVerifyHandle = MyHostnameVerify.$new() 218 | 219 | var internalOkhttpClientClasses = Java.use(OkhttpClientClassName).class.getDeclaredClasses() 220 | internalOkhttpClientClasses.forEach(function (internalClass) { 221 | var methods = internalClass.getDeclaredMethods() 222 | methods.forEach(function(method) { 223 | if(method.getParameterCount() < 1){ 224 | return 225 | } 226 | var firstParameterTypeName = method.getParameterTypes()[0].getName() 227 | 228 | if(firstParameterTypeName == "javax.net.ssl.SSLSocketFactory"){ 229 | var Builder = Java.use(internalClass.getName()) 230 | var sslSocketFacotryMethodName = method.getName() 231 | Builder[sslSocketFacotryMethodName].overloads.forEach(function(overload){ 232 | overload.implementation = function(SSLSocketFactory){ 233 | arguments[0] = sslSocketFactory 234 | return this[sslSocketFacotryMethodName].apply(this,arguments) 235 | } 236 | console.Blue(sslSocketFacotryMethodName+" Hooked!") 237 | }); 238 | 239 | } 240 | if(firstParameterTypeName == "javax.net.ssl.HostnameVerifier"){ 241 | var Builder = Java.use(internalClass.getName()) 242 | var hostnameVerifierMethodName = method.getName() 243 | Builder[hostnameVerifierMethodName].overloads.forEach(function(overload){ 244 | overload.implementation = function(hostnameVerifier){ 245 | arguments[0] = myHostnameVerifyHandle 246 | return this[hostnameVerifierMethodName].apply(this,arguments) 247 | } 248 | console.Yellow(hostnameVerifierMethodName+" Hooked!") 249 | }); 250 | } 251 | 252 | if(firstParameterTypeName == CertificatePinnerClassName){ 253 | var Builder = Java.use(internalClass.getName()) 254 | var certificatePinnerMethodName = method.getName() 255 | 256 | Builder[certificatePinnerMethodName].overloads.forEach(function(overload){ 257 | overload.implementation = function(certificatePinner){ 258 | return Java.retain(this) 259 | } 260 | console.Purple(certificatePinnerMethodName+" Hooked!") 261 | }); 262 | 263 | } 264 | }) 265 | }); 266 | 267 | var CertificatePinnerClass = Java.use(CertificatePinnerClassName) 268 | var methods = CertificatePinnerClass.class.getDeclaredMethods() 269 | methods.forEach(function (method){ 270 | if(method.getReturnType().getName() == 'void'){ 271 | var methodName = method.getName() 272 | console.Cyan(methodName+" Hooked!") 273 | CertificatePinnerClass[methodName].overloads.forEach(function (overload){ 274 | if(overload.returnType.name == 'V'){ 275 | overload.implementation = function(){ 276 | console.Cyan("certificatePinner check called!") 277 | } 278 | } 279 | }) 280 | } 281 | }) 282 | }) 283 | } 284 | 285 | function main(){ 286 | initConsole() 287 | loadOkhttpClient() 288 | loadClasses() 289 | findOkhttpClass() 290 | hook() 291 | } 292 | setImmediate(main) --------------------------------------------------------------------------------