commit
4eabd557af
|
|
@ -8,11 +8,13 @@ release/
|
|||
build/
|
||||
debug/
|
||||
*XE Results*/
|
||||
doxygen*/
|
||||
doc/
|
||||
|
||||
#global filetypes to ignore
|
||||
*.depend
|
||||
*.layout
|
||||
*.patch
|
||||
*.patch
|
||||
*.cscope_file_list
|
||||
*.bmarks
|
||||
*.chw
|
||||
|
|
@ -61,10 +63,16 @@ x64_dbg_gui/Project/Src/Bridge/libx32_bridge.a
|
|||
x64_dbg_gui/Project/Src/Bridge/libx64_bridge.a
|
||||
x64_dbg_gui/Project/Src/Bridge/x32_bridge.lib
|
||||
x64_dbg_gui/Project/Src/Bridge/x64_bridge.lib
|
||||
x64_dbg_gui/*/Makefile
|
||||
x64_dbg_gui/*/Makefile.Debug
|
||||
x64_dbg_gui/*/Makefile.Release
|
||||
tools/
|
||||
RCa*
|
||||
*.aps
|
||||
|
||||
# Intel performance guide
|
||||
*.ipgset
|
||||
|
||||
#exceptions
|
||||
!/AStyleWhore.exe
|
||||
!/AStyle.dll
|
||||
|
|
@ -1,9 +1,7 @@
|
|||
# x64_dbg
|
||||
|
||||
## Note
|
||||
**This is a new version of this repository. The old version can be found [here](https://bitbucket.org/mrexodia/x64_dbg_old).**
|
||||
|
||||
Also please run `install.bat` before you start committing code, this ensures your code is auto-formatted to the *x64_dbg* [standards](https://bitbucket.org/mrexodia/x64_dbg/wiki/x64_dbg_coding_guidelines).
|
||||
Please run `install.bat` before you start committing code, this ensures your code is auto-formatted to the *x64_dbg* [standards](https://bitbucket.org/mrexodia/x64_dbg/wiki/x64_dbg_coding_guidelines).
|
||||
|
||||
## Compiling
|
||||
For a complete guide on compiling *x64_dbg* read [this](https://bitbucket.org/mrexodia/x64_dbg/wiki/Compiling%20the%20whole%20project).
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ copy bin\x32\jansson.dll %RELEASEDIR%\bin_base\x32\jansson.dll
|
|||
copy bin\x32\lz4.dll %RELEASEDIR%\bin_base\x32\lz4.dll
|
||||
copy bin\x32\TitanEngine.dll %RELEASEDIR%\bin_base\x32\TitanEngine.dll
|
||||
copy bin\x32\XEDParse.dll %RELEASEDIR%\bin_base\x32\XEDParse.dll
|
||||
copy bin\x32\yara.dll %RELEASEDIR%\bin_base\x32\yara.dll
|
||||
copy bin\x64\BeaEngine.dll %RELEASEDIR%\bin_base\x64\BeaEngine.dll
|
||||
copy bin\x64\dbghelp.dll %RELEASEDIR%\bin_base\x64\dbghelp.dll
|
||||
copy bin\x64\symsrv.dll %RELEASEDIR%\bin_base\x64\symsrv.dll
|
||||
|
|
@ -40,6 +41,7 @@ copy bin\x64\jansson.dll %RELEASEDIR%\bin_base\x64\jansson.dll
|
|||
copy bin\x64\lz4.dll %RELEASEDIR%\bin_base\x64\lz4.dll
|
||||
copy bin\x64\TitanEngine.dll %RELEASEDIR%\bin_base\x64\TitanEngine.dll
|
||||
copy bin\x64\XEDParse.dll %RELEASEDIR%\bin_base\x64\XEDParse.dll
|
||||
copy bin\x64\yara.dll %RELEASEDIR%\bin_base\x64\yara.dll
|
||||
|
||||
echo help
|
||||
|
||||
|
|
@ -57,6 +59,8 @@ mkdir %RELEASEDIR%\pluginsdk\jansson
|
|||
mkdir %RELEASEDIR%\pluginsdk\lz4
|
||||
mkdir %RELEASEDIR%\pluginsdk\TitanEngine
|
||||
mkdir %RELEASEDIR%\pluginsdk\XEDParse
|
||||
mkdir %RELEASEDIR%\pluginsdk\yara
|
||||
mkdir %RELEASEDIR%\pluginsdk\yara\yara
|
||||
|
||||
xcopy x64_dbg_dbg\BeaEngine %RELEASEDIR%\pluginsdk\BeaEngine /S /Y
|
||||
xcopy x64_dbg_dbg\dbghelp %RELEASEDIR%\pluginsdk\dbghelp /S /Y
|
||||
|
|
@ -66,6 +70,7 @@ xcopy x64_dbg_dbg\lz4 %RELEASEDIR%\pluginsdk\lz4 /S /Y
|
|||
xcopy x64_dbg_dbg\TitanEngine %RELEASEDIR%\pluginsdk\TitanEngine /S /Y
|
||||
del %RELEASEDIR%\pluginsdk\TitanEngine\TitanEngine.txt /F /Q
|
||||
xcopy x64_dbg_dbg\XEDParse %RELEASEDIR%\pluginsdk\XEDParse /S /Y
|
||||
xcopy x64_dbg_dbg\yara %RELEASEDIR%\pluginsdk\yara /S /Y
|
||||
copy x64_dbg_dbg\_plugin_types.h %RELEASEDIR%\pluginsdk\_plugin_types.h
|
||||
copy x64_dbg_dbg\_plugins.h %RELEASEDIR%\pluginsdk\_plugins.h
|
||||
copy x64_dbg_dbg\_dbgfunctions.h %RELEASEDIR%\pluginsdk\_dbgfunctions.h
|
||||
|
|
|
|||
|
|
@ -0,0 +1,93 @@
|
|||
#include <stdio.h>
|
||||
#include <cstring>
|
||||
#include <stdint.h>
|
||||
|
||||
#define uint size_t
|
||||
#define PAGE_SIZE 0x1000
|
||||
|
||||
#ifdef _WIN64
|
||||
#define HIGHEST_USER_ADDR 0x7FFFFFEFFFF
|
||||
#else //x86
|
||||
#define HIGHEST_USER_ADDR 0x7FFEFFFF
|
||||
#endif // _WIN64
|
||||
|
||||
bool readblock(uint addr, unsigned char block[PAGE_SIZE])
|
||||
{
|
||||
printf("readblock(%X[%X])\n", addr, PAGE_SIZE);
|
||||
memset(block, 0xFF, PAGE_SIZE);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool memread(uint addr, unsigned char* data, uint size)
|
||||
{
|
||||
//check if the address is inside user space
|
||||
if(addr > HIGHEST_USER_ADDR)
|
||||
return false;
|
||||
|
||||
puts("-start-");
|
||||
printf(" addr: %X\n size: %X\n", addr, size);
|
||||
|
||||
//calculate the start page
|
||||
uint start = addr & ~(PAGE_SIZE - 1);
|
||||
printf(" start: %X\n", start);
|
||||
|
||||
//calculate the end page
|
||||
uint end = addr + size;
|
||||
uint x = end & (PAGE_SIZE - 1);
|
||||
if(x)
|
||||
end += (PAGE_SIZE - x);
|
||||
printf(" end: %X\n", end);
|
||||
|
||||
//calculate the number of pages to read
|
||||
uint npages = (end - start) / PAGE_SIZE;
|
||||
printf("npages: %d\n\n", npages);
|
||||
|
||||
//go over all pages
|
||||
for(uint i = 0, j = start; i < npages; i++)
|
||||
{
|
||||
//read one page (j should always align with PAGE_SIZE)
|
||||
unsigned char block[PAGE_SIZE];
|
||||
if(!readblock(j, block))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//these are the offsets and sizes in the block to write to append to the output buffer
|
||||
uint roffset = 0;
|
||||
uint rsize = PAGE_SIZE;
|
||||
|
||||
if(i == npages - 1) //last page (first because there might only be one page)
|
||||
{
|
||||
rsize = size - (j - start); //remaining size
|
||||
}
|
||||
else if(i == 0) //first page
|
||||
{
|
||||
roffset = addr & (PAGE_SIZE - 1);
|
||||
rsize = PAGE_SIZE - roffset;
|
||||
}
|
||||
|
||||
printf("roffset: %X\n rsize: %X\n", roffset, rsize);
|
||||
puts("");
|
||||
|
||||
//copy the required block data in the output buffer
|
||||
memcpy(data, block + roffset, rsize);
|
||||
data += rsize;
|
||||
|
||||
j += rsize;
|
||||
}
|
||||
|
||||
puts("--end--\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
unsigned char out[0x10000] = {0};
|
||||
memread(0x12A45, out, 0x3456);
|
||||
memread(0x12000, out, 0x456);
|
||||
memread(0x12000, out, 0x3456);
|
||||
memread(0x12000, out, 0x4000);
|
||||
memread(0x12ff0, out, 0x16);
|
||||
memread(0x100, out, 0x3090);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -33,10 +33,10 @@ Global
|
|||
{944D9923-CB1A-6F6C-BCBC-9E00A71954C1}.Release|Win32.Build.0 = Release|Win32
|
||||
{944D9923-CB1A-6F6C-BCBC-9E00A71954C1}.Release|x64.ActiveCfg = Release|x64
|
||||
{944D9923-CB1A-6F6C-BCBC-9E00A71954C1}.Release|x64.Build.0 = Release|x64
|
||||
{3A22175E-6B72-FDCC-1603-C4A2163C7900}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{3A22175E-6B72-FDCC-1603-C4A2163C7900}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{3A22175E-6B72-FDCC-1603-C4A2163C7900}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{3A22175E-6B72-FDCC-1603-C4A2163C7900}.Debug|x64.Build.0 = Debug|x64
|
||||
{3A22175E-6B72-FDCC-1603-C4A2163C7900}.Debug|Win32.ActiveCfg = Release|Win32
|
||||
{3A22175E-6B72-FDCC-1603-C4A2163C7900}.Debug|Win32.Build.0 = Release|Win32
|
||||
{3A22175E-6B72-FDCC-1603-C4A2163C7900}.Debug|x64.ActiveCfg = Release|x64
|
||||
{3A22175E-6B72-FDCC-1603-C4A2163C7900}.Debug|x64.Build.0 = Release|x64
|
||||
{3A22175E-6B72-FDCC-1603-C4A2163C7900}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{3A22175E-6B72-FDCC-1603-C4A2163C7900}.Release|Win32.Build.0 = Release|Win32
|
||||
{3A22175E-6B72-FDCC-1603-C4A2163C7900}.Release|x64.ActiveCfg = Release|x64
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
#include "_global.h"
|
||||
|
||||
//GUI functions
|
||||
GUIGUIINIT _gui_guiinit;
|
||||
GUISENDMESSAGE _gui_sendmessage;
|
||||
GUISENDMESSAGEASYNC _gui_sendmessageasync;
|
||||
|
||||
//DBG functions
|
||||
DBGDBGINIT _dbg_dbginit;
|
||||
DBGMEMFINDBASEADDR _dbg_memfindbaseaddr;
|
||||
DBGMEMREAD _dbg_memread;
|
||||
|
|
|
|||
|
|
@ -7,10 +7,12 @@
|
|||
//GUI typedefs
|
||||
typedef int (*GUIGUIINIT)(int, char**);
|
||||
typedef void* (*GUISENDMESSAGE)(GUIMSG type, void* param1, void* param2);
|
||||
typedef void (*GUISENDMESSAGEASYNC)(GUIMSG type, void* param1, void* param2);
|
||||
|
||||
//GUI functions
|
||||
extern GUIGUIINIT _gui_guiinit;
|
||||
extern GUISENDMESSAGE _gui_sendmessage;
|
||||
extern GUISENDMESSAGEASYNC _gui_sendmessageasync;
|
||||
|
||||
//DBG typedefs
|
||||
typedef const char* (*DBGDBGINIT)();
|
||||
|
|
@ -27,7 +29,7 @@ typedef bool (*DBGADDRINFOGET)(duint addr, SEGMENTREG segment, ADDRINFO* addrinf
|
|||
typedef bool (*DBGADDRINFOSET)(duint addr, ADDRINFO* addrinfo);
|
||||
typedef BPXTYPE (*DBGBPGETTYPEAT)(duint addr);
|
||||
typedef bool (*DBGGETREGDUMP)(REGDUMP* regdump);
|
||||
typedef bool (*DBGVALTOSTRING)(const char* string, duint* value);
|
||||
typedef bool (*DBGVALTOSTRING)(const char* string, duint value);
|
||||
typedef bool (*DBGMEMISVALIDREADPTR)(duint addr);
|
||||
typedef int (*DBGGETBPLIST)(BPXTYPE type, BPMAP* bplist);
|
||||
typedef bool (*DBGDBGCMDEXECDIRECT)(const char* cmd);
|
||||
|
|
|
|||
|
|
@ -1,9 +1,16 @@
|
|||
/**
|
||||
* \file bridgemain.cpp
|
||||
*
|
||||
* \brief Defines functions to initialize and start the Bridge and
|
||||
* to interface with the GUI and the DBG.
|
||||
*/
|
||||
#include "_global.h"
|
||||
#include "bridgemain.h"
|
||||
#include <stdio.h>
|
||||
#include "simpleini.h"
|
||||
|
||||
static HINSTANCE hInst;
|
||||
|
||||
static wchar_t szIniFile[MAX_PATH] = L"";
|
||||
static CRITICAL_SECTION csIni;
|
||||
|
||||
|
|
@ -29,7 +36,6 @@ static CRITICAL_SECTION csIni;
|
|||
return szError; \
|
||||
}
|
||||
|
||||
//Bridge
|
||||
BRIDGE_IMPEXP const char* BridgeInit()
|
||||
{
|
||||
//Initialize critial section
|
||||
|
|
@ -179,7 +185,6 @@ BRIDGE_IMPEXP int BridgeGetDbgVersion()
|
|||
return DBG_VERSION;
|
||||
}
|
||||
|
||||
//Debugger
|
||||
BRIDGE_IMPEXP bool DbgMemRead(duint va, unsigned char* dest, duint size)
|
||||
{
|
||||
if(IsBadWritePtr(dest, size))
|
||||
|
|
@ -203,6 +208,7 @@ BRIDGE_IMPEXP bool DbgMemWrite(duint va, const unsigned char* src, duint size)
|
|||
return _dbg_memwrite(va, src, size, 0);
|
||||
}
|
||||
|
||||
// FIXME, not exactly base if it still does a find?
|
||||
BRIDGE_IMPEXP duint DbgMemGetPageSize(duint base)
|
||||
{
|
||||
duint size = 0;
|
||||
|
|
@ -220,6 +226,7 @@ BRIDGE_IMPEXP bool DbgCmdExec(const char* cmd)
|
|||
return _dbg_dbgcmdexec(cmd);
|
||||
}
|
||||
|
||||
// FIXME
|
||||
BRIDGE_IMPEXP bool DbgMemMap(MEMMAP* memmap)
|
||||
{
|
||||
return _dbg_memmap(memmap);
|
||||
|
|
@ -241,6 +248,7 @@ BRIDGE_IMPEXP bool DbgIsJumpGoingToExecute(duint addr)
|
|||
return _dbg_isjumpgoingtoexecute(addr);
|
||||
}
|
||||
|
||||
// FIXME required size of arg _text_?
|
||||
BRIDGE_IMPEXP bool DbgGetLabelAt(duint addr, SEGMENTREG segment, char* text) //(module.)+label
|
||||
{
|
||||
if(!text || !addr)
|
||||
|
|
@ -276,6 +284,7 @@ BRIDGE_IMPEXP bool DbgSetLabelAt(duint addr, const char* text)
|
|||
return true;
|
||||
}
|
||||
|
||||
// FIXME required size of arg _text_?
|
||||
BRIDGE_IMPEXP bool DbgGetCommentAt(duint addr, char* text) //comment (not live)
|
||||
{
|
||||
if(!text || !addr)
|
||||
|
|
@ -302,6 +311,7 @@ BRIDGE_IMPEXP bool DbgSetCommentAt(duint addr, const char* text)
|
|||
return true;
|
||||
}
|
||||
|
||||
// FIXME required size of arg _text_?
|
||||
BRIDGE_IMPEXP bool DbgGetModuleAt(duint addr, char* text)
|
||||
{
|
||||
if(!text || !addr)
|
||||
|
|
@ -338,6 +348,7 @@ BRIDGE_IMPEXP bool DbgSetBookmarkAt(duint addr, bool isbookmark)
|
|||
return _dbg_addrinfoset(addr, &info);
|
||||
}
|
||||
|
||||
// FIXME return on success?
|
||||
BRIDGE_IMPEXP const char* DbgInit()
|
||||
{
|
||||
return _dbg_dbginit();
|
||||
|
|
@ -365,10 +376,10 @@ BRIDGE_IMPEXP bool DbgGetRegDump(REGDUMP* regdump)
|
|||
return _dbg_getregdump(regdump);
|
||||
}
|
||||
|
||||
// FIXME all
|
||||
BRIDGE_IMPEXP bool DbgValToString(const char* string, duint value)
|
||||
{
|
||||
duint valueCopy = value;
|
||||
return _dbg_valtostring(string, &valueCopy);
|
||||
return _dbg_valtostring(string, value);
|
||||
}
|
||||
|
||||
BRIDGE_IMPEXP bool DbgMemIsValidReadPtr(duint addr)
|
||||
|
|
@ -376,11 +387,13 @@ BRIDGE_IMPEXP bool DbgMemIsValidReadPtr(duint addr)
|
|||
return _dbg_memisvalidreadptr(addr);
|
||||
}
|
||||
|
||||
// FIXME return
|
||||
BRIDGE_IMPEXP int DbgGetBpList(BPXTYPE type, BPMAP* list)
|
||||
{
|
||||
return _dbg_getbplist(type, list);
|
||||
}
|
||||
|
||||
// FIXME all
|
||||
BRIDGE_IMPEXP bool DbgCmdExecDirect(const char* cmd)
|
||||
{
|
||||
return _dbg_dbgcmddirectexec(cmd);
|
||||
|
|
@ -404,6 +417,7 @@ BRIDGE_IMPEXP FUNCTYPE DbgGetFunctionTypeAt(duint addr)
|
|||
return FUNC_MIDDLE;
|
||||
}
|
||||
|
||||
// FIXME depth
|
||||
BRIDGE_IMPEXP LOOPTYPE DbgGetLoopTypeAt(duint addr, int depth)
|
||||
{
|
||||
ADDRINFO info;
|
||||
|
|
@ -431,11 +445,13 @@ BRIDGE_IMPEXP void DbgScriptLoad(const char* filename)
|
|||
_dbg_sendmessage(DBG_SCRIPT_LOAD, (void*)filename, 0);
|
||||
}
|
||||
|
||||
// FIXME every?
|
||||
BRIDGE_IMPEXP void DbgScriptUnload()
|
||||
{
|
||||
_dbg_sendmessage(DBG_SCRIPT_UNLOAD, 0, 0);
|
||||
}
|
||||
|
||||
// FIXME "the script?"; destline
|
||||
BRIDGE_IMPEXP void DbgScriptRun(int destline)
|
||||
{
|
||||
_dbg_sendmessage(DBG_SCRIPT_RUN, (void*)(duint)destline, 0);
|
||||
|
|
@ -482,11 +498,13 @@ BRIDGE_IMPEXP void DbgScriptSetIp(int line)
|
|||
_dbg_sendmessage(DBG_SCRIPT_SETIP, (void*)(duint)line, 0);
|
||||
}
|
||||
|
||||
// FIXME non-null?
|
||||
BRIDGE_IMPEXP bool DbgScriptGetBranchInfo(int line, SCRIPTBRANCH* info)
|
||||
{
|
||||
return !!_dbg_sendmessage(DBG_SCRIPT_GETBRANCHINFO, (void*)(duint)line, info);
|
||||
}
|
||||
|
||||
// FIXME all
|
||||
BRIDGE_IMPEXP void DbgSymbolEnum(duint base, CBSYMBOLENUM cbSymbolEnum, void* user)
|
||||
{
|
||||
SYMBOLCBINFO cbInfo;
|
||||
|
|
@ -538,7 +556,7 @@ BRIDGE_IMPEXP void DbgMenuEntryClicked(int hEntry)
|
|||
_dbg_sendmessage(DBG_MENU_ENTRY_CLICKED, (void*)(duint)hEntry, 0);
|
||||
}
|
||||
|
||||
|
||||
// FIXME not sure
|
||||
BRIDGE_IMPEXP bool DbgFunctionGet(duint addr, duint* start, duint* end)
|
||||
{
|
||||
FUNCTION_LOOP_INFO info;
|
||||
|
|
@ -550,6 +568,7 @@ BRIDGE_IMPEXP bool DbgFunctionGet(duint addr, duint* start, duint* end)
|
|||
return true;
|
||||
}
|
||||
|
||||
// FIXME brief, return
|
||||
BRIDGE_IMPEXP bool DbgFunctionOverlaps(duint start, duint end)
|
||||
{
|
||||
FUNCTION_LOOP_INFO info;
|
||||
|
|
@ -560,6 +579,7 @@ BRIDGE_IMPEXP bool DbgFunctionOverlaps(duint start, duint end)
|
|||
return true;
|
||||
}
|
||||
|
||||
// FIXME brief, return
|
||||
BRIDGE_IMPEXP bool DbgFunctionAdd(duint start, duint end)
|
||||
{
|
||||
FUNCTION_LOOP_INFO info;
|
||||
|
|
@ -571,6 +591,7 @@ BRIDGE_IMPEXP bool DbgFunctionAdd(duint start, duint end)
|
|||
return true;
|
||||
}
|
||||
|
||||
// FIXME brief, return
|
||||
BRIDGE_IMPEXP bool DbgFunctionDel(duint addr)
|
||||
{
|
||||
FUNCTION_LOOP_INFO info;
|
||||
|
|
@ -580,6 +601,7 @@ BRIDGE_IMPEXP bool DbgFunctionDel(duint addr)
|
|||
return true;
|
||||
}
|
||||
|
||||
// FIXME depth
|
||||
BRIDGE_IMPEXP bool DbgLoopGet(int depth, duint addr, duint* start, duint* end)
|
||||
{
|
||||
FUNCTION_LOOP_INFO info;
|
||||
|
|
@ -592,6 +614,7 @@ BRIDGE_IMPEXP bool DbgLoopGet(int depth, duint addr, duint* start, duint* end)
|
|||
return true;
|
||||
}
|
||||
|
||||
// FIXME brief, depth, return
|
||||
BRIDGE_IMPEXP bool DbgLoopOverlaps(int depth, duint start, duint end)
|
||||
{
|
||||
FUNCTION_LOOP_INFO info;
|
||||
|
|
@ -603,6 +626,7 @@ BRIDGE_IMPEXP bool DbgLoopOverlaps(int depth, duint start, duint end)
|
|||
return true;
|
||||
}
|
||||
|
||||
// FIXME brief, return
|
||||
BRIDGE_IMPEXP bool DbgLoopAdd(duint start, duint end)
|
||||
{
|
||||
FUNCTION_LOOP_INFO info;
|
||||
|
|
@ -614,6 +638,7 @@ BRIDGE_IMPEXP bool DbgLoopAdd(duint start, duint end)
|
|||
return true;
|
||||
}
|
||||
|
||||
// FIXME brief, brief
|
||||
BRIDGE_IMPEXP bool DbgLoopDel(int depth, duint addr)
|
||||
{
|
||||
FUNCTION_LOOP_INFO info;
|
||||
|
|
@ -624,6 +649,7 @@ BRIDGE_IMPEXP bool DbgLoopDel(int depth, duint addr)
|
|||
return true;
|
||||
}
|
||||
|
||||
// FIXME all
|
||||
BRIDGE_IMPEXP bool DbgIsRunLocked()
|
||||
{
|
||||
if(_dbg_sendmessage(DBG_IS_RUN_LOCKED, 0, 0))
|
||||
|
|
@ -645,6 +671,7 @@ BRIDGE_IMPEXP bool DbgSetAutoCommentAt(duint addr, const char* text)
|
|||
return false;
|
||||
}
|
||||
|
||||
// FIXME brief
|
||||
BRIDGE_IMPEXP void DbgClearAutoCommentRange(duint start, duint end)
|
||||
{
|
||||
_dbg_sendmessage(DBG_DELETE_AUTO_COMMENT_RANGE, (void*)start, (void*)end);
|
||||
|
|
@ -657,6 +684,7 @@ BRIDGE_IMPEXP bool DbgSetAutoLabelAt(duint addr, const char* text)
|
|||
return false;
|
||||
}
|
||||
|
||||
// FIXME brief
|
||||
BRIDGE_IMPEXP void DbgClearAutoLabelRange(duint start, duint end)
|
||||
{
|
||||
_dbg_sendmessage(DBG_DELETE_AUTO_LABEL_RANGE, (void*)start, (void*)end);
|
||||
|
|
@ -669,6 +697,7 @@ BRIDGE_IMPEXP bool DbgSetAutoBookmarkAt(duint addr)
|
|||
return false;
|
||||
}
|
||||
|
||||
// FIXME brief
|
||||
BRIDGE_IMPEXP void DbgClearAutoBookmarkRange(duint start, duint end)
|
||||
{
|
||||
_dbg_sendmessage(DBG_DELETE_AUTO_BOOKMARK_RANGE, (void*)start, (void*)end);
|
||||
|
|
@ -681,11 +710,13 @@ BRIDGE_IMPEXP bool DbgSetAutoFunctionAt(duint start, duint end)
|
|||
return false;
|
||||
}
|
||||
|
||||
// FIXME brief
|
||||
BRIDGE_IMPEXP void DbgClearAutoFunctionRange(duint start, duint end)
|
||||
{
|
||||
_dbg_sendmessage(DBG_DELETE_AUTO_FUNCTION_RANGE, (void*)start, (void*)end);
|
||||
}
|
||||
|
||||
// FIXME size of the buffer?
|
||||
BRIDGE_IMPEXP bool DbgGetStringAt(duint addr, char* text)
|
||||
{
|
||||
if(_dbg_sendmessage(DBG_GET_STRING_AT, (void*)addr, text))
|
||||
|
|
@ -693,11 +724,13 @@ BRIDGE_IMPEXP bool DbgGetStringAt(duint addr, char* text)
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP const DBGFUNCTIONS* DbgFunctions()
|
||||
{
|
||||
return (const DBGFUNCTIONS*)_dbg_sendmessage(DBG_GET_FUNCTIONS, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP bool DbgWinEvent(MSG* message, long* result)
|
||||
{
|
||||
if(_dbg_sendmessage(DBG_WIN_EVENT, message, result))
|
||||
|
|
@ -705,6 +738,7 @@ BRIDGE_IMPEXP bool DbgWinEvent(MSG* message, long* result)
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP bool DbgWinEventGlobal(MSG* message)
|
||||
{
|
||||
if(_dbg_sendmessage(DBG_WIN_EVENT_GLOBAL, message, 0))
|
||||
|
|
@ -712,27 +746,31 @@ BRIDGE_IMPEXP bool DbgWinEventGlobal(MSG* message)
|
|||
return false;
|
||||
}
|
||||
|
||||
//GUI
|
||||
|
||||
BRIDGE_IMPEXP void GuiDisasmAt(duint addr, duint cip)
|
||||
{
|
||||
_gui_sendmessage(GUI_DISASSEMBLE_AT, (void*)addr, (void*)cip);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP void GuiSetDebugState(DBGSTATE state)
|
||||
{
|
||||
_gui_sendmessage(GUI_SET_DEBUG_STATE, (void*)state, 0);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP void GuiAddLogMessage(const char* msg)
|
||||
{
|
||||
_gui_sendmessage(GUI_ADD_MSG_TO_LOG, (void*)msg, 0);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP void GuiLogClear()
|
||||
{
|
||||
_gui_sendmessage(GUI_CLEAR_LOG, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP void GuiUpdateAllViews()
|
||||
{
|
||||
GuiUpdateRegisterView();
|
||||
|
|
@ -744,121 +782,145 @@ BRIDGE_IMPEXP void GuiUpdateAllViews()
|
|||
GuiRepaintTableView();
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP void GuiUpdateRegisterView()
|
||||
{
|
||||
_gui_sendmessage(GUI_UPDATE_REGISTER_VIEW, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP void GuiUpdateDisassemblyView()
|
||||
{
|
||||
_gui_sendmessage(GUI_UPDATE_DISASSEMBLY_VIEW, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP void GuiUpdateBreakpointsView()
|
||||
{
|
||||
_gui_sendmessage(GUI_UPDATE_BREAKPOINTS_VIEW, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP void GuiUpdateWindowTitle(const char* filename)
|
||||
{
|
||||
_gui_sendmessage(GUI_UPDATE_WINDOW_TITLE, (void*)filename, 0);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP HWND GuiGetWindowHandle()
|
||||
{
|
||||
return (HWND)_gui_sendmessage(GUI_GET_WINDOW_HANDLE, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP void GuiDumpAt(duint va)
|
||||
{
|
||||
_gui_sendmessage(GUI_DUMP_AT, (void*)va, 0);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP void GuiScriptAdd(int count, const char** lines)
|
||||
{
|
||||
_gui_sendmessage(GUI_SCRIPT_ADD, (void*)(duint)count, (void*)lines);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP void GuiScriptClear()
|
||||
{
|
||||
_gui_sendmessage(GUI_SCRIPT_CLEAR, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP void GuiScriptSetIp(int line)
|
||||
{
|
||||
_gui_sendmessage(GUI_SCRIPT_SETIP, (void*)(duint)line, 0);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP void GuiScriptError(int line, const char* message)
|
||||
{
|
||||
_gui_sendmessage(GUI_SCRIPT_ERROR, (void*)(duint)line, (void*)message);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP void GuiScriptSetTitle(const char* title)
|
||||
{
|
||||
_gui_sendmessage(GUI_SCRIPT_SETTITLE, (void*)title, 0);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP void GuiScriptSetInfoLine(int line, const char* info)
|
||||
{
|
||||
_gui_sendmessage(GUI_SCRIPT_SETINFOLINE, (void*)(duint)line, (void*)info);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP void GuiScriptMessage(const char* message)
|
||||
{
|
||||
_gui_sendmessage(GUI_SCRIPT_MESSAGE, (void*)message, 0);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP int GuiScriptMsgyn(const char* message)
|
||||
{
|
||||
return (int)(duint)_gui_sendmessage(GUI_SCRIPT_MSGYN, (void*)message, 0);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP void GuiScriptEnableHighlighting(bool enable)
|
||||
{
|
||||
_gui_sendmessage(GUI_SCRIPT_ENABLEHIGHLIGHTING, (void*)(duint)enable, 0);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP void GuiSymbolLogAdd(const char* message)
|
||||
{
|
||||
_gui_sendmessage(GUI_SYMBOL_LOG_ADD, (void*)message, 0);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP void GuiSymbolLogClear()
|
||||
{
|
||||
_gui_sendmessage(GUI_SYMBOL_LOG_CLEAR, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP void GuiSymbolSetProgress(int percent)
|
||||
{
|
||||
_gui_sendmessage(GUI_SYMBOL_SET_PROGRESS, (void*)(duint)percent, 0);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP void GuiSymbolUpdateModuleList(int count, SYMBOLMODULEINFO* modules)
|
||||
{
|
||||
_gui_sendmessage(GUI_SYMBOL_UPDATE_MODULE_LIST, (void*)(duint)count, (void*)modules);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP void GuiReferenceAddColumn(int width, const char* title)
|
||||
{
|
||||
_gui_sendmessage(GUI_REF_ADDCOLUMN, (void*)(duint)width, (void*)title);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP void GuiSymbolRefreshCurrent()
|
||||
{
|
||||
_gui_sendmessage(GUI_SYMBOL_REFRESH_CURRENT, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP void GuiReferenceSetRowCount(int count)
|
||||
{
|
||||
_gui_sendmessage(GUI_REF_SETROWCOUNT, (void*)(duint)count, 0);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP int GuiReferenceGetRowCount()
|
||||
{
|
||||
return (int)(duint)_gui_sendmessage(GUI_REF_GETROWCOUNT, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP void GuiReferenceDeleteAllColumns()
|
||||
{
|
||||
_gui_sendmessage(GUI_REF_DELETEALLCOLUMNS, 0, 0);
|
||||
|
|
@ -878,142 +940,173 @@ BRIDGE_IMPEXP void GuiReferenceSetCellContent(int row, int col, const char* str)
|
|||
_gui_sendmessage(GUI_REF_SETCELLCONTENT, &info, 0);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP const char* GuiReferenceGetCellContent(int row, int col)
|
||||
{
|
||||
return (const char*)_gui_sendmessage(GUI_REF_GETCELLCONTENT, (void*)(duint)row, (void*)(duint)col);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP void GuiReferenceReloadData()
|
||||
{
|
||||
_gui_sendmessage(GUI_REF_RELOADDATA, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP void GuiReferenceSetSingleSelection(int index, bool scroll)
|
||||
{
|
||||
_gui_sendmessage(GUI_REF_SETSINGLESELECTION, (void*)(duint)index, (void*)(duint)scroll);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP void GuiReferenceSetProgress(int progress)
|
||||
{
|
||||
_gui_sendmessage(GUI_REF_SETPROGRESS, (void*)(duint)progress, 0);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP void GuiReferenceSetSearchStartCol(int col)
|
||||
{
|
||||
_gui_sendmessage(GUI_REF_SETSEARCHSTARTCOL, (void*)(duint)col, 0);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP void GuiStackDumpAt(duint addr, duint csp)
|
||||
{
|
||||
_gui_sendmessage(GUI_STACK_DUMP_AT, (void*)addr, (void*)csp);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP void GuiUpdateDumpView()
|
||||
{
|
||||
_gui_sendmessage(GUI_UPDATE_DUMP_VIEW, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP void GuiUpdateMemoryView()
|
||||
{
|
||||
_gui_sendmessage(GUI_UPDATE_MEMORY_VIEW, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP void GuiUpdateThreadView()
|
||||
{
|
||||
_gui_sendmessage(GUI_UPDATE_THREAD_VIEW, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP void GuiAddRecentFile(const char* file)
|
||||
{
|
||||
_gui_sendmessage(GUI_ADD_RECENT_FILE, (void*)file, 0);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP void GuiSetLastException(unsigned int exception)
|
||||
{
|
||||
_gui_sendmessage(GUI_SET_LAST_EXCEPTION, (void*)(duint)exception, 0);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP bool GuiGetDisassembly(duint addr, char* text)
|
||||
{
|
||||
return !!_gui_sendmessage(GUI_GET_DISASSEMBLY, (void*)addr, text);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP int GuiMenuAdd(int hMenu, const char* title)
|
||||
{
|
||||
return (int)(duint)_gui_sendmessage(GUI_MENU_ADD, (void*)(duint)hMenu, (void*)title);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP int GuiMenuAddEntry(int hMenu, const char* title)
|
||||
{
|
||||
return (int)(duint)_gui_sendmessage(GUI_MENU_ADD_ENTRY, (void*)(duint)hMenu, (void*)title);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP void GuiMenuAddSeparator(int hMenu)
|
||||
{
|
||||
_gui_sendmessage(GUI_MENU_ADD_SEPARATOR, (void*)(duint)hMenu, 0);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP void GuiMenuClear(int hMenu)
|
||||
{
|
||||
_gui_sendmessage(GUI_MENU_CLEAR, (void*)(duint)hMenu, 0);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP bool GuiSelectionGet(int hWindow, SELECTIONDATA* selection)
|
||||
{
|
||||
return !!_gui_sendmessage(GUI_SELECTION_GET, (void*)(duint)hWindow, selection);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP bool GuiSelectionSet(int hWindow, const SELECTIONDATA* selection)
|
||||
{
|
||||
return !!_gui_sendmessage(GUI_SELECTION_SET, (void*)(duint)hWindow, (void*)selection);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP bool GuiGetLineWindow(const char* title, char* text)
|
||||
{
|
||||
return !!_gui_sendmessage(GUI_GETLINE_WINDOW, (void*)title, text);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP void GuiAutoCompleteAddCmd(const char* cmd)
|
||||
{
|
||||
_gui_sendmessage(GUI_AUTOCOMPLETE_ADDCMD, (void*)cmd, 0);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP void GuiAutoCompleteDelCmd(const char* cmd)
|
||||
{
|
||||
_gui_sendmessage(GUI_AUTOCOMPLETE_DELCMD, (void*)cmd, 0);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP void GuiAutoCompleteClearAll()
|
||||
{
|
||||
_gui_sendmessage(GUI_AUTOCOMPLETE_CLEARALL, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP void GuiAddStatusBarMessage(const char* msg)
|
||||
{
|
||||
_gui_sendmessage(GUI_ADD_MSG_TO_STATUSBAR, (void*)msg, 0);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP void GuiUpdateSideBar()
|
||||
{
|
||||
_gui_sendmessage(GUI_UPDATE_SIDEBAR, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP void GuiRepaintTableView()
|
||||
{
|
||||
_gui_sendmessage(GUI_REPAINT_TABLE_VIEW, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP void GuiUpdatePatches()
|
||||
{
|
||||
_gui_sendmessage(GUI_UPDATE_PATCHES, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
BRIDGE_IMPEXP void GuiUpdateCallStack()
|
||||
{
|
||||
_gui_sendmessage(GUI_UPDATE_CALLSTACK, 0, 0);
|
||||
}
|
||||
|
||||
//Main
|
||||
BRIDGE_IMPEXP void GuiLoadSourceFile(const char* path, int line)
|
||||
{
|
||||
_gui_sendmessage(GUI_LOAD_SOURCE_FILE, (void*)path, (void*)line);
|
||||
}
|
||||
|
||||
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
|
||||
{
|
||||
hInst = hinstDLL;
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ extern "C"
|
|||
|
||||
//Bridge defines
|
||||
#define MAX_SETTING_SIZE 65536
|
||||
#define DBG_VERSION 24
|
||||
#define DBG_VERSION 25
|
||||
|
||||
//Bridge functions
|
||||
BRIDGE_IMPEXP const char* BridgeInit();
|
||||
|
|
@ -501,6 +501,12 @@ typedef struct
|
|||
#endif
|
||||
} REGISTERCONTEXT;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
DWORD code;
|
||||
const char* name;
|
||||
} LASTERROR;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
REGISTERCONTEXT regcontext;
|
||||
|
|
@ -510,6 +516,7 @@ typedef struct
|
|||
MXCSRFIELDS MxCsrFields;
|
||||
X87STATUSWORDFIELDS x87StatusWordFields;
|
||||
X87CONTROLWORDFIELDS x87ControlWordFields;
|
||||
LASTERROR lastError;
|
||||
} REGDUMP;
|
||||
|
||||
typedef struct
|
||||
|
|
@ -749,7 +756,8 @@ typedef enum
|
|||
GUI_UPDATE_CALLSTACK, // param1=unused, param2=unused
|
||||
GUI_SYMBOL_REFRESH_CURRENT, // param1=unused, param2=unused
|
||||
GUI_UPDATE_MEMORY_VIEW, // param1=unused, param2=unused
|
||||
GUI_REF_INITIALIZE // param1=const char* name param2=unused
|
||||
GUI_REF_INITIALIZE, // param1=const char* name, param2=unused
|
||||
GUI_LOAD_SOURCE_FILE // param1=const char* path, param2=line
|
||||
} GUIMSG;
|
||||
|
||||
//GUI structures
|
||||
|
|
@ -826,6 +834,7 @@ BRIDGE_IMPEXP void GuiRepaintTableView();
|
|||
BRIDGE_IMPEXP void GuiUpdatePatches();
|
||||
BRIDGE_IMPEXP void GuiUpdateCallStack();
|
||||
BRIDGE_IMPEXP void GuiUpdateMemoryView();
|
||||
BRIDGE_IMPEXP void GuiLoadSourceFile(const char* path, int line);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,10 +9,6 @@
|
|||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="_global.cpp">
|
||||
|
|
|
|||
|
|
@ -1,3 +1,9 @@
|
|||
/**
|
||||
@file _dbgfunctions.cpp
|
||||
|
||||
@brief Implements the dbgfunctions class.
|
||||
*/
|
||||
|
||||
#include "_global.h"
|
||||
#include "_dbgfunctions.h"
|
||||
#include "assemble.h"
|
||||
|
|
@ -19,7 +25,7 @@ const DBGFUNCTIONS* dbgfunctionsget()
|
|||
|
||||
static bool _assembleatex(duint addr, const char* instruction, char* error, bool fillnop)
|
||||
{
|
||||
return assembleat(addr, instruction, 0, error, fillnop);
|
||||
return assembleat(addr, instruction, nullptr, error, fillnop);
|
||||
}
|
||||
|
||||
static bool _sectionfromaddr(duint addr, char* section)
|
||||
|
|
@ -53,44 +59,42 @@ static bool _sectionfromaddr(duint addr, char* section)
|
|||
|
||||
static bool _patchget(duint addr)
|
||||
{
|
||||
return patchget(addr, 0);
|
||||
return PatchGet(addr, nullptr);
|
||||
}
|
||||
|
||||
static bool _patchinrange(duint start, duint end)
|
||||
{
|
||||
if(start > end)
|
||||
std::swap(start, end);
|
||||
|
||||
for (duint i = start; i <= end; i++)
|
||||
{
|
||||
duint a = start;
|
||||
start = end;
|
||||
end = a;
|
||||
}
|
||||
for(duint i = start; i < end + 1; i++)
|
||||
if(_patchget(i))
|
||||
if (_patchget(i))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool _mempatch(duint va, const unsigned char* src, duint size)
|
||||
{
|
||||
return MemPatch((void*)va, (void*)src, size, 0);
|
||||
return MemPatch((void*)va, (void*)src, size, nullptr);
|
||||
}
|
||||
|
||||
static void _patchrestorerange(duint start, duint end)
|
||||
{
|
||||
if(start > end)
|
||||
{
|
||||
duint a = start;
|
||||
start = end;
|
||||
end = a;
|
||||
}
|
||||
for(duint i = start; i < end + 1; i++)
|
||||
patchdel(i, true);
|
||||
if (start > end)
|
||||
std::swap(start, end);
|
||||
|
||||
for(duint i = start; i <= end; i++)
|
||||
PatchDelete(i, true);
|
||||
|
||||
GuiUpdatePatches();
|
||||
}
|
||||
|
||||
static bool _patchrestore(duint addr)
|
||||
{
|
||||
return patchdel(addr, true);
|
||||
return PatchDelete(addr, true);
|
||||
}
|
||||
|
||||
static void _getcallstack(DBGCALLSTACK* callstack)
|
||||
|
|
@ -120,7 +124,7 @@ static bool _getcmdline(char* cmd_line, size_t* cbsize)
|
|||
|
||||
static bool _setcmdline(const char* cmd_line)
|
||||
{
|
||||
return dbgsetcmdline(cmd_line, NULL);
|
||||
return dbgsetcmdline(cmd_line, nullptr);
|
||||
}
|
||||
|
||||
static bool _getjit(char* jit, bool jit64)
|
||||
|
|
@ -178,9 +182,9 @@ void dbgfunctionsinit()
|
|||
_dbgfunctions.PatchInRange = _patchinrange;
|
||||
_dbgfunctions.MemPatch = _mempatch;
|
||||
_dbgfunctions.PatchRestoreRange = _patchrestorerange;
|
||||
_dbgfunctions.PatchEnum = (PATCHENUM)patchenum;
|
||||
_dbgfunctions.PatchEnum = (PATCHENUM)PatchEnum;
|
||||
_dbgfunctions.PatchRestore = _patchrestore;
|
||||
_dbgfunctions.PatchFile = (PATCHFILE)patchfile;
|
||||
_dbgfunctions.PatchFile = (PATCHFILE)PatchFile;
|
||||
_dbgfunctions.ModPathFromAddr = ModPathFromAddr;
|
||||
_dbgfunctions.ModPathFromName = ModPathFromName;
|
||||
_dbgfunctions.DisasmFast = disasmfast;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,9 @@
|
|||
/**
|
||||
@file _exports.cpp
|
||||
|
||||
@brief Implements the exports class.
|
||||
*/
|
||||
|
||||
#include "_exports.h"
|
||||
#include "memory.h"
|
||||
#include "debugger.h"
|
||||
|
|
@ -21,6 +27,7 @@
|
|||
#include "bookmark.h"
|
||||
#include "function.h"
|
||||
#include "loop.h"
|
||||
#include "error.h"
|
||||
|
||||
static bool bOnlyCipAutoComments = false;
|
||||
|
||||
|
|
@ -47,11 +54,17 @@ extern "C" DLL_EXPORT bool _dbg_memmap(MEMMAP* memmap)
|
|||
memmap->count = pagecount;
|
||||
if(!pagecount)
|
||||
return true;
|
||||
|
||||
// Allocate memory that is already zeroed
|
||||
memmap->page = (MEMPAGE*)BridgeAlloc(sizeof(MEMPAGE) * pagecount);
|
||||
memset(memmap->page, 0, sizeof(MEMPAGE)*pagecount);
|
||||
int j = 0;
|
||||
for(MemoryMap::iterator i = memoryPages.begin(); i != memoryPages.end(); ++i, j++)
|
||||
memcpy(&memmap->page[j], &i->second, sizeof(MEMPAGE));
|
||||
|
||||
// Copy all elements over
|
||||
int i = 0;
|
||||
|
||||
for (auto& itr : memoryPages)
|
||||
memcpy(&memmap->page[i++], &itr.second, sizeof(MEMPAGE));
|
||||
|
||||
// Done
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -99,7 +112,7 @@ extern "C" DLL_EXPORT bool _dbg_addrinfoget(duint addr, SEGMENTREG segment, ADDR
|
|||
}
|
||||
if(addrinfo->flags & flaglabel)
|
||||
{
|
||||
if(labelget(addr, addrinfo->label))
|
||||
if(LabelGet(addr, addrinfo->label))
|
||||
retval = true;
|
||||
else //no user labels
|
||||
{
|
||||
|
|
@ -148,7 +161,7 @@ extern "C" DLL_EXPORT bool _dbg_addrinfoget(duint addr, SEGMENTREG segment, ADDR
|
|||
}
|
||||
if(addrinfo->flags & flagloop)
|
||||
{
|
||||
if(loopget(addrinfo->loop.depth, addr, &addrinfo->loop.start, &addrinfo->loop.end))
|
||||
if(LoopGet(addrinfo->loop.depth, addr, &addrinfo->loop.start, &addrinfo->loop.end))
|
||||
retval = true;
|
||||
}
|
||||
if(addrinfo->flags & flagcomment)
|
||||
|
|
@ -295,7 +308,7 @@ extern "C" DLL_EXPORT bool _dbg_addrinfoset(duint addr, ADDRINFO* addrinfo)
|
|||
bool retval = false;
|
||||
if(addrinfo->flags & flaglabel) //set label
|
||||
{
|
||||
if(labelset(addr, addrinfo->label, true))
|
||||
if(LabelSet(addr, addrinfo->label, true))
|
||||
retval = true;
|
||||
}
|
||||
if(addrinfo->flags & flagcomment) //set comment
|
||||
|
|
@ -490,11 +503,15 @@ extern "C" DLL_EXPORT bool _dbg_getregdump(REGDUMP* regdump)
|
|||
GetMxCsrFields(& (regdump->MxCsrFields), regdump->regcontext.MxCsr);
|
||||
Getx87ControlWordFields(& (regdump->x87ControlWordFields), regdump->regcontext.x87fpu.ControlWord);
|
||||
Getx87StatusWordFields(& (regdump->x87StatusWordFields), regdump->regcontext.x87fpu.StatusWord);
|
||||
LASTERROR lastError;
|
||||
lastError.code = ThreadGetLastError(ThreadGetId(hActiveThread));
|
||||
lastError.name = ErrorCodeToName(lastError.code);
|
||||
regdump->lastError = lastError;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
extern "C" DLL_EXPORT bool _dbg_valtostring(const char* string, duint* value)
|
||||
extern "C" DLL_EXPORT bool _dbg_valtostring(const char* string, duint value)
|
||||
{
|
||||
return valtostring(string, value, true);
|
||||
}
|
||||
|
|
@ -731,6 +748,7 @@ extern "C" DLL_EXPORT uint _dbg_sendmessage(DBGMSG type, void* param1, void* par
|
|||
bOnlyCipAutoComments = settingboolget("Disassembler", "OnlyCipAutoComments");
|
||||
bListAllPages = settingboolget("Engine", "ListAllPages");
|
||||
bUndecorateSymbolNames = settingboolget("Engine", "UndecorateSymbolNames");
|
||||
bEnableSourceDebugging = settingboolget("Engine", "EnableSourceDebugging");
|
||||
|
||||
uint setting;
|
||||
if(BridgeSettingGetUint("Engine", "BreakpointType", &setting))
|
||||
|
|
@ -833,28 +851,28 @@ extern "C" DLL_EXPORT uint _dbg_sendmessage(DBGMSG type, void* param1, void* par
|
|||
case DBG_LOOP_GET:
|
||||
{
|
||||
FUNCTION_LOOP_INFO* info = (FUNCTION_LOOP_INFO*)param1;
|
||||
return (uint)loopget(info->depth, info->addr, &info->start, &info->end);
|
||||
return (uint)LoopGet(info->depth, info->addr, &info->start, &info->end);
|
||||
}
|
||||
break;
|
||||
|
||||
case DBG_LOOP_OVERLAPS:
|
||||
{
|
||||
FUNCTION_LOOP_INFO* info = (FUNCTION_LOOP_INFO*)param1;
|
||||
return (uint)loopoverlaps(info->depth, info->start, info->end, 0);
|
||||
return (uint)LoopOverlaps(info->depth, info->start, info->end, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case DBG_LOOP_ADD:
|
||||
{
|
||||
FUNCTION_LOOP_INFO* info = (FUNCTION_LOOP_INFO*)param1;
|
||||
return (uint)loopadd(info->start, info->end, info->manual);
|
||||
return (uint)LoopAdd(info->start, info->end, info->manual);
|
||||
}
|
||||
break;
|
||||
|
||||
case DBG_LOOP_DEL:
|
||||
{
|
||||
FUNCTION_LOOP_INFO* info = (FUNCTION_LOOP_INFO*)param1;
|
||||
return (uint)loopdel(info->depth, info->addr);
|
||||
return (uint)LoopDelete(info->depth, info->addr);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -887,13 +905,13 @@ extern "C" DLL_EXPORT uint _dbg_sendmessage(DBGMSG type, void* param1, void* par
|
|||
|
||||
case DBG_SET_AUTO_LABEL_AT:
|
||||
{
|
||||
return (uint)labelset((uint)param1, (const char*)param2, false);
|
||||
return (uint)LabelSet((uint)param1, (const char*)param2, false);
|
||||
}
|
||||
break;
|
||||
|
||||
case DBG_DELETE_AUTO_LABEL_RANGE:
|
||||
{
|
||||
labeldelrange((uint)param1, (uint)param2);
|
||||
LabelDelRange((uint)param1, (uint)param2);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ DLL_EXPORT bool _dbg_addrinfoget(duint addr, SEGMENTREG segment, ADDRINFO* addri
|
|||
DLL_EXPORT bool _dbg_addrinfoset(duint addr, ADDRINFO* addrinfo);
|
||||
DLL_EXPORT int _dbg_bpgettypeat(duint addr);
|
||||
DLL_EXPORT bool _dbg_getregdump(REGDUMP* regdump);
|
||||
DLL_EXPORT bool _dbg_valtostring(const char* string, duint* value);
|
||||
DLL_EXPORT bool _dbg_valtostring(const char* string, duint value);
|
||||
DLL_EXPORT int _dbg_getbplist(BPXTYPE type, BPMAP* list);
|
||||
DLL_EXPORT uint _dbg_getbranchdestination(uint addr);
|
||||
DLL_EXPORT bool _dbg_functionoverlaps(uint start, uint end);
|
||||
|
|
|
|||
|
|
@ -1,15 +1,44 @@
|
|||
/**
|
||||
\file _global.cpp
|
||||
\brief Implements the global class.
|
||||
*/
|
||||
|
||||
#include "_global.h"
|
||||
#include <objbase.h>
|
||||
#include <shlobj.h>
|
||||
#include <new>
|
||||
|
||||
/**
|
||||
\brief x64_dbg library instance.
|
||||
*/
|
||||
HINSTANCE hInst;
|
||||
|
||||
/**
|
||||
\brief Directory where program databases are stored (usually in \db). UTF-8 encoding.
|
||||
*/
|
||||
char dbbasepath[deflen] = "";
|
||||
|
||||
/**
|
||||
\brief Path of the current program database. UTF-8 encoding.
|
||||
*/
|
||||
char dbpath[3 * deflen] = "";
|
||||
|
||||
/**
|
||||
\brief Number of allocated buffers by emalloc(). This should be 0 when x64_dbg ends.
|
||||
*/
|
||||
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] = "";
|
||||
|
||||
/**
|
||||
\brief Allocates a new buffer.
|
||||
\param size The size of the buffer to allocate (in bytes).
|
||||
\param reason The reason for allocation (can be used for memory allocation tracking).
|
||||
\return Always returns a valid pointer to the buffer you requested. Will quit the application on errors.
|
||||
*/
|
||||
void* emalloc(size_t size, const char* reason)
|
||||
{
|
||||
unsigned char* a = (unsigned char*)GlobalAlloc(GMEM_FIXED, size);
|
||||
|
|
@ -28,6 +57,13 @@ void* emalloc(size_t size, const char* reason)
|
|||
return a;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Reallocates a buffer allocated with emalloc().
|
||||
\param [in] Pointer to memory previously allocated with emalloc(). When NULL a new buffer will be allocated by emalloc().
|
||||
\param size The new memory size.
|
||||
\param reason The reason for allocation (can be used for memory allocation tracking).
|
||||
\return Always returns a valid pointer to the buffer you requested. Will quit the application on errors.
|
||||
*/
|
||||
void* erealloc(void* ptr, size_t size, const char* reason)
|
||||
{
|
||||
if(!ptr)
|
||||
|
|
@ -47,6 +83,11 @@ void* erealloc(void* ptr, size_t size, const char* reason)
|
|||
return a;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Free memory previously allocated with emalloc().
|
||||
\param [in] Pointer to the memory to free.
|
||||
\param reason The reason for freeing, should be the same as the reason for allocating.
|
||||
*/
|
||||
void efree(void* ptr, const char* reason)
|
||||
{
|
||||
emalloc_count--;
|
||||
|
|
@ -58,16 +99,30 @@ void efree(void* ptr, const char* reason)
|
|||
GlobalFree(ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Gets the number of memory leaks. This number is only valid in _dbg_dbgexitsignal().
|
||||
\return The number of memory leaks.
|
||||
*/
|
||||
int memleaks()
|
||||
{
|
||||
return emalloc_count;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Sets the path for the allocation trace file.
|
||||
\param file UTF-8 filepath.
|
||||
*/
|
||||
void setalloctrace(const char* file)
|
||||
{
|
||||
strcpy_s(alloctrace, file);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief A function to determine if a string is contained in a specifically formatted 'array string'.
|
||||
\param cmd_list Array of strings separated by '\1'.
|
||||
\param cmd The string to look for.
|
||||
\return true if \p cmd is contained in \p cmd_list.
|
||||
*/
|
||||
bool arraycontains(const char* cmd_list, const char* cmd)
|
||||
{
|
||||
//TODO: fix this function a little
|
||||
|
|
@ -95,11 +150,23 @@ bool arraycontains(const char* cmd_list, const char* cmd)
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Compares two strings without case-sensitivity.
|
||||
\param a The first string.
|
||||
\param b The second string.
|
||||
\return true if the strings are equal (case-insensitive).
|
||||
*/
|
||||
bool scmp(const char* a, const char* b)
|
||||
{
|
||||
return _stricmp(a, b) == 0;
|
||||
if(_stricmp(a, b))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Formats a string to hexadecimal format (removes all non-hex characters).
|
||||
\param [in,out] String to format.
|
||||
*/
|
||||
void formathex(char* string)
|
||||
{
|
||||
int len = (int)strlen(string);
|
||||
|
|
@ -112,6 +179,10 @@ void formathex(char* string)
|
|||
strcpy_s(string, len + 1, new_string);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Formats a string to decimal format (removed all non-numeric characters).
|
||||
\param [in,out] String to format.
|
||||
*/
|
||||
void formatdec(char* string)
|
||||
{
|
||||
int len = (int)strlen(string);
|
||||
|
|
@ -124,18 +195,34 @@ void formatdec(char* string)
|
|||
strcpy_s(string, len + 1, new_string);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Queries if a given file exists.
|
||||
\param file Path to the file to check (UTF-8).
|
||||
\return true if the file exists on the hard drive.
|
||||
*/
|
||||
bool FileExists(const char* file)
|
||||
{
|
||||
DWORD attrib = GetFileAttributesW(StringUtils::Utf8ToUtf16(file).c_str());
|
||||
return (attrib != INVALID_FILE_ATTRIBUTES && !(attrib & FILE_ATTRIBUTE_DIRECTORY));
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Queries if a given directory exists.
|
||||
\param dir Path to the directory to check (UTF-8).
|
||||
\return true if the directory exists.
|
||||
*/
|
||||
bool DirExists(const char* dir)
|
||||
{
|
||||
DWORD attrib = GetFileAttributesW(StringUtils::Utf8ToUtf16(dir).c_str());
|
||||
return (attrib == FILE_ATTRIBUTE_DIRECTORY);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Gets file path from a file handle.
|
||||
\param hFile File handle to get the path from.
|
||||
\param [in,out] szFileName Buffer of size MAX_PATH.
|
||||
\return true if it succeeds, false if it fails.
|
||||
*/
|
||||
bool GetFileNameFromHandle(HANDLE hFile, char* szFileName)
|
||||
{
|
||||
wchar_t wszFileName[MAX_PATH] = L"";
|
||||
|
|
@ -145,6 +232,12 @@ bool GetFileNameFromHandle(HANDLE hFile, char* szFileName)
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Get a boolean setting from the configuration file.
|
||||
\param section The section of the setting (UTF-8).
|
||||
\param name The name of the setting (UTF-8).
|
||||
\return true if the setting was set and equals to true, otherwise returns false.
|
||||
*/
|
||||
bool settingboolget(const char* section, const char* name)
|
||||
{
|
||||
uint setting;
|
||||
|
|
@ -155,6 +248,11 @@ bool settingboolget(const char* section, const char* name)
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Gets file architecture.
|
||||
\param szFileName UTF-8 encoded file path.
|
||||
\return The file architecture (::arch).
|
||||
*/
|
||||
arch GetFileArchitecture(const char* szFileName)
|
||||
{
|
||||
arch retval = notfound;
|
||||
|
|
@ -188,6 +286,10 @@ arch GetFileArchitecture(const char* szFileName)
|
|||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Query if x64_dbg is running in Wow64 mode.
|
||||
\return true if running in Wow64, false otherwise.
|
||||
*/
|
||||
bool IsWow64()
|
||||
{
|
||||
BOOL bIsWow64Process = FALSE;
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
#include <tlhelp32.h>
|
||||
#include "..\x64_dbg_bridge\bridgemain.h"
|
||||
#include "jansson\jansson.h"
|
||||
#include "yara\yara.h"
|
||||
#include "DeviceNameResolver\DeviceNameResolver.h"
|
||||
#include "handle.h"
|
||||
#include "stringutils.h"
|
||||
|
|
|
|||
|
|
@ -1,11 +1,15 @@
|
|||
/**
|
||||
@file _plugins.cpp
|
||||
|
||||
@brief Implements the plugins class.
|
||||
*/
|
||||
|
||||
#include "_plugins.h"
|
||||
#include "plugin_loader.h"
|
||||
#include "console.h"
|
||||
#include "debugger.h"
|
||||
#include "threading.h"
|
||||
|
||||
static char msg[66000];
|
||||
|
||||
///debugger plugin exports (wrappers)
|
||||
PLUG_IMPEXP void _plugin_registercallback(int pluginHandle, CBTYPE cbType, CBPLUGIN cbPlugin)
|
||||
{
|
||||
|
|
@ -30,9 +34,10 @@ PLUG_IMPEXP bool _plugin_unregistercommand(int pluginHandle, const char* command
|
|||
PLUG_IMPEXP void _plugin_logprintf(const char* format, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, format);
|
||||
vsprintf(msg, format, args);
|
||||
GuiAddLogMessage(msg);
|
||||
dprintf_args(format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
PLUG_IMPEXP void _plugin_logputs(const char* text)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,9 @@
|
|||
/**
|
||||
@file addrinfo.cpp
|
||||
|
||||
@brief Implements the addrinfo class.
|
||||
*/
|
||||
|
||||
#include "addrinfo.h"
|
||||
#include "debugger.h"
|
||||
#include "console.h"
|
||||
|
|
@ -22,10 +28,10 @@ void dbsave()
|
|||
DWORD ticks = GetTickCount();
|
||||
JSON root = json_object();
|
||||
CommentCacheSave(root);
|
||||
labelcachesave(root);
|
||||
LabelCacheSave(root);
|
||||
BookmarkCacheSave(root);
|
||||
FunctionCacheSave(root);
|
||||
loopcachesave(root);
|
||||
LoopCacheSave(root);
|
||||
BpCacheSave(root);
|
||||
WString wdbpath = StringUtils::Utf8ToUtf16(dbpath);
|
||||
if(json_object_size(root))
|
||||
|
|
@ -55,40 +61,75 @@ void dbsave()
|
|||
|
||||
void dbload()
|
||||
{
|
||||
if(!FileExists(dbpath)) //no database to load
|
||||
// If the file doesn't exist, there is no DB to load
|
||||
if(!FileExists(dbpath))
|
||||
return;
|
||||
dprintf("loading database...");
|
||||
|
||||
dprintf("Loading database...");
|
||||
DWORD ticks = GetTickCount();
|
||||
WString wdbpath = StringUtils::Utf8ToUtf16(dbpath);
|
||||
bool compress = !settingboolget("Engine", "DisableCompression");
|
||||
LZ4_STATUS status = LZ4_decompress_fileW(wdbpath.c_str(), wdbpath.c_str());
|
||||
if(status != LZ4_SUCCESS && status != LZ4_INVALID_ARCHIVE && compress)
|
||||
|
||||
// Multi-byte (UTF8) file path converted to UTF16
|
||||
WString databasePathW = StringUtils::Utf8ToUtf16(dbpath);
|
||||
|
||||
// Decompress the file if compression was enabled
|
||||
bool useCompression = !settingboolget("Engine", "DisableCompression");
|
||||
LZ4_STATUS lzmaStatus = LZ4_INVALID_ARCHIVE;
|
||||
{
|
||||
dputs("\ninvalid database file!");
|
||||
lzmaStatus = LZ4_decompress_fileW(databasePathW.c_str(), databasePathW.c_str());
|
||||
|
||||
// Check return code
|
||||
if (useCompression && lzmaStatus != LZ4_SUCCESS && lzmaStatus != LZ4_INVALID_ARCHIVE)
|
||||
{
|
||||
dputs("\nInvalid database file!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Open the file for reading by the JSON parser
|
||||
FILE* jsonFile = nullptr;
|
||||
long jsonFileSize = 0;
|
||||
|
||||
if(_wfopen_s(&jsonFile, databasePathW.c_str(), L"rb"))
|
||||
{
|
||||
dputs("\nFailed to open database file!");
|
||||
return;
|
||||
}
|
||||
FILE* jsonFile = 0;
|
||||
if(_wfopen_s(&jsonFile, wdbpath.c_str(), L"rb") != 0)
|
||||
{
|
||||
dputs("\nfailed to open database file!");
|
||||
return;
|
||||
}
|
||||
JSON root = json_loadf(jsonFile, 0, 0);
|
||||
|
||||
// Get the current file size
|
||||
fseek(jsonFile, 0, SEEK_END);
|
||||
jsonFileSize = ftell(jsonFile);
|
||||
fseek(jsonFile, 0, SEEK_SET);
|
||||
|
||||
// Verify that the file size is greater than 0.
|
||||
// This corrects a bug when a file exists, but there is no data inside.
|
||||
JSON root = nullptr;
|
||||
|
||||
if (jsonFileSize > 0)
|
||||
root = json_loadf(jsonFile, 0, 0);
|
||||
|
||||
// Release the file handle and re-compress
|
||||
fclose(jsonFile);
|
||||
if(status != LZ4_INVALID_ARCHIVE && compress)
|
||||
LZ4_compress_fileW(wdbpath.c_str(), wdbpath.c_str());
|
||||
|
||||
if(lzmaStatus != LZ4_INVALID_ARCHIVE && useCompression)
|
||||
LZ4_compress_fileW(databasePathW.c_str(), databasePathW.c_str());
|
||||
|
||||
// Validate JSON load status
|
||||
if(!root)
|
||||
{
|
||||
dputs("\ninvalid database file (JSON)!");
|
||||
dputs("\nInvalid database file (JSON)!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Finally load all structures
|
||||
CommentCacheLoad(root);
|
||||
labelcacheload(root);
|
||||
LabelCacheLoad(root);
|
||||
BookmarkCacheLoad(root);
|
||||
FunctionCacheLoad(root);
|
||||
loopcacheload(root);
|
||||
LoopCacheLoad(root);
|
||||
BpCacheLoad(root);
|
||||
json_decref(root); //free root
|
||||
|
||||
// Free root
|
||||
json_decref(root);
|
||||
dprintf("%ums\n", GetTickCount() - ticks);
|
||||
}
|
||||
|
||||
|
|
@ -96,12 +137,12 @@ void dbclose()
|
|||
{
|
||||
dbsave();
|
||||
CommentClear();
|
||||
labelclear();
|
||||
LabelClear();
|
||||
BookmarkClear();
|
||||
FunctionClear();
|
||||
loopclear();
|
||||
LoopClear();
|
||||
BpClear();
|
||||
patchclear();
|
||||
PatchClear();
|
||||
}
|
||||
|
||||
///api functions
|
||||
|
|
|
|||
|
|
@ -1,270 +0,0 @@
|
|||
#include "argument.h"
|
||||
#include "console.h"
|
||||
|
||||
/*
|
||||
formatarg:
|
||||
01) remove prepended spaces
|
||||
02) get command (first space) and lowercase
|
||||
03) get arguments
|
||||
04) remove double quotes (from arguments)
|
||||
05) temp. remove double backslash
|
||||
06) remove prepended/appended non-escaped commas and spaces (from arguments)
|
||||
a) prepended
|
||||
b) appended
|
||||
07) get quote count, ignore escaped (from arguments)
|
||||
08) process quotes (from arguments):
|
||||
a) zero quotes
|
||||
b) restore double backslash
|
||||
c) escape commas and spaces
|
||||
09) temp. remove double backslash
|
||||
10) remove unescaped double commas (from arguments)
|
||||
11) remove unescaped spaces (from arguments)
|
||||
12) restore double backslash
|
||||
13) combine formatted arguments and command
|
||||
*/
|
||||
void argformat(char* cmd)
|
||||
{
|
||||
if(strlen(cmd) >= deflen)
|
||||
return;
|
||||
|
||||
char command_[deflen] = "";
|
||||
char* command = command_;
|
||||
strcpy_s(command, deflen, cmd);
|
||||
while(*command == ' ')
|
||||
command++;
|
||||
|
||||
int len = (int)strlen(command);
|
||||
int start = 0;
|
||||
for(int i = 0; i < len; i++)
|
||||
if(command[i] == ' ')
|
||||
{
|
||||
command[i] = 0;
|
||||
start = i + 1;
|
||||
break;
|
||||
}
|
||||
if(!start)
|
||||
start = len;
|
||||
|
||||
char arguments_[deflen] = "";
|
||||
char* arguments = arguments_;
|
||||
strcpy_s(arguments, deflen, command + start);
|
||||
|
||||
char temp[deflen] = "";
|
||||
len = (int)strlen(arguments);
|
||||
for(int i = 0, j = 0; i < len; i++)
|
||||
{
|
||||
if(arguments[i] == '"' and arguments[i + 1] == '"') //TODO: fix this
|
||||
i += 2;
|
||||
j += sprintf(temp + j, "%c", arguments[i]);
|
||||
}
|
||||
strcpy_s(arguments, deflen, temp);
|
||||
|
||||
len = (int)strlen(arguments);
|
||||
for(int i = 0; i < len; i++)
|
||||
if(arguments[i] == '\\' and arguments[i + 1] == '\\')
|
||||
{
|
||||
arguments[i] = 1;
|
||||
arguments[i + 1] = 1;
|
||||
}
|
||||
|
||||
while((*arguments == ',' or * arguments == ' ') and * (arguments - 1) != '\\')
|
||||
arguments++;
|
||||
len = (int)strlen(arguments);
|
||||
while((arguments[len - 1] == ' ' or arguments[len - 1] == ',') and arguments[len - 2] != '\\')
|
||||
len--;
|
||||
arguments[len] = 0;
|
||||
|
||||
len = (int)strlen(arguments);
|
||||
int quote_count = 0;
|
||||
for(int i = 0; i < len; i++)
|
||||
if(arguments[i] == '"')
|
||||
quote_count++;
|
||||
|
||||
if(!(quote_count % 2))
|
||||
{
|
||||
for(int i = 0; i < len; i++)
|
||||
if(arguments[i] == '"')
|
||||
arguments[i] = 0;
|
||||
|
||||
for(int i = 0; i < len; i++)
|
||||
if(arguments[i] == 1 and (i < len - 1 and arguments[i + 1] == 1))
|
||||
{
|
||||
arguments[i] = '\\';
|
||||
arguments[i + 1] = '\\';
|
||||
}
|
||||
|
||||
for(int i = 0, j = 0; i < len; i++)
|
||||
{
|
||||
if(!arguments[i])
|
||||
{
|
||||
i++;
|
||||
int len2 = (int)strlen(arguments + i);
|
||||
for(int k = 0; k < len2; k++)
|
||||
{
|
||||
if(arguments[i + k] == ',' or arguments[i + k] == ' ' or arguments[i + k] == '\\')
|
||||
j += sprintf(temp + j, "\\%c", arguments[i + k]);
|
||||
else
|
||||
j += sprintf(temp + j, "%c", arguments[i + k]);
|
||||
}
|
||||
i += len2;
|
||||
}
|
||||
else
|
||||
j += sprintf(temp + j, "%c", arguments[i]);
|
||||
}
|
||||
arguments = arguments_;
|
||||
strcpy_s(arguments, deflen, temp);
|
||||
}
|
||||
len = (int)strlen(arguments);
|
||||
for(int i = 0; i < len; i++)
|
||||
if(arguments[i] == '\\' and arguments[i + 1] == '\\')
|
||||
{
|
||||
arguments[i] = 1;
|
||||
arguments[i + 1] = 1;
|
||||
}
|
||||
len = (int)strlen(arguments);
|
||||
for(int i = 0, j = 0; i < len; i++)
|
||||
{
|
||||
if(arguments[i] == ',' and arguments[i + 1] == ',')
|
||||
i += 2;
|
||||
j += sprintf(temp + j, "%c", arguments[i]);
|
||||
}
|
||||
strcpy_s(arguments, deflen, temp);
|
||||
|
||||
len = (int)strlen(arguments);
|
||||
for(int i = 0, j = 0; i < len; i++)
|
||||
{
|
||||
while(arguments[i] == ' ' and arguments[i - 1] != '\\')
|
||||
i++;
|
||||
j += sprintf(temp + j, "%c", arguments[i]);
|
||||
}
|
||||
strcpy_s(arguments, deflen, temp);
|
||||
|
||||
len = (int)strlen(arguments);
|
||||
for(int i = 0; i < len; i++)
|
||||
if(arguments[i] == 1 and arguments[i + 1] == 1)
|
||||
{
|
||||
arguments[i] = '\\';
|
||||
arguments[i + 1] = '\\';
|
||||
}
|
||||
|
||||
if(strlen(arguments))
|
||||
sprintf(cmd, "%s %s", command, arguments);
|
||||
else
|
||||
strcpy_s(cmd, deflen, command);
|
||||
}
|
||||
|
||||
/*
|
||||
1) remove double backslash
|
||||
2) count unescaped commas
|
||||
*/
|
||||
int arggetcount(const char* cmd)
|
||||
{
|
||||
int len = (int)strlen(cmd);
|
||||
if(!len or len >= deflen)
|
||||
return -1;
|
||||
|
||||
int arg_count = 0;
|
||||
|
||||
int start = 0;
|
||||
while(cmd[start] != ' ' and start < len)
|
||||
start++;
|
||||
if(start == len)
|
||||
return arg_count;
|
||||
arg_count = 1;
|
||||
char temp_[deflen] = "";
|
||||
char* temp = temp_ + 1;
|
||||
strcpy_s(temp, deflen - 1, cmd);
|
||||
for(int i = start; i < len; i++)
|
||||
if(temp[i] == '\\' and (i < len - 1 and temp[i + 1] == '\\'))
|
||||
{
|
||||
temp[i] = 1;
|
||||
temp[i + 1] = 1;
|
||||
}
|
||||
|
||||
for(int i = start; i < len; i++)
|
||||
{
|
||||
if(temp[i] == ',' and temp[i - 1] != '\\')
|
||||
arg_count++;
|
||||
}
|
||||
return arg_count;
|
||||
}
|
||||
/*
|
||||
1) get arg count
|
||||
2) remove double backslash
|
||||
3) zero non-escaped commas
|
||||
4) restore double backslash
|
||||
5) handle escape characters
|
||||
*/
|
||||
bool argget(const char* cmd, char* arg, int arg_num, bool optional)
|
||||
{
|
||||
if(strlen(cmd) >= deflen)
|
||||
return false;
|
||||
int argcount = arggetcount(cmd);
|
||||
if((arg_num + 1) > argcount)
|
||||
{
|
||||
if(!optional)
|
||||
dprintf("missing argument nr %d\n", arg_num + 1);
|
||||
return false;
|
||||
}
|
||||
int start = 0;
|
||||
while(cmd[start] != ' ') //ignore the command
|
||||
start++;
|
||||
while(cmd[start] == ' ') //ignore initial spaces
|
||||
start++;
|
||||
char temp_[deflen] = "";
|
||||
char* temp = temp_ + 1;
|
||||
strcpy_s(temp, deflen - 1, cmd + start);
|
||||
|
||||
int len = (int)strlen(temp);
|
||||
for(int i = 0; i < len; i++)
|
||||
if(temp[i] == '\\' and temp[i + 1] == '\\')
|
||||
{
|
||||
temp[i] = 1;
|
||||
temp[i + 1] = 1;
|
||||
}
|
||||
|
||||
for(int i = 0; i < len; i++)
|
||||
{
|
||||
if(temp[i] == ',' and temp[i - 1] != '\\')
|
||||
temp[i] = 0;
|
||||
}
|
||||
|
||||
for(int i = 0; i < len; i++)
|
||||
if(temp[i] == 1 and temp[i + 1] == 1)
|
||||
{
|
||||
temp[i] = '\\';
|
||||
temp[i + 1] = '\\';
|
||||
}
|
||||
|
||||
char new_temp[deflen] = "";
|
||||
int new_len = len;
|
||||
for(int i = 0, j = 0; i < len; i++) //handle escape characters
|
||||
{
|
||||
if(temp[i] == '\\' and (temp[i + 1] == ',' or temp[i + 1] == ' ' or temp[i + 1] == '\\'))
|
||||
{
|
||||
new_len--;
|
||||
j += sprintf(new_temp + j, "%c", temp[i + 1]);
|
||||
i++;
|
||||
}
|
||||
else
|
||||
j += sprintf(new_temp + j, "%c", temp[i]);
|
||||
}
|
||||
len = new_len;
|
||||
memcpy(temp, new_temp, len + 1);
|
||||
if(arg_num == 0) //first argument
|
||||
{
|
||||
strcpy_s(arg, deflen, temp);
|
||||
return true;
|
||||
}
|
||||
for(int i = 0, j = 0; i < len; i++)
|
||||
{
|
||||
if(!temp[i])
|
||||
j++;
|
||||
if(j == arg_num)
|
||||
{
|
||||
strcpy_s(arg, deflen, temp + i + 1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
#ifndef _ARGUMENT_H
|
||||
#define _ARGUMENT_H
|
||||
|
||||
#include "_global.h"
|
||||
|
||||
//functions
|
||||
bool argget(const char* cmd, char* arg, int arg_num, bool optional);
|
||||
int arggetcount(const char* cmd);
|
||||
void argformat(char* cmd);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,3 +1,9 @@
|
|||
/**
|
||||
@file assemble.cpp
|
||||
|
||||
@brief Implements the assemble class.
|
||||
*/
|
||||
|
||||
#include "assemble.h"
|
||||
#include "memory.h"
|
||||
#include "debugger.h"
|
||||
|
|
@ -30,11 +36,7 @@ bool assemble(uint addr, unsigned char* dest, int* size, const char* instruction
|
|||
#endif
|
||||
parse.cbUnknown = cbUnknown;
|
||||
parse.cip = addr;
|
||||
String instr = instruction;
|
||||
size_t pos = instr.find(" short ");
|
||||
if(pos != String::npos)
|
||||
instr.erase(pos, 6);
|
||||
strcpy_s(parse.instr, instr.c_str());
|
||||
strcpy_s(parse.instr, instruction);
|
||||
if(XEDParseAssemble(&parse) == XEDPARSE_ERROR)
|
||||
{
|
||||
if(error)
|
||||
|
|
|
|||
|
|
@ -4,9 +4,7 @@
|
|||
#include "debugger.h"
|
||||
#include "memory.h"
|
||||
|
||||
typedef std::unordered_map<uint, BOOKMARKSINFO> BookmarksInfo;
|
||||
|
||||
static BookmarksInfo bookmarks;
|
||||
std::unordered_map<uint, BOOKMARKSINFO> bookmarks;
|
||||
|
||||
bool BookmarkSet(uint Address, bool Manual)
|
||||
{
|
||||
|
|
@ -20,13 +18,13 @@ bool BookmarkSet(uint Address, bool Manual)
|
|||
|
||||
BOOKMARKSINFO bookmark;
|
||||
ModNameFromAddr(Address, bookmark.mod, true);
|
||||
bookmark.addr = Address;
|
||||
bookmark.addr = Address - ModBaseFromAddr(Address);
|
||||
bookmark.manual = Manual;
|
||||
|
||||
// Exclusive lock to insert new data
|
||||
EXCLUSIVE_ACQUIRE(LockBookmarks);
|
||||
|
||||
if(!bookmarks.insert(std::make_pair(Address, bookmark)).second)
|
||||
if(!bookmarks.insert(std::make_pair(ModHashFromAddr(Address), bookmark)).second)
|
||||
return BookmarkDelete(Address);
|
||||
|
||||
return true;
|
||||
|
|
@ -39,7 +37,7 @@ bool BookmarkGet(uint Address)
|
|||
return false;
|
||||
|
||||
SHARED_ACQUIRE(LockBookmarks);
|
||||
return (bookmarks.count(Address) > 0);
|
||||
return (bookmarks.count(ModHashFromAddr(Address)) > 0);
|
||||
}
|
||||
|
||||
bool BookmarkDelete(uint Address)
|
||||
|
|
@ -49,7 +47,7 @@ bool BookmarkDelete(uint Address)
|
|||
return false;
|
||||
|
||||
EXCLUSIVE_ACQUIRE(LockBookmarks);
|
||||
return (bookmarks.erase(Address) > 0);
|
||||
return (bookmarks.erase(ModHashFromAddr(Address)) > 0);
|
||||
}
|
||||
|
||||
void BookmarkDelRange(uint Start, uint End)
|
||||
|
|
@ -59,7 +57,7 @@ void BookmarkDelRange(uint Start, uint End)
|
|||
return;
|
||||
|
||||
// Are all bookmarks going to be deleted?
|
||||
// 0x00000000 - 0xFFFFFFFF
|
||||
// 0x00000000 - 0xFFFFFFFF
|
||||
if(Start == 0 && End == ~0)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockBookmarks);
|
||||
|
|
@ -73,6 +71,10 @@ void BookmarkDelRange(uint Start, uint End)
|
|||
if(moduleBase != ModBaseFromAddr(End))
|
||||
return;
|
||||
|
||||
// Virtual -> relative offset
|
||||
Start -= moduleBase;
|
||||
End -= moduleBase;
|
||||
|
||||
EXCLUSIVE_ACQUIRE(LockBookmarks);
|
||||
for(auto itr = bookmarks.begin(); itr != bookmarks.end();)
|
||||
{
|
||||
|
|
@ -104,12 +106,8 @@ void BookmarkCacheSave(JSON Root)
|
|||
{
|
||||
JSON currentBookmark = json_object();
|
||||
|
||||
// The address must be adjusted to use an offset
|
||||
// OFFSET = ADDRESS - MOD_BASE
|
||||
uint virtualOffset = itr.second.addr - ModBaseFromAddr(itr.second.addr);
|
||||
|
||||
json_object_set_new(currentBookmark, "module", json_string(itr.second.mod));
|
||||
json_object_set_new(currentBookmark, "address", json_hex(virtualOffset));
|
||||
json_object_set_new(currentBookmark, "address", json_hex(itr.second.addr));
|
||||
|
||||
if(itr.second.manual)
|
||||
json_array_append_new(jsonBookmarks, currentBookmark);
|
||||
|
|
@ -145,18 +143,17 @@ void BookmarkCacheLoad(JSON Root)
|
|||
// Load the module name
|
||||
const char* mod = json_string_value(json_object_get(value, "module"));
|
||||
|
||||
if(mod && *mod && strlen(mod) < MAX_MODULE_SIZE)
|
||||
if(mod && strlen(mod) < MAX_MODULE_SIZE)
|
||||
strcpy_s(bookmarkInfo.mod, mod);
|
||||
else
|
||||
bookmarkInfo.mod[0] = '\0';
|
||||
|
||||
// Load address and set auto-generated flag
|
||||
bookmarkInfo.addr = (uint)json_hex_value(json_object_get(value, "address"));
|
||||
bookmarkInfo.manual = Manual;
|
||||
|
||||
// The offset must be adjusted to use virtual addressing
|
||||
// ADDRESS = OFFSET + MOD_BASE
|
||||
bookmarkInfo.addr += ModBaseFromName(bookmarkInfo.mod);
|
||||
|
||||
bookmarks.insert(std::make_pair(bookmarkInfo.addr, bookmarkInfo));
|
||||
const uint key = ModHashFromName(bookmarkInfo.mod) + bookmarkInfo.addr;
|
||||
bookmarks.insert(std::make_pair(key, bookmarkInfo));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -192,11 +189,11 @@ bool BookmarkEnum(BOOKMARKSINFO* List, size_t* Size)
|
|||
return true;
|
||||
}
|
||||
|
||||
// Copy struct over
|
||||
// Copy struct and adjust the relative offset to a virtual address
|
||||
for(auto & itr : bookmarks)
|
||||
{
|
||||
*List = itr.second;
|
||||
List++;
|
||||
*List = itr.second;
|
||||
List->addr += ModBaseFromName(List->mod);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,9 @@
|
|||
/**
|
||||
@file breakpoint.cpp
|
||||
|
||||
@brief Implements the breakpoint class.
|
||||
*/
|
||||
|
||||
#include "breakpoint.h"
|
||||
#include "debugger.h"
|
||||
#include "addrinfo.h"
|
||||
|
|
@ -7,9 +13,7 @@
|
|||
#include "module.h"
|
||||
|
||||
typedef std::pair<BP_TYPE, uint> BreakpointKey;
|
||||
typedef std::map<BreakpointKey, BREAKPOINT> BreakpointsInfo;
|
||||
|
||||
static BreakpointsInfo breakpoints;
|
||||
std::map<BreakpointKey, BREAKPOINT> breakpoints;
|
||||
|
||||
BREAKPOINT* BpInfoFromAddr(BP_TYPE Type, uint Address)
|
||||
{
|
||||
|
|
@ -48,7 +52,7 @@ int BpGetList(std::vector<BREAKPOINT>* List)
|
|||
}
|
||||
}
|
||||
|
||||
return (int)breakpoints.size();
|
||||
return breakpoints.size();
|
||||
}
|
||||
|
||||
bool BpNew(uint Address, bool Enable, bool Singleshot, short OldBytes, BP_TYPE Type, DWORD TitanType, const char* Name)
|
||||
|
|
|
|||
|
|
@ -1,10 +1,23 @@
|
|||
/**
|
||||
@file command.cpp
|
||||
|
||||
@brief Implements the command class.
|
||||
*/
|
||||
|
||||
#include "command.h"
|
||||
#include "argument.h"
|
||||
#include "value.h"
|
||||
#include "console.h"
|
||||
#include "debugger.h"
|
||||
#include "math.h"
|
||||
#include "commandparser.h"
|
||||
|
||||
/**
|
||||
\brief Finds a ::COMMAND in a command list.
|
||||
\param [in] command list.
|
||||
\param name The name of the command to find.
|
||||
\param [out] Link to the command.
|
||||
\return null if it fails, else a ::COMMAND*.
|
||||
*/
|
||||
COMMAND* cmdfind(COMMAND* command_list, const char* name, COMMAND** link)
|
||||
{
|
||||
COMMAND* cur = command_list;
|
||||
|
|
@ -25,6 +38,10 @@ COMMAND* cmdfind(COMMAND* command_list, const char* name, COMMAND** link)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Initialize a command list.
|
||||
\return a ::COMMAND*
|
||||
*/
|
||||
COMMAND* cmdinit()
|
||||
{
|
||||
COMMAND* cmd = (COMMAND*)emalloc(sizeof(COMMAND), "cmdinit:cmd");
|
||||
|
|
@ -32,6 +49,10 @@ COMMAND* cmdinit()
|
|||
return cmd;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Clear a command list.
|
||||
\param [in] cmd_list Command list to clear.
|
||||
*/
|
||||
void cmdfree(COMMAND* cmd_list)
|
||||
{
|
||||
COMMAND* cur = cmd_list;
|
||||
|
|
@ -44,6 +65,14 @@ void cmdfree(COMMAND* cmd_list)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Creates a new command and adds it to the list.
|
||||
\param [in,out] command_list Command list. Cannot be null.
|
||||
\param name The command name.
|
||||
\param cbCommand The command callback.
|
||||
\param debugonly true if the command can only be executed in a debugging context.
|
||||
\return true if the command was successfully added to the list.
|
||||
*/
|
||||
bool cmdnew(COMMAND* command_list, const char* name, CBCOMMAND cbCommand, bool debugonly)
|
||||
{
|
||||
if(!command_list or !cbCommand or !name or !*name or cmdfind(command_list, name, 0))
|
||||
|
|
@ -72,6 +101,12 @@ bool cmdnew(COMMAND* command_list, const char* name, CBCOMMAND cbCommand, bool d
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Gets a ::COMMAND from the command list.
|
||||
\param [in] command_list Command list.
|
||||
\param cmd The command to get from the list.
|
||||
\return null if the command was not found. Otherwise a ::COMMAND*.
|
||||
*/
|
||||
COMMAND* cmdget(COMMAND* command_list, const char* cmd)
|
||||
{
|
||||
char new_cmd[deflen] = "";
|
||||
|
|
@ -87,6 +122,14 @@ COMMAND* cmdget(COMMAND* command_list, const char* cmd)
|
|||
return found;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Sets a new command callback and debugonly property in a command list.
|
||||
\param [in] command_list Command list.
|
||||
\param name The name of the command to change.
|
||||
\param cbCommand The new command callback.
|
||||
\param debugonly The new debugonly value.
|
||||
\return The old command callback.
|
||||
*/
|
||||
CBCOMMAND cmdset(COMMAND* command_list, const char* name, CBCOMMAND cbCommand, bool debugonly)
|
||||
{
|
||||
if(!cbCommand)
|
||||
|
|
@ -100,6 +143,12 @@ CBCOMMAND cmdset(COMMAND* command_list, const char* name, CBCOMMAND cbCommand, b
|
|||
return old;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Deletes a command from a command list.
|
||||
\param [in] command_list Command list.
|
||||
\param name The name of the command to delete.
|
||||
\return true if the command was deleted.
|
||||
*/
|
||||
bool cmddel(COMMAND* command_list, const char* name)
|
||||
{
|
||||
COMMAND* prev = 0;
|
||||
|
|
@ -134,6 +183,16 @@ cbCommandProvider: function that provides commands (fgets for example), does
|
|||
cbCommandFinder: non-default command finder
|
||||
error_is_fatal: error return of a command callback stops the command processing
|
||||
*/
|
||||
|
||||
/**
|
||||
\brief Initiates a command loop. This function will not return until a command returns ::STATUS_EXIT.
|
||||
\param [in] command_list Command list to use for the command lookups.
|
||||
\param cbUnknownCommand The unknown command callback.
|
||||
\param cbCommandProvider The command provider callback.
|
||||
\param cbCommandFinder The command finder callback.
|
||||
\param error_is_fatal true if commands that return ::STATUS_ERROR terminate the command loop.
|
||||
\return A CMDRESULT, will always be ::STATUS_EXIT.
|
||||
*/
|
||||
CMDRESULT cmdloop(COMMAND* command_list, CBCOMMAND cbUnknownCommand, CBCOMMANDPROVIDER cbCommandProvider, CBCOMMANDFINDER cbCommandFinder, bool error_is_fatal)
|
||||
{
|
||||
if(!cbUnknownCommand or !cbCommandProvider)
|
||||
|
|
@ -146,7 +205,7 @@ CMDRESULT cmdloop(COMMAND* command_list, CBCOMMAND cbUnknownCommand, CBCOMMANDPR
|
|||
break;
|
||||
if(strlen(command))
|
||||
{
|
||||
argformat(command); //default formatting
|
||||
strcpy_s(command, StringUtils::Trim(command).c_str());
|
||||
COMMAND* cmd;
|
||||
if(!cbCommandFinder) //'clean' command processing
|
||||
cmd = cmdget(command_list, command);
|
||||
|
|
@ -171,14 +230,15 @@ CMDRESULT cmdloop(COMMAND* command_list, CBCOMMAND cbUnknownCommand, CBCOMMANDPR
|
|||
}
|
||||
else
|
||||
{
|
||||
int argcount = arggetcount(command);
|
||||
Command commandParsed(command);
|
||||
int argcount = commandParsed.GetArgCount();
|
||||
char** argv = (char**)emalloc((argcount + 1) * sizeof(char*), "cmdloop:argv");
|
||||
argv[0] = command;
|
||||
for(int i = 0; i < argcount; i++)
|
||||
{
|
||||
argv[i + 1] = (char*)emalloc(deflen, "cmdloop:argv[i+1]");
|
||||
*argv[i + 1] = 0;
|
||||
argget(command, argv[i + 1], i, true);
|
||||
strcpy_s(argv[i + 1], deflen, commandParsed.GetArg(i).c_str());
|
||||
}
|
||||
CMDRESULT res = cmd->cbCommand(argcount + 1, argv);
|
||||
for(int i = 0; i < argcount; i++)
|
||||
|
|
@ -197,12 +257,21 @@ CMDRESULT cmdloop(COMMAND* command_list, CBCOMMAND cbUnknownCommand, CBCOMMANDPR
|
|||
- custom command formatting rules
|
||||
*/
|
||||
|
||||
/**
|
||||
\brief Query if a string is a valid expression.
|
||||
\param expression The expression to check.
|
||||
\return true if the string is a valid expression.
|
||||
*/
|
||||
static bool isvalidexpression(const char* expression)
|
||||
{
|
||||
uint value;
|
||||
return valfromstring(expression, &value);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Special formats a given command. Used as a little hack to support stuff like 'x++' and 'x=y'
|
||||
\param [in,out] string String to format.
|
||||
*/
|
||||
static void specialformat(char* string)
|
||||
{
|
||||
int len = (int)strlen(string);
|
||||
|
|
@ -266,6 +335,13 @@ static void specialformat(char* string)
|
|||
/*
|
||||
- 'default' command finder, with some custom rules
|
||||
*/
|
||||
|
||||
/**
|
||||
\brief Default command finder. It uses specialformat() and mathformat() to make sure the command is optimally checked.
|
||||
\param [in] cmd_list Command list.
|
||||
\param [in] command Command name.
|
||||
\return null if it fails, else a COMMAND*.
|
||||
*/
|
||||
COMMAND* cmdfindmain(COMMAND* cmd_list, char* command)
|
||||
{
|
||||
COMMAND* cmd = cmdfind(cmd_list, command, 0);
|
||||
|
|
@ -279,26 +355,32 @@ COMMAND* cmdfindmain(COMMAND* cmd_list, char* command)
|
|||
return cmd;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Directly execute a command.
|
||||
\param [in,out] cmd_list Command list.
|
||||
\param cmd The command to execute.
|
||||
\return A CMDRESULT.
|
||||
*/
|
||||
CMDRESULT cmddirectexec(COMMAND* cmd_list, const char* cmd)
|
||||
{
|
||||
if(!cmd or !strlen(cmd))
|
||||
return STATUS_ERROR;
|
||||
char command[deflen] = "";
|
||||
strcpy(command, cmd);
|
||||
argformat(command);
|
||||
strcpy(command, StringUtils::Trim(cmd).c_str());
|
||||
COMMAND* found = cmdfindmain(cmd_list, command);
|
||||
if(!found or !found->cbCommand)
|
||||
return STATUS_ERROR;
|
||||
if(found->debugonly and !DbgIsDebugging())
|
||||
return STATUS_ERROR;
|
||||
int argcount = arggetcount(command);
|
||||
Command cmdParsed(command);
|
||||
int argcount = cmdParsed.GetArgCount();
|
||||
char** argv = (char**)emalloc((argcount + 1) * sizeof(char*), "cmddirectexec:argv");
|
||||
argv[0] = command;
|
||||
for(int i = 0; i < argcount; i++)
|
||||
{
|
||||
argv[i + 1] = (char*)emalloc(deflen, "cmddirectexec:argv[i+1]");
|
||||
*argv[i + 1] = 0;
|
||||
argget(command, argv[i + 1], i, true);
|
||||
strcpy_s(argv[i + 1], deflen, cmdParsed.GetArg(i).c_str());
|
||||
}
|
||||
CMDRESULT res = found->cbCommand(argcount + 1, argv);
|
||||
for(int i = 0; i < argcount; i++)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,114 @@
|
|||
#include "commandparser.h"
|
||||
|
||||
Command::Command(const String & command)
|
||||
{
|
||||
ParseState state = Default;
|
||||
int len = command.length();
|
||||
for(int i = 0; i < len; i++)
|
||||
{
|
||||
char ch = command[i];
|
||||
switch(state)
|
||||
{
|
||||
case Default:
|
||||
switch(ch)
|
||||
{
|
||||
case ' ':
|
||||
if(!_tokens.size())
|
||||
dataFinish();
|
||||
break;
|
||||
case ',':
|
||||
dataFinish();
|
||||
break;
|
||||
case '\\':
|
||||
state = Escaped;
|
||||
break;
|
||||
case '\"':
|
||||
state = Text;
|
||||
break;
|
||||
default:
|
||||
dataAppend(ch);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case Escaped:
|
||||
switch(ch)
|
||||
{
|
||||
case ' ':
|
||||
dataAppend(ch);
|
||||
break;
|
||||
case ',':
|
||||
dataAppend(ch);
|
||||
break;
|
||||
case '\"':
|
||||
dataAppend(ch);
|
||||
break;
|
||||
default:
|
||||
dataAppend('\\');
|
||||
dataAppend(ch);
|
||||
break;
|
||||
}
|
||||
state = Default;
|
||||
break;
|
||||
case Text:
|
||||
switch(ch)
|
||||
{
|
||||
case '\\':
|
||||
state = TextEscaped;
|
||||
break;
|
||||
case '\"':
|
||||
dataFinish();
|
||||
state = Default;
|
||||
break;
|
||||
default:
|
||||
dataAppend(ch);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case TextEscaped:
|
||||
switch(ch)
|
||||
{
|
||||
case '\"':
|
||||
dataAppend(ch);
|
||||
break;
|
||||
default:
|
||||
dataAppend('\\');
|
||||
dataAppend(ch);
|
||||
break;
|
||||
}
|
||||
state = Text;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(state == Escaped || state == TextEscaped)
|
||||
dataAppend('\\');
|
||||
dataFinish();
|
||||
}
|
||||
|
||||
const String Command::GetText()
|
||||
{
|
||||
return _tokens.size() ? _tokens[0] : String();
|
||||
}
|
||||
|
||||
const int Command::GetArgCount()
|
||||
{
|
||||
return _tokens.size() ? _tokens.size() - 1 : 0;
|
||||
}
|
||||
|
||||
const String Command::GetArg(int argnum)
|
||||
{
|
||||
return (int)_tokens.size() < argnum + 1 ? String() : _tokens[argnum + 1];
|
||||
}
|
||||
|
||||
void Command::dataAppend(const char ch)
|
||||
{
|
||||
_data += ch;
|
||||
}
|
||||
|
||||
void Command::dataFinish()
|
||||
{
|
||||
if(_data.length())
|
||||
{
|
||||
_tokens.push_back(_data);
|
||||
_data = "";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
#ifndef _COMMANDPARSER_H
|
||||
#define _COMMANDPARSER_H
|
||||
|
||||
#include "_global.h"
|
||||
|
||||
class Command
|
||||
{
|
||||
public:
|
||||
Command(const String & command);
|
||||
const String GetText();
|
||||
const String GetArg(const int argnum);
|
||||
const int GetArgCount();
|
||||
|
||||
private:
|
||||
String _data;
|
||||
std::vector<String> _tokens;
|
||||
|
||||
enum ParseState
|
||||
{
|
||||
Default,
|
||||
Escaped,
|
||||
Text,
|
||||
TextEscaped
|
||||
};
|
||||
|
||||
void dataFinish();
|
||||
void dataAppend(const char ch);
|
||||
};
|
||||
|
||||
#endif // _COMMANDPARSER_H
|
||||
|
|
@ -4,9 +4,7 @@
|
|||
#include "debugger.h"
|
||||
#include "memory.h"
|
||||
|
||||
typedef std::unordered_map<uint, COMMENTSINFO> CommentsInfo;
|
||||
|
||||
static CommentsInfo comments;
|
||||
std::unordered_map<uint, COMMENTSINFO> comments;
|
||||
|
||||
bool CommentSet(uint Address, const char* Text, bool Manual)
|
||||
{
|
||||
|
|
@ -24,10 +22,7 @@ bool CommentSet(uint Address, const char* Text, bool Manual)
|
|||
|
||||
// Delete the comment if no text was supplied
|
||||
if(Text[0] == '\0')
|
||||
{
|
||||
CommentDelete(Address);
|
||||
return true;
|
||||
}
|
||||
return CommentDelete(Address);
|
||||
|
||||
// Fill out the structure
|
||||
COMMENTSINFO comment;
|
||||
|
|
@ -35,13 +30,16 @@ bool CommentSet(uint Address, const char* Text, bool Manual)
|
|||
ModNameFromAddr(Address, comment.mod, true);
|
||||
|
||||
comment.manual = Manual;
|
||||
comment.addr = Address;
|
||||
comment.addr = Address - ModBaseFromAddr(Address);
|
||||
|
||||
EXCLUSIVE_ACQUIRE(LockComments);
|
||||
// Insert into list
|
||||
const uint key = ModHashFromAddr(Address);
|
||||
|
||||
// Insert if possible, otherwise replace
|
||||
if (!comments.insert(std::make_pair(Address, comment)).second)
|
||||
comments[Address] = comment;
|
||||
EXCLUSIVE_ACQUIRE(LockComments);
|
||||
|
||||
// Insert if possible, otherwise replace
|
||||
if(!comments.insert(std::make_pair(key, comment)).second)
|
||||
comments[key] = comment;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -55,7 +53,7 @@ bool CommentGet(uint Address, char* Text)
|
|||
SHARED_ACQUIRE(LockComments);
|
||||
|
||||
// Get an existing comment and copy the string buffer
|
||||
auto found = comments.find(Address);
|
||||
auto found = comments.find(ModHashFromAddr(Address));
|
||||
|
||||
// Was it found?
|
||||
if(found == comments.end())
|
||||
|
|
@ -72,7 +70,7 @@ bool CommentDelete(uint Address)
|
|||
return false;
|
||||
|
||||
EXCLUSIVE_ACQUIRE(LockComments);
|
||||
return (comments.erase(Address) > 0);
|
||||
return (comments.erase(ModHashFromAddr(Address)) > 0);
|
||||
}
|
||||
|
||||
void CommentDelRange(uint Start, uint End)
|
||||
|
|
@ -82,7 +80,7 @@ void CommentDelRange(uint Start, uint End)
|
|||
return;
|
||||
|
||||
// Are all comments going to be deleted?
|
||||
// 0x00000000 - 0xFFFFFFFF
|
||||
// 0x00000000 - 0xFFFFFFFF
|
||||
if(Start == 0 && End == ~0)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockComments);
|
||||
|
|
@ -96,6 +94,10 @@ void CommentDelRange(uint Start, uint End)
|
|||
if(moduleBase != ModBaseFromAddr(End))
|
||||
return;
|
||||
|
||||
// Virtual -> relative offset
|
||||
Start -= moduleBase;
|
||||
End -= moduleBase;
|
||||
|
||||
EXCLUSIVE_ACQUIRE(LockComments);
|
||||
for(auto itr = comments.begin(); itr != comments.end();)
|
||||
{
|
||||
|
|
@ -119,19 +121,16 @@ void CommentCacheSave(JSON Root)
|
|||
{
|
||||
EXCLUSIVE_ACQUIRE(LockComments);
|
||||
|
||||
const JSON jsonComments = json_array();
|
||||
const JSON jsonAutoComments = json_array();
|
||||
const JSON jsonComments = json_array();
|
||||
const JSON jsonAutoComments = json_array();
|
||||
|
||||
// Build the JSON array
|
||||
for(auto & itr : comments)
|
||||
{
|
||||
JSON currentComment = json_object();
|
||||
|
||||
// OFFSET = ADDRESS - MOD_BASE
|
||||
uint virtualOffset = itr.second.addr - ModBaseFromAddr(itr.second.addr);
|
||||
|
||||
json_object_set_new(currentComment, "module", json_string(itr.second.mod));
|
||||
json_object_set_new(currentComment, "address", json_hex(virtualOffset));
|
||||
json_object_set_new(currentComment, "address", json_hex(itr.second.addr));
|
||||
json_object_set_new(currentComment, "text", json_string(itr.second.text));
|
||||
|
||||
if(itr.second.manual)
|
||||
|
|
@ -164,11 +163,12 @@ void CommentCacheLoad(JSON Root)
|
|||
json_array_foreach(Object, i, value)
|
||||
{
|
||||
COMMENTSINFO commentInfo;
|
||||
memset(&commentInfo, 0, sizeof(COMMENTSINFO));
|
||||
|
||||
// Module
|
||||
const char* mod = json_string_value(json_object_get(value, "module"));
|
||||
|
||||
if(mod && *mod && strlen(mod) < MAX_MODULE_SIZE)
|
||||
if(mod && strlen(mod) < MAX_MODULE_SIZE)
|
||||
strcpy_s(commentInfo.mod, mod);
|
||||
else
|
||||
commentInfo.mod[0] = '\0';
|
||||
|
|
@ -188,10 +188,8 @@ void CommentCacheLoad(JSON Root)
|
|||
continue;
|
||||
}
|
||||
|
||||
// ADDRESS = OFFSET + MOD_BASE
|
||||
commentInfo.addr += ModBaseFromName(commentInfo.mod);
|
||||
|
||||
comments.insert(std::make_pair(commentInfo.addr, commentInfo));
|
||||
const uint key = ModHashFromName(commentInfo.mod) + commentInfo.addr;
|
||||
comments.insert(std::make_pair(key, commentInfo));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -234,7 +232,9 @@ bool CommentEnum(COMMENTSINFO* List, size_t* Size)
|
|||
// Populate the returned array
|
||||
for(auto & itr : comments)
|
||||
{
|
||||
*List = itr.second;
|
||||
*List = itr.second;
|
||||
List->addr += ModBaseFromName(List->mod);
|
||||
|
||||
List++;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,18 +1,41 @@
|
|||
/**
|
||||
\file console.cpp
|
||||
\brief Implements the console class.
|
||||
*/
|
||||
|
||||
#include "console.h"
|
||||
|
||||
/**
|
||||
\brief Print a line with text, terminated with a newline to the console.
|
||||
\param text The text to print.
|
||||
*/
|
||||
void dputs(const char* Text)
|
||||
{
|
||||
dprintf("%s\n", Text);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Print a formatted string to the console.
|
||||
\param format The printf format to use (see documentation of printf for more information).
|
||||
*/
|
||||
void dprintf(const char* Format, ...)
|
||||
{
|
||||
va_list args;
|
||||
char buffer[16384];
|
||||
|
||||
va_start(args, Format);
|
||||
vsnprintf_s(buffer, _TRUNCATE, Format, args);
|
||||
dprintf_args(Format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Print a formatted string to the console.
|
||||
\param format The printf format to use (see documentation of printf for more information).
|
||||
\param Args The argument buffer passed to the string parser.
|
||||
*/
|
||||
void dprintf_args(const char* Format, va_list Args)
|
||||
{
|
||||
char buffer[16384];
|
||||
vsnprintf_s(buffer, _TRUNCATE, Format, Args);
|
||||
|
||||
GuiAddLogMessage(buffer);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,4 +3,5 @@
|
|||
#include "_global.h"
|
||||
|
||||
void dputs(const char* Text);
|
||||
void dprintf(const char* Format, ...);
|
||||
void dprintf(const char* Format, ...);
|
||||
void dprintf_args(const char* Format, va_list Args);
|
||||
|
|
@ -3,63 +3,65 @@
|
|||
#include "threading.h"
|
||||
|
||||
DWORD
|
||||
SafeUnDecorateSymbolName(
|
||||
SafeUnDecorateSymbolName(
|
||||
__in PCSTR name,
|
||||
__out_ecount(maxStringLength) PSTR outputString,
|
||||
__in DWORD maxStringLength,
|
||||
__in DWORD flags
|
||||
)
|
||||
)
|
||||
{
|
||||
// NOTE: Disabled because of potential recursive deadlocks
|
||||
// EXCLUSIVE_ACQUIRE(LockSym);
|
||||
return UnDecorateSymbolName(name, outputString, maxStringLength, flags);
|
||||
}
|
||||
BOOL
|
||||
SafeSymUnloadModule64(
|
||||
SafeSymUnloadModule64(
|
||||
__in HANDLE hProcess,
|
||||
__in DWORD64 BaseOfDll
|
||||
)
|
||||
)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockSym);
|
||||
return SymUnloadModule64(hProcess, BaseOfDll);
|
||||
}
|
||||
BOOL
|
||||
SafeSymSetSearchPath(
|
||||
SafeSymSetSearchPath(
|
||||
__in HANDLE hProcess,
|
||||
__in_opt PCSTR SearchPath
|
||||
)
|
||||
)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockSym);
|
||||
return SymSetSearchPath(hProcess, SearchPath);
|
||||
}
|
||||
DWORD
|
||||
SafeSymSetOptions(
|
||||
SafeSymSetOptions(
|
||||
__in DWORD SymOptions
|
||||
)
|
||||
)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockSym);
|
||||
return SymSetOptions(SymOptions);
|
||||
}
|
||||
BOOL
|
||||
SafeSymInitialize(
|
||||
SafeSymInitialize(
|
||||
__in HANDLE hProcess,
|
||||
__in_opt PCSTR UserSearchPath,
|
||||
__in BOOL fInvadeProcess
|
||||
)
|
||||
)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockSym);
|
||||
return SymInitialize(hProcess, UserSearchPath, fInvadeProcess);
|
||||
}
|
||||
BOOL
|
||||
SafeSymRegisterCallback64(
|
||||
SafeSymRegisterCallback64(
|
||||
__in HANDLE hProcess,
|
||||
__in PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction,
|
||||
__in ULONG64 UserContext
|
||||
)
|
||||
)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockSym);
|
||||
return SymRegisterCallback64(hProcess, CallbackFunction, UserContext);
|
||||
}
|
||||
DWORD64
|
||||
SafeSymLoadModuleEx(
|
||||
SafeSymLoadModuleEx(
|
||||
__in HANDLE hProcess,
|
||||
__in_opt HANDLE hFile,
|
||||
__in_opt PCSTR ImageName,
|
||||
|
|
@ -68,99 +70,89 @@ DWORD64
|
|||
__in DWORD DllSize,
|
||||
__in_opt PMODLOAD_DATA Data,
|
||||
__in_opt DWORD Flags
|
||||
)
|
||||
)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockSym);
|
||||
return SymLoadModuleEx(hProcess, hFile, ImageName, ModuleName, BaseOfDll, DllSize, Data, Flags);
|
||||
}
|
||||
BOOL
|
||||
SafeSymGetModuleInfo64(
|
||||
SafeSymGetModuleInfo64(
|
||||
__in HANDLE hProcess,
|
||||
__in DWORD64 qwAddr,
|
||||
__out PIMAGEHLP_MODULE64 ModuleInfo
|
||||
)
|
||||
)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockSym);
|
||||
return SymGetModuleInfo64(hProcess, qwAddr, ModuleInfo);
|
||||
}
|
||||
BOOL
|
||||
SafeSymGetSearchPath(
|
||||
SafeSymGetSearchPath(
|
||||
__in HANDLE hProcess,
|
||||
__out_ecount(SearchPathLength) PSTR SearchPath,
|
||||
__in DWORD SearchPathLength
|
||||
)
|
||||
)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockSym);
|
||||
return SymGetSearchPath(hProcess, SearchPath, SearchPathLength);
|
||||
}
|
||||
BOOL
|
||||
SafeSymEnumSymbols(
|
||||
SafeSymEnumSymbols(
|
||||
__in HANDLE hProcess,
|
||||
__in ULONG64 BaseOfDll,
|
||||
__in_opt PCSTR Mask,
|
||||
__in PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
|
||||
__in_opt PVOID UserContext
|
||||
)
|
||||
)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockSym);
|
||||
return SymEnumSymbols(hProcess, BaseOfDll, Mask, EnumSymbolsCallback, UserContext);
|
||||
}
|
||||
BOOL
|
||||
SafeSymEnumerateModules64(
|
||||
__in HANDLE hProcess,
|
||||
__in PSYM_ENUMMODULES_CALLBACK64 EnumModulesCallback,
|
||||
__in_opt PVOID UserContext
|
||||
)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockSym);
|
||||
return SymEnumerateModules64(hProcess, EnumModulesCallback, UserContext);
|
||||
}
|
||||
BOOL
|
||||
SafeSymEnumerateModules(
|
||||
SafeSymEnumerateModules64(
|
||||
__in HANDLE hProcess,
|
||||
__in PSYM_ENUMMODULES_CALLBACK EnumModulesCallback,
|
||||
__in PSYM_ENUMMODULES_CALLBACK64 EnumModulesCallback,
|
||||
__in_opt PVOID UserContext
|
||||
)
|
||||
)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockSym);
|
||||
return SymEnumerateModules(hProcess, EnumModulesCallback, UserContext);
|
||||
return SymEnumerateModules64(hProcess, EnumModulesCallback, UserContext);
|
||||
}
|
||||
BOOL
|
||||
SafeSymGetLineFromAddr64(
|
||||
SafeSymGetLineFromAddr64(
|
||||
__in HANDLE hProcess,
|
||||
__in DWORD64 qwAddr,
|
||||
__out PDWORD pdwDisplacement,
|
||||
__out PIMAGEHLP_LINE64 Line64
|
||||
)
|
||||
)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockSym);
|
||||
return SymGetLineFromAddr64(hProcess, qwAddr, pdwDisplacement, Line64);
|
||||
}
|
||||
BOOL
|
||||
SafeSymFromName(
|
||||
SafeSymFromName(
|
||||
__in HANDLE hProcess,
|
||||
__in PCSTR Name,
|
||||
__inout PSYMBOL_INFO Symbol
|
||||
)
|
||||
)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockSym);
|
||||
return SymFromName(hProcess, Name, Symbol);
|
||||
}
|
||||
BOOL
|
||||
SafeSymFromAddr(
|
||||
SafeSymFromAddr(
|
||||
__in HANDLE hProcess,
|
||||
__in DWORD64 Address,
|
||||
__out_opt PDWORD64 Displacement,
|
||||
__inout PSYMBOL_INFO Symbol
|
||||
)
|
||||
)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockSym);
|
||||
return SymFromAddr(hProcess, Address, Displacement, Symbol);
|
||||
}
|
||||
BOOL
|
||||
SafeSymCleanup(
|
||||
SafeSymCleanup(
|
||||
__in HANDLE hProcess
|
||||
)
|
||||
)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockSym);
|
||||
return SymCleanup(hProcess);
|
||||
|
|
|
|||
|
|
@ -8,40 +8,40 @@
|
|||
#endif //__GNUC__
|
||||
|
||||
DWORD
|
||||
SafeUnDecorateSymbolName(
|
||||
SafeUnDecorateSymbolName(
|
||||
__in PCSTR name,
|
||||
__out_ecount(maxStringLength) PSTR outputString,
|
||||
__in DWORD maxStringLength,
|
||||
__in DWORD flags
|
||||
);
|
||||
);
|
||||
BOOL
|
||||
SafeSymUnloadModule64(
|
||||
SafeSymUnloadModule64(
|
||||
__in HANDLE hProcess,
|
||||
__in DWORD64 BaseOfDll
|
||||
);
|
||||
);
|
||||
BOOL
|
||||
SafeSymSetSearchPath(
|
||||
SafeSymSetSearchPath(
|
||||
__in HANDLE hProcess,
|
||||
__in_opt PCSTR SearchPath
|
||||
);
|
||||
);
|
||||
DWORD
|
||||
SafeSymSetOptions(
|
||||
SafeSymSetOptions(
|
||||
__in DWORD SymOptions
|
||||
);
|
||||
);
|
||||
BOOL
|
||||
SafeSymInitialize(
|
||||
SafeSymInitialize(
|
||||
__in HANDLE hProcess,
|
||||
__in_opt PCSTR UserSearchPath,
|
||||
__in BOOL fInvadeProcess
|
||||
);
|
||||
);
|
||||
BOOL
|
||||
SafeSymRegisterCallback64(
|
||||
SafeSymRegisterCallback64(
|
||||
__in HANDLE hProcess,
|
||||
__in PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction,
|
||||
__in ULONG64 UserContext
|
||||
);
|
||||
);
|
||||
DWORD64
|
||||
SafeSymLoadModuleEx(
|
||||
SafeSymLoadModuleEx(
|
||||
__in HANDLE hProcess,
|
||||
__in_opt HANDLE hFile,
|
||||
__in_opt PCSTR ImageName,
|
||||
|
|
@ -50,62 +50,56 @@ DWORD64
|
|||
__in DWORD DllSize,
|
||||
__in_opt PMODLOAD_DATA Data,
|
||||
__in_opt DWORD Flags
|
||||
);
|
||||
);
|
||||
BOOL
|
||||
SafeSymGetModuleInfo64(
|
||||
SafeSymGetModuleInfo64(
|
||||
__in HANDLE hProcess,
|
||||
__in DWORD64 qwAddr,
|
||||
__out PIMAGEHLP_MODULE64 ModuleInfo
|
||||
);
|
||||
);
|
||||
BOOL
|
||||
SafeSymGetSearchPath(
|
||||
SafeSymGetSearchPath(
|
||||
__in HANDLE hProcess,
|
||||
__out_ecount(SearchPathLength) PSTR SearchPath,
|
||||
__in DWORD SearchPathLength
|
||||
);
|
||||
);
|
||||
BOOL
|
||||
SafeSymEnumSymbols(
|
||||
SafeSymEnumSymbols(
|
||||
__in HANDLE hProcess,
|
||||
__in ULONG64 BaseOfDll,
|
||||
__in_opt PCSTR Mask,
|
||||
__in PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
|
||||
__in_opt PVOID UserContext
|
||||
);
|
||||
);
|
||||
BOOL
|
||||
SafeSymEnumerateModules64(
|
||||
__in HANDLE hProcess,
|
||||
__in PSYM_ENUMMODULES_CALLBACK64 EnumModulesCallback,
|
||||
__in_opt PVOID UserContext
|
||||
);
|
||||
BOOL
|
||||
SafeSymEnumerateModules(
|
||||
SafeSymEnumerateModules64(
|
||||
__in HANDLE hProcess,
|
||||
__in PSYM_ENUMMODULES_CALLBACK EnumModulesCallback,
|
||||
__in PSYM_ENUMMODULES_CALLBACK64 EnumModulesCallback,
|
||||
__in_opt PVOID UserContext
|
||||
);
|
||||
);
|
||||
BOOL
|
||||
SafeSymGetLineFromAddr64(
|
||||
SafeSymGetLineFromAddr64(
|
||||
__in HANDLE hProcess,
|
||||
__in DWORD64 qwAddr,
|
||||
__out PDWORD pdwDisplacement,
|
||||
__out PIMAGEHLP_LINE64 Line64
|
||||
);
|
||||
);
|
||||
BOOL
|
||||
SafeSymFromName(
|
||||
SafeSymFromName(
|
||||
__in HANDLE hProcess,
|
||||
__in PCSTR Name,
|
||||
__inout PSYMBOL_INFO Symbol
|
||||
);
|
||||
);
|
||||
BOOL
|
||||
SafeSymFromAddr(
|
||||
SafeSymFromAddr(
|
||||
__in HANDLE hProcess,
|
||||
__in DWORD64 Address,
|
||||
__out_opt PDWORD64 Displacement,
|
||||
__inout PSYMBOL_INFO Symbol
|
||||
);
|
||||
);
|
||||
BOOL
|
||||
SafeSymCleanup(
|
||||
SafeSymCleanup(
|
||||
__in HANDLE hProcess
|
||||
);
|
||||
);
|
||||
|
||||
#endif //_DBGHELP_SAFE_H
|
||||
|
|
@ -1,3 +1,9 @@
|
|||
/**
|
||||
@file debugger.cpp
|
||||
|
||||
@brief Implements the debugger class.
|
||||
*/
|
||||
|
||||
#include "debugger.h"
|
||||
#include "console.h"
|
||||
#include "memory.h"
|
||||
|
|
@ -30,14 +36,13 @@ static std::vector<ExceptionRange> ignoredExceptionRange;
|
|||
static SIZE_T cachePrivateUsage = 0;
|
||||
static HANDLE hEvent = 0;
|
||||
static String lastDebugText;
|
||||
|
||||
//Superglobal variables
|
||||
char szFileName[MAX_PATH] = "";
|
||||
char szSymbolCachePath[MAX_PATH] = "";
|
||||
char sqlitedb[deflen] = "";
|
||||
PROCESS_INFORMATION* fdProcessInfo = &g_pi;
|
||||
HANDLE hActiveThread;
|
||||
bool bUndecorateSymbolNames = true;
|
||||
bool bEnableSourceDebugging = true;
|
||||
|
||||
static DWORD WINAPI memMapThread(void* ptr)
|
||||
{
|
||||
|
|
@ -140,7 +145,7 @@ void dbgsetisdetachedbyuser(bool b)
|
|||
|
||||
void dbgclearignoredexceptions()
|
||||
{
|
||||
std::vector<ExceptionRange>().swap(ignoredExceptionRange);
|
||||
ignoredExceptionRange.clear();
|
||||
}
|
||||
|
||||
void dbgaddignoredexception(ExceptionRange range)
|
||||
|
|
@ -185,8 +190,17 @@ DWORD WINAPI updateCallStackThread(void* ptr)
|
|||
void DebugUpdateGui(uint disasm_addr, bool stack)
|
||||
{
|
||||
uint cip = GetContextDataEx(hActiveThread, UE_CIP);
|
||||
if(MemIsValidReadPtr(disasm_addr))
|
||||
if (MemIsValidReadPtr(disasm_addr))
|
||||
{
|
||||
if (bEnableSourceDebugging)
|
||||
{
|
||||
char szSourceFile[MAX_STRING_SIZE] = "";
|
||||
int line = 0;
|
||||
if (SymGetSourceLine(cip, szSourceFile, &line))
|
||||
GuiLoadSourceFile(szSourceFile, line);
|
||||
}
|
||||
GuiDisasmAt(disasm_addr, cip);
|
||||
}
|
||||
uint csp = GetContextDataEx(hActiveThread, UE_CSP);
|
||||
if(stack)
|
||||
GuiStackDumpAt(csp, csp);
|
||||
|
|
@ -589,7 +603,6 @@ void cbRtrStep()
|
|||
StepOver((void*)cbRtrStep);
|
||||
}
|
||||
|
||||
///custom handlers
|
||||
static void cbCreateProcess(CREATE_PROCESS_DEBUG_INFO* CreateProcessInfo)
|
||||
{
|
||||
void* base = CreateProcessInfo->lpBaseOfImage;
|
||||
|
|
@ -933,6 +946,7 @@ static void cbUnloadDll(UNLOAD_DLL_DEBUG_INFO* UnloadDll)
|
|||
|
||||
static void cbOutputDebugString(OUTPUT_DEBUG_STRING_INFO* DebugString)
|
||||
{
|
||||
|
||||
hActiveThread = ThreadGetHandle(((DEBUG_EVENT*)GetDebugData())->dwThreadId);
|
||||
PLUG_CB_OUTPUTDEBUGSTRING callbackInfo;
|
||||
callbackInfo.DebugString = DebugString;
|
||||
|
|
@ -1021,7 +1035,7 @@ static void cbException(EXCEPTION_DEBUG_INFO* ExceptionData)
|
|||
if(nameInfo.dwType == 0x1000 and nameInfo.dwFlags == 0 and ThreadIsValid(nameInfo.dwThreadID)) //passed basic checks
|
||||
{
|
||||
Memory<char*> ThreadName(MAX_THREAD_NAME_SIZE, "cbException:ThreadName");
|
||||
if(MemRead((void*)nameInfo.szName, ThreadName, MAX_THREAD_NAME_SIZE - 1, 0))
|
||||
if(MemRead((void *)nameInfo.szName, ThreadName, MAX_THREAD_NAME_SIZE - 1, 0))
|
||||
{
|
||||
String ThreadNameEscaped = StringUtils::Escape(ThreadName);
|
||||
dprintf("SetThreadName(%X, \"%s\")\n", nameInfo.dwThreadID, ThreadNameEscaped.c_str());
|
||||
|
|
@ -1752,7 +1766,6 @@ static bool getcommandlineaddr(uint* addr, cmdline_error_t* cmd_line_error)
|
|||
return true;
|
||||
}
|
||||
|
||||
//update the pointer in the GetCommandLine function
|
||||
static bool patchcmdline(uint getcommandline, uint new_command_line, cmdline_error_t* cmd_line_error)
|
||||
{
|
||||
uint command_line_stored = 0;
|
||||
|
|
@ -1878,7 +1891,7 @@ bool dbgsetcmdline(const char* cmd_line, cmdline_error_t* cmd_line_error)
|
|||
return false;
|
||||
}
|
||||
|
||||
if(!MemWrite((void*)(mem + new_command_line.Length), (void*)cmd_line, strlen(cmd_line) + 1, &size))
|
||||
if(!MemWrite((void*)(mem + new_command_line.Length), (void *)cmd_line, strlen(cmd_line) + 1, &size))
|
||||
{
|
||||
cmd_line_error->addr = mem + new_command_line.Length;
|
||||
cmd_line_error->type = CMDL_ERR_WRITE_ANSI_COMMANDLINE;
|
||||
|
|
|
|||
|
|
@ -131,5 +131,6 @@ extern HANDLE hActiveThread;
|
|||
extern char szFileName[MAX_PATH];
|
||||
extern char szSymbolCachePath[MAX_PATH];
|
||||
extern bool bUndecorateSymbolNames;
|
||||
extern bool bEnableSourceDebugging;
|
||||
|
||||
#endif // _DEBUGGER_H
|
||||
|
|
|
|||
|
|
@ -1,3 +1,9 @@
|
|||
/**
|
||||
@file debugger_commands.cpp
|
||||
|
||||
@brief Implements the debugger commands class.
|
||||
*/
|
||||
|
||||
#include "debugger_commands.h"
|
||||
#include "console.h"
|
||||
#include "value.h"
|
||||
|
|
@ -5,7 +11,6 @@
|
|||
#include "memory.h"
|
||||
#include "threading.h"
|
||||
#include "variable.h"
|
||||
#include "argument.h"
|
||||
#include "plugin_loader.h"
|
||||
#include "simplescript.h"
|
||||
#include "symbolinfo.h"
|
||||
|
|
@ -29,8 +34,12 @@ CMDRESULT cbDebugInit(int argc, char* argv[])
|
|||
DbgCmdExecDirect("stop");
|
||||
|
||||
static char arg1[deflen] = "";
|
||||
if(!argget(*argv, arg1, 0, false))
|
||||
if(argc < 2)
|
||||
{
|
||||
dputs("not enough arguments!");
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
strcpy_s(arg1, argv[1]);
|
||||
char szResolvedPath[MAX_PATH] = "";
|
||||
if(ResolveShortcut(GuiGetWindowHandle(), StringUtils::Utf8ToUtf16(arg1).c_str(), szResolvedPath, _countof(szResolvedPath)))
|
||||
{
|
||||
|
|
@ -70,13 +79,15 @@ CMDRESULT cbDebugInit(int argc, char* argv[])
|
|||
}
|
||||
|
||||
static char arg2[deflen] = "";
|
||||
argget(*argv, arg2, 1, true);
|
||||
if(argc > 2)
|
||||
strcpy_s(arg2, argv[2]);
|
||||
char* commandline = 0;
|
||||
if(strlen(arg2))
|
||||
commandline = arg2;
|
||||
|
||||
char arg3[deflen] = "";
|
||||
argget(*argv, arg3, 2, true);
|
||||
if(argc > 3)
|
||||
strcpy_s(arg3, argv[3]);
|
||||
|
||||
static char currentfolder[deflen] = "";
|
||||
strcpy_s(currentfolder, arg1);
|
||||
|
|
@ -134,25 +145,27 @@ CMDRESULT cbDebugErun(int argc, char* argv[])
|
|||
|
||||
CMDRESULT cbDebugSetBPXOptions(int argc, char* argv[])
|
||||
{
|
||||
char argtype[deflen] = "";
|
||||
DWORD type = 0;
|
||||
if(!argget(*argv, argtype, 0, false))
|
||||
if(argc < 2)
|
||||
{
|
||||
dputs("not enough arguments!");
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
DWORD type = 0;
|
||||
const char* a = 0;
|
||||
uint setting_type;
|
||||
if(strstr(argtype, "long"))
|
||||
if(strstr(argv[1], "long"))
|
||||
{
|
||||
setting_type = 1; //break_int3long
|
||||
a = "TYPE_LONG_INT3";
|
||||
type = UE_BREAKPOINT_LONG_INT3;
|
||||
}
|
||||
else if(strstr(argtype, "ud2"))
|
||||
else if(strstr(argv[1], "ud2"))
|
||||
{
|
||||
setting_type = 2; //break_ud2
|
||||
a = "TYPE_UD2";
|
||||
type = UE_BREAKPOINT_UD2;
|
||||
}
|
||||
else if(strstr(argtype, "short"))
|
||||
else if(strstr(argv[1], "short"))
|
||||
{
|
||||
setting_type = 0; //break_int3short
|
||||
a = "TYPE_INT3";
|
||||
|
|
@ -171,13 +184,20 @@ CMDRESULT cbDebugSetBPXOptions(int argc, char* argv[])
|
|||
|
||||
CMDRESULT cbDebugSetBPX(int argc, char* argv[]) //bp addr [,name [,type]]
|
||||
{
|
||||
char argaddr[deflen] = "";
|
||||
if(!argget(*argv, argaddr, 0, false))
|
||||
if(argc < 2)
|
||||
{
|
||||
dputs("not enough arguments!");
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
char argaddr[deflen] = "";
|
||||
strcpy_s(argaddr, argv[1]);
|
||||
char argname[deflen] = "";
|
||||
argget(*argv, argname, 1, true);
|
||||
if(argc > 2)
|
||||
strcpy_s(argname, argv[2]);
|
||||
char argtype[deflen] = "";
|
||||
bool has_arg2 = argget(*argv, argtype, 2, true);
|
||||
bool has_arg2 = argc > 3;
|
||||
if(has_arg2)
|
||||
strcpy_s(argtype, argv[3]);
|
||||
if(!has_arg2 and (scmp(argname, "ss") or scmp(argname, "long") or scmp(argname, "ud2")))
|
||||
{
|
||||
strcpy_s(argtype, argname);
|
||||
|
|
@ -241,8 +261,7 @@ CMDRESULT cbDebugSetBPX(int argc, char* argv[]) //bp addr [,name [,type]]
|
|||
|
||||
CMDRESULT cbDebugDeleteBPX(int argc, char* argv[])
|
||||
{
|
||||
char arg1[deflen] = "";
|
||||
if(!argget(*argv, arg1, 0, true)) //delete all breakpoints
|
||||
if(argc < 2) //delete all breakpoints
|
||||
{
|
||||
if(!BpGetCount(BPNORMAL))
|
||||
{
|
||||
|
|
@ -256,7 +275,7 @@ CMDRESULT cbDebugDeleteBPX(int argc, char* argv[])
|
|||
return STATUS_CONTINUE;
|
||||
}
|
||||
BREAKPOINT found;
|
||||
if(BpGet(0, BPNORMAL, arg1, &found)) //found a breakpoint with name
|
||||
if(BpGet(0, BPNORMAL, argv[1], &found)) //found a breakpoint with name
|
||||
{
|
||||
if(!BpDelete(found.addr, BPNORMAL))
|
||||
{
|
||||
|
|
@ -272,9 +291,9 @@ CMDRESULT cbDebugDeleteBPX(int argc, char* argv[])
|
|||
return STATUS_CONTINUE;
|
||||
}
|
||||
uint addr = 0;
|
||||
if(!valfromstring(arg1, &addr) or !BpGet(addr, BPNORMAL, 0, &found)) //invalid breakpoint
|
||||
if(!valfromstring(argv[1], &addr) or !BpGet(addr, BPNORMAL, 0, &found)) //invalid breakpoint
|
||||
{
|
||||
dprintf("No such breakpoint \"%s\"\n", arg1);
|
||||
dprintf("No such breakpoint \"%s\"\n", argv[1]);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
if(!BpDelete(found.addr, BPNORMAL))
|
||||
|
|
@ -295,8 +314,7 @@ CMDRESULT cbDebugDeleteBPX(int argc, char* argv[])
|
|||
|
||||
CMDRESULT cbDebugEnableBPX(int argc, char* argv[])
|
||||
{
|
||||
char arg1[deflen] = "";
|
||||
if(!argget(*argv, arg1, 0, true)) //enable all breakpoints
|
||||
if(argc < 2) //enable all breakpoints
|
||||
{
|
||||
if(!BpGetCount(BPNORMAL))
|
||||
{
|
||||
|
|
@ -310,7 +328,7 @@ CMDRESULT cbDebugEnableBPX(int argc, char* argv[])
|
|||
return STATUS_CONTINUE;
|
||||
}
|
||||
BREAKPOINT found;
|
||||
if(BpGet(0, BPNORMAL, arg1, &found)) //found a breakpoint with name
|
||||
if(BpGet(0, BPNORMAL, argv[1], &found)) //found a breakpoint with name
|
||||
{
|
||||
if(!BpEnable(found.addr, BPNORMAL, true) or !SetBPX(found.addr, found.titantype, (void*)cbUserBreakpoint))
|
||||
{
|
||||
|
|
@ -321,9 +339,9 @@ CMDRESULT cbDebugEnableBPX(int argc, char* argv[])
|
|||
return STATUS_CONTINUE;
|
||||
}
|
||||
uint addr = 0;
|
||||
if(!valfromstring(arg1, &addr) or !BpGet(addr, BPNORMAL, 0, &found)) //invalid breakpoint
|
||||
if(!valfromstring(argv[1], &addr) or !BpGet(addr, BPNORMAL, 0, &found)) //invalid breakpoint
|
||||
{
|
||||
dprintf("No such breakpoint \"%s\"\n", arg1);
|
||||
dprintf("No such breakpoint \"%s\"\n", argv[1]);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
if(found.enabled)
|
||||
|
|
@ -344,8 +362,7 @@ CMDRESULT cbDebugEnableBPX(int argc, char* argv[])
|
|||
|
||||
CMDRESULT cbDebugDisableBPX(int argc, char* argv[])
|
||||
{
|
||||
char arg1[deflen] = "";
|
||||
if(!argget(*argv, arg1, 0, true)) //delete all breakpoints
|
||||
if(argc < 2) //delete all breakpoints
|
||||
{
|
||||
if(!BpGetCount(BPNORMAL))
|
||||
{
|
||||
|
|
@ -359,7 +376,7 @@ CMDRESULT cbDebugDisableBPX(int argc, char* argv[])
|
|||
return STATUS_CONTINUE;
|
||||
}
|
||||
BREAKPOINT found;
|
||||
if(BpGet(0, BPNORMAL, arg1, &found)) //found a breakpoint with name
|
||||
if(BpGet(0, BPNORMAL, argv[1], &found)) //found a breakpoint with name
|
||||
{
|
||||
if(!BpEnable(found.addr, BPNORMAL, false) or !DeleteBPX(found.addr))
|
||||
{
|
||||
|
|
@ -370,9 +387,9 @@ CMDRESULT cbDebugDisableBPX(int argc, char* argv[])
|
|||
return STATUS_CONTINUE;
|
||||
}
|
||||
uint addr = 0;
|
||||
if(!valfromstring(arg1, &addr) or !BpGet(addr, BPNORMAL, 0, &found)) //invalid breakpoint
|
||||
if(!valfromstring(argv[1], &addr) or !BpGet(addr, BPNORMAL, 0, &found)) //invalid breakpoint
|
||||
{
|
||||
dprintf("No such breakpoint \"%s\"\n", arg1);
|
||||
dprintf("No such breakpoint \"%s\"\n", argv[1]);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
if(!found.enabled)
|
||||
|
|
@ -424,13 +441,10 @@ CMDRESULT cbDebugeStepOver(int argc, char* argv[])
|
|||
|
||||
CMDRESULT cbDebugSingleStep(int argc, char* argv[])
|
||||
{
|
||||
char arg1[deflen] = "";
|
||||
uint stepcount = 1;
|
||||
if(argget(*argv, arg1, 0, true))
|
||||
{
|
||||
if(!valfromstring(arg1, &stepcount))
|
||||
if(argc > 1)
|
||||
if(!valfromstring(argv[1], &stepcount))
|
||||
stepcount = 1;
|
||||
}
|
||||
SingleStep((DWORD)stepcount, (void*)cbStep);
|
||||
dbgsetstepping(true);
|
||||
return cbDebugRun(argc, argv);
|
||||
|
|
@ -453,10 +467,9 @@ CMDRESULT cbDebugHide(int argc, char* argv[])
|
|||
|
||||
CMDRESULT cbDebugDisasm(int argc, char* argv[])
|
||||
{
|
||||
char arg1[deflen] = "";
|
||||
uint addr = GetContextDataEx(hActiveThread, UE_CIP);
|
||||
if(argget(*argv, arg1, 0, true))
|
||||
if(!valfromstring(arg1, &addr))
|
||||
uint addr;
|
||||
if(argc > 1)
|
||||
if(!valfromstring(argv[1], &addr))
|
||||
addr = GetContextDataEx(hActiveThread, UE_CIP);
|
||||
if(!MemIsValidReadPtr(addr))
|
||||
return STATUS_CONTINUE;
|
||||
|
|
@ -466,24 +479,26 @@ CMDRESULT cbDebugDisasm(int argc, char* argv[])
|
|||
|
||||
CMDRESULT cbDebugSetMemoryBpx(int argc, char* argv[])
|
||||
{
|
||||
char arg1[deflen] = ""; //addr
|
||||
if(!argget(*argv, arg1, 0, false))
|
||||
if(argc < 2)
|
||||
{
|
||||
dputs("not enough arguments!");
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
uint addr;
|
||||
if(!valfromstring(arg1, &addr))
|
||||
if(!valfromstring(argv[1], &addr))
|
||||
return STATUS_ERROR;
|
||||
bool restore = false;
|
||||
char arg2[deflen] = ""; //restore
|
||||
char arg3[deflen] = ""; //type
|
||||
argget(*argv, arg3, 2, true);
|
||||
if(argget(*argv, arg2, 1, true))
|
||||
char arg3[deflen] = "";
|
||||
if(argc > 3)
|
||||
strcpy_s(arg3, argv[3]);
|
||||
if(argc > 2)
|
||||
{
|
||||
if(*arg2 == '1')
|
||||
if(*argv[2] == '1')
|
||||
restore = true;
|
||||
else if(*arg2 == '0')
|
||||
else if(*argv[2] == '0')
|
||||
restore = false;
|
||||
else
|
||||
strcpy_s(arg3, arg2);
|
||||
strcpy_s(arg3, argv[2]);
|
||||
}
|
||||
DWORD type = UE_MEMORY;
|
||||
if(*arg3)
|
||||
|
|
@ -527,7 +542,7 @@ CMDRESULT cbDebugSetMemoryBpx(int argc, char* argv[])
|
|||
CMDRESULT cbDebugDeleteMemoryBreakpoint(int argc, char* argv[])
|
||||
{
|
||||
char arg1[deflen] = "";
|
||||
if(!argget(*argv, arg1, 0, true)) //delete all breakpoints
|
||||
if(argc < 2) //delete all breakpoints
|
||||
{
|
||||
if(!BpGetCount(BPMEMORY))
|
||||
{
|
||||
|
|
@ -585,17 +600,18 @@ CMDRESULT cbDebugeRtr(int argc, char* argv[])
|
|||
|
||||
CMDRESULT cbDebugSetHardwareBreakpoint(int argc, char* argv[])
|
||||
{
|
||||
char arg1[deflen] = ""; //addr
|
||||
if(!argget(*argv, arg1, 0, false))
|
||||
if(argc < 2)
|
||||
{
|
||||
dputs("not enough arguments!");
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
uint addr;
|
||||
if(!valfromstring(arg1, &addr))
|
||||
if(!valfromstring(argv[1], &addr))
|
||||
return STATUS_ERROR;
|
||||
DWORD type = UE_HARDWARE_EXECUTE;
|
||||
char arg2[deflen] = ""; //type
|
||||
if(argget(*argv, arg2, 1, true))
|
||||
if(argc > 2)
|
||||
{
|
||||
switch(*arg2)
|
||||
switch(*argv[2])
|
||||
{
|
||||
case 'r':
|
||||
type = UE_HARDWARE_READWRITE;
|
||||
|
|
@ -610,12 +626,11 @@ CMDRESULT cbDebugSetHardwareBreakpoint(int argc, char* argv[])
|
|||
break;
|
||||
}
|
||||
}
|
||||
char arg3[deflen] = ""; //size
|
||||
DWORD titsize = UE_HARDWARE_SIZE_1;
|
||||
if(argget(*argv, arg3, 2, true))
|
||||
if(argc > 3)
|
||||
{
|
||||
uint size;
|
||||
if(!valfromstring(arg3, &size))
|
||||
if(!valfromstring(argv[3], &size))
|
||||
return STATUS_ERROR;
|
||||
switch(size)
|
||||
{
|
||||
|
|
@ -677,8 +692,7 @@ CMDRESULT cbDebugSetHardwareBreakpoint(int argc, char* argv[])
|
|||
|
||||
CMDRESULT cbDebugDeleteHardwareBreakpoint(int argc, char* argv[])
|
||||
{
|
||||
char arg1[deflen] = "";
|
||||
if(!argget(*argv, arg1, 0, true)) //delete all breakpoints
|
||||
if(argc < 2) //delete all breakpoints
|
||||
{
|
||||
if(!BpGetCount(BPHARDWARE))
|
||||
{
|
||||
|
|
@ -692,7 +706,7 @@ CMDRESULT cbDebugDeleteHardwareBreakpoint(int argc, char* argv[])
|
|||
return STATUS_CONTINUE;
|
||||
}
|
||||
BREAKPOINT found;
|
||||
if(BpGet(0, BPHARDWARE, arg1, &found)) //found a breakpoint with name
|
||||
if(BpGet(0, BPHARDWARE, argv[1], &found)) //found a breakpoint with name
|
||||
{
|
||||
if(!BpDelete(found.addr, BPHARDWARE) or !DeleteHardwareBreakPoint(TITANGETDRX(found.titantype)))
|
||||
{
|
||||
|
|
@ -702,9 +716,9 @@ CMDRESULT cbDebugDeleteHardwareBreakpoint(int argc, char* argv[])
|
|||
return STATUS_CONTINUE;
|
||||
}
|
||||
uint addr = 0;
|
||||
if(!valfromstring(arg1, &addr) or !BpGet(addr, BPHARDWARE, 0, &found)) //invalid breakpoint
|
||||
if(!valfromstring(argv[1], &addr) or !BpGet(addr, BPHARDWARE, 0, &found)) //invalid breakpoint
|
||||
{
|
||||
dprintf("No such hardware breakpoint \"%s\"\n", arg1);
|
||||
dprintf("No such hardware breakpoint \"%s\"\n", argv[1]);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
if(!BpDelete(found.addr, BPHARDWARE) or !DeleteHardwareBreakPoint(TITANGETDRX(found.titantype)))
|
||||
|
|
@ -719,10 +733,9 @@ CMDRESULT cbDebugDeleteHardwareBreakpoint(int argc, char* argv[])
|
|||
|
||||
CMDRESULT cbDebugAlloc(int argc, char* argv[])
|
||||
{
|
||||
char arg1[deflen] = ""; //size
|
||||
uint size = 0x1000;
|
||||
if(argget(*argv, arg1, 0, true))
|
||||
if(!valfromstring(arg1, &size, false))
|
||||
if(argc > 1)
|
||||
if(!valfromstring(argv[1], &size, false))
|
||||
return STATUS_ERROR;
|
||||
uint mem = (uint)MemAllocRemote(0, size, PAGE_EXECUTE_READWRITE);
|
||||
if(!mem)
|
||||
|
|
@ -742,11 +755,10 @@ CMDRESULT cbDebugFree(int argc, char* argv[])
|
|||
{
|
||||
uint lastalloc;
|
||||
varget("$lastalloc", &lastalloc, 0, 0);
|
||||
char arg1[deflen] = ""; //addr
|
||||
uint addr = lastalloc;
|
||||
if(argget(*argv, arg1, 0, true))
|
||||
if(argc > 1)
|
||||
{
|
||||
if(!valfromstring(arg1, &addr, false))
|
||||
if(!valfromstring(argv[1], &addr, false))
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
else if(!lastalloc)
|
||||
|
|
@ -768,7 +780,6 @@ CMDRESULT cbDebugFree(int argc, char* argv[])
|
|||
|
||||
CMDRESULT cbDebugMemset(int argc, char* argv[])
|
||||
{
|
||||
char arg3[deflen] = ""; //size
|
||||
uint addr;
|
||||
uint value;
|
||||
uint size;
|
||||
|
|
@ -779,9 +790,9 @@ CMDRESULT cbDebugMemset(int argc, char* argv[])
|
|||
}
|
||||
if(!valfromstring(argv[1], &addr, false) or !valfromstring(argv[2], &value, false))
|
||||
return STATUS_ERROR;
|
||||
if(argget(*argv, arg3, 2, true))
|
||||
if(argc > 3)
|
||||
{
|
||||
if(!valfromstring(arg3, &size, false))
|
||||
if(!valfromstring(argv[3], &size, false))
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
else
|
||||
|
|
@ -812,7 +823,7 @@ CMDRESULT cbDebugBenchmark(int argc, char* argv[])
|
|||
for(uint i = addr; i < addr + 100000; i++)
|
||||
{
|
||||
CommentSet(i, "test", false);
|
||||
labelset(i, "test", false);
|
||||
LabelSet(i, "test", false);
|
||||
BookmarkSet(i, false);
|
||||
FunctionAdd(i, i, false);
|
||||
}
|
||||
|
|
@ -1201,14 +1212,13 @@ CMDRESULT cbDebugSetPriority(int argc, char* argv[])
|
|||
|
||||
CMDRESULT cbDebugEnableHardwareBreakpoint(int argc, char* argv[])
|
||||
{
|
||||
char arg1[deflen] = "";
|
||||
DWORD drx = 0;
|
||||
if(!GetUnusedHardwareBreakPointRegister(&drx))
|
||||
{
|
||||
dputs("You can only set 4 hardware breakpoints");
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
if(!argget(*argv, arg1, 0, true)) //enable all hardware breakpoints
|
||||
if(argc < 2) //enable all hardware breakpoints
|
||||
{
|
||||
if(!BpGetCount(BPHARDWARE))
|
||||
{
|
||||
|
|
@ -1223,9 +1233,9 @@ CMDRESULT cbDebugEnableHardwareBreakpoint(int argc, char* argv[])
|
|||
}
|
||||
BREAKPOINT found;
|
||||
uint addr = 0;
|
||||
if(!valfromstring(arg1, &addr) or !BpGet(addr, BPHARDWARE, 0, &found)) //invalid hardware breakpoint
|
||||
if(!valfromstring(argv[1], &addr) or !BpGet(addr, BPHARDWARE, 0, &found)) //invalid hardware breakpoint
|
||||
{
|
||||
dprintf("No such hardware breakpoint \"%s\"\n", arg1);
|
||||
dprintf("No such hardware breakpoint \"%s\"\n", argv[1]);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
if(found.enabled)
|
||||
|
|
@ -1248,8 +1258,7 @@ CMDRESULT cbDebugEnableHardwareBreakpoint(int argc, char* argv[])
|
|||
|
||||
CMDRESULT cbDebugDisableHardwareBreakpoint(int argc, char* argv[])
|
||||
{
|
||||
char arg1[deflen] = "";
|
||||
if(!argget(*argv, arg1, 0, true)) //delete all hardware breakpoints
|
||||
if(argc < 2) //delete all hardware breakpoints
|
||||
{
|
||||
if(!BpGetCount(BPHARDWARE))
|
||||
{
|
||||
|
|
@ -1264,9 +1273,9 @@ CMDRESULT cbDebugDisableHardwareBreakpoint(int argc, char* argv[])
|
|||
}
|
||||
BREAKPOINT found;
|
||||
uint addr = 0;
|
||||
if(!valfromstring(arg1, &addr) or !BpGet(addr, BPHARDWARE, 0, &found)) //invalid hardware breakpoint
|
||||
if(!valfromstring(argv[1], &addr) or !BpGet(addr, BPHARDWARE, 0, &found)) //invalid hardware breakpoint
|
||||
{
|
||||
dprintf("No such hardware breakpoint \"%s\"\n", arg1);
|
||||
dprintf("No such hardware breakpoint \"%s\"\n", argv[1]);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
if(!found.enabled)
|
||||
|
|
@ -1286,21 +1295,14 @@ CMDRESULT cbDebugDisableHardwareBreakpoint(int argc, char* argv[])
|
|||
|
||||
CMDRESULT cbDebugEnableMemoryBreakpoint(int argc, char* argv[])
|
||||
{
|
||||
char arg1[deflen] = "";
|
||||
DWORD drx = 0;
|
||||
if(!GetUnusedHardwareBreakPointRegister(0))
|
||||
{
|
||||
dputs("You can only set 4 hardware breakpoints");
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
if(!argget(*argv, arg1, 0, true)) //enable all memory breakpoints
|
||||
if(argc < 2) //enable all memory breakpoints
|
||||
{
|
||||
if(!BpGetCount(BPMEMORY))
|
||||
{
|
||||
dputs("No hardware breakpoints to enable!");
|
||||
dputs("No memory breakpoints to enable!");
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
if(!BpEnumAll(cbEnableAllHardwareBreakpoints)) //at least one enable failed
|
||||
if(!BpEnumAll(cbEnableAllMemoryBreakpoints)) //at least one enable failed
|
||||
return STATUS_ERROR;
|
||||
dputs("All memory breakpoints enabled!");
|
||||
GuiUpdateAllViews();
|
||||
|
|
@ -1308,14 +1310,14 @@ CMDRESULT cbDebugEnableMemoryBreakpoint(int argc, char* argv[])
|
|||
}
|
||||
BREAKPOINT found;
|
||||
uint addr = 0;
|
||||
if(!valfromstring(arg1, &addr) or !BpGet(addr, BPMEMORY, 0, &found)) //invalid memory breakpoint
|
||||
if(!valfromstring(argv[1], &addr) or !BpGet(addr, BPMEMORY, 0, &found)) //invalid memory breakpoint
|
||||
{
|
||||
dprintf("No such memory breakpoint \"%s\"\n", arg1);
|
||||
dprintf("No such memory breakpoint \"%s\"\n", argv[1]);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
if(found.enabled)
|
||||
{
|
||||
dputs("Hardware memory already enabled!");
|
||||
dputs("Memory memory already enabled!");
|
||||
GuiUpdateAllViews();
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
|
|
@ -1333,8 +1335,7 @@ CMDRESULT cbDebugEnableMemoryBreakpoint(int argc, char* argv[])
|
|||
|
||||
CMDRESULT cbDebugDisableMemoryBreakpoint(int argc, char* argv[])
|
||||
{
|
||||
char arg1[deflen] = "";
|
||||
if(!argget(*argv, arg1, 0, true)) //delete all memory breakpoints
|
||||
if(argc < 2) //delete all memory breakpoints
|
||||
{
|
||||
if(!BpGetCount(BPMEMORY))
|
||||
{
|
||||
|
|
@ -1349,9 +1350,9 @@ CMDRESULT cbDebugDisableMemoryBreakpoint(int argc, char* argv[])
|
|||
}
|
||||
BREAKPOINT found;
|
||||
uint addr = 0;
|
||||
if(!valfromstring(arg1, &addr) or !BpGet(addr, BPMEMORY, 0, &found)) //invalid memory breakpoint
|
||||
if(!valfromstring(argv[1], &addr) or !BpGet(addr, BPMEMORY, 0, &found)) //invalid memory breakpoint
|
||||
{
|
||||
dprintf("No such memory breakpoint \"%s\"\n", arg1);
|
||||
dprintf("No such memory breakpoint \"%s\"\n", argv[1]);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
if(!found.enabled)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,9 @@
|
|||
/**
|
||||
@file disasm_fast.cpp
|
||||
|
||||
@brief Implements the disasm fast class.
|
||||
*/
|
||||
|
||||
#include "disasm_fast.h"
|
||||
#include "debugger.h"
|
||||
#include "memory.h"
|
||||
|
|
@ -117,7 +123,7 @@ bool disasmfast(unsigned char* data, uint addr, BASIC_INSTRUCTION_INFO* basicinf
|
|||
bool disasmfast(uint addr, BASIC_INSTRUCTION_INFO* basicinfo)
|
||||
{
|
||||
unsigned int data[16];
|
||||
if(!MemRead((void*)addr, data, sizeof(data), 0))
|
||||
if(!MemRead((void*)addr, data, sizeof(data), nullptr))
|
||||
return false;
|
||||
return disasmfast((unsigned char*)data, addr, basicinfo);
|
||||
}
|
||||
|
|
@ -1,3 +1,9 @@
|
|||
/**
|
||||
@file disasm_helper.cpp
|
||||
|
||||
@brief Implements the disasm helper class.
|
||||
*/
|
||||
|
||||
#include "disasm_helper.h"
|
||||
#include "BeaEngine\BeaEngine.h"
|
||||
#include "value.h"
|
||||
|
|
|
|||
|
|
@ -4,45 +4,45 @@ template<typename T>
|
|||
class Memory
|
||||
{
|
||||
public:
|
||||
//
|
||||
// This class guarantees that the returned allocated memory
|
||||
// will always be zeroed
|
||||
//
|
||||
//
|
||||
// This class guarantees that the returned allocated memory
|
||||
// will always be zeroed
|
||||
//
|
||||
Memory(const char* Reason = "Memory:???")
|
||||
{
|
||||
m_Ptr = nullptr;
|
||||
m_Size = 0;
|
||||
m_Reason = Reason;
|
||||
m_Ptr = nullptr;
|
||||
m_Size = 0;
|
||||
m_Reason = Reason;
|
||||
}
|
||||
|
||||
Memory(size_t Size, const char* Reason = "Memory:???")
|
||||
{
|
||||
m_Ptr = reinterpret_cast<T>(emalloc(Size));
|
||||
m_Size = Size;
|
||||
m_Reason = Reason;
|
||||
m_Ptr = reinterpret_cast<T>(emalloc(Size));
|
||||
m_Size = Size;
|
||||
m_Reason = Reason;
|
||||
|
||||
memset(m_Ptr, 0, Size);
|
||||
}
|
||||
|
||||
~Memory()
|
||||
{
|
||||
if (m_Ptr)
|
||||
efree(m_Ptr);
|
||||
if (m_Ptr)
|
||||
efree(m_Ptr);
|
||||
}
|
||||
|
||||
T realloc(size_t Size, const char* Reason = "Memory:???")
|
||||
{
|
||||
m_Ptr = reinterpret_cast<T>(erealloc(m_Ptr, Size));
|
||||
m_Size = Size;
|
||||
m_Reason = Reason;
|
||||
m_Ptr = reinterpret_cast<T>(erealloc(m_Ptr, Size));
|
||||
m_Size = Size;
|
||||
m_Reason = Reason;
|
||||
|
||||
return (T)memset(m_Ptr, 0, m_Size);
|
||||
}
|
||||
|
||||
size_t size()
|
||||
{
|
||||
return m_Size;
|
||||
}
|
||||
size_t size()
|
||||
{
|
||||
return m_Size;
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
operator U()
|
||||
|
|
@ -60,14 +60,14 @@ public:
|
|||
return m_Ptr;
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
T operator+(const U& Other)
|
||||
{
|
||||
return m_Ptr + Other;
|
||||
}
|
||||
template<typename U>
|
||||
T operator+(const U& Other)
|
||||
{
|
||||
return m_Ptr + Other;
|
||||
}
|
||||
|
||||
private:
|
||||
T m_Ptr;
|
||||
size_t m_Size;
|
||||
T m_Ptr;
|
||||
size_t m_Size;
|
||||
const char* m_Reason;
|
||||
};
|
||||
|
|
@ -5,7 +5,7 @@ std::unordered_map<unsigned int, const char*> ErrorNames;
|
|||
|
||||
void ErrorCodeInit()
|
||||
{
|
||||
ErrorNames.clear();
|
||||
ErrorNames.clear();
|
||||
ErrorNames.insert(std::make_pair(0, "ERROR_SUCCESS"));
|
||||
ErrorNames.insert(std::make_pair(1, "ERROR_INVALID_FUNCTION"));
|
||||
ErrorNames.insert(std::make_pair(2, "ERROR_FILE_NOT_FOUND"));
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ std::unordered_map<unsigned int, const char*> ExceptionNames;
|
|||
|
||||
void ExceptionCodeInit()
|
||||
{
|
||||
ExceptionNames.clear();
|
||||
ExceptionNames.clear();
|
||||
ExceptionNames.insert(std::make_pair(0x04242420, "CLRDBG_NOTIFICATION_EXCEPTION_CODE"));
|
||||
ExceptionNames.insert(std::make_pair(0x40000005, "STATUS_SEGMENT_NOTIFICATION"));
|
||||
ExceptionNames.insert(std::make_pair(0x4000001C, "STATUS_WX86_UNSIMULATE"));
|
||||
|
|
|
|||
|
|
@ -4,9 +4,7 @@
|
|||
#include "memory.h"
|
||||
#include "threading.h"
|
||||
|
||||
typedef std::map<ModuleRange, FUNCTIONSINFO, ModuleRangeCompare> FunctionsInfo;
|
||||
|
||||
static FunctionsInfo functions;
|
||||
std::map<ModuleRange, FUNCTIONSINFO, ModuleRangeCompare> functions;
|
||||
|
||||
bool FunctionAdd(uint Start, uint End, bool Manual)
|
||||
{
|
||||
|
|
@ -47,22 +45,22 @@ bool FunctionGet(uint Address, uint* Start, uint* End)
|
|||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
|
||||
const uint modbase = ModBaseFromAddr(Address);
|
||||
const uint moduleBase = ModBaseFromAddr(Address);
|
||||
|
||||
// Lookup by module hash, then function range
|
||||
SHARED_ACQUIRE(LockFunctions);
|
||||
|
||||
auto found = functions.find(ModuleRange(ModHashFromAddr(modbase), Range(Address - modbase, Address - modbase)));
|
||||
auto found = functions.find(ModuleRange(ModHashFromAddr(moduleBase), Range(Address - moduleBase, Address - moduleBase)));
|
||||
|
||||
// Was this range found?
|
||||
if(found == functions.end())
|
||||
return false;
|
||||
|
||||
if(Start)
|
||||
*Start = found->second.start + modbase;
|
||||
*Start = found->second.start + moduleBase;
|
||||
|
||||
if(End)
|
||||
*End = found->second.end + modbase;
|
||||
*End = found->second.end + moduleBase;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -102,7 +100,7 @@ void FunctionDelRange(uint Start, uint End)
|
|||
return;
|
||||
|
||||
// Should all functions be deleted?
|
||||
// 0x00000000 - 0xFFFFFFFF
|
||||
// 0x00000000 - 0xFFFFFFFF
|
||||
if(Start == 0 && End == ~0)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockFunctions);
|
||||
|
|
@ -186,36 +184,39 @@ void FunctionCacheLoad(JSON Root)
|
|||
JSON value;
|
||||
json_array_foreach(Object, i, value)
|
||||
{
|
||||
FUNCTIONSINFO function;
|
||||
FUNCTIONSINFO functionInfo;
|
||||
memset(&functionInfo, 0, sizeof(FUNCTIONSINFO));
|
||||
|
||||
// Copy module name
|
||||
const char* mod = json_string_value(json_object_get(value, "module"));
|
||||
|
||||
if(mod && *mod && strlen(mod) < MAX_MODULE_SIZE)
|
||||
strcpy_s(function.mod, mod);
|
||||
strcpy_s(functionInfo.mod, mod);
|
||||
else
|
||||
function.mod[0] = '\0';
|
||||
functionInfo.mod[0] = '\0';
|
||||
|
||||
// Function address
|
||||
function.start = (uint)json_hex_value(json_object_get(value, "start"));
|
||||
function.end = (uint)json_hex_value(json_object_get(value, "end"));
|
||||
function.manual = Manual;
|
||||
functionInfo.start = (uint)json_hex_value(json_object_get(value, "start"));
|
||||
functionInfo.end = (uint)json_hex_value(json_object_get(value, "end"));
|
||||
functionInfo.manual = Manual;
|
||||
|
||||
// Sanity check
|
||||
if(function.end < function.start)
|
||||
if(functionInfo.end < functionInfo.start)
|
||||
continue;
|
||||
|
||||
const uint key = ModHashFromName(function.mod);
|
||||
functions.insert(std::make_pair(ModuleRange(ModHashFromName(function.mod), Range(function.start, function.end)), function));
|
||||
const uint key = ModHashFromName(functionInfo.mod);
|
||||
functions.insert(std::make_pair(ModuleRange(key, Range(functionInfo.start, functionInfo.end)), functionInfo));
|
||||
}
|
||||
};
|
||||
|
||||
const JSON jsonFunctions = json_object_get(Root, "functions");
|
||||
const JSON jsonAutoFunctions = json_object_get(Root, "autofunctions");
|
||||
|
||||
// Manual
|
||||
if(jsonFunctions)
|
||||
InsertFunctions(jsonFunctions, true);
|
||||
|
||||
// Auto
|
||||
if(jsonAutoFunctions)
|
||||
InsertFunctions(jsonAutoFunctions, false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,10 @@
|
|||
/**
|
||||
@file instruction.cpp
|
||||
|
||||
@brief Implements the instruction class.
|
||||
*/
|
||||
|
||||
#include "instruction.h"
|
||||
#include "argument.h"
|
||||
#include "variable.h"
|
||||
#include "console.h"
|
||||
#include "value.h"
|
||||
|
|
@ -18,6 +23,8 @@
|
|||
#include "function.h"
|
||||
#include "loop.h"
|
||||
#include "patternfind.h"
|
||||
#include "module.h"
|
||||
#include "stringformat.h"
|
||||
|
||||
static bool bRefinit = false;
|
||||
|
||||
|
|
@ -84,8 +91,9 @@ CMDRESULT cbInstrVar(int argc, char* argv[])
|
|||
dputs("not enough arguments!");
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
char arg2[deflen] = "";
|
||||
argget(*argv, arg2, 1, true); //var value (optional)
|
||||
char arg2[deflen] = ""; //var value (optional)
|
||||
if(argc > 2)
|
||||
strcpy_s(arg2, argv[2]);
|
||||
uint value = 0;
|
||||
int add = 0;
|
||||
if(*argv[1] == '$')
|
||||
|
|
@ -196,7 +204,7 @@ CMDRESULT cbInstrMov(int argc, char* argv[])
|
|||
valfromstring(argv[1], &temp, true, false, 0, &isvar, 0);
|
||||
if(!isvar)
|
||||
isvar = vargettype(argv[1], 0);
|
||||
if(!isvar or !valtostring(argv[1], &set_value, true))
|
||||
if(!isvar or !valtostring(argv[1], set_value, true))
|
||||
{
|
||||
uint value;
|
||||
if(valfromstring(argv[1], &value)) //if the var is a value already it's an invalid destination
|
||||
|
|
@ -212,15 +220,16 @@ CMDRESULT cbInstrMov(int argc, char* argv[])
|
|||
|
||||
CMDRESULT cbInstrVarList(int argc, char* argv[])
|
||||
{
|
||||
char arg1[deflen] = "";
|
||||
argget(*argv, arg1, 0, true);
|
||||
int filter = 0;
|
||||
if(!_stricmp(arg1, "USER"))
|
||||
filter = VAR_USER;
|
||||
else if(!_stricmp(arg1, "READONLY"))
|
||||
filter = VAR_READONLY;
|
||||
else if(!_stricmp(arg1, "SYSTEM"))
|
||||
filter = VAR_SYSTEM;
|
||||
if(argc > 1)
|
||||
{
|
||||
if(!_stricmp(argv[1], "USER"))
|
||||
filter = VAR_USER;
|
||||
else if(!_stricmp(argv[1], "READONLY"))
|
||||
filter = VAR_READONLY;
|
||||
else if(!_stricmp(argv[1], "SYSTEM"))
|
||||
filter = VAR_SYSTEM;
|
||||
}
|
||||
|
||||
size_t cbsize = 0;
|
||||
if(!varenum(0, &cbsize))
|
||||
|
|
@ -331,7 +340,7 @@ CMDRESULT cbInstrLbl(int argc, char* argv[])
|
|||
uint addr = 0;
|
||||
if(!valfromstring(argv[1], &addr, false))
|
||||
return STATUS_ERROR;
|
||||
if(!labelset(addr, argv[2], true))
|
||||
if(!LabelSet(addr, argv[2], true))
|
||||
{
|
||||
dputs("error setting label");
|
||||
return STATUS_ERROR;
|
||||
|
|
@ -350,7 +359,7 @@ CMDRESULT cbInstrLbldel(int argc, char* argv[])
|
|||
uint addr = 0;
|
||||
if(!valfromstring(argv[1], &addr, false))
|
||||
return STATUS_ERROR;
|
||||
if(!labeldel(addr))
|
||||
if(!LabelDelete(addr))
|
||||
{
|
||||
dputs("error deleting label");
|
||||
return STATUS_ERROR;
|
||||
|
|
@ -803,7 +812,6 @@ struct VALUERANGE
|
|||
uint end;
|
||||
};
|
||||
|
||||
//reffind value[,page]
|
||||
static bool cbRefFind(DISASM* disasm, BASIC_INSTRUCTION_INFO* basicinfo, REFINFO* refinfo)
|
||||
{
|
||||
if(!disasm && !basicinfo) //initialize
|
||||
|
|
@ -886,13 +894,17 @@ CMDRESULT cbInstrRefFindRange(int argc, char* argv[])
|
|||
if(!valfromstring(argv[4], &size))
|
||||
size = 0;
|
||||
uint ticks = GetTickCount();
|
||||
int found = reffind(addr, size, cbRefFind, &range, false, "Constant");
|
||||
char title[256] = "";
|
||||
if(range.start == range.end)
|
||||
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);
|
||||
dprintf("%u reference(s) in %ums\n", found, GetTickCount() - ticks);
|
||||
varset("$result", found, false);
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
|
||||
//refstr [page]
|
||||
bool cbRefStr(DISASM* disasm, BASIC_INSTRUCTION_INFO* basicinfo, REFINFO* refinfo)
|
||||
{
|
||||
if(!disasm && !basicinfo) //initialize
|
||||
|
|
@ -951,7 +963,7 @@ CMDRESULT cbInstrRefStr(int argc, char* argv[])
|
|||
if(!valfromstring(argv[2], &size, true))
|
||||
size = 0;
|
||||
uint ticks = GetTickCount();
|
||||
int found = reffind(addr, size, cbRefStr, 0, false, "Strings");
|
||||
int found = RefFind(addr, size, cbRefStr, 0, false, "Strings");
|
||||
dprintf("%u string(s) in %ums\n", found, GetTickCount() - ticks);
|
||||
varset("$result", found, false);
|
||||
return STATUS_CONTINUE;
|
||||
|
|
@ -1166,7 +1178,13 @@ CMDRESULT cbInstrFindAll(int argc, char* argv[])
|
|||
else
|
||||
find_size = size - start;
|
||||
//setup reference view
|
||||
GuiReferenceInitialize("Occurrences");
|
||||
char patternshort[256] = "";
|
||||
strncpy_s(patternshort, pattern, min(16, len));
|
||||
if(len > 16)
|
||||
strcat_s(patternshort, "...");
|
||||
char patterntitle[256] = "";
|
||||
sprintf_s(patterntitle, "Pattern: %s", patternshort);
|
||||
GuiReferenceInitialize(patterntitle);
|
||||
GuiReferenceAddColumn(2 * sizeof(uint), "Address");
|
||||
if(findData)
|
||||
GuiReferenceAddColumn(0, "&Data&");
|
||||
|
|
@ -1212,7 +1230,6 @@ CMDRESULT cbInstrFindAll(int argc, char* argv[])
|
|||
return STATUS_CONTINUE;
|
||||
}
|
||||
|
||||
//modcallfind [page]
|
||||
static bool cbModCallFind(DISASM* disasm, BASIC_INSTRUCTION_INFO* basicinfo, REFINFO* refinfo)
|
||||
{
|
||||
if(!disasm && !basicinfo) //initialize
|
||||
|
|
@ -1228,7 +1245,7 @@ static bool cbModCallFind(DISASM* disasm, BASIC_INSTRUCTION_INFO* basicinfo, REF
|
|||
{
|
||||
uint ptr = basicinfo->addr > 0 ? basicinfo->addr : basicinfo->memory.value;
|
||||
char label[MAX_LABEL_SIZE] = "";
|
||||
found = DbgGetLabelAt(ptr, SEG_DEFAULT, label) && !labelget(ptr, label); //a non-user label
|
||||
found = DbgGetLabelAt(ptr, SEG_DEFAULT, label) && !LabelGet(ptr, label); //a non-user label
|
||||
}
|
||||
if(found)
|
||||
{
|
||||
|
|
@ -1255,7 +1272,7 @@ CMDRESULT cbInstrModCallFind(int argc, char* argv[])
|
|||
if(!valfromstring(argv[2], &size, true))
|
||||
size = 0;
|
||||
uint ticks = GetTickCount();
|
||||
int found = reffind(addr, size, cbModCallFind, 0, false, "Calls");
|
||||
int found = RefFind(addr, size, cbModCallFind, 0, false, "Calls");
|
||||
dprintf("%u call(s) in %ums\n", found, GetTickCount() - ticks);
|
||||
varset("$result", found, false);
|
||||
return STATUS_CONTINUE;
|
||||
|
|
@ -1305,14 +1322,14 @@ CMDRESULT cbInstrLabelList(int argc, char* argv[])
|
|||
GuiReferenceAddColumn(0, "Label");
|
||||
GuiReferenceReloadData();
|
||||
size_t cbsize;
|
||||
labelenum(0, &cbsize);
|
||||
LabelEnum(0, &cbsize);
|
||||
if(!cbsize)
|
||||
{
|
||||
dputs("no labels");
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
Memory<LABELSINFO*> labels(cbsize, "cbInstrLabelList:labels");
|
||||
labelenum(labels, 0);
|
||||
LabelEnum(labels, 0);
|
||||
int count = (int)(cbsize / sizeof(LABELSINFO));
|
||||
for(int i = 0; i < count; i++)
|
||||
{
|
||||
|
|
@ -1395,7 +1412,7 @@ CMDRESULT cbInstrFunctionList(int argc, char* argv[])
|
|||
if(GuiGetDisassembly(functions[i].start, disassembly))
|
||||
GuiReferenceSetCellContent(i, 2, disassembly);
|
||||
char label[MAX_LABEL_SIZE] = "";
|
||||
if(labelget(functions[i].start, label))
|
||||
if(LabelGet(functions[i].start, label))
|
||||
GuiReferenceSetCellContent(i, 3, label);
|
||||
else
|
||||
{
|
||||
|
|
@ -1420,14 +1437,14 @@ CMDRESULT cbInstrLoopList(int argc, char* argv[])
|
|||
GuiReferenceAddColumn(0, "Label/Comment");
|
||||
GuiReferenceReloadData();
|
||||
size_t cbsize;
|
||||
loopenum(0, &cbsize);
|
||||
LoopEnum(0, &cbsize);
|
||||
if(!cbsize)
|
||||
{
|
||||
dputs("no loops");
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
Memory<LOOPSINFO*> loops(cbsize, "cbInstrLoopList:loops");
|
||||
loopenum(loops, 0);
|
||||
LoopEnum(loops, 0);
|
||||
int count = (int)(cbsize / sizeof(LOOPSINFO));
|
||||
for(int i = 0; i < count; i++)
|
||||
{
|
||||
|
|
@ -1441,7 +1458,7 @@ CMDRESULT cbInstrLoopList(int argc, char* argv[])
|
|||
if(GuiGetDisassembly(loops[i].start, disassembly))
|
||||
GuiReferenceSetCellContent(i, 2, disassembly);
|
||||
char label[MAX_LABEL_SIZE] = "";
|
||||
if(labelget(loops[i].start, label))
|
||||
if(LabelGet(loops[i].start, label))
|
||||
GuiReferenceSetCellContent(i, 3, label);
|
||||
else
|
||||
{
|
||||
|
|
@ -1468,7 +1485,6 @@ CMDRESULT cbInstrSleep(int argc, char* argv[])
|
|||
return STATUS_CONTINUE;
|
||||
}
|
||||
|
||||
//reffindasm value[,page]
|
||||
static bool cbFindAsm(DISASM* disasm, BASIC_INSTRUCTION_INFO* basicinfo, REFINFO* refinfo)
|
||||
{
|
||||
if(!disasm && !basicinfo) //initialize
|
||||
|
|
@ -1525,8 +1541,257 @@ CMDRESULT cbInstrFindAsm(int argc, char* argv[])
|
|||
disasmfast(dest, addr + size / 2, &basicinfo);
|
||||
|
||||
uint ticks = GetTickCount();
|
||||
int found = reffind(addr, size, cbFindAsm, (void*)&basicinfo.instruction[0], false, "Command");
|
||||
char title[256] = "";
|
||||
sprintf_s(title, "Command: \"%s\"", basicinfo.instruction);
|
||||
int found = RefFind(addr, size, cbFindAsm, (void*)&basicinfo.instruction[0], false, title);
|
||||
dprintf("%u result(s) in %ums\n", found, GetTickCount() - ticks);
|
||||
varset("$result", found, false);
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
|
||||
static void yaraCompilerCallback(int error_level, const char* file_name, int line_number, const char* message, void* user_data)
|
||||
{
|
||||
switch(error_level)
|
||||
{
|
||||
case YARA_ERROR_LEVEL_ERROR:
|
||||
dprintf("[YARA ERROR] ");
|
||||
break;
|
||||
case YARA_ERROR_LEVEL_WARNING:
|
||||
dprintf("[YARA WARNING] ");
|
||||
break;
|
||||
}
|
||||
dprintf("File: \"%s\", Line: %d, Message: \"%s\"\n", file_name, line_number, message);
|
||||
}
|
||||
|
||||
static String yara_print_string(const uint8_t* data, int length)
|
||||
{
|
||||
String result = "\"";
|
||||
const char* str = (const char*)data;
|
||||
for(int i = 0; i < length; i++)
|
||||
{
|
||||
char cur[16] = "";
|
||||
if(str[i] >= 32 && str[i] <= 126)
|
||||
sprintf_s(cur, "%c", str[i]);
|
||||
else
|
||||
sprintf_s(cur, "\\x%02X", (uint8_t) str[i]);
|
||||
result += cur;
|
||||
}
|
||||
result += "\"";
|
||||
return result;
|
||||
}
|
||||
|
||||
static String yara_print_hex_string(const uint8_t* data, int length)
|
||||
{
|
||||
String result = "";
|
||||
for(int i = 0; i < length; i++)
|
||||
{
|
||||
if(i)
|
||||
result += " ";
|
||||
char cur[16] = "";
|
||||
sprintf_s(cur, "%02X", (uint8_t) data[i]);
|
||||
result += cur;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
struct YaraScanInfo
|
||||
{
|
||||
uint base;
|
||||
int index;
|
||||
};
|
||||
|
||||
static int yaraScanCallback(int message, void* message_data, void* user_data)
|
||||
{
|
||||
YaraScanInfo* scanInfo = (YaraScanInfo*)user_data;
|
||||
switch(message)
|
||||
{
|
||||
case CALLBACK_MSG_RULE_MATCHING:
|
||||
{
|
||||
uint base = scanInfo->base;
|
||||
YR_RULE* yrRule = (YR_RULE*)message_data;
|
||||
dprintf("[YARA] Rule \"%s\" matched:\n", yrRule->identifier);
|
||||
YR_STRING* string;
|
||||
yr_rule_strings_foreach(yrRule, string)
|
||||
{
|
||||
YR_MATCH* match;
|
||||
yr_string_matches_foreach(string, match)
|
||||
{
|
||||
String pattern;
|
||||
if(STRING_IS_HEX(string))
|
||||
pattern = yara_print_hex_string(match->data, match->length);
|
||||
else
|
||||
pattern = yara_print_string(match->data, match->length);
|
||||
uint addr = (uint)(base + match->base + match->offset);
|
||||
//dprintf("[YARA] String \"%s\" : %s on 0x%"fext"X\n", string->identifier, pattern.c_str(), addr);
|
||||
|
||||
//update references
|
||||
int index = scanInfo->index;
|
||||
GuiReferenceSetRowCount(index + 1);
|
||||
scanInfo->index++;
|
||||
char addr_text[deflen] = "";
|
||||
sprintf(addr_text, fhex, addr);
|
||||
GuiReferenceSetCellContent(index, 0, addr_text); //Address
|
||||
String ruleFullName = "";
|
||||
ruleFullName += yrRule->identifier;
|
||||
ruleFullName += ".";
|
||||
ruleFullName += string->identifier;
|
||||
GuiReferenceSetCellContent(index, 1, ruleFullName.c_str()); //Rule
|
||||
GuiReferenceSetCellContent(index, 2, pattern.c_str()); //Data
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case CALLBACK_MSG_RULE_NOT_MATCHING:
|
||||
{
|
||||
YR_RULE* yrRule = (YR_RULE*)message_data;
|
||||
dprintf("[YARA] Rule \"%s\" did not match!\n", yrRule->identifier);
|
||||
}
|
||||
break;
|
||||
|
||||
case CALLBACK_MSG_SCAN_FINISHED:
|
||||
{
|
||||
dputs("[YARA] Scan finished!");
|
||||
}
|
||||
break;
|
||||
|
||||
case CALLBACK_MSG_IMPORT_MODULE:
|
||||
{
|
||||
YR_MODULE_IMPORT* yrModuleImport = (YR_MODULE_IMPORT*)message_data;
|
||||
dprintf("[YARA] Imported module \"%s\"!\n", yrModuleImport->module_name);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return ERROR_SUCCESS; //nicely undocumented what this should be
|
||||
}
|
||||
|
||||
CMDRESULT cbInstrYara(int argc, char* argv[])
|
||||
{
|
||||
if(argc < 2) //yara rulesFile, addr_of_mempage, size_of_scan
|
||||
{
|
||||
dputs("not enough arguments!");
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
uint addr = 0;
|
||||
if(argc < 3 || !valfromstring(argv[2], &addr))
|
||||
addr = GetContextDataEx(hActiveThread, UE_CIP);
|
||||
uint size = 0;
|
||||
if(argc >= 4)
|
||||
if(!valfromstring(argv[3], &size))
|
||||
size = 0;
|
||||
if(!size)
|
||||
addr = MemFindBaseAddr(addr, &size);
|
||||
uint base = addr;
|
||||
dprintf("%p[%p]\n", base, size);
|
||||
Memory<uint8_t*> data(size);
|
||||
if(!MemRead((void*)base, data(), size, 0))
|
||||
{
|
||||
dprintf("failed to read memory page %p[%X]!\n", base, size);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
|
||||
FILE* rulesFile = 0;
|
||||
if(_wfopen_s(&rulesFile, StringUtils::Utf8ToUtf16(argv[1]).c_str(), L"rb"))
|
||||
{
|
||||
dputs("failed to open yara rules file!");
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
|
||||
bool bSuccess = false;
|
||||
YR_COMPILER* yrCompiler;
|
||||
if(yr_compiler_create(&yrCompiler) == ERROR_SUCCESS)
|
||||
{
|
||||
yr_compiler_set_callback(yrCompiler, yaraCompilerCallback, 0);
|
||||
if(yr_compiler_add_file(yrCompiler, rulesFile, NULL, argv[1]) == 0) //no errors found
|
||||
{
|
||||
fclose(rulesFile);
|
||||
YR_RULES* yrRules;
|
||||
if(yr_compiler_get_rules(yrCompiler, &yrRules) == ERROR_SUCCESS)
|
||||
{
|
||||
//initialize new reference tab
|
||||
char modname[MAX_MODULE_SIZE] = "";
|
||||
if(!ModNameFromAddr(base, modname, true))
|
||||
sprintf_s(modname, "%p", base);
|
||||
String fullName;
|
||||
const char* fileName = strrchr(argv[1], '\\');
|
||||
if(fileName)
|
||||
fullName = fileName + 1;
|
||||
else
|
||||
fullName = argv[1];
|
||||
fullName += " (";
|
||||
fullName += modname;
|
||||
fullName += ")"; //nanana, very ugly code (long live open source)
|
||||
GuiReferenceInitialize(fullName.c_str());
|
||||
GuiReferenceAddColumn(sizeof(uint) * 2, "Address");
|
||||
GuiReferenceAddColumn(48, "Rule");
|
||||
GuiReferenceAddColumn(0, "Data");
|
||||
GuiReferenceSetRowCount(0);
|
||||
GuiReferenceReloadData();
|
||||
YaraScanInfo scanInfo;
|
||||
scanInfo.base = base;
|
||||
scanInfo.index = 0;
|
||||
uint ticks = GetTickCount();
|
||||
dputs("[YARA] Scan started...");
|
||||
int err = yr_rules_scan_mem(yrRules, data(), size, 0, yaraScanCallback, &scanInfo, 0);
|
||||
GuiReferenceReloadData();
|
||||
switch(err)
|
||||
{
|
||||
case ERROR_SUCCESS:
|
||||
dprintf("%u scan results in %ums...\n", scanInfo.index, GetTickCount() - ticks);
|
||||
bSuccess = true;
|
||||
break;
|
||||
case ERROR_TOO_MANY_MATCHES:
|
||||
dputs("too many matches!");
|
||||
break;
|
||||
default:
|
||||
dputs("error while scanning memory!");
|
||||
break;
|
||||
}
|
||||
yr_rules_destroy(yrRules);
|
||||
}
|
||||
else
|
||||
dputs("error while getting the rules!");
|
||||
}
|
||||
else
|
||||
dputs("errors in the rules file!");
|
||||
yr_compiler_destroy(yrCompiler);
|
||||
}
|
||||
else
|
||||
dputs("yr_compiler_create failed!");
|
||||
return bSuccess ? STATUS_CONTINUE : STATUS_ERROR;
|
||||
}
|
||||
|
||||
CMDRESULT cbInstrYaramod(int argc, char* argv[])
|
||||
{
|
||||
if(argc < 3)
|
||||
{
|
||||
dputs("not enough arguments!");
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
uint base = ModBaseFromName(argv[2]);
|
||||
if(!base)
|
||||
{
|
||||
dprintf("invalid module \"%s\"!\n", argv[2]);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
uint size = ModSizeFromAddr(base);
|
||||
char newcmd[deflen] = "";
|
||||
sprintf_s(newcmd, "yara \"%s\",%p,%p", argv[1], base, size);
|
||||
return cmddirectexec(dbggetcommandlist(), newcmd);
|
||||
}
|
||||
|
||||
CMDRESULT cbInstrLog(int argc, char* argv[])
|
||||
{
|
||||
//log "format {0} string",arg1, arg2, argN
|
||||
if(argc == 1) //just log newline
|
||||
{
|
||||
dputs("");
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
FormatValueVector formatArgs;
|
||||
for(int i = 2; i < argc; i++)
|
||||
formatArgs.push_back(argv[i]);
|
||||
String logString = stringformat(argv[1], formatArgs);
|
||||
dputs(logString.c_str());
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,5 +62,8 @@ CMDRESULT cbInstrFunctionList(int argc, char* argv[]);
|
|||
CMDRESULT cbInstrLoopList(int argc, char* argv[]);
|
||||
CMDRESULT cbInstrSleep(int argc, char* argv[]);
|
||||
CMDRESULT cbInstrFindAsm(int argc, char* argv[]);
|
||||
CMDRESULT cbInstrYara(int argc, char* argv[]);
|
||||
CMDRESULT cbInstrYaramod(int argc, char* argv[]);
|
||||
CMDRESULT cbInstrLog(int argc, char* argv[]);
|
||||
|
||||
#endif // _INSTRUCTIONS_H
|
||||
|
|
|
|||
|
|
@ -4,201 +4,279 @@
|
|||
#include "memory.h"
|
||||
#include "debugger.h"
|
||||
|
||||
typedef std::unordered_map<uint, LABELSINFO> LabelsInfo;
|
||||
std::unordered_map<uint, LABELSINFO> labels;
|
||||
|
||||
static LabelsInfo labels;
|
||||
|
||||
bool labelset(uint addr, const char* text, bool manual)
|
||||
bool LabelSet(uint Address, const char* Text, bool Manual)
|
||||
{
|
||||
if(!DbgIsDebugging() or !MemIsValidReadPtr(addr) or !text or strlen(text) >= MAX_LABEL_SIZE - 1 or strstr(text, "&"))
|
||||
// CHECK: Exported/Command function
|
||||
if (!DbgIsDebugging())
|
||||
return false;
|
||||
if(!*text) //NOTE: delete when there is no text
|
||||
{
|
||||
labeldel(addr);
|
||||
return true;
|
||||
}
|
||||
LABELSINFO label;
|
||||
label.manual = manual;
|
||||
strcpy_s(label.text, text);
|
||||
ModNameFromAddr(addr, label.mod, true);
|
||||
label.addr = addr - ModBaseFromAddr(addr);
|
||||
uint key = ModHashFromAddr(addr);
|
||||
CriticalSectionLocker locker(LockLabels);
|
||||
if(!labels.insert(std::make_pair(ModHashFromAddr(key), label)).second) //already present
|
||||
labels[key] = label;
|
||||
|
||||
// A valid memory address must be supplied
|
||||
if (!MemIsValidReadPtr(Address))
|
||||
return false;
|
||||
|
||||
// Make sure the string is supplied, within bounds, and not a special delimiter
|
||||
if (!Text || Text[0] == '\1' || strlen(Text) >= MAX_LABEL_SIZE - 1)
|
||||
return false;
|
||||
|
||||
// Labels cannot be "address" of actual variables
|
||||
if (strstr(Text, "&"))
|
||||
return false;
|
||||
|
||||
// Delete the label if no text was supplied
|
||||
if(Text[0] == '\0')
|
||||
return LabelDelete(Address);
|
||||
|
||||
// Fill out the structure data
|
||||
LABELSINFO labelInfo;
|
||||
labelInfo.manual = Manual;
|
||||
labelInfo.addr = Address - ModBaseFromAddr(Address);
|
||||
strcpy_s(labelInfo.text, Text);
|
||||
ModNameFromAddr(Address, labelInfo.mod, true);
|
||||
|
||||
EXCLUSIVE_ACQUIRE(LockLabels);
|
||||
|
||||
// Insert label by key
|
||||
const uint key = ModHashFromAddr(Address);
|
||||
|
||||
if(!labels.insert(std::make_pair(ModHashFromAddr(key), labelInfo)).second)
|
||||
labels[key] = labelInfo;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool labelfromstring(const char* text, uint* addr)
|
||||
bool LabelFromString(const char* Text, uint* Address)
|
||||
{
|
||||
// CHECK: Future? (Not used)
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
CriticalSectionLocker locker(LockLabels);
|
||||
for(LabelsInfo::iterator i = labels.begin(); i != labels.end(); ++i)
|
||||
|
||||
SHARED_ACQUIRE(LockLabels);
|
||||
|
||||
for (auto& itr : labels)
|
||||
{
|
||||
if(!strcmp(i->second.text, text))
|
||||
{
|
||||
if(addr)
|
||||
*addr = i->second.addr + ModBaseFromName(i->second.mod);
|
||||
return true;
|
||||
}
|
||||
// Check if the actual label name matches
|
||||
if (strcmp(itr.second.text, Text))
|
||||
continue;
|
||||
|
||||
if (Address)
|
||||
*Address = itr.second.addr + ModBaseFromName(itr.second.mod);
|
||||
|
||||
// Set status to indicate if label was ever found
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool labelget(uint addr, char* text)
|
||||
bool LabelGet(uint Address, char* Text)
|
||||
{
|
||||
// CHECK: Export function
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
CriticalSectionLocker locker(LockLabels);
|
||||
const LabelsInfo::iterator found = labels.find(ModHashFromAddr(addr));
|
||||
if(found == labels.end()) //not found
|
||||
|
||||
SHARED_ACQUIRE(LockLabels);
|
||||
|
||||
// Was the label at this address exist?
|
||||
auto found = labels.find(ModHashFromAddr(Address));
|
||||
|
||||
if(found == labels.end())
|
||||
return false;
|
||||
if(text)
|
||||
strcpy_s(text, MAX_LABEL_SIZE, found->second.text);
|
||||
|
||||
// Copy to user buffer
|
||||
if(Text)
|
||||
strcpy_s(Text, MAX_LABEL_SIZE, found->second.text);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool labeldel(uint addr)
|
||||
bool LabelDelete(uint Address)
|
||||
{
|
||||
// CHECK: Export function
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
CriticalSectionLocker locker(LockLabels);
|
||||
return (labels.erase(ModHashFromAddr(addr)) > 0);
|
||||
|
||||
EXCLUSIVE_ACQUIRE(LockLabels);
|
||||
return (labels.erase(ModHashFromAddr(Address)) > 0);
|
||||
}
|
||||
|
||||
void labeldelrange(uint start, uint end)
|
||||
void LabelDelRange(uint Start, uint End)
|
||||
{
|
||||
if(!DbgIsDebugging())
|
||||
// CHECK: Export function
|
||||
if (!DbgIsDebugging())
|
||||
return;
|
||||
bool bDelAll = (start == 0 && end == ~0); //0x00000000-0xFFFFFFFF
|
||||
uint modbase = ModBaseFromAddr(start);
|
||||
if(modbase != ModBaseFromAddr(end))
|
||||
return;
|
||||
start -= modbase;
|
||||
end -= modbase;
|
||||
CriticalSectionLocker locker(LockLabels);
|
||||
LabelsInfo::iterator i = labels.begin();
|
||||
while(i != labels.end())
|
||||
|
||||
// Are all comments going to be deleted?
|
||||
// 0x00000000 - 0xFFFFFFFF
|
||||
if (Start == 0 && End == ~0)
|
||||
{
|
||||
if(i->second.manual) //ignore manual
|
||||
EXCLUSIVE_ACQUIRE(LockLabels);
|
||||
labels.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Make sure 'Start' and 'End' reference the same module
|
||||
uint moduleBase = ModBaseFromAddr(Start);
|
||||
|
||||
if (moduleBase != ModBaseFromAddr(End))
|
||||
return;
|
||||
|
||||
EXCLUSIVE_ACQUIRE(LockLabels);
|
||||
for (auto itr = labels.begin(); itr != labels.end();)
|
||||
{
|
||||
i++;
|
||||
continue;
|
||||
// Ignore manually set entries
|
||||
if (itr->second.manual)
|
||||
{
|
||||
itr++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// [Start, End)
|
||||
if (itr->second.addr >= Start && itr->second.addr < End)
|
||||
itr = labels.erase(itr);
|
||||
else
|
||||
itr++;
|
||||
}
|
||||
if(bDelAll || (i->second.addr >= start && i->second.addr < end))
|
||||
labels.erase(i++);
|
||||
else
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void labelcachesave(JSON root)
|
||||
void LabelCacheSave(JSON Root)
|
||||
{
|
||||
CriticalSectionLocker locker(LockLabels);
|
||||
const JSON jsonlabels = json_array();
|
||||
const JSON jsonautolabels = json_array();
|
||||
for(LabelsInfo::iterator i = labels.begin(); i != labels.end(); ++i)
|
||||
EXCLUSIVE_ACQUIRE(LockLabels);
|
||||
|
||||
// Create the sub-root structures in memory
|
||||
const JSON jsonLabels = json_array();
|
||||
const JSON jsonAutoLabels = json_array();
|
||||
|
||||
// Iterator each label
|
||||
for(auto& itr : labels)
|
||||
{
|
||||
const LABELSINFO curLabel = i->second;
|
||||
JSON curjsonlabel = json_object();
|
||||
json_object_set_new(curjsonlabel, "module", json_string(curLabel.mod));
|
||||
json_object_set_new(curjsonlabel, "address", json_hex(curLabel.addr));
|
||||
json_object_set_new(curjsonlabel, "text", json_string(curLabel.text));
|
||||
if(curLabel.manual)
|
||||
json_array_append_new(jsonlabels, curjsonlabel);
|
||||
JSON jsonLabel = json_object();
|
||||
json_object_set_new(jsonLabel, "module", json_string(itr.second.mod));
|
||||
json_object_set_new(jsonLabel, "address", json_hex(itr.second.addr));
|
||||
json_object_set_new(jsonLabel, "text", json_string(itr.second.text));
|
||||
|
||||
// Was the label manually added?
|
||||
if(itr.second.manual)
|
||||
json_array_append_new(jsonLabels, jsonLabel);
|
||||
else
|
||||
json_array_append_new(jsonautolabels, curjsonlabel);
|
||||
json_array_append_new(jsonAutoLabels, jsonLabel);
|
||||
}
|
||||
if(json_array_size(jsonlabels))
|
||||
json_object_set(root, "labels", jsonlabels);
|
||||
json_decref(jsonlabels);
|
||||
if(json_array_size(jsonautolabels))
|
||||
json_object_set(root, "autolabels", jsonautolabels);
|
||||
json_decref(jsonautolabels);
|
||||
|
||||
// Apply the object to the global root
|
||||
if(json_array_size(jsonLabels))
|
||||
json_object_set(Root, "labels", jsonLabels);
|
||||
|
||||
if(json_array_size(jsonAutoLabels))
|
||||
json_object_set(Root, "autolabels", jsonAutoLabels);
|
||||
|
||||
json_decref(jsonLabels);
|
||||
json_decref(jsonAutoLabels);
|
||||
}
|
||||
|
||||
void labelcacheload(JSON root)
|
||||
void LabelCacheLoad(JSON Root)
|
||||
{
|
||||
CriticalSectionLocker locker(LockLabels);
|
||||
EXCLUSIVE_ACQUIRE(LockLabels);
|
||||
|
||||
// Inline lambda to parse each JSON entry
|
||||
auto AddLabels = [](const JSON Object, bool Manual)
|
||||
{
|
||||
size_t i;
|
||||
JSON value;
|
||||
|
||||
json_array_foreach(Object, i, value)
|
||||
{
|
||||
LABELSINFO labelInfo;
|
||||
memset(&labelInfo, 0, sizeof(LABELSINFO));
|
||||
|
||||
// Module
|
||||
const char* mod = json_string_value(json_object_get(value, "module"));
|
||||
|
||||
if (mod && strlen(mod) < MAX_MODULE_SIZE)
|
||||
strcpy_s(labelInfo.mod, mod);
|
||||
else
|
||||
labelInfo.mod[0] = '\0';
|
||||
|
||||
// Address/Manual
|
||||
labelInfo.addr = (uint)json_hex_value(json_object_get(value, "address"));
|
||||
labelInfo.manual = Manual;
|
||||
|
||||
// Text string
|
||||
const char* text = json_string_value(json_object_get(value, "text"));
|
||||
|
||||
if (text)
|
||||
strcpy_s(labelInfo.text, text);
|
||||
else
|
||||
{
|
||||
// Skip empty strings
|
||||
continue;
|
||||
}
|
||||
|
||||
// Go through the string replacing '&' with spaces
|
||||
for (char *ptr = labelInfo.text; ptr[0] != '\0'; ptr++)
|
||||
{
|
||||
if (ptr[0] == '&')
|
||||
ptr[0] = ' ';
|
||||
}
|
||||
|
||||
// Finally insert the data
|
||||
const uint key = ModHashFromName(labelInfo.mod) + labelInfo.addr;
|
||||
|
||||
labels.insert(std::make_pair(key, labelInfo));
|
||||
}
|
||||
};
|
||||
|
||||
// Remove previous data
|
||||
labels.clear();
|
||||
const JSON jsonlabels = json_object_get(root, "labels");
|
||||
if(jsonlabels)
|
||||
{
|
||||
size_t i;
|
||||
JSON value;
|
||||
json_array_foreach(jsonlabels, i, value)
|
||||
{
|
||||
LABELSINFO curLabel;
|
||||
const char* mod = json_string_value(json_object_get(value, "module"));
|
||||
if(mod && *mod && strlen(mod) < MAX_MODULE_SIZE)
|
||||
strcpy_s(curLabel.mod, mod);
|
||||
else
|
||||
*curLabel.mod = '\0';
|
||||
curLabel.addr = (uint)json_hex_value(json_object_get(value, "address"));
|
||||
curLabel.manual = true;
|
||||
const char* text = json_string_value(json_object_get(value, "text"));
|
||||
if(text)
|
||||
strcpy_s(curLabel.text, text);
|
||||
else
|
||||
continue; //skip
|
||||
int len = (int)strlen(curLabel.text);
|
||||
for(int i = 0; i < len; i++)
|
||||
if(curLabel.text[i] == '&')
|
||||
curLabel.text[i] = ' ';
|
||||
const uint key = ModHashFromName(curLabel.mod) + curLabel.addr;
|
||||
labels.insert(std::make_pair(key, curLabel));
|
||||
}
|
||||
}
|
||||
JSON jsonautolabels = json_object_get(root, "autolabels");
|
||||
if(jsonautolabels)
|
||||
{
|
||||
size_t i;
|
||||
JSON value;
|
||||
json_array_foreach(jsonautolabels, i, value)
|
||||
{
|
||||
LABELSINFO curLabel;
|
||||
const char* mod = json_string_value(json_object_get(value, "module"));
|
||||
if(mod && *mod && strlen(mod) < MAX_MODULE_SIZE)
|
||||
strcpy_s(curLabel.mod, mod);
|
||||
else
|
||||
*curLabel.mod = '\0';
|
||||
curLabel.addr = (uint)json_hex_value(json_object_get(value, "address"));
|
||||
curLabel.manual = false;
|
||||
const char* text = json_string_value(json_object_get(value, "text"));
|
||||
if(text)
|
||||
strcpy_s(curLabel.text, text);
|
||||
else
|
||||
continue; //skip
|
||||
const uint key = ModHashFromName(curLabel.mod) + curLabel.addr;
|
||||
labels.insert(std::make_pair(key, curLabel));
|
||||
}
|
||||
}
|
||||
|
||||
const JSON jsonLabels = json_object_get(Root, "labels");
|
||||
const JSON jsonAutoLabels = json_object_get(Root, "autolabels");
|
||||
|
||||
// Load user-set labels
|
||||
if (jsonLabels)
|
||||
AddLabels(jsonLabels, true);
|
||||
|
||||
// Load auto-set labels
|
||||
if (jsonAutoLabels)
|
||||
AddLabels(jsonAutoLabels, false);
|
||||
}
|
||||
|
||||
bool labelenum(LABELSINFO* labellist, size_t* cbsize)
|
||||
bool LabelEnum(LABELSINFO* List, size_t* Size)
|
||||
{
|
||||
// CHECK: Export function
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
if(!labellist && !cbsize)
|
||||
|
||||
// At least 1 parameter is required
|
||||
if(!List && !Size)
|
||||
return false;
|
||||
CriticalSectionLocker locker(LockLabels);
|
||||
if(!labellist && cbsize)
|
||||
|
||||
EXCLUSIVE_ACQUIRE(LockLabels);
|
||||
|
||||
// See if the user requested a size
|
||||
if(Size)
|
||||
{
|
||||
*cbsize = labels.size() * sizeof(LABELSINFO);
|
||||
return true;
|
||||
*Size = labels.size() * sizeof(LABELSINFO);
|
||||
|
||||
if (!List)
|
||||
return true;
|
||||
}
|
||||
int j = 0;
|
||||
for(LabelsInfo::iterator i = labels.begin(); i != labels.end(); ++i, j++)
|
||||
|
||||
// Fill out the return list while converting the offset
|
||||
// to a virtual address
|
||||
for (auto& itr : labels)
|
||||
{
|
||||
labellist[j] = i->second;
|
||||
labellist[j].addr += ModBaseFromName(labellist[j].mod);
|
||||
*List = itr.second;
|
||||
List->addr += ModBaseFromName(itr.second.mod);
|
||||
List++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void labelclear()
|
||||
void LabelClear()
|
||||
{
|
||||
CriticalSectionLocker locker(LockLabels);
|
||||
LabelsInfo().swap(labels);
|
||||
EXCLUSIVE_ACQUIRE(LockLabels);
|
||||
labels.clear();
|
||||
}
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
#ifndef _LABEL_H
|
||||
#define _LABEL_H
|
||||
#pragma once
|
||||
|
||||
#include "_global.h"
|
||||
|
||||
|
|
@ -11,14 +10,12 @@ struct LABELSINFO
|
|||
bool manual;
|
||||
};
|
||||
|
||||
bool labelset(uint addr, const char* text, bool manual);
|
||||
bool labelfromstring(const char* text, uint* addr);
|
||||
bool labelget(uint addr, char* text);
|
||||
bool labeldel(uint addr);
|
||||
void labeldelrange(uint start, uint end);
|
||||
void labelcachesave(JSON root);
|
||||
void labelcacheload(JSON root);
|
||||
bool labelenum(LABELSINFO* labellist, size_t* cbsize);
|
||||
void labelclear();
|
||||
|
||||
#endif //_LABEL_H
|
||||
bool LabelSet(uint Address, const char* Text, bool Manual);
|
||||
bool LabelFromString(const char* Text, uint* Address);
|
||||
bool LabelGet(uint Address, char* Text);
|
||||
bool LabelDelete(uint Address);
|
||||
void LabelDelRange(uint Start, uint End);
|
||||
void LabelCacheSave(JSON root);
|
||||
void LabelCacheLoad(JSON root);
|
||||
bool LabelEnum(LABELSINFO* List, size_t* Size);
|
||||
void LabelClear();
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
#include "log.h"
|
||||
#include "_global.h"
|
||||
|
||||
log::log(void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
log::~log(void)
|
||||
{
|
||||
GuiAddLogMessage(message.str().c_str());
|
||||
|
||||
}
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
#ifndef _LOG_H
|
||||
#define _LOG_H
|
||||
|
||||
#include <sstream>
|
||||
|
||||
// a Qt's QDebug like message logging
|
||||
// usage: "log() << "hi" << "there";
|
||||
class log
|
||||
{
|
||||
public:
|
||||
log();
|
||||
~log();
|
||||
|
||||
public:
|
||||
template<class T>
|
||||
inline log & operator<<(const T & x)
|
||||
{
|
||||
// accumulate messages
|
||||
message << x;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
std::ostringstream message;
|
||||
};
|
||||
|
||||
#endif _LOG_H
|
||||
|
|
@ -4,178 +4,241 @@
|
|||
#include "threading.h"
|
||||
#include "module.h"
|
||||
|
||||
typedef std::map<DepthModuleRange, LOOPSINFO, DepthModuleRangeCompare> LoopsInfo;
|
||||
std::map<DepthModuleRange, LOOPSINFO, DepthModuleRangeCompare> loops;
|
||||
|
||||
static LoopsInfo loops;
|
||||
|
||||
bool loopadd(uint start, uint end, bool manual)
|
||||
bool LoopAdd(uint Start, uint End, bool Manual)
|
||||
{
|
||||
if(!DbgIsDebugging() or end < start or !MemIsValidReadPtr(start))
|
||||
// CHECK: Export function
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
const uint modbase = ModBaseFromAddr(start);
|
||||
if(modbase != ModBaseFromAddr(end)) //the function boundaries are not in the same mem page
|
||||
|
||||
// Loop must begin before it ends
|
||||
if (Start > End)
|
||||
return false;
|
||||
int finaldepth;
|
||||
if(loopoverlaps(0, start, end, &finaldepth)) //loop cannot overlap another loop
|
||||
|
||||
// Memory addresses must be valid
|
||||
if (!MemIsValidReadPtr(Start) || !MemIsValidReadPtr(End))
|
||||
return false;
|
||||
LOOPSINFO loop;
|
||||
ModNameFromAddr(start, loop.mod, true);
|
||||
loop.start = start - modbase;
|
||||
loop.end = end - modbase;
|
||||
loop.depth = finaldepth;
|
||||
if(finaldepth)
|
||||
loopget(finaldepth - 1, start, &loop.parent, 0);
|
||||
|
||||
// Check if loop boundaries are in the same module range
|
||||
const uint moduleBase = ModBaseFromAddr(Start);
|
||||
|
||||
if(moduleBase != ModBaseFromAddr(End))
|
||||
return false;
|
||||
|
||||
// Loops cannot overlap other loops
|
||||
int finalDepth = 0;
|
||||
|
||||
if(LoopOverlaps(0, Start, End, &finalDepth))
|
||||
return false;
|
||||
|
||||
// Fill out loop information structure
|
||||
LOOPSINFO loopInfo;
|
||||
loopInfo.start = Start - moduleBase;
|
||||
loopInfo.end = End - moduleBase;
|
||||
loopInfo.depth = finalDepth;
|
||||
loopInfo.manual = Manual;
|
||||
ModNameFromAddr(Start, loopInfo.mod, true);
|
||||
|
||||
// Link this to a parent loop if one does exist
|
||||
if(finalDepth)
|
||||
LoopGet(finalDepth - 1, Start, &loopInfo.parent, 0);
|
||||
else
|
||||
loop.parent = 0;
|
||||
loop.manual = manual;
|
||||
CriticalSectionLocker locker(LockLoops);
|
||||
loops.insert(std::make_pair(DepthModuleRange(finaldepth, ModuleRange(ModHashFromAddr(modbase), Range(loop.start, loop.end))), loop));
|
||||
loopInfo.parent = 0;
|
||||
|
||||
EXCLUSIVE_ACQUIRE(LockLoops);
|
||||
|
||||
// Insert into list
|
||||
loops.insert(std::make_pair(DepthModuleRange(finalDepth, ModuleRange(ModHashFromAddr(moduleBase), Range(loopInfo.start, loopInfo.end))), loopInfo));
|
||||
return true;
|
||||
}
|
||||
|
||||
//get the start/end of a loop at a certain depth and addr
|
||||
bool loopget(int depth, uint addr, uint* start, uint* end)
|
||||
// Get the start/end of a loop at a certain depth and address
|
||||
bool LoopGet(int Depth, uint Address, uint* Start, uint* End)
|
||||
{
|
||||
// CHECK: Exported function
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
const uint modbase = ModBaseFromAddr(addr);
|
||||
CriticalSectionLocker locker(LockLoops);
|
||||
LoopsInfo::iterator found = loops.find(DepthModuleRange(depth, ModuleRange(ModHashFromAddr(modbase), Range(addr - modbase, addr - modbase))));
|
||||
if(found == loops.end()) //not found
|
||||
|
||||
// Get the virtual address module
|
||||
const uint moduleBase = ModBaseFromAddr(Address);
|
||||
|
||||
// Virtual address to relative address
|
||||
Address -= moduleBase;
|
||||
|
||||
SHARED_ACQUIRE(LockLoops);
|
||||
|
||||
// Search with this address range
|
||||
auto found = loops.find(DepthModuleRange(Depth, ModuleRange(ModHashFromAddr(moduleBase), Range(Address, Address))));
|
||||
|
||||
if(found == loops.end())
|
||||
return false;
|
||||
if(start)
|
||||
*start = found->second.start + modbase;
|
||||
if(end)
|
||||
*end = found->second.end + modbase;
|
||||
|
||||
// Return the loop start
|
||||
if(Start)
|
||||
*Start = found->second.start + moduleBase;
|
||||
|
||||
// Also the loop end
|
||||
if(End)
|
||||
*End = found->second.end + moduleBase;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//check if a loop overlaps a range, inside is not overlapping
|
||||
bool loopoverlaps(int depth, uint start, uint end, int* finaldepth)
|
||||
bool LoopOverlaps(int Depth, uint Start, uint End, int* FinalDepth)
|
||||
{
|
||||
// CHECK: Export function
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
|
||||
const uint modbase = ModBaseFromAddr(start);
|
||||
uint curStart = start - modbase;
|
||||
uint curEnd = end - modbase;
|
||||
const uint key = ModHashFromAddr(modbase);
|
||||
// Determine module addresses and lookup keys
|
||||
const uint moduleBase = ModBaseFromAddr(Start);
|
||||
const uint key = ModHashFromAddr(moduleBase);
|
||||
|
||||
CriticalSectionLocker locker(LockLoops);
|
||||
uint curStart = Start - moduleBase;
|
||||
uint curEnd = End - moduleBase;
|
||||
|
||||
//check if the new loop fits in the old loop
|
||||
for(LoopsInfo::iterator i = loops.begin(); i != loops.end(); ++i)
|
||||
SHARED_ACQUIRE(LockLoops);
|
||||
|
||||
// Check if the new loop fits in the old loop
|
||||
for(auto& itr : loops)
|
||||
{
|
||||
if(i->first.second.first != key) //only look in the current module
|
||||
// Only look in the current module
|
||||
if(itr.first.second.first != key)
|
||||
continue;
|
||||
LOOPSINFO* curLoop = &i->second;
|
||||
if(curLoop->start < curStart and curLoop->end > curEnd and curLoop->depth == depth)
|
||||
return loopoverlaps(depth + 1, curStart, curEnd, finaldepth);
|
||||
|
||||
// Loop must be at this recursive depth
|
||||
if (itr.second.depth != Depth)
|
||||
continue;
|
||||
|
||||
if(itr.second.start < curStart && itr.second.end > curEnd)
|
||||
return LoopOverlaps(Depth + 1, curStart, curEnd, FinalDepth);
|
||||
}
|
||||
|
||||
if(finaldepth)
|
||||
*finaldepth = depth;
|
||||
// Did the user request t the loop depth?
|
||||
if(FinalDepth)
|
||||
*FinalDepth = Depth;
|
||||
|
||||
//check for loop overlaps
|
||||
for(LoopsInfo::iterator i = loops.begin(); i != loops.end(); ++i)
|
||||
// Check for loop overlaps
|
||||
for (auto& itr : loops)
|
||||
{
|
||||
if(i->first.second.first != key) //only look in the current module
|
||||
// Only look in the current module
|
||||
if (itr.first.second.first != key)
|
||||
continue;
|
||||
LOOPSINFO* curLoop = &i->second;
|
||||
if(curLoop->start <= curEnd and curLoop->end >= curStart and curLoop->depth == depth)
|
||||
|
||||
// Loop must be at this recursive depth
|
||||
if (itr.second.depth != Depth)
|
||||
continue;
|
||||
|
||||
if(itr.second.start <= curEnd && itr.second.end >= curStart)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//this should delete a loop and all sub-loops that matches a certain addr
|
||||
bool loopdel(int depth, uint addr)
|
||||
// This should delete a loop and all sub-loops that matches a certain addr
|
||||
bool LoopDelete(int Depth, uint Address)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void loopcachesave(JSON root)
|
||||
void LoopCacheSave(JSON Root)
|
||||
{
|
||||
CriticalSectionLocker locker(LockLoops);
|
||||
const JSON jsonloops = json_array();
|
||||
const JSON jsonautoloops = json_array();
|
||||
for(LoopsInfo::iterator i = loops.begin(); i != loops.end(); ++i)
|
||||
EXCLUSIVE_ACQUIRE(LockLoops);
|
||||
|
||||
// Create the root JSON objects
|
||||
const JSON jsonLoops = json_array();
|
||||
const JSON jsonAutoLoops = json_array();
|
||||
|
||||
// Write all entries
|
||||
for(auto& itr : loops)
|
||||
{
|
||||
const LOOPSINFO curLoop = i->second;
|
||||
JSON curjsonloop = json_object();
|
||||
json_object_set_new(curjsonloop, "module", json_string(curLoop.mod));
|
||||
json_object_set_new(curjsonloop, "start", json_hex(curLoop.start));
|
||||
json_object_set_new(curjsonloop, "end", json_hex(curLoop.end));
|
||||
json_object_set_new(curjsonloop, "depth", json_integer(curLoop.depth));
|
||||
json_object_set_new(curjsonloop, "parent", json_hex(curLoop.parent));
|
||||
if(curLoop.manual)
|
||||
json_array_append_new(jsonloops, curjsonloop);
|
||||
const LOOPSINFO& currentLoop = itr.second;
|
||||
JSON currentJson = json_object();
|
||||
|
||||
json_object_set_new(currentJson, "module", json_string(currentLoop.mod));
|
||||
json_object_set_new(currentJson, "start", json_hex(currentLoop.start));
|
||||
json_object_set_new(currentJson, "end", json_hex(currentLoop.end));
|
||||
json_object_set_new(currentJson, "depth", json_integer(currentLoop.depth));
|
||||
json_object_set_new(currentJson, "parent", json_hex(currentLoop.parent));
|
||||
|
||||
if(currentLoop.manual)
|
||||
json_array_append_new(jsonLoops, currentJson);
|
||||
else
|
||||
json_array_append_new(jsonautoloops, curjsonloop);
|
||||
json_array_append_new(jsonAutoLoops, currentJson);
|
||||
}
|
||||
if(json_array_size(jsonloops))
|
||||
json_object_set(root, "loops", jsonloops);
|
||||
json_decref(jsonloops);
|
||||
if(json_array_size(jsonautoloops))
|
||||
json_object_set(root, "autoloops", jsonautoloops);
|
||||
json_decref(jsonautoloops);
|
||||
|
||||
// Append a link to the global root
|
||||
if(json_array_size(jsonLoops))
|
||||
json_object_set(Root, "loops", jsonLoops);
|
||||
|
||||
if(json_array_size(jsonAutoLoops))
|
||||
json_object_set(Root, "autoloops", jsonAutoLoops);
|
||||
|
||||
// Release memory/references
|
||||
json_decref(jsonLoops);
|
||||
json_decref(jsonAutoLoops);
|
||||
}
|
||||
|
||||
void loopcacheload(JSON root)
|
||||
void LoopCacheLoad(JSON Root)
|
||||
{
|
||||
CriticalSectionLocker locker(LockLoops);
|
||||
EXCLUSIVE_ACQUIRE(LockLoops);
|
||||
|
||||
// Inline lambda to parse each JSON entry
|
||||
auto AddLoops = [](const JSON Object, bool Manual)
|
||||
{
|
||||
size_t i;
|
||||
JSON value;
|
||||
|
||||
json_array_foreach(Object, i, value)
|
||||
{
|
||||
LOOPSINFO loopInfo;
|
||||
memset(&loopInfo, 0, sizeof(LOOPSINFO));
|
||||
|
||||
// Module name
|
||||
const char* mod = json_string_value(json_object_get(value, "module"));
|
||||
|
||||
if (mod && strlen(mod) < MAX_MODULE_SIZE)
|
||||
strcpy_s(loopInfo.mod, mod);
|
||||
else
|
||||
loopInfo.mod[0] = '\0';
|
||||
|
||||
// All other variables
|
||||
loopInfo.start = (uint)json_hex_value(json_object_get(value, "start"));
|
||||
loopInfo.end = (uint)json_hex_value(json_object_get(value, "end"));
|
||||
loopInfo.depth = (int)json_integer_value(json_object_get(value, "depth"));
|
||||
loopInfo.parent = (uint)json_hex_value(json_object_get(value, "parent"));
|
||||
loopInfo.manual = Manual;
|
||||
|
||||
// Sanity check: Make sure the loop starts before it ends
|
||||
if (loopInfo.end < loopInfo.start)
|
||||
continue;
|
||||
|
||||
// Insert into global list
|
||||
loops.insert(std::make_pair(DepthModuleRange(loopInfo.depth, ModuleRange(ModHashFromName(loopInfo.mod), Range(loopInfo.start, loopInfo.end))), loopInfo));
|
||||
}
|
||||
};
|
||||
|
||||
// Remove existing entries
|
||||
loops.clear();
|
||||
const JSON jsonloops = json_object_get(root, "loops");
|
||||
if(jsonloops)
|
||||
{
|
||||
size_t i;
|
||||
JSON value;
|
||||
json_array_foreach(jsonloops, i, value)
|
||||
{
|
||||
LOOPSINFO curLoop;
|
||||
const char* mod = json_string_value(json_object_get(value, "module"));
|
||||
if(mod && *mod && strlen(mod) < MAX_MODULE_SIZE)
|
||||
strcpy_s(curLoop.mod, mod);
|
||||
else
|
||||
*curLoop.mod = '\0';
|
||||
curLoop.start = (uint)json_hex_value(json_object_get(value, "start"));
|
||||
curLoop.end = (uint)json_hex_value(json_object_get(value, "end"));
|
||||
curLoop.depth = (int)json_integer_value(json_object_get(value, "depth"));
|
||||
curLoop.parent = (uint)json_hex_value(json_object_get(value, "parent"));
|
||||
if(curLoop.end < curLoop.start)
|
||||
continue; //invalid loop
|
||||
curLoop.manual = true;
|
||||
loops.insert(std::make_pair(DepthModuleRange(curLoop.depth, ModuleRange(ModHashFromName(curLoop.mod), Range(curLoop.start, curLoop.end))), curLoop));
|
||||
}
|
||||
}
|
||||
JSON jsonautoloops = json_object_get(root, "autoloops");
|
||||
if(jsonautoloops)
|
||||
{
|
||||
size_t i;
|
||||
JSON value;
|
||||
json_array_foreach(jsonautoloops, i, value)
|
||||
{
|
||||
LOOPSINFO curLoop;
|
||||
const char* mod = json_string_value(json_object_get(value, "module"));
|
||||
if(mod && *mod && strlen(mod) < MAX_MODULE_SIZE)
|
||||
strcpy_s(curLoop.mod, mod);
|
||||
else
|
||||
*curLoop.mod = '\0';
|
||||
curLoop.start = (uint)json_hex_value(json_object_get(value, "start"));
|
||||
curLoop.end = (uint)json_hex_value(json_object_get(value, "end"));
|
||||
curLoop.depth = (int)json_integer_value(json_object_get(value, "depth"));
|
||||
curLoop.parent = (uint)json_hex_value(json_object_get(value, "parent"));
|
||||
if(curLoop.end < curLoop.start)
|
||||
continue; //invalid loop
|
||||
curLoop.manual = false;
|
||||
loops.insert(std::make_pair(DepthModuleRange(curLoop.depth, ModuleRange(ModHashFromName(curLoop.mod), Range(curLoop.start, curLoop.end))), curLoop));
|
||||
}
|
||||
}
|
||||
|
||||
const JSON jsonLoops = json_object_get(Root, "loops");
|
||||
const JSON jsonAutoLoops = json_object_get(Root, "autoloops");
|
||||
|
||||
// Load user-set loops
|
||||
if (jsonLoops)
|
||||
AddLoops(jsonLoops, true);
|
||||
|
||||
// Load auto-set loops
|
||||
if (jsonAutoLoops)
|
||||
AddLoops(jsonAutoLoops, false);
|
||||
}
|
||||
|
||||
bool loopenum(LOOPSINFO* List, size_t* Size)
|
||||
bool LoopEnum(LOOPSINFO* List, size_t* Size)
|
||||
{
|
||||
// If looplist or size is not requested, fail
|
||||
// If list or size is not requested, fail
|
||||
if(!List && !Size)
|
||||
return false;
|
||||
|
||||
|
|
@ -190,14 +253,14 @@ bool loopenum(LOOPSINFO* List, size_t* Size)
|
|||
return true;
|
||||
}
|
||||
|
||||
for(auto itr = loops.begin(); itr != loops.end(); itr++)
|
||||
for (auto& itr : loops)
|
||||
{
|
||||
*List = itr->second;
|
||||
*List = itr.second;
|
||||
|
||||
// Adjust the offset to a real virtual address
|
||||
uint modbase = ModBaseFromName(List->mod);
|
||||
List->start += modbase;
|
||||
List->end += modbase;
|
||||
List->start += modbase;
|
||||
List->end += modbase;
|
||||
|
||||
List++;
|
||||
}
|
||||
|
|
@ -205,7 +268,7 @@ bool loopenum(LOOPSINFO* List, size_t* Size)
|
|||
return true;
|
||||
}
|
||||
|
||||
void loopclear()
|
||||
void LoopClear()
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockLoops);
|
||||
loops.clear();
|
||||
|
|
|
|||
|
|
@ -13,13 +13,13 @@ struct LOOPSINFO
|
|||
bool manual;
|
||||
};
|
||||
|
||||
bool loopadd(uint start, uint end, bool manual);
|
||||
bool loopget(int depth, uint addr, uint* start, uint* end);
|
||||
bool loopoverlaps(int depth, uint start, uint end, int* finaldepth);
|
||||
bool loopdel(int depth, uint addr);
|
||||
void loopcachesave(JSON root);
|
||||
void loopcacheload(JSON root);
|
||||
bool loopenum(LOOPSINFO* looplist, size_t* cbsize);
|
||||
void loopclear();
|
||||
bool LoopAdd(uint Start, uint End, bool Manual);
|
||||
bool LoopGet(int Depth, uint Address, uint* Start, uint* End);
|
||||
bool LoopOverlaps(int Depth, uint Start, uint End, int* FinalDepth);
|
||||
bool LoopDelete(int Depth, uint Address);
|
||||
void LoopCacheSave(JSON Root);
|
||||
void LoopCacheLoad(JSON Root);
|
||||
bool LoopEnum(LOOPSINFO* List, size_t* Size);
|
||||
void LoopClear();
|
||||
|
||||
#endif //_LOOP_H
|
||||
|
|
@ -1,3 +1,9 @@
|
|||
/**
|
||||
@file main.cpp
|
||||
|
||||
@brief Implements the main class.
|
||||
*/
|
||||
|
||||
#include "_global.h"
|
||||
|
||||
extern "C" DLL_EXPORT BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
|
||||
|
|
|
|||
|
|
@ -1,55 +1,84 @@
|
|||
/**
|
||||
@file math.cpp
|
||||
|
||||
@brief Implements various functionalities that have to do with handling expression text.
|
||||
*/
|
||||
|
||||
#include "math.h"
|
||||
#include "value.h"
|
||||
|
||||
enum BRACKET_TYPE
|
||||
{
|
||||
BRACKET_FREE,
|
||||
BRACKET_OPEN,
|
||||
BRACKET_CLOSE,
|
||||
};
|
||||
|
||||
/**
|
||||
\brief A bracket pair. This structure describes a piece of brackets '(' and ')'
|
||||
*/
|
||||
struct BRACKET_PAIR
|
||||
{
|
||||
/**
|
||||
\brief The position in the string of the opening bracket '('.
|
||||
*/
|
||||
int openpos;
|
||||
|
||||
/**
|
||||
\brief The position in the string of the closing bracket ')'.
|
||||
*/
|
||||
int closepos;
|
||||
|
||||
/**
|
||||
\brief The depth of the pair (for example when you have "((1+4)*4)" the second '(' has layer 2).
|
||||
*/
|
||||
int layer;
|
||||
BRACKET_TYPE isset;
|
||||
|
||||
/**
|
||||
\brief 0 when there is nothing set, 1 when the openpos is set, 2 when everything is set (aka pair is complete).
|
||||
*/
|
||||
int isset;
|
||||
};
|
||||
|
||||
/**
|
||||
\brief An expression. This structure describes an expression in form of bracket pairs.
|
||||
*/
|
||||
struct EXPRESSION
|
||||
{
|
||||
/**
|
||||
\brief The bracket pairs.
|
||||
*/
|
||||
BRACKET_PAIR* pairs;
|
||||
|
||||
/**
|
||||
\brief The total number of bracket pairs.
|
||||
*/
|
||||
int total_pairs;
|
||||
|
||||
/**
|
||||
\brief The expression text everything is derived from.
|
||||
*/
|
||||
char* expression;
|
||||
};
|
||||
|
||||
/*
|
||||
operator precedence
|
||||
0 (INVALID/NONE)
|
||||
1 ( ) (PARENTHESIS)
|
||||
2 ~ (NOT)
|
||||
3 * / % (MUL DIV)
|
||||
4 + - (ADD SUB)
|
||||
5 < > (SHL SHR)
|
||||
6 & (AND)
|
||||
7 ^ (XOR)
|
||||
8 | (OR)
|
||||
/**
|
||||
\brief Determines if a characters is an operator.
|
||||
\param ch The character to check.
|
||||
\return The number of the operator. 0 when the character is no operator. Otherwise it returns one of the following numbers:
|
||||
|
||||
- 1 ( )
|
||||
- 2 ~ (NOT)
|
||||
- 3 * / % (MUL DIV)
|
||||
- 4 + - (ADD SUB)
|
||||
- 5 < > (SHL SHR)
|
||||
- 6 & (AND)
|
||||
- 7 ^ (XOR)
|
||||
- 8 | (OR)
|
||||
*/
|
||||
int mathisoperator(char ch)
|
||||
{
|
||||
//
|
||||
// The lower the number, the higher the priority.
|
||||
// Zero indicates no operator was found.
|
||||
//
|
||||
if(ch == '(' || ch == ')')
|
||||
if(ch == '(' or ch == ')')
|
||||
return 1;
|
||||
else if(ch == '~')
|
||||
return 2;
|
||||
else if(ch == '*' || ch == '`' || ch == '/' || ch == '%')
|
||||
else if(ch == '*' or ch == '`' or ch == '/' or ch == '%')
|
||||
return 3;
|
||||
else if(ch == '+' || ch == '-')
|
||||
else if(ch == '+' or ch == '-')
|
||||
return 4;
|
||||
else if(ch == '<' || ch == '>')
|
||||
else if(ch == '<' or ch == '>')
|
||||
return 5;
|
||||
else if(ch == '&')
|
||||
return 6;
|
||||
|
|
@ -57,165 +86,225 @@ int mathisoperator(char ch)
|
|||
return 7;
|
||||
else if(ch == '|')
|
||||
return 8;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
mathformat:
|
||||
- remove doubles
|
||||
/**
|
||||
\brief Formats the given text. It removes double operators like "**" and "||"
|
||||
\param [in,out] text The text to format.
|
||||
*/
|
||||
void mathformat(char* text)
|
||||
{
|
||||
int len = (int)strlen(text);
|
||||
Memory<char*> temp(len + 1, "mathformat:temp");
|
||||
|
||||
for (int i = 0, j = 0; i < len; i++)
|
||||
{
|
||||
if (mathisoperator(text[i]) < 3 || text[i] != text[i + 1])
|
||||
j += sprintf(temp + j, "%c", text[i]);
|
||||
}
|
||||
|
||||
memset(temp, 0, len + 1);
|
||||
for(int i = 0, j = 0; i < len; i++)
|
||||
if(mathisoperator(text[i]) < 3 or text[i] != text[i + 1])
|
||||
j += sprintf(temp + j, "%c", text[i]);
|
||||
strcpy(text, temp);
|
||||
}
|
||||
|
||||
/*
|
||||
- check for math operators
|
||||
/**
|
||||
\brief Checks if the given text contains operators.
|
||||
\param text The text to check.
|
||||
\return true if the text contains operator, false if not.
|
||||
*/
|
||||
bool mathcontains(const char* text)
|
||||
{
|
||||
// Skip negative values
|
||||
if(*text == '-')
|
||||
if(*text == '-') //ignore negative values
|
||||
text++;
|
||||
|
||||
// Search the entire string looking for a math operator
|
||||
for (; text[0] != '\0'; text++)
|
||||
{
|
||||
if (mathisoperator(text[0]))
|
||||
return true;
|
||||
}
|
||||
|
||||
int len = (int)strlen(text);
|
||||
for(int i = 0; i < len; i++)
|
||||
if(mathisoperator(text[i]))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef __MINGW64__
|
||||
inline unsigned long long umulhi(unsigned long long x, unsigned long long y)
|
||||
static inline unsigned long long umulhi(unsigned long long x, unsigned long long y)
|
||||
{
|
||||
return (unsigned long long)(((__uint128_t)x * y) >> 64);
|
||||
}
|
||||
|
||||
inline long long mulhi(long long x, long long y)
|
||||
static inline long long mulhi(long long x, long long y)
|
||||
{
|
||||
return (long long)(((__int128_t)x * y) >> 64);
|
||||
}
|
||||
#elif _WIN64
|
||||
#include <intrin.h>
|
||||
inline unsigned long long umulhi(unsigned long long x, unsigned long long y)
|
||||
static inline unsigned long long umulhi(unsigned long long x, unsigned long long y)
|
||||
{
|
||||
unsigned __int64 res;
|
||||
_umul128(x, y, &res);
|
||||
return res;
|
||||
}
|
||||
|
||||
inline long long mulhi(long long x, long long y)
|
||||
static inline long long mulhi(long long x, long long y)
|
||||
{
|
||||
__int64 res;
|
||||
_mul128(x, y, &res);
|
||||
return res;
|
||||
}
|
||||
#else
|
||||
inline unsigned int umulhi(unsigned int x, unsigned int y)
|
||||
static inline unsigned int umulhi(unsigned int x, unsigned int y)
|
||||
{
|
||||
return (unsigned int)(((unsigned long long)x * y) >> 32);
|
||||
}
|
||||
|
||||
inline int mulhi(int x, int y)
|
||||
static inline int mulhi(int x, int y)
|
||||
{
|
||||
return (int)(((long long)x * y) >> 32);
|
||||
}
|
||||
#endif //__MINGW64__
|
||||
|
||||
template<typename T>
|
||||
bool MathDoOperation(char op, T left, T right, T* result)
|
||||
{
|
||||
switch (op)
|
||||
{
|
||||
case '*':
|
||||
*result = left * right;
|
||||
return true;
|
||||
case '`':
|
||||
*result = umulhi(left, right);
|
||||
return true;
|
||||
case '/':
|
||||
if (right)
|
||||
{
|
||||
*result = left / right;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case '%':
|
||||
if (right)
|
||||
{
|
||||
*result = left % right;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case '+':
|
||||
*result = left + right;
|
||||
return true;
|
||||
case '-':
|
||||
*result = left - right;
|
||||
return true;
|
||||
case '<':
|
||||
*result = left << right;
|
||||
return true;
|
||||
case '>':
|
||||
*result = left >> right;
|
||||
return true;
|
||||
case '&':
|
||||
*result = left & right;
|
||||
return true;
|
||||
case '^':
|
||||
*result = left ^ right;
|
||||
return true;
|
||||
case '|':
|
||||
*result = left | right;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Do an operation on two unsigned numbers.
|
||||
\param op The operation to do (this must be a valid operator).
|
||||
\param left The number left of the operator.
|
||||
\param right The number right of the operator.
|
||||
\param [out] result The result of the operator. Cannot be null.
|
||||
\return true if the operation succeeded. It could fail on zero devision or an invalid operator.
|
||||
*/
|
||||
bool mathdounsignedoperation(char op, uint left, uint right, uint* result)
|
||||
{
|
||||
return MathDoOperation<uint>(op, left, right, result);
|
||||
switch(op)
|
||||
{
|
||||
case '*':
|
||||
*result = left * right;
|
||||
return true;
|
||||
case '`':
|
||||
*result = umulhi(left, right);
|
||||
return true;
|
||||
case '/':
|
||||
if(right)
|
||||
{
|
||||
*result = left / right;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case '%':
|
||||
if(right)
|
||||
{
|
||||
*result = left % right;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case '+':
|
||||
*result = left + right;
|
||||
return true;
|
||||
case '-':
|
||||
*result = left - right;
|
||||
return true;
|
||||
case '<':
|
||||
*result = left << right;
|
||||
return true;
|
||||
case '>':
|
||||
*result = left >> right;
|
||||
return true;
|
||||
case '&':
|
||||
*result = left & right;
|
||||
return true;
|
||||
case '^':
|
||||
*result = left ^ right;
|
||||
return true;
|
||||
case '|':
|
||||
*result = left | right;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Do an operation on two signed numbers.
|
||||
\param op The operation to do (this must be a valid operator).
|
||||
\param left The number left of the operator.
|
||||
\param right The number right of the operator.
|
||||
\param [out] result The result of the operator. Cannot be null.
|
||||
\return true if the operation succeeded. It could fail on zero devision or an invalid operator.
|
||||
*/
|
||||
bool mathdosignedoperation(char op, sint left, sint right, sint* result)
|
||||
{
|
||||
return MathDoOperation<sint>(op, left, right, result);
|
||||
switch(op)
|
||||
{
|
||||
case '*':
|
||||
*result = left * right;
|
||||
return true;
|
||||
case '`':
|
||||
*result = mulhi(left, right);
|
||||
return true;
|
||||
case '/':
|
||||
if(right)
|
||||
{
|
||||
*result = left / right;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case '%':
|
||||
if(right)
|
||||
{
|
||||
*result = left % right;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case '+':
|
||||
*result = left + right;
|
||||
return true;
|
||||
case '-':
|
||||
*result = left - right;
|
||||
return true;
|
||||
case '<':
|
||||
*result = left << right;
|
||||
return true;
|
||||
case '>':
|
||||
*result = left >> right;
|
||||
return true;
|
||||
case '&':
|
||||
*result = left & right;
|
||||
return true;
|
||||
case '^':
|
||||
*result = left ^ right;
|
||||
return true;
|
||||
case '|':
|
||||
*result = left | right;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void fillpair(EXPRESSION* expstruct, int pos, int layer)
|
||||
/**
|
||||
\brief Fills a BRACKET_PAIR structure.
|
||||
\param [in,out] expstruct The expression structure. Cannot be null.
|
||||
\param pos The position to fill, position of '(' or ')'.
|
||||
\param layer The layer this bracket is in.
|
||||
*/
|
||||
static void fillpair(EXPRESSION* expstruct, int pos, int layer)
|
||||
{
|
||||
for(int i = 0; i < expstruct->total_pairs; i++)
|
||||
{
|
||||
if(expstruct->pairs[i].isset == BRACKET_FREE)
|
||||
if(!expstruct->pairs[i].isset)
|
||||
{
|
||||
expstruct->pairs[i].layer = layer;
|
||||
expstruct->pairs[i].openpos = pos;
|
||||
expstruct->pairs[i].isset = BRACKET_OPEN;
|
||||
expstruct->pairs[i].layer = layer;
|
||||
expstruct->pairs[i].openpos = pos;
|
||||
expstruct->pairs[i].isset = 1;
|
||||
break;
|
||||
}
|
||||
else if(expstruct->pairs[i].layer == layer && expstruct->pairs[i].isset == BRACKET_OPEN)
|
||||
else if(expstruct->pairs[i].layer == layer and expstruct->pairs[i].isset == 1)
|
||||
{
|
||||
expstruct->pairs[i].closepos = pos;
|
||||
expstruct->pairs[i].isset = BRACKET_CLOSE;
|
||||
expstruct->pairs[i].closepos = pos;
|
||||
expstruct->pairs[i].isset = 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int matchpairs(EXPRESSION* expstruct, char* expression, int endlayer)
|
||||
/**
|
||||
\brief This function recursively matches bracket pair in an EXPRESSION.
|
||||
\param [in,out] expstruct The expression structure. Cannot be null.
|
||||
\param [in,out] expression The expression text to parse. Cannot be null.
|
||||
\param endlayer The layer to stop on. This variable is used for the recursion termination condition.
|
||||
\return The position in the \p expression mathpairs ended in.
|
||||
*/
|
||||
static int matchpairs(EXPRESSION* expstruct, char* expression, int endlayer = 0)
|
||||
{
|
||||
int layer = endlayer;
|
||||
int len = (int)strlen(expression);
|
||||
|
|
@ -243,7 +332,12 @@ int matchpairs(EXPRESSION* expstruct, char* expression, int endlayer)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int expressionformat(char* exp)
|
||||
/**
|
||||
\brief Formats a given expression. This function checks if the number of brackets is even and adds brackets to the end if needed.
|
||||
\param [in,out] exp The expression to format.
|
||||
\return The number of bracket pairs in the expression or -1 on error.
|
||||
*/
|
||||
static int expressionformat(char* exp)
|
||||
{
|
||||
int len = (int)strlen(exp);
|
||||
int open = 0;
|
||||
|
|
@ -266,85 +360,105 @@ int expressionformat(char* exp)
|
|||
return open;
|
||||
}
|
||||
|
||||
void adjustpairs(EXPRESSION* exps, int cur_open, int cur_close, int cur_len, int new_len)
|
||||
/**
|
||||
\brief Adjusts bracket pair positions to insert a new string in the expression.
|
||||
\param [in,out] exps The expression structure.
|
||||
\param cur_open The current opening bracket '(' position.
|
||||
\param cur_close The current closing bracket ')' position.
|
||||
\param cur_len The current string length in between the brackets.
|
||||
\param new_len Length of the new string.
|
||||
*/
|
||||
static void adjustpairs(EXPRESSION* exps, int cur_open, int cur_close, int cur_len, int new_len)
|
||||
{
|
||||
for(int i = 0; i < exps->total_pairs; i++)
|
||||
{
|
||||
if(exps->pairs[i].openpos > cur_open)
|
||||
exps->pairs[i].openpos += new_len - cur_len;
|
||||
|
||||
if(exps->pairs[i].closepos > cur_close)
|
||||
exps->pairs[i].closepos += new_len - cur_len;
|
||||
}
|
||||
}
|
||||
|
||||
bool printlayer(char* exp, EXPRESSION* exps, int layer, bool silent, bool baseonly)
|
||||
/**
|
||||
\brief Prints value of expressions in between brackets on a certain bracket layer (expression is resolved using mathfromstring(), which means the whole thing can work recursively).
|
||||
\param [in,out] exp The expression to print. Cannot be null.
|
||||
\param [in,out] exps The expression structure. Cannot be null.
|
||||
\param layer The layer to print.
|
||||
\param silent Value to pass on to mathfromstring().
|
||||
\param baseonly Value to pass on to mathfromstring().
|
||||
\return true if printing the layer was succesful, false otherwise.
|
||||
*/
|
||||
static bool printlayer(char* exp, EXPRESSION* exps, int layer, bool silent, bool baseonly)
|
||||
{
|
||||
for(int i = 0; i < exps->total_pairs; i++)
|
||||
{
|
||||
if(exps->pairs[i].layer == layer)
|
||||
{
|
||||
int open = exps->pairs[i].openpos;
|
||||
int close = exps->pairs[i].closepos;
|
||||
int len = close - open;
|
||||
char temp[256] = "";
|
||||
char backup[256] = "";
|
||||
|
||||
char temp[256];
|
||||
int open = exps->pairs[i].openpos;
|
||||
int close = exps->pairs[i].closepos;
|
||||
int len = close - open;
|
||||
strncpy(temp, exp + open + 1, len - 1);
|
||||
|
||||
char backup[256];
|
||||
strcpy_s(backup, exp + open + len + 1);
|
||||
|
||||
uint value;
|
||||
if(!mathfromstring(temp, &value, silent, baseonly, nullptr, nullptr))
|
||||
if(!mathfromstring(temp, &value, silent, baseonly, 0, 0))
|
||||
return false;
|
||||
|
||||
adjustpairs(exps, open, close, len + 1, sprintf(exp + open, "%"fext"X", value));
|
||||
|
||||
if(*backup)
|
||||
strcat(exp, backup);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Handle brackets in an expression (calculate the values of expressions in between brackets).
|
||||
\param [in,out] expression Expression to handle. Cannot be null.
|
||||
\param silent Value to pass on to printlayer().
|
||||
\param baseonly Value to pass on to printlayer().
|
||||
\return true if the brackets are correctly expanded, false otherwise.
|
||||
*/
|
||||
bool mathhandlebrackets(char* expression, bool silent, bool baseonly)
|
||||
{
|
||||
int totalPairs = expressionformat(expression);
|
||||
|
||||
if(totalPairs == -1)
|
||||
EXPRESSION expstruct;
|
||||
expstruct.expression = expression;
|
||||
int total_pairs = expressionformat(expression);
|
||||
if(total_pairs == -1)
|
||||
return false;
|
||||
else if(!totalPairs)
|
||||
else if(!total_pairs)
|
||||
return true;
|
||||
expstruct.total_pairs = total_pairs;
|
||||
|
||||
Memory<BRACKET_PAIR*> pairs(totalPairs * sizeof(BRACKET_PAIR), "mathhandlebrackets:pairs");
|
||||
|
||||
EXPRESSION expStruct;
|
||||
expStruct.expression = expression;
|
||||
expStruct.total_pairs = totalPairs;
|
||||
expStruct.pairs = pairs;
|
||||
|
||||
matchpairs(&expStruct, expression, 0);
|
||||
|
||||
Memory<BRACKET_PAIR*> pairs(expstruct.total_pairs * sizeof(BRACKET_PAIR), "mathhandlebrackets:expstruct.pairs");
|
||||
expstruct.pairs = pairs;
|
||||
memset(expstruct.pairs, 0, expstruct.total_pairs * sizeof(BRACKET_PAIR));
|
||||
matchpairs(&expstruct, expression);
|
||||
int deepest = 0;
|
||||
for (int i = 0; i < expStruct.total_pairs; i++)
|
||||
{
|
||||
if (expStruct.pairs[i].layer > deepest)
|
||||
deepest = expStruct.pairs[i].layer;
|
||||
}
|
||||
|
||||
for (int i = deepest; i > 0; i--)
|
||||
{
|
||||
if (!printlayer(expression, &expStruct, i, silent, baseonly))
|
||||
return false;
|
||||
}
|
||||
for(int i = 0; i < expstruct.total_pairs; i++)
|
||||
if(expstruct.pairs[i].layer > deepest)
|
||||
deepest = expstruct.pairs[i].layer;
|
||||
|
||||
for(int i = deepest; i > 0; i--)
|
||||
if(!printlayer(expression, &expstruct, i, silent, baseonly))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
- handle math
|
||||
/**
|
||||
\brief Calculate the value of an expression string.
|
||||
\param string The string to calculate the value of. Cannot be null.
|
||||
\param [in,out] value The resulting value. Cannot be null.
|
||||
\param silent Value to pass on to valfromstring().
|
||||
\param baseonly Value to pass on to valfromstring().
|
||||
\param [in,out] value_size Value to pass on to valfromstring(). Can be null.
|
||||
\param [in,out] isvar Value to pass on to valfromstring(). Can be null.
|
||||
\return true if the string was successfully parsed and the value was calculated.
|
||||
*/
|
||||
bool mathfromstring(const char* string, uint* value, bool silent, bool baseonly, int* value_size, bool* isvar)
|
||||
{
|
||||
|
|
@ -370,6 +484,8 @@ bool mathfromstring(const char* string, uint* value, bool silent, bool baseonly,
|
|||
return valfromstring(string, value, silent, baseonly, value_size, isvar, 0);
|
||||
Memory<char*> strleft(len + 1 + negative, "mathfromstring:strleft");
|
||||
Memory<char*> strright(len + 1, "mathfromstring:strright");
|
||||
memset(strleft, 0, len + 1);
|
||||
memset(strright, 0, len + 1);
|
||||
strncpy(strleft, string - negative, highestop_pos + negative);
|
||||
strcpy(strright, string + highestop_pos + 1);
|
||||
strcpy(strleft, StringUtils::Trim(strleft).c_str());
|
||||
|
|
@ -399,4 +515,3 @@ bool mathfromstring(const char* string, uint* value, bool silent, bool baseonly,
|
|||
math_ok = mathdounsignedoperation(string[highestop_pos], left, right, value);
|
||||
return math_ok;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
#ifndef _MATH_H
|
||||
#define _MATH_H
|
||||
|
||||
#include "_global.h"
|
||||
|
||||
|
|
@ -8,4 +9,6 @@ bool mathcontains(const char* text);
|
|||
bool mathhandlebrackets(char* expression, bool silent, bool baseonly);
|
||||
bool mathfromstring(const char* string, uint* value, bool silent, bool baseonly, int* value_size, bool* isvar);
|
||||
bool mathdounsignedoperation(char op, uint left, uint right, uint* result);
|
||||
bool mathdosignedoperation(char op, sint left, sint right, sint* result);
|
||||
bool mathdosignedoperation(char op, sint left, sint right, sint* result);
|
||||
|
||||
#endif // _MATH_H
|
||||
|
|
|
|||
|
|
@ -1,3 +1,9 @@
|
|||
/**
|
||||
@file memory.cpp
|
||||
|
||||
@brief Implements the memory class.
|
||||
*/
|
||||
|
||||
#include "memory.h"
|
||||
#include "debugger.h"
|
||||
#include "patches.h"
|
||||
|
|
@ -5,13 +11,13 @@
|
|||
#include "threading.h"
|
||||
#include "module.h"
|
||||
|
||||
#define PAGE_SHIFT (12)
|
||||
#define PAGE_SIZE (4096)
|
||||
#define PAGE_ALIGN(Va) ((ULONG_PTR)((ULONG_PTR)(Va) & ~(PAGE_SIZE - 1)))
|
||||
#define BYTES_TO_PAGES(Size) (((Size) >> PAGE_SHIFT) + (((Size) & (PAGE_SIZE - 1)) != 0))
|
||||
#define ROUND_TO_PAGES(Size) (((ULONG_PTR)(Size) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))
|
||||
#define PAGE_SHIFT (12)
|
||||
#define PAGE_SIZE (4096)
|
||||
#define PAGE_ALIGN(Va) ((ULONG_PTR)((ULONG_PTR)(Va) & ~(PAGE_SIZE - 1)))
|
||||
#define BYTES_TO_PAGES(Size) (((Size) >> PAGE_SHIFT) + (((Size) & (PAGE_SIZE - 1)) != 0))
|
||||
#define ROUND_TO_PAGES(Size) (((ULONG_PTR)(Size) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))
|
||||
|
||||
MemoryMap memoryPages;
|
||||
std::map<Range, MEMPAGE, RangeCompare> memoryPages;
|
||||
bool bListAllPages = false;
|
||||
|
||||
void MemUpdateMap(HANDLE hProcess)
|
||||
|
|
@ -129,16 +135,16 @@ void MemUpdateMap(HANDLE hProcess)
|
|||
}
|
||||
}
|
||||
|
||||
uint MemFindBaseAddr(uint addr, uint* Size, bool refresh)
|
||||
uint MemFindBaseAddr(uint Address, uint* Size, bool Refresh)
|
||||
{
|
||||
// Update the memory map if needed
|
||||
if(refresh)
|
||||
if(Refresh)
|
||||
MemUpdateMap(fdProcessInfo->hProcess);
|
||||
|
||||
SHARED_ACQUIRE(LockMemoryPages);
|
||||
|
||||
// Search for the memory page address
|
||||
auto found = memoryPages.find(std::make_pair(addr, addr));
|
||||
auto found = memoryPages.find(std::make_pair(Address, Address));
|
||||
|
||||
if(found == memoryPages.end())
|
||||
return 0;
|
||||
|
|
@ -152,64 +158,64 @@ uint MemFindBaseAddr(uint addr, uint* Size, bool refresh)
|
|||
|
||||
bool MemRead(void* BaseAddress, void* Buffer, SIZE_T Size, SIZE_T* NumberOfBytesRead)
|
||||
{
|
||||
// Fast fail if address is invalid
|
||||
if (!MemIsCanonicalAddress((uint)BaseAddress))
|
||||
return false;
|
||||
// Fast fail if address is invalid
|
||||
if (!MemIsCanonicalAddress((uint)BaseAddress))
|
||||
return false;
|
||||
|
||||
// Buffer must be supplied and size must be greater than 0
|
||||
if (!Buffer || Size <= 0)
|
||||
return false;
|
||||
// Buffer must be supplied and size must be greater than 0
|
||||
if (!Buffer || Size <= 0)
|
||||
return false;
|
||||
|
||||
// If the 'bytes read' parameter is null, use a temp
|
||||
SIZE_T bytesReadTemp = 0;
|
||||
// If the 'bytes read' parameter is null, use a temp
|
||||
SIZE_T bytesReadTemp = 0;
|
||||
|
||||
if (!NumberOfBytesRead)
|
||||
NumberOfBytesRead = &bytesReadTemp;
|
||||
if (!NumberOfBytesRead)
|
||||
NumberOfBytesRead = &bytesReadTemp;
|
||||
|
||||
// Normal single-call read
|
||||
bool ret = MemoryReadSafe(fdProcessInfo->hProcess, BaseAddress, Buffer, Size, NumberOfBytesRead);
|
||||
// Normal single-call read
|
||||
bool ret = MemoryReadSafe(fdProcessInfo->hProcess, BaseAddress, Buffer, Size, NumberOfBytesRead);
|
||||
|
||||
if (ret && *NumberOfBytesRead == Size)
|
||||
return true;
|
||||
if (ret && *NumberOfBytesRead == Size)
|
||||
return true;
|
||||
|
||||
// Read page-by-page (Skip if only 1 page exists)
|
||||
// If (SIZE > PAGE_SIZE) or (ADDRESS exceeds boundary), multiple reads will be needed
|
||||
SIZE_T pageCount = BYTES_TO_PAGES(Size);
|
||||
// Read page-by-page (Skip if only 1 page exists)
|
||||
// If (SIZE > PAGE_SIZE) or (ADDRESS exceeds boundary), multiple reads will be needed
|
||||
SIZE_T pageCount = BYTES_TO_PAGES(Size);
|
||||
|
||||
if (pageCount > 1)
|
||||
{
|
||||
// Determine the number of bytes between ADDRESS and the next page
|
||||
uint offset = 0;
|
||||
uint readBase = (uint)BaseAddress;
|
||||
uint readSize = ROUND_TO_PAGES(readBase) - readBase;
|
||||
if (pageCount > 1)
|
||||
{
|
||||
// Determine the number of bytes between ADDRESS and the next page
|
||||
uint offset = 0;
|
||||
uint readBase = (uint)BaseAddress;
|
||||
uint readSize = ROUND_TO_PAGES(readBase) - readBase;
|
||||
|
||||
// Reset the bytes read count
|
||||
*NumberOfBytesRead = 0;
|
||||
// Reset the bytes read count
|
||||
*NumberOfBytesRead = 0;
|
||||
|
||||
for (SIZE_T i = 0; i < pageCount; i++)
|
||||
{
|
||||
SIZE_T bytesRead = 0;
|
||||
for (SIZE_T i = 0; i < pageCount; i++)
|
||||
{
|
||||
SIZE_T bytesRead = 0;
|
||||
|
||||
if (MemoryReadSafe(fdProcessInfo->hProcess, (PVOID)readBase, ((PBYTE)Buffer + offset), readSize, &bytesRead))
|
||||
*NumberOfBytesRead += bytesRead;
|
||||
if (MemoryReadSafe(fdProcessInfo->hProcess, (PVOID)readBase, ((PBYTE)Buffer + offset), readSize, &bytesRead))
|
||||
*NumberOfBytesRead += bytesRead;
|
||||
|
||||
offset += readSize;
|
||||
readBase += readSize;
|
||||
offset += readSize;
|
||||
readBase += readSize;
|
||||
|
||||
Size -= readSize;
|
||||
readSize = (Size > PAGE_SIZE) ? PAGE_SIZE : Size;
|
||||
}
|
||||
}
|
||||
Size -= readSize;
|
||||
readSize = (Size > PAGE_SIZE) ? PAGE_SIZE : Size;
|
||||
}
|
||||
}
|
||||
|
||||
SetLastError(ERROR_PARTIAL_COPY);
|
||||
SetLastError(ERROR_PARTIAL_COPY);
|
||||
return (*NumberOfBytesRead > 0);
|
||||
}
|
||||
|
||||
bool MemWrite(void* BaseAddress, void* Buffer, SIZE_T Size, SIZE_T* NumberOfBytesWritten)
|
||||
{
|
||||
// Fast fail if address is invalid
|
||||
if (!MemIsCanonicalAddress((uint)BaseAddress))
|
||||
return false;
|
||||
// Fast fail if address is invalid
|
||||
if (!MemIsCanonicalAddress((uint)BaseAddress))
|
||||
return false;
|
||||
|
||||
// Buffer must be supplied and size must be greater than 0
|
||||
if(!Buffer || Size <= 0)
|
||||
|
|
@ -224,40 +230,40 @@ bool MemWrite(void* BaseAddress, void* Buffer, SIZE_T Size, SIZE_T* NumberOfByte
|
|||
// Try a regular WriteProcessMemory call
|
||||
bool ret = MemoryWriteSafe(fdProcessInfo->hProcess, BaseAddress, Buffer, Size, NumberOfBytesWritten);
|
||||
|
||||
if(ret && * NumberOfBytesWritten == Size)
|
||||
if(ret && *NumberOfBytesWritten == Size)
|
||||
return true;
|
||||
|
||||
// Write page-by-page (Skip if only 1 page exists)
|
||||
// See: MemRead
|
||||
SIZE_T pageCount = BYTES_TO_PAGES(Size);
|
||||
// Write page-by-page (Skip if only 1 page exists)
|
||||
// See: MemRead
|
||||
SIZE_T pageCount = BYTES_TO_PAGES(Size);
|
||||
|
||||
if (pageCount > 1)
|
||||
{
|
||||
// Determine the number of bytes between ADDRESS and the next page
|
||||
uint offset = 0;
|
||||
uint writeBase = (uint)BaseAddress;
|
||||
uint writeSize = ROUND_TO_PAGES(writeBase) - writeBase;
|
||||
if (pageCount > 1)
|
||||
{
|
||||
// Determine the number of bytes between ADDRESS and the next page
|
||||
uint offset = 0;
|
||||
uint writeBase = (uint)BaseAddress;
|
||||
uint writeSize = ROUND_TO_PAGES(writeBase) - writeBase;
|
||||
|
||||
// Reset the bytes read count
|
||||
*NumberOfBytesWritten = 0;
|
||||
// Reset the bytes read count
|
||||
*NumberOfBytesWritten = 0;
|
||||
|
||||
for (SIZE_T i = 0; i < pageCount; i++)
|
||||
{
|
||||
SIZE_T bytesWritten = 0;
|
||||
for (SIZE_T i = 0; i < pageCount; i++)
|
||||
{
|
||||
SIZE_T bytesWritten = 0;
|
||||
|
||||
if (MemoryWriteSafe(fdProcessInfo->hProcess, (PVOID)writeBase, ((PBYTE)Buffer + offset), writeSize, &bytesWritten))
|
||||
*NumberOfBytesWritten += bytesWritten;
|
||||
if (MemoryWriteSafe(fdProcessInfo->hProcess, (PVOID)writeBase, ((PBYTE)Buffer + offset), writeSize, &bytesWritten))
|
||||
*NumberOfBytesWritten += bytesWritten;
|
||||
|
||||
offset += writeSize;
|
||||
writeBase += writeSize;
|
||||
offset += writeSize;
|
||||
writeBase += writeSize;
|
||||
|
||||
Size -= writeSize;
|
||||
writeSize = (Size > PAGE_SIZE) ? PAGE_SIZE : Size;
|
||||
}
|
||||
}
|
||||
Size -= writeSize;
|
||||
writeSize = (Size > PAGE_SIZE) ? PAGE_SIZE : Size;
|
||||
}
|
||||
}
|
||||
|
||||
SetLastError(ERROR_PARTIAL_COPY);
|
||||
return (*NumberOfBytesWritten > 0);
|
||||
SetLastError(ERROR_PARTIAL_COPY);
|
||||
return (*NumberOfBytesWritten > 0);
|
||||
}
|
||||
|
||||
bool MemPatch(void* BaseAddress, void* Buffer, SIZE_T Size, SIZE_T* NumberOfBytesWritten)
|
||||
|
|
@ -277,7 +283,7 @@ bool MemPatch(void* BaseAddress, void* Buffer, SIZE_T Size, SIZE_T* NumberOfByte
|
|||
}
|
||||
|
||||
for(SIZE_T i = 0; i < Size; i++)
|
||||
patchset((uint)BaseAddress + i, oldData[i], ((unsigned char*)Buffer)[i]);
|
||||
PatchSet((uint)BaseAddress + i, oldData[i], ((unsigned char*)Buffer)[i]);
|
||||
|
||||
return MemWrite(BaseAddress, Buffer, Size, NumberOfBytesWritten);
|
||||
}
|
||||
|
|
@ -285,22 +291,22 @@ bool MemPatch(void* BaseAddress, void* Buffer, SIZE_T Size, SIZE_T* NumberOfByte
|
|||
bool MemIsValidReadPtr(uint Address)
|
||||
{
|
||||
unsigned char a = 0;
|
||||
return MemRead((void*)Address, &a, 1, nullptr);
|
||||
return MemRead((void*)Address, &a, sizeof(unsigned char), nullptr);
|
||||
}
|
||||
|
||||
bool MemIsCanonicalAddress(uint Address)
|
||||
{
|
||||
#ifndef _WIN64
|
||||
// 32-bit mode only supports 4GB max, so limits are
|
||||
// not an issue
|
||||
return true;
|
||||
// 32-bit mode only supports 4GB max, so limits are
|
||||
// not an issue
|
||||
return true;
|
||||
#else
|
||||
// The most-significant 16 bits must be all 1 or all 0.
|
||||
// (64 - 16) = 48bit linear address range.
|
||||
//
|
||||
// 0xFFFF800000000000 = Significant 16 bits set
|
||||
// 0x0000800000000000 = 48th bit set
|
||||
return (((Address & 0xFFFF800000000000) + 0x800000000000) & ~0x800000000000) == 0;
|
||||
// The most-significant 16 bits must be all 1 or all 0.
|
||||
// (64 - 16) = 48bit linear address range.
|
||||
//
|
||||
// 0xFFFF800000000000 = Significant 16 bits set
|
||||
// 0x0000800000000000 = 48th bit set
|
||||
return (((Address & 0xFFFF800000000000) + 0x800000000000) & ~0x800000000000) == 0;
|
||||
#endif // _WIN64
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
#pragma once
|
||||
|
||||
#include "_global.h"
|
||||
#include "addrinfo.h"
|
||||
|
||||
typedef std::map<Range, MEMPAGE, RangeCompare> MemoryMap;
|
||||
|
||||
extern MemoryMap memoryPages;
|
||||
extern std::map<Range, MEMPAGE, RangeCompare> memoryPages;
|
||||
extern bool bListAllPages;
|
||||
|
||||
void MemUpdateMap(HANDLE hProcess);
|
||||
uint MemFindBaseAddr(uint addr, uint* Size, bool refresh = false);
|
||||
uint MemFindBaseAddr(uint Address, uint* Size, bool Refresh = false);
|
||||
bool MemRead(void* BaseAddress, void* Buffer, SIZE_T Size, SIZE_T* NumberOfBytesRead);
|
||||
bool MemWrite(void* BaseAddress, void* Buffer, SIZE_T Size, SIZE_T* NumberOfBytesWritten);
|
||||
bool MemPatch(void* BaseAddress, void* Buffer, SIZE_T Size, SIZE_T* NumberOfBytesWritten);
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
#include "symbolinfo.h"
|
||||
#include "murmurhash.h"
|
||||
|
||||
static ModulesInfo modinfo;
|
||||
std::map<Range, MODINFO, RangeCompare> modinfo;
|
||||
|
||||
bool ModLoad(uint Base, uint Size, const char* FullPath)
|
||||
{
|
||||
|
|
@ -93,11 +93,11 @@ bool ModUnload(uint Base)
|
|||
if(found == modinfo.end())
|
||||
return false;
|
||||
|
||||
// Remove it from the list
|
||||
modinfo.erase(found);
|
||||
|
||||
// Unload everything from TitanEngine
|
||||
StaticFileUnloadW(nullptr, false, found->second.Handle, found->second.FileMapSize, found->second.MapHandle, found->second.FileMapVA);
|
||||
|
||||
// Remove it from the list
|
||||
modinfo.erase(found);
|
||||
EXCLUSIVE_RELEASE();
|
||||
|
||||
// Update symbols
|
||||
|
|
@ -199,8 +199,8 @@ uint ModBaseFromName(const char* Module)
|
|||
for(auto itr = modinfo.begin(); itr != modinfo.end(); itr++)
|
||||
{
|
||||
char currentModule[MAX_MODULE_SIZE];
|
||||
strcpy_s(currentModule, itr->second.name);
|
||||
strcat_s(currentModule, itr->second.extension);
|
||||
strcpy_s(currentModule, itr->second.name);
|
||||
strcat_s(currentModule, itr->second.extension);
|
||||
|
||||
// Test with and without extension
|
||||
if(!_stricmp(currentModule, Module) || !_stricmp(itr->second.name, Module))
|
||||
|
|
|
|||
|
|
@ -29,8 +29,6 @@ struct MODINFO
|
|||
std::vector<MODSECTIONINFO> sections;
|
||||
};
|
||||
|
||||
typedef std::map<Range, MODINFO, RangeCompare> ModulesInfo;
|
||||
|
||||
bool ModLoad(uint Base, uint Size, const char* FullPath);
|
||||
bool ModUnload(uint Base);
|
||||
void ModClear();
|
||||
|
|
|
|||
|
|
@ -1,89 +1,55 @@
|
|||
/**
|
||||
@file msgqueue.cpp
|
||||
|
||||
@brief Implements the msgqueue class.
|
||||
*/
|
||||
|
||||
#include "msgqueue.h"
|
||||
#include <stdio.h>
|
||||
|
||||
//allocate a message (internal)
|
||||
static MESSAGE* msgalloc()
|
||||
// Allocate a message stack
|
||||
MESSAGE_STACK* MsgAllocStack()
|
||||
{
|
||||
return (MESSAGE*)emalloc(sizeof(MESSAGE), "msgalloc:msg");
|
||||
// Allocate memory for the structure
|
||||
PVOID memoryBuffer = emalloc(sizeof(MESSAGE_STACK), "MsgAllocStack:memoryBuffer");
|
||||
|
||||
if (!memoryBuffer)
|
||||
return nullptr;
|
||||
|
||||
// Use placement new to ensure all constructors are called correctly
|
||||
return new(memoryBuffer) MESSAGE_STACK;
|
||||
}
|
||||
|
||||
//free a message (internal)
|
||||
static void msgfree(MESSAGE* msg)
|
||||
// Free a message stack and all messages in the queue
|
||||
void MsgFreeStack(MESSAGE_STACK* Stack)
|
||||
{
|
||||
efree(msg, "msgfree:msg");
|
||||
// Destructor must be called manually due to placement new
|
||||
Stack->FIFOStack.~unbounded_buffer();
|
||||
|
||||
// Free memory
|
||||
efree(Stack, "MsgFreeStack:Stack");
|
||||
}
|
||||
|
||||
//allocate a message stack
|
||||
MESSAGE_STACK* msgallocstack()
|
||||
// Add a message to the stack
|
||||
bool MsgSend(MESSAGE_STACK* Stack, int Msg, uint Param1, uint Param2)
|
||||
{
|
||||
MESSAGE_STACK* msgstack = (MESSAGE_STACK*)emalloc(sizeof(MESSAGE_STACK), "msgallocstack:msgstack");
|
||||
if(!msgstack)
|
||||
return 0;
|
||||
memset(msgstack, 0, sizeof(MESSAGE_STACK));
|
||||
InitializeCriticalSection(&msgstack->cr);
|
||||
return msgstack;
|
||||
}
|
||||
MESSAGE messageInfo;
|
||||
messageInfo.msg = Msg;
|
||||
messageInfo.param1 = Param1;
|
||||
messageInfo.param2 = Param2;
|
||||
|
||||
//free a message stack
|
||||
void msgfreestack(MESSAGE_STACK* msgstack)
|
||||
{
|
||||
DeleteCriticalSection(&msgstack->cr);
|
||||
int stackpos = msgstack->stackpos;
|
||||
for(int i = 0; i < stackpos; i++) //free all messages left in stack
|
||||
msgfree(msgstack->msg[i]);
|
||||
efree(msgstack, "msgfreestack:msgstack");
|
||||
}
|
||||
|
||||
//add a message to the stack
|
||||
bool msgsend(MESSAGE_STACK* msgstack, int msg, uint param1, uint param2)
|
||||
{
|
||||
CRITICAL_SECTION* cr = &msgstack->cr;
|
||||
EnterCriticalSection(cr);
|
||||
int stackpos = msgstack->stackpos;
|
||||
if(stackpos >= MAX_MESSAGES)
|
||||
{
|
||||
LeaveCriticalSection(cr);
|
||||
return false;
|
||||
}
|
||||
MESSAGE* newmsg = msgalloc();
|
||||
if(!newmsg)
|
||||
{
|
||||
LeaveCriticalSection(cr);
|
||||
return false;
|
||||
}
|
||||
newmsg->msg = msg;
|
||||
newmsg->param1 = param1;
|
||||
newmsg->param2 = param2;
|
||||
msgstack->msg[stackpos] = newmsg;
|
||||
msgstack->stackpos++; //increase stack pointer
|
||||
LeaveCriticalSection(cr);
|
||||
// Asynchronous send. Return value doesn't matter.
|
||||
concurrency::asend(Stack->FIFOStack, messageInfo);
|
||||
return true;
|
||||
}
|
||||
|
||||
//get a message from the stack (will return false when there are no messages)
|
||||
bool msgget(MESSAGE_STACK* msgstack, MESSAGE* msg)
|
||||
// Get a message from the stack (will return false when there are no messages)
|
||||
bool MsgGet(MESSAGE_STACK* Stack, MESSAGE* Message)
|
||||
{
|
||||
CRITICAL_SECTION* cr = &msgstack->cr;
|
||||
EnterCriticalSection(cr);
|
||||
int stackpos = msgstack->stackpos;
|
||||
if(!msgstack->stackpos) //no messages to process
|
||||
{
|
||||
LeaveCriticalSection(cr);
|
||||
return false;
|
||||
}
|
||||
msgstack->stackpos--; //current message is at stackpos-1
|
||||
stackpos--;
|
||||
MESSAGE* stackmsg = msgstack->msg[stackpos];
|
||||
memcpy(msg, stackmsg, sizeof(MESSAGE));
|
||||
msgfree(stackmsg);
|
||||
msgstack->msg[stackpos] = 0;
|
||||
LeaveCriticalSection(cr);
|
||||
return true;
|
||||
return concurrency::try_receive(Stack->FIFOStack, *Message);
|
||||
}
|
||||
|
||||
//wait for a message on the specified stack
|
||||
void msgwait(MESSAGE_STACK* msgstack, MESSAGE* msg)
|
||||
// Wait for a message on the specified stack
|
||||
void MsgWait(MESSAGE_STACK* Stack, MESSAGE* Message)
|
||||
{
|
||||
while(!msgget(msgstack, msg))
|
||||
Sleep(1);
|
||||
*Message = concurrency::receive(Stack->FIFOStack);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,10 +3,9 @@
|
|||
|
||||
#include "_global.h"
|
||||
#include <windows.h>
|
||||
#include <agents.h>
|
||||
|
||||
#define MAX_MESSAGES 256
|
||||
|
||||
//message structure
|
||||
// Message structure
|
||||
struct MESSAGE
|
||||
{
|
||||
int msg;
|
||||
|
|
@ -14,19 +13,17 @@ struct MESSAGE
|
|||
uint param2;
|
||||
};
|
||||
|
||||
//message stack structure
|
||||
// Message stack structure.
|
||||
// Supports an unlimited number of messages.
|
||||
struct MESSAGE_STACK
|
||||
{
|
||||
CRITICAL_SECTION cr;
|
||||
int stackpos;
|
||||
MESSAGE* msg[MAX_MESSAGES];
|
||||
concurrency::unbounded_buffer<MESSAGE> FIFOStack;
|
||||
};
|
||||
|
||||
//function definitions
|
||||
MESSAGE_STACK* msgallocstack();
|
||||
void msgfreestack(MESSAGE_STACK* msgstack);
|
||||
bool msgsend(MESSAGE_STACK* msgstack, int msg, uint param1, uint param2);
|
||||
bool msgget(MESSAGE_STACK* msgstack, MESSAGE* msg);
|
||||
void msgwait(MESSAGE_STACK* msgstack, MESSAGE* msg);
|
||||
MESSAGE_STACK* MsgAllocStack();
|
||||
void MsgFreeStack(MESSAGE_STACK* Stack);
|
||||
bool MsgSend(MESSAGE_STACK* Stack, int Msg, uint Param1, uint Param2);
|
||||
bool MsgGet(MESSAGE_STACK* Stack, MESSAGE* Message);
|
||||
void MsgWait(MESSAGE_STACK* Stack, MESSAGE* Message);
|
||||
|
||||
#endif // _MSGQUEUE_H
|
||||
|
|
|
|||
|
|
@ -16,19 +16,56 @@
|
|||
|
||||
#if defined(_MSC_VER)
|
||||
|
||||
/**
|
||||
@def FORCE_INLINE
|
||||
|
||||
@brief A macro that defines force inline.
|
||||
*/
|
||||
|
||||
#define FORCE_INLINE __forceinline
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/**
|
||||
@def ROTL32(x,y) _rotl(x,y)
|
||||
|
||||
@brief A macro that defines rotl 32.
|
||||
|
||||
@param x The void to process.
|
||||
@param y The void to process.
|
||||
*/
|
||||
|
||||
#define ROTL32(x,y) _rotl(x,y)
|
||||
|
||||
/**
|
||||
@def ROTL64(x,y) _rotl64(x,y)
|
||||
|
||||
@brief A macro that defines rotl 64.
|
||||
|
||||
@param x The void to process.
|
||||
@param y The void to process.
|
||||
*/
|
||||
|
||||
#define ROTL64(x,y) _rotl64(x,y)
|
||||
|
||||
/**
|
||||
@def BIG_CONSTANT(x) (x)
|
||||
|
||||
@brief A macro that defines big constant.
|
||||
|
||||
@param x The void to process.
|
||||
*/
|
||||
|
||||
#define BIG_CONSTANT(x) (x)
|
||||
|
||||
// Other compilers
|
||||
|
||||
#else // defined(_MSC_VER)
|
||||
|
||||
/**
|
||||
@brief The force inline.
|
||||
*/
|
||||
|
||||
#define FORCE_INLINE inline __attribute__((always_inline))
|
||||
|
||||
inline uint32_t rotl32(uint32_t x, int8_t r)
|
||||
|
|
@ -41,29 +78,84 @@ inline uint64_t rotl64(uint64_t x, int8_t r)
|
|||
return (x << r) | (x >> (64 - r));
|
||||
}
|
||||
|
||||
/**
|
||||
@def ROTL32(x,y) rotl32(x,y)
|
||||
|
||||
@brief A macro that defines rotl 32.
|
||||
|
||||
@param x The void to process.
|
||||
@param y The void to process.
|
||||
*/
|
||||
|
||||
#define ROTL32(x,y) rotl32(x,y)
|
||||
|
||||
/**
|
||||
@def ROTL64(x,y) rotl64(x,y)
|
||||
|
||||
@brief A macro that defines rotl 64.
|
||||
|
||||
@param x The void to process.
|
||||
@param y The void to process.
|
||||
*/
|
||||
|
||||
#define ROTL64(x,y) rotl64(x,y)
|
||||
|
||||
/**
|
||||
@def BIG_CONSTANT(x) (x##LLU)
|
||||
|
||||
@brief A macro that defines big constant.
|
||||
|
||||
@param x The void to process.
|
||||
*/
|
||||
|
||||
#define BIG_CONSTANT(x) (x##LLU)
|
||||
|
||||
#endif // !defined(_MSC_VER)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Block read - if your platform needs to do endian-swapping or can only
|
||||
// handle aligned reads, do the conversion here
|
||||
/**
|
||||
@fn FORCE_INLINE uint32_t getblock32(const uint32_t* p, int i)
|
||||
|
||||
@brief -----------------------------------------------------------------------------
|
||||
Block read - if your platform needs to do endian-swapping or can only handle aligned reads, do
|
||||
the conversion here.
|
||||
|
||||
@param p The const uint32_t* to process.
|
||||
@param i Zero-based index of the.
|
||||
|
||||
@return An uint32_t.
|
||||
*/
|
||||
|
||||
FORCE_INLINE uint32_t getblock32(const uint32_t* p, int i)
|
||||
{
|
||||
return p[i];
|
||||
}
|
||||
|
||||
/**
|
||||
@fn FORCE_INLINE uint64_t getblock64(const uint64_t* p, int i)
|
||||
|
||||
@brief Getblock 64.
|
||||
|
||||
@param p The const uint64_t* to process.
|
||||
@param i Zero-based index of the.
|
||||
|
||||
@return An uint64_t.
|
||||
*/
|
||||
|
||||
FORCE_INLINE uint64_t getblock64(const uint64_t* p, int i)
|
||||
{
|
||||
return p[i];
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Finalization mix - force all bits of a hash block to avalanche
|
||||
/**
|
||||
@fn FORCE_INLINE uint32_t fmix32(uint32_t h)
|
||||
|
||||
@brief -----------------------------------------------------------------------------
|
||||
Finalization mix - force all bits of a hash block to avalanche.
|
||||
|
||||
@param h The uint32_t to process.
|
||||
|
||||
@return An uint32_t.
|
||||
*/
|
||||
|
||||
FORCE_INLINE uint32_t fmix32(uint32_t h)
|
||||
{
|
||||
|
|
@ -78,6 +170,16 @@ FORCE_INLINE uint32_t fmix32(uint32_t h)
|
|||
|
||||
//----------
|
||||
|
||||
/**
|
||||
@fn FORCE_INLINE uint64_t fmix64(uint64_t k)
|
||||
|
||||
@brief Fmix 64.
|
||||
|
||||
@param k The uint64_t to process.
|
||||
|
||||
@return An uint64_t.
|
||||
*/
|
||||
|
||||
FORCE_INLINE uint64_t fmix64(uint64_t k)
|
||||
{
|
||||
k ^= k >> 33;
|
||||
|
|
@ -91,6 +193,17 @@ FORCE_INLINE uint64_t fmix64(uint64_t k)
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
@fn void MurmurHash3_x86_32(const void* key, int len, uint32_t seed, void* out)
|
||||
|
||||
@brief Murmur hash 3 x coordinate 86 32.
|
||||
|
||||
@param key The key.
|
||||
@param len The length.
|
||||
@param seed The seed.
|
||||
@param [in,out] out If non-null, the out.
|
||||
*/
|
||||
|
||||
void MurmurHash3_x86_32(const void* key, int len,
|
||||
uint32_t seed, void* out)
|
||||
{
|
||||
|
|
@ -153,6 +266,17 @@ void MurmurHash3_x86_32(const void* key, int len,
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
@fn void MurmurHash3_x86_128(const void* key, const int len, uint32_t seed, void* out)
|
||||
|
||||
@brief Murmur hash 3 x coordinate 86 128.
|
||||
|
||||
@param key The key.
|
||||
@param len The length.
|
||||
@param seed The seed.
|
||||
@param [in,out] out If non-null, the out.
|
||||
*/
|
||||
|
||||
void MurmurHash3_x86_128(const void* key, const int len,
|
||||
uint32_t seed, void* out)
|
||||
{
|
||||
|
|
@ -316,6 +440,17 @@ void MurmurHash3_x86_128(const void* key, const int len,
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
@fn void MurmurHash3_x64_128(const void* key, const int len, const uint32_t seed, void* out)
|
||||
|
||||
@brief Murmur hash 3 x coordinate 64 128.
|
||||
|
||||
@param key The key.
|
||||
@param len The length.
|
||||
@param seed The seed.
|
||||
@param [in,out] out If non-null, the out.
|
||||
*/
|
||||
|
||||
void MurmurHash3_x64_128(const void* key, const int len,
|
||||
const uint32_t seed, void* out)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,3 +1,9 @@
|
|||
/**
|
||||
@file patches.cpp
|
||||
|
||||
@brief Implements the patches class.
|
||||
*/
|
||||
|
||||
#include "patches.h"
|
||||
#include "addrinfo.h"
|
||||
#include "memory.h"
|
||||
|
|
@ -6,198 +12,308 @@
|
|||
#include "threading.h"
|
||||
#include "module.h"
|
||||
|
||||
static PatchesInfo patches;
|
||||
std::unordered_map<uint, PATCHINFO> patches;
|
||||
|
||||
bool patchset(uint addr, unsigned char oldbyte, unsigned char newbyte)
|
||||
bool PatchSet(uint Address, unsigned char OldByte, unsigned char NewByte)
|
||||
{
|
||||
if(!DbgIsDebugging() || !MemIsValidReadPtr(addr))
|
||||
// CHECK: Exported function
|
||||
if (!DbgIsDebugging())
|
||||
return false;
|
||||
if(oldbyte == newbyte)
|
||||
return true; //no need to make a patch for a byte that is equal to itself
|
||||
|
||||
// Address must be valid
|
||||
if(!MemIsValidReadPtr(Address))
|
||||
return false;
|
||||
|
||||
// Don't patch anything if the new and old values are the same
|
||||
if(OldByte == NewByte)
|
||||
return true;
|
||||
|
||||
PATCHINFO newPatch;
|
||||
newPatch.addr = addr - ModBaseFromAddr(addr);
|
||||
ModNameFromAddr(addr, newPatch.mod, true);
|
||||
newPatch.oldbyte = oldbyte;
|
||||
newPatch.newbyte = newbyte;
|
||||
uint key = ModHashFromAddr(addr);
|
||||
CriticalSectionLocker locker(LockPatches);
|
||||
PatchesInfo::iterator found = patches.find(key);
|
||||
if(found != patches.end()) //we found a patch on the specified address
|
||||
newPatch.addr = Address - ModBaseFromAddr(Address);
|
||||
newPatch.oldbyte = OldByte;
|
||||
newPatch.newbyte = NewByte;
|
||||
ModNameFromAddr(Address, newPatch.mod, true);
|
||||
|
||||
// Generate a key for this address
|
||||
const uint key = ModHashFromAddr(Address);
|
||||
|
||||
EXCLUSIVE_ACQUIRE(LockPatches);
|
||||
|
||||
// Find any patch with this specific address
|
||||
auto found = patches.find(key);
|
||||
|
||||
if(found != patches.end())
|
||||
{
|
||||
if(found->second.oldbyte == newbyte) //patch is undone
|
||||
if(found->second.oldbyte == NewByte)
|
||||
{
|
||||
// The patch was undone here
|
||||
patches.erase(found);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
newPatch.oldbyte = found->second.oldbyte; //keep the original byte from the previous patch
|
||||
found->second = newPatch;
|
||||
// Keep the original byte from the previous patch
|
||||
newPatch.oldbyte = found->second.oldbyte;
|
||||
found->second = newPatch;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// The entry was never found, insert it
|
||||
patches.insert(std::make_pair(key, newPatch));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool patchget(uint addr, PATCHINFO* patch)
|
||||
bool PatchGet(uint Address, PATCHINFO* Patch)
|
||||
{
|
||||
// CHECK: Export
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
CriticalSectionLocker locker(LockPatches);
|
||||
PatchesInfo::iterator found = patches.find(ModHashFromAddr(addr));
|
||||
if(found == patches.end()) //not found
|
||||
|
||||
SHARED_ACQUIRE(LockPatches);
|
||||
|
||||
// Find this specific address in the list
|
||||
auto found = patches.find(ModHashFromAddr(Address));
|
||||
|
||||
if(found == patches.end())
|
||||
return false;
|
||||
if(patch)
|
||||
|
||||
// Did the user request an output buffer?
|
||||
if(Patch)
|
||||
{
|
||||
*patch = found->second;
|
||||
patch->addr += ModBaseFromAddr(addr);
|
||||
return true;
|
||||
*Patch = found->second;
|
||||
Patch->addr += ModBaseFromAddr(Address);
|
||||
}
|
||||
return (found->second.oldbyte != found->second.newbyte);
|
||||
|
||||
// Return true because the patch was found
|
||||
return true;
|
||||
}
|
||||
|
||||
bool patchdel(uint addr, bool restore)
|
||||
bool PatchDelete(uint Address, bool Restore)
|
||||
{
|
||||
// CHECK: Export function
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
CriticalSectionLocker locker(LockPatches);
|
||||
PatchesInfo::iterator found = patches.find(ModHashFromAddr(addr));
|
||||
if(found == patches.end()) //not found
|
||||
|
||||
EXCLUSIVE_ACQUIRE(LockPatches);
|
||||
|
||||
// Do a list lookup with hash
|
||||
auto found = patches.find(ModHashFromAddr(Address));
|
||||
|
||||
if(found == patches.end())
|
||||
return false;
|
||||
if(restore)
|
||||
MemWrite((void*)(found->second.addr + ModBaseFromAddr(addr)), &found->second.oldbyte, sizeof(char), 0);
|
||||
|
||||
// Restore the original byte at this address
|
||||
if(Restore)
|
||||
MemWrite((void*)(found->second.addr + ModBaseFromAddr(Address)), &found->second.oldbyte, sizeof(char), nullptr);
|
||||
|
||||
// Finally remove it from the list
|
||||
patches.erase(found);
|
||||
return true;
|
||||
}
|
||||
|
||||
void patchdelrange(uint start, uint end, bool restore)
|
||||
void PatchDelRange(uint Start, uint End, bool Restore)
|
||||
{
|
||||
if(!DbgIsDebugging())
|
||||
// CHECK: Export call
|
||||
if (!DbgIsDebugging())
|
||||
return;
|
||||
bool bDelAll = (start == 0 && end == ~0); //0x00000000-0xFFFFFFFF
|
||||
uint modbase = ModBaseFromAddr(start);
|
||||
if(modbase != ModBaseFromAddr(end))
|
||||
return;
|
||||
start -= modbase;
|
||||
end -= modbase;
|
||||
CriticalSectionLocker locker(LockPatches);
|
||||
PatchesInfo::iterator i = patches.begin();
|
||||
while(i != patches.end())
|
||||
{
|
||||
if(bDelAll || (i->second.addr >= start && i->second.addr < end))
|
||||
{
|
||||
if(restore)
|
||||
MemWrite((void*)(i->second.addr + modbase), &i->second.oldbyte, sizeof(char), 0);
|
||||
patches.erase(i++);
|
||||
}
|
||||
else
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void patchclear(const char* mod)
|
||||
{
|
||||
CriticalSectionLocker locker(LockPatches);
|
||||
if(!mod or !*mod)
|
||||
// Are all bookmarks going to be deleted?
|
||||
// 0x00000000 - 0xFFFFFFFF
|
||||
if (Start == 0 && End == ~0)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockPatches);
|
||||
patches.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
PatchesInfo::iterator i = patches.begin();
|
||||
while(i != patches.end())
|
||||
// Make sure 'Start' and 'End' reference the same module
|
||||
uint moduleBase = ModBaseFromAddr(Start);
|
||||
|
||||
if (moduleBase != ModBaseFromAddr(End))
|
||||
return;
|
||||
|
||||
// VA to RVA in module
|
||||
Start -= moduleBase;
|
||||
End -= moduleBase;
|
||||
|
||||
EXCLUSIVE_ACQUIRE(LockPatches);
|
||||
for (auto itr = patches.begin(); itr != patches.end();)
|
||||
{
|
||||
if(!_stricmp(i->second.mod, mod))
|
||||
patches.erase(i++);
|
||||
// [Start, End)
|
||||
if (itr->second.addr >= Start && itr->second.addr < End)
|
||||
{
|
||||
// Restore the original byte if necessary
|
||||
if (Restore)
|
||||
MemWrite((void*)(itr->second.addr + moduleBase), &itr->second.oldbyte, sizeof(char), nullptr);
|
||||
|
||||
itr = patches.erase(itr);
|
||||
}
|
||||
else
|
||||
i++;
|
||||
itr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool patchenum(PATCHINFO* patcheslist, size_t* cbsize)
|
||||
bool PatchEnum(PATCHINFO* List, size_t* Size)
|
||||
{
|
||||
// CHECK: Exported
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
if(!patcheslist && !cbsize)
|
||||
|
||||
// At least one parameter is needed
|
||||
if(!List && !Size)
|
||||
return false;
|
||||
CriticalSectionLocker locker(LockPatches);
|
||||
if(!patcheslist && cbsize)
|
||||
|
||||
SHARED_ACQUIRE(LockPatches);
|
||||
|
||||
// Did the user request the size?
|
||||
if(Size)
|
||||
{
|
||||
*cbsize = patches.size() * sizeof(PATCHINFO);
|
||||
return true;
|
||||
*Size = patches.size() * sizeof(PATCHINFO);
|
||||
|
||||
if (!List)
|
||||
return true;
|
||||
}
|
||||
int j = 0;
|
||||
for(PatchesInfo::iterator i = patches.begin(); i != patches.end(); ++i, j++)
|
||||
|
||||
// Copy each vector entry to a C-style array
|
||||
for(auto& itr : patches)
|
||||
{
|
||||
patcheslist[j] = i->second;
|
||||
uint modbase = ModBaseFromName(patcheslist[j].mod);
|
||||
patcheslist[j].addr += modbase;
|
||||
*List = itr.second;
|
||||
List->addr += ModBaseFromName(itr.second.mod);;
|
||||
List++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int patchfile(const PATCHINFO* patchlist, int count, const char* szFileName, char* error)
|
||||
int PatchFile(const PATCHINFO* List, int Count, const char* FileName, char* Error)
|
||||
{
|
||||
if(!count)
|
||||
//
|
||||
// This function returns an int based on the number
|
||||
// of patches applied. -1 indicates a failure.
|
||||
//
|
||||
if(Count <= 0)
|
||||
{
|
||||
if(error)
|
||||
strcpy_s(error, MAX_ERROR_SIZE, "no patches to apply");
|
||||
// Notify the user of the error
|
||||
if(Error)
|
||||
strcpy_s(Error, MAX_ERROR_SIZE, "No patches to apply");
|
||||
|
||||
return -1;
|
||||
}
|
||||
char modname[MAX_MODULE_SIZE] = "";
|
||||
strcpy_s(modname, patchlist[0].mod);
|
||||
//check if all patches are in the same module
|
||||
for(int i = 0; i < count; i++)
|
||||
if(_stricmp(patchlist[i].mod, modname))
|
||||
|
||||
// Get a copy of the first module name in the array
|
||||
char moduleName[MAX_MODULE_SIZE];
|
||||
strcpy_s(moduleName, List[0].mod);
|
||||
|
||||
// Check if all patches are in the same module
|
||||
for (int i = 0; i < Count; i++)
|
||||
{
|
||||
if (_stricmp(List[i].mod, moduleName))
|
||||
{
|
||||
if(error)
|
||||
sprintf(error, "not all patches are in module %s", modname);
|
||||
if (Error)
|
||||
sprintf_s(Error, MAX_ERROR_SIZE, "not all patches are in module %s", moduleName);
|
||||
|
||||
return -1;
|
||||
}
|
||||
uint modbase = ModBaseFromName(modname);
|
||||
if(!modbase) //module not loaded
|
||||
}
|
||||
|
||||
// See if the module was loaded
|
||||
uint moduleBase = ModBaseFromName(moduleName);
|
||||
|
||||
if(!moduleBase)
|
||||
{
|
||||
if(error)
|
||||
sprintf(error, "failed to get base of module %s", modname);
|
||||
if(Error)
|
||||
sprintf_s(Error, MAX_ERROR_SIZE, "failed to get base of module %s", moduleName);
|
||||
|
||||
return -1;
|
||||
}
|
||||
wchar_t szOriginalName[MAX_PATH] = L"";
|
||||
if(!GetModuleFileNameExW(fdProcessInfo->hProcess, (HMODULE)modbase, szOriginalName, MAX_PATH))
|
||||
|
||||
// Get the unicode version of the module's path
|
||||
wchar_t originalName[MAX_PATH];
|
||||
|
||||
if(!GetModuleFileNameExW(fdProcessInfo->hProcess, (HMODULE)moduleBase, originalName, ARRAYSIZE(originalName)))
|
||||
{
|
||||
if(error)
|
||||
sprintf(error, "failed to get module path of module %s", modname);
|
||||
if(Error)
|
||||
sprintf_s(Error, MAX_ERROR_SIZE, "Failed to get module path of module %s", moduleName);
|
||||
|
||||
return -1;
|
||||
}
|
||||
if(!CopyFileW(szOriginalName, StringUtils::Utf8ToUtf16(szFileName).c_str(), false))
|
||||
|
||||
// Create a temporary backup file
|
||||
if(!CopyFileW(originalName, StringUtils::Utf8ToUtf16(FileName).c_str(), false))
|
||||
{
|
||||
if(error)
|
||||
strcpy_s(error, MAX_ERROR_SIZE, "failed to make a copy of the original file (patch target is in use?)");
|
||||
if(Error)
|
||||
strcpy_s(Error, MAX_ERROR_SIZE, "Failed to make a copy of the original file (patch target is in use?)");
|
||||
|
||||
return -1;
|
||||
}
|
||||
HANDLE FileHandle;
|
||||
DWORD LoadedSize;
|
||||
HANDLE FileMap;
|
||||
ULONG_PTR FileMapVA;
|
||||
if(StaticFileLoadW(StringUtils::Utf8ToUtf16(szFileName).c_str(), UE_ACCESS_ALL, false, &FileHandle, &LoadedSize, &FileMap, &FileMapVA))
|
||||
|
||||
HANDLE fileHandle;
|
||||
DWORD loadedSize;
|
||||
HANDLE fileMap;
|
||||
ULONG_PTR fileMapVa;
|
||||
if (!StaticFileLoadW(StringUtils::Utf8ToUtf16(FileName).c_str(), UE_ACCESS_ALL, false, &fileHandle, &loadedSize, &fileMap, &fileMapVa))
|
||||
{
|
||||
int patched = 0;
|
||||
for(int i = 0; i < count; i++)
|
||||
{
|
||||
unsigned char* ptr = (unsigned char*)ConvertVAtoFileOffsetEx(FileMapVA, LoadedSize, modbase, patchlist[i].addr, false, true);
|
||||
if(!ptr) //skip patches that do not have a raw address
|
||||
continue;
|
||||
dprintf("patch%.4d|%s[%.8X]:%.2X/%.2X->%.2X\n", i + 1, modname, ptr - FileMapVA, *ptr, patchlist[i].oldbyte, patchlist[i].newbyte);
|
||||
*ptr = patchlist[i].newbyte;
|
||||
patched++;
|
||||
}
|
||||
if(!StaticFileUnloadW(StringUtils::Utf8ToUtf16(szFileName).c_str(), true, FileHandle, LoadedSize, FileMap, FileMapVA))
|
||||
{
|
||||
if(error)
|
||||
strcpy_s(error, MAX_ERROR_SIZE, "StaticFileUnload failed");
|
||||
return -1;
|
||||
}
|
||||
return patched;
|
||||
strcpy_s(Error, MAX_ERROR_SIZE, "StaticFileLoad failed");
|
||||
return -1;
|
||||
}
|
||||
strcpy_s(error, MAX_ERROR_SIZE, "StaticFileLoad failed");
|
||||
return -1;
|
||||
|
||||
// Begin iterating all patches, applying them to a file
|
||||
int patchCount = 0;
|
||||
|
||||
for(int i = 0; i < Count; i++)
|
||||
{
|
||||
// Convert the virtual address to an offset within disk file data
|
||||
unsigned char* ptr = (unsigned char*)ConvertVAtoFileOffsetEx(fileMapVa, loadedSize, moduleBase, List[i].addr, false, true);
|
||||
|
||||
// Skip patches that do not have a raw address
|
||||
if(!ptr)
|
||||
continue;
|
||||
|
||||
dprintf("patch%.4d|%s[%.8X]:%.2X/%.2X->%.2X\n", i + 1, moduleName, ptr - fileMapVa, *ptr, List[i].oldbyte, List[i].newbyte);
|
||||
*ptr = List[i].newbyte;
|
||||
patchCount++;
|
||||
}
|
||||
|
||||
// Unload the file from memory and commit changes to disk
|
||||
if(!StaticFileUnloadW(StringUtils::Utf8ToUtf16(FileName).c_str(), true, fileHandle, loadedSize, fileMap, fileMapVa))
|
||||
{
|
||||
if(Error)
|
||||
strcpy_s(Error, MAX_ERROR_SIZE, "StaticFileUnload failed");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Zero the error message and return count
|
||||
if (Error)
|
||||
memset(Error, 0, MAX_ERROR_SIZE * sizeof(char));
|
||||
|
||||
return patchCount;
|
||||
}
|
||||
|
||||
void PatchClear(const char* Module)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockPatches);
|
||||
|
||||
// Was a module specified?
|
||||
if (!Module || Module[0] == '\0')
|
||||
{
|
||||
// No specific entries to delete, so remove all of them
|
||||
patches.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise iterate over each patch and check the owner
|
||||
// module for the address
|
||||
for (auto itr = patches.begin(); itr != patches.end();)
|
||||
{
|
||||
if (!_stricmp(itr->second.mod, Module))
|
||||
itr = patches.erase(itr);
|
||||
else
|
||||
itr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
#ifndef _PATCHES_H
|
||||
#define _PATCHES_H
|
||||
#pragma once
|
||||
|
||||
#include "_global.h"
|
||||
|
||||
|
|
@ -10,14 +9,11 @@ struct PATCHINFO
|
|||
unsigned char oldbyte;
|
||||
unsigned char newbyte;
|
||||
};
|
||||
typedef std::map<uint, PATCHINFO> PatchesInfo;
|
||||
|
||||
bool patchset(uint addr, unsigned char oldbyte, unsigned char newbyte);
|
||||
bool patchget(uint addr, PATCHINFO* patch);
|
||||
bool patchdel(uint addr, bool restore);
|
||||
void patchdelrange(uint start, uint end, bool restore);
|
||||
void patchclear(const char* mod = 0);
|
||||
bool patchenum(PATCHINFO* patchlist, size_t* cbsize);
|
||||
int patchfile(const PATCHINFO* patchlist, int count, const char* szFileName, char* error);
|
||||
|
||||
#endif //_PATCHES_H
|
||||
bool PatchSet(uint Address, unsigned char OldByte, unsigned char NewByte);
|
||||
bool PatchGet(uint Address, PATCHINFO* Patch);
|
||||
bool PatchDelete(uint Address, bool Restore);
|
||||
void PatchDelRange(uint Start, uint End, bool Restore);
|
||||
bool PatchEnum(PATCHINFO* List, size_t* Size);
|
||||
int PatchFile(const PATCHINFO* List, int Count, const char* FileName, char* Error);
|
||||
void PatchClear(const char* Module = nullptr);
|
||||
|
|
@ -16,7 +16,7 @@ struct PatternByte
|
|||
static string formathexpattern(string patterntext)
|
||||
{
|
||||
string result;
|
||||
int len = patterntext.length();
|
||||
int len = (int)patterntext.length();
|
||||
for(int i = 0; i < len; i++)
|
||||
if(patterntext[i] == '?' || isxdigit(patterntext[i]))
|
||||
result += toupper(patterntext[i]);
|
||||
|
|
@ -38,7 +38,7 @@ static bool patterntransform(string patterntext, vector<PatternByte> & pattern)
|
|||
{
|
||||
pattern.clear();
|
||||
patterntext = formathexpattern(patterntext);
|
||||
int len = patterntext.length();
|
||||
int len = (int)patterntext.length();
|
||||
if(!len)
|
||||
return false;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,16 +1,44 @@
|
|||
/**
|
||||
@file plugin_loader.cpp
|
||||
|
||||
@brief Implements the plugin loader.
|
||||
*/
|
||||
|
||||
#include "plugin_loader.h"
|
||||
#include "console.h"
|
||||
#include "debugger.h"
|
||||
#include "memory.h"
|
||||
#include "x64_dbg.h"
|
||||
|
||||
/**
|
||||
\brief List of plugins.
|
||||
*/
|
||||
static std::vector<PLUG_DATA> pluginList;
|
||||
|
||||
/**
|
||||
\brief The current plugin handle.
|
||||
*/
|
||||
static int curPluginHandle = 0;
|
||||
|
||||
/**
|
||||
\brief List of plugin callbacks.
|
||||
*/
|
||||
static std::vector<PLUG_CALLBACK> pluginCallbackList;
|
||||
|
||||
/**
|
||||
\brief List of plugin commands.
|
||||
*/
|
||||
static std::vector<PLUG_COMMAND> pluginCommandList;
|
||||
|
||||
/**
|
||||
\brief List of plugin menus.
|
||||
*/
|
||||
static std::vector<PLUG_MENU> pluginMenuList;
|
||||
|
||||
///internal plugin functions
|
||||
/**
|
||||
\brief Loads plugins from a specified directory.
|
||||
\param pluginDir The directory to load plugins from.
|
||||
*/
|
||||
void pluginload(const char* pluginDir)
|
||||
{
|
||||
//load new plugins
|
||||
|
|
@ -240,6 +268,10 @@ void pluginload(const char* pluginDir)
|
|||
SetCurrentDirectoryW(currentDir);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Unregister all plugin commands.
|
||||
\param pluginHandle Handle of the plugin to remove the commands from.
|
||||
*/
|
||||
static void plugincmdunregisterall(int pluginHandle)
|
||||
{
|
||||
int listsize = (int)pluginCommandList.size();
|
||||
|
|
@ -253,6 +285,9 @@ static void plugincmdunregisterall(int pluginHandle)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Unloads all plugins.
|
||||
*/
|
||||
void pluginunload()
|
||||
{
|
||||
int pluginCount = (int)pluginList.size();
|
||||
|
|
@ -270,7 +305,12 @@ void pluginunload()
|
|||
GuiMenuClear(GUI_PLUGIN_MENU); //clear the plugin menu
|
||||
}
|
||||
|
||||
///debugging plugin exports
|
||||
/**
|
||||
\brief Register a plugin callback.
|
||||
\param pluginHandle Handle of the plugin to register a callback for.
|
||||
\param cbType The type of the callback to register.
|
||||
\param cbPlugin The actual callback function.
|
||||
*/
|
||||
void pluginregistercallback(int pluginHandle, CBTYPE cbType, CBPLUGIN cbPlugin)
|
||||
{
|
||||
pluginunregistercallback(pluginHandle, cbType); //remove previous callback
|
||||
|
|
@ -281,6 +321,11 @@ void pluginregistercallback(int pluginHandle, CBTYPE cbType, CBPLUGIN cbPlugin)
|
|||
pluginCallbackList.push_back(cbStruct);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Unregister all plugin callbacks of a certain type.
|
||||
\param pluginHandle Handle of the plugin to unregister a callback from.
|
||||
\param cbType The type of the callback to unregister.
|
||||
*/
|
||||
bool pluginunregistercallback(int pluginHandle, CBTYPE cbType)
|
||||
{
|
||||
int pluginCallbackCount = (int)pluginCallbackList.size();
|
||||
|
|
@ -295,6 +340,11 @@ bool pluginunregistercallback(int pluginHandle, CBTYPE cbType)
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Call all registered callbacks of a certain type.
|
||||
\param cbType The type of callbacks to call.
|
||||
\param [in,out] callbackInfo Information describing the callback. See plugin documentation for more information on this.
|
||||
*/
|
||||
void plugincbcall(CBTYPE cbType, void* callbackInfo)
|
||||
{
|
||||
int pluginCallbackCount = (int)pluginCallbackList.size();
|
||||
|
|
@ -303,12 +353,20 @@ void plugincbcall(CBTYPE cbType, void* callbackInfo)
|
|||
if(pluginCallbackList.at(i).cbType == cbType)
|
||||
{
|
||||
CBPLUGIN cbPlugin = pluginCallbackList.at(i).cbPlugin;
|
||||
if(!IsBadReadPtr((const void*)cbPlugin, sizeof(uint)))
|
||||
if(!IsBadReadPtr((const void *)cbPlugin, sizeof(uint)))
|
||||
cbPlugin(cbType, callbackInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Register a plugin command.
|
||||
\param pluginHandle Handle of the plugin to register a command for.
|
||||
\param command The command text to register. This text cannot contain the '\1' character. This text is not case sensitive.
|
||||
\param cbCommand The command callback.
|
||||
\param debugonly true if the command can only be called during debugging.
|
||||
\return true if it the registration succeeded, false otherwise.
|
||||
*/
|
||||
bool plugincmdregister(int pluginHandle, const char* command, CBPLUGINCOMMAND cbCommand, bool debugonly)
|
||||
{
|
||||
if(!command or strlen(command) >= deflen or strstr(command, "\1"))
|
||||
|
|
@ -323,6 +381,12 @@ bool plugincmdregister(int pluginHandle, const char* command, CBPLUGINCOMMAND cb
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Unregister a plugin command.
|
||||
\param pluginHandle Handle of the plugin to unregister the command from.
|
||||
\param command The command text to unregister. This text is not case sensitive.
|
||||
\return true if the command was found and removed, false otherwise.
|
||||
*/
|
||||
bool plugincmdunregister(int pluginHandle, const char* command)
|
||||
{
|
||||
if(!command or strlen(command) >= deflen or strstr(command, "\1"))
|
||||
|
|
@ -342,6 +406,12 @@ bool plugincmdunregister(int pluginHandle, const char* command)
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Add a new plugin (sub)menu.
|
||||
\param hMenu The menu handle to add the (sub)menu to.
|
||||
\param title The title of the (sub)menu.
|
||||
\return The handle of the new (sub)menu.
|
||||
*/
|
||||
int pluginmenuadd(int hMenu, const char* title)
|
||||
{
|
||||
if(!title or !strlen(title))
|
||||
|
|
@ -366,6 +436,13 @@ int pluginmenuadd(int hMenu, const char* title)
|
|||
return hMenuNew;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Add a plugin menu entry to a menu.
|
||||
\param hMenu The menu to add the entry to.
|
||||
\param hEntry The handle you like to have the entry. This should be a unique value in the scope of the plugin that registered the \p hMenu.
|
||||
\param title The menu entry title.
|
||||
\return true if the \p hEntry was unique and the entry was successfully added, false otherwise.
|
||||
*/
|
||||
bool pluginmenuaddentry(int hMenu, int hEntry, const char* title)
|
||||
{
|
||||
if(!title or !strlen(title) or hEntry == -1)
|
||||
|
|
@ -397,6 +474,11 @@ bool pluginmenuaddentry(int hMenu, int hEntry, const char* title)
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Add a menu separator to a menu.
|
||||
\param hMenu The menu to add the separator to.
|
||||
\return true if it succeeds, false otherwise.
|
||||
*/
|
||||
bool pluginmenuaddseparator(int hMenu)
|
||||
{
|
||||
bool bFound = false;
|
||||
|
|
@ -414,6 +496,11 @@ bool pluginmenuaddseparator(int hMenu)
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Clears a plugin menu.
|
||||
\param hMenu The menu to clear.
|
||||
\return true if it succeeds, false otherwise.
|
||||
*/
|
||||
bool pluginmenuclear(int hMenu)
|
||||
{
|
||||
bool bFound = false;
|
||||
|
|
@ -431,6 +518,10 @@ bool pluginmenuclear(int hMenu)
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Call the registered CB_MENUENTRY callbacks for a menu entry.
|
||||
\param hEntry The menu entry that triggered the event.
|
||||
*/
|
||||
void pluginmenucall(int hEntry)
|
||||
{
|
||||
if(hEntry == -1)
|
||||
|
|
@ -456,6 +547,12 @@ void pluginmenucall(int hEntry)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Calls the registered CB_WINEVENT callbacks.
|
||||
\param [in,out] message the message that triggered the event. Cannot be null.
|
||||
\param [out] result The result value. Cannot be null.
|
||||
\return The value the plugin told it to return. See plugin documentation for more information.
|
||||
*/
|
||||
bool pluginwinevent(MSG* message, long* result)
|
||||
{
|
||||
PLUG_CB_WINEVENT winevent;
|
||||
|
|
@ -466,6 +563,11 @@ bool pluginwinevent(MSG* message, long* result)
|
|||
return winevent.retval;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Calls the registered CB_WINEVENTGLOBAL callbacks.
|
||||
\param [in,out] message the message that triggered the event. Cannot be null.
|
||||
\return The value the plugin told it to return. See plugin documentation for more information.
|
||||
*/
|
||||
bool pluginwineventglobal(MSG* message)
|
||||
{
|
||||
PLUG_CB_WINEVENTGLOBAL winevent;
|
||||
|
|
|
|||
|
|
@ -1,86 +1,118 @@
|
|||
/**
|
||||
@file reference.cpp
|
||||
|
||||
@brief Implements the reference class.
|
||||
*/
|
||||
|
||||
#include "reference.h"
|
||||
#include "debugger.h"
|
||||
#include "memory.h"
|
||||
#include "console.h"
|
||||
#include "module.h"
|
||||
|
||||
int reffind(uint addr, uint size, CBREF cbRef, void* userinfo, bool silent, const char* name)
|
||||
int RefFind(uint Address, uint Size, CBREF Callback, void* UserData, bool Silent, const char* Name)
|
||||
{
|
||||
uint start_addr;
|
||||
uint start_size;
|
||||
uint base;
|
||||
uint base_size;
|
||||
base = MemFindBaseAddr(addr, &base_size, true);
|
||||
if(!base or !base_size)
|
||||
uint regionSize = 0;
|
||||
uint regionBase = MemFindBaseAddr(Address, ®ionSize, true);
|
||||
|
||||
// If the memory page wasn't found, fail
|
||||
if(!regionBase || !regionSize)
|
||||
{
|
||||
if(!silent)
|
||||
dputs("invalid memory page");
|
||||
if(!Silent)
|
||||
dprintf("Invalid memory page 0x%p", Address);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!size) //assume the whole page
|
||||
// Assume the entire range is used
|
||||
uint scanStart = regionBase;
|
||||
uint scanSize = regionSize;
|
||||
|
||||
// Otherwise use custom boundaries if size was supplied
|
||||
if (Size)
|
||||
{
|
||||
start_addr = base;
|
||||
start_size = base_size;
|
||||
uint maxsize = Size - (Address - regionBase);
|
||||
|
||||
// Make sure the size fits in one page
|
||||
scanStart = Address;
|
||||
scanSize = min(Size, maxsize);
|
||||
}
|
||||
else //custom boundaries
|
||||
|
||||
// Allocate and read a buffer from the remote process
|
||||
Memory<unsigned char*> data(scanSize, "reffind:data");
|
||||
|
||||
if(!MemRead((PVOID)scanStart, data, scanSize, nullptr))
|
||||
{
|
||||
start_addr = addr;
|
||||
uint maxsize = size - (start_addr - base);
|
||||
if(size < maxsize) //check if the size fits in the page
|
||||
start_size = size;
|
||||
else
|
||||
start_size = maxsize;
|
||||
}
|
||||
Memory<unsigned char*> data(start_size, "reffind:data");
|
||||
if(!MemRead((void*)start_addr, data, start_size, 0))
|
||||
{
|
||||
if(!silent)
|
||||
dputs("error reading memory");
|
||||
if(!Silent)
|
||||
dprintf("Error reading memory in reference search\n");
|
||||
|
||||
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 the disassembler
|
||||
DISASM disasm;
|
||||
memset(&disasm, 0, sizeof(disasm));
|
||||
|
||||
#ifdef _WIN64
|
||||
disasm.Archi = 64;
|
||||
#endif // _WIN64
|
||||
disasm.EIP = (UIntPtr)data;
|
||||
disasm.VirtualAddr = (UInt64)start_addr;
|
||||
uint i = 0;
|
||||
BASIC_INSTRUCTION_INFO basicinfo;
|
||||
REFINFO refinfo;
|
||||
memset(&refinfo, 0, sizeof(REFINFO));
|
||||
refinfo.userinfo = userinfo;
|
||||
char fullName[deflen] = "";
|
||||
char modname[MAX_MODULE_SIZE] = "";
|
||||
if(ModNameFromAddr(start_addr, modname, true))
|
||||
sprintf_s(fullName, "%s (%s)", name, modname);
|
||||
else
|
||||
sprintf_s(fullName, "%s (%p)", name, start_addr);
|
||||
refinfo.name = fullName;
|
||||
cbRef(0, 0, &refinfo); //allow initializing
|
||||
while(i < start_size)
|
||||
disasm.EIP = (UIntPtr)data;
|
||||
disasm.VirtualAddr = (UInt64)scanStart;
|
||||
|
||||
// Allow an "initialization" notice
|
||||
REFINFO refInfo;
|
||||
refInfo.refcount = 0;
|
||||
refInfo.userinfo = UserData;
|
||||
refInfo.name = fullName;
|
||||
|
||||
Callback(0, 0, &refInfo);
|
||||
|
||||
//concurrency::parallel_for(uint(0), scanSize, [&](uint i)
|
||||
for (uint i = 0; i < scanSize;)
|
||||
{
|
||||
if(!(i % 0x1000))
|
||||
// Print the progress every 4096 bytes
|
||||
if((i % 0x1000) == 0)
|
||||
{
|
||||
double percent = (double)i / (double)start_size;
|
||||
GuiReferenceSetProgress((int)(percent * 100));
|
||||
// Percent = (current / total) * 100
|
||||
// Integer = floor(percent)
|
||||
float percent = floor(((float)i / (float)scanSize) * 100.0f);
|
||||
|
||||
GuiReferenceSetProgress((int)percent);
|
||||
}
|
||||
|
||||
// Disassemble the instruction
|
||||
int len = Disasm(&disasm);
|
||||
|
||||
if(len != UNKNOWN_OPCODE)
|
||||
{
|
||||
BASIC_INSTRUCTION_INFO basicinfo;
|
||||
fillbasicinfo(&disasm, &basicinfo);
|
||||
basicinfo.size = len;
|
||||
if(cbRef(&disasm, &basicinfo, &refinfo))
|
||||
refinfo.refcount++;
|
||||
|
||||
if(Callback(&disasm, &basicinfo, &refInfo))
|
||||
refInfo.refcount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Invalid instruction detected, so just skip the byte
|
||||
len = 1;
|
||||
disasm.EIP += len;
|
||||
disasm.VirtualAddr += len;
|
||||
i += len;
|
||||
}
|
||||
|
||||
disasm.EIP += len;
|
||||
disasm.VirtualAddr += len;
|
||||
i += len;
|
||||
}
|
||||
|
||||
GuiReferenceSetProgress(100);
|
||||
GuiReferenceReloadData();
|
||||
return refinfo.refcount;
|
||||
return refInfo.refcount;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
#ifndef _REFERENCE_H
|
||||
#define _REFERENCE_H
|
||||
#pragma once
|
||||
|
||||
#include "_global.h"
|
||||
#include "disasm_fast.h"
|
||||
|
||||
//structs
|
||||
struct REFINFO
|
||||
{
|
||||
int refcount;
|
||||
|
|
@ -12,10 +10,7 @@ struct REFINFO
|
|||
const char* name;
|
||||
};
|
||||
|
||||
//typedefs
|
||||
// Reference callback typedef
|
||||
typedef bool (*CBREF)(DISASM* disasm, BASIC_INSTRUCTION_INFO* basicinfo, REFINFO* refinfo);
|
||||
|
||||
//functions
|
||||
int reffind(uint page, uint size, CBREF cbRef, void* userinfo, bool silent, const char* name);
|
||||
|
||||
#endif //_REFERENCE_H
|
||||
int RefFind(uint Address, uint Size, CBREF Callback, void* UserData, bool Silent, const char* Name);
|
||||
|
|
@ -1,24 +1,34 @@
|
|||
/**
|
||||
@file simplescript.cpp
|
||||
|
||||
@brief Implements the simplescript class.
|
||||
*/
|
||||
|
||||
#include "simplescript.h"
|
||||
#include "value.h"
|
||||
#include "console.h"
|
||||
#include "argument.h"
|
||||
#include "variable.h"
|
||||
#include "threading.h"
|
||||
#include "x64_dbg.h"
|
||||
#include "debugger.h"
|
||||
#include "commandparser.h"
|
||||
|
||||
static std::vector<LINEMAPENTRY> linemap;
|
||||
|
||||
static std::vector<SCRIPTBP> scriptbplist;
|
||||
|
||||
static std::vector<int> scriptstack;
|
||||
|
||||
static int scriptIp = 0;
|
||||
|
||||
static bool volatile bAbort = false;
|
||||
|
||||
static bool volatile bIsRunning = false;
|
||||
|
||||
static SCRIPTBRANCHTYPE scriptgetbranchtype(const char* text)
|
||||
{
|
||||
char newtext[MAX_SCRIPT_LINE_SIZE] = "";
|
||||
strcpy_s(newtext, text);
|
||||
argformat(newtext); //format jump commands
|
||||
strcpy_s(newtext, StringUtils::Trim(text).c_str());
|
||||
if(!strstr(newtext, " "))
|
||||
strcat(newtext, " ");
|
||||
if(!strncmp(newtext, "jmp ", 4) or !strncmp(newtext, "goto ", 5))
|
||||
|
|
@ -176,7 +186,7 @@ static bool scriptcreatelinemap(const char* filename)
|
|||
{
|
||||
cur.type = linelabel;
|
||||
sprintf(cur.u.label, "l %.*s", rawlen - 1, cur.raw); //create a fake command for formatting
|
||||
argformat(cur.u.label); //format labels
|
||||
strcpy_s(cur.u.label, StringUtils::Trim(cur.u.label).c_str());
|
||||
char temp[256] = "";
|
||||
strcpy_s(temp, cur.u.label + 2);
|
||||
strcpy_s(cur.u.label, temp); //remove fake command
|
||||
|
|
@ -203,8 +213,7 @@ static bool scriptcreatelinemap(const char* filename)
|
|||
cur.type = linebranch;
|
||||
cur.u.branch.type = scriptgetbranchtype(cur.raw);
|
||||
char newraw[MAX_SCRIPT_LINE_SIZE] = "";
|
||||
strcpy_s(newraw, cur.raw);
|
||||
argformat(newraw);
|
||||
strcpy_s(newraw, StringUtils::Trim(cur.raw).c_str());
|
||||
int len = (int)strlen(newraw);
|
||||
for(int i = 0; i < len; i++)
|
||||
if(newraw[i] == ' ')
|
||||
|
|
@ -343,8 +352,7 @@ static CMDRESULT scriptinternalcmdexec(const char* cmd)
|
|||
else if(scriptisinternalcommand(cmd, "nop")) //do nothing
|
||||
return STATUS_CONTINUE;
|
||||
char command[deflen] = "";
|
||||
strcpy_s(command, cmd);
|
||||
argformat(command);
|
||||
strcpy_s(command, StringUtils::Trim(cmd).c_str());
|
||||
COMMAND* found = cmdfindmain(dbggetcommandlist(), command);
|
||||
if(!found) //invalid command
|
||||
return STATUS_ERROR;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,9 @@
|
|||
/**
|
||||
@file stackinfo.cpp
|
||||
|
||||
@brief Implements the stackinfo class.
|
||||
*/
|
||||
|
||||
#include "stackinfo.h"
|
||||
#include "debugger.h"
|
||||
#include "memory.h"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,142 @@
|
|||
#include "stringformat.h"
|
||||
#include "console.h"
|
||||
#include "value.h"
|
||||
#include "disasm_helper.h"
|
||||
|
||||
namespace ValueType
|
||||
{
|
||||
enum ValueType
|
||||
{
|
||||
Unknown,
|
||||
SignedDecimal,
|
||||
UnsignedDecimal,
|
||||
Hex,
|
||||
Pointer,
|
||||
String
|
||||
};
|
||||
}
|
||||
|
||||
static String printValue(FormatValueType value, ValueType::ValueType type)
|
||||
{
|
||||
uint valuint = 0;
|
||||
bool validval = valfromstring(value, &valuint);
|
||||
char result[deflen] = "???";
|
||||
switch(type)
|
||||
{
|
||||
case ValueType::Unknown:
|
||||
break;
|
||||
case ValueType::SignedDecimal:
|
||||
if(validval)
|
||||
sprintf_s(result, "%"fext"d", valuint);
|
||||
break;
|
||||
case ValueType::UnsignedDecimal:
|
||||
if(validval)
|
||||
sprintf_s(result, "%"fext"u", valuint);
|
||||
break;
|
||||
case ValueType::Hex:
|
||||
if(validval)
|
||||
sprintf_s(result, "%"fext"X", valuint);
|
||||
break;
|
||||
case ValueType::Pointer:
|
||||
if(validval)
|
||||
sprintf_s(result, "0x%"fhex, valuint);
|
||||
break;
|
||||
case ValueType::String:
|
||||
if(validval)
|
||||
{
|
||||
STRING_TYPE strtype;
|
||||
char string[512] = "";
|
||||
if(disasmgetstringat(valuint, &strtype, string, string, 500))
|
||||
strcpy_s(result, string);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static unsigned int getArgNumType(const String & formatString, ValueType::ValueType & type)
|
||||
{
|
||||
int add = 0;
|
||||
switch(formatString[0])
|
||||
{
|
||||
case 'd':
|
||||
type = ValueType::SignedDecimal;
|
||||
add++;
|
||||
break;
|
||||
case 'u':
|
||||
type = ValueType::UnsignedDecimal;
|
||||
add++;
|
||||
break;
|
||||
case 'p':
|
||||
type = ValueType::Pointer;
|
||||
add++;
|
||||
break;
|
||||
case 's':
|
||||
type = ValueType::String;
|
||||
add++;
|
||||
break;
|
||||
default:
|
||||
type = ValueType::Hex;
|
||||
}
|
||||
unsigned int argnum = 0;
|
||||
if(sscanf(formatString.c_str() + add, "%u", &argnum) != 1)
|
||||
type = ValueType::Unknown;
|
||||
return argnum;
|
||||
}
|
||||
|
||||
static String handleFormatString(const String & formatString, const FormatValueVector & values)
|
||||
{
|
||||
String result;
|
||||
ValueType::ValueType type = ValueType::Unknown;
|
||||
unsigned int argnum = getArgNumType(formatString, type);
|
||||
if(argnum < values.size())
|
||||
return printValue(values.at(argnum), type);
|
||||
return "[Formatting Error]";
|
||||
}
|
||||
|
||||
String stringformat(String format, const FormatValueVector & values)
|
||||
{
|
||||
StringUtils::ReplaceAll(format, "\\n", "\n");
|
||||
int len = (int)format.length();
|
||||
String output;
|
||||
String formatString;
|
||||
bool inFormatter = false;
|
||||
for(int i = 0; i < len; i++)
|
||||
{
|
||||
//handle escaped format sequences "{{" and "}}"
|
||||
if(format[i] == '{' && (i + 1 < len && format[i + 1] == '{'))
|
||||
{
|
||||
output += "{";
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
else if(format[i] == '}' && (i + 1 < len && format[i + 1] == '}'))
|
||||
{
|
||||
output += "}";
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
//handle actual formatting
|
||||
if(format[i] == '{' && !inFormatter) //opening bracket
|
||||
{
|
||||
inFormatter = true;
|
||||
formatString.clear();
|
||||
}
|
||||
else if(format[i] == '}' && inFormatter) //closing bracket
|
||||
{
|
||||
inFormatter = false;
|
||||
if(formatString.length())
|
||||
{
|
||||
output += handleFormatString(formatString, values);
|
||||
formatString.clear();
|
||||
}
|
||||
}
|
||||
else if(inFormatter) //inside brackets
|
||||
formatString += format[i];
|
||||
else //outside brackets
|
||||
output += format[i];
|
||||
}
|
||||
if(inFormatter && formatString.size())
|
||||
output += handleFormatString(formatString, values);
|
||||
return output;
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
#ifndef _STRINGFORMAT_H
|
||||
#define _STRINGFORMAT_H
|
||||
|
||||
#include "_global.h"
|
||||
|
||||
typedef const char* FormatValueType;
|
||||
typedef std::vector<FormatValueType> FormatValueVector;
|
||||
|
||||
String stringformat(String format, const FormatValueVector & values);
|
||||
|
||||
#endif //_STRINGFORMAT_H
|
||||
|
|
@ -122,4 +122,25 @@ WString StringUtils::Utf8ToUtf16(const String & str)
|
|||
WString StringUtils::Utf8ToUtf16(const char* str)
|
||||
{
|
||||
return Utf8ToUtf16(str ? String(str) : String());
|
||||
}
|
||||
|
||||
//Taken from: http://stackoverflow.com/a/24315631
|
||||
void StringUtils::ReplaceAll(String & s, const String & from, const String & to)
|
||||
{
|
||||
size_t start_pos = 0;
|
||||
while((start_pos = s.find(from, start_pos)) != std::string::npos)
|
||||
{
|
||||
s.replace(start_pos, from.length(), to);
|
||||
start_pos += to.length(); // Handles case where 'to' is a substring of 'from'
|
||||
}
|
||||
}
|
||||
|
||||
void StringUtils::ReplaceAll(WString & s, const WString & from, const WString & to)
|
||||
{
|
||||
size_t start_pos = 0;
|
||||
while((start_pos = s.find(from, start_pos)) != std::string::npos)
|
||||
{
|
||||
s.replace(start_pos, from.length(), to);
|
||||
start_pos += to.length(); // Handles case where 'to' is a substring of 'from'
|
||||
}
|
||||
}
|
||||
|
|
@ -22,6 +22,8 @@ public:
|
|||
static String Utf16ToUtf8(const wchar_t* wstr);
|
||||
static WString Utf8ToUtf16(const String & str);
|
||||
static WString Utf8ToUtf16(const char* str);
|
||||
static void ReplaceAll(String & s, const String & from, const String & to);
|
||||
static void ReplaceAll(WString & s, const WString & from, const WString & to);
|
||||
|
||||
private:
|
||||
static const String WHITESPACE;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,9 @@
|
|||
/**
|
||||
@file symbolinfo.cpp
|
||||
|
||||
@brief Implements the symbolinfo class.
|
||||
*/
|
||||
|
||||
#include "symbolinfo.h"
|
||||
#include "debugger.h"
|
||||
#include "addrinfo.h"
|
||||
|
|
@ -93,12 +99,12 @@ void SymUpdateModuleList()
|
|||
if(!SymGetModuleList(&modList))
|
||||
return;
|
||||
|
||||
// Create a new array to be sent to the GUI thread
|
||||
size_t moduleCount = modList.size();
|
||||
SYMBOLMODULEINFO *data = (SYMBOLMODULEINFO *)BridgeAlloc(moduleCount * sizeof(SYMBOLMODULEINFO));
|
||||
// Create a new array to be sent to the GUI thread
|
||||
size_t moduleCount = modList.size();
|
||||
SYMBOLMODULEINFO *data = (SYMBOLMODULEINFO *)BridgeAlloc(moduleCount * sizeof(SYMBOLMODULEINFO));
|
||||
|
||||
// Direct copy from std::vector data
|
||||
memcpy(data, modList.data(), moduleCount * sizeof(SYMBOLMODULEINFO));
|
||||
// Direct copy from std::vector data
|
||||
memcpy(data, modList.data(), moduleCount * sizeof(SYMBOLMODULEINFO));
|
||||
|
||||
// Send the module data to the GUI for updating
|
||||
GuiSymbolUpdateModuleList((int)moduleCount, data);
|
||||
|
|
@ -206,7 +212,7 @@ const char* SymGetSymbolicName(uint Address)
|
|||
|
||||
// User labels have priority, but if one wasn't found,
|
||||
// default to a symbol lookup
|
||||
if(!labelget(Address, label))
|
||||
if(!LabelGet(Address, label))
|
||||
{
|
||||
char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(char)];
|
||||
|
||||
|
|
@ -242,3 +248,53 @@ const char* SymGetSymbolicName(uint Address)
|
|||
|
||||
return symbolicname;
|
||||
}
|
||||
|
||||
bool SymGetSourceLine(uint Cip, char* FileName, int* Line)
|
||||
{
|
||||
IMAGEHLP_LINE64 lineInfo;
|
||||
memset(&lineInfo, 0, sizeof(IMAGEHLP_LINE64));
|
||||
|
||||
lineInfo.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
|
||||
|
||||
// Perform a symbol lookup from a specific address
|
||||
DWORD displacement;
|
||||
|
||||
if(!SafeSymGetLineFromAddr64(fdProcessInfo->hProcess, Cip, &displacement, &lineInfo))
|
||||
return false;
|
||||
|
||||
// Copy line number if requested
|
||||
if(Line)
|
||||
*Line = lineInfo.LineNumber;
|
||||
|
||||
// Copy file name if requested
|
||||
if (FileName)
|
||||
{
|
||||
// Check if it was a full path
|
||||
if (lineInfo.FileName[1] == ':' && lineInfo.FileName[2] == '\\')
|
||||
{
|
||||
// Success: no more parsing
|
||||
strcpy_s(FileName, MAX_STRING_SIZE, lineInfo.FileName);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Construct full path from .pdb path
|
||||
IMAGEHLP_MODULE64 modInfo;
|
||||
memset(&modInfo, 0, sizeof(IMAGEHLP_MODULE64));
|
||||
modInfo.SizeOfStruct = sizeof(IMAGEHLP_MODULE64);
|
||||
|
||||
if (!SafeSymGetModuleInfo64(fdProcessInfo->hProcess, Cip, &modInfo))
|
||||
return false;
|
||||
|
||||
// Strip the full path, leaving only the file name
|
||||
char* fileName = strrchr(modInfo.LoadedPdbName, '\\');
|
||||
|
||||
if (fileName)
|
||||
fileName[1] = '\0';
|
||||
|
||||
// Copy back to the caller's buffer
|
||||
strcpy_s(FileName, MAX_STRING_SIZE, modInfo.LoadedPdbName);
|
||||
strcat_s(FileName, MAX_STRING_SIZE, lineInfo.FileName);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -7,4 +7,13 @@ bool SymGetModuleList(std::vector<SYMBOLMODULEINFO>* List);
|
|||
void SymUpdateModuleList();
|
||||
void SymDownloadAllSymbols(const char* SymbolStore);
|
||||
bool SymAddrFromName(const char* Name, uint* Address);
|
||||
const char* SymGetSymbolicName(uint Address);
|
||||
const char* SymGetSymbolicName(uint Address);
|
||||
|
||||
/**
|
||||
\brief Gets the source code file name and line from an address.
|
||||
\param cip The address to check.
|
||||
\param [out] szFileName Source code file. Buffer of MAX_STRING_SIZE length. UTF-8. Can be null.
|
||||
\param [out] nLine Line number. Can be null.
|
||||
\return true if it succeeds, false if it fails.
|
||||
*/
|
||||
bool SymGetSourceLine(uint Cip, char* FileName, int* Line);
|
||||
|
|
@ -1,3 +1,9 @@
|
|||
/**
|
||||
@file thread.cpp
|
||||
|
||||
@brief Implements the thread class.
|
||||
*/
|
||||
|
||||
#include "thread.h"
|
||||
#include "console.h"
|
||||
#include "undocumented.h"
|
||||
|
|
@ -30,14 +36,14 @@ void ThreadCreate(CREATE_THREAD_DEBUG_INFO* CreateThread)
|
|||
GuiUpdateThreadView();
|
||||
}
|
||||
|
||||
void ThreadExit(DWORD dwThreadId)
|
||||
void ThreadExit(DWORD ThreadId)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockThreads);
|
||||
|
||||
// Don't use a foreach loop here because of the erase() call
|
||||
for(auto itr = threadList.begin(); itr != threadList.end(); itr++)
|
||||
{
|
||||
if(itr->ThreadId == dwThreadId)
|
||||
if(itr->ThreadId == ThreadId)
|
||||
{
|
||||
threadList.erase(itr);
|
||||
break;
|
||||
|
|
@ -65,21 +71,21 @@ int ThreadGetCount()
|
|||
return (int)threadList.size();
|
||||
}
|
||||
|
||||
void ThreadGetList(THREADLIST* list)
|
||||
void ThreadGetList(THREADLIST* List)
|
||||
{
|
||||
SHARED_ACQUIRE(LockThreads);
|
||||
|
||||
//
|
||||
// This function converts a C++ std::vector to a C-style THREADLIST[]
|
||||
// Also assume BridgeAlloc zeros the returned buffer
|
||||
// This function converts a C++ std::vector to a C-style THREADLIST[].
|
||||
// Also assume BridgeAlloc zeros the returned buffer.
|
||||
//
|
||||
size_t count = threadList.size();
|
||||
|
||||
if(count <= 0)
|
||||
return;
|
||||
|
||||
list->count = (int)count;
|
||||
list->list = (THREADALLINFO*)BridgeAlloc(count * sizeof(THREADALLINFO));
|
||||
List->count = (int)count;
|
||||
List->list = (THREADALLINFO*)BridgeAlloc(count * sizeof(THREADALLINFO));
|
||||
|
||||
// Fill out the list data
|
||||
for(size_t i = 0; i < count; i++)
|
||||
|
|
@ -88,25 +94,25 @@ void ThreadGetList(THREADLIST* list)
|
|||
|
||||
// Get the debugger's current thread index
|
||||
if(threadHandle == hActiveThread)
|
||||
list->CurrentThread = (int)i;
|
||||
List->CurrentThread = (int)i;
|
||||
|
||||
memcpy(&list->list[i].BasicInfo, &threadList[i], sizeof(THREADINFO));
|
||||
memcpy(&List->list[i].BasicInfo, &threadList[i], sizeof(THREADINFO));
|
||||
|
||||
list->list[i].ThreadCip = GetContextDataEx(threadHandle, UE_CIP);
|
||||
list->list[i].SuspendCount = ThreadGetSuspendCount(threadHandle);
|
||||
list->list[i].Priority = ThreadGetPriority(threadHandle);
|
||||
list->list[i].WaitReason = ThreadGetWaitReason(threadHandle);
|
||||
list->list[i].LastError = ThreadGetLastError(list->list[i].BasicInfo.ThreadLocalBase);
|
||||
List->list[i].ThreadCip = GetContextDataEx(threadHandle, UE_CIP);
|
||||
List->list[i].SuspendCount = ThreadGetSuspendCount(threadHandle);
|
||||
List->list[i].Priority = ThreadGetPriority(threadHandle);
|
||||
List->list[i].WaitReason = ThreadGetWaitReason(threadHandle);
|
||||
List->list[i].LastError = ThreadGetLastError(List->list[i].BasicInfo.ThreadLocalBase);
|
||||
}
|
||||
}
|
||||
|
||||
bool ThreadIsValid(DWORD dwThreadId)
|
||||
bool ThreadIsValid(DWORD ThreadId)
|
||||
{
|
||||
SHARED_ACQUIRE(LockThreads);
|
||||
|
||||
for(auto & entry : threadList)
|
||||
{
|
||||
if(entry.ThreadId == dwThreadId)
|
||||
if(entry.ThreadId == ThreadId)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -153,31 +159,39 @@ THREADWAITREASON ThreadGetWaitReason(HANDLE Thread)
|
|||
return _Executive;
|
||||
}
|
||||
|
||||
DWORD ThreadGetLastError(uint tebAddress)
|
||||
DWORD ThreadGetLastError(DWORD ThreadId)
|
||||
{
|
||||
SHARED_ACQUIRE(LockThreads);
|
||||
|
||||
TEB teb;
|
||||
if(!ThreadGetTeb(tebAddress, &teb))
|
||||
for (auto & entry : threadList)
|
||||
{
|
||||
// TODO: Assert (Why would the TEB fail?)
|
||||
return 0;
|
||||
if (entry.ThreadId != ThreadId)
|
||||
continue;
|
||||
|
||||
if (!ThreadGetTeb(entry.ThreadLocalBase, &teb))
|
||||
{
|
||||
// TODO: Assert (Why would the TEB fail?)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return teb.LastErrorValue;
|
||||
}
|
||||
|
||||
bool ThreadSetName(DWORD dwThreadId, const char* name)
|
||||
bool ThreadSetName(DWORD ThreadId, const char* Name)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockThreads);
|
||||
|
||||
// Modifies a variable (name), so an exclusive lock is required
|
||||
for(auto & entry : threadList)
|
||||
{
|
||||
if(entry.ThreadId == dwThreadId)
|
||||
if(entry.ThreadId == ThreadId)
|
||||
{
|
||||
if(!name)
|
||||
name = "";
|
||||
if(!Name)
|
||||
Name = "";
|
||||
|
||||
strcpy_s(entry.threadName, name);
|
||||
strcpy_s(entry.threadName, Name);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -185,13 +199,13 @@ bool ThreadSetName(DWORD dwThreadId, const char* name)
|
|||
return false;
|
||||
}
|
||||
|
||||
HANDLE ThreadGetHandle(DWORD dwThreadId)
|
||||
HANDLE ThreadGetHandle(DWORD ThreadId)
|
||||
{
|
||||
SHARED_ACQUIRE(LockThreads);
|
||||
|
||||
for(auto & entry : threadList)
|
||||
{
|
||||
if(entry.ThreadId == dwThreadId)
|
||||
if(entry.ThreadId == ThreadId)
|
||||
return entry.Handle;
|
||||
}
|
||||
|
||||
|
|
@ -200,20 +214,20 @@ HANDLE ThreadGetHandle(DWORD dwThreadId)
|
|||
return 0;
|
||||
}
|
||||
|
||||
DWORD ThreadGetId(HANDLE hThread)
|
||||
DWORD ThreadGetId(HANDLE Thread)
|
||||
{
|
||||
SHARED_ACQUIRE(LockThreads);
|
||||
|
||||
// Search for the ID in the local list
|
||||
for(auto & entry : threadList)
|
||||
{
|
||||
if(entry.Handle == hThread)
|
||||
if(entry.Handle == Thread)
|
||||
return entry.ThreadId;
|
||||
}
|
||||
|
||||
// Wasn't found, check with Windows
|
||||
// NOTE: Requires VISTA+
|
||||
DWORD id = GetThreadId(hThread);
|
||||
// NOTE: Requires VISTA+
|
||||
DWORD id = GetThreadId(Thread);
|
||||
|
||||
// Returns 0 on error;
|
||||
// TODO: Same problem with ThreadGetHandle()
|
||||
|
|
|
|||
|
|
@ -4,19 +4,19 @@
|
|||
#include "debugger.h"
|
||||
|
||||
void ThreadCreate(CREATE_THREAD_DEBUG_INFO* CreateThread);
|
||||
void ThreadExit(DWORD dwThreadId);
|
||||
void ThreadExit(DWORD ThreadId);
|
||||
void ThreadClear();
|
||||
int ThreadGetCount();
|
||||
void ThreadGetList(THREADLIST* list);
|
||||
bool ThreadIsValid(DWORD dwThreadId);
|
||||
bool ThreadSetName(DWORD dwTHreadId, const char* name);
|
||||
bool ThreadIsValid(DWORD ThreadId);
|
||||
bool ThreadSetName(DWORD ThreadId, const char* name);
|
||||
bool ThreadGetTeb(uint TEBAddress, TEB* Teb);
|
||||
int ThreadGetSuspendCount(HANDLE Thread);
|
||||
THREADPRIORITY ThreadGetPriority(HANDLE Thread);
|
||||
THREADWAITREASON ThreadGetWaitReason(HANDLE Thread);
|
||||
DWORD ThreadGetLastError(uint tebAddress);
|
||||
DWORD ThreadGetLastError(DWORD ThreadId);
|
||||
bool ThreadSetName(DWORD dwThreadId, const char* name);
|
||||
HANDLE ThreadGetHandle(DWORD dwThreadId);
|
||||
DWORD ThreadGetId(HANDLE hThread);
|
||||
HANDLE ThreadGetHandle(DWORD ThreadId);
|
||||
DWORD ThreadGetId(HANDLE Thread);
|
||||
int ThreadSuspendAll();
|
||||
int ThreadResumeAll();
|
||||
|
|
@ -45,7 +45,7 @@ enum SectionLock
|
|||
LockPatches,
|
||||
LockThreads,
|
||||
LockDprintf,
|
||||
LockSym,
|
||||
LockSym,
|
||||
|
||||
// This is defined because of a bug in the Windows 8.1 kernel;
|
||||
// Calling VirtualQuery/VirtualProtect/ReadProcessMemory can and will cause
|
||||
|
|
@ -85,8 +85,8 @@ public:
|
|||
Unlock();
|
||||
|
||||
#ifdef _DEBUG
|
||||
// TODO: Assert that the lock count is zero on destructor
|
||||
if (m_LockCount > 0)
|
||||
// TODO: Assert that the lock count is zero on destructor
|
||||
if (m_LockCount > 0)
|
||||
__debugbreak();
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,9 @@
|
|||
/**
|
||||
@file value.cpp
|
||||
|
||||
@brief Implements the value class.
|
||||
*/
|
||||
|
||||
#include "value.h"
|
||||
#include "variable.h"
|
||||
#include "debugger.h"
|
||||
|
|
@ -11,16 +17,29 @@
|
|||
|
||||
static bool dosignedcalc = false;
|
||||
|
||||
/**
|
||||
\brief Returns whether we do signed or unsigned calculations.
|
||||
\return true if we do signed calculations, false for unsigned calculationss.
|
||||
*/
|
||||
bool valuesignedcalc()
|
||||
{
|
||||
return dosignedcalc;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Set whether we do signed or unsigned calculations.
|
||||
\param a true for signed calculations, false for unsigned calculations.
|
||||
*/
|
||||
void valuesetsignedcalc(bool a)
|
||||
{
|
||||
dosignedcalc = a;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Check if a string is a flag.
|
||||
\param string The string to check.
|
||||
\return true if the string is a flag, false otherwise.
|
||||
*/
|
||||
static bool isflag(const char* string)
|
||||
{
|
||||
if(scmp(string, "cf"))
|
||||
|
|
@ -56,6 +75,11 @@ static bool isflag(const char* string)
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Check if a string is a register.
|
||||
\param string The string to check.
|
||||
\return true if the string is a register, false otherwise.
|
||||
*/
|
||||
static bool isregister(const char* string)
|
||||
{
|
||||
if(scmp(string, "eax"))
|
||||
|
|
@ -282,7 +306,12 @@ typedef struct
|
|||
|
||||
#define MXCSR_NAME_FLAG_TABLE_ENTRY(flag_name) { #flag_name, MXCSRFLAG_##flag_name }
|
||||
|
||||
unsigned int getmxcsrflagfromstring(const char* string)
|
||||
/**
|
||||
\brief Gets the MXCSR flag AND value from a string.
|
||||
\param string The flag name.
|
||||
\return The value to AND the MXCSR value with to get the flag. 0 when not found.
|
||||
*/
|
||||
static unsigned int getmxcsrflagfromstring(const char* string)
|
||||
{
|
||||
static FLAG_NAME_VALUE_TABLE_t mxcsrnameflagtable[] =
|
||||
{
|
||||
|
|
@ -301,9 +330,8 @@ unsigned int getmxcsrflagfromstring(const char* string)
|
|||
MXCSR_NAME_FLAG_TABLE_ENTRY(PM),
|
||||
MXCSR_NAME_FLAG_TABLE_ENTRY(FZ)
|
||||
};
|
||||
int i;
|
||||
|
||||
for(i = 0; i < (sizeof(mxcsrnameflagtable) / sizeof(*mxcsrnameflagtable)); i++)
|
||||
for(int i = 0; i < (sizeof(mxcsrnameflagtable) / sizeof(*mxcsrnameflagtable)); i++)
|
||||
{
|
||||
if(scmp(string, mxcsrnameflagtable[i].name))
|
||||
return mxcsrnameflagtable[i].flag;
|
||||
|
|
@ -312,6 +340,12 @@ unsigned int getmxcsrflagfromstring(const char* string)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Gets the MXCSR flag from a string and a flags value.
|
||||
\param mxcsrflags The flags value to get the flag from.
|
||||
\param string The string with the flag name.
|
||||
\return true if the flag is 1, false if the flag is 0.
|
||||
*/
|
||||
bool valmxcsrflagfromstring(uint mxcsrflags, const char* string)
|
||||
{
|
||||
unsigned int flag = getmxcsrflagfromstring(string);
|
||||
|
|
@ -337,7 +371,12 @@ bool valmxcsrflagfromstring(uint mxcsrflags, const char* string)
|
|||
|
||||
#define X87STATUSWORD_NAME_FLAG_TABLE_ENTRY(flag_name) { #flag_name, x87STATUSWORD_FLAG_##flag_name }
|
||||
|
||||
unsigned int getx87statuswordflagfromstring(const char* string)
|
||||
/**
|
||||
\brief Gets the x87 status word AND value from a string.
|
||||
\param string The status word name.
|
||||
\return The value to AND the status word with to get the flag. 0 when not found.
|
||||
*/
|
||||
static unsigned int getx87statuswordflagfromstring(const char* string)
|
||||
{
|
||||
static FLAG_NAME_VALUE_TABLE_t statuswordflagtable[] =
|
||||
{
|
||||
|
|
@ -355,9 +394,8 @@ unsigned int getx87statuswordflagfromstring(const char* string)
|
|||
X87STATUSWORD_NAME_FLAG_TABLE_ENTRY(C3),
|
||||
X87STATUSWORD_NAME_FLAG_TABLE_ENTRY(B)
|
||||
};
|
||||
int i;
|
||||
|
||||
for(i = 0; i < (sizeof(statuswordflagtable) / sizeof(*statuswordflagtable)); i++)
|
||||
for(int i = 0; i < (sizeof(statuswordflagtable) / sizeof(*statuswordflagtable)); i++)
|
||||
{
|
||||
if(scmp(string, statuswordflagtable[i].name))
|
||||
return statuswordflagtable[i].flag;
|
||||
|
|
@ -366,6 +404,12 @@ unsigned int getx87statuswordflagfromstring(const char* string)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Gets an x87 status flag from a string.
|
||||
\param statusword The status word value.
|
||||
\param string The flag name.
|
||||
\return true if the flag is 1, false if the flag is 0.
|
||||
*/
|
||||
bool valx87statuswordflagfromstring(uint statusword, const char* string)
|
||||
{
|
||||
unsigned int flag = getx87statuswordflagfromstring(string);
|
||||
|
|
@ -386,7 +430,12 @@ bool valx87statuswordflagfromstring(uint statusword, const char* string)
|
|||
|
||||
#define X87CONTROLWORD_NAME_FLAG_TABLE_ENTRY(flag_name) { #flag_name, x87CONTROLWORD_FLAG_##flag_name }
|
||||
|
||||
unsigned int getx87controlwordflagfromstring(const char* string)
|
||||
/**
|
||||
\brief Gets the x87 control word flag AND value from a string.
|
||||
\param string The name of the control word.
|
||||
\return The value to AND the control word with to get the flag. 0 when not found.
|
||||
*/
|
||||
static unsigned int getx87controlwordflagfromstring(const char* string)
|
||||
{
|
||||
static FLAG_NAME_VALUE_TABLE_t controlwordflagtable[] =
|
||||
{
|
||||
|
|
@ -399,9 +448,8 @@ unsigned int getx87controlwordflagfromstring(const char* string)
|
|||
X87CONTROLWORD_NAME_FLAG_TABLE_ENTRY(IEM),
|
||||
X87CONTROLWORD_NAME_FLAG_TABLE_ENTRY(IC)
|
||||
};
|
||||
int i;
|
||||
|
||||
for(i = 0; i < (sizeof(controlwordflagtable) / sizeof(*controlwordflagtable)); i++)
|
||||
for(int i = 0; i < (sizeof(controlwordflagtable) / sizeof(*controlwordflagtable)); i++)
|
||||
{
|
||||
if(scmp(string, controlwordflagtable[i].name))
|
||||
return controlwordflagtable[i].flag;
|
||||
|
|
@ -410,6 +458,12 @@ unsigned int getx87controlwordflagfromstring(const char* string)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Get an x87 control word flag from a string.
|
||||
\param controlword The control word to get the flag from.
|
||||
\param string The flag name.
|
||||
\return true if the flag is 1, false when the flag is 0.
|
||||
*/
|
||||
bool valx87controlwordflagfromstring(uint controlword, const char* string)
|
||||
{
|
||||
unsigned int flag = getx87controlwordflagfromstring(string);
|
||||
|
|
@ -420,6 +474,12 @@ bool valx87controlwordflagfromstring(uint controlword, const char* string)
|
|||
return (bool)((int)(controlword & flag) != 0);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Gets the MXCSR field from a string.
|
||||
\param mxcsrflags The mxcsrflags to get the field from.
|
||||
\param string The name of the field (should be "RC").
|
||||
\return The MXCSR field word.
|
||||
*/
|
||||
unsigned short valmxcsrfieldfromstring(uint mxcsrflags, const char* string)
|
||||
{
|
||||
if(scmp(string, "RC"))
|
||||
|
|
@ -428,6 +488,12 @@ unsigned short valmxcsrfieldfromstring(uint mxcsrflags, const char* string)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Gets the x87 status word field from a string.
|
||||
\param statusword The status word to get the field from.
|
||||
\param string The name of the field (should be "TOP").
|
||||
\return The x87 status word field.
|
||||
*/
|
||||
unsigned short valx87statuswordfieldfromstring(uint statusword, const char* string)
|
||||
{
|
||||
if(scmp(string, "TOP"))
|
||||
|
|
@ -436,6 +502,12 @@ unsigned short valx87statuswordfieldfromstring(uint statusword, const char* stri
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Gets the x87 control word field from a string.
|
||||
\param controlword The control word to get the field from.
|
||||
\param string The name of the field.
|
||||
\return The x87 control word field.
|
||||
*/
|
||||
unsigned short valx87controlwordfieldfromstring(uint controlword, const char* string)
|
||||
{
|
||||
if(scmp(string, "PC"))
|
||||
|
|
@ -446,6 +518,12 @@ unsigned short valx87controlwordfieldfromstring(uint controlword, const char* st
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Gets a flag from a string.
|
||||
\param eflags The eflags value to get the flag from.
|
||||
\param string The name of the flag.
|
||||
\return true if the flag equals to 1, false if the flag is 0 or not found.
|
||||
*/
|
||||
bool valflagfromstring(uint eflags, const char* string)
|
||||
{
|
||||
if(scmp(string, "cf"))
|
||||
|
|
@ -481,6 +559,12 @@ bool valflagfromstring(uint eflags, const char* string)
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Sets a flag value.
|
||||
\param string The name of the flag.
|
||||
\param set The value of the flag.
|
||||
\return true if the flag was successfully set, false otherwise.
|
||||
*/
|
||||
static bool setflag(const char* string, bool set)
|
||||
{
|
||||
uint eflags = GetContextDataEx(hActiveThread, UE_CFLAGS);
|
||||
|
|
@ -523,6 +607,12 @@ static bool setflag(const char* string, bool set)
|
|||
return SetContextDataEx(hActiveThread, UE_CFLAGS, eflags ^ xorval);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Gets a register from a string.
|
||||
\param [out] size This function can store the register size in bytes in this parameter. Can be null, in that case it will be ignored.
|
||||
\param string The name of the register to get.
|
||||
\return The register value.
|
||||
*/
|
||||
static uint getregister(int* size, const char* string)
|
||||
{
|
||||
if(size)
|
||||
|
|
@ -961,6 +1051,12 @@ static uint getregister(int* size, const char* string)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Sets a register value based on the register name.
|
||||
\param string The name of the register to set.
|
||||
\param value The new register value.
|
||||
\return true if the register was set, false otherwise.
|
||||
*/
|
||||
static bool setregister(const char* string, uint value)
|
||||
{
|
||||
if(scmp(string, "eax"))
|
||||
|
|
@ -1165,6 +1261,16 @@ static bool setregister(const char* string, uint value)
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Gets the address of an API from a name.
|
||||
\param name The name of the API, see the command help for more information about valid constructions.
|
||||
\param [out] value The address of the retrieved API. Cannot be null.
|
||||
\param [out] value_size This function sets this value to the size of the address, sizeof(uint).
|
||||
\param printall true to print all possible API values to the console.
|
||||
\param silent true to have no console output. If true, the \p printall parameter is ignored.
|
||||
\param [out] hexonly If set to true, the values should be printed in hex only. Usually this function sets it to true.
|
||||
\return true if the API was found and a value retrieved, false otherwise.
|
||||
*/
|
||||
bool valapifromstring(const char* name, uint* value, int* value_size, bool printall, bool silent, bool* hexonly)
|
||||
{
|
||||
if(!value or !DbgIsDebugging())
|
||||
|
|
@ -1338,8 +1444,10 @@ bool valapifromstring(const char* name, uint* value, int* value_size, bool print
|
|||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
check whether a string is a valid dec number
|
||||
/**
|
||||
\brief Check if a string is a valid decimal number. This function also accepts "-" or "." as prefix.
|
||||
\param string The string to check.
|
||||
\return true if the string is a valid decimal number.
|
||||
*/
|
||||
static bool isdecnumber(const char* string)
|
||||
{
|
||||
|
|
@ -1359,8 +1467,10 @@ static bool isdecnumber(const char* string)
|
|||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
check whether a string is a valid hex number
|
||||
/**
|
||||
\brief Check if a string is a valid hexadecimal number. This function also accepts "0x" or "x" as prefix.
|
||||
\param string The string to check.
|
||||
\return true if the string is a valid hexadecimal number.
|
||||
*/
|
||||
static bool ishexnumber(const char* string)
|
||||
{
|
||||
|
|
@ -1378,6 +1488,17 @@ static bool ishexnumber(const char* string)
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Gets a value from a string. This function can parse expressions, memory locations, registers, flags, API names, labels, symbols and variables.
|
||||
\param string The string to parse.
|
||||
\param [out] value The value of the expression. This value cannot be null.
|
||||
\param silent true to not output anything to the console.
|
||||
\param baseonly true to skip parsing API names, labels, symbols and variables (basic expressions only).
|
||||
\param [out] value_size This function can output the value size parsed (for example memory location size or register size). Can be null.
|
||||
\param [out] isvar This function can output if the expression is variable (for example memory locations, registers or variables are variable). Can be null.
|
||||
\param [out] hexonly This function can output if the output value should only be printed as hexadecimal (for example addresses). Can be null.
|
||||
\return true if the expression was parsed successfull, false otherwise.
|
||||
*/
|
||||
bool valfromstring(const char* string, uint* value, bool silent, bool baseonly, int* value_size, bool* isvar, bool* hexonly)
|
||||
{
|
||||
if(!value or !string)
|
||||
|
|
@ -1557,7 +1678,7 @@ bool valfromstring(const char* string, uint* value, bool silent, bool baseonly,
|
|||
return false;
|
||||
else if(valapifromstring(string, value, value_size, true, silent, hexonly)) //then come APIs
|
||||
return true;
|
||||
else if(labelfromstring(string, value)) //then come labels
|
||||
else if(LabelFromString(string, value)) //then come labels
|
||||
return true;
|
||||
else if(SymAddrFromName(string, value)) //then come symbols
|
||||
return true;
|
||||
|
|
@ -1572,6 +1693,12 @@ bool valfromstring(const char* string, uint* value, bool silent, bool baseonly,
|
|||
return false; //nothing was OK
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Checks if a string is long enough.
|
||||
\param str The string to check.
|
||||
\param min_length The minimum length of \p str.
|
||||
\return true if the string is long enough, false otherwise.
|
||||
*/
|
||||
static bool longEnough(const char* str, size_t min_length)
|
||||
{
|
||||
size_t length = 0;
|
||||
|
|
@ -1582,6 +1709,12 @@ static bool longEnough(const char* str, size_t min_length)
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Checks if a string starts with another string.
|
||||
\param pre The desired prefix of the string.
|
||||
\param str The complete string.
|
||||
\return true if \p str starts with \p pre.
|
||||
*/
|
||||
static bool startsWith(const char* pre, const char* str)
|
||||
{
|
||||
size_t lenpre = strlen(pre);
|
||||
|
|
@ -1598,7 +1731,12 @@ static bool startsWith(const char* pre, const char* str)
|
|||
#define x8780BITFPU_PRE_FIELD_STRING "x87r"
|
||||
#define STRLEN_USING_SIZEOF(string) (sizeof(string) - 1)
|
||||
|
||||
static void fpustuff(const char* string, uint value)
|
||||
/**
|
||||
\brief Sets an FPU value (MXCSR fields, MMX fields, etc.) by name.
|
||||
\param string The name of the FPU value to set.
|
||||
\param value The value to set.
|
||||
*/
|
||||
static void setfpuvalue(const char* string, uint value)
|
||||
{
|
||||
uint xorval = 0;
|
||||
uint flags = 0;
|
||||
|
|
@ -1978,9 +2116,16 @@ static void fpustuff(const char* string, uint value)
|
|||
}
|
||||
}
|
||||
|
||||
bool valtostring(const char* string, uint* value, bool silent)
|
||||
/**
|
||||
\brief Sets a register, variable, flag, memory location or FPU value by name.
|
||||
\param string The name of the thing to set.
|
||||
\param value The value to set.
|
||||
\param silent true to not have output to the console.
|
||||
\return true if the value was set successfully, false otherwise.
|
||||
*/
|
||||
bool valtostring(const char* string, uint value, bool silent)
|
||||
{
|
||||
if(!*string or !value)
|
||||
if(!*string)
|
||||
return false;
|
||||
else if(*string == '@' or strstr(string, "[")) //memory location
|
||||
{
|
||||
|
|
@ -2025,7 +2170,8 @@ bool valtostring(const char* string, uint* value, bool silent)
|
|||
{
|
||||
return false;
|
||||
}
|
||||
if(!MemPatch((void*)temp, value, read_size, 0))
|
||||
uint value_ = value;
|
||||
if(!MemPatch((void*)temp, &value_, read_size, 0))
|
||||
{
|
||||
if(!silent)
|
||||
dputs("failed to write memory");
|
||||
|
|
@ -2043,7 +2189,7 @@ bool valtostring(const char* string, uint* value, bool silent)
|
|||
dputs("not debugging!");
|
||||
return false;
|
||||
}
|
||||
bool ok = setregister(string, *value);
|
||||
bool ok = setregister(string, value);
|
||||
int len = (int)strlen(string);
|
||||
Memory<char*> regName(len + 1, "valtostring:regname");
|
||||
strcpy_s(regName, len + 1, string);
|
||||
|
|
@ -2060,7 +2206,7 @@ bool valtostring(const char* string, uint* value, bool silent)
|
|||
GuiUpdateAllViews(); //repaint gui
|
||||
return ok;
|
||||
}
|
||||
else if((*string == '_'))
|
||||
else if((*string == '_')) //FPU values
|
||||
{
|
||||
if(!DbgIsDebugging())
|
||||
{
|
||||
|
|
@ -2068,9 +2214,8 @@ bool valtostring(const char* string, uint* value, bool silent)
|
|||
dputs("not debugging!");
|
||||
return false;
|
||||
}
|
||||
fpustuff(string + 1, * value);
|
||||
setfpuvalue(string + 1, value);
|
||||
GuiUpdateAllViews(); //repaint gui
|
||||
|
||||
return true;
|
||||
}
|
||||
else if(*string == '!' and isflag(string + 1)) //flag
|
||||
|
|
@ -2082,15 +2227,21 @@ bool valtostring(const char* string, uint* value, bool silent)
|
|||
return false;
|
||||
}
|
||||
bool set = false;
|
||||
if(*value)
|
||||
if(value)
|
||||
set = true;
|
||||
setflag(string + 1, set);
|
||||
GuiUpdateAllViews(); //repaint gui
|
||||
return true;
|
||||
}
|
||||
return varset(string, *value, false); //variable
|
||||
return varset(string, value, false); //variable
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Converts a file offset to a virtual address.
|
||||
\param modname The name (not the path) of the module the file offset is in.
|
||||
\param offset The file offset.
|
||||
\return The VA of the file offset, 0 when there was a problem with the conversion.
|
||||
*/
|
||||
uint valfileoffsettova(const char* modname, uint offset)
|
||||
{
|
||||
char modpath[MAX_PATH] = "";
|
||||
|
|
@ -2112,6 +2263,11 @@ uint valfileoffsettova(const char* modname, uint offset)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Converts a virtual address to a file offset.
|
||||
\param va The virtual address (must be inside a module).
|
||||
\return The file offset. 0 when there was a problem with the conversion.
|
||||
*/
|
||||
uint valvatofileoffset(uint va)
|
||||
{
|
||||
char modpath[MAX_PATH] = "";
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ void valuesetsignedcalc(bool a);
|
|||
bool valapifromstring(const char* name, uint* value, int* value_size, bool printall, bool silent, bool* hexonly);
|
||||
bool valfromstring(const char* string, uint* value, bool silent = true, bool baseonly = false, int* value_size = 0, bool* isvar = 0, bool* hexonly = 0);
|
||||
bool valflagfromstring(uint eflags, const char* string);
|
||||
bool valtostring(const char* string, uint* value, bool silent);
|
||||
bool valtostring(const char* string, uint value, bool silent);
|
||||
bool valmxcsrflagfromstring(uint mxcsrflags, const char* string);
|
||||
bool valx87statuswordflagfromstring(uint statusword, const char* string);
|
||||
bool valx87controlwordflagfromstring(uint controlword, const char* string);
|
||||
|
|
|
|||
|
|
@ -1,31 +1,51 @@
|
|||
/**
|
||||
@file variable.cpp
|
||||
|
||||
@brief Implements the variable class.
|
||||
*/
|
||||
|
||||
#include "variable.h"
|
||||
#include "threading.h"
|
||||
|
||||
static VariableMap variables;
|
||||
static VAR* vars;
|
||||
/**
|
||||
\brief The container that stores all variables.
|
||||
*/
|
||||
std::map<String, VAR, CaseInsensitiveCompare> variables;
|
||||
|
||||
static void varsetvalue(VAR* var, VAR_VALUE* value)
|
||||
/**
|
||||
\brief Sets a variable with a value.
|
||||
\param [in,out] Var The variable to set the value of. The previous value will be freed. Cannot be null.
|
||||
\param [in] Value The new value. Cannot be null.
|
||||
*/
|
||||
void varsetvalue(VAR* Var, VAR_VALUE* Value)
|
||||
{
|
||||
// VAR_STRING needs to be freed before destroying it
|
||||
if(var->value.type == VAR_STRING)
|
||||
if(Var->value.type == VAR_STRING)
|
||||
{
|
||||
var->value.u.data->clear();
|
||||
delete var->value.u.data;
|
||||
Var->value.u.data->clear();
|
||||
delete Var->value.u.data;
|
||||
}
|
||||
|
||||
// Replace all information in the struct
|
||||
memcpy(&var->value, value, sizeof(VAR_VALUE));
|
||||
memcpy(&Var->value, Value, sizeof(VAR_VALUE));
|
||||
}
|
||||
|
||||
static bool varset(const char* name, VAR_VALUE* value, bool setreadonly)
|
||||
/**
|
||||
\brief Sets a variable by name.
|
||||
\param Name The name of the variable. Cannot be null.
|
||||
\param Value The new value. Cannot be null.
|
||||
\param ReadOnly true to set read-only variables (like $hProcess etc.).
|
||||
\return true if the variable was set correctly, false otherwise.
|
||||
*/
|
||||
bool varset(const char* Name, VAR_VALUE* Value, bool ReadOnly)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockVariables);
|
||||
|
||||
String name_;
|
||||
if(*name != '$')
|
||||
if(*Name != '$')
|
||||
name_ = "$";
|
||||
name_ += name;
|
||||
VariableMap::iterator found = variables.find(name_);
|
||||
name_ += Name;
|
||||
auto found = variables.find(name_);
|
||||
if(found == variables.end()) //not found
|
||||
return false;
|
||||
if(found->second.alias.length())
|
||||
|
|
@ -33,15 +53,18 @@ static bool varset(const char* name, VAR_VALUE* value, bool setreadonly)
|
|||
// Release the lock (potential deadlock here)
|
||||
EXCLUSIVE_RELEASE();
|
||||
|
||||
return varset(found->second.alias.c_str(), value, setreadonly);
|
||||
return varset(found->second.alias.c_str(), Value, ReadOnly);
|
||||
}
|
||||
|
||||
if(!setreadonly && (found->second.type == VAR_READONLY || found->second.type == VAR_HIDDEN))
|
||||
if(!ReadOnly && (found->second.type == VAR_READONLY || found->second.type == VAR_HIDDEN))
|
||||
return false;
|
||||
varsetvalue(&found->second, value);
|
||||
varsetvalue(&found->second, Value);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Initializes various default variables.
|
||||
*/
|
||||
void varinit()
|
||||
{
|
||||
varfree();
|
||||
|
|
@ -66,69 +89,81 @@ void varinit()
|
|||
varnew("$_BS_FLAG", 0, VAR_READONLY); // Bigger/smaller flag for internal use (1=bigger, 0=smaller)
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Clears all variables.
|
||||
*/
|
||||
void varfree()
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockVariables);
|
||||
EXCLUSIVE_ACQUIRE(LockVariables);
|
||||
|
||||
// Each variable must be deleted manually; strings especially
|
||||
// because there are sub-allocations
|
||||
VAR_VALUE emptyValue;
|
||||
// Each variable must be deleted manually; strings especially
|
||||
// because there are sub-allocations
|
||||
VAR_VALUE emptyValue;
|
||||
|
||||
for (auto& itr : variables)
|
||||
varsetvalue(&itr.second, &emptyValue);
|
||||
for (auto& itr : variables)
|
||||
varsetvalue(&itr.second, &emptyValue);
|
||||
|
||||
// Now clear all vector elements
|
||||
// Now clear all vector elements
|
||||
variables.clear();
|
||||
}
|
||||
|
||||
VAR* vargetptr()
|
||||
/**
|
||||
\brief Creates a new variable.
|
||||
\param Name The name of the variable. You can specify alias names by separating the names by '\1'. Cannot be null.
|
||||
\param Value The new variable value.
|
||||
\param Type The variable type.
|
||||
\return true if the new variables was created and set successfully, false otherwise.
|
||||
*/
|
||||
bool varnew(const char* Name, uint Value, VAR_TYPE Type)
|
||||
{
|
||||
// TODO: Implement this? Or remove it
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool varnew(const char* name, uint value, VAR_TYPE type)
|
||||
{
|
||||
if(!name)
|
||||
if(!Name)
|
||||
return false;
|
||||
|
||||
CriticalSectionLocker locker(LockVariables);
|
||||
EXCLUSIVE_ACQUIRE(LockVariables);
|
||||
|
||||
std::vector<String> names = StringUtils::Split(name, '\1');
|
||||
std::vector<String> names = StringUtils::Split(Name, '\1');
|
||||
String firstName;
|
||||
for(int i = 0; i < (int)names.size(); i++)
|
||||
{
|
||||
String name_;
|
||||
name = names.at(i).c_str();
|
||||
if(*name != '$')
|
||||
Name = names.at(i).c_str();
|
||||
if(*Name != '$')
|
||||
name_ = "$";
|
||||
name_ += name;
|
||||
name_ += Name;
|
||||
if(!i)
|
||||
firstName = name;
|
||||
firstName = Name;
|
||||
if(variables.find(name_) != variables.end()) //found
|
||||
return false;
|
||||
VAR var;
|
||||
var.name = name_;
|
||||
if(i)
|
||||
var.alias = firstName;
|
||||
var.type = type;
|
||||
var.type = Type;
|
||||
var.value.size = sizeof(uint);
|
||||
var.value.type = VAR_UINT;
|
||||
var.value.u.value = value;
|
||||
var.value.u.value = Value;
|
||||
variables.insert(std::make_pair(name_, var));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool varget(const char* name, VAR_VALUE* value, int* size, VAR_TYPE* type)
|
||||
/**
|
||||
\brief Gets a variable value.
|
||||
\param Name The name of the variable.
|
||||
\param [out] Value This function can get the variable value. If this value is null, it is ignored.
|
||||
\param [out] Size This function can get the variable size. If this value is null, it is ignored.
|
||||
\param [out] Type This function can get the variable type. If this value is null, it is ignored.
|
||||
\return true if the variable was found and the optional values were retrieved successfully, false otherwise.
|
||||
*/
|
||||
bool varget(const char* Name, VAR_VALUE* Value, int* Size, VAR_TYPE* Type)
|
||||
{
|
||||
SHARED_ACQUIRE(LockVariables);
|
||||
|
||||
String name_;
|
||||
if(*name != '$')
|
||||
if(*Name != '$')
|
||||
name_ = "$";
|
||||
name_ += name;
|
||||
VariableMap::iterator found = variables.find(name_);
|
||||
name_ += Name;
|
||||
auto found = variables.find(name_);
|
||||
if(found == variables.end()) //not found
|
||||
return false;
|
||||
if(found->second.alias.length())
|
||||
|
|
@ -136,89 +171,130 @@ static bool varget(const char* name, VAR_VALUE* value, int* size, VAR_TYPE* type
|
|||
// Release the lock (potential deadlock here)
|
||||
SHARED_RELEASE();
|
||||
|
||||
return varget(found->second.alias.c_str(), value, size, type);
|
||||
return varget(found->second.alias.c_str(), Value, Size, Type);
|
||||
}
|
||||
if(type)
|
||||
*type = found->second.type;
|
||||
if(size)
|
||||
*size = found->second.value.size;
|
||||
if(value)
|
||||
*value = found->second.value;
|
||||
if(Type)
|
||||
*Type = found->second.type;
|
||||
if(Size)
|
||||
*Size = found->second.value.size;
|
||||
if(Value)
|
||||
*Value = found->second.value;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool varget(const char* name, uint* value, int* size, VAR_TYPE* type)
|
||||
/**
|
||||
\brief Gets a variable value.
|
||||
\param Name The name of the variable.
|
||||
\param [out] Value This function can get the variable value. If this value is null, it is ignored.
|
||||
\param [out] Size This function can get the variable size. If this value is null, it is ignored.
|
||||
\param [out] Type This function can get the variable type. If this value is null, it is ignored.
|
||||
\return true if the variable was found and the optional values were retrieved successfully, false otherwise.
|
||||
*/
|
||||
bool varget(const char* Name, uint* Value, int* Size, VAR_TYPE* Type)
|
||||
{
|
||||
VAR_VALUE varvalue;
|
||||
int varsize;
|
||||
VAR_TYPE vartype;
|
||||
if(!varget(name, &varvalue, &varsize, &vartype) or varvalue.type != VAR_UINT)
|
||||
if(!varget(Name, &varvalue, &varsize, &vartype) or varvalue.type != VAR_UINT)
|
||||
return false;
|
||||
if(size)
|
||||
*size = varsize;
|
||||
if(!value && size)
|
||||
return true; //variable was valid, just get the size
|
||||
if(type)
|
||||
*type = vartype;
|
||||
if(value)
|
||||
*value = varvalue.u.value;
|
||||
if(Size)
|
||||
*Size = varsize;
|
||||
if(Type)
|
||||
*Type = vartype;
|
||||
if(Value)
|
||||
*Value = varvalue.u.value;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool varget(const char* name, char* string, int* size, VAR_TYPE* type)
|
||||
/**
|
||||
\brief Gets a variable value.
|
||||
\param Name The name of the variable.
|
||||
\param [out] String This function can get the variable value. If this value is null, it is ignored.
|
||||
\param [out] Size This function can get the variable size. If this value is null, it is ignored.
|
||||
\param [out] Type This function can get the variable type. If this value is null, it is ignored.
|
||||
\return true if the variable was found and the optional values were retrieved successfully, false otherwise.
|
||||
*/
|
||||
bool varget(const char* Name, char* String, int* Size, VAR_TYPE* Type)
|
||||
{
|
||||
VAR_VALUE varvalue;
|
||||
int varsize;
|
||||
VAR_TYPE vartype;
|
||||
if(!varget(name, &varvalue, &varsize, &vartype) or varvalue.type != VAR_STRING)
|
||||
if(!varget(Name, &varvalue, &varsize, &vartype) or varvalue.type != VAR_STRING)
|
||||
return false;
|
||||
if(size)
|
||||
*size = varsize;
|
||||
if(!string && size)
|
||||
return true; //variable was valid, just get the size
|
||||
if(type)
|
||||
*type = vartype;
|
||||
if(string)
|
||||
memcpy(string, &varvalue.u.data->front(), varsize);
|
||||
if(Size)
|
||||
*Size = varsize;
|
||||
if(Type)
|
||||
*Type = vartype;
|
||||
if(String)
|
||||
memcpy(String, varvalue.u.data->data(), varsize);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool varset(const char* name, uint value, bool setreadonly)
|
||||
/**
|
||||
\brief Sets a variable by name.
|
||||
\param Name The name of the variable. Cannot be null.
|
||||
\param Value The new value.
|
||||
\param ReadOnly true to set read-only variables (like $hProcess etc.).
|
||||
\return true if the variable was set successfully, false otherwise.
|
||||
*/
|
||||
bool varset(const char* Name, uint Value, bool ReadOnly)
|
||||
{
|
||||
VAR_VALUE varvalue;
|
||||
varvalue.size = sizeof(uint);
|
||||
varvalue.type = VAR_UINT;
|
||||
varvalue.u.value = value;
|
||||
return varset(name, &varvalue, setreadonly);
|
||||
// Insert variable as an unsigned integer
|
||||
VAR_VALUE varValue;
|
||||
varValue.size = sizeof(uint);
|
||||
varValue.type = VAR_UINT;
|
||||
varValue.u.value = Value;
|
||||
|
||||
return varset(Name, &varValue, ReadOnly);
|
||||
}
|
||||
|
||||
bool varset(const char* name, const char* string, bool setreadonly)
|
||||
/**
|
||||
\brief Sets a variable by name.
|
||||
\param Name The name of the variable. Cannot be null.
|
||||
\param Value The new value. Cannot be null.
|
||||
\param ReadOnly true to set read-only variables (like $hProcess etc.).
|
||||
\return true if the variable was set successfully, false otherwise.
|
||||
*/
|
||||
bool varset(const char* Name, const char* Value, bool ReadOnly)
|
||||
{
|
||||
VAR_VALUE varvalue;
|
||||
int size = (int)strlen(string);
|
||||
varvalue.size = size;
|
||||
varvalue.type = VAR_STRING;
|
||||
varvalue.u.data = new std::vector<unsigned char>;
|
||||
varvalue.u.data->resize(size);
|
||||
memcpy(&varvalue.u.data->front(), string, size);
|
||||
if(!varset(name, &varvalue, setreadonly))
|
||||
VAR_VALUE varValue;
|
||||
int stringLen = (int)strlen(Value);
|
||||
varValue.size = stringLen;
|
||||
varValue.type = VAR_STRING;
|
||||
varValue.u.data = new std::vector<unsigned char>;
|
||||
|
||||
// Allocate space for the string
|
||||
varValue.u.data->resize(stringLen);
|
||||
|
||||
// Copy directly to vector array
|
||||
memcpy(varValue.u.data->data(), Value, stringLen);
|
||||
|
||||
// Try to register variable
|
||||
if(!varset(Name, &varValue, ReadOnly))
|
||||
{
|
||||
varvalue.u.data->clear();
|
||||
delete varvalue.u.data;
|
||||
varValue.u.data->clear();
|
||||
delete varValue.u.data;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool vardel(const char* name, bool delsystem)
|
||||
/**
|
||||
\brief Deletes a variable.
|
||||
\param Name The name of the variable to delete. Cannot be null.
|
||||
\param DelSystem true to allow deleting system variables.
|
||||
\return true if the variable was deleted successfully, false otherwise.
|
||||
*/
|
||||
bool vardel(const char* Name, bool DelSystem)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockVariables);
|
||||
|
||||
String name_;
|
||||
if(*name != '$')
|
||||
if(*Name != '$')
|
||||
name_ = "$";
|
||||
name_ += name;
|
||||
VariableMap::iterator found = variables.find(name_);
|
||||
name_ += Name;
|
||||
auto found = variables.find(name_);
|
||||
if(found == variables.end()) //not found
|
||||
return false;
|
||||
if(found->second.alias.length())
|
||||
|
|
@ -226,42 +302,55 @@ bool vardel(const char* name, bool delsystem)
|
|||
// Release the lock (potential deadlock here)
|
||||
EXCLUSIVE_RELEASE();
|
||||
|
||||
return vardel(found->second.alias.c_str(), delsystem);
|
||||
return vardel(found->second.alias.c_str(), DelSystem);
|
||||
}
|
||||
|
||||
if(!delsystem && found->second.type != VAR_USER)
|
||||
if(!DelSystem && found->second.type != VAR_USER)
|
||||
return false;
|
||||
found = variables.begin();
|
||||
while(found != variables.end())
|
||||
{
|
||||
VariableMap::iterator del = found;
|
||||
auto del = found;
|
||||
found++;
|
||||
if(found->second.name == String(name))
|
||||
if(found->second.name == String(Name))
|
||||
variables.erase(del);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool vargettype(const char* name, VAR_TYPE* type, VAR_VALUE_TYPE* valtype)
|
||||
/**
|
||||
\brief Gets a variable type.
|
||||
\param Name The name of the variable. Cannot be null.
|
||||
\param [out] Type This function can retrieve the variable type. If null it is ignored.
|
||||
\param [out] ValueType This function can retrieve the variable value type. If null it is ignored.
|
||||
\return true if getting the type was successful, false otherwise.
|
||||
*/
|
||||
bool vargettype(const char* Name, VAR_TYPE* Type, VAR_VALUE_TYPE* ValueType)
|
||||
{
|
||||
SHARED_ACQUIRE(LockVariables);
|
||||
|
||||
String name_;
|
||||
if(*name != '$')
|
||||
if(*Name != '$')
|
||||
name_ = "$";
|
||||
name_ += name;
|
||||
VariableMap::iterator found = variables.find(name_);
|
||||
name_ += Name;
|
||||
auto found = variables.find(name_);
|
||||
if(found == variables.end()) //not found
|
||||
return false;
|
||||
if(found->second.alias.length())
|
||||
return vargettype(found->second.alias.c_str(), type, valtype);
|
||||
if(valtype)
|
||||
*valtype = found->second.value.type;
|
||||
if(type)
|
||||
*type = found->second.type;
|
||||
return vargettype(found->second.alias.c_str(), Type, ValueType);
|
||||
if(ValueType)
|
||||
*ValueType = found->second.value.type;
|
||||
if(Type)
|
||||
*Type = found->second.type;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Enumerates all variables.
|
||||
\param [in,out] List A pointer to place the variables in. If null, \p cbsize will be filled to the number of bytes required.
|
||||
\param [in,out] Size This function retrieves the number of bytes required to store all variables. Can be null if \p entries is not null.
|
||||
\return true if it succeeds, false if it fails.
|
||||
*/
|
||||
bool varenum(VAR* List, size_t* Size)
|
||||
{
|
||||
// A list or size must be requested
|
||||
|
|
|
|||
|
|
@ -46,19 +46,19 @@ struct CaseInsensitiveCompare
|
|||
}
|
||||
};
|
||||
|
||||
typedef std::map<String, VAR, CaseInsensitiveCompare> VariableMap;
|
||||
|
||||
//functions
|
||||
void varsetvalue(VAR* Var, VAR_VALUE* Value);
|
||||
bool varset(const char* Name, VAR_VALUE* Value, bool ReadOnly);
|
||||
void varinit();
|
||||
void varfree();
|
||||
VAR* vargetptr();
|
||||
bool varnew(const char* name, uint value, VAR_TYPE type);
|
||||
bool varget(const char* name, uint* value, int* size, VAR_TYPE* type);
|
||||
bool varget(const char* name, char* string, int* size, VAR_TYPE* type);
|
||||
bool varset(const char* name, uint value, bool setreadonly);
|
||||
bool varset(const char* name, const char* string, bool setreadonly);
|
||||
bool vardel(const char* name, bool delsystem);
|
||||
bool vargettype(const char* name, VAR_TYPE* type = 0, VAR_VALUE_TYPE* valtype = 0);
|
||||
bool varenum(VAR* entries, size_t* cbsize);
|
||||
bool varnew(const char* Name, uint Value, VAR_TYPE Type);
|
||||
bool varget(const char* Name, VAR_VALUE* Value, int* Size, VAR_TYPE* Type);
|
||||
bool varget(const char* Name, uint* Value, int* Size, VAR_TYPE* Type);
|
||||
bool varget(const char* Name, char* String, int* Size, VAR_TYPE* Type);
|
||||
bool varset(const char* Name, uint Value, bool ReadOnly);
|
||||
bool varset(const char* Name, const char* Value, bool ReadOnly);
|
||||
bool vardel(const char* Name, bool DelSystem);
|
||||
bool vargettype(const char* Name, VAR_TYPE* Type = nullptr, VAR_VALUE_TYPE* ValueType = nullptr);
|
||||
bool varenum(VAR* List, size_t* Size);
|
||||
|
||||
#endif // _VARIABLE_H
|
||||
|
|
|
|||
|
|
@ -1,5 +1,10 @@
|
|||
/**
|
||||
@file x64_dbg.cpp
|
||||
|
||||
@brief Implements the 64 debug class.
|
||||
*/
|
||||
|
||||
#include "_global.h"
|
||||
#include "argument.h"
|
||||
#include "command.h"
|
||||
#include "variable.h"
|
||||
#include "instruction.h"
|
||||
|
|
@ -17,8 +22,11 @@
|
|||
#include "debugger_commands.h"
|
||||
|
||||
static MESSAGE_STACK* gMsgStack = 0;
|
||||
|
||||
static COMMAND* command_list = 0;
|
||||
|
||||
static HANDLE hCommandLoopThread = 0;
|
||||
|
||||
static char alloctrace[MAX_PATH] = "";
|
||||
|
||||
static CMDRESULT cbStrLen(int argc, char* argv[])
|
||||
|
|
@ -189,12 +197,15 @@ static void registercommands()
|
|||
dbgcmdnew("getstr\1strget", cbInstrGetstr, false); //get a string variable
|
||||
dbgcmdnew("copystr\1strcpy", cbInstrCopystr, true); //write a string variable to memory
|
||||
dbgcmdnew("looplist", cbInstrLoopList, true); //list loops
|
||||
dbgcmdnew("yara", cbInstrYara, true); //yara test command
|
||||
dbgcmdnew("yaramod", cbInstrYaramod, true); //yara rule on module
|
||||
dbgcmdnew("log", cbInstrLog, false); //log command with superawesome hax
|
||||
}
|
||||
|
||||
static bool cbCommandProvider(char* cmd, int maxlen)
|
||||
{
|
||||
MESSAGE msg;
|
||||
msgwait(gMsgStack, &msg);
|
||||
MsgWait(gMsgStack, &msg);
|
||||
char* newcmd = (char*)msg.param1;
|
||||
if(strlen(newcmd) >= deflen)
|
||||
{
|
||||
|
|
@ -211,7 +222,7 @@ extern "C" DLL_EXPORT bool _dbg_dbgcmdexec(const char* cmd)
|
|||
int len = (int)strlen(cmd);
|
||||
char* newcmd = (char*)emalloc((len + 1) * sizeof(char), "_dbg_dbgcmdexec:newcmd");
|
||||
strcpy_s(newcmd, len + 1, cmd);
|
||||
return msgsend(gMsgStack, 0, (uint)newcmd, 0);
|
||||
return MsgSend(gMsgStack, 0, (uint)newcmd, 0);
|
||||
}
|
||||
|
||||
static DWORD WINAPI DbgCommandLoopThread(void* a)
|
||||
|
|
@ -240,6 +251,8 @@ extern "C" DLL_EXPORT const char* _dbg_dbginit()
|
|||
dbginit();
|
||||
dbgfunctionsinit();
|
||||
json_set_alloc_funcs(emalloc_json, efree_json);
|
||||
if(yr_initialize() != ERROR_SUCCESS)
|
||||
return "Failed to initialize Yara!";
|
||||
wchar_t wszDir[deflen] = L"";
|
||||
if(!GetModuleFileNameW(hInst, wszDir, deflen))
|
||||
return "GetModuleFileNameW failed!";
|
||||
|
|
@ -259,7 +272,7 @@ extern "C" DLL_EXPORT const char* _dbg_dbginit()
|
|||
strcpy_s(szSymbolCachePath, dir);
|
||||
PathAppendA(szSymbolCachePath, "symbols");
|
||||
SetCurrentDirectoryW(StringUtils::Utf8ToUtf16(dir).c_str());;
|
||||
gMsgStack = msgallocstack();
|
||||
gMsgStack = MsgAllocStack();
|
||||
if(!gMsgStack)
|
||||
return "Could not allocate message stack!";
|
||||
varinit();
|
||||
|
|
@ -306,7 +319,8 @@ extern "C" DLL_EXPORT void _dbg_dbgexitsignal()
|
|||
CloseHandle(hCommandLoopThread);
|
||||
cmdfree(command_list);
|
||||
varfree();
|
||||
msgfreestack(gMsgStack);
|
||||
MsgFreeStack(gMsgStack);
|
||||
yr_finalize();
|
||||
if(memleaks())
|
||||
{
|
||||
char msg[256] = "";
|
||||
|
|
|
|||
|
|
@ -20,11 +20,11 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="addrinfo.cpp" />
|
||||
<ClCompile Include="argument.cpp" />
|
||||
<ClCompile Include="assemble.cpp" />
|
||||
<ClCompile Include="bookmark.cpp" />
|
||||
<ClCompile Include="breakpoint.cpp" />
|
||||
<ClCompile Include="command.cpp" />
|
||||
<ClCompile Include="commandparser.cpp" />
|
||||
<ClCompile Include="comment.cpp" />
|
||||
<ClCompile Include="console.cpp" />
|
||||
<ClCompile Include="dbghelp_safe.cpp" />
|
||||
|
|
@ -37,7 +37,6 @@
|
|||
<ClCompile Include="function.cpp" />
|
||||
<ClCompile Include="instruction.cpp" />
|
||||
<ClCompile Include="label.cpp" />
|
||||
<ClCompile Include="log.cpp" />
|
||||
<ClCompile Include="loop.cpp" />
|
||||
<ClCompile Include="main.cpp" />
|
||||
<ClCompile Include="math.cpp" />
|
||||
|
|
@ -51,6 +50,7 @@
|
|||
<ClCompile Include="reference.cpp" />
|
||||
<ClCompile Include="simplescript.cpp" />
|
||||
<ClCompile Include="stackinfo.cpp" />
|
||||
<ClCompile Include="stringformat.cpp" />
|
||||
<ClCompile Include="stringutils.cpp" />
|
||||
<ClCompile Include="symbolinfo.cpp" />
|
||||
<ClCompile Include="thread.cpp" />
|
||||
|
|
@ -65,7 +65,6 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="addrinfo.h" />
|
||||
<ClInclude Include="argument.h" />
|
||||
<ClInclude Include="assemble.h" />
|
||||
<ClInclude Include="BeaEngine\basic_types.h" />
|
||||
<ClInclude Include="BeaEngine\BeaEngine.h" />
|
||||
|
|
@ -74,6 +73,7 @@
|
|||
<ClInclude Include="bookmark.h" />
|
||||
<ClInclude Include="breakpoint.h" />
|
||||
<ClInclude Include="command.h" />
|
||||
<ClInclude Include="commandparser.h" />
|
||||
<ClInclude Include="comment.h" />
|
||||
<ClInclude Include="console.h" />
|
||||
<ClInclude Include="dbghelp\dbghelp.h" />
|
||||
|
|
@ -92,7 +92,6 @@
|
|||
<ClInclude Include="jansson\jansson.h" />
|
||||
<ClInclude Include="jansson\jansson_config.h" />
|
||||
<ClInclude Include="label.h" />
|
||||
<ClInclude Include="log.h" />
|
||||
<ClInclude Include="loop.h" />
|
||||
<ClInclude Include="lz4\lz4.h" />
|
||||
<ClInclude Include="lz4\lz4file.h" />
|
||||
|
|
@ -108,6 +107,7 @@
|
|||
<ClInclude Include="reference.h" />
|
||||
<ClInclude Include="simplescript.h" />
|
||||
<ClInclude Include="stackinfo.h" />
|
||||
<ClInclude Include="stringformat.h" />
|
||||
<ClInclude Include="stringutils.h" />
|
||||
<ClInclude Include="symbolinfo.h" />
|
||||
<ClInclude Include="thread.h" />
|
||||
|
|
@ -118,6 +118,36 @@
|
|||
<ClInclude Include="variable.h" />
|
||||
<ClInclude Include="x64_dbg.h" />
|
||||
<ClInclude Include="XEDParse\XEDParse.h" />
|
||||
<ClInclude Include="yara\yara.h" />
|
||||
<ClInclude Include="yara\yara\ahocorasick.h" />
|
||||
<ClInclude Include="yara\yara\arena.h" />
|
||||
<ClInclude Include="yara\yara\atoms.h" />
|
||||
<ClInclude Include="yara\yara\compiler.h" />
|
||||
<ClInclude Include="yara\yara\elf.h" />
|
||||
<ClInclude Include="yara\yara\error.h" />
|
||||
<ClInclude Include="yara\yara\exec.h" />
|
||||
<ClInclude Include="yara\yara\exefiles.h" />
|
||||
<ClInclude Include="yara\yara\filemap.h" />
|
||||
<ClInclude Include="yara\yara\globals.h" />
|
||||
<ClInclude Include="yara\yara\hash.h" />
|
||||
<ClInclude Include="yara\yara\hex_lexer.h" />
|
||||
<ClInclude Include="yara\yara\lexer.h" />
|
||||
<ClInclude Include="yara\yara\libyara.h" />
|
||||
<ClInclude Include="yara\yara\limits.h" />
|
||||
<ClInclude Include="yara\yara\mem.h" />
|
||||
<ClInclude Include="yara\yara\modules.h" />
|
||||
<ClInclude Include="yara\yara\object.h" />
|
||||
<ClInclude Include="yara\yara\parser.h" />
|
||||
<ClInclude Include="yara\yara\pe.h" />
|
||||
<ClInclude Include="yara\yara\proc.h" />
|
||||
<ClInclude Include="yara\yara\re.h" />
|
||||
<ClInclude Include="yara\yara\re_lexer.h" />
|
||||
<ClInclude Include="yara\yara\rules.h" />
|
||||
<ClInclude Include="yara\yara\scan.h" />
|
||||
<ClInclude Include="yara\yara\sizedstr.h" />
|
||||
<ClInclude Include="yara\yara\strutils.h" />
|
||||
<ClInclude Include="yara\yara\types.h" />
|
||||
<ClInclude Include="yara\yara\utils.h" />
|
||||
<ClInclude Include="_exports.h" />
|
||||
<ClInclude Include="_dbgfunctions.h" />
|
||||
<ClInclude Include="_global.h" />
|
||||
|
|
@ -132,22 +162,22 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<PlatformToolset>Intel C++ Compiler XE 15.0</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<PlatformToolset>Intel C++ Compiler XE 15.0</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<PlatformToolset>Intel C++ Compiler XE 15.0</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<PlatformToolset>Intel C++ Compiler XE 15.0</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
|
|
@ -209,7 +239,7 @@
|
|||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>lz4\lz4_x86.lib;jansson\jansson_x86.lib;DeviceNameResolver\DeviceNameResolver_x86.lib;XEDParse\XEDParse_x86.lib;$(SolutionDir)bin\x32\x32_bridge.lib;dbghelp\dbghelp_x86.lib;TitanEngine\TitanEngine_x86.lib;BeaEngine\BeaEngine.lib;psapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>yara\yara_x86.lib;lz4\lz4_x86.lib;jansson\jansson_x86.lib;DeviceNameResolver\DeviceNameResolver_x86.lib;XEDParse\XEDParse_x86.lib;$(SolutionDir)bin\x32\x32_bridge.lib;dbghelp\dbghelp_x86.lib;TitanEngine\TitanEngine_x86.lib;BeaEngine\BeaEngine.lib;psapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
|
|
@ -230,7 +260,7 @@
|
|||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>false</EnableCOMDATFolding>
|
||||
<OptimizeReferences>false</OptimizeReferences>
|
||||
<AdditionalDependencies>lz4\lz4_x86.lib;jansson\jansson_x86.lib;DeviceNameResolver\DeviceNameResolver_x86.lib;XEDParse\XEDParse_x86.lib;$(SolutionDir)bin\x32\x32_bridge.lib;dbghelp\dbghelp_x86.lib;TitanEngine\TitanEngine_x86.lib;BeaEngine\BeaEngine.lib;psapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>yara\yara_x86.lib;lz4\lz4_x86.lib;jansson\jansson_x86.lib;DeviceNameResolver\DeviceNameResolver_x86.lib;XEDParse\XEDParse_x86.lib;$(SolutionDir)bin\x32\x32_bridge.lib;dbghelp\dbghelp_x86.lib;TitanEngine\TitanEngine_x86.lib;BeaEngine\BeaEngine.lib;psapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
|
|
@ -257,7 +287,7 @@
|
|||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>lz4\lz4_x64.lib;jansson\jansson_x64.lib;DeviceNameResolver\DeviceNameResolver_x64.lib;XEDParse\XEDParse_x64.lib;$(SolutionDir)bin\x64\x64_bridge.lib;dbghelp\dbghelp_x64.lib;TitanEngine\TitanEngine_x64.lib;BeaEngine\BeaEngine_64.lib;psapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>yara\yara_x64.lib;lz4\lz4_x64.lib;jansson\jansson_x64.lib;DeviceNameResolver\DeviceNameResolver_x64.lib;XEDParse\XEDParse_x64.lib;$(SolutionDir)bin\x64\x64_bridge.lib;dbghelp\dbghelp_x64.lib;TitanEngine\TitanEngine_x64.lib;BeaEngine\BeaEngine_64.lib;psapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
|
|
@ -271,16 +301,17 @@
|
|||
<OptimizeForWindowsApplication>false</OptimizeForWindowsApplication>
|
||||
<UseIntelOptimizedHeaders>false</UseIntelOptimizedHeaders>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<CheckPointers>Rw</CheckPointers>
|
||||
<CheckPointers>None</CheckPointers>
|
||||
<CheckDanglingPointers>None</CheckDanglingPointers>
|
||||
<CheckUndimensionedArrays>true</CheckUndimensionedArrays>
|
||||
<CheckUndimensionedArrays>false</CheckUndimensionedArrays>
|
||||
<EnableExpandedLineNumberInfo>true</EnableExpandedLineNumberInfo>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>false</EnableCOMDATFolding>
|
||||
<OptimizeReferences>false</OptimizeReferences>
|
||||
<AdditionalDependencies>lz4\lz4_x64.lib;jansson\jansson_x64.lib;DeviceNameResolver\DeviceNameResolver_x64.lib;XEDParse\XEDParse_x64.lib;$(SolutionDir)bin\x64\x64_bridge.lib;dbghelp\dbghelp_x64.lib;TitanEngine\TitanEngine_x64.lib;BeaEngine\BeaEngine_64.lib;psapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>yara\yara_x64.lib;lz4\lz4_x64.lib;jansson\jansson_x64.lib;DeviceNameResolver\DeviceNameResolver_x64.lib;XEDParse\XEDParse_x64.lib;$(SolutionDir)bin\x64\x64_bridge.lib;dbghelp\dbghelp_x64.lib;TitanEngine\TitanEngine_x64.lib;BeaEngine\BeaEngine_64.lib;psapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
|
|
|
|||
|
|
@ -9,6 +9,10 @@
|
|||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\Interfaces/Exports">
|
||||
<UniqueIdentifier>{44fd9eb7-2017-49b8-8d9a-dec680632343}</UniqueIdentifier>
|
||||
</Filter>
|
||||
|
|
@ -63,6 +67,12 @@
|
|||
<Filter Include="Header Files\Information">
|
||||
<UniqueIdentifier>{b006b04c-d7ea-49cb-b097-0cac1388f98e}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\Third Party\yara">
|
||||
<UniqueIdentifier>{efe5d058-e77c-49e9-a25b-75b90346dbf2}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\Third Party\yara\yara">
|
||||
<UniqueIdentifier>{f79c5166-e315-44ca-9e93-dabc9f00fa78}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="main.cpp">
|
||||
|
|
@ -83,9 +93,6 @@
|
|||
<ClCompile Include="_global.cpp">
|
||||
<Filter>Source Files\Core</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="argument.cpp">
|
||||
<Filter>Source Files\Core</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="command.cpp">
|
||||
<Filter>Source Files\Core</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -143,9 +150,6 @@
|
|||
<ClCompile Include="debugger.cpp">
|
||||
<Filter>Source Files\Debugger Core</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="log.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="stringutils.cpp">
|
||||
<Filter>Source Files\Utilities</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -194,6 +198,12 @@
|
|||
<ClCompile Include="dbghelp_safe.cpp">
|
||||
<Filter>Source Files\Utilities</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="stringformat.cpp">
|
||||
<Filter>Source Files\Utilities</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="commandparser.cpp">
|
||||
<Filter>Source Files\Core</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="x64_dbg.h">
|
||||
|
|
@ -241,9 +251,6 @@
|
|||
<ClInclude Include="_global.h">
|
||||
<Filter>Header Files\Core</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="argument.h">
|
||||
<Filter>Header Files\Core</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="console.h">
|
||||
<Filter>Header Files\Core</Filter>
|
||||
</ClInclude>
|
||||
|
|
@ -319,9 +326,6 @@
|
|||
<ClInclude Include="handle.h">
|
||||
<Filter>Header Files\Utilities</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="log.h">
|
||||
<Filter>Header Files\Utilities</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="undocumented.h">
|
||||
<Filter>Header Files\Debugger Core</Filter>
|
||||
</ClInclude>
|
||||
|
|
@ -373,5 +377,101 @@
|
|||
<ClInclude Include="dbghelp_safe.h">
|
||||
<Filter>Header Files\Utilities</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="yara\yara.h">
|
||||
<Filter>Header Files\Third Party\yara</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="yara\yara\ahocorasick.h">
|
||||
<Filter>Header Files\Third Party\yara\yara</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="yara\yara\arena.h">
|
||||
<Filter>Header Files\Third Party\yara\yara</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="yara\yara\atoms.h">
|
||||
<Filter>Header Files\Third Party\yara\yara</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="yara\yara\compiler.h">
|
||||
<Filter>Header Files\Third Party\yara\yara</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="yara\yara\elf.h">
|
||||
<Filter>Header Files\Third Party\yara\yara</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="yara\yara\error.h">
|
||||
<Filter>Header Files\Third Party\yara\yara</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="yara\yara\exec.h">
|
||||
<Filter>Header Files\Third Party\yara\yara</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="yara\yara\exefiles.h">
|
||||
<Filter>Header Files\Third Party\yara\yara</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="yara\yara\filemap.h">
|
||||
<Filter>Header Files\Third Party\yara\yara</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="yara\yara\globals.h">
|
||||
<Filter>Header Files\Third Party\yara\yara</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="yara\yara\hash.h">
|
||||
<Filter>Header Files\Third Party\yara\yara</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="yara\yara\hex_lexer.h">
|
||||
<Filter>Header Files\Third Party\yara\yara</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="yara\yara\lexer.h">
|
||||
<Filter>Header Files\Third Party\yara\yara</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="yara\yara\libyara.h">
|
||||
<Filter>Header Files\Third Party\yara\yara</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="yara\yara\limits.h">
|
||||
<Filter>Header Files\Third Party\yara\yara</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="yara\yara\mem.h">
|
||||
<Filter>Header Files\Third Party\yara\yara</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="yara\yara\modules.h">
|
||||
<Filter>Header Files\Third Party\yara\yara</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="yara\yara\object.h">
|
||||
<Filter>Header Files\Third Party\yara\yara</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="yara\yara\parser.h">
|
||||
<Filter>Header Files\Third Party\yara\yara</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="yara\yara\pe.h">
|
||||
<Filter>Header Files\Third Party\yara\yara</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="yara\yara\proc.h">
|
||||
<Filter>Header Files\Third Party\yara\yara</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="yara\yara\re.h">
|
||||
<Filter>Header Files\Third Party\yara\yara</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="yara\yara\re_lexer.h">
|
||||
<Filter>Header Files\Third Party\yara\yara</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="yara\yara\rules.h">
|
||||
<Filter>Header Files\Third Party\yara\yara</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="yara\yara\scan.h">
|
||||
<Filter>Header Files\Third Party\yara\yara</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="yara\yara\sizedstr.h">
|
||||
<Filter>Header Files\Third Party\yara\yara</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="yara\yara\strutils.h">
|
||||
<Filter>Header Files\Third Party\yara\yara</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="yara\yara\types.h">
|
||||
<Filter>Header Files\Third Party\yara\yara</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="yara\yara\utils.h">
|
||||
<Filter>Header Files\Third Party\yara\yara</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="stringformat.h">
|
||||
<Filter>Header Files\Utilities</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="commandparser.h">
|
||||
<Filter>Header Files\Core</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
Copyright (c) 2007-2013. The YARA Authors. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef YR_YARA_H
|
||||
#define YR_YARA_H
|
||||
|
||||
#include "yara/utils.h"
|
||||
#include "yara/filemap.h"
|
||||
#include "yara/compiler.h"
|
||||
#include "yara/modules.h"
|
||||
#include "yara/object.h"
|
||||
#include "yara/libyara.h"
|
||||
#include "yara/error.h"
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
Copyright (c) 2013. The YARA Authors. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _AHOCORASICK_H
|
||||
#define _AHOCORASICK_H
|
||||
|
||||
#include "limits.h"
|
||||
#include "atoms.h"
|
||||
#include "types.h"
|
||||
|
||||
|
||||
int yr_ac_create_automaton(
|
||||
YR_ARENA* arena,
|
||||
YR_AC_AUTOMATON** automaton);
|
||||
|
||||
|
||||
int yr_ac_add_string(
|
||||
YR_ARENA* arena,
|
||||
YR_AC_AUTOMATON* automaton,
|
||||
YR_STRING* string,
|
||||
YR_ATOM_LIST_ITEM* atom);
|
||||
|
||||
|
||||
YR_AC_STATE* yr_ac_next_state(
|
||||
YR_AC_STATE* state,
|
||||
uint8_t input);
|
||||
|
||||
|
||||
int yr_ac_create_failure_links(
|
||||
YR_ARENA* arena,
|
||||
YR_AC_AUTOMATON* automaton);
|
||||
|
||||
|
||||
void yr_ac_print_automaton(
|
||||
YR_AC_AUTOMATON* automaton);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
Copyright (c) 2013. The YARA Authors. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef YR_ARENA_H
|
||||
#define YR_ARENA_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
|
||||
#define ARENA_FLAGS_FIXED_SIZE 1
|
||||
#define ARENA_FLAGS_COALESCED 2
|
||||
#define ARENA_FILE_VERSION 6
|
||||
|
||||
#define EOL ((size_t) -1)
|
||||
|
||||
|
||||
typedef struct _YR_RELOC
|
||||
{
|
||||
int32_t offset;
|
||||
struct _YR_RELOC* next;
|
||||
|
||||
} YR_RELOC;
|
||||
|
||||
|
||||
typedef struct _YR_ARENA_PAGE
|
||||
{
|
||||
|
||||
uint8_t* new_address;
|
||||
uint8_t* address;
|
||||
|
||||
size_t size;
|
||||
size_t used;
|
||||
|
||||
YR_RELOC* reloc_list_head;
|
||||
YR_RELOC* reloc_list_tail;
|
||||
|
||||
struct _YR_ARENA_PAGE* next;
|
||||
struct _YR_ARENA_PAGE* prev;
|
||||
|
||||
} YR_ARENA_PAGE;
|
||||
|
||||
|
||||
typedef struct _YR_ARENA
|
||||
{
|
||||
int flags;
|
||||
|
||||
YR_ARENA_PAGE* page_list_head;
|
||||
YR_ARENA_PAGE* current_page;
|
||||
|
||||
} YR_ARENA;
|
||||
|
||||
|
||||
int yr_arena_create(
|
||||
size_t initial_size,
|
||||
int flags,
|
||||
YR_ARENA** arena);
|
||||
|
||||
|
||||
void yr_arena_destroy(
|
||||
YR_ARENA* arena);
|
||||
|
||||
|
||||
void* yr_arena_base_address(
|
||||
YR_ARENA* arena);
|
||||
|
||||
|
||||
void* yr_arena_next_address(
|
||||
YR_ARENA* arena,
|
||||
void* address,
|
||||
int offset);
|
||||
|
||||
|
||||
int yr_arena_coalesce(
|
||||
YR_ARENA* arena);
|
||||
|
||||
|
||||
int yr_arena_reserve_memory(
|
||||
YR_ARENA* arena,
|
||||
size_t size);
|
||||
|
||||
|
||||
int yr_arena_allocate_memory(
|
||||
YR_ARENA* arena,
|
||||
size_t size,
|
||||
void** allocated_memory);
|
||||
|
||||
|
||||
int yr_arena_allocate_struct(
|
||||
YR_ARENA* arena,
|
||||
size_t size,
|
||||
void** allocated_memory,
|
||||
...);
|
||||
|
||||
|
||||
int yr_arena_make_relocatable(
|
||||
YR_ARENA* arena,
|
||||
void* base,
|
||||
...);
|
||||
|
||||
|
||||
int yr_arena_write_data(
|
||||
YR_ARENA* arena,
|
||||
void* data,
|
||||
size_t size,
|
||||
void** written_data);
|
||||
|
||||
|
||||
int yr_arena_write_string(
|
||||
YR_ARENA* arena,
|
||||
const char* string,
|
||||
char** written_string);
|
||||
|
||||
|
||||
int yr_arena_append(
|
||||
YR_ARENA* target_arena,
|
||||
YR_ARENA* source_arena);
|
||||
|
||||
|
||||
int yr_arena_save(
|
||||
YR_ARENA* arena,
|
||||
const char* filename);
|
||||
|
||||
|
||||
int yr_arena_load(
|
||||
const char* filename,
|
||||
YR_ARENA** arena);
|
||||
|
||||
|
||||
int yr_arena_duplicate(
|
||||
YR_ARENA* arena,
|
||||
YR_ARENA** duplicated);
|
||||
|
||||
|
||||
void yr_arena_print(
|
||||
YR_ARENA* arena);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
Copyright (c) 2013. The YARA Authors. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef YR_ATOMS_H
|
||||
#define YR_ATOMS_H
|
||||
|
||||
#include "limits.h"
|
||||
#include "re.h"
|
||||
|
||||
#define ATOM_TREE_LEAF 1
|
||||
#define ATOM_TREE_AND 2
|
||||
#define ATOM_TREE_OR 3
|
||||
|
||||
|
||||
typedef struct _ATOM_TREE_NODE
|
||||
{
|
||||
uint8_t type;
|
||||
uint8_t atom_length;
|
||||
uint8_t atom[MAX_ATOM_LENGTH];
|
||||
|
||||
uint8_t* forward_code;
|
||||
uint8_t* backward_code;
|
||||
|
||||
RE_NODE* recent_nodes[MAX_ATOM_LENGTH];
|
||||
|
||||
struct _ATOM_TREE_NODE* children_head;
|
||||
struct _ATOM_TREE_NODE* children_tail;
|
||||
struct _ATOM_TREE_NODE* next_sibling;
|
||||
|
||||
} ATOM_TREE_NODE;
|
||||
|
||||
|
||||
typedef struct _ATOM_TREE
|
||||
{
|
||||
ATOM_TREE_NODE* current_leaf;
|
||||
ATOM_TREE_NODE* root_node;
|
||||
|
||||
} ATOM_TREE;
|
||||
|
||||
|
||||
typedef struct _YR_ATOM_LIST_ITEM
|
||||
{
|
||||
uint8_t atom_length;
|
||||
uint8_t atom[MAX_ATOM_LENGTH];
|
||||
|
||||
uint16_t backtrack;
|
||||
|
||||
uint8_t* forward_code;
|
||||
uint8_t* backward_code;
|
||||
|
||||
struct _YR_ATOM_LIST_ITEM* next;
|
||||
|
||||
} YR_ATOM_LIST_ITEM;
|
||||
|
||||
|
||||
int yr_atoms_extract_from_re(
|
||||
RE* re,
|
||||
int flags,
|
||||
YR_ATOM_LIST_ITEM** atoms);
|
||||
|
||||
|
||||
int yr_atoms_extract_from_string(
|
||||
uint8_t* string,
|
||||
int string_length,
|
||||
int flags,
|
||||
YR_ATOM_LIST_ITEM** atoms);
|
||||
|
||||
|
||||
int yr_atoms_min_quality(
|
||||
YR_ATOM_LIST_ITEM* atom_list);
|
||||
|
||||
|
||||
void yr_atoms_list_destroy(
|
||||
YR_ATOM_LIST_ITEM* list_head);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,196 @@
|
|||
/*
|
||||
Copyright (c) 2013. The YARA Authors. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef YR_COMPILER_H
|
||||
#define YR_COMPILER_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#include "ahocorasick.h"
|
||||
#include "arena.h"
|
||||
#include "hash.h"
|
||||
#include "utils.h"
|
||||
|
||||
|
||||
#define YARA_ERROR_LEVEL_ERROR 0
|
||||
#define YARA_ERROR_LEVEL_WARNING 1
|
||||
|
||||
|
||||
typedef void (*YR_COMPILER_CALLBACK_FUNC)(
|
||||
int error_level,
|
||||
const char* file_name,
|
||||
int line_number,
|
||||
const char* message,
|
||||
void* user_data);
|
||||
|
||||
|
||||
typedef struct _YR_COMPILER
|
||||
{
|
||||
int errors;
|
||||
int error_line;
|
||||
int last_error;
|
||||
int last_error_line;
|
||||
int last_result;
|
||||
|
||||
jmp_buf error_recovery;
|
||||
|
||||
YR_ARENA* sz_arena;
|
||||
YR_ARENA* rules_arena;
|
||||
YR_ARENA* strings_arena;
|
||||
YR_ARENA* code_arena;
|
||||
YR_ARENA* re_code_arena;
|
||||
YR_ARENA* automaton_arena;
|
||||
YR_ARENA* compiled_rules_arena;
|
||||
YR_ARENA* externals_arena;
|
||||
YR_ARENA* namespaces_arena;
|
||||
YR_ARENA* metas_arena;
|
||||
|
||||
YR_AC_AUTOMATON* automaton;
|
||||
YR_HASH_TABLE* rules_table;
|
||||
YR_HASH_TABLE* objects_table;
|
||||
YR_NAMESPACE* current_namespace;
|
||||
YR_STRING* current_rule_strings;
|
||||
|
||||
int current_rule_flags;
|
||||
int namespaces_count;
|
||||
|
||||
int8_t* loop_address[MAX_LOOP_NESTING];
|
||||
char* loop_identifier[MAX_LOOP_NESTING];
|
||||
int loop_depth;
|
||||
int loop_for_of_mem_offset;
|
||||
|
||||
int allow_includes;
|
||||
|
||||
char* file_name_stack[MAX_INCLUDE_DEPTH];
|
||||
int file_name_stack_ptr;
|
||||
|
||||
FILE* file_stack[MAX_INCLUDE_DEPTH];
|
||||
int file_stack_ptr;
|
||||
|
||||
char last_error_extra_info[MAX_COMPILER_ERROR_EXTRA_INFO];
|
||||
|
||||
char lex_buf[LEX_BUF_SIZE];
|
||||
char* lex_buf_ptr;
|
||||
unsigned short lex_buf_len;
|
||||
|
||||
char include_base_dir[MAX_PATH];
|
||||
void* user_data;
|
||||
|
||||
YR_COMPILER_CALLBACK_FUNC callback;
|
||||
|
||||
} YR_COMPILER;
|
||||
|
||||
|
||||
#define yr_compiler_set_error_extra_info(compiler, info) \
|
||||
strlcpy( \
|
||||
compiler->last_error_extra_info, \
|
||||
info, \
|
||||
sizeof(compiler->last_error_extra_info)); \
|
||||
|
||||
|
||||
#define yr_compiler_set_error_extra_info_fmt(compiler, fmt, ...) \
|
||||
snprintf( \
|
||||
compiler->last_error_extra_info, \
|
||||
sizeof(compiler->last_error_extra_info), \
|
||||
fmt, __VA_ARGS__);
|
||||
|
||||
|
||||
int _yr_compiler_push_file(
|
||||
YR_COMPILER* compiler,
|
||||
FILE* fh);
|
||||
|
||||
|
||||
FILE* _yr_compiler_pop_file(
|
||||
YR_COMPILER* compiler);
|
||||
|
||||
|
||||
int _yr_compiler_push_file_name(
|
||||
YR_COMPILER* compiler,
|
||||
const char* file_name);
|
||||
|
||||
|
||||
void _yr_compiler_pop_file_name(
|
||||
YR_COMPILER* compiler);
|
||||
|
||||
|
||||
YR_API int yr_compiler_create(
|
||||
YR_COMPILER** compiler);
|
||||
|
||||
|
||||
YR_API void yr_compiler_destroy(
|
||||
YR_COMPILER* compiler);
|
||||
|
||||
|
||||
YR_API void yr_compiler_set_callback(
|
||||
YR_COMPILER* compiler,
|
||||
YR_COMPILER_CALLBACK_FUNC callback,
|
||||
void* user_data);
|
||||
|
||||
|
||||
YR_API int yr_compiler_add_file(
|
||||
YR_COMPILER* compiler,
|
||||
FILE* rules_file,
|
||||
const char* namespace_,
|
||||
const char* file_name);
|
||||
|
||||
|
||||
YR_API int yr_compiler_add_string(
|
||||
YR_COMPILER* compiler,
|
||||
const char* rules_string,
|
||||
const char* namespace_);
|
||||
|
||||
|
||||
YR_API char* yr_compiler_get_error_message(
|
||||
YR_COMPILER* compiler,
|
||||
char* buffer,
|
||||
int buffer_size);
|
||||
|
||||
|
||||
YR_API char* yr_compiler_get_current_file_name(
|
||||
YR_COMPILER* context);
|
||||
|
||||
|
||||
YR_API int yr_compiler_define_integer_variable(
|
||||
YR_COMPILER* compiler,
|
||||
const char* identifier,
|
||||
int64_t value);
|
||||
|
||||
|
||||
YR_API int yr_compiler_define_boolean_variable(
|
||||
YR_COMPILER* compiler,
|
||||
const char* identifier,
|
||||
int value);
|
||||
|
||||
|
||||
YR_API int yr_compiler_define_float_variable(
|
||||
YR_COMPILER* compiler,
|
||||
const char* identifier,
|
||||
double value);
|
||||
|
||||
|
||||
YR_API int yr_compiler_define_string_variable(
|
||||
YR_COMPILER* compiler,
|
||||
const char* identifier,
|
||||
const char* value);
|
||||
|
||||
|
||||
YR_API int yr_compiler_get_rules(
|
||||
YR_COMPILER* compiler,
|
||||
YR_RULES** rules);
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,202 @@
|
|||
/*
|
||||
Copyright (c) 2013. The YARA Authors. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _ELF_H
|
||||
#define _ELF_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
// 32-bit ELF base types
|
||||
|
||||
typedef uint32_t elf32_addr_t;
|
||||
typedef uint16_t elf32_half_t;
|
||||
typedef uint32_t elf32_off_t;
|
||||
typedef uint32_t elf32_word_t;
|
||||
|
||||
// 64-bit ELF base types
|
||||
|
||||
typedef uint64_t elf64_addr_t;
|
||||
typedef uint16_t elf64_half_t;
|
||||
typedef uint64_t elf64_off_t;
|
||||
typedef uint32_t elf64_word_t;
|
||||
typedef uint64_t elf64_xword_t;
|
||||
|
||||
#define ELF_MAGIC 0x464C457F
|
||||
|
||||
#define ELF_ET_NONE 0x0000 // no type
|
||||
#define ELF_ET_REL 0x0001 // relocatable
|
||||
#define ELF_ET_EXEC 0x0002 // executeable
|
||||
#define ELF_ET_DYN 0x0003 // Shared-Object-File
|
||||
#define ELF_ET_CORE 0x0004 // Corefile
|
||||
#define ELF_ET_LOPROC 0xFF00 // Processor-specific
|
||||
#define ELF_ET_HIPROC 0x00FF // Processor-specific
|
||||
|
||||
#define ELF_EM_NONE 0x0000 // no type
|
||||
#define ELF_EM_M32 0x0001 // AT&T WE 32100
|
||||
#define ELF_EM_SPARC 0x0002 // SPARC
|
||||
#define ELF_EM_386 0x0003 // Intel 80386
|
||||
#define ELF_EM_68K 0x0004 // Motorola 68000
|
||||
#define ELF_EM_88K 0x0005 // Motorola 88000
|
||||
#define ELF_EM_860 0x0007 // Intel 80860
|
||||
#define ELF_EM_MIPS 0x0008 // MIPS RS3000
|
||||
#define ELF_EM_ARM 0x0032 // ARM
|
||||
#define ELF_EM_X86_64 0x003E // AMD/Intel x86_64
|
||||
|
||||
#define ELF_CLASS_NONE 0x0000
|
||||
#define ELF_CLASS_32 0x0001 // 32bit file
|
||||
#define ELF_CLASS_64 0x0002 // 64bit file
|
||||
|
||||
#define ELF_DATA_NONE 0x0000
|
||||
#define ELF_DATA_2LSB 0x0001
|
||||
#define ELF_DATA_2MSB 0x002
|
||||
|
||||
|
||||
#define ELF_SHT_NULL 0 // Section header table entry unused
|
||||
#define ELF_SHT_PROGBITS 1 // Program data
|
||||
#define ELF_SHT_SYMTAB 2 // Symbol table
|
||||
#define ELF_SHT_STRTAB 3 // String table
|
||||
#define ELF_SHT_RELA 4 // Relocation entries with addends
|
||||
#define ELF_SHT_HASH 5 // Symbol hash table
|
||||
#define ELF_SHT_DYNAMIC 6 // Dynamic linking information
|
||||
#define ELF_SHT_NOTE 7 // Notes
|
||||
#define ELF_SHT_NOBITS 8 // Program space with no data (bss)
|
||||
#define ELF_SHT_REL 9 // Relocation entries, no addends
|
||||
#define ELF_SHT_SHLIB 10 // Reserved
|
||||
#define ELF_SHT_DYNSYM 11 // Dynamic linker symbol table
|
||||
#define ELF_SHT_NUM 12 // Number of defined types
|
||||
|
||||
#define ELF_SHF_WRITE 0x1 // Section is writable
|
||||
#define ELF_SHF_ALLOC 0x2 // Section is present during execution
|
||||
#define ELF_SHF_EXECINSTR 0x4 // Section contains executable instructions
|
||||
|
||||
#pragma pack(push,1)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t magic;
|
||||
uint8_t _class;
|
||||
uint8_t data;
|
||||
uint8_t version;
|
||||
uint8_t pad[8];
|
||||
uint8_t nident;
|
||||
|
||||
} elf_ident_t;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
elf_ident_t ident;
|
||||
elf32_half_t type;
|
||||
elf32_half_t machine;
|
||||
elf32_word_t version;
|
||||
elf32_addr_t entry;
|
||||
elf32_off_t ph_offset;
|
||||
elf32_off_t sh_offset;
|
||||
elf32_word_t flags;
|
||||
elf32_half_t header_size;
|
||||
elf32_half_t ph_entry_size;
|
||||
elf32_half_t ph_entry_count;
|
||||
elf32_half_t sh_entry_size;
|
||||
elf32_half_t sh_entry_count;
|
||||
elf32_half_t sh_str_table_index;
|
||||
|
||||
} elf32_header_t;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
elf_ident_t ident;
|
||||
elf64_half_t type;
|
||||
elf64_half_t machine;
|
||||
elf64_word_t version;
|
||||
elf64_addr_t entry;
|
||||
elf64_off_t ph_offset;
|
||||
elf64_off_t sh_offset;
|
||||
elf64_word_t flags;
|
||||
elf64_half_t header_size;
|
||||
elf64_half_t ph_entry_size;
|
||||
elf64_half_t ph_entry_count;
|
||||
elf64_half_t sh_entry_size;
|
||||
elf64_half_t sh_entry_count;
|
||||
elf64_half_t sh_str_table_index;
|
||||
|
||||
} elf64_header_t;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
elf32_word_t type;
|
||||
elf32_off_t offset;
|
||||
elf32_addr_t virt_addr;
|
||||
elf32_addr_t phys_addr;
|
||||
elf32_word_t file_size;
|
||||
elf32_word_t mem_size;
|
||||
elf32_word_t flags;
|
||||
elf32_word_t alignment;
|
||||
|
||||
} elf32_program_header_t;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
elf64_word_t type;
|
||||
elf64_word_t flags;
|
||||
elf64_off_t offset;
|
||||
elf64_addr_t virt_addr;
|
||||
elf64_addr_t phys_addr;
|
||||
elf64_xword_t file_size;
|
||||
elf64_xword_t mem_size;
|
||||
elf64_xword_t alignment;
|
||||
|
||||
} elf64_program_header_t;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
elf32_word_t name;
|
||||
elf32_word_t type;
|
||||
elf32_word_t flags;
|
||||
elf32_addr_t addr;
|
||||
elf32_off_t offset;
|
||||
elf32_word_t size;
|
||||
elf32_word_t link;
|
||||
elf32_word_t info;
|
||||
elf32_word_t align;
|
||||
elf32_word_t entry_size;
|
||||
|
||||
} elf32_section_header_t;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
elf64_word_t name;
|
||||
elf64_word_t type;
|
||||
elf64_xword_t flags;
|
||||
elf64_addr_t addr;
|
||||
elf64_off_t offset;
|
||||
elf64_xword_t size;
|
||||
elf64_word_t link;
|
||||
elf64_word_t info;
|
||||
elf64_xword_t align;
|
||||
elf64_xword_t entry_size;
|
||||
|
||||
} elf64_section_header_t;
|
||||
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
Copyright (c) 2014. The YARA Authors. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef YR_ERROR_H
|
||||
#define YR_ERROR_H
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#ifndef ERROR_SUCCESS
|
||||
#define ERROR_SUCCESS 0
|
||||
#endif
|
||||
|
||||
#define ERROR_INSUFICIENT_MEMORY 1
|
||||
#define ERROR_COULD_NOT_ATTACH_TO_PROCESS 2
|
||||
#define ERROR_COULD_NOT_OPEN_FILE 3
|
||||
#define ERROR_COULD_NOT_MAP_FILE 4
|
||||
#define ERROR_INVALID_FILE 6
|
||||
#define ERROR_CORRUPT_FILE 7
|
||||
#define ERROR_UNSUPPORTED_FILE_VERSION 8
|
||||
#define ERROR_INVALID_REGULAR_EXPRESSION 9
|
||||
#define ERROR_INVALID_HEX_STRING 10
|
||||
#define ERROR_SYNTAX_ERROR 11
|
||||
#define ERROR_LOOP_NESTING_LIMIT_EXCEEDED 12
|
||||
#define ERROR_DUPLICATED_LOOP_IDENTIFIER 13
|
||||
#define ERROR_DUPLICATED_IDENTIFIER 14
|
||||
#define ERROR_DUPLICATED_TAG_IDENTIFIER 15
|
||||
#define ERROR_DUPLICATED_META_IDENTIFIER 16
|
||||
#define ERROR_DUPLICATED_STRING_IDENTIFIER 17
|
||||
#define ERROR_UNREFERENCED_STRING 18
|
||||
#define ERROR_UNDEFINED_STRING 19
|
||||
#define ERROR_UNDEFINED_IDENTIFIER 20
|
||||
#define ERROR_MISPLACED_ANONYMOUS_STRING 21
|
||||
#define ERROR_INCLUDES_CIRCULAR_REFERENCE 22
|
||||
#define ERROR_INCLUDE_DEPTH_EXCEEDED 23
|
||||
#define ERROR_WRONG_TYPE 24
|
||||
#define ERROR_EXEC_STACK_OVERFLOW 25
|
||||
#define ERROR_SCAN_TIMEOUT 26
|
||||
#define ERROR_TOO_MANY_SCAN_THREADS 27
|
||||
#define ERROR_CALLBACK_ERROR 28
|
||||
#define ERROR_INVALID_ARGUMENT 29
|
||||
#define ERROR_TOO_MANY_MATCHES 30
|
||||
#define ERROR_INTERNAL_FATAL_ERROR 31
|
||||
#define ERROR_NESTED_FOR_OF_LOOP 32
|
||||
#define ERROR_INVALID_FIELD_NAME 33
|
||||
#define ERROR_UNKNOWN_MODULE 34
|
||||
#define ERROR_NOT_A_STRUCTURE 35
|
||||
#define ERROR_NOT_INDEXABLE 36
|
||||
#define ERROR_NOT_A_FUNCTION 37
|
||||
#define ERROR_INVALID_FORMAT 38
|
||||
#define ERROR_TOO_MANY_ARGUMENTS 39
|
||||
#define ERROR_WRONG_ARGUMENTS 40
|
||||
#define ERROR_WRONG_RETURN_TYPE 41
|
||||
#define ERROR_DUPLICATED_STRUCTURE_MEMBER 42
|
||||
|
||||
|
||||
#define FAIL_ON_ERROR(x) { \
|
||||
int result = (x); \
|
||||
if (result != ERROR_SUCCESS) \
|
||||
return result; \
|
||||
}
|
||||
|
||||
#define FAIL_ON_ERROR_WITH_CLEANUP(x, cleanup) { \
|
||||
int result = (x); \
|
||||
if (result != ERROR_SUCCESS) { \
|
||||
cleanup; \
|
||||
return result; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define FAIL_ON_COMPILER_ERROR(x) { \
|
||||
compiler->last_result = (x); \
|
||||
if (compiler->last_result != ERROR_SUCCESS) \
|
||||
return compiler->last_result; \
|
||||
}
|
||||
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define assertf(expr, msg) ((void)0)
|
||||
#else
|
||||
#define assertf(expr, msg, ...) \
|
||||
if(!(expr)) { \
|
||||
fprintf(stderr, "%s:%d: " msg "\n", __FILE__, __LINE__, ##__VA_ARGS__); \
|
||||
abort(); \
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
Copyright (c) 2013-2014. The YARA Authors. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef YR_EXEC_H
|
||||
#define YR_EXEC_H
|
||||
|
||||
#include "hash.h"
|
||||
#include "scan.h"
|
||||
#include "types.h"
|
||||
#include "rules.h"
|
||||
|
||||
|
||||
#define UNDEFINED 0xFFFABADAFABADAFFLL
|
||||
#define IS_UNDEFINED(x) ((size_t)(x) == (size_t) UNDEFINED)
|
||||
|
||||
#define OP_ERROR 0
|
||||
#define OP_HALT 255
|
||||
|
||||
#define OP_AND 1
|
||||
#define OP_OR 2
|
||||
#define OP_NOT 3
|
||||
#define OP_BITWISE_NOT 4
|
||||
#define OP_BITWISE_AND 5
|
||||
#define OP_BITWISE_OR 6
|
||||
#define OP_BITWISE_XOR 7
|
||||
#define OP_SHL 8
|
||||
#define OP_SHR 9
|
||||
#define OP_MOD 10
|
||||
#define OP_INT_TO_DBL 11
|
||||
#define OP_STR_TO_BOOL 12
|
||||
#define OP_PUSH 13
|
||||
#define OP_POP 14
|
||||
#define OP_CALL 15
|
||||
#define OP_OBJ_LOAD 16
|
||||
#define OP_OBJ_VALUE 17
|
||||
#define OP_OBJ_FIELD 18
|
||||
#define OP_INDEX_ARRAY 19
|
||||
#define OP_COUNT 20
|
||||
#define OP_FOUND 21
|
||||
#define OP_FOUND_AT 22
|
||||
#define OP_FOUND_IN 23
|
||||
#define OP_OFFSET 24
|
||||
#define OP_OF 25
|
||||
#define OP_PUSH_RULE 26
|
||||
#define OP_MATCH_RULE 27
|
||||
#define OP_INCR_M 28
|
||||
#define OP_CLEAR_M 29
|
||||
#define OP_ADD_M 30
|
||||
#define OP_POP_M 31
|
||||
#define OP_PUSH_M 32
|
||||
#define OP_SWAPUNDEF 33
|
||||
#define OP_JNUNDEF 34
|
||||
#define OP_JLE 35
|
||||
#define OP_FILESIZE 36
|
||||
#define OP_ENTRYPOINT 37
|
||||
#define OP_CONTAINS 38
|
||||
#define OP_MATCHES 39
|
||||
#define OP_IMPORT 40
|
||||
#define OP_LOOKUP_DICT 41
|
||||
|
||||
#define _OP_EQ 0
|
||||
#define _OP_NEQ 1
|
||||
#define _OP_LT 2
|
||||
#define _OP_GT 3
|
||||
#define _OP_LE 4
|
||||
#define _OP_GE 5
|
||||
#define _OP_ADD 6
|
||||
#define _OP_SUB 7
|
||||
#define _OP_MUL 8
|
||||
#define _OP_DIV 9
|
||||
#define _OP_MINUS 10
|
||||
|
||||
#define OP_INT_BEGIN 100
|
||||
#define OP_INT_EQ (OP_INT_BEGIN + _OP_EQ)
|
||||
#define OP_INT_NEQ (OP_INT_BEGIN + _OP_NEQ)
|
||||
#define OP_INT_LT (OP_INT_BEGIN + _OP_LT)
|
||||
#define OP_INT_GT (OP_INT_BEGIN + _OP_GT)
|
||||
#define OP_INT_LE (OP_INT_BEGIN + _OP_LE)
|
||||
#define OP_INT_GE (OP_INT_BEGIN + _OP_GE)
|
||||
#define OP_INT_ADD (OP_INT_BEGIN + _OP_ADD)
|
||||
#define OP_INT_SUB (OP_INT_BEGIN + _OP_SUB)
|
||||
#define OP_INT_MUL (OP_INT_BEGIN + _OP_MUL)
|
||||
#define OP_INT_DIV (OP_INT_BEGIN + _OP_DIV)
|
||||
#define OP_INT_MINUS (OP_INT_BEGIN + _OP_MINUS)
|
||||
#define OP_INT_END OP_INT_MINUS
|
||||
|
||||
#define OP_DBL_BEGIN 120
|
||||
#define OP_DBL_EQ (OP_DBL_BEGIN + _OP_EQ)
|
||||
#define OP_DBL_NEQ (OP_DBL_BEGIN + _OP_NEQ)
|
||||
#define OP_DBL_LT (OP_DBL_BEGIN + _OP_LT)
|
||||
#define OP_DBL_GT (OP_DBL_BEGIN + _OP_GT)
|
||||
#define OP_DBL_LE (OP_DBL_BEGIN + _OP_LE)
|
||||
#define OP_DBL_GE (OP_DBL_BEGIN + _OP_GE)
|
||||
#define OP_DBL_ADD (OP_DBL_BEGIN + _OP_ADD)
|
||||
#define OP_DBL_SUB (OP_DBL_BEGIN + _OP_SUB)
|
||||
#define OP_DBL_MUL (OP_DBL_BEGIN + _OP_MUL)
|
||||
#define OP_DBL_DIV (OP_DBL_BEGIN + _OP_DIV)
|
||||
#define OP_DBL_MINUS (OP_DBL_BEGIN + _OP_MINUS)
|
||||
#define OP_DBL_END OP_DBL_MINUS
|
||||
|
||||
#define OP_STR_BEGIN 140
|
||||
#define OP_STR_EQ (OP_STR_BEGIN + _OP_EQ)
|
||||
#define OP_STR_NEQ (OP_STR_BEGIN + _OP_NEQ)
|
||||
#define OP_STR_LT (OP_STR_BEGIN + _OP_LT)
|
||||
#define OP_STR_GT (OP_STR_BEGIN + _OP_GT)
|
||||
#define OP_STR_LE (OP_STR_BEGIN + _OP_LE)
|
||||
#define OP_STR_GE (OP_STR_BEGIN + _OP_GE)
|
||||
#define OP_STR_END OP_STR_GE
|
||||
|
||||
#define IS_INT_OP(x) ((x) >= OP_INT_BEGIN && (x) <= OP_INT_END)
|
||||
#define IS_DBL_OP(x) ((x) >= OP_DBL_BEGIN && (x) <= OP_DBL_END)
|
||||
#define IS_STR_OP(x) ((x) >= OP_STR_BEGIN && (x) <= OP_STR_END)
|
||||
|
||||
#define OP_READ_INT 240
|
||||
#define OP_INT8 (OP_READ_INT + 0)
|
||||
#define OP_INT16 (OP_READ_INT + 1)
|
||||
#define OP_INT32 (OP_READ_INT + 2)
|
||||
#define OP_UINT8 (OP_READ_INT + 3)
|
||||
#define OP_UINT16 (OP_READ_INT + 4)
|
||||
#define OP_UINT32 (OP_READ_INT + 5)
|
||||
#define OP_INT8BE (OP_READ_INT + 6)
|
||||
#define OP_INT16BE (OP_READ_INT + 7)
|
||||
#define OP_INT32BE (OP_READ_INT + 8)
|
||||
#define OP_UINT8BE (OP_READ_INT + 9)
|
||||
#define OP_UINT16BE (OP_READ_INT + 10)
|
||||
#define OP_UINT32BE (OP_READ_INT + 11)
|
||||
|
||||
|
||||
#define OPERATION(operator, op1, op2) \
|
||||
(IS_UNDEFINED(op1) || IS_UNDEFINED(op2)) ? (UNDEFINED) : (op1 operator op2)
|
||||
|
||||
|
||||
#define COMPARISON(operator, op1, op2) \
|
||||
(IS_UNDEFINED(op1) || IS_UNDEFINED(op2)) ? (0) : (op1 operator op2)
|
||||
|
||||
|
||||
int yr_execute_code(
|
||||
YR_RULES* rules,
|
||||
YR_SCAN_CONTEXT* context,
|
||||
int timeout,
|
||||
time_t start_time);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
Copyright (c) 2007. The YARA Authors. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef YR_EXEFILES_H
|
||||
#define YR_EXEFILES_H
|
||||
|
||||
uint64_t yr_get_entry_point_offset(
|
||||
uint8_t* buffer,
|
||||
size_t buffer_length);
|
||||
|
||||
|
||||
uint64_t yr_get_entry_point_address(
|
||||
uint8_t* buffer,
|
||||
size_t buffer_length,
|
||||
size_t base_address);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
Copyright (c) 2007-2015. The YARA Authors. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef YR_FILEMAP_H
|
||||
#define YR_FILEMAP_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#define FILE_DESCRIPTOR HANDLE
|
||||
#define off_t int64_t
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#define FILE_DESCRIPTOR int
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
|
||||
typedef struct _YR_MAPPED_FILE
|
||||
{
|
||||
FILE_DESCRIPTOR file;
|
||||
size_t size;
|
||||
uint8_t* data;
|
||||
#ifdef _WIN32
|
||||
HANDLE mapping;
|
||||
#endif
|
||||
|
||||
} YR_MAPPED_FILE;
|
||||
|
||||
|
||||
YR_API int yr_filemap_map(
|
||||
const char* file_path,
|
||||
YR_MAPPED_FILE* pmapped_file);
|
||||
|
||||
|
||||
YR_API int yr_filemap_map_ex(
|
||||
const char* file_path,
|
||||
off_t offset,
|
||||
size_t size,
|
||||
YR_MAPPED_FILE* pmapped_file);
|
||||
|
||||
|
||||
YR_API void yr_filemap_unmap(
|
||||
YR_MAPPED_FILE* pmapped_file);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
Copyright (c) 2014. The YARA Authors. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef YR_GLOBALS_H
|
||||
#define YR_GLOBALS_H
|
||||
|
||||
extern char lowercase[256];
|
||||
extern char altercase[256];
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
Copyright (c) 2013. The YARA Authors. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef YR_HASH_H
|
||||
#define YR_HASH_H
|
||||
|
||||
|
||||
typedef struct _YR_HASH_TABLE_ENTRY
|
||||
{
|
||||
char* key;
|
||||
char* ns;
|
||||
void* value;
|
||||
|
||||
struct _YR_HASH_TABLE_ENTRY* next;
|
||||
|
||||
} YR_HASH_TABLE_ENTRY;
|
||||
|
||||
|
||||
typedef struct _YR_HASH_TABLE
|
||||
{
|
||||
int size;
|
||||
|
||||
YR_HASH_TABLE_ENTRY* buckets[1];
|
||||
|
||||
} YR_HASH_TABLE;
|
||||
|
||||
|
||||
typedef int (*YR_HASH_TABLE_FREE_VALUE_FUNC)(void* value);
|
||||
|
||||
|
||||
int yr_hash_table_create(
|
||||
int size,
|
||||
YR_HASH_TABLE** table);
|
||||
|
||||
|
||||
void yr_hash_table_destroy(
|
||||
YR_HASH_TABLE* table,
|
||||
YR_HASH_TABLE_FREE_VALUE_FUNC free_value);
|
||||
|
||||
|
||||
void* yr_hash_table_lookup(
|
||||
YR_HASH_TABLE* table,
|
||||
const char* key,
|
||||
const char* ns);
|
||||
|
||||
|
||||
int yr_hash_table_add(
|
||||
YR_HASH_TABLE* table,
|
||||
const char* key,
|
||||
const char* ns,
|
||||
void* value);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
Copyright (c) 2007. Victor M. Alvarez [plusvic@gmail.com].
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include "re.h"
|
||||
|
||||
#undef yyparse
|
||||
#undef yylex
|
||||
#undef yyerror
|
||||
#undef yyfatal
|
||||
#undef yychar
|
||||
#undef yydebug
|
||||
#undef yynerrs
|
||||
#undef yyget_extra
|
||||
#undef yyget_lineno
|
||||
|
||||
#undef YY_FATAL_ERROR
|
||||
#undef YY_DECL
|
||||
#undef LEX_ENV
|
||||
|
||||
#define yyparse hex_yyparse
|
||||
#define yylex hex_yylex
|
||||
#define yyerror hex_yyerror
|
||||
#define yyfatal hex_yyfatal
|
||||
#define yychar hex_yychar
|
||||
#define yydebug hex_yydebug
|
||||
#define yynerrs hex_yynerrs
|
||||
#define yyget_extra hex_yyget_extra
|
||||
#define yyget_lineno hex_yyget_lineno
|
||||
|
||||
|
||||
#ifndef YY_TYPEDEF_YY_SCANNER_T
|
||||
#define YY_TYPEDEF_YY_SCANNER_T
|
||||
typedef void* yyscan_t;
|
||||
#endif
|
||||
|
||||
#define YY_EXTRA_TYPE RE*
|
||||
#define YY_USE_CONST
|
||||
|
||||
|
||||
typedef struct _HEX_LEX_ENVIRONMENT
|
||||
{
|
||||
int token_count;
|
||||
int inside_or;
|
||||
int last_error_code;
|
||||
char last_error_message[256];
|
||||
|
||||
} HEX_LEX_ENVIRONMENT;
|
||||
|
||||
|
||||
#define YY_FATAL_ERROR(msg) hex_yyfatal(yyscanner, msg)
|
||||
|
||||
#define LEX_ENV ((HEX_LEX_ENVIRONMENT*) lex_env)
|
||||
|
||||
#include <hex_grammar.h>
|
||||
|
||||
#define YY_DECL int hex_yylex \
|
||||
(YYSTYPE * yylval_param , yyscan_t yyscanner, HEX_LEX_ENVIRONMENT* lex_env)
|
||||
|
||||
|
||||
YY_EXTRA_TYPE yyget_extra(
|
||||
yyscan_t yyscanner);
|
||||
|
||||
int yylex(
|
||||
YYSTYPE* yylval_param,
|
||||
yyscan_t yyscanner,
|
||||
HEX_LEX_ENVIRONMENT* lex_env);
|
||||
|
||||
int yyparse(
|
||||
void* yyscanner,
|
||||
HEX_LEX_ENVIRONMENT* lex_env);
|
||||
|
||||
void yyerror(
|
||||
yyscan_t yyscanner,
|
||||
HEX_LEX_ENVIRONMENT* lex_env,
|
||||
const char* error_message);
|
||||
|
||||
void yyfatal(
|
||||
yyscan_t yyscanner,
|
||||
const char* error_message);
|
||||
|
||||
int yr_parse_hex_string(
|
||||
const char* hex_string,
|
||||
int flags,
|
||||
RE** re,
|
||||
RE_ERROR* error);
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
Copyright (c) 2007. Victor M. Alvarez [plusvic@gmail.com].
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include "compiler.h"
|
||||
|
||||
|
||||
#undef yyparse
|
||||
#undef yylex
|
||||
#undef yyerror
|
||||
#undef yyfatal
|
||||
#undef yychar
|
||||
#undef yydebug
|
||||
#undef yynerrs
|
||||
#undef yyget_extra
|
||||
#undef yyget_lineno
|
||||
|
||||
#undef YY_DECL
|
||||
#undef YY_FATAL_ERROR
|
||||
#undef YY_EXTRA_TYPE
|
||||
|
||||
#define yyparse yara_yyparse
|
||||
#define yylex yara_yylex
|
||||
#define yyerror yara_yyerror
|
||||
#define yyfatal yara_yyfatal
|
||||
#define yywarning yara_yywarning
|
||||
#define yychar yara_yychar
|
||||
#define yydebug yara_yydebug
|
||||
#define yynerrs yara_yynerrs
|
||||
#define yyget_extra yara_yyget_extra
|
||||
#define yyget_lineno yara_yyget_lineno
|
||||
|
||||
|
||||
#ifndef YY_TYPEDEF_YY_SCANNER_T
|
||||
#define YY_TYPEDEF_YY_SCANNER_T
|
||||
typedef void* yyscan_t;
|
||||
#endif
|
||||
|
||||
#ifndef YY_TYPEDEF_EXPRESSION_T
|
||||
#define YY_TYPEDEF_EXPRESSION_T
|
||||
|
||||
|
||||
// Expression type constants are powers of two because they are used as flags.
|
||||
// For example:
|
||||
// CHECK_TYPE(whatever, EXPRESSION_TYPE_INTEGER | EXPRESSION_TYPE_FLOAT)
|
||||
// The expression above is used to ensure that the type of "whatever" is either
|
||||
// integer or float.
|
||||
|
||||
#define EXPRESSION_TYPE_BOOLEAN 1
|
||||
#define EXPRESSION_TYPE_INTEGER 2
|
||||
#define EXPRESSION_TYPE_STRING 4
|
||||
#define EXPRESSION_TYPE_REGEXP 8
|
||||
#define EXPRESSION_TYPE_OBJECT 16
|
||||
#define EXPRESSION_TYPE_FLOAT 32
|
||||
|
||||
typedef struct _EXPRESSION
|
||||
{
|
||||
int type;
|
||||
|
||||
union
|
||||
{
|
||||
int64_t integer;
|
||||
YR_OBJECT* object;
|
||||
} value;
|
||||
|
||||
const char* identifier;
|
||||
|
||||
} EXPRESSION;
|
||||
|
||||
union YYSTYPE;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#define YY_DECL int yylex( \
|
||||
union YYSTYPE* yylval_param, yyscan_t yyscanner, YR_COMPILER* compiler)
|
||||
|
||||
|
||||
#define YY_FATAL_ERROR(msg) yara_yyfatal(yyscanner, msg)
|
||||
|
||||
|
||||
#define YY_EXTRA_TYPE YR_COMPILER*
|
||||
#define YY_USE_CONST
|
||||
|
||||
|
||||
int yyget_lineno(yyscan_t yyscanner);
|
||||
|
||||
int yylex(
|
||||
union YYSTYPE* yylval_param,
|
||||
yyscan_t yyscanner,
|
||||
YR_COMPILER* compiler);
|
||||
|
||||
int yyparse(
|
||||
void* yyscanner,
|
||||
YR_COMPILER* compiler);
|
||||
|
||||
void yyerror(
|
||||
yyscan_t yyscanner,
|
||||
YR_COMPILER* compiler,
|
||||
const char* error_message);
|
||||
|
||||
void yywarning(
|
||||
yyscan_t yyscanner,
|
||||
const char* warning_message);
|
||||
|
||||
void yyfatal(
|
||||
yyscan_t yyscanner,
|
||||
const char* error_message);
|
||||
|
||||
YY_EXTRA_TYPE yyget_extra(
|
||||
yyscan_t yyscanner);
|
||||
|
||||
int yr_lex_parse_rules_string(
|
||||
const char* rules_string,
|
||||
YR_COMPILER* compiler);
|
||||
|
||||
int yr_lex_parse_rules_file(
|
||||
FILE* rules_file,
|
||||
YR_COMPILER* compiler);
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
Copyright (c) 2014. The YARA Authors. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef YR_LIBYARA_H
|
||||
#define YR_LIBYARA_H
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
#define YR_MAJOR_VERSION 3
|
||||
#define YR_MINOR_VERSION 3
|
||||
#define YR_MICRO_VERSION 0
|
||||
|
||||
// Version as a string
|
||||
#define YR_VERSION "3.3.0"
|
||||
|
||||
// Version as a single 4-byte hex number, e.g. 0x030401 == 3.4.1.
|
||||
#define YR_VERSION_HEX ((YR_MAJOR_VERSION << 16) | \
|
||||
(YR_MINOR_VERSION << 8) | \
|
||||
(YR_MICRO_VERSION << 0)
|
||||
|
||||
|
||||
YR_API int yr_initialize(void);
|
||||
|
||||
|
||||
YR_API int yr_finalize(void);
|
||||
|
||||
|
||||
YR_API void yr_finalize_thread(void);
|
||||
|
||||
|
||||
YR_API int yr_get_tidx(void);
|
||||
|
||||
|
||||
YR_API void yr_set_tidx(int);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
Copyright (c) 2013. The YARA Authors. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef YR_LIMITS_H
|
||||
#define YR_LIMITS_H
|
||||
|
||||
|
||||
// MAX_THREADS is the number of threads that can use a YR_RULES
|
||||
// object simultaneosly. This value is limited by the number of
|
||||
// bits in tidx_mask.
|
||||
|
||||
#define MAX_THREADS 32
|
||||
|
||||
|
||||
#ifndef MAX_PATH
|
||||
#define MAX_PATH 1024
|
||||
#endif
|
||||
|
||||
#define MAX_COMPILER_ERROR_EXTRA_INFO 256
|
||||
#define MAX_ATOM_LENGTH 4
|
||||
#define MAX_LOOP_NESTING 4
|
||||
#define MAX_ARENA_PAGES 32
|
||||
#define MAX_INCLUDE_DEPTH 16
|
||||
#define MAX_STRING_MATCHES 1000000
|
||||
#define MAX_FUNCTION_ARGS 128
|
||||
#define MAX_FAST_HEX_RE_STACK 300
|
||||
#define MAX_OVERLOADED_FUNCTIONS 10
|
||||
#define MAX_HEX_STRING_TOKENS 10000
|
||||
|
||||
#define LOOP_LOCAL_VARS 4
|
||||
#define STRING_CHAINING_THRESHOLD 200
|
||||
#define LEX_BUF_SIZE 1024
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
Copyright (c) 2007. The YARA Authors. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef YR_MEM_H
|
||||
#define YR_MEM_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef DMALLOC
|
||||
|
||||
#define yr_malloc malloc
|
||||
#define yr_calloc calloc
|
||||
#define yr_realloc realloc
|
||||
#define yr_free free
|
||||
#define yr_strdup strdup
|
||||
#define yr_strndup strndup
|
||||
|
||||
#include <dmalloc.h>
|
||||
|
||||
#else
|
||||
|
||||
void* yr_calloc(
|
||||
size_t count,
|
||||
size_t size);
|
||||
|
||||
void* yr_malloc(
|
||||
size_t size);
|
||||
|
||||
void* yr_realloc(
|
||||
void* ptr,
|
||||
size_t size);
|
||||
|
||||
void yr_free(
|
||||
void* ptr);
|
||||
|
||||
char* yr_strdup(
|
||||
const char* str);
|
||||
|
||||
char* yr_strndup(
|
||||
const char* str, size_t n);
|
||||
|
||||
#endif
|
||||
|
||||
int yr_heap_alloc();
|
||||
|
||||
int yr_heap_free();
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue