use crate::api::regs::Reg;
use crate::plugin_import;
use crate::sys::{target_ptr_t, CPUState};
use std::collections::HashSet;
use std::ops::Range;
use std::os::raw::{c_int, c_long, c_void};
use std::ptr;
use std::sync::Once;
plugin_import! {
static TAINT: Taint = extern "taint2" {
fn taint2_enable_taint();
fn taint2_enable_tainted_pointer();
fn taint2_enabled() -> bool;
fn taint2_label_addr(a: Addr, offset: c_int, label: u32);
fn taint2_label_ram(ram_offset: u64, label: u32);
fn taint2_label_reg(reg_num: c_int, offset: c_int, label: u32);
fn taint2_label_io(ia: u64, label: u32);
fn taint2_label_ram_additive(ram_offset: u64, label: u32);
fn taint2_label_reg_additive(reg_num: c_int, offset: c_int, label: u32);
fn taint2_label_io_additive(ia: u64, label: u32);
fn taint2_add_taint_ram_pos(cpu: &mut CPUState, addr: u64, length: u32, start_label: u32);
fn taint2_add_taint_ram_single_label(cpu: &mut CPUState, addr: u64, length: u32, label: c_long);
fn taint2_delete_ram(ram_offset: u64);
fn taint2_delete_reg(reg_num: c_int, offset: c_int);
fn taint2_delete_io(ia: u64);
fn taint2_query_pandalog(addr: Addr, offset: u32) -> *mut c_void;
fn pandalog_taint_query_free(tq: *mut c_void);
fn taint2_query(addr: Addr) -> u32;
fn taint2_query_reg(reg_num: c_int, offset: c_int) -> u32;
fn taint2_query_ram(ram_offset: u64) -> u32;
fn taint2_query_laddr(la: u64, off: u64) -> u32;
fn taint2_query_io(ia: u64) -> u32;
fn taint2_query_llvm(reg_num: c_int, offset: c_int) -> u32;
fn taint2_query_set_a(a: Addr, out: &mut *mut u32, outsz: &mut u32) -> u32;
fn taint2_query_set(a: Addr, out: *mut u32);
fn taint2_query_set_ram(ram_offset: u64, out: *mut u32);
fn taint2_query_set_reg(reg_num: c_int, offset: c_int, out: *mut u32);
fn taint2_query_set_io(ia: u64, out: *mut u32);
fn taint2_query_tcn(a: Addr) -> u32;
fn taint2_query_tcn_ram(ram_offset: u64) -> u32;
fn taint2_query_tcn_reg(reg_num: c_int, offset: c_int) -> u32;
fn taint2_query_tcn_io(ia: u64) -> u32;
fn taint2_query_tcn_llvm(reg_num: c_int, offset: c_int) -> u32;
fn taint2_query_cb_mask(a: Addr, size: u8) -> u64;
fn taint2_labelset_addr_iter(addr: Addr, app: LabelSetVisitorRawFn, stuff: *mut c_void);
fn taint2_labelset_ram_iter(ram_offset: u64, app: LabelSetVisitorRawFn, stuff: *mut c_void);
fn taint2_labelset_reg_iter(reg_num: c_int, offset: c_int, app: LabelSetVisitorRawFn, stuff: *mut c_void);
fn taint2_labelset_io_iter(ia: u64, app: LabelSetVisitorRawFn, stuff: *mut c_void);
fn taint2_labelset_llvm_iter(reg_num: c_int, offset: c_int, app: LabelSetVisitorRawFn, stuff: *mut c_void);
fn taint2_num_labels_applied() -> u32;
fn taint2_track_taint_state();
fn taint2_query_results_iter(qr: &mut QueryResult);
fn taint2_query_result_next(qr: &mut QueryResult, done: &mut bool) -> u32;
fn taint2_query_laddr_full(reg_num: u64, offset: u64, qr: &mut QueryResult);
fn taint2_query_reg_full(reg_num: u32, offset: u32, qr: &mut QueryResult);
fn taint2_query_ram_full(addr: u64, qr: &mut QueryResult);
};
}
pub type LabelSetVisitorRawFn = extern "C" fn(u32, *mut c_void) -> c_int;
#[derive(Clone, Copy)]
#[repr(C)]
pub union ValueUnion {
pub ha: u64,
pub ma: u64,
pub ia: u64,
pub pa: u64,
pub la: u64,
pub gr: u64,
pub gs: u64,
pub ua: u64,
pub con: u64,
pub ret: u64,
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[repr(C)]
#[allow(non_camel_case_types)]
pub enum AddrType {
HADDR,
MADDR,
IADDR,
PADDR,
LADDR,
GREG,
GSPEC,
UNK,
CONST,
RET,
ADDR_LAST,
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[repr(C)]
#[allow(non_camel_case_types)]
pub enum AddrFlag {
IRRELEVANT = 5,
EXCEPTION = 1,
READLOG,
FUNCARG,
}
#[derive(Clone, Copy)]
#[repr(C)]
pub struct Addr {
pub typ: AddrType,
pub val: ValueUnion,
pub off: u16,
pub flag: AddrFlag,
}
static TAINT_ENABLE: Once = Once::new();
pub fn enable() {
TAINT_ENABLE.call_once(|| {
TAINT.taint2_enable_taint();
})
}
pub fn is_enabled() -> bool {
TAINT.taint2_enabled()
}
pub fn enable_tainted_pointer() {
TAINT.taint2_enable_tainted_pointer()
}
pub fn label_reg(register: impl Into<Reg>, label: u32) {
let reg = register.into() as c_int;
enable();
for i in 0..std::mem::size_of::<target_ptr_t>() {
TAINT.taint2_label_reg(reg, i as c_int, label);
}
}
pub fn label_reg_additive(register: impl Into<Reg>, label: u32) {
let reg = register.into() as c_int;
enable();
for i in 0..std::mem::size_of::<target_ptr_t>() {
TAINT.taint2_label_reg_additive(reg, i as c_int, label);
}
}
pub fn label_reg_byte(register: impl Into<Reg>, byte_offset: usize, label: u32) {
assert!(byte_offset < std::mem::size_of::<target_ptr_t>());
let reg = register.into() as c_int;
enable();
TAINT.taint2_label_reg(reg, byte_offset as c_int, label);
}
pub fn label_reg_byte_additive(register: impl Into<Reg>, byte_offset: usize, label: u32) {
assert!(byte_offset < std::mem::size_of::<target_ptr_t>());
let reg = register.into() as c_int;
enable();
TAINT.taint2_label_reg_additive(reg, byte_offset as c_int, label);
}
pub fn label_ram(addr: target_ptr_t, label: u32) {
enable();
TAINT.taint2_label_ram(addr as u64, label)
}
pub fn label_ram_additive(addr: target_ptr_t, label: u32) {
enable();
TAINT.taint2_label_ram_additive(addr as u64, label);
}
pub fn label_ram_range(addr_range: Range<target_ptr_t>, label: u32) {
enable();
for addr in addr_range {
TAINT.taint2_label_ram(addr as u64, label);
}
}
pub fn label_ram_range_additive(addr_range: Range<target_ptr_t>, label: u32) {
enable();
for addr in addr_range {
TAINT.taint2_label_ram_additive(addr as u64, label);
}
}
pub fn unlabel_reg(register: impl Into<Reg>) {
if !TAINT_ENABLE.is_completed() {
return;
}
let reg = register.into() as c_int;
for i in 0..std::mem::size_of::<target_ptr_t>() {
TAINT.taint2_delete_reg(reg, i as c_int);
}
}
pub fn unlabel_reg_byte(register: impl Into<Reg>, byte_offset: usize) {
assert!(byte_offset < std::mem::size_of::<target_ptr_t>());
if !TAINT_ENABLE.is_completed() {
return;
}
let reg = register.into() as c_int;
TAINT.taint2_delete_reg(reg, byte_offset as c_int);
}
pub fn unlabel_ram(addr: target_ptr_t) {
if !TAINT_ENABLE.is_completed() {
return;
}
TAINT.taint2_delete_ram(addr as u64);
}
pub fn unlabel_ram_range(addr_range: Range<target_ptr_t>) {
if !TAINT_ENABLE.is_completed() {
return;
}
for addr in addr_range {
TAINT.taint2_delete_ram(addr as u64);
}
}
pub fn check_reg(reg: impl Into<Reg>) -> bool {
let reg_num = reg.into() as c_int;
check_reg_num(reg_num)
}
pub fn check_reg_byte(reg: impl Into<Reg>, byte_offset: usize) -> bool {
assert!(byte_offset < std::mem::size_of::<target_ptr_t>());
let reg_num = reg.into() as c_int;
check_reg_num_byte(reg_num, byte_offset)
}
pub fn check_reg_num(reg_num: c_int) -> bool {
TAINT_ENABLE.is_completed() && {
let reg_size = std::mem::size_of::<target_ptr_t>();
(0..reg_size).any(|offset| TAINT.taint2_query_reg(reg_num, offset as c_int) > 0)
}
}
pub fn check_reg_num_byte(reg_num: c_int, byte_offset: usize) -> bool {
assert!(byte_offset < std::mem::size_of::<target_ptr_t>());
TAINT_ENABLE.is_completed() && TAINT.taint2_query_reg(reg_num, byte_offset as c_int) > 0
}
pub fn check_ram(addr: target_ptr_t) -> bool {
TAINT_ENABLE.is_completed() && TAINT.taint2_query_ram(addr as u64) > 0
}
pub fn check_ram_range(mut addr_range: Range<target_ptr_t>) -> bool {
TAINT_ENABLE.is_completed() && addr_range.any(|addr| TAINT.taint2_query_ram(addr as u64) > 0)
}
pub fn check_laddr(addr: u64, offset: u64) -> bool {
TAINT_ENABLE.is_completed() && TAINT.taint2_query_laddr(addr, offset) > 0
}
pub fn get_reg(reg: impl Into<Reg>) -> Vec<u32> {
let labels: HashSet<u32> = iter_reg_labels(reg).collect();
labels.into_iter().collect()
}
pub fn get_reg_byte(reg: impl Into<Reg>, byte_offset: usize) -> Vec<u32> {
assert!(byte_offset < std::mem::size_of::<target_ptr_t>());
iter_reg_byte_labels(reg, byte_offset).collect()
}
pub fn get_ram(addr: target_ptr_t) -> Vec<u32> {
let mut query_result = QueryResult::empty();
TAINT.taint2_query_ram_full(addr as u64, &mut query_result);
if check_ram(addr) {
LabelIter {
done: query_result.num_labels == 0,
query_result,
}
.collect()
} else {
Vec::with_capacity(0)
}
}
pub fn get_ram_range(addr_range: Range<target_ptr_t>) -> Vec<u32> {
let labels: HashSet<u32> = iter_ram_labels(addr_range).collect();
labels.into_iter().collect()
}
pub fn iter_reg_labels(reg: impl Into<Reg>) -> impl Iterator<Item = u32> {
let reg_size = std::mem::size_of::<target_ptr_t>();
let reg = reg.into();
(0..reg_size)
.map(move |i| iter_reg_byte_labels(reg, i))
.flatten()
}
pub fn iter_reg_byte_labels(reg: impl Into<Reg>, byte_offset: usize) -> impl Iterator<Item = u32> {
assert!(byte_offset < std::mem::size_of::<target_ptr_t>());
let reg = reg.into();
let mut query_result = QueryResult::empty();
TAINT.taint2_query_reg_full(reg as u32, byte_offset as u32, &mut query_result);
if TAINT.taint2_query_reg(reg as c_int, byte_offset as c_int) > 0 {
LabelIter {
done: query_result.is_empty_or_invalid(),
query_result,
}
} else {
LabelIter {
done: true,
query_result,
}
}
}
pub fn iter_ram_labels(addr_range: Range<target_ptr_t>) -> impl Iterator<Item = u32> {
addr_range
.map(move |addr| {
let mut query_result = QueryResult::empty();
TAINT.taint2_query_ram_full(addr as u64, &mut query_result);
if check_ram(addr) {
LabelIter {
done: query_result.is_empty_or_invalid(),
query_result,
}
} else {
LabelIter {
done: true,
query_result,
}
}
})
.flatten()
}
#[repr(C)]
pub struct QueryResult {
num_labels: u32,
ls: *mut c_void,
it_end: *mut c_void,
it_curr: *mut c_void,
tcn: u32,
cb_mask: u8,
}
impl QueryResult {
fn empty() -> Self {
Self {
num_labels: 0,
ls: ptr::null_mut(),
it_end: ptr::null_mut(),
it_curr: ptr::null_mut(),
tcn: 0,
cb_mask: 0,
}
}
fn is_empty_or_invalid(&self) -> bool {
self.num_labels == 0 || self.it_end.is_null() || self.it_curr.is_null()
}
}
pub struct LabelIter {
query_result: QueryResult,
done: bool,
}
impl Iterator for LabelIter {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> {
if self.done {
None
} else {
Some(TAINT.taint2_query_result_next(&mut self.query_result, &mut self.done))
}
}
}