Skip to content

Commit

Permalink
Dereference registers value for literal string, UTF16/UTF32 strings, …
Browse files Browse the repository at this point in the history
…functions, symbols, and data variables. Fix Vector35#209
  • Loading branch information
xusheng6 committed Mar 7, 2023
1 parent 3758886 commit ec593d6
Show file tree
Hide file tree
Showing 8 changed files with 241 additions and 49 deletions.
2 changes: 2 additions & 0 deletions api/debuggerapi.h
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,8 @@ namespace BinaryNinjaDebuggerAPI {

bool ActivateDebugAdapter();

std::string GetAddressInformation(uint64_t address);

void PostDebuggerEvent(const DebuggerEvent& event);
};

Expand Down
9 changes: 9 additions & 0 deletions api/debuggercontroller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -737,6 +737,15 @@ bool DebuggerController::ActivateDebugAdapter()
}


std::string DebuggerController::GetAddressInformation(uint64_t address)
{
char* info = BNDebuggerGetAddressInformation(m_object, address);
std::string result = std::string(info);
BNDebuggerFreeString(info);
return result;
}


void DebuggerController::PostDebuggerEvent(const DebuggerEvent &event)
{
BNDebuggerEvent* evt = new BNDebuggerEvent;
Expand Down
2 changes: 2 additions & 0 deletions api/ffi.h
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,8 @@ extern "C"

DEBUGGER_FFI_API bool BNDebuggerActivateDebugAdapter(BNDebuggerController* controller);

DEBUGGER_FFI_API char* BNDebuggerGetAddressInformation(BNDebuggerController* controller, uint64_t address);

DEBUGGER_FFI_API void BNDebuggerPostDebuggerEvent(BNDebuggerController* controller, BNDebuggerEvent* event);

// DebugAdapterType
Expand Down
3 changes: 3 additions & 0 deletions api/python/debuggercontroller.py
Original file line number Diff line number Diff line change
Expand Up @@ -1330,6 +1330,9 @@ def set_adapter_property(self, name: str, value: binaryninja.metadata.MetadataVa
handle = ctypes.cast(_value.handle, ctypes.POINTER(dbgcore.BNMetadata))
return dbgcore.BNDebuggerSetAdapterProperty(self.handle, name, handle)

def get_addr_info(self, addr: int):
return dbgcore.BNDebuggerGetAddressInformation(self.handle, addr)

def __del__(self):
if dbgcore is not None:
dbgcore.BNDebuggerFreeController(self.handle)
Expand Down
209 changes: 209 additions & 0 deletions core/debuggercontroller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1773,3 +1773,212 @@ bool DebuggerController::ActivateDebugAdapter()
{
return CreateDebugAdapter();
}


static inline bool IsPrintableChar(uint8_t c)
{
return (c == '\r') || (c == '\n') || (c == '\t') || ((c >= 0x20) && (c <= 0x7e));
}


static std::string CheckForASCIIString(const DataBuffer& memory)
{
std::string result;
size_t i = 0;
while (true)
{
if (i > memory.GetLength() - 1)
break;
if (IsPrintableChar(memory[i]))
{
result += memory[i];
i++;
}
else
{
break;
}
}

if (result.length() >= 4)
return result;
else
return "";
}


static std::string CheckForUTF16String(const DataBuffer& memory)
{
std::string result;
size_t i = 0;
while (true)
{
if (i > memory.GetLength() - 2)
break;
if (IsPrintableChar(memory[i]) && (memory[i + 1] == 0))
{
result += memory[i];
i += 2;
}
else
{
break;
}
}

if (result.length() >= 4)
return result;
else
return "";
}


static std::string CheckForUTF32String(const DataBuffer& memory)
{
std::string result;
size_t i = 0;
while (true)
{
if (i > memory.GetLength() - 4)
break;
if (IsPrintableChar(memory[i]) && (memory[i + 1] == 0) && (memory[i + 2] == 0) && (memory[i + 3] == 0))
{
result += memory[i];
i += 4;
}
else
{
break;
}
}

if (result.length() >= 4)
return result;
else
return "";
}


static std::string CheckForPrintableString(const DataBuffer& memory)
{
std::string result;
result = CheckForASCIIString(memory);
if (!result.empty())
return result;

result = CheckForUTF16String(memory);
if (!result.empty())
return result;

result = CheckForUTF32String(memory);
if (!result.empty())
return result;

return "";
}


static std::string CheckForLiteralString(uint64_t address)
{
bool ok = true;
bool zeroFound = false;
std::string result;
for (size_t i = 0; i < 8; i++)
{
uint8_t c = (address >> (8 * i)) & 0xff;
if (IsPrintableChar(c) && (!zeroFound))
{
result = std::string(1, c) + result;
}
else if (c == 0)
{
zeroFound = true;
}
else if (c != 0)
{
ok = false;
break;
}
}

if (ok)
return result;

return "";
}


std::string DebuggerController::GetAddressInformation(uint64_t address)
{
const DataBuffer memory = ReadMemory(address, 128);
auto result = CheckForPrintableString(memory);
// If we can find a string at the address, return it
if (!result.empty())
return fmt::format("\"{}\"", BinaryNinja::EscapeString(result));

// Check pointer to strings
auto buffer = m_liveView->ReadBuffer(address, m_liveView->GetAddressSize());
if (buffer.GetLength() == m_liveView->GetAddressSize())
{
uint64_t pointerValue = *reinterpret_cast<std::uintptr_t*>(buffer.GetData());
if (pointerValue != 0)
{
const DataBuffer pointerMemory = ReadMemory(pointerValue, 128);
result = CheckForPrintableString(pointerMemory);
if (!result.empty())
return fmt::format("&\"{}\"", BinaryNinja::EscapeString(result));
}
}


// Look for functions starting at the address
auto func = m_liveView->GetAnalysisFunction(m_liveView->GetDefaultPlatform(), address);
if (func)
{
auto sym = func->GetSymbol();
if (sym)
return sym->GetShortName();
}

// Look for functions containing the address
for (const auto& func: m_liveView->GetAnalysisFunctionsContainingAddress(address))
{
auto sym = func->GetSymbol();
if (sym)
{
return fmt::format("{} + 0x{:x}", sym->GetShortName(), address - func->GetStart());
}
}

// Look for symbols
auto sym = m_liveView->GetSymbolByAddress(address);
if (sym)
{
return sym->GetShortName();
}

// Look for data variables
DataVariable var;
if (m_liveView->GetDataVariableAtAddress(address, var))
{
sym = m_liveView->GetSymbolByAddress(var.address);
if (sym)
{
return fmt::format("{} + 0x{:x}", sym->GetShortName(), address - var.address);
}
else
{
result = fmt::format("data_{:x}", var.address);
if (address != var.address)
result += fmt::format(" + 0x{:x}", address - var.address);
return result;
}
}

// Check if the address itself is a printable string, e.g., 0x61626364 ==> "abcd"
result = CheckForLiteralString(address);
if (!result.empty())
return result;

return "";
}
3 changes: 3 additions & 0 deletions core/debuggercontroller.h
Original file line number Diff line number Diff line change
Expand Up @@ -254,5 +254,8 @@ namespace BinaryNinjaDebugger {
bool SetAdapterProperty(const std::string& name, const BinaryNinja::Ref<BinaryNinja::Metadata>& value);

bool ActivateDebugAdapter();

// Dereference an address and check for printable strings, functions, symbols, etc
std::string GetAddressInformation(uint64_t address);
};
}; // namespace BinaryNinjaDebugger
56 changes: 7 additions & 49 deletions core/debuggerstate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,32 +95,6 @@ bool DebuggerRegisters::SetRegisterValue(const std::string& name, uint64_t value
}


// TODO: we definitely need better string detection
static std::string CheckForPrintableString(const DataBuffer& memory)
{
std::string reg_string;
if (memory.GetLength() > 0)
reg_string = std::string((const char*)memory.GetData(), memory.GetLength());
else
return "";

size_t printableChars = 0;
for (size_t i = 0; i < reg_string.size(); i++)
{
int c = reg_string[i];
if (c == '\n' || std::isprint(c))
printableChars++;
else
break;
}

if (printableChars > 0)
return reg_string.substr(0, printableChars);
else
return "";
}


std::vector<DebugRegister> DebuggerRegisters::GetAllRegisters()
{
if (IsDirty())
Expand All @@ -139,32 +113,16 @@ std::vector<DebugRegister> DebuggerRegisters::GetAllRegisters()
if (!controller->GetState()->IsConnected())
return result;

std::map<uint64_t, std::string> regHints;
for (auto& reg : result)
{
const DataBuffer memory = controller->ReadMemory(reg.m_value, 128);
std::string reg_string = CheckForPrintableString(memory);
if (reg_string.size() > 3)
{
reg.m_hint = fmt::format("\"{}\"", reg_string);
}
auto it = regHints.find(reg.m_value);
if (it != regHints.end())
reg.m_hint = it->second;
else
{
reg.m_hint = "";
DataBuffer buffer = controller->ReadMemory(reg.m_value, reg.m_width);
if (buffer.GetLength() > 0)
{
uint64_t pointerValue = *reinterpret_cast<std::uintptr_t*>(buffer.GetData());
if (pointerValue != 0)
{
const DataBuffer memory = controller->ReadMemory(pointerValue, 128);
std::string reg_string = CheckForPrintableString(memory);
if (reg_string.size() > 3)
{
reg.m_hint = fmt::format("&\"{}\"", reg_string);
}
}
}
}
it->second = controller->GetAddressInformation(reg.m_value);

reg.m_hint = it->second;
}

return result;
Expand Down
6 changes: 6 additions & 0 deletions core/ffi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -929,6 +929,12 @@ bool BNDebuggerActivateDebugAdapter(BNDebuggerController* controller)
}


char* BNDebuggerGetAddressInformation(BNDebuggerController* controller, uint64_t address)
{
return BNDebuggerAllocString(controller->object->GetAddressInformation(address).c_str());
}


void BNDebuggerPostDebuggerEvent(BNDebuggerController* controller, BNDebuggerEvent* event)
{
DebuggerEvent evt;
Expand Down

0 comments on commit ec593d6

Please sign in to comment.