1
0
Fork 0

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:
Torusrxxx 2016-08-26 14:03:08 +00:00 committed by Duncan Ogilvie
parent 94e157c7dc
commit c076aa583c
13 changed files with 109 additions and 28 deletions

View File

@ -24,4 +24,4 @@ DBGMEMISVALIDREADPTR _dbg_memisvalidreadptr;
DBGGETBPLIST _dbg_getbplist;
DBGDBGCMDEXECDIRECT _dbg_dbgcmddirectexec;
DBGGETBRANCHDESTINATION _dbg_getbranchdestination;
DBGSENDMESSAGE _dbg_sendmessage;
DBGSENDMESSAGE _dbg_sendmessage;

View File

@ -340,4 +340,5 @@ void dbgfunctionsinit()
_dbgfunctions.GetHandleName = _gethandlename;
_dbgfunctions.EnumTcpConnections = _enumtcpconnections;
_dbgfunctions.GetDbgEvents = dbggetdbgevents;
_dbgfunctions.MemIsCodePage = MemIsCodePage;
}

View File

@ -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

View File

@ -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)

View File

@ -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;
}

View File

@ -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();

View File

@ -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;

View File

@ -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

View File

@ -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
};

View File

@ -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)

View File

@ -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)

View File

@ -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();

View File

@ -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();
}