Implement gdb remote stub

This commit is contained in:
momo5502
2024-08-25 19:31:08 +02:00
parent 2b978eb7a6
commit 5a250d5824
7 changed files with 210 additions and 1 deletions

4
.gitmodules vendored
View File

@@ -11,3 +11,7 @@
path = deps/reflect
url = https://github.com/qlibs/reflect.git
shallow = true
[submodule "deps/mini-gdbstub"]
path = deps/mini-gdbstub
url = ../mini-gdbstub.git
shallow = true

4
deps/CMakeLists.txt vendored
View File

@@ -9,3 +9,7 @@ add_library(reflect INTERFACE)
target_include_directories(reflect INTERFACE
"${CMAKE_CURRENT_LIST_DIR}/reflect"
)
##########################################
include(mini-gdbstub.cmake)

1
deps/mini-gdbstub vendored Submodule

Submodule deps/mini-gdbstub added at e0fc593337

11
deps/mini-gdbstub.cmake vendored Normal file
View File

@@ -0,0 +1,11 @@
file(GLOB_RECURSE SRC_FILES CONFIGURE_DEPENDS
mini-gdbstub/lib/*.c
)
list(SORT SRC_FILES)
add_library(mini-gdbstub ${SRC_FILES})
target_include_directories(mini-gdbstub PUBLIC
"${CMAKE_CURRENT_LIST_DIR}/mini-gdbstub/include"
)

View File

@@ -15,6 +15,11 @@ public:
static constexpr registers stack_pointer = StackPointer;
static constexpr registers instruction_pointer = InstructionPointer;
void start_from_ip(const std::chrono::microseconds timeout = {}, const size_t count = 0)
{
this->start(this->read_instruction_pointer(), 0, timeout, count);
}
void write_register(registers reg, const void* value, const size_t size)
{
this->write_raw_register(static_cast<int>(reg), value, size);

View File

@@ -17,6 +17,7 @@ target_link_libraries(windows_emulator PRIVATE
phnt::phnt
reflect
unicorn_emulator
mini-gdbstub
)
set_property(GLOBAL PROPERTY VS_STARTUP_PROJECT windows_emulator)

View File

@@ -9,6 +9,10 @@
#include <unicorn_x64_emulator.hpp>
extern "C" {
#include <gdbstub.h>
}
#define GS_SEGMENT_ADDR 0x6000000ULL
#define GS_SEGMENT_SIZE (20 << 20) // 20 MB
@@ -286,8 +290,182 @@ namespace
});
}
enum class gdb_registers
{
rax = 0,
rbx,
rcx,
rdx,
rsi,
rdi,
rbp,
rsp,
r8,
r9,
r10,
r11,
r12,
r13,
r14,
r15,
rip,
eflags,
end,
};
std::unordered_map<gdb_registers, x64_register> register_map{
{gdb_registers::rax, x64_register::rax},
{gdb_registers::rbx, x64_register::rbx},
{gdb_registers::rcx, x64_register::rcx},
{gdb_registers::rdx, x64_register::rdx},
{gdb_registers::rsi, x64_register::rsi},
{gdb_registers::rdi, x64_register::rdi},
{gdb_registers::rbp, x64_register::rbp},
{gdb_registers::rsp, x64_register::rsp},
{gdb_registers::r8, x64_register::r8},
{gdb_registers::r9, x64_register::r9},
{gdb_registers::r10, x64_register::r10},
{gdb_registers::r11, x64_register::r11},
{gdb_registers::r12, x64_register::r12},
{gdb_registers::r13, x64_register::r13},
{gdb_registers::r14, x64_register::r14},
{gdb_registers::r15, x64_register::r15},
{gdb_registers::rip, x64_register::rip},
{gdb_registers::eflags, x64_register::rflags},
};
void run()
{
gdbstub_t stub{};
target_ops ops{};
ops.cont = +[](void* args)
{
static_cast<x64_emulator*>(static_cast<emulator*>(args))->start_from_ip();
return ACT_RESUME;
};
ops.stepi = +[](void* args)
{
static_cast<x64_emulator*>(static_cast<emulator*>(args))->start_from_ip({}, 1);
return ACT_RESUME;
};
ops.read_reg = +[](void* args, int regno, size_t* value)
{
try
{
const auto mapped_register = register_map.at(static_cast<gdb_registers>(regno));
static_cast<emulator*>(args)->read_raw_register(static_cast<int>(mapped_register), value, sizeof(*value));
return 0;
}
catch (...)
{
*value = 0;
return 0;
}
};
ops.write_reg = +[](void* args, const int regno, const size_t value)
{
try
{
const auto mapped_register = register_map.at(static_cast<gdb_registers>(regno));
static_cast<emulator*>(args)->write_raw_register(static_cast<int>(mapped_register), &value, sizeof(value));
return 0;
}
catch (...)
{
return 1;
}
};
ops.read_mem = +[](void* args, const size_t addr, const size_t len, void* val)
{
try
{
static_cast<emulator*>(args)->read_memory(addr, val, len);
return 0;
}
catch (...)
{
return 1;
}
};
ops.write_mem = +[](void* args, const size_t addr, const size_t len, void* val)
{
try
{
static_cast<emulator*>(args)->write_memory(addr, val, len);
return 0;
}
catch (...)
{
return 1;
}
};
static std::unordered_map<size_t, emulator_hook*> hooks{};
ops.set_bp = +[](void* args, const size_t addr, bp_type_t)
{
try
{
const auto entry = hooks.find(addr);
if (entry != hooks.end())
{
static_cast<emulator*>(args)->delete_hook(entry->second);
hooks.erase(entry);
}
hooks[addr] = static_cast<emulator*>(args)->hook_memory_execution(addr, 1, [args](uint64_t, size_t)
{
static_cast<emulator*>(args)->stop();
});
return true;
}
catch (...)
{
return false;
}
};
ops.del_bp = +[](void* args, const size_t addr, bp_type_t)
{
try
{
const auto entry = hooks.find(addr);
if (entry == hooks.end())
{
return false;
}
static_cast<emulator*>(args)->delete_hook(entry->second);
hooks.erase(entry);
return true;
}
catch (...)
{
return false;
}
};
ops.on_interrupt = +[](void* args)
{
static_cast<emulator*>(args)->stop();
};
constexpr arch_info_t info{
const_cast<char*>("i386:x86-64"), static_cast<int>(gdb_registers::end), sizeof(uint64_t)
};
gdbstub_init(&stub, &ops, info, const_cast<char*>("0.0.0.0:28960"));
const auto emu = unicorn::create_x64_emulator();
auto context = setup_context(*emu);
@@ -353,9 +531,13 @@ namespace
emu->reg(x64_register::rcx, execution_context.value());
emu->reg(x64_register::rdx, context.ntdll.image_base);
emu->reg(x64_register::rip, entry1);
try
{
emu->start(entry1);
gdbstub_run(&stub, static_cast<emulator*>(emu.get()));
//emu->start_from_ip();
}
catch (...)
{
@@ -364,6 +546,7 @@ namespace
}
printf("Emulation done.\n");
gdbstub_close(&stub);
}
}