1use std::io::{BufRead, BufReader, Write};
7use std::net::TcpStream;
8use std::time::Duration;
9
10use anyhow::Result;
11use serde_json::json;
12use tracing::debug;
13
14use super::protocol::{BridgeRequest, BridgeResponse};
15
16pub struct BridgeClient {
18 port: u16,
19}
20
21impl BridgeClient {
22 pub fn new(port: u16) -> Self {
24 Self { port }
25 }
26
27 #[allow(dead_code)]
29 pub fn port(&self) -> u16 {
30 self.port
31 }
32
33 pub fn send_command(
35 &self,
36 command: &str,
37 args: Option<serde_json::Value>,
38 ) -> Result<serde_json::Value> {
39 let addr: std::net::SocketAddr = format!("127.0.0.1:{}", self.port)
40 .parse()
41 .map_err(|e| anyhow::anyhow!("Invalid address: {}", e))?;
42 let mut stream =
43 TcpStream::connect_timeout(&addr, Duration::from_secs(10)).map_err(|e| {
44 anyhow::anyhow!("Failed to connect to bridge on port {}: {}", self.port, e)
45 })?;
46 stream.set_read_timeout(Some(Duration::from_secs(300))).ok();
47 stream.set_write_timeout(Some(Duration::from_secs(30))).ok();
48
49 let request = BridgeRequest {
50 command: command.to_string(),
51 args,
52 };
53
54 let request_json = serde_json::to_string(&request)?;
55 debug!("Sending: {}", request_json);
56
57 writeln!(stream, "{}", request_json)?;
58 stream.flush()?;
59
60 let mut reader = BufReader::new(&stream);
61 let mut response_line = String::new();
62 reader.read_line(&mut response_line)?;
63
64 debug!("Received: {}", response_line.trim());
65
66 let response: BridgeResponse = serde_json::from_str(&response_line)?;
67
68 match response.status.as_str() {
69 "success" => Ok(response.data.unwrap_or(json!({}))),
70 "error" => {
71 let msg = response
72 .message
73 .unwrap_or_else(|| "Unknown error".to_string());
74 anyhow::bail!("{}", msg)
75 }
76 "shutdown" => Ok(json!({"status": "shutdown"})),
77 _ => Ok(response.data.unwrap_or(json!({}))),
78 }
79 }
80
81 pub fn ping(&self) -> Result<bool> {
83 match self.send_command("ping", None) {
84 Ok(_) => Ok(true),
85 Err(_) => Ok(false),
86 }
87 }
88
89 pub fn shutdown(&self) -> Result<()> {
91 self.send_command("shutdown", None)?;
92 Ok(())
93 }
94
95 #[allow(dead_code)]
97 pub fn status(&self) -> Result<serde_json::Value> {
98 self.send_command("status", None)
99 }
100
101 pub fn bridge_info(&self) -> Result<serde_json::Value> {
103 self.send_command("bridge_info", None)
104 }
105
106 pub fn list_functions(
108 &self,
109 limit: Option<usize>,
110 filter: Option<String>,
111 ) -> Result<serde_json::Value> {
112 self.send_command(
113 "list_functions",
114 Some(json!({"limit": limit, "filter": filter})),
115 )
116 }
117
118 pub fn decompile(
120 &self,
121 address: String,
122 with_vars: bool,
123 with_params: bool,
124 ) -> Result<serde_json::Value> {
125 self.send_command(
126 "decompile",
127 Some(json!({
128 "address": address,
129 "with_vars": with_vars,
130 "with_params": with_params,
131 })),
132 )
133 }
134
135 pub fn list_strings(&self, limit: Option<usize>, filter: Option<String>) -> Result<serde_json::Value> {
137 self.send_command("list_strings", Some(json!({"limit": limit, "filter": filter})))
138 }
139
140 pub fn list_imports(&self) -> Result<serde_json::Value> {
142 self.send_command("list_imports", None)
143 }
144
145 pub fn list_exports(&self) -> Result<serde_json::Value> {
147 self.send_command("list_exports", None)
148 }
149
150 pub fn memory_map(&self) -> Result<serde_json::Value> {
152 self.send_command("memory_map", None)
153 }
154
155 pub fn program_info(&self) -> Result<serde_json::Value> {
157 self.send_command("program_info", None)
158 }
159
160 pub fn xrefs_to(&self, address: String) -> Result<serde_json::Value> {
162 self.send_command("xrefs_to", Some(json!({"address": address})))
163 }
164
165 pub fn xrefs_from(&self, address: String) -> Result<serde_json::Value> {
167 self.send_command("xrefs_from", Some(json!({"address": address})))
168 }
169
170 pub fn import_binary(
172 &self,
173 binary_path: &str,
174 program: Option<&str>,
175 ) -> Result<serde_json::Value> {
176 self.send_command(
177 "import",
178 Some(json!({"binary_path": binary_path, "program": program})),
179 )
180 }
181
182 pub fn analyze(&self) -> Result<serde_json::Value> {
184 self.send_command("analyze", None)
185 }
186
187 pub fn list_programs(&self) -> Result<serde_json::Value> {
189 self.send_command("list_programs", None)
190 }
191
192 pub fn open_program(&self, program: &str) -> Result<serde_json::Value> {
194 self.send_command("open_program", Some(json!({"program": program})))
195 }
196
197 pub fn symbol_list(&self, limit: Option<usize>, filter: Option<&str>) -> Result<serde_json::Value> {
200 self.send_command("symbol_list", Some(json!({"limit": limit, "filter": filter})))
201 }
202
203 pub fn symbol_get(&self, name: &str) -> Result<serde_json::Value> {
204 self.send_command("symbol_get", Some(json!({"name": name})))
205 }
206
207 pub fn symbol_create(&self, address: &str, name: &str) -> Result<serde_json::Value> {
208 self.send_command(
209 "symbol_create",
210 Some(json!({"address": address, "name": name})),
211 )
212 }
213
214 pub fn symbol_delete(&self, name: &str) -> Result<serde_json::Value> {
215 self.send_command("symbol_delete", Some(json!({"name": name})))
216 }
217
218 pub fn symbol_rename(&self, old_name: &str, new_name: &str) -> Result<serde_json::Value> {
219 self.send_command(
220 "symbol_rename",
221 Some(json!({"old_name": old_name, "new_name": new_name})),
222 )
223 }
224
225 pub fn type_list(&self, limit: Option<usize>, filter: Option<&str>) -> Result<serde_json::Value> {
226 self.send_command("type_list", Some(json!({"limit": limit, "filter": filter})))
227 }
228
229 pub fn type_get(&self, name: &str) -> Result<serde_json::Value> {
230 self.send_command("type_get", Some(json!({"name": name})))
231 }
232
233 pub fn type_create(&self, definition: &str) -> Result<serde_json::Value> {
234 self.send_command("type_create", Some(json!({"definition": definition})))
235 }
236
237 pub fn type_apply(&self, address: &str, type_name: &str) -> Result<serde_json::Value> {
238 self.send_command(
239 "type_apply",
240 Some(json!({"address": address, "type_name": type_name})),
241 )
242 }
243
244 pub fn comment_list(&self, limit: Option<usize>, filter: Option<&str>) -> Result<serde_json::Value> {
245 self.send_command("comment_list", Some(json!({"limit": limit, "filter": filter})))
246 }
247
248 pub fn comment_get(&self, address: &str) -> Result<serde_json::Value> {
249 self.send_command("comment_get", Some(json!({"address": address})))
250 }
251
252 pub fn comment_set(
253 &self,
254 address: &str,
255 text: &str,
256 comment_type: Option<&str>,
257 ) -> Result<serde_json::Value> {
258 self.send_command(
259 "comment_set",
260 Some(json!({
261 "address": address,
262 "text": text,
263 "type": comment_type,
264 })),
265 )
266 }
267
268 pub fn comment_delete(&self, address: &str) -> Result<serde_json::Value> {
269 self.send_command("comment_delete", Some(json!({"address": address})))
270 }
271
272 pub fn graph_calls(&self, limit: Option<usize>) -> Result<serde_json::Value> {
273 self.send_command("graph_calls", Some(json!({"limit": limit})))
274 }
275
276 pub fn graph_callers(&self, function: &str, depth: Option<usize>) -> Result<serde_json::Value> {
277 self.send_command(
278 "graph_callers",
279 Some(json!({"function": function, "depth": depth})),
280 )
281 }
282
283 pub fn graph_callees(&self, function: &str, depth: Option<usize>) -> Result<serde_json::Value> {
284 self.send_command(
285 "graph_callees",
286 Some(json!({"function": function, "depth": depth})),
287 )
288 }
289
290 pub fn graph_export(&self, format: &str) -> Result<serde_json::Value> {
291 self.send_command("graph_export", Some(json!({"format": format})))
292 }
293
294 pub fn find_string(&self, pattern: &str) -> Result<serde_json::Value> {
295 self.send_command("find_string", Some(json!({"pattern": pattern})))
296 }
297
298 pub fn find_bytes(&self, hex: &str) -> Result<serde_json::Value> {
299 self.send_command("find_bytes", Some(json!({"hex": hex})))
300 }
301
302 pub fn find_function(&self, pattern: &str) -> Result<serde_json::Value> {
303 self.send_command("find_function", Some(json!({"pattern": pattern})))
304 }
305
306 pub fn find_calls(&self, function: &str) -> Result<serde_json::Value> {
307 self.send_command("find_calls", Some(json!({"function": function})))
308 }
309
310 pub fn find_crypto(&self) -> Result<serde_json::Value> {
311 self.send_command("find_crypto", None)
312 }
313
314 pub fn find_interesting(&self) -> Result<serde_json::Value> {
315 self.send_command("find_interesting", None)
316 }
317
318 pub fn diff_programs(&self, program1: &str, program2: &str) -> Result<serde_json::Value> {
319 self.send_command(
320 "diff_programs",
321 Some(json!({"program1": program1, "program2": program2})),
322 )
323 }
324
325 pub fn diff_functions(&self, func1: &str, func2: &str) -> Result<serde_json::Value> {
326 self.send_command(
327 "diff_functions",
328 Some(json!({"func1": func1, "func2": func2})),
329 )
330 }
331
332 pub fn patch_bytes(&self, address: &str, hex: &str) -> Result<serde_json::Value> {
333 self.send_command("patch_bytes", Some(json!({"address": address, "hex": hex})))
334 }
335
336 pub fn patch_nop(&self, address: &str) -> Result<serde_json::Value> {
337 self.send_command("patch_nop", Some(json!({"address": address})))
338 }
339
340 pub fn patch_export(&self, output: &str) -> Result<serde_json::Value> {
341 self.send_command("patch_export", Some(json!({"output": output})))
342 }
343
344 pub fn disasm(
345 &self,
346 address: &str,
347 num_instructions: Option<usize>,
348 ) -> Result<serde_json::Value> {
349 self.send_command(
350 "disasm",
351 Some(json!({"address": address, "count": num_instructions})),
352 )
353 }
354
355 pub fn stats(&self) -> Result<serde_json::Value> {
356 self.send_command("stats", None)
357 }
358
359 pub fn script_run(&self, script_path: &str, args: &[String]) -> Result<serde_json::Value> {
360 self.send_command(
361 "script_run",
362 Some(json!({"path": script_path, "args": args})),
363 )
364 }
365
366 pub fn script_python(&self, code: &str) -> Result<serde_json::Value> {
367 self.send_command("script_python", Some(json!({"code": code})))
368 }
369
370 pub fn script_java(&self, code: &str) -> Result<serde_json::Value> {
371 self.send_command("script_java", Some(json!({"code": code})))
372 }
373
374 pub fn script_list(&self) -> Result<serde_json::Value> {
375 self.send_command("script_list", None)
376 }
377
378 pub fn program_close(&self) -> Result<serde_json::Value> {
379 self.send_command("close_program", None)
380 }
381
382 pub fn program_delete(&self, program: &str) -> Result<serde_json::Value> {
383 self.send_command("delete_program", Some(json!({"program": program})))
384 }
385
386 pub fn program_export(&self, format: &str, output: Option<&str>) -> Result<serde_json::Value> {
387 self.send_command(
388 "export_program",
389 Some(json!({"format": format, "output": output})),
390 )
391 }
392}