Skip to content

Commit

Permalink
Added the capstone disassembler and a disassembler window
Browse files Browse the repository at this point in the history
  • Loading branch information
WerWolv committed Nov 22, 2020
1 parent b3fffdf commit 4402120
Show file tree
Hide file tree
Showing 5 changed files with 327 additions and 4 deletions.
9 changes: 6 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ set(CMAKE_CXX_STANDARD 20)

find_package(PkgConfig REQUIRED)
pkg_search_module(GLFW REQUIRED glfw3)
pkg_search_module(GLM REQUIRED glm)
pkg_search_module(CAPSTONE REQUIRED capstone)
find_package(OpenGL REQUIRED)

include_directories(include ${GLFW_INCLUDE_DIRS} libs/ImGui/include libs/glad/include)
include_directories(include ${GLFW_INCLUDE_DIRS} ${CAPSTONE_INCLUDE_DIRS} libs/ImGui/include libs/glad/include)
SET(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -DIMGUI_IMPL_OPENGL_LOADER_GLAD")

if (WIN32)
Expand Down Expand Up @@ -37,6 +39,7 @@ add_executable(ImHex
source/views/view_tools.cpp
source/views/view_strings.cpp
source/views/view_data_inspector.cpp
source/views/view_disassembler.cpp

libs/glad/source/glad.c

Expand All @@ -53,9 +56,9 @@ add_executable(ImHex
)

if (WIN32)
target_link_libraries(ImHex libglfw3.a libgcc.a libstdc++.a libmagic.a libgnurx.a libtre.a libintl.a libiconv.a shlwapi.lib libcrypto.a libwinpthread.a)
target_link_libraries(ImHex libglfw3.a libgcc.a libstdc++.a libmagic.a libgnurx.a libtre.a libintl.a libiconv.a shlwapi.lib libcrypto.a libwinpthread.a libcapstone.a)
endif (WIN32)

if (UNIX)
target_link_libraries(ImHex libglfw.so libmagic.so libcrypto.so libdl.so)
target_link_libraries(ImHex libglfw.so libmagic.so libcrypto.so libdl.so libcapstone.so)
endif (UNIX)
49 changes: 49 additions & 0 deletions include/views/view_disassembler.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#pragma once

#include "views/view.hpp"

#include <capstone/capstone.h>

#include <cstdio>
#include <string>
#include <vector>

namespace hex {

namespace prv { class Provider; }

struct Disassembly {
u64 address;
u64 offset;
std::string bytes;
std::string opcodeString;
};

class ViewDisassembler : public View {
public:
explicit ViewDisassembler(prv::Provider* &dataProvider);
~ViewDisassembler() override;

void createView() override;
void createMenu() override;

private:
prv::Provider* &m_dataProvider;
bool m_windowOpen = true;

bool m_shouldInvalidate = false;

u64 m_baseAddress = 0;
u64 m_codeOffset = 0;
u64 m_codeSize = 0;

cs_arch m_architecture = CS_ARCH_ARM;
cs_mode m_modeBasicARM = cs_mode(0), m_modeExtraARM = cs_mode(0), m_modeBasicMIPS = cs_mode(0), m_modeBasicPPC = cs_mode(0), m_modeBasicX86 = cs_mode(0);
bool m_littleEndianMode = true, m_micoMode = false, m_sparcV9Mode = false;

std::vector<Disassembly> m_disassembly;


};

}
4 changes: 3 additions & 1 deletion source/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "views/view_tools.hpp"
#include "views/view_strings.hpp"
#include "views/view_data_inspector.hpp"
#include "views/view_disassembler.hpp"

#include "providers/provider.hpp"

Expand All @@ -29,8 +30,9 @@ int main() {
window.addView<hex::ViewHashes>(dataProvider);
window.addView<hex::ViewInformation>(dataProvider);
window.addView<hex::ViewStrings>(dataProvider);
window.addView<hex::ViewHelp>();
window.addView<hex::ViewDisassembler>(dataProvider);
window.addView<hex::ViewTools>();
window.addView<hex::ViewHelp>();

window.loop();

Expand Down
268 changes: 268 additions & 0 deletions source/views/view_disassembler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,268 @@
#include "views/view_disassembler.hpp"

#include "providers/provider.hpp"
#include "utils.hpp"

#include <cstring>

using namespace std::literals::string_literals;

namespace hex {

ViewDisassembler::ViewDisassembler(prv::Provider* &dataProvider) : View(), m_dataProvider(dataProvider) {
View::subscribeEvent(Events::DataChanged, [this](const void*){
this->m_shouldInvalidate = true;
});
}

ViewDisassembler::~ViewDisassembler() {
View::unsubscribeEvent(Events::DataChanged);
}

void ViewDisassembler::createView() {
if (!this->m_windowOpen)
return;

if (this->m_shouldInvalidate) {
this->m_disassembly.clear();

csh capstoneHandle;
cs_insn *instructions = nullptr;

cs_mode mode = cs_mode(this->m_modeBasicARM | this->m_modeExtraARM | this->m_modeBasicMIPS | this->m_modeBasicX86 | this->m_modeBasicPPC);

if (this->m_littleEndianMode)
mode = cs_mode(mode | CS_MODE_LITTLE_ENDIAN);
else
mode = cs_mode(mode | CS_MODE_BIG_ENDIAN);

if (this->m_micoMode)
mode = cs_mode(mode | CS_MODE_MICRO);

if (this->m_sparcV9Mode)
mode = cs_mode(mode | CS_MODE_V9);

if (cs_open(this->m_architecture, mode, &capstoneHandle) == CS_ERR_OK) {

std::vector<u8> buffer(2048, 0x00);
for (u64 address = 0; address < this->m_codeSize; address += 2048) {
size_t bufferSize = std::min(u64(2048), this->m_codeSize - address);
this->m_dataProvider->read(this->m_codeOffset + address, buffer.data(), bufferSize);

size_t instructionCount = cs_disasm(capstoneHandle, buffer.data(), buffer.size(), this->m_baseAddress + address, 0, &instructions);

if (instructionCount == 0)
break;

u64 usedBytes = 0;
for (u32 instr = 0; instr < instructionCount; instr++) {
Disassembly disassembly = { 0 };
disassembly.address = instructions[instr].address;
disassembly.offset = this->m_codeOffset + address + usedBytes;
disassembly.opcodeString = instructions[instr].mnemonic + " "s + instructions[instr].op_str;

for (u8 i = 0; i < instructions[instr].size; i++)
disassembly.bytes += hex::format("%02X ", instructions[instr].bytes[i]);
disassembly.bytes.pop_back();

this->m_disassembly.push_back(disassembly);

usedBytes += instructions[instr].size;
}

if (instructionCount < bufferSize)
address -= (bufferSize - usedBytes);

cs_free(instructions, instructionCount);
}

cs_close(&capstoneHandle);
}

this->m_shouldInvalidate = false;
}


if (ImGui::Begin("Disassembler", &this->m_windowOpen)) {

if (this->m_dataProvider != nullptr && this->m_dataProvider->isReadable()) {
constexpr static const char * const ArchitectureNames[] = { "ARM32", "ARM64", "MIPS", "x86", "PowerPC", "Sparc", "SystemZ", "XCore", "68K", "TMS320C64x", "680X", "Ethereum" };

ImGui::InputScalar("Base address", ImGuiDataType_U64, &this->m_baseAddress, nullptr, nullptr, "%llx", ImGuiInputTextFlags_CharsHexadecimal);

ImGui::NewLine();

ImGui::InputScalar("Code start offset", ImGuiDataType_U64, &this->m_codeOffset, nullptr, nullptr, "%llx", ImGuiInputTextFlags_CharsHexadecimal);
ImGui::InputScalar("Code size", ImGuiDataType_U64, &this->m_codeSize, nullptr, nullptr, "%llx", ImGuiInputTextFlags_CharsHexadecimal);

ImGui::NewLine();
ImGui::Separator();
ImGui::NewLine();

ImGui::Combo("Architecture", reinterpret_cast<int*>(&this->m_architecture), ArchitectureNames, 12);


if (ImGui::BeginChild("modes", ImVec2(0, 100), true)) {

if (ImGui::RadioButton("Little Endian", this->m_littleEndianMode))
this->m_littleEndianMode = true;
ImGui::SameLine();
if (ImGui::RadioButton("Big Endian", !this->m_littleEndianMode))
this->m_littleEndianMode = false;

ImGui::NewLine();

switch (this->m_architecture) {
case CS_ARCH_ARM:
this->m_modeBasicMIPS = cs_mode(0);
this->m_modeBasicX86 = cs_mode(0);
this->m_modeBasicPPC = cs_mode(0);
this->m_micoMode = false;
this->m_sparcV9Mode = false;

if (ImGui::RadioButton("ARM mode", this->m_modeBasicARM == CS_MODE_ARM))
this->m_modeBasicARM = CS_MODE_ARM;
ImGui::SameLine();
if (ImGui::RadioButton("Thumb mode", this->m_modeBasicARM == CS_MODE_THUMB))
this->m_modeBasicARM = CS_MODE_THUMB;

if (ImGui::RadioButton("Default mode", (this->m_modeExtraARM & (CS_MODE_MCLASS | CS_MODE_V8)) == 0))
this->m_modeExtraARM = cs_mode(0);
ImGui::SameLine();
if (ImGui::RadioButton("Cortex-M mode", (this->m_modeExtraARM & (CS_MODE_MCLASS | CS_MODE_V8)) == CS_MODE_MCLASS))
this->m_modeExtraARM = CS_MODE_MCLASS;
ImGui::SameLine();
if (ImGui::RadioButton("ARMv8 mode", (this->m_modeExtraARM & (CS_MODE_MCLASS | CS_MODE_V8)) == CS_MODE_V8))
this->m_modeExtraARM = CS_MODE_V8;
break;
case CS_ARCH_MIPS:
this->m_modeBasicARM = cs_mode(0);
this->m_modeExtraARM = cs_mode(0);
this->m_modeBasicX86 = cs_mode(0);
this->m_modeBasicPPC = cs_mode(0);
this->m_sparcV9Mode = false;

if (ImGui::RadioButton("MIPS32 mode", this->m_modeBasicMIPS == CS_MODE_MIPS32))
this->m_modeBasicMIPS = CS_MODE_MIPS32;
ImGui::SameLine();
if (ImGui::RadioButton("MIPS64 mode", this->m_modeBasicMIPS == CS_MODE_MIPS64))
this->m_modeBasicMIPS = CS_MODE_MIPS64;
ImGui::SameLine();
if (ImGui::RadioButton("MIPS32R6 mode", this->m_modeBasicMIPS == CS_MODE_MIPS32R6))
this->m_modeBasicMIPS = CS_MODE_MIPS32R6;

ImGui::Checkbox("Micro Mode", &this->m_micoMode);
break;
case CS_ARCH_X86:
this->m_modeBasicARM = cs_mode(0);
this->m_modeExtraARM = cs_mode(0);
this->m_modeBasicMIPS = cs_mode(0);
this->m_modeBasicPPC = cs_mode(0);
this->m_micoMode = false;
this->m_sparcV9Mode = false;

if (ImGui::RadioButton("16-bit mode", this->m_modeBasicX86 == CS_MODE_16))
this->m_modeBasicX86 = CS_MODE_16;
ImGui::SameLine();
if (ImGui::RadioButton("32-bit mode", this->m_modeBasicX86 == CS_MODE_32))
this->m_modeBasicX86 = CS_MODE_32;
ImGui::SameLine();
if (ImGui::RadioButton("64-bit mode", this->m_modeBasicX86 == CS_MODE_64))
this->m_modeBasicX86 = CS_MODE_64;
break;
case CS_ARCH_PPC:
this->m_modeBasicARM = cs_mode(0);
this->m_modeExtraARM = cs_mode(0);
this->m_modeBasicMIPS = cs_mode(0);
this->m_modeBasicX86 = cs_mode(0);
this->m_micoMode = false;
this->m_sparcV9Mode = false;

if (ImGui::RadioButton("32-bit mode", this->m_modeBasicPPC == CS_MODE_32))
this->m_modeBasicPPC = CS_MODE_32;
ImGui::SameLine();
if (ImGui::RadioButton("64-bit mode", this->m_modeBasicPPC == CS_MODE_64))
this->m_modeBasicPPC = CS_MODE_64;
break;
case CS_ARCH_SPARC:
this->m_modeBasicARM = cs_mode(0);
this->m_modeExtraARM = cs_mode(0);
this->m_modeBasicMIPS = cs_mode(0);
this->m_modeBasicX86 = cs_mode(0);
this->m_modeBasicPPC = cs_mode(0);
this->m_micoMode = false;

ImGui::Checkbox("Sparc V9 mode", &this->m_sparcV9Mode);
break;
case CS_ARCH_ARM64:
case CS_ARCH_SYSZ:
case CS_ARCH_XCORE:
case CS_ARCH_M68K:
case CS_ARCH_TMS320C64X:
case CS_ARCH_M680X:
case CS_ARCH_EVM:
this->m_modeBasicARM = cs_mode(0);
this->m_modeExtraARM = cs_mode(0);
this->m_modeBasicMIPS = cs_mode(0);
this->m_modeBasicX86 = cs_mode(0);
this->m_modeBasicPPC = cs_mode(0);
this->m_micoMode = false;
this->m_sparcV9Mode = false;
break;
}

ImGui::EndChild();
}

ImGui::NewLine();
if (ImGui::Button("Disassemble"))
this->m_shouldInvalidate = true;
ImGui::NewLine();
ImGui::Separator();
ImGui::NewLine();

if (ImGui::BeginChild("##scrolling")) {
if (ImGui::BeginTable("##disassembly", 4, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoBordersInBody)) {
ImGui::TableSetupColumn("Address");
ImGui::TableSetupColumn("Offset");
ImGui::TableSetupColumn("Bytes");
ImGui::TableSetupColumn("Disassembly");

ImGuiListClipper clipper;
clipper.Begin(this->m_disassembly.size());

ImGui::TableHeadersRow();
while (clipper.Step()) {
for (u64 i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("0x%llx", this->m_disassembly[i].address);
ImGui::TableNextColumn();
ImGui::Text("0x%llx", this->m_disassembly[i].offset);
ImGui::TableNextColumn();
ImGui::TextUnformatted(this->m_disassembly[i].bytes.c_str());
ImGui::TableNextColumn();
ImGui::TextUnformatted(this->m_disassembly[i].opcodeString.c_str());
}
}

clipper.End();

ImGui::EndTable();
}
}
ImGui::EndChild();

}
}
ImGui::End();
}

void ViewDisassembler::createMenu() {
if (ImGui::BeginMenu("View")) {
ImGui::MenuItem("Disassembler View", "", &this->m_windowOpen);
ImGui::EndMenu();
}
}

}
1 change: 1 addition & 0 deletions source/views/view_help.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ namespace hex {
ImGui::BulletText("imgui_club by ocornut");
ImGui::BulletText("ImGui-Addons by gallickgunner");
ImGui::BulletText("ImGuiColorTextEdit by BalazsJako");
ImGui::BulletText("capstone by aquynh");
ImGui::NewLine();
ImGui::BulletText("GNU libmagic");
ImGui::BulletText("OpenSSL libcrypto");
Expand Down

0 comments on commit 4402120

Please sign in to comment.