1
0
Fork 0

Merge pull request #453 from Herz3h/Herz3hDev

I didn't check all the code, but I trust you to fix the potential issues you created 😄
This commit is contained in:
Duncan Ogilvie 2015-12-16 11:49:09 +01:00
commit 37b5ea5f2e
63 changed files with 2073 additions and 243 deletions

View File

@ -575,6 +575,16 @@ BRIDGE_IMPEXP void DbgSymbolEnum(duint base, CBSYMBOLENUM cbSymbolEnum, void* us
_dbg_sendmessage(DBG_SYMBOL_ENUM, &cbInfo, 0);
}
// FIXME all
BRIDGE_IMPEXP void DbgSymbolEnumFromCache(duint base, CBSYMBOLENUM cbSymbolEnum, void* user)
{
SYMBOLCBINFO cbInfo;
cbInfo.base = base;
cbInfo.cbSymbolEnum = cbSymbolEnum;
cbInfo.user = user;
_dbg_sendmessage(DBG_SYMBOL_ENUM_FROMCACHE, &cbInfo, 0);
}
BRIDGE_IMPEXP bool DbgAssembleAt(duint addr, const char* instruction)
{
if(_dbg_sendmessage(DBG_ASSEMBLE_AT, (void*)addr, (void*)instruction))
@ -1028,6 +1038,10 @@ BRIDGE_IMPEXP void GuiReferenceSetProgress(int progress)
_gui_sendmessage(GUI_REF_SETPROGRESS, (void*)(duint)progress, 0);
}
BRIDGE_IMPEXP void GuiReferenceSetCurrentTaskProgress(int progress, const char* taskTitle)
{
_gui_sendmessage(GUI_REF_SETCURRENTTASKPROGRESS, (void*)(duint)progress, (void*)taskTitle);
}
BRIDGE_IMPEXP void GuiReferenceSetSearchStartCol(int col)
{
@ -1236,6 +1250,11 @@ BRIDGE_IMPEXP void GuiDumpAtN(duint va, int index)
_gui_sendmessage(GUI_DUMP_AT_N, (void*)va, (void*)index);
}
BRIDGE_IMPEXP void GuiDisplayWarning(const char *title, const char *text)
{
_gui_sendmessage(GUI_DISPLAY_WARNING, (void*)title, (void*)text);
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
hInst = hinstDLL;

View File

@ -59,6 +59,7 @@ BRIDGE_IMPEXP int BridgeGetDbgVersion();
#define MAX_LABEL_SIZE 256
#define MAX_COMMENT_SIZE 512
#define MAX_MODULE_SIZE 256
#define MAX_IMPORT_SIZE 256
#define MAX_BREAKPOINT_SIZE 256
#define MAX_SCRIPT_LINE_SIZE 2048
#define MAX_THREAD_NAME_SIZE 256
@ -66,6 +67,7 @@ BRIDGE_IMPEXP int BridgeGetDbgVersion();
#define MAX_ERROR_SIZE 512
#define RIGHTS_STRING_SIZE (sizeof("ERWCG") + 1)
#define MAX_SECTION_SIZE 10
#define MAX_COMMAND_LINE_SIZE 256
#define TYPE_VALUE 1
#define TYPE_MEMORY 2
@ -143,6 +145,7 @@ typedef enum
DBG_SCRIPT_SETIP, // param1=int line, param2=unused
DBG_SCRIPT_GETBRANCHINFO, // param1=int line, param2=SCRIPTBRANCH* info
DBG_SYMBOL_ENUM, // param1=SYMBOLCBINFO* cbInfo, param2=unused
DBG_SYMBOL_ENUM_FROMCACHE, // param1=SYMBOLCBINFO* cbInfo, param2=unused
DBG_ASSEMBLE_AT, // param1=duint addr, param2=const char* instruction
DBG_MODBASE_FROM_NAME, // param1=const char* modname, param2=unused
DBG_DISASM_AT, // param1=duint addr, param2=DISASM_INSTR* instr
@ -349,6 +352,7 @@ struct SYMBOLINFO_
duint addr;
char* decoratedSymbol;
char* undecoratedSymbol;
bool isImported;
};
typedef struct
@ -662,6 +666,7 @@ BRIDGE_IMPEXP SCRIPTLINETYPE DbgScriptGetLineType(int line);
BRIDGE_IMPEXP void DbgScriptSetIp(int line);
BRIDGE_IMPEXP bool DbgScriptGetBranchInfo(int line, SCRIPTBRANCH* info);
BRIDGE_IMPEXP void DbgSymbolEnum(duint base, CBSYMBOLENUM cbSymbolEnum, void* user);
BRIDGE_IMPEXP void DbgSymbolEnumFromCache(duint base, CBSYMBOLENUM cbSymbolEnum, void* user);
BRIDGE_IMPEXP bool DbgAssembleAt(duint addr, const char* instruction);
BRIDGE_IMPEXP duint DbgModBaseFromName(const char* name);
BRIDGE_IMPEXP void DbgDisasmAt(duint addr, DISASM_INSTR* instr);
@ -741,7 +746,8 @@ typedef enum
GUI_REF_GETCELLCONTENT, // param1=int row, param2=int col
GUI_REF_RELOADDATA, // param1=unused, param2=unused
GUI_REF_SETSINGLESELECTION, // param1=int index, param2=bool scroll
GUI_REF_SETPROGRESS, // param1=int progress, param2=unused
GUI_REF_SETPROGRESS, // param1=int progress, param2=unused
GUI_REF_SETCURRENTTASKPROGRESS, // param1=int progress, param2=const char* taskTitle
GUI_REF_SETSEARCHSTARTCOL, // param1=int col param2=unused
GUI_STACK_DUMP_AT, // param1=duint addr, param2=duint csp
GUI_UPDATE_DUMP_VIEW, // param1=unused, param2=unused
@ -758,7 +764,7 @@ typedef enum
GUI_GETLINE_WINDOW, // param1=const char* title, param2=char* text
GUI_AUTOCOMPLETE_ADDCMD, // param1=const char* cmd, param2=ununsed
GUI_AUTOCOMPLETE_DELCMD, // param1=const char* cmd, param2=ununsed
GUI_AUTOCOMPLETE_CLEARALL, // param1=unused, param2=unused
GUI_AUTOCOMPLETE_CLEARALL, // param1=unused, param2=unused
GUI_SCRIPT_ENABLEHIGHLIGHTING, // param1=bool enable, param2=unused
GUI_ADD_MSG_TO_STATUSBAR, // param1=const char* msg, param2=unused
GUI_UPDATE_SIDEBAR, // param1=unused, param2=unused
@ -782,6 +788,7 @@ typedef enum
GUI_SET_DEBUGGEE_NOTES, // param1=const char* text, param2=unused
GUI_GET_DEBUGGEE_NOTES, // param1=char** text, param2=unused
GUI_DUMP_AT_N, // param1=int index, param2=duint va
GUI_DISPLAY_WARNING // param1=const char *text, param2=unused
} GUIMSG;
//GUI Typedefs
@ -843,6 +850,7 @@ BRIDGE_IMPEXP const char* GuiReferenceGetCellContent(int row, int col);
BRIDGE_IMPEXP void GuiReferenceReloadData();
BRIDGE_IMPEXP void GuiReferenceSetSingleSelection(int index, bool scroll);
BRIDGE_IMPEXP void GuiReferenceSetProgress(int progress);
BRIDGE_IMPEXP void GuiReferenceSetCurrentTaskProgress(int progress, const char* taskTitle);
BRIDGE_IMPEXP void GuiReferenceSetSearchStartCol(int col);
BRIDGE_IMPEXP void GuiStackDumpAt(duint addr, duint csp);
BRIDGE_IMPEXP void GuiUpdateDumpView();
@ -880,6 +888,7 @@ BRIDGE_IMPEXP void GuiGetGlobalNotes(char** text);
BRIDGE_IMPEXP void GuiSetDebuggeeNotes(const char* text);
BRIDGE_IMPEXP void GuiGetDebuggeeNotes(char** text);
BRIDGE_IMPEXP void GuiDumpAtN(duint va, int index);
BRIDGE_IMPEXP void GuiDisplayWarning(const char *title, const char *text);
#ifdef __cplusplus
}

View File

@ -766,6 +766,13 @@ extern "C" DLL_EXPORT duint _dbg_sendmessage(DBGMSG type, void* param1, void* pa
}
break;
case DBG_SYMBOL_ENUM_FROMCACHE:
{
SYMBOLCBINFO* cbInfo = (SYMBOLCBINFO*)param1;
SymEnumFromCache(cbInfo->base, cbInfo->cbSymbolEnum, cbInfo->user);
}
break;
case DBG_ASSEMBLE_AT:
{
return assembleat((duint)param1, (const char*)param2, 0, 0, false);

View File

@ -1,7 +1,7 @@
#ifndef _GLOBAL_H
#define _GLOBAL_H
#define _WIN32_WINNT 0x0501
#define _WIN32_WINNT 0x0601
#define WINVER 0x0501
#define _WIN32_IE 0x0500

View File

@ -87,5 +87,91 @@ bool apienumexports(duint base, EXPORTENUMCALLBACK cbEnum)
cbEnum(base, modname, cur_name, curFunctionRva + base);
}
}
return true;
}
bool apienumimports(duint base, IMPORTENUMCALLBACK cbEnum)
{
// Variables
bool readSuccess;
char importName[MAX_IMPORT_SIZE];
char importModuleName[MAX_MODULE_SIZE];
duint regionSize, importNameLen;
ULONG_PTR importTableRva, importTableSize;
MEMORY_BASIC_INFORMATION mbi;
PIMAGE_IMPORT_DESCRIPTOR importTableVa;
IMAGE_IMPORT_DESCRIPTOR importDescriptor;
PIMAGE_THUNK_DATA imageIATVa, imageINTVa;
IMAGE_THUNK_DATA imageOftThunkData, imageFtThunkData;
PIMAGE_IMPORT_BY_NAME pImageImportByNameVa;
// Get page size
VirtualQueryEx(fdProcessInfo->hProcess, (const void*)base, &mbi, sizeof(mbi));
regionSize = mbi.RegionSize;
Memory<void* > buffer(regionSize, "apienumimports:buffer");
// Read first page into buffer
if (!MemRead(base, buffer(), regionSize))
return false;
// Import Table address and size
importTableRva = GetPE32DataFromMappedFile((duint)buffer(), 0, UE_IMPORTTABLEADDRESS);
importTableSize = GetPE32DataFromMappedFile((duint)buffer(), 0, UE_IMPORTTABLESIZE);
// Return if no imports
if (!importTableSize)
return false;
importTableVa = (PIMAGE_IMPORT_DESCRIPTOR)(base + importTableRva);
readSuccess = MemRead((duint)importTableVa, &importDescriptor, sizeof(importDescriptor));
// Loop through all dlls
while (readSuccess && importDescriptor.FirstThunk)
{
// Copy module name into importModuleName
MemRead((duint)(base + importDescriptor.Name), &importModuleName, MAX_MODULE_SIZE);
imageIATVa = (PIMAGE_THUNK_DATA)(base + importDescriptor.FirstThunk);
imageINTVa = (PIMAGE_THUNK_DATA)(base + importDescriptor.OriginalFirstThunk);
if (!MemRead((duint)imageIATVa, &imageFtThunkData, sizeof(imageFtThunkData)))
return false;
if (!MemRead((duint)imageINTVa, &imageOftThunkData, sizeof(imageOftThunkData)))
return false;
// Loop through all imported function in this dll
while (imageFtThunkData.u1.Function)
{
pImageImportByNameVa = (PIMAGE_IMPORT_BY_NAME)(base + imageOftThunkData.u1.AddressOfData);
// Read every IMPORT_BY_NAME.name
if (!MemRead((duint)pImageImportByNameVa + sizeof(WORD), buffer(), regionSize))
return false;
// Alloc buffer for name and copy name import name to buffer
importNameLen = strlen((char*)buffer());
strcpy_s(importName, MAX_IMPORT_SIZE, (char*)buffer());
// Callback
cbEnum(base, imageFtThunkData.u1.Function, importName, importModuleName);
// Move to next address in the INT
imageINTVa++;
if(!MemRead((duint)imageINTVa, &imageOftThunkData, sizeof(imageOftThunkData)))
return false;
// Move to next address in the IAT and read it into imageFtThunkData
imageIATVa++;
if (!MemRead((duint)imageIATVa, &imageFtThunkData, sizeof(imageFtThunkData)))
return false;
}
importTableVa++;
readSuccess = MemRead((duint)importTableVa, &importDescriptor, sizeof(importDescriptor));
}
return true;
}

View File

@ -55,7 +55,10 @@ struct DepthModuleRangeCompare
//typedefs
typedef std::function<void (duint base, const char* mod, const char* name, duint addr)> EXPORTENUMCALLBACK;
typedef std::function<void (duint base, duint addr, char* name, char* moduleName)> IMPORTENUMCALLBACK;
bool apienumexports(duint base, EXPORTENUMCALLBACK cbEnum);
bool apienumimports(duint base, IMPORTENUMCALLBACK cbEnum);
#endif // _ADDRINFO_H

View File

@ -9,6 +9,7 @@
#include "XEDParse\XEDParse.h"
#include "value.h"
#include "disasm_helper.h"
#include "debugger.h"
static bool cbUnknown(const char* text, ULONGLONG* value)
{
@ -67,6 +68,10 @@ bool assembleat(duint addr, const char* instruction, int* size, char* error, boo
if(size)
*size = destSize;
// Check if the instruction doesn't set IP to non-executable memory
if (isInstructionPointingToExMemory(addr, dest) == NX_MEMORY)
GuiDisplayWarning("Non-executable memory region", "Assembled instruction points to non-executable memory region !");
bool ret = MemPatch(addr, dest, destSize);
if (ret)
@ -91,3 +96,81 @@ bool assembleat(duint addr, const char* instruction, int* size, char* error, boo
return ret;
}
INSTR_POINTING_TO isInstructionPointingToExMemory(duint addr, const unsigned char* dest)
{
MEMMAP wMemMapStruct;
DISASM_ARG arg;
DISASM_INSTR wDisasInstrStruct;
MEMORY_BASIC_INFORMATION *wMbiStruct = NULL;
duint instrArgCount;
dsint instrMemValues[3] = {0};
duint instrMemValuesIndex = 0;
dsint mbiBaseAddr, mbiEndAddr;
disasmget((unsigned char*)dest, 0, &wDisasInstrStruct);
instrArgCount = wDisasInstrStruct.argcount;
if (instrArgCount)
{
// Loop through all arguements
for (int i = 0; i < wDisasInstrStruct.argcount; i++)
{
arg = wDisasInstrStruct.arg[i];
// Check if any of the arguments is a memory
if (arg.type == arg_memory)
{
instrMemValues[instrMemValuesIndex] = addr + arg.memvalue; // add current instruction VA for rip-relative addressing
instrMemValuesIndex++;
}
else if (wDisasInstrStruct.type == instr_branch)
{
instrMemValues[instrMemValuesIndex] = addr + arg.value;
instrMemValuesIndex++;
}
}
}
// No memory pointer in the instruction, no need to go further
if (!instrMemValuesIndex)
return NO_POINTER;
// Get memory map to locate the sections to which the instr memory address belongs to
DbgMemMap(&wMemMapStruct);
// For each memPointerValue
for (auto & memValue : instrMemValues)
{
// Loop through the memMaps
for (int i = 0; i < wMemMapStruct.count; i++)
{
wMbiStruct = &(wMemMapStruct.page)[i].mbi;
mbiBaseAddr = (dsint)wMbiStruct->BaseAddress;
mbiEndAddr = (dsint)wMbiStruct->BaseAddress + (dsint)wMbiStruct->RegionSize;
if (memValue >= mbiBaseAddr && memValue < mbiEndAddr)
{
if (wMbiStruct->Protect == PAGE_EXECUTE ||
wMbiStruct->Protect == PAGE_EXECUTE_READ ||
wMbiStruct->Protect == PAGE_EXECUTE_READWRITE ||
wMbiStruct->Protect == PAGE_EXECUTE_WRITECOPY)
{
// Memory region is marked as executable
#ifndef _WIN64
DWORD lpFlagsDep;
BOOL bPermanentDep;
// DEP is disabled if lpFlagsDep == 0
if (GetProcessDEPPolicy(fdProcessInfo->hProcess, &lpFlagsDep, &bPermanentDep) && lpFlagsDep != 0)
return EX_MEMORY;
#else
// DEP enabled on x64
return EX_MEMORY;
#endif
}
}
}
}
return NX_MEMORY;
}

View File

@ -3,7 +3,15 @@
#include "_global.h"
enum INSTR_POINTING_TO
{
EX_MEMORY,
NX_MEMORY,
NO_POINTER
};
bool assemble(duint addr, unsigned char* dest, int* size, const char* instruction, char* error);
bool assembleat(duint addr, const char* instruction, int* size, char* error, bool fillnop);
INSTR_POINTING_TO isInstructionPointingToExMemory(duint addr, const unsigned char* dest);
#endif // _ASSEMBLE_H

90
src/dbg/commandline.cpp Normal file
View File

@ -0,0 +1,90 @@
#include "commandline.h"
#include "threading.h"
#include "memory.h"
#include "debugger.h"
#include "debugger_commands.h"
char commandLine[MAX_COMMAND_LINE_SIZE];
bool isCmdLineEmpty()
{
return !strlen(commandLine);
}
char* getCommandLineArgs()
{
char* commandLineArguments = NULL;
char* extensionPtr = strchr(commandLine, '.');
if (!extensionPtr)
return NULL;
commandLineArguments = strchr(extensionPtr, ' ');
if (!commandLineArguments)
return NULL;
return (commandLineArguments + 1);
}
void CmdLineCacheSave(JSON Root)
{
EXCLUSIVE_ACQUIRE(LockCmdLine);
// return if command line is empty
if (!strlen(commandLine))
return;
// Create a JSON array to store each sub-object with a breakpoint
const JSON jsonCmdLine = json_object();
json_object_set_new(jsonCmdLine, "cmdLine", json_string(commandLine));
json_object_set(Root, "commandLine", jsonCmdLine);
// Notify garbage collector
json_decref(jsonCmdLine);
}
void CmdLineCacheLoad(JSON Root)
{
EXCLUSIVE_ACQUIRE(LockCmdLine);
// Clear command line
memset(commandLine, 0, MAX_COMMAND_LINE_SIZE);
// Get a handle to the root object -> commandLine
const JSON jsonCmdLine = json_object_get(Root, "commandLine");
// Return if there was nothing to load
if (!jsonCmdLine)
return;
const char *cmdLine = json_string_value(json_object_get(jsonCmdLine, "cmdLine"));
strcpy_s(commandLine, cmdLine);
json_decref(jsonCmdLine);
}
void copyCommandLine(const char* cmdLine)
{
strcpy_s(commandLine, cmdLine);
}
CMDRESULT SetCommandLine()
{
cmdline_error_t cmdline_error = { (cmdline_error_type_t)0, 0 };
if (!dbgsetcmdline(commandLine, &cmdline_error))
{
showcommandlineerror(&cmdline_error);
return STATUS_ERROR;
}
//update the memory map
MemUpdateMap();
GuiUpdateMemoryView();
return STATUS_CONTINUE;
}

11
src/dbg/commandline.h Normal file
View File

@ -0,0 +1,11 @@
#pragma once
#include "_global.h"
#include "command.h"
bool isCmdLineEmpty();
char* getCommandLineArgs();
void CmdLineCacheSave(JSON Root);
void CmdLineCacheLoad(JSON Root);
void copyCommandLine(const char* cmdLine);
CMDRESULT setCommandLine();

View File

@ -13,6 +13,7 @@
#include "bookmark.h"
#include "function.h"
#include "loop.h"
#include "commandline.h"
/**
\brief Directory where program databases are stored (usually in \db). UTF-8 encoding.
@ -24,26 +25,44 @@ char dbbasepath[deflen];
*/
char dbpath[deflen];
void DBSave()
enum LOAD_SAVE_DB_TYPE
{
COMMAND_LINE_ONLY,
ALL_BUT_COMMAND_LINE,
ALL
};
void DBSave(LOAD_SAVE_DB_TYPE saveType)
{
dprintf("Saving database...");
DWORD ticks = GetTickCount();
JSON root = json_object();
CommentCacheSave(root);
LabelCacheSave(root);
BookmarkCacheSave(root);
FunctionCacheSave(root);
LoopCacheSave(root);
BpCacheSave(root);
//save notes
char* text = nullptr;
GuiGetDebuggeeNotes(&text);
if (text)
// Save only command line
if (saveType == COMMAND_LINE_ONLY || saveType == ALL)
{
json_object_set_new(root, "notes", json_string(text));
BridgeFree(text);
CmdLineCacheSave(root);
}
if (saveType == ALL_BUT_COMMAND_LINE || saveType == ALL)
{
CommentCacheSave(root);
LabelCacheSave(root);
BookmarkCacheSave(root);
FunctionCacheSave(root);
LoopCacheSave(root);
BpCacheSave(root);
//save notes
char* text = nullptr;
GuiGetDebuggeeNotes(&text);
if (text)
{
json_object_set_new(root, "notes", json_string(text));
BridgeFree(text);
}
GuiSetDebuggeeNotes("");
}
GuiSetDebuggeeNotes("");
WString wdbpath = StringUtils::Utf8ToUtf16(dbpath);
if (json_object_size(root))
@ -76,7 +95,7 @@ void DBSave()
json_decref(root); //free root
}
void DBLoad()
void DBLoad(LOAD_SAVE_DB_TYPE loadType)
{
// If the file doesn't exist, there is no DB to load
if (!FileExists(dbpath))
@ -139,17 +158,26 @@ void DBLoad()
return;
}
// Finally load all structures
CommentCacheLoad(root);
LabelCacheLoad(root);
BookmarkCacheLoad(root);
FunctionCacheLoad(root);
LoopCacheLoad(root);
BpCacheLoad(root);
// Load only command line
if (loadType == COMMAND_LINE_ONLY || loadType == ALL)
{
CmdLineCacheLoad(root);
}
// Load notes
const char* text = json_string_value(json_object_get(root, "notes"));
GuiSetDebuggeeNotes(text);
if (loadType == ALL_BUT_COMMAND_LINE || loadType == ALL)
{
// Finally load all structures
CommentCacheLoad(root);
LabelCacheLoad(root);
BookmarkCacheLoad(root);
FunctionCacheLoad(root);
LoopCacheLoad(root);
BpCacheLoad(root);
// Load notes
const char* text = json_string_value(json_object_get(root, "notes"));
GuiSetDebuggeeNotes(text);
}
// Free root
json_decref(root);
@ -158,7 +186,7 @@ void DBLoad()
void DBClose()
{
DBSave();
DBSave(ALL);
CommentClear();
LabelClear();
BookmarkClear();

View File

@ -2,7 +2,14 @@
#include "_global.h"
void DBSave();
void DBLoad();
enum LOAD_SAVE_DB_TYPE
{
COMMAND_LINE_ONLY,
ALL_BUT_COMMAND_LINE,
ALL
};
void DBSave(LOAD_SAVE_DB_TYPE saveType);
void DBLoad(LOAD_SAVE_DB_TYPE loadType);
void DBClose();
void DBSetPath(const char *Directory, const char *ModulePath);

View File

@ -20,6 +20,7 @@
#include "exception.h"
#include "error.h"
#include "module.h"
#include "commandline.h"
static PROCESS_INFORMATION g_pi = {0, 0, 0, 0};
static char szBaseFileName[MAX_PATH] = "";
@ -33,6 +34,7 @@ static bool isDetachedByUser = false;
static bool bIsAttached = false;
static bool bSkipExceptions = false;
static bool bBreakOnNextDll = false;
static bool bFreezeStack = false;
static int ecount = 0;
static std::vector<ExceptionRange> ignoredExceptionRange;
static HANDLE hEvent = 0;
@ -154,6 +156,11 @@ void dbgsetisdetachedbyuser(bool b)
isDetachedByUser = b;
}
void dbgsetfreezestack(bool freeze)
{
bFreezeStack = freeze;
}
void dbgclearignoredexceptions()
{
ignoredExceptionRange.clear();
@ -214,7 +221,7 @@ void DebugUpdateGui(duint disasm_addr, bool stack)
}
duint csp = GetContextDataEx(hActiveThread, UE_CSP);
if(stack)
GuiStackDumpAt(csp, csp);
DebugUpdateStack(csp, csp);
static duint cacheCsp = 0;
if(csp != cacheCsp)
{
@ -233,6 +240,17 @@ void DebugUpdateGui(duint disasm_addr, bool stack)
GuiUpdateAllViews();
}
void DebugUpdateStack(duint dumpAddr, duint csp, bool forceDump)
{
if (!forceDump && bFreezeStack)
{
SELECTIONDATA selection;
if (GuiSelectionGet(GUI_STACK, &selection))
dumpAddr = selection.start;
}
GuiStackDumpAt(dumpAddr, csp);
}
void cbUserBreakpoint()
{
hActiveThread = ThreadGetHandle(((DEBUG_EVENT*)GetDebugData())->dwThreadId);
@ -632,7 +650,7 @@ static void cbCreateProcess(CREATE_PROCESS_DEBUG_INFO* CreateProcessInfo)
// Init program database
DBSetPath(nullptr, szFileName);
DBLoad();
DBLoad(ALL_BUT_COMMAND_LINE);
SafeSymSetOptions(SYMOPT_DEBUG | SYMOPT_LOAD_LINES | SYMOPT_ALLOW_ABSOLUTE_SYMBOLS | SYMOPT_FAVOR_COMPRESSED | SYMOPT_IGNORE_NT_SYMPATH);
GuiSymbolLogClear();
@ -1116,10 +1134,26 @@ DWORD WINAPI threadDebugLoop(void* lpParameter)
bIsAttached = false;
bSkipExceptions = false;
bBreakOnNextDll = false;
bFreezeStack = false;
INIT_STRUCT* init = (INIT_STRUCT*)lpParameter;
bFileIsDll = IsFileDLLW(StringUtils::Utf8ToUtf16(init->exe).c_str(), 0);
pDebuggedEntry = GetPE32DataW(StringUtils::Utf8ToUtf16(init->exe).c_str(), 0, UE_OEP);
strcpy_s(szFileName, init->exe);
// Load command line if it exists in DB
DBSetPath(nullptr, szFileName);
DBLoad(COMMAND_LINE_ONLY);
if (!isCmdLineEmpty())
{
char* commandLineArguments = NULL;
commandLineArguments = getCommandLineArgs();
if (commandLineArguments)
init->commandline = commandLineArguments;
}
if(bFileIsDll)
fdProcessInfo = (PROCESS_INFORMATION*)InitDLLDebugW(StringUtils::Utf8ToUtf16(init->exe).c_str(), false, StringUtils::Utf8ToUtf16(init->commandline).c_str(), StringUtils::Utf8ToUtf16(init->currentfolder).c_str(), 0);
else
@ -1195,6 +1229,7 @@ DWORD WINAPI threadDebugLoop(void* lpParameter)
DBClose();
ModClear();
ThreadClear();
SymClearMemoryCache();
GuiSetDebugState(stopped);
dputs("Debugging stopped!");
varset("$hp", (duint)0, true);
@ -1409,6 +1444,7 @@ DWORD WINAPI threadAttachLoop(void* lpParameter)
lock(WAITID_STOP);
bIsAttached = true;
bSkipExceptions = false;
bFreezeStack = false;
DWORD pid = (DWORD)lpParameter;
static PROCESS_INFORMATION pi_attached;
fdProcessInfo = &pi_attached;
@ -1461,6 +1497,7 @@ DWORD WINAPI threadAttachLoop(void* lpParameter)
DBClose();
ModClear();
ThreadClear();
SymClearMemoryCache();
GuiSetDebugState(stopped);
dputs("debugging stopped!");
varset("$hp", (duint)0, true);
@ -1596,7 +1633,7 @@ static bool fixgetcommandlinesbase(duint new_command_line_unicode, duint new_com
{
duint getcommandline;
if(!valfromstring("kernelbase:GetCommandLineA", &getcommandline))
if(!valfromstring("kernelBase:GetCommandLineA", &getcommandline))
{
if(!valfromstring("kernel32:GetCommandLineA", &getcommandline))
{
@ -1682,6 +1719,9 @@ bool dbgsetcmdline(const char* cmd_line, cmdline_error_t* cmd_line_error)
return false;
}
// Copy command line
copyCommandLine(cmd_line);
return true;
}
@ -1723,6 +1763,7 @@ bool dbggetcmdline(char** cmd_line, cmdline_error_t* cmd_line_error)
cmd_line_error->type = CMDL_ERR_CONVERTUNICODE;
return false;
}
return true;
}

View File

@ -67,10 +67,12 @@ bool dbgisrunning();
bool dbgisdll();
void dbgsetattachevent(HANDLE handle);
void DebugUpdateGui(duint disasm_addr, bool stack);
void DebugUpdateStack(duint dumpAddr, duint csp, bool forceDump = false);
void dbgsetskipexceptions(bool skip);
void dbgsetstepping(bool stepping);
void dbgsetispausedbyuser(bool b);
void dbgsetisdetachedbyuser(bool b);
void dbgsetfreezestack(bool freeze);
void dbgclearignoredexceptions();
void dbgaddignoredexception(ExceptionRange range);
bool dbgisignoredexception(unsigned int exception);

View File

@ -1056,7 +1056,7 @@ CMDRESULT cbDebugStackDump(int argc, char* argv[])
duint size = 0;
duint base = MemFindBaseAddr(csp, &size);
if(base && addr >= base && addr < (base + size))
GuiStackDumpAt(addr, csp);
DebugUpdateStack(addr, csp, true);
else
dputs("Invalid stack address!");
return STATUS_CONTINUE;
@ -2102,3 +2102,16 @@ CMDRESULT cbDebugSkip(int argc, char* argv[])
DebugUpdateGui(cip, false); //update GUI
return STATUS_CONTINUE;
}
CMDRESULT cbDebugSetfreezestack(int argc, char* argv[])
{
if (argc < 2)
{
dputs("Not enough arguments!");
return STATUS_ERROR;
}
bool freeze = *argv[1] != '0';
dbgsetfreezestack(freeze);
dprintf("Stack is now %s\n", freeze ? "freezed" : "unfreezed");
return STATUS_CONTINUE;
}

View File

@ -64,6 +64,7 @@ CMDRESULT cbDebugDownloadSymbol(int argc, char* argv[]);
CMDRESULT cbDebugGetPageRights(int argc, char* argv[]);
CMDRESULT cbDebugSetPageRights(int argc, char* argv[]);
CMDRESULT cbDebugSkip(int argc, char* argv[]);
CMDRESULT cbDebugSetfreezestack(int argc, char* argv[]);
//misc
void showcommandlineerror(cmdline_error_t* cmdline_error);

View File

@ -416,14 +416,14 @@ CMDRESULT cbInstrBookmarkDel(int argc, char* argv[])
CMDRESULT cbInstrLoaddb(int argc, char* argv[])
{
DBLoad();
DBLoad(ALL);
GuiUpdateAllViews();
return STATUS_CONTINUE;
}
CMDRESULT cbInstrSavedb(int argc, char* argv[])
{
DBSave();
DBSave(ALL);
return STATUS_CONTINUE;
}
@ -767,7 +767,7 @@ CMDRESULT cbInstrPush(int argc, char* argv[])
}
Script::Stack::Push(value);
duint csp = GetContextDataEx(hActiveThread, UE_CSP);
GuiStackDumpAt(csp, csp);
DebugUpdateStack(csp, csp);
GuiUpdateRegisterView();
return STATUS_CONTINUE;
}
@ -776,7 +776,7 @@ CMDRESULT cbInstrPop(int argc, char* argv[])
{
duint value = Script::Stack::Pop();
duint csp = GetContextDataEx(hActiveThread, UE_CSP);
GuiStackDumpAt(csp, csp);
DebugUpdateStack(csp, csp);
GuiUpdateRegisterView();
if (argc > 1)
{
@ -885,6 +885,8 @@ CMDRESULT cbInstrRefFind(int argc, char* argv[])
newCommand += std::string(",") + argv[2];
if (argc > 3)
newCommand += std::string(",") + argv[3];
if (argc > 4)
newCommand += std::string(",") + argv[4];
return cmddirectexec(newCommand.c_str());
}
@ -913,7 +915,13 @@ CMDRESULT cbInstrRefFindRange(int argc, char* argv[])
sprintf_s(title, "Constant: %" fext "X", range.start);
else
sprintf_s(title, "Range: %" fext "X-%" fext "X", range.start, range.end);
int found = RefFind(addr, size, cbRefFind, &range, false, title);
duint refFindType = CURRENT_REGION;
if (argc >= 6 && valfromstring(argv[5], &refFindType, true))
if (refFindType != CURRENT_REGION && refFindType != CURRENT_MODULE && refFindType != ALL_MODULES)
refFindType = CURRENT_REGION;
int found = RefFind(addr, size, cbRefFind, &range, false, title, (REFFINDTYPE)refFindType);
dprintf("%u reference(s) in %ums\n", found, GetTickCount() - ticks);
varset("$result", found, false);
return STATUS_CONTINUE;
@ -970,14 +978,22 @@ bool cbRefStr(Capstone* disasm, BASIC_INSTRUCTION_INFO* basicinfo, REFINFO* refi
CMDRESULT cbInstrRefStr(int argc, char* argv[])
{
duint addr;
duint size = 0;
// If not specified, assume CURRENT_REGION by default
if (argc < 2 || !valfromstring(argv[1], &addr, true))
addr = GetContextDataEx(hActiveThread, UE_CIP);
duint size = 0;
if (argc >= 3)
if (!valfromstring(argv[2], &size, true))
size = 0;
duint refFindType = CURRENT_REGION;
if (argc >= 4 && valfromstring(argv[3], &refFindType, true))
if (refFindType != CURRENT_REGION && refFindType != CURRENT_MODULE && refFindType != ALL_MODULES)
refFindType = CURRENT_REGION;
duint ticks = GetTickCount();
int found = RefFind(addr, size, cbRefStr, 0, false, "Strings");
int found = RefFind(addr, size, cbRefStr, 0, false, "Strings", (REFFINDTYPE)refFindType);
dprintf("%u string(s) in %ums\n", found, GetTickCount() - ticks);
varset("$result", found, false);
return STATUS_CONTINUE;
@ -1399,8 +1415,14 @@ CMDRESULT cbInstrModCallFind(int argc, char* argv[])
if (argc >= 3)
if (!valfromstring(argv[2], &size, true))
size = 0;
duint refFindType = CURRENT_REGION;
if (argc >= 4 && valfromstring(argv[3], &refFindType, true))
if (refFindType != CURRENT_REGION && refFindType != CURRENT_MODULE && refFindType != ALL_MODULES)
refFindType = CURRENT_REGION;
duint ticks = GetTickCount();
int found = RefFind(addr, size, cbModCallFind, 0, false, "Calls");
int found = RefFind(addr, size, cbModCallFind, 0, false, "Calls", (REFFINDTYPE)refFindType);
dprintf("%u call(s) in %ums\n", found, GetTickCount() - ticks);
varset("$result", found, false);
return STATUS_CONTINUE;
@ -1656,6 +1678,11 @@ CMDRESULT cbInstrFindAsm(int argc, char* argv[])
if (!valfromstring(argv[3], &size))
size = 0;
duint refFindType = CURRENT_REGION;
if (argc >= 5 && valfromstring(argv[4], &refFindType, true))
if (refFindType != CURRENT_REGION && refFindType != CURRENT_MODULE && refFindType != ALL_MODULES)
refFindType = CURRENT_REGION;
unsigned char dest[16];
int asmsize = 0;
char error[MAX_ERROR_SIZE] = "";
@ -1671,7 +1698,7 @@ CMDRESULT cbInstrFindAsm(int argc, char* argv[])
duint ticks = GetTickCount();
char title[256] = "";
sprintf_s(title, "Command: \"%s\"", basicinfo.instruction);
int found = RefFind(addr, size, cbFindAsm, (void*)&basicinfo.instruction[0], false, title);
int found = RefFind(addr, size, cbFindAsm, (void*)&basicinfo.instruction[0], false, title, (REFFINDTYPE)refFindType);
dprintf("%u result(s) in %ums\n", found, GetTickCount() - ticks);
varset("$result", found, false);
return STATUS_CONTINUE;

View File

@ -45,6 +45,9 @@ void GetModuleInfo(MODINFO & Info, ULONG_PTR FileMapVA)
// Add entry to the vector
Info.sections.push_back(curSection);
}
// Clear imports by default
Info.imports.clear();
}
bool ModLoad(duint Base, duint Size, const char* FullPath)
@ -292,6 +295,20 @@ bool ModSectionsFromAddr(duint Address, std::vector<MODSECTIONINFO>* Sections)
return true;
}
bool ModImportsFromAddr(duint Address, std::vector<MODIMPORTINFO>* Imports)
{
SHARED_ACQUIRE(LockModules);
auto module = ModInfoFromAddr(Address);
if (!module)
return false;
// Copy vector <-> vector
*Imports = module->imports;
return true;
}
duint ModEntryFromAddr(duint Address)
{
SHARED_ACQUIRE(LockModules);
@ -328,4 +345,33 @@ void ModGetList(std::vector<MODINFO> & list)
list.clear();
for(const auto & mod : modinfo)
list.push_back(mod.second);
}
bool ModAddImportToModule(duint Base, MODIMPORTINFO importInfo)
{
SHARED_ACQUIRE(LockModules);
if (!Base || !importInfo.addr)
return false;
auto module = ModInfoFromAddr(Base);
if (!module)
return false;
// Search in Import Vector
std::vector<MODIMPORTINFO> *pImports = &(module->imports);
auto it = std::find_if(pImports->begin(), pImports->end(), [&importInfo](MODIMPORTINFO currentImportInfo)->bool
{
return (importInfo.addr == currentImportInfo.addr);
});
// Import in the list already
if (it != pImports->end())
return false;
// Add import to imports vector
pImports->push_back(importInfo);
return true;
}

View File

@ -9,6 +9,13 @@ struct MODSECTIONINFO
char name[MAX_SECTION_SIZE * 5]; // Escaped section name
};
struct MODIMPORTINFO
{
duint addr; // Virtual address
char name[MAX_IMPORT_SIZE];
char moduleName[MAX_MODULE_SIZE];
};
struct MODINFO
{
duint base; // Module base
@ -21,6 +28,7 @@ struct MODINFO
char path[MAX_PATH]; // File path (in UTF8)
std::vector<MODSECTIONINFO> sections;
std::vector<MODIMPORTINFO> imports;
};
bool ModLoad(duint Base, duint Size, const char* FullPath);
@ -34,7 +42,9 @@ duint ModHashFromName(const char* Module);
duint ModBaseFromName(const char* Module);
duint ModSizeFromAddr(duint Address);
bool ModSectionsFromAddr(duint Address, std::vector<MODSECTIONINFO>* Sections);
bool ModImportsFromAddr(duint Address, std::vector<MODIMPORTINFO>* Imports);
duint ModEntryFromAddr(duint Address);
int ModPathFromAddr(duint Address, char* Path, int Size);
int ModPathFromName(const char* Module, char* Path, int Size);
void ModGetList(std::vector<MODINFO> & list);
void ModGetList(std::vector<MODINFO> & list);
bool ModAddImportToModule(duint Base, MODIMPORTINFO importInfo);

View File

@ -9,34 +9,182 @@
#include "console.h"
#include "module.h"
int RefFind(duint Address, duint Size, CBREF Callback, void* UserData, bool Silent, const char* Name)
int RefFind(duint Address, duint Size, CBREF Callback, void* UserData, bool Silent, const char* Name, REFFINDTYPE type)
{
duint regionSize = 0;
duint regionBase = MemFindBaseAddr(Address, &regionSize, true);
char fullName[deflen];
char moduleName[MAX_MODULE_SIZE];
int refFindInRangeRet;
duint scanStart, scanSize;
REFINFO refInfo;
// If the memory page wasn't found, fail
if(!regionBase || !regionSize)
// Search in current Region
if (type == CURRENT_REGION)
{
if(!Silent)
dprintf("Invalid memory page 0x%p\n", Address);
duint regionSize = 0;
duint regionBase = MemFindBaseAddr(Address, &regionSize, true);
return 0;
// If the memory page wasn't found, fail
if (!regionBase || !regionSize)
{
if (!Silent)
dprintf("Invalid memory page 0x%p\n", Address);
return 0;
}
// Assume the entire range is used
scanStart = regionBase;
scanSize = regionSize;
// Otherwise use custom boundaries if size was supplied
if(Size)
{
duint maxsize = Size - (Address - regionBase);
// Make sure the size fits in one page
scanStart = Address;
scanSize = min(Size, maxsize);
}
// Determine the full module name
if (ModNameFromAddr(scanStart, moduleName, true))
sprintf_s(fullName, "%s (Region %s)", Name, moduleName);
else
sprintf_s(fullName, "%s (Region %p)", Name, scanStart);
// Initialize disassembler
Capstone cp;
// Allow an "initialization" notice
refInfo.refcount = 0;
refInfo.userinfo = UserData;
refInfo.name = fullName;
refFindInRangeRet = RefFindInRange(scanStart, scanSize, Callback, UserData, Silent, refInfo, cp, true, [](int percent)
{
GuiReferenceSetCurrentTaskProgress(percent, "Region Search");
GuiReferenceSetProgress(percent);
});
GuiReferenceReloadData();
if (!refFindInRangeRet)
return refFindInRangeRet;
refInfo.refcount += refFindInRangeRet;
}
// Assume the entire range is used
duint scanStart = regionBase;
duint scanSize = regionSize;
// Otherwise use custom boundaries if size was supplied
if(Size)
// Search in current Module
else if (type == CURRENT_MODULE)
{
duint maxsize = Size - (Address - regionBase);
MODINFO *modInfo = ModInfoFromAddr(Address);
// Make sure the size fits in one page
scanStart = Address;
scanSize = min(Size, maxsize);
if (!modInfo)
{
if (!Silent)
dprintf("Couldn't locate module for 0x%p\n", Address);
return 0;
}
duint modBase = modInfo->base;
duint modSize = modInfo->size;
scanStart = modBase;
scanSize = modSize;
// Determine the full module name
if (ModNameFromAddr(scanStart, moduleName, true))
sprintf_s(fullName, "%s (%s)", Name, moduleName);
else
sprintf_s(fullName, "%s (%p)", Name, scanStart);
// Initialize disassembler
Capstone cp;
// Allow an "initialization" notice
refInfo.refcount = 0;
refInfo.userinfo = UserData;
refInfo.name = fullName;
refFindInRangeRet = RefFindInRange(scanStart, scanSize, Callback, UserData, Silent, refInfo, cp, true, [](int percent)
{
GuiReferenceSetCurrentTaskProgress(percent, "Module Search");
GuiReferenceSetProgress(percent);
});
if (!refFindInRangeRet)
return refFindInRangeRet;
GuiReferenceReloadData();
}
// Search in all Modules
else if (type == ALL_MODULES)
{
bool initCallBack = true;
std::vector<MODINFO > modList;
ModGetList(modList);
if (!modList.size())
{
if (!Silent)
dprintf("Couldn't get module list");
return 0;
}
// Initialize disassembler
Capstone cp;
// Determine the full module
sprintf_s(fullName, "All Modules (%s)", Name);
// Allow an "initialization" notice
refInfo.refcount = 0;
refInfo.userinfo = UserData;
refInfo.name = fullName;
for (duint i = 0; i < modList.size(); i++)
{
scanStart = modList[i].base;
scanSize = modList[i].size;
if (i != 0)
initCallBack = false;
refFindInRangeRet = RefFindInRange(scanStart, scanSize, Callback, UserData, Silent, refInfo, cp, initCallBack, [&i, &modList](int percent)
{
float fPercent = (float)percent / 100.f;
float fTotalPercent = ((float)i + fPercent) / (float)modList.size();
int totalPercent = (int)floor(fTotalPercent * 100.f);
char tst[256];
strcpy_s(tst, modList[i].name);
GuiReferenceSetCurrentTaskProgress(percent, modList[i].name);
GuiReferenceSetProgress(totalPercent);
});
if (!refFindInRangeRet)
return refFindInRangeRet;
GuiReferenceReloadData();
}
}
GuiReferenceSetProgress(100);
GuiReferenceReloadData();
return refInfo.refcount;
}
int RefFindInRange(duint scanStart, duint scanSize, CBREF Callback, void* UserData, bool Silent, REFINFO &refInfo, Capstone &cp, bool initCallBack, CBPROGRESS cbUpdateProgress)
{
// Allocate and read a buffer from the remote process
Memory<unsigned char*> data(scanSize, "reffind:data");
@ -48,25 +196,8 @@ int RefFind(duint Address, duint Size, CBREF Callback, void* UserData, bool Sile
return 0;
}
// Determine the full module name
char fullName[deflen];
char moduleName[MAX_MODULE_SIZE];
if(ModNameFromAddr(scanStart, moduleName, true))
sprintf_s(fullName, "%s (%s)", Name, moduleName);
else
sprintf_s(fullName, "%s (%p)", Name, scanStart);
// Initialize disassembler
Capstone cp;
// Allow an "initialization" notice
REFINFO refInfo;
refInfo.refcount = 0;
refInfo.userinfo = UserData;
refInfo.name = fullName;
Callback(0, 0, &refInfo);
if(initCallBack)
Callback(0, 0, &refInfo);
//concurrency::parallel_for(duint (0), scanSize, [&](duint i)
for(duint i = 0; i < scanSize;)
@ -78,7 +209,7 @@ int RefFind(duint Address, duint Size, CBREF Callback, void* UserData, bool Sile
// Integer = floor(percent)
int percent = (int)floor(((float)i / (float)scanSize) * 100.0f);
GuiReferenceSetProgress(percent);
cbUpdateProgress(percent);
}
// Disassemble the instruction
@ -104,7 +235,6 @@ int RefFind(duint Address, duint Size, CBREF Callback, void* UserData, bool Sile
i += disasmLen;
}
GuiReferenceSetProgress(100);
GuiReferenceReloadData();
cbUpdateProgress(100);
return refInfo.refcount;
}

View File

@ -2,6 +2,7 @@
#include "_global.h"
#include "disasm_fast.h"
#include <functional>
struct REFINFO
{
@ -10,7 +11,16 @@ struct REFINFO
const char* name;
};
typedef enum
{
CURRENT_REGION,
CURRENT_MODULE,
ALL_MODULES
} REFFINDTYPE;
// Reference callback typedef
typedef bool (*CBREF)(Capstone* disasm, BASIC_INSTRUCTION_INFO* basicinfo, REFINFO* refinfo);
typedef std::function<void(int) > CBPROGRESS;
int RefFind(duint Address, duint Size, CBREF Callback, void* UserData, bool Silent, const char* Name);
int RefFind(duint Address, duint Size, CBREF Callback, void* UserData, bool Silent, const char* Name, REFFINDTYPE type);
int RefFindInRange(duint scanStart, duint scanSize, CBREF Callback, void* UserData, bool Silent, REFINFO &refInfo, Capstone &cp, bool initCallBack, CBPROGRESS cbUpdateProgress);

View File

@ -9,6 +9,7 @@
#include "console.h"
#include "module.h"
#include "label.h"
#include "addrinfo.h"
struct SYMBOLCBDATA
{
@ -16,35 +17,25 @@ struct SYMBOLCBDATA
void* user;
};
typedef std::vector<SYMBOLINFO> SYMBOLINFOVECTOR;
typedef std::map<ULONG64, SYMBOLINFOVECTOR> SYMBOLINFOMAP;
SYMBOLINFOMAP modulesCacheList;
BOOL CALLBACK EnumSymbols(PSYMBOL_INFO SymInfo, ULONG SymbolSize, PVOID UserContext)
{
bool returnValue;
SYMBOLINFO curSymbol;
memset(&curSymbol, 0, sizeof(SYMBOLINFO));
curSymbol.addr = (duint)SymInfo->Address;
curSymbol.decoratedSymbol = (char*)BridgeAlloc(strlen(SymInfo->Name) + 1);
curSymbol.undecoratedSymbol = (char*)BridgeAlloc(MAX_SYM_NAME);
strcpy_s(curSymbol.decoratedSymbol, strlen(SymInfo->Name) + 1, SymInfo->Name);
// Convert from SYMBOL_INFO to SYMBOLINFO
returnValue = SymGetSymbolInfo(SymInfo, &curSymbol, false);
// Skip bad ordinals
if(strstr(SymInfo->Name, "Ordinal"))
{
// Does the symbol point to the module base?
if(SymInfo->Address == SymInfo->ModBase)
return TRUE;
}
if (!returnValue)
return false;
// Convert a mangled/decorated C++ name to a readable format
if(!SafeUnDecorateSymbolName(SymInfo->Name, curSymbol.undecoratedSymbol, MAX_SYM_NAME, UNDNAME_COMPLETE))
{
BridgeFree(curSymbol.undecoratedSymbol);
curSymbol.undecoratedSymbol = nullptr;
}
else if(!strcmp(curSymbol.decoratedSymbol, curSymbol.undecoratedSymbol))
{
BridgeFree(curSymbol.undecoratedSymbol);
curSymbol.undecoratedSymbol = nullptr;
}
// Add to the cache
modulesCacheList[SymInfo->ModBase].push_back(curSymbol);
SYMBOLCBDATA* cbData = (SYMBOLCBDATA*)UserContext;
cbData->cbSymbolEnum(&curSymbol, cbData->user);
@ -57,11 +48,35 @@ void SymEnum(duint Base, CBSYMBOLENUM EnumCallback, void* UserData)
symbolCbData.cbSymbolEnum = EnumCallback;
symbolCbData.user = UserData;
SymEnumImports(Base, &symbolCbData);
// Enumerate every single symbol for the module in 'base'
if(!SafeSymEnumSymbols(fdProcessInfo->hProcess, Base, "*", EnumSymbols, &symbolCbData))
dputs("SymEnumSymbols failed!");
}
void SymEnumFromCache(duint Base, CBSYMBOLENUM EnumCallback, void* UserData)
{
SYMBOLCBDATA symbolCbData;
symbolCbData.cbSymbolEnum = EnumCallback;
symbolCbData.user = UserData;
// Check if this module is cached in the list
if (modulesCacheList.find(Base) != modulesCacheList.end())
{
SymEnumImports(Base, &symbolCbData);
// Callback
for (duint i = 0; i < modulesCacheList[Base].size(); i++)
symbolCbData.cbSymbolEnum(&modulesCacheList[Base].at(i), symbolCbData.user);
}
else
{
// Then get the symbols and cache them
SymEnum(Base, EnumCallback, UserData);
}
}
bool SymGetModuleList(std::vector<SYMBOLMODULEINFO>* List)
{
//
@ -301,4 +316,133 @@ bool SymGetSourceLine(duint Cip, char* FileName, int* Line)
}
return true;
}
void SymClearMemoryCache()
{
SYMBOLINFOMAP::iterator it = modulesCacheList.begin();
for (; it != modulesCacheList.end(); it++)
{
SYMBOLINFOVECTOR* pModuleVector = &((*it).second);
// Free up previously allocated memory
for (duint i = 0; i < pModuleVector->size(); i++)
{
BridgeFree(pModuleVector->at(i).decoratedSymbol);
BridgeFree(pModuleVector->at(i).undecoratedSymbol);
}
}
// Clear the whole map
modulesCacheList.clear();
}
bool SymGetSymbolInfo(PSYMBOL_INFO SymInfo, SYMBOLINFO* curSymbol, bool isImported)
{
// SYMBOL_INFO is a structure used by Sym* functions
// SYMBOLINFO is the custom structure used by the debugger
// This functions fills SYMBOLINFO fields from SYMBOL_INFO data
curSymbol->addr = (duint)SymInfo->Address;
curSymbol->decoratedSymbol = (char*)BridgeAlloc(strlen(SymInfo->Name) + 1);
curSymbol->undecoratedSymbol = (char*)BridgeAlloc(MAX_SYM_NAME);
strcpy_s(curSymbol->decoratedSymbol, strlen(SymInfo->Name) + 1, SymInfo->Name);
// Skip bad ordinals
if (strstr(SymInfo->Name, "Ordinal"))
{
// Does the symbol point to the module base?
if (SymInfo->Address == SymInfo->ModBase)
return FALSE;
}
// Convert a mangled/decorated C++ name to a readable format
if (!SafeUnDecorateSymbolName(SymInfo->Name, curSymbol->undecoratedSymbol, MAX_SYM_NAME, UNDNAME_COMPLETE))
{
BridgeFree(curSymbol->undecoratedSymbol);
curSymbol->undecoratedSymbol = nullptr;
}
else if (!strcmp(curSymbol->decoratedSymbol, curSymbol->undecoratedSymbol))
{
BridgeFree(curSymbol->undecoratedSymbol);
curSymbol->undecoratedSymbol = nullptr;
}
// Symbol is exported
curSymbol->isImported = isImported;
return true;
}
void SymEnumImports(duint Base, SYMBOLCBDATA* pSymbolCbData)
{
char buf[MAX_IMPORT_SIZE];
char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME]; // Reserve enough space for symbol name, see msdn for this
SYMBOLINFO curSymbol;
PSYMBOL_INFO pSymInfo;
std::vector<MODIMPORTINFO> imports;
// SizeOfStruct and MaxNameLen need to be set or SymFromAddr() returns INVALID_PARAMETER
pSymInfo = (PSYMBOL_INFO)buffer;
pSymInfo->SizeOfStruct = sizeof(SYMBOL_INFO);
pSymInfo->MaxNameLen = MAX_SYM_NAME;
// Enum imports if none found
if (ModImportsFromAddr(Base, &imports) && !imports.size())
{
// Enum imports from current module
apienumimports(Base, [](duint Base, duint Address, char* name, char* moduleName)
{
MODIMPORTINFO importInfo;
importInfo.addr = Address;
strcpy_s(importInfo.name, MAX_IMPORT_SIZE, name);
strcpy_s(importInfo.moduleName, MAX_MODULE_SIZE, moduleName);
// Add import to the module structure
ModAddImportToModule(Base, importInfo);
});
}
// Get imports
if (ModImportsFromAddr(Base, &imports) && imports.size())
{
for (duint i = 0; i < imports.size(); i++)
{
// Can we get symbol for the import address
if (SafeSymFromAddr(fdProcessInfo->hProcess, (duint)imports[i].addr, 0, pSymInfo))
{
// Does the symbol point to the module base?
if (!SymGetSymbolInfo(pSymInfo, &curSymbol, true))
continue;
}
// Otherwise just use import info from module itself
else
{
curSymbol.addr = imports[i].addr;
curSymbol.isImported = true;
curSymbol.undecoratedSymbol = nullptr;
curSymbol.decoratedSymbol = imports[i].name;
}
// Format so that we get : moduleName.importSymbol
duint lenWithoutExt = strlen(imports[i].moduleName) - 3; // Remove extension
strncpy_s(buf, lenWithoutExt, imports[i].moduleName, _TRUNCATE);
strcat_s(buf , ".");
if (curSymbol.undecoratedSymbol)
{
strcat(buf, curSymbol.undecoratedSymbol);
curSymbol.undecoratedSymbol = buf;
}
if (curSymbol.decoratedSymbol)
{
strcat(buf, curSymbol.decoratedSymbol);
curSymbol.decoratedSymbol = buf;
}
// Callback
pSymbolCbData->cbSymbolEnum(&curSymbol, pSymbolCbData->user);
}
}
}

View File

@ -2,12 +2,18 @@
#include "_global.h"
struct SYMBOLCBDATA;
void SymEnum(duint Base, CBSYMBOLENUM EnumCallback, void* UserData);
void SymEnumFromCache(duint Base, CBSYMBOLENUM EnumCallback, void* UserData);
bool SymGetModuleList(std::vector<SYMBOLMODULEINFO>* List);
void SymUpdateModuleList();
void SymDownloadAllSymbols(const char* SymbolStore);
bool SymAddrFromName(const char* Name, duint* Address);
const char* SymGetSymbolicName(duint Address);
void SymClearMemoryCache();
bool SymGetSymbolInfo(PSYMBOL_INFO SymInfo, SYMBOLINFO* curSymbol, bool isImported);
void SymEnumImports(duint Base, SYMBOLCBDATA* pSymbolCbData);
/**
\brief Gets the source code file name and line from an address.

View File

@ -51,6 +51,7 @@ enum SectionLock
LockPluginCommandList,
LockPluginMenuList,
LockLast,
LockCmdLine
};
class SectionLockerGlobal

View File

@ -2187,7 +2187,7 @@ bool valtostring(const char* string, duint value, bool silent)
else if(strstr(regName(), "sp")) //update stack
{
duint csp = GetContextDataEx(hActiveThread, UE_CSP);
GuiStackDumpAt(csp, csp);
DebugUpdateStack(csp, csp);
GuiUpdateRegisterView();
}
else

View File

@ -94,6 +94,7 @@ static void registercommands()
dbgcmdnew("setcmdline\1setcommandline", cbDebugSetCmdline, true); //Set CmdLine
dbgcmdnew("loadlib", cbDebugLoadLib, true); //Load DLL
dbgcmdnew("skip", cbDebugSkip, true); //skip one instruction
dbgcmdnew("setfreezestack", cbDebugSetfreezestack, false); //freeze the stack from auto updates
//breakpoints
dbgcmdnew("bplist", cbDebugBplist, true); //breakpoint list

View File

@ -28,6 +28,7 @@
<ClCompile Include="breakpoint.cpp" />
<ClCompile Include="CodeFollowPass.cpp" />
<ClCompile Include="command.cpp" />
<ClCompile Include="commandline.cpp" />
<ClCompile Include="commandparser.cpp" />
<ClCompile Include="comment.cpp" />
<ClCompile Include="console.cpp" />
@ -106,6 +107,7 @@
<ClInclude Include="capstone\xcore.h" />
<ClInclude Include="CodeFollowPass.h" />
<ClInclude Include="command.h" />
<ClInclude Include="commandline.h" />
<ClInclude Include="commandparser.h" />
<ClInclude Include="comment.h" />
<ClInclude Include="console.h" />

View File

@ -278,6 +278,9 @@
<ClCompile Include="jit.cpp">
<Filter>Source Files\Debugger Core</Filter>
</ClCompile>
<ClCompile Include="commandline.cpp">
<Filter>Source Files\Information</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="x64_dbg.h">
@ -646,5 +649,8 @@
<ClInclude Include="yara\yara\stream.h">
<Filter>Header Files\Third Party\yara\yara</Filter>
</ClInclude>
<ClInclude Include="commandline.h">
<Filter>Header Files\Information</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -964,10 +964,16 @@ dsint AbstractTableView::getTableOffset()
void AbstractTableView::setTableOffset(dsint val)
{
dsint wMaxOffset = getRowCount() - getViewableRowsCount() + 1;
wMaxOffset = wMaxOffset > 0 ? wMaxOffset : 0;
wMaxOffset = wMaxOffset > 0 ? getRowCount() : 0;
if(val > wMaxOffset)
return;
mTableOffset = val;
// If val is within the last ViewableRows, then set RVA to rowCount - ViewableRows + 1
if(wMaxOffset && val >= (getRowCount() - getViewableRowsCount() + 1))
mTableOffset = (getRowCount() - getViewableRowsCount()) + 1;
else
mTableOffset = val;
emit tableOffsetChanged(val);
#ifdef _WIN64

View File

@ -1,6 +1,7 @@
#include "Disassembly.h"
#include "Configuration.h"
#include "Bridge.h"
#include "MainWindow.h"
Disassembly::Disassembly(QWidget* parent) : AbstractTableView(parent)
{
@ -1271,6 +1272,7 @@ void Disassembly::disassembleAt(dsint parVA, dsint parCIP, bool history, dsint n
{
dsint wBase = DbgMemFindBaseAddr(parVA, 0);
dsint wSize = DbgMemGetPageSize(wBase);
if(!wBase || !wSize)
return;
dsint wRVA = parVA - wBase;
@ -1300,6 +1302,7 @@ void Disassembly::disassembleAt(dsint parVA, dsint parCIP, bool history, dsint n
mCurrentVa++;
newHistory.va = selectionVA;
newHistory.tableOffset = selectionTableOffset;
newHistory.windowTitle = MainWindow::windowTitle;
mVaHistory.push_back(newHistory);
}
}
@ -1360,6 +1363,7 @@ void Disassembly::disassembleAt(dsint parVA, dsint parCIP, bool history, dsint n
//new disassembled address
newHistory.va = parVA;
newHistory.tableOffset = getTableOffset();
newHistory.windowTitle = MainWindow::windowTitle;
if(mVaHistory.size())
{
if(mVaHistory.last().va != parVA) //not 2x the same va in history
@ -1469,6 +1473,9 @@ void Disassembly::historyPrevious()
return;
mCurrentVa--;
disassembleAt(mVaHistory.at(mCurrentVa).va, rvaToVa(mCipRva), false, mVaHistory.at(mCurrentVa).tableOffset);
// Update window title
emit updateWindowTitle(mVaHistory.at(mCurrentVa).windowTitle);
}
void Disassembly::historyNext()
@ -1478,6 +1485,9 @@ void Disassembly::historyNext()
return;
mCurrentVa++;
disassembleAt(mVaHistory.at(mCurrentVa).va, rvaToVa(mCipRva), false, mVaHistory.at(mCurrentVa).tableOffset);
// Update window title
emit updateWindowTitle(mVaHistory.at(mCurrentVa).windowTitle);
}
bool Disassembly::historyHasPrevious()

View File

@ -98,6 +98,7 @@ public:
signals:
void selectionChanged(dsint parVA);
void disassembledAt(dsint parVA, dsint parCIP, bool history, dsint newTableOffset);
void updateWindowTitle(QString title);
public slots:
void disassembleAt(dsint parVA, dsint parCIP);
@ -131,6 +132,7 @@ private:
{
dsint va;
dsint tableOffset;
QString windowTitle;
} HistoryData_t;
QList<HistoryData_t> mVaHistory;

View File

@ -10,25 +10,41 @@ ReferenceView::ReferenceView()
mSearchStartCol = 1;
mFollowDumpDefault = false;
QHBoxLayout* layout = new QHBoxLayout();
QHBoxLayout* layoutTotalProgress = new QHBoxLayout();
QHBoxLayout* layoutCurrentTaskProgress = new QHBoxLayout();
// Create search progress bar
mSearchProgress = new QProgressBar();
mSearchProgress->setRange(0, 100);
mSearchProgress->setTextVisible(false);
mSearchProgress->setMaximumHeight(15);
layout->addWidget(mSearchProgress);
// Create current task search progress bar
mSearchCurrentTaskProgress = new QProgressBar();
mSearchCurrentTaskProgress->setRange(0, 100);
mSearchCurrentTaskProgress->setTextVisible(true);
mSearchCurrentTaskProgress->setMaximumHeight(15);
layoutCurrentTaskProgress->addWidget(mSearchCurrentTaskProgress);
// Create total search progress bar
mSearchTotalProgress = new QProgressBar();
mSearchTotalProgress->setRange(0, 100);
mSearchTotalProgress->setTextVisible(true);
mSearchTotalProgress->setMaximumHeight(15);
layoutTotalProgress->addWidget(mSearchTotalProgress);
// Label for the number of references
mCountLabel = new QLabel("tst");
mCountLabel->setAlignment(Qt::AlignCenter);
mCountLabel->setMaximumHeight(16);
mCountLabel->setMinimumWidth(40);
mCountLabel->setContentsMargins(2, 0, 5, 0);
layout->addWidget(mCountLabel);
mCountTotalLabel = new QLabel("tst");
mCountTotalLabel->setAlignment(Qt::AlignCenter);
mCountTotalLabel->setMaximumHeight(16);
mCountTotalLabel->setMinimumWidth(40);
mCountTotalLabel->setContentsMargins(2, 0, 5, 0);
layoutTotalProgress->addWidget(mCountTotalLabel);
mCountCurrentTaskLabel = new QLabel("");
mCountCurrentTaskLabel->setAlignment(Qt::AlignCenter);
mCountCurrentTaskLabel->setMaximumHeight(16);
mCountCurrentTaskLabel->setMinimumWidth(40);
mCountCurrentTaskLabel->setContentsMargins(2, 0, 5, 0);
layoutCurrentTaskProgress->addWidget(mCountCurrentTaskLabel);
// Add the progress bar and label to the main layout
mMainLayout->addLayout(layout);
mMainLayout->addLayout(layoutCurrentTaskProgress);
mMainLayout->addLayout(layoutTotalProgress);
// Setup signals
connect(Bridge::getBridge(), SIGNAL(referenceAddColumnAt(int, QString)), this, SLOT(addColumnAt(int, QString)));
@ -36,7 +52,8 @@ ReferenceView::ReferenceView()
connect(Bridge::getBridge(), SIGNAL(referenceSetCellContent(int, int, QString)), this, SLOT(setCellContent(int, int, QString)));
connect(Bridge::getBridge(), SIGNAL(referenceReloadData()), this, SLOT(reloadData()));
connect(Bridge::getBridge(), SIGNAL(referenceSetSingleSelection(int, bool)), this, SLOT(setSingleSelection(int, bool)));
connect(Bridge::getBridge(), SIGNAL(referenceSetProgress(int)), mSearchProgress, SLOT(setValue(int)));
connect(Bridge::getBridge(), SIGNAL(referenceSetProgress(int)), this, SLOT(referenceSetProgressSlot(int)));
connect(Bridge::getBridge(), SIGNAL(referenceSetCurrentTaskProgress(int,QString)), this, SLOT(referenceSetCurrentTaskProgressSlot(int,QString)));
connect(Bridge::getBridge(), SIGNAL(referenceSetSearchStartCol(int)), this, SLOT(setSearchStartCol(int)));
connect(this, SIGNAL(listContextMenuSignal(QMenu*)), this, SLOT(referenceContextMenu(QMenu*)));
connect(this, SIGNAL(enterPressedSignal()), this, SLOT(followGenericAddress()));
@ -80,7 +97,7 @@ void ReferenceView::disconnectBridge()
disconnect(Bridge::getBridge(), SIGNAL(referenceSetCellContent(int, int, QString)), this, SLOT(setCellContent(int, int, QString)));
disconnect(Bridge::getBridge(), SIGNAL(referenceReloadData()), this, SLOT(reloadData()));
disconnect(Bridge::getBridge(), SIGNAL(referenceSetSingleSelection(int, bool)), this, SLOT(setSingleSelection(int, bool)));
disconnect(Bridge::getBridge(), SIGNAL(referenceSetProgress(int)), mSearchProgress, SLOT(setValue(int)));
disconnect(Bridge::getBridge(), SIGNAL(referenceSetProgress(int)), mSearchTotalProgress, SLOT(setValue(int)));
disconnect(Bridge::getBridge(), SIGNAL(referenceSetSearchStartCol(int)), this, SLOT(setSearchStartCol(int)));
}
@ -90,6 +107,20 @@ void ReferenceView::refreshShortcutsSlot()
mToggleBookmark->setShortcut(ConfigShortcut("ActionToggleBookmark"));
}
void ReferenceView::referenceSetProgressSlot(int progress)
{
mSearchTotalProgress->setValue(progress);
mSearchTotalProgress->setAlignment(Qt::AlignCenter);
mSearchTotalProgress->setFormat("Total Progress " + QString::number(progress) + "%");
}
void ReferenceView::referenceSetCurrentTaskProgressSlot(int progress, QString taskTitle)
{
mSearchCurrentTaskProgress->setValue(progress);
mSearchCurrentTaskProgress->setAlignment(Qt::AlignCenter);
mSearchCurrentTaskProgress->setFormat(taskTitle + " " + QString::number(progress) + "%");
}
void ReferenceView::addColumnAt(int width, QString title)
{
int charwidth = mList->getCharWidth();
@ -109,7 +140,7 @@ void ReferenceView::addColumnAt(int width, QString title)
void ReferenceView::setRowCount(dsint count)
{
emit mCountLabel->setText(QString("%1").arg(count));
emit mCountTotalLabel->setText(QString("%1").arg(count));
mSearchBox->setText("");
mList->setRowCount(count);
}

View File

@ -29,19 +29,23 @@ private slots:
void toggleBreakpoint();
void toggleBookmark();
void refreshShortcutsSlot();
void referenceSetProgressSlot(int progress);
void referenceSetCurrentTaskProgressSlot(int progress, QString taskTitle);
signals:
void showCpu();
private:
QProgressBar* mSearchProgress;
QProgressBar* mSearchTotalProgress;
QProgressBar* mSearchCurrentTaskProgress;
QAction* mFollowAddress;
QAction* mFollowDumpAddress;
QAction* mFollowApiAddress;
QAction* mToggleBreakpoint;
QAction* mToggleBookmark;
bool mFollowDumpDefault;
QLabel* mCountLabel;
QLabel* mCountTotalLabel;
QLabel* mCountCurrentTaskLabel;
dsint apiAddressFromString(const QString & s);
};

View File

@ -2,6 +2,8 @@
#include "ui_SearchListView.h"
#include "FlickerThread.h"
#include <QMessageBox>
SearchListView::SearchListView(QWidget* parent) :
QWidget(parent),
ui(new Ui::SearchListView)
@ -9,7 +11,7 @@ SearchListView::SearchListView(QWidget* parent) :
ui->setupUi(this);
setContextMenuPolicy(Qt::CustomContextMenu);
mCursorPosition = 0;
// Create the reference list
mList = new SearchListViewTable();
@ -50,15 +52,20 @@ SearchListView::SearchListView(QWidget* parent) :
for(int i = 0; i < ui->mainSplitter->count(); i++)
ui->mainSplitter->handle(i)->setEnabled(false);
// Install eventFilter
mList->installEventFilter(this);
mSearchList->installEventFilter(this);
mSearchBox->installEventFilter(this);
// Setup search menu action
mSearchAction = new QAction("Search...", this);
connect(mSearchAction, SIGNAL(triggered()), this, SLOT(searchSlot()));
// Slots
connect(mList, SIGNAL(keyPressedSignal(QKeyEvent*)), this, SLOT(listKeyPressed(QKeyEvent*)));
// connect(mList, SIGNAL(keyPressedSignal(QKeyEvent*)), this, SLOT(listKeyPressed(QKeyEvent*)));
connect(mList, SIGNAL(contextMenuSignal(QPoint)), this, SLOT(listContextMenu(QPoint)));
connect(mList, SIGNAL(doubleClickedSignal()), this, SLOT(doubleClickedSlot()));
connect(mSearchList, SIGNAL(keyPressedSignal(QKeyEvent*)), this, SLOT(listKeyPressed(QKeyEvent*)));
// connect(mSearchList, SIGNAL(keyPressedSignal(QKeyEvent*)), this, SLOT(listKeyPressed(QKeyEvent*)));
connect(mSearchList, SIGNAL(contextMenuSignal(QPoint)), this, SLOT(listContextMenu(QPoint)));
connect(mSearchList, SIGNAL(doubleClickedSignal()), this, SLOT(doubleClickedSlot()));
connect(mSearchBox, SIGNAL(textChanged(QString)), this, SLOT(searchTextChanged(QString)));
@ -69,29 +76,6 @@ SearchListView::~SearchListView()
delete ui;
}
void SearchListView::listKeyPressed(QKeyEvent* event)
{
char ch = event->text().toUtf8().constData()[0];
if(isprint(ch)) //add a char to the search box
mSearchBox->setText(mSearchBox->text().insert(mSearchBox->cursorPosition(), QString(QChar(ch))));
else if(event->key() == Qt::Key_Backspace) //remove a char from the search box
{
QString newText;
if(event->modifiers() == Qt::ControlModifier) //clear the search box
newText = "";
else
{
newText = mSearchBox->text();
newText.chop(1);
}
mSearchBox->setText(newText);
}
else if((event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter)) //user pressed enter
emit enterPressedSignal();
else if(event->key() == Qt::Key_Escape) // Press escape, clears the search box
mSearchBox->clear();
}
bool SearchListView::findTextInList(SearchListViewTable* list, QString text, int row, int startcol, bool startswith)
{
int count = list->getColumnCount();
@ -168,6 +152,10 @@ void SearchListView::searchTextChanged(const QString & arg1)
break;
}
}
if(rows == 0)
emit emptySearchResult();
if(ui->checkBoxRegex->checkState() != Qt::Checked) //do not highlight with regex
mSearchList->highlightText = arg1;
mSearchList->reloadData();
@ -199,6 +187,69 @@ void SearchListView::on_checkBoxRegex_toggled(bool checked)
searchTextChanged(ui->searchBox->text());
}
bool SearchListView::eventFilter(QObject *obj, QEvent *event)
{
// Click in searchBox
if(obj == mSearchBox && event->type() == QEvent::MouseButtonPress)
{
QMouseEvent *mouseEvent = static_cast<QMouseEvent* >(event);
QLineEdit *lineEdit = static_cast<QLineEdit* >(obj);
mCursorPosition = lineEdit->cursorPositionAt(mouseEvent->pos());
lineEdit->setFocusPolicy(Qt::NoFocus);
return QObject::eventFilter(obj, event);
}
// KeyPress in List
else if((obj == mList || obj == mSearchList) && event->type() == QEvent::KeyPress)
{
QKeyEvent *keyEvent = static_cast<QKeyEvent* >(event);
char ch = keyEvent->text().toUtf8().constData()[0];
if(isprint(ch)) //add a char to the search box
{
mSearchBox->setText(mSearchBox->text().insert(mSearchBox->cursorPosition(), QString(QChar(ch))));
mCursorPosition++;
}
else if(keyEvent->key() == Qt::Key_Backspace) //remove a char from the search box
{
QString newText;
if(keyEvent->modifiers() == Qt::ControlModifier) //clear the search box
{
newText = "";
mCursorPosition = 0;
}
else
{
newText = mSearchBox->text();
if(mCursorPosition > 0)
newText.remove(mCursorPosition-1, 1);
((mCursorPosition - 1) < 0) ? mCursorPosition = 0 : mCursorPosition--;
}
mSearchBox->setText(newText);
}
else if((keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter)) //user pressed enter
{
if(mCurList->getCellContent(mCurList->getInitialSelection(), 0).length())
emit enterPressedSignal();
}
else if(keyEvent->key() == Qt::Key_Escape) // Press escape, clears the search box
{
mSearchBox->clear();
mCursorPosition = 0;
}
// Update cursorPosition to avoid a weird bug
mSearchBox->setCursorPosition(mCursorPosition);
return true;
}
else
return QObject::eventFilter(obj, event);
}
void SearchListView::searchSlot()
{
FlickerThread* thread = new FlickerThread(ui->searchBox, this);

View File

@ -31,7 +31,6 @@ public:
private slots:
void searchTextChanged(const QString & arg1);
void listKeyPressed(QKeyEvent* event);
void listContextMenu(const QPoint & pos);
void doubleClickedSlot();
void searchSlot();
@ -40,12 +39,17 @@ private slots:
signals:
void enterPressedSignal();
void listContextMenuSignal(QMenu* wMenu);
void emptySearchResult();
private:
Ui::SearchListView* ui;
QVBoxLayout* mListLayout;
QWidget* mListPlaceHolder;
QAction* mSearchAction;
int mCursorPosition;
protected:
bool eventFilter(QObject *obj, QEvent *event);
};
#endif // SEARCHLISTVIEW_H

View File

@ -228,6 +228,10 @@ void* Bridge::processMessage(GUIMSG type, void* param1, void* param2)
emit referenceSetProgress((int)param1);
break;
case GUI_REF_SETCURRENTTASKPROGRESS:
emit referenceSetCurrentTaskProgress((int)param1, QString((const char*)param2));
break;
case GUI_REF_SETSEARCHSTARTCOL:
emit referenceSetSearchStartCol((int)param1);
break;
@ -524,6 +528,14 @@ void* Bridge::processMessage(GUIMSG type, void* param1, void* param2)
emit dumpAtN((duint)param1, (int)param2);
}
break;
case GUI_DISPLAY_WARNING:
{
QString title = QString((const char*)param1);
QString text = QString((const char*)param2);
emit displayWarning(title, text);
}
break;
}
return nullptr;
}

View File

@ -70,6 +70,7 @@ signals:
void referenceReloadData();
void referenceSetSingleSelection(int index, bool scroll);
void referenceSetProgress(int progress);
void referenceSetCurrentTaskProgress(int progress, QString taskTitle);
void referenceSetSearchStartCol(int col);
void referenceInitialize(QString name);
void stackDumpAt(duint va, duint csp);
@ -114,6 +115,7 @@ signals:
void setDebuggeeNotes(const QString text);
void getDebuggeeNotes(void* text);
void dumpAtN(duint va, int index);
void displayWarning(QString title, QString text);
private:
QMutex* mBridgeMutex;

View File

@ -0,0 +1,193 @@
#include "AssembleDialog.h"
#include "ui_AssembleDialog.h"
#include <QMessageBox>
bool AssembleDialog::bWarningShowedOnce = false;
AssembleDialog::AssembleDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::AssembleDialog)
{
ui->setupUi(this);
setModal(true);
setFixedSize(this->size()); //fixed size
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
setWindowFlags(Qt::Dialog | Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::MSWindowsFixedSizeDialogHint);
#endif
mSelectedInstrVa = 0;
bKeepSizeChecked = false;
bFillWithNopsChecked = false;
mValidateThread = new ValidateExpressionThread(this);
mValidateThread->setOnExpressionChangedCallback(std::bind(&AssembleDialog::validateInstruction, this, std::placeholders::_1));
connect(ui->lineEdit, SIGNAL(textEdited(QString)), this, SLOT(textChangedSlot(QString)));
connect(mValidateThread, SIGNAL(instructionChanged(dsint,QString)), this, SLOT(instructionChangedSlot(dsint, QString)));
}
AssembleDialog::~AssembleDialog()
{
delete ui;
}
void AssembleDialog::setTextEditValue(const QString &text)
{
ui->lineEdit->setText(text);
}
void AssembleDialog::setKeepSizeChecked(bool checked)
{
ui->checkBoxKeepSize->setChecked(checked);
bKeepSizeChecked = checked;
}
void AssembleDialog::setKeepSizeLabel(const QString &text)
{
ui->labelKeepSize->setText(text);
}
void AssembleDialog::setFillWithNopsChecked(bool checked)
{
ui->checkBoxFillWithNops->setChecked(checked);
bFillWithNopsChecked = checked;
}
void AssembleDialog::setFillWithNopsLabel(const QString &text)
{
ui->labelFillWithNops->setText(text);
}
void AssembleDialog::setSelectedInstrVa(const duint va)
{
this->mSelectedInstrVa = va;
}
void AssembleDialog::setOkButtonEnabled(bool enabled)
{
ui->pushButtonOk->setEnabled(enabled);
}
void AssembleDialog::validateInstruction(QString expression)
{
//void instructionChanged(bool validInstruction, dsint sizeDifference, QString error)
dsint sizeDifference = 0;
int typedInstructionSize = 0;
int selectedInstructionSize = 0;
bool validInstruction = false;
QByteArray error(MAX_ERROR_SIZE, 0);
BASIC_INSTRUCTION_INFO basicInstrInfo;
// Get selected instruction info (size here)
DbgDisasmFastAt(mSelectedInstrVa, &basicInstrInfo);
selectedInstructionSize = basicInstrInfo.size;
// Get typed in instruction size
if(!DbgFunctions()->Assemble(this->mSelectedInstrVa, NULL, &typedInstructionSize, editText.toUtf8().constData(), error.data()) || selectedInstructionSize == 0)
{
emit mValidateThread->emitInstructionChanged(0, QString(error));
return;
}
// Valid instruction
validInstruction = true;
sizeDifference = typedInstructionSize - selectedInstructionSize;
emit mValidateThread->emitInstructionChanged(sizeDifference, "");
}
void AssembleDialog::hideEvent(QHideEvent *event)
{
Q_UNUSED(event);
mValidateThread->stop();
mValidateThread->wait();
}
void AssembleDialog::textChangedSlot(QString text)
{
if(ui->checkBoxKeepSize->isChecked())
mValidateThread->textChanged(text);
}
void AssembleDialog::instructionChangedSlot(dsint sizeDifference, QString error)
{
if(ui->checkBoxKeepSize->isChecked())
{
// If there was an error
if(error.length())
{
this->setKeepSizeLabel("<font color='orange'><b>Instruction decoding error : " + error + "</b></font>");
return;
}
// No error
else
{
// SizeDifference > 0 <=> Typed instruction is bigger
if(sizeDifference > 0)
{
QString message = "<font color='red'><b>Instruction bigger by " + QString::number(sizeDifference);
if(sizeDifference == 1)
message += QString(" byte</b></font>");
else
message += QString(" bytes</b></font>");
this->setKeepSizeLabel(message);
this->setOkButtonEnabled(false);
}
// SizeDifference < 0 <=> Typed instruction is smaller
else if(sizeDifference < 0)
{
QString message = "<font color='#00cc00'><b>Instruction smaller by " + QString::number(sizeDifference);
if(sizeDifference == -1)
message += QString(" byte</b></font>");
else
message += QString(" bytes</b></font>");
this->setKeepSizeLabel(message);
this->setOkButtonEnabled(true);
}
// SizeDifference == 0 <=> Both instruction have same size
else
{
QString message = "<font color='#00cc00'><b>Instruction is same size</b></font>";
this->setKeepSizeLabel(message);
this->setOkButtonEnabled(true);
}
}
}
}
void AssembleDialog::on_lineEdit_textChanged(const QString &arg1)
{
editText = arg1;
if(ui->checkBoxKeepSize->isChecked() && editText.size())
mValidateThread->start(editText);
}
void AssembleDialog::on_checkBoxKeepSize_clicked(bool checked)
{
if(checked && editText.size())
{
mValidateThread->start();
mValidateThread->textChanged(ui->lineEdit->text()); // Have to add this or textChanged isn't called inside start()
}
else
{
mValidateThread->stop();
mValidateThread->wait();
ui->labelKeepSize->setText("");
ui->pushButtonOk->setEnabled(true);
}
bKeepSizeChecked = checked;
}
void AssembleDialog::on_checkBoxFillWithNops_clicked(bool checked)
{
bFillWithNopsChecked = checked;
}

View File

@ -0,0 +1,53 @@
#ifndef ASSEMBLEDIALOG_H
#define ASSEMBLEDIALOG_H
#include <QDialog>
#include <functional>
#include "Bridge.h"
#include "ValidateExpressionThread.h"
namespace Ui
{
class AssembleDialog;
}
class AssembleDialog : public QDialog
{
Q_OBJECT
public:
explicit AssembleDialog(QWidget *parent = 0);
~AssembleDialog();
QString editText;
static bool bWarningShowedOnce;
void setTextEditValue(const QString & text);
bool bKeepSizeChecked;
void setKeepSizeChecked(bool checked);
void setKeepSizeLabel(const QString & text);
bool bFillWithNopsChecked;
void setFillWithNopsChecked(bool checked);
void setFillWithNopsLabel(const QString & text);
void setSelectedInstrVa(const duint va);
void setOkButtonEnabled(bool enabled);
void validateInstruction(QString expression);
void hideEvent(QHideEvent *event);
private slots:
void textChangedSlot(QString text);
void instructionChangedSlot(dsint sizeDifference, QString error);
void on_lineEdit_textChanged(const QString &arg1);
void on_checkBoxKeepSize_clicked(bool checked);
void on_checkBoxFillWithNops_clicked(bool checked);
private:
Ui::AssembleDialog *ui;
duint mSelectedInstrVa;
ValidateExpressionThread *mValidateThread;
};
#endif // ASSEMBLEDIALOG_H

View File

@ -0,0 +1,160 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AssembleDialog</class>
<widget class="QDialog" name="AssembleDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>433</width>
<height>114</height>
</rect>
</property>
<property name="windowTitle">
<string>0</string>
</property>
<property name="windowIcon">
<iconset resource="../../resource.qrc">
<normaloff>:/icons/images/ui-combo-box-edit.png</normaloff>:/icons/images/ui-combo-box-edit.png</iconset>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="1" column="0">
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>6</number>
</property>
<item>
<widget class="QLineEdit" name="lineEdit">
<property name="minimumSize">
<size>
<width>0</width>
<height>24</height>
</size>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QCheckBox" name="checkBoxKeepSize">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Keep Size</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="labelKeepSize">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QCheckBox" name="checkBoxFillWithNops">
<property name="text">
<string>Fill with NOP's</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="labelFillWithNops">
<property name="minimumSize">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButtonOk">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>OK</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButtonCancel">
<property name="text">
<string>Cancel</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
<resources>
<include location="../../resource.qrc"/>
</resources>
<connections>
<connection>
<sender>pushButtonOk</sender>
<signal>clicked()</signal>
<receiver>AssembleDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>265</x>
<y>77</y>
</hint>
<hint type="destinationlabel">
<x>217</x>
<y>49</y>
</hint>
</hints>
</connection>
<connection>
<sender>pushButtonCancel</sender>
<signal>clicked()</signal>
<receiver>AssembleDialog</receiver>
<slot>close()</slot>
<hints>
<hint type="sourcelabel">
<x>373</x>
<y>77</y>
</hint>
<hint type="destinationlabel">
<x>217</x>
<y>49</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -8,6 +8,7 @@
#include "WordEditDialog.h"
#include "HexEditDialog.h"
#include "YaraRuleSelectionDialog.h"
#include "AssembleDialog.h"
CPUDisassembly::CPUDisassembly(CPUWidget* parent) : Disassembly(parent)
{
@ -23,6 +24,7 @@ CPUDisassembly::CPUDisassembly(CPUWidget* parent) : Disassembly(parent)
connect(Bridge::getBridge(), SIGNAL(dbgStateChanged(DBGSTATE)), this, SLOT(debugStateChangedSlot(DBGSTATE)));
connect(Bridge::getBridge(), SIGNAL(selectionDisasmGet(SELECTIONDATA*)), this, SLOT(selectionGetSlot(SELECTIONDATA*)));
connect(Bridge::getBridge(), SIGNAL(selectionDisasmSet(const SELECTIONDATA*)), this, SLOT(selectionSetSlot(const SELECTIONDATA*)));
connect(Bridge::getBridge(), SIGNAL(displayWarning(QString, QString)), this, SLOT(displayWarningSlot(QString, QString)));
Initialize();
}
@ -301,7 +303,22 @@ void CPUDisassembly::setupRightClickContextMenu()
mMenuBuilder->addAction(makeShortcutAction(QIcon(":/icons/images/highlight.png"), "&Highlighting mode", SLOT(enableHighlightingModeSlot()), "ActionHighlightingMode"));
mMenuBuilder->addSeparator();
mMenuBuilder->addAction(makeShortcutAction(QIcon(":/icons/images/label.png"), "Label", SLOT(setLabelSlot()), "ActionSetLabel"));
MenuBuilder* labelMenu = new MenuBuilder(this);
labelMenu->addAction(makeShortcutAction("Label Current Address", SLOT(setLabelSlot()), "ActionSetLabel"));
QAction* labelAddress = makeAction("Label", SLOT(setLabelAddressSlot()));
labelMenu->addAction(labelAddress, [this, labelAddress](QMenu*)
{
BASIC_INSTRUCTION_INFO instr_info;
duint wVA = rvaToVa(getInitialSelection());
DbgDisasmFastAt(wVA, &instr_info);
QString targetAddress = "0x" + QString::number(instr_info.addr, 16).toUpper();
labelAddress->setText("Label " + targetAddress);
return (instr_info.branch || instr_info.call);
});
mMenuBuilder->addMenu(makeMenu(QIcon(":/icons/images/label.png"), "Label"), labelMenu);
mMenuBuilder->addAction(makeShortcutAction(QIcon(":/icons/images/comment.png"), "Comment", SLOT(setCommentSlot()), "ActionSetComment"));
mMenuBuilder->addAction(makeShortcutAction(QIcon(":/icons/images/bookmark.png"), "Bookmark", SLOT(setBookmarkSlot()), "ActionToggleBookmark"));
QAction* toggleFunctionAction = makeShortcutAction(QIcon(":/icons/images/functions.png"), "Function", SLOT(toggleFunctionSlot()), "ActionToggleFunction");
@ -342,11 +359,45 @@ void CPUDisassembly::setupRightClickContextMenu()
mMenuBuilder->addSeparator();
MenuBuilder* searchMenu = new MenuBuilder(this);
searchMenu->addAction(makeShortcutAction("C&ommand", SLOT(findCommandSlot()), "ActionFind"));
searchMenu->addAction(makeAction("&Constant", SLOT(findConstantSlot())));
searchMenu->addAction(makeAction("&String references", SLOT(findStringsSlot())));
searchMenu->addAction(makeAction("&Intermodular calls", SLOT(findCallsSlot())));
searchMenu->addAction(makeShortcutAction("&Pattern", SLOT(findPatternSlot()), "ActionFindPattern"));
MenuBuilder* mSearchRegionMenu = new MenuBuilder(this);
MenuBuilder* mSearchModuleMenu = new MenuBuilder(this);
MenuBuilder* mSearchAllMenu = new MenuBuilder(this);
// Search in Current Region menu
mFindCommandRegion = makeShortcutAction("C&ommand", SLOT(findCommandSlot()), "ActionFind");
mFindConstantRegion = makeAction("&Constant", SLOT(findConstantSlot()));
mFindStringsRegion = makeAction("&String references", SLOT(findStringsSlot()));
mFindCallsRegion = makeAction("&Intermodular calls", SLOT(findCallsSlot()));
mSearchRegionMenu->addAction(mFindCommandRegion);
mSearchRegionMenu->addAction(mFindConstantRegion);
mSearchRegionMenu->addAction(mFindStringsRegion);
mSearchRegionMenu->addAction(mFindCallsRegion);
mSearchRegionMenu->addAction(makeShortcutAction("&Pattern", SLOT(findPatternSlot()), "ActionFindPattern"));
// Search in Current Module menu
mFindCommandModule = makeShortcutAction("C&ommand", SLOT(findCommandSlot()), "ActionFind");
mFindConstantModule = makeAction("&Constant", SLOT(findConstantSlot()));
mFindStringsModule = makeAction("&String references", SLOT(findStringsSlot()));
mFindCallsModule = makeAction("&Intermodular calls", SLOT(findCallsSlot()));
mSearchModuleMenu->addAction(mFindCommandModule);
mSearchModuleMenu->addAction(mFindConstantModule);
mSearchModuleMenu->addAction(mFindStringsModule);
mSearchModuleMenu->addAction(mFindCallsModule);
// Search in All Modules menu
mFindCommandAll = makeShortcutAction("C&ommand", SLOT(findCommandSlot()), "ActionFind");
mFindConstantAll = makeAction("&Constant", SLOT(findConstantSlot()));
mFindStringsAll = makeAction("&String references", SLOT(findStringsSlot()));
mFindCallsAll = makeAction("&Intermodular calls", SLOT(findCallsSlot()));
mSearchAllMenu->addAction(mFindCommandAll);
mSearchAllMenu->addAction(mFindConstantAll);
mSearchAllMenu->addAction(mFindStringsAll);
mSearchAllMenu->addAction(mFindCallsAll);
searchMenu->addMenu(makeMenu("Current Region"), mSearchRegionMenu);
searchMenu->addMenu(makeMenu("Current Module"), mSearchModuleMenu);
searchMenu->addMenu(makeMenu("All Modules"), mSearchAllMenu);
mMenuBuilder->addMenu(makeMenu(QIcon(":/icons/images/search-for.png"), "&Search for"), searchMenu);
mReferenceSelectedAddressAction = makeShortcutAction("&Selected Address(es)", SLOT(findReferencesSlot()), "ActionFindReferencesToSelectedAddress");
@ -510,6 +561,35 @@ void CPUDisassembly::setLabelSlot()
GuiUpdateAllViews();
}
void CPUDisassembly::setLabelAddressSlot()
{
if(!DbgIsDebugging())
return;
BASIC_INSTRUCTION_INFO instr_info;
duint wVA = rvaToVa(getInitialSelection());
DbgDisasmFastAt(wVA, &instr_info);
wVA = instr_info.addr;
LineEditDialog mLineEdit(this);
QString addr_text = QString("%1").arg(wVA, sizeof(dsint) * 2, 16, QChar('0')).toUpper();
char label_text[MAX_COMMENT_SIZE] = "";
if(DbgGetLabelAt((duint)wVA, SEG_DEFAULT, label_text))
mLineEdit.setText(QString(label_text));
mLineEdit.setWindowTitle("Add label at " + addr_text);
if(mLineEdit.exec() != QDialog::Accepted)
return;
if(!DbgSetLabelAt(wVA, mLineEdit.editText.toUtf8().constData()))
{
QMessageBox msg(QMessageBox::Critical, "Error!", "DbgSetLabelAt failed!");
msg.setWindowIcon(QIcon(":/icons/images/compile-error.png"));
msg.setParent(this, Qt::Dialog);
msg.setWindowFlags(msg.windowFlags() & (~Qt::WindowContextHelpButtonHint));
msg.exec();
}
GuiUpdateAllViews();
}
void CPUDisassembly::setCommentSlot()
{
if(!DbgIsDebugging())
@ -617,62 +697,49 @@ void CPUDisassembly::assembleSlot()
if(!DbgIsDebugging())
return;
AssembleDialog assembleDialog;
do
{
dsint wRVA = getInitialSelection();
duint wVA = rvaToVa(wRVA);
QString addr_text = QString("%1").arg(wVA, sizeof(dsint) * 2, 16, QChar('0')).toUpper();
QByteArray wBuffer;
dsint wMaxByteCountToRead = 16 * 2;
//TODO: fix size problems
dsint size = getSize();
if(!size)
size = wRVA;
// Bounding
wMaxByteCountToRead = wMaxByteCountToRead > (size - wRVA) ? (size - wRVA) : wMaxByteCountToRead;
wBuffer.resize(wMaxByteCountToRead);
mMemPage->read(reinterpret_cast<byte_t*>(wBuffer.data()), wRVA, wMaxByteCountToRead);
QBeaEngine disasm(-1);
Instruction_t instr = disasm.DisassembleAt(reinterpret_cast<byte_t*>(wBuffer.data()), wMaxByteCountToRead, 0, 0, wVA);
Instruction_t instr = this->DisassembleAt(wRVA);
QString actual_inst = instr.instStr;
bool assembly_error;
do
{
char error[MAX_ERROR_SIZE] = "";
assembly_error = false;
LineEditDialog mLineEdit(this);
mLineEdit.setText(actual_inst);
mLineEdit.setWindowTitle("Assemble at " + addr_text);
mLineEdit.setCheckBoxText("&Fill with NOPs");
mLineEdit.enableCheckBox(true);
mLineEdit.setCheckBox(ConfigBool("Disassembler", "FillNOPs"));
if(mLineEdit.exec() != QDialog::Accepted)
assembleDialog.setSelectedInstrVa(wVA);
assembleDialog.setTextEditValue(actual_inst);
assembleDialog.setWindowTitle("Assemble at " + addr_text);
assembleDialog.setFillWithNopsChecked(ConfigBool("Disassembler", "FillNOPs"));
assembleDialog.setKeepSizeChecked(ConfigBool("Disassembler", "KeepSize"));
if(assembleDialog.exec() != QDialog::Accepted)
return;
//if the instruction its unkown or is the old instruction or empty (easy way to skip from GUI) skipping
if(mLineEdit.editText == QString("???") || mLineEdit.editText.toLower() == instr.instStr.toLower() || mLineEdit.editText == QString(""))
//if the instruction its unknown or is the old instruction or empty (easy way to skip from GUI) skipping
if(assembleDialog.editText == QString("???") || assembleDialog.editText.toLower() == instr.instStr.toLower() || assembleDialog.editText == QString(""))
break;
Config()->setBool("Disassembler", "FillNOPs", mLineEdit.bChecked);
Config()->setBool("Disassembler", "FillNOPs", assembleDialog.bFillWithNopsChecked);
Config()->setBool("Disassembler", "KeepSize", assembleDialog.bKeepSizeChecked);
char error[MAX_ERROR_SIZE] = "";
if(!DbgFunctions()->AssembleAtEx(wVA, mLineEdit.editText.toUtf8().constData(), error, mLineEdit.bChecked))
if(!DbgFunctions()->AssembleAtEx(wVA, assembleDialog.editText.toUtf8().constData(), error, assembleDialog.bFillWithNopsChecked))
{
QMessageBox msg(QMessageBox::Critical, "Error!", "Failed to assemble instruction \"" + mLineEdit.editText + "\" (" + error + ")");
QMessageBox msg(QMessageBox::Critical, "Error!", "Failed to assemble instruction \"" + assembleDialog.editText + "\" (" + error + ")");
msg.setWindowIcon(QIcon(":/icons/images/compile-error.png"));
msg.setParent(this, Qt::Dialog);
msg.setWindowFlags(msg.windowFlags() & (~Qt::WindowContextHelpButtonHint));
msg.exec();
actual_inst = mLineEdit.editText;
actual_inst = assembleDialog.editText;
assembly_error = true;
}
}
@ -782,27 +849,52 @@ void CPUDisassembly::findReferencesSlot()
void CPUDisassembly::findConstantSlot()
{
int refFindType = 0;
if(sender() == mFindConstantRegion)
refFindType = 0;
else if(sender() == mFindConstantModule)
refFindType = 1;
else if(sender() == mFindConstantAll)
refFindType = 2;
WordEditDialog wordEdit(this);
wordEdit.setup("Enter Constant", 0, sizeof(dsint));
if(wordEdit.exec() != QDialog::Accepted) //cancel pressed
return;
QString addrText = QString("%1").arg(rvaToVa(getInitialSelection()), sizeof(dsint) * 2, 16, QChar('0')).toUpper();
QString constText = QString("%1").arg(wordEdit.getVal(), sizeof(dsint) * 2, 16, QChar('0')).toUpper();
DbgCmdExec(QString("findref " + constText + ", " + addrText).toUtf8().constData());
DbgCmdExec(QString("findref " + constText + ", " + addrText + ", 0, %1").arg(refFindType).toUtf8().constData());
emit displayReferencesWidget();
}
void CPUDisassembly::findStringsSlot()
{
int refFindType = 0;
if(sender() == mFindStringsRegion)
refFindType = 0;
else if(sender() == mFindStringsModule)
refFindType = 1;
else if(sender() == mFindStringsAll)
refFindType = 2;
QString addrText = QString("%1").arg(rvaToVa(getInitialSelection()), sizeof(dsint) * 2, 16, QChar('0')).toUpper();
DbgCmdExec(QString("strref " + addrText).toUtf8().constData());
DbgCmdExec(QString("strref " + addrText + ", 0, %1").arg(refFindType).toUtf8().constData());
emit displayReferencesWidget();
}
void CPUDisassembly::findCallsSlot()
{
int refFindType = 0;
if(sender() == mFindCallsRegion)
refFindType = 0;
else if(sender() == mFindCallsModule)
refFindType = 1;
else if(sender() == mFindCallsAll)
refFindType = 2;
QString addrText = QString("%1").arg(rvaToVa(getInitialSelection()), sizeof(dsint) * 2, 16, QChar('0')).toUpper();
DbgCmdExec(QString("modcallfind " + addrText).toUtf8().constData());
DbgCmdExec(QString("modcallfind " + addrText + ", 0, 0").toUtf8().constData());
emit displayReferencesWidget();
}
@ -1072,10 +1164,18 @@ void CPUDisassembly::findCommandSlot()
if(!DbgIsDebugging())
return;
int refFindType = 0;
if(sender() == mFindCommandRegion)
refFindType = 0;
else if(sender() == mFindCommandModule)
refFindType = 1;
else if(sender() == mFindCommandAll)
refFindType = 2;
LineEditDialog mLineEdit(this);
mLineEdit.enableCheckBox(true);
mLineEdit.setCheckBoxText("Entire &Block");
mLineEdit.setCheckBox(ConfigBool("Disassembler", "FindCommandEntireBlock"));
mLineEdit.enableCheckBox(false);
// mLineEdit.setCheckBoxText("Entire &Block");
// mLineEdit.setCheckBox(ConfigBool("Disassembler", "FindCommandEntireBlock"));
mLineEdit.setWindowTitle("Find Command");
if(mLineEdit.exec() != QDialog::Accepted)
return;
@ -1098,13 +1198,8 @@ void CPUDisassembly::findCommandSlot()
QString addr_text = QString("%1").arg(va, sizeof(dsint) * 2, 16, QChar('0')).toUpper();
if(!mLineEdit.bChecked)
{
dsint size = mMemPage->getSize();
DbgCmdExec(QString("findasm \"%1\", %2, .%3").arg(mLineEdit.editText).arg(addr_text).arg(size).toUtf8().constData());
}
else
DbgCmdExec(QString("findasm \"%1\", %2").arg(mLineEdit.editText).arg(addr_text).toUtf8().constData());
dsint size = mMemPage->getSize();
DbgCmdExec(QString("findasm \"%1\", %2, .%3, %4").arg(mLineEdit.editText).arg(addr_text).arg(size).arg(refFindType).toUtf8().constData());
emit displayReferencesWidget();
}
@ -1139,6 +1234,11 @@ void CPUDisassembly::decompileFunctionSlot()
}
}
void CPUDisassembly::displayWarningSlot(QString title, QString text)
{
QMessageBox::QMessageBox(QMessageBox::Information, title, text, QMessageBox::Ok).exec();
}
void CPUDisassembly::paintEvent(QPaintEvent* event)
{
// Hook/hack to update the sidebar at the same time as this widget.

View File

@ -45,6 +45,7 @@ public slots:
void setNewOriginHereActionSlot();
void gotoOriginSlot();
void setLabelSlot();
void setLabelAddressSlot();
void setCommentSlot();
void setBookmarkSlot();
void toggleFunctionSlot();
@ -82,6 +83,7 @@ public slots:
void openSourceSlot();
void decompileSelectionSlot();
void decompileFunctionSlot();
void displayWarningSlot(QString title, QString text);
protected:
void paintEvent(QPaintEvent* event);
@ -93,6 +95,21 @@ private:
// Actions
QAction* mReferenceSelectedAddressAction;
QAction* mFindCommandRegion;
QAction* mFindConstantRegion;
QAction* mFindStringsRegion;
QAction* mFindCallsRegion;
QAction* mFindCommandModule;
QAction* mFindConstantModule;
QAction* mFindStringsModule;
QAction* mFindCallsModule;
QAction* mFindCommandAll;
QAction* mFindConstantAll;
QAction* mFindStringsAll;
QAction* mFindCallsAll;
// Goto dialog specific
GotoDialog* mGoto;
@ -101,6 +118,7 @@ private:
CPUWidget *mParentCPUWindow;
MenuBuilder* mMenuBuilder;
};
#endif // CPUDISASSEMBLY_H

View File

@ -1,6 +1,7 @@
#include "CPUDump.h"
#include <QMessageBox>
#include <QClipboard>
#include <QFileDialog>
#include "Configuration.h"
#include "Bridge.h"
#include "LineEditDialog.h"
@ -9,6 +10,7 @@
#include "DataCopyDialog.h"
#include "EntropyDialog.h"
#include "CPUMultiDump.h"
#include <QToolTip>
CPUDump::CPUDump(CPUDisassembly* disas, CPUMultiDump* multiDump, QWidget* parent) : HexDump(parent)
{
@ -131,6 +133,14 @@ void CPUDump::setupContextMenu()
connect(mBinaryPasteIgnoreSizeAction, SIGNAL(triggered()), this, SLOT(binaryPasteIgnoreSizeSlot()));
mBinaryMenu->addAction(mBinaryPasteIgnoreSizeAction);
//Binary->Save To a File
mBinarySaveToFile = new QAction("Save To a File", this);
mBinarySaveToFile->setShortcutContext(Qt::WidgetShortcut);
this->addAction(mBinarySaveToFile);
connect(mBinarySaveToFile, SIGNAL(triggered()), this, SLOT(binarySaveToFileSlot()));
mBinaryMenu->addAction(mBinarySaveToFile);
// Restore Selection
mUndoSelection = new QAction("&Restore selection", this);
mUndoSelection->setShortcutContext(Qt::WidgetShortcut);
@ -241,7 +251,7 @@ void CPUDump::setupContextMenu()
mMemoryAccessSingleshoot = new QAction("&Singleshoot", this);
connect(mMemoryAccessSingleshoot, SIGNAL(triggered()), this, SLOT(memoryAccessSingleshootSlot()));
mMemoryAccessMenu->addAction(mMemoryAccessSingleshoot);
mMemoryAccessRestore = new QAction("&Restore", this);
mMemoryAccessRestore = new QAction("&Restore on hit", this);
connect(mMemoryAccessRestore, SIGNAL(triggered()), this, SLOT(memoryAccessRestoreSlot()));
mMemoryAccessMenu->addAction(mMemoryAccessRestore);
mBreakpointMenu->addMenu(mMemoryAccessMenu);
@ -251,7 +261,7 @@ void CPUDump::setupContextMenu()
mMemoryWriteSingleshoot = new QAction("&Singleshoot", this);
connect(mMemoryWriteSingleshoot, SIGNAL(triggered()), this, SLOT(memoryWriteSingleshootSlot()));
mMemoryWriteMenu->addAction(mMemoryWriteSingleshoot);
mMemoryWriteRestore = new QAction("&Restore", this);
mMemoryWriteRestore = new QAction("&Restore on hit", this);
connect(mMemoryWriteRestore, SIGNAL(triggered()), this, SLOT(memoryWriteRestoreSlot()));
mMemoryWriteMenu->addAction(mMemoryWriteRestore);
mBreakpointMenu->addMenu(mMemoryWriteMenu);
@ -261,7 +271,7 @@ void CPUDump::setupContextMenu()
mMemoryExecuteSingleshoot = new QAction("&Singleshoot", this);
connect(mMemoryExecuteSingleshoot, SIGNAL(triggered()), this, SLOT(memoryExecuteSingleshootSlot()));
mMemoryExecuteMenu->addAction(mMemoryExecuteSingleshoot);
mMemoryExecuteRestore = new QAction("&Restore", this);
mMemoryExecuteRestore = new QAction("&Restore on hit", this);
connect(mMemoryExecuteRestore, SIGNAL(triggered()), this, SLOT(memoryExecuteRestoreSlot()));
mMemoryExecuteMenu->addAction(mMemoryExecuteRestore);
mBreakpointMenu->addMenu(mMemoryExecuteMenu);
@ -449,6 +459,7 @@ void CPUDump::setupContextMenu()
connect(mCopyRva, SIGNAL(triggered()), this, SLOT(copyRvaSlot()));
mCopyMenu->addAction(mCopyRva);
refreshShortcutsSlot();
connect(Config(), SIGNAL(shortcutsUpdated()), this, SLOT(refreshShortcutsSlot()));
}
@ -686,6 +697,47 @@ void CPUDump::mouseDoubleClickEvent(QMouseEvent* event)
}
}
void CPUDump::mouseMoveEvent(QMouseEvent *event)
{
dsint ptr = 0, ptrValue = 0;
// Get mouse pointer relative position
int x = event->x();
int y = event->y();
// Get HexDump own RVA address, then VA in memory
int rva = getItemStartingAddress(x, y);
int va = rvaToVa(rva);
// Read VA
DbgMemRead(va, (unsigned char*)&ptr, sizeof(dsint));
// Check if its a pointer
if(DbgMemIsValidReadPtr(ptr))
{
// Get the value at the address pointed by the ptr
DbgMemRead(ptr, (unsigned char*)&ptrValue, sizeof(dsint));
// Format text like this : [ptr] = ptrValue
QString strPtrValue;
#ifdef _WIN64
strPtrValue.sprintf("[0x%016X] = 0x%016X", ptr, ptrValue);
#else
strPtrValue.sprintf("[0x%08X] = 0x%08X", ptr, ptrValue);
#endif
// Show tooltip
QToolTip::showText(event->globalPos(), strPtrValue);
}
// If not a pointer, hide tooltips
else
{
QToolTip::hideText();
}
HexDump::mouseMoveEvent(event);
}
void CPUDump::addVaToHistory(dsint parVa)
{
mVaHistory.push_back(parVa);
@ -1489,6 +1541,22 @@ void CPUDump::binaryPasteIgnoreSizeSlot()
GuiUpdateAllViews();
}
void CPUDump::binarySaveToFileSlot()
{
QString fileName = QFileDialog::getSaveFileName(this, "Save to file", QDir::currentPath(), tr("All files (*.*)"));
if(fileName.length())
{
// Get starting selection and selection size, then convert selStart to VA
dsint rvaSelStart = getSelectionStart();
dsint selSize = getSelectionEnd() - rvaSelStart + 1;
dsint vaSelStart = rvaToVa(rvaSelStart);
// Prepare command
QString cmd = QString("savedata %1,%2,%3").arg(fileName, QString::number(vaSelStart, 16), QString::number(selSize));
DbgCmdExec(cmd.toUtf8().constData());
}
}
void CPUDump::findPattern()
{
HexEditDialog hexEdit(this);

View File

@ -17,6 +17,7 @@ public:
void setupContextMenu();
void contextMenuEvent(QContextMenuEvent* event);
void mouseDoubleClickEvent(QMouseEvent* event);
void mouseMoveEvent(QMouseEvent* event);
void addVaToHistory(dsint parVa);
bool historyHasPrev();
bool historyHasNext();
@ -25,6 +26,7 @@ public:
void historyClear();
signals:
void displayReferencesWidget();
@ -85,6 +87,7 @@ public slots:
void binaryCopySlot();
void binaryPasteSlot();
void binaryPasteIgnoreSizeSlot();
void binarySaveToFileSlot();
void findPattern();
void undoSelectionSlot();
void followStackSlot();
@ -187,6 +190,7 @@ private:
QAction* mBinaryCopyAction;
QAction* mBinaryPasteAction;
QAction* mBinaryPasteIgnoreSizeAction;
QAction* mBinarySaveToFile;
QAction* mFindPatternAction;
QAction* mFindReferencesAction;
QAction* mYaraAction;

View File

@ -11,6 +11,7 @@ CPUStack::CPUStack(QWidget* parent) : HexDump(parent)
int charwidth = getCharWidth();
ColumnDescriptor_t wColDesc;
DataDescriptor_t dDesc;
bStackFrozen = false;
mForceColumn = 1;
@ -42,6 +43,8 @@ CPUStack::CPUStack(QWidget* parent) : HexDump(parent)
connect(Bridge::getBridge(), SIGNAL(stackDumpAt(duint, duint)), this, SLOT(stackDumpAt(duint, duint)));
connect(Bridge::getBridge(), SIGNAL(selectionStackGet(SELECTIONDATA*)), this, SLOT(selectionGet(SELECTIONDATA*)));
connect(Bridge::getBridge(), SIGNAL(selectionStackSet(const SELECTIONDATA*)), this, SLOT(selectionSet(const SELECTIONDATA*)));
connect(Bridge::getBridge(), SIGNAL(dbgStateChanged(DBGSTATE)), this, SLOT(dbgStateChangedSlot(DBGSTATE)));
Initialize();
}
@ -125,6 +128,10 @@ void CPUStack::setupContextMenu()
connect(mGotoSp, SIGNAL(triggered()), this, SLOT(gotoSpSlot()));
connect(mGotoBp, SIGNAL(triggered()), this, SLOT(gotoBpSlot()));
mFreezeStack = new QAction("Freeze stack", this);
this->addAction(mFreezeStack);
connect(mFreezeStack, SIGNAL(triggered()), this, SLOT(freezeStackSlot()));
//Find Pattern
mFindPatternAction = new QAction("&Find Pattern...", this);
mFindPatternAction->setShortcutContext(Qt::WidgetShortcut);
@ -156,6 +163,24 @@ void CPUStack::setupContextMenu()
connect(Config(), SIGNAL(shortcutsUpdated()), this, SLOT(refreshShortcutsSlot()));
}
void CPUStack::updateFreezeStackAction()
{
QFont font = mFreezeStack->font();
if(bStackFrozen)
{
font.setBold(true);
mFreezeStack->setFont(font);
mFreezeStack->setText("Unfreeze the stack");
}
else
{
font.setBold(false);
mFreezeStack->setFont(font);
mFreezeStack->setText("Freeze the stack");
}
}
void CPUStack::refreshShortcutsSlot()
{
mBinaryEditAction->setShortcut(ConfigShortcut("ActionBinaryEdit"));
@ -180,6 +205,10 @@ QString CPUStack::paintContent(QPainter* painter, dsint rowBase, int rowOffset,
dsint wRva = (rowBase + rowOffset) * wBytePerRowCount - mByteOffset;
duint wVa = rvaToVa(wRva);
// This sets the first visible row to be selected when stack is frozen, so that we can scroll the stack without it being reset to first selection
if(bStackFrozen && rowOffset == 0)
setSingleSelection(wRva);
bool wIsSelected = isSelected(wRva);
if(wIsSelected) //highlight if selected
painter->fillRect(QRect(x, y, w, h), QBrush(selectionColor));
@ -320,6 +349,7 @@ void CPUStack::contextMenuEvent(QContextMenuEvent* event)
wMenu->addAction(mFindPatternAction);
wMenu->addAction(mGotoSp);
wMenu->addAction(mGotoBp);
wMenu->addAction(mFreezeStack);
wMenu->addAction(mGotoExpression);
duint selectedData;
@ -596,3 +626,23 @@ void CPUStack::modifySlot()
mMemPage->write(&value, addr, sizeof(dsint));
reloadData();
}
void CPUStack::freezeStackSlot()
{
if(bStackFrozen)
DbgCmdExec(QString("setfreezestack 0").toUtf8().constData());
else
DbgCmdExec(QString("setfreezestack 1").toUtf8().constData());
bStackFrozen = !bStackFrozen;
updateFreezeStackAction();
}
void CPUStack::dbgStateChangedSlot(DBGSTATE state)
{
if(state == initialized)
bStackFrozen = false;
updateFreezeStackAction();
}

View File

@ -18,6 +18,7 @@ public:
void contextMenuEvent(QContextMenuEvent* event);
void mouseDoubleClickEvent(QMouseEvent* event);
void setupContextMenu();
void updateFreezeStackAction();
signals:
void displayReferencesWidget();
@ -41,9 +42,12 @@ public slots:
void binaryPasteIgnoreSizeSlot();
void undoSelectionSlot();
void modifySlot();
void freezeStackSlot();
void dbgStateChangedSlot(DBGSTATE state);
private:
duint mCsp;
bool bStackFrozen;
QMenu* mBinaryMenu;
QAction* mBinaryEditAction;
@ -55,6 +59,7 @@ private:
QAction* mUndoSelection;
QAction* mGotoSp;
QAction* mGotoBp;
QAction* mFreezeStack;
QAction* mGotoExpression;
QAction* mFindPatternAction;
QAction* mFollowDisasm;

View File

@ -17,6 +17,63 @@ CommandLineEdit::CommandLineEdit(QWidget* parent) : HistoryLineEdit(parent)
connect(Bridge::getBridge(), SIGNAL(autoCompleteClearAll()), this, SLOT(autoCompleteClearAll()));
}
void CommandLineEdit::keyPressEvent(QKeyEvent *event)
{
if(event->type() == QEvent::KeyPress)
{
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
if(keyEvent->key() == Qt::Key_Tab)
{
QStringListModel *strListModel = (QStringListModel*)(mCompleter->model());
QStringList stringList = strListModel->stringList();
if(stringList.size())
{
QModelIndex currentModelIndex = mCompleter->popup()->currentIndex();
// If not item selected, select first one in the list
if(currentModelIndex.row() < 0)
currentModelIndex = mCompleter->currentIndex();
// If popup list is not visible, selected next suggested command
if(!mCompleter->popup()->isVisible())
{
for(int row=0; row < mCompleter->popup()->model()->rowCount(); row++)
{
QModelIndex modelIndex = mCompleter->popup()->model()->index(row, 0);
// If the lineedit contains a suggested command, get the next suggested one
if(mCompleter->popup()->model()->data(modelIndex) == this->text())
{
int nextModelIndexRow = (currentModelIndex.row() + 1) % mCompleter->popup()->model()->rowCount();
currentModelIndex = mCompleter->popup()->model()->index(nextModelIndexRow, 0);
break;
}
}
}
mCompleter->popup()->setCurrentIndex(currentModelIndex);
mCompleter->popup()->hide();
int currentRow = mCompleter->currentRow();
mCompleter->setCurrentRow(currentRow);
}
}
else
HistoryLineEdit::keyPressEvent(event);
}
else
HistoryLineEdit::keyPressEvent(event);
}
// Disables moving to Prev/Next child when pressing tab
bool CommandLineEdit::focusNextPrevChild(bool next)
{
Q_UNUSED(next);
return false;
}
void CommandLineEdit::autoCompleteAddCmd(const QString cmd)
{
QStringListModel* model = (QStringListModel*)(mCompleter->model());

View File

@ -10,6 +10,8 @@ class CommandLineEdit : public HistoryLineEdit
public:
explicit CommandLineEdit(QWidget* parent = 0);
void keyPressEvent(QKeyEvent *event);
bool focusNextPrevChild(bool next);
public slots:
void autoCompleteAddCmd(const QString cmd);

View File

@ -21,6 +21,8 @@ GotoDialog::GotoDialog(QWidget* parent) : QDialog(parent), ui(new Ui::GotoDialog
validRangeEnd = 0;
fileOffset = false;
mValidateThread = new ValidateExpressionThread(this);
mValidateThread->setOnExpressionChangedCallback(std::bind(&GotoDialog::validateExpression, this, std::placeholders::_1));
connect(mValidateThread, SIGNAL(expressionChanged(bool, bool, dsint)), this, SLOT(expressionChanged(bool, bool, dsint)));
connect(ui->editExpression, SIGNAL(textChanged(QString)), mValidateThread, SLOT(textChanged(QString)));
connect(this, SIGNAL(finished(int)), this, SLOT(finishedSlot(int)));
@ -44,6 +46,14 @@ void GotoDialog::hideEvent(QHideEvent* event)
mValidateThread->wait();
}
void GotoDialog::validateExpression(QString expression)
{
duint value;
bool validExpression = DbgFunctions()->ValFromString(expression.toUtf8().constData(), &value);
bool validPointer = validExpression && DbgMemIsValidReadPtr(value);
this->mValidateThread->emitExpressionChanged(validExpression, validPointer, value);
}
void GotoDialog::expressionChanged(bool validExpression, bool validPointer, dsint value)
{
QString expression = ui->editExpression->text();

View File

@ -24,6 +24,7 @@ public:
QString modName;
void showEvent(QShowEvent* event);
void hideEvent(QHideEvent* event);
void validateExpression(QString expression);
private slots:
void expressionChanged(bool validExpression, bool validPointer, dsint value);

View File

@ -13,6 +13,8 @@
#include "AttachDialog.h"
#include "LineEditDialog.h"
QString MainWindow::windowTitle = "";
MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
ui->setupUi(this);
@ -144,19 +146,25 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWi
// Create the tab widget
mTabWidget = new MHTabWidget(NULL);
// Setup tabs
addQWidgetTab(mCpuWidget);
addQWidgetTab(mLogView);
addQWidgetTab(mNotesManager);
addQWidgetTab(mBreakpointsView);
addQWidgetTab(mMemMapView);
addQWidgetTab(mCallStackView);
addQWidgetTab(mScriptView);
addQWidgetTab(mSymbolView);
addQWidgetTab(mSourceViewManager);
addQWidgetTab(mReferenceManager);
addQWidgetTab(mThreadView);
addQWidgetTab(mSnowmanView);
// Add all widgets to the list
mWidgetList.push_back(mCpuWidget);
mWidgetList.push_back(mLogView);
mWidgetList.push_back(mNotesManager);
mWidgetList.push_back(mBreakpointsView);
mWidgetList.push_back(mMemMapView);
mWidgetList.push_back(mCallStackView);
mWidgetList.push_back(mScriptView);
mWidgetList.push_back(mSymbolView);
mWidgetList.push_back(mSourceViewManager);
mWidgetList.push_back(mReferenceManager);
mWidgetList.push_back(mThreadView);
mWidgetList.push_back(mSnowmanView);
// If LoadSaveTabOrder disabled, load tabs in default order
if(!ConfigBool("Miscellaneous", "LoadSaveTabOrder"))
loadTabDefaultOrder();
else
loadTabSavedOrder();
setCentralWidget(mTabWidget);
@ -233,6 +241,7 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWi
connect(ui->actionChangeCommandLine, SIGNAL(triggered()), this, SLOT(changeCommandLine()));
connect(ui->actionManual, SIGNAL(triggered()), this, SLOT(displayManual()));
connect(mCpuWidget->getDisasmWidget(), SIGNAL(updateWindowTitle(QString)), this, SLOT(updateWindowTitleSlot(QString)));
connect(mCpuWidget->getDisasmWidget(), SIGNAL(displayReferencesWidget()), this, SLOT(displayReferencesWidget()));
connect(mCpuWidget->getDisasmWidget(), SIGNAL(displaySourceManagerWidget()), this, SLOT(displaySourceViewWidget()));
connect(mCpuWidget->getDisasmWidget(), SIGNAL(displaySnowmanWidget()), this, SLOT(displaySnowmanWidget()));
@ -240,13 +249,16 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWi
connect(mCpuWidget->getDisasmWidget(), SIGNAL(decompileAt(dsint, dsint)), this, SLOT(decompileAt(dsint, dsint)));
connect(mCpuWidget->getDumpWidget(), SIGNAL(displayReferencesWidget()), this, SLOT(displayReferencesWidget()));
connect(mCpuWidget->getStackWidget(), SIGNAL(displayReferencesWidget()), this, SLOT(displayReferencesWidget()));
connect(mTabWidget, SIGNAL(tabMovedTabWidget(int,int)), this, SLOT(tabMovedSlot(int, int)));
connect(Config(), SIGNAL(shortcutsUpdated()), this, SLOT(refreshShortcuts()));
// Set default setttings (when not set)
SettingsDialog defaultSettings;
lastException = 0;
defaultSettings.SaveSettings();
// Create updatechecker
mUpdateChecker = new UpdateChecker(this);
@ -302,6 +314,49 @@ void MainWindow::setTab(QWidget* widget)
}
}
void MainWindow::loadTabDefaultOrder()
{
clearTabWidget();
// Setup tabs
for(int i=0; i < mWidgetList.size(); i++)
addQWidgetTab(mWidgetList[i]);
}
void MainWindow::loadTabSavedOrder()
{
clearTabWidget();
QMap<duint, QWidget* > tabIndexToWidget;
// Get tabIndex for each widget and add them to tabIndexToWidget
for(int i=0; i < mWidgetList.size(); i++)
{
QString tabName = mWidgetList[i]->windowTitle();
tabName = tabName.replace(" ", "") + "Tab";
duint tabIndex = Config()->getUint("TabOrder", tabName);
tabIndexToWidget.insert(tabIndex, mWidgetList[i]);
}
// Setup tabs
QMap<duint, QWidget* >::iterator it = tabIndexToWidget.begin();
for(it; it != tabIndexToWidget.end(); it++)
{
addQWidgetTab(it.value());
}
}
void MainWindow::clearTabWidget()
{
if(!mTabWidget->count())
return;
for(int i=mTabWidget->count()-1; i >= 0; i--)
{
mTabWidget->removeTab(i);
}
}
void MainWindow::setGlobalShortcut(QAction* action, const QKeySequence & key)
{
action->setShortcut(key);
@ -642,9 +697,15 @@ void MainWindow::dropEvent(QDropEvent* pEvent)
void MainWindow::updateWindowTitleSlot(QString filename)
{
if(filename.length())
{
setWindowTitle(QString(mWindowMainTitle) + QString(" - ") + filename);
windowTitle = filename;
}
else
{
setWindowTitle(QString(mWindowMainTitle));
windowTitle = QString(mWindowMainTitle);
}
}
void MainWindow::execeStepOver()
@ -703,9 +764,10 @@ void MainWindow::displaySnowmanWidget()
void MainWindow::openSettings()
{
SettingsDialog settings(this);
settings.lastException = lastException;
settings.exec();
SettingsDialog *settings = new SettingsDialog(this);
connect(settings, SIGNAL(chkSaveLoadTabOrderStateChanged(bool)), this, SLOT(chkSaveloadTabSavedOrderStateChangedSlot(bool)));
settings->lastException = lastException;
settings->exec();
}
void MainWindow::openAppearance()
@ -1150,3 +1212,21 @@ void MainWindow::executeOnGuiThread(void* cbGuiThread)
{
((GUICALLBACK)cbGuiThread)();
}
void MainWindow::tabMovedSlot(int from, int to)
{
for(int i=0; i < mTabWidget->count(); i++)
{
// Remove space in widget name and append Tab to get config settings (CPUTab, MemoryMapTab, etc...)
QString tabName = mTabWidget->tabText(i).replace(" ", "") + "Tab";
Config()->setUint("TabOrder", tabName, i);
}
}
void MainWindow::chkSaveloadTabSavedOrderStateChangedSlot(bool state)
{
if(state)
loadTabSavedOrder();
else
loadTabDefaultOrder();
}

View File

@ -24,6 +24,7 @@
#include "MainWindowCloseThread.h"
#include "TimeWastedCounter.h"
#include "NotesManager.h"
#include "SettingsDialog.h"
namespace Ui
{
@ -40,6 +41,9 @@ public:
static DWORD WINAPI closeThread(void* ptr);
void closeEvent(QCloseEvent* event);
void setTab(QWidget* widget);
void loadTabDefaultOrder();
void loadTabSavedOrder();
void clearTabWidget();
public slots:
void executeCommand();
@ -111,6 +115,8 @@ public slots:
void showQWidgetTab(QWidget* qWidget);
void closeQWidgetTab(QWidget* qWidget);
void executeOnGuiThread(void* cbGuiThread);
void tabMovedSlot(int from, int to);
void chkSaveloadTabSavedOrderStateChangedSlot(bool state);
private:
Ui::MainWindow* ui;
@ -186,10 +192,14 @@ private:
bool bCanClose;
MainWindowCloseThread* mCloseThread;
QVector<QWidget* > mWidgetList;
protected:
void dragEnterEvent(QDragEnterEvent* pEvent);
void dropEvent(QDropEvent* pEvent);
public:
static QString windowTitle;
};
#endif // MAINWINDOW_H

View File

@ -231,6 +231,9 @@ void SettingsDialog::LoadSettings()
bJitOld = settings.miscSetJIT;
bJitAutoOld = settings.miscSetJITAuto;
GetSettingBool("Miscellaneous", "LoadSaveTabOrder", &settings.miscLoadSaveTabOrder);
ui->chkSaveLoadTabOrder->setChecked(settings.miscLoadSaveTabOrder);
}
void SettingsDialog::SaveSettings()
@ -298,6 +301,8 @@ void SettingsDialog::SaveSettings()
if(settings.miscSymbolCache)
BridgeSettingSet("Symbols", "CachePath", ui->editSymbolCache->text().toUtf8().constData());
BridgeSettingSetUint("Miscellaneous", "LoadSaveTabOrder", settings.miscLoadSaveTabOrder);
BridgeSettingFlush();
Config()->load();
DbgSettingsUpdated();
@ -625,3 +630,13 @@ void SettingsDialog::on_editSymbolCache_textEdited(const QString & arg1)
Q_UNUSED(arg1);
settings.miscSymbolCache = true;
}
void SettingsDialog::on_chkSaveLoadTabOrder_stateChanged(int arg1)
{
if(arg1 == Qt::Unchecked)
settings.miscLoadSaveTabOrder = false;
else
settings.miscLoadSaveTabOrder = true;
emit chkSaveLoadTabOrderStateChanged((bool)arg1);
}

View File

@ -18,6 +18,9 @@ public:
void SaveSettings();
unsigned int lastException;
signals:
void chkSaveLoadTabOrderStateChanged(bool state);
private slots:
//Manual slots
void setLastException(unsigned int exceptionCode);
@ -62,6 +65,8 @@ private slots:
void on_editSymbolStore_textEdited(const QString & arg1);
void on_editSymbolCache_textEdited(const QString & arg1);
void on_chkSaveLoadTabOrder_stateChanged(int arg1);
private:
//enums
enum CalcType
@ -127,6 +132,7 @@ private:
bool miscSetJITAuto;
bool miscSymbolStore;
bool miscSymbolCache;
bool miscLoadSaveTabOrder;
};
//variables

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>383</width>
<height>307</height>
<height>365</height>
</rect>
</property>
<property name="sizePolicy">
@ -432,7 +432,7 @@
<x>11</x>
<y>13</y>
<width>341</width>
<height>145</height>
<height>168</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_9">
@ -507,6 +507,13 @@
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="chkSaveLoadTabOrder">
<property name="text">
<string>Enable Load/Save Tab Order</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>

View File

@ -31,11 +31,13 @@ SymbolView::SymbolView(QWidget* parent) : QWidget(parent), ui(new Ui::SymbolView
// Setup symbol list
mSearchListView->mList->addColumnAt(charwidth * 2 * sizeof(dsint) + 8, "Address", true);
mSearchListView->mList->addColumnAt(charwidth * 2 * sizeof(dsint) + 8, "Type", true);
mSearchListView->mList->addColumnAt(charwidth * 80, "Symbol", true);
mSearchListView->mList->addColumnAt(2000, "Symbol (undecorated)", true);
// Setup search list
mSearchListView->mSearchList->addColumnAt(charwidth * 2 * sizeof(dsint) + 8, "Address", true);
mSearchListView->mSearchList->addColumnAt(charwidth * 2 * sizeof(dsint) + 8, "Type", true);
mSearchListView->mSearchList->addColumnAt(charwidth * 80, "Symbol", true);
mSearchListView->mSearchList->addColumnAt(2000, "Symbol (undecorated)", true);
@ -71,6 +73,7 @@ SymbolView::SymbolView(QWidget* parent) : QWidget(parent), ui(new Ui::SymbolView
connect(Bridge::getBridge(), SIGNAL(clearSymbolLog()), this, SLOT(clearSymbolLogSlot()));
connect(mModuleList->mList, SIGNAL(selectionChangedSignal(int)), this, SLOT(moduleSelectionChanged(int)));
connect(mModuleList->mSearchList, SIGNAL(selectionChangedSignal(int)), this, SLOT(moduleSelectionChanged(int)));
connect(mModuleList, SIGNAL(emptySearchResult()), this, SLOT(emptySearchResultSlot()));
connect(mModuleList, SIGNAL(listContextMenuSignal(QMenu*)), this, SLOT(moduleContextMenu(QMenu*)));
connect(mModuleList, SIGNAL(enterPressedSignal()), this, SLOT(moduleFollow()));
connect(Bridge::getBridge(), SIGNAL(updateSymbolList(int, SYMBOLMODULEINFO*)), this, SLOT(updateSymbolList(int, SYMBOLMODULEINFO*)));
@ -172,13 +175,20 @@ void SymbolView::cbSymbolEnum(SYMBOLINFO* symbol, void* user)
symbolList->setCellContent(index, 0, QString("%1").arg(symbol->addr, sizeof(dsint) * 2, 16, QChar('0')).toUpper());
if(symbol->decoratedSymbol)
{
symbolList->setCellContent(index, 1, symbol->decoratedSymbol);
BridgeFree(symbol->decoratedSymbol);
symbolList->setCellContent(index, 2, symbol->decoratedSymbol);
}
if(symbol->undecoratedSymbol)
{
symbolList->setCellContent(index, 2, symbol->undecoratedSymbol);
BridgeFree(symbol->undecoratedSymbol);
symbolList->setCellContent(index, 3, symbol->undecoratedSymbol);
}
if(symbol->isImported)
{
symbolList->setCellContent(index, 1, "Import");
}
else
{
symbolList->setCellContent(index, 1, "Export");
}
}
@ -188,7 +198,7 @@ void SymbolView::moduleSelectionChanged(int index)
if(!mModuleBaseList.count(mod))
return;
mSearchListView->mList->setRowCount(0);
DbgSymbolEnum(mModuleBaseList[mod], cbSymbolEnum, mSearchListView->mList);
DbgSymbolEnumFromCache(mModuleBaseList[mod], cbSymbolEnum, mSearchListView->mList);
mSearchListView->mList->reloadData();
mSearchListView->mList->setSingleSelection(0);
mSearchListView->mList->setTableOffset(0);
@ -204,7 +214,7 @@ void SymbolView::updateSymbolList(int module_count, SYMBOLMODULEINFO* modules)
mSearchListView->mList->setSingleSelection(0);
mModuleList->mList->setSingleSelection(0);
}
mModuleList->mList->setFocus();
mModuleBaseList.clear();
for(int i = 0; i < module_count; i++)
{
@ -395,3 +405,9 @@ void SymbolView::moduleEntropy()
entropyDialog.exec();
}
}
void SymbolView::emptySearchResultSlot()
{
// No result after search
mSearchListView->mCurList->setRowCount(0);
}

View File

@ -40,6 +40,7 @@ private slots:
void toggleBookmark();
void refreshShortcutsSlot();
void moduleEntropy();
void emptySearchResultSlot();
signals:
void showCpu();

View File

@ -11,6 +11,7 @@ MHTabWidget::MHTabWidget(QWidget* parent, bool allowDetach, bool allowDelete) :
connect(m_tabBar, SIGNAL(OnDetachTab(int, QPoint &)), this, SLOT(DetachTab(int, QPoint &)));
connect(m_tabBar, SIGNAL(OnMoveTab(int, int)), this, SLOT(MoveTab(int, int)));
connect(m_tabBar, SIGNAL(OnDeleteTab(int)), this, SLOT(DeleteTab(int)));
connect(m_tabBar, SIGNAL(tabMoved(int,int)), this, SLOT(tabMoved(int, int)));
setTabBar(m_tabBar);
setMovable(true);
@ -132,6 +133,11 @@ void MHTabWidget::DeleteTab(int index)
removeTab(index);
}
void MHTabWidget::tabMoved(int from, int to)
{
emit tabMovedTabWidget(from, to);
}
void MHTabWidget::setCurrentIndex(int index)
{
// Check if it's just a normal tab

View File

@ -30,11 +30,15 @@ public:
int count() const;
QList<QWidget*> windows();
signals:
void tabMovedTabWidget(int from, int to);
public slots:
void AttachTab(QWidget* parent);
void DetachTab(int index, QPoint &);
void MoveTab(int fromIndex, int toIndex);
void DeleteTab(int index);
void tabMoved(int from, int to);
public Q_SLOTS:
void setCurrentIndex(int index);

View File

@ -159,6 +159,7 @@ Configuration::Configuration() : QObject()
QMap<QString, bool> disassemblyBool;
disassemblyBool.insert("ArgumentSpaces", false);
disassemblyBool.insert("MemorySpaces", false);
disassemblyBool.insert("KeepSize", false);
disassemblyBool.insert("FillNOPs", false);
disassemblyBool.insert("Uppercase", false);
disassemblyBool.insert("FindCommandEntireBlock", false);
@ -170,6 +171,10 @@ Configuration::Configuration() : QObject()
engineBool.insert("ListAllPages", false);
defaultBools.insert("Engine", engineBool);
QMap<QString, bool> miscellaneousBool;
miscellaneousBool.insert("LoadSaveTabOrder", false);
defaultBools.insert("Miscellaneous", miscellaneousBool);
//uint settings
QMap<QString, duint> hexdumpUint;
hexdumpUint.insert("DefaultView", 0);
@ -177,6 +182,20 @@ Configuration::Configuration() : QObject()
QMap<QString, duint> disasmUint;
disasmUint.insert("MaxModuleSize", -1);
defaultUints.insert("Disassembler", disasmUint);
QMap<QString, duint> tabOrderUint;
tabOrderUint.insert("CPUTab", 0);
tabOrderUint.insert("LogTab", 1);
tabOrderUint.insert("NotesTab", 2);
tabOrderUint.insert("BreakpointsTab", 3);
tabOrderUint.insert("MemoryMapTab", 4);
tabOrderUint.insert("CallStackTab", 5);
tabOrderUint.insert("ScriptTab", 6);
tabOrderUint.insert("SymbolsTab", 7);
tabOrderUint.insert("SourceTab", 8);
tabOrderUint.insert("ReferencesTab", 9);
tabOrderUint.insert("ThreadsTab", 10);
tabOrderUint.insert("SnowmanTab", 11);
defaultUints.insert("TabOrder", tabOrderUint);
//font settings
QFont font("Lucida Console", 8, QFont::Normal, false);
@ -398,6 +417,9 @@ void Configuration::readUints()
void Configuration::writeUints()
{
duint setting;
bool bSaveLoadTabOrder = ConfigBool("Miscellaneous", "LoadSaveTabOrder");
//write config
for(int i = 0; i < Uints.size(); i++)
{
@ -406,6 +428,11 @@ void Configuration::writeUints()
for(int j = 0; j < currentUint->size(); j++)
{
QString id = (*currentUint).keys().at(j);
// Do not save settings to file if saveLoadTabOrder checkbox is Unchecked
if(!bSaveLoadTabOrder && category == "TabOrder" && BridgeSettingGetUint(category.toUtf8().constData(), id.toUtf8().constData(), &setting))
continue;
uintToConfig(category, id, (*currentUint)[id]);
}
}

View File

@ -2,6 +2,7 @@
ValidateExpressionThread::ValidateExpressionThread(QObject* parent) : QThread(parent), mExpressionChanged(false), mStopThread(false)
{
this->mOnExpressionChangedCallback = nullptr;
}
void ValidateExpressionThread::start(QString initialValue)
@ -16,6 +17,16 @@ void ValidateExpressionThread::stop()
mStopThread = true;
}
void ValidateExpressionThread::emitExpressionChanged(bool validExpression, bool validPointer, dsint value)
{
emit expressionChanged(validExpression, validPointer, value);
}
void ValidateExpressionThread::emitInstructionChanged(dsint sizeDifference, QString error)
{
emit instructionChanged(sizeDifference, error);
}
void ValidateExpressionThread::textChanged(QString text)
{
mExpressionMutex.lock();
@ -27,6 +38,11 @@ void ValidateExpressionThread::textChanged(QString text)
mExpressionMutex.unlock();
}
void ValidateExpressionThread::setOnExpressionChangedCallback(EXPRESSIONCHANGEDCB callback)
{
mOnExpressionChangedCallback = callback;
}
void ValidateExpressionThread::run()
{
while(!mStopThread)
@ -36,12 +52,9 @@ void ValidateExpressionThread::run()
bool changed = mExpressionChanged;
mExpressionChanged = false;
mExpressionMutex.unlock();
if(changed)
if(changed && mOnExpressionChangedCallback != nullptr)
{
duint value;
bool validExpression = DbgFunctions()->ValFromString(expression.toUtf8().constData(), &value);
bool validPointer = validExpression && DbgMemIsValidReadPtr(value);
emit expressionChanged(validExpression, validPointer, value);
mOnExpressionChangedCallback(expression);
}
Sleep(50);
}

View File

@ -3,8 +3,11 @@
#include <QThread>
#include <QMutex>
#include <functional>
#include "Imports.h"
typedef std::function<void(QString expression) > EXPRESSIONCHANGEDCB;
class ValidateExpressionThread : public QThread
{
Q_OBJECT
@ -12,18 +15,23 @@ public:
ValidateExpressionThread(QObject* parent = 0);
void start(QString initialValue = QString());
void stop();
void emitExpressionChanged(bool validExpression, bool validPointer, dsint value);
void emitInstructionChanged(dsint sizeDifference, QString error);
signals:
void expressionChanged(bool validExpression, bool validPointer, dsint value);
void instructionChanged(dsint sizeDifference, QString error);
public slots:
void textChanged(QString text);
void setOnExpressionChangedCallback(EXPRESSIONCHANGEDCB callback);
private:
QMutex mExpressionMutex;
QString mExpressionText;
bool mExpressionChanged;
volatile bool mStopThread;
EXPRESSIONCHANGEDCB mOnExpressionChangedCallback;
void run();
};

View File

@ -139,7 +139,8 @@ SOURCES += \
Src/Gui/EntropyDialog.cpp \
Src/Gui/NotesManager.cpp \
Src/Gui/NotepadView.cpp \
Src/Gui/CPUMultiDump.cpp
Src/Gui/CPUMultiDump.cpp \
Src/Gui/AssembleDialog.cpp
HEADERS += \
@ -220,7 +221,8 @@ HEADERS += \
Src/Gui/NotepadView.h \
Src/Utils/MenuBuilder.h \
Src/Utils/QActionLambda.h \
Src/Gui/CPUMultiDump.h
Src/Gui/CPUMultiDump.h \
Src/Gui/AssembleDialog.h
FORMS += \
Src/Gui/MainWindow.ui \
@ -245,7 +247,8 @@ FORMS += \
Src/Gui/SelectFields.ui \
Src/Gui/YaraRuleSelectionDialog.ui \
Src/Gui/DataCopyDialog.ui \
Src/Gui/EntropyDialog.ui
Src/Gui/EntropyDialog.ui \
Src/Gui/AssembleDialog.ui
##
## Libraries