Skip to content

Commit 0fcfd65

Browse files
committed
[WARP] Filter out LLIL_JUMP artifacts in lifted IL
With the new instruction retrieval we are getting the instructions at the end of the lifted function which are not really apart of the function, but they share the address of the last ret/jump.
1 parent fc07989 commit 0fcfd65

File tree

2 files changed

+31
-9
lines changed

2 files changed

+31
-9
lines changed

plugins/warp/src/lib.rs

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::convert::{bn_comment_to_comment, bn_var_to_location, from_bn_symbol,
33
use binaryninja::architecture::{
44
Architecture, ImplicitRegisterExtend, Register as BNRegister, RegisterInfo,
55
};
6-
use binaryninja::basic_block::BasicBlock as BNBasicBlock;
6+
use binaryninja::basic_block::{BasicBlock as BNBasicBlock};
77
use binaryninja::binary_view::{BinaryView, BinaryViewExt};
88
use binaryninja::confidence::MAX_CONFIDENCE;
99
use binaryninja::function::{Function as BNFunction, NativeBlock};
@@ -186,7 +186,7 @@ pub fn basic_block_guid<M: FunctionMutability>(
186186
instr_bytes.truncate(instr_info.length);
187187

188188
// Find variant and blacklisted instructions using lifted il.
189-
for lifted_il_instr in lifted_il.instructions_at(instr_addr) {
189+
for lifted_il_instr in filtered_instructions_at(lifted_il, instr_addr) {
190190
// If instruction is blacklisted, don't include the bytes.
191191
if is_blacklisted_instruction(&lifted_il_instr) {
192192
continue;
@@ -209,7 +209,7 @@ pub fn basic_block_guid<M: FunctionMutability>(
209209
// TODO: A "mapped llil" or having some simple data flow, the simple data flow is the most attractive
210210
// TODO: "solution", but it would require
211211
if let Ok(llil) = &low_level_il {
212-
for low_level_instr in llil.instructions_at(instr_addr) {
212+
for low_level_instr in filtered_instructions_at(llil, instr_addr) {
213213
if is_computed_variant_instruction(relocatable_regions, &low_level_instr) {
214214
// Found a computed variant instruction, mask off the entire instruction.
215215
instr_bytes.fill(0);
@@ -226,6 +226,25 @@ pub fn basic_block_guid<M: FunctionMutability>(
226226
BasicBlockGUID::from(basic_block_bytes.as_slice())
227227
}
228228

229+
pub fn filtered_instructions_at<M: FunctionMutability>(
230+
il: &LowLevelILFunction<M, NonSSA>,
231+
addr: u64,
232+
) -> Vec<LowLevelILInstruction<M, NonSSA>> {
233+
il.instructions_at(addr)
234+
.into_iter()
235+
.enumerate()
236+
.take_while(|(i, instr)| match instr.kind() {
237+
// Stop collecting instructions after we see a LLIL_RET, LLIL_NO_RET.
238+
LowLevelILInstructionKind::NoRet(_) | LowLevelILInstructionKind::Ret(_) => false,
239+
// Stop collecting instruction if we are probably the end function jump in lifted IL. This
240+
// is emitted at the end of the function and will mess with our GUID.
241+
LowLevelILInstructionKind::Jump(_) => *i != 0,
242+
_ => true,
243+
})
244+
.map(|(_, instr)| instr)
245+
.collect()
246+
}
247+
229248
/// Is the instruction not included in the masked byte sequence?
230249
///
231250
/// Blacklisted instructions will make an otherwise identical function GUID fail to match.
@@ -301,7 +320,7 @@ pub fn is_computed_variant_instruction<M: FunctionMutability>(
301320
instr: &LowLevelILInstruction<M, NonSSA>,
302321
) -> bool {
303322
let is_expr_constant = |expr: &LowLevelILExpression<M, NonSSA, ValueExpr>| match expr.kind() {
304-
LowLevelILExpressionKind::Const(_) => true,
323+
LowLevelILExpressionKind::Const(_) | LowLevelILExpressionKind::ConstPtr(_) => true,
305324
_ => false,
306325
};
307326

plugins/warp/src/plugin/render_layer.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::{
2-
is_blacklisted_instruction, is_computed_variant_instruction, is_variant_instruction,
3-
relocatable_regions,
2+
filtered_instructions_at, is_blacklisted_instruction, is_computed_variant_instruction,
3+
is_variant_instruction, relocatable_regions,
44
};
55
use binaryninja::basic_block::BasicBlock;
66
use binaryninja::disassembly::DisassemblyTextLine;
@@ -51,15 +51,15 @@ impl HighlightRenderLayer {
5151
let relocatable_regions = relocatable_regions(&lifted_il.function().view());
5252
for line in lines {
5353
// We use address here instead of index since it's more reliable for other IL's.
54-
for lifted_il_instr in lifted_il.instructions_at(line.address) {
54+
for lifted_il_instr in filtered_instructions_at(lifted_il, line.address) {
5555
if is_blacklisted_instruction(&lifted_il_instr) {
5656
line.highlight = self.blacklist;
5757
} else if is_variant_instruction(&relocatable_regions, &lifted_il_instr) {
5858
line.highlight = self.variant;
5959
}
6060
}
6161

62-
for llil_instr in llil.instructions_at(line.address) {
62+
for llil_instr in filtered_instructions_at(llil, line.address) {
6363
if is_computed_variant_instruction(&relocatable_regions, &llil_instr) {
6464
line.highlight = self.computed_variant;
6565
}
@@ -86,7 +86,10 @@ impl RenderLayer for HighlightRenderLayer {
8686
) -> Vec<DisassemblyTextLine> {
8787
// Highlight any instruction that WARP will mask.
8888
let function = block.function();
89-
if let (Ok(lifted_il), Ok(llil)) = (function.lifted_il(), function.low_level_il()) {
89+
if let (Some(lifted_il), Some(llil)) = (
90+
function.lifted_il_if_available(),
91+
function.low_level_il_if_available(),
92+
) {
9093
self.highlight_lines(&lifted_il, &llil, &mut lines);
9194
}
9295
lines

0 commit comments

Comments
 (0)