-
Notifications
You must be signed in to change notification settings - Fork 15
Expand file tree
/
Copy pathmulti_program_strings.rs
More file actions
132 lines (115 loc) · 3.89 KB
/
Copy pathmulti_program_strings.rs
File metadata and controls
132 lines (115 loc) · 3.89 KB
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
// Copyright (c) 2024-2026 Elias Bachaalany
// SPDX-License-Identifier: LicenseRef-Human-Origin-Source-1.0
//
// multi_program_strings: launch one live Ghidra headless project, import and
// analyze one or more binaries, count defined strings for each active program,
// save the project, and shut down.
//
// Usage:
// cargo run --example multi_program_strings -- <ghidra_dir> <project_dir> <project_name> <binary> [binary...]
use std::time::Duration;
use libghidra as ghidra;
fn usage(program: &str) {
eprintln!("Usage: {program} <ghidra_dir> <project_dir> <project_name> <binary> [binary...]");
}
fn main() {
let args: Vec<String> = std::env::args().collect();
if args.len() < 5 {
usage(&args[0]);
std::process::exit(1);
}
let ghidra_dir = args[1].clone();
let project_dir = args[2].clone();
let project_name = args[3].clone();
let opts = ghidra::HeadlessProjectOptions {
ghidra_dir,
project_dir: project_dir.clone(),
project_name: project_name.clone(),
port: 0,
shutdown: "save".to_string(),
bind_attempts: 5,
startup_timeout: Duration::from_secs(600),
read_timeout: Duration::from_secs(300),
..Default::default()
};
let mut host = match ghidra::launch_headless_project(opts) {
Ok(host) => host,
Err(err) => {
eprintln!("ERROR: {err}");
std::process::exit(1);
}
};
let mut failed = false;
for binary in &args[4..] {
let imported = match host.import_program(&ghidra::ImportProgramRequest {
source_path: binary.clone(),
overwrite: true,
analyze: true,
..Default::default()
}) {
Ok(imported) => imported,
Err(err) => {
eprintln!("ImportProgram failed for {binary}: {err}");
failed = true;
break;
}
};
let program_path = imported.primary_program_path;
if program_path.is_empty() {
eprintln!("ImportProgram returned no primary program path for {binary}");
failed = true;
break;
}
println!("imported {program_path} source={binary}");
let opened = match host.open_program(&ghidra::OpenProgramRequest {
project_path: project_dir.clone(),
project_name: project_name.clone(),
program_path: program_path.clone(),
analyze: false,
read_only: false,
..Default::default()
}) {
Ok(opened) => opened,
Err(err) => {
eprintln!("OpenProgram failed for {program_path}: {err}");
failed = true;
break;
}
};
let strings = match host.list_defined_strings(0, u64::MAX, 0, 0) {
Ok(strings) => strings,
Err(err) => {
eprintln!("ListDefinedStrings failed for {program_path}: {err}");
failed = true;
break;
}
};
println!(
"strings {program_path} program={} count={}",
opened.program_name,
strings.strings.len()
);
match host.close_program(ghidra::ShutdownPolicy::Save) {
Ok(closed) if closed.closed => {}
Ok(_) => {
eprintln!("CloseProgram did not close {program_path}");
failed = true;
break;
}
Err(err) => {
eprintln!("CloseProgram failed for {program_path}: {err}");
failed = true;
break;
}
}
}
let ghidra_exit = host.close(true);
if failed {
std::process::exit(1);
}
if ghidra_exit != 0 {
eprintln!("Ghidra exited with code {ghidra_exit}");
std::process::exit(1);
}
println!("saved project={project_name}");
}