Warn the user if the software breakpoint is not executable (#1010)
* Translate some strings and export memiscodepage. * fixed memory leaks in watch view * warn the user if the breakpoint is not executable * use dbgfunctions * remove unused exports * fix * fix
This commit is contained in:
parent
94e157c7dc
commit
c076aa583c
|
@ -24,4 +24,4 @@ DBGMEMISVALIDREADPTR _dbg_memisvalidreadptr;
|
|||
DBGGETBPLIST _dbg_getbplist;
|
||||
DBGDBGCMDEXECDIRECT _dbg_dbgcmddirectexec;
|
||||
DBGGETBRANCHDESTINATION _dbg_getbranchdestination;
|
||||
DBGSENDMESSAGE _dbg_sendmessage;
|
||||
DBGSENDMESSAGE _dbg_sendmessage;
|
|
@ -340,4 +340,5 @@ void dbgfunctionsinit()
|
|||
_dbgfunctions.GetHandleName = _gethandlename;
|
||||
_dbgfunctions.EnumTcpConnections = _enumtcpconnections;
|
||||
_dbgfunctions.GetDbgEvents = dbggetdbgevents;
|
||||
_dbgfunctions.MemIsCodePage = MemIsCodePage;
|
||||
}
|
||||
|
|
|
@ -144,7 +144,8 @@ typedef bool (*ENUMTCPCONNECTIONS)(ListOf(TCPCONNECTIONINFO) connections);
|
|||
typedef duint(*GETDBGEVENTS)();
|
||||
typedef int (*MODGETPARTY)(duint base);
|
||||
typedef void (*MODSETPARTY)(duint base, int party);
|
||||
typedef bool (*WATCHISWATCHDOGTRIGGERED)(unsigned int id);
|
||||
typedef bool(*WATCHISWATCHDOGTRIGGERED)(unsigned int id);
|
||||
typedef bool(*MEMISCODEPAGE)(duint addr, bool refresh);
|
||||
|
||||
typedef struct DBGFUNCTIONS_
|
||||
{
|
||||
|
@ -199,6 +200,7 @@ typedef struct DBGFUNCTIONS_
|
|||
MODGETPARTY ModGetParty;
|
||||
MODSETPARTY ModSetParty;
|
||||
WATCHISWATCHDOGTRIGGERED WatchIsWatchdogTriggered;
|
||||
MEMISCODEPAGE MemIsCodePage;
|
||||
} DBGFUNCTIONS;
|
||||
|
||||
#ifdef BUILD_DBG
|
||||
|
|
|
@ -86,10 +86,7 @@ extern "C" DLL_EXPORT bool _dbg_valfromstring(const char* string, duint* value)
|
|||
|
||||
extern "C" DLL_EXPORT bool _dbg_isdebugging()
|
||||
{
|
||||
if(IsFileBeingDebugged())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
return IsFileBeingDebugged();
|
||||
}
|
||||
|
||||
extern "C" DLL_EXPORT bool _dbg_isjumpgoingtoexecute(duint addr)
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
\brief x64dbg library instance.
|
||||
*/
|
||||
HINSTANCE hInst;
|
||||
//#define ENABLE_MEM_TRACE
|
||||
|
||||
/**
|
||||
\brief Number of allocated buffers by emalloc(). This should be 0 when x64dbg ends.
|
||||
|
@ -21,7 +20,8 @@ static int emalloc_count = 0;
|
|||
/**
|
||||
\brief Path for debugging, used to create an allocation trace file on emalloc() or efree(). Not used.
|
||||
*/
|
||||
static char alloctrace[MAX_PATH] = "memtrace.txt";
|
||||
static char alloctrace[MAX_PATH] = "";
|
||||
static std::map<void*, int> alloctracemap;
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
@ -33,21 +33,29 @@ static char alloctrace[MAX_PATH] = "memtrace.txt";
|
|||
void* emalloc(size_t size, const char* reason)
|
||||
{
|
||||
ASSERT_NONZERO(size);
|
||||
|
||||
#ifdef ENABLE_MEM_TRACE
|
||||
unsigned char* a = (unsigned char*)GlobalAlloc(GMEM_FIXED, size + sizeof(void*));
|
||||
#else
|
||||
unsigned char* a = (unsigned char*)GlobalAlloc(GMEM_FIXED, size);
|
||||
#endif //ENABLE_MEM_TRACE
|
||||
if(!a)
|
||||
{
|
||||
MessageBoxW(0, L"Could not allocate memory", L"Error", MB_ICONERROR);
|
||||
ExitProcess(1);
|
||||
}
|
||||
memset(a, 0, size);
|
||||
emalloc_count++;
|
||||
#ifdef ENABLE_MEM_TRACE
|
||||
memset(a, 0, size + sizeof(void*));
|
||||
FILE* file = fopen(alloctrace, "a+");
|
||||
fprintf(file, "DBG%.5d: alloc:%p:%s:%p\n", emalloc_count, a, reason, size);
|
||||
fprintf(file, "DBG%.5d: alloc:%p:%p:%s:%p\n", emalloc_count, a, _ReturnAddress(), reason, size);
|
||||
fclose(file);
|
||||
#endif //ENABLE_MEM_TRACE
|
||||
alloctracemap[_ReturnAddress()]++;
|
||||
*(void**)a = _ReturnAddress();
|
||||
return a + sizeof(void*);
|
||||
#else
|
||||
memset(a, 0, size);
|
||||
return a;
|
||||
#endif //ENABLE_MEM_TRACE
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -77,20 +85,45 @@ void efree(void* ptr, const char* reason)
|
|||
{
|
||||
emalloc_count--;
|
||||
#ifdef ENABLE_MEM_TRACE
|
||||
char* ptr2 = (char*)ptr - sizeof(void*);
|
||||
FILE* file = fopen(alloctrace, "a+");
|
||||
fprintf(file, "DBG%.5d: free:%p:%s\n", emalloc_count, ptr, reason);
|
||||
fprintf(file, "DBG%.5d: free:%p:%p:%s\n", emalloc_count, ptr, *(void**)ptr2, reason);
|
||||
fclose(file);
|
||||
#endif //ENABLE_MEM_TRACE
|
||||
if(alloctracemap.find(*(void**)ptr2) != alloctracemap.end())
|
||||
{
|
||||
if(--alloctracemap.at(*(void**)ptr2) < 0)
|
||||
{
|
||||
String str = StringUtils::sprintf("address %p, reason %s", *(void**)ptr2, reason);
|
||||
MessageBoxA(0, str.c_str, "Free memory more than once", MB_OK);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
String str = StringUtils::sprintf("address %p, reason %s", *(void**)ptr2, reason);
|
||||
MessageBoxA(0, str.c_str(), "Trying to free a const memory", MB_OK);
|
||||
}
|
||||
GlobalFree(ptr2);
|
||||
#else
|
||||
GlobalFree(ptr);
|
||||
#endif //ENABLE_MEM_TRACE
|
||||
}
|
||||
|
||||
void* json_malloc(size_t size)
|
||||
{
|
||||
#ifdef ENABLE_MEM_TRACE
|
||||
return emalloc(size, "json:ptr");
|
||||
#else
|
||||
return emalloc(size);
|
||||
#endif
|
||||
}
|
||||
|
||||
void json_free(void* ptr)
|
||||
{
|
||||
#ifdef ENABLE_MEM_TRACE
|
||||
return efree(ptr, "json:ptr");
|
||||
#else
|
||||
return efree(ptr);
|
||||
#endif
|
||||
efree(ptr, "json:ptr");
|
||||
}
|
||||
|
||||
|
@ -100,6 +133,16 @@ void json_free(void* ptr)
|
|||
*/
|
||||
int memleaks()
|
||||
{
|
||||
#ifdef ENABLE_MEM_TRACE
|
||||
for(auto & i : alloctracemap)
|
||||
{
|
||||
if(i.second != 0)
|
||||
{
|
||||
String str = StringUtils::sprintf("memory leak at %p : count %d", i.first, i.second);
|
||||
MessageBoxA(0, str.c_str(), "memory leaks", MB_OK);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return emalloc_count;
|
||||
}
|
||||
|
||||
|
|
|
@ -45,6 +45,8 @@
|
|||
#ifndef QT_TRANSLATE_NOOP
|
||||
#define QT_TRANSLATE_NOOP(context, source) source
|
||||
#endif //QT_TRANSLATE_NOOP
|
||||
// Uncomment the following line to allow memory leak tracing
|
||||
//#define ENABLE_MEM_TRACE
|
||||
|
||||
//defines
|
||||
#define deflen 1024
|
||||
|
@ -61,9 +63,15 @@ enum arch
|
|||
extern HINSTANCE hInst;
|
||||
|
||||
//functions
|
||||
#ifdef ENABLE_MEM_TRACE
|
||||
void* emalloc(size_t size, const char* reason = "emalloc:???");
|
||||
void* erealloc(void* ptr, size_t size, const char* reason = "erealloc:???");
|
||||
void efree(void* ptr, const char* reason = "efree:???");
|
||||
#else
|
||||
void* emalloc(size_t size, const char* reason = nullptr);
|
||||
void* erealloc(void* ptr, size_t size, const char* reason = nullptr);
|
||||
void efree(void* ptr, const char* reason = nullptr);
|
||||
#endif //ENABLE_MEM_TRACE
|
||||
void* json_malloc(size_t size);
|
||||
void json_free(void* ptr);
|
||||
int memleaks();
|
||||
|
|
|
@ -75,7 +75,7 @@ namespace Keystone
|
|||
ks_err err = ks_open(KS_ARCH_X86, XEDParse->x64 ? KS_MODE_64 : KS_MODE_32, &ks);
|
||||
if(err != KS_ERR_OK)
|
||||
{
|
||||
strcpy_s(XEDParse->error, "Failed on ks_open()...");
|
||||
strcpy_s(XEDParse->error, GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "Failed on ks_open()...")));
|
||||
return XEDPARSE_ERROR;
|
||||
}
|
||||
//ks_option(ks, KS_OPT_SYNTAX, KS_OPT_SYNTAX_INTEL);
|
||||
|
@ -85,7 +85,7 @@ namespace Keystone
|
|||
size_t count;
|
||||
if(ks_asm(ks, XEDParse->instr, XEDParse->cip, &encode, &size, &count) != KS_ERR_OK)
|
||||
{
|
||||
sprintf_s(XEDParse->error, "ks_asm() failed: count = %lu, error = %u", count, ks_errno(ks));
|
||||
sprintf_s(XEDParse->error, GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "ks_asm() failed: count = %lu, error = %u")), count, ks_errno(ks));
|
||||
result = XEDPARSE_ERROR;
|
||||
}
|
||||
else
|
||||
|
@ -216,7 +216,13 @@ bool assembleat(duint addr, const char* instruction, int* size, char* error, boo
|
|||
|
||||
// Check if the instruction doesn't set IP to non-executable memory
|
||||
if(!isInstructionPointingToExMemory(addr, dest()))
|
||||
GuiDisplayWarning("Non-executable memory region", "Assembled branch does not point to an executable memory region!");
|
||||
{
|
||||
String Title;
|
||||
String Text;
|
||||
Title = GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "Non-executable memory region"));
|
||||
Text = GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "Assembled branch does not point to an executable memory region!"));
|
||||
GuiDisplayWarning(Title.c_str(), Text.c_str());
|
||||
}
|
||||
|
||||
bool ret = MemPatch(addr, dest(), destSize);
|
||||
|
||||
|
@ -237,7 +243,7 @@ bool assembleat(duint addr, const char* instruction, int* size, char* error, boo
|
|||
else
|
||||
{
|
||||
// Tell the user writing is blocked
|
||||
strcpy_s(error, MAX_ERROR_SIZE, "Error while writing process memory");
|
||||
strcpy_s(error, MAX_ERROR_SIZE, GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "Error while writing process memory")));
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -1245,9 +1245,9 @@ static void cbCreateThread(CREATE_THREAD_DEBUG_INFO* CreateThread)
|
|||
|
||||
if(settingboolget("Events", "ThreadEntry"))
|
||||
{
|
||||
char command[256] = "";
|
||||
sprintf_s(command, "bp %p,\"Thread %X\",ss", (duint)CreateThread->lpStartAddress, dwThreadId);
|
||||
cmddirectexec(command);
|
||||
String command;
|
||||
command = StringUtils::sprintf("bp %p,\"%s %X\",ss", (duint)CreateThread->lpStartAddress, GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "Thread")), dwThreadId);
|
||||
cmddirectexec(command.c_str());
|
||||
}
|
||||
|
||||
PLUG_CB_CREATETHREAD callbackInfo;
|
||||
|
@ -1379,7 +1379,7 @@ static void cbLoadDll(LOAD_DLL_DEBUG_INFO* LoadDll)
|
|||
if(settingboolget("Events", "EntryBreakpoint"))
|
||||
{
|
||||
bAlreadySetEntry = true;
|
||||
sprintf_s(command, "bp %p,\"entry breakpoint\",ss", pDebuggedBase + pDebuggedEntry);
|
||||
sprintf_s(command, "bp %p,\"%s\",ss", pDebuggedBase + pDebuggedEntry, GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "entry breakpoint")));
|
||||
cmddirectexec(command);
|
||||
}
|
||||
}
|
||||
|
@ -1405,9 +1405,9 @@ static void cbLoadDll(LOAD_DLL_DEBUG_INFO* LoadDll)
|
|||
if(MemIsValidReadPtr(callbackVA))
|
||||
{
|
||||
if(bIsDebuggingThis)
|
||||
sprintf_s(command, "bp %p,\"TLS Callback %d\",ss", callbackVA, i + 1);
|
||||
sprintf_s(command, "bp %p,\"%s %d\",ss", callbackVA, GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "TLS Callback")), i + 1);
|
||||
else
|
||||
sprintf_s(command, "bp %p,\"TLS Callback %d (%s)\",ss", callbackVA, i + 1, modname);
|
||||
sprintf_s(command, "bp %p,\"%s %d (%s)\",ss", callbackVA, GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "TLS Callback")), i + 1, modname);
|
||||
cmddirectexec(command);
|
||||
}
|
||||
else
|
||||
|
|
|
@ -12,14 +12,18 @@ public:
|
|||
{
|
||||
m_Ptr = nullptr;
|
||||
m_Size = 0;
|
||||
#ifdef ENABLE_MEM_TRACE
|
||||
m_Reason = Reason;
|
||||
#endif //ENABLE_MEM_TRACE
|
||||
}
|
||||
|
||||
explicit Memory(size_t Size, const char* Reason = "Memory:???")
|
||||
{
|
||||
m_Ptr = reinterpret_cast<T>(emalloc(Size));
|
||||
m_Ptr = reinterpret_cast<T>(emalloc(Size, Reason));
|
||||
m_Size = Size;
|
||||
#ifdef ENABLE_MEM_TRACE
|
||||
m_Reason = Reason;
|
||||
#endif //ENABLE_MEM_TRACE
|
||||
|
||||
memset(m_Ptr, 0, Size);
|
||||
}
|
||||
|
@ -27,14 +31,20 @@ public:
|
|||
~Memory()
|
||||
{
|
||||
if(m_Ptr)
|
||||
#ifdef ENABLE_MEM_TRACE
|
||||
efree(m_Ptr, m_Reason);
|
||||
#else
|
||||
efree(m_Ptr);
|
||||
#endif //ENABLE_MEM_TRACE
|
||||
}
|
||||
|
||||
T realloc(size_t Size, const char* Reason = "Memory:???")
|
||||
{
|
||||
m_Ptr = reinterpret_cast<T>(erealloc(m_Ptr, Size));
|
||||
m_Ptr = reinterpret_cast<T>(erealloc(m_Ptr, Size, Reason));
|
||||
m_Size = Size;
|
||||
#ifdef ENABLE_MEM_TRACE
|
||||
m_Reason = Reason;
|
||||
#endif //ENABLE_MEM_TRACE
|
||||
|
||||
return (T)memset(m_Ptr, 0, m_Size);
|
||||
}
|
||||
|
@ -52,5 +62,7 @@ public:
|
|||
private:
|
||||
T m_Ptr;
|
||||
size_t m_Size;
|
||||
#ifdef ENABLE_MEM_TRACE
|
||||
const char* m_Reason;
|
||||
#endif //ENABLE_MEM_TRACE
|
||||
};
|
|
@ -681,7 +681,7 @@ bool MemDecodePointer(duint* Pointer, bool vistaPlus)
|
|||
OUT PULONG ReturnLength
|
||||
);
|
||||
|
||||
static auto NtQIP = (pfnNtQueryInformationProcess)GetProcAddress(GetModuleHandle("ntdll.dll"), "NtQueryInformationProcess");
|
||||
static auto NtQIP = (pfnNtQueryInformationProcess)GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "NtQueryInformationProcess");
|
||||
|
||||
// Verify
|
||||
if(!NtQIP || !Pointer)
|
||||
|
|
|
@ -350,6 +350,8 @@ void WatchCacheSave(JSON root)
|
|||
}
|
||||
if(json_array_size(watchroot))
|
||||
json_object_set(root, "watch", watchroot);
|
||||
|
||||
json_decref(watchroot);
|
||||
}
|
||||
|
||||
void WatchCacheLoad(JSON root)
|
||||
|
|
|
@ -462,12 +462,12 @@ extern "C" DLL_EXPORT const char* _dbg_dbginit()
|
|||
while(dir[len] != '\\')
|
||||
len--;
|
||||
dir[len] = 0;
|
||||
#ifdef ENABLE_MEM_TRACE
|
||||
strcpy_s(alloctrace, dir);
|
||||
strcat_s(alloctrace, "\\alloctrace.txt");
|
||||
strcpy_s(scriptDllDir, dir);
|
||||
strcat_s(scriptDllDir, "\\scripts\\");
|
||||
DeleteFileW(StringUtils::Utf8ToUtf16(alloctrace).c_str());
|
||||
#ifdef ENABLE_MEM_TRACE
|
||||
setalloctrace(alloctrace);
|
||||
#endif //ENABLE_MEM_TRACE
|
||||
initDataInstMap();
|
||||
|
|
|
@ -619,6 +619,16 @@ void CPUDisassembly::toggleInt3BPActionSlot()
|
|||
}
|
||||
else
|
||||
{
|
||||
if(!DbgFunctions()->MemIsCodePage(wVA, false))
|
||||
{
|
||||
QMessageBox msgyn(QMessageBox::Warning, tr("Current address is not executable"),
|
||||
tr("Setting software breakpoint here may result in crash. Do you really want to continue?"), QMessageBox::Yes | QMessageBox::No, this);
|
||||
msgyn.setWindowIcon(DIcon("compile-warning.png"));
|
||||
msgyn.setParent(this, Qt::Dialog);
|
||||
msgyn.setWindowFlags(msgyn.windowFlags() & (~Qt::WindowContextHelpButtonHint));
|
||||
if(msgyn.exec() == QMessageBox::No)
|
||||
return;
|
||||
}
|
||||
wCmd = "bp " + QString("%1").arg(wVA, sizeof(dsint) * 2, 16, QChar('0')).toUpper();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue