Newer
Older
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
4021
4022
4023
4024
4025
4026
4027
4028
4029
4030
4031
4032
4033
4034
4035
4036
4037
4038
4039
4040
4041
4042
4043
4044
4045
4046
4047
4048
4049
4050
4051
4052
4053
4054
4055
4056
4057
if(!url)
url = decryptUrl(encrypted.signatureCipher, true);
return url;
}
source.decryptUrlTestN = function(n) {
prepareCipher();
let url = "https://whatever.com/asdgdsag?a=b&n=" + n + "&u=asd"
return decryptUrlN(url, true);
}
function decryptUrl(encrypted, jsUrl, doLogging) {
if(!encrypted) return null;
const query = parseQueryString(encrypted);
const baseUrl = query.url;
const sigKey = query.sp;
const sigValue = decodeCipher(decodeURIComponent(query.s), jsUrl);
let decryptedUrl = decodeURIComponent(baseUrl) + "&" + sigKey + "=" + sigValue;
if(doLogging) {
log("SigKey: " + sigKey);
log("SigValue: " + sigValue);
log("Decrypted: " + decryptedUrl);
}
return decryptUrlN(decryptedUrl, jsUrl, doLogging);
}
function decryptUrlN(url, jsUrl, doLogging) {
const nParamMatch = REGEX_PARAM_N.exec(url);
if(nParamMatch) {
const encryptedN = nParamMatch[1];
const decryptedN = decryptN(encryptedN, jsUrl);
if(doLogging) {
log("Encrypt URL:" + url);
log("NParam Found: " + encryptedN + " (length:" + encryptedN.length + ")");
log("NParam Decrypted: " + decryptedN + " (size:" + decryptedN.length + ")");
log("Decrypted URL:" + url.replace(encryptedN, decryptedN));
}
url = url.replace(encryptedN, decryptedN);
}
else if(doLogging)
log("No NParam found in (" + url + ")");
return url;
}
function decodeCipher(cipher, jsUrl) {
if(!_cipherDecode[jsUrl])
throw new ScriptException("Cipher decoder was not available [" + jsUrl + "]");
return _cipherDecode[jsUrl](cipher);
}
function decryptN(encryptedN, jsUrl) {
if(!_nDecrypt[jsUrl])
throw new ScriptException("N Decryptor was not available [" + jsUrl + "]");
return _nDecrypt[jsUrl](encryptedN);
}
function testCipher(hash) {
const jsUrl = CIPHER_TEST_PREFIX + hash + CIPHER_TEST_SUFFIX;
try{
const result = prepareCipher(jsUrl);
clearCipher(jsUrl);
return {
success: result,
exception: ""
};
}
catch(ex) {
return {
success: false,
exception: ex
};
}
}
source.testCipher = testCipher;
4076
4077
4078
4079
4080
4081
4082
4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
4105
function testCiphers() {
let testResults = [];
for(hash of CIPHER_TEST_HASHES) {
const jsUrl = CIPHER_TEST_PREFIX + hash + CIPHER_TEST_SUFFIX;
try{
if(prepareCipher(jsUrl))
testResults.push("CipherTest [" + hash + "]: PASSED");
else
testResults.push("CipherTest [" + hash + "]: FAIL");
}
catch(ex) {
testResults.push(["CipherTest [" + hash + "]: FAIL", ex]);
}
clearCipher(jsUrl);
}
for(result of testResults) {
if(result.constructor === Array)
console.log(result[0], result[1]);
else
console.log(result);
}
}
source.testCiphers = testCiphers;
function prepareCipher(jsUrl) {
if(_cipherDecode[jsUrl])
return false;//_cipherDecode[jsUrl];
log("New JS Url found: [" + jsUrl + "], fetching new js (total: " + (Object.keys(_cipherDecode).length + 1) + ")");
try{
const playerCodeResp = http.GET(URL_BASE + jsUrl, {});
if(!playerCodeResp.isOk) {
if(bridge.devSubmit) bridge.devSubmit("prepareCipher - Failed to get player js", jsUrl);
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
4123
4124
4125
4126
4127
4128
4129
4130
4131
4132
console.log("Javascript Url: " + URL_BASE + jsUrl);
const playerCode = playerCodeResp.body;
const cipherFunctionCode = getCipherFunctionCode(playerCode, jsUrl);
console.log("DecodeCipher Function: " + cipherFunctionCode);
_cipherDecode[jsUrl] = eval(cipherFunctionCode);
const decryptFunctionCode = getNDecryptorFunctionCode(playerCode, jsUrl);
console.log("DecryptN Function: " + decryptFunctionCode);
_nDecrypt[jsUrl] = eval(decryptFunctionCode);
const stsMatch = playerCode.match(STS_REGEX);
console.log("stsMatch: " + stsMatch);
if (stsMatch !== null && stsMatch.length > 1) {
const sts = stsMatch[1];
_sts[jsUrl] = sts;
console.log("sts: " + sts);
}
return true;//_cipherDecode[jsUrl];
}
catch(ex) {
clearCipher(jsUrl);
if(bridge.devSubmit) bridge.devSubmit("prepareCipher - Failed to get Cipher due to: " + ex, jsUrl);
throw new ScriptException("Failed to get Cipher due to: " + ex);
}
}
source.prepareCipher = prepareCipher;
function clearCipher(jsUrl) {
if(_cipherDecode[jsUrl])
_cipherDecode[jsUrl] = undefined;
if(_nDecrypt[jsUrl])
_nDecrypt[jsUrl] = undefined;
}
function getNDecryptorFunctionCode(code, jsUrl) {
if(_nDecrypt[jsUrl])
return _nDecrypt[jsUrl];
const nDecryptFunctionArrNameMatch = REGEX_DECRYPT_N.exec(code);
if(!nDecryptFunctionArrNameMatch) {
if(bridge.devSubmit) bridge.devSubmit("getNDecryptorFunctionCode - Failed to find n decryptor (name)", jsUrl);
const nDecryptFunctionArrName = nDecryptFunctionArrNameMatch[1];
const nDecryptFunctionArrIndex = parseInt(nDecryptFunctionArrNameMatch[2]);
const nDecryptFunctionNameMatch = code.match(nDecryptFunctionArrName + "\\s*=\\s*\\[([a-zA-Z0-9,\\(,\\)\\.]+?)]");
if(!nDecryptFunctionNameMatch) {
if(bridge.devSubmit) bridge.devSubmit("getNDecryptorFunctionCode - Failed to find n decryptor (array)", jsUrl);
throw new ScriptException("Failed to find n decryptor (array)");
if(nDecryptArray.length <= nDecryptFunctionArrIndex) {
if(bridge.devSubmit) bridge.devSubmit("getNDecryptorFunctionCode - Failed to find n decryptor (index)", jsUrl);
throw new ScriptException("Failed to find n decryptor (index)");
const nDecryptFunctionName = nDecryptArray[nDecryptFunctionArrIndex];
const nDecryptFunctionCodeMatch = code.match(nDecryptFunctionName + "=function\\(a\\)\\{[\\s\\S]*?join\\(\\\"\\\"\\)};");
if(!nDecryptFunctionCodeMatch) {
if(bridge.devSubmit) bridge.devSubmit("getNDecryptorFunctionCode - Failed to find n decryptor (code)", jsUrl, code);
return "(function(){" +
"var " + nDecryptFunctionCodeMatch[0] + "\n" +
"return function decryptN(nEncrypted){ return " + nDecryptFunctionName + "(nEncrypted); } \n" +
"})()";
}
function getCipherFunctionCode(playerCode, jsUrl) {
if(_cipherDecode[jsUrl])
return _cipherDecode[jsUrl];
let cipherFunctionName = null;
for(let i = 0; i < REGEX_CIPHERS.length; i++) {
const match = playerCode.match(REGEX_CIPHERS[i]);
if(match) {
cipherFunctionName = match[1];
break;
}
}
if(!cipherFunctionName) {
if(bridge.devSubmit) bridge.devSubmit("getCipherFunctionCode - Failed to find cipher (name)", jsUrl);
const cipherFunctionCodeMatch = playerCode.match("(" + cipherFunctionName.replace("$", "\\$") + "=function\\([a-zA-Z0-9_]+\\)\\{.+?\\})");
if(!cipherFunctionCodeMatch) {
if(IS_TESTING)
console.log("Failed to find cipher function in: ", playerCode);
if(bridge.devSubmit) bridge.devSubmit("getCipherFunctionCode - Failed to find cipher (function)", jsUrl);
throw new ScriptException("Failed to find cipher (function)");
}
const cipherFunctionCode = cipherFunctionCodeMatch[1];
const cipherFunctionCodeVar = "var " + cipherFunctionCode;
const helperObjNameMatch = cipherFunctionCode.match(";([A-Za-z0-9_\\$]{2,3})\\...\\(");
if(!helperObjNameMatch) {
if(IS_TESTING)
console.log("Failed to find helper name in: ", playerCode);
if(bridge.devSubmit) bridge.devSubmit("getCipherFunctionCode - Failed to find helper (name)", jsUrl);
throw new ScriptException("Failed to find helper (name)");
}
if(IS_TESTING)
console.log("Cipher Code: ", cipherFunctionCode);
const helperObjName = helperObjNameMatch[1];
const helperObjMatch = playerCode.match("(var " + escapeRegex(helperObjName) + "=\\{[\\s\\S]*?\\};)");
if(!helperObjMatch) {
if(IS_TESTING)
console.log("Failed to find helper method [" + helperObjName + "] in: ", playerCode);
if(bridge.devSubmit) bridge.devSubmit("getCipherFunctionCode - Failed to find helper (methods)", jsUrl);
4217
4218
4219
4220
4221
4222
4223
4224
4225
4226
4227
4228
4229
4230
4231
4232
4233
4234
4235
4236
4237
4238
4239
4240
4241
4242
4243
4244
4245
4246
4247
4248
4249
4250
4251
4252
4253
4254
4255
4256
4257
4258
4259
4260
4261
4262
4263
4264
4265
4266
4267
4268
throw new ScriptException("Failed to extract helper (methods)");
}
const helperObj = helperObjMatch[1];
const functionCode = "return function decodeCipher(str){ return " + cipherFunctionName + "(str); }";
return "(function(){" + helperObj + "\n" +
cipherFunctionCodeVar + "\n" +
functionCode + "})()";
}
function escapeRegex(str) {
return str.replace("$", "\\$");
}
function decodeHexEncodedString(str) {
return str.replace(/\\x([0-9A-Fa-f]{2})/g, function() {
return String.fromCharCode(parseInt(arguments[1], 16));
});
}
function parseQueryString(query) {
if(query.indexOf("?") >= 0)
query = query.substring(query.indexOf("?") + 1);
const parts = query.split("&");
const results = {};
for(let i = 0; i < parts.length; i++) {
const part = parts[i];
const valueIndex = part.indexOf("=");
if(valueIndex == -1)
results[part] = true;
else
results[part.substring(0, valueIndex)] = part.substring(valueIndex + 1);
}
return results;
}
//#endregion
//#region Others
const RANDOM_CHARACTER_SET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
function randomString(length) {
let str = "";
for(let i = 0; i < length; i++)
str += RANDOM_CHARACTER_SET[Math.floor(Math.random() * RANDOM_CHARACTER_SET.length)]
return str;
}
function randomInt(start, end) {
return Math.floor(random() * (end + start) - end);
}
//#endregion
console.log("LOADED");