Skip to main content

falcon/translator/x86/
mode.rs

1use crate::il::Expression as Expr;
2use crate::il::*;
3use crate::translator::x86::x86register::{get_register, X86Register};
4use crate::Error;
5use falcon_capstone::capstone;
6use falcon_capstone::capstone::cs_x86_op;
7use falcon_capstone::capstone_sys::{x86_op_type, x86_reg};
8use std::cmp::Ordering;
9
10/// Mode used by translators to pick the correct registers/operations
11#[derive(Clone, Debug)]
12pub(crate) enum Mode {
13    X86,
14    Amd64,
15}
16
17impl Mode {
18    pub(crate) fn get_register(&self, capstone_id: x86_reg) -> Result<&'static X86Register, Error> {
19        get_register(self, capstone_id)
20    }
21
22    pub(crate) fn bits(&self) -> usize {
23        match *self {
24            Mode::X86 => 32,
25            Mode::Amd64 => 64,
26        }
27    }
28
29    pub(crate) fn sp(&self) -> Scalar {
30        match *self {
31            Mode::X86 => scalar("esp", 32),
32            Mode::Amd64 => scalar("rsp", 64),
33        }
34    }
35
36    pub(crate) fn get_register_expression(
37        &self,
38        register: capstone::x86_reg,
39        instruction: &capstone::Instr,
40    ) -> Result<Expression, Error> {
41        Ok(match register {
42            x86_reg::X86_REG_RIP => {
43                let value = instruction.address + instruction.size as u64;
44                expr_const(value, 64)
45            }
46            _ => get_register(self, register)?.get()?,
47        })
48    }
49
50    /// Gets the value of an operand as an IL expression
51    pub(crate) fn operand_value(
52        &self,
53        operand: &cs_x86_op,
54        instruction: &capstone::Instr,
55    ) -> Result<Expression, Error> {
56        match operand.type_ {
57            x86_op_type::X86_OP_INVALID => Err("Invalid operand".into()),
58            x86_op_type::X86_OP_REG => {
59                // Get the register value
60                get_register(self, operand.reg())?.get()
61            }
62            x86_op_type::X86_OP_MEM => {
63                let mem = operand.mem();
64                let base_capstone_reg = mem.base;
65                let index_capstone_reg = mem.index;
66
67                let base = match base_capstone_reg {
68                    x86_reg::X86_REG_INVALID => None,
69                    reg => Some(self.get_register_expression(reg, instruction)?),
70                };
71
72                let index = match index_capstone_reg {
73                    x86_reg::X86_REG_INVALID => None,
74                    reg => Some(self.get_register_expression(reg, instruction)?),
75                };
76
77                let scale = Expr::constant(Constant::new(mem.scale as i64 as u64, self.bits()));
78
79                let si = match index {
80                    Some(index) => Some(Expr::mul(index, scale)?),
81                    None => None,
82                };
83
84                // Handle base and scale/index
85                let op: Option<Expression> = match (base, si) {
86                    (Some(base), Some(si)) => Some(Expr::add(base, si)?),
87                    (Some(base), None) => Some(base),
88                    (None, si) => si,
89                };
90
91                // handle disp
92                let op = if let Some(op) = op {
93                    match mem.disp.cmp(&0) {
94                        Ordering::Greater => {
95                            Expr::add(op, expr_const(mem.disp as u64, self.bits()))?
96                        }
97                        Ordering::Less => {
98                            Expr::sub(op, expr_const(mem.disp.unsigned_abs(), self.bits()))?
99                        }
100                        Ordering::Equal => op,
101                    }
102                } else {
103                    expr_const(mem.disp as u64, self.bits())
104                };
105
106                match mem.segment {
107                    x86_reg::X86_REG_INVALID => Ok(op),
108                    x86_reg::X86_REG_CS
109                    | x86_reg::X86_REG_DS
110                    | x86_reg::X86_REG_ES
111                    | x86_reg::X86_REG_FS
112                    | x86_reg::X86_REG_GS
113                    | x86_reg::X86_REG_SS => {
114                        let segment_register = self.get_register(mem.segment)?.get()?;
115                        Ok(Expr::add(segment_register, op)?)
116                    }
117                    _ => Err(Error::Custom("invalid segment register".to_string())),
118                }
119            }
120            x86_op_type::X86_OP_IMM => {
121                // https://github.com/aquynh/capstone/issues/1586
122                let operand_size = if operand.size == 0 {
123                    8
124                } else {
125                    operand.size as usize * 8
126                };
127                Ok(expr_const(operand.imm() as u64, operand_size))
128            }
129        }
130    }
131
132    /// Gets the value of an operand as an IL expression, performing any required loads as needed.
133    pub fn operand_load(
134        &self,
135        block: &mut Block,
136        operand: &cs_x86_op,
137        instruction: &capstone::Instr,
138    ) -> Result<Expression, Error> {
139        let op = self.operand_value(operand, instruction)?;
140
141        if operand.type_ == x86_op_type::X86_OP_MEM {
142            let temp = Scalar::temp(instruction.address, operand.size as usize * 8);
143            block.load(temp.clone(), op);
144            return Ok(temp.into());
145        }
146        Ok(op)
147    }
148
149    /// Stores a value in an operand, performing any stores as necessary.
150    pub fn operand_store(
151        &self,
152        block: &mut Block,
153        operand: &cs_x86_op,
154        value: Expression,
155        instruction: &capstone::Instr,
156    ) -> Result<(), Error> {
157        match operand.type_ {
158            x86_op_type::X86_OP_INVALID => Err("operand_store called on invalid operand".into()),
159            x86_op_type::X86_OP_IMM => Err("operand_store called on immediate operand".into()),
160            x86_op_type::X86_OP_REG => {
161                let dst_register = self.get_register(operand.reg())?;
162                dst_register.set(block, value)
163            }
164            x86_op_type::X86_OP_MEM => {
165                let address = self.operand_value(operand, instruction)?;
166                block.store(address, value);
167                Ok(())
168            }
169        }
170    }
171
172    /// Convenience function to pop a value off the stack
173    pub fn pop_value(
174        &self,
175        block: &mut Block,
176        bits: usize,
177        instruction: &capstone::Instr,
178    ) -> Result<Expression, Error> {
179        let temp = Scalar::temp(instruction.address, bits);
180
181        block.load(temp.clone(), self.sp().into());
182        block.assign(
183            self.sp(),
184            Expr::add(self.sp().into(), expr_const((bits / 8) as u64, self.bits()))?,
185        );
186
187        Ok(temp.into())
188    }
189
190    /// Convenience function to push a value onto the stack
191    pub fn push_value(&self, block: &mut Block, value: Expression) -> Result<(), Error> {
192        match self {
193            Mode::X86 => block.assign(self.sp(), Expr::sub(self.sp().into(), expr_const(4, 32))?),
194            Mode::Amd64 => block.assign(self.sp(), Expr::sub(self.sp().into(), expr_const(8, 64))?),
195        };
196
197        block.store(self.sp().into(), value);
198        Ok(())
199    }
200}