From fb04c3b6d2bdb7b56498374f379f51971b8ddb63 Mon Sep 17 00:00:00 2001 From: Nukem Date: Mon, 29 Jun 2015 02:22:45 -0400 Subject: [PATCH 01/43] DBG: New analysis framework (VERY volatile) --- x64_dbg_dbg/Analysis.cpp | 22 ++++ x64_dbg_dbg/Analysis.h | 8 ++ x64_dbg_dbg/AnalysisPass.cpp | 41 ++++++++ x64_dbg_dbg/AnalysisPass.h | 21 ++++ x64_dbg_dbg/BasicBlock.cpp | 2 + x64_dbg_dbg/BasicBlock.h | 42 ++++++++ x64_dbg_dbg/CodeFollowPass.cpp | 84 +++++++++++++++ x64_dbg_dbg/CodeFollowPass.h | 18 ++++ x64_dbg_dbg/FunctionPass.cpp | 15 +++ x64_dbg_dbg/FunctionPass.h | 15 +++ x64_dbg_dbg/Int3CoagulatorPass.cpp | 15 +++ x64_dbg_dbg/Int3CoagulatorPass.h | 15 +++ x64_dbg_dbg/LinearPass.cpp | 132 ++++++++++++++++++++++++ x64_dbg_dbg/LinearPass.h | 23 +++++ x64_dbg_dbg/functionanalysis.cpp | 12 ++- x64_dbg_dbg/x64_dbg_dbg.vcxproj | 14 +++ x64_dbg_dbg/x64_dbg_dbg.vcxproj.filters | 42 ++++++++ 17 files changed, 520 insertions(+), 1 deletion(-) create mode 100644 x64_dbg_dbg/Analysis.cpp create mode 100644 x64_dbg_dbg/Analysis.h create mode 100644 x64_dbg_dbg/AnalysisPass.cpp create mode 100644 x64_dbg_dbg/AnalysisPass.h create mode 100644 x64_dbg_dbg/BasicBlock.cpp create mode 100644 x64_dbg_dbg/BasicBlock.h create mode 100644 x64_dbg_dbg/CodeFollowPass.cpp create mode 100644 x64_dbg_dbg/CodeFollowPass.h create mode 100644 x64_dbg_dbg/FunctionPass.cpp create mode 100644 x64_dbg_dbg/FunctionPass.h create mode 100644 x64_dbg_dbg/Int3CoagulatorPass.cpp create mode 100644 x64_dbg_dbg/Int3CoagulatorPass.h create mode 100644 x64_dbg_dbg/LinearPass.cpp create mode 100644 x64_dbg_dbg/LinearPass.h diff --git a/x64_dbg_dbg/Analysis.cpp b/x64_dbg_dbg/Analysis.cpp new file mode 100644 index 00000000..f4ec080f --- /dev/null +++ b/x64_dbg_dbg/Analysis.cpp @@ -0,0 +1,22 @@ +#include "Analysis.h" +#include "console.h" +#include "module.h" + +void Derp() +{ + dputs("Starting analysis..."); + DWORD ticks = GetTickCount(); + + uint modBase = ModBaseFromAddr(_base); + uint modSize = ModSizeFromAddr(_base); + + LinearPass* pass = new LinearPass(modBase, modBase + modSize); + pass->Analyse(); + /* + + PopulateReferences(); + dprintf("%u called functions populated\n", _functions.size()); + AnalyseFunctions(); + */ + dprintf("Analysis finished in %ums!\n", GetTickCount() - ticks); +} \ No newline at end of file diff --git a/x64_dbg_dbg/Analysis.h b/x64_dbg_dbg/Analysis.h new file mode 100644 index 00000000..8d858752 --- /dev/null +++ b/x64_dbg_dbg/Analysis.h @@ -0,0 +1,8 @@ +#pragma once + +#include "_global.h" +#include "LinearPass.h" +#include "CodeFollowPass.h" +#include "FunctionPass.h" +#include "Int3CoagulatorPass.h" +// TODO: CallConvPass? Or keep it inside FunctionPass? \ No newline at end of file diff --git a/x64_dbg_dbg/AnalysisPass.cpp b/x64_dbg_dbg/AnalysisPass.cpp new file mode 100644 index 00000000..b9319908 --- /dev/null +++ b/x64_dbg_dbg/AnalysisPass.cpp @@ -0,0 +1,41 @@ +#include +#include "AnalysisPass.h" +#include "capstone_wrapper.h" +#include "memory.h" + +AnalysisPass::AnalysisPass(uint VirtualStart, uint VirtualEnd) +{ + // Internal class data + m_VirtualStart = VirtualStart; + m_VirtualEnd = VirtualEnd; + + // Read remote instruction data to local memory + m_DataSize = VirtualEnd - VirtualStart; + m_Data = (unsigned char*)BridgeAlloc(m_DataSize); + + if(!MemRead((PVOID)VirtualStart, m_Data, m_DataSize, nullptr)) + { + BridgeFree(m_Data); + m_Data = nullptr; + + assert(false); + } +} + +AnalysisPass::~AnalysisPass() +{ + if(m_Data) + BridgeFree(m_Data); +} + +unsigned char* AnalysisPass::TranslateAddress(uint Address) +{ + assert(ValidateAddress(Address)); + + return &m_Data[Address - m_VirtualStart]; +} + +bool AnalysisPass::ValidateAddress(uint Address) +{ + return (Address >= m_VirtualStart && Address < m_VirtualEnd); +} \ No newline at end of file diff --git a/x64_dbg_dbg/AnalysisPass.h b/x64_dbg_dbg/AnalysisPass.h new file mode 100644 index 00000000..49bdf8ec --- /dev/null +++ b/x64_dbg_dbg/AnalysisPass.h @@ -0,0 +1,21 @@ +#pragma once + +#include "_global.h" + +class AnalysisPass +{ +public: + AnalysisPass(uint VirtualStart, uint VirtualEnd); + virtual ~AnalysisPass(); + + virtual bool Analyse() = 0; + +protected: + uint m_VirtualStart; + uint m_VirtualEnd; + uint m_DataSize; + unsigned char* m_Data; + + unsigned char* TranslateAddress(uint Address); + bool ValidateAddress(uint Address); +}; \ No newline at end of file diff --git a/x64_dbg_dbg/BasicBlock.cpp b/x64_dbg_dbg/BasicBlock.cpp new file mode 100644 index 00000000..0c14f769 --- /dev/null +++ b/x64_dbg_dbg/BasicBlock.cpp @@ -0,0 +1,2 @@ +#include "BasicBlock.h" +#include "memory.h" \ No newline at end of file diff --git a/x64_dbg_dbg/BasicBlock.h b/x64_dbg_dbg/BasicBlock.h new file mode 100644 index 00000000..ff86f727 --- /dev/null +++ b/x64_dbg_dbg/BasicBlock.h @@ -0,0 +1,42 @@ +#pragma once + +#include "_global.h" + +enum BasicBlockFlags : uint +{ + BASIC_BLOCK_FLAG_NONE, // No flag + BASIC_BLOCK_FLAG_SCANNED = (1 << 1), // The block was scanned at least once + BASIC_BLOCK_FLAG_ORPHANED = (1 << 2), // No targets ever reach this block + BASIC_BLOCK_FLAG_CALL = (1 << 3), // The block ends with a call + BASIC_BLOCK_FLAG_RET = (1 << 4), // The block ends with a retn + BASIC_BLOCK_FLAG_INDIRECT = (1 << 5), // This block ends with an indirect branch + BASIC_BLOCK_FLAG_INT3 = (1 << 6), // Block is only a series of INT3 +}; + +struct BasicBlock +{ + uint VirtualStart; + uint VirtualEnd; + uint Flags; + //std::vector Targets; + + inline bool GetFlag(uint Flag) + { + return (Flags & Flag) == Flag; + } + + inline void SetFlag(uint Flag) + { + Flags |= Flag; + } + + bool operator< (const BasicBlock & b) const + { + return VirtualStart < b.VirtualStart; + } + + bool operator== (const BasicBlock & b) const + { + return VirtualStart == b.VirtualStart; + } +}; \ No newline at end of file diff --git a/x64_dbg_dbg/CodeFollowPass.cpp b/x64_dbg_dbg/CodeFollowPass.cpp new file mode 100644 index 00000000..83ae2872 --- /dev/null +++ b/x64_dbg_dbg/CodeFollowPass.cpp @@ -0,0 +1,84 @@ +#include "AnalysisPass.h" +#include "CodeFollowPass.h" + +CodeFollowPass::CodeFollowPass(uint VirtualStart, uint VirtualEnd) + : AnalysisPass(VirtualStart, VirtualEnd) +{ + +} + +CodeFollowPass::~CodeFollowPass() +{ +} + +bool CodeFollowPass::Analyse() +{ + // First gather all possible function references with a linear scan-down + // + // This includes: + // call + // jmp + // push + // mov XXX, + return false; +} + +uint CodeFollowPass::GetReferenceOperand(const cs_x86 & Context) +{ + for(int i = 0; i < Context.op_count; i++) + { + auto operand = Context.operands[i]; + + // Looking for immediate references + if(operand.type == X86_OP_IMM) + { + uint dest = (uint)operand.imm; + + if(ValidateAddress(dest)) + return dest; + } + } + + return 0; +} + +uint CodeFollowPass::GetMemoryOperand(Capstone & Disasm, const cs_x86 & Context, bool* Indirect) +{ + if(Context.op_count <= 0) + return 0; + + // Only the first operand matters + auto operand = Context.operands[0]; + + // Jumps and calls only + if(Disasm.InGroup(CS_GRP_CALL) || Disasm.InGroup(CS_GRP_JUMP)) + { + // Looking for memory references + if(operand.type == X86_OP_MEM) + { + // Notify if the operand was indirect + if(Indirect) + { + if(operand.mem.base != X86_REG_INVALID || + operand.mem.index != X86_REG_INVALID || + operand.mem.scale != 0) + { + *Indirect = true; + return 0; + } + } + + // TODO: Read pointer + // TODO: Find virtual tables (new pass?) + // TODO: Translate RIP-Relative + return 0; + + uint dest = (uint)operand.mem.disp; + + if(ValidateAddress(dest)) + return dest; + } + } + + return 0; +} \ No newline at end of file diff --git a/x64_dbg_dbg/CodeFollowPass.h b/x64_dbg_dbg/CodeFollowPass.h new file mode 100644 index 00000000..42fd5871 --- /dev/null +++ b/x64_dbg_dbg/CodeFollowPass.h @@ -0,0 +1,18 @@ +#pragma once + +#include "AnalysisPass.h" +#include "BasicBlock.h" +#include "capstone_wrapper.h" + +class CodeFollowPass : public AnalysisPass +{ +public: + CodeFollowPass(uint VirtualStart, uint VirtualEnd); + virtual ~CodeFollowPass(); + + virtual bool Analyse() override; + +private: + uint GetReferenceOperand(const cs_x86 & Context); + uint GetMemoryOperand(Capstone & Disasm, const cs_x86 & Context, bool* Indirect); +}; \ No newline at end of file diff --git a/x64_dbg_dbg/FunctionPass.cpp b/x64_dbg_dbg/FunctionPass.cpp new file mode 100644 index 00000000..406ff58d --- /dev/null +++ b/x64_dbg_dbg/FunctionPass.cpp @@ -0,0 +1,15 @@ +#include "FunctionPass.h" + +FunctionPass::FunctionPass(uint VirtualStart, uint VirtualEnd) + : AnalysisPass(VirtualStart, VirtualEnd) +{ +} + +FunctionPass::~FunctionPass() +{ +} + +bool FunctionPass::Analyse() +{ + return false; +} \ No newline at end of file diff --git a/x64_dbg_dbg/FunctionPass.h b/x64_dbg_dbg/FunctionPass.h new file mode 100644 index 00000000..67003c43 --- /dev/null +++ b/x64_dbg_dbg/FunctionPass.h @@ -0,0 +1,15 @@ +#pragma once + +#include "AnalysisPass.h" +#include "BasicBlock.h" + +class FunctionPass : public AnalysisPass +{ +public: + FunctionPass(uint VirtualStart, uint VirtualEnd); + virtual ~FunctionPass(); + + virtual bool Analyse() override; + +private: +}; \ No newline at end of file diff --git a/x64_dbg_dbg/Int3CoagulatorPass.cpp b/x64_dbg_dbg/Int3CoagulatorPass.cpp new file mode 100644 index 00000000..142469d0 --- /dev/null +++ b/x64_dbg_dbg/Int3CoagulatorPass.cpp @@ -0,0 +1,15 @@ +#include "Int3CoagulatorPass.h" + +Int3CoagulatorPass::Int3CoagulatorPass(uint VirtualStart, uint VirtualEnd) + : AnalysisPass(VirtualStart, VirtualEnd) +{ +} + +Int3CoagulatorPass::~Int3CoagulatorPass() +{ +} + +bool Int3CoagulatorPass::Analyse() +{ + return false; +} \ No newline at end of file diff --git a/x64_dbg_dbg/Int3CoagulatorPass.h b/x64_dbg_dbg/Int3CoagulatorPass.h new file mode 100644 index 00000000..3087c970 --- /dev/null +++ b/x64_dbg_dbg/Int3CoagulatorPass.h @@ -0,0 +1,15 @@ +#pragma once + +#include "AnalysisPass.h" +#include "BasicBlock.h" + +class Int3CoagulatorPass : public AnalysisPass +{ +public: + Int3CoagulatorPass(uint VirtualStart, uint VirtualEnd); + virtual ~Int3CoagulatorPass(); + + virtual bool Analyse() override; + +private: +}; \ No newline at end of file diff --git a/x64_dbg_dbg/LinearPass.cpp b/x64_dbg_dbg/LinearPass.cpp new file mode 100644 index 00000000..ca9ab202 --- /dev/null +++ b/x64_dbg_dbg/LinearPass.cpp @@ -0,0 +1,132 @@ +#include "AnalysisPass.h" +#include "LinearPass.h" +#include "console.h" + +LinearPass::LinearPass(uint VirtualStart, uint VirtualEnd) + : AnalysisPass(VirtualStart, VirtualEnd) +{ + // Determine the maximum hardware thread count at once + m_MaximumThreads = max(std::thread::hardware_concurrency(), 1); + + // Don't consume 100% of the CPU, so adjust accordingly + if(m_MaximumThreads > 1) + m_MaximumThreads -= 1; +} + +LinearPass::~LinearPass() +{ +} + +bool LinearPass::Analyse() +{ + // Divide the work up between each thread + // THREAD_WORK = (TOTAL / # THREADS) + uint workCurrent = 0; + uint workAmount = m_DataSize / m_MaximumThreads; + + // Initialize thread vector + std::vector localThreads(m_MaximumThreads); + std::vector* threadBlocks = new std::vector[m_MaximumThreads]; + + for(uint i = 0; i < m_MaximumThreads; i++) + { + uint threadWorkStart = m_VirtualStart + workCurrent; + uint threadWorkStop = min((threadWorkStart + workAmount), m_VirtualEnd); + + // Allow a 16-byte variance of scanning because of + // integer rounding errors + if(workCurrent >= 16) + threadWorkStart -= 16; + + // Memory allocation optimization + // TODO: Option to conserve memory + threadBlocks[i].reserve(100000); + + // Execute + localThreads[i] = std::thread(&LinearPass::AnalysisWorker, this, threadWorkStart, threadWorkStop, &threadBlocks[i]); + + // Increment the work counter + workCurrent += workAmount; + } + + // Wait for all threads to finish and combine vectors + for(uint i = 0; i < m_MaximumThreads; i++) + { + localThreads[i].join(); + m_InitialBlocks.insert(m_InitialBlocks.end(), threadBlocks[i].begin(), threadBlocks[i].end()); + } + + // Sort and remove duplicates + std::sort(m_InitialBlocks.begin(), m_InitialBlocks.end()); + m_InitialBlocks.erase(std::unique(m_InitialBlocks.begin(), m_InitialBlocks.end()), m_InitialBlocks.end()); + + // Logging + dprintf("Total basic blocks: %d\n", m_InitialBlocks.size()); + + // Cleanup + delete[] threadBlocks; + + return true; +} + +void LinearPass::AnalysisWorker(uint Start, uint End, std::vector* Blocks) +{ + Capstone disasm; + uint blockBegin = Start; + + int intSeriesSize = 0; + int intSeriesCount = 0; + + for(uint i = Start; i < End;) + { + if(!disasm.Disassemble(i, TranslateAddress(i))) + { + // Skip instructions that can't be determined + i++; + continue; + } + + // Increment counter + i += disasm.Size(); + + // The basic block ends here if it is a branch + bool call = disasm.InGroup(CS_GRP_CALL); // CALL + bool jmp = disasm.InGroup(CS_GRP_JUMP); // JUMP + bool ret = disasm.InGroup(CS_GRP_RET); // RETURN + bool intr = disasm.InGroup(CS_GRP_INT); // INTERRUPT + + if(call || jmp || ret || intr) + { + BasicBlock block; + block.VirtualStart = blockBegin; + block.VirtualEnd = i - 1; + + // Check for calls + if(call) + block.SetFlag(BASIC_BLOCK_FLAG_CALL); + + // Check for returns + if(ret) + block.SetFlag(BASIC_BLOCK_FLAG_RET); + + // Check for interrupts + if(intr) + block.SetFlag(BASIC_BLOCK_FLAG_INT3); + + // Check for indirects + auto operand = disasm.x86().operands[0]; + + if(operand.mem.base != X86_REG_INVALID || + operand.mem.index != X86_REG_INVALID || + operand.mem.scale != 0) + { + block.SetFlag(BASIC_BLOCK_FLAG_INDIRECT); + } + + Blocks->push_back(block); + + // Reset the loop variables + blockBegin = i; + } + } +} \ No newline at end of file diff --git a/x64_dbg_dbg/LinearPass.h b/x64_dbg_dbg/LinearPass.h new file mode 100644 index 00000000..ad7989c8 --- /dev/null +++ b/x64_dbg_dbg/LinearPass.h @@ -0,0 +1,23 @@ +#pragma once + +#include +#include + +#include "AnalysisPass.h" +#include "BasicBlock.h" +#include "capstone_wrapper.h" + +class LinearPass : public AnalysisPass +{ +public: + LinearPass(uint VirtualStart, uint VirtualEnd); + virtual ~LinearPass(); + + virtual bool Analyse() override; + +private: + uint m_MaximumThreads; + std::vector m_InitialBlocks; + + void AnalysisWorker(uint Start, uint End, std::vector* Blocks); +}; \ No newline at end of file diff --git a/x64_dbg_dbg/functionanalysis.cpp b/x64_dbg_dbg/functionanalysis.cpp index da1f63cd..a42507ea 100644 --- a/x64_dbg_dbg/functionanalysis.cpp +++ b/x64_dbg_dbg/functionanalysis.cpp @@ -3,6 +3,9 @@ #include "memory.h" #include "function.h" +#include "module.h" +#include "LinearPass.h" + FunctionAnalysis::FunctionAnalysis(uint base, uint size) { _base = base; @@ -26,10 +29,17 @@ void FunctionAnalysis::Analyse() dputs("Starting analysis..."); DWORD ticks = GetTickCount(); + uint modBase = ModBaseFromAddr(_base); + uint modSize = ModSizeFromAddr(_base); + + LinearPass* pass = new LinearPass(modBase, modBase + modSize); + pass->Analyse(); + /* + PopulateReferences(); dprintf("%u called functions populated\n", _functions.size()); AnalyseFunctions(); - + */ dprintf("Analysis finished in %ums!\n", GetTickCount() - ticks); } diff --git a/x64_dbg_dbg/x64_dbg_dbg.vcxproj b/x64_dbg_dbg/x64_dbg_dbg.vcxproj index 82667823..cad97f5e 100644 --- a/x64_dbg_dbg/x64_dbg_dbg.vcxproj +++ b/x64_dbg_dbg/x64_dbg_dbg.vcxproj @@ -20,10 +20,14 @@ + + + + @@ -39,8 +43,11 @@ + + + @@ -69,7 +76,10 @@ + + + @@ -83,6 +93,7 @@ + @@ -101,12 +112,15 @@ + + + diff --git a/x64_dbg_dbg/x64_dbg_dbg.vcxproj.filters b/x64_dbg_dbg/x64_dbg_dbg.vcxproj.filters index 1cbb0655..cc998d6e 100644 --- a/x64_dbg_dbg/x64_dbg_dbg.vcxproj.filters +++ b/x64_dbg_dbg/x64_dbg_dbg.vcxproj.filters @@ -222,6 +222,27 @@ Source Files\Interfaces/Exports + + Source Files\Analysis + + + Source Files\Analysis + + + Source Files\Analysis + + + Source Files\Analysis + + + Source Files\Analysis + + + Source Files\Analysis + + + Source Files\Analysis + @@ -524,5 +545,26 @@ Header Files\Interfaces/Exports + + Header Files\Analysis + + + Header Files\Analysis + + + Header Files\Analysis + + + Header Files\Analysis + + + Header Files\Analysis + + + Header Files\Analysis + + + Header Files\Analysis + \ No newline at end of file From 8b5b1dea8b8c3ba26089340abb9dd935ab394877 Mon Sep 17 00:00:00 2001 From: Nukem Date: Mon, 29 Jun 2015 21:41:34 -0400 Subject: [PATCH 02/43] DBG: Split each INT3 into a separate basic block --- x64_dbg_dbg/Analysis.cpp | 1 + x64_dbg_dbg/AnalysisPass.cpp | 16 +------ x64_dbg_dbg/AnalysisPass.h | 18 +++++++- x64_dbg_dbg/BasicBlock.h | 9 ++-- x64_dbg_dbg/LinearPass.cpp | 85 ++++++++++++++++++++++++++---------- x64_dbg_dbg/LinearPass.h | 2 + 6 files changed, 89 insertions(+), 42 deletions(-) diff --git a/x64_dbg_dbg/Analysis.cpp b/x64_dbg_dbg/Analysis.cpp index f4ec080f..5cadb891 100644 --- a/x64_dbg_dbg/Analysis.cpp +++ b/x64_dbg_dbg/Analysis.cpp @@ -7,6 +7,7 @@ void Derp() dputs("Starting analysis..."); DWORD ticks = GetTickCount(); + uint _base = 0; uint modBase = ModBaseFromAddr(_base); uint modSize = ModSizeFromAddr(_base); diff --git a/x64_dbg_dbg/AnalysisPass.cpp b/x64_dbg_dbg/AnalysisPass.cpp index b9319908..edca681a 100644 --- a/x64_dbg_dbg/AnalysisPass.cpp +++ b/x64_dbg_dbg/AnalysisPass.cpp @@ -5,6 +5,8 @@ AnalysisPass::AnalysisPass(uint VirtualStart, uint VirtualEnd) { + assert(VirtualEnd > VirtualStart); + // Internal class data m_VirtualStart = VirtualStart; m_VirtualEnd = VirtualEnd; @@ -16,8 +18,6 @@ AnalysisPass::AnalysisPass(uint VirtualStart, uint VirtualEnd) if(!MemRead((PVOID)VirtualStart, m_Data, m_DataSize, nullptr)) { BridgeFree(m_Data); - m_Data = nullptr; - assert(false); } } @@ -26,16 +26,4 @@ AnalysisPass::~AnalysisPass() { if(m_Data) BridgeFree(m_Data); -} - -unsigned char* AnalysisPass::TranslateAddress(uint Address) -{ - assert(ValidateAddress(Address)); - - return &m_Data[Address - m_VirtualStart]; -} - -bool AnalysisPass::ValidateAddress(uint Address) -{ - return (Address >= m_VirtualStart && Address < m_VirtualEnd); } \ No newline at end of file diff --git a/x64_dbg_dbg/AnalysisPass.h b/x64_dbg_dbg/AnalysisPass.h index 49bdf8ec..42528c6a 100644 --- a/x64_dbg_dbg/AnalysisPass.h +++ b/x64_dbg_dbg/AnalysisPass.h @@ -1,6 +1,8 @@ #pragma once +#include #include "_global.h" +#include "BasicBlock.h" class AnalysisPass { @@ -10,12 +12,24 @@ public: virtual bool Analyse() = 0; + virtual std::vector & GetModifiedBlocks() = 0; + //virtual std::vector& GetModifiedFunctions() = 0; + protected: uint m_VirtualStart; uint m_VirtualEnd; uint m_DataSize; unsigned char* m_Data; - unsigned char* TranslateAddress(uint Address); - bool ValidateAddress(uint Address); + inline unsigned char* TranslateAddress(uint Address) + { + assert(ValidateAddress(Address)); + + return &m_Data[Address - m_VirtualStart]; + } + + inline bool ValidateAddress(uint Address) + { + return (Address >= m_VirtualStart && Address < m_VirtualEnd); + } }; \ No newline at end of file diff --git a/x64_dbg_dbg/BasicBlock.h b/x64_dbg_dbg/BasicBlock.h index ff86f727..314b27ac 100644 --- a/x64_dbg_dbg/BasicBlock.h +++ b/x64_dbg_dbg/BasicBlock.h @@ -10,15 +10,16 @@ enum BasicBlockFlags : uint BASIC_BLOCK_FLAG_CALL = (1 << 3), // The block ends with a call BASIC_BLOCK_FLAG_RET = (1 << 4), // The block ends with a retn BASIC_BLOCK_FLAG_INDIRECT = (1 << 5), // This block ends with an indirect branch - BASIC_BLOCK_FLAG_INT3 = (1 << 6), // Block is only a series of INT3 + BASIC_BLOCK_FLAG_PREINT3 = (1 << 6), // Block ends because there was an INT3 afterwards + BASIC_BLOCK_FLAG_INT3 = (1 << 7), // Block is only a series of INT3 }; struct BasicBlock { - uint VirtualStart; - uint VirtualEnd; + uint VirtualStart; // Inclusive byte + uint VirtualEnd; // Exclusive byte uint Flags; - //std::vector Targets; + uint Target; inline bool GetFlag(uint Flag) { diff --git a/x64_dbg_dbg/LinearPass.cpp b/x64_dbg_dbg/LinearPass.cpp index ca9ab202..83d4f3a5 100644 --- a/x64_dbg_dbg/LinearPass.cpp +++ b/x64_dbg_dbg/LinearPass.cpp @@ -63,19 +63,36 @@ bool LinearPass::Analyse() // Logging dprintf("Total basic blocks: %d\n", m_InitialBlocks.size()); + /* + FILE *f = fopen("C:\\test.txt", "w"); + + for (auto& block : m_InitialBlocks) + { + char buf[256]; + size_t size = sprintf_s(buf, "Start: 0x%p End: 0x%p\n", block.VirtualStart, block.VirtualEnd); + + fwrite(buf, size, 1, f); + } + + fclose(f); + */ + // Cleanup delete[] threadBlocks; return true; } +std::vector & LinearPass::GetModifiedBlocks() +{ + return m_InitialBlocks; +} + void LinearPass::AnalysisWorker(uint Start, uint End, std::vector* Blocks) { Capstone disasm; uint blockBegin = Start; - - int intSeriesSize = 0; - int intSeriesCount = 0; + uint blockEnd = End; for(uint i = Start; i < End;) { @@ -88,6 +105,7 @@ void LinearPass::AnalysisWorker(uint Start, uint End, std::vector* B // Increment counter i += disasm.Size(); + blockEnd = i; // The basic block ends here if it is a branch bool call = disasm.InGroup(CS_GRP_CALL); // CALL @@ -95,23 +113,25 @@ void LinearPass::AnalysisWorker(uint Start, uint End, std::vector* B bool ret = disasm.InGroup(CS_GRP_RET); // RETURN bool intr = disasm.InGroup(CS_GRP_INT); // INTERRUPT + if(intr) + { + // INT3s are treated differently. They are all created as their + // own separate block for more analysis later. + uint realBlockEnd = blockEnd - disasm.Size(); + + if((realBlockEnd - blockBegin) > 0) + { + // The next line terminates the BBlock before the INT instruction. + // (Early termination, faked as an indirect JMP) + CreateBlockWorker(Blocks, blockBegin, realBlockEnd, false, false, false, false)->SetFlag(BASIC_BLOCK_FLAG_PREINT3); + + blockBegin = realBlockEnd; + } + } + if(call || jmp || ret || intr) { - BasicBlock block; - block.VirtualStart = blockBegin; - block.VirtualEnd = i - 1; - - // Check for calls - if(call) - block.SetFlag(BASIC_BLOCK_FLAG_CALL); - - // Check for returns - if(ret) - block.SetFlag(BASIC_BLOCK_FLAG_RET); - - // Check for interrupts - if(intr) - block.SetFlag(BASIC_BLOCK_FLAG_INT3); + BasicBlock* block = CreateBlockWorker(Blocks, blockBegin, blockEnd, call, jmp, ret, intr); // Check for indirects auto operand = disasm.x86().operands[0]; @@ -119,14 +139,35 @@ void LinearPass::AnalysisWorker(uint Start, uint End, std::vector* B if(operand.mem.base != X86_REG_INVALID || operand.mem.index != X86_REG_INVALID || operand.mem.scale != 0) - { - block.SetFlag(BASIC_BLOCK_FLAG_INDIRECT); - } + block->SetFlag(BASIC_BLOCK_FLAG_INDIRECT); - Blocks->push_back(block); + // Determine the target + block->Target = operand.imm; // Reset the loop variables blockBegin = i; } } +} + +BasicBlock* LinearPass::CreateBlockWorker(std::vector* Blocks, uint Start, uint End, bool Call, bool Jmp, bool Ret, bool Intr) +{ + BasicBlock block; + block.VirtualStart = Start; + block.VirtualEnd = End; + + // Check for calls + if(Call) + block.SetFlag(BASIC_BLOCK_FLAG_CALL); + + // Check for returns + if(Ret) + block.SetFlag(BASIC_BLOCK_FLAG_RET); + + // Check for interrupts + if(Intr) + block.SetFlag(BASIC_BLOCK_FLAG_INT3); + + Blocks->push_back(block); + return &Blocks->back(); } \ No newline at end of file diff --git a/x64_dbg_dbg/LinearPass.h b/x64_dbg_dbg/LinearPass.h index ad7989c8..4250e230 100644 --- a/x64_dbg_dbg/LinearPass.h +++ b/x64_dbg_dbg/LinearPass.h @@ -14,10 +14,12 @@ public: virtual ~LinearPass(); virtual bool Analyse() override; + virtual std::vector & GetModifiedBlocks() override; private: uint m_MaximumThreads; std::vector m_InitialBlocks; void AnalysisWorker(uint Start, uint End, std::vector* Blocks); + BasicBlock* CreateBlockWorker(std::vector* Blocks, uint Start, uint End, bool Call, bool Jmp, bool Ret, bool Intr); }; \ No newline at end of file From 76a92c3e444d9f7993b467bc3b6aee43c89902a3 Mon Sep 17 00:00:00 2001 From: Nukem Date: Tue, 30 Jun 2015 00:52:59 -0400 Subject: [PATCH 03/43] DBG: AnalysisPass: Add locking functions --- x64_dbg_dbg/AnalysisPass.cpp | 25 ++++++++++++++++++++++++- x64_dbg_dbg/AnalysisPass.h | 19 +++++++++++++------ 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/x64_dbg_dbg/AnalysisPass.cpp b/x64_dbg_dbg/AnalysisPass.cpp index edca681a..15d6676d 100644 --- a/x64_dbg_dbg/AnalysisPass.cpp +++ b/x64_dbg_dbg/AnalysisPass.cpp @@ -3,10 +3,13 @@ #include "capstone_wrapper.h" #include "memory.h" -AnalysisPass::AnalysisPass(uint VirtualStart, uint VirtualEnd) +AnalysisPass::AnalysisPass(uint VirtualStart, uint VirtualEnd, BBlockArray & MainBlocks) : m_MainBlocks(MainBlocks) { assert(VirtualEnd > VirtualStart); + // Shared lock init + InitializeSRWLock(&m_InternalLock); + // Internal class data m_VirtualStart = VirtualStart; m_VirtualEnd = VirtualEnd; @@ -26,4 +29,24 @@ AnalysisPass::~AnalysisPass() { if(m_Data) BridgeFree(m_Data); +} + +void AnalysisPass::AcquireReadLock() +{ + AcquireSRWLockShared(&m_InternalLock); +} + +void AnalysisPass::ReleaseReadLock() +{ + ReleaseSRWLockShared(&m_InternalLock); +} + +void AnalysisPass::AcquireExclusiveLock() +{ + AcquireSRWLockExclusive(&m_InternalLock); +} + +void AnalysisPass::ReleaseExclusiveLock() +{ + ReleaseSRWLockExclusive(&m_InternalLock); } \ No newline at end of file diff --git a/x64_dbg_dbg/AnalysisPass.h b/x64_dbg_dbg/AnalysisPass.h index 42528c6a..f5f9eda9 100644 --- a/x64_dbg_dbg/AnalysisPass.h +++ b/x64_dbg_dbg/AnalysisPass.h @@ -7,29 +7,36 @@ class AnalysisPass { public: - AnalysisPass(uint VirtualStart, uint VirtualEnd); + AnalysisPass(uint VirtualStart, uint VirtualEnd, BBlockArray & MainBlocks); virtual ~AnalysisPass(); + virtual const char* GetName() = 0; virtual bool Analyse() = 0; - virtual std::vector & GetModifiedBlocks() = 0; - //virtual std::vector& GetModifiedFunctions() = 0; - protected: uint m_VirtualStart; uint m_VirtualEnd; uint m_DataSize; unsigned char* m_Data; + BBlockArray & m_MainBlocks; - inline unsigned char* TranslateAddress(uint Address) + inline unsigned char* AnalysisPass::TranslateAddress(uint Address) { assert(ValidateAddress(Address)); return &m_Data[Address - m_VirtualStart]; } - inline bool ValidateAddress(uint Address) + inline bool AnalysisPass::ValidateAddress(uint Address) { return (Address >= m_VirtualStart && Address < m_VirtualEnd); } + + void AcquireReadLock(); + void ReleaseReadLock(); + void AcquireExclusiveLock(); + void ReleaseExclusiveLock(); + +private: + SRWLOCK m_InternalLock; }; \ No newline at end of file From 576b58e7c3cc25acb359c3148698fa008949bd42 Mon Sep 17 00:00:00 2001 From: Nukem Date: Tue, 30 Jun 2015 00:53:44 -0400 Subject: [PATCH 04/43] DBG: Analysis typedef changes --- x64_dbg_dbg/BasicBlock.h | 8 +++++--- x64_dbg_dbg/CodeFollowPass.cpp | 4 ++-- x64_dbg_dbg/CodeFollowPass.h | 2 +- x64_dbg_dbg/FunctionPass.cpp | 4 ++-- x64_dbg_dbg/FunctionPass.h | 2 +- x64_dbg_dbg/Int3CoagulatorPass.h | 8 +++++++- x64_dbg_dbg/LinearPass.h | 6 +++--- x64_dbg_dbg/functionanalysis.cpp | 17 ++--------------- 8 files changed, 23 insertions(+), 28 deletions(-) diff --git a/x64_dbg_dbg/BasicBlock.h b/x64_dbg_dbg/BasicBlock.h index 314b27ac..f866207f 100644 --- a/x64_dbg_dbg/BasicBlock.h +++ b/x64_dbg_dbg/BasicBlock.h @@ -16,8 +16,8 @@ enum BasicBlockFlags : uint struct BasicBlock { - uint VirtualStart; // Inclusive byte - uint VirtualEnd; // Exclusive byte + uint VirtualStart; // Inclusive + uint VirtualEnd; // Exclusive uint Flags; uint Target; @@ -40,4 +40,6 @@ struct BasicBlock { return VirtualStart == b.VirtualStart; } -}; \ No newline at end of file +}; + +typedef std::vector BBlockArray; \ No newline at end of file diff --git a/x64_dbg_dbg/CodeFollowPass.cpp b/x64_dbg_dbg/CodeFollowPass.cpp index 83ae2872..a84a6923 100644 --- a/x64_dbg_dbg/CodeFollowPass.cpp +++ b/x64_dbg_dbg/CodeFollowPass.cpp @@ -1,8 +1,8 @@ #include "AnalysisPass.h" #include "CodeFollowPass.h" -CodeFollowPass::CodeFollowPass(uint VirtualStart, uint VirtualEnd) - : AnalysisPass(VirtualStart, VirtualEnd) +CodeFollowPass::CodeFollowPass(uint VirtualStart, uint VirtualEnd, BBlockArray & MainBlocks) + : AnalysisPass(VirtualStart, VirtualEnd, MainBlocks) { } diff --git a/x64_dbg_dbg/CodeFollowPass.h b/x64_dbg_dbg/CodeFollowPass.h index 42fd5871..1454b8b3 100644 --- a/x64_dbg_dbg/CodeFollowPass.h +++ b/x64_dbg_dbg/CodeFollowPass.h @@ -7,7 +7,7 @@ class CodeFollowPass : public AnalysisPass { public: - CodeFollowPass(uint VirtualStart, uint VirtualEnd); + CodeFollowPass(uint VirtualStart, uint VirtualEnd, BBlockArray & MainBlocks); virtual ~CodeFollowPass(); virtual bool Analyse() override; diff --git a/x64_dbg_dbg/FunctionPass.cpp b/x64_dbg_dbg/FunctionPass.cpp index 406ff58d..38b5d26b 100644 --- a/x64_dbg_dbg/FunctionPass.cpp +++ b/x64_dbg_dbg/FunctionPass.cpp @@ -1,7 +1,7 @@ #include "FunctionPass.h" -FunctionPass::FunctionPass(uint VirtualStart, uint VirtualEnd) - : AnalysisPass(VirtualStart, VirtualEnd) +FunctionPass::FunctionPass(uint VirtualStart, uint VirtualEnd, BBlockArray & MainBlocks) + : AnalysisPass(VirtualStart, VirtualEnd, MainBlocks) { } diff --git a/x64_dbg_dbg/FunctionPass.h b/x64_dbg_dbg/FunctionPass.h index 67003c43..3e6f4491 100644 --- a/x64_dbg_dbg/FunctionPass.h +++ b/x64_dbg_dbg/FunctionPass.h @@ -6,7 +6,7 @@ class FunctionPass : public AnalysisPass { public: - FunctionPass(uint VirtualStart, uint VirtualEnd); + FunctionPass(uint VirtualStart, uint VirtualEnd, BBlockArray & MainBlocks); virtual ~FunctionPass(); virtual bool Analyse() override; diff --git a/x64_dbg_dbg/Int3CoagulatorPass.h b/x64_dbg_dbg/Int3CoagulatorPass.h index 3087c970..6eff3176 100644 --- a/x64_dbg_dbg/Int3CoagulatorPass.h +++ b/x64_dbg_dbg/Int3CoagulatorPass.h @@ -1,15 +1,21 @@ #pragma once +#include +#include + #include "AnalysisPass.h" #include "BasicBlock.h" class Int3CoagulatorPass : public AnalysisPass { public: - Int3CoagulatorPass(uint VirtualStart, uint VirtualEnd); + Int3CoagulatorPass(uint VirtualStart, uint VirtualEnd, BBlockArray & MainBlocks); virtual ~Int3CoagulatorPass(); virtual bool Analyse() override; + virtual const char* GetName() override; + private: + void AnalysisWorker(uint Start, uint End, std::vector* Blocks); }; \ No newline at end of file diff --git a/x64_dbg_dbg/LinearPass.h b/x64_dbg_dbg/LinearPass.h index 4250e230..e67e7253 100644 --- a/x64_dbg_dbg/LinearPass.h +++ b/x64_dbg_dbg/LinearPass.h @@ -10,15 +10,15 @@ class LinearPass : public AnalysisPass { public: - LinearPass(uint VirtualStart, uint VirtualEnd); + LinearPass(uint VirtualStart, uint VirtualEnd, BBlockArray & MainBlocks); virtual ~LinearPass(); virtual bool Analyse() override; - virtual std::vector & GetModifiedBlocks() override; + + virtual const char* GetName() override; private: uint m_MaximumThreads; - std::vector m_InitialBlocks; void AnalysisWorker(uint Start, uint End, std::vector* Blocks); BasicBlock* CreateBlockWorker(std::vector* Blocks, uint Start, uint End, bool Call, bool Jmp, bool Ret, bool Intr); diff --git a/x64_dbg_dbg/functionanalysis.cpp b/x64_dbg_dbg/functionanalysis.cpp index a42507ea..bf205be0 100644 --- a/x64_dbg_dbg/functionanalysis.cpp +++ b/x64_dbg_dbg/functionanalysis.cpp @@ -24,23 +24,10 @@ const unsigned char* FunctionAnalysis::TranslateAddress(uint addr) return (addr >= _base && addr < _base + _size) ? _data + (addr - _base) : nullptr; } +void Derp(uint _base); void FunctionAnalysis::Analyse() { - dputs("Starting analysis..."); - DWORD ticks = GetTickCount(); - - uint modBase = ModBaseFromAddr(_base); - uint modSize = ModSizeFromAddr(_base); - - LinearPass* pass = new LinearPass(modBase, modBase + modSize); - pass->Analyse(); - /* - - PopulateReferences(); - dprintf("%u called functions populated\n", _functions.size()); - AnalyseFunctions(); - */ - dprintf("Analysis finished in %ums!\n", GetTickCount() - ticks); + Derp(_base); } void FunctionAnalysis::SetMarkers() From 1602c52b7051a97652c03d1955d3332ee15967e2 Mon Sep 17 00:00:00 2001 From: Nukem Date: Tue, 30 Jun 2015 00:54:04 -0400 Subject: [PATCH 05/43] DBG: Int3CoagulatorPass finished --- x64_dbg_dbg/Int3CoagulatorPass.cpp | 67 ++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 3 deletions(-) diff --git a/x64_dbg_dbg/Int3CoagulatorPass.cpp b/x64_dbg_dbg/Int3CoagulatorPass.cpp index 142469d0..f5e1cd7e 100644 --- a/x64_dbg_dbg/Int3CoagulatorPass.cpp +++ b/x64_dbg_dbg/Int3CoagulatorPass.cpp @@ -1,7 +1,9 @@ +#include "AnalysisPass.h" #include "Int3CoagulatorPass.h" +#include "console.h" -Int3CoagulatorPass::Int3CoagulatorPass(uint VirtualStart, uint VirtualEnd) - : AnalysisPass(VirtualStart, VirtualEnd) +Int3CoagulatorPass::Int3CoagulatorPass(uint VirtualStart, uint VirtualEnd, BBlockArray & MainBlocks) + : AnalysisPass(VirtualStart, VirtualEnd, MainBlocks) { } @@ -9,7 +11,66 @@ Int3CoagulatorPass::~Int3CoagulatorPass() { } +const char* Int3CoagulatorPass::GetName() +{ + return "INT3 Group Combiner"; +} + bool Int3CoagulatorPass::Analyse() { - return false; + // Execute + std::thread thread(&Int3CoagulatorPass::AnalysisWorker, this, 0, m_MainBlocks.size(), &m_MainBlocks); + + // Wait for thread to finish + thread.join(); + + dprintf("Total basic blocks: %d\n", m_MainBlocks.size()); + return true; +} + +void Int3CoagulatorPass::AnalysisWorker(uint Start, uint End, std::vector* Blocks) +{ + int counterIndex = 0; // Loop counter + + uint intSeriesStart = 0; // Block starting address + uint intSeriesCount = 0; // Number of blocks + uint intSeriesSize = 0; // Size of instructions + + for(auto itr = Blocks->begin(); counterIndex < End; itr++, counterIndex++) + { + if(!itr->GetFlag(BASIC_BLOCK_FLAG_INT3)) + { + // Synchronize the vector if more than 1 instruction + // is present. (Combine) + if(intSeriesCount > 1) + { + // Removal of old blocks + itr = Blocks->erase(itr - intSeriesCount, itr); + + // Build the new block and insert + BasicBlock block; + block.VirtualStart = intSeriesStart; + block.VirtualEnd = intSeriesStart + intSeriesSize; + block.SetFlag(BASIC_BLOCK_FLAG_INT3); + + itr = Blocks->insert(itr, block); + + // Adjust the integer counter manually + End -= (intSeriesCount - 1); + } + + // Counter is reset because the series is broken + intSeriesCount = 0; + intSeriesSize = 0; + continue; + } + + // Hit! An INT3 instruction block has been found. + // Update the counter stats. + if(intSeriesCount == 0) + intSeriesStart = itr->VirtualStart; + + intSeriesCount += 1; + intSeriesSize += (itr->VirtualEnd - itr->VirtualStart); + } } \ No newline at end of file From f8d4492ae96f5fde27bcf39389b99fa714df07df Mon Sep 17 00:00:00 2001 From: Nukem Date: Tue, 30 Jun 2015 00:54:43 -0400 Subject: [PATCH 06/43] DBG: Int3CoagulatorPass deprecated and merged into LinearPass for performance/memory reasons --- x64_dbg_dbg/Analysis.cpp | 9 ++++-- x64_dbg_dbg/LinearPass.cpp | 63 ++++++++++++++++++++++++-------------- 2 files changed, 46 insertions(+), 26 deletions(-) diff --git a/x64_dbg_dbg/Analysis.cpp b/x64_dbg_dbg/Analysis.cpp index 5cadb891..06ac85c1 100644 --- a/x64_dbg_dbg/Analysis.cpp +++ b/x64_dbg_dbg/Analysis.cpp @@ -2,17 +2,20 @@ #include "console.h" #include "module.h" -void Derp() +void Derp(uint _base) { dputs("Starting analysis..."); DWORD ticks = GetTickCount(); - uint _base = 0; uint modBase = ModBaseFromAddr(_base); uint modSize = ModSizeFromAddr(_base); - LinearPass* pass = new LinearPass(modBase, modBase + modSize); + BBlockArray array; + LinearPass* pass = new LinearPass(modBase, modBase + modSize, array); pass->Analyse(); + + //Int3CoagulatorPass *pass2 = new Int3CoagulatorPass(modBase, modBase + modSize, array); + //pass2->Analyse(); /* PopulateReferences(); diff --git a/x64_dbg_dbg/LinearPass.cpp b/x64_dbg_dbg/LinearPass.cpp index 83d4f3a5..62bb7942 100644 --- a/x64_dbg_dbg/LinearPass.cpp +++ b/x64_dbg_dbg/LinearPass.cpp @@ -2,8 +2,8 @@ #include "LinearPass.h" #include "console.h" -LinearPass::LinearPass(uint VirtualStart, uint VirtualEnd) - : AnalysisPass(VirtualStart, VirtualEnd) +LinearPass::LinearPass(uint VirtualStart, uint VirtualEnd, BBlockArray & MainBlocks) + : AnalysisPass(VirtualStart, VirtualEnd, MainBlocks) { // Determine the maximum hardware thread count at once m_MaximumThreads = max(std::thread::hardware_concurrency(), 1); @@ -17,6 +17,11 @@ LinearPass::~LinearPass() { } +const char* LinearPass::GetName() +{ + return "Linear Scandown"; +} + bool LinearPass::Analyse() { // Divide the work up between each thread @@ -50,18 +55,20 @@ bool LinearPass::Analyse() } // Wait for all threads to finish and combine vectors + m_MainBlocks.clear(); + for(uint i = 0; i < m_MaximumThreads; i++) { localThreads[i].join(); - m_InitialBlocks.insert(m_InitialBlocks.end(), threadBlocks[i].begin(), threadBlocks[i].end()); + m_MainBlocks.insert(m_MainBlocks.end(), threadBlocks[i].begin(), threadBlocks[i].end()); } // Sort and remove duplicates - std::sort(m_InitialBlocks.begin(), m_InitialBlocks.end()); - m_InitialBlocks.erase(std::unique(m_InitialBlocks.begin(), m_InitialBlocks.end()), m_InitialBlocks.end()); + std::sort(m_MainBlocks.begin(), m_MainBlocks.end()); + m_MainBlocks.erase(std::unique(m_MainBlocks.begin(), m_MainBlocks.end()), m_MainBlocks.end()); // Logging - dprintf("Total basic blocks: %d\n", m_InitialBlocks.size()); + dprintf("Total basic blocks: %d\n", m_MainBlocks.size()); /* FILE *f = fopen("C:\\test.txt", "w"); @@ -83,16 +90,13 @@ bool LinearPass::Analyse() return true; } -std::vector & LinearPass::GetModifiedBlocks() -{ - return m_InitialBlocks; -} - void LinearPass::AnalysisWorker(uint Start, uint End, std::vector* Blocks) { Capstone disasm; - uint blockBegin = Start; - uint blockEnd = End; + + uint blockBegin = Start; // BBlock starting virtual address + uint blockEnd = End; // BBlock ending virtual address + bool blockPrevInt = false; // Indicator if the last instruction was INT for(uint i = Start; i < End;) { @@ -122,7 +126,7 @@ void LinearPass::AnalysisWorker(uint Start, uint End, std::vector* B if((realBlockEnd - blockBegin) > 0) { // The next line terminates the BBlock before the INT instruction. - // (Early termination, faked as an indirect JMP) + // Early termination, faked as an indirect JMP. Rare case. CreateBlockWorker(Blocks, blockBegin, realBlockEnd, false, false, false, false)->SetFlag(BASIC_BLOCK_FLAG_PREINT3); blockBegin = realBlockEnd; @@ -131,21 +135,32 @@ void LinearPass::AnalysisWorker(uint Start, uint End, std::vector* B if(call || jmp || ret || intr) { - BasicBlock* block = CreateBlockWorker(Blocks, blockBegin, blockEnd, call, jmp, ret, intr); + // Was this an INT3? + if(intr && blockPrevInt) + { + // Append it to the previous block. Do not create a new BBlock for it. + Blocks->back().VirtualEnd = blockEnd; + } + else + { + // Otherwise use the default route: create a new entry + auto block = CreateBlockWorker(Blocks, blockBegin, blockEnd, call, jmp, ret, intr); - // Check for indirects - auto operand = disasm.x86().operands[0]; + // Check for indirects + auto operand = disasm.x86().operands[0]; - if(operand.mem.base != X86_REG_INVALID || - operand.mem.index != X86_REG_INVALID || - operand.mem.scale != 0) - block->SetFlag(BASIC_BLOCK_FLAG_INDIRECT); + if(operand.mem.base != X86_REG_INVALID || + operand.mem.index != X86_REG_INVALID || + operand.mem.scale != 0) + block->SetFlag(BASIC_BLOCK_FLAG_INDIRECT); - // Determine the target - block->Target = operand.imm; + // Determine the target + block->Target = operand.imm; + } // Reset the loop variables blockBegin = i; + blockPrevInt = intr; } } } @@ -155,6 +170,8 @@ BasicBlock* LinearPass::CreateBlockWorker(std::vector* Blocks, uint BasicBlock block; block.VirtualStart = Start; block.VirtualEnd = End; + block.Flags = 0; + block.Target = 0; // Check for calls if(Call) From ab81a1aaabb18344fce8a1b74099fc43af999014 Mon Sep 17 00:00:00 2001 From: Nukem Date: Tue, 30 Jun 2015 01:08:16 -0400 Subject: [PATCH 07/43] DBG: Virtual inheritance consistency --- x64_dbg_dbg/CodeFollowPass.cpp | 18 +++++++++++++----- x64_dbg_dbg/CodeFollowPass.h | 1 + x64_dbg_dbg/FunctionPass.cpp | 5 +++++ x64_dbg_dbg/FunctionPass.h | 1 + x64_dbg_dbg/Int3CoagulatorPass.cpp | 2 +- x64_dbg_dbg/Int3CoagulatorPass.h | 3 +-- x64_dbg_dbg/LinearPass.cpp | 12 +++++------- x64_dbg_dbg/LinearPass.h | 3 +-- 8 files changed, 28 insertions(+), 17 deletions(-) diff --git a/x64_dbg_dbg/CodeFollowPass.cpp b/x64_dbg_dbg/CodeFollowPass.cpp index a84a6923..cb3144c6 100644 --- a/x64_dbg_dbg/CodeFollowPass.cpp +++ b/x64_dbg_dbg/CodeFollowPass.cpp @@ -11,15 +11,23 @@ CodeFollowPass::~CodeFollowPass() { } +const char* CodeFollowPass::GetName() +{ + return "Code Follower"; +} + bool CodeFollowPass::Analyse() { - // First gather all possible function references with a linear scan-down + // First gather all possible function references with certain tables // // This includes: - // call - // jmp - // push - // mov XXX, + // Main entry + // Module exports + // Module import references (?) + // Control flow guard + // RUNTIME_FUNCTION + // TLS callbacks + // FLS callbacks return false; } diff --git a/x64_dbg_dbg/CodeFollowPass.h b/x64_dbg_dbg/CodeFollowPass.h index 1454b8b3..ea517a1e 100644 --- a/x64_dbg_dbg/CodeFollowPass.h +++ b/x64_dbg_dbg/CodeFollowPass.h @@ -10,6 +10,7 @@ public: CodeFollowPass(uint VirtualStart, uint VirtualEnd, BBlockArray & MainBlocks); virtual ~CodeFollowPass(); + virtual const char* GetName() override; virtual bool Analyse() override; private: diff --git a/x64_dbg_dbg/FunctionPass.cpp b/x64_dbg_dbg/FunctionPass.cpp index 38b5d26b..25001d63 100644 --- a/x64_dbg_dbg/FunctionPass.cpp +++ b/x64_dbg_dbg/FunctionPass.cpp @@ -9,6 +9,11 @@ FunctionPass::~FunctionPass() { } +const char* FunctionPass::GetName() +{ + return "Function Analysis"; +} + bool FunctionPass::Analyse() { return false; diff --git a/x64_dbg_dbg/FunctionPass.h b/x64_dbg_dbg/FunctionPass.h index 3e6f4491..60361159 100644 --- a/x64_dbg_dbg/FunctionPass.h +++ b/x64_dbg_dbg/FunctionPass.h @@ -9,6 +9,7 @@ public: FunctionPass(uint VirtualStart, uint VirtualEnd, BBlockArray & MainBlocks); virtual ~FunctionPass(); + virtual const char* GetName() override; virtual bool Analyse() override; private: diff --git a/x64_dbg_dbg/Int3CoagulatorPass.cpp b/x64_dbg_dbg/Int3CoagulatorPass.cpp index f5e1cd7e..bac0b665 100644 --- a/x64_dbg_dbg/Int3CoagulatorPass.cpp +++ b/x64_dbg_dbg/Int3CoagulatorPass.cpp @@ -13,7 +13,7 @@ Int3CoagulatorPass::~Int3CoagulatorPass() const char* Int3CoagulatorPass::GetName() { - return "INT3 Group Combiner"; + return "INT3 Group Combiner - DEPRECATED"; } bool Int3CoagulatorPass::Analyse() diff --git a/x64_dbg_dbg/Int3CoagulatorPass.h b/x64_dbg_dbg/Int3CoagulatorPass.h index 6eff3176..9d781961 100644 --- a/x64_dbg_dbg/Int3CoagulatorPass.h +++ b/x64_dbg_dbg/Int3CoagulatorPass.h @@ -12,9 +12,8 @@ public: Int3CoagulatorPass(uint VirtualStart, uint VirtualEnd, BBlockArray & MainBlocks); virtual ~Int3CoagulatorPass(); - virtual bool Analyse() override; - virtual const char* GetName() override; + virtual bool Analyse() override; private: void AnalysisWorker(uint Start, uint End, std::vector* Blocks); diff --git a/x64_dbg_dbg/LinearPass.cpp b/x64_dbg_dbg/LinearPass.cpp index 62bb7942..3fe6b21d 100644 --- a/x64_dbg_dbg/LinearPass.cpp +++ b/x64_dbg_dbg/LinearPass.cpp @@ -70,10 +70,9 @@ bool LinearPass::Analyse() // Logging dprintf("Total basic blocks: %d\n", m_MainBlocks.size()); - /* - FILE *f = fopen("C:\\test.txt", "w"); + FILE* f = fopen("C:\\test.txt", "w"); - for (auto& block : m_InitialBlocks) + for(auto & block : m_MainBlocks) { char buf[256]; size_t size = sprintf_s(buf, "Start: 0x%p End: 0x%p\n", block.VirtualStart, block.VirtualEnd); @@ -82,7 +81,6 @@ bool LinearPass::Analyse() } fclose(f); - */ // Cleanup delete[] threadBlocks; @@ -138,7 +136,7 @@ void LinearPass::AnalysisWorker(uint Start, uint End, std::vector* B // Was this an INT3? if(intr && blockPrevInt) { - // Append it to the previous block. Do not create a new BBlock for it. + // Append it to the previous block Blocks->back().VirtualEnd = blockEnd; } else @@ -146,7 +144,7 @@ void LinearPass::AnalysisWorker(uint Start, uint End, std::vector* B // Otherwise use the default route: create a new entry auto block = CreateBlockWorker(Blocks, blockBegin, blockEnd, call, jmp, ret, intr); - // Check for indirects + // Indirect branching auto operand = disasm.x86().operands[0]; if(operand.mem.base != X86_REG_INVALID || @@ -154,7 +152,7 @@ void LinearPass::AnalysisWorker(uint Start, uint End, std::vector* B operand.mem.scale != 0) block->SetFlag(BASIC_BLOCK_FLAG_INDIRECT); - // Determine the target + // Branch target block->Target = operand.imm; } diff --git a/x64_dbg_dbg/LinearPass.h b/x64_dbg_dbg/LinearPass.h index e67e7253..23abcfc5 100644 --- a/x64_dbg_dbg/LinearPass.h +++ b/x64_dbg_dbg/LinearPass.h @@ -13,9 +13,8 @@ public: LinearPass(uint VirtualStart, uint VirtualEnd, BBlockArray & MainBlocks); virtual ~LinearPass(); - virtual bool Analyse() override; - virtual const char* GetName() override; + virtual bool Analyse() override; private: uint m_MaximumThreads; From a3ebaf92bf211b8c01cf0757fbdc1d4c7e63a9d4 Mon Sep 17 00:00:00 2001 From: Nukem Date: Tue, 30 Jun 2015 22:18:27 -0400 Subject: [PATCH 08/43] DBG: Don't conflict with windows headers in Yara (ugly fix) --- x64_dbg_dbg/yara/yara/modules.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/x64_dbg_dbg/yara/yara/modules.h b/x64_dbg_dbg/yara/yara/modules.h index 8ecc89a8..c9070d83 100644 --- a/x64_dbg_dbg/yara/yara/modules.h +++ b/x64_dbg_dbg/yara/yara/modules.h @@ -32,15 +32,15 @@ limitations under the License. // Concatenation that macro-expands its arguments. -#define CONCAT(arg1, arg2) _CONCAT(arg1, arg2) // expands the arguments. -#define _CONCAT(arg1, arg2) arg1 ## arg2 // do the actual concatenation. +#define CONCAT_ARGS(arg1, arg2) _CONCAT(arg1, arg2) // expands the arguments. +#define _CONCAT_ARGS(arg1, arg2) arg1 ## arg2 // do the actual concatenation. -#define module_declarations CONCAT(MODULE_NAME, __declarations) -#define module_load CONCAT(MODULE_NAME, __load) -#define module_unload CONCAT(MODULE_NAME, __unload) -#define module_initialize CONCAT(MODULE_NAME, __initialize) -#define module_finalize CONCAT(MODULE_NAME, __finalize) +#define module_declarations CONCAT_ARGS(MODULE_NAME, __declarations) +#define module_load CONCAT_ARGS(MODULE_NAME, __load) +#define module_unload CONCAT_ARGS(MODULE_NAME, __unload) +#define module_initialize CONCAT_ARGS(MODULE_NAME, __initialize) +#define module_finalize CONCAT_ARGS(MODULE_NAME, __finalize) #define begin_declarations \ int module_declarations(YR_OBJECT* module) { \ From c98c82203aeee3eec8157188a312ecda09c4c6ab Mon Sep 17 00:00:00 2001 From: Nukem Date: Tue, 30 Jun 2015 22:21:42 -0400 Subject: [PATCH 09/43] DBG: LinearPass: more parallel-ness --- x64_dbg_dbg/LinearPass.cpp | 28 +++++++++++++--------------- x64_dbg_dbg/LinearPass.h | 2 -- 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/x64_dbg_dbg/LinearPass.cpp b/x64_dbg_dbg/LinearPass.cpp index 3fe6b21d..97957e4c 100644 --- a/x64_dbg_dbg/LinearPass.cpp +++ b/x64_dbg_dbg/LinearPass.cpp @@ -1,6 +1,7 @@ #include "AnalysisPass.h" #include "LinearPass.h" -#include "console.h" +#include +#include LinearPass::LinearPass(uint VirtualStart, uint VirtualEnd, BBlockArray & MainBlocks) : AnalysisPass(VirtualStart, VirtualEnd, MainBlocks) @@ -26,48 +27,44 @@ bool LinearPass::Analyse() { // Divide the work up between each thread // THREAD_WORK = (TOTAL / # THREADS) - uint workCurrent = 0; uint workAmount = m_DataSize / m_MaximumThreads; // Initialize thread vector - std::vector localThreads(m_MaximumThreads); std::vector* threadBlocks = new std::vector[m_MaximumThreads]; - for(uint i = 0; i < m_MaximumThreads; i++) + concurrency::parallel_for(uint(0), m_MaximumThreads, [&](uint i) { - uint threadWorkStart = m_VirtualStart + workCurrent; + uint threadWorkStart = m_VirtualStart + (workAmount * i); uint threadWorkStop = min((threadWorkStart + workAmount), m_VirtualEnd); // Allow a 16-byte variance of scanning because of // integer rounding errors - if(workCurrent >= 16) + if(threadWorkStart > m_VirtualStart) + { threadWorkStart -= 16; + threadWorkStop += 16; + } // Memory allocation optimization // TODO: Option to conserve memory threadBlocks[i].reserve(100000); // Execute - localThreads[i] = std::thread(&LinearPass::AnalysisWorker, this, threadWorkStart, threadWorkStop, &threadBlocks[i]); + AnalysisWorker(threadWorkStart, threadWorkStop, &threadBlocks[i]); + }); - // Increment the work counter - workCurrent += workAmount; - } - - // Wait for all threads to finish and combine vectors + // Clear old data and combine vectors m_MainBlocks.clear(); for(uint i = 0; i < m_MaximumThreads; i++) - { - localThreads[i].join(); m_MainBlocks.insert(m_MainBlocks.end(), threadBlocks[i].begin(), threadBlocks[i].end()); - } // Sort and remove duplicates std::sort(m_MainBlocks.begin(), m_MainBlocks.end()); m_MainBlocks.erase(std::unique(m_MainBlocks.begin(), m_MainBlocks.end()), m_MainBlocks.end()); // Logging + /* dprintf("Total basic blocks: %d\n", m_MainBlocks.size()); FILE* f = fopen("C:\\test.txt", "w"); @@ -81,6 +78,7 @@ bool LinearPass::Analyse() } fclose(f); + */ // Cleanup delete[] threadBlocks; diff --git a/x64_dbg_dbg/LinearPass.h b/x64_dbg_dbg/LinearPass.h index 23abcfc5..bd689c81 100644 --- a/x64_dbg_dbg/LinearPass.h +++ b/x64_dbg_dbg/LinearPass.h @@ -1,8 +1,6 @@ #pragma once #include -#include - #include "AnalysisPass.h" #include "BasicBlock.h" #include "capstone_wrapper.h" From 47f3923464e60fd3656b65d720e7545567e82002 Mon Sep 17 00:00:00 2001 From: Nukem Date: Tue, 30 Jun 2015 23:35:59 -0400 Subject: [PATCH 10/43] DBG: Conserve memory when copying BBlock vectors --- x64_dbg_dbg/LinearPass.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/x64_dbg_dbg/LinearPass.cpp b/x64_dbg_dbg/LinearPass.cpp index 97957e4c..7d444bca 100644 --- a/x64_dbg_dbg/LinearPass.cpp +++ b/x64_dbg_dbg/LinearPass.cpp @@ -57,7 +57,12 @@ bool LinearPass::Analyse() m_MainBlocks.clear(); for(uint i = 0; i < m_MaximumThreads; i++) - m_MainBlocks.insert(m_MainBlocks.end(), threadBlocks[i].begin(), threadBlocks[i].end()); + { + std::move(threadBlocks[i].begin(), threadBlocks[i].end(), std::back_inserter(m_MainBlocks)); + + // Free vector elements to conserve memory further + BBlockArray().swap(threadBlocks[i]); + } // Sort and remove duplicates std::sort(m_MainBlocks.begin(), m_MainBlocks.end()); From 25c83adadf96b8a9a4589a02eb5168012be0191d Mon Sep 17 00:00:00 2001 From: Nukem Date: Wed, 1 Jul 2015 00:59:16 -0400 Subject: [PATCH 11/43] DBG: Add ideal thread count function --- x64_dbg_dbg/AnalysisPass.cpp | 13 +++++++++++++ x64_dbg_dbg/AnalysisPass.h | 1 + 2 files changed, 14 insertions(+) diff --git a/x64_dbg_dbg/AnalysisPass.cpp b/x64_dbg_dbg/AnalysisPass.cpp index 15d6676d..78355647 100644 --- a/x64_dbg_dbg/AnalysisPass.cpp +++ b/x64_dbg_dbg/AnalysisPass.cpp @@ -1,4 +1,5 @@ #include +#include #include "AnalysisPass.h" #include "capstone_wrapper.h" #include "memory.h" @@ -49,4 +50,16 @@ void AnalysisPass::AcquireExclusiveLock() void AnalysisPass::ReleaseExclusiveLock() { ReleaseSRWLockExclusive(&m_InternalLock); +} + +uint AnalysisPass::IdealThreadCount() +{ + // Determine the maximum hardware thread count at once + uint maximumThreads = max(std::thread::hardware_concurrency(), 1); + + // Don't consume 100% of the CPU, adjust accordingly + if(maximumThreads > 1) + maximumThreads -= 1; + + return maximumThreads; } \ No newline at end of file diff --git a/x64_dbg_dbg/AnalysisPass.h b/x64_dbg_dbg/AnalysisPass.h index f5f9eda9..fc6861b3 100644 --- a/x64_dbg_dbg/AnalysisPass.h +++ b/x64_dbg_dbg/AnalysisPass.h @@ -36,6 +36,7 @@ protected: void ReleaseReadLock(); void AcquireExclusiveLock(); void ReleaseExclusiveLock(); + uint IdealThreadCount(); private: SRWLOCK m_InternalLock; From b25e49b5a57ffad6e5c9d36fa46c0735d087a627 Mon Sep 17 00:00:00 2001 From: Nukem Date: Wed, 1 Jul 2015 00:59:39 -0400 Subject: [PATCH 12/43] DBG: Better operand checks in linear pass --- x64_dbg_dbg/LinearPass.cpp | 57 ++++++++++++++++---------------------- x64_dbg_dbg/LinearPass.h | 2 -- 2 files changed, 24 insertions(+), 35 deletions(-) diff --git a/x64_dbg_dbg/LinearPass.cpp b/x64_dbg_dbg/LinearPass.cpp index 7d444bca..9e75d848 100644 --- a/x64_dbg_dbg/LinearPass.cpp +++ b/x64_dbg_dbg/LinearPass.cpp @@ -2,16 +2,11 @@ #include "LinearPass.h" #include #include +#include "console.h" LinearPass::LinearPass(uint VirtualStart, uint VirtualEnd, BBlockArray & MainBlocks) : AnalysisPass(VirtualStart, VirtualEnd, MainBlocks) { - // Determine the maximum hardware thread count at once - m_MaximumThreads = max(std::thread::hardware_concurrency(), 1); - - // Don't consume 100% of the CPU, so adjust accordingly - if(m_MaximumThreads > 1) - m_MaximumThreads -= 1; } LinearPass::~LinearPass() @@ -27,12 +22,12 @@ bool LinearPass::Analyse() { // Divide the work up between each thread // THREAD_WORK = (TOTAL / # THREADS) - uint workAmount = m_DataSize / m_MaximumThreads; + uint workAmount = m_DataSize / IdealThreadCount(); // Initialize thread vector - std::vector* threadBlocks = new std::vector[m_MaximumThreads]; + auto threadBlocks = new std::vector[IdealThreadCount()]; - concurrency::parallel_for(uint(0), m_MaximumThreads, [&](uint i) + concurrency::parallel_for(uint(0), IdealThreadCount(), [&](uint i) { uint threadWorkStart = m_VirtualStart + (workAmount * i); uint threadWorkStop = min((threadWorkStart + workAmount), m_VirtualEnd); @@ -56,11 +51,11 @@ bool LinearPass::Analyse() // Clear old data and combine vectors m_MainBlocks.clear(); - for(uint i = 0; i < m_MaximumThreads; i++) + for(uint i = 0; i < IdealThreadCount(); i++) { std::move(threadBlocks[i].begin(), threadBlocks[i].end(), std::back_inserter(m_MainBlocks)); - // Free vector elements to conserve memory further + // Free old elements to conserve memory further BBlockArray().swap(threadBlocks[i]); } @@ -69,25 +64,9 @@ bool LinearPass::Analyse() m_MainBlocks.erase(std::unique(m_MainBlocks.begin(), m_MainBlocks.end()), m_MainBlocks.end()); // Logging - /* dprintf("Total basic blocks: %d\n", m_MainBlocks.size()); - FILE* f = fopen("C:\\test.txt", "w"); - - for(auto & block : m_MainBlocks) - { - char buf[256]; - size_t size = sprintf_s(buf, "Start: 0x%p End: 0x%p\n", block.VirtualStart, block.VirtualEnd); - - fwrite(buf, size, 1, f); - } - - fclose(f); - */ - - // Cleanup delete[] threadBlocks; - return true; } @@ -147,16 +126,28 @@ void LinearPass::AnalysisWorker(uint Start, uint End, std::vector* B // Otherwise use the default route: create a new entry auto block = CreateBlockWorker(Blocks, blockBegin, blockEnd, call, jmp, ret, intr); - // Indirect branching + // Figure out the operand type auto operand = disasm.x86().operands[0]; - if(operand.mem.base != X86_REG_INVALID || - operand.mem.index != X86_REG_INVALID || - operand.mem.scale != 0) + if(operand.type == X86_OP_IMM) + { + // Branch target immediate + block->Target = operand.imm; + } + else + { + // Indirects block->SetFlag(BASIC_BLOCK_FLAG_INDIRECT); - // Branch target - block->Target = operand.imm; + if(operand.type == X86_OP_MEM && + operand.mem.base == X86_REG_INVALID && + operand.mem.index == X86_REG_INVALID && + operand.mem.scale == 0) + { + block->SetFlag(BASIC_BLOCK_FLAG_INDIRPTR); + block->Target = operand.mem.disp; + } + } } // Reset the loop variables diff --git a/x64_dbg_dbg/LinearPass.h b/x64_dbg_dbg/LinearPass.h index bd689c81..f2ea749f 100644 --- a/x64_dbg_dbg/LinearPass.h +++ b/x64_dbg_dbg/LinearPass.h @@ -15,8 +15,6 @@ public: virtual bool Analyse() override; private: - uint m_MaximumThreads; - void AnalysisWorker(uint Start, uint End, std::vector* Blocks); BasicBlock* CreateBlockWorker(std::vector* Blocks, uint Start, uint End, bool Call, bool Jmp, bool Ret, bool Intr); }; \ No newline at end of file From 417d6b251302e411265860287845f51071fd9dfc Mon Sep 17 00:00:00 2001 From: Nukem Date: Wed, 1 Jul 2015 01:00:15 -0400 Subject: [PATCH 13/43] DBG: Add structure and flags for function locations --- x64_dbg_dbg/BasicBlock.h | 24 +++++++++++++++++++++--- x64_dbg_dbg/memory.cpp | 2 -- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/x64_dbg_dbg/BasicBlock.h b/x64_dbg_dbg/BasicBlock.h index f866207f..6ad15f12 100644 --- a/x64_dbg_dbg/BasicBlock.h +++ b/x64_dbg_dbg/BasicBlock.h @@ -10,8 +10,9 @@ enum BasicBlockFlags : uint BASIC_BLOCK_FLAG_CALL = (1 << 3), // The block ends with a call BASIC_BLOCK_FLAG_RET = (1 << 4), // The block ends with a retn BASIC_BLOCK_FLAG_INDIRECT = (1 << 5), // This block ends with an indirect branch - BASIC_BLOCK_FLAG_PREINT3 = (1 << 6), // Block ends because there was an INT3 afterwards - BASIC_BLOCK_FLAG_INT3 = (1 << 7), // Block is only a series of INT3 + BASIC_BLOCK_FLAG_INDIRPTR = (1 << 6), // This block ends with an indirect branch; pointer known + BASIC_BLOCK_FLAG_PREINT3 = (1 << 7), // Block ends because there was an INT3 afterwards + BASIC_BLOCK_FLAG_INT3 = (1 << 8), // Block is only a series of INT3 }; struct BasicBlock @@ -42,4 +43,21 @@ struct BasicBlock } }; -typedef std::vector BBlockArray; \ No newline at end of file +struct FunctionDef +{ + uint VirtualStart; // Inclusive + uint VirtualEnd; // Exclusive + + bool operator< (const FunctionDef & b) const + { + return VirtualStart < b.VirtualStart; + } + + bool operator== (const FunctionDef & b) const + { + return VirtualStart == b.VirtualStart; + } +}; + +typedef std::vector BBlockArray; +typedef std::vector FuncDefArray; \ No newline at end of file diff --git a/x64_dbg_dbg/memory.cpp b/x64_dbg_dbg/memory.cpp index e19dc6a1..879f4f35 100644 --- a/x64_dbg_dbg/memory.cpp +++ b/x64_dbg_dbg/memory.cpp @@ -157,7 +157,6 @@ uint MemFindBaseAddr(uint Address, uint* Size, bool Refresh) bool MemRead(void* BaseAddress, void* Buffer, SIZE_T Size, SIZE_T* NumberOfBytesRead) { - // Fast fail if address is invalid if(!MemIsCanonicalAddress((uint)BaseAddress)) return false; @@ -212,7 +211,6 @@ bool MemRead(void* BaseAddress, void* Buffer, SIZE_T Size, SIZE_T* NumberOfBytes bool MemWrite(void* BaseAddress, void* Buffer, SIZE_T Size, SIZE_T* NumberOfBytesWritten) { - // Fast fail if address is invalid if(!MemIsCanonicalAddress((uint)BaseAddress)) return false; From bc4d1ccc13118646efcd3834bb60d73a9780b916 Mon Sep 17 00:00:00 2001 From: Nukem Date: Wed, 1 Jul 2015 01:00:33 -0400 Subject: [PATCH 14/43] DBG: Start implementing FunctionPass --- x64_dbg_dbg/Analysis.cpp | 3 ++ x64_dbg_dbg/FunctionPass.cpp | 68 +++++++++++++++++++++++++++++++++++- x64_dbg_dbg/FunctionPass.h | 1 + 3 files changed, 71 insertions(+), 1 deletion(-) diff --git a/x64_dbg_dbg/Analysis.cpp b/x64_dbg_dbg/Analysis.cpp index 06ac85c1..0f270f3a 100644 --- a/x64_dbg_dbg/Analysis.cpp +++ b/x64_dbg_dbg/Analysis.cpp @@ -14,6 +14,9 @@ void Derp(uint _base) LinearPass* pass = new LinearPass(modBase, modBase + modSize, array); pass->Analyse(); + FunctionPass* pass3 = new FunctionPass(modBase, modBase + modSize, array); + pass3->Analyse(); + //Int3CoagulatorPass *pass2 = new Int3CoagulatorPass(modBase, modBase + modSize, array); //pass2->Analyse(); /* diff --git a/x64_dbg_dbg/FunctionPass.cpp b/x64_dbg_dbg/FunctionPass.cpp index 25001d63..a58e1500 100644 --- a/x64_dbg_dbg/FunctionPass.cpp +++ b/x64_dbg_dbg/FunctionPass.cpp @@ -1,4 +1,8 @@ #include "FunctionPass.h" +#include "capstone_wrapper.h" +#include +#include "memory.h" +#include "console.h" FunctionPass::FunctionPass(uint VirtualStart, uint VirtualEnd, BBlockArray & MainBlocks) : AnalysisPass(VirtualStart, VirtualEnd, MainBlocks) @@ -16,5 +20,67 @@ const char* FunctionPass::GetName() bool FunctionPass::Analyse() { - return false; + // THREAD_WORK = (TOTAL / # THREADS) + float workDivision = (float)m_MainBlocks.size() / (float)IdealThreadCount(); + uint workAmount = (int)ceil(workDivision); + + // Initialize thread vector + auto threadFunctions = new std::vector[IdealThreadCount()]; + + concurrency::parallel_for(uint(0), IdealThreadCount(), [&](uint i) + { + uint threadWorkStart = (workAmount * i); + uint threadWorkStop = min((threadWorkStart + workAmount), m_MainBlocks.size()); + + // Memory allocation optimization + // TODO: Option to conserve memory + threadFunctions[i].reserve(10000); + + // Execute + AnalysisWorker(threadWorkStart, threadWorkStop, &threadFunctions[i]); + }); + + delete[] threadFunctions; + return true; +} + +void FunctionPass::AnalysisWorker(uint Start, uint End, std::vector* Blocks) +{ + // Step 1: for each block that contains a CALL flag, + // add it to a local function start array + // + // NOTE: *Some* indirect calls are included + auto blockItr = std::next(m_MainBlocks.begin(), Start); + + for(uint i = Start; i < End; i++, blockItr++) + { + if(blockItr->GetFlag(BASIC_BLOCK_FLAG_CALL)) + { + uint destination = blockItr->Target; + + // Was it a pointer? + if(blockItr->GetFlag(BASIC_BLOCK_FLAG_INDIRPTR)) + { + // Read it from memory + if(!MemRead((PVOID)destination, &destination, sizeof(uint), nullptr)) + continue; + + // Validity check + if(!MemIsValidReadPtr(destination)) + continue; + } + + FunctionDef def; + def.VirtualStart = destination; + def.VirtualEnd = destination; + Blocks->push_back(def); + } + } + + // Step 2: Sort and remove duplicates + std::sort(Blocks->begin(), Blocks->end()); + Blocks->erase(std::unique(Blocks->begin(), Blocks->end()), Blocks->end()); + + // Step 3: ? + dprintf("Total call instructions: %d\n", Blocks->size()); } \ No newline at end of file diff --git a/x64_dbg_dbg/FunctionPass.h b/x64_dbg_dbg/FunctionPass.h index 60361159..146655c2 100644 --- a/x64_dbg_dbg/FunctionPass.h +++ b/x64_dbg_dbg/FunctionPass.h @@ -13,4 +13,5 @@ public: virtual bool Analyse() override; private: + void AnalysisWorker(uint Start, uint End, std::vector* Blocks); }; \ No newline at end of file From 17701115a89fb777203f68d6775e9b056fa8dcc3 Mon Sep 17 00:00:00 2001 From: Nukem Date: Wed, 1 Jul 2015 01:14:56 -0400 Subject: [PATCH 15/43] DBG: Bugfix --- x64_dbg_dbg/LinearPass.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x64_dbg_dbg/LinearPass.cpp b/x64_dbg_dbg/LinearPass.cpp index 9e75d848..2be3f4ad 100644 --- a/x64_dbg_dbg/LinearPass.cpp +++ b/x64_dbg_dbg/LinearPass.cpp @@ -37,7 +37,7 @@ bool LinearPass::Analyse() if(threadWorkStart > m_VirtualStart) { threadWorkStart -= 16; - threadWorkStop += 16; + threadWorkStop = min((threadWorkStop + 16), m_VirtualEnd); } // Memory allocation optimization From 57391ef4450863ce19042af7338c4b51a8a84263 Mon Sep 17 00:00:00 2001 From: Nukem Date: Thu, 2 Jul 2015 01:54:05 -0400 Subject: [PATCH 16/43] DBG: Use RUNTIME_FUNCTION when available in function analysis --- x64_dbg_dbg/BasicBlock.h | 10 ++- x64_dbg_dbg/FunctionPass.cpp | 117 ++++++++++++++++++++++++++++++++++- x64_dbg_dbg/FunctionPass.h | 10 +++ 3 files changed, 133 insertions(+), 4 deletions(-) diff --git a/x64_dbg_dbg/BasicBlock.h b/x64_dbg_dbg/BasicBlock.h index 6ad15f12..9eb29ada 100644 --- a/x64_dbg_dbg/BasicBlock.h +++ b/x64_dbg_dbg/BasicBlock.h @@ -4,8 +4,8 @@ enum BasicBlockFlags : uint { - BASIC_BLOCK_FLAG_NONE, // No flag - BASIC_BLOCK_FLAG_SCANNED = (1 << 1), // The block was scanned at least once + BASIC_BLOCK_FLAG_NONE = 0, // No flag + BASIC_BLOCK_FLAG_FUNCTION = (1 << 1), // Scanned; also part of a known function BASIC_BLOCK_FLAG_ORPHANED = (1 << 2), // No targets ever reach this block BASIC_BLOCK_FLAG_CALL = (1 << 3), // The block ends with a call BASIC_BLOCK_FLAG_RET = (1 << 4), // The block ends with a retn @@ -48,8 +48,14 @@ struct FunctionDef uint VirtualStart; // Inclusive uint VirtualEnd; // Exclusive + uint BBlockStart; // Index of first basic block + uint BBlockEnd; // Index of last basic block + bool operator< (const FunctionDef & b) const { + if(VirtualStart == b.VirtualStart) + return VirtualEnd > b.VirtualEnd; + return VirtualStart < b.VirtualStart; } diff --git a/x64_dbg_dbg/FunctionPass.cpp b/x64_dbg_dbg/FunctionPass.cpp index a58e1500..11299446 100644 --- a/x64_dbg_dbg/FunctionPass.cpp +++ b/x64_dbg_dbg/FunctionPass.cpp @@ -3,14 +3,67 @@ #include #include "memory.h" #include "console.h" +#include "debugger.h" +#include "module.h" FunctionPass::FunctionPass(uint VirtualStart, uint VirtualEnd, BBlockArray & MainBlocks) : AnalysisPass(VirtualStart, VirtualEnd, MainBlocks) { + // Zero values + m_FunctionInfo = nullptr; + m_FunctionInfoSize = 0; + + // This will only be valid if the address range is within a loaded module + m_ModuleStart = ModBaseFromAddr(VirtualStart); + + if(m_ModuleStart != 0) + { + char modulePath[MAX_PATH]; + memset(modulePath, 0, sizeof(modulePath)); + + ModPathFromAddr(m_ModuleStart, modulePath, ARRAYSIZE(modulePath)); + + HANDLE fileHandle; + DWORD fileSize; + HANDLE fileMapHandle; + ULONG_PTR fileMapVa; + if(StaticFileLoadW( + StringUtils::Utf8ToUtf16(modulePath).c_str(), + UE_ACCESS_READ, + false, + &fileHandle, + &fileSize, + &fileMapHandle, + &fileMapVa)) + { + // Find a pointer to IMAGE_DIRECTORY_ENTRY_EXCEPTION for later use + ULONG_PTR virtualOffset = GetPE32DataFromMappedFile(fileMapVa, IMAGE_DIRECTORY_ENTRY_EXCEPTION, UE_SECTIONVIRTUALOFFSET); + m_FunctionInfoSize = (ULONG)GetPE32DataFromMappedFile(fileMapVa, IMAGE_DIRECTORY_ENTRY_EXCEPTION, UE_SECTIONVIRTUALSIZE); + + // Unload the file + StaticFileUnloadW(nullptr, false, fileHandle, fileSize, fileMapHandle, fileMapVa); + + dprintf("VA - 0x%p\n", virtualOffset); + + // Get a copy of the function table + if(virtualOffset) + { + // Read the table into a buffer + m_FunctionInfo = BridgeAlloc(m_FunctionInfoSize); + + if(m_FunctionInfo) + MemRead((PVOID)(virtualOffset + m_ModuleStart), m_FunctionInfo, m_FunctionInfoSize, nullptr); + } + } + } + + dprintf("Function info: 0x%p - 0x%p\n", m_FunctionInfo, m_FunctionInfoSize); } FunctionPass::~FunctionPass() { + if(m_FunctionInfo) + BridgeFree(m_FunctionInfo); } const char* FunctionPass::GetName() @@ -46,7 +99,10 @@ bool FunctionPass::Analyse() void FunctionPass::AnalysisWorker(uint Start, uint End, std::vector* Blocks) { - // Step 1: for each block that contains a CALL flag, + // Step 1: Use any defined functions in the PE function table + FindFunctionWorkerPrepass(Start, End, Blocks); + + // Step 2: for each block that contains a CALL flag, // add it to a local function start array // // NOTE: *Some* indirect calls are included @@ -68,11 +124,19 @@ void FunctionPass::AnalysisWorker(uint Start, uint End, std::vector // Validity check if(!MemIsValidReadPtr(destination)) continue; + + dprintf("Indirect pointer: 0x%p 0x%p\n", blockItr->Target, destination); } + // Destination must be within analysis limits + if(!ValidateAddress(destination)) + continue; + FunctionDef def; def.VirtualStart = destination; def.VirtualEnd = destination; + def.BBlockStart = 0; + def.BBlockEnd = 0; Blocks->push_back(def); } } @@ -81,6 +145,55 @@ void FunctionPass::AnalysisWorker(uint Start, uint End, std::vector std::sort(Blocks->begin(), Blocks->end()); Blocks->erase(std::unique(Blocks->begin(), Blocks->end()), Blocks->end()); - // Step 3: ? + // Step 3: Find the end of functions dprintf("Total call instructions: %d\n", Blocks->size()); + FindFunctionWorker(Blocks); +} + +void FunctionPass::FindFunctionWorkerPrepass(uint Start, uint End, std::vector* Blocks) +{ + uint minFunc = std::next(m_MainBlocks.begin(), Start)->VirtualStart; + uint maxFunc = std::next(m_MainBlocks.begin(), End - 1)->VirtualEnd; + + EnumerateFunctionRuntimeEntries64([&](PRUNTIME_FUNCTION Function) + { + const uint funcAddr = m_ModuleStart + Function->BeginAddress; + const uint funcEnd = m_ModuleStart + Function->EndAddress; + + // If within limits... + if(funcAddr >= minFunc && funcAddr < maxFunc) + { + // Add the descriptor + FunctionDef def; + def.VirtualStart = funcAddr; + def.VirtualEnd = funcEnd; + def.BBlockStart = 0; + def.BBlockEnd = 0; + Blocks->push_back(def); + } + + return true; + }); +} + +void FunctionPass::FindFunctionWorker(std::vector* Blocks) +{ +} + +void FunctionPass::EnumerateFunctionRuntimeEntries64(std::function Callback) +{ + if(!m_FunctionInfo) + return; + + // Get the table pointer + PRUNTIME_FUNCTION functionTable = (PRUNTIME_FUNCTION)m_FunctionInfo; + + // Enumerate each entry + ULONG totalCount = (m_FunctionInfoSize / sizeof(RUNTIME_FUNCTION)); + + for(ULONG i = 0; i < totalCount; i++) + { + if(!Callback(&functionTable[i])) + break; + } } \ No newline at end of file diff --git a/x64_dbg_dbg/FunctionPass.h b/x64_dbg_dbg/FunctionPass.h index 146655c2..c866f8e4 100644 --- a/x64_dbg_dbg/FunctionPass.h +++ b/x64_dbg_dbg/FunctionPass.h @@ -1,5 +1,6 @@ #pragma once +#include #include "AnalysisPass.h" #include "BasicBlock.h" @@ -13,5 +14,14 @@ public: virtual bool Analyse() override; private: + uint m_ModuleStart; + + PVOID m_FunctionInfo; + ULONG m_FunctionInfoSize; + void AnalysisWorker(uint Start, uint End, std::vector* Blocks); + void FindFunctionWorkerPrepass(uint Start, uint End, std::vector* Blocks); + void FindFunctionWorker(std::vector* Blocks); + + void EnumerateFunctionRuntimeEntries64(std::function Callback); }; \ No newline at end of file From 255d6c9e2c24d0d30c0c64926eea165503e6d517 Mon Sep 17 00:00:00 2001 From: Nukem Date: Thu, 2 Jul 2015 02:18:22 -0400 Subject: [PATCH 17/43] DBG: Fix some comments --- x64_dbg_dbg/FunctionPass.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/x64_dbg_dbg/FunctionPass.cpp b/x64_dbg_dbg/FunctionPass.cpp index 11299446..20a3be11 100644 --- a/x64_dbg_dbg/FunctionPass.cpp +++ b/x64_dbg_dbg/FunctionPass.cpp @@ -141,13 +141,17 @@ void FunctionPass::AnalysisWorker(uint Start, uint End, std::vector } } - // Step 2: Sort and remove duplicates + // Step 3: Sort and remove duplicates std::sort(Blocks->begin(), Blocks->end()); Blocks->erase(std::unique(Blocks->begin(), Blocks->end()), Blocks->end()); - // Step 3: Find the end of functions - dprintf("Total call instructions: %d\n", Blocks->size()); + // Step 4: Find the end of functions FindFunctionWorker(Blocks); + + dprintf("Total detected functions: %d\n", Blocks->size()); + + // Step 5: Find all orphaned blocks and repeat analysis process + // TODO } void FunctionPass::FindFunctionWorkerPrepass(uint Start, uint End, std::vector* Blocks) From 0c7919930ff0dc0f84cf3c25f934c6b4bc26a34c Mon Sep 17 00:00:00 2001 From: Nukem Date: Fri, 3 Jul 2015 00:50:38 -0400 Subject: [PATCH 18/43] DBG: Cache thread count --- x64_dbg_dbg/AnalysisPass.cpp | 17 +++++++++++------ x64_dbg_dbg/AnalysisPass.h | 1 + x64_dbg_dbg/FunctionPass.cpp | 6 ++---- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/x64_dbg_dbg/AnalysisPass.cpp b/x64_dbg_dbg/AnalysisPass.cpp index 78355647..661879f5 100644 --- a/x64_dbg_dbg/AnalysisPass.cpp +++ b/x64_dbg_dbg/AnalysisPass.cpp @@ -54,12 +54,17 @@ void AnalysisPass::ReleaseExclusiveLock() uint AnalysisPass::IdealThreadCount() { - // Determine the maximum hardware thread count at once - uint maximumThreads = max(std::thread::hardware_concurrency(), 1); + if(m_InternalMaxThreads == 0) + { + // Determine the maximum hardware thread count at once + uint maximumThreads = max(std::thread::hardware_concurrency(), 1); - // Don't consume 100% of the CPU, adjust accordingly - if(maximumThreads > 1) - maximumThreads -= 1; + // Don't consume 100% of the CPU, adjust accordingly + if(maximumThreads > 1) + maximumThreads -= 1; - return maximumThreads; + m_InternalMaxThreads = (BYTE)min(maximumThreads, 255); + } + + return m_InternalMaxThreads; } \ No newline at end of file diff --git a/x64_dbg_dbg/AnalysisPass.h b/x64_dbg_dbg/AnalysisPass.h index fc6861b3..2f36dde3 100644 --- a/x64_dbg_dbg/AnalysisPass.h +++ b/x64_dbg_dbg/AnalysisPass.h @@ -40,4 +40,5 @@ protected: private: SRWLOCK m_InternalLock; + BYTE m_InternalMaxThreads; }; \ No newline at end of file diff --git a/x64_dbg_dbg/FunctionPass.cpp b/x64_dbg_dbg/FunctionPass.cpp index 20a3be11..b3c0edb6 100644 --- a/x64_dbg_dbg/FunctionPass.cpp +++ b/x64_dbg_dbg/FunctionPass.cpp @@ -43,8 +43,6 @@ FunctionPass::FunctionPass(uint VirtualStart, uint VirtualEnd, BBlockArray & Mai // Unload the file StaticFileUnloadW(nullptr, false, fileHandle, fileSize, fileMapHandle, fileMapVa); - dprintf("VA - 0x%p\n", virtualOffset); - // Get a copy of the function table if(virtualOffset) { @@ -156,8 +154,8 @@ void FunctionPass::AnalysisWorker(uint Start, uint End, std::vector void FunctionPass::FindFunctionWorkerPrepass(uint Start, uint End, std::vector* Blocks) { - uint minFunc = std::next(m_MainBlocks.begin(), Start)->VirtualStart; - uint maxFunc = std::next(m_MainBlocks.begin(), End - 1)->VirtualEnd; + const uint minFunc = std::next(m_MainBlocks.begin(), Start)->VirtualStart; + const uint maxFunc = std::next(m_MainBlocks.begin(), End - 1)->VirtualEnd; EnumerateFunctionRuntimeEntries64([&](PRUNTIME_FUNCTION Function) { From eb0cfe9aa134cc43d5507b2b4a5144254f61c1a9 Mon Sep 17 00:00:00 2001 From: Nukem Date: Sat, 4 Jul 2015 00:47:00 -0400 Subject: [PATCH 19/43] DBG: Replace float rounding with integer rounding division --- x64_dbg_dbg/FunctionPass.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/x64_dbg_dbg/FunctionPass.cpp b/x64_dbg_dbg/FunctionPass.cpp index b3c0edb6..62106799 100644 --- a/x64_dbg_dbg/FunctionPass.cpp +++ b/x64_dbg_dbg/FunctionPass.cpp @@ -71,9 +71,8 @@ const char* FunctionPass::GetName() bool FunctionPass::Analyse() { - // THREAD_WORK = (TOTAL / # THREADS) - float workDivision = (float)m_MainBlocks.size() / (float)IdealThreadCount(); - uint workAmount = (int)ceil(workDivision); + // THREAD_WORK = ceil(TOTAL / # THREADS) + uint workAmount = (m_MainBlocks.size() + (IdealThreadCount() - 1)) / IdealThreadCount(); // Initialize thread vector auto threadFunctions = new std::vector[IdealThreadCount()]; From 358cbf1a16df42bdc36b8623346c287a8351eb72 Mon Sep 17 00:00:00 2001 From: Nukem Date: Sat, 4 Jul 2015 00:48:49 -0400 Subject: [PATCH 20/43] DBG: LinearPass: Fix problems with overlapping basic blocks --- x64_dbg_dbg/AnalysisPass.cpp | 1 + x64_dbg_dbg/BasicBlock.h | 7 ++ x64_dbg_dbg/LinearPass.cpp | 218 ++++++++++++++++++++++++++++++++--- x64_dbg_dbg/LinearPass.h | 8 +- 4 files changed, 215 insertions(+), 19 deletions(-) diff --git a/x64_dbg_dbg/AnalysisPass.cpp b/x64_dbg_dbg/AnalysisPass.cpp index 661879f5..228dba18 100644 --- a/x64_dbg_dbg/AnalysisPass.cpp +++ b/x64_dbg_dbg/AnalysisPass.cpp @@ -14,6 +14,7 @@ AnalysisPass::AnalysisPass(uint VirtualStart, uint VirtualEnd, BBlockArray & Mai // Internal class data m_VirtualStart = VirtualStart; m_VirtualEnd = VirtualEnd; + m_InternalMaxThreads = 0; // Read remote instruction data to local memory m_DataSize = VirtualEnd - VirtualStart; diff --git a/x64_dbg_dbg/BasicBlock.h b/x64_dbg_dbg/BasicBlock.h index 9eb29ada..bd4f3528 100644 --- a/x64_dbg_dbg/BasicBlock.h +++ b/x64_dbg_dbg/BasicBlock.h @@ -13,6 +13,8 @@ enum BasicBlockFlags : uint BASIC_BLOCK_FLAG_INDIRPTR = (1 << 6), // This block ends with an indirect branch; pointer known BASIC_BLOCK_FLAG_PREINT3 = (1 << 7), // Block ends because there was an INT3 afterwards BASIC_BLOCK_FLAG_INT3 = (1 << 8), // Block is only a series of INT3 + BASIC_BLOCK_FLAG_CUTOFF = (1 << 9), // Ends prematurely because of another JMP to location + BASIC_BLOCK_FLAG_DELETE = (1 << 10), // Delete element at the next possible time }; struct BasicBlock @@ -32,6 +34,11 @@ struct BasicBlock Flags |= Flag; } + inline uint Size() + { + return VirtualEnd - VirtualStart; + } + bool operator< (const BasicBlock & b) const { return VirtualStart < b.VirtualStart; diff --git a/x64_dbg_dbg/LinearPass.cpp b/x64_dbg_dbg/LinearPass.cpp index 2be3f4ad..7b575f09 100644 --- a/x64_dbg_dbg/LinearPass.cpp +++ b/x64_dbg_dbg/LinearPass.cpp @@ -3,6 +3,7 @@ #include #include #include "console.h" +#include "function.h" LinearPass::LinearPass(uint VirtualStart, uint VirtualEnd, BBlockArray & MainBlocks) : AnalysisPass(VirtualStart, VirtualEnd, MainBlocks) @@ -24,6 +25,12 @@ bool LinearPass::Analyse() // THREAD_WORK = (TOTAL / # THREADS) uint workAmount = m_DataSize / IdealThreadCount(); + if(workAmount <= 0) + { + dprintf("Error: Total instruction data size is too small to analyse.\n"); + return false; + } + // Initialize thread vector auto threadBlocks = new std::vector[IdealThreadCount()]; @@ -32,14 +39,16 @@ bool LinearPass::Analyse() uint threadWorkStart = m_VirtualStart + (workAmount * i); uint threadWorkStop = min((threadWorkStart + workAmount), m_VirtualEnd); - // Allow a 16-byte variance of scanning because of - // integer rounding errors + // Allow a 256-byte variance of scanning because of + // integer rounding errors and instruction overlap if(threadWorkStart > m_VirtualStart) { - threadWorkStart -= 16; - threadWorkStop = min((threadWorkStop + 16), m_VirtualEnd); + threadWorkStart = max((threadWorkStart - 256), m_VirtualStart); + threadWorkStop = min((threadWorkStop + 256), m_VirtualEnd); } + dprintf("Boundaries: 0x%p 0x%p\n", threadWorkStart, threadWorkStop); + // Memory allocation optimization // TODO: Option to conserve memory threadBlocks[i].reserve(100000); @@ -59,24 +68,95 @@ bool LinearPass::Analyse() BBlockArray().swap(threadBlocks[i]); } + // Free memory ASAP + delete[] threadBlocks; + // Sort and remove duplicates std::sort(m_MainBlocks.begin(), m_MainBlocks.end()); m_MainBlocks.erase(std::unique(m_MainBlocks.begin(), m_MainBlocks.end()), m_MainBlocks.end()); - // Logging - dprintf("Total basic blocks: %d\n", m_MainBlocks.size()); - - delete[] threadBlocks; + // Run overlap analysis sub-pass + AnalyseOverlaps(); return true; } -void LinearPass::AnalysisWorker(uint Start, uint End, std::vector* Blocks) +void LinearPass::AnalyseOverlaps() +{ + // We don't care if only one thread was used + if(IdealThreadCount() <= 1) + return; + + // Goal of this function: + // + // Remove all overlapping + // basic blocks because of threads not ending or + // starting at absolutely defined points. + // (Example: one thread starts in the middle of + // an instruction) + // + // This also checks for basic block targets jumping into + // the middle of other basic blocks. + // + // THREAD_WORK = ceil(TOTAL / # THREADS) + uint workTotal = m_MainBlocks.size(); + uint workAmount = (workTotal + (IdealThreadCount() - 1)) / IdealThreadCount(); + + // Initialize thread vectors + auto threadInserts = new std::vector[IdealThreadCount()]; + + concurrency::parallel_for(uint(0), IdealThreadCount(), [&](uint i) + { + uint threadWorkStart = (workAmount * i); + uint threadWorkStop = min((threadWorkStart + workAmount), workTotal); + + // Again, allow an overlap of +/- 1 entry + if(threadWorkStart > 0) + { + threadWorkStart = max((threadWorkStart - 1), 0); + threadWorkStop = min((threadWorkStop + 1), workAmount); + } + + // Execute + AnalysisOverlapWorker(threadWorkStart, threadWorkStop, &threadInserts[i]); + }); + + // THREAD VECTOR + std::vector overlapInserts; + { + for(uint i = 0; i < IdealThreadCount(); i++) + std::move(threadInserts[i].begin(), threadInserts[i].end(), std::back_inserter(overlapInserts)); + + // Sort and remove duplicates + std::sort(overlapInserts.begin(), overlapInserts.end()); + overlapInserts.erase(std::unique(overlapInserts.begin(), overlapInserts.end()), overlapInserts.end()); + + delete[] threadInserts; + } + + // GLOBAL VECTOR + { + // Erase blocks marked for deletion + m_MainBlocks.erase(std::remove_if(m_MainBlocks.begin(), m_MainBlocks.end(), [](BasicBlock & Elem) + { + return Elem.GetFlag(BASIC_BLOCK_FLAG_DELETE); + })); + + // Insert + std::move(overlapInserts.begin(), overlapInserts.end(), std::back_inserter(m_MainBlocks)); + + // Final sort + std::sort(m_MainBlocks.begin(), m_MainBlocks.end()); + } +} + +void LinearPass::AnalysisWorker(uint Start, uint End, BBlockArray* Blocks) { Capstone disasm; - uint blockBegin = Start; // BBlock starting virtual address - uint blockEnd = End; // BBlock ending virtual address - bool blockPrevInt = false; // Indicator if the last instruction was INT + uint blockBegin = Start; // BBlock starting virtual address + uint blockEnd = End; // BBlock ending virtual address + bool blockPrevInt = false; // Indicator if the last instruction was INT + BasicBlock* lastBlock = nullptr;// Avoid an expensive call to std::vector::back() for(uint i = Start; i < End;) { @@ -107,7 +187,8 @@ void LinearPass::AnalysisWorker(uint Start, uint End, std::vector* B { // The next line terminates the BBlock before the INT instruction. // Early termination, faked as an indirect JMP. Rare case. - CreateBlockWorker(Blocks, blockBegin, realBlockEnd, false, false, false, false)->SetFlag(BASIC_BLOCK_FLAG_PREINT3); + lastBlock = CreateBlockWorker(Blocks, blockBegin, realBlockEnd, false, false, false, false); + lastBlock->SetFlag(BASIC_BLOCK_FLAG_PREINT3); blockBegin = realBlockEnd; } @@ -119,12 +200,12 @@ void LinearPass::AnalysisWorker(uint Start, uint End, std::vector* B if(intr && blockPrevInt) { // Append it to the previous block - Blocks->back().VirtualEnd = blockEnd; + lastBlock->VirtualEnd = blockEnd; } else { // Otherwise use the default route: create a new entry - auto block = CreateBlockWorker(Blocks, blockBegin, blockEnd, call, jmp, ret, intr); + auto block = lastBlock = CreateBlockWorker(Blocks, blockBegin, blockEnd, call, jmp, ret, intr); // Figure out the operand type auto operand = disasm.x86().operands[0]; @@ -142,7 +223,7 @@ void LinearPass::AnalysisWorker(uint Start, uint End, std::vector* B if(operand.type == X86_OP_MEM && operand.mem.base == X86_REG_INVALID && operand.mem.index == X86_REG_INVALID && - operand.mem.scale == 0) + operand.mem.scale == 1) { block->SetFlag(BASIC_BLOCK_FLAG_INDIRPTR); block->Target = operand.mem.disp; @@ -157,6 +238,73 @@ void LinearPass::AnalysisWorker(uint Start, uint End, std::vector* B } } +void LinearPass::AnalysisOverlapWorker(uint Start, uint End, BBlockArray* Insertions) +{ + // Comparison function to see if two blocks overlap + auto BlockOverlapsRemove = [](BasicBlock * A, BasicBlock * B) -> BasicBlock* + { + // Do the blocks overlap? + if(max(A->VirtualStart, B->VirtualStart) <= min((A->VirtualEnd - 1), (B->VirtualEnd - 1))) + { + // Return the block that should be removed + if(A->Size() > B->Size()) + return B; + + return A; + } + + return nullptr; + }; + + // Get a pointer to pure data + const auto blocks = m_MainBlocks.data(); + + for(uint i = Start; i < End - 1; i++) + { + const auto curr = &blocks[i]; + const auto next = &blocks[i + 1]; + + // Current versus next (overlap -> delete) + BasicBlock* removal = BlockOverlapsRemove(curr, next); + + if(removal) + removal->SetFlag(BASIC_BLOCK_FLAG_DELETE); + + // Find blocks that need to be split in two because + // of CALL/JMP targets + // + // Find targets in the virtual range + if(ValidateAddress(curr->Target)) + { + removal = FindBBlockInRange(curr->Target); + + // If the target does not equal the block start... + if(removal && curr->Target != removal->VirtualStart) + { + // Mark for deletion + removal->SetFlag(BASIC_BLOCK_FLAG_DELETE); + + // Block part 1 + BasicBlock block1; + block1.VirtualStart = removal->VirtualStart; + block1.VirtualEnd = curr->Target; + block1.Target = 0; + block1.Flags = BASIC_BLOCK_FLAG_CUTOFF; + + // Block part 2 + BasicBlock block2; + block2.VirtualStart = curr->Target; + block2.VirtualEnd = removal->VirtualEnd; + block2.Target = removal->Target; + block2.Flags = removal->Flags; + + Insertions->push_back(block1); + Insertions->push_back(block2); + } + } + } +} + BasicBlock* LinearPass::CreateBlockWorker(std::vector* Blocks, uint Start, uint End, bool Call, bool Jmp, bool Ret, bool Intr) { BasicBlock block; @@ -179,4 +327,42 @@ BasicBlock* LinearPass::CreateBlockWorker(std::vector* Blocks, uint Blocks->push_back(block); return &Blocks->back(); +} + +BasicBlock* LinearPass::FindBBlockInRange(uint Address) +{ + // NOTE: This function assumes that the main block + // vector is sorted + // + // Use a binary search + uint indexLo = 0; + uint indexHi = m_MainBlocks.size(); + + // Get a pointer to pure data + const auto blocks = m_MainBlocks.data(); + + while(indexHi > indexLo) + { + uint indexMid = (indexLo + indexHi) / 2; + auto entry = &blocks[indexMid]; + + if(Address < entry->VirtualStart) + { + // Continue search in lower half + indexHi = indexMid; + } + else if(Address >= entry->VirtualEnd) + { + // Continue search in upper half + indexLo = indexMid + 1; + } + else + { + // Address is within limits, return entry + return entry; + } + } + + // Not found + return nullptr; } \ No newline at end of file diff --git a/x64_dbg_dbg/LinearPass.h b/x64_dbg_dbg/LinearPass.h index f2ea749f..befc60fd 100644 --- a/x64_dbg_dbg/LinearPass.h +++ b/x64_dbg_dbg/LinearPass.h @@ -1,6 +1,5 @@ #pragma once -#include #include "AnalysisPass.h" #include "BasicBlock.h" #include "capstone_wrapper.h" @@ -13,8 +12,11 @@ public: virtual const char* GetName() override; virtual bool Analyse() override; + void AnalyseOverlaps(); private: - void AnalysisWorker(uint Start, uint End, std::vector* Blocks); - BasicBlock* CreateBlockWorker(std::vector* Blocks, uint Start, uint End, bool Call, bool Jmp, bool Ret, bool Intr); + void AnalysisWorker(uint Start, uint End, BBlockArray* Blocks); + void AnalysisOverlapWorker(uint Start, uint End, BBlockArray* Insertions); + BasicBlock* CreateBlockWorker(BBlockArray* Blocks, uint Start, uint End, bool Call, bool Jmp, bool Ret, bool Intr); + BasicBlock* FindBBlockInRange(uint Address); }; \ No newline at end of file From 6e7aa67fa45572fd699bf88ee3f1693fc348b69f Mon Sep 17 00:00:00 2001 From: Nukem Date: Sat, 4 Jul 2015 01:12:13 -0400 Subject: [PATCH 21/43] DBG: The compiler doesn't listen very well --- x64_dbg_dbg/BasicBlock.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/x64_dbg_dbg/BasicBlock.h b/x64_dbg_dbg/BasicBlock.h index bd4f3528..30860650 100644 --- a/x64_dbg_dbg/BasicBlock.h +++ b/x64_dbg_dbg/BasicBlock.h @@ -24,17 +24,17 @@ struct BasicBlock uint Flags; uint Target; - inline bool GetFlag(uint Flag) + __forceinline bool GetFlag(uint Flag) { return (Flags & Flag) == Flag; } - inline void SetFlag(uint Flag) + __forceinline void SetFlag(uint Flag) { Flags |= Flag; } - inline uint Size() + __forceinline uint Size() { return VirtualEnd - VirtualStart; } From ab4f5a893cf049520af84d8a3d1539aba8069100 Mon Sep 17 00:00:00 2001 From: Nukem Date: Sat, 4 Jul 2015 01:25:16 -0400 Subject: [PATCH 22/43] DBG: Function still needs to run, even with 1 thread (jump targets) --- x64_dbg_dbg/LinearPass.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/x64_dbg_dbg/LinearPass.cpp b/x64_dbg_dbg/LinearPass.cpp index 7b575f09..f9f907ce 100644 --- a/x64_dbg_dbg/LinearPass.cpp +++ b/x64_dbg_dbg/LinearPass.cpp @@ -82,10 +82,6 @@ bool LinearPass::Analyse() void LinearPass::AnalyseOverlaps() { - // We don't care if only one thread was used - if(IdealThreadCount() <= 1) - return; - // Goal of this function: // // Remove all overlapping From a80e03988dbb32637152b63647bc620a900e20ac Mon Sep 17 00:00:00 2001 From: Nukem Date: Sat, 4 Jul 2015 01:40:40 -0400 Subject: [PATCH 23/43] DBG: Fix unneeded -1 in for loop --- x64_dbg_dbg/FunctionPass.cpp | 2 -- x64_dbg_dbg/LinearPass.cpp | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/x64_dbg_dbg/FunctionPass.cpp b/x64_dbg_dbg/FunctionPass.cpp index 62106799..bc6fb238 100644 --- a/x64_dbg_dbg/FunctionPass.cpp +++ b/x64_dbg_dbg/FunctionPass.cpp @@ -54,8 +54,6 @@ FunctionPass::FunctionPass(uint VirtualStart, uint VirtualEnd, BBlockArray & Mai } } } - - dprintf("Function info: 0x%p - 0x%p\n", m_FunctionInfo, m_FunctionInfoSize); } FunctionPass::~FunctionPass() diff --git a/x64_dbg_dbg/LinearPass.cpp b/x64_dbg_dbg/LinearPass.cpp index f9f907ce..245d36bd 100644 --- a/x64_dbg_dbg/LinearPass.cpp +++ b/x64_dbg_dbg/LinearPass.cpp @@ -255,7 +255,7 @@ void LinearPass::AnalysisOverlapWorker(uint Start, uint End, BBlockArray* Insert // Get a pointer to pure data const auto blocks = m_MainBlocks.data(); - for(uint i = Start; i < End - 1; i++) + for(uint i = Start; i < End; i++) { const auto curr = &blocks[i]; const auto next = &blocks[i + 1]; From 74a22ca503529daaef0229d820b7391a4623a2e2 Mon Sep 17 00:00:00 2001 From: Nukem Date: Sun, 5 Jul 2015 01:15:46 -0400 Subject: [PATCH 24/43] DBG: Use a single thread in LinearPass if the supplied data set is too small --- x64_dbg_dbg/AnalysisPass.cpp | 5 +++++ x64_dbg_dbg/AnalysisPass.h | 1 + x64_dbg_dbg/LinearPass.cpp | 14 ++++++-------- x64_dbg_dbg/memory.cpp | 2 +- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/x64_dbg_dbg/AnalysisPass.cpp b/x64_dbg_dbg/AnalysisPass.cpp index 228dba18..db42a990 100644 --- a/x64_dbg_dbg/AnalysisPass.cpp +++ b/x64_dbg_dbg/AnalysisPass.cpp @@ -68,4 +68,9 @@ uint AnalysisPass::IdealThreadCount() } return m_InternalMaxThreads; +} + +void AnalysisPass::SetIdealThreadCount(uint Count) +{ + m_InternalMaxThreads = (BYTE)min(Count, 255); } \ No newline at end of file diff --git a/x64_dbg_dbg/AnalysisPass.h b/x64_dbg_dbg/AnalysisPass.h index 2f36dde3..57425c19 100644 --- a/x64_dbg_dbg/AnalysisPass.h +++ b/x64_dbg_dbg/AnalysisPass.h @@ -37,6 +37,7 @@ protected: void AcquireExclusiveLock(); void ReleaseExclusiveLock(); uint IdealThreadCount(); + void SetIdealThreadCount(uint Count); private: SRWLOCK m_InternalLock; diff --git a/x64_dbg_dbg/LinearPass.cpp b/x64_dbg_dbg/LinearPass.cpp index 245d36bd..7278b6cc 100644 --- a/x64_dbg_dbg/LinearPass.cpp +++ b/x64_dbg_dbg/LinearPass.cpp @@ -8,6 +8,12 @@ LinearPass::LinearPass(uint VirtualStart, uint VirtualEnd, BBlockArray & MainBlocks) : AnalysisPass(VirtualStart, VirtualEnd, MainBlocks) { + // This is a fix for when the total data analysis size is less + // than what parallelization can support. The minimum size requirement + // is ((# THREADS) * (512)) bytes. If the requirement isn't met, + // scale to use a single thread. + if((512 * IdealThreadCount()) >= m_DataSize) + SetIdealThreadCount(1); } LinearPass::~LinearPass() @@ -25,12 +31,6 @@ bool LinearPass::Analyse() // THREAD_WORK = (TOTAL / # THREADS) uint workAmount = m_DataSize / IdealThreadCount(); - if(workAmount <= 0) - { - dprintf("Error: Total instruction data size is too small to analyse.\n"); - return false; - } - // Initialize thread vector auto threadBlocks = new std::vector[IdealThreadCount()]; @@ -47,8 +47,6 @@ bool LinearPass::Analyse() threadWorkStop = min((threadWorkStop + 256), m_VirtualEnd); } - dprintf("Boundaries: 0x%p 0x%p\n", threadWorkStart, threadWorkStop); - // Memory allocation optimization // TODO: Option to conserve memory threadBlocks[i].reserve(100000); diff --git a/x64_dbg_dbg/memory.cpp b/x64_dbg_dbg/memory.cpp index 879f4f35..6db4e5cd 100644 --- a/x64_dbg_dbg/memory.cpp +++ b/x64_dbg_dbg/memory.cpp @@ -304,7 +304,7 @@ bool MemIsCanonicalAddress(uint Address) // 0xFFFF800000000000 = Significant 16 bits set // 0x0000800000000000 = 48th bit set return (((Address & 0xFFFF800000000000) + 0x800000000000) & ~0x800000000000) == 0; -#endif // _WIN64 +#endif // ndef _WIN64 } void* MemAllocRemote(uint Address, SIZE_T Size, DWORD Protect) From d379a5a13338bf04ec34c63b4fd3fa8d55ceb05c Mon Sep 17 00:00:00 2001 From: Nukem Date: Sun, 5 Jul 2015 01:16:52 -0400 Subject: [PATCH 25/43] DBG: Typo --- x64_dbg_dbg/LinearPass.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x64_dbg_dbg/LinearPass.cpp b/x64_dbg_dbg/LinearPass.cpp index 7278b6cc..fad49132 100644 --- a/x64_dbg_dbg/LinearPass.cpp +++ b/x64_dbg_dbg/LinearPass.cpp @@ -107,7 +107,7 @@ void LinearPass::AnalyseOverlaps() if(threadWorkStart > 0) { threadWorkStart = max((threadWorkStart - 1), 0); - threadWorkStop = min((threadWorkStop + 1), workAmount); + threadWorkStop = min((threadWorkStop + 1), workTotal); } // Execute From b4b4fa04856f0643f2fa810dab48e3360e1e0905 Mon Sep 17 00:00:00 2001 From: Nukem Date: Thu, 9 Jul 2015 02:57:49 -0400 Subject: [PATCH 26/43] DBG: Start resolving function ends --- x64_dbg_dbg/AnalysisPass.cpp | 39 +++++++++++++++++++++- x64_dbg_dbg/AnalysisPass.h | 1 + x64_dbg_dbg/FunctionPass.cpp | 63 +++++++++++++++++++++++++++++++++--- x64_dbg_dbg/LinearPass.cpp | 38 ---------------------- x64_dbg_dbg/LinearPass.h | 1 - 5 files changed, 98 insertions(+), 44 deletions(-) diff --git a/x64_dbg_dbg/AnalysisPass.cpp b/x64_dbg_dbg/AnalysisPass.cpp index db42a990..0620f7ef 100644 --- a/x64_dbg_dbg/AnalysisPass.cpp +++ b/x64_dbg_dbg/AnalysisPass.cpp @@ -33,6 +33,43 @@ AnalysisPass::~AnalysisPass() BridgeFree(m_Data); } +BasicBlock* AnalysisPass::FindBBlockInRange(uint Address) +{ + // NOTE: __MUST__ BE A SORTED VECTOR + // + // Use a binary search + uint indexLo = 0; + uint indexHi = m_MainBlocks.size(); + + // Get a pointer to pure data + const auto blocks = m_MainBlocks.data(); + + while(indexHi > indexLo) + { + uint indexMid = (indexLo + indexHi) / 2; + auto entry = &blocks[indexMid]; + + if(Address < entry->VirtualStart) + { + // Continue search in lower half + indexHi = indexMid; + } + else if(Address >= entry->VirtualEnd) + { + // Continue search in upper half + indexLo = indexMid + 1; + } + else + { + // Address is within limits, return entry + return entry; + } + } + + // Not found + return nullptr; +} + void AnalysisPass::AcquireReadLock() { AcquireSRWLockShared(&m_InternalLock); @@ -64,7 +101,7 @@ uint AnalysisPass::IdealThreadCount() if(maximumThreads > 1) maximumThreads -= 1; - m_InternalMaxThreads = (BYTE)min(maximumThreads, 255); + SetIdealThreadCount(maximumThreads); } return m_InternalMaxThreads; diff --git a/x64_dbg_dbg/AnalysisPass.h b/x64_dbg_dbg/AnalysisPass.h index 57425c19..19aa880a 100644 --- a/x64_dbg_dbg/AnalysisPass.h +++ b/x64_dbg_dbg/AnalysisPass.h @@ -32,6 +32,7 @@ protected: return (Address >= m_VirtualStart && Address < m_VirtualEnd); } + BasicBlock* FindBBlockInRange(uint Address); void AcquireReadLock(); void ReleaseReadLock(); void AcquireExclusiveLock(); diff --git a/x64_dbg_dbg/FunctionPass.cpp b/x64_dbg_dbg/FunctionPass.cpp index bc6fb238..2d19a4e1 100644 --- a/x64_dbg_dbg/FunctionPass.cpp +++ b/x64_dbg_dbg/FunctionPass.cpp @@ -5,6 +5,7 @@ #include "console.h" #include "debugger.h" #include "module.h" +#include "function.h" FunctionPass::FunctionPass(uint VirtualStart, uint VirtualEnd, BBlockArray & MainBlocks) : AnalysisPass(VirtualStart, VirtualEnd, MainBlocks) @@ -88,6 +89,23 @@ bool FunctionPass::Analyse() AnalysisWorker(threadWorkStart, threadWorkStop, &threadFunctions[i]); }); + std::vector funcs; + + // Merge thread vectors into single local + for(uint i = 0; i < IdealThreadCount(); i++) + std::move(threadFunctions[i].begin(), threadFunctions[i].end(), std::back_inserter(funcs)); + + // Sort and remove duplicates + std::sort(funcs.begin(), funcs.end()); + funcs.erase(std::unique(funcs.begin(), funcs.end()), funcs.end()); + + FunctionClear(); + for(auto & func : funcs) + { + FunctionAdd(func.VirtualStart, func.VirtualEnd - 1, true); + } + GuiUpdateAllViews(); + delete[] threadFunctions; return true; } @@ -177,6 +195,44 @@ void FunctionPass::FindFunctionWorkerPrepass(uint Start, uint End, std::vector* Blocks) { + // Helper to link final blocks to function + auto ResolveKnownFunctionEnd = [this](FunctionDef * Function) + { + auto startBlock = FindBBlockInRange(Function->VirtualStart); + auto endBlock = FindBBlockInRange(Function->VirtualEnd); + + if(!startBlock || !endBlock) + return false; + + // Debug + //assert(startBlock->VirtualStart == Function->VirtualStart); + //assert(endBlock->VirtualEnd == Function->VirtualEnd); + + // Calculate indexes from pointer arithmetic + Function->BBlockStart = ((uint)startBlock - (uint)m_MainBlocks.data()) / sizeof(BasicBlock); + Function->BBlockEnd = ((uint)endBlock - (uint)m_MainBlocks.data()) / sizeof(BasicBlock); + + // Set the flag for blocks that have been scanned + for(uint i = Function->BBlockStart; i < Function->BBlockEnd; i++) + m_MainBlocks[i].SetFlag(BASIC_BLOCK_FLAG_FUNCTION); + + return true; + }; + + // Enumerate all function entries for this thread + for(auto & block : *Blocks) + { + // Sometimes the ending address is already supplied, so + // check first + if(block.VirtualEnd != 0) + { + if(ResolveKnownFunctionEnd(&block)) + continue; + } + + // else + // ... + } } void FunctionPass::EnumerateFunctionRuntimeEntries64(std::function Callback) @@ -184,12 +240,11 @@ void FunctionPass::EnumerateFunctionRuntimeEntries64(std::function* Blocks, uint Blocks->push_back(block); return &Blocks->back(); -} - -BasicBlock* LinearPass::FindBBlockInRange(uint Address) -{ - // NOTE: This function assumes that the main block - // vector is sorted - // - // Use a binary search - uint indexLo = 0; - uint indexHi = m_MainBlocks.size(); - - // Get a pointer to pure data - const auto blocks = m_MainBlocks.data(); - - while(indexHi > indexLo) - { - uint indexMid = (indexLo + indexHi) / 2; - auto entry = &blocks[indexMid]; - - if(Address < entry->VirtualStart) - { - // Continue search in lower half - indexHi = indexMid; - } - else if(Address >= entry->VirtualEnd) - { - // Continue search in upper half - indexLo = indexMid + 1; - } - else - { - // Address is within limits, return entry - return entry; - } - } - - // Not found - return nullptr; } \ No newline at end of file diff --git a/x64_dbg_dbg/LinearPass.h b/x64_dbg_dbg/LinearPass.h index befc60fd..439ce91f 100644 --- a/x64_dbg_dbg/LinearPass.h +++ b/x64_dbg_dbg/LinearPass.h @@ -18,5 +18,4 @@ private: void AnalysisWorker(uint Start, uint End, BBlockArray* Blocks); void AnalysisOverlapWorker(uint Start, uint End, BBlockArray* Insertions); BasicBlock* CreateBlockWorker(BBlockArray* Blocks, uint Start, uint End, bool Call, bool Jmp, bool Ret, bool Intr); - BasicBlock* FindBBlockInRange(uint Address); }; \ No newline at end of file From 9aa2a0cf7c1af6572d94d9c306a15bc7831a132e Mon Sep 17 00:00:00 2001 From: Nukem Date: Thu, 9 Jul 2015 21:08:53 -0400 Subject: [PATCH 27/43] DBG: FindBBlockIndex function --- x64_dbg_dbg/AnalysisPass.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/x64_dbg_dbg/AnalysisPass.cpp b/x64_dbg_dbg/AnalysisPass.cpp index 0620f7ef..ed3991ce 100644 --- a/x64_dbg_dbg/AnalysisPass.cpp +++ b/x64_dbg_dbg/AnalysisPass.cpp @@ -1,7 +1,6 @@ #include #include #include "AnalysisPass.h" -#include "capstone_wrapper.h" #include "memory.h" AnalysisPass::AnalysisPass(uint VirtualStart, uint VirtualEnd, BBlockArray & MainBlocks) : m_MainBlocks(MainBlocks) @@ -70,6 +69,12 @@ BasicBlock* AnalysisPass::FindBBlockInRange(uint Address) return nullptr; } +uint AnalysisPass::FindBBlockIndex(BasicBlock* Block) +{ + // Fast pointer arithmetic to find index + return ((uint)Block - (uint)m_MainBlocks.data()) / sizeof(BasicBlock); +} + void AnalysisPass::AcquireReadLock() { AcquireSRWLockShared(&m_InternalLock); From d74f6478da1b4c9bfe871af6dbc5d975e1ccd89e Mon Sep 17 00:00:00 2001 From: Nukem Date: Thu, 9 Jul 2015 21:09:52 -0400 Subject: [PATCH 28/43] DBG: Small fixes from merge --- x64_dbg_dbg/AnalysisPass.h | 1 + x64_dbg_dbg/Int3CoagulatorPass.cpp | 1 + x64_dbg_dbg/Int3CoagulatorPass.h | 5 +---- x64_dbg_dbg/LinearPass.cpp | 7 +++---- x64_dbg_dbg/LinearPass.h | 1 - x64_dbg_dbg/functionanalysis.cpp | 14 +++++++++++++- 6 files changed, 19 insertions(+), 10 deletions(-) diff --git a/x64_dbg_dbg/AnalysisPass.h b/x64_dbg_dbg/AnalysisPass.h index 19aa880a..4049df7d 100644 --- a/x64_dbg_dbg/AnalysisPass.h +++ b/x64_dbg_dbg/AnalysisPass.h @@ -33,6 +33,7 @@ protected: } BasicBlock* FindBBlockInRange(uint Address); + uint FindBBlockIndex(BasicBlock* Block); void AcquireReadLock(); void ReleaseReadLock(); void AcquireExclusiveLock(); diff --git a/x64_dbg_dbg/Int3CoagulatorPass.cpp b/x64_dbg_dbg/Int3CoagulatorPass.cpp index bac0b665..fe851c75 100644 --- a/x64_dbg_dbg/Int3CoagulatorPass.cpp +++ b/x64_dbg_dbg/Int3CoagulatorPass.cpp @@ -1,3 +1,4 @@ +#include #include "AnalysisPass.h" #include "Int3CoagulatorPass.h" #include "console.h" diff --git a/x64_dbg_dbg/Int3CoagulatorPass.h b/x64_dbg_dbg/Int3CoagulatorPass.h index 9d781961..d9645089 100644 --- a/x64_dbg_dbg/Int3CoagulatorPass.h +++ b/x64_dbg_dbg/Int3CoagulatorPass.h @@ -1,8 +1,5 @@ #pragma once -#include -#include - #include "AnalysisPass.h" #include "BasicBlock.h" @@ -16,5 +13,5 @@ public: virtual bool Analyse() override; private: - void AnalysisWorker(uint Start, uint End, std::vector* Blocks); + void AnalysisWorker(uint Start, uint End, BBlockArray* Blocks); }; \ No newline at end of file diff --git a/x64_dbg_dbg/LinearPass.cpp b/x64_dbg_dbg/LinearPass.cpp index 653facd6..837b3c32 100644 --- a/x64_dbg_dbg/LinearPass.cpp +++ b/x64_dbg_dbg/LinearPass.cpp @@ -1,9 +1,8 @@ -#include "AnalysisPass.h" -#include "LinearPass.h" #include #include -#include "console.h" -#include "function.h" +#include "AnalysisPass.h" +#include "LinearPass.h" +#include "capstone_wrapper.h" LinearPass::LinearPass(uint VirtualStart, uint VirtualEnd, BBlockArray & MainBlocks) : AnalysisPass(VirtualStart, VirtualEnd, MainBlocks) diff --git a/x64_dbg_dbg/LinearPass.h b/x64_dbg_dbg/LinearPass.h index 439ce91f..fcf992e7 100644 --- a/x64_dbg_dbg/LinearPass.h +++ b/x64_dbg_dbg/LinearPass.h @@ -2,7 +2,6 @@ #include "AnalysisPass.h" #include "BasicBlock.h" -#include "capstone_wrapper.h" class LinearPass : public AnalysisPass { diff --git a/x64_dbg_dbg/functionanalysis.cpp b/x64_dbg_dbg/functionanalysis.cpp index d3c0ec1b..ce405fc7 100644 --- a/x64_dbg_dbg/functionanalysis.cpp +++ b/x64_dbg_dbg/functionanalysis.cpp @@ -3,6 +3,11 @@ #include "memory.h" #include "function.h" +#include "AnalysisPass.h" +#include "BasicBlock.h" +#include "FunctionPass.h" +#include "LinearPass.h" + FunctionAnalysis::FunctionAnalysis(uint base, uint size) : Analysis(base, size) { } @@ -12,10 +17,17 @@ void FunctionAnalysis::Analyse() dputs("Starting analysis..."); DWORD ticks = GetTickCount(); + BBlockArray blocks; + LinearPass* pass1 = new LinearPass(_base, _base + _size, blocks); + pass1->Analyse(); + + FunctionPass* pass2 = new FunctionPass(_base, _base + _size, blocks); + pass2->Analyse(); + /* PopulateReferences(); dprintf("%u called functions populated\n", _functions.size()); AnalyseFunctions(); - + */ dprintf("Analysis finished in %ums!\n", GetTickCount() - ticks); } From a04cded464e82ae07230a1b9226a4e8362918bb7 Mon Sep 17 00:00:00 2001 From: Nukem Date: Thu, 9 Jul 2015 21:10:47 -0400 Subject: [PATCH 29/43] DBG: Start code for function end heuristic --- x64_dbg_dbg/FunctionPass.cpp | 94 +++++++++++++++++++++++++++++++----- 1 file changed, 82 insertions(+), 12 deletions(-) diff --git a/x64_dbg_dbg/FunctionPass.cpp b/x64_dbg_dbg/FunctionPass.cpp index 2d19a4e1..6485da97 100644 --- a/x64_dbg_dbg/FunctionPass.cpp +++ b/x64_dbg_dbg/FunctionPass.cpp @@ -1,5 +1,4 @@ #include "FunctionPass.h" -#include "capstone_wrapper.h" #include #include "memory.h" #include "console.h" @@ -113,7 +112,7 @@ bool FunctionPass::Analyse() void FunctionPass::AnalysisWorker(uint Start, uint End, std::vector* Blocks) { // Step 1: Use any defined functions in the PE function table - FindFunctionWorkerPrepass(Start, End, Blocks); + //FindFunctionWorkerPrepass(Start, End, Blocks); // Step 2: for each block that contains a CALL flag, // add it to a local function start array @@ -147,7 +146,7 @@ void FunctionPass::AnalysisWorker(uint Start, uint End, std::vector FunctionDef def; def.VirtualStart = destination; - def.VirtualEnd = destination; + def.VirtualEnd = 0; def.BBlockStart = 0; def.BBlockEnd = 0; Blocks->push_back(def); @@ -204,13 +203,9 @@ void FunctionPass::FindFunctionWorker(std::vector* Blocks) if(!startBlock || !endBlock) return false; - // Debug - //assert(startBlock->VirtualStart == Function->VirtualStart); - //assert(endBlock->VirtualEnd == Function->VirtualEnd); - - // Calculate indexes from pointer arithmetic - Function->BBlockStart = ((uint)startBlock - (uint)m_MainBlocks.data()) / sizeof(BasicBlock); - Function->BBlockEnd = ((uint)endBlock - (uint)m_MainBlocks.data()) / sizeof(BasicBlock); + // Find block start/end indices + Function->BBlockStart = FindBBlockIndex(startBlock); + Function->BBlockEnd = FindBBlockIndex(endBlock); // Set the flag for blocks that have been scanned for(uint i = Function->BBlockStart; i < Function->BBlockEnd; i++) @@ -219,6 +214,81 @@ void FunctionPass::FindFunctionWorker(std::vector* Blocks) return true; }; + // Find the end manually + auto ResolveFunctionEnd = [this](FunctionDef * Function, BasicBlock * LastBlock) + { + assert(Function->VirtualStart != 0); + Function->VirtualStart = 0x00007FF83B4315D0; + // Find the first basic block of the function + BasicBlock* block = FindBBlockInRange(Function->VirtualStart); + + if(!block) + { + assert(false); + return false; + } + + // The maximum address is determined by any jump that extends past + // a RET or other terminating basic block. A function may have multiple + // return statements. + uint maximumAddr = 0; + + // Loop forever until the end is found + for(; (uint)block <= (uint)LastBlock; block++) + { + // Calculate max from just linear instructions + maximumAddr = max(maximumAddr, block->VirtualEnd); + + // Each block has the potential to increase the + // maximum function end address. + if(!block->GetFlag(BASIC_BLOCK_FLAG_CALL) && !block->GetFlag(BASIC_BLOCK_FLAG_INDIRECT)) + { + // Here's a problem: Compilers add tail-call elimination with a jump. + // Solve this by creating a maximum jump limit: +/- 128 bytes from the end. + if(abs((__int64)(block->VirtualEnd - block->Target)) <= 128) + maximumAddr = max(maximumAddr, block->Target); + } + + // Does this node contain the maximum address? + if(block->VirtualStart > maximumAddr) + __debugbreak(); + + if(maximumAddr >= block->VirtualStart && maximumAddr <= block->VirtualEnd) + { + // It does! But does it end with a return statement? + if(block->GetFlag(BASIC_BLOCK_FLAG_RET)) + { +__test: + Function->VirtualEnd = block->VirtualEnd; + Function->BBlockEnd = FindBBlockIndex(block); + break; + } + else + { + // It doesn't end with a return. There's 2 possibilities: + // tail-call elimination or an optimized loop. + if(abs((__int64)(block->VirtualEnd - block->Target)) > 128) + { + dprintf("Test: 0x%p\n", block->VirtualEnd); + } + + goto __test; + } + } + } + + dprintf("test - 0x%p 0x%p\n", Function->VirtualStart, Function->VirtualEnd); + + // Set the flag for blocks that have been scanned + for(uint i = Function->BBlockStart; i < Function->BBlockEnd; i++) + m_MainBlocks[i].SetFlag(BASIC_BLOCK_FLAG_FUNCTION); + + return true; + }; + + // Cached final block + BasicBlock* finalBlock = &m_MainBlocks.back(); + // Enumerate all function entries for this thread for(auto & block : *Blocks) { @@ -230,8 +300,8 @@ void FunctionPass::FindFunctionWorker(std::vector* Blocks) continue; } - // else - // ... + // Now the function end must be determined by heuristics + ResolveFunctionEnd(&block, finalBlock); } } From 14c885dff49613aaaccf8412504ca557738dd7a7 Mon Sep 17 00:00:00 2001 From: Nukem Date: Thu, 9 Jul 2015 21:16:23 -0400 Subject: [PATCH 30/43] DBG: BasicBlock: Switch flags from INT3 to PADDING in terms of instructions --- x64_dbg_dbg/BasicBlock.h | 4 ++-- x64_dbg_dbg/Int3CoagulatorPass.cpp | 4 ++-- x64_dbg_dbg/LinearPass.cpp | 24 ++++++++++++------------ x64_dbg_dbg/LinearPass.h | 2 +- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/x64_dbg_dbg/BasicBlock.h b/x64_dbg_dbg/BasicBlock.h index 30860650..1aeed604 100644 --- a/x64_dbg_dbg/BasicBlock.h +++ b/x64_dbg_dbg/BasicBlock.h @@ -11,8 +11,8 @@ enum BasicBlockFlags : uint BASIC_BLOCK_FLAG_RET = (1 << 4), // The block ends with a retn BASIC_BLOCK_FLAG_INDIRECT = (1 << 5), // This block ends with an indirect branch BASIC_BLOCK_FLAG_INDIRPTR = (1 << 6), // This block ends with an indirect branch; pointer known - BASIC_BLOCK_FLAG_PREINT3 = (1 << 7), // Block ends because there was an INT3 afterwards - BASIC_BLOCK_FLAG_INT3 = (1 << 8), // Block is only a series of INT3 + BASIC_BLOCK_FLAG_PREPAD = (1 << 7), // Block ends because there was padding afterwards + BASIC_BLOCK_FLAG_PAD = (1 << 8), // Block is only a series of padding instructions BASIC_BLOCK_FLAG_CUTOFF = (1 << 9), // Ends prematurely because of another JMP to location BASIC_BLOCK_FLAG_DELETE = (1 << 10), // Delete element at the next possible time }; diff --git a/x64_dbg_dbg/Int3CoagulatorPass.cpp b/x64_dbg_dbg/Int3CoagulatorPass.cpp index fe851c75..b5804c6d 100644 --- a/x64_dbg_dbg/Int3CoagulatorPass.cpp +++ b/x64_dbg_dbg/Int3CoagulatorPass.cpp @@ -39,7 +39,7 @@ void Int3CoagulatorPass::AnalysisWorker(uint Start, uint End, std::vectorbegin(); counterIndex < End; itr++, counterIndex++) { - if(!itr->GetFlag(BASIC_BLOCK_FLAG_INT3)) + if(!itr->GetFlag(BASIC_BLOCK_FLAG_PAD)) { // Synchronize the vector if more than 1 instruction // is present. (Combine) @@ -52,7 +52,7 @@ void Int3CoagulatorPass::AnalysisWorker(uint Start, uint End, std::vectorinsert(itr, block); diff --git a/x64_dbg_dbg/LinearPass.cpp b/x64_dbg_dbg/LinearPass.cpp index 837b3c32..f8947293 100644 --- a/x64_dbg_dbg/LinearPass.cpp +++ b/x64_dbg_dbg/LinearPass.cpp @@ -148,7 +148,7 @@ void LinearPass::AnalysisWorker(uint Start, uint End, BBlockArray* Blocks) uint blockBegin = Start; // BBlock starting virtual address uint blockEnd = End; // BBlock ending virtual address - bool blockPrevInt = false; // Indicator if the last instruction was INT + bool blockPrevPad = false; // Indicator if the last instruction was padding BasicBlock* lastBlock = nullptr;// Avoid an expensive call to std::vector::back() for(uint i = Start; i < End;) @@ -168,9 +168,9 @@ void LinearPass::AnalysisWorker(uint Start, uint End, BBlockArray* Blocks) bool call = disasm.InGroup(CS_GRP_CALL); // CALL bool jmp = disasm.InGroup(CS_GRP_JUMP); // JUMP bool ret = disasm.InGroup(CS_GRP_RET); // RETURN - bool intr = disasm.InGroup(CS_GRP_INT); // INTERRUPT + bool padding = disasm.IsFilling(); // INSTRUCTION PADDING - if(intr) + if(padding) { // INT3s are treated differently. They are all created as their // own separate block for more analysis later. @@ -181,16 +181,16 @@ void LinearPass::AnalysisWorker(uint Start, uint End, BBlockArray* Blocks) // The next line terminates the BBlock before the INT instruction. // Early termination, faked as an indirect JMP. Rare case. lastBlock = CreateBlockWorker(Blocks, blockBegin, realBlockEnd, false, false, false, false); - lastBlock->SetFlag(BASIC_BLOCK_FLAG_PREINT3); + lastBlock->SetFlag(BASIC_BLOCK_FLAG_PREPAD); blockBegin = realBlockEnd; } } - if(call || jmp || ret || intr) + if(call || jmp || ret || padding) { - // Was this an INT3? - if(intr && blockPrevInt) + // Was this a padding instruction? + if(padding && blockPrevPad) { // Append it to the previous block lastBlock->VirtualEnd = blockEnd; @@ -198,7 +198,7 @@ void LinearPass::AnalysisWorker(uint Start, uint End, BBlockArray* Blocks) else { // Otherwise use the default route: create a new entry - auto block = lastBlock = CreateBlockWorker(Blocks, blockBegin, blockEnd, call, jmp, ret, intr); + auto block = lastBlock = CreateBlockWorker(Blocks, blockBegin, blockEnd, call, jmp, ret, padding); // Figure out the operand type auto operand = disasm.x86().operands[0]; @@ -226,7 +226,7 @@ void LinearPass::AnalysisWorker(uint Start, uint End, BBlockArray* Blocks) // Reset the loop variables blockBegin = i; - blockPrevInt = intr; + blockPrevPad = padding; } } } @@ -298,7 +298,7 @@ void LinearPass::AnalysisOverlapWorker(uint Start, uint End, BBlockArray* Insert } } -BasicBlock* LinearPass::CreateBlockWorker(std::vector* Blocks, uint Start, uint End, bool Call, bool Jmp, bool Ret, bool Intr) +BasicBlock* LinearPass::CreateBlockWorker(std::vector* Blocks, uint Start, uint End, bool Call, bool Jmp, bool Ret, bool Pad) { BasicBlock block; block.VirtualStart = Start; @@ -315,8 +315,8 @@ BasicBlock* LinearPass::CreateBlockWorker(std::vector* Blocks, uint block.SetFlag(BASIC_BLOCK_FLAG_RET); // Check for interrupts - if(Intr) - block.SetFlag(BASIC_BLOCK_FLAG_INT3); + if(Pad) + block.SetFlag(BASIC_BLOCK_FLAG_PAD); Blocks->push_back(block); return &Blocks->back(); diff --git a/x64_dbg_dbg/LinearPass.h b/x64_dbg_dbg/LinearPass.h index fcf992e7..9b15c35a 100644 --- a/x64_dbg_dbg/LinearPass.h +++ b/x64_dbg_dbg/LinearPass.h @@ -16,5 +16,5 @@ public: private: void AnalysisWorker(uint Start, uint End, BBlockArray* Blocks); void AnalysisOverlapWorker(uint Start, uint End, BBlockArray* Insertions); - BasicBlock* CreateBlockWorker(BBlockArray* Blocks, uint Start, uint End, bool Call, bool Jmp, bool Ret, bool Intr); + BasicBlock* CreateBlockWorker(BBlockArray* Blocks, uint Start, uint End, bool Call, bool Jmp, bool Ret, bool Pad); }; \ No newline at end of file From f5c0d2fd01aaa1b90ebc720f64765fc72d0311b9 Mon Sep 17 00:00:00 2001 From: Nukem Date: Thu, 9 Jul 2015 22:24:13 -0400 Subject: [PATCH 31/43] DBG: BBlock flag reorganization --- x64_dbg_dbg/BasicBlock.h | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/x64_dbg_dbg/BasicBlock.h b/x64_dbg_dbg/BasicBlock.h index 1aeed604..02d0d059 100644 --- a/x64_dbg_dbg/BasicBlock.h +++ b/x64_dbg_dbg/BasicBlock.h @@ -5,16 +5,20 @@ enum BasicBlockFlags : uint { BASIC_BLOCK_FLAG_NONE = 0, // No flag + BASIC_BLOCK_FLAG_FUNCTION = (1 << 1), // Scanned; also part of a known function BASIC_BLOCK_FLAG_ORPHANED = (1 << 2), // No targets ever reach this block - BASIC_BLOCK_FLAG_CALL = (1 << 3), // The block ends with a call - BASIC_BLOCK_FLAG_RET = (1 << 4), // The block ends with a retn - BASIC_BLOCK_FLAG_INDIRECT = (1 << 5), // This block ends with an indirect branch - BASIC_BLOCK_FLAG_INDIRPTR = (1 << 6), // This block ends with an indirect branch; pointer known - BASIC_BLOCK_FLAG_PREPAD = (1 << 7), // Block ends because there was padding afterwards - BASIC_BLOCK_FLAG_PAD = (1 << 8), // Block is only a series of padding instructions - BASIC_BLOCK_FLAG_CUTOFF = (1 << 9), // Ends prematurely because of another JMP to location - BASIC_BLOCK_FLAG_DELETE = (1 << 10), // Delete element at the next possible time + BASIC_BLOCK_FLAG_CUTOFF = (1 << 3), // Ends prematurely because of another JMP to location + BASIC_BLOCK_FLAG_DELETE = (1 << 4), // Delete element at the next possible time + + BASIC_BLOCK_FLAG_CALL = (1 << 5), // The block ends with a call + BASIC_BLOCK_FLAG_RET = (1 << 6), // The block ends with a retn + BASIC_BLOCK_FLAG_ABSJMP = (1 << 7), // Branch is absolute + BASIC_BLOCK_FLAG_INDIRECT = (1 << 8), // This block ends with an indirect branch + BASIC_BLOCK_FLAG_INDIRPTR = (1 << 9), // This block ends with an indirect branch; pointer known + + BASIC_BLOCK_FLAG_PREPAD = (1 << 10), // Block ends because there was padding afterwards + BASIC_BLOCK_FLAG_PAD = (1 << 11), // Block is only a series of padding instructions }; struct BasicBlock From 5f7c34f8aa5ada0aa028605669deb5201d340b80 Mon Sep 17 00:00:00 2001 From: Nukem Date: Thu, 9 Jul 2015 22:24:40 -0400 Subject: [PATCH 32/43] DBG: LinearPass: BASIC_BLOCK_FLAG_ABSJMP --- x64_dbg_dbg/LinearPass.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/x64_dbg_dbg/LinearPass.cpp b/x64_dbg_dbg/LinearPass.cpp index f8947293..fa24b44b 100644 --- a/x64_dbg_dbg/LinearPass.cpp +++ b/x64_dbg_dbg/LinearPass.cpp @@ -207,6 +207,10 @@ void LinearPass::AnalysisWorker(uint Start, uint End, BBlockArray* Blocks) { // Branch target immediate block->Target = operand.imm; + + // Check if abs jump + if(disasm.GetId() == X86_INS_JMP) + block->SetFlag(BASIC_BLOCK_FLAG_ABSJMP); } else { From 37047a243c5fa273196232d9c6a0760f3d291a4b Mon Sep 17 00:00:00 2001 From: Nukem Date: Thu, 9 Jul 2015 22:24:55 -0400 Subject: [PATCH 33/43] DBG: FunctionPass mostly finished --- x64_dbg_dbg/FunctionPass.cpp | 80 +++++++++++++++++++++--------------- 1 file changed, 46 insertions(+), 34 deletions(-) diff --git a/x64_dbg_dbg/FunctionPass.cpp b/x64_dbg_dbg/FunctionPass.cpp index 6485da97..8b68e684 100644 --- a/x64_dbg_dbg/FunctionPass.cpp +++ b/x64_dbg_dbg/FunctionPass.cpp @@ -82,7 +82,7 @@ bool FunctionPass::Analyse() // Memory allocation optimization // TODO: Option to conserve memory - threadFunctions[i].reserve(10000); + threadFunctions[i].reserve(30000); // Execute AnalysisWorker(threadWorkStart, threadWorkStop, &threadFunctions[i]); @@ -97,14 +97,14 @@ bool FunctionPass::Analyse() // Sort and remove duplicates std::sort(funcs.begin(), funcs.end()); funcs.erase(std::unique(funcs.begin(), funcs.end()), funcs.end()); - + /* FunctionClear(); for(auto & func : funcs) { FunctionAdd(func.VirtualStart, func.VirtualEnd - 1, true); } GuiUpdateAllViews(); - + */ delete[] threadFunctions; return true; } @@ -112,7 +112,7 @@ bool FunctionPass::Analyse() void FunctionPass::AnalysisWorker(uint Start, uint End, std::vector* Blocks) { // Step 1: Use any defined functions in the PE function table - //FindFunctionWorkerPrepass(Start, End, Blocks); + FindFunctionWorkerPrepass(Start, End, Blocks); // Step 2: for each block that contains a CALL flag, // add it to a local function start array @@ -218,7 +218,7 @@ void FunctionPass::FindFunctionWorker(std::vector* Blocks) auto ResolveFunctionEnd = [this](FunctionDef * Function, BasicBlock * LastBlock) { assert(Function->VirtualStart != 0); - Function->VirtualStart = 0x00007FF83B4315D0; + // Find the first basic block of the function BasicBlock* block = FindBBlockInRange(Function->VirtualStart); @@ -236,53 +236,65 @@ void FunctionPass::FindFunctionWorker(std::vector* Blocks) // Loop forever until the end is found for(; (uint)block <= (uint)LastBlock; block++) { - // Calculate max from just linear instructions - maximumAddr = max(maximumAddr, block->VirtualEnd); + // Block is now in use + block->SetFlag(BASIC_BLOCK_FLAG_FUNCTION); - // Each block has the potential to increase the - // maximum function end address. + // Calculate max from just linear instructions + maximumAddr = max(maximumAddr, block->VirtualEnd - 1); + + // Find maximum jump target if(!block->GetFlag(BASIC_BLOCK_FLAG_CALL) && !block->GetFlag(BASIC_BLOCK_FLAG_INDIRECT)) { - // Here's a problem: Compilers add tail-call elimination with a jump. - // Solve this by creating a maximum jump limit: +/- 128 bytes from the end. - if(abs((__int64)(block->VirtualEnd - block->Target)) <= 128) - maximumAddr = max(maximumAddr, block->Target); + if(block->Target != 0) + { + // Here's a problem: Compilers add tail-call elimination with a jump. + // Solve this by creating a maximum jump limit: +/- 128 bytes from the end. + if(abs((__int64)(block->VirtualEnd - block->Target)) <= 512) + maximumAddr = max(maximumAddr, block->Target); + } } - // Does this node contain the maximum address? - if(block->VirtualStart > maximumAddr) - __debugbreak(); + // Sanity check + assert(maximumAddr >= block->VirtualStart); - if(maximumAddr >= block->VirtualStart && maximumAddr <= block->VirtualEnd) + // Does this node contain the maximum address? + if(maximumAddr >= block->VirtualStart && maximumAddr < block->VirtualEnd) { - // It does! But does it end with a return statement? + // It does! There's 4 possibilities next: + // + // 1. Return + // 2. Tail-call elimination + // 3. Optimized loop + // 4. Function continues to next block + // + // 1. if(block->GetFlag(BASIC_BLOCK_FLAG_RET)) { -__test: +__endfunc: Function->VirtualEnd = block->VirtualEnd; Function->BBlockEnd = FindBBlockIndex(block); break; } - else - { - // It doesn't end with a return. There's 2 possibilities: - // tail-call elimination or an optimized loop. - if(abs((__int64)(block->VirtualEnd - block->Target)) > 128) - { - dprintf("Test: 0x%p\n", block->VirtualEnd); - } - goto __test; + if(block->Target != 0) + { + // NOTE: Both must be an absolute jump + if(block->GetFlag(BASIC_BLOCK_FLAG_ABSJMP)) + { + // 2. + if(abs((__int64)(block->VirtualEnd - block->Target)) > 128) + goto __endfunc; + + // 3. + if(block->Target >= Function->VirtualStart && block->Target < block->VirtualEnd) + goto __endfunc; + } } + + // 4. Just continue } } - dprintf("test - 0x%p 0x%p\n", Function->VirtualStart, Function->VirtualEnd); - - // Set the flag for blocks that have been scanned - for(uint i = Function->BBlockStart; i < Function->BBlockEnd; i++) - m_MainBlocks[i].SetFlag(BASIC_BLOCK_FLAG_FUNCTION); - return true; }; From d8445e14b8f97dcd7ab851f210edd64a86401593 Mon Sep 17 00:00:00 2001 From: Nukem Date: Fri, 10 Jul 2015 01:12:16 -0400 Subject: [PATCH 34/43] DBG: Clean up various includes (ReSharper) --- x64_dbg_dbg/BasicBlock.cpp | 2 -- x64_dbg_dbg/FunctionPass.cpp | 8 ++++---- x64_dbg_dbg/_dbgfunctions.cpp | 1 - x64_dbg_dbg/_exports.cpp | 2 -- x64_dbg_dbg/_global.cpp | 1 - x64_dbg_dbg/addrinfo.cpp | 3 --- x64_dbg_dbg/assemble.cpp | 2 -- x64_dbg_dbg/bookmark.cpp | 1 - x64_dbg_dbg/breakpoint.cpp | 3 --- x64_dbg_dbg/capstone_wrapper.cpp | 1 - x64_dbg_dbg/command.cpp | 2 -- x64_dbg_dbg/comment.cpp | 1 - x64_dbg_dbg/controlflowanalysis.cpp | 1 - x64_dbg_dbg/disasm_fast.cpp | 1 - x64_dbg_dbg/disasm_helper.cpp | 3 --- x64_dbg_dbg/error.cpp | 2 +- x64_dbg_dbg/exception.cpp | 2 +- x64_dbg_dbg/function.cpp | 1 - x64_dbg_dbg/functionanalysis.cpp | 8 ++++++-- x64_dbg_dbg/label.cpp | 1 - x64_dbg_dbg/loop.cpp | 1 - x64_dbg_dbg/memory.cpp | 1 - x64_dbg_dbg/msgqueue.cpp | 1 - x64_dbg_dbg/patches.cpp | 1 - x64_dbg_dbg/plugin_loader.cpp | 2 -- x64_dbg_dbg/reference.cpp | 1 - x64_dbg_dbg/simplescript.cpp | 3 --- x64_dbg_dbg/stackinfo.cpp | 2 -- x64_dbg_dbg/stringformat.cpp | 1 - x64_dbg_dbg/stringutils.cpp | 3 +-- x64_dbg_dbg/symbolinfo.cpp | 1 - x64_dbg_dbg/thread.cpp | 2 -- x64_dbg_dbg/value.cpp | 2 -- x64_dbg_dbg/x64_dbg.cpp | 3 --- x64_dbg_dbg/x64_dbg_dbg.vcxproj | 1 - x64_dbg_dbg/x64_dbg_dbg.vcxproj.filters | 27 ++++++++++++++++++++++--- 36 files changed, 37 insertions(+), 61 deletions(-) delete mode 100644 x64_dbg_dbg/BasicBlock.cpp diff --git a/x64_dbg_dbg/BasicBlock.cpp b/x64_dbg_dbg/BasicBlock.cpp deleted file mode 100644 index 0c14f769..00000000 --- a/x64_dbg_dbg/BasicBlock.cpp +++ /dev/null @@ -1,2 +0,0 @@ -#include "BasicBlock.h" -#include "memory.h" \ No newline at end of file diff --git a/x64_dbg_dbg/FunctionPass.cpp b/x64_dbg_dbg/FunctionPass.cpp index 8b68e684..83df94f1 100644 --- a/x64_dbg_dbg/FunctionPass.cpp +++ b/x64_dbg_dbg/FunctionPass.cpp @@ -97,14 +97,14 @@ bool FunctionPass::Analyse() // Sort and remove duplicates std::sort(funcs.begin(), funcs.end()); funcs.erase(std::unique(funcs.begin(), funcs.end()), funcs.end()); - /* + FunctionClear(); for(auto & func : funcs) { FunctionAdd(func.VirtualStart, func.VirtualEnd - 1, true); } GuiUpdateAllViews(); - */ + delete[] threadFunctions; return true; } @@ -248,7 +248,7 @@ void FunctionPass::FindFunctionWorker(std::vector* Blocks) if(block->Target != 0) { // Here's a problem: Compilers add tail-call elimination with a jump. - // Solve this by creating a maximum jump limit: +/- 128 bytes from the end. + // Solve this by creating a maximum jump limit: +/- 512 bytes from the end. if(abs((__int64)(block->VirtualEnd - block->Target)) <= 512) maximumAddr = max(maximumAddr, block->Target); } @@ -291,7 +291,7 @@ __endfunc: } } - // 4. Just continue + // 4. Continue } } diff --git a/x64_dbg_dbg/_dbgfunctions.cpp b/x64_dbg_dbg/_dbgfunctions.cpp index d049adcc..a0159703 100644 --- a/x64_dbg_dbg/_dbgfunctions.cpp +++ b/x64_dbg_dbg/_dbgfunctions.cpp @@ -8,7 +8,6 @@ #include "_dbgfunctions.h" #include "assemble.h" #include "debugger.h" -#include "addrinfo.h" #include "patches.h" #include "memory.h" #include "disasm_fast.h" diff --git a/x64_dbg_dbg/_exports.cpp b/x64_dbg_dbg/_exports.cpp index ec9d89cb..fa4ed46f 100644 --- a/x64_dbg_dbg/_exports.cpp +++ b/x64_dbg_dbg/_exports.cpp @@ -8,8 +8,6 @@ #include "memory.h" #include "debugger.h" #include "value.h" -#include "addrinfo.h" -#include "console.h" #include "threading.h" #include "breakpoint.h" #include "disasm_helper.h" diff --git a/x64_dbg_dbg/_global.cpp b/x64_dbg_dbg/_global.cpp index a7c56e6b..47318e51 100644 --- a/x64_dbg_dbg/_global.cpp +++ b/x64_dbg_dbg/_global.cpp @@ -6,7 +6,6 @@ #include "_global.h" #include #include -#include /** \brief x64dbg library instance. diff --git a/x64_dbg_dbg/addrinfo.cpp b/x64_dbg_dbg/addrinfo.cpp index 5aa42a76..43e25f29 100644 --- a/x64_dbg_dbg/addrinfo.cpp +++ b/x64_dbg_dbg/addrinfo.cpp @@ -9,9 +9,6 @@ #include "console.h" #include "memory.h" #include "breakpoint.h" -#include "threading.h" -#include "symbolinfo.h" -#include "murmurhash.h" #include "lz4\lz4file.h" #include "patches.h" #include "module.h" diff --git a/x64_dbg_dbg/assemble.cpp b/x64_dbg_dbg/assemble.cpp index 8cf40b00..da4a568c 100644 --- a/x64_dbg_dbg/assemble.cpp +++ b/x64_dbg_dbg/assemble.cpp @@ -6,11 +6,9 @@ #include "assemble.h" #include "memory.h" -#include "debugger.h" #include "XEDParse\XEDParse.h" #include "value.h" #include "disasm_helper.h" -#include "console.h" static bool cbUnknown(const char* text, ULONGLONG* value) { diff --git a/x64_dbg_dbg/bookmark.cpp b/x64_dbg_dbg/bookmark.cpp index c5882afd..3367f3e4 100644 --- a/x64_dbg_dbg/bookmark.cpp +++ b/x64_dbg_dbg/bookmark.cpp @@ -1,7 +1,6 @@ #include "bookmark.h" #include "threading.h" #include "module.h" -#include "debugger.h" #include "memory.h" std::unordered_map bookmarks; diff --git a/x64_dbg_dbg/breakpoint.cpp b/x64_dbg_dbg/breakpoint.cpp index 5f041f8b..03580fcc 100644 --- a/x64_dbg_dbg/breakpoint.cpp +++ b/x64_dbg_dbg/breakpoint.cpp @@ -5,9 +5,6 @@ */ #include "breakpoint.h" -#include "debugger.h" -#include "addrinfo.h" -#include "console.h" #include "memory.h" #include "threading.h" #include "module.h" diff --git a/x64_dbg_dbg/capstone_wrapper.cpp b/x64_dbg_dbg/capstone_wrapper.cpp index ef2770b1..c5d726e8 100644 --- a/x64_dbg_dbg/capstone_wrapper.cpp +++ b/x64_dbg_dbg/capstone_wrapper.cpp @@ -1,6 +1,5 @@ #include "console.h" #include "capstone_wrapper.h" -#include "TitanEngine\TitanEngine.h" csh Capstone::mHandle = 0; diff --git a/x64_dbg_dbg/command.cpp b/x64_dbg_dbg/command.cpp index b88537cf..16ca6b05 100644 --- a/x64_dbg_dbg/command.cpp +++ b/x64_dbg_dbg/command.cpp @@ -7,8 +7,6 @@ #include "command.h" #include "value.h" #include "console.h" -#include "debugger.h" -#include "math.h" #include "commandparser.h" /** diff --git a/x64_dbg_dbg/comment.cpp b/x64_dbg_dbg/comment.cpp index 2f9f6054..89dace73 100644 --- a/x64_dbg_dbg/comment.cpp +++ b/x64_dbg_dbg/comment.cpp @@ -1,7 +1,6 @@ #include "comment.h" #include "threading.h" #include "module.h" -#include "debugger.h" #include "memory.h" std::unordered_map comments; diff --git a/x64_dbg_dbg/controlflowanalysis.cpp b/x64_dbg_dbg/controlflowanalysis.cpp index 0e51fc88..69db9d9f 100644 --- a/x64_dbg_dbg/controlflowanalysis.cpp +++ b/x64_dbg_dbg/controlflowanalysis.cpp @@ -1,5 +1,4 @@ #include "controlflowanalysis.h" -#include "memory.h" #include "console.h" ControlFlowAnalysis::ControlFlowAnalysis(uint base, uint size) : Analysis(base, size) diff --git a/x64_dbg_dbg/disasm_fast.cpp b/x64_dbg_dbg/disasm_fast.cpp index e665243a..983b5158 100644 --- a/x64_dbg_dbg/disasm_fast.cpp +++ b/x64_dbg_dbg/disasm_fast.cpp @@ -5,7 +5,6 @@ */ #include "disasm_fast.h" -#include "debugger.h" #include "memory.h" static MEMORY_SIZE argsize2memsize(int argsize) diff --git a/x64_dbg_dbg/disasm_helper.cpp b/x64_dbg_dbg/disasm_helper.cpp index 3af16346..a0d06d77 100644 --- a/x64_dbg_dbg/disasm_helper.cpp +++ b/x64_dbg_dbg/disasm_helper.cpp @@ -7,10 +7,7 @@ #include "disasm_helper.h" #include "value.h" #include "console.h" -#include "debugger.h" #include "memory.h" -#include -#include #include "capstone_wrapper.h" uint disasmback(unsigned char* data, uint base, uint size, uint ip, int n) diff --git a/x64_dbg_dbg/error.cpp b/x64_dbg_dbg/error.cpp index e8e1ce6d..8d9ab838 100644 --- a/x64_dbg_dbg/error.cpp +++ b/x64_dbg_dbg/error.cpp @@ -1,5 +1,5 @@ -#include "error.h" #include +#include "error.h" std::unordered_map ErrorNames; diff --git a/x64_dbg_dbg/exception.cpp b/x64_dbg_dbg/exception.cpp index 38975061..99b99eea 100644 --- a/x64_dbg_dbg/exception.cpp +++ b/x64_dbg_dbg/exception.cpp @@ -1,5 +1,5 @@ -#include "exception.h" #include +#include "exception.h" std::unordered_map ExceptionNames; diff --git a/x64_dbg_dbg/function.cpp b/x64_dbg_dbg/function.cpp index 79e68e45..63d72206 100644 --- a/x64_dbg_dbg/function.cpp +++ b/x64_dbg_dbg/function.cpp @@ -1,6 +1,5 @@ #include "function.h" #include "module.h" -#include "debugger.h" #include "memory.h" #include "threading.h" diff --git a/x64_dbg_dbg/functionanalysis.cpp b/x64_dbg_dbg/functionanalysis.cpp index ce405fc7..f15a4a04 100644 --- a/x64_dbg_dbg/functionanalysis.cpp +++ b/x64_dbg_dbg/functionanalysis.cpp @@ -7,6 +7,7 @@ #include "BasicBlock.h" #include "FunctionPass.h" #include "LinearPass.h" +#include "module.h" FunctionAnalysis::FunctionAnalysis(uint base, uint size) : Analysis(base, size) { @@ -17,11 +18,14 @@ void FunctionAnalysis::Analyse() dputs("Starting analysis..."); DWORD ticks = GetTickCount(); + uint start = ModBaseFromAddr(_base); + uint end = start + ModSizeFromAddr(_base); + BBlockArray blocks; - LinearPass* pass1 = new LinearPass(_base, _base + _size, blocks); + LinearPass* pass1 = new LinearPass(start, end, blocks); pass1->Analyse(); - FunctionPass* pass2 = new FunctionPass(_base, _base + _size, blocks); + FunctionPass* pass2 = new FunctionPass(start, end, blocks); pass2->Analyse(); /* PopulateReferences(); diff --git a/x64_dbg_dbg/label.cpp b/x64_dbg_dbg/label.cpp index f262ab22..f7bb43cb 100644 --- a/x64_dbg_dbg/label.cpp +++ b/x64_dbg_dbg/label.cpp @@ -2,7 +2,6 @@ #include "threading.h" #include "module.h" #include "memory.h" -#include "debugger.h" std::unordered_map labels; diff --git a/x64_dbg_dbg/loop.cpp b/x64_dbg_dbg/loop.cpp index 7c7f1044..e0f2d5a3 100644 --- a/x64_dbg_dbg/loop.cpp +++ b/x64_dbg_dbg/loop.cpp @@ -1,5 +1,4 @@ #include "loop.h" -#include "debugger.h" #include "memory.h" #include "threading.h" #include "module.h" diff --git a/x64_dbg_dbg/memory.cpp b/x64_dbg_dbg/memory.cpp index 18746ebd..0422e217 100644 --- a/x64_dbg_dbg/memory.cpp +++ b/x64_dbg_dbg/memory.cpp @@ -7,7 +7,6 @@ #include "memory.h" #include "debugger.h" #include "patches.h" -#include "console.h" #include "threading.h" #include "module.h" diff --git a/x64_dbg_dbg/msgqueue.cpp b/x64_dbg_dbg/msgqueue.cpp index 0adaa60c..d0071367 100644 --- a/x64_dbg_dbg/msgqueue.cpp +++ b/x64_dbg_dbg/msgqueue.cpp @@ -1,5 +1,4 @@ #include "msgqueue.h" -#include //allocate a message (internal) static MESSAGE* msgalloc() diff --git a/x64_dbg_dbg/patches.cpp b/x64_dbg_dbg/patches.cpp index b98d37d7..32be250a 100644 --- a/x64_dbg_dbg/patches.cpp +++ b/x64_dbg_dbg/patches.cpp @@ -5,7 +5,6 @@ */ #include "patches.h" -#include "addrinfo.h" #include "memory.h" #include "debugger.h" #include "console.h" diff --git a/x64_dbg_dbg/plugin_loader.cpp b/x64_dbg_dbg/plugin_loader.cpp index 4fafaa90..7720ea40 100644 --- a/x64_dbg_dbg/plugin_loader.cpp +++ b/x64_dbg_dbg/plugin_loader.cpp @@ -7,8 +7,6 @@ #include "plugin_loader.h" #include "console.h" #include "debugger.h" -#include "memory.h" -#include "x64_dbg.h" /** \brief List of plugins. diff --git a/x64_dbg_dbg/reference.cpp b/x64_dbg_dbg/reference.cpp index d30a0d34..5cbc6c68 100644 --- a/x64_dbg_dbg/reference.cpp +++ b/x64_dbg_dbg/reference.cpp @@ -5,7 +5,6 @@ */ #include "reference.h" -#include "debugger.h" #include "memory.h" #include "console.h" #include "module.h" diff --git a/x64_dbg_dbg/simplescript.cpp b/x64_dbg_dbg/simplescript.cpp index 3cdfef31..1c0d3752 100644 --- a/x64_dbg_dbg/simplescript.cpp +++ b/x64_dbg_dbg/simplescript.cpp @@ -5,13 +5,10 @@ */ #include "simplescript.h" -#include "value.h" #include "console.h" #include "variable.h" -#include "threading.h" #include "x64_dbg.h" #include "debugger.h" -#include "commandparser.h" static std::vector linemap; diff --git a/x64_dbg_dbg/stackinfo.cpp b/x64_dbg_dbg/stackinfo.cpp index a8a71782..389d9ef1 100644 --- a/x64_dbg_dbg/stackinfo.cpp +++ b/x64_dbg_dbg/stackinfo.cpp @@ -5,11 +5,9 @@ */ #include "stackinfo.h" -#include "debugger.h" #include "memory.h" #include "disasm_helper.h" #include "disasm_fast.h" -#include "addrinfo.h" #include "_exports.h" #include "module.h" diff --git a/x64_dbg_dbg/stringformat.cpp b/x64_dbg_dbg/stringformat.cpp index 0a3d6e90..ecaafd8f 100644 --- a/x64_dbg_dbg/stringformat.cpp +++ b/x64_dbg_dbg/stringformat.cpp @@ -1,5 +1,4 @@ #include "stringformat.h" -#include "console.h" #include "value.h" #include "disasm_helper.h" diff --git a/x64_dbg_dbg/stringutils.cpp b/x64_dbg_dbg/stringutils.cpp index f1528a76..c2ec8031 100644 --- a/x64_dbg_dbg/stringutils.cpp +++ b/x64_dbg_dbg/stringutils.cpp @@ -1,7 +1,6 @@ +#include #include "stringutils.h" #include "memory.h" -#include -#include StringList StringUtils::Split(const String & s, char delim, std::vector & elems) { diff --git a/x64_dbg_dbg/symbolinfo.cpp b/x64_dbg_dbg/symbolinfo.cpp index 4328672a..cfabdab1 100644 --- a/x64_dbg_dbg/symbolinfo.cpp +++ b/x64_dbg_dbg/symbolinfo.cpp @@ -6,7 +6,6 @@ #include "symbolinfo.h" #include "debugger.h" -#include "addrinfo.h" #include "console.h" #include "module.h" #include "label.h" diff --git a/x64_dbg_dbg/thread.cpp b/x64_dbg_dbg/thread.cpp index 125f0965..4de11a8c 100644 --- a/x64_dbg_dbg/thread.cpp +++ b/x64_dbg_dbg/thread.cpp @@ -5,8 +5,6 @@ */ #include "thread.h" -#include "console.h" -#include "undocumented.h" #include "memory.h" #include "threading.h" diff --git a/x64_dbg_dbg/value.cpp b/x64_dbg_dbg/value.cpp index 3604cef9..75009f16 100644 --- a/x64_dbg_dbg/value.cpp +++ b/x64_dbg_dbg/value.cpp @@ -8,9 +8,7 @@ #include "variable.h" #include "debugger.h" #include "console.h" -#include "math.h" #include "memory.h" -#include "addrinfo.h" #include "symbolinfo.h" #include "module.h" #include "label.h" diff --git a/x64_dbg_dbg/x64_dbg.cpp b/x64_dbg_dbg/x64_dbg.cpp index b8d0e109..0d1269f6 100644 --- a/x64_dbg_dbg/x64_dbg.cpp +++ b/x64_dbg_dbg/x64_dbg.cpp @@ -11,13 +11,10 @@ #include "debugger.h" #include "simplescript.h" #include "console.h" -#include "math.h" #include "x64_dbg.h" #include "msgqueue.h" -#include "addrinfo.h" #include "threading.h" #include "plugin_loader.h" -#include "assemble.h" #include "_dbgfunctions.h" #include "debugger_commands.h" #include "capstone_wrapper.h" diff --git a/x64_dbg_dbg/x64_dbg_dbg.vcxproj b/x64_dbg_dbg/x64_dbg_dbg.vcxproj index 074fa32a..a401c7df 100644 --- a/x64_dbg_dbg/x64_dbg_dbg.vcxproj +++ b/x64_dbg_dbg/x64_dbg_dbg.vcxproj @@ -23,7 +23,6 @@ - diff --git a/x64_dbg_dbg/x64_dbg_dbg.vcxproj.filters b/x64_dbg_dbg/x64_dbg_dbg.vcxproj.filters index d5f81abb..effa1d5e 100644 --- a/x64_dbg_dbg/x64_dbg_dbg.vcxproj.filters +++ b/x64_dbg_dbg/x64_dbg_dbg.vcxproj.filters @@ -243,9 +243,6 @@ Source Files\Interfaces/Exports\_scriptapi - - Source Files\Analysis - Source Files\Analysis @@ -264,6 +261,18 @@ Source Files\Analysis + + Source Files + + + Source Files + + + Source Files + + + Source Files + @@ -605,5 +614,17 @@ Header Files\Analysis + + Header Files + + + Header Files + + + Header Files + + + Header Files + \ No newline at end of file From 45bb20f29760eff003b36ccb890586306d53139e Mon Sep 17 00:00:00 2001 From: Nukem Date: Fri, 10 Jul 2015 01:23:39 -0400 Subject: [PATCH 35/43] DBG: Use unordered_map in thread.cpp --- x64_dbg_dbg/thread.cpp | 75 +++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 48 deletions(-) diff --git a/x64_dbg_dbg/thread.cpp b/x64_dbg_dbg/thread.cpp index 4de11a8c..b03a9f46 100644 --- a/x64_dbg_dbg/thread.cpp +++ b/x64_dbg_dbg/thread.cpp @@ -8,7 +8,7 @@ #include "memory.h" #include "threading.h" -static std::vector threadList; +static std::unordered_map threadList; void ThreadCreate(CREATE_THREAD_DEBUG_INFO* CreateThread) { @@ -27,7 +27,7 @@ void ThreadCreate(CREATE_THREAD_DEBUG_INFO* CreateThread) // Modify global thread list EXCLUSIVE_ACQUIRE(LockThreads); - threadList.push_back(curInfo); + threadList.insert(std::make_pair(curInfo.ThreadId, curInfo)); EXCLUSIVE_RELEASE(); // Notify GUI @@ -38,10 +38,10 @@ void ThreadExit(DWORD ThreadId) { EXCLUSIVE_ACQUIRE(LockThreads); - // Don't use a foreach loop here because of the erase() call + // Don't use a foreach loop here because of the iterator erase() call for(auto itr = threadList.begin(); itr != threadList.end(); itr++) { - if(itr->ThreadId == ThreadId) + if(itr->first == ThreadId) { threadList.erase(itr); break; @@ -69,11 +69,13 @@ int ThreadGetCount() return (int)threadList.size(); } -static DWORD getLastErrorFromTeb(ULONG_PTR ThreadLocalBase) +DWORD getLastErrorFromTeb(ULONG_PTR ThreadLocalBase) { TEB teb; + if(!ThreadGetTeb(ThreadLocalBase, &teb)) return 0; + return teb.LastErrorValue; } @@ -85,22 +87,22 @@ void ThreadGetList(THREADLIST* List) // This function converts a C++ std::vector to a C-style THREADLIST[]. // Also assume BridgeAlloc zeros the returned buffer. // - size_t count = threadList.size(); + int count = (int)threadList.size(); if(count <= 0) return; - List->count = (int)count; + List->count = count; List->list = (THREADALLINFO*)BridgeAlloc(count * sizeof(THREADALLINFO)); // Fill out the list data - for(size_t i = 0; i < count; i++) + for(int i = 0; i < count; i++) { HANDLE threadHandle = threadList[i].Handle; // Get the debugger's current thread index if(threadHandle == hActiveThread) - List->CurrentThread = (int)i; + List->CurrentThread = i; memcpy(&List->list[i].BasicInfo, &threadList[i], sizeof(THREADINFO)); @@ -115,14 +117,7 @@ void ThreadGetList(THREADLIST* List) bool ThreadIsValid(DWORD ThreadId) { SHARED_ACQUIRE(LockThreads); - - for(auto & entry : threadList) - { - if(entry.ThreadId == ThreadId) - return true; - } - - return false; + return threadList.find(ThreadId) != threadList.end(); } bool ThreadGetTeb(uint TEBAddress, TEB* Teb) @@ -169,11 +164,8 @@ DWORD ThreadGetLastError(DWORD ThreadId) { SHARED_ACQUIRE(LockThreads); - for(auto & entry : threadList) - { - if(entry.ThreadId == ThreadId) - return getLastErrorFromTeb(entry.ThreadLocalBase); - } + if(threadList.find(ThreadId) != threadList.end()) + return getLastErrorFromTeb(threadList[ThreadId].ThreadLocalBase); return 0; } @@ -183,16 +175,13 @@ bool ThreadSetName(DWORD ThreadId, const char* Name) EXCLUSIVE_ACQUIRE(LockThreads); // Modifies a variable (name), so an exclusive lock is required - for(auto & entry : threadList) + if(threadList.find(ThreadId) != threadList.end()) { - if(entry.ThreadId == ThreadId) - { - if(!Name) - Name = ""; + if(!Name) + Name = ""; - strcpy_s(entry.threadName, Name); - return true; - } + strcpy_s(threadList[ThreadId].threadName, Name); + return true; } return false; @@ -202,15 +191,10 @@ HANDLE ThreadGetHandle(DWORD ThreadId) { SHARED_ACQUIRE(LockThreads); - for(auto & entry : threadList) - { - if(entry.ThreadId == ThreadId) - return entry.Handle; - } + if(threadList.find(ThreadId) != threadList.end()) + return threadList[ThreadId].Handle; - // TODO: Set an assert if the handle is never found, - // using a bad handle causes random/silent issues everywhere - return 0; + return nullptr; } DWORD ThreadGetId(HANDLE Thread) @@ -220,17 +204,12 @@ DWORD ThreadGetId(HANDLE Thread) // Search for the ID in the local list for(auto & entry : threadList) { - if(entry.Handle == Thread) - return entry.ThreadId; + if(entry.second.Handle == Thread) + return entry.first; } // Wasn't found, check with Windows - // NOTE: Requires VISTA+ - DWORD id = GetThreadId(Thread); - - // Returns 0 on error; - // TODO: Same problem with ThreadGetHandle() - return id; + return GetThreadId(Thread); } int ThreadSuspendAll() @@ -243,7 +222,7 @@ int ThreadSuspendAll() int count = 0; for(auto & entry : threadList) { - if(SuspendThread(entry.Handle) != -1) + if(SuspendThread(entry.second.Handle) != -1) count++; } @@ -260,7 +239,7 @@ int ThreadResumeAll() int count = 0; for(auto & entry : threadList) { - if(ResumeThread(entry.Handle) != -1) + if(ResumeThread(entry.second.Handle) != -1) count++; } From 529e5f1e3a4a1b3bd94c3858fd1fb876a9216859 Mon Sep 17 00:00:00 2001 From: Nukem Date: Fri, 10 Jul 2015 01:25:14 -0400 Subject: [PATCH 36/43] DBG: Small ThreadExit optimization --- x64_dbg_dbg/thread.cpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/x64_dbg_dbg/thread.cpp b/x64_dbg_dbg/thread.cpp index b03a9f46..728ef43c 100644 --- a/x64_dbg_dbg/thread.cpp +++ b/x64_dbg_dbg/thread.cpp @@ -38,15 +38,11 @@ void ThreadExit(DWORD ThreadId) { EXCLUSIVE_ACQUIRE(LockThreads); - // Don't use a foreach loop here because of the iterator erase() call - for(auto itr = threadList.begin(); itr != threadList.end(); itr++) - { - if(itr->first == ThreadId) - { - threadList.erase(itr); - break; - } - } + // Erase element using native functions + auto itr = threadList.find(ThreadId); + + if(itr != threadList.end()) + threadList.erase(itr); EXCLUSIVE_RELEASE(); GuiUpdateThreadView(); From b881e2d134d6bff81ffc2a60f9b6d6159e6db4a0 Mon Sep 17 00:00:00 2001 From: Nukem Date: Fri, 10 Jul 2015 02:14:25 -0400 Subject: [PATCH 37/43] DBG: Partially refactor MemUpdateMap --- x64_dbg_dbg/memory.cpp | 77 ++++++++++++++++++++++++++---------------- 1 file changed, 47 insertions(+), 30 deletions(-) diff --git a/x64_dbg_dbg/memory.cpp b/x64_dbg_dbg/memory.cpp index 0422e217..66fba38b 100644 --- a/x64_dbg_dbg/memory.cpp +++ b/x64_dbg_dbg/memory.cpp @@ -22,37 +22,55 @@ bool bListAllPages = false; void MemUpdateMap(HANDLE hProcess) { EXCLUSIVE_ACQUIRE(LockMemoryPages); - MEMORY_BASIC_INFORMATION mbi; - SIZE_T numBytes; - uint MyAddress = 0, newAddress = 0; - uint curAllocationBase = 0; + // First gather all possible pages in the memory range std::vector pageVector; - do { - memset(&mbi, 0, sizeof(mbi)); - numBytes = VirtualQueryEx(hProcess, (LPCVOID)MyAddress, &mbi, sizeof(mbi)); - if(mbi.State == MEM_COMMIT) + SIZE_T numBytes = 0; + uint pageStart = 0; + uint allocationBase = 0; + + do { - if(bListAllPages || curAllocationBase != (uint)mbi.AllocationBase) //only list allocation bases + // Query memory attributes + MEMORY_BASIC_INFORMATION mbi; + memset(&mbi, 0, sizeof(mbi)); + + numBytes = VirtualQueryEx(hProcess, (LPVOID)pageStart, &mbi, sizeof(mbi)); + + // Only allow pages that are committed to memory (exclude reserved/mapped) + if(mbi.State == MEM_COMMIT) { - curAllocationBase = (uint)mbi.AllocationBase; - MEMPAGE curPage; - *curPage.info = 0; - ModNameFromAddr(MyAddress, curPage.info, true); - memcpy(&curPage.mbi, &mbi, sizeof(mbi)); - pageVector.push_back(curPage); + // Only list allocation bases, unless if forced to list all + if(bListAllPages || allocationBase != (uint)mbi.AllocationBase) + { + // Set the new allocation base page + allocationBase = (uint)mbi.AllocationBase; + + MEMPAGE curPage; + memset(&curPage, 0, sizeof(MEMPAGE)); + memcpy(&curPage.mbi, &mbi, sizeof(mbi)); + + ModNameFromAddr(pageStart, curPage.info, true); + pageVector.push_back(curPage); + } + else + { + // Otherwise append the page to the last created entry + pageVector.back().mbi.RegionSize += mbi.RegionSize; + } } - else - pageVector.at(pageVector.size() - 1).mbi.RegionSize += mbi.RegionSize; + + // Calculate the next page start + uint newAddress = (uint)mbi.BaseAddress + mbi.RegionSize; + + if(newAddress <= pageStart) + break; + + pageStart = newAddress; } - newAddress = (uint)mbi.BaseAddress + mbi.RegionSize; - if(newAddress <= MyAddress) - numBytes = 0; - else - MyAddress = newAddress; + while(numBytes); } - while(numBytes); //process file sections int pagecount = (int)pageVector.size(); @@ -121,15 +139,14 @@ void MemUpdateMap(HANDLE hProcess) } } - //convert to memoryPages map - pagecount = (int)pageVector.size(); + // Convert the vector to a map memoryPages.clear(); - for(int i = 0; i < pagecount; i++) + + for(auto & page : pageVector) { - const MEMPAGE & curPage = pageVector.at(i); - uint start = (uint)curPage.mbi.BaseAddress; - uint size = curPage.mbi.RegionSize; - memoryPages.insert(std::make_pair(std::make_pair(start, start + size - 1), curPage)); + uint start = (uint)page.mbi.BaseAddress; + uint size = (uint)page.mbi.RegionSize; + memoryPages.insert(std::make_pair(std::make_pair(start, start + size - 1), page)); } } From 6974fec6c3d4d000efbcfda892d1ce871b6b888f Mon Sep 17 00:00:00 2001 From: Nukem Date: Fri, 10 Jul 2015 18:58:18 -0400 Subject: [PATCH 38/43] DBG: Remove unused locks from AnalysisPass --- x64_dbg_dbg/AnalysisPass.cpp | 23 ----------------------- x64_dbg_dbg/AnalysisPass.h | 6 ------ x64_dbg_dbg/LinearPass.cpp | 2 +- 3 files changed, 1 insertion(+), 30 deletions(-) diff --git a/x64_dbg_dbg/AnalysisPass.cpp b/x64_dbg_dbg/AnalysisPass.cpp index ed3991ce..0a9d3be8 100644 --- a/x64_dbg_dbg/AnalysisPass.cpp +++ b/x64_dbg_dbg/AnalysisPass.cpp @@ -7,9 +7,6 @@ AnalysisPass::AnalysisPass(uint VirtualStart, uint VirtualEnd, BBlockArray & Mai { assert(VirtualEnd > VirtualStart); - // Shared lock init - InitializeSRWLock(&m_InternalLock); - // Internal class data m_VirtualStart = VirtualStart; m_VirtualEnd = VirtualEnd; @@ -75,26 +72,6 @@ uint AnalysisPass::FindBBlockIndex(BasicBlock* Block) return ((uint)Block - (uint)m_MainBlocks.data()) / sizeof(BasicBlock); } -void AnalysisPass::AcquireReadLock() -{ - AcquireSRWLockShared(&m_InternalLock); -} - -void AnalysisPass::ReleaseReadLock() -{ - ReleaseSRWLockShared(&m_InternalLock); -} - -void AnalysisPass::AcquireExclusiveLock() -{ - AcquireSRWLockExclusive(&m_InternalLock); -} - -void AnalysisPass::ReleaseExclusiveLock() -{ - ReleaseSRWLockExclusive(&m_InternalLock); -} - uint AnalysisPass::IdealThreadCount() { if(m_InternalMaxThreads == 0) diff --git a/x64_dbg_dbg/AnalysisPass.h b/x64_dbg_dbg/AnalysisPass.h index 4049df7d..8c7d67ad 100644 --- a/x64_dbg_dbg/AnalysisPass.h +++ b/x64_dbg_dbg/AnalysisPass.h @@ -1,6 +1,5 @@ #pragma once -#include #include "_global.h" #include "BasicBlock.h" @@ -34,14 +33,9 @@ protected: BasicBlock* FindBBlockInRange(uint Address); uint FindBBlockIndex(BasicBlock* Block); - void AcquireReadLock(); - void ReleaseReadLock(); - void AcquireExclusiveLock(); - void ReleaseExclusiveLock(); uint IdealThreadCount(); void SetIdealThreadCount(uint Count); private: - SRWLOCK m_InternalLock; BYTE m_InternalMaxThreads; }; \ No newline at end of file diff --git a/x64_dbg_dbg/LinearPass.cpp b/x64_dbg_dbg/LinearPass.cpp index fa24b44b..1f78693c 100644 --- a/x64_dbg_dbg/LinearPass.cpp +++ b/x64_dbg_dbg/LinearPass.cpp @@ -172,7 +172,7 @@ void LinearPass::AnalysisWorker(uint Start, uint End, BBlockArray* Blocks) if(padding) { - // INT3s are treated differently. They are all created as their + // PADDING is treated differently. They are all created as their // own separate block for more analysis later. uint realBlockEnd = blockEnd - disasm.Size(); From 76a9d6232bdfb6189c55771a4aeb0b97f3aa9cc7 Mon Sep 17 00:00:00 2001 From: Nukem Date: Sat, 11 Jul 2015 16:09:47 -0400 Subject: [PATCH 39/43] DBG: Move FunctionPass lambdas into their own class functions --- x64_dbg_dbg/FunctionPass.cpp | 211 +++++++++++++++++------------------ x64_dbg_dbg/FunctionPass.h | 3 + 2 files changed, 108 insertions(+), 106 deletions(-) diff --git a/x64_dbg_dbg/FunctionPass.cpp b/x64_dbg_dbg/FunctionPass.cpp index 83df94f1..6eab02ef 100644 --- a/x64_dbg_dbg/FunctionPass.cpp +++ b/x64_dbg_dbg/FunctionPass.cpp @@ -120,7 +120,7 @@ void FunctionPass::AnalysisWorker(uint Start, uint End, std::vector // NOTE: *Some* indirect calls are included auto blockItr = std::next(m_MainBlocks.begin(), Start); - for(uint i = Start; i < End; i++, blockItr++) + for(uint i = Start; i < End; i++, ++blockItr) { if(blockItr->GetFlag(BASIC_BLOCK_FLAG_CALL)) { @@ -194,110 +194,6 @@ void FunctionPass::FindFunctionWorkerPrepass(uint Start, uint End, std::vector* Blocks) { - // Helper to link final blocks to function - auto ResolveKnownFunctionEnd = [this](FunctionDef * Function) - { - auto startBlock = FindBBlockInRange(Function->VirtualStart); - auto endBlock = FindBBlockInRange(Function->VirtualEnd); - - if(!startBlock || !endBlock) - return false; - - // Find block start/end indices - Function->BBlockStart = FindBBlockIndex(startBlock); - Function->BBlockEnd = FindBBlockIndex(endBlock); - - // Set the flag for blocks that have been scanned - for(uint i = Function->BBlockStart; i < Function->BBlockEnd; i++) - m_MainBlocks[i].SetFlag(BASIC_BLOCK_FLAG_FUNCTION); - - return true; - }; - - // Find the end manually - auto ResolveFunctionEnd = [this](FunctionDef * Function, BasicBlock * LastBlock) - { - assert(Function->VirtualStart != 0); - - // Find the first basic block of the function - BasicBlock* block = FindBBlockInRange(Function->VirtualStart); - - if(!block) - { - assert(false); - return false; - } - - // The maximum address is determined by any jump that extends past - // a RET or other terminating basic block. A function may have multiple - // return statements. - uint maximumAddr = 0; - - // Loop forever until the end is found - for(; (uint)block <= (uint)LastBlock; block++) - { - // Block is now in use - block->SetFlag(BASIC_BLOCK_FLAG_FUNCTION); - - // Calculate max from just linear instructions - maximumAddr = max(maximumAddr, block->VirtualEnd - 1); - - // Find maximum jump target - if(!block->GetFlag(BASIC_BLOCK_FLAG_CALL) && !block->GetFlag(BASIC_BLOCK_FLAG_INDIRECT)) - { - if(block->Target != 0) - { - // Here's a problem: Compilers add tail-call elimination with a jump. - // Solve this by creating a maximum jump limit: +/- 512 bytes from the end. - if(abs((__int64)(block->VirtualEnd - block->Target)) <= 512) - maximumAddr = max(maximumAddr, block->Target); - } - } - - // Sanity check - assert(maximumAddr >= block->VirtualStart); - - // Does this node contain the maximum address? - if(maximumAddr >= block->VirtualStart && maximumAddr < block->VirtualEnd) - { - // It does! There's 4 possibilities next: - // - // 1. Return - // 2. Tail-call elimination - // 3. Optimized loop - // 4. Function continues to next block - // - // 1. - if(block->GetFlag(BASIC_BLOCK_FLAG_RET)) - { -__endfunc: - Function->VirtualEnd = block->VirtualEnd; - Function->BBlockEnd = FindBBlockIndex(block); - break; - } - - if(block->Target != 0) - { - // NOTE: Both must be an absolute jump - if(block->GetFlag(BASIC_BLOCK_FLAG_ABSJMP)) - { - // 2. - if(abs((__int64)(block->VirtualEnd - block->Target)) > 128) - goto __endfunc; - - // 3. - if(block->Target >= Function->VirtualStart && block->Target < block->VirtualEnd) - goto __endfunc; - } - } - - // 4. Continue - } - } - - return true; - }; - // Cached final block BasicBlock* finalBlock = &m_MainBlocks.back(); @@ -312,11 +208,114 @@ __endfunc: continue; } - // Now the function end must be determined by heuristics + // Now the function end must be determined by heuristics (find manually) ResolveFunctionEnd(&block, finalBlock); } } +bool FunctionPass::ResolveKnownFunctionEnd(FunctionDef* Function) +{ + // Helper to link final blocks to function + auto startBlock = FindBBlockInRange(Function->VirtualStart); + auto endBlock = FindBBlockInRange(Function->VirtualEnd); + + if(!startBlock || !endBlock) + return false; + + // Find block start/end indices + Function->BBlockStart = FindBBlockIndex(startBlock); + Function->BBlockEnd = FindBBlockIndex(endBlock); + + // Set the flag for blocks that have been scanned + for(BasicBlock* block = startBlock; (uint)block <= (uint)endBlock; block++) + block->SetFlag(BASIC_BLOCK_FLAG_FUNCTION); + + return true; +} + +bool FunctionPass::ResolveFunctionEnd(FunctionDef* Function, BasicBlock* LastBlock) +{ + assert(Function->VirtualStart != 0); + + // Find the first basic block of the function + BasicBlock* block = FindBBlockInRange(Function->VirtualStart); + + if(!block) + { + assert(false); + return false; + } + + // The maximum address is determined by any jump that extends past + // a RET or other terminating basic block. A function may have multiple + // return statements. + uint maximumAddr = 0; + + // Loop forever until the end is found + for(; (uint)block <= (uint)LastBlock; block++) + { + // Block is now in use + block->SetFlag(BASIC_BLOCK_FLAG_FUNCTION); + + // Calculate max from just linear instructions + maximumAddr = max(maximumAddr, block->VirtualEnd - 1); + + // Find maximum jump target + if(!block->GetFlag(BASIC_BLOCK_FLAG_CALL) && !block->GetFlag(BASIC_BLOCK_FLAG_INDIRECT)) + { + if(block->Target != 0) + { + // Here's a problem: Compilers add tail-call elimination with a jump. + // Solve this by creating a maximum jump limit: +/- 512 bytes from the end. + if(abs((__int64)(block->VirtualEnd - block->Target)) <= 512) + maximumAddr = max(maximumAddr, block->Target); + } + } + + // Sanity check + assert(maximumAddr >= block->VirtualStart); + + // Does this node contain the maximum address? + if(maximumAddr >= block->VirtualStart && maximumAddr < block->VirtualEnd) + { + // It does! There's 4 possibilities next: + // + // 1. Return + // 2. Tail-call elimination + // 3. Optimized loop + // 4. Function continues to next block + // + // 1. + if(block->GetFlag(BASIC_BLOCK_FLAG_RET)) + { +__endfunc: + Function->VirtualEnd = block->VirtualEnd; + Function->BBlockEnd = FindBBlockIndex(block); + break; + } + + if(block->Target != 0) + { + // NOTE: Both must be an absolute jump + if(block->GetFlag(BASIC_BLOCK_FLAG_ABSJMP)) + { + // 2. + if(abs((__int64)(block->VirtualEnd - block->Target)) > 128) + goto __endfunc; + + // 3. + if(block->Target >= Function->VirtualStart && block->Target < block->VirtualEnd) + goto __endfunc; + } + } + + // 4. Continue + } + } + + return true; +} + void FunctionPass::EnumerateFunctionRuntimeEntries64(std::function Callback) { if(!m_FunctionInfo) diff --git a/x64_dbg_dbg/FunctionPass.h b/x64_dbg_dbg/FunctionPass.h index c866f8e4..fea9c5b2 100644 --- a/x64_dbg_dbg/FunctionPass.h +++ b/x64_dbg_dbg/FunctionPass.h @@ -23,5 +23,8 @@ private: void FindFunctionWorkerPrepass(uint Start, uint End, std::vector* Blocks); void FindFunctionWorker(std::vector* Blocks); + bool ResolveKnownFunctionEnd(FunctionDef* Function); + bool ResolveFunctionEnd(FunctionDef* Function, BasicBlock* LastBlock); + void EnumerateFunctionRuntimeEntries64(std::function Callback); }; \ No newline at end of file From 9fa4c9dece44101da6fc009386662162f25f2051 Mon Sep 17 00:00:00 2001 From: Nukem Date: Sat, 11 Jul 2015 16:15:11 -0400 Subject: [PATCH 40/43] DBG: Try fixing git filesystem bug --- x64_dbg_dbg/Analysis.cpp | 29 ----------------------------- x64_dbg_dbg/Analysis.h | 8 -------- x64_dbg_dbg/LinearPass.cpp | 2 +- x64_dbg_dbg/analysis.cpp | 25 ------------------------- x64_dbg_dbg/analysis.h | 26 -------------------------- 5 files changed, 1 insertion(+), 89 deletions(-) delete mode 100644 x64_dbg_dbg/Analysis.cpp delete mode 100644 x64_dbg_dbg/Analysis.h delete mode 100644 x64_dbg_dbg/analysis.cpp delete mode 100644 x64_dbg_dbg/analysis.h diff --git a/x64_dbg_dbg/Analysis.cpp b/x64_dbg_dbg/Analysis.cpp deleted file mode 100644 index 0f270f3a..00000000 --- a/x64_dbg_dbg/Analysis.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "Analysis.h" -#include "console.h" -#include "module.h" - -void Derp(uint _base) -{ - dputs("Starting analysis..."); - DWORD ticks = GetTickCount(); - - uint modBase = ModBaseFromAddr(_base); - uint modSize = ModSizeFromAddr(_base); - - BBlockArray array; - LinearPass* pass = new LinearPass(modBase, modBase + modSize, array); - pass->Analyse(); - - FunctionPass* pass3 = new FunctionPass(modBase, modBase + modSize, array); - pass3->Analyse(); - - //Int3CoagulatorPass *pass2 = new Int3CoagulatorPass(modBase, modBase + modSize, array); - //pass2->Analyse(); - /* - - PopulateReferences(); - dprintf("%u called functions populated\n", _functions.size()); - AnalyseFunctions(); - */ - dprintf("Analysis finished in %ums!\n", GetTickCount() - ticks); -} \ No newline at end of file diff --git a/x64_dbg_dbg/Analysis.h b/x64_dbg_dbg/Analysis.h deleted file mode 100644 index 8d858752..00000000 --- a/x64_dbg_dbg/Analysis.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -#include "_global.h" -#include "LinearPass.h" -#include "CodeFollowPass.h" -#include "FunctionPass.h" -#include "Int3CoagulatorPass.h" -// TODO: CallConvPass? Or keep it inside FunctionPass? \ No newline at end of file diff --git a/x64_dbg_dbg/LinearPass.cpp b/x64_dbg_dbg/LinearPass.cpp index 1f78693c..d83ae0e1 100644 --- a/x64_dbg_dbg/LinearPass.cpp +++ b/x64_dbg_dbg/LinearPass.cpp @@ -208,7 +208,7 @@ void LinearPass::AnalysisWorker(uint Start, uint End, BBlockArray* Blocks) // Branch target immediate block->Target = operand.imm; - // Check if abs jump + // Check if absolute jump if(disasm.GetId() == X86_INS_JMP) block->SetFlag(BASIC_BLOCK_FLAG_ABSJMP); } diff --git a/x64_dbg_dbg/analysis.cpp b/x64_dbg_dbg/analysis.cpp deleted file mode 100644 index c3a3c8de..00000000 --- a/x64_dbg_dbg/analysis.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "analysis.h" -#include "memory.h" - -Analysis::Analysis(uint base, uint size) -{ - _base = base; - _size = size; - _data = new unsigned char[_size + MAX_DISASM_BUFFER]; - MemRead((void*)_base, _data, _size, 0); -} - -Analysis::~Analysis() -{ - delete[] _data; -} - -bool Analysis::IsValidAddress(uint addr) -{ - return addr >= _base && addr < _base + _size; -} - -const unsigned char* Analysis::TranslateAddress(uint addr) -{ - return IsValidAddress(addr) ? _data + (addr - _base) : nullptr; -} \ No newline at end of file diff --git a/x64_dbg_dbg/analysis.h b/x64_dbg_dbg/analysis.h deleted file mode 100644 index 4f3a9169..00000000 --- a/x64_dbg_dbg/analysis.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef _ANALYSIS_H -#define _ANALYSIS_H - -#include "_global.h" -#include "capstone_wrapper.h" - -class Analysis -{ -public: - explicit Analysis(uint base, uint size); - Analysis(const Analysis & that) = delete; - ~Analysis(); - virtual void Analyse() = 0; - virtual void SetMarkers() = 0; - -protected: - uint _base; - uint _size; - unsigned char* _data; - Capstone _cp; - - bool IsValidAddress(uint addr); - const unsigned char* TranslateAddress(uint addr); -}; - -#endif //_ANALYSIS_H \ No newline at end of file From 0bfc496a7a241ce2f2305e30e6b8c4374da98018 Mon Sep 17 00:00:00 2001 From: Nukem Date: Sat, 11 Jul 2015 16:21:40 -0400 Subject: [PATCH 41/43] DBG: Re-add fixed analysis.cpp files --- x64_dbg_dbg/analysis.cpp | 25 ++++++++++++++++++++++++ x64_dbg_dbg/analysis.h | 26 +++++++++++++++++++++++++ x64_dbg_dbg/x64_dbg_dbg.vcxproj | 4 ++-- x64_dbg_dbg/x64_dbg_dbg.vcxproj.filters | 12 ++++++------ 4 files changed, 59 insertions(+), 8 deletions(-) create mode 100644 x64_dbg_dbg/analysis.cpp create mode 100644 x64_dbg_dbg/analysis.h diff --git a/x64_dbg_dbg/analysis.cpp b/x64_dbg_dbg/analysis.cpp new file mode 100644 index 00000000..de0200e7 --- /dev/null +++ b/x64_dbg_dbg/analysis.cpp @@ -0,0 +1,25 @@ +#include "analysis.h" +#include "memory.h" + +Analysis::Analysis(uint base, uint size) +{ + _base = base; + _size = size; + _data = new unsigned char[_size + MAX_DISASM_BUFFER]; + MemRead((void*)_base, _data, _size, 0); +} + +Analysis::~Analysis() +{ + delete[] _data; +} + +bool Analysis::IsValidAddress(uint addr) +{ + return addr >= _base && addr < _base + _size; +} + +const unsigned char* Analysis::TranslateAddress(uint addr) +{ + return IsValidAddress(addr) ? _data + (addr - _base) : nullptr; +} \ No newline at end of file diff --git a/x64_dbg_dbg/analysis.h b/x64_dbg_dbg/analysis.h new file mode 100644 index 00000000..d5bf6cd4 --- /dev/null +++ b/x64_dbg_dbg/analysis.h @@ -0,0 +1,26 @@ +#ifndef _ANALYSIS_H +#define _ANALYSIS_H + +#include "_global.h" +#include "capstone_wrapper.h" + +class Analysis +{ +public: + explicit Analysis(uint base, uint size); + Analysis(const Analysis & that) = delete; + ~Analysis(); + virtual void Analyse() = 0; + virtual void SetMarkers() = 0; + +protected: + uint _base; + uint _size; + unsigned char* _data; + Capstone _cp; + + bool IsValidAddress(uint addr); + const unsigned char* TranslateAddress(uint addr); +}; + +#endif //_ANALYSIS_H \ No newline at end of file diff --git a/x64_dbg_dbg/x64_dbg_dbg.vcxproj b/x64_dbg_dbg/x64_dbg_dbg.vcxproj index a401c7df..f1e3cfde 100644 --- a/x64_dbg_dbg/x64_dbg_dbg.vcxproj +++ b/x64_dbg_dbg/x64_dbg_dbg.vcxproj @@ -20,7 +20,7 @@ - + @@ -84,7 +84,7 @@ - + diff --git a/x64_dbg_dbg/x64_dbg_dbg.vcxproj.filters b/x64_dbg_dbg/x64_dbg_dbg.vcxproj.filters index effa1d5e..43712536 100644 --- a/x64_dbg_dbg/x64_dbg_dbg.vcxproj.filters +++ b/x64_dbg_dbg/x64_dbg_dbg.vcxproj.filters @@ -246,9 +246,6 @@ Source Files\Analysis - - Source Files\Analysis - Source Files\Analysis @@ -273,6 +270,9 @@ Source Files + + Source Files\Analysis + @@ -599,9 +599,6 @@ Header Files\Analysis - - Header Files\Analysis - Header Files\Analysis @@ -626,5 +623,8 @@ Header Files + + Header Files\Analysis + \ No newline at end of file From 28d8c9012740bc979b428e390bacab155cbb6019 Mon Sep 17 00:00:00 2001 From: Nukem Date: Sat, 11 Jul 2015 16:26:06 -0400 Subject: [PATCH 42/43] DBG: Restore functionanalysis.cpp to the main repo's --- x64_dbg_dbg/functionanalysis.cpp | 39 +++++++++----------------------- 1 file changed, 11 insertions(+), 28 deletions(-) diff --git a/x64_dbg_dbg/functionanalysis.cpp b/x64_dbg_dbg/functionanalysis.cpp index 53149ad8..91f359db 100644 --- a/x64_dbg_dbg/functionanalysis.cpp +++ b/x64_dbg_dbg/functionanalysis.cpp @@ -1,14 +1,7 @@ #include "functionanalysis.h" #include "console.h" -#include "memory.h" #include "function.h" -#include "AnalysisPass.h" -#include "BasicBlock.h" -#include "FunctionPass.h" -#include "LinearPass.h" -#include "module.h" - FunctionAnalysis::FunctionAnalysis(uint base, uint size) : Analysis(base, size) { } @@ -18,20 +11,10 @@ void FunctionAnalysis::Analyse() dputs("Starting analysis..."); DWORD ticks = GetTickCount(); - uint start = ModBaseFromAddr(_base); - uint end = start + ModSizeFromAddr(_base); - - BBlockArray blocks; - LinearPass* pass1 = new LinearPass(start, end, blocks); - pass1->Analyse(); - - FunctionPass* pass2 = new FunctionPass(start, end, blocks); - pass2->Analyse(); - /* PopulateReferences(); dprintf("%u called functions populated\n", _functions.size()); AnalyseFunctions(); - */ + dprintf("Analysis finished in %ums!\n", GetTickCount() - ticks); } @@ -78,7 +61,7 @@ void FunctionAnalysis::AnalyseFunctions() for(size_t i = 0; i < _functions.size(); i++) { FunctionInfo & function = _functions[i]; - if(function.end) //skip already-analysed functions + if(function.end) //skip already-analysed functions continue; uint maxaddr = _base + _size; if(i < _functions.size() - 1) @@ -112,31 +95,31 @@ uint FunctionAnalysis::FindFunctionEnd(uint start, uint maxaddr) { if(_cp.Disassemble(addr, TranslateAddress(addr), MAX_DISASM_BUFFER)) { - if(addr + _cp.Size() > maxaddr) //we went past the maximum allowed address + if(addr + _cp.Size() > maxaddr) //we went past the maximum allowed address break; const cs_x86_op & operand = _cp.x86().operands[0]; - if((_cp.InGroup(CS_GRP_JUMP) || _cp.IsLoop()) && operand.type == X86_OP_IMM) //jump + if((_cp.InGroup(CS_GRP_JUMP) || _cp.IsLoop()) && operand.type == X86_OP_IMM) //jump { uint dest = (uint)operand.imm; - if(dest >= maxaddr) //jump across function boundaries + if(dest >= maxaddr) //jump across function boundaries { //currently unused } - else if(dest > addr && dest > fardest) //save the farthest JXX destination forward + else if(dest > addr && dest > fardest) //save the farthest JXX destination forward { fardest = dest; } - else if(end && dest < end && (_cp.GetId() == X86_INS_JMP || _cp.GetId() == X86_INS_LOOP)) //save the last JMP backwards + else if(end && dest < end && (_cp.GetId() == X86_INS_JMP || _cp.GetId() == X86_INS_LOOP)) //save the last JMP backwards { jumpback = addr; } } - else if(_cp.InGroup(CS_GRP_RET)) //possible function end? + else if(_cp.InGroup(CS_GRP_RET)) //possible function end? { end = addr; - if(fardest < addr) //we stop if the farthest JXX destination forward is before this RET + if(fardest < addr) //we stop if the farthest JXX destination forward is before this RET break; } @@ -153,9 +136,9 @@ uint FunctionAnalysis::GetReferenceOperand() for(int i = 0; i < _cp.x86().op_count; i++) { const cs_x86_op & operand = _cp.x86().operands[i]; - if(_cp.InGroup(CS_GRP_JUMP) || _cp.IsLoop()) //skip jumps/loops + if(_cp.InGroup(CS_GRP_JUMP) || _cp.IsLoop()) //skip jumps/loops continue; - if(operand.type == X86_OP_IMM) //we are looking for immediate references + if(operand.type == X86_OP_IMM) //we are looking for immediate references { uint dest = (uint)operand.imm; if(dest >= _base && dest < _base + _size) From 4e41298bb4f6451045c085f866e787eecb4e0a3f Mon Sep 17 00:00:00 2001 From: Nukem Date: Sat, 11 Jul 2015 16:41:00 -0400 Subject: [PATCH 43/43] DBG: Separate my analysis into analysis_nukem.cpp (along with command) --- x64_dbg_dbg/analysis_nukem.cpp | 23 +++++++++++++++++++++++ x64_dbg_dbg/analysis_nukem.h | 5 +++++ x64_dbg_dbg/instruction.cpp | 12 ++++++++++++ x64_dbg_dbg/instruction.h | 1 + x64_dbg_dbg/x64_dbg.cpp | 1 + x64_dbg_dbg/x64_dbg_dbg.vcxproj | 2 ++ x64_dbg_dbg/x64_dbg_dbg.vcxproj.filters | 6 ++++++ 7 files changed, 50 insertions(+) create mode 100644 x64_dbg_dbg/analysis_nukem.cpp create mode 100644 x64_dbg_dbg/analysis_nukem.h diff --git a/x64_dbg_dbg/analysis_nukem.cpp b/x64_dbg_dbg/analysis_nukem.cpp new file mode 100644 index 00000000..96779d09 --- /dev/null +++ b/x64_dbg_dbg/analysis_nukem.cpp @@ -0,0 +1,23 @@ +#include "analysis_nukem.h" +#include "BasicBlock.h" +#include "LinearPass.h" +#include "FunctionPass.h" +#include "console.h" + +void Analyse_nukem(uint base, uint size) +{ + dputs("Starting analysis (Nukem)..."); + DWORD ticks = GetTickCount(); + + uint end = base + size; + + BBlockArray blocks; + + LinearPass* pass1 = new LinearPass(base, end, blocks); + pass1->Analyse(); + + FunctionPass* pass2 = new FunctionPass(base, end, blocks); + pass2->Analyse(); + + dprintf("Analysis finished in %ums!\n", GetTickCount() - ticks); +} \ No newline at end of file diff --git a/x64_dbg_dbg/analysis_nukem.h b/x64_dbg_dbg/analysis_nukem.h new file mode 100644 index 00000000..c20eba7a --- /dev/null +++ b/x64_dbg_dbg/analysis_nukem.h @@ -0,0 +1,5 @@ +#pragma once + +#include "_global.h" + +void Analyse_nukem(uint base, uint size); \ No newline at end of file diff --git a/x64_dbg_dbg/instruction.cpp b/x64_dbg_dbg/instruction.cpp index 1f9dfe10..6e5d0467 100644 --- a/x64_dbg_dbg/instruction.cpp +++ b/x64_dbg_dbg/instruction.cpp @@ -28,6 +28,7 @@ #include "filereader.h" #include "functionanalysis.h" #include "controlflowanalysis.h" +#include "analysis_nukem.h" static bool bRefinit = false; @@ -1899,6 +1900,17 @@ CMDRESULT cbInstrCapstone(int argc, char* argv[]) return STATUS_CONTINUE; } +CMDRESULT cbInstrAnalyseNukem(int argc, char* argv[]) +{ + SELECTIONDATA sel; + GuiSelectionGet(GUI_DISASSEMBLY, &sel); + uint size = 0; + uint base = MemFindBaseAddr(sel.start, &size); + Analyse_nukem(base, size); + GuiUpdateAllViews(); + return STATUS_CONTINUE; +} + CMDRESULT cbInstrAnalyse(int argc, char* argv[]) { SELECTIONDATA sel; diff --git a/x64_dbg_dbg/instruction.h b/x64_dbg_dbg/instruction.h index 8cafb549..a9e8eeee 100644 --- a/x64_dbg_dbg/instruction.h +++ b/x64_dbg_dbg/instruction.h @@ -67,6 +67,7 @@ CMDRESULT cbInstrYaramod(int argc, char* argv[]); CMDRESULT cbInstrLog(int argc, char* argv[]); CMDRESULT cbInstrCapstone(int argc, char* argv[]); +CMDRESULT cbInstrAnalyseNukem(int argc, char* argv[]); CMDRESULT cbInstrAnalyse(int argc, char* argv[]); CMDRESULT cbInstrVisualize(int argc, char* argv[]); CMDRESULT cbInstrMeminfo(int argc, char* argv[]); diff --git a/x64_dbg_dbg/x64_dbg.cpp b/x64_dbg_dbg/x64_dbg.cpp index 0d1269f6..743d0f6c 100644 --- a/x64_dbg_dbg/x64_dbg.cpp +++ b/x64_dbg_dbg/x64_dbg.cpp @@ -189,6 +189,7 @@ static void registercommands() dbgcmdnew("yara", cbInstrYara, true); //yara test command dbgcmdnew("yaramod", cbInstrYaramod, true); //yara rule on module dbgcmdnew("analyse\1analyze\1anal", cbInstrAnalyse, true); //secret analysis command + dbgcmdnew("analyse_nukem", cbInstrAnalyseNukem, true); //secret analysis command #2 //undocumented dbgcmdnew("bench", cbDebugBenchmark, true); //benchmark test (readmem etc) diff --git a/x64_dbg_dbg/x64_dbg_dbg.vcxproj b/x64_dbg_dbg/x64_dbg_dbg.vcxproj index f1e3cfde..7b323e4e 100644 --- a/x64_dbg_dbg/x64_dbg_dbg.vcxproj +++ b/x64_dbg_dbg/x64_dbg_dbg.vcxproj @@ -22,6 +22,7 @@ + @@ -86,6 +87,7 @@ + diff --git a/x64_dbg_dbg/x64_dbg_dbg.vcxproj.filters b/x64_dbg_dbg/x64_dbg_dbg.vcxproj.filters index 43712536..118349a1 100644 --- a/x64_dbg_dbg/x64_dbg_dbg.vcxproj.filters +++ b/x64_dbg_dbg/x64_dbg_dbg.vcxproj.filters @@ -273,6 +273,9 @@ Source Files\Analysis + + Source Files\Analysis + @@ -626,5 +629,8 @@ Header Files\Analysis + + Header Files\Analysis + \ No newline at end of file