From 80147413ee3190bb530f8f6b02738bcc787a6444 Mon Sep 17 00:00:00 2001 From: ThetaDev Date: Fri, 13 Dec 2024 22:36:01 +0100 Subject: [PATCH] fix: nsig fn extra variable extraction --- src/deobfuscate.rs | 76 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 65 insertions(+), 11 deletions(-) diff --git a/src/deobfuscate.rs b/src/deobfuscate.rs index b767302..c4d8ca1 100644 --- a/src/deobfuscate.rs +++ b/src/deobfuscate.rs @@ -206,6 +206,11 @@ fn extract_js_fn(js: &str, offset: usize, name: &str) -> Result = HashMap::new(); + let global_objects = [ + "NaN", "Infinity", "Object", "Function", "Boolean", "Symbol", "Error", "Number", "BigInt", + "Math", "Date", "String", "RegExp", "Array", "Map", "Set", + ]; + for item in scan { let it = item?; let token = it.token; @@ -240,12 +245,14 @@ fn extract_js_fn(js: &str, offset: usize, name: &str) -> Result Result Option { +fn extract_js_var(js: &str) -> Option<&str> { let scan = ress::Scanner::new(js); let mut braces: Vec = Vec::new(); let mut end = 0; @@ -299,17 +313,29 @@ fn extract_js_var(js: &str) -> Option { }; for item in scan { - let it = item.ok()?; + let it = match item { + Ok(it) => it, + Err(e) => { + // If the variable definition is the last statement in a closure and followed by a } + // the scanner thinks the code is invalid + if e.msg == "unmatched close brace" && braces.is_empty() { + end = e.idx; + break; + } else { + return None; + } + } + }; let token = it.token; if let Token::Punct(p) = &token { match p { - ress::tokens::Punct::OpenBrace => braces.push(b'}'), + ress::tokens::Punct::OpenBrace => braces.push(b'{'), ress::tokens::Punct::OpenBracket => braces.push(b'['), ress::tokens::Punct::OpenParen => braces.push(b'('), - ress::tokens::Punct::CloseBrace => close_brace(&mut braces, b'}')?, - ress::tokens::Punct::CloseBracket => close_brace(&mut braces, b']')?, - ress::tokens::Punct::CloseParen => close_brace(&mut braces, b')')?, + ress::tokens::Punct::CloseBrace => close_brace(&mut braces, b'{')?, + ress::tokens::Punct::CloseBracket => close_brace(&mut braces, b'[')?, + ress::tokens::Punct::CloseParen => close_brace(&mut braces, b'(')?, ress::tokens::Punct::Comma | ress::tokens::Punct::SemiColon => { if braces.is_empty() { end = it.span.start; @@ -320,7 +346,13 @@ fn extract_js_var(js: &str) -> Option { } } } - Some(js[0..end].to_owned()) + if end > 0 { + Some(&js[0..end]) + } else if braces.is_empty() { + Some(js) + } else { + None + } } /// Verify if the deobfuscation function successfully processes a random input string @@ -499,6 +531,28 @@ 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!( + res, + "var a = {v1:1,v2:2}; var Wka = function(d){var x=1+2+a.v1;return x;};" + ); + } + + #[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!( + res, + "var a=[1,2,3]; var Wka = function(d){var x=1+2+a[0];return x;};" + ); + } + #[test] fn t_get_nsig_fn() { let res = get_nsig_fn(&TEST_JS).unwrap();