Merge remote-tracking branch 'nukem/master'
Conflicts: x64_dbg_dbg/plugin_loader.cpp
This commit is contained in:
commit
3789fad460
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
};
|
||||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
};
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
};
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
};
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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);
|
||||
};
|
||||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
#include "_global.h"
|
||||
#include <objbase.h>
|
||||
#include <shlobj.h>
|
||||
#include <new>
|
||||
|
||||
/**
|
||||
\brief x64dbg library instance.
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#include "_global.h"
|
||||
|
||||
void Analyse_nukem(uint base, uint size);
|
||||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
#include "console.h"
|
||||
#include "capstone_wrapper.h"
|
||||
#include "TitanEngine\TitanEngine.h"
|
||||
|
||||
csh Capstone::mHandle = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -7,8 +7,6 @@
|
|||
#include "command.h"
|
||||
#include "value.h"
|
||||
#include "console.h"
|
||||
#include "debugger.h"
|
||||
#include "math.h"
|
||||
#include "commandparser.h"
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
#include "controlflowanalysis.h"
|
||||
#include "memory.h"
|
||||
#include "console.h"
|
||||
|
||||
ControlFlowAnalysis::ControlFlowAnalysis(uint base, uint size) : Analysis(base, size)
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
*/
|
||||
|
||||
#include "disasm_fast.h"
|
||||
#include "debugger.h"
|
||||
#include "memory.h"
|
||||
|
||||
static MEMORY_SIZE argsize2memsize(int argsize)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#include "error.h"
|
||||
#include <unordered_map>
|
||||
#include "error.h"
|
||||
|
||||
std::unordered_map<unsigned int, const char*> ErrorNames;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#include "exception.h"
|
||||
#include <unordered_map>
|
||||
#include "exception.h"
|
||||
|
||||
std::unordered_map<unsigned int, const char*> ExceptionNames;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
#include "function.h"
|
||||
#include "module.h"
|
||||
#include "debugger.h"
|
||||
#include "memory.h"
|
||||
#include "threading.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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[]);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
#include "threading.h"
|
||||
#include "module.h"
|
||||
#include "memory.h"
|
||||
#include "debugger.h"
|
||||
|
||||
std::unordered_map<uint, LABELSINFO> labels;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
#include "loop.h"
|
||||
#include "debugger.h"
|
||||
#include "memory.h"
|
||||
#include "threading.h"
|
||||
#include "module.h"
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
#include "msgqueue.h"
|
||||
#include <stdio.h>
|
||||
|
||||
//allocate a message (internal)
|
||||
static MESSAGE* msgalloc()
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
*/
|
||||
|
||||
#include "patches.h"
|
||||
#include "addrinfo.h"
|
||||
#include "memory.h"
|
||||
#include "debugger.h"
|
||||
#include "console.h"
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
*/
|
||||
|
||||
#include "reference.h"
|
||||
#include "debugger.h"
|
||||
#include "memory.h"
|
||||
#include "console.h"
|
||||
#include "module.h"
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
#include "stringformat.h"
|
||||
#include "console.h"
|
||||
#include "value.h"
|
||||
#include "disasm_helper.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
#include "symbolinfo.h"
|
||||
#include "debugger.h"
|
||||
#include "addrinfo.h"
|
||||
#include "console.h"
|
||||
#include "module.h"
|
||||
#include "label.h"
|
||||
|
|
|
|||
|
|
@ -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++;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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" />
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -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) { \
|
||||
|
|
|
|||
Loading…
Reference in New Issue