diff --git a/src/ghidra/headless.rs b/src/ghidra/headless.rs index 0ccb557..5e646bc 100644 --- a/src/ghidra/headless.rs +++ b/src/ghidra/headless.rs @@ -47,6 +47,7 @@ impl<'a> HeadlessExecutor<'a> { let headless = self.client.get_headless_script(); let mut cmd = Command::new(&headless); + cmd.arg(project_path.to_str().unwrap()) .arg(project_name) .arg("-process") diff --git a/src/ghidra/mod.rs b/src/ghidra/mod.rs index cc6bd62..85da21d 100644 --- a/src/ghidra/mod.rs +++ b/src/ghidra/mod.rs @@ -30,16 +30,22 @@ impl GhidraClient { }) } + pub fn install_dir(&self) -> &PathBuf { + &self.install_dir + } + pub fn get_headless_script(&self) -> PathBuf { let support_dir = self.install_dir.join("support"); #[cfg(target_os = "windows")] { + // Use analyzeHeadless with Jython support support_dir.join("analyzeHeadless.bat") } #[cfg(not(target_os = "windows"))] { + // Use analyzeHeadless with Jython support support_dir.join("analyzeHeadless") } } @@ -70,21 +76,10 @@ impl GhidraClient { return Ok(()); } + // Ghidra creates the project automatically when you import or process a file + // Just create the directory structure std::fs::create_dir_all(&project_path)?; - // Run headless to create project - let headless = self.get_headless_script(); - let output = Command::new(&headless) - .arg(project_path.to_str().unwrap()) - .arg(project_name) - .output()?; - - if !output.status.success() { - return Err(GhidraError::ExecutionFailed( - String::from_utf8_lossy(&output.stderr).to_string() - )); - } - Ok(()) } @@ -128,9 +123,6 @@ impl GhidraClient { .arg(project_name) .arg("-process") .arg(program_name) - .arg("-noanalysis") // Don't auto-analyze - .arg("-scriptPath") - .arg(self.get_scripts_dir()?.to_str().unwrap()) .output()?; if !output.status.success() { diff --git a/src/ghidra/scripts.rs b/src/ghidra/scripts.rs index 5a6383b..a7ac11a 100644 --- a/src/ghidra/scripts.rs +++ b/src/ghidra/scripts.rs @@ -107,29 +107,38 @@ pub fn get_list_strings_script() -> &'static str { r#" # List all strings in the program # @category Analysis +# @runtime Jython import json strings = [] -string_table = currentProgram.getListing().getDefinedData(True) +listing = currentProgram.getListing() +data_iterator = listing.getDefinedData(True) -for data in string_table: +while data_iterator.hasNext(): + data = data_iterator.next() if data.hasStringValue(): - string_data = { - "address": data.getAddress().toString(), - "value": data.getValue().toString(), - "length": len(data.getValue().toString()), - "encoding": "ascii" - } + try: + # Get string value, handle Unicode properly + string_val = unicode(data.getValue()) + string_data = { + "address": str(data.getAddress()), + "value": string_val, + "length": len(string_val), + "encoding": "unicode" + } - # Get references to this string - refs = [] - refs_to = currentProgram.getReferenceManager().getReferencesTo(data.getAddress()) - for ref in refs_to: - refs.append(ref.getFromAddress().toString()) + # Get references to this string + refs = [] + refs_to = currentProgram.getReferenceManager().getReferencesTo(data.getAddress()) + for ref in refs_to: + refs.append(str(ref.getFromAddress())) - string_data["references"] = refs - strings.append(string_data) + string_data["references"] = refs + strings.append(string_data) + except Exception as e: + # Skip strings that cause encoding issues + pass print(json.dumps(strings, indent=2)) "# @@ -292,6 +301,7 @@ print(json.dumps(xrefs, indent=2)) /// Save a script to disk pub fn save_script(name: &str, content: &str, scripts_dir: &std::path::Path) -> crate::error::Result { + // All scripts are Python now with PyGhidra support let script_path = scripts_dir.join(format!("{}.py", name)); std::fs::write(&script_path, content)?; Ok(script_path)