1
0
Fork 0

Merged in Nukem9/x64_dbg/master (pull request #47)

PR (second try)
This commit is contained in:
mrexodia 2015-04-05 22:23:08 +02:00
commit 4eabd557af
163 changed files with 11226 additions and 1902 deletions

10
.gitignore vendored
View File

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

2366
Doxyfile Normal file

File diff suppressed because it is too large Load Diff

View File

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

BIN
bug.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

View File

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

93
rpm.cpp Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,13 +0,0 @@
#include "log.h"
#include "_global.h"
log::log(void)
{
}
log::~log(void)
{
GuiAddLogMessage(message.str().c_str());
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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, &regionSize, 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;
}

View File

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

View File

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

View File

@ -1,3 +1,9 @@
/**
@file stackinfo.cpp
@brief Implements the stackinfo class.
*/
#include "stackinfo.h"
#include "debugger.h"
#include "memory.h"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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] = "";

View File

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

View File

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

View File

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

View File

@ -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] = "";

View File

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

View File

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

28
x64_dbg_dbg/yara/yara.h Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

202
x64_dbg_dbg/yara/yara/elf.h Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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