Skip to content

Commit

Permalink
Feature/strings (#23)
Browse files Browse the repository at this point in the history
* Add `StringList` and `StringIndex` and associated methods
* Add `address_to_string` wrapper for `ea2str`
  • Loading branch information
0xdea authored Dec 4, 2024
1 parent 3298d7a commit bf9f585
Show file tree
Hide file tree
Showing 7 changed files with 170 additions and 0 deletions.
10 changes: 10 additions & 0 deletions idalib-sys/src/kernwin_extras.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,3 +142,13 @@ int idalib_open_database_quiet(const char *name, bool auto_analysis) {

return result;
}

rust::String idalib_ea2str(ea_t ea) {
auto out = qstring();

if (ea2str(&out, ea)) {
return rust::String(out.c_str());
} else {
return rust::String();
}
}
21 changes: 21 additions & 0 deletions idalib-sys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ include_cpp! {
#include "moves.hpp"
#include "pro.h"
#include "segment.hpp"
#include "strlist.hpp"
#include "ua.hpp"
#include "xref.hpp"

Expand Down Expand Up @@ -330,6 +331,11 @@ include_cpp! {
generate!("set_cmt")
generate!("append_cmt")

// strings
generate!("build_strlist")
generate!("clear_strlist")
generate!("get_strlist_qty")

// loader
generate!("plugin_t")
generate!("find_plugin")
Expand Down Expand Up @@ -695,6 +701,7 @@ mod ffix {
include!("ph_extras.h");
include!("segm_extras.h");
include!("search_extras.h");
include!("strings_extras.h");

type c_short = autocxx::c_short;
type c_int = autocxx::c_int;
Expand Down Expand Up @@ -970,6 +977,11 @@ mod ffix {
unsafe fn idalib_find_imm(ea: c_ulonglong, imm: c_uint) -> c_ulonglong;
unsafe fn idalib_find_defined(ea: c_ulonglong) -> c_ulonglong;

unsafe fn idalib_get_strlist_item_addr(index: usize) -> c_ulonglong;
unsafe fn idalib_get_strlist_item_length(index: usize) -> usize;

unsafe fn idalib_ea2str(ea: c_ulonglong) -> String;

unsafe fn idalib_get_byte(ea: c_ulonglong) -> u8;
unsafe fn idalib_get_word(ea: c_ulonglong) -> u16;
unsafe fn idalib_get_dword(ea: c_ulonglong) -> u32;
Expand Down Expand Up @@ -1126,6 +1138,10 @@ pub mod comments {
pub use super::ffix::idalib_get_cmt;
}

pub mod conversions {
pub use super::ffix::idalib_ea2str;
}

pub mod bookmarks {
pub use super::ffix::{
idalib_bookmarks_t_erase, idalib_bookmarks_t_find_index, idalib_bookmarks_t_get,
Expand All @@ -1137,6 +1153,11 @@ pub mod search {
pub use super::ffix::{idalib_find_defined, idalib_find_imm, idalib_find_text};
}

pub mod strings {
pub use super::ffi::{build_strlist, clear_strlist, get_strlist_qty};
pub use super::ffix::{idalib_get_strlist_item_addr, idalib_get_strlist_item_length};
}

pub mod loader {
pub use super::ffi::{find_plugin, plugin_t, run_plugin};
pub use super::ffix::{idalib_plugin_flags, idalib_plugin_version};
Expand Down
17 changes: 17 additions & 0 deletions idalib-sys/src/strings_extras.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#pragma once

#include "strlist.hpp"

#include "cxx.h"

ea_t idalib_get_strlist_item_addr(size_t n) {
string_info_t si;
get_strlist_item(&si, n);
return si.ea;
}

size_t idalib_get_strlist_item_length(size_t n) {
string_info_t si;
get_strlist_item(&si, n);
return (size_t)si.length;
}
34 changes: 34 additions & 0 deletions idalib/examples/strings_ls.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
use idalib::idb::IDB;

fn main() -> anyhow::Result<()> {
println!("Trying to open IDA database...");

// Open IDA database
let idb = IDB::open("./tests/ls")?;

println!("Testing len(), get_by_index(), and get_address_by_index() (valid indexes)");
// len()
for i in 0..idb.strings().len() {
/*
println!(
"\t{:#x}\t{:?}",
idb.strings().get_address_by_index(i).unwrap(),
idb.strings().get_by_index(i).unwrap()
);
*/
// get_by_index()
assert!(idb.strings().get_by_index(i).is_some());
// get_address_by_index()
assert!(idb.strings().get_address_by_index(i).is_some());
}

println!("Testing len(), get_by_index(), and get_address_by_index() (invalid index)");
// len()
let len = idb.strings().len();
// get_by_index()
assert!(idb.strings().get_by_index(len).is_none());
// get_address_by_index()
assert!(idb.strings().get_address_by_index(len).is_none());

Ok(())
}
16 changes: 16 additions & 0 deletions idalib/src/idb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use std::path::{Path, PathBuf};

use crate::ffi::bytes::*;
use crate::ffi::comments::{append_cmt, idalib_get_cmt, set_cmt};
use crate::ffi::conversions::idalib_ea2str;
use crate::ffi::entry::{get_entry, get_entry_ordinal, get_entry_qty};
use crate::ffi::func::{get_func, get_func_qty, getn_func};
use crate::ffi::hexrays::{decompile_func, init_hexrays_plugin, term_hexrays_plugin};
Expand All @@ -28,6 +29,7 @@ use crate::meta::{Metadata, MetadataMut};
use crate::plugin::Plugin;
use crate::processor::Processor;
use crate::segment::{Segment, SegmentId};
use crate::strings::StringList;
use crate::xref::{XRef, XRefQuery};
use crate::{prepare_library, Address, IDAError, IDARuntimeHandle};

Expand Down Expand Up @@ -382,6 +384,20 @@ impl IDB {
}
}

pub fn strings(&self) -> StringList {
StringList::new(self)
}

pub fn address_to_string(&self, ea: Address) -> Option<String> {
let s = unsafe { idalib_ea2str(ea.into()) };

if s.is_empty() {
None
} else {
Some(s)
}
}

pub fn get_byte(&self, ea: Address) -> u8 {
unsafe { idalib_get_byte(ea.into()) }
}
Expand Down
1 change: 1 addition & 0 deletions idalib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ pub mod meta;
pub mod plugin;
pub mod processor;
pub mod segment;
pub mod strings;
pub mod xref;

pub use idalib_sys as ffi;
Expand Down
71 changes: 71 additions & 0 deletions idalib/src/strings.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
use std::marker::PhantomData;

use crate::ffi::bytes::idalib_get_bytes;
use crate::ffi::strings::{
build_strlist, clear_strlist, get_strlist_qty, idalib_get_strlist_item_addr,
idalib_get_strlist_item_length,
};
use crate::ffi::BADADDR;

use crate::idb::IDB;
use crate::Address;

pub type StringIndex = usize;

pub struct StringList<'a> {
_marker: PhantomData<&'a IDB>,
}

impl<'a> StringList<'a> {
pub(crate) fn new(_: &'a IDB) -> Self {
Self {
_marker: PhantomData,
}
}

pub fn rebuild(&self) {
unsafe { build_strlist() }
}

pub fn clear(&self) {
unsafe { clear_strlist() }
}

pub fn get_by_index(&self, index: StringIndex) -> Option<String> {
let addr = self.get_address_by_index(index)?;
let size = self.get_length_by_index(index);

// See also `IDB::get_bytes`
let mut buf = Vec::with_capacity(size);
let Ok(new_len) = (unsafe { idalib_get_bytes(addr.into(), &mut buf) }) else {
return None;
};
unsafe {
buf.set_len(new_len);
}

// TODO: switch to `String::from_utf8_lossy_owned` once it's stable
Some(String::from_utf8_lossy(&buf).into_owned())
}

pub fn get_address_by_index(&self, index: StringIndex) -> Option<Address> {
let addr = unsafe { idalib_get_strlist_item_addr(index) };
if addr == BADADDR {
None
} else {
Some(addr.into())
}
}

fn get_length_by_index(&self, index: StringIndex) -> usize {
unsafe { idalib_get_strlist_item_length(index) }
}

pub fn len(&self) -> StringIndex {
unsafe { get_strlist_qty() }
}

pub fn is_empty(&self) -> bool {
self.len() == 0
}
}

0 comments on commit bf9f585

Please sign in to comment.