refactored, started with get_player_js (TEMP)

This commit is contained in:
ThetaDev 2022-07-21 17:13:50 +02:00
parent 0c76125595
commit 0acf8a9fb9
5 changed files with 307 additions and 333 deletions

View file

@ -14,10 +14,5 @@ anyhow = "1.0"
thiserror = "1.0.31"
url = "2.2.2"
log = "0.4.17"
[dev-dependencies]
criterion = "0.3.6"
[[bench]]
name = "my_benchmark"
harness = false
reqwest = "0.11.11"
tokio = {version = "1.20.0", features = ["macros"]}

View file

@ -1,44 +0,0 @@
use criterion::{criterion_group, criterion_main, Criterion};
use rusty_pipe::*;
const TEST_JS: &str = include_str!("../notes/base.js");
fn bench_match_to_closing_parenthesis(c: &mut Criterion) {
c.bench_function("match_to_closing_parenthesis", |b| {
b.iter(|| match_to_closing_parenthesis(TEST_JS, "Vo=function"))
});
}
fn bench_sig(c: &mut Criterion) {
c.bench_function("deobf_sig", |b| {
b.iter(|| {
let dcode = load_deobfuscation_code(TEST_JS).unwrap();
deobfuscate_signature("GOqGOqGOq0QJ8wRAIgaryQHfplJ9xJSKFywyaSMHuuwZYsoMTAvRvfm51qIGECIA5061zWeyfMPX9hEl_U6f9J0tr7GTJMKyPf5XNrJb5fb5i", &dcode).unwrap()
})
});
c.bench_function("deobf_nsig", |b| {
b.iter(|| {
let name = get_n_deobfuscation_function_name(TEST_JS).unwrap();
let dcode = parse_n_decode_function(TEST_JS, &name).unwrap();
deobfuscate_n_signature(&dcode, &name, "BI_n4PxQ22is-KKajKUW").unwrap()
})
});
}
fn bench_sig_cached(c: &mut Criterion) {
let sig_dcode = load_deobfuscation_code(TEST_JS).unwrap();
let nsig_name = get_n_deobfuscation_function_name(TEST_JS).unwrap();
let nsig_dcode = parse_n_decode_function(TEST_JS, &nsig_name).unwrap();
c.bench_function("deobf_sig_cached", |b| {
b.iter(|| deobfuscate_signature("GOqGOqGOq0QJ8wRAIgaryQHfplJ9xJSKFywyaSMHuuwZYsoMTAvRvfm51qIGECIA5061zWeyfMPX9hEl_U6f9J0tr7GTJMKyPf5XNrJb5fb5i", &sig_dcode).unwrap())
});
c.bench_function("deobf_sig_cached", |b| {
b.iter(|| deobfuscate_n_signature(&nsig_dcode, &nsig_name, "BI_n4PxQ22is-KKajKUW").unwrap())
});
}
criterion_group!(benches, bench_match_to_closing_parenthesis, bench_sig, bench_sig_cached);
criterion_main!(benches);

303
src/deobfuscate.rs Normal file
View file

@ -0,0 +1,303 @@
use anyhow::{anyhow, bail, Result};
use fancy_regex::Regex;
use once_cell::sync::Lazy;
use quick_js::Context;
use std::result::Result::Ok;
pub struct Deobfuscator {
// js_url: String,
// last_update
sig_fn: String,
nsig_fn: String,
}
impl Deobfuscator {
pub fn from_js(player_js: &str) -> Result<Self> {
Ok(Self {
sig_fn: get_sig_fn(player_js)?,
nsig_fn: get_nsig_fn(player_js)?,
})
}
pub fn deobfuscate_sig(&self, sig: &str) -> Result<String> {
deobfuscate_sig(sig, &self.sig_fn)
}
pub fn deobfuscate_nsig(&self, nsig: &str) -> Result<String> {
deobfuscate_nsig(nsig, &self.nsig_fn)
}
}
const DEOBFUSCATION_FUNC_NAME: &str = "deobfuscate";
fn get_sig_fn_name(player_js: &str) -> Result<String> {
static FUNCTION_PATTERNS: Lazy<[Regex; 6]> = Lazy::new(|| {
[
Regex::new("(?:\\b|[^a-zA-Z0-9$])([a-zA-Z0-9$]{2,})\\s*=\\s*function\\(\\s*a\\s*\\)\\s*\\{\\s*a\\s*=\\s*a\\.split\\(\\s*\"\"\\s*\\)").unwrap(),
Regex::new("\\bm=([a-zA-Z0-9$]{2,})\\(decodeURIComponent\\(h\\.s\\)\\)").unwrap(),
Regex::new("\\bc&&\\(c=([a-zA-Z0-9$]{2,})\\(decodeURIComponent\\(c\\)\\)").unwrap(),
Regex::new("([\\w$]+)\\s*=\\s*function\\((\\w+)\\)\\{\\s*\\2=\\s*\\2\\.split\\(\"\"\\)\\s*;").unwrap(),
Regex::new("\\b([\\w$]{2,})\\s*=\\s*function\\((\\w+)\\)\\{\\s*\\2=\\s*\\2\\.split\\(\"\"\\)\\s*;").unwrap(),
Regex::new("\\bc\\s*&&\\s*d\\.set\\([^,]+\\s*,\\s*(:encodeURIComponent\\s*\\()([a-zA-Z0-9$]+)\\(").unwrap(),
]
});
FUNCTION_PATTERNS
.iter()
.find_map(|pattern| pattern.captures(player_js).ok().flatten())
.map(|c| c.get(1).unwrap().as_str().to_string())
.ok_or_else(|| anyhow!("could not find deobf function name"))
}
fn caller_function(fn_name: &str) -> String {
"function ".to_string() + DEOBFUSCATION_FUNC_NAME + "(a){return " + &fn_name + "(a);}"
}
fn get_sig_fn(player_js: &str) -> Result<String> {
let dfunc_name = get_sig_fn_name(player_js)?;
let function_pattern_str = "(".to_string()
+ &dfunc_name.replace('$', "\\$")
+ "=function\\([a-zA-Z0-9_]+\\)\\{.+?\\})";
let function_pattern = ok_or_bail!(
Regex::new(&function_pattern_str),
Err(anyhow!("could not parse function pattern regex"))
);
let deobfuscate_function = "var ".to_string()
+ some_or_bail!(
function_pattern.captures(player_js).ok().flatten(),
Err(anyhow!("could not find deobf function"))
)
.get(1)
.unwrap()
.as_str()
+ ";";
let helper_object_name_pattern = Regex::new(";([A-Za-z0-9_\\$]{2})\\...\\(").unwrap();
let helper_object_name = some_or_bail!(
helper_object_name_pattern
.captures(&deobfuscate_function)
.ok()
.flatten(),
Err(anyhow!("could not find helper object name"))
)
.get(1)
.unwrap()
.as_str();
let helper_pattern_str =
"(var ".to_string() + &helper_object_name.replace('$', "\\$") + "=\\{.+?\\}\\};)";
let helper_pattern = ok_or_bail!(
Regex::new(&helper_pattern_str),
Err(anyhow!("could not parse helper pattern regex"))
);
let player_js_nonl = player_js.replace('\n', "");
let helper_object = some_or_bail!(
helper_pattern.captures(&player_js_nonl).ok().flatten(),
Err(anyhow!("could not find helper object"))
)
.get(1)
.unwrap()
.as_str();
Ok(helper_object.to_string() + &deobfuscate_function + &caller_function(&dfunc_name))
}
fn deobfuscate_sig(sig: &str, sig_fn: &str) -> Result<String> {
let context = Context::new()?;
context.eval(sig_fn)?;
let res = context.call_function(DEOBFUSCATION_FUNC_NAME, vec![sig])?;
match res.as_str() {
Some(res) => Ok(res.to_string()),
None => bail!("deobfuscation func returned null"),
}
}
fn get_nsig_fn_name(player_js: &str) -> Result<String> {
let function_name_pattern =
Regex::new("\\.get\\(\"n\"\\)\\)&&\\(b=([a-zA-Z0-9$]+)(?:\\[(\\d+)])?\\([a-zA-Z0-9]\\)")
.unwrap();
let fname_match = some_or_bail!(
function_name_pattern.captures(player_js).ok().flatten(),
Err(anyhow!("could not find n_deobf function"))
);
let function_name = fname_match.get(1).unwrap().as_str();
if fname_match.len() == 1 {
return Ok(function_name.to_string());
}
let array_num = fname_match.get(2).unwrap().as_str().parse::<u32>()?;
let array_pattern_str =
"var ".to_string() + &fancy_regex::escape(function_name) + "\\s*=\\s*\\[(.+?)];";
let array_pattern = Regex::new(&array_pattern_str)?;
let array_str = some_or_bail!(
array_pattern.captures(player_js).ok().flatten(),
Err(anyhow!("could not find n_deobf array_str"))
)
.get(1)
.unwrap()
.as_str();
let mut names = array_str.split(',');
let name = some_or_bail!(
names.nth(array_num.try_into()?),
Err(anyhow!(
"could not get {}th item from {}",
array_num,
array_str
))
);
Ok(name.to_string())
}
fn match_to_closing_parenthesis(string: &str, start: &str) -> Option<String> {
let mut start_index = string.find(start)?;
start_index += start.len();
let mut visited_par = false;
let mut open_par = 0;
let mut res = String::new();
for c in string[start_index..].chars() {
res.push(c);
match c {
'{' => {
visited_par = true;
open_par += 1;
}
'}' => {
open_par -= 1;
}
_ => {}
};
if visited_par && open_par == 0 {
break;
}
}
Some(res)
}
fn get_nsig_fn(player_js: &str) -> Result<String> {
let function_name = get_nsig_fn_name(player_js)?;
// Find using parentheses
let function_base = function_name.to_string() + "=function";
let nsig_fn_code = match match_to_closing_parenthesis(player_js, &function_base) {
Some(m) => function_base.clone() + &m + ";",
None => {
// Find using regex
let player_js_nonl = player_js.replace('\n', "");
let function_pattern_str = function_name.to_string() + "=function(.*?}};)\n";
let function_pattern = Regex::new(&function_pattern_str)?;
let function = some_or_bail!(
function_pattern.captures(&player_js_nonl)?,
Err(anyhow!("could not find n_decode function"))
)
.get(1)
.unwrap()
.as_str();
"function ".to_string() + function
}
};
Ok(nsig_fn_code + &caller_function(&function_name))
}
fn deobfuscate_nsig(sig: &str, nsig_fn: &str) -> Result<String> {
let context = quick_js::Context::new()?;
context.eval(nsig_fn)?;
let res = context.call_function(DEOBFUSCATION_FUNC_NAME, vec![sig])?;
match res.as_str() {
Some(res) => Ok(res.to_string()),
None => bail!("deobfuscation func returned null"),
}
}
async fn get_player_js_url() -> Result<String> {
let resp = reqwest::get("https://www.youtube.com/iframe_api").await?;
let text = resp.text().await?;
println!("{}", text);
Ok("x".to_string())
}
#[cfg(test)]
mod tests {
use super::*;
const TEST_JS: &str = include_str!("../notes/base.js");
const N_DEOBF_FUNC: &str = r#"Vo=function(a){var b=a.split(""),c=[function(d,e,f){var h=f.length;d.forEach(function(l,m,n){this.push(n[m]=f[(f.indexOf(l)-f.indexOf(this[m])+m+h--)%f.length])},e.split(""))},
928409064,-595856984,1403221911,653089124,-168714481,-1883008765,158931990,1346921902,361518508,1403221911,-362174697,-233641452,function(){for(var d=64,e=[];++d-e.length-32;){switch(d){case 91:d=44;continue;case 123:d=65;break;case 65:d-=18;continue;case 58:d=96;continue;case 46:d=95}e.push(String.fromCharCode(d))}return e},
b,158931990,791141857,-907319795,-1776185924,1595027902,-829736173,function(d,e){e=(e%d.length+d.length)%d.length;d.splice(0,1,d.splice(e,1,d[0])[0])},
-1274951142,function(){for(var d=64,e=[];++d-e.length-32;){switch(d){case 91:d=44;continue;case 123:d=65;break;case 65:d-=18;continue;case 58:d=96;continue;case 46:d=95}e.push(String.fromCharCode(d))}return e},
1758743891,function(d){d.reverse()},
-830417133,"AF43j",1942017693,function(d,e){e=(e%d.length+d.length)%d.length;d.splice(e,1)},
null,-959991459,-287691724,-1365731946,b,1250397544,-1883008765,-1912322658,b,1300441121,null,-1962382380,1954679120,function(d){for(var e=d.length;e;)d.push(d.splice(--e,1)[0])},
-985125467,function(d,e){for(e=(e%d.length+d.length)%d.length;e--;)d.unshift(d.pop())},
null,497372841,-1912651541,function(d,e){d.push(e)},
function(d,e){e=(e%d.length+d.length)%d.length;d.splice(-e).reverse().forEach(function(f){d.unshift(f)})},
function(d,e){e=(e%d.length+d.length)%d.length;var f=d[0];d[0]=d[e];d[e]=f}];
c[30]=c;c[40]=c;c[46]=c;try{c[43](c[34]),c[45](c[40],c[47]),c[46](c[51],c[33]),c[16](c[47],c[36]),c[38](c[31],c[49]),c[16](c[11],c[39]),c[0](c[11]),c[35](c[0],c[30]),c[35](c[4],c[17]),c[34](c[48],c[7],c[11]()),c[35](c[4],c[23]),c[35](c[4],c[9]),c[5](c[48],c[28]),c[36](c[46],c[16]),c[4](c[41],c[1]),c[4](c[16],c[28]),c[3](c[40],c[17]),c[9](c[8],c[23]),c[45](c[30],c[4]),c[50](c[3],c[28]),c[36](c[51],c[23]),c[14](c[0],c[24]),c[14](c[35],c[1]),c[20](c[51],c[41]),c[15](c[8],c[0]),c[31](c[35]),c[29](c[26]),
c[36](c[8],c[32]),c[20](c[25],c[10]),c[2](c[22],c[8]),c[32](c[20],c[16]),c[32](c[47],c[49]),c[1](c[44],c[28]),c[39](c[16]),c[32](c[42],c[22]),c[46](c[14],c[48]),c[26](c[29],c[10]),c[46](c[9],c[3]),c[32](c[45])}catch(d){return"enhanced_except_85UBjOr-_w8_"+a}return b.join("")};function deobfuscate(a){return Vo(a);}"#;
#[test]
fn test_get_sig_fn_name() {
let dfunc_name = get_sig_fn_name(TEST_JS).unwrap();
assert_eq!(dfunc_name, "Rva");
}
#[test]
fn test_get_sig_fn() {
let dcode = get_sig_fn(TEST_JS).unwrap();
assert_eq!(
dcode,
r#"var qB={w8:function(a){a.reverse()},EC:function(a,b){var c=a[0];a[0]=a[b%a.length];a[b%a.length]=c},Np:function(a,b){a.splice(0,b)}};var Rva=function(a){a=a.split("");qB.Np(a,3);qB.w8(a,41);qB.EC(a,55);qB.Np(a,3);qB.w8(a,33);qB.Np(a,3);qB.EC(a,48);qB.EC(a,17);qB.EC(a,43);return a.join("")};function deobfuscate(a){return Rva(a);}"#
);
}
#[test]
fn test_deobfuscate_sig() {
let dcode = get_sig_fn(TEST_JS).unwrap();
let deobf = deobfuscate_sig("GOqGOqGOq0QJ8wRAIgaryQHfplJ9xJSKFywyaSMHuuwZYsoMTAvRvfm51qIGECIA5061zWeyfMPX9hEl_U6f9J0tr7GTJMKyPf5XNrJb5fb5i", &dcode).unwrap();
assert_eq!(deobf, "AOq0QJ8wRAIgaryQHmplJ9xJSKFywyaSMHuuwZYsoMTfvRviG51qIGECIA5061zWeyfMPX9hEl_U6f9J0tr7GTJMKyPf5XNrJb5f");
}
#[test]
fn test_get_nsig_fn_name() {
let name = get_nsig_fn_name(TEST_JS).unwrap();
assert_eq!(name, "Vo");
}
#[test]
fn test_match_to_closing_parenthesis() {
let res =
match_to_closing_parenthesis("Kx Hello { Thx { Bye } } Wut {Tst {}}", "Hello").unwrap();
assert_eq!(res, " { Thx { Bye } }")
}
#[test]
fn test_get_nsig_fn() {
let res = get_nsig_fn(TEST_JS).unwrap();
assert_eq!(res, N_DEOBF_FUNC);
}
#[test]
fn test_deobfuscate_nsig() {
let res = deobfuscate_nsig("BI_n4PxQ22is-KKajKUW", N_DEOBF_FUNC).unwrap();
assert_eq!(res, "nrkec0fwgTWolw");
}
#[tokio::test]
async fn test_get_player_js_url() {
let x = get_player_js_url().await.unwrap();
}
}

View file

@ -1,268 +1,3 @@
use anyhow::{anyhow, bail, Result};
use fancy_regex::Regex;
use once_cell::sync::Lazy;
use quick_js::Context;
use std::result::Result::Ok;
#[macro_use] mod macros;
#[macro_use]
mod macros;
const DEOBFUSCATION_FUNC_NAME: &str = "deobfuscate";
fn get_deobfuscation_func_name(player_js: &str) -> Result<String> {
static FUNCTION_PATTERNS: Lazy<[Regex; 6]> = Lazy::new(|| {
[
Regex::new("(?:\\b|[^a-zA-Z0-9$])([a-zA-Z0-9$]{2,})\\s*=\\s*function\\(\\s*a\\s*\\)\\s*\\{\\s*a\\s*=\\s*a\\.split\\(\\s*\"\"\\s*\\)").unwrap(),
Regex::new("\\bm=([a-zA-Z0-9$]{2,})\\(decodeURIComponent\\(h\\.s\\)\\)").unwrap(),
Regex::new("\\bc&&\\(c=([a-zA-Z0-9$]{2,})\\(decodeURIComponent\\(c\\)\\)").unwrap(),
Regex::new("([\\w$]+)\\s*=\\s*function\\((\\w+)\\)\\{\\s*\\2=\\s*\\2\\.split\\(\"\"\\)\\s*;").unwrap(),
Regex::new("\\b([\\w$]{2,})\\s*=\\s*function\\((\\w+)\\)\\{\\s*\\2=\\s*\\2\\.split\\(\"\"\\)\\s*;").unwrap(),
Regex::new("\\bc\\s*&&\\s*d\\.set\\([^,]+\\s*,\\s*(:encodeURIComponent\\s*\\()([a-zA-Z0-9$]+)\\(").unwrap(),
]
});
FUNCTION_PATTERNS
.iter()
.find_map(|pattern| pattern.captures(player_js).ok().flatten())
.map(|c| c.get(1).unwrap().as_str().to_string())
.ok_or_else(|| anyhow!("could not find deobf function name"))
}
pub fn load_deobfuscation_code(player_js: &str) -> Result<String> {
let dfunc_name = get_deobfuscation_func_name(player_js)?;
let function_pattern_str = "(".to_string()
+ &dfunc_name.replace('$', "\\$")
+ "=function\\([a-zA-Z0-9_]+\\)\\{.+?\\})";
let function_pattern = ok_or_bail!(
Regex::new(&function_pattern_str),
Err(anyhow!("could not parse function pattern regex"))
);
let deobfuscate_function = "var ".to_string()
+ some_or_bail!(
function_pattern.captures(player_js).ok().flatten(),
Err(anyhow!("could not find deobf function"))
)
.get(1)
.unwrap()
.as_str()
+ ";";
let helper_object_name_pattern = Regex::new(";([A-Za-z0-9_\\$]{2})\\...\\(").unwrap();
let helper_object_name = some_or_bail!(
helper_object_name_pattern
.captures(&deobfuscate_function)
.ok()
.flatten(),
Err(anyhow!("could not find helper object name"))
)
.get(1)
.unwrap()
.as_str();
let helper_pattern_str =
"(var ".to_string() + &helper_object_name.replace('$', "\\$") + "=\\{.+?\\}\\};)";
let helper_pattern = ok_or_bail!(
Regex::new(&helper_pattern_str),
Err(anyhow!("could not parse helper pattern regex"))
);
let player_js_nonl = player_js.replace('\n', "");
let helper_object = some_or_bail!(
helper_pattern.captures(&player_js_nonl).ok().flatten(),
Err(anyhow!("could not find helper object"))
)
.get(1)
.unwrap()
.as_str();
let caller_function =
"function ".to_string() + DEOBFUSCATION_FUNC_NAME + "(a){return " + &dfunc_name + "(a);}";
Ok(helper_object.to_string() + &deobfuscate_function + &caller_function)
}
pub fn deobfuscate_signature(obfuscated_sig: &str, deobfuscation_code: &str) -> Result<String> {
let context = Context::new()?;
context.eval(deobfuscation_code)?;
let res = context.call_function(DEOBFUSCATION_FUNC_NAME, vec![obfuscated_sig])?;
match res.as_str() {
Some(res) => Ok(res.to_string()),
None => bail!("deobfuscation func returned null"),
}
}
pub fn get_n_deobfuscation_function_name(player_js: &str) -> Result<String> {
let function_name_pattern =
Regex::new("\\.get\\(\"n\"\\)\\)&&\\(b=([a-zA-Z0-9$]+)(?:\\[(\\d+)])?\\([a-zA-Z0-9]\\)")
.unwrap();
let fname_match = some_or_bail!(
function_name_pattern.captures(player_js).ok().flatten(),
Err(anyhow!("could not find n_deobf function"))
);
let function_name = fname_match.get(1).unwrap().as_str();
if fname_match.len() == 1 {
return Ok(function_name.to_string());
}
let array_num = fname_match.get(2).unwrap().as_str().parse::<u32>()?;
let array_pattern_str =
"var ".to_string() + &fancy_regex::escape(function_name) + "\\s*=\\s*\\[(.+?)];";
let array_pattern = Regex::new(&array_pattern_str)?;
let array_str = some_or_bail!(
array_pattern.captures(player_js).ok().flatten(),
Err(anyhow!("could not find n_deobf array_str"))
)
.get(1)
.unwrap()
.as_str();
let mut names = array_str.split(',');
let name = some_or_bail!(
names.nth(array_num.try_into()?),
Err(anyhow!(
"could not get {}th item from {}",
array_num,
array_str
))
);
Ok(name.to_string())
}
pub fn match_to_closing_parenthesis(string: &str, start: &str) -> Option<String> {
let mut start_index = string.find(start)?;
start_index += start.len();
let mut visited_par = false;
let mut open_par = 0;
let mut res = String::new();
for c in string[start_index..].chars() {
res.push(c);
match c {
'{' => {
visited_par = true;
open_par += 1;
}
'}' => {
open_par -= 1;
}
_ => {}
}
if visited_par && open_par == 0 {
break;
}
}
Some(res)
}
pub fn parse_n_decode_function(player_js: &str, function_name: &str) -> Result<String> {
// Find using parentheses
let function_base = function_name.to_string() + "=function";
match match_to_closing_parenthesis(player_js, &function_base) {
Some(m) => Ok(function_base.clone() + &m + ";"),
None => {
// Find using regex
let player_js_nonl = player_js.replace('\n', "");
let function_pattern_str = function_name.to_string() + "=function(.*?}};)\n";
let function_pattern = Regex::new(&function_pattern_str)?;
let function = some_or_bail!(
function_pattern.captures(&player_js_nonl)?,
Err(anyhow!("could not find n_decode function"))
)
.get(1)
.unwrap()
.as_str();
Ok("function ".to_string() + function)
}
}
}
pub fn deobfuscate_n_signature(
function: &str,
function_name: &str,
obfuscated_sig: &str,
) -> Result<String> {
let context = quick_js::Context::new()?;
context.eval(function)?;
let res = context.call_function(function_name, vec![obfuscated_sig])?;
match res.as_str() {
Some(res) => Ok(res.to_string()),
None => bail!("deobfuscation func returned null"),
}
}
#[cfg(test)]
mod tests {
use super::*;
const TEST_JS: &str = include_str!("../notes/base.js");
const N_DEOBF_FUNC: &str = r#"Vo=function(a){var b=a.split(""),c=[function(d,e,f){var h=f.length;d.forEach(function(l,m,n){this.push(n[m]=f[(f.indexOf(l)-f.indexOf(this[m])+m+h--)%f.length])},e.split(""))},
928409064,-595856984,1403221911,653089124,-168714481,-1883008765,158931990,1346921902,361518508,1403221911,-362174697,-233641452,function(){for(var d=64,e=[];++d-e.length-32;){switch(d){case 91:d=44;continue;case 123:d=65;break;case 65:d-=18;continue;case 58:d=96;continue;case 46:d=95}e.push(String.fromCharCode(d))}return e},
b,158931990,791141857,-907319795,-1776185924,1595027902,-829736173,function(d,e){e=(e%d.length+d.length)%d.length;d.splice(0,1,d.splice(e,1,d[0])[0])},
-1274951142,function(){for(var d=64,e=[];++d-e.length-32;){switch(d){case 91:d=44;continue;case 123:d=65;break;case 65:d-=18;continue;case 58:d=96;continue;case 46:d=95}e.push(String.fromCharCode(d))}return e},
1758743891,function(d){d.reverse()},
-830417133,"AF43j",1942017693,function(d,e){e=(e%d.length+d.length)%d.length;d.splice(e,1)},
null,-959991459,-287691724,-1365731946,b,1250397544,-1883008765,-1912322658,b,1300441121,null,-1962382380,1954679120,function(d){for(var e=d.length;e;)d.push(d.splice(--e,1)[0])},
-985125467,function(d,e){for(e=(e%d.length+d.length)%d.length;e--;)d.unshift(d.pop())},
null,497372841,-1912651541,function(d,e){d.push(e)},
function(d,e){e=(e%d.length+d.length)%d.length;d.splice(-e).reverse().forEach(function(f){d.unshift(f)})},
function(d,e){e=(e%d.length+d.length)%d.length;var f=d[0];d[0]=d[e];d[e]=f}];
c[30]=c;c[40]=c;c[46]=c;try{c[43](c[34]),c[45](c[40],c[47]),c[46](c[51],c[33]),c[16](c[47],c[36]),c[38](c[31],c[49]),c[16](c[11],c[39]),c[0](c[11]),c[35](c[0],c[30]),c[35](c[4],c[17]),c[34](c[48],c[7],c[11]()),c[35](c[4],c[23]),c[35](c[4],c[9]),c[5](c[48],c[28]),c[36](c[46],c[16]),c[4](c[41],c[1]),c[4](c[16],c[28]),c[3](c[40],c[17]),c[9](c[8],c[23]),c[45](c[30],c[4]),c[50](c[3],c[28]),c[36](c[51],c[23]),c[14](c[0],c[24]),c[14](c[35],c[1]),c[20](c[51],c[41]),c[15](c[8],c[0]),c[31](c[35]),c[29](c[26]),
c[36](c[8],c[32]),c[20](c[25],c[10]),c[2](c[22],c[8]),c[32](c[20],c[16]),c[32](c[47],c[49]),c[1](c[44],c[28]),c[39](c[16]),c[32](c[42],c[22]),c[46](c[14],c[48]),c[26](c[29],c[10]),c[46](c[9],c[3]),c[32](c[45])}catch(d){return"enhanced_except_85UBjOr-_w8_"+a}return b.join("")};"#;
#[test]
fn test_get_deobfuscation_func_name() {
let dfunc_name = get_deobfuscation_func_name(TEST_JS).unwrap();
assert_eq!(dfunc_name, "Rva");
}
#[test]
fn test_load_deobfuscation_code() {
let dcode = load_deobfuscation_code(TEST_JS).unwrap();
assert_eq!(
dcode,
r#"var qB={w8:function(a){a.reverse()},EC:function(a,b){var c=a[0];a[0]=a[b%a.length];a[b%a.length]=c},Np:function(a,b){a.splice(0,b)}};var Rva=function(a){a=a.split("");qB.Np(a,3);qB.w8(a,41);qB.EC(a,55);qB.Np(a,3);qB.w8(a,33);qB.Np(a,3);qB.EC(a,48);qB.EC(a,17);qB.EC(a,43);return a.join("")};function deobfuscate(a){return Rva(a);}"#
);
}
#[test]
fn test_deobfuscate_signature() {
let dcode = load_deobfuscation_code(TEST_JS).unwrap();
let deobf = deobfuscate_signature("GOqGOqGOq0QJ8wRAIgaryQHfplJ9xJSKFywyaSMHuuwZYsoMTAvRvfm51qIGECIA5061zWeyfMPX9hEl_U6f9J0tr7GTJMKyPf5XNrJb5fb5i", &dcode).unwrap();
assert_eq!(deobf, "AOq0QJ8wRAIgaryQHmplJ9xJSKFywyaSMHuuwZYsoMTfvRviG51qIGECIA5061zWeyfMPX9hEl_U6f9J0tr7GTJMKyPf5XNrJb5f");
}
#[test]
fn test_get_n_deobfuscation_function_name() {
let name = get_n_deobfuscation_function_name(TEST_JS).unwrap();
assert_eq!(name, "Vo");
}
#[test]
fn test_match_to_closing_parenthesis() {
let res =
match_to_closing_parenthesis("Kx Hello { Thx { Bye } } Wut {Tst {}}", "Hello").unwrap();
assert_eq!(res, " { Thx { Bye } }")
}
#[test]
fn test_parse_n_decode_function() {
let res = parse_n_decode_function(TEST_JS, "Vo").unwrap();
assert_eq!(res, N_DEOBF_FUNC);
}
#[test]
fn test_deobfuscate_n_signature() {
let res = deobfuscate_n_signature(N_DEOBF_FUNC, "Vo", "BI_n4PxQ22is-KKajKUW").unwrap();
assert_eq!(res, "nrkec0fwgTWolw");
}
}
mod deobfuscate;

View file

@ -1,18 +1,3 @@
/// Aggressively prints to the terminal. Useful for rapid debugging in a sea of
/// terminal output.
#[allow(unused_macros)]
macro_rules! highlight {
($($arg:tt)+) => (
{
let indent = ">>>>>";
let focus = ">>>>>>";
let start = ">>>";
let end = ">>>";
println!("{}\n{}\n{} {}\n{}\n{}", start,indent,focus,format!($($arg)+),indent,end);
}
)
}
/// Returns an unwrapped Option if Some() otherwise returns the passed expression
#[allow(unused_macros)]
macro_rules! some_or_bail {