Merge branch 'master' of https://github.com/x64dbg/x64dbg
This commit is contained in:
commit
6dfcfd99e7
|
@ -16,7 +16,7 @@ AnalysisPass::AnalysisPass(uint VirtualStart, uint VirtualEnd, BBlockArray & Mai
|
|||
m_DataSize = VirtualEnd - VirtualStart;
|
||||
m_Data = (unsigned char*)BridgeAlloc(m_DataSize);
|
||||
|
||||
if(!MemRead(VirtualStart, m_Data, m_DataSize, nullptr))
|
||||
if(!MemRead(VirtualStart, m_Data, m_DataSize))
|
||||
{
|
||||
BridgeFree(m_Data);
|
||||
assert(false);
|
||||
|
|
|
@ -50,7 +50,7 @@ FunctionPass::FunctionPass(uint VirtualStart, uint VirtualEnd, BBlockArray & Mai
|
|||
m_FunctionInfo = BridgeAlloc(m_FunctionInfoSize);
|
||||
|
||||
if(m_FunctionInfo)
|
||||
MemRead(virtualOffset + m_ModuleStart, m_FunctionInfo, m_FunctionInfoSize, nullptr);
|
||||
MemRead(virtualOffset + m_ModuleStart, m_FunctionInfo, m_FunctionInfoSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -98,6 +98,8 @@ bool FunctionPass::Analyse()
|
|||
std::sort(funcs.begin(), funcs.end());
|
||||
funcs.erase(std::unique(funcs.begin(), funcs.end()), funcs.end());
|
||||
|
||||
dprintf("%u functions\n", funcs.size());
|
||||
|
||||
FunctionClear();
|
||||
for(auto & func : funcs)
|
||||
{
|
||||
|
@ -130,7 +132,7 @@ void FunctionPass::AnalysisWorker(uint Start, uint End, std::vector<FunctionDef>
|
|||
if(blockItr->GetFlag(BASIC_BLOCK_FLAG_INDIRPTR))
|
||||
{
|
||||
// Read it from memory
|
||||
if(!MemRead(destination, &destination, sizeof(uint), nullptr))
|
||||
if(!MemRead(destination, &destination, sizeof(uint)))
|
||||
continue;
|
||||
|
||||
// Validity check
|
||||
|
@ -168,6 +170,7 @@ void FunctionPass::AnalysisWorker(uint Start, uint End, std::vector<FunctionDef>
|
|||
|
||||
void FunctionPass::FindFunctionWorkerPrepass(uint Start, uint End, std::vector<FunctionDef>* Blocks)
|
||||
{
|
||||
return;
|
||||
const uint minFunc = std::next(m_MainBlocks.begin(), Start)->VirtualStart;
|
||||
const uint maxFunc = std::next(m_MainBlocks.begin(), End - 1)->VirtualEnd;
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ extern "C" DLL_EXPORT bool _dbg_memread(duint addr, unsigned char* dest, duint s
|
|||
|
||||
extern "C" DLL_EXPORT bool _dbg_memwrite(duint addr, const unsigned char* src, duint size, duint* written)
|
||||
{
|
||||
return MemWrite(addr, (void*)src, size, written);
|
||||
return MemWrite(addr, src, size, written);
|
||||
}
|
||||
|
||||
extern "C" DLL_EXPORT bool _dbg_memmap(MEMMAP* memmap)
|
||||
|
@ -134,7 +134,7 @@ extern "C" DLL_EXPORT bool _dbg_addrinfoget(duint addr, SEGMENTREG segment, ADDR
|
|||
if(disasmfast(addr, &basicinfo) && basicinfo.branch && !basicinfo.call && basicinfo.memory.value) //thing is a JMP
|
||||
{
|
||||
uint val = 0;
|
||||
if(MemRead(basicinfo.memory.value, &val, sizeof(val), 0))
|
||||
if(MemRead(basicinfo.memory.value, &val, sizeof(val)))
|
||||
{
|
||||
if(SafeSymFromAddr(fdProcessInfo->hProcess, (DWORD64)val, &displacement, pSymbol) && !displacement)
|
||||
{
|
||||
|
@ -785,6 +785,8 @@ extern "C" DLL_EXPORT uint _dbg_sendmessage(DBGMSG type, void* param1, void* par
|
|||
entry = strtok(0, ",");
|
||||
}
|
||||
}
|
||||
|
||||
BridgeSettingGet("Symbols", "CachePath", szSymbolCachePath);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ SCRIPT_EXPORT bool Script::Memory::IsValidPtr(duint addr)
|
|||
|
||||
SCRIPT_EXPORT duint Script::Memory::RemoteAlloc(duint addr, duint size)
|
||||
{
|
||||
return (duint)MemAllocRemote(addr, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
|
||||
return (duint)MemAllocRemote(addr, size);
|
||||
}
|
||||
|
||||
SCRIPT_EXPORT bool Script::Memory::RemoteFree(duint addr)
|
||||
|
|
|
@ -10,7 +10,7 @@ SCRIPT_EXPORT duint Script::Pattern::Find(unsigned char* data, duint datasize, c
|
|||
SCRIPT_EXPORT duint Script::Pattern::FindMem(duint start, duint size, const char* pattern)
|
||||
{
|
||||
Memory<unsigned char*> data(size, "Script::Pattern::FindMem::data");
|
||||
if(!MemRead(start, data(), size, nullptr))
|
||||
if(!MemRead(start, data(), size))
|
||||
return -1;
|
||||
return Pattern::Find(data(), data.size(), pattern) + start;
|
||||
}
|
||||
|
@ -23,10 +23,10 @@ SCRIPT_EXPORT void Script::Pattern::Write(unsigned char* data, duint datasize, c
|
|||
SCRIPT_EXPORT void Script::Pattern::WriteMem(duint start, duint size, const char* pattern)
|
||||
{
|
||||
Memory<unsigned char*> data(size, "Script::Pattern::WriteMem::data");
|
||||
if(!MemRead(start, data(), data.size(), nullptr))
|
||||
if(!MemRead(start, data(), data.size()))
|
||||
return;
|
||||
patternwrite(data(), data.size(), pattern);
|
||||
MemWrite(start, data(), data.size(), nullptr);
|
||||
MemWrite(start, data(), data.size());
|
||||
}
|
||||
|
||||
SCRIPT_EXPORT bool Script::Pattern::SearchAndReplace(unsigned char* data, duint datasize, const char* searchpattern, const char* replacepattern)
|
||||
|
@ -37,12 +37,12 @@ SCRIPT_EXPORT bool Script::Pattern::SearchAndReplace(unsigned char* data, duint
|
|||
SCRIPT_EXPORT bool Script::Pattern::SearchAndReplaceMem(duint start, duint size, const char* searchpattern, const char* replacepattern)
|
||||
{
|
||||
Memory<unsigned char*> data(size, "Script::Pattern::SearchAndReplaceMem::data");
|
||||
if(!MemRead(start, data(), size, nullptr))
|
||||
if(!MemRead(start, data(), size))
|
||||
return false;
|
||||
duint found = patternfind(data(), data.size(), searchpattern);
|
||||
if(found == -1)
|
||||
return false;
|
||||
patternwrite(data() + found, data.size() - found, replacepattern);
|
||||
MemWrite((start + found), data() + found, data.size() - found, nullptr);
|
||||
MemWrite((start + found), data() + found, data.size() - found);
|
||||
return true;
|
||||
}
|
|
@ -154,14 +154,14 @@ bool apienumexports(uint base, EXPORTENUMCALLBACK cbEnum)
|
|||
VirtualQueryEx(fdProcessInfo->hProcess, (const void*)base, &mbi, sizeof(mbi));
|
||||
uint size = mbi.RegionSize;
|
||||
Memory<void*> buffer(size, "apienumexports:buffer");
|
||||
if(!MemRead(base, buffer(), size, 0))
|
||||
if(!MemRead(base, buffer(), size))
|
||||
return false;
|
||||
IMAGE_NT_HEADERS* pnth = (IMAGE_NT_HEADERS*)((uint)buffer() + GetPE32DataFromMappedFile((ULONG_PTR)buffer(), 0, UE_PE_OFFSET));
|
||||
uint export_dir_rva = pnth->OptionalHeader.DataDirectory[0].VirtualAddress;
|
||||
uint export_dir_size = pnth->OptionalHeader.DataDirectory[0].Size;
|
||||
IMAGE_EXPORT_DIRECTORY export_dir;
|
||||
memset(&export_dir, 0, sizeof(export_dir));
|
||||
MemRead((export_dir_rva + base), &export_dir, sizeof(export_dir), 0);
|
||||
MemRead((export_dir_rva + base), &export_dir, sizeof(export_dir));
|
||||
unsigned int NumberOfNames = export_dir.NumberOfNames;
|
||||
if(!export_dir.NumberOfFunctions || !NumberOfNames) //no named exports
|
||||
return false;
|
||||
|
@ -170,28 +170,28 @@ bool apienumexports(uint base, EXPORTENUMCALLBACK cbEnum)
|
|||
uint original_name_va = export_dir.Name + base;
|
||||
char original_name[deflen] = "";
|
||||
memset(original_name, 0, sizeof(original_name));
|
||||
MemRead(original_name_va, original_name, deflen, 0);
|
||||
MemRead(original_name_va, original_name, deflen);
|
||||
char* AddrOfFunctions_va = (char*)(export_dir.AddressOfFunctions + base); //not a valid local pointer
|
||||
char* AddrOfNames_va = (char*)(export_dir.AddressOfNames + base); //not a valid local pointer
|
||||
char* AddrOfNameOrdinals_va = (char*)(export_dir.AddressOfNameOrdinals + base); //not a valid local pointer
|
||||
for(DWORD i = 0; i < NumberOfNames; i++)
|
||||
{
|
||||
DWORD curAddrOfName = 0;
|
||||
MemRead((uint)(AddrOfNames_va + sizeof(DWORD)*i), &curAddrOfName, sizeof(DWORD), 0);
|
||||
MemRead((uint)(AddrOfNames_va + sizeof(DWORD)*i), &curAddrOfName, sizeof(DWORD));
|
||||
char* cur_name_va = (char*)(curAddrOfName + base);
|
||||
char cur_name[deflen] = "";
|
||||
memset(cur_name, 0, deflen);
|
||||
MemRead((uint)cur_name_va, cur_name, deflen, 0);
|
||||
MemRead((uint)cur_name_va, cur_name, deflen);
|
||||
WORD curAddrOfNameOrdinals = 0;
|
||||
MemRead((uint)(AddrOfNameOrdinals_va + sizeof(WORD)*i), &curAddrOfNameOrdinals, sizeof(WORD), 0);
|
||||
MemRead((uint)(AddrOfNameOrdinals_va + sizeof(WORD)*i), &curAddrOfNameOrdinals, sizeof(WORD));
|
||||
DWORD curFunctionRva = 0;
|
||||
MemRead((uint)(AddrOfFunctions_va + sizeof(DWORD)*curAddrOfNameOrdinals), &curFunctionRva, sizeof(DWORD), 0);
|
||||
MemRead((uint)(AddrOfFunctions_va + sizeof(DWORD)*curAddrOfNameOrdinals), &curFunctionRva, sizeof(DWORD));
|
||||
|
||||
if(curFunctionRva >= export_dir_rva && curFunctionRva < export_dir_rva + export_dir_size)
|
||||
{
|
||||
char forwarded_api[deflen] = "";
|
||||
memset(forwarded_api, 0, deflen);
|
||||
MemRead((curFunctionRva + base), forwarded_api, deflen, 0);
|
||||
MemRead((curFunctionRva + base), forwarded_api, deflen);
|
||||
int len = (int)strlen(forwarded_api);
|
||||
int j = 0;
|
||||
while(forwarded_api[j] != '.' && j < len)
|
||||
|
|
|
@ -6,7 +6,7 @@ Analysis::Analysis(uint base, uint size)
|
|||
_base = base;
|
||||
_size = size;
|
||||
_data = new unsigned char[_size + MAX_DISASM_BUFFER];
|
||||
MemRead(_base, _data, _size, 0);
|
||||
MemRead(_base, _data, _size);
|
||||
}
|
||||
|
||||
Analysis::~Analysis()
|
||||
|
|
|
@ -9,7 +9,7 @@ class Analysis
|
|||
public:
|
||||
explicit Analysis(uint base, uint size);
|
||||
Analysis(const Analysis & that) = delete;
|
||||
~Analysis();
|
||||
virtual ~Analysis();
|
||||
virtual void Analyse() = 0;
|
||||
virtual void SetMarkers() = 0;
|
||||
|
||||
|
|
|
@ -67,12 +67,12 @@ bool assembleat(uint addr, const char* instruction, int* size, char* error, bool
|
|||
if(size)
|
||||
*size = destSize;
|
||||
|
||||
bool ret = MemPatch(addr, dest, destSize, 0);
|
||||
bool ret = MemPatch(addr, dest, destSize);
|
||||
if(ret && fillnop && nopsize)
|
||||
{
|
||||
if(size)
|
||||
*size += nopsize;
|
||||
if(!MemPatch((addr + destSize), nops, nopsize, 0))
|
||||
if(!MemPatch((addr + destSize), nops, nopsize))
|
||||
ret = false;
|
||||
}
|
||||
GuiUpdatePatches();
|
||||
|
|
|
@ -1,8 +1,61 @@
|
|||
#include "controlflowanalysis.h"
|
||||
#include "console.h"
|
||||
#include "module.h"
|
||||
#include "TitanEngine/TitanEngine.h"
|
||||
#include "memory.h"
|
||||
|
||||
ControlFlowAnalysis::ControlFlowAnalysis(uint base, uint size) : Analysis(base, size)
|
||||
ControlFlowAnalysis::ControlFlowAnalysis(uint base, uint size, bool exceptionDirectory) : Analysis(base, size)
|
||||
{
|
||||
_functionInfoData = nullptr;
|
||||
#ifdef _WIN64
|
||||
// This will only be valid if the address range is within a loaded module
|
||||
_moduleBase = ModBaseFromAddr(base);
|
||||
|
||||
if(exceptionDirectory && _moduleBase != 0)
|
||||
{
|
||||
char modulePath[MAX_PATH];
|
||||
memset(modulePath, 0, sizeof(modulePath));
|
||||
|
||||
ModPathFromAddr(_moduleBase, 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);
|
||||
_functionInfoSize = (uint)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
|
||||
_functionInfoData = emalloc(_functionInfoSize);
|
||||
|
||||
if(_functionInfoData)
|
||||
MemRead(virtualOffset + _moduleBase, _functionInfoData, _functionInfoSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif //_WIN64
|
||||
}
|
||||
|
||||
ControlFlowAnalysis::~ControlFlowAnalysis()
|
||||
{
|
||||
if(_functionInfoData)
|
||||
efree(_functionInfoData);
|
||||
}
|
||||
|
||||
void ControlFlowAnalysis::Analyse()
|
||||
|
@ -11,9 +64,17 @@ void ControlFlowAnalysis::Analyse()
|
|||
DWORD ticks = GetTickCount();
|
||||
|
||||
BasicBlockStarts();
|
||||
BasicBlocks();
|
||||
dprintf("Basic block starts in %ums!\n", GetTickCount() - ticks);
|
||||
ticks = GetTickCount();
|
||||
|
||||
dprintf("Analysis finished in %ums!\n", GetTickCount() - ticks);
|
||||
BasicBlocks();
|
||||
dprintf("Basic blocks in %ums!\n", GetTickCount() - ticks);
|
||||
ticks = GetTickCount();
|
||||
|
||||
Functions();
|
||||
dprintf("Functions in %ums!\n", GetTickCount() - ticks);
|
||||
|
||||
dprintf("Analysis finished!\n");
|
||||
}
|
||||
|
||||
void ControlFlowAnalysis::SetMarkers()
|
||||
|
@ -21,14 +82,16 @@ void ControlFlowAnalysis::SetMarkers()
|
|||
dprintf("digraph ControlFlow {\n");
|
||||
int i = 0;
|
||||
std::map<uint, int> nodeMap;
|
||||
for(auto block : _blocks)
|
||||
for(const auto & it : _blocks)
|
||||
{
|
||||
const auto & block = it.second;
|
||||
nodeMap.insert({ block.start, i });
|
||||
dprintf(" node%u [label=\"start=%p, end=%p\"];\n", i, block.start, block.end);
|
||||
dprintf(" node%u [label=\"s=%p, e=%p, f=%p\"];\n", i, block.start, block.end, block.function);
|
||||
i++;
|
||||
}
|
||||
for(auto block : _blocks)
|
||||
for(auto it : _blocks)
|
||||
{
|
||||
const auto & block = it.second;
|
||||
int startNode = nodeMap[block.start];
|
||||
if(block.left)
|
||||
{
|
||||
|
@ -65,26 +128,26 @@ void ControlFlowAnalysis::BasicBlockStarts()
|
|||
uint addr = _base + i;
|
||||
if(_cp.Disassemble(addr, TranslateAddress(addr), MAX_DISASM_BUFFER))
|
||||
{
|
||||
if(bSkipFilling) //handle filling skip mode
|
||||
if(bSkipFilling) //handle filling skip mode
|
||||
{
|
||||
if(!_cp.IsFilling()) //do nothing until the filling stopped
|
||||
if(!_cp.IsFilling()) //do nothing until the filling stopped
|
||||
{
|
||||
bSkipFilling = false;
|
||||
_blockStarts.insert(addr);
|
||||
}
|
||||
}
|
||||
else if(_cp.InGroup(CS_GRP_RET) || _cp.InGroup(CS_GRP_INT)) //RET/INT break control flow
|
||||
else if(_cp.InGroup(CS_GRP_RET) || _cp.GetId() == X86_INS_INT3) //RET/INT3 break control flow
|
||||
{
|
||||
bSkipFilling = true; //skip INT3/NOP/whatever filling bytes (those are not part of the control flow)
|
||||
}
|
||||
else if(_cp.InGroup(CS_GRP_JUMP) || _cp.IsLoop()) //branches
|
||||
else if(_cp.InGroup(CS_GRP_JUMP) || _cp.IsLoop()) //branches
|
||||
{
|
||||
uint dest1 = GetBranchOperand();
|
||||
uint dest1 = GetReferenceOperand();
|
||||
uint dest2 = 0;
|
||||
if(_cp.GetId() != X86_INS_JMP) //unconditional jump
|
||||
if(_cp.GetId() != X86_INS_JMP) //unconditional jump
|
||||
dest2 = addr + _cp.Size();
|
||||
|
||||
if(!dest1 && !dest2) //TODO: better code for this (make sure absolutely no filling is inserted)
|
||||
if(!dest1 && !dest2) //TODO: better code for this (make sure absolutely no filling is inserted)
|
||||
bSkipFilling = true;
|
||||
if(dest1)
|
||||
_blockStarts.insert(dest1);
|
||||
|
@ -93,13 +156,16 @@ void ControlFlowAnalysis::BasicBlockStarts()
|
|||
}
|
||||
else if(_cp.InGroup(CS_GRP_CALL))
|
||||
{
|
||||
uint dest1 = GetBranchOperand();
|
||||
uint dest1 = GetReferenceOperand();
|
||||
if(dest1)
|
||||
{
|
||||
_blockStarts.insert(dest1);
|
||||
_functionStarts.insert(dest1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uint dest1 = GetBranchOperand();
|
||||
uint dest1 = GetReferenceOperand();
|
||||
if(dest1)
|
||||
_blockStarts.insert(dest1);
|
||||
}
|
||||
|
@ -126,32 +192,181 @@ void ControlFlowAnalysis::BasicBlocks()
|
|||
prevaddr = addr;
|
||||
if(_cp.Disassemble(addr, TranslateAddress(addr), MAX_DISASM_BUFFER))
|
||||
{
|
||||
if(_cp.InGroup(CS_GRP_RET))
|
||||
if(_cp.InGroup(CS_GRP_RET) || _cp.GetId() == X86_INS_INT3)
|
||||
{
|
||||
_blocks.push_back(BasicBlock(start, addr, 0, 0)); //leaf block
|
||||
insertBlock(BasicBlock(start, addr, 0, 0)); //leaf block
|
||||
break;
|
||||
}
|
||||
else if(_cp.InGroup(CS_GRP_JUMP) || _cp.IsLoop())
|
||||
{
|
||||
uint dest1 = GetBranchOperand();
|
||||
uint dest1 = GetReferenceOperand();
|
||||
uint dest2 = _cp.GetId() != X86_INS_JMP ? addr + _cp.Size() : 0;
|
||||
_blocks.push_back(BasicBlock(start, addr, dest1, dest2));
|
||||
insertBlock(BasicBlock(start, addr, dest1, dest2));
|
||||
insertParent(dest1, start);
|
||||
insertParent(dest2, start);
|
||||
break;
|
||||
}
|
||||
addr += _cp.Size();
|
||||
}
|
||||
else
|
||||
addr++;
|
||||
if(addr == nextStart) //special case handling overlapping blocks
|
||||
if(addr == nextStart) //special case handling overlapping blocks
|
||||
{
|
||||
_blocks.push_back(BasicBlock(start, prevaddr, 0, nextStart));
|
||||
insertBlock(BasicBlock(start, prevaddr, 0, nextStart));
|
||||
insertParent(nextStart, start);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
_blockStarts.clear();
|
||||
|
||||
#ifdef _WIN64
|
||||
int count = 0;
|
||||
EnumerateFunctionRuntimeEntries64([&](PRUNTIME_FUNCTION Function)
|
||||
{
|
||||
const uint funcAddr = _moduleBase + Function->BeginAddress;
|
||||
const uint funcEnd = _moduleBase + Function->EndAddress;
|
||||
|
||||
// If within limits...
|
||||
if(funcAddr >= _base && funcAddr < _base + _size)
|
||||
_functionStarts.insert(funcAddr);
|
||||
count++;
|
||||
return true;
|
||||
});
|
||||
dprintf("%u functions from the exception directory...\n", count);
|
||||
#endif // _WIN64
|
||||
|
||||
dprintf("%u basic blocks, %u function starts detected...\n", _blocks.size(), _functionStarts.size());
|
||||
}
|
||||
|
||||
uint ControlFlowAnalysis::GetBranchOperand()
|
||||
void ControlFlowAnalysis::Functions()
|
||||
{
|
||||
typedef std::pair<BasicBlock*, UintSet*> DelayedBlock;
|
||||
std::vector<DelayedBlock> delayedBlocks;
|
||||
for(auto & it : _blocks)
|
||||
{
|
||||
BasicBlock* block = &it.second;
|
||||
UintSet* parents = findParents(block->start);
|
||||
if(!block->function)
|
||||
{
|
||||
if(!parents || _functionStarts.count(block->start)) //no parents = function start
|
||||
{
|
||||
uint functionStart = block->start;
|
||||
block->function = functionStart;
|
||||
UintSet functionBlocks;
|
||||
functionBlocks.insert(functionStart);
|
||||
_functions[functionStart] = functionBlocks;
|
||||
}
|
||||
else //in function
|
||||
{
|
||||
uint function = findFunctionStart(block, parents);
|
||||
if(!function) //this happens with loops sometimes
|
||||
delayedBlocks.push_back(DelayedBlock(block, parents));
|
||||
else
|
||||
block->function = function;
|
||||
}
|
||||
}
|
||||
else
|
||||
DebugBreak(); //this should not happen
|
||||
}
|
||||
int delayedCount = (int)delayedBlocks.size();
|
||||
dprintf("%u/%u delayed blocks...\n", delayedCount, _blocks.size());
|
||||
int resolved = 0;
|
||||
for(auto & delayedBlock : delayedBlocks)
|
||||
{
|
||||
BasicBlock* block = delayedBlock.first;
|
||||
UintSet* parents = delayedBlock.second;
|
||||
uint function = findFunctionStart(block, parents);
|
||||
if(!function)
|
||||
{
|
||||
continue;
|
||||
/*dprintf("unresolved block %s\n", blockToString(block).c_str());
|
||||
if(parents)
|
||||
{
|
||||
dprintf("parents:\n");
|
||||
for(auto parent : *parents)
|
||||
dprintf(" %s\n", blockToString(findBlock(parent)).c_str());
|
||||
}
|
||||
else
|
||||
dprintf("parents: null");
|
||||
dprintf("left: %s\n", blockToString(findBlock(block->left)).c_str());
|
||||
dprintf("right: %s\n", blockToString(findBlock(block->right)).c_str());
|
||||
return;*/
|
||||
}
|
||||
block->function = function;
|
||||
resolved++;
|
||||
}
|
||||
dprintf("%u/%u delayed blocks resolved (%u/%u still left, probably unreferenced functions)\n", resolved, delayedCount, delayedCount - resolved, _blocks.size());
|
||||
dprintf("%u functions found!\n", _functions.size());
|
||||
}
|
||||
|
||||
void ControlFlowAnalysis::insertBlock(BasicBlock block)
|
||||
{
|
||||
if(_blocks.find(block.start) != _blocks.end())
|
||||
DebugBreak();
|
||||
_blocks[block.start] = block;
|
||||
}
|
||||
|
||||
ControlFlowAnalysis::BasicBlock* ControlFlowAnalysis::findBlock(uint start)
|
||||
{
|
||||
if(!start)
|
||||
return nullptr;
|
||||
auto found = _blocks.find(start);
|
||||
return found != _blocks.end() ? &found->second : nullptr;
|
||||
}
|
||||
|
||||
void ControlFlowAnalysis::insertParent(uint child, uint parent)
|
||||
{
|
||||
if(!child || !parent)
|
||||
return;
|
||||
auto found = _parentMap.find(child);
|
||||
if(found == _parentMap.end())
|
||||
{
|
||||
UintSet parents;
|
||||
parents.insert(parent);
|
||||
_parentMap[child] = parents;
|
||||
}
|
||||
else
|
||||
found->second.insert(parent);
|
||||
}
|
||||
|
||||
ControlFlowAnalysis::UintSet* ControlFlowAnalysis::findParents(uint child)
|
||||
{
|
||||
if(!child)
|
||||
return nullptr;
|
||||
auto found = _parentMap.find(child);
|
||||
return found != _parentMap.end() ? &found->second : nullptr;
|
||||
}
|
||||
|
||||
uint ControlFlowAnalysis::findFunctionStart(BasicBlock* block, ControlFlowAnalysis::UintSet* parents)
|
||||
{
|
||||
if(!block)
|
||||
return 0;
|
||||
if(block->function)
|
||||
return block->function;
|
||||
BasicBlock* left = findBlock(block->left);
|
||||
if(left && left->function)
|
||||
return left->function;
|
||||
BasicBlock* right = findBlock(block->right);
|
||||
if(right && right->function)
|
||||
return right->function;
|
||||
for(auto start : *parents)
|
||||
{
|
||||
BasicBlock* parent = findBlock(start);
|
||||
if(parent->function)
|
||||
return parent->function;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
String ControlFlowAnalysis::blockToString(BasicBlock* block)
|
||||
{
|
||||
if(!block)
|
||||
return String("null");
|
||||
return block->toString();
|
||||
}
|
||||
|
||||
uint ControlFlowAnalysis::GetReferenceOperand()
|
||||
{
|
||||
for(int i = 0; i < _cp.x86().op_count; i++)
|
||||
{
|
||||
|
@ -164,4 +379,23 @@ uint ControlFlowAnalysis::GetBranchOperand()
|
|||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN64
|
||||
void ControlFlowAnalysis::EnumerateFunctionRuntimeEntries64(std::function<bool(PRUNTIME_FUNCTION)> Callback)
|
||||
{
|
||||
if(!_functionInfoData)
|
||||
return;
|
||||
|
||||
// Get the table pointer and size
|
||||
auto functionTable = (PRUNTIME_FUNCTION)_functionInfoData;
|
||||
uint totalCount = (_functionInfoSize / sizeof(RUNTIME_FUNCTION));
|
||||
|
||||
// Enumerate each entry
|
||||
for(ULONG i = 0; i < totalCount; i++)
|
||||
{
|
||||
if(!Callback(&functionTable[i]))
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif // _WIN64
|
|
@ -2,15 +2,17 @@
|
|||
#define _CONTROLFLOWANALYSIS_H
|
||||
|
||||
#include "_global.h"
|
||||
#include "capstone_wrapper.h"
|
||||
#include "analysis.h"
|
||||
#include "addrinfo.h"
|
||||
#include <functional>
|
||||
|
||||
class ControlFlowAnalysis : public Analysis
|
||||
{
|
||||
public:
|
||||
explicit ControlFlowAnalysis(uint base, uint size);
|
||||
void Analyse();
|
||||
void SetMarkers();
|
||||
explicit ControlFlowAnalysis(uint base, uint size, bool exceptionDirectory);
|
||||
~ControlFlowAnalysis();
|
||||
void Analyse() override;
|
||||
void SetMarkers() override;
|
||||
|
||||
private:
|
||||
struct BasicBlock
|
||||
|
@ -19,6 +21,7 @@ private:
|
|||
uint end;
|
||||
uint left;
|
||||
uint right;
|
||||
uint function;
|
||||
|
||||
BasicBlock()
|
||||
{
|
||||
|
@ -26,6 +29,7 @@ private:
|
|||
this->end = 0;
|
||||
this->left = 0;
|
||||
this->right = 0;
|
||||
this->function = 0;
|
||||
}
|
||||
|
||||
BasicBlock(uint start, uint end, uint left, uint right)
|
||||
|
@ -34,15 +38,40 @@ private:
|
|||
this->end = end;
|
||||
this->left = min(left, right);
|
||||
this->right = max(left, right);
|
||||
this->function = 0;
|
||||
}
|
||||
|
||||
String toString()
|
||||
{
|
||||
return StringUtils::sprintf("start:%p,end:%p,left:%p,right:%p,func:%p", start, end, left, right, function);
|
||||
}
|
||||
};
|
||||
|
||||
std::set<uint> _blockStarts;
|
||||
std::vector<BasicBlock> _blocks;
|
||||
typedef std::set<uint> UintSet;
|
||||
|
||||
uint _moduleBase;
|
||||
uint _functionInfoSize;
|
||||
void* _functionInfoData;
|
||||
|
||||
UintSet _blockStarts;
|
||||
UintSet _functionStarts;
|
||||
std::map<uint, BasicBlock> _blocks; //start of block -> block
|
||||
std::map<uint, UintSet> _parentMap; //start child -> parents
|
||||
std::map<uint, UintSet> _functions; //function start -> function block starts
|
||||
|
||||
void BasicBlockStarts();
|
||||
void BasicBlocks();
|
||||
uint GetBranchOperand();
|
||||
void Functions();
|
||||
void insertBlock(BasicBlock block);
|
||||
BasicBlock* findBlock(uint start);
|
||||
void insertParent(uint child, uint parent);
|
||||
UintSet* findParents(uint child);
|
||||
uint findFunctionStart(BasicBlock* block, UintSet* parents);
|
||||
String blockToString(BasicBlock* block);
|
||||
uint GetReferenceOperand();
|
||||
#ifdef _WIN64
|
||||
void EnumerateFunctionRuntimeEntries64(std::function<bool(PRUNTIME_FUNCTION)> Callback);
|
||||
#endif // _WIN64
|
||||
};
|
||||
|
||||
#endif //_CONTROLFLOWANALYSIS_H
|
|
@ -24,13 +24,13 @@ SafeSymUnloadModule64(
|
|||
return SymUnloadModule64(hProcess, BaseOfDll);
|
||||
}
|
||||
BOOL
|
||||
SafeSymSetSearchPath(
|
||||
SafeSymSetSearchPathW(
|
||||
__in HANDLE hProcess,
|
||||
__in_opt PCSTR SearchPath
|
||||
__in_opt PCWSTR SearchPath
|
||||
)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockSym);
|
||||
return SymSetSearchPath(hProcess, SearchPath);
|
||||
return SymSetSearchPathW(hProcess, SearchPath);
|
||||
}
|
||||
DWORD
|
||||
SafeSymSetOptions(
|
||||
|
@ -41,14 +41,14 @@ SafeSymSetOptions(
|
|||
return SymSetOptions(SymOptions);
|
||||
}
|
||||
BOOL
|
||||
SafeSymInitialize(
|
||||
SafeSymInitializeW(
|
||||
__in HANDLE hProcess,
|
||||
__in_opt PCSTR UserSearchPath,
|
||||
__in_opt PCWSTR UserSearchPath,
|
||||
__in BOOL fInvadeProcess
|
||||
)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockSym);
|
||||
return SymInitialize(hProcess, UserSearchPath, fInvadeProcess);
|
||||
return SymInitializeW(hProcess, UserSearchPath, fInvadeProcess);
|
||||
}
|
||||
BOOL
|
||||
SafeSymRegisterCallback64(
|
||||
|
@ -86,14 +86,14 @@ SafeSymGetModuleInfo64(
|
|||
return SymGetModuleInfo64(hProcess, qwAddr, ModuleInfo);
|
||||
}
|
||||
BOOL
|
||||
SafeSymGetSearchPath(
|
||||
SafeSymGetSearchPathW(
|
||||
__in HANDLE hProcess,
|
||||
__out_ecount(SearchPathLength) PSTR SearchPath,
|
||||
__out_ecount(SearchPathLength) PWSTR SearchPath,
|
||||
__in DWORD SearchPathLength
|
||||
)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockSym);
|
||||
return SymGetSearchPath(hProcess, SearchPath, SearchPathLength);
|
||||
return SymGetSearchPathW(hProcess, SearchPath, SearchPathLength);
|
||||
}
|
||||
BOOL
|
||||
SafeSymEnumSymbols(
|
||||
|
|
|
@ -20,18 +20,18 @@ SafeSymUnloadModule64(
|
|||
__in DWORD64 BaseOfDll
|
||||
);
|
||||
BOOL
|
||||
SafeSymSetSearchPath(
|
||||
SafeSymSetSearchPathW(
|
||||
__in HANDLE hProcess,
|
||||
__in_opt PCSTR SearchPath
|
||||
__in_opt PCWSTR SearchPath
|
||||
);
|
||||
DWORD
|
||||
SafeSymSetOptions(
|
||||
__in DWORD SymOptions
|
||||
);
|
||||
BOOL
|
||||
SafeSymInitialize(
|
||||
SafeSymInitializeW(
|
||||
__in HANDLE hProcess,
|
||||
__in_opt PCSTR UserSearchPath,
|
||||
__in_opt PCWSTR UserSearchPath,
|
||||
__in BOOL fInvadeProcess
|
||||
);
|
||||
BOOL
|
||||
|
@ -58,9 +58,9 @@ SafeSymGetModuleInfo64(
|
|||
__out PIMAGEHLP_MODULE64 ModuleInfo
|
||||
);
|
||||
BOOL
|
||||
SafeSymGetSearchPath(
|
||||
SafeSymGetSearchPathW(
|
||||
__in HANDLE hProcess,
|
||||
__out_ecount(SearchPathLength) PSTR SearchPath,
|
||||
__out_ecount(SearchPathLength) PWSTR SearchPath,
|
||||
__in DWORD SearchPathLength
|
||||
);
|
||||
BOOL
|
||||
|
|
|
@ -569,7 +569,7 @@ static unsigned char getCIPch()
|
|||
{
|
||||
unsigned char ch = 0x90;
|
||||
uint cip = GetContextDataEx(hActiveThread, UE_CIP);
|
||||
MemRead(cip, &ch, 1, 0);
|
||||
MemRead(cip, &ch, 1);
|
||||
return ch;
|
||||
}
|
||||
|
||||
|
@ -633,7 +633,7 @@ static void cbCreateProcess(CREATE_PROCESS_DEBUG_INFO* CreateProcessInfo)
|
|||
GuiSymbolLogClear();
|
||||
char szServerSearchPath[MAX_PATH * 2] = "";
|
||||
sprintf_s(szServerSearchPath, "SRV*%s", szSymbolCachePath);
|
||||
SafeSymInitialize(fdProcessInfo->hProcess, szServerSearchPath, false); //initialize symbols
|
||||
SafeSymInitializeW(fdProcessInfo->hProcess, StringUtils::Utf8ToUtf16(szServerSearchPath).c_str(), false); //initialize symbols
|
||||
SafeSymRegisterCallback64(fdProcessInfo->hProcess, SymRegisterCallbackProc64, 0);
|
||||
SafeSymLoadModuleEx(fdProcessInfo->hProcess, CreateProcessInfo->hFile, DebugFileName, 0, (DWORD64)base, 0, 0, 0);
|
||||
|
||||
|
@ -965,7 +965,7 @@ static void cbOutputDebugString(OUTPUT_DEBUG_STRING_INFO* DebugString)
|
|||
if(!DebugString->fUnicode) //ASCII
|
||||
{
|
||||
Memory<char*> DebugText(DebugString->nDebugStringLength + 1, "cbOutputDebugString:DebugText");
|
||||
if(MemRead((uint)DebugString->lpDebugStringData, DebugText(), DebugString->nDebugStringLength, 0))
|
||||
if(MemRead((uint)DebugString->lpDebugStringData, DebugText(), DebugString->nDebugStringLength))
|
||||
{
|
||||
String str = String(DebugText());
|
||||
if(str != lastDebugText) //fix for every string being printed twice
|
||||
|
@ -1047,7 +1047,7 @@ static void cbException(EXCEPTION_DEBUG_INFO* ExceptionData)
|
|||
if(nameInfo.dwType == 0x1000 && nameInfo.dwFlags == 0 && ThreadIsValid(nameInfo.dwThreadID)) //passed basic checks
|
||||
{
|
||||
Memory<char*> ThreadName(MAX_THREAD_NAME_SIZE, "cbException:ThreadName");
|
||||
if(MemRead((uint)nameInfo.szName, ThreadName(), MAX_THREAD_NAME_SIZE - 1, 0))
|
||||
if(MemRead((uint)nameInfo.szName, ThreadName(), MAX_THREAD_NAME_SIZE - 1))
|
||||
{
|
||||
String ThreadNameEscaped = StringUtils::Escape(ThreadName());
|
||||
dprintf("SetThreadName(%X, \"%s\")\n", nameInfo.dwThreadID, ThreadNameEscaped.c_str());
|
||||
|
@ -1805,7 +1805,6 @@ bool dbglistprocesses(std::vector<PROCESSENTRY32>* list)
|
|||
|
||||
static bool getcommandlineaddr(uint* addr, cmdline_error_t* cmd_line_error)
|
||||
{
|
||||
SIZE_T size;
|
||||
uint pprocess_parameters;
|
||||
|
||||
cmd_line_error->addr = (uint)GetPEBLocation(fdProcessInfo->hProcess);
|
||||
|
@ -1818,7 +1817,7 @@ static bool getcommandlineaddr(uint* addr, cmdline_error_t* cmd_line_error)
|
|||
|
||||
//cast-trick to calculate the address of the remote peb field ProcessParameters
|
||||
cmd_line_error->addr = (uint) & (((PPEB) cmd_line_error->addr)->ProcessParameters);
|
||||
if(!MemRead(cmd_line_error->addr, &pprocess_parameters, sizeof(pprocess_parameters), &size))
|
||||
if(!MemRead(cmd_line_error->addr, &pprocess_parameters, sizeof(pprocess_parameters)))
|
||||
{
|
||||
cmd_line_error->type = CMDL_ERR_READ_PEBBASE;
|
||||
return false;
|
||||
|
@ -1832,11 +1831,10 @@ static bool patchcmdline(uint getcommandline, uint new_command_line, cmdline_err
|
|||
{
|
||||
uint command_line_stored = 0;
|
||||
uint aux = 0;
|
||||
SIZE_T size;
|
||||
unsigned char data[100];
|
||||
|
||||
cmd_line_error->addr = getcommandline;
|
||||
if(!MemRead(cmd_line_error->addr, & data, sizeof(data), & size))
|
||||
if(!MemRead(cmd_line_error->addr, & data, sizeof(data)))
|
||||
{
|
||||
cmd_line_error->type = CMDL_ERR_READ_GETCOMMANDLINEBASE;
|
||||
return false;
|
||||
|
@ -1870,7 +1868,7 @@ static bool patchcmdline(uint getcommandline, uint new_command_line, cmdline_err
|
|||
#endif
|
||||
|
||||
//update the pointer in the debuggee
|
||||
if(!MemWrite(command_line_stored, &new_command_line, sizeof(new_command_line), &size))
|
||||
if(!MemWrite(command_line_stored, &new_command_line, sizeof(new_command_line)))
|
||||
{
|
||||
cmd_line_error->addr = command_line_stored;
|
||||
cmd_line_error->type = CMDL_ERR_WRITE_GETCOMMANDLINESTORED;
|
||||
|
@ -1913,7 +1911,6 @@ bool dbgsetcmdline(const char* cmd_line, cmdline_error_t* cmd_line_error)
|
|||
{
|
||||
cmdline_error_t cmd_line_error_aux;
|
||||
UNICODE_STRING new_command_line;
|
||||
SIZE_T size;
|
||||
uint command_line_addr;
|
||||
|
||||
if(cmd_line_error == NULL)
|
||||
|
@ -1939,21 +1936,21 @@ bool dbgsetcmdline(const char* cmd_line, cmdline_error_t* cmd_line_error)
|
|||
|
||||
new_command_line.Buffer = command_linewstr();
|
||||
|
||||
uint mem = (uint)MemAllocRemote(0, new_command_line.Length * 2, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
||||
uint mem = (uint)MemAllocRemote(0, new_command_line.Length * 2);
|
||||
if(!mem)
|
||||
{
|
||||
cmd_line_error->type = CMDL_ERR_ALLOC_UNICODEANSI_COMMANDLINE;
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!MemWrite(mem, new_command_line.Buffer, new_command_line.Length, &size))
|
||||
if(!MemWrite(mem, new_command_line.Buffer, new_command_line.Length))
|
||||
{
|
||||
cmd_line_error->addr = mem;
|
||||
cmd_line_error->type = CMDL_ERR_WRITE_UNICODE_COMMANDLINE;
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!MemWrite((mem + new_command_line.Length), (void*)cmd_line, strlen(cmd_line) + 1, &size))
|
||||
if(!MemWrite((mem + new_command_line.Length), (void*)cmd_line, strlen(cmd_line) + 1))
|
||||
{
|
||||
cmd_line_error->addr = mem + new_command_line.Length;
|
||||
cmd_line_error->type = CMDL_ERR_WRITE_ANSI_COMMANDLINE;
|
||||
|
@ -1964,7 +1961,7 @@ bool dbgsetcmdline(const char* cmd_line, cmdline_error_t* cmd_line_error)
|
|||
return false;
|
||||
|
||||
new_command_line.Buffer = (PWSTR) mem;
|
||||
if(!MemWrite(command_line_addr, &new_command_line, sizeof(new_command_line), &size))
|
||||
if(!MemWrite(command_line_addr, &new_command_line, sizeof(new_command_line)))
|
||||
{
|
||||
cmd_line_error->addr = command_line_addr;
|
||||
cmd_line_error->type = CMDL_ERR_WRITE_PEBUNICODE_COMMANDLINE;
|
||||
|
@ -1976,7 +1973,6 @@ bool dbgsetcmdline(const char* cmd_line, cmdline_error_t* cmd_line_error)
|
|||
|
||||
bool dbggetcmdline(char** cmd_line, cmdline_error_t* cmd_line_error)
|
||||
{
|
||||
SIZE_T size;
|
||||
UNICODE_STRING CommandLine;
|
||||
cmdline_error_t cmd_line_error_aux;
|
||||
|
||||
|
@ -1986,7 +1982,7 @@ bool dbggetcmdline(char** cmd_line, cmdline_error_t* cmd_line_error)
|
|||
if(!getcommandlineaddr(&cmd_line_error->addr, cmd_line_error))
|
||||
return false;
|
||||
|
||||
if(!MemRead(cmd_line_error->addr, &CommandLine, sizeof(CommandLine), &size))
|
||||
if(!MemRead(cmd_line_error->addr, &CommandLine, sizeof(CommandLine)))
|
||||
{
|
||||
cmd_line_error->type = CMDL_ERR_READ_PROCPARM_PTR;
|
||||
return false;
|
||||
|
@ -1995,7 +1991,7 @@ bool dbggetcmdline(char** cmd_line, cmdline_error_t* cmd_line_error)
|
|||
Memory<wchar_t*> wstr_cmd(CommandLine.Length + sizeof(wchar_t));
|
||||
|
||||
cmd_line_error->addr = (uint) CommandLine.Buffer;
|
||||
if(!MemRead(cmd_line_error->addr, wstr_cmd(), CommandLine.Length, &size))
|
||||
if(!MemRead(cmd_line_error->addr, wstr_cmd(), CommandLine.Length))
|
||||
{
|
||||
cmd_line_error->type = CMDL_ERR_READ_PROCPARM_CMDLINE;
|
||||
return false;
|
||||
|
|
|
@ -238,7 +238,7 @@ CMDRESULT cbDebugSetBPX(int argc, char* argv[]) //bp addr [,name [,type]]
|
|||
dprintf("Error setting breakpoint at "fhex"! (IsBPXEnabled)\n", addr);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
else if(!MemRead(addr, &oldbytes, sizeof(short), 0))
|
||||
else if(!MemRead(addr, &oldbytes, sizeof(short)))
|
||||
{
|
||||
dprintf("Error setting breakpoint at "fhex"! (memread)\n", addr);
|
||||
return STATUS_ERROR;
|
||||
|
@ -789,7 +789,7 @@ CMDRESULT cbDebugAlloc(int argc, char* argv[])
|
|||
if(argc > 1)
|
||||
if(!valfromstring(argv[1], &size, false))
|
||||
return STATUS_ERROR;
|
||||
uint mem = (uint)MemAllocRemote(0, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
|
||||
uint mem = (uint)MemAllocRemote(0, size);
|
||||
if(!mem)
|
||||
dputs("VirtualAllocEx failed");
|
||||
else
|
||||
|
@ -1473,8 +1473,8 @@ CMDRESULT cbDebugDownloadSymbol(int argc, char* argv[])
|
|||
}
|
||||
char szModulePath[MAX_PATH] = "";
|
||||
strcpy_s(szModulePath, StringUtils::Utf16ToUtf8(wszModulePath).c_str());
|
||||
char szOldSearchPath[MAX_PATH] = "";
|
||||
if(!SafeSymGetSearchPath(fdProcessInfo->hProcess, szOldSearchPath, MAX_PATH)) //backup current search path
|
||||
wchar_t szOldSearchPath[MAX_PATH] = L"";
|
||||
if(!SafeSymGetSearchPathW(fdProcessInfo->hProcess, szOldSearchPath, MAX_PATH)) //backup current search path
|
||||
{
|
||||
dputs("SymGetSearchPath failed!");
|
||||
return STATUS_ERROR;
|
||||
|
@ -1483,26 +1483,26 @@ CMDRESULT cbDebugDownloadSymbol(int argc, char* argv[])
|
|||
if(argc > 2)
|
||||
szSymbolStore = argv[2];
|
||||
sprintf_s(szServerSearchPath, "SRV*%s*%s", szSymbolCachePath, szSymbolStore);
|
||||
if(!SafeSymSetSearchPath(fdProcessInfo->hProcess, szServerSearchPath)) //set new search path
|
||||
if(!SafeSymSetSearchPathW(fdProcessInfo->hProcess, StringUtils::Utf8ToUtf16(szServerSearchPath).c_str())) //set new search path
|
||||
{
|
||||
dputs("SymSetSearchPath (1) failed!");
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
if(!SafeSymUnloadModule64(fdProcessInfo->hProcess, (DWORD64)modbase)) //unload module
|
||||
{
|
||||
SafeSymSetSearchPath(fdProcessInfo->hProcess, szOldSearchPath);
|
||||
SafeSymSetSearchPathW(fdProcessInfo->hProcess, szOldSearchPath);
|
||||
dputs("SymUnloadModule64 failed!");
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
if(!SafeSymLoadModuleEx(fdProcessInfo->hProcess, 0, szModulePath, 0, (DWORD64)modbase, 0, 0, 0)) //load module
|
||||
{
|
||||
dputs("SymLoadModuleEx failed!");
|
||||
SafeSymSetSearchPath(fdProcessInfo->hProcess, szOldSearchPath);
|
||||
SafeSymSetSearchPathW(fdProcessInfo->hProcess, szOldSearchPath);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
if(!SafeSymSetSearchPath(fdProcessInfo->hProcess, szOldSearchPath))
|
||||
if(!SafeSymSetSearchPathW(fdProcessInfo->hProcess, szOldSearchPath))
|
||||
{
|
||||
dputs("SymSetSearchPath (2) failed!");
|
||||
dputs("SymSetSearchPathW (2) failed!");
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
GuiSymbolRefreshCurrent();
|
||||
|
@ -1888,8 +1888,8 @@ CMDRESULT cbDebugLoadLib(int argc, char* argv[])
|
|||
LoadLibThreadID = fdProcessInfo->dwThreadId;
|
||||
HANDLE LoadLibThread = ThreadGetHandle((DWORD)LoadLibThreadID);
|
||||
|
||||
DLLNameMem = MemAllocRemote(0, strlen(argv[1]) + 1, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
|
||||
ASMAddr = MemAllocRemote(0, 0x1000, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||
DLLNameMem = MemAllocRemote(0, strlen(argv[1]) + 1);
|
||||
ASMAddr = MemAllocRemote(0, 0x1000);
|
||||
|
||||
if(!DLLNameMem || !ASMAddr)
|
||||
{
|
||||
|
@ -1897,7 +1897,7 @@ CMDRESULT cbDebugLoadLib(int argc, char* argv[])
|
|||
return STATUS_ERROR;
|
||||
}
|
||||
|
||||
if(!MemWrite(DLLNameMem, argv[1], strlen(argv[1]), NULL))
|
||||
if(!MemWrite(DLLNameMem, argv[1], strlen(argv[1])))
|
||||
{
|
||||
dprintf("Error: couldn't write process memory");
|
||||
return STATUS_ERROR;
|
||||
|
|
|
@ -103,7 +103,7 @@ bool disasmfast(unsigned char* data, uint addr, BASIC_INSTRUCTION_INFO* basicinf
|
|||
bool disasmfast(uint addr, BASIC_INSTRUCTION_INFO* basicinfo)
|
||||
{
|
||||
unsigned int data[16];
|
||||
if(!MemRead(addr, data, sizeof(data), nullptr))
|
||||
if(!MemRead(addr, data, sizeof(data)))
|
||||
return false;
|
||||
return disasmfast((unsigned char*)data, addr, basicinfo);
|
||||
}
|
|
@ -278,7 +278,7 @@ bool disasmispossiblestring(uint addr)
|
|||
{
|
||||
unsigned char data[11];
|
||||
memset(data, 0, sizeof(data));
|
||||
if(!MemRead(addr, data, sizeof(data) - 3, 0))
|
||||
if(!MemRead(addr, data, sizeof(data) - 3))
|
||||
return false;
|
||||
uint test = 0;
|
||||
memcpy(&test, data, sizeof(uint));
|
||||
|
@ -294,7 +294,7 @@ bool disasmgetstringat(uint addr, STRING_TYPE* type, char* ascii, char* unicode,
|
|||
if(!disasmispossiblestring(addr))
|
||||
return false;
|
||||
Memory<unsigned char*> data((maxlen + 1) * 2, "disasmgetstringat:data");
|
||||
if(!MemRead(addr, data(), (maxlen + 1) * 2, 0))
|
||||
if(!MemRead(addr, data(), (maxlen + 1) * 2))
|
||||
return false;
|
||||
uint test = 0;
|
||||
memcpy(&test, data(), sizeof(uint));
|
||||
|
@ -388,7 +388,7 @@ int disasmgetsize(uint addr, unsigned char* data)
|
|||
int disasmgetsize(uint addr)
|
||||
{
|
||||
char data[MAX_DISASM_BUFFER];
|
||||
if(!MemRead(addr, data, sizeof(data), 0))
|
||||
if(!MemRead(addr, data, sizeof(data)))
|
||||
return 1;
|
||||
return disasmgetsize(addr, (unsigned char*)data);
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
#include "exceptiondirectoryanalysis.h"
|
||||
#include "module.h"
|
||||
#include "TitanEngine/TitanEngine.h"
|
||||
#include "memory.h"
|
||||
#include "console.h"
|
||||
#include "function.h"
|
||||
|
||||
ExceptionDirectoryAnalysis::ExceptionDirectoryAnalysis(uint base, uint size) : Analysis(base, size)
|
||||
{
|
||||
_functionInfoData = nullptr;
|
||||
#ifdef _WIN64
|
||||
// This will only be valid if the address range is within a loaded module
|
||||
_moduleBase = ModBaseFromAddr(base);
|
||||
|
||||
if(_moduleBase != 0)
|
||||
{
|
||||
char modulePath[MAX_PATH];
|
||||
memset(modulePath, 0, sizeof(modulePath));
|
||||
|
||||
ModPathFromAddr(_moduleBase, 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);
|
||||
_functionInfoSize = (uint)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
|
||||
_functionInfoData = emalloc(_functionInfoSize);
|
||||
|
||||
if(_functionInfoData)
|
||||
MemRead(virtualOffset + _moduleBase, _functionInfoData, _functionInfoSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif //_WIN64
|
||||
}
|
||||
|
||||
ExceptionDirectoryAnalysis::~ExceptionDirectoryAnalysis()
|
||||
{
|
||||
if(_functionInfoData)
|
||||
efree(_functionInfoData);
|
||||
}
|
||||
|
||||
void ExceptionDirectoryAnalysis::Analyse()
|
||||
{
|
||||
#ifdef _WIN64
|
||||
EnumerateFunctionRuntimeEntries64([&](PRUNTIME_FUNCTION Function)
|
||||
{
|
||||
const uint funcAddr = _moduleBase + Function->BeginAddress;
|
||||
const uint funcEnd = _moduleBase + Function->EndAddress;
|
||||
|
||||
// If within limits...
|
||||
if(funcAddr >= _base && funcAddr < _base + _size)
|
||||
_functions.push_back({ funcAddr, funcEnd });
|
||||
|
||||
return true;
|
||||
});
|
||||
dprintf("%u functions discovered!\n", _functions.size());
|
||||
#else //x32
|
||||
dprintf("This kind of analysis doesn't work on x32 executables...\n");
|
||||
#endif // _WIN64
|
||||
}
|
||||
|
||||
void ExceptionDirectoryAnalysis::SetMarkers()
|
||||
{
|
||||
FunctionDelRange(_base, _base + _size);
|
||||
for(const auto & function : _functions)
|
||||
FunctionAdd(function.first, function.second, false);
|
||||
}
|
||||
|
||||
#ifdef _WIN64
|
||||
void ExceptionDirectoryAnalysis::EnumerateFunctionRuntimeEntries64(std::function<bool(PRUNTIME_FUNCTION)> Callback)
|
||||
{
|
||||
if(!_functionInfoData)
|
||||
return;
|
||||
|
||||
// Get the table pointer and size
|
||||
auto functionTable = (PRUNTIME_FUNCTION)_functionInfoData;
|
||||
uint totalCount = (_functionInfoSize / sizeof(RUNTIME_FUNCTION));
|
||||
|
||||
// Enumerate each entry
|
||||
for(uint i = 0; i < totalCount; i++)
|
||||
{
|
||||
if(!Callback(&functionTable[i]))
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif // _WIN64
|
|
@ -0,0 +1,26 @@
|
|||
#ifndef _EXCEPTIONDIRECTORYANALYSIS_H
|
||||
#define _EXCEPTIONDIRECTORYANALYSIS_H
|
||||
|
||||
#include "analysis.h"
|
||||
#include <functional>
|
||||
|
||||
class ExceptionDirectoryAnalysis : public Analysis
|
||||
{
|
||||
public:
|
||||
explicit ExceptionDirectoryAnalysis(uint base, uint size);
|
||||
~ExceptionDirectoryAnalysis();
|
||||
void Analyse() override;
|
||||
void SetMarkers() override;
|
||||
|
||||
private:
|
||||
uint _moduleBase;
|
||||
uint _functionInfoSize;
|
||||
void* _functionInfoData;
|
||||
std::vector<std::pair<uint, uint>> _functions;
|
||||
|
||||
#ifdef _WIN64
|
||||
void EnumerateFunctionRuntimeEntries64(std::function<bool(PRUNTIME_FUNCTION)> Callback);
|
||||
#endif // _WIN64
|
||||
};
|
||||
|
||||
#endif //_EXCEPTIONDIRECTORYANALYSIS_H
|
|
@ -26,9 +26,10 @@
|
|||
#include "module.h"
|
||||
#include "stringformat.h"
|
||||
#include "filereader.h"
|
||||
#include "functionanalysis.h"
|
||||
#include "linearanalysis.h"
|
||||
#include "controlflowanalysis.h"
|
||||
#include "analysis_nukem.h"
|
||||
#include "exceptiondirectoryanalysis.h"
|
||||
|
||||
static bool bRefinit = false;
|
||||
|
||||
|
@ -187,7 +188,7 @@ CMDRESULT cbInstrMov(int argc, char* argv[])
|
|||
data()[j] = res;
|
||||
}
|
||||
//Move data to destination
|
||||
if(!MemWrite(dest, data(), data.size(), 0))
|
||||
if(!MemWrite(dest, data(), data.size()))
|
||||
{
|
||||
dprintf("failed to write to "fhex"\n", dest);
|
||||
return STATUS_ERROR;
|
||||
|
@ -1067,7 +1068,7 @@ CMDRESULT cbInstrCopystr(int argc, char* argv[])
|
|||
dprintf("invalid address \"%s\"!\n", argv[1]);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
if(!MemPatch(addr, string(), strlen(string()), 0))
|
||||
if(!MemPatch(addr, string(), strlen(string())))
|
||||
{
|
||||
dputs("memwrite failed!");
|
||||
return STATUS_ERROR;
|
||||
|
@ -1105,7 +1106,7 @@ CMDRESULT cbInstrFind(int argc, char* argv[])
|
|||
return STATUS_ERROR;
|
||||
}
|
||||
Memory<unsigned char*> data(size, "cbInstrFind:data");
|
||||
if(!MemRead(base, data(), size, 0))
|
||||
if(!MemRead(base, data(), size))
|
||||
{
|
||||
dputs("failed to read memory!");
|
||||
return STATUS_ERROR;
|
||||
|
@ -1157,7 +1158,7 @@ CMDRESULT cbInstrFindAll(int argc, char* argv[])
|
|||
return STATUS_ERROR;
|
||||
}
|
||||
Memory<unsigned char*> data(size, "cbInstrFindAll:data");
|
||||
if(!MemRead(base, data(), size, 0))
|
||||
if(!MemRead(base, data(), size))
|
||||
{
|
||||
dputs("failed to read memory!");
|
||||
return STATUS_ERROR;
|
||||
|
@ -1217,7 +1218,7 @@ CMDRESULT cbInstrFindAll(int argc, char* argv[])
|
|||
if(findData)
|
||||
{
|
||||
Memory<unsigned char*> printData(searchpattern.size(), "cbInstrFindAll:printData");
|
||||
MemRead(result, printData(), printData.size(), 0);
|
||||
MemRead(result, printData(), printData.size());
|
||||
for(size_t j = 0, k = 0; j < printData.size(); j++)
|
||||
{
|
||||
if(j)
|
||||
|
@ -1712,7 +1713,7 @@ CMDRESULT cbInstrYara(int argc, char* argv[])
|
|||
base = addr;
|
||||
}
|
||||
Memory<uint8_t*> data(size);
|
||||
if(!MemRead(base, data(), size, 0))
|
||||
if(!MemRead(base, data(), size))
|
||||
{
|
||||
dprintf("failed to read memory page %p[%X]!\n", base, size);
|
||||
return STATUS_ERROR;
|
||||
|
@ -1842,7 +1843,7 @@ CMDRESULT cbInstrCapstone(int argc, char* argv[])
|
|||
}
|
||||
|
||||
unsigned char data[16];
|
||||
if(!MemRead(addr, data, sizeof(data), 0))
|
||||
if(!MemRead(addr, data, sizeof(data)))
|
||||
{
|
||||
dprintf("could not read memory at %p\n", addr);
|
||||
return STATUS_ERROR;
|
||||
|
@ -1865,6 +1866,7 @@ CMDRESULT cbInstrCapstone(int argc, char* argv[])
|
|||
const cs_x86 & x86 = cp.x86();
|
||||
int argcount = x86.op_count;
|
||||
dprintf("%s %s\n", instr->mnemonic, instr->op_str);
|
||||
dprintf("%d, NOP=%d\n", cp.GetId(), X86_INS_NOP);
|
||||
for(int i = 0; i < argcount; i++)
|
||||
{
|
||||
const cs_x86_op & op = x86.operands[i];
|
||||
|
@ -1915,7 +1917,7 @@ CMDRESULT cbInstrAnalyse(int argc, char* argv[])
|
|||
GuiSelectionGet(GUI_DISASSEMBLY, &sel);
|
||||
uint size = 0;
|
||||
uint base = MemFindBaseAddr(sel.start, &size);
|
||||
FunctionAnalysis anal(base, size);
|
||||
LinearAnalysis anal(base, size);
|
||||
anal.Analyse();
|
||||
anal.SetMarkers();
|
||||
GuiUpdateAllViews();
|
||||
|
@ -1924,11 +1926,27 @@ CMDRESULT cbInstrAnalyse(int argc, char* argv[])
|
|||
|
||||
CMDRESULT cbInstrCfanalyse(int argc, char* argv[])
|
||||
{
|
||||
bool exceptionDirectory = false;
|
||||
if(argc > 1)
|
||||
exceptionDirectory = true;
|
||||
SELECTIONDATA sel;
|
||||
GuiSelectionGet(GUI_DISASSEMBLY, &sel);
|
||||
uint size = 0;
|
||||
uint base = MemFindBaseAddr(sel.start, &size);
|
||||
ControlFlowAnalysis anal(base, size);
|
||||
ControlFlowAnalysis anal(base, size, exceptionDirectory);
|
||||
anal.Analyse();
|
||||
//anal.SetMarkers();
|
||||
GuiUpdateAllViews();
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
|
||||
CMDRESULT cbInstrExanalyse(int argc, char* argv[])
|
||||
{
|
||||
SELECTIONDATA sel;
|
||||
GuiSelectionGet(GUI_DISASSEMBLY, &sel);
|
||||
uint size = 0;
|
||||
uint base = MemFindBaseAddr(sel.start, &size);
|
||||
ExceptionDirectoryAnalysis anal(base, size);
|
||||
anal.Analyse();
|
||||
anal.SetMarkers();
|
||||
GuiUpdateAllViews();
|
||||
|
@ -1963,7 +1981,7 @@ CMDRESULT cbInstrVisualize(int argc, char* argv[])
|
|||
uint _base = start;
|
||||
uint _size = maxaddr - start;
|
||||
Memory<unsigned char*> _data(_size);
|
||||
MemRead(_base, _data(), _size, nullptr);
|
||||
MemRead(_base, _data(), _size);
|
||||
FunctionClear();
|
||||
|
||||
//linear search with some trickery
|
||||
|
|
|
@ -72,5 +72,6 @@ CMDRESULT cbInstrAnalyse(int argc, char* argv[]);
|
|||
CMDRESULT cbInstrVisualize(int argc, char* argv[]);
|
||||
CMDRESULT cbInstrMeminfo(int argc, char* argv[]);
|
||||
CMDRESULT cbInstrCfanalyse(int argc, char* argv[]);
|
||||
CMDRESULT cbInstrExanalyse(int argc, char* argv[]);
|
||||
|
||||
#endif // _INSTRUCTIONS_H
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
#include "functionanalysis.h"
|
||||
#include "linearanalysis.h"
|
||||
#include "console.h"
|
||||
#include "memory.h"
|
||||
#include "function.h"
|
||||
|
||||
FunctionAnalysis::FunctionAnalysis(uint base, uint size) : Analysis(base, size)
|
||||
LinearAnalysis::LinearAnalysis(uint base, uint size) : Analysis(base, size)
|
||||
{
|
||||
}
|
||||
|
||||
void FunctionAnalysis::Analyse()
|
||||
void LinearAnalysis::Analyse()
|
||||
{
|
||||
dputs("Starting analysis...");
|
||||
DWORD ticks = GetTickCount();
|
||||
|
@ -19,7 +19,7 @@ void FunctionAnalysis::Analyse()
|
|||
dprintf("Analysis finished in %ums!\n", GetTickCount() - ticks);
|
||||
}
|
||||
|
||||
void FunctionAnalysis::SetMarkers()
|
||||
void LinearAnalysis::SetMarkers()
|
||||
{
|
||||
FunctionDelRange(_base, _base + _size);
|
||||
for(auto & function : _functions)
|
||||
|
@ -30,7 +30,7 @@ void FunctionAnalysis::SetMarkers()
|
|||
}
|
||||
}
|
||||
|
||||
void FunctionAnalysis::SortCleanup()
|
||||
void LinearAnalysis::SortCleanup()
|
||||
{
|
||||
//sort & remove duplicates
|
||||
std::sort(_functions.begin(), _functions.end());
|
||||
|
@ -38,7 +38,7 @@ void FunctionAnalysis::SortCleanup()
|
|||
_functions.erase(last, _functions.end());
|
||||
}
|
||||
|
||||
void FunctionAnalysis::PopulateReferences()
|
||||
void LinearAnalysis::PopulateReferences()
|
||||
{
|
||||
//linear immediate reference scan (call <addr>, push <addr>, mov [somewhere], <addr>)
|
||||
for(uint i = 0; i < _size;)
|
||||
|
@ -57,7 +57,7 @@ void FunctionAnalysis::PopulateReferences()
|
|||
SortCleanup();
|
||||
}
|
||||
|
||||
void FunctionAnalysis::AnalyseFunctions()
|
||||
void LinearAnalysis::AnalyseFunctions()
|
||||
{
|
||||
for(size_t i = 0; i < _functions.size(); i++)
|
||||
{
|
||||
|
@ -79,7 +79,7 @@ void FunctionAnalysis::AnalyseFunctions()
|
|||
}
|
||||
}
|
||||
|
||||
uint FunctionAnalysis::FindFunctionEnd(uint start, uint maxaddr)
|
||||
uint LinearAnalysis::FindFunctionEnd(uint start, uint maxaddr)
|
||||
{
|
||||
//disassemble first instruction for some heuristics
|
||||
if(_cp.Disassemble(start, TranslateAddress(start), MAX_DISASM_BUFFER))
|
||||
|
@ -132,7 +132,7 @@ uint FunctionAnalysis::FindFunctionEnd(uint start, uint maxaddr)
|
|||
return end < jumpback ? jumpback : end;
|
||||
}
|
||||
|
||||
uint FunctionAnalysis::GetReferenceOperand()
|
||||
uint LinearAnalysis::GetReferenceOperand()
|
||||
{
|
||||
for(int i = 0; i < _cp.x86().op_count; i++)
|
||||
{
|
|
@ -1,16 +1,15 @@
|
|||
#ifndef _FUNCTIONANALYSIS_H
|
||||
#define _FUNCTIONANALYSIS_H
|
||||
#ifndef _LINEARANALYSIS_H
|
||||
#define _LINEARANALYSIS_H
|
||||
|
||||
#include "_global.h"
|
||||
#include "capstone_wrapper.h"
|
||||
#include "analysis.h"
|
||||
|
||||
class FunctionAnalysis : public Analysis
|
||||
class LinearAnalysis : public Analysis
|
||||
{
|
||||
public:
|
||||
explicit FunctionAnalysis(uint base, uint size);
|
||||
void Analyse();
|
||||
void SetMarkers();
|
||||
explicit LinearAnalysis(uint base, uint size);
|
||||
void Analyse() override;
|
||||
void SetMarkers() override;
|
||||
|
||||
private:
|
||||
struct FunctionInfo
|
||||
|
@ -38,4 +37,4 @@ private:
|
|||
uint GetReferenceOperand();
|
||||
};
|
||||
|
||||
#endif //_FUNCTIONANALYSIS_H
|
||||
#endif //_LINEARANALYSIS_H
|
|
@ -173,7 +173,7 @@ uint MemFindBaseAddr(uint Address, uint* Size, bool Refresh)
|
|||
return found->first.first;
|
||||
}
|
||||
|
||||
bool MemRead(uint BaseAddress, void* Buffer, SIZE_T Size, SIZE_T* NumberOfBytesRead)
|
||||
bool MemRead(uint BaseAddress, void* Buffer, uint Size, uint* NumberOfBytesRead)
|
||||
{
|
||||
if(!MemIsCanonicalAddress((uint)BaseAddress))
|
||||
return false;
|
||||
|
@ -227,7 +227,7 @@ bool MemRead(uint BaseAddress, void* Buffer, SIZE_T Size, SIZE_T* NumberOfBytesR
|
|||
return (*NumberOfBytesRead > 0);
|
||||
}
|
||||
|
||||
bool MemWrite(uint BaseAddress, const void* Buffer, SIZE_T Size, SIZE_T* NumberOfBytesWritten)
|
||||
bool MemWrite(uint BaseAddress, const void* Buffer, uint Size, uint* NumberOfBytesWritten)
|
||||
{
|
||||
if(!MemIsCanonicalAddress((uint)BaseAddress))
|
||||
return false;
|
||||
|
@ -281,7 +281,7 @@ bool MemWrite(uint BaseAddress, const void* Buffer, SIZE_T Size, SIZE_T* NumberO
|
|||
return (*NumberOfBytesWritten > 0);
|
||||
}
|
||||
|
||||
bool MemPatch(uint BaseAddress, const void* Buffer, SIZE_T Size, SIZE_T* NumberOfBytesWritten)
|
||||
bool MemPatch(uint BaseAddress, const void* Buffer, uint Size, uint* NumberOfBytesWritten)
|
||||
{
|
||||
// Buffer and size must be valid
|
||||
if(!Buffer || Size <= 0)
|
||||
|
@ -290,7 +290,7 @@ bool MemPatch(uint BaseAddress, const void* Buffer, SIZE_T Size, SIZE_T* NumberO
|
|||
// Allocate the memory
|
||||
Memory<unsigned char*> oldData(Size, "mempatch:oldData");
|
||||
|
||||
if(!MemRead(BaseAddress, oldData(), Size, nullptr))
|
||||
if(!MemRead(BaseAddress, oldData(), Size))
|
||||
{
|
||||
// If no memory can be read, no memory can be written. Fail out
|
||||
// of this function.
|
||||
|
@ -306,7 +306,7 @@ bool MemPatch(uint BaseAddress, const void* Buffer, SIZE_T Size, SIZE_T* NumberO
|
|||
bool MemIsValidReadPtr(uint Address)
|
||||
{
|
||||
unsigned char a = 0;
|
||||
return MemRead(Address, &a, sizeof(unsigned char), nullptr);
|
||||
return MemRead(Address, &a, sizeof(unsigned char));
|
||||
}
|
||||
|
||||
bool MemIsCanonicalAddress(uint Address)
|
||||
|
|
|
@ -8,10 +8,10 @@ extern bool bListAllPages;
|
|||
|
||||
void MemUpdateMap();
|
||||
uint MemFindBaseAddr(uint Address, uint* Size, bool Refresh = false);
|
||||
bool MemRead(uint BaseAddress, void* Buffer, SIZE_T Size, SIZE_T* NumberOfBytesRead);
|
||||
bool MemWrite(uint BaseAddress, const void* Buffer, SIZE_T Size, SIZE_T* NumberOfBytesWritten);
|
||||
bool MemPatch(uint BaseAddress, const void* Buffer, SIZE_T Size, SIZE_T* NumberOfBytesWritten);
|
||||
bool MemRead(uint BaseAddress, void* Buffer, uint Size, uint* NumberOfBytesRead = nullptr);
|
||||
bool MemWrite(uint BaseAddress, const void* Buffer, uint Size, uint* NumberOfBytesWritten = nullptr);
|
||||
bool MemPatch(uint BaseAddress, const void* Buffer, uint Size, uint* NumberOfBytesWritten = nullptr);
|
||||
bool MemIsValidReadPtr(uint Address);
|
||||
bool MemIsCanonicalAddress(uint Address);
|
||||
uint MemAllocRemote(uint Address, uint Size, DWORD Type, DWORD Protect);
|
||||
uint MemAllocRemote(uint Address, uint Size, DWORD Type = MEM_RESERVE | MEM_COMMIT, DWORD Protect = PAGE_EXECUTE_READWRITE);
|
||||
bool MemFreeRemote(uint Address);
|
|
@ -106,7 +106,7 @@ bool PatchDelete(uint Address, bool Restore)
|
|||
|
||||
// Restore the original byte at this address
|
||||
if(Restore)
|
||||
MemWrite((found->second.addr + ModBaseFromAddr(Address)), &found->second.oldbyte, sizeof(char), nullptr);
|
||||
MemWrite((found->second.addr + ModBaseFromAddr(Address)), &found->second.oldbyte, sizeof(char));
|
||||
|
||||
// Finally remove it from the list
|
||||
patches.erase(found);
|
||||
|
@ -147,7 +147,7 @@ void PatchDelRange(uint Start, uint End, bool Restore)
|
|||
{
|
||||
// Restore the original byte if necessary
|
||||
if(Restore)
|
||||
MemWrite((currentPatch.addr + moduleBase), ¤tPatch.oldbyte, sizeof(char), nullptr);
|
||||
MemWrite((currentPatch.addr + moduleBase), ¤tPatch.oldbyte, sizeof(char));
|
||||
|
||||
itr = patches.erase(itr);
|
||||
}
|
||||
|
@ -273,7 +273,6 @@ int PatchFile(const PATCHINFO* List, int Count, const char* FileName, char* Erro
|
|||
if(!ptr)
|
||||
continue;
|
||||
|
||||
dprintf("patch%.4d|%s[%.8X]:%.2X/%.2X->%.2X\n", i + 1, moduleName, ptr - fileMapVa, *ptr, List[i].oldbyte, List[i].newbyte);
|
||||
*ptr = List[i].newbyte;
|
||||
patchCount++;
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ int RefFind(uint Address, uint Size, CBREF Callback, void* UserData, bool Silent
|
|||
// Allocate and read a buffer from the remote process
|
||||
Memory<unsigned char*> data(scanSize, "reffind:data");
|
||||
|
||||
if(!MemRead(scanStart, data(), scanSize, nullptr))
|
||||
if(!MemRead(scanStart, data(), scanSize))
|
||||
{
|
||||
if(!Silent)
|
||||
dprintf("Error reading memory in reference search\n");
|
||||
|
|
|
@ -16,7 +16,7 @@ bool stackcommentget(uint addr, STACK_COMMENT* comment)
|
|||
{
|
||||
uint data = 0;
|
||||
memset(comment, 0, sizeof(STACK_COMMENT));
|
||||
MemRead(addr, &data, sizeof(uint), 0);
|
||||
MemRead(addr, &data, sizeof(uint));
|
||||
if(!MemIsValidReadPtr(data)) //the stack value is no pointer
|
||||
return false;
|
||||
|
||||
|
@ -26,7 +26,7 @@ bool stackcommentget(uint addr, STACK_COMMENT* comment)
|
|||
if(readStart < base)
|
||||
readStart = base;
|
||||
unsigned char disasmData[256];
|
||||
MemRead(readStart, disasmData, sizeof(disasmData), 0);
|
||||
MemRead(readStart, disasmData, sizeof(disasmData));
|
||||
uint prev = disasmback(disasmData, 0, sizeof(disasmData), data - readStart, 1);
|
||||
uint previousInstr = readStart + prev;
|
||||
|
||||
|
@ -202,7 +202,7 @@ void stackgetcallstack(uint csp, CALLSTACK* callstack)
|
|||
while(i != stackbase + stacksize)
|
||||
{
|
||||
uint data = 0;
|
||||
MemRead(i, &data, sizeof(uint), 0);
|
||||
MemRead(i, &data, sizeof(uint));
|
||||
if(MemIsValidReadPtr(data)) //the stack value is a pointer
|
||||
{
|
||||
uint size = 0;
|
||||
|
@ -211,7 +211,7 @@ void stackgetcallstack(uint csp, CALLSTACK* callstack)
|
|||
if(readStart < base)
|
||||
readStart = base;
|
||||
unsigned char disasmData[256];
|
||||
MemRead(readStart, disasmData, sizeof(disasmData), 0);
|
||||
MemRead(readStart, disasmData, sizeof(disasmData));
|
||||
uint prev = disasmback(disasmData, 0, sizeof(disasmData), data - readStart, 1);
|
||||
uint previousInstr = readStart + prev;
|
||||
BASIC_INSTRUCTION_INFO basicinfo;
|
||||
|
|
|
@ -129,11 +129,11 @@ void SymDownloadAllSymbols(const char* SymbolStore)
|
|||
return;
|
||||
|
||||
// Backup the current symbol search path
|
||||
char oldSearchPath[MAX_PATH];
|
||||
wchar_t oldSearchPath[MAX_PATH];
|
||||
|
||||
if(!SafeSymGetSearchPath(fdProcessInfo->hProcess, oldSearchPath, MAX_PATH))
|
||||
if(!SafeSymGetSearchPathW(fdProcessInfo->hProcess, oldSearchPath, MAX_PATH))
|
||||
{
|
||||
dputs("SymGetSearchPath failed!");
|
||||
dputs("SymGetSearchPathW failed!");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -141,9 +141,9 @@ void SymDownloadAllSymbols(const char* SymbolStore)
|
|||
char customSearchPath[MAX_PATH * 2];
|
||||
sprintf_s(customSearchPath, "SRV*%s*%s", szSymbolCachePath, SymbolStore);
|
||||
|
||||
if(!SafeSymSetSearchPath(fdProcessInfo->hProcess, customSearchPath))
|
||||
if(!SafeSymSetSearchPathW(fdProcessInfo->hProcess, StringUtils::Utf8ToUtf16(customSearchPath).c_str()))
|
||||
{
|
||||
dputs("SymSetSearchPath (1) failed!");
|
||||
dputs("SymSetSearchPathW (1) failed!");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -173,8 +173,8 @@ void SymDownloadAllSymbols(const char* SymbolStore)
|
|||
}
|
||||
|
||||
// Restore the old search path
|
||||
if(!SafeSymSetSearchPath(fdProcessInfo->hProcess, oldSearchPath))
|
||||
dputs("SymSetSearchPath (2) failed!");
|
||||
if(!SafeSymSetSearchPathW(fdProcessInfo->hProcess, oldSearchPath))
|
||||
dputs("SymSetSearchPathW (2) failed!");
|
||||
}
|
||||
|
||||
bool SymAddrFromName(const char* Name, uint* Address)
|
||||
|
|
|
@ -126,7 +126,7 @@ bool ThreadGetTeb(uint TEBAddress, TEB* Teb)
|
|||
//
|
||||
memset(Teb, 0, sizeof(TEB));
|
||||
|
||||
return MemRead(TEBAddress, Teb, sizeof(TEB), nullptr);
|
||||
return MemRead(TEBAddress, Teb, sizeof(TEB));
|
||||
}
|
||||
|
||||
int ThreadGetSuspendCount(HANDLE Thread)
|
||||
|
|
|
@ -1550,7 +1550,7 @@ bool valfromstring_noexpr(const char* string, uint* value, bool silent, bool bas
|
|||
}
|
||||
uint addr = *value;
|
||||
*value = 0;
|
||||
if(!MemRead(addr, value, read_size, 0))
|
||||
if(!MemRead(addr, value, read_size))
|
||||
{
|
||||
if(!silent)
|
||||
dputs("failed to read memory");
|
||||
|
@ -2151,7 +2151,7 @@ bool valtostring(const char* string, uint value, bool silent)
|
|||
return false;
|
||||
}
|
||||
uint value_ = value;
|
||||
if(!MemPatch(temp, &value_, read_size, 0))
|
||||
if(!MemPatch(temp, &value_, read_size))
|
||||
{
|
||||
if(!silent)
|
||||
dputs("failed to write memory");
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "_dbgfunctions.h"
|
||||
#include "debugger_commands.h"
|
||||
#include "capstone_wrapper.h"
|
||||
#include "_scriptapi_gui.h"
|
||||
|
||||
static MESSAGE_STACK* gMsgStack = 0;
|
||||
static COMMAND* command_list = 0;
|
||||
|
@ -189,7 +190,6 @@ 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)
|
||||
|
@ -202,6 +202,8 @@ static void registercommands()
|
|||
dbgcmdnew("visualize", cbInstrVisualize, true); //visualize analysis
|
||||
dbgcmdnew("meminfo", cbInstrMeminfo, true); //command to debug memory map bugs
|
||||
dbgcmdnew("cfanal\1cfanalyse\1cfanalyze", cbInstrCfanalyse, true); //control flow analysis
|
||||
dbgcmdnew("analyse_nukem\1analyze_nukem\1anal_nukem", cbInstrAnalyseNukem, true); //secret analysis command #2
|
||||
dbgcmdnew("exanal\1exanalyse\1exanalyze", cbInstrExanalyse, true); //exception directory analysis
|
||||
}
|
||||
|
||||
static bool cbCommandProvider(char* cmd, int maxlen)
|
||||
|
@ -273,8 +275,25 @@ extern "C" DLL_EXPORT const char* _dbg_dbginit()
|
|||
strcpy_s(dbbasepath, dir); //debug directory
|
||||
strcat_s(dbbasepath, "\\db");
|
||||
CreateDirectoryW(StringUtils::Utf8ToUtf16(dbbasepath).c_str(), 0); //create database directory
|
||||
strcpy_s(szSymbolCachePath, dir);
|
||||
strcat_s(szSymbolCachePath, "\\symbols");
|
||||
char szLocalSymbolPath[MAX_PATH] = "";
|
||||
strcpy_s(szLocalSymbolPath, dir);
|
||||
strcat_s(szLocalSymbolPath, "\\symbols");
|
||||
if(!BridgeSettingGet("Symbols", "CachePath", szSymbolCachePath) || !*szSymbolCachePath)
|
||||
{
|
||||
strcpy_s(szSymbolCachePath, szLocalSymbolPath);
|
||||
BridgeSettingSet("Symbols", "CachePath", szLocalSymbolPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(strstr(szSymbolCachePath, "http://") || strstr(szSymbolCachePath, "https://"))
|
||||
{
|
||||
if(Script::Gui::MessageYesNo("It is strongly discouraged to use symbol servers in your path directly (use the store option instead).\n\nDo you want me to fix this?"))
|
||||
{
|
||||
strcpy_s(szSymbolCachePath, szLocalSymbolPath);
|
||||
BridgeSettingSet("Symbols", "CachePath", szLocalSymbolPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
SetCurrentDirectoryW(StringUtils::Utf8ToUtf16(dir).c_str());
|
||||
dputs("Allocating message stack...");
|
||||
gMsgStack = MsgAllocStack();
|
||||
|
|
|
@ -40,10 +40,11 @@
|
|||
<ClCompile Include="disasm_helper.cpp" />
|
||||
<ClCompile Include="error.cpp" />
|
||||
<ClCompile Include="exception.cpp" />
|
||||
<ClCompile Include="exceptiondirectoryanalysis.cpp" />
|
||||
<ClCompile Include="expressionparser.cpp" />
|
||||
<ClCompile Include="filereader.cpp" />
|
||||
<ClCompile Include="function.cpp" />
|
||||
<ClCompile Include="functionanalysis.cpp" />
|
||||
<ClCompile Include="linearanalysis.cpp" />
|
||||
<ClCompile Include="FunctionPass.cpp" />
|
||||
<ClCompile Include="instruction.cpp" />
|
||||
<ClCompile Include="Int3CoagulatorPass.cpp" />
|
||||
|
@ -119,10 +120,11 @@
|
|||
<ClInclude Include="dynamicmem.h" />
|
||||
<ClInclude Include="error.h" />
|
||||
<ClInclude Include="exception.h" />
|
||||
<ClInclude Include="exceptiondirectoryanalysis.h" />
|
||||
<ClInclude Include="expressionparser.h" />
|
||||
<ClInclude Include="filereader.h" />
|
||||
<ClInclude Include="function.h" />
|
||||
<ClInclude Include="functionanalysis.h" />
|
||||
<ClInclude Include="linearanalysis.h" />
|
||||
<ClInclude Include="FunctionPass.h" />
|
||||
<ClInclude Include="handle.h" />
|
||||
<ClInclude Include="instruction.h" />
|
||||
|
|
|
@ -216,9 +216,6 @@
|
|||
<ClCompile Include="capstone_wrapper.cpp">
|
||||
<Filter>Source Files\Utilities</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="functionanalysis.cpp">
|
||||
<Filter>Source Files\Analysis</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="filereader.cpp">
|
||||
<Filter>Source Files\Utilities</Filter>
|
||||
</ClCompile>
|
||||
|
@ -258,24 +255,30 @@
|
|||
<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="analysis_nukem.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>
|
||||
<ClCompile Include="controlflowanalysis.cpp">
|
||||
<Filter>Source Files\Analysis</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="exceptiondirectoryanalysis.cpp">
|
||||
<Filter>Source Files\Analysis</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="linearanalysis.cpp">
|
||||
<Filter>Source Files\Analysis</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="x64_dbg.h">
|
||||
|
@ -566,9 +569,6 @@
|
|||
<ClInclude Include="capstone\xcore.h">
|
||||
<Filter>Header Files\Third Party\capstone</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="functionanalysis.h">
|
||||
<Filter>Header Files\Analysis</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="filereader.h">
|
||||
<Filter>Header Files\Utilities</Filter>
|
||||
</ClInclude>
|
||||
|
@ -614,23 +614,29 @@
|
|||
<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="analysis_nukem.h">
|
||||
<Filter>Header Files\Analysis</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="controlflowanalysis.h">
|
||||
<Filter>Header Files\Analysis</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="_scriptapi_stack.h">
|
||||
<Filter>Header Files\Interfaces/Exports\_scriptapi</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="exceptiondirectoryanalysis.h">
|
||||
<Filter>Header Files\Analysis</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="linearanalysis.h">
|
||||
<Filter>Header Files\Analysis</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -21,7 +21,10 @@ Disassembly::Disassembly(QWidget* parent) : AbstractTableView(parent)
|
|||
mHighlightToken.text = "";
|
||||
mHighlightingMode = false;
|
||||
|
||||
mDisasm = new QBeaEngine();
|
||||
int maxModuleSize = (int)ConfigUint("Disassembler", "MaxModuleSize");
|
||||
Config()->writeUints();
|
||||
|
||||
mDisasm = new QBeaEngine(maxModuleSize);
|
||||
|
||||
mIsLastInstDisplayed = false;
|
||||
|
||||
|
|
|
@ -52,16 +52,19 @@ void ReferenceView::setupContextMenu()
|
|||
mFollowDumpAddress = new QAction("Follow in &Dump", this);
|
||||
connect(mFollowDumpAddress, SIGNAL(triggered()), this, SLOT(followDumpAddress()));
|
||||
|
||||
mFollowApiAddress = new QAction("Follow &API Address", this);
|
||||
connect(mFollowApiAddress, SIGNAL(triggered()), this, SLOT(followApiAddress()));
|
||||
|
||||
mToggleBreakpoint = new QAction("Toggle Breakpoint", this);
|
||||
mToggleBreakpoint->setShortcutContext(Qt::WidgetShortcut);
|
||||
this->addAction(mToggleBreakpoint);
|
||||
addAction(mToggleBreakpoint);
|
||||
mList->addAction(mToggleBreakpoint);
|
||||
mSearchList->addAction(mToggleBreakpoint);
|
||||
connect(mToggleBreakpoint, SIGNAL(triggered()), this, SLOT(toggleBreakpoint()));
|
||||
|
||||
mToggleBookmark = new QAction("Toggle Bookmark", this);
|
||||
mToggleBookmark->setShortcutContext(Qt::WidgetShortcut);
|
||||
this->addAction(mToggleBookmark);
|
||||
addAction(mToggleBookmark);
|
||||
mList->addAction(mToggleBookmark);
|
||||
mSearchList->addAction(mToggleBookmark);
|
||||
connect(mToggleBookmark, SIGNAL(triggered()), this, SLOT(toggleBookmark()));
|
||||
|
@ -134,12 +137,12 @@ void ReferenceView::setSingleSelection(int index, bool scroll)
|
|||
void ReferenceView::setSearchStartCol(int col)
|
||||
{
|
||||
if(col < mList->getColumnCount())
|
||||
this->mSearchStartCol = col;
|
||||
mSearchStartCol = col;
|
||||
}
|
||||
|
||||
void ReferenceView::referenceContextMenu(QMenu* wMenu)
|
||||
{
|
||||
if(!this->mCurList->getRowCount())
|
||||
if(!mCurList->getRowCount())
|
||||
return;
|
||||
QString text = mCurList->getCellContent(mCurList->getInitialSelection(), 0);
|
||||
duint addr;
|
||||
|
@ -149,6 +152,8 @@ void ReferenceView::referenceContextMenu(QMenu* wMenu)
|
|||
return;
|
||||
wMenu->addAction(mFollowAddress);
|
||||
wMenu->addAction(mFollowDumpAddress);
|
||||
if(apiAddressFromString(mCurList->getCellContent(mCurList->getInitialSelection(), 1)))
|
||||
wMenu->addAction(mFollowApiAddress);
|
||||
wMenu->addSeparator();
|
||||
wMenu->addAction(mToggleBreakpoint);
|
||||
wMenu->addAction(mToggleBookmark);
|
||||
|
@ -156,13 +161,20 @@ void ReferenceView::referenceContextMenu(QMenu* wMenu)
|
|||
|
||||
void ReferenceView::followAddress()
|
||||
{
|
||||
DbgCmdExecDirect(QString("disasm " + this->mCurList->getCellContent(this->mCurList->getInitialSelection(), 0)).toUtf8().constData());
|
||||
DbgCmdExecDirect(QString("disasm " + mCurList->getCellContent(mCurList->getInitialSelection(), 0)).toUtf8().constData());
|
||||
emit showCpu();
|
||||
}
|
||||
|
||||
void ReferenceView::followDumpAddress()
|
||||
{
|
||||
DbgCmdExecDirect(QString("dump " + this->mCurList->getCellContent(this->mCurList->getInitialSelection(), 0)).toUtf8().constData());
|
||||
DbgCmdExecDirect(QString("dump " + mCurList->getCellContent(mCurList->getInitialSelection(), 0)).toUtf8().constData());
|
||||
emit showCpu();
|
||||
}
|
||||
|
||||
void ReferenceView::followApiAddress()
|
||||
{
|
||||
int_t apiValue = apiAddressFromString(mCurList->getCellContent(mCurList->getInitialSelection(), 1));
|
||||
DbgCmdExecDirect(QString("disasm " + QString().sprintf("%p", apiValue)).toUtf8().constData());
|
||||
emit showCpu();
|
||||
}
|
||||
|
||||
|
@ -179,9 +191,9 @@ void ReferenceView::toggleBreakpoint()
|
|||
if(!DbgIsDebugging())
|
||||
return;
|
||||
|
||||
if(!this->mCurList->getRowCount())
|
||||
if(!mCurList->getRowCount())
|
||||
return;
|
||||
QString addrText = this->mCurList->getCellContent(this->mCurList->getInitialSelection(), 0).toUtf8().constData();
|
||||
QString addrText = mCurList->getCellContent(mCurList->getInitialSelection(), 0).toUtf8().constData();
|
||||
duint wVA;
|
||||
if(!DbgFunctions()->ValFromString(addrText.toUtf8().constData(), &wVA))
|
||||
return;
|
||||
|
@ -208,9 +220,9 @@ void ReferenceView::toggleBookmark()
|
|||
if(!DbgIsDebugging())
|
||||
return;
|
||||
|
||||
if(!this->mCurList->getRowCount())
|
||||
if(!mCurList->getRowCount())
|
||||
return;
|
||||
QString addrText = this->mCurList->getCellContent(this->mCurList->getInitialSelection(), 0);
|
||||
QString addrText = mCurList->getCellContent(mCurList->getInitialSelection(), 0);
|
||||
duint wVA;
|
||||
if(!DbgFunctions()->ValFromString(addrText.toUtf8().constData(), &wVA))
|
||||
return;
|
||||
|
@ -232,3 +244,17 @@ void ReferenceView::toggleBookmark()
|
|||
}
|
||||
GuiUpdateAllViews();
|
||||
}
|
||||
|
||||
int_t ReferenceView::apiAddressFromString(const QString & s)
|
||||
{
|
||||
QRegExp regEx("call.+<(.+)>");
|
||||
regEx.indexIn(s);
|
||||
QStringList list = regEx.capturedTexts();
|
||||
if(list.length() < 2)
|
||||
return 0;
|
||||
QString match = list[1];
|
||||
if(match[0] == QChar('&'))
|
||||
match.remove(0, 1);
|
||||
duint value;
|
||||
return DbgFunctions()->ValFromString(match.toUtf8().constData(), &value) && DbgMemIsValidReadPtr(value) ? value : 0;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ private slots:
|
|||
void referenceContextMenu(QMenu* wMenu);
|
||||
void followAddress();
|
||||
void followDumpAddress();
|
||||
void followApiAddress();
|
||||
void followGenericAddress();
|
||||
void toggleBreakpoint();
|
||||
void toggleBookmark();
|
||||
|
@ -36,10 +37,13 @@ private:
|
|||
QProgressBar* mSearchProgress;
|
||||
QAction* mFollowAddress;
|
||||
QAction* mFollowDumpAddress;
|
||||
QAction* mFollowApiAddress;
|
||||
QAction* mToggleBreakpoint;
|
||||
QAction* mToggleBookmark;
|
||||
bool mFollowDumpDefault;
|
||||
QLabel* mCountLabel;
|
||||
|
||||
int_t apiAddressFromString(const QString & s);
|
||||
};
|
||||
|
||||
#endif // REFERENCEVIEW_H
|
||||
|
|
|
@ -308,6 +308,7 @@ void StdTable::copyLineSlot()
|
|||
QString title = mCopyTitles.at(i);
|
||||
if(title.length())
|
||||
finalText += title + "=";
|
||||
while(cellContent.endsWith(" ")) cellContent.chop(1);
|
||||
finalText += cellContent;
|
||||
finalText += "\r\n";
|
||||
}
|
||||
|
@ -353,7 +354,7 @@ void StdTable::copyTableSlot()
|
|||
finalRowText += " ";
|
||||
QString cellContent = getCellContent(i, j);
|
||||
int colWidth = getColumnWidth(j) / charwidth;
|
||||
if(colWidth)
|
||||
if(colWidth && j != colCount - 1)
|
||||
finalRowText += cellContent.leftJustified(colWidth, QChar(' '), true);
|
||||
else
|
||||
finalRowText += cellContent;
|
||||
|
@ -370,7 +371,9 @@ void StdTable::copyEntrySlot()
|
|||
if(!action)
|
||||
return;
|
||||
int col = action->objectName().toInt();
|
||||
Bridge::CopyToClipboard(getCellContent(getInitialSelection(), col));
|
||||
QString finalText = getCellContent(getInitialSelection(), col);
|
||||
while(finalText.endsWith(" ")) finalText.chop(1);
|
||||
Bridge::CopyToClipboard(finalText);
|
||||
}
|
||||
|
||||
void StdTable::setupCopyMenu(QMenu* copyMenu)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -23,75 +23,18 @@ public:
|
|||
static Bridge* getBridge();
|
||||
static void initBridge();
|
||||
|
||||
// Message processing function
|
||||
void* processMessage(GUIMSG type, void* param1, void* param2);
|
||||
|
||||
// Misc functions
|
||||
static void CopyToClipboard(const QString & text);
|
||||
|
||||
//result function
|
||||
void setResult(int_t result = 0);
|
||||
|
||||
// Exports Binding
|
||||
void emitDisassembleAtSignal(int_t va, int_t eip);
|
||||
void emitUpdateDisassembly();
|
||||
void emitDbgStateChanged(DBGSTATE state);
|
||||
void emitAddMsgToLog(QString msg);
|
||||
void emitClearLog();
|
||||
void emitUpdateRegisters();
|
||||
void emitUpdateBreakpoints();
|
||||
void emitUpdateWindowTitle(QString filename);
|
||||
void emitDumpAt(int_t va);
|
||||
void emitScriptAdd(int count, const char** lines);
|
||||
void emitScriptClear();
|
||||
void emitScriptSetIp(int line);
|
||||
void emitScriptError(int line, QString message);
|
||||
void emitScriptSetTitle(QString title);
|
||||
void emitScriptSetInfoLine(int line, QString info);
|
||||
void emitScriptMessage(QString message);
|
||||
int emitScriptQuestion(QString message);
|
||||
void emitScriptEnableHighlighting(bool enable);
|
||||
void emitUpdateSymbolList(int module_count, SYMBOLMODULEINFO* modules);
|
||||
void emitAddMsgToSymbolLog(QString msg);
|
||||
void emitClearSymbolLog();
|
||||
void emitSetSymbolProgress(int progress);
|
||||
void emitReferenceAddColumnAt(int width, QString title);
|
||||
void emitReferenceSetRowCount(int_t count);
|
||||
void emitReferenceSetCellContent(int r, int c, QString s);
|
||||
void emitReferenceReloadData();
|
||||
void emitReferenceSetSingleSelection(int index, bool scroll);
|
||||
void emitReferenceSetProgress(int progress);
|
||||
void emitReferenceSetSearchStartCol(int col);
|
||||
void emitReferenceInitialize(QString name);
|
||||
void emitStackDumpAt(uint_t va, uint_t csp);
|
||||
void emitUpdateDump();
|
||||
void emitUpdateThreads();
|
||||
void emitUpdateMemory();
|
||||
void emitAddRecentFile(QString file);
|
||||
void emitSetLastException(unsigned int exceptionCode);
|
||||
void emitMenuAddToList(QWidget* parent, QMenu* menu, int hMenu, int hParentMenu = -1);
|
||||
int emitMenuAddMenu(int hMenu, QString title);
|
||||
int emitMenuAddMenuEntry(int hMenu, QString title);
|
||||
void emitMenuAddSeparator(int hMenu);
|
||||
void emitMenuClearMenu(int hMenu);
|
||||
void emitMenuRemoveEntry(int hEntry);
|
||||
bool emitSelectionGet(int hWindow, SELECTIONDATA* selection);
|
||||
bool emitSelectionSet(int hWindow, const SELECTIONDATA* selection);
|
||||
bool emitGetStrWindow(const QString title, QString* text);
|
||||
void emitAutoCompleteAddCmd(const QString cmd);
|
||||
void emitAutoCompleteDelCmd(const QString cmd);
|
||||
void emitAutoCompleteClearAll();
|
||||
void emitAddMsgToStatusBar(QString msg);
|
||||
void emitUpdateSideBar();
|
||||
void emitRepaintTableView();
|
||||
void emitUpdatePatches();
|
||||
void emitUpdateCallStack();
|
||||
void emitSymbolRefreshCurrent();
|
||||
//helper functions
|
||||
void emitLoadSourceFile(const QString path, int line = 0, int selection = 0);
|
||||
void emitSetMenuEntryIcon(int hEntry, const ICONDATA* icon);
|
||||
void emitSetMenuIcon(int hMenu, const ICONDATA* icon);
|
||||
void emitShowCpu();
|
||||
void emitAddQWidgetTab(QWidget* qWidget);
|
||||
void emitShowQWidgetTab(QWidget* qWidget);
|
||||
void emitCloseQWidgetTab(QWidget* qWidget);
|
||||
void emitExecuteOnGuiThread(void* cbGuiThread);
|
||||
void emitMenuAddToList(QWidget* parent, QMenu* menu, int hMenu, int hParentMenu = -1);
|
||||
|
||||
//Public variables
|
||||
void* winId;
|
||||
|
@ -170,9 +113,6 @@ private:
|
|||
QMutex* mBridgeMutex;
|
||||
int_t bridgeResult;
|
||||
volatile bool hasBridgeResult;
|
||||
|
||||
public:
|
||||
|
||||
};
|
||||
|
||||
#endif // BRIDGE_H
|
||||
|
|
|
@ -172,20 +172,26 @@ void BeaTokenizer::Mnemonic(BeaInstructionToken* instr, const DISASM* disasm)
|
|||
}
|
||||
}
|
||||
|
||||
QString BeaTokenizer::PrintValue(const BeaTokenValue* value, bool module)
|
||||
QString BeaTokenizer::PrintValue(const BeaTokenValue* value, bool module, int maxModuleSize)
|
||||
{
|
||||
char labelText[MAX_LABEL_SIZE] = "";
|
||||
char moduleText[MAX_MODULE_SIZE] = "";
|
||||
char module_[MAX_MODULE_SIZE] = "";
|
||||
QString moduleText;
|
||||
int_t addr = value->value;
|
||||
bool bHasLabel = DbgGetLabelAt(addr, SEG_DEFAULT, labelText);
|
||||
bool bHasModule = (module && DbgGetModuleAt(addr, moduleText) && !QString(labelText).startsWith("JMP.&"));
|
||||
bool bHasModule = (module && DbgGetModuleAt(addr, module_) && !QString(labelText).startsWith("JMP.&"));
|
||||
moduleText = QString(module_);
|
||||
if(maxModuleSize != -1)
|
||||
moduleText.truncate(maxModuleSize);
|
||||
if(moduleText.length())
|
||||
moduleText += ".";
|
||||
QString addrText;
|
||||
addrText = QString("%1").arg(addr & (uint_t) - 1, 0, 16, QChar('0')).toUpper();
|
||||
QString finalText;
|
||||
if(bHasLabel && bHasModule) //<module.label>
|
||||
finalText = QString("<%1.%2>").arg(moduleText).arg(labelText);
|
||||
finalText = QString("<%1%2>").arg(moduleText).arg(labelText);
|
||||
else if(bHasModule) //module.addr
|
||||
finalText = QString("%1.%2").arg(moduleText).arg(addrText);
|
||||
finalText = QString("%1%2").arg(moduleText).arg(addrText);
|
||||
else if(bHasLabel) //<label>
|
||||
finalText = QString("<%1>").arg(labelText);
|
||||
else
|
||||
|
@ -204,7 +210,7 @@ QString BeaTokenizer::RegisterToString(int size, int reg)
|
|||
return currentMap->find(regValue).value();
|
||||
}
|
||||
|
||||
void BeaTokenizer::Argument(BeaInstructionToken* instr, const DISASM* disasm, const ARGTYPE* arg, bool* hadarg)
|
||||
void BeaTokenizer::Argument(BeaInstructionToken* instr, const DISASM* disasm, const ARGTYPE* arg, bool* hadarg, int maxModuleSize)
|
||||
{
|
||||
if(arg->ArgType == NO_ARGUMENT || !arg->ArgMnemonic[0]) //empty/implicit argument
|
||||
return;
|
||||
|
@ -287,7 +293,7 @@ void BeaTokenizer::Argument(BeaInstructionToken* instr, const DISASM* disasm, co
|
|||
BeaTokenType type = TokenValue;
|
||||
if(DbgMemIsValidReadPtr(displacement.value)) //pointer
|
||||
type = TokenAddress;
|
||||
AddToken(instr, type, PrintValue(&printDisplacement, false), &displacement);
|
||||
AddToken(instr, type, PrintValue(&printDisplacement, false, maxModuleSize), &displacement);
|
||||
}
|
||||
AddToken(instr, bracketsType, "]", 0);
|
||||
}
|
||||
|
@ -296,7 +302,7 @@ void BeaTokenizer::Argument(BeaInstructionToken* instr, const DISASM* disasm, co
|
|||
BeaTokenValue value;
|
||||
value.size = arg->ArgSize / 8;
|
||||
value.value = disasm->Instruction.AddrValue;
|
||||
AddToken(instr, TokenAddress, PrintValue(&value, true), &value);
|
||||
AddToken(instr, TokenAddress, PrintValue(&value, true, maxModuleSize), &value);
|
||||
}
|
||||
else if((arg->ArgType & CONSTANT_TYPE) == CONSTANT_TYPE) //immediat
|
||||
{
|
||||
|
@ -326,7 +332,7 @@ void BeaTokenizer::Argument(BeaInstructionToken* instr, const DISASM* disasm, co
|
|||
BeaTokenType type = TokenValue;
|
||||
if(DbgMemIsValidReadPtr(value.value)) //pointer
|
||||
type = TokenAddress;
|
||||
AddToken(instr, type, PrintValue(&value, true), &value);
|
||||
AddToken(instr, type, PrintValue(&value, true, maxModuleSize), &value);
|
||||
}
|
||||
else if((arg->ArgType & REGISTER_TYPE) == REGISTER_TYPE) //registers
|
||||
{
|
||||
|
@ -527,7 +533,7 @@ unsigned long BeaTokenizer::HashInstruction(const DISASM* disasm)
|
|||
return hash;
|
||||
}
|
||||
|
||||
void BeaTokenizer::TokenizeInstruction(BeaInstructionToken* instr, const DISASM* disasm)
|
||||
void BeaTokenizer::TokenizeInstruction(BeaInstructionToken* instr, const DISASM* disasm, int maxModuleSize)
|
||||
{
|
||||
//initialization
|
||||
instr->hash = HashInstruction(disasm); //hash instruction
|
||||
|
@ -548,18 +554,18 @@ void BeaTokenizer::TokenizeInstruction(BeaInstructionToken* instr, const DISASM*
|
|||
BeaTokenValue val;
|
||||
val.size = 2;
|
||||
val.value = segment;
|
||||
AddToken(instr, TokenValue, PrintValue(&val, true), &val);
|
||||
AddToken(instr, TokenValue, PrintValue(&val, true, maxModuleSize), &val);
|
||||
AddToken(instr, TokenUncategorized, ":", 0);
|
||||
val.size = 4;
|
||||
val.value = address;
|
||||
AddToken(instr, TokenAddress, PrintValue(&val, true), &val);
|
||||
AddToken(instr, TokenAddress, PrintValue(&val, true, maxModuleSize), &val);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool hadarg = false;
|
||||
Argument(instr, disasm, &disasm->Argument1, &hadarg);
|
||||
Argument(instr, disasm, &disasm->Argument2, &hadarg);
|
||||
Argument(instr, disasm, &disasm->Argument3, &hadarg);
|
||||
Argument(instr, disasm, &disasm->Argument1, &hadarg, maxModuleSize);
|
||||
Argument(instr, disasm, &disasm->Argument2, &hadarg, maxModuleSize);
|
||||
Argument(instr, disasm, &disasm->Argument3, &hadarg, maxModuleSize);
|
||||
}
|
||||
|
||||
//remove spaces when needed
|
||||
|
|
|
@ -78,7 +78,7 @@ public:
|
|||
|
||||
static void Init();
|
||||
static unsigned long HashInstruction(const DISASM* disasm);
|
||||
static void TokenizeInstruction(BeaInstructionToken* instr, const DISASM* disasm);
|
||||
static void TokenizeInstruction(BeaInstructionToken* instr, const DISASM* disasm, int maxModuleSize);
|
||||
static void TokenToRichText(const BeaInstructionToken* instr, QList<RichTextPainter::CustomRichText_t>* richTextList, const BeaSingleToken* highlightToken);
|
||||
static bool TokenFromX(const BeaInstructionToken* instr, BeaSingleToken* token, int x, int charwidth);
|
||||
static bool IsHighlightableToken(const BeaSingleToken* token);
|
||||
|
@ -99,9 +99,9 @@ private:
|
|||
static void StringInstructionMemory(BeaInstructionToken* instr, int size, QString segment, ARGUMENTS_TYPE reg);
|
||||
static void StringInstruction(QString mnemonic, BeaInstructionToken* instr, const DISASM* disasm);
|
||||
static void Mnemonic(BeaInstructionToken* instr, const DISASM* disasm);
|
||||
static QString PrintValue(const BeaTokenValue* value, bool module);
|
||||
static QString PrintValue(const BeaTokenValue* value, bool module, int maxModuleSize);
|
||||
static QString RegisterToString(int size, int reg);
|
||||
static void Argument(BeaInstructionToken* instr, const DISASM* disasm, const ARGTYPE* arg, bool* hadarg);
|
||||
static void Argument(BeaInstructionToken* instr, const DISASM* disasm, const ARGTYPE* arg, bool* hadarg, int maxModuleSize);
|
||||
static void AddColorName(BeaTokenType type, QString color, QString backgroundColor);
|
||||
};
|
||||
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
#include "QBeaEngine.h"
|
||||
|
||||
QBeaEngine::QBeaEngine()
|
||||
QBeaEngine::QBeaEngine(int maxModuleSize)
|
||||
{
|
||||
mMaxModuleSize = maxModuleSize;
|
||||
// Reset the Disasm structure
|
||||
memset(&mDisasmStruct, 0, sizeof(DISASM));
|
||||
BeaTokenizer::Init();
|
||||
|
@ -182,7 +183,7 @@ Instruction_t QBeaEngine::DisassembleAt(byte_t* data, uint_t size, uint_t instIn
|
|||
wInst.disasm = mDisasmStruct;
|
||||
|
||||
//tokenize
|
||||
BeaTokenizer::TokenizeInstruction(&wInst.tokens, &mDisasmStruct);
|
||||
BeaTokenizer::TokenizeInstruction(&wInst.tokens, &mDisasmStruct, mMaxModuleSize);
|
||||
|
||||
return wInst;
|
||||
}
|
||||
|
|
|
@ -18,13 +18,14 @@ typedef struct _Instruction_t
|
|||
class QBeaEngine
|
||||
{
|
||||
public:
|
||||
explicit QBeaEngine();
|
||||
explicit QBeaEngine(int maxModuleSize);
|
||||
ulong DisassembleBack(byte_t* data, uint_t base, uint_t size, uint_t ip, int n);
|
||||
ulong DisassembleNext(byte_t* data, uint_t base, uint_t size, uint_t ip, int n);
|
||||
Instruction_t DisassembleAt(byte_t* data, uint_t size, uint_t instIndex, uint_t origBase, uint_t origInstRVA);
|
||||
|
||||
private:
|
||||
DISASM mDisasmStruct;
|
||||
int mMaxModuleSize;
|
||||
};
|
||||
|
||||
#endif // QBEAENGINE_H
|
||||
|
|
|
@ -917,7 +917,7 @@ void CPUDisassembly::assembleAt()
|
|||
|
||||
mMemPage->read(reinterpret_cast<byte_t*>(wBuffer.data()), wRVA, wMaxByteCountToRead);
|
||||
|
||||
QBeaEngine disasm;
|
||||
QBeaEngine disasm(-1);
|
||||
Instruction_t instr = disasm.DisassembleAt(reinterpret_cast<byte_t*>(wBuffer.data()), wMaxByteCountToRead, 0, 0, wVA);
|
||||
|
||||
QString actual_inst = instr.instStr;
|
||||
|
|
|
@ -211,9 +211,22 @@ void SettingsDialog::LoadSettings()
|
|||
{
|
||||
ui->chkSetJIT->setDisabled(true);
|
||||
ui->chkConfirmBeforeAtt->setDisabled(true);
|
||||
ui->lbladminwarning->setText(QString("Warning: Run the debugger as Admin to enable JIT."));
|
||||
ui->lblAdminWarning->setText(QString("<font color=\"red\"><b>Warning</b></font>: Run the debugger as Admin to enable JIT."));
|
||||
}
|
||||
else
|
||||
ui->lblAdminWarning->setText("");
|
||||
}
|
||||
char setting[MAX_SETTING_SIZE] = "";
|
||||
if(BridgeSettingGet("Symbols", "DefaultStore", setting))
|
||||
ui->editSymbolStore->setText(QString(setting));
|
||||
else
|
||||
{
|
||||
QString defaultStore = "http://msdl.microsoft.com/download/symbols";
|
||||
ui->editSymbolStore->setText(defaultStore);
|
||||
BridgeSettingSet("Symbols", "DefaultStore", defaultStore.toUtf8().constData());
|
||||
}
|
||||
if(BridgeSettingGet("Symbols", "CachePath", setting))
|
||||
ui->editSymbolCache->setText(QString(setting));
|
||||
|
||||
bJitOld = settings.miscSetJIT;
|
||||
bJitAutoOld = settings.miscSetJITAuto;
|
||||
|
@ -279,6 +292,10 @@ void SettingsDialog::SaveSettings()
|
|||
DbgCmdExecDirect("setjitauto off");
|
||||
}
|
||||
}
|
||||
if(settings.miscSymbolStore)
|
||||
BridgeSettingSet("Symbols", "DefaultStore", ui->editSymbolStore->text().toUtf8().constData());
|
||||
if(settings.miscSymbolCache)
|
||||
BridgeSettingSet("Symbols", "CachePath", ui->editSymbolCache->text().toUtf8().constData());
|
||||
|
||||
Config()->load();
|
||||
DbgSettingsUpdated();
|
||||
|
@ -594,3 +611,13 @@ void SettingsDialog::on_chkTabBetweenMnemonicAndArguments_stateChanged(int arg1)
|
|||
{
|
||||
settings.disasmTabBetweenMnemonicAndArguments = arg1 == Qt::Checked;
|
||||
}
|
||||
|
||||
void SettingsDialog::on_editSymbolStore_textEdited(const QString & arg1)
|
||||
{
|
||||
settings.miscSymbolStore = true;
|
||||
}
|
||||
|
||||
void SettingsDialog::on_editSymbolCache_textEdited(const QString & arg1)
|
||||
{
|
||||
settings.miscSymbolCache = true;
|
||||
}
|
||||
|
|
|
@ -59,6 +59,8 @@ private slots:
|
|||
//Misc tab
|
||||
void on_chkSetJIT_stateChanged(int arg1);
|
||||
void on_chkConfirmBeforeAtt_stateChanged(int arg1);
|
||||
void on_editSymbolStore_textEdited(const QString & arg1);
|
||||
void on_editSymbolCache_textEdited(const QString & arg1);
|
||||
|
||||
private:
|
||||
//enums
|
||||
|
@ -123,6 +125,8 @@ private:
|
|||
//Misc Tab
|
||||
bool miscSetJIT;
|
||||
bool miscSetJITAuto;
|
||||
bool miscSymbolStore;
|
||||
bool miscSymbolCache;
|
||||
};
|
||||
|
||||
//variables
|
||||
|
|
|
@ -426,60 +426,89 @@
|
|||
<attribute name="title">
|
||||
<string>Misc</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="chkSetJIT">
|
||||
<property name="text">
|
||||
<string>Set x64dbg as Just In Time Debugger</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>JIT:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="editJIT">
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="chkConfirmBeforeAtt">
|
||||
<property name="text">
|
||||
<string>Confirm before attaching</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lbladminwarning">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
<widget class="QWidget" name="layoutWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>11</x>
|
||||
<y>13</y>
|
||||
<width>341</width>
|
||||
<height>145</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_9">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Symbol Store:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Symbol Path:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_8">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="editSymbolStore"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="editSymbolCache"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="chkSetJIT">
|
||||
<property name="text">
|
||||
<string>Set x64dbg as Just In Time Debugger</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>JIT:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="editJIT">
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="chkConfirmBeforeAtt">
|
||||
<property name="text">
|
||||
<string>Confirm before attaching</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblAdminWarning">
|
||||
<property name="text">
|
||||
<string><font color="red">DIE SCUM!</font></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
|
@ -40,7 +40,15 @@ void SourceView::setSelection(int line)
|
|||
{
|
||||
int offset = line - 1;
|
||||
if(isValidIndex(offset, 0))
|
||||
{
|
||||
int rangefrom = getTableOffset();
|
||||
int rangeto = rangefrom + getViewableRowsCount() - 1;
|
||||
if(offset < rangefrom) //ip lays before the current view
|
||||
setTableOffset(offset);
|
||||
else if(offset > (rangeto - 1)) //ip lays after the current view
|
||||
setTableOffset(offset - getViewableRowsCount() + 2);
|
||||
setSingleSelection(offset);
|
||||
}
|
||||
reloadData(); //repaint
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "StatusLabel.h"
|
||||
#include <QTextDocument>
|
||||
|
||||
StatusLabel::StatusLabel(QStatusBar* parent) : QLabel(parent)
|
||||
{
|
||||
|
@ -55,8 +56,8 @@ void StatusLabel::logUpdate(QString message)
|
|||
//only show the last line in the status label
|
||||
QStringList lineList = labelText.split(QChar('\n'), QString::SkipEmptyParts);
|
||||
if(lineList.size())
|
||||
setText(lineList[lineList.length() - 1]);
|
||||
setText(Qt::convertFromPlainText(lineList[lineList.length() - 1]));
|
||||
else
|
||||
setText(labelText);
|
||||
setText(Qt::convertFromPlainText(labelText));
|
||||
this->repaint();
|
||||
}
|
||||
|
|
|
@ -170,6 +170,9 @@ Configuration::Configuration() : QObject()
|
|||
QMap<QString, uint_t> hexdumpUint;
|
||||
hexdumpUint.insert("DefaultView", 0);
|
||||
defaultUints.insert("HexDump", hexdumpUint);
|
||||
QMap<QString, uint_t> disasmUint;
|
||||
disasmUint.insert("MaxModuleSize", -1);
|
||||
defaultUints.insert("Disassembler", disasmUint);
|
||||
|
||||
//font settings
|
||||
QFont font("Lucida Console", 8, QFont::Normal, false);
|
||||
|
@ -295,7 +298,6 @@ Configuration* Config()
|
|||
return mPtr;
|
||||
}
|
||||
|
||||
|
||||
void Configuration::load()
|
||||
{
|
||||
readColors();
|
||||
|
|
Loading…
Reference in New Issue