Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions core/adapters/corelliumadapter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -669,6 +669,14 @@ std::vector<DebugModule> CorelliumAdapter::GetModuleList()
}


std::vector<DebugMemoryRegion> CorelliumAdapter::GetMemoryRegions()
{
// Corellium adapter currently doesn't implement memory region enumeration
// TODO: Implement this by querying the Corellium-specific memory layout APIs
return {};
}


std::string CorelliumAdapter::GetTargetArchitecture()
{
return m_remoteArch;
Expand Down
2 changes: 2 additions & 0 deletions core/adapters/corelliumadapter.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ namespace BinaryNinjaDebugger
std::string GetRemoteFile(const std::string& path);
std::vector<DebugModule> GetModuleList() override;

std::vector<DebugMemoryRegion> GetMemoryRegions() override;

std::string GetTargetArchitecture() override;

DebugStopReason StopReason() override;
Expand Down
64 changes: 64 additions & 0 deletions core/adapters/dbgengadapter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1207,6 +1207,70 @@ std::vector<DebugModule> DbgEngAdapter::GetModuleList()
return modules;
}


std::vector<DebugMemoryRegion> DbgEngAdapter::GetMemoryRegions()
{
std::vector<DebugMemoryRegion> regions;

if (!this->m_debugDataSpaces)
return regions;

// Start from address 0 and enumerate all virtual memory regions
ULONG64 address = 0;
MEMORY_BASIC_INFORMATION64 mbi;

while (true)
{
HRESULT hr = this->m_debugDataSpaces->QueryVirtual(address, &mbi);
if (hr != S_OK)
break;

// Only include committed memory regions
if (mbi.State == MEM_COMMIT)
{
uint32_t permissions = 0;
if (mbi.Protect & (PAGE_READONLY | PAGE_READWRITE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE))
permissions |= DebugMemoryRegion::PermRead;
if (mbi.Protect & (PAGE_READWRITE | PAGE_EXECUTE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_WRITECOPY))
permissions |= DebugMemoryRegion::PermWrite;
if (mbi.Protect & (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY))
permissions |= DebugMemoryRegion::PermExecute;

std::string name;
switch (mbi.Type)
{
case MEM_IMAGE:
name = "[image]";
break;
case MEM_MAPPED:
name = "[mapped]";
break;
case MEM_PRIVATE:
name = "[private]";
break;
default:
name = "[unknown]";
break;
}

regions.emplace_back(
mbi.BaseAddress,
mbi.BaseAddress + mbi.RegionSize,
permissions,
name,
""
);
}

// Move to next region
address = mbi.BaseAddress + mbi.RegionSize;
if (address == 0) // Overflow check
break;
}

return regions;
}

bool DbgEngAdapter::BreakInto()
{
if (ExecStatus() == DEBUG_STATUS_BREAK || ExecStatus() == DEBUG_STATUS_NO_DEBUGGEE)
Expand Down
2 changes: 2 additions & 0 deletions core/adapters/dbgengadapter.h
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,8 @@ namespace BinaryNinjaDebugger {
// bool WriteMemory(std::uintptr_t address, const void* out, std::size_t size) override;
std::vector<DebugModule> GetModuleList() override;

std::vector<DebugMemoryRegion> GetMemoryRegions() override;

std::string GetTargetArchitecture() override;

DebugStopReason StopReason() override;
Expand Down
63 changes: 63 additions & 0 deletions core/adapters/gdbadapter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -790,6 +790,69 @@ std::vector<DebugModule> GdbAdapter::GetModuleList()
}


std::vector<DebugMemoryRegion> GdbAdapter::GetMemoryRegions()
{
if (m_isTargetRunning)
return {};

const auto path = "/proc/" + std::to_string(this->m_lastActiveThreadId) + "/maps";
std::string data = GetRemoteFile(path);
if (data.empty())
return {};

std::vector<DebugMemoryRegion> regions;

for (const std::string& line: RspConnector::Split(data, "\n"))
{
std::string_view v = line;
v.remove_prefix(std::min(v.find_first_not_of(" "), v.size()));
auto trimPosition = v.find_last_not_of(" ");
if (trimPosition != v.npos)
v.remove_suffix(v.size() - trimPosition - 1);

// regex_match() requires the first argument to be const
const std::string trimmedLine = std::string(v);

std::smatch match;
// Pattern: start-end permissions offset dev inode pathname
// Example: 00400000-00401000 r-xp 00000000 08:01 1234567 /bin/ls
const std::regex region_regex("^([0-9a-f]+)-([0-9a-f]+) ([rwxp-]{4}) [0-9a-f]+ [0-9a-f]+:[0-9a-f]+ [0-9]+(?: (.*))?$");
bool found = std::regex_match(trimmedLine, match, region_regex);
if (found && match.size() >= 4)
{
std::string startString = match[1].str();
uint64_t start = std::strtoull(startString.c_str(), nullptr, 16);
std::string endString = match[2].str();
uint64_t end = std::strtoull(endString.c_str(), nullptr, 16);
std::string perms = match[3].str();
std::string name = (match.size() > 4) ? match[4].str() : "";

// Parse permissions
uint32_t permissions = 0;
if (perms[0] == 'r') permissions |= DebugMemoryRegion::PermRead;
if (perms[1] == 'w') permissions |= DebugMemoryRegion::PermWrite;
if (perms[2] == 'x') permissions |= DebugMemoryRegion::PermExecute;

// Determine region type/name if empty
if (name.empty())
{
if (permissions & DebugMemoryRegion::PermExecute)
name = "[executable]";
else if (permissions & DebugMemoryRegion::PermWrite)
name = "[heap/stack]";
else
name = "[anonymous]";
}

DebugMemoryRegion region(start, end, permissions, name, name);
regions.push_back(region);
}
}

return regions;
}


std::string GdbAdapter::GetTargetArchitecture()
{
return m_remoteArch;
Expand Down
2 changes: 2 additions & 0 deletions core/adapters/gdbadapter.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ namespace BinaryNinjaDebugger
std::string GetRemoteFile(const std::string& path);
std::vector<DebugModule> GetModuleList() override;

std::vector<DebugMemoryRegion> GetMemoryRegions() override;

std::string GetTargetArchitecture() override;

DebugStopReason StopReason() override;
Expand Down
60 changes: 60 additions & 0 deletions core/adapters/lldbadapter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1214,6 +1214,66 @@ std::vector<DebugModule> LldbAdapter::GetModuleList()
}


std::vector<DebugMemoryRegion> LldbAdapter::GetMemoryRegions()
{
std::vector<DebugMemoryRegion> regions;

if (!m_process.IsValid() || m_process.GetState() != lldb::eStateStopped)
return regions;

// LLDB doesn't have a direct API to enumerate all memory regions
// We'll use the memory region info API to build a list
// by probing the address space in chunks

lldb::addr_t address = 0;

while (address != LLDB_INVALID_ADDRESS)
{
lldb::SBMemoryRegionInfo regionInfo;
lldb::SBError error = m_process.GetMemoryRegionInfo(address, regionInfo);

if (error.Fail())
break;

if (regionInfo.IsMapped())
{
uint32_t permissions = 0;
if (regionInfo.IsReadable()) permissions |= DebugMemoryRegion::PermRead;
if (regionInfo.IsWritable()) permissions |= DebugMemoryRegion::PermWrite;
if (regionInfo.IsExecutable()) permissions |= DebugMemoryRegion::PermExecute;

std::string name = regionInfo.GetName() ? regionInfo.GetName() : "";
if (name.empty())
{
if (permissions & DebugMemoryRegion::PermExecute)
name = "[executable]";
else if (permissions & DebugMemoryRegion::PermWrite)
name = "[heap/stack]";
else
name = "[anonymous]";
}

DebugMemoryRegion region(
regionInfo.GetRegionBase(),
regionInfo.GetRegionEnd(),
permissions,
name,
name
);
regions.push_back(region);
}

// Move to the next region
lldb::addr_t nextAddress = regionInfo.GetRegionEnd();
if (nextAddress <= address)
break; // Prevent infinite loop
address = nextAddress;
}

return regions;
}


std::string LldbAdapter::GetTargetArchitecture()
{
SBPlatform platform = m_target.GetPlatform();
Expand Down
2 changes: 2 additions & 0 deletions core/adapters/lldbadapter.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ namespace BinaryNinjaDebugger {

std::vector<DebugModule> GetModuleList() override;

std::vector<DebugMemoryRegion> GetMemoryRegions() override;

std::string GetTargetArchitecture() override;

DebugStopReason StopReason() override;
Expand Down
28 changes: 28 additions & 0 deletions core/debugadapter.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,32 @@ namespace BinaryNinjaDebugger {
{}
};

struct DebugMemoryRegion
{
std::uintptr_t m_start = 0;
std::uintptr_t m_end = 0;
uint32_t m_permissions = 0; // flags for read/write/execute permissions
std::string m_name;
std::string m_module; // associated module/file if applicable

// Permission flags
static constexpr uint32_t PermRead = 1;
static constexpr uint32_t PermWrite = 2;
static constexpr uint32_t PermExecute = 4;

DebugMemoryRegion() = default;
DebugMemoryRegion(std::uintptr_t start, std::uintptr_t end, uint32_t permissions,
const std::string& name = "", const std::string& module = "") :
m_start(start), m_end(end), m_permissions(permissions), m_name(name), m_module(module)
{}

std::size_t GetSize() const { return m_end > m_start ? m_end - m_start : 0; }
bool IsReadable() const { return (m_permissions & PermRead) != 0; }
bool IsWritable() const { return (m_permissions & PermWrite) != 0; }
bool IsExecutable() const { return (m_permissions & PermExecute) != 0; }
bool Contains(std::uintptr_t address) const { return address >= m_start && address < m_end; }
};

class DebuggerController;
class DebugAdapter
{
Expand Down Expand Up @@ -276,6 +302,8 @@ namespace BinaryNinjaDebugger {

virtual std::vector<DebugModule> GetModuleList() = 0;

virtual std::vector<DebugMemoryRegion> GetMemoryRegions() { return {}; }

virtual std::string GetTargetArchitecture() = 0;

virtual DebugStopReason StopReason() = 0;
Expand Down
Loading