Improved formatter performance

Added symbol resolver example
This commit is contained in:
flobernd 2014-11-01 03:42:37 +01:00
parent 9c52df0fe4
commit 11cb62c1ed
5 changed files with 231 additions and 57 deletions

View File

@ -40,30 +40,38 @@ using namespace Disassembler;
void testDecodingAndFormatting(uintptr_t baseAddress, PIMAGE_NT_HEADERS ntHeaders)
{
uint32_t sizeTotal = 0;
VXInstructionInfo info;
VXInstructionDecoder decoder;
VXIntelInstructionFormatter formatter;
#ifdef _M_X64
decoder.setDisassemblerMode(VXDisassemblerMode::M32BIT);
#else
decoder.setDisassemblerMode(VXDisassemblerMode::M64BIT);
PIMAGE_SECTION_HEADER sectionHeader =
reinterpret_cast<PIMAGE_SECTION_HEADER>(
reinterpret_cast<uintptr_t>(ntHeaders) + sizeof(IMAGE_NT_HEADERS)
+ ntHeaders->FileHeader.SizeOfOptionalHeader - sizeof(IMAGE_OPTIONAL_HEADER));
// Decode and format all code sections
for (unsigned int i = 0; i < ntHeaders->FileHeader.NumberOfSections; ++i)
#endif
while (sizeTotal < 1024 * 1024 * 50)
{
if (sectionHeader->Characteristics & IMAGE_SCN_CNT_CODE)
PIMAGE_SECTION_HEADER sectionHeader =
reinterpret_cast<PIMAGE_SECTION_HEADER>(
reinterpret_cast<uintptr_t>(ntHeaders) + sizeof(IMAGE_NT_HEADERS)
+ ntHeaders->FileHeader.SizeOfOptionalHeader - sizeof(IMAGE_OPTIONAL_HEADER));
// Decode and format all code sections
for (unsigned int i = 0; i < ntHeaders->FileHeader.NumberOfSections; ++i)
{
std::cout << sectionHeader->SizeOfRawData / 1024 << " KiB" << std::endl;
VXMemoryDataSource input(reinterpret_cast<const void*>(
baseAddress + sectionHeader->VirtualAddress), sectionHeader->SizeOfRawData);
decoder.setDataSource(&input);
decoder.setInstructionPointer(baseAddress + sectionHeader->VirtualAddress);
while (decoder.decodeInstruction(info))
if (sectionHeader->Characteristics & IMAGE_SCN_CNT_CODE)
{
formatter.formatInstruction(info);
VXMemoryDataSource input(reinterpret_cast<const void*>(
baseAddress + sectionHeader->VirtualAddress), sectionHeader->SizeOfRawData);
decoder.setDataSource(&input);
decoder.setInstructionPointer(baseAddress + sectionHeader->VirtualAddress);
while (decoder.decodeInstruction(info))
{
formatter.formatInstruction(info);
}
sizeTotal += sectionHeader->SizeOfRawData;
}
sectionHeader++;
}
sectionHeader++;
}
}
@ -87,8 +95,8 @@ int _tmain(int argc, _TCHAR* argv[])
return 1;
}
double pcFrequency = 0.0;
uint64_t pcStart = 0;
double pcFrequency;
uint64_t pcStart;
LARGE_INTEGER li;
// Start the performance counter

View File

@ -30,9 +30,160 @@
**************************************************************************************************/
#include <tchar.h>
#include <fstream>
#include <iomanip>
#include <string>
#include "VXDisassembler.h"
#include <Windows.h>
using namespace Verteron;
using namespace Disassembler;
int _tmain(int argc, _TCHAR* argv[])
{
// TODO:
// Find module base in memory
void *moduleBase = GetModuleHandle(L"kernel32.dll");
uintptr_t baseAddress = reinterpret_cast<uintptr_t>(moduleBase);
// Parse PE headers
PIMAGE_DOS_HEADER dosHeader = static_cast<PIMAGE_DOS_HEADER>(moduleBase);
if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE)
{
return 1;
}
PIMAGE_NT_HEADERS ntHeaders =
reinterpret_cast<PIMAGE_NT_HEADERS>(baseAddress + dosHeader->e_lfanew);
if (ntHeaders->Signature != IMAGE_NT_SIGNATURE)
{
return 1;
}
// Initialize disassembler
VXInstructionInfo info;
VXInstructionDecoder decoder;
VXExactSymbolResolver resolver;
VXIntelInstructionFormatter formatter;
decoder.setDisassemblerMode(VXDisassemblerMode::M64BIT);
formatter.setSymbolResolver(&resolver);
// Initialize output stream
std::ofstream out;
out.open(".\\output.txt");
// Find all call and jump targets
uint64_t subCount = 0;
uint64_t locCount = 0;
PIMAGE_SECTION_HEADER sectionHeader =
reinterpret_cast<PIMAGE_SECTION_HEADER>(
reinterpret_cast<uintptr_t>(ntHeaders) + sizeof(IMAGE_NT_HEADERS)
+ ntHeaders->FileHeader.SizeOfOptionalHeader - sizeof(IMAGE_OPTIONAL_HEADER));
for (unsigned int i = 0; i < ntHeaders->FileHeader.NumberOfSections; ++i)
{
if (sectionHeader->Characteristics & IMAGE_SCN_CNT_CODE)
{
VXMemoryDataSource input(reinterpret_cast<const void*>(
baseAddress + sectionHeader->VirtualAddress), sectionHeader->SizeOfRawData);
decoder.setDataSource(&input);
decoder.setInstructionPointer(baseAddress + sectionHeader->VirtualAddress);
while (decoder.decodeInstruction(info))
{
// Skip invalid instructions and non-relative instructions
if ((info.flags & IF_ERROR_MASK) || !(info.flags & IF_RELATIVE))
{
continue;
}
switch (info.mnemonic)
{
case VXInstructionMnemonic::CALL:
resolver.setSymbol(VDECalcAbsoluteTarget(info, info.operand[0]),
std::string("sub_" + std::to_string(subCount)).c_str());
subCount++;
break;
case VXInstructionMnemonic::JMP:
case VXInstructionMnemonic::JO:
case VXInstructionMnemonic::JNO:
case VXInstructionMnemonic::JB:
case VXInstructionMnemonic::JNB:
case VXInstructionMnemonic::JE:
case VXInstructionMnemonic::JNE:
case VXInstructionMnemonic::JBE:
case VXInstructionMnemonic::JA:
case VXInstructionMnemonic::JS:
case VXInstructionMnemonic::JNS:
case VXInstructionMnemonic::JP:
case VXInstructionMnemonic::JNP:
case VXInstructionMnemonic::JL:
case VXInstructionMnemonic::JGE:
case VXInstructionMnemonic::JLE:
case VXInstructionMnemonic::JG:
case VXInstructionMnemonic::JCXZ:
case VXInstructionMnemonic::JECXZ:
case VXInstructionMnemonic::JRCXZ:
resolver.setSymbol(VDECalcAbsoluteTarget(info, info.operand[0]),
std::string("loc_" + std::to_string(locCount)).c_str());
locCount++;
break;
default:
break;
}
}
}
sectionHeader++;
}
// Add entry point symbol
resolver.setSymbol(baseAddress + ntHeaders->OptionalHeader.AddressOfEntryPoint, "EntryPoint");
// Add exported symbols
if (ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress > 0)
{
PIMAGE_EXPORT_DIRECTORY exports =
reinterpret_cast<PIMAGE_EXPORT_DIRECTORY>(reinterpret_cast<LPBYTE>(baseAddress) +
ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
PDWORD address =
reinterpret_cast<PDWORD>(reinterpret_cast<LPBYTE>(baseAddress) +
exports->AddressOfFunctions);
PDWORD name =
reinterpret_cast<PDWORD>(reinterpret_cast<LPBYTE>(baseAddress) +
exports->AddressOfNames);
PWORD ordinal =
reinterpret_cast<PWORD>(reinterpret_cast<LPBYTE>(baseAddress) +
exports->AddressOfNameOrdinals);
for(unsigned int i = 0; i < exports->NumberOfNames; ++i)
{
resolver.setSymbol(baseAddress + address[ordinal[i]],
reinterpret_cast<char*>(baseAddress) + name[i]);
}
}
// Disassemble
sectionHeader =
reinterpret_cast<PIMAGE_SECTION_HEADER>(
reinterpret_cast<uintptr_t>(ntHeaders) + sizeof(IMAGE_NT_HEADERS)
+ ntHeaders->FileHeader.SizeOfOptionalHeader - sizeof(IMAGE_OPTIONAL_HEADER));
for (unsigned int i = 0; i < ntHeaders->FileHeader.NumberOfSections; ++i)
{
if (sectionHeader->Characteristics & IMAGE_SCN_CNT_CODE)
{
VXMemoryDataSource input(reinterpret_cast<const void*>(
baseAddress + sectionHeader->VirtualAddress), sectionHeader->SizeOfRawData);
decoder.setDataSource(&input);
decoder.setInstructionPointer(baseAddress + sectionHeader->VirtualAddress);
while (decoder.decodeInstruction(info))
{
uint64_t offset;
const char *symbol = resolver.resolveSymbol(info, info.instrAddress, offset);
if (symbol)
{
out << symbol << ": " << std::endl;
}
out << " " << std::hex << std::setw(16) << std::setfill('0')
<< info.instrAddress << " ";
if (info.flags & IF_ERROR_MASK)
{
out << "db " << std::hex << std::setw(2) << std::setfill('0')
<< static_cast<int>(info.data[0]) << std::endl;
} else
{
out << formatter.formatInstruction(info) << std::endl;
}
}
}
sectionHeader++;
}
out.close();
return 0;
}

View File

@ -96,13 +96,14 @@ const char* VXBaseInstructionFormatter::m_registerStrings[] =
"rip"
};
void VXBaseInstructionFormatter::internalFormatInstruction(VXInstructionInfo const& info)
void VXBaseInstructionFormatter::internalFormatInstruction(const VXInstructionInfo &info)
{
// Nothing to do here
}
VXBaseInstructionFormatter::VXBaseInstructionFormatter()
: m_symbolResolver(nullptr)
, m_outputStringLen(0)
, m_uppercase(false)
{
@ -110,6 +111,7 @@ VXBaseInstructionFormatter::VXBaseInstructionFormatter()
VXBaseInstructionFormatter::VXBaseInstructionFormatter(VXBaseSymbolResolver *symbolResolver)
: m_symbolResolver(symbolResolver)
, m_outputStringLen(0)
, m_uppercase(false)
{
@ -137,7 +139,7 @@ VXBaseInstructionFormatter::~VXBaseInstructionFormatter()
void VXBaseInstructionFormatter::outputClear()
{
m_outputBuffer.clear();
m_outputStringLen = 0;
}
char const* VXBaseInstructionFormatter::outputString()
@ -145,65 +147,72 @@ char const* VXBaseInstructionFormatter::outputString()
return &m_outputBuffer[0];
}
void VXBaseInstructionFormatter::outputAppend(char const *text)
{
void VXBaseInstructionFormatter::outputAppend(char const *text)
{
// Get the string length including the null-terminator char
size_t strLen = strlen(text) + 1;
// Get the buffer capacity and size
size_t bufCap = m_outputBuffer.capacity();
// Get the buffer size
size_t bufLen = m_outputBuffer.size();
// Decrease the offset by one, to exclude already existing null-terminator chars in the
// Decrease the offset by one, to exclude already existing null-terminator chars in the
// output buffer
size_t offset = (bufLen) ? bufLen - 1 : 0;
size_t offset = (m_outputStringLen) ? m_outputStringLen - 1 : 0;
// Resize capacity of the output buffer on demand and add some extra space to improve the
// performance
if (bufCap <= (bufLen + strLen))
// performance
if (bufLen <= (m_outputStringLen + strLen))
{
m_outputBuffer.reserve(bufCap + strLen + 256);
m_outputBuffer.resize(bufLen + strLen + 512);
}
// Append the text
m_outputBuffer.resize(offset + strLen);
// Write the text to the output buffer
memcpy(&m_outputBuffer[offset], text, strLen);
// Increase the string length
m_outputStringLen = offset + strLen;
// Convert to uppercase
if (m_uppercase)
{
for (size_t i = offset; i < m_outputBuffer.size() - 1; ++i)
for (size_t i = offset; i < m_outputStringLen - 1; ++i)
{
m_outputBuffer[i] = toupper(m_outputBuffer[i]);
}
}
}
}
void VXBaseInstructionFormatter::outputAppendFormatted(char const *format, ...)
{
void VXBaseInstructionFormatter::outputAppendFormatted(char const *format, ...)
{
va_list arguments;
va_start(arguments, format);
// Get the string length including the null-terminator char
size_t strLen = _vscprintf(format, arguments) + 1;
// Get the buffer capacity and size
size_t bufCap = m_outputBuffer.capacity();
// Get the buffer size
size_t bufLen = m_outputBuffer.size();
// Decrease the offset by one, to exclude already existing null-terminator chars in the
// Decrease the offset by one, to exclude already existing null-terminator chars in the
// output buffer
size_t offset = (bufLen) ? bufLen - 1 : 0;
if (strLen > 1)
size_t offset = (m_outputStringLen) ? m_outputStringLen - 1 : 0;
// Resize the output buffer on demand and add some extra space to improve the performance
if ((bufLen - m_outputStringLen) < 256)
{
// Resize capacity of the output buffer on demand and add some extra space to improve the
// performance
if (bufCap < (bufLen + strLen))
bufLen = bufLen + 512;
m_outputBuffer.resize(bufLen);
}
int strLen = 0;
do
{
// If the formatted text did not fit in the output buffer, resize it, and try again
if (strLen < 0)
{
m_outputBuffer.reserve(bufCap + strLen + 256);
m_outputBuffer.resize(bufLen + 512);
return outputAppendFormatted(format, arguments);
}
// Append the formatted text
m_outputBuffer.resize(offset + strLen);
vsnprintf_s(&m_outputBuffer[offset], strLen, strLen, format, arguments);
// Convert to uppercase
if (m_uppercase)
// Write the formatted text to the output buffer
assert((bufLen - offset) > 0);
strLen =
vsnprintf_s(&m_outputBuffer[offset], bufLen - offset, _TRUNCATE, format, arguments);
} while (strLen < 0);
// Increase the string length
m_outputStringLen = offset + strLen + 1;
// Convert to uppercase
if (m_uppercase)
{
for (size_t i = offset; i < m_outputStringLen - 1; ++i)
{
for (size_t i = offset; i < m_outputBuffer.size() - 1; ++i)
{
m_outputBuffer[i] = toupper(m_outputBuffer[i]);
}
m_outputBuffer[i] = toupper(m_outputBuffer[i]);
}
}
va_end(arguments);

View File

@ -50,6 +50,7 @@ private:
static const char *m_registerStrings[];
VXBaseSymbolResolver *m_symbolResolver;
std::vector<char> m_outputBuffer;
size_t m_outputStringLen;
bool m_uppercase;
protected:
/**

View File

@ -59,13 +59,18 @@ const char* VXExactSymbolResolver::resolveSymbol(const VXInstructionInfo &info,
uint64_t &offset)
{
std::unordered_map<uint64_t, std::string>::const_iterator iterator = m_symbolMap.find(address);
return (iterator == m_symbolMap.end()) ? nullptr : iterator->second.c_str();
if (iterator != m_symbolMap.end())
{
offset = 0;
return iterator->second.c_str();
}
return nullptr;
}
bool VXExactSymbolResolver::containsSymbol(uint64_t address) const
{
std::unordered_map<uint64_t, std::string>::const_iterator iterator = m_symbolMap.find(address);
return (iterator == m_symbolMap.end()) ? false : true;
return (iterator != m_symbolMap.end());
}
void VXExactSymbolResolver::setSymbol(uint64_t address, const char* name)