mirror of
https://github.com/momo5502/emulator.git
synced 2026-01-11 16:46:16 +00:00
Implement gdb remote stub
This commit is contained in:
4
.gitmodules
vendored
4
.gitmodules
vendored
@@ -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
4
deps/CMakeLists.txt
vendored
@@ -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
1
deps/mini-gdbstub
vendored
Submodule
Submodule deps/mini-gdbstub added at e0fc593337
11
deps/mini-gdbstub.cmake
vendored
Normal file
11
deps/mini-gdbstub.cmake
vendored
Normal 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"
|
||||
)
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user