Skip to content

Commit

Permalink
Decluter InstructionInformation (#42)
Browse files Browse the repository at this point in the history
This PR removes the `BeaEngine` / `Capstone` specific field from the `InstructionInformation` structure and simplifies the `DisassEngineWrapper` interface as well (fixes #33).

It also fixes the `Gadget::Comparator` functor to operate on the dissassembly because since #41 they might not be there anymore.

Finally, it properly detects any kind of branches in a gadget - if `--allow-branches` is not specified, those will not appear as valid results.
  • Loading branch information
0vercl0k authored Feb 20, 2022
1 parent d381b12 commit 5cf4898
Show file tree
Hide file tree
Showing 6 changed files with 41 additions and 113 deletions.
39 changes: 13 additions & 26 deletions src/rp/arm.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,6 @@ class ArmCapstone : public DisassEngineWrapper {
instr.virtual_address_in_memory = uintptr_t(vaddr);
instr.disassembly = mnemonic + ' ' + std::string(insn[0].op_str);
instr.size = insn[0].size;

instr.cap_is_branch = false;
instr.cap_is_valid_ending_instr = false;
ret = AllRight;

if (insn[0].detail == nullptr) {
Expand All @@ -54,28 +51,28 @@ class ArmCapstone : public DisassEngineWrapper {
}

if (cs_insn_group(m_handle, insn, ARM_GRP_JUMP)) {
instr.cap_is_branch = true;
instr.cap_is_valid_ending_instr =
instr.is_branch = true;
instr.is_valid_ending_instr =
insn[0].detail->arm.op_count == 1 &&
insn[0].detail->arm.operands[0].type != ARM_OP_IMM;
} else if (mnemonic == "b" || mnemonic == "bl" || mnemonic == "blx" ||
mnemonic == "cb" || mnemonic == "cbz") {
instr.cap_is_branch = true;
instr.is_branch = true;
} else if (mnemonic == "swi" || mnemonic == "svc") {
instr.cap_is_branch = true;
instr.cap_is_valid_ending_instr = true;
instr.is_branch = true;
instr.is_valid_ending_instr = true;
} else if (mnemonic == "mov" && insn[0].detail->arm.op_count >= 1 &&
insn[0].detail->arm.operands[0].type == ARM_OP_REG &&
insn[0].detail->arm.operands[0].reg == ARM_REG_PC) {
instr.cap_is_branch = true;
instr.cap_is_valid_ending_instr = true;
instr.is_branch = true;
instr.is_valid_ending_instr = true;
} else if (mnemonic == "bx") {
instr.cap_is_branch = true;
instr.cap_is_valid_ending_instr =
instr.is_branch = true;
instr.is_valid_ending_instr =
insn[0].detail->arm.operands[0].type == ARM_OP_REG;
} else if (mnemonic == "blx") {
instr.cap_is_branch = true;
instr.cap_is_valid_ending_instr = true;
instr.is_branch = true;
instr.is_valid_ending_instr = true;
} else if (mnemonic == "pop") {
bool has_pc = false;
for (size_t i = 0; i < insn[0].detail->arm.op_count; ++i) {
Expand All @@ -87,25 +84,15 @@ class ArmCapstone : public DisassEngineWrapper {
}

if (has_pc) {
instr.cap_is_branch = true;
instr.cap_is_valid_ending_instr = true;
instr.is_branch = true;
instr.is_valid_ending_instr = true;
}
}

cs_free(insn, count);
return instr;
}

bool is_valid_ending_instruction(
const InstructionInformation &instr) const override {
return instr.cap_is_valid_ending_instr;
}

bool
is_valid_instruction(const InstructionInformation &instr) const override {
return instr.cap_is_branch == false;
}

uint32_t get_size_biggest_instruction() const override { return 4; }

uint32_t get_alignement() const override {
Expand Down
17 changes: 2 additions & 15 deletions src/rp/arm64.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,6 @@ class Arm64Capstone : public DisassEngineWrapper {
instr.virtual_address_in_memory = uintptr_t(vaddr);
instr.disassembly = mnemonic + ' ' + std::string(insn[0].op_str);
instr.size = insn[0].size;

instr.cap_is_branch = false;
instr.cap_is_valid_ending_instr = false;
ret = AllRight;

if (insn[0].detail == nullptr) {
Expand All @@ -51,8 +48,8 @@ class Arm64Capstone : public DisassEngineWrapper {
const bool Call = cs_insn_group(m_handle, insn, ARM64_GRP_CALL);
const bool Ret = cs_insn_group(m_handle, insn, ARM64_GRP_RET);
const bool Int = cs_insn_group(m_handle, insn, ARM64_GRP_INT);
instr.cap_is_branch = Jump || Call || Ret || Int;
instr.cap_is_valid_ending_instr =
instr.is_branch = Jump || Call || Ret || Int;
instr.is_valid_ending_instr =
Ret || Int ||
((Jump || Call) && insn[0].detail->arm64.op_count == 1 &&
insn[0].detail->arm64.operands[0].type != ARM64_OP_IMM);
Expand All @@ -61,16 +58,6 @@ class Arm64Capstone : public DisassEngineWrapper {
return instr;
}

bool is_valid_ending_instruction(
const InstructionInformation &instr) const override {
return instr.cap_is_valid_ending_instr;
}

bool
is_valid_instruction(const InstructionInformation &instr) const override {
return instr.cap_is_branch == false;
}

uint32_t get_size_biggest_instruction() const override { return 4; }

uint32_t get_alignement() const override { return 4; }
Expand Down
16 changes: 2 additions & 14 deletions src/rp/disassenginewrapper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,14 @@
#include <vector>

struct InstructionInformation {
// Generic fields
std::string disassembly;
std::string mnemonic;
uint32_t size = 0;
uintptr_t address = 0;
uintptr_t virtual_address_in_memory = 0;
std::vector<uint8_t> bytes;

// Capstone field
bool cap_is_branch = false;
bool cap_is_valid_ending_instr = false;

// BeaEngine fields
uint32_t bea_branch_type = 0; // This is used by BeaEngine ; and this will
// hold DISASM.Instruction.BranchType
uint64_t bea_addr_value = 0; // This is used by BeaEngine, DISASM.Instruction
bool is_branch = false;
bool is_valid_ending_instr = false;
};

enum DisassEngineReturn { UnknownInstruction, OutOfBlock, AllRight };
Expand All @@ -39,10 +31,6 @@ class DisassEngineWrapper {
virtual InstructionInformation disass(const uint8_t *data, uint64_t len,
const uint64_t vaddr,
DisassEngineReturn &ret) = 0;
virtual bool
is_valid_ending_instruction(const InstructionInformation &instr) const = 0;
virtual bool
is_valid_instruction(const InstructionInformation &instr) const = 0;
virtual uint32_t get_size_biggest_instruction() const = 0;
virtual uint32_t get_alignement() const = 0;
};
40 changes: 12 additions & 28 deletions src/rp/gadget.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,34 +142,18 @@ class Gadget {
return true;
}

const auto &current_a_bytes = a.m_instructions[current_a_idx].bytes();
const size_t current_a_bytes_size = current_a_bytes.size();
const auto &current_b_bytes = b.m_instructions[current_b_idx].bytes();
const size_t current_b_bytes_size = current_b_bytes.size();
while (1) {
if (current_a_bytes_idx >= current_a_bytes_size) {
current_a_idx++;
current_a_bytes_idx = 0;
break;
}

if (current_b_bytes_idx >= current_b_bytes_size) {
current_b_idx++;
current_b_bytes_idx = 0;
break;
}

if (current_a_bytes[current_a_bytes_idx] !=
current_b_bytes[current_b_bytes_idx]) {
return current_a_bytes[current_a_bytes_idx] <
current_b_bytes[current_b_bytes_idx];
}

current_a_bytes_idx++;
current_b_bytes_idx++;
const auto &current_a_disass =
a.m_instructions[current_a_idx].get_disassembly();
const auto &current_b_disass =
b.m_instructions[current_b_idx].get_disassembly();
const int compare = current_a_disass.compare(current_b_disass);
if (compare != 0) {
return (compare < 0) ? true : false;
}

current_a_idx++;
current_b_idx++;
}
return false;
}
};

Expand All @@ -186,8 +170,8 @@ class Gadget {
uint32_t m_size; /*!< the size in byte of the gadget*/

std::vector<Instruction>
m_instructions; /*!< the list of the different instructions composing the
gadget*/
m_instructions; /*!< the list of the different instructions composing
the gadget*/

mutable std::vector<Info>
m_info_gadgets; /*!< the vector which stores where you can find the same
Expand Down
36 changes: 10 additions & 26 deletions src/rp/intelbeaengine.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,49 +44,33 @@ class IntelBeaEngine : public DisassEngineWrapper {
instr.disassembly = m_disasm.CompleteInstr;
instr.mnemonic = m_disasm.Instruction.Mnemonic;
instr.size = len_instr;
instr.bea_branch_type = m_disasm.Instruction.BranchType;
instr.bea_addr_value = m_disasm.Instruction.AddrValue;
return instr;
}

bool is_valid_ending_instruction(
const InstructionInformation &instr) const override {
const uint32_t branch_type = instr.bea_branch_type;
const uint64_t addr_value = instr.bea_addr_value;
const char *mnemonic_s = instr.mnemonic.c_str();
const auto branch_type = m_disasm.Instruction.BranchType;
const auto addr_value = m_disasm.Instruction.AddrValue;
const char *mnemonic_s = m_disasm.Instruction.Mnemonic;
const char *disass_s = instr.disassembly.c_str();

const std::string &disass = instr.disassembly;
const char *disass_s = disass.c_str();
instr.is_branch = branch_type != 0;

const bool is_good_branch_type =
// We accept all the ret type instructions (except retf/iret)
(branch_type == RetType && (strncmp(mnemonic_s, "retf", 4) != 0) &&
(strncmp(mnemonic_s, "iretd", 5) != 0)) ||

// call reg32 / call [reg32]
(branch_type == CallType && addr_value == 0) ||

// jmp reg32 / jmp [reg32]
(branch_type == JmpType && addr_value == 0) ||

// int 0x80 & int 0x2e
((strncmp(disass_s, "int 0x80", 8) == 0) ||
(strncmp(disass_s, "int 0x2e", 8) == 0) ||
(strncmp(disass_s, "syscall", 7) == 0));

return is_good_branch_type &&
// Yeah, we don't accept jmp far/call far
disass.find("far") == std::string::npos;
}
instr.is_valid_ending_instr =
is_good_branch_type &&
// Yeah, we don't accept jmp far/call far
instr.disassembly.find("far") == std::string::npos;

bool
is_valid_instruction(const InstructionInformation &instr) const override {
const Int32 branch_type = instr.bea_branch_type;
const uint64_t addr_value = instr.bea_addr_value;
return branch_type != RetType && branch_type != JmpType &&
((branch_type == CallType && addr_value == 0) ||
branch_type != CallType) &&
instr.disassembly.find("far") == std::string::npos;
return instr;
}

uint32_t get_size_biggest_instruction() const override { return 15; }
Expand Down
6 changes: 2 additions & 4 deletions src/rp/ropsearch_algorithm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,7 @@ void find_all_gadget_from_ret(const std::vector<uint8_t> &memory,
InstructionInformation instr =
disass_engine.disass(EIP_, end_data - EIP_, VirtualAddr, ret);

const bool is_valid = g_opts.allow_branches
? true
: disass_engine.is_valid_instruction(instr);
const bool is_valid = g_opts.allow_branches || (!instr.is_branch);
// if the instruction isn't valid, ends this function
if (ret == UnknownInstruction || ret == OutOfBlock || !is_valid) {
break;
Expand Down Expand Up @@ -126,7 +124,7 @@ void find_rop_gadgets(const std::vector<uint8_t> &section, const uint64_t vaddr,
continue;
}

if (!disass_engine.is_valid_ending_instruction(ret_instr)) {
if (!ret_instr.is_valid_ending_instr) {
continue;
}

Expand Down

0 comments on commit 5cf4898

Please sign in to comment.