File size: 7,984 Bytes
94c29e9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
// JavaScript parsing utilities for extracting keys and analyzing code
use crate::utils::error::{ChatGptError, Result};
use regex::Regex;
use std::collections::HashMap;

/// JavaScript parser for analyzing decompiled code
pub struct Parser;

impl Parser {
    /// Find variable definition in JavaScript code
    ///
    /// This is a simplified version that uses regex patterns instead of full AST parsing
    pub fn find_var_definition(var_name: &str, start_line: usize, code: &str) -> Option<String> {
        let lines: Vec<&str> = code.lines().collect();

        // Search backwards from start_line
        for i in (0..start_line.min(lines.len())).rev() {
            let line = lines[i];

            // Look for variable declaration: var var_X = ...;
            let var_pattern = format!(r"var\s+var_{}\s*=\s*(.+?);", regex::escape(var_name));
            if let Ok(re) = Regex::new(&var_pattern) {
                if let Some(caps) = re.captures(line) {
                let value = caps.get(1)?.as_str().trim();

                // Skip complex operations
                if value.contains("btoa")
                    || value.contains("XOR_STR")
                    || value.contains("doubleXOR")
                    || value.contains("singlebtoa")
                {
                    continue;
                }

                return Some(value.to_string());
                }
            }
        }

        None
    }

    /// Parse assignments in decompiled JavaScript code
    pub fn parse_assignments(code: &str) -> HashMap<String, String> {
        let mut assignments = HashMap::new();

        // Find all variable assignments like: var_X = var_Y;
        let assign_re = Regex::new(r"var\s+var_(\w+)\s*=\s*(.+?);").unwrap();

        for caps in assign_re.captures_iter(code) {
            if let (Some(key), Some(value)) = (caps.get(1), caps.get(2)) {
                let key_str = key.as_str();
                let value_str = value.as_str().trim();

                // Skip function calls and complex expressions
                if !value_str.contains('(') || value_str.starts_with('"') {
                    assignments.insert(key_str.to_string(), value_str.to_string());
                }
            }
        }

        assignments
    }

    /// Extract XOR key from JavaScript code
    pub fn get_xor_key(js_code: &str) -> Option<String> {
        // Look for XOR_STR function calls: XOR_STR(var_X, "key") or XOR_STR(var_X, var_Y)
        let xor_pattern = Regex::new(r#"XOR_STR\s*\([^,]+,\s*([^)]+)\)"#).unwrap();

        for caps in xor_pattern.captures_iter(js_code) {
            if let Some(second_arg) = caps.get(1) {
                let arg = second_arg.as_str().trim();

                // If it's a string literal, return it
                if arg.starts_with('"') && arg.ends_with('"') {
                    return Some(arg.trim_matches('"').to_string());
                }

                // If it's a variable, try to find its value
                if arg.starts_with("var_") {
                    let var_name = arg.strip_prefix("var_").unwrap();
                    let var_pattern =
                        format!(r#"var\s+var_{}\s*=\s*"([^"]+)";"#, regex::escape(var_name));
                    if let Ok(re) = Regex::new(&var_pattern) {
                        if let Some(value_caps) = re.captures(js_code)
                    {
                        return value_caps.get(1).map(|m| m.as_str().to_string());
                        }
                    }
                }
            }
        }

        None
    }

    /// Parse keys from decompiled code
    pub fn parse_keys(decompiled_code: &str) -> Result<(String, HashMap<String, String>)> {
        let assignments = Self::parse_assignments(decompiled_code);
        let xor_key = Self::get_xor_key(decompiled_code)
            .ok_or_else(|| ChatGptError::vm_execution("XOR key not found"))?;

        let mut parsed_keys = HashMap::new();
        let mut random_index = 1;

        for (key, value) in assignments {
            let parsed_value = if value.starts_with("Array") && !value.contains("location") {
                // Parse array operations: Array(5) : 1.5 + 2.5
                if let Some(sum_part) = value.split(") : ").nth(1) {
                    let numbers: Vec<f64> = sum_part
                        .split(" + ")
                        .filter_map(|s| s.trim().parse().ok())
                        .collect();

                    if numbers.len() >= 2 {
                        (numbers[0] + numbers[1]).to_string()
                    } else {
                        value.clone()
                    }
                } else {
                    value.clone()
                }
            } else if value.contains("location") {
                "location".to_string()
            } else if value.contains("cfIpLongitude") {
                "ipinfo".to_string()
            } else if value.contains("maxTouchPoints") {
                "vendor".to_string()
            } else if value.contains("history") {
                "history".to_string()
            } else if value.contains(r#"window["Object"]["keys"]"#) {
                "localstorage".to_string()
            } else if value.contains("createElement") {
                "element".to_string()
            } else if value.chars().all(|c| c.is_ascii_digit() || c == '.') {
                value.clone()
            } else if value.contains("random") {
                let result = format!("random_{}", random_index);
                random_index += 1;
                result
            } else if value.contains("doublexor") || value.contains("singlebtoa") {
                value.clone()
            } else {
                continue;
            };

            parsed_keys.insert(key, parsed_value);
        }

        Ok((xor_key, parsed_keys))
    }

    /// Analyze JavaScript structure for variable dependencies
    pub fn analyze_dependencies(code: &str) -> HashMap<String, Vec<String>> {
        let mut dependencies = HashMap::new();

        // Find variable declarations and their dependencies
        let var_re = Regex::new(r"var\s+var_(\w+)\s*=\s*(.+?);").unwrap();
        let ref_re = Regex::new(r"var_(\w+)").unwrap();

        for caps in var_re.captures_iter(code) {
            if let (Some(var_name), Some(expr)) = (caps.get(1), caps.get(2)) {
                let var = var_name.as_str().to_string();
                let expression = expr.as_str();

                // Find all variable references in the expression
                let mut deps = Vec::new();
                for ref_caps in ref_re.captures_iter(expression) {
                    if let Some(ref_var) = ref_caps.get(1) {
                        let ref_name = ref_var.as_str().to_string();
                        if ref_name != var {
                            deps.push(ref_name);
                        }
                    }
                }

                dependencies.insert(var, deps);
            }
        }

        dependencies
    }

    /// Extract string literals from code
    pub fn extract_strings(code: &str) -> Vec<String> {
        let mut strings = Vec::new();
        let string_re = Regex::new(r#""([^"\\]*(\\.[^"\\]*)*)""#).unwrap();

        for caps in string_re.captures_iter(code) {
            if let Some(s) = caps.get(1) {
                strings.push(s.as_str().to_string());
            }
        }

        strings
    }

    /// Check if code contains specific pattern
    pub fn contains_pattern(code: &str, pattern: &str) -> bool {
        if let Ok(re) = Regex::new(pattern) {
            re.is_match(code)
        } else {
            code.contains(pattern)
        }
    }

    /// Count occurrences of a pattern in code
    pub fn count_pattern(code: &str, pattern: &str) -> usize {
        if let Ok(re) = Regex::new(pattern) {
            re.find_iter(code).count()
        } else {
            code.matches(pattern).count()
        }
    }
}