1
0
Fork 0

Merge remote-tracking branch 'nukem/master'

Conflicts:
	x64_dbg_dbg/plugin_loader.cpp
This commit is contained in:
Mr. eXoDia 2015-07-11 23:52:12 +02:00
commit 3789fad460
50 changed files with 1387 additions and 209 deletions

View File

@ -0,0 +1,95 @@
#include <assert.h>
#include <thread>
#include "AnalysisPass.h"
#include "memory.h"
AnalysisPass::AnalysisPass(uint VirtualStart, uint VirtualEnd, BBlockArray & MainBlocks) : m_MainBlocks(MainBlocks)
{
assert(VirtualEnd > VirtualStart);
// Internal class data
m_VirtualStart = VirtualStart;
m_VirtualEnd = VirtualEnd;
m_InternalMaxThreads = 0;
// 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);
assert(false);
}
}
AnalysisPass::~AnalysisPass()
{
if(m_Data)
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;
}
uint AnalysisPass::FindBBlockIndex(BasicBlock* Block)
{
// Fast pointer arithmetic to find index
return ((uint)Block - (uint)m_MainBlocks.data()) / sizeof(BasicBlock);
}
uint AnalysisPass::IdealThreadCount()
{
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;
SetIdealThreadCount(maximumThreads);
}
return m_InternalMaxThreads;
}
void AnalysisPass::SetIdealThreadCount(uint Count)
{
m_InternalMaxThreads = (BYTE)min(Count, 255);
}

View File

@ -0,0 +1,41 @@
#pragma once
#include "_global.h"
#include "BasicBlock.h"
class AnalysisPass
{
public:
AnalysisPass(uint VirtualStart, uint VirtualEnd, BBlockArray & MainBlocks);
virtual ~AnalysisPass();
virtual const char* GetName() = 0;
virtual bool Analyse() = 0;
protected:
uint m_VirtualStart;
uint m_VirtualEnd;
uint m_DataSize;
unsigned char* m_Data;
BBlockArray & m_MainBlocks;
inline unsigned char* AnalysisPass::TranslateAddress(uint Address)
{
assert(ValidateAddress(Address));
return &m_Data[Address - m_VirtualStart];
}
inline bool AnalysisPass::ValidateAddress(uint Address)
{
return (Address >= m_VirtualStart && Address < m_VirtualEnd);
}
BasicBlock* FindBBlockInRange(uint Address);
uint FindBBlockIndex(BasicBlock* Block);
uint IdealThreadCount();
void SetIdealThreadCount(uint Count);
private:
BYTE m_InternalMaxThreads;
};

80
x64_dbg_dbg/BasicBlock.h Normal file
View File

@ -0,0 +1,80 @@
#pragma once
#include "_global.h"
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_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
{
uint VirtualStart; // Inclusive
uint VirtualEnd; // Exclusive
uint Flags;
uint Target;
__forceinline bool GetFlag(uint Flag)
{
return (Flags & Flag) == Flag;
}
__forceinline void SetFlag(uint Flag)
{
Flags |= Flag;
}
__forceinline uint Size()
{
return VirtualEnd - VirtualStart;
}
bool operator< (const BasicBlock & b) const
{
return VirtualStart < b.VirtualStart;
}
bool operator== (const BasicBlock & b) const
{
return VirtualStart == b.VirtualStart;
}
};
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;
}
bool operator== (const FunctionDef & b) const
{
return VirtualStart == b.VirtualStart;
}
};
typedef std::vector<BasicBlock> BBlockArray;
typedef std::vector<FunctionDef> FuncDefArray;

View File

@ -0,0 +1,92 @@
#include "AnalysisPass.h"
#include "CodeFollowPass.h"
CodeFollowPass::CodeFollowPass(uint VirtualStart, uint VirtualEnd, BBlockArray & MainBlocks)
: AnalysisPass(VirtualStart, VirtualEnd, MainBlocks)
{
}
CodeFollowPass::~CodeFollowPass()
{
}
const char* CodeFollowPass::GetName()
{
return "Code Follower";
}
bool CodeFollowPass::Analyse()
{
// First gather all possible function references with certain tables
//
// This includes:
// Main entry
// Module exports
// Module import references (?)
// Control flow guard
// RUNTIME_FUNCTION
// TLS callbacks
// FLS callbacks
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;
}

View File

@ -0,0 +1,19 @@
#pragma once
#include "AnalysisPass.h"
#include "BasicBlock.h"
#include "capstone_wrapper.h"
class CodeFollowPass : public AnalysisPass
{
public:
CodeFollowPass(uint VirtualStart, uint VirtualEnd, BBlockArray & MainBlocks);
virtual ~CodeFollowPass();
virtual const char* GetName() override;
virtual bool Analyse() override;
private:
uint GetReferenceOperand(const cs_x86 & Context);
uint GetMemoryOperand(Capstone & Disasm, const cs_x86 & Context, bool* Indirect);
};

View File

@ -0,0 +1,338 @@
#include "FunctionPass.h"
#include <ppl.h>
#include "memory.h"
#include "console.h"
#include "debugger.h"
#include "module.h"
#include "function.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);
// 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);
}
}
}
}
FunctionPass::~FunctionPass()
{
if(m_FunctionInfo)
BridgeFree(m_FunctionInfo);
}
const char* FunctionPass::GetName()
{
return "Function Analysis";
}
bool FunctionPass::Analyse()
{
// THREAD_WORK = ceil(TOTAL / # THREADS)
uint workAmount = (m_MainBlocks.size() + (IdealThreadCount() - 1)) / IdealThreadCount();
// Initialize thread vector
auto threadFunctions = new std::vector<FunctionDef>[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(30000);
// Execute
AnalysisWorker(threadWorkStart, threadWorkStop, &threadFunctions[i]);
});
std::vector<FunctionDef> 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;
}
void FunctionPass::AnalysisWorker(uint Start, uint End, std::vector<FunctionDef>* Blocks)
{
// 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
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;
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 = 0;
def.BBlockStart = 0;
def.BBlockEnd = 0;
Blocks->push_back(def);
}
}
// Step 3: Sort and remove duplicates
std::sort(Blocks->begin(), Blocks->end());
Blocks->erase(std::unique(Blocks->begin(), Blocks->end()), Blocks->end());
// 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<FunctionDef>* Blocks)
{
#ifdef _WIN64
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)
{
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;
});
#endif // _WIN64
}
void FunctionPass::FindFunctionWorker(std::vector<FunctionDef>* Blocks)
{
// Cached final block
BasicBlock* finalBlock = &m_MainBlocks.back();
// 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;
}
// 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;
}
#ifdef _WIN64
void FunctionPass::EnumerateFunctionRuntimeEntries64(std::function<bool (PRUNTIME_FUNCTION)> Callback)
{
if(!m_FunctionInfo)
return;
// Get the table pointer and size
auto functionTable = (PRUNTIME_FUNCTION)m_FunctionInfo;
ULONG totalCount = (m_FunctionInfoSize / sizeof(RUNTIME_FUNCTION));
// Enumerate each entry
for(ULONG i = 0; i < totalCount; i++)
{
if(!Callback(&functionTable[i]))
break;
}
}
#endif // _WIN64

View File

@ -0,0 +1,32 @@
#pragma once
#include <functional>
#include "AnalysisPass.h"
#include "BasicBlock.h"
class FunctionPass : public AnalysisPass
{
public:
FunctionPass(uint VirtualStart, uint VirtualEnd, BBlockArray & MainBlocks);
virtual ~FunctionPass();
virtual const char* GetName() override;
virtual bool Analyse() override;
private:
uint m_ModuleStart;
PVOID m_FunctionInfo;
ULONG m_FunctionInfoSize;
void AnalysisWorker(uint Start, uint End, std::vector<FunctionDef>* Blocks);
void FindFunctionWorkerPrepass(uint Start, uint End, std::vector<FunctionDef>* Blocks);
void FindFunctionWorker(std::vector<FunctionDef>* Blocks);
bool ResolveKnownFunctionEnd(FunctionDef* Function);
bool ResolveFunctionEnd(FunctionDef* Function, BasicBlock* LastBlock);
#ifdef _WIN64
void EnumerateFunctionRuntimeEntries64(std::function<bool(PRUNTIME_FUNCTION)> Callback);
#endif // _WIN64
};

View File

@ -0,0 +1,77 @@
#include <thread>
#include "AnalysisPass.h"
#include "Int3CoagulatorPass.h"
#include "console.h"
Int3CoagulatorPass::Int3CoagulatorPass(uint VirtualStart, uint VirtualEnd, BBlockArray & MainBlocks)
: AnalysisPass(VirtualStart, VirtualEnd, MainBlocks)
{
}
Int3CoagulatorPass::~Int3CoagulatorPass()
{
}
const char* Int3CoagulatorPass::GetName()
{
return "INT3 Group Combiner - DEPRECATED";
}
bool Int3CoagulatorPass::Analyse()
{
// 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<BasicBlock>* 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_PAD))
{
// 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_PAD);
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);
}
}

View File

@ -0,0 +1,17 @@
#pragma once
#include "AnalysisPass.h"
#include "BasicBlock.h"
class Int3CoagulatorPass : public AnalysisPass
{
public:
Int3CoagulatorPass(uint VirtualStart, uint VirtualEnd, BBlockArray & MainBlocks);
virtual ~Int3CoagulatorPass();
virtual const char* GetName() override;
virtual bool Analyse() override;
private:
void AnalysisWorker(uint Start, uint End, BBlockArray* Blocks);
};

327
x64_dbg_dbg/LinearPass.cpp Normal file
View File

@ -0,0 +1,327 @@
#include <thread>
#include <ppl.h>
#include "AnalysisPass.h"
#include "LinearPass.h"
#include "capstone_wrapper.h"
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()
{
}
const char* LinearPass::GetName()
{
return "Linear Scandown";
}
bool LinearPass::Analyse()
{
// Divide the work up between each thread
// THREAD_WORK = (TOTAL / # THREADS)
uint workAmount = m_DataSize / IdealThreadCount();
// Initialize thread vector
auto threadBlocks = new std::vector<BasicBlock>[IdealThreadCount()];
concurrency::parallel_for(uint(0), IdealThreadCount(), [&](uint i)
{
uint threadWorkStart = m_VirtualStart + (workAmount * i);
uint threadWorkStop = min((threadWorkStart + workAmount), m_VirtualEnd);
// Allow a 256-byte variance of scanning because of
// integer rounding errors and instruction overlap
if(threadWorkStart > m_VirtualStart)
{
threadWorkStart = max((threadWorkStart - 256), m_VirtualStart);
threadWorkStop = min((threadWorkStop + 256), m_VirtualEnd);
}
// Memory allocation optimization
// TODO: Option to conserve memory
threadBlocks[i].reserve(100000);
// Execute
AnalysisWorker(threadWorkStart, threadWorkStop, &threadBlocks[i]);
});
// Clear old data and combine vectors
m_MainBlocks.clear();
for(uint i = 0; i < IdealThreadCount(); i++)
{
std::move(threadBlocks[i].begin(), threadBlocks[i].end(), std::back_inserter(m_MainBlocks));
// Free old elements to conserve memory further
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());
// Run overlap analysis sub-pass
AnalyseOverlaps();
return true;
}
void LinearPass::AnalyseOverlaps()
{
// 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<BasicBlock>[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), workTotal);
}
// Execute
AnalysisOverlapWorker(threadWorkStart, threadWorkStop, &threadInserts[i]);
});
// THREAD VECTOR
std::vector<BasicBlock> 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 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;)
{
if(!disasm.Disassemble(i, TranslateAddress(i)))
{
// Skip instructions that can't be determined
i++;
continue;
}
// 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
bool jmp = disasm.InGroup(CS_GRP_JUMP); // JUMP
bool ret = disasm.InGroup(CS_GRP_RET); // RETURN
bool padding = disasm.IsFilling(); // INSTRUCTION PADDING
if(padding)
{
// PADDING is 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. Rare case.
lastBlock = CreateBlockWorker(Blocks, blockBegin, realBlockEnd, false, false, false, false);
lastBlock->SetFlag(BASIC_BLOCK_FLAG_PREPAD);
blockBegin = realBlockEnd;
}
}
if(call || jmp || ret || padding)
{
// Was this a padding instruction?
if(padding && blockPrevPad)
{
// Append it to the previous block
lastBlock->VirtualEnd = blockEnd;
}
else
{
// Otherwise use the default route: create a new entry
auto block = lastBlock = CreateBlockWorker(Blocks, blockBegin, blockEnd, call, jmp, ret, padding);
// Figure out the operand type
auto operand = disasm.x86().operands[0];
if(operand.type == X86_OP_IMM)
{
// Branch target immediate
block->Target = operand.imm;
// Check if absolute jump
if(disasm.GetId() == X86_INS_JMP)
block->SetFlag(BASIC_BLOCK_FLAG_ABSJMP);
}
else
{
// Indirects
block->SetFlag(BASIC_BLOCK_FLAG_INDIRECT);
if(operand.type == X86_OP_MEM &&
operand.mem.base == X86_REG_INVALID &&
operand.mem.index == X86_REG_INVALID &&
operand.mem.scale == 1)
{
block->SetFlag(BASIC_BLOCK_FLAG_INDIRPTR);
block->Target = operand.mem.disp;
}
}
}
// Reset the loop variables
blockBegin = i;
blockPrevPad = padding;
}
}
}
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; 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<BasicBlock>* Blocks, uint Start, uint End, bool Call, bool Jmp, bool Ret, bool Pad)
{
BasicBlock block;
block.VirtualStart = Start;
block.VirtualEnd = End;
block.Flags = 0;
block.Target = 0;
// 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(Pad)
block.SetFlag(BASIC_BLOCK_FLAG_PAD);
Blocks->push_back(block);
return &Blocks->back();
}

20
x64_dbg_dbg/LinearPass.h Normal file
View File

@ -0,0 +1,20 @@
#pragma once
#include "AnalysisPass.h"
#include "BasicBlock.h"
class LinearPass : public AnalysisPass
{
public:
LinearPass(uint VirtualStart, uint VirtualEnd, BBlockArray & MainBlocks);
virtual ~LinearPass();
virtual const char* GetName() override;
virtual bool Analyse() override;
void AnalyseOverlaps();
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 Pad);
};

View File

@ -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"

View File

@ -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"

View File

@ -6,7 +6,6 @@
#include "_global.h"
#include <objbase.h>
#include <shlobj.h>
#include <new>
/**
\brief x64dbg library instance.

View File

@ -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"

View File

@ -1,25 +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;
#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;
}

View File

@ -1,26 +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);
};
#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

View File

@ -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);
}

View File

@ -0,0 +1,5 @@
#pragma once
#include "_global.h"
void Analyse_nukem(uint base, uint size);

View File

@ -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)
{

View File

@ -1,7 +1,6 @@
#include "bookmark.h"
#include "threading.h"
#include "module.h"
#include "debugger.h"
#include "memory.h"
std::unordered_map<uint, BOOKMARKSINFO> bookmarks;

View File

@ -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"

View File

@ -1,6 +1,5 @@
#include "console.h"
#include "capstone_wrapper.h"
#include "TitanEngine\TitanEngine.h"
csh Capstone::mHandle = 0;

View File

@ -7,8 +7,6 @@
#include "command.h"
#include "value.h"
#include "console.h"
#include "debugger.h"
#include "math.h"
#include "commandparser.h"
/**

View File

@ -1,7 +1,6 @@
#include "comment.h"
#include "threading.h"
#include "module.h"
#include "debugger.h"
#include "memory.h"
std::unordered_map<uint, COMMENTSINFO> comments;

View File

@ -1,5 +1,4 @@
#include "controlflowanalysis.h"
#include "memory.h"
#include "console.h"
ControlFlowAnalysis::ControlFlowAnalysis(uint base, uint size) : Analysis(base, size)

View File

@ -5,7 +5,6 @@
*/
#include "disasm_fast.h"
#include "debugger.h"
#include "memory.h"
static MEMORY_SIZE argsize2memsize(int argsize)

View File

@ -7,10 +7,7 @@
#include "disasm_helper.h"
#include "value.h"
#include "console.h"
#include "debugger.h"
#include "memory.h"
#include <cwctype>
#include <cwchar>
#include "capstone_wrapper.h"
uint disasmback(unsigned char* data, uint base, uint size, uint ip, int n)

View File

@ -1,5 +1,5 @@
#include "error.h"
#include <unordered_map>
#include "error.h"
std::unordered_map<unsigned int, const char*> ErrorNames;

View File

@ -1,5 +1,5 @@
#include "exception.h"
#include <unordered_map>
#include "exception.h"
std::unordered_map<unsigned int, const char*> ExceptionNames;

View File

@ -1,6 +1,5 @@
#include "function.h"
#include "module.h"
#include "debugger.h"
#include "memory.h"
#include "threading.h"

View File

@ -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;

View File

@ -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[]);

View File

@ -2,7 +2,6 @@
#include "threading.h"
#include "module.h"
#include "memory.h"
#include "debugger.h"
std::unordered_map<uint, LABELSINFO> labels;

View File

@ -1,5 +1,4 @@
#include "loop.h"
#include "debugger.h"
#include "memory.h"
#include "threading.h"
#include "module.h"

View File

@ -7,7 +7,6 @@
#include "memory.h"
#include "debugger.h"
#include "patches.h"
#include "console.h"
#include "threading.h"
#include "module.h"
@ -23,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<MEMPAGE> 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();
@ -125,15 +142,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));
}
}
@ -160,7 +176,6 @@ uint MemFindBaseAddr(uint Address, uint* Size, bool Refresh)
bool MemRead(const void* BaseAddress, void* Buffer, SIZE_T Size, SIZE_T* NumberOfBytesRead)
{
// Fast fail if address is invalid
if(!MemIsCanonicalAddress((uint)BaseAddress))
return false;
@ -215,7 +230,6 @@ bool MemRead(const void* BaseAddress, void* Buffer, SIZE_T Size, SIZE_T* NumberO
bool MemWrite(void* BaseAddress, const void* Buffer, SIZE_T Size, SIZE_T* NumberOfBytesWritten)
{
// Fast fail if address is invalid
if(!MemIsCanonicalAddress((uint)BaseAddress))
return false;
@ -309,7 +323,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)

View File

@ -1,5 +1,4 @@
#include "msgqueue.h"
#include <stdio.h>
//allocate a message (internal)
static MESSAGE* msgalloc()

View File

@ -5,7 +5,6 @@
*/
#include "patches.h"
#include "addrinfo.h"
#include "memory.h"
#include "debugger.h"
#include "console.h"

View File

@ -5,7 +5,6 @@
*/
#include "reference.h"
#include "debugger.h"
#include "memory.h"
#include "console.h"
#include "module.h"

View File

@ -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<LINEMAPENTRY> linemap;

View File

@ -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"

View File

@ -1,5 +1,4 @@
#include "stringformat.h"
#include "console.h"
#include "value.h"
#include "disasm_helper.h"

View File

@ -1,7 +1,6 @@
#include <sstream>
#include "stringutils.h"
#include "memory.h"
#include <iostream>
#include <sstream>
StringList StringUtils::Split(const String & s, char delim, std::vector<String> & elems)
{

View File

@ -6,7 +6,6 @@
#include "symbolinfo.h"
#include "debugger.h"
#include "addrinfo.h"
#include "console.h"
#include "module.h"
#include "label.h"

View File

@ -5,12 +5,10 @@
*/
#include "thread.h"
#include "console.h"
#include "undocumented.h"
#include "memory.h"
#include "threading.h"
static std::vector<THREADINFO> threadList;
static std::unordered_map<DWORD, THREADINFO> threadList;
void ThreadCreate(CREATE_THREAD_DEBUG_INFO* CreateThread)
{
@ -29,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
@ -40,15 +38,11 @@ void ThreadExit(DWORD ThreadId)
{
EXCLUSIVE_ACQUIRE(LockThreads);
// Don't use a foreach loop here because of the erase() call
for(auto itr = threadList.begin(); itr != threadList.end(); ++itr)
{
if(itr->ThreadId == 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();
@ -71,11 +65,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;
}
@ -87,22 +83,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));
@ -117,14 +113,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)
@ -171,11 +160,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;
}
@ -185,16 +171,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;
@ -204,15 +187,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)
@ -222,17 +200,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()
@ -245,7 +218,7 @@ int ThreadSuspendAll()
int count = 0;
for(auto & entry : threadList)
{
if(SuspendThread(entry.Handle) != -1)
if(SuspendThread(entry.second.Handle) != -1)
count++;
}
@ -262,7 +235,7 @@ int ThreadResumeAll()
int count = 0;
for(auto & entry : threadList)
{
if(ResumeThread(entry.Handle) != -1)
if(ResumeThread(entry.second.Handle) != -1)
count++;
}

View File

@ -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"

View File

@ -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"
@ -192,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\1analyze_nukem\1anal_nukem", cbInstrAnalyseNukem, true); //secret analysis command #2
//undocumented
dbgcmdnew("bench", cbDebugBenchmark, true); //benchmark test (readmem etc)

View File

@ -21,10 +21,13 @@
<ItemGroup>
<ClCompile Include="addrinfo.cpp" />
<ClCompile Include="analysis.cpp" />
<ClCompile Include="AnalysisPass.cpp" />
<ClCompile Include="analysis_nukem.cpp" />
<ClCompile Include="assemble.cpp" />
<ClCompile Include="bookmark.cpp" />
<ClCompile Include="breakpoint.cpp" />
<ClCompile Include="capstone_wrapper.cpp" />
<ClCompile Include="CodeFollowPass.cpp" />
<ClCompile Include="command.cpp" />
<ClCompile Include="commandparser.cpp" />
<ClCompile Include="comment.cpp" />
@ -41,8 +44,11 @@
<ClCompile Include="filereader.cpp" />
<ClCompile Include="function.cpp" />
<ClCompile Include="functionanalysis.cpp" />
<ClCompile Include="FunctionPass.cpp" />
<ClCompile Include="instruction.cpp" />
<ClCompile Include="Int3CoagulatorPass.cpp" />
<ClCompile Include="label.cpp" />
<ClCompile Include="LinearPass.cpp" />
<ClCompile Include="loop.cpp" />
<ClCompile Include="main.cpp" />
<ClCompile Include="memory.cpp" />
@ -80,7 +86,10 @@
<ItemGroup>
<ClInclude Include="addrinfo.h" />
<ClInclude Include="analysis.h" />
<ClInclude Include="AnalysisPass.h" />
<ClInclude Include="analysis_nukem.h" />
<ClInclude Include="assemble.h" />
<ClInclude Include="BasicBlock.h" />
<ClInclude Include="bookmark.h" />
<ClInclude Include="breakpoint.h" />
<ClInclude Include="capstone\arm.h" />
@ -94,6 +103,7 @@
<ClInclude Include="capstone\x86.h" />
<ClInclude Include="capstone\xcore.h" />
<ClInclude Include="capstone_wrapper.h" />
<ClInclude Include="CodeFollowPass.h" />
<ClInclude Include="command.h" />
<ClInclude Include="commandparser.h" />
<ClInclude Include="comment.h" />
@ -113,12 +123,15 @@
<ClInclude Include="filereader.h" />
<ClInclude Include="function.h" />
<ClInclude Include="functionanalysis.h" />
<ClInclude Include="FunctionPass.h" />
<ClInclude Include="handle.h" />
<ClInclude Include="instruction.h" />
<ClInclude Include="Int3CoagulatorPass.h" />
<ClInclude Include="jansson\jansson.h" />
<ClInclude Include="jansson\jansson_config.h" />
<ClInclude Include="jansson\jansson_x64dbg.h" />
<ClInclude Include="label.h" />
<ClInclude Include="LinearPass.h" />
<ClInclude Include="loop.h" />
<ClInclude Include="lz4\lz4.h" />
<ClInclude Include="lz4\lz4file.h" />

View File

@ -243,20 +243,38 @@
<ClCompile Include="_scriptapi_gui.cpp">
<Filter>Source Files\Interfaces/Exports\_scriptapi</Filter>
</ClCompile>
<ClCompile Include="controlflowanalysis.cpp">
<ClCompile Include="AnalysisPass.cpp">
<Filter>Source Files\Analysis</Filter>
</ClCompile>
<ClCompile Include="LinearPass.cpp">
<Filter>Source Files\Analysis</Filter>
</ClCompile>
<ClCompile Include="CodeFollowPass.cpp">
<Filter>Source Files\Analysis</Filter>
</ClCompile>
<ClCompile Include="FunctionPass.cpp">
<Filter>Source Files\Analysis</Filter>
</ClCompile>
<ClCompile Include="Int3CoagulatorPass.cpp">
<Filter>Source Files\Analysis</Filter>
</ClCompile>
<ClCompile Include="controlflowanalysis.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="_scriptapi_assembler.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="_scriptapi_misc.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="_scriptapi_stack.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="analysis.cpp">
<Filter>Source Files\Analysis</Filter>
</ClCompile>
<ClCompile Include="_scriptapi_assembler.cpp">
<Filter>Source Files\Interfaces/Exports\_scriptapi</Filter>
</ClCompile>
<ClCompile Include="_scriptapi_misc.cpp">
<Filter>Source Files\Interfaces/Exports\_scriptapi</Filter>
</ClCompile>
<ClCompile Include="_scriptapi_stack.cpp">
<Filter>Source Files\Interfaces/Exports\_scriptapi</Filter>
<ClCompile Include="analysis_nukem.cpp">
<Filter>Source Files\Analysis</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
@ -578,20 +596,41 @@
<ClInclude Include="_scriptapi_gui.h">
<Filter>Header Files\Interfaces/Exports\_scriptapi</Filter>
</ClInclude>
<ClInclude Include="controlflowanalysis.h">
<ClInclude Include="BasicBlock.h">
<Filter>Header Files\Analysis</Filter>
</ClInclude>
<ClInclude Include="AnalysisPass.h">
<Filter>Header Files\Analysis</Filter>
</ClInclude>
<ClInclude Include="LinearPass.h">
<Filter>Header Files\Analysis</Filter>
</ClInclude>
<ClInclude Include="CodeFollowPass.h">
<Filter>Header Files\Analysis</Filter>
</ClInclude>
<ClInclude Include="FunctionPass.h">
<Filter>Header Files\Analysis</Filter>
</ClInclude>
<ClInclude Include="Int3CoagulatorPass.h">
<Filter>Header Files\Analysis</Filter>
</ClInclude>
<ClInclude Include="controlflowanalysis.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="_scriptapi_assembler.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="_scriptapi_misc.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="_scriptapi_stack.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="analysis.h">
<Filter>Header Files\Analysis</Filter>
</ClInclude>
<ClInclude Include="_scriptapi_assembler.h">
<Filter>Header Files\Interfaces/Exports\_scriptapi</Filter>
</ClInclude>
<ClInclude Include="_scriptapi_misc.h">
<Filter>Header Files\Interfaces/Exports\_scriptapi</Filter>
</ClInclude>
<ClInclude Include="_scriptapi_stack.h">
<Filter>Header Files\Interfaces/Exports\_scriptapi</Filter>
<ClInclude Include="analysis_nukem.h">
<Filter>Header Files\Analysis</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -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) { \