1
0
Fork 0
Conflicts:
	x64_dbg_dbg/functionanalysis.cpp
	x64_dbg_dbg/x64_dbg_dbg.vcxproj
	x64_dbg_dbg/x64_dbg_dbg.vcxproj.filters
This commit is contained in:
Nukem 2015-07-09 17:05:37 -04:00
commit ab3ecaf054
40 changed files with 807 additions and 173 deletions

View File

@ -1120,6 +1120,26 @@ BRIDGE_IMPEXP void GuiShowCpu()
_gui_sendmessage(GUI_SHOW_CPU, 0, 0);
}
BRIDGE_IMPEXP void GuiAddQWidgetTab(void* qWidget)
{
_gui_sendmessage(GUI_ADD_QWIDGET_TAB, qWidget, nullptr);
}
BRIDGE_IMPEXP void GuiShowQWidgetTab(void* qWidget)
{
_gui_sendmessage(GUI_SHOW_QWIDGET_TAB, qWidget, nullptr);
}
BRIDGE_IMPEXP void GuiCloseQWidgetTab(void* qWidget)
{
_gui_sendmessage(GUI_CLOSE_QWIDGET_TAB, qWidget, nullptr);
}
BRIDGE_IMPEXP void GuiExecuteOnGuiThread(GUICALLBACK cbGuiThread)
{
_gui_sendmessage(GUI_EXECUTE_ON_GUI_THREAD, cbGuiThread, nullptr);
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
hInst = hinstDLL;

View File

@ -761,9 +761,16 @@ typedef enum
GUI_LOAD_SOURCE_FILE, // param1=const char* path, param2=line
GUI_MENU_SET_ICON, // param1=int hMenu, param2=ICONINFO*
GUI_MENU_SET_ENTRY_ICON, // param1=int hEntry, param2=ICONINFO*
GUI_SHOW_CPU // param1=unused, param2=unused
GUI_SHOW_CPU, // param1=unused, param2=unused
GUI_ADD_QWIDGET_TAB, // param1=QWidget*, param2=unused
GUI_SHOW_QWIDGET_TAB, // param1=QWidget*, param2=unused
GUI_CLOSE_QWIDGET_TAB, // param1=QWidget*, param2=unused
GUI_EXECUTE_ON_GUI_THREAD // param1=GUICALLBACK, param2=unused
} GUIMSG;
//GUI Typedefs
typedef void (*GUICALLBACK)();
//GUI structures
typedef struct
{
@ -848,6 +855,10 @@ BRIDGE_IMPEXP void GuiLoadSourceFile(const char* path, int line);
BRIDGE_IMPEXP void GuiMenuSetIcon(int hMenu, const ICONDATA* icon);
BRIDGE_IMPEXP void GuiMenuSetEntryIcon(int hEntry, const ICONDATA* icon);
BRIDGE_IMPEXP void GuiShowCpu();
BRIDGE_IMPEXP void GuiAddQWidgetTab(void* qWidget);
BRIDGE_IMPEXP void GuiShowQWidgetTab(void* qWidget);
BRIDGE_IMPEXP void GuiCloseQWidgetTab(void* qWidget);
BRIDGE_IMPEXP void GuiExecuteOnGuiThread(GUICALLBACK cbGuiThread);
#ifdef __cplusplus
}

View File

@ -109,7 +109,7 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PreprocessorDefinitions>BUILD_BRIDGE;WIN32;NDEBUG;_WINDOWS;_USRDLL;X64_DBG_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<Optimization>MaxSpeed</Optimization>
@ -139,7 +139,7 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PreprocessorDefinitions>BUILD_BRIDGE;WIN32;NDEBUG;_WINDOWS;_USRDLL;X64_DBG_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>

View File

@ -17,6 +17,7 @@
#include <vector>
#include <stack>
#include <map>
#include <set>
#include <algorithm>
#include <unordered_map>
#include <tlhelp32.h>

View File

@ -0,0 +1,22 @@
#include "_scriptapi_assembler.h"
#include "assemble.h"
SCRIPT_EXPORT bool Script::Assembler::Assemble(duint addr, unsigned char* dest, int* size, const char* instruction)
{
return assemble(addr, dest, size, instruction, nullptr);
}
SCRIPT_EXPORT bool Script::Assembler::AssembleEx(duint addr, unsigned char* dest, int* size, const char* instruction, char* error)
{
return assemble(addr, dest, size, instruction, error);
}
SCRIPT_EXPORT bool Script::Assembler::AssembleMem(duint addr, const char* instruction)
{
return assembleat(addr, instruction, nullptr, nullptr, false);
}
SCRIPT_EXPORT bool Script::Assembler::AssembleMemEx(duint addr, const char* instruction, int* size, char* error, bool fillnop)
{
return assembleat(addr, instruction, size, error, fillnop);
}

View File

@ -0,0 +1,17 @@
#ifndef _SCRIPTAPI_ASSEMBLER_H
#define _SCRIPTAPI_ASSEMBLER_H
#include "_scriptapi.h"
namespace Script
{
namespace Assembler
{
SCRIPT_EXPORT bool Assemble(duint addr, unsigned char* dest, int* size, const char* instruction); //dest[16]
SCRIPT_EXPORT bool AssembleEx(duint addr, unsigned char* dest, int* size, const char* instruction, char* error); //dest[16], error[MAX_ERROR_SIZE]
SCRIPT_EXPORT bool AssembleMem(duint addr, const char* instruction);
SCRIPT_EXPORT bool AssembleMemEx(duint addr, const char* instruction, int* size, char* error, bool fillnop); //error[MAX_ERROR_SIZE]
}; //Assembler
}; //Script
#endif //_SCRIPTAPI_ASSEMBLER_H

View File

@ -1,51 +1,5 @@
#include "_scriptapi_gui.h"
static inline int windowToBridge(Script::Gui::Window window)
{
switch(window)
{
case Script::Gui::DisassemblyWindow:
return GUI_DISASSEMBLY;
case Script::Gui::DumpWindow:
return GUI_DUMP;
case Script::Gui::StackWindow:
return GUI_STACK;
default:
return GUI_DISASSEMBLY;
}
}
SCRIPT_EXPORT bool Script::Gui::SelectionGet(Script::Gui::Window window, duint* start, duint* end)
{
SELECTIONDATA selection;
if(!GuiSelectionGet(windowToBridge(window), &selection))
return false;
if(start)
*start = selection.start;
if(end)
*end = selection.end;
return true;
}
SCRIPT_EXPORT bool Script::Gui::SelectionSet(Script::Gui::Window window, duint start, duint end)
{
SELECTIONDATA selection;
selection.start = start;
selection.end = end;
return GuiSelectionSet(windowToBridge(window), &selection);
}
SCRIPT_EXPORT duint Script::Gui::SelectionGetStart(Script::Gui::Window window)
{
duint start;
return Gui::SelectionGet(window, &start, nullptr) ? start : 0;
}
SCRIPT_EXPORT duint Script::Gui::SelectionGetEnd(Script::Gui::Window window)
{
duint end;
return Gui::SelectionGet(window, nullptr, &end) ? end : 0;
}
#include "_scriptapi_misc.h"
SCRIPT_EXPORT bool Script::Gui::Disassembly::SelectionGet(duint* start, duint* end)
{
@ -106,3 +60,93 @@ SCRIPT_EXPORT duint Script::Gui::Stack::SelectionGetEnd()
{
return Gui::SelectionGetEnd(StackWindow);
}
static inline int windowToBridge(Script::Gui::Window window)
{
switch(window)
{
case Script::Gui::DisassemblyWindow:
return GUI_DISASSEMBLY;
case Script::Gui::DumpWindow:
return GUI_DUMP;
case Script::Gui::StackWindow:
return GUI_STACK;
default:
return GUI_DISASSEMBLY;
}
}
SCRIPT_EXPORT bool Script::Gui::SelectionGet(Script::Gui::Window window, duint* start, duint* end)
{
SELECTIONDATA selection;
if(!GuiSelectionGet(windowToBridge(window), &selection))
return false;
if(start)
*start = selection.start;
if(end)
*end = selection.end;
return true;
}
SCRIPT_EXPORT bool Script::Gui::SelectionSet(Script::Gui::Window window, duint start, duint end)
{
SELECTIONDATA selection;
selection.start = start;
selection.end = end;
return GuiSelectionSet(windowToBridge(window), &selection);
}
SCRIPT_EXPORT duint Script::Gui::SelectionGetStart(Script::Gui::Window window)
{
duint start;
return Gui::SelectionGet(window, &start, nullptr) ? start : 0;
}
SCRIPT_EXPORT duint Script::Gui::SelectionGetEnd(Script::Gui::Window window)
{
duint end;
return Gui::SelectionGet(window, nullptr, &end) ? end : 0;
}
SCRIPT_EXPORT void Script::Gui::Message(const char* message)
{
GuiScriptMessage(message);
}
SCRIPT_EXPORT bool Script::Gui::MessageYesNo(const char* message)
{
return !!GuiScriptMsgyn(message);
}
SCRIPT_EXPORT bool Script::Gui::InputLine(const char* title, char* text)
{
return GuiGetLineWindow(title, text);
}
SCRIPT_EXPORT bool Script::Gui::InputValue(const char* title, duint* value)
{
Memory<char*> line(GUI_MAX_LINE_SIZE);
if(!GuiGetLineWindow(title, line()))
return false;
return Misc::ParseExpression(line(), value);
}
SCRIPT_EXPORT void Script::Gui::Refresh()
{
GuiUpdateAllViews();
}
SCRIPT_EXPORT void Script::Gui::AddQWidgetTab(void* qWidget)
{
GuiAddQWidgetTab(qWidget);
}
SCRIPT_EXPORT void Script::Gui::ShowQWidgetTab(void* qWidget)
{
GuiShowQWidgetTab(qWidget);
}
SCRIPT_EXPORT void Script::Gui::CloseQWidgetTab(void* qWidget)
{
GuiCloseQWidgetTab(qWidget);
}

View File

@ -7,18 +7,6 @@ namespace Script
{
namespace Gui
{
enum Window
{
DisassemblyWindow,
DumpWindow,
StackWindow
};
SCRIPT_EXPORT bool SelectionGet(Window window, duint* start, duint* end);
SCRIPT_EXPORT bool SelectionSet(Window window, duint start, duint end);
SCRIPT_EXPORT duint SelectionGetStart(Window window);
SCRIPT_EXPORT duint SelectionGetEnd(Window window);
namespace Disassembly
{
SCRIPT_EXPORT bool SelectionGet(duint* start, duint* end);
@ -42,6 +30,30 @@ SCRIPT_EXPORT bool SelectionSet(duint start, duint end);
SCRIPT_EXPORT duint SelectionGetStart();
SCRIPT_EXPORT duint SelectionGetEnd();
}; //Stack
}; //Gui
namespace Gui
{
enum Window
{
DisassemblyWindow,
DumpWindow,
StackWindow
};
SCRIPT_EXPORT bool SelectionGet(Window window, duint* start, duint* end);
SCRIPT_EXPORT bool SelectionSet(Window window, duint start, duint end);
SCRIPT_EXPORT duint SelectionGetStart(Window window);
SCRIPT_EXPORT duint SelectionGetEnd(Window window);
SCRIPT_EXPORT void Message(const char* message);
SCRIPT_EXPORT bool MessageYesNo(const char* message);
SCRIPT_EXPORT bool InputLine(const char* title, char* text); //text[GUI_MAX_LINE_SIZE]
SCRIPT_EXPORT bool InputValue(const char* title, duint* value);
SCRIPT_EXPORT void Refresh();
SCRIPT_EXPORT void AddQWidgetTab(void* qWidget);
SCRIPT_EXPORT void ShowQWidgetTab(void* qWidget);
SCRIPT_EXPORT void CloseQWidgetTab(void* qWidget);
}; //Gui
}; //Script

View File

@ -11,6 +11,21 @@ SCRIPT_EXPORT bool Script::Memory::Write(duint addr, const void* data, duint siz
return MemWrite((void*)addr, (void*)data, size, sizeWritten);
}
SCRIPT_EXPORT bool Script::Memory::IsValidPtr(duint addr)
{
return MemIsValidReadPtr(addr);
}
SCRIPT_EXPORT duint Script::Memory::RemoteAlloc(duint addr, duint size)
{
return (duint)MemAllocRemote(addr, size, PAGE_EXECUTE_READWRITE);
}
SCRIPT_EXPORT bool Script::Memory::RemoteFree(duint addr)
{
return MemFreeRemote(addr);
}
SCRIPT_EXPORT unsigned char Script::Memory::ReadByte(duint addr)
{
unsigned char data;

View File

@ -9,6 +9,9 @@ namespace Memory
{
SCRIPT_EXPORT bool Read(duint addr, void* data, duint size, duint* sizeRead);
SCRIPT_EXPORT bool Write(duint addr, const void* data, duint size, duint* sizeWritten);
SCRIPT_EXPORT bool IsValidPtr(duint addr);
SCRIPT_EXPORT duint RemoteAlloc(duint addr, duint size);
SCRIPT_EXPORT bool RemoteFree(duint addr);
SCRIPT_EXPORT unsigned char ReadByte(duint addr);
SCRIPT_EXPORT bool WriteByte(duint addr, unsigned char data);

View File

@ -0,0 +1,33 @@
#include "_scriptapi_misc.h"
#include "value.h"
SCRIPT_EXPORT bool Script::Misc::ParseExpression(const char* expression, duint* value)
{
return valfromstring(expression, value);
}
SCRIPT_EXPORT duint Script::Misc::RemoteGetProcAddress(const char* module, const char* api)
{
duint value;
if(!ParseExpression(StringUtils::sprintf("%s:%s", module, api).c_str(), &value))
return 0;
return value;
}
SCRIPT_EXPORT duint Script::Misc::ResolveLabel(const char* label)
{
duint value;
if(!ParseExpression(label, &value))
return 0;
return value;
}
SCRIPT_EXPORT void* Script::Misc::Alloc(duint size)
{
return emalloc(size, "Script::Misc::Alloc");
}
SCRIPT_EXPORT void Script::Misc::Free(void* ptr)
{
return efree(ptr, "Script::Misc::Free");
}

View File

@ -0,0 +1,18 @@
#ifndef _SCRIPTAPI_MISC_H
#define _SCRIPTAPI_MISC_H
#include "_scriptapi.h"
namespace Script
{
namespace Misc
{
SCRIPT_EXPORT bool ParseExpression(const char* expression, duint* value);
SCRIPT_EXPORT duint RemoteGetProcAddress(const char* module, const char* api);
SCRIPT_EXPORT duint ResolveLabel(const char* label);
SCRIPT_EXPORT void* Alloc(duint size);
SCRIPT_EXPORT void Free(void* ptr);
}; //Misc
}; //Script
#endif //_SCRIPTAPI_MISC_H

View File

@ -9,6 +9,7 @@ static const char* regTable[] =
"DR3",
"DR6",
"DR7",
"EAX",
"AX",
"AH",
@ -34,7 +35,7 @@ static const char* regTable[] =
"ESP",
"SP",
"EIP",
"CIP",
#ifdef _WIN64
"RAX",
"RBX",
@ -80,7 +81,15 @@ static const char* regTable[] =
"R15",
"R15D",
"R15W",
"R15"
"R15",
#endif //_WIN64
#ifdef _WIN64
"RIP",
"RSP"
#else //x32
"EIP",
"ESP"
#endif //_WIN64
};
@ -96,6 +105,11 @@ SCRIPT_EXPORT bool Script::Register::Set(Script::Register::RegisterEnum reg, dui
return setregister(regTable[reg], value);
}
SCRIPT_EXPORT int Script::Register::Size()
{
return (int)sizeof(duint);
}
SCRIPT_EXPORT duint Script::Register::GetDR0()
{
return Get(DR0);
@ -406,16 +420,6 @@ SCRIPT_EXPORT bool Script::Register::SetEIP(unsigned int value)
return Set(EIP, value);
}
SCRIPT_EXPORT duint Script::Register::GetCIP()
{
return Get(CIP);
}
SCRIPT_EXPORT bool Script::Register::SetCIP(duint value)
{
return Set(CIP, value);
}
#ifdef _WIN64
SCRIPT_EXPORT unsigned long long Script::Register::GetRAX()
{
@ -867,3 +871,23 @@ SCRIPT_EXPORT bool Script::Register::SetR15B(unsigned char value)
return Set(R15B, value);
}
#endif //_WIN64
SCRIPT_EXPORT duint Script::Register::GetCIP()
{
return Get(CIP);
}
SCRIPT_EXPORT bool Script::Register::SetCIP(duint value)
{
return Set(CIP, value);
}
SCRIPT_EXPORT duint Script::Register::GetCSP()
{
return Get(CSP);
}
SCRIPT_EXPORT bool Script::Register::SetCSP(duint value)
{
return Set(CSP, value);
}

View File

@ -15,6 +15,7 @@ enum RegisterEnum
DR3,
DR6,
DR7,
EAX,
AX,
AH,
@ -40,7 +41,7 @@ enum RegisterEnum
ESP,
SP,
EIP,
CIP,
#ifdef _WIN64
RAX,
RBX,
@ -86,12 +87,16 @@ enum RegisterEnum
R15,
R15D,
R15W,
R15B
R15B,
#endif //_WIN64
CIP,
CSP,
}; //RegisterEnum
SCRIPT_EXPORT duint Get(RegisterEnum reg);
SCRIPT_EXPORT bool Set(RegisterEnum reg, duint value);
SCRIPT_EXPORT int Size(); //gets architecture register size in bytes
SCRIPT_EXPORT duint GetDR0();
SCRIPT_EXPORT bool SetDR0(duint value);
@ -105,6 +110,7 @@ SCRIPT_EXPORT duint GetDR6();
SCRIPT_EXPORT bool SetDR6(duint value);
SCRIPT_EXPORT duint GetDR7();
SCRIPT_EXPORT bool SetDR7(duint value);
SCRIPT_EXPORT unsigned int GetEAX();
SCRIPT_EXPORT bool SetEAX(unsigned int value);
SCRIPT_EXPORT unsigned short GetAX();
@ -155,8 +161,7 @@ SCRIPT_EXPORT unsigned short GetSP();
SCRIPT_EXPORT bool SetSP(unsigned short value);
SCRIPT_EXPORT unsigned int GetEIP();
SCRIPT_EXPORT bool SetEIP(unsigned int value);
SCRIPT_EXPORT duint GetCIP();
SCRIPT_EXPORT bool SetCIP(duint value);
#ifdef _WIN64
SCRIPT_EXPORT unsigned long long GetRAX();
SCRIPT_EXPORT bool SetRAX(unsigned long long value);
@ -249,6 +254,11 @@ SCRIPT_EXPORT bool SetR15W(unsigned short value);
SCRIPT_EXPORT unsigned char GetR15B();
SCRIPT_EXPORT bool SetR15B(unsigned char value);
#endif //_WIN64
SCRIPT_EXPORT duint GetCIP();
SCRIPT_EXPORT bool SetCIP(duint value);
SCRIPT_EXPORT duint GetCSP();
SCRIPT_EXPORT bool SetCSP(duint value);
}; //Register
}; //Script

View File

@ -0,0 +1,24 @@
#include "_scriptapi_stack.h"
#include "_scriptapi_memory.h"
#include "_scriptapi_register.h"
SCRIPT_EXPORT duint Script::Stack::Pop()
{
duint csp = Register::GetCSP();
duint top = Memory::ReadPtr(csp);
Register::SetCSP(csp + sizeof(duint));
return top;
}
SCRIPT_EXPORT duint Script::Stack::Push(duint value)
{
duint csp = Register::GetCSP();
Register::SetCSP(csp - sizeof(duint));
Memory::WritePtr(csp, value);
return Memory::ReadPtr(csp);
}
SCRIPT_EXPORT duint Script::Stack::Peek(int offset)
{
return Memory::ReadPtr(Register::GetCSP() + offset * sizeof(duint));
}

View File

@ -0,0 +1,16 @@
#ifndef _SCRIPTAPI_STACK_H
#define _SCRIPTAPI_STACK_H
#include "_scriptapi.h"
namespace Script
{
namespace Stack
{
SCRIPT_EXPORT duint Pop();
SCRIPT_EXPORT duint Push(duint value); //returns the previous top, equal to Peek(1)
SCRIPT_EXPORT duint Peek(int offset = 0); //offset is in multiples of Register::Size(), for easy x32/x64 portability
}; //Stack
}; //Script
#endif //_SCRIPTAPI_STACK_H

25
x64_dbg_dbg/analysis.cpp Normal file
View File

@ -0,0 +1,25 @@
#include "analysis.h"
#include "memory.h"
Analysis::Analysis(uint base, uint size)
{
_base = base;
_size = size;
_data = new unsigned char[_size + MAX_DISASM_BUFFER];
MemRead((void*)_base, _data, _size, 0);
}
Analysis::~Analysis()
{
delete[] _data;
}
bool Analysis::IsValidAddress(uint addr)
{
return addr >= _base && addr < _base + _size;
}
const unsigned char* Analysis::TranslateAddress(uint addr)
{
return IsValidAddress(addr) ? _data + (addr - _base) : nullptr;
}

26
x64_dbg_dbg/analysis.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef _ANALYSIS_H
#define _ANALYSIS_H
#include "_global.h"
#include "capstone_wrapper.h"
class Analysis
{
public:
explicit Analysis(uint base, uint size);
Analysis(const Analysis & that) = delete;
~Analysis();
virtual void Analyse() = 0;
virtual void SetMarkers() = 0;
protected:
uint _base;
uint _size;
unsigned char* _data;
Capstone _cp;
bool IsValidAddress(uint addr);
const unsigned char* TranslateAddress(uint addr);
};
#endif //_ANALYSIS_H

View File

@ -86,7 +86,7 @@ String Capstone::OperandText(int opindex)
case X86_OP_IMM:
{
if(InGroup(CS_GRP_JUMP) || InGroup(CS_GRP_CALL))
if(InGroup(CS_GRP_JUMP) || InGroup(CS_GRP_CALL) || IsLoop())
sprintf_s(temp, "%"fext"X", op.imm + mInstr->size);
else
sprintf_s(temp, "%"fext"X", op.imm);
@ -163,8 +163,27 @@ const cs_x86 & Capstone::x86()
bool Capstone::IsFilling()
{
uint8_t opcode = x86().opcode[0];
return opcode == 0x90 || opcode == 0xCC;
switch(GetId())
{
case X86_INS_NOP:
case X86_INS_INT3:
return true;
default:
return false;
}
}
bool Capstone::IsLoop()
{
switch(GetId())
{
case X86_INS_LOOP:
case X86_INS_LOOPE:
case X86_INS_LOOPNE:
return true;
default:
return false;
}
}
x86_insn Capstone::GetId()

View File

@ -24,6 +24,7 @@ public:
const uint Address();
const cs_x86 & x86();
bool IsFilling();
bool IsLoop();
x86_insn GetId();
String InstructionText();

View File

@ -0,0 +1,168 @@
#include "controlflowanalysis.h"
#include "memory.h"
#include "console.h"
ControlFlowAnalysis::ControlFlowAnalysis(uint base, uint size) : Analysis(base, size)
{
}
void ControlFlowAnalysis::Analyse()
{
dputs("Starting analysis...");
DWORD ticks = GetTickCount();
BasicBlockStarts();
BasicBlocks();
dprintf("Analysis finished in %ums!\n", GetTickCount() - ticks);
}
void ControlFlowAnalysis::SetMarkers()
{
dprintf("digraph ControlFlow {\n");
int i = 0;
std::map<uint, int> nodeMap;
for(auto block : _blocks)
{
nodeMap.insert({ block.start, i });
dprintf(" node%u [label=\"start=%p, end=%p\"];\n", i, block.start, block.end);
i++;
}
for(auto block : _blocks)
{
int startNode = nodeMap[block.start];
if(block.left)
{
if(nodeMap.count(block.left))
dprintf(" node%u -> node%u;\n", startNode, nodeMap[block.left]);
}
else
{
dprintf(" node%u [shape=point];\n", i);
dprintf(" node%u -> node%u;\n", startNode, i);
i++;
}
if(block.right)
{
if(nodeMap.count(block.right))
dprintf(" node%u -> node%u;\n", startNode, nodeMap[block.right]);
}
else
{
dprintf(" node%u [shape=point];\n", i);
dprintf(" node%u -> node%u;\n", startNode, i);
i++;
}
}
dprintf("}\n");
}
void ControlFlowAnalysis::BasicBlockStarts()
{
_blockStarts.insert(_base);
bool bSkipFilling = false;
for(uint i = 0; i < _size;)
{
uint addr = _base + i;
if(_cp.Disassemble(addr, TranslateAddress(addr), MAX_DISASM_BUFFER))
{
if(bSkipFilling) //handle filling skip mode
{
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
{
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
{
uint dest1 = GetBranchOperand();
uint dest2 = 0;
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)
bSkipFilling = true;
if(dest1)
_blockStarts.insert(dest1);
if(dest2)
_blockStarts.insert(dest2);
}
else if(_cp.InGroup(CS_GRP_CALL))
{
uint dest1 = GetBranchOperand();
if(dest1)
_blockStarts.insert(dest1);
}
else
{
uint dest1 = GetBranchOperand();
if(dest1)
_blockStarts.insert(dest1);
}
i += _cp.Size();
}
else
i++;
}
}
void ControlFlowAnalysis::BasicBlocks()
{
for(auto i = _blockStarts.begin(); i != _blockStarts.end(); i++)
{
uint start = *i;
if(!IsValidAddress(start))
continue;
uint nextStart = _base + _size;
auto next = std::next(i);
if(next != _blockStarts.end())
nextStart = *next;
for(uint addr = start, prevaddr = 0; addr < _base + _size;)
{
prevaddr = addr;
if(_cp.Disassemble(addr, TranslateAddress(addr), MAX_DISASM_BUFFER))
{
if(_cp.InGroup(CS_GRP_RET))
{
_blocks.push_back(BasicBlock(start, addr, 0, 0)); //leaf block
break;
}
else if(_cp.InGroup(CS_GRP_JUMP) || _cp.IsLoop())
{
uint dest1 = GetBranchOperand();
uint dest2 = _cp.GetId() != X86_INS_JMP ? addr + _cp.Size() : 0;
_blocks.push_back(BasicBlock(start, addr, dest1, dest2));
break;
}
addr += _cp.Size();
}
else
addr++;
if(addr == nextStart) //special case handling overlapping blocks
{
_blocks.push_back(BasicBlock(start, prevaddr, 0, nextStart));
break;
}
}
}
}
uint ControlFlowAnalysis::GetBranchOperand()
{
for(int i = 0; i < _cp.x86().op_count; i++)
{
const cs_x86_op & operand = _cp.x86().operands[i];
if(operand.type == X86_OP_IMM)
{
uint dest = (uint)operand.imm;
if(dest >= _base && dest < _base + _size)
return dest;
}
}
return 0;
}

View File

@ -0,0 +1,48 @@
#ifndef _CONTROLFLOWANALYSIS_H
#define _CONTROLFLOWANALYSIS_H
#include "_global.h"
#include "capstone_wrapper.h"
#include "analysis.h"
class ControlFlowAnalysis : public Analysis
{
public:
explicit ControlFlowAnalysis(uint base, uint size);
void Analyse();
void SetMarkers();
private:
struct BasicBlock
{
uint start;
uint end;
uint left;
uint right;
BasicBlock()
{
this->start = 0;
this->end = 0;
this->left = 0;
this->right = 0;
}
BasicBlock(uint start, uint end, uint left, uint right)
{
this->start = start;
this->end = end;
this->left = min(left, right);
this->right = max(left, right);
}
};
std::set<uint> _blockStarts;
std::vector<BasicBlock> _blocks;
void BasicBlockStarts();
void BasicBlocks();
uint GetBranchOperand();
};
#endif //_CONTROLFLOWANALYSIS_H

View File

@ -776,14 +776,16 @@ static void cbExitThread(EXIT_THREAD_DEBUG_INFO* ExitThread)
static void cbSystemBreakpoint(void* ExceptionData)
{
hActiveThread = ThreadGetHandle(((DEBUG_EVENT*)GetDebugData())->dwThreadId);
uint cip = GetContextDataEx(hActiveThread, UE_CIP);
GuiDumpAt(MemFindBaseAddr(cip, 0, true)); //dump somewhere
//log message
if(bIsAttached)
dputs("Attach breakpoint reached!");
else
dputs("System breakpoint reached!");
bSkipExceptions = false; //we are not skipping first-chance exceptions
uint cip = GetContextDataEx(hActiveThread, UE_CIP);
GuiDumpAt(MemFindBaseAddr(cip, 0, true)); //dump somewhere
//plugin callbacks
PLUG_CB_SYSTEMBREAKPOINT callbackInfo;

View File

@ -38,7 +38,7 @@ void fillbasicinfo(Capstone* cp, BASIC_INSTRUCTION_INFO* basicinfo)
basicinfo->branch = true;
basicinfo->call = true;
}
else if(cp->InGroup(CS_GRP_JUMP))
else if(cp->InGroup(CS_GRP_JUMP) || cp->IsLoop())
{
basicinfo->branch = true;
}

View File

@ -204,7 +204,7 @@ void disasmget(unsigned char* buffer, uint addr, DISASM_INSTR* instr)
sprintf_s(instr->instruction, "%s %s", cp.GetInstr()->mnemonic, cp.GetInstr()->op_str);
const cs_x86 & x86 = cp.GetInstr()->detail->x86;
instr->instr_size = cp.GetInstr()->size;
if(cp.InGroup(CS_GRP_JUMP) || cp.InGroup(CS_GRP_RET) || cp.InGroup(CS_GRP_CALL))
if(cp.InGroup(CS_GRP_JUMP) || cp.IsLoop() || cp.InGroup(CS_GRP_RET) || cp.InGroup(CS_GRP_CALL))
instr->type = instr_branch;
else if(strstr(cp.GetInstr()->op_str, "sp") || strstr(cp.GetInstr()->op_str, "bp"))
instr->type = instr_stack;

View File

@ -3,31 +3,20 @@
#include "memory.h"
#include "function.h"
#include "module.h"
#include "LinearPass.h"
FunctionAnalysis::FunctionAnalysis(uint base, uint size)
FunctionAnalysis::FunctionAnalysis(uint base, uint size) : Analysis(base, size)
{
_base = base;
_size = size;
_data = new unsigned char[_size + MAX_DISASM_BUFFER];
MemRead((void*)_base, _data, _size, 0);
}
FunctionAnalysis::~FunctionAnalysis()
{
delete[] _data;
}
const unsigned char* FunctionAnalysis::TranslateAddress(uint addr)
{
return (addr >= _base && addr < _base + _size) ? _data + (addr - _base) : nullptr;
}
void Derp(uint _base);
void FunctionAnalysis::Analyse()
{
Derp(_base);
dputs("Starting analysis...");
DWORD ticks = GetTickCount();
PopulateReferences();
dprintf("%u called functions populated\n", _functions.size());
AnalyseFunctions();
dprintf("Analysis finished in %ums!\n", GetTickCount() - ticks);
}
void FunctionAnalysis::SetMarkers()
@ -109,7 +98,7 @@ uint FunctionAnalysis::FindFunctionEnd(uint start, uint maxaddr)
break;
const cs_x86_op & operand = _cp.x86().operands[0];
if(_cp.InGroup(CS_GRP_JUMP) && operand.type == X86_OP_IMM) //jump
if((_cp.InGroup(CS_GRP_JUMP) || _cp.IsLoop()) && operand.type == X86_OP_IMM) //jump
{
uint dest = (uint)operand.imm;
@ -121,7 +110,7 @@ uint FunctionAnalysis::FindFunctionEnd(uint start, uint maxaddr)
{
fardest = dest;
}
else if(end && dest < end && _cp.GetId() == X86_INS_JMP) //save the last JMP backwards
else if(end && dest < end && (_cp.GetId() == X86_INS_JMP || _cp.GetId() == X86_INS_LOOP)) //save the last JMP backwards
{
jumpback = addr;
}
@ -146,7 +135,7 @@ uint FunctionAnalysis::GetReferenceOperand()
for(int i = 0; i < _cp.x86().op_count; i++)
{
const cs_x86_op & operand = _cp.x86().operands[i];
if(_cp.InGroup(CS_GRP_JUMP)) //skip jumps
if(_cp.InGroup(CS_GRP_JUMP) || _cp.IsLoop()) //skip jumps/loops
continue;
if(operand.type == X86_OP_IMM) //we are looking for immediate references
{

View File

@ -3,17 +3,16 @@
#include "_global.h"
#include "capstone_wrapper.h"
#include "analysis.h"
class FunctionAnalysis
class FunctionAnalysis : public Analysis
{
public:
explicit FunctionAnalysis(uint base, uint size);
FunctionAnalysis(const FunctionAnalysis & that) = delete;
~FunctionAnalysis();
const unsigned char* TranslateAddress(uint addr);
void Analyse();
void SetMarkers();
private:
struct FunctionInfo
{
uint start;
@ -30,12 +29,7 @@ public:
}
};
private:
uint _base;
uint _size;
unsigned char* _data;
std::vector<FunctionInfo> _functions;
Capstone _cp;
void SortCleanup();
void PopulateReferences();

View File

@ -26,6 +26,8 @@
#include "module.h"
#include "stringformat.h"
#include "filereader.h"
#include "functionanalysis.h"
#include "controlflowanalysis.h"
static bool bRefinit = false;
@ -1877,8 +1879,6 @@ CMDRESULT cbInstrCapstone(int argc, char* argv[])
return STATUS_CONTINUE;
}
#include "functionanalysis.h"
CMDRESULT cbInstrAnalyse(int argc, char* argv[])
{
SELECTIONDATA sel;
@ -1892,6 +1892,19 @@ CMDRESULT cbInstrAnalyse(int argc, char* argv[])
return STATUS_CONTINUE;
}
CMDRESULT cbInstrCfanalyse(int argc, char* argv[])
{
SELECTIONDATA sel;
GuiSelectionGet(GUI_DISASSEMBLY, &sel);
uint size = 0;
uint base = MemFindBaseAddr(sel.start, &size);
ControlFlowAnalysis anal(base, size);
anal.Analyse();
anal.SetMarkers();
GuiUpdateAllViews();
return STATUS_CONTINUE;
}
CMDRESULT cbInstrVisualize(int argc, char* argv[])
{
if(argc < 3)
@ -1950,7 +1963,7 @@ CMDRESULT cbInstrVisualize(int argc, char* argv[])
break;
const cs_x86_op & operand = _cp.x86().operands[0];
if(_cp.InGroup(CS_GRP_JUMP) && operand.type == X86_OP_IMM) //jump
if((_cp.InGroup(CS_GRP_JUMP) || _cp.IsLoop()) && operand.type == X86_OP_IMM) //jump
{
uint dest = (uint)operand.imm;

View File

@ -70,5 +70,6 @@ CMDRESULT cbInstrCapstone(int argc, char* argv[]);
CMDRESULT cbInstrAnalyse(int argc, char* argv[]);
CMDRESULT cbInstrVisualize(int argc, char* argv[]);
CMDRESULT cbInstrMeminfo(int argc, char* argv[]);
CMDRESULT cbInstrCfanalyse(int argc, char* argv[]);
#endif // _INSTRUCTIONS_H

View File

@ -312,7 +312,7 @@ void* MemAllocRemote(uint Address, SIZE_T Size, DWORD Protect)
return VirtualAllocEx(fdProcessInfo->hProcess, (void*)Address, Size, MEM_RESERVE | MEM_COMMIT, Protect);
}
void MemFreeRemote(uint Address)
bool MemFreeRemote(uint Address)
{
VirtualFreeEx(fdProcessInfo->hProcess, (void*)Address, 0, MEM_RELEASE);
return !!VirtualFreeEx(fdProcessInfo->hProcess, (void*)Address, 0, MEM_RELEASE);
}

View File

@ -14,4 +14,4 @@ bool MemPatch(void* BaseAddress, void* Buffer, SIZE_T Size, SIZE_T* NumberOfByte
bool MemIsValidReadPtr(uint Address);
bool MemIsCanonicalAddress(uint Address);
void* MemAllocRemote(uint Address, SIZE_T Size, DWORD Protect);
void MemFreeRemote(uint Address);
bool MemFreeRemote(uint Address);

View File

@ -203,6 +203,7 @@ static void registercommands()
dbgcmdnew("capstone", cbInstrCapstone, true); //disassemble using capstone
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
}
static bool cbCommandProvider(char* cmd, int maxlen)

View File

@ -32,6 +32,7 @@
<ClCompile Include="commandparser.cpp" />
<ClCompile Include="comment.cpp" />
<ClCompile Include="console.cpp" />
<ClCompile Include="controlflowanalysis.cpp" />
<ClCompile Include="dbghelp_safe.cpp" />
<ClCompile Include="debugger.cpp" />
<ClCompile Include="debugger_commands.cpp" />
@ -72,12 +73,15 @@
<ClCompile Include="_dbgfunctions.cpp" />
<ClCompile Include="_global.cpp" />
<ClCompile Include="_plugins.cpp" />
<ClCompile Include="_scriptapi_assembler.cpp" />
<ClCompile Include="_scriptapi_debug.cpp" />
<ClCompile Include="_scriptapi_gui.cpp" />
<ClCompile Include="_scriptapi_misc.cpp" />
<ClCompile Include="_scriptapi_pattern.cpp" />
<ClCompile Include="_scriptapi_memory.cpp" />
<ClCompile Include="_scriptapi_module.cpp" />
<ClCompile Include="_scriptapi_register.cpp" />
<ClCompile Include="_scriptapi_stack.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="addrinfo.h" />
@ -103,6 +107,7 @@
<ClInclude Include="commandparser.h" />
<ClInclude Include="comment.h" />
<ClInclude Include="console.h" />
<ClInclude Include="controlflowanalysis.h" />
<ClInclude Include="dbghelp\dbghelp.h" />
<ClInclude Include="dbghelp_safe.h" />
<ClInclude Include="debugger.h" />
@ -187,12 +192,15 @@
<ClInclude Include="_global.h" />
<ClInclude Include="_plugins.h" />
<ClInclude Include="_plugin_types.h" />
<ClInclude Include="_scriptapi_assembler.h" />
<ClInclude Include="_scriptapi_debug.h" />
<ClInclude Include="_scriptapi_gui.h" />
<ClInclude Include="_scriptapi_misc.h" />
<ClInclude Include="_scriptapi_pattern.h" />
<ClInclude Include="_scriptapi_memory.h" />
<ClInclude Include="_scriptapi_module.h" />
<ClInclude Include="_scriptapi_register.h" />
<ClInclude Include="_scriptapi_stack.h" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{E6548308-401E-3A8A-5819-905DB90522A6}</ProjectGuid>

View File

@ -123,7 +123,7 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;X64_DBG_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
@ -160,7 +160,7 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;X64_DBG_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>

View File

@ -410,6 +410,27 @@ void Bridge::emitShowCpu()
emit showCpu();
}
void Bridge::emitAddQWidgetTab(QWidget* qWidget)
{
emit addQWidgetTab(qWidget);
}
void Bridge::emitShowQWidgetTab(QWidget* qWidget)
{
emit showQWidgetTab(qWidget);
}
void Bridge::emitCloseQWidgetTab(QWidget* qWidget)
{
emit closeQWidgetTab(qWidget);
}
void Bridge::emitExecuteOnGuiThread(void* cbGuiThread)
{
GuiAddLogMessage(QString().sprintf("thread id (bridge) %X\n", GetCurrentThreadId()).toUtf8().constData());
emit executeOnGuiThread(cbGuiThread);
}
/************************************************************************************
Static Functions
************************************************************************************/
@ -824,6 +845,30 @@ __declspec(dllexport) void* _gui_sendmessage(GUIMSG type, void* param1, void* pa
}
break;
case GUI_ADD_QWIDGET_TAB:
{
Bridge::getBridge()->emitAddQWidgetTab((QWidget*)param1);
}
break;
case GUI_SHOW_QWIDGET_TAB:
{
Bridge::getBridge()->emitShowQWidgetTab((QWidget*)param1);
}
break;
case GUI_CLOSE_QWIDGET_TAB:
{
Bridge::getBridge()->emitCloseQWidgetTab((QWidget*)param1);
}
break;
case GUI_EXECUTE_ON_GUI_THREAD:
{
Bridge::getBridge()->emitExecuteOnGuiThread(param1);
}
break;
default:
{

View File

@ -3,6 +3,7 @@
#include <agents.h>
#include <QObject>
#include <QWidget>
#include <QMutex>
#include "Imports.h"
#include "NewTypes.h"
@ -87,6 +88,10 @@ public:
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);
//Public variables
void* winId;
@ -156,6 +161,10 @@ signals:
void setIconMenuEntry(int hEntry, QIcon icon);
void setIconMenu(int hMenu, QIcon icon);
void showCpu();
void addQWidgetTab(QWidget* qWidget);
void showQWidgetTab(QWidget* qWidget);
void closeQWidgetTab(QWidget* qWidget);
void executeOnGuiThread(void* cbGuiThread);
private:
QMutex* mBridgeMutex;

View File

@ -31,6 +31,10 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWi
connect(Bridge::getBridge(), SIGNAL(setIconMenu(int, QIcon)), this, SLOT(setIconMenu(int, QIcon)));
connect(Bridge::getBridge(), SIGNAL(setIconMenuEntry(int, QIcon)), this, SLOT(setIconMenuEntry(int, QIcon)));
connect(Bridge::getBridge(), SIGNAL(showCpu()), this, SLOT(displayCpuWidget()));
connect(Bridge::getBridge(), SIGNAL(addQWidgetTab(QWidget*)), this, SLOT(addQWidgetTab(QWidget*)));
connect(Bridge::getBridge(), SIGNAL(showQWidgetTab(QWidget*)), this, SLOT(showQWidgetTab(QWidget*)));
connect(Bridge::getBridge(), SIGNAL(closeQWidgetTab(QWidget*)), this, SLOT(closeQWidgetTab(QWidget*)));
connect(Bridge::getBridge(), SIGNAL(executeOnGuiThread(void*)), this, SLOT(executeOnGuiThread(void*)));
//setup menu api
initMenuApi();
@ -130,17 +134,17 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWi
mTabWidget = new MHTabWidget(NULL);
//Setup tabs
mTabWidget->addTab(mCpuWidget, mCpuWidget->windowIcon(), mCpuWidget->windowTitle());
mTabWidget->addTab(mLogView, mLogView->windowIcon(), mLogView->windowTitle());
mTabWidget->addTab(mBreakpointsView, mBreakpointsView->windowIcon(), mBreakpointsView->windowTitle());
mTabWidget->addTab(mMemMapView, mMemMapView->windowIcon(), mMemMapView->windowTitle());
mTabWidget->addTab(mCallStackView, mCallStackView->windowIcon(), mCallStackView->windowTitle());
mTabWidget->addTab(mScriptView, mScriptView->windowIcon(), mScriptView->windowTitle());
mTabWidget->addTab(mSymbolView, mSymbolView->windowIcon(), mSymbolView->windowTitle());
mTabWidget->addTab(mSourceViewManager, mSourceViewManager->windowIcon(), mSourceViewManager->windowTitle());
mTabWidget->addTab(mReferenceManager, mReferenceManager->windowIcon(), mReferenceManager->windowTitle());
mTabWidget->addTab(mThreadView, mThreadView->windowIcon(), mThreadView->windowTitle());
mTabWidget->addTab(mSnowmanView, mSnowmanView->windowIcon(), mSnowmanView->windowTitle());
addQWidgetTab(mCpuWidget);
addQWidgetTab(mLogView);
addQWidgetTab(mBreakpointsView);
addQWidgetTab(mMemMapView);
addQWidgetTab(mCallStackView);
addQWidgetTab(mScriptView);
addQWidgetTab(mSymbolView);
addQWidgetTab(mSourceViewManager);
addQWidgetTab(mReferenceManager);
addQWidgetTab(mThreadView);
addQWidgetTab(mSnowmanView);
setCentralWidget(mTabWidget);
@ -237,6 +241,8 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWi
mCloseDialog = new CloseDialog(this);
mCpuWidget->mDisas->setFocus();
GuiAddLogMessage(QString().sprintf("thread id (GUI thread) %X\n", GetCurrentThreadId()).toUtf8().constData());
}
void MainWindow::closeEvent(QCloseEvent* event)
@ -343,7 +349,7 @@ void MainWindow::loadMRUList(int maxItems)
mMaxMRU = maxItems;
for(int i = 0; i < mMaxMRU; i++)
{
char currentFile[MAX_PATH] = "";
char currentFile[MAX_SETTING_SIZE] = "";
if(!BridgeSettingGet("Recent Files", QString().sprintf("%.2d", i + 1).toUtf8().constData(), currentFile))
break;
if(QString(currentFile).size() && QFile(currentFile).exists())
@ -488,23 +494,17 @@ void MainWindow::execRtr()
void MainWindow::displayMemMapWidget()
{
mMemMapView->show();
mMemMapView->setFocus();
setTab(mMemMapView);
showQWidgetTab(mMemMapView);
}
void MainWindow::displayLogWidget()
{
mLogView->show();
mLogView->setFocus();
setTab(mLogView);
showQWidgetTab(mLogView);
}
void MainWindow::displayScriptWidget()
{
mScriptView->show();
mScriptView->setFocus();
setTab(mScriptView);
showQWidgetTab(mScriptView);
}
void MainWindow::displayAboutWidget()
@ -607,9 +607,7 @@ void MainWindow::restartDebugging()
void MainWindow::displayBreakpointWidget()
{
mBreakpointsView->show();
mBreakpointsView->setFocus();
setTab(mBreakpointsView);
showQWidgetTab(mBreakpointsView);
}
void MainWindow::dragEnterEvent(QDragEnterEvent* pEvent)
@ -667,44 +665,32 @@ void MainWindow::execSkip()
void MainWindow::displayCpuWidget()
{
mCpuWidget->show();
mCpuWidget->setFocus();
setTab(mCpuWidget);
showQWidgetTab(mCpuWidget);
}
void MainWindow::displaySymbolWidget()
{
mSymbolView->show();
mSymbolView->setFocus();
setTab(mSymbolView);
showQWidgetTab(mSymbolView);
}
void MainWindow::displaySourceViewWidget()
{
mSourceViewManager->show();
mSourceViewManager->setFocus();
setTab(mSourceViewManager);
showQWidgetTab(mSourceViewManager);
}
void MainWindow::displayReferencesWidget()
{
mReferenceManager->show();
mReferenceManager->setFocus();
setTab(mReferenceManager);
showQWidgetTab(mReferenceManager);
}
void MainWindow::displayThreadsWidget()
{
mThreadView->show();
mThreadView->setFocus();
setTab(mThreadView);
showQWidgetTab(mThreadView);
}
void MainWindow::displaySnowmanWidget()
{
mSnowmanView->show();
mSnowmanView->setFocus();
setTab(mSnowmanView);
showQWidgetTab(mSnowmanView);
}
void MainWindow::openSettings()
@ -1025,9 +1011,7 @@ void MainWindow::checkUpdates()
void MainWindow::displayCallstack()
{
mCallStackView->show();
mCallStackView->setFocus();
setTab(mCallStackView);
showQWidgetTab(mCallStackView);
}
void MainWindow::donate()
@ -1122,3 +1106,30 @@ void MainWindow::canClose()
bCanClose = true;
close();
}
void MainWindow::addQWidgetTab(QWidget* qWidget)
{
mTabWidget->addTab(qWidget, qWidget->windowIcon(), qWidget->windowTitle());
}
void MainWindow::showQWidgetTab(QWidget* qWidget)
{
qWidget->show();
qWidget->setFocus();
setTab(qWidget);
}
void MainWindow::closeQWidgetTab(QWidget* qWidget)
{
for(int i = 0; i < mTabWidget->count(); i++)
if(mTabWidget->widget(i) == qWidget)
{
mTabWidget->DeleteTab(i);
break;
}
}
void MainWindow::executeOnGuiThread(void* cbGuiThread)
{
((GUICALLBACK)cbGuiThread)();
}

View File

@ -104,6 +104,10 @@ public slots:
void changeCommandLine();
void decompileAt(int_t start, int_t end);
void canClose();
void addQWidgetTab(QWidget* qWidget);
void showQWidgetTab(QWidget* qWidget);
void closeQWidgetTab(QWidget* qWidget);
void executeOnGuiThread(void* cbGuiThread);
private:
Ui::MainWindow* ui;

View File

@ -579,7 +579,7 @@ void ScriptView::cmdExec()
void ScriptView::message(QString message)
{
QMessageBox msg(QMessageBox::Information, "Information", message);
QMessageBox msg(QMessageBox::Information, "Message", message);
msg.setWindowIcon(QIcon(":/icons/images/information.png"));
msg.setParent(this, Qt::Dialog);
msg.setWindowFlags(msg.windowFlags() & (~Qt::WindowContextHelpButtonHint));

View File

@ -80,7 +80,7 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;X64_DBG_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>