From eda16e378730a3b57c4982a626df1622a93c574a Mon Sep 17 00:00:00 2001 From: ThetaDev Date: Wed, 5 Feb 2025 10:15:52 +0100 Subject: [PATCH] fix: extracting nsig fn when outside variable starts with $ --- src/deobfuscate.rs | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/src/deobfuscate.rs b/src/deobfuscate.rs index aab5d53..e1bc68e 100644 --- a/src/deobfuscate.rs +++ b/src/deobfuscate.rs @@ -117,12 +117,12 @@ const DEOBF_NSIG_FUNC_NAME: &str = "deobf_nsig"; fn get_sig_fn_name(player_js: &str) -> Result { let pattern = [ - r#"\b(?P[a-zA-Z0-9_$]+)&&\((?P=var)=(?P[a-zA-Z0-9_$]{2,})\(decodeURIComponent\((?P=var)\)\)"#, - r#"(?P[a-zA-Z0-9_$]+)\s*=\s*function\(\s*(?P[a-zA-Z0-9_$]+)\s*\)\s*{\s*(?P=arg)\s*=\s*(?P=arg)\.split\(\s*""\s*\)\s*;\s*[^}]+;\s*return\s+(?P=arg)\.join\(\s*""\s*\)"#, - r#"(?:\b|[^a-zA-Z0-9_$])(?P[a-zA-Z0-9_$]{2,})\s*=\s*function\(\s*a\s*\)\s*{\s*a\s*=\s*a\.split\(\s*""\s*\)(?:;[a-zA-Z0-9_$]{2}\.[a-zA-Z0-9_$]{2}\(a,\d+\))?"#, - r#"\b[cs]\s*&&\s*[adf]\.set\([^,]+\s*,\s*encodeURIComponent\s*\(\s*(?P[a-zA-Z0-9_$]+)\("#, - r#"\b[a-zA-Z0-9]+\s*&&\s*[a-zA-Z0-9]+\.set\([^,]+\s*,\s*encodeURIComponent\s*\(\s*(?P[a-zA-Z0-9_$]+)\("#, - r#"\bm=(?P[a-zA-Z0-9_$]{2,})\(decodeURIComponent\(h\.s\)\)"#, + r#"\b(?P[\w$]+)&&\((?P=var)=(?P[\w$]{2,})\(decodeURIComponent\((?P=var)\)\)"#, + r#"(?P[\w$]+)\s*=\s*function\(\s*(?P[\w$]+)\s*\)\s*{\s*(?P=arg)\s*=\s*(?P=arg)\.split\(\s*""\s*\)\s*;\s*[^}]+;\s*return\s+(?P=arg)\.join\(\s*""\s*\)"#, + r#"(?:\b|[^\w$])(?P[\w$]{2,})\s*=\s*function\(\s*a\s*\)\s*{\s*a\s*=\s*a\.split\(\s*""\s*\)(?:;[\w$]{2}\.[\w$]{2}\(a,\d+\))?"#, + r#"\b[cs]\s*&&\s*[adf]\.set\([^,]+\s*,\s*encodeURIComponent\s*\(\s*(?P[\w$]+)\("#, + r#"\b[a-zA-Z0-9]+\s*&&\s*[a-zA-Z0-9]+\.set\([^,]+\s*,\s*encodeURIComponent\s*\(\s*(?P[\w$]+)\("#, + r#"\bm=(?P[\w$]{2,})\(decodeURIComponent\(h\.s\)\)"#, ]; util::get_cg_from_fancy_regexes(&pattern, player_js, "sig") @@ -137,7 +137,7 @@ fn get_sig_fn(player_js: &str) -> Result { let dfunc_name = get_sig_fn_name(player_js)?; let function_pattern_str = format!( - r#"({}=function\([a-zA-Z0-9_]+\)\{{.+?\}})"#, + r#"({}=function\([\w]+\)\{{.+?\}})"#, dfunc_name.replace('$', "\\$") ); let function_pattern = Regex::new(&function_pattern_str) @@ -150,7 +150,7 @@ fn get_sig_fn(player_js: &str) -> Result { .ok_or(DeobfError::Extraction("sig fn"))?[1] ); - let helper_object_name_pattern = Regex::new(r";([A-Za-z0-9_\$]{2,3})\...\(").unwrap(); + let helper_object_name_pattern = Regex::new(r";([\w\$]{2,3})\...\(").unwrap(); let helper_object_name = helper_object_name_pattern .captures(&deobfuscate_function) .ok_or(DeobfError::Extraction("sig fn helper object name"))? @@ -182,7 +182,7 @@ fn get_sig_fn(player_js: &str) -> Result { fn get_nsig_fn_names(player_js: &str) -> impl Iterator + '_ { static FUNCTION_NAME_REGEX: Lazy = Lazy::new(|| { // x.get( .. y=functionName[array_num](z) .. x.set( - Regex::new(r#"(?:[a-zA-Z0-9_$]\.get\(|index\.m3u8).+[a-zA-Z]=([a-zA-Z0-9_$]{2,})(?:\[(\d+)\])?\([a-zA-Z0-9]\).+[a-zA-Z0-9]\.set\("#) + Regex::new(r#"(?:[\w$]\.get\(|index\.m3u8).+[a-zA-Z]=([\w$]{2,})(?:\[(\d+)\])?\([a-zA-Z0-9]\).+[a-zA-Z0-9]\.set\("#) .unwrap() }); @@ -288,12 +288,15 @@ fn extract_js_fn(js: &str, offset: usize, name: &str) -> Result Result { let code = extract_js_fn(player_js, offset, name)?; let js_fn = format!("{}{}", code, caller_function(DEOBF_NSIG_FUNC_NAME, name)); - tracing::trace!("sig_fn: {js_fn}"); + tracing::trace!("nsig_fn: {js_fn}"); verify_fn(&js_fn, DEOBF_NSIG_FUNC_NAME)?; tracing::debug!("successfully extracted nsig fn `{name}`"); Ok(js_fn) @@ -542,9 +545,9 @@ 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 #[test] fn t_extract_js_fn_outside_vars() { - // Function depending on outside variables let base_js = "let a = 42;foo();var b=11;bar();Wka = function(d){var x=1+2+a*b;return x;}"; let res = extract_js_fn(base_js, 0, "Wka").unwrap(); + // order of variables is non-reproducible assert!( res == "var a = 42; var b=11; var Wka = function(d){var x=1+2+a*b;return x;};" || res == "var b=11; var a = 42; var Wka = function(d){var x=1+2+a*b;return x;};", @@ -554,7 +557,6 @@ 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 #[test] fn t_extract_js_fn_outside_vars2() { - // Function depending on outside variables let base_js = "{let a = {v1:1,v2:2}}foo();Wka = function(d){var x=1+2+a.v1;return x;}"; let res = extract_js_fn(base_js, 0, "Wka").unwrap(); assert_eq!( @@ -565,7 +567,6 @@ 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 #[test] fn t_extract_js_fn_outside_vars3() { - // Function depending on outside variables let base_js = "Wka = function(d){var x=1+2+a[0];return x;};let a=[1,2,3]"; let res = extract_js_fn(base_js, 0, "Wka").unwrap(); assert_eq!( @@ -672,6 +673,7 @@ 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 #[case("b12cc44b", "keLa5R2U00sR9SQK", "N1OGyujjEwMnLw")] #[case("3bb1f723", "gK15nzVyaXE9RsMP3z", "ZFFWFLPWx9DEgQ")] #[case("2f1832d2", "YWt1qdbe8SAfkoPHW5d", "RrRjWQOJmBiP")] + #[case("19d2ae9d", "YWt1qdbe8SAfkoPHW5d", "CS6dVTYzpZrAZ5TD")] #[tokio::test] #[traced_test] async fn nsig_tests(#[case] js_hash: &str, #[case] nsig_in: &str, #[case] expect: &str) {