Merge branch 'master' into capstone
Conflicts: x64_dbg_dbg/instruction.cpp x64_dbg_dbg/log.cpp x64_dbg_dbg/x64_dbg.cpp x64_dbg_dbg/x64_dbg_dbg.vcxproj x64_dbg_dbg/x64_dbg_dbg.vcxproj.filters
This commit is contained in:
commit
cab3ebf263
|
@ -8,11 +8,13 @@ release/
|
|||
build/
|
||||
debug/
|
||||
*XE Results*/
|
||||
doxygen*/
|
||||
doc/
|
||||
|
||||
#global filetypes to ignore
|
||||
*.depend
|
||||
*.layout
|
||||
*.patch
|
||||
*.patch
|
||||
*.cscope_file_list
|
||||
*.bmarks
|
||||
*.chw
|
||||
|
@ -27,7 +29,6 @@ debug/
|
|||
*.exe
|
||||
*.pro.user.*
|
||||
*.orig
|
||||
coverity*
|
||||
cov-int*
|
||||
COV/
|
||||
*.pdb
|
||||
|
@ -35,7 +36,7 @@ ui_*
|
|||
|
||||
#project to ignore
|
||||
todo_bridge.txt
|
||||
help/x64_dbg.chm
|
||||
help/x64*dbg.chm
|
||||
help/output/
|
||||
|
||||
#debugger files to ignore
|
||||
|
@ -57,14 +58,20 @@ x64_dbg_gui/Project/x64/
|
|||
x64_dbg_gui/Project/Makefile
|
||||
x64_dbg_gui/Project/Makefile.Debug
|
||||
x64_dbg_gui/Project/Makefile.Release
|
||||
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/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
|
4
LICENSE
4
LICENSE
|
@ -156,8 +156,8 @@ same work.
|
|||
2. Treatment of plugins
|
||||
|
||||
This license does not affect plugins, i.e., dynamically linked
|
||||
libraries, that use the provided plugin interface mechanism of x64_dbg
|
||||
for contibuting additional features to the x64_dbg project and can only
|
||||
libraries, that use the provided plugin interface mechanism of x64dbg
|
||||
for contibuting additional features to the x64dbg project and can only
|
||||
be run from x64dbg. In fact you are allowed to create and share
|
||||
(non-)commercial, non-standalone closed-source plugins for x64dbg under
|
||||
your own license.
|
||||
|
|
22
README.md
22
README.md
|
@ -1,20 +1,18 @@
|
|||
# x64_dbg
|
||||
# x64dbg
|
||||
|
||||
## 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 *x64dbg* [standards](https://github.com/x64dbg/x64dbg/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).
|
||||
For a complete guide on compiling *x64dbg* read [this](https://github.com/x64dbg/x64dbg/wiki/Compiling the whole project).
|
||||
|
||||
## Downloads
|
||||
Releases of *x64_dbg* can be found [here](http://download.x64dbg.com).
|
||||
Snapshots of *x64_dbg* can be found [here](http://snapshots.x64dbg.com).
|
||||
Releases of *x64dbg* can be found [here](http://download.x64dbg.com).
|
||||
Snapshots of *x64dbg* can be found [here](http://snapshots.x64dbg.com).
|
||||
Jenkins build server can be found [here](http://jenkins.x64dbg.com).
|
||||
|
||||
## Overview
|
||||
*x64_dbg* is an open-source x32/x64 debugger for Windows.
|
||||
*x64dbg* is an open-source x32/x64 debugger for Windows.
|
||||
|
||||
## Features
|
||||
- Open-source
|
||||
|
@ -26,6 +24,7 @@ Jenkins build server can be found [here](http://jenkins.x64dbg.com).
|
|||
- Memory map
|
||||
- Symbol view
|
||||
- Thread view
|
||||
- Source code view
|
||||
- Content-sensitive register view
|
||||
- Fully customizable color scheme
|
||||
- Dynamically recognize modules and strings
|
||||
|
@ -38,12 +37,13 @@ Jenkins build server can be found [here](http://jenkins.x64dbg.com).
|
|||
- Basic debug symbol (PDB) support
|
||||
- Dynamic stack view
|
||||
- Built-in assembler (XEDParse)
|
||||
- Executable patching
|
||||
|
||||
## Known bugs
|
||||
- Memory breakpoints sometimes fail (TitanEngine bug)
|
||||
|
||||
## License
|
||||
*x64_dbg* is licensed under GLPv3, which means you can freely distribute and/or modify the source of *x64_dbg*, as long as you share your changes with us. The only exception is that plugins you write do not have to comply with the GLPv3 license. They do not have to be open-source and they can be commercial and/or private. The only exception to this is when your plugin uses code copied from *x64_dbg*. In that case you would still have to share the changes to *x64_dbg* with us.
|
||||
*x64dbg* is licensed under GLPv3, which means you can freely distribute and/or modify the source of *x64dbg*, as long as you share your changes with us. The only exception is that plugins you write do not have to comply with the GLPv3 license. They do not have to be open-source and they can be commercial and/or private. The only exception to this is when your plugin uses code copied from *x64dbg*. In that case you would still have to share the changes to *x64dbg* with us.
|
||||
|
||||
## Credits
|
||||
- Debugger core by [TitanEngine Community Edition](https://bitbucket.org/mrexodia/titanengine-update)
|
||||
|
@ -65,11 +65,11 @@ Jenkins build server can be found [here](http://jenkins.x64dbg.com).
|
|||
- TEAM DVT
|
||||
- DMichael
|
||||
- Artic
|
||||
- Nukem
|
||||
- ahmadmansoor
|
||||
|
||||
## Developers (in order of joining)
|
||||
- [Mr. eXoDia](http://mrexodia.cf)
|
||||
- Sigma
|
||||
- [tr4ceflow](http://blog.tr4ceflow.com)
|
||||
- [Dreg](http://www.fr33project.org)
|
||||
- [Dreg](http://www.fr33project.org)
|
||||
- Nukem
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
@echo off
|
||||
|
||||
echo Saving PATH
|
||||
if "%OLDPATH%"=="" set OLDPATH=%PATH%
|
||||
|
||||
if "%1"=="x32" (
|
||||
call setenv.bat x32
|
||||
set type=Win32
|
||||
goto build
|
||||
) else if "%1"=="x64" (
|
||||
call setenv.bat x64
|
||||
set type=x64
|
||||
goto build
|
||||
) else if "%1"=="coverity" (
|
||||
if "%2"=="" (
|
||||
echo "usage: build.bat coverity x32/x64"
|
||||
goto :eof
|
||||
)
|
||||
goto coverity
|
||||
) else if "%1"=="doxygen" (
|
||||
goto doxygen
|
||||
) else if "%1"=="chm" (
|
||||
goto chm
|
||||
) else (
|
||||
echo "usage: build.bat x32/x64/coverity/doxygen/chm"
|
||||
goto :eof
|
||||
)
|
||||
|
||||
:build
|
||||
echo Building DBG...
|
||||
devenv /Rebuild "Release|%type%" x64_dbg.sln
|
||||
|
||||
echo GUI prebuildStep
|
||||
cd x64_dbg_gui\Project
|
||||
cmd /k "prebuildStep.bat %1"
|
||||
cd ..
|
||||
cd ..
|
||||
|
||||
echo Building GUI...
|
||||
rmdir /S /Q build
|
||||
mkdir build
|
||||
cd build
|
||||
qmake ..\x64_dbg_gui\Project\x64_dbg.pro CONFIG+=release
|
||||
jom
|
||||
cd ..
|
||||
|
||||
echo GUI afterbuildStep
|
||||
cd x64_dbg_gui\Project
|
||||
call afterbuildStep.bat %1 ..\..\build\release
|
||||
cd ..
|
||||
cd ..
|
||||
goto restorepath
|
||||
|
||||
:coverity
|
||||
call setenv.bat coverity
|
||||
echo Building with Coverity
|
||||
cov-configure --msvc
|
||||
cov-build --dir cov-int --instrument build.bat %2%
|
||||
goto restorepath
|
||||
|
||||
:doxygen
|
||||
call setenv.bat doxygen
|
||||
doxygen
|
||||
goto restorepath
|
||||
|
||||
:chm
|
||||
call setenv.bat chm
|
||||
start /w "" winchm.exe help\x64_dbg.wcp /h
|
||||
goto restorepath
|
||||
|
||||
:restorepath
|
||||
echo Resetting PATH
|
||||
set PATH=%OLDPATH%
|
||||
set OLDPATH=
|
24
clean.bat
24
clean.bat
|
@ -40,10 +40,10 @@ rmdir /S /Q Project\release
|
|||
rmdir /S /Q Project\debug
|
||||
rmdir /S /Q Project\Win32
|
||||
rmdir /S /Q Project\x64
|
||||
del /Q Project\Src\Bridge\libx32_bridge.a
|
||||
del /Q Project\Src\Bridge\libx64_bridge.a
|
||||
del /Q Project\Src\Bridge\x32_bridge.lib
|
||||
del /Q Project\Src\Bridge\x64_bridge.lib
|
||||
del /Q Project\Src\Bridge\libx32bridge.a
|
||||
del /Q Project\Src\Bridge\libx64bridge.a
|
||||
del /Q Project\Src\Bridge\x32bridge.lib
|
||||
del /Q Project\Src\Bridge\x64bridge.lib
|
||||
cd ..
|
||||
echo cleaning bin\
|
||||
del /Q bin\*.pdb
|
||||
|
@ -59,10 +59,10 @@ del /Q bin\x32\*.exp
|
|||
del /Q bin\x32\*.a
|
||||
del /Q bin\x32\*.lib
|
||||
del /Q bin\x32\*.def
|
||||
del /Q bin\x32\x32_dbg.exe
|
||||
del /Q bin\x32\x32_dbg.dll
|
||||
del /Q bin\x32\x32_gui.dll
|
||||
del /Q bin\x32\x32_bridge.dll
|
||||
del /Q bin\x32\x32dbg.exe
|
||||
del /Q bin\x32\x32dbg.dll
|
||||
del /Q bin\x32\x32gui.dll
|
||||
del /Q bin\x32\x32bridge.dll
|
||||
echo cleaning bin\x64...
|
||||
rmdir /S /Q bin\x64\db
|
||||
del /Q bin\x64\*.pdb
|
||||
|
@ -70,10 +70,10 @@ del /Q bin\x64\*.exp
|
|||
del /Q bin\x64\*.a
|
||||
del /Q bin\x64\*.lib
|
||||
del /Q bin\x64\*.def
|
||||
del /Q bin\x64\x64_dbg.exe
|
||||
del /Q bin\x64\x64_dbg.dll
|
||||
del /Q bin\x64\x64_gui.dll
|
||||
del /Q bin\x64\x64_bridge.dll
|
||||
del /Q bin\x64\x64dbg.exe
|
||||
del /Q bin\x64\x64dbg.dll
|
||||
del /Q bin\x64\x64gui.dll
|
||||
del /Q bin\x64\x64bridge.dll
|
||||
echo cleaning help...
|
||||
cd help
|
||||
del /Q *.chm
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
# this file is only for the people who have serious mental issues (USE WITH CAUTION, THIS DOESN'T WORK)
|
||||
/\s*([\^+\-*=&|<>\/%!]|<<|>>)?\s*=\s*/ -> / \1= /
|
|
@ -20,7 +20,7 @@ breakpoint on DLL load/unload.</P>
|
|||
<P><U>arguments</U><BR> arg1: DLL Name to break
|
||||
on.</P>
|
||||
<P>[arg2]: 'l' means on load, 'u' means on unload. When not
|
||||
specified, x64_dbg will break on both load and unload.</P>
|
||||
specified, x64dbg will break on both load and unload.</P>
|
||||
<P>[arg3]: When specified, the breakpoint will not be singleshoot. When not specified the
|
||||
breakpoint will be removed after it has been hit.</P>
|
||||
<P><U>result<BR></U>This command does not set any result
|
||||
|
|
|
@ -12,18 +12,24 @@ html,body {
|
|||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
</head>
|
||||
|
||||
|
||||
<body>
|
||||
<P><STRONG>plugsetup</STRONG><BR>This structure is used by the function that allows the
|
||||
creation of plugin menu entries:</P>
|
||||
<P>
|
||||
struct <STRONG>PLUG_SETUPSTRUCT</STRONG>
|
||||
<BR>{<BR> <EM>//data provided by the debugger to
|
||||
the plugin.</EM>
|
||||
<BR> [IN] <STRONG>HWND</STRONG> hwndDlg; //GUI window
|
||||
handle<BR> [IN]
|
||||
<STRONG>int</STRONG> hMenu; //plugin menu
|
||||
handle<BR>
|
||||
|
||||
<body>
|
||||
<P><STRONG>plugsetup</STRONG><BR>This structure is used by the function that allows the
|
||||
creation of plugin menu entries:</P>
|
||||
<P>
|
||||
struct <STRONG>PLUG_SETUPSTRUCT</STRONG>
|
||||
<BR>{<BR> <EM>//data provided by the debugger to
|
||||
the plugin.</EM>
|
||||
<BR> [IN] <STRONG>HWND</STRONG> hwndDlg; //GUI window
|
||||
handle<BR> [IN]
|
||||
<STRONG>int</STRONG> hMenu; //plugin menu
|
||||
handle<BR> [IN] <STRONG>int</STRONG> hMenuDisasm;
|
||||
//plugin disasm menu handle<BR> [IN] <STRONG>int</STRONG>
|
||||
hMenuDump; //plugin dump menu handle<BR> [IN]
|
||||
<STRONG>int</STRONG> hMenuStack; //plugin stack menu
|
||||
handle<BR>
|
||||
};</P></body>
|
||||
</html>
|
||||
|
|
|
@ -16,7 +16,7 @@ html,body {
|
|||
|
||||
<body>
|
||||
<P><STRONG>Plugins<BR></STRONG>This section describes
|
||||
various plugin functions for x64_dbg.</P>
|
||||
various plugin functions for x64dbg.</P>
|
||||
<P>You can install plugins by copying the *.dp32 (x32
|
||||
plugins) or *.dp64 (x64
|
||||
plugins) to the 'plugins' directory.</P></body>
|
||||
|
|
|
@ -16,6 +16,6 @@ html,body {
|
|||
|
||||
<body>
|
||||
<P><STRONG>Scripting</STRONG><BR>This sections provides an overview of automating tasks with
|
||||
x64_dbg using scripts. See Commands for a description of all possible script commands. See Introduction for an introduction to
|
||||
x64dbg using scripts. See Commands for a description of all possible script commands. See Introduction for an introduction to
|
||||
expressions.</P></body>
|
||||
</html>
|
|
@ -16,7 +16,7 @@ html,body {
|
|||
|
||||
<body>
|
||||
<P><STRONG>Credits</STRONG><BR>
|
||||
This page is reserved for people/organisations that contributed to x64_dbg.</P>
|
||||
This page is reserved for people/organisations that contributed to x64dbg.</P>
|
||||
<UL>
|
||||
<LI>
|
||||
<DIV>Debugger core by <A
|
||||
|
@ -77,4 +77,7 @@ Sigma </DIV>
|
|||
<LI>
|
||||
<DIV><A href="http://www.fr33project.org"
|
||||
target=_blank>Dreg</A>
|
||||
</DIV>
|
||||
<LI>
|
||||
<DIV>Nukem
|
||||
</DIV></LI></UL></body></HTML>
|
||||
|
|
|
@ -17,7 +17,7 @@ html,body {
|
|||
|
||||
<body>
|
||||
<P><STRONG>The basics</STRONG><BR>This page covers the
|
||||
basic principles of plugin development for x64_dbg.</P>
|
||||
basic principles of plugin development for x64dbg.</P>
|
||||
<P><STRONG>Exports</STRONG><BR>A plugin has at least one
|
||||
export. This export must be called <U>pluginit</U>. See the PLUG_INITSTRUCT and
|
||||
the plugin headers for
|
||||
|
|
|
@ -17,7 +17,7 @@ html,body {
|
|||
<body>
|
||||
<P><STRONG>_plugin_debugpause<BR></STRONG>This function returns debugger control to the
|
||||
user. You would use this function when you write an unpacker that needs support
|
||||
from x64_dbg (for example in development). Calling this function will set the
|
||||
from x64dbg (for example in development). Calling this function will set the
|
||||
debug state to 'paused' and <U>it will <STRONG>not</STRONG> return until the
|
||||
user runs the debuggee using the 'run' command</U>
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ window.onafterprint = d_onafterprint;
|
|||
<p><FONT face=Courier>($content$)</FONT></p>
|
||||
<hr>
|
||||
<font face="Courier" color="#808080" size="1"><A
|
||||
href="http://x64dbg.com" target=_blank>x64_dbg</A>, GPLv3</font> </div>
|
||||
href="http://x64dbg.com" target=_blank>x64dbg</A>, GPLv3</font> </div>
|
||||
|
||||
</body>
|
||||
|
||||
|
|
BIN
help/x64_dbg.wcp
BIN
help/x64_dbg.wcp
Binary file not shown.
69
release.bat
69
release.bat
|
@ -22,6 +22,8 @@ mkdir %RELEASEDIR%\bin_base
|
|||
mkdir %RELEASEDIR%\bin_base\x32
|
||||
mkdir %RELEASEDIR%\bin_base\x64
|
||||
|
||||
copy bin\x32\x32_bridge.dll %RELEASEDIR%\bin_base\x32\x32_bridge.dll
|
||||
copy bin\x32\x32_dbg.dll %RELEASEDIR%\bin_base\x32\x32_dbg.dll
|
||||
copy bin\x32\BeaEngine.dll %RELEASEDIR%\bin_base\x32\BeaEngine.dll
|
||||
copy bin\x32\dbghelp.dll %RELEASEDIR%\bin_base\x32\dbghelp.dll
|
||||
copy bin\x32\symsrv.dll %RELEASEDIR%\bin_base\x32\symsrv.dll
|
||||
|
@ -31,6 +33,9 @@ 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\x64_bridge.dll %RELEASEDIR%\bin_base\x64\x64_bridge.dll
|
||||
copy bin\x64\x64_dbg.dll %RELEASEDIR%\bin_base\x64\x64_dbg.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,12 +45,13 @@ 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
|
||||
|
||||
mkdir %RELEASEDIR%\help
|
||||
|
||||
copy help\x64_dbg.chm %RELEASEDIR%\help
|
||||
copy help\x64dbg.chm %RELEASEDIR%\help
|
||||
|
||||
echo pluginsdk
|
||||
|
||||
|
@ -57,6 +63,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,34 +74,35 @@ 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
|
||||
copy x64_dbg_bridge\bridgemain.h %RELEASEDIR%\pluginsdk\bridgemain.h
|
||||
|
||||
genlib bin\x32\x32_bridge.dll
|
||||
copy x32_bridge.a %RELEASEDIR%\pluginsdk\libx32_bridge.a
|
||||
del x32_bridge.def
|
||||
del x32_bridge.a
|
||||
copy bin\x32\x32_bridge.lib %RELEASEDIR%\pluginsdk\x32_bridge.lib
|
||||
genlib bin\x32\x32bridge.dll
|
||||
copy x32bridge.a %RELEASEDIR%\pluginsdk\libx32bridge.a
|
||||
del x32bridge.def
|
||||
del x32bridge.a
|
||||
copy bin\x32\x32bridge.lib %RELEASEDIR%\pluginsdk\x32bridge.lib
|
||||
|
||||
genlib bin\x32\x32_dbg.dll
|
||||
copy x32_dbg.a %RELEASEDIR%\pluginsdk\libx32_dbg.a
|
||||
del x32_dbg.def
|
||||
del x32_dbg.a
|
||||
copy bin\x32\x32_dbg.lib %RELEASEDIR%\pluginsdk\x32_dbg.lib
|
||||
genlib bin\x32\x32dbg.dll
|
||||
copy x32dbg.a %RELEASEDIR%\pluginsdk\libx32dbg.a
|
||||
del x32dbg.def
|
||||
del x32dbg.a
|
||||
copy bin\x32\x32dbg.lib %RELEASEDIR%\pluginsdk\x32dbg.lib
|
||||
|
||||
genlib bin\x64\x64_bridge.dll
|
||||
copy x64_bridge.a %RELEASEDIR%\pluginsdk\libx64_bridge.a
|
||||
del x64_bridge.def
|
||||
del x64_bridge.a
|
||||
copy bin\x64\x64_bridge.lib %RELEASEDIR%\pluginsdk\x64_bridge.lib
|
||||
genlib bin\x64\x64bridge.dll
|
||||
copy x64bridge.a %RELEASEDIR%\pluginsdk\libx64bridge.a
|
||||
del x64bridge.def
|
||||
del x64bridge.a
|
||||
copy bin\x64\x64bridge.lib %RELEASEDIR%\pluginsdk\x64bridge.lib
|
||||
|
||||
genlib bin\x64\x64_dbg.dll
|
||||
copy x64_dbg.a %RELEASEDIR%\pluginsdk\libx64_dbg.a
|
||||
del x64_dbg.def
|
||||
del x64_dbg.a
|
||||
copy bin\x64\x64_dbg.lib %RELEASEDIR%\pluginsdk\x64_dbg.lib
|
||||
genlib bin\x64\x64dbg.dll
|
||||
copy x64dbg.a %RELEASEDIR%\pluginsdk\libx64dbg.a
|
||||
del x64dbg.def
|
||||
del x64dbg.a
|
||||
copy bin\x64\x64dbg.lib %RELEASEDIR%\pluginsdk\x64dbg.lib
|
||||
|
||||
echo release
|
||||
|
||||
|
@ -101,15 +110,15 @@ mkdir %RELEASEDIR%\release
|
|||
mkdir %RELEASEDIR%\release\x32
|
||||
mkdir %RELEASEDIR%\release\x64
|
||||
|
||||
copy bin\x96_dbg.exe %RELEASEDIR%\release\x96_dbg.exe
|
||||
copy bin\x32\x32_bridge.dll %RELEASEDIR%\release\x32\x32_bridge.dll
|
||||
copy bin\x32\x32_dbg.dll %RELEASEDIR%\release\x32\x32_dbg.dll
|
||||
copy bin\x32\x32_dbg.exe %RELEASEDIR%\release\x32\x32_dbg.exe
|
||||
copy bin\x32\x32_gui.dll %RELEASEDIR%\release\x32\x32_gui.dll
|
||||
copy bin\x64\x64_bridge.dll %RELEASEDIR%\release\x64\x64_bridge.dll
|
||||
copy bin\x64\x64_dbg.dll %RELEASEDIR%\release\x64\x64_dbg.dll
|
||||
copy bin\x64\x64_dbg.exe %RELEASEDIR%\release\x64\x64_dbg.exe
|
||||
copy bin\x64\x64_gui.dll %RELEASEDIR%\release\x64\x64_gui.dll
|
||||
copy bin\x96dbg.exe %RELEASEDIR%\release\x96dbg.exe
|
||||
copy bin\x32\x32bridge.dll %RELEASEDIR%\release\x32\x32bridge.dll
|
||||
copy bin\x32\x32dbg.dll %RELEASEDIR%\release\x32\x32dbg.dll
|
||||
copy bin\x32\x32dbg.exe %RELEASEDIR%\release\x32\x32dbg.exe
|
||||
copy bin\x32\x32gui.dll %RELEASEDIR%\release\x32\x32gui.dll
|
||||
copy bin\x64\x64bridge.dll %RELEASEDIR%\release\x64\x64bridge.dll
|
||||
copy bin\x64\x64dbg.dll %RELEASEDIR%\release\x64\x64dbg.dll
|
||||
copy bin\x64\x64dbg.exe %RELEASEDIR%\release\x64\x64dbg.exe
|
||||
copy bin\x64\x64gui.dll %RELEASEDIR%\release\x64\x64gui.dll
|
||||
|
||||
xcopy %RELEASEDIR%\qt_base %RELEASEDIR%\release /S /Y
|
||||
xcopy %RELEASEDIR%\bin_base %RELEASEDIR%\release /S /Y
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
@echo off
|
||||
|
||||
if "%OLDPATH%"=="" set OLDPATH=%PATH%
|
||||
|
||||
if "%QT32PATH%"=="" set QT32PATH=c:\Qt\qt-4.8.6-x86-msvc2013\qt-4.8.6-x86-msvc2013\bin
|
||||
if "%QT64PATH%"=="" set QT64PATH=c:\Qt\qt-4.8.6-x64-msvc2013\qt-4.8.6-x64-msvc2013\bin
|
||||
if "%QTCREATORPATH%"=="" set QTCREATORPATH=c:\Qt\qtcreator-3.1.1\bin
|
||||
if "%VSVARSALLPATH%"=="" set VSVARSALLPATH=c:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat
|
||||
if "%COVERITYPATH%"=="" set COVERITYPATH=c:\coverity\bin
|
||||
if "%DOXYGENPATH%"=="" set DOXYGENPATH=C:\Program Files\doxygen\bin
|
||||
if "%CHMPATH%"=="" set CHMPATH=c:\Program Files (x86)\Softany\WinCHM
|
||||
|
||||
if "%1"=="x32" (
|
||||
goto x32
|
||||
) else if "%1"=="x64" (
|
||||
goto x64
|
||||
) else if "%1"=="coverity" (
|
||||
goto coverity
|
||||
) else if "%1"=="doxygen" (
|
||||
goto doxygen
|
||||
) else if "%1"=="chm" (
|
||||
goto chm
|
||||
) else (
|
||||
echo "usage: setenv x32/x64/coverity/doxygen/chm"
|
||||
goto :eof
|
||||
)
|
||||
|
||||
:x32
|
||||
echo Setting Qt in PATH
|
||||
set PATH=%PATH%;%QT32PATH%
|
||||
set PATH=%PATH%;%QTCREATORPATH%
|
||||
echo Setting VS in PATH
|
||||
call "%VSVARSALLPATH%"
|
||||
goto :eof
|
||||
|
||||
:x64
|
||||
echo Setting Qt in PATH
|
||||
set PATH=%PATH%;%QT64PATH%
|
||||
set PATH=%PATH%;%QTCREATORPATH%
|
||||
echo Setting VS in PATH
|
||||
call "%VSVARSALLPATH%" amd64
|
||||
goto :eof
|
||||
|
||||
:coverity
|
||||
echo Setting Coverity in PATH
|
||||
set PATH=%PATH%;%COVERITYPATH%
|
||||
goto :eof
|
||||
|
||||
:doxygen
|
||||
echo Setting Doxygen in PATH
|
||||
set PATH=%PATH%;%DOXYGENPATH%
|
||||
goto :eof
|
||||
|
||||
:chm
|
||||
echo Setting CHM in PATH
|
||||
set PATH=%PATH%;%CHMPATH%
|
||||
goto :eof
|
52
todo_dbg.txt
52
todo_dbg.txt
|
@ -1,52 +0,0 @@
|
|||
- detach debugger
|
||||
- memcpy
|
||||
- pe data access
|
||||
- fpu support
|
||||
- mmx support
|
||||
- find asm
|
||||
- find memory (pattern+wildcard)
|
||||
- mov [mem],#data#,size
|
||||
- getremotestring
|
||||
- function parameter
|
||||
- help file updates
|
||||
- inject dll
|
||||
- dump memory
|
||||
- dump process
|
||||
- set pe data in memory
|
||||
- va to offset
|
||||
- offset to va
|
||||
- float calculations
|
||||
- command help
|
||||
- inject asm code
|
||||
- display open handles
|
||||
- step to user code
|
||||
- tracing(?)
|
||||
- [OPTIONAL] child processes (TitanEngine)
|
||||
- display source in PDB files (source debugging)
|
||||
- patching (+save)
|
||||
- handle view
|
||||
- window view
|
||||
- process privileges
|
||||
- loaded modules window
|
||||
- strings
|
||||
- references
|
||||
- callstack
|
||||
- heap
|
||||
- TEB/TBI
|
||||
- PEB/PBI
|
||||
- log breakpoints
|
||||
- membp in memmap
|
||||
- command va2offset (and the other way around)
|
||||
- various different float calculations
|
||||
- restore window position (BridgeSetting)
|
||||
- follow in dump
|
||||
- opcode byte split
|
||||
- tabbed GUI (workspace+dragable windows)
|
||||
- LUA/Python support
|
||||
- custom colours
|
||||
- find all intermodular calls
|
||||
- highlight register changes (only when CIP changed also)
|
||||
- 'dead' bytes custom analysis
|
||||
- loops lines database for analysis
|
||||
- enable/disable hw+mem breakpoint
|
||||
- highlight words
|
23
x64_dbg.sln
23
x64_dbg.sln
|
@ -1,6 +1,8 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 11.00
|
||||
# Visual Studio 2010
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 2013
|
||||
VisualStudioVersion = 12.0.31101.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "x64_dbg_bridge", "x64_dbg_bridge\x64_dbg_bridge.vcxproj", "{944D9923-CB1A-6F6C-BCBC-9E00A71954C1}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "x64_dbg_exe", "x64_dbg_exe\x64_dbg_exe.vcxproj", "{3A22175E-6B72-FDCC-1603-C4A2163C7900}"
|
||||
|
@ -17,22 +19,39 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "x64_dbg_launcher", "x64_dbg
|
|||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Debug|x64 = Debug|x64
|
||||
Release|Win32 = Release|Win32
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{944D9923-CB1A-6F6C-BCBC-9E00A71954C1}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{944D9923-CB1A-6F6C-BCBC-9E00A71954C1}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{944D9923-CB1A-6F6C-BCBC-9E00A71954C1}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{944D9923-CB1A-6F6C-BCBC-9E00A71954C1}.Debug|x64.Build.0 = Debug|x64
|
||||
{944D9923-CB1A-6F6C-BCBC-9E00A71954C1}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{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 = 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
|
||||
{3A22175E-6B72-FDCC-1603-C4A2163C7900}.Release|x64.Build.0 = Release|x64
|
||||
{E6548308-401E-3A8A-5819-905DB90522A6}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{E6548308-401E-3A8A-5819-905DB90522A6}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{E6548308-401E-3A8A-5819-905DB90522A6}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{E6548308-401E-3A8A-5819-905DB90522A6}.Debug|x64.Build.0 = Debug|x64
|
||||
{E6548308-401E-3A8A-5819-905DB90522A6}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{E6548308-401E-3A8A-5819-905DB90522A6}.Release|Win32.Build.0 = Release|Win32
|
||||
{E6548308-401E-3A8A-5819-905DB90522A6}.Release|x64.ActiveCfg = Release|x64
|
||||
{E6548308-401E-3A8A-5819-905DB90522A6}.Release|x64.Build.0 = Release|x64
|
||||
{AC3F927A-4079-4C97-B8BE-8D04546802E7}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{AC3F927A-4079-4C97-B8BE-8D04546802E7}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{AC3F927A-4079-4C97-B8BE-8D04546802E7}.Debug|x64.ActiveCfg = Debug|Win32
|
||||
{AC3F927A-4079-4C97-B8BE-8D04546802E7}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{AC3F927A-4079-4C97-B8BE-8D04546802E7}.Release|Win32.Build.0 = Release|Win32
|
||||
{AC3F927A-4079-4C97-B8BE-8D04546802E7}.Release|x64.ActiveCfg = Release|Win32
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
#include "_global.h"
|
||||
|
||||
//GUI functions
|
||||
GUIGUIINIT _gui_guiinit;
|
||||
GUISENDMESSAGE _gui_sendmessage;
|
||||
GUISENDMESSAGEASYNC _gui_sendmessageasync;
|
||||
|
||||
//DBG functions
|
||||
DBGDBGINIT _dbg_dbginit;
|
||||
DBGMEMFINDBASEADDR _dbg_memfindbaseaddr;
|
||||
DBGMEMREAD _dbg_memread;
|
||||
|
|
|
@ -7,10 +7,12 @@
|
|||
//GUI typedefs
|
||||
typedef int (*GUIGUIINIT)(int, char**);
|
||||
typedef void* (*GUISENDMESSAGE)(GUIMSG type, void* param1, void* param2);
|
||||
typedef void (*GUISENDMESSAGEASYNC)(GUIMSG type, void* param1, void* param2);
|
||||
|
||||
//GUI functions
|
||||
extern GUIGUIINIT _gui_guiinit;
|
||||
extern GUISENDMESSAGE _gui_sendmessage;
|
||||
extern GUISENDMESSAGEASYNC _gui_sendmessageasync;
|
||||
|
||||
//DBG typedefs
|
||||
typedef const char* (*DBGDBGINIT)();
|
||||
|
@ -27,7 +29,7 @@ typedef bool (*DBGADDRINFOGET)(duint addr, SEGMENTREG segment, ADDRINFO* addrinf
|
|||
typedef bool (*DBGADDRINFOSET)(duint addr, ADDRINFO* addrinfo);
|
||||
typedef BPXTYPE (*DBGBPGETTYPEAT)(duint addr);
|
||||
typedef bool (*DBGGETREGDUMP)(REGDUMP* regdump);
|
||||
typedef bool (*DBGVALTOSTRING)(const char* string, duint* value);
|
||||
typedef bool (*DBGVALTOSTRING)(const char* string, duint value);
|
||||
typedef bool (*DBGMEMISVALIDREADPTR)(duint addr);
|
||||
typedef int (*DBGGETBPLIST)(BPXTYPE type, BPMAP* bplist);
|
||||
typedef bool (*DBGDBGCMDEXECDIRECT)(const char* cmd);
|
||||
|
|
|
@ -1,17 +1,25 @@
|
|||
/**
|
||||
* \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;
|
||||
|
||||
#ifdef _WIN64
|
||||
#define dbg_lib "x64_dbg.dll"
|
||||
#define gui_lib "x64_gui.dll"
|
||||
#define dbg_lib "x64dbg.dll"
|
||||
#define gui_lib "x64gui.dll"
|
||||
#else
|
||||
#define dbg_lib "x32_dbg.dll"
|
||||
#define gui_lib "x32_gui.dll"
|
||||
#define dbg_lib "x32dbg.dll"
|
||||
#define gui_lib "x32gui.dll"
|
||||
#endif // _WIN64
|
||||
|
||||
#define LOADLIBRARY(name) \
|
||||
|
@ -28,10 +36,12 @@ static wchar_t szIniFile[MAX_PATH] = L"";
|
|||
return szError; \
|
||||
}
|
||||
|
||||
//Bridge
|
||||
BRIDGE_IMPEXP const char* BridgeInit()
|
||||
{
|
||||
///Settings load
|
||||
//Initialize critial section
|
||||
InitializeCriticalSection(&csIni);
|
||||
|
||||
//Settings load
|
||||
if(!GetModuleFileNameW(0, szIniFile, MAX_PATH))
|
||||
return "Error getting module path!";
|
||||
int len = (int)wcslen(szIniFile);
|
||||
|
@ -81,6 +91,7 @@ BRIDGE_IMPEXP const char* BridgeStart()
|
|||
if(!_dbg_dbginit || !_gui_guiinit)
|
||||
return "\"_dbg_dbginit\" || \"_gui_guiinit\" was not loaded yet, call BridgeInit!";
|
||||
_gui_guiinit(0, 0); //remove arguments
|
||||
DeleteCriticalSection(&csIni);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -105,14 +116,20 @@ BRIDGE_IMPEXP bool BridgeSettingGet(const char* section, const char* key, char*
|
|||
{
|
||||
if(!section || !key || !value)
|
||||
return false;
|
||||
EnterCriticalSection(&csIni);
|
||||
CSimpleIniA inifile(true, false, false);
|
||||
if(inifile.LoadFile(szIniFile) < 0)
|
||||
return false;
|
||||
const char* szValue = inifile.GetValue(section, key);
|
||||
if(!szValue)
|
||||
return false;
|
||||
strcpy_s(value, MAX_SETTING_SIZE, szValue);
|
||||
return true;
|
||||
bool success = false;
|
||||
if(inifile.LoadFile(szIniFile) >= 0)
|
||||
{
|
||||
const char* szValue = inifile.GetValue(section, key);
|
||||
if(szValue)
|
||||
{
|
||||
strcpy_s(value, MAX_SETTING_SIZE, szValue);
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
LeaveCriticalSection(&csIni);
|
||||
return success;
|
||||
}
|
||||
|
||||
BRIDGE_IMPEXP bool BridgeSettingGetUint(const char* section, const char* key, duint* value)
|
||||
|
@ -134,15 +151,20 @@ BRIDGE_IMPEXP bool BridgeSettingGetUint(const char* section, const char* key, du
|
|||
|
||||
BRIDGE_IMPEXP bool BridgeSettingSet(const char* section, const char* key, const char* value)
|
||||
{
|
||||
if(!section)
|
||||
return false;
|
||||
CSimpleIniA inifile(true, false, false);
|
||||
inifile.LoadFile(szIniFile);
|
||||
if(!key || !value) //delete value/key when 0
|
||||
inifile.Delete(section, key, true);
|
||||
else
|
||||
inifile.SetValue(section, key, value);
|
||||
return inifile.SaveFile(szIniFile, false) >= 0;
|
||||
bool success = false;
|
||||
if(section)
|
||||
{
|
||||
EnterCriticalSection(&csIni);
|
||||
CSimpleIniA inifile(true, false, false);
|
||||
inifile.LoadFile(szIniFile);
|
||||
if(!key || !value) //delete value/key when 0
|
||||
inifile.Delete(section, key, true);
|
||||
else
|
||||
inifile.SetValue(section, key, value);
|
||||
success = inifile.SaveFile(szIniFile, false) >= 0;
|
||||
LeaveCriticalSection(&csIni);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
BRIDGE_IMPEXP bool BridgeSettingSetUint(const char* section, const char* key, duint value)
|
||||
|
@ -163,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))
|
||||
|
@ -187,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;
|
||||
|
@ -204,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);
|
||||
|
@ -225,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)
|
||||
|
@ -243,7 +267,7 @@ BRIDGE_IMPEXP bool DbgGetLabelAt(duint addr, SEGMENTREG segment, char* text) //(
|
|||
return false;
|
||||
sprintf_s(info.label, "&%s", ptrinfo.label);
|
||||
}
|
||||
strcpy(text, info.label);
|
||||
strcpy_s(text, MAX_LABEL_SIZE, info.label);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -254,12 +278,13 @@ BRIDGE_IMPEXP bool DbgSetLabelAt(duint addr, const char* text)
|
|||
ADDRINFO info;
|
||||
memset(&info, 0, sizeof(info));
|
||||
info.flags = flaglabel;
|
||||
strcpy(info.label, text);
|
||||
strcpy_s(info.label, text);
|
||||
if(!_dbg_addrinfoset(addr, &info))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// FIXME required size of arg _text_?
|
||||
BRIDGE_IMPEXP bool DbgGetCommentAt(duint addr, char* text) //comment (not live)
|
||||
{
|
||||
if(!text || !addr)
|
||||
|
@ -269,7 +294,7 @@ BRIDGE_IMPEXP bool DbgGetCommentAt(duint addr, char* text) //comment (not live)
|
|||
info.flags = flagcomment;
|
||||
if(!_dbg_addrinfoget(addr, SEG_DEFAULT, &info))
|
||||
return false;
|
||||
strcpy(text, info.comment);
|
||||
strcpy_s(text, MAX_COMMENT_SIZE, info.comment);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -280,12 +305,13 @@ BRIDGE_IMPEXP bool DbgSetCommentAt(duint addr, const char* text)
|
|||
ADDRINFO info;
|
||||
memset(&info, 0, sizeof(info));
|
||||
info.flags = flagcomment;
|
||||
strcpy(info.comment, text);
|
||||
strcpy_s(info.comment, MAX_COMMENT_SIZE, text);
|
||||
if(!_dbg_addrinfoset(addr, &info))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// FIXME required size of arg _text_?
|
||||
BRIDGE_IMPEXP bool DbgGetModuleAt(duint addr, char* text)
|
||||
{
|
||||
if(!text || !addr)
|
||||
|
@ -295,7 +321,7 @@ BRIDGE_IMPEXP bool DbgGetModuleAt(duint addr, char* text)
|
|||
info.flags = flagmodule;
|
||||
if(!_dbg_addrinfoget(addr, SEG_DEFAULT, &info))
|
||||
return false;
|
||||
strcpy(text, info.module);
|
||||
strcpy_s(text, MAX_MODULE_SIZE, info.module);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -322,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();
|
||||
|
@ -349,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)
|
||||
|
@ -360,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);
|
||||
|
@ -388,6 +417,7 @@ BRIDGE_IMPEXP FUNCTYPE DbgGetFunctionTypeAt(duint addr)
|
|||
return FUNC_MIDDLE;
|
||||
}
|
||||
|
||||
// FIXME depth
|
||||
BRIDGE_IMPEXP LOOPTYPE DbgGetLoopTypeAt(duint addr, int depth)
|
||||
{
|
||||
ADDRINFO info;
|
||||
|
@ -415,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);
|
||||
|
@ -466,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;
|
||||
|
@ -522,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;
|
||||
|
@ -534,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;
|
||||
|
@ -544,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;
|
||||
|
@ -555,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;
|
||||
|
@ -564,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;
|
||||
|
@ -576,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;
|
||||
|
@ -587,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;
|
||||
|
@ -598,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;
|
||||
|
@ -608,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))
|
||||
|
@ -629,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);
|
||||
|
@ -641,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);
|
||||
|
@ -653,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);
|
||||
|
@ -665,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))
|
||||
|
@ -677,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))
|
||||
|
@ -689,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))
|
||||
|
@ -696,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();
|
||||
|
@ -728,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);
|
||||
|
@ -862,145 +940,175 @@ 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;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ extern "C"
|
|||
|
||||
//Bridge defines
|
||||
#define MAX_SETTING_SIZE 65536
|
||||
#define DBG_VERSION 23
|
||||
#define DBG_VERSION 25
|
||||
|
||||
//Bridge functions
|
||||
BRIDGE_IMPEXP const char* BridgeInit();
|
||||
|
@ -60,6 +60,7 @@ BRIDGE_IMPEXP int BridgeGetDbgVersion();
|
|||
#define MAX_STRING_SIZE 512
|
||||
#define MAX_ERROR_SIZE 512
|
||||
#define RIGHTS_STRING_SIZE (sizeof("ERWCG") + 1)
|
||||
#define MAX_SECTION_SIZE 10
|
||||
|
||||
#define TYPE_VALUE 1
|
||||
#define TYPE_MEMORY 2
|
||||
|
@ -423,6 +424,18 @@ typedef struct
|
|||
|
||||
} X87CONTROLWORDFIELDS;
|
||||
|
||||
typedef struct DECLSPEC_ALIGN(16) _XMMREGISTER
|
||||
{
|
||||
ULONGLONG Low;
|
||||
LONGLONG High;
|
||||
} XMMREGISTER;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
XMMREGISTER Low; //XMM/SSE part
|
||||
XMMREGISTER High; //AVX part
|
||||
} YMMREGISTER;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
BYTE data[10];
|
||||
|
@ -480,14 +493,20 @@ typedef struct
|
|||
X87FPU x87fpu;
|
||||
DWORD MxCsr;
|
||||
#ifdef _WIN64
|
||||
M128A XmmRegisters[16];
|
||||
BYTE YmmRegisters[32 * 16];
|
||||
XMMREGISTER XmmRegisters[16];
|
||||
YMMREGISTER YmmRegisters[16];
|
||||
#else // x86
|
||||
M128A XmmRegisters[8];
|
||||
BYTE YmmRegisters[32 * 8];
|
||||
XMMREGISTER XmmRegisters[8];
|
||||
YMMREGISTER YmmRegisters[8];
|
||||
#endif
|
||||
} REGISTERCONTEXT;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
DWORD code;
|
||||
const char* name;
|
||||
} LASTERROR;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
REGISTERCONTEXT regcontext;
|
||||
|
@ -497,6 +516,7 @@ typedef struct
|
|||
MXCSRFIELDS MxCsrFields;
|
||||
X87STATUSWORDFIELDS x87StatusWordFields;
|
||||
X87CONTROLWORDFIELDS x87ControlWordFields;
|
||||
LASTERROR lastError;
|
||||
} REGDUMP;
|
||||
|
||||
typedef struct
|
||||
|
@ -527,8 +547,8 @@ typedef struct
|
|||
typedef struct
|
||||
{
|
||||
int ThreadNumber;
|
||||
HANDLE hThread;
|
||||
DWORD dwThreadId;
|
||||
HANDLE Handle;
|
||||
DWORD ThreadId;
|
||||
duint ThreadStartAddress;
|
||||
duint ThreadLocalBase;
|
||||
char threadName[MAX_THREAD_NAME_SIZE];
|
||||
|
@ -666,6 +686,9 @@ BRIDGE_IMPEXP bool DbgWinEventGlobal(MSG* message);
|
|||
|
||||
//Gui defines
|
||||
#define GUI_PLUGIN_MENU 0
|
||||
#define GUI_DISASM_MENU 1
|
||||
#define GUI_DUMP_MENU 2
|
||||
#define GUI_STACK_MENU 3
|
||||
|
||||
#define GUI_DISASSEMBLY 0
|
||||
#define GUI_DUMP 1
|
||||
|
@ -733,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
|
||||
|
@ -810,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
|
||||
}
|
||||
|
|
|
@ -1,6 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
|
@ -27,10 +35,22 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
|
@ -38,20 +58,37 @@
|
|||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)bin\x32\</OutDir>
|
||||
<IntDir>$(Platform)\$(Configuration)\</IntDir>
|
||||
<TargetName>x32_bridge</TargetName>
|
||||
<TargetName>x32bridge</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)bin\x32\</OutDir>
|
||||
<IntDir>$(Platform)\$(Configuration)\</IntDir>
|
||||
<TargetName>x32bridge</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)bin\x64\</OutDir>
|
||||
<TargetName>x64_bridge</TargetName>
|
||||
<TargetName>x64bridge</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)bin\x64\</OutDir>
|
||||
<TargetName>x64bridge</TargetName>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
|
@ -69,6 +106,22 @@
|
|||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>BUILD_BRIDGE;WIN32;NDEBUG;_WINDOWS;_USRDLL;X64_DBG_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>BUILD_BRIDGE;WIN32;NDEBUG;_WINDOWS;_USRDLL;X64_DBG_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
|
@ -83,6 +136,20 @@
|
|||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>BUILD_BRIDGE;WIN32;NDEBUG;_WINDOWS;_USRDLL;X64_DBG_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
|
|
|
@ -9,10 +9,6 @@
|
|||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="_global.cpp">
|
||||
|
|
|
@ -1,12 +1,22 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LocalDebuggerCommand>$(OutDir)\x32_dbg.exe</LocalDebuggerCommand>
|
||||
<LocalDebuggerCommand>$(OutDir)\x32dbg.exe</LocalDebuggerCommand>
|
||||
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
|
||||
<LocalDebuggerWorkingDirectory>$(OutDir)</LocalDebuggerWorkingDirectory>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LocalDebuggerCommand>$(OutDir)\x32dbg.exe</LocalDebuggerCommand>
|
||||
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
|
||||
<LocalDebuggerWorkingDirectory>$(OutDir)</LocalDebuggerWorkingDirectory>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LocalDebuggerCommand>$(OutDir)\x64_dbg.exe</LocalDebuggerCommand>
|
||||
<LocalDebuggerCommand>$(OutDir)\x64dbg.exe</LocalDebuggerCommand>
|
||||
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
|
||||
<LocalDebuggerWorkingDirectory>$(OutDir)</LocalDebuggerWorkingDirectory>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LocalDebuggerCommand>$(OutDir)\x64dbg.exe</LocalDebuggerCommand>
|
||||
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
|
||||
<LocalDebuggerWorkingDirectory>$(OutDir)</LocalDebuggerWorkingDirectory>
|
||||
</PropertyGroup>
|
||||
|
|
|
@ -10,14 +10,6 @@
|
|||
#include <windows.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __GNUC__
|
||||
typedef struct DECLSPEC_ALIGN(16) _M128A
|
||||
{
|
||||
ULONGLONG Low;
|
||||
LONGLONG High;
|
||||
} M128A, *PM128A;
|
||||
#endif //__GNUC__
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
// Global.Constant.Structure.Declaration:
|
||||
|
@ -594,10 +586,16 @@ typedef struct
|
|||
DWORD OriginalCOMTableSize;
|
||||
} FILE_FIX_INFO, *PFILE_FIX_INFO;
|
||||
|
||||
typedef struct DECLSPEC_ALIGN(16) _XmmRegister_t
|
||||
{
|
||||
ULONGLONG Low;
|
||||
LONGLONG High;
|
||||
} XmmRegister_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
M128A Low; //XMM/SSE part
|
||||
M128A High; //AVX part
|
||||
XmmRegister_t Low; //XMM/SSE part
|
||||
XmmRegister_t High; //AVX part
|
||||
} YmmRegister_t;
|
||||
|
||||
typedef struct
|
||||
|
@ -657,10 +655,10 @@ typedef struct
|
|||
x87FPU_t x87fpu;
|
||||
DWORD MxCsr;
|
||||
#ifdef _WIN64
|
||||
M128A XmmRegisters[16];
|
||||
XmmRegister_t XmmRegisters[16];
|
||||
YmmRegister_t YmmRegisters[16];
|
||||
#else // x86
|
||||
M128A XmmRegisters[8];
|
||||
XmmRegister_t XmmRegisters[8];
|
||||
YmmRegister_t YmmRegisters[8];
|
||||
#endif
|
||||
} TITAN_ENGINE_CONTEXT_t;
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
/**
|
||||
@file _dbgfunctions.cpp
|
||||
|
||||
@brief Implements the dbgfunctions class.
|
||||
*/
|
||||
|
||||
#include "_global.h"
|
||||
#include "_dbgfunctions.h"
|
||||
#include "assemble.h"
|
||||
|
@ -8,6 +14,7 @@
|
|||
#include "disasm_fast.h"
|
||||
#include "stackinfo.h"
|
||||
#include "symbolinfo.h"
|
||||
#include "module.h"
|
||||
|
||||
static DBGFUNCTIONS _dbgfunctions;
|
||||
|
||||
|
@ -18,12 +25,12 @@ 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)
|
||||
{
|
||||
HMODULE hMod = (HMODULE)modbasefromaddr(addr);
|
||||
HMODULE hMod = (HMODULE)ModBaseFromAddr(addr);
|
||||
if(!hMod)
|
||||
return false;
|
||||
wchar_t curModPath[MAX_PATH] = L"";
|
||||
|
@ -41,7 +48,7 @@ static bool _sectionfromaddr(duint addr, char* section)
|
|||
{
|
||||
const char* name = (const char*)GetPE32DataFromMappedFile(FileMapVA, sectionNumber, UE_SECTIONNAME);
|
||||
if(section)
|
||||
strcpy(section, name);
|
||||
strcpy_s(section, MAX_SECTION_SIZE, name); //maxi
|
||||
StaticFileUnloadW(curModPath, false, FileHandle, LoadedSize, FileMap, FileMapVA);
|
||||
return true;
|
||||
}
|
||||
|
@ -52,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))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool _mempatch(duint va, const unsigned char* src, duint size)
|
||||
{
|
||||
return mempatch(fdProcessInfo->hProcess, (void*)va, 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);
|
||||
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)
|
||||
|
@ -119,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)
|
||||
|
@ -130,7 +135,7 @@ static bool _getjit(char* jit, bool jit64)
|
|||
{
|
||||
if(!dbggetjit(jit_tmp, jit64 ? x64 : x32, &dummy, NULL))
|
||||
return false;
|
||||
strcpy(jit, jit_tmp);
|
||||
strcpy_s(jit, MAX_SETTING_SIZE, jit_tmp);
|
||||
}
|
||||
else // if jit input == NULL: it returns false if there are not an OLD JIT STORED.
|
||||
{
|
||||
|
@ -161,31 +166,31 @@ bool _getprocesslist(DBGPROCESSINFO** entries, int* count)
|
|||
|
||||
static void _memupdatemap()
|
||||
{
|
||||
memupdatemap(fdProcessInfo->hProcess);
|
||||
MemUpdateMap(fdProcessInfo->hProcess);
|
||||
}
|
||||
|
||||
void dbgfunctionsinit()
|
||||
{
|
||||
_dbgfunctions.AssembleAtEx = _assembleatex;
|
||||
_dbgfunctions.SectionFromAddr = _sectionfromaddr;
|
||||
_dbgfunctions.ModNameFromAddr = modnamefromaddr;
|
||||
_dbgfunctions.ModBaseFromAddr = modbasefromaddr;
|
||||
_dbgfunctions.ModBaseFromName = modbasefromname;
|
||||
_dbgfunctions.ModSizeFromAddr = modsizefromaddr;
|
||||
_dbgfunctions.ModNameFromAddr = ModNameFromAddr;
|
||||
_dbgfunctions.ModBaseFromAddr = ModBaseFromAddr;
|
||||
_dbgfunctions.ModBaseFromName = ModBaseFromName;
|
||||
_dbgfunctions.ModSizeFromAddr = ModSizeFromAddr;
|
||||
_dbgfunctions.Assemble = assemble;
|
||||
_dbgfunctions.PatchGet = _patchget;
|
||||
_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.ModPathFromAddr = modpathfromaddr;
|
||||
_dbgfunctions.ModPathFromName = modpathfromname;
|
||||
_dbgfunctions.PatchFile = (PATCHFILE)PatchFile;
|
||||
_dbgfunctions.ModPathFromAddr = ModPathFromAddr;
|
||||
_dbgfunctions.ModPathFromName = ModPathFromName;
|
||||
_dbgfunctions.DisasmFast = disasmfast;
|
||||
_dbgfunctions.MemUpdateMap = _memupdatemap;
|
||||
_dbgfunctions.GetCallStack = _getcallstack;
|
||||
_dbgfunctions.SymbolDownloadAllSymbols = symdownloadallsymbols;
|
||||
_dbgfunctions.SymbolDownloadAllSymbols = SymDownloadAllSymbols;
|
||||
_dbgfunctions.GetJit = _getjit;
|
||||
_dbgfunctions.GetJitAuto = _getjitauto;
|
||||
_dbgfunctions.GetDefJit = dbggetdefjit;
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
/**
|
||||
@file _exports.cpp
|
||||
|
||||
@brief Implements the exports class.
|
||||
*/
|
||||
|
||||
#include "_exports.h"
|
||||
#include "memory.h"
|
||||
#include "debugger.h"
|
||||
|
@ -15,22 +21,29 @@
|
|||
#include "disasm_fast.h"
|
||||
#include "plugin_loader.h"
|
||||
#include "_dbgfunctions.h"
|
||||
#include "module.h"
|
||||
#include "comment.h"
|
||||
#include "label.h"
|
||||
#include "bookmark.h"
|
||||
#include "function.h"
|
||||
#include "loop.h"
|
||||
#include "error.h"
|
||||
|
||||
static bool bOnlyCipAutoComments = false;
|
||||
|
||||
extern "C" DLL_EXPORT duint _dbg_memfindbaseaddr(duint addr, duint* size)
|
||||
{
|
||||
return memfindbaseaddr(addr, size);
|
||||
return MemFindBaseAddr(addr, size);
|
||||
}
|
||||
|
||||
extern "C" DLL_EXPORT bool _dbg_memread(duint addr, unsigned char* dest, duint size, duint* read)
|
||||
{
|
||||
return memread(fdProcessInfo->hProcess, (void*)addr, dest, size, read);
|
||||
return MemRead((void*)addr, dest, size, read);
|
||||
}
|
||||
|
||||
extern "C" DLL_EXPORT bool _dbg_memwrite(duint addr, const unsigned char* src, duint size, duint* written)
|
||||
{
|
||||
return memwrite(fdProcessInfo->hProcess, (void*)addr, src, size, written);
|
||||
return MemWrite((void*)addr, (void*)src, size, written);
|
||||
}
|
||||
|
||||
extern "C" DLL_EXPORT bool _dbg_memmap(MEMMAP* memmap)
|
||||
|
@ -41,17 +54,23 @@ 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;
|
||||
}
|
||||
|
||||
extern "C" DLL_EXPORT bool _dbg_memisvalidreadptr(duint addr)
|
||||
{
|
||||
return memisvalidreadptr(fdProcessInfo->hProcess, addr);
|
||||
return MemIsValidReadPtr(addr);
|
||||
}
|
||||
|
||||
extern "C" DLL_EXPORT bool _dbg_valfromstring(const char* string, duint* value)
|
||||
|
@ -63,6 +82,7 @@ extern "C" DLL_EXPORT bool _dbg_isdebugging()
|
|||
{
|
||||
if(IsFileBeingDebugged())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -87,12 +107,12 @@ extern "C" DLL_EXPORT bool _dbg_addrinfoget(duint addr, SEGMENTREG segment, ADDR
|
|||
bool retval = false;
|
||||
if(addrinfo->flags & flagmodule) //get module
|
||||
{
|
||||
if(modnamefromaddr(addr, addrinfo->module, false)) //get module name
|
||||
if(ModNameFromAddr(addr, addrinfo->module, false)) //get module name
|
||||
retval = true;
|
||||
}
|
||||
if(addrinfo->flags & flaglabel)
|
||||
{
|
||||
if(labelget(addr, addrinfo->label))
|
||||
if(LabelGet(addr, addrinfo->label))
|
||||
retval = true;
|
||||
else //no user labels
|
||||
{
|
||||
|
@ -101,10 +121,10 @@ extern "C" DLL_EXPORT bool _dbg_addrinfoget(duint addr, SEGMENTREG segment, ADDR
|
|||
PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
|
||||
pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
||||
pSymbol->MaxNameLen = MAX_LABEL_SIZE;
|
||||
if(SymFromAddr(fdProcessInfo->hProcess, (DWORD64)addr, &displacement, pSymbol) and !displacement)
|
||||
if(SafeSymFromAddr(fdProcessInfo->hProcess, (DWORD64)addr, &displacement, pSymbol) and !displacement)
|
||||
{
|
||||
pSymbol->Name[pSymbol->MaxNameLen - 1] = '\0';
|
||||
if(!bUndecorateSymbolNames or !UnDecorateSymbolName(pSymbol->Name, addrinfo->label, MAX_LABEL_SIZE, UNDNAME_COMPLETE))
|
||||
if(!bUndecorateSymbolNames or !SafeUnDecorateSymbolName(pSymbol->Name, addrinfo->label, MAX_LABEL_SIZE, UNDNAME_COMPLETE))
|
||||
strcpy_s(addrinfo->label, pSymbol->Name);
|
||||
retval = true;
|
||||
}
|
||||
|
@ -115,12 +135,12 @@ extern "C" DLL_EXPORT bool _dbg_addrinfoget(duint addr, SEGMENTREG segment, ADDR
|
|||
if(disasmfast(addr, &basicinfo) && basicinfo.branch && !basicinfo.call && basicinfo.memory.value) //thing is a JMP
|
||||
{
|
||||
uint val = 0;
|
||||
if(memread(fdProcessInfo->hProcess, (const void*)basicinfo.memory.value, &val, sizeof(val), 0))
|
||||
if(MemRead((void*)basicinfo.memory.value, &val, sizeof(val), 0))
|
||||
{
|
||||
if(SymFromAddr(fdProcessInfo->hProcess, (DWORD64)val, &displacement, pSymbol) and !displacement)
|
||||
if(SafeSymFromAddr(fdProcessInfo->hProcess, (DWORD64)val, &displacement, pSymbol) and !displacement)
|
||||
{
|
||||
pSymbol->Name[pSymbol->MaxNameLen - 1] = '\0';
|
||||
if(!bUndecorateSymbolNames or !UnDecorateSymbolName(pSymbol->Name, addrinfo->label, MAX_LABEL_SIZE, UNDNAME_COMPLETE))
|
||||
if(!bUndecorateSymbolNames or !SafeUnDecorateSymbolName(pSymbol->Name, addrinfo->label, MAX_LABEL_SIZE, UNDNAME_COMPLETE))
|
||||
sprintf_s(addrinfo->label, "JMP.&%s", pSymbol->Name);
|
||||
retval = true;
|
||||
}
|
||||
|
@ -131,33 +151,33 @@ extern "C" DLL_EXPORT bool _dbg_addrinfoget(duint addr, SEGMENTREG segment, ADDR
|
|||
}
|
||||
if(addrinfo->flags & flagbookmark)
|
||||
{
|
||||
addrinfo->isbookmark = bookmarkget(addr);
|
||||
addrinfo->isbookmark = BookmarkGet(addr);
|
||||
retval = true;
|
||||
}
|
||||
if(addrinfo->flags & flagfunction)
|
||||
{
|
||||
if(functionget(addr, &addrinfo->function.start, &addrinfo->function.end))
|
||||
if(FunctionGet(addr, &addrinfo->function.start, &addrinfo->function.end))
|
||||
retval = true;
|
||||
}
|
||||
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)
|
||||
{
|
||||
*addrinfo->comment = 0;
|
||||
if(commentget(addr, addrinfo->comment))
|
||||
if(CommentGet(addr, addrinfo->comment))
|
||||
retval = true;
|
||||
else
|
||||
{
|
||||
DWORD dwDisplacement;
|
||||
IMAGEHLP_LINE64 line;
|
||||
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
|
||||
if(SymGetLineFromAddr64(fdProcessInfo->hProcess, (DWORD64)addr, &dwDisplacement, &line) and !dwDisplacement)
|
||||
if(SafeSymGetLineFromAddr64(fdProcessInfo->hProcess, (DWORD64)addr, &dwDisplacement, &line) and !dwDisplacement)
|
||||
{
|
||||
char filename[deflen] = "";
|
||||
strcpy(filename, line.FileName);
|
||||
strcpy_s(filename, line.FileName);
|
||||
int len = (int)strlen(filename);
|
||||
while(filename[len] != '\\' and len != 0)
|
||||
len--;
|
||||
|
@ -288,20 +308,20 @@ 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
|
||||
{
|
||||
if(commentset(addr, addrinfo->comment, true))
|
||||
if(CommentSet(addr, addrinfo->comment, true))
|
||||
retval = true;
|
||||
}
|
||||
if(addrinfo->flags & flagbookmark) //set bookmark
|
||||
{
|
||||
if(addrinfo->isbookmark)
|
||||
retval = bookmarkset(addr, true);
|
||||
retval = BookmarkSet(addr, true);
|
||||
else
|
||||
retval = bookmarkdel(addr);
|
||||
retval = BookmarkDelete(addr);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
@ -311,20 +331,20 @@ extern "C" DLL_EXPORT int _dbg_bpgettypeat(duint addr)
|
|||
static uint cacheAddr;
|
||||
static int cacheBpCount;
|
||||
static int cacheResult;
|
||||
int bpcount = bpgetlist(0);
|
||||
int bpcount = BpGetList(nullptr);
|
||||
if(cacheAddr != addr or cacheBpCount != bpcount)
|
||||
{
|
||||
BREAKPOINT bp;
|
||||
cacheAddr = addr;
|
||||
cacheResult = 0;
|
||||
cacheBpCount = bpcount;
|
||||
if(bpget(addr, BPNORMAL, 0, &bp))
|
||||
if(BpGet(addr, BPNORMAL, 0, &bp))
|
||||
if(bp.enabled)
|
||||
cacheResult |= bp_normal;
|
||||
if(bpget(addr, BPHARDWARE, 0, &bp))
|
||||
if(BpGet(addr, BPHARDWARE, 0, &bp))
|
||||
if(bp.enabled)
|
||||
cacheResult |= bp_hardware;
|
||||
if(bpget(addr, BPMEMORY, 0, &bp))
|
||||
if(BpGet(addr, BPMEMORY, 0, &bp))
|
||||
if(bp.enabled)
|
||||
cacheResult |= bp_memory;
|
||||
}
|
||||
|
@ -483,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);
|
||||
}
|
||||
|
@ -497,7 +521,7 @@ extern "C" DLL_EXPORT int _dbg_getbplist(BPXTYPE type, BPMAP* bpmap)
|
|||
if(!bpmap)
|
||||
return 0;
|
||||
std::vector<BREAKPOINT> list;
|
||||
int bpcount = bpgetlist(&list);
|
||||
int bpcount = BpGetList(&list);
|
||||
if(bpcount == 0)
|
||||
{
|
||||
bpmap->count = 0;
|
||||
|
@ -560,10 +584,10 @@ extern "C" DLL_EXPORT int _dbg_getbplist(BPXTYPE type, BPMAP* bpmap)
|
|||
curBp.addr = list[i].addr;
|
||||
curBp.enabled = list[i].enabled;
|
||||
//TODO: fix this
|
||||
if(memisvalidreadptr(fdProcessInfo->hProcess, curBp.addr))
|
||||
if(MemIsValidReadPtr(curBp.addr))
|
||||
curBp.active = true;
|
||||
strcpy(curBp.mod, list[i].mod);
|
||||
strcpy(curBp.name, list[i].name);
|
||||
strcpy_s(curBp.mod, list[i].mod);
|
||||
strcpy_s(curBp.name, list[i].name);
|
||||
curBp.singleshoot = list[i].singleshoot;
|
||||
curBp.slot = slot;
|
||||
if(curBp.active)
|
||||
|
@ -607,7 +631,7 @@ extern "C" DLL_EXPORT uint _dbg_getbranchdestination(uint addr)
|
|||
|
||||
extern "C" DLL_EXPORT bool _dbg_functionoverlaps(uint start, uint end)
|
||||
{
|
||||
return functionoverlaps(start, end);
|
||||
return FunctionOverlaps(start, end);
|
||||
}
|
||||
|
||||
extern "C" DLL_EXPORT uint _dbg_sendmessage(DBGMSG type, void* param1, void* param2)
|
||||
|
@ -683,7 +707,7 @@ extern "C" DLL_EXPORT uint _dbg_sendmessage(DBGMSG type, void* param1, void* par
|
|||
case DBG_SYMBOL_ENUM:
|
||||
{
|
||||
SYMBOLCBINFO* cbInfo = (SYMBOLCBINFO*)param1;
|
||||
symenum(cbInfo->base, cbInfo->cbSymbolEnum, cbInfo->user);
|
||||
SymEnum(cbInfo->base, cbInfo->cbSymbolEnum, cbInfo->user);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -695,7 +719,7 @@ extern "C" DLL_EXPORT uint _dbg_sendmessage(DBGMSG type, void* param1, void* par
|
|||
|
||||
case DBG_MODBASE_FROM_NAME:
|
||||
{
|
||||
return modbasefromname((const char*)param1);
|
||||
return ModBaseFromName((const char*)param1);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -713,7 +737,7 @@ extern "C" DLL_EXPORT uint _dbg_sendmessage(DBGMSG type, void* param1, void* par
|
|||
|
||||
case DBG_GET_THREAD_LIST:
|
||||
{
|
||||
threadgetlist((THREADLIST*)param1);
|
||||
ThreadGetList((THREADLIST*)param1);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -724,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))
|
||||
|
@ -769,7 +794,7 @@ extern "C" DLL_EXPORT uint _dbg_sendmessage(DBGMSG type, void* param1, void* par
|
|||
if(!param1 or !param2)
|
||||
return 0;
|
||||
unsigned char data[16];
|
||||
if(!memread(fdProcessInfo->hProcess, param1, data, sizeof(data), 0))
|
||||
if(!MemRead(param1, data, sizeof(data), 0))
|
||||
return 0;
|
||||
DISASM disasm;
|
||||
memset(&disasm, 0, sizeof(disasm));
|
||||
|
@ -798,56 +823,56 @@ extern "C" DLL_EXPORT uint _dbg_sendmessage(DBGMSG type, void* param1, void* par
|
|||
case DBG_FUNCTION_GET:
|
||||
{
|
||||
FUNCTION_LOOP_INFO* info = (FUNCTION_LOOP_INFO*)param1;
|
||||
return (uint)functionget(info->addr, &info->start, &info->end);
|
||||
return (uint)FunctionGet(info->addr, &info->start, &info->end);
|
||||
}
|
||||
break;
|
||||
|
||||
case DBG_FUNCTION_OVERLAPS:
|
||||
{
|
||||
FUNCTION_LOOP_INFO* info = (FUNCTION_LOOP_INFO*)param1;
|
||||
return (uint)functionoverlaps(info->start, info->end);
|
||||
return (uint)FunctionOverlaps(info->start, info->end);
|
||||
}
|
||||
break;
|
||||
|
||||
case DBG_FUNCTION_ADD:
|
||||
{
|
||||
FUNCTION_LOOP_INFO* info = (FUNCTION_LOOP_INFO*)param1;
|
||||
return (uint)functionadd(info->start, info->end, info->manual);
|
||||
return (uint)FunctionAdd(info->start, info->end, info->manual);
|
||||
}
|
||||
break;
|
||||
|
||||
case DBG_FUNCTION_DEL:
|
||||
{
|
||||
FUNCTION_LOOP_INFO* info = (FUNCTION_LOOP_INFO*)param1;
|
||||
return (uint)functiondel(info->addr);
|
||||
return (uint)FunctionDelete(info->addr);
|
||||
}
|
||||
break;
|
||||
|
||||
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;
|
||||
|
||||
|
@ -860,7 +885,7 @@ extern "C" DLL_EXPORT uint _dbg_sendmessage(DBGMSG type, void* param1, void* par
|
|||
case DBG_IS_BP_DISABLED:
|
||||
{
|
||||
BREAKPOINT bp;
|
||||
if(bpget((uint)param1, BPNORMAL, 0, &bp))
|
||||
if(BpGet((uint)param1, BPNORMAL, 0, &bp))
|
||||
return !(uint)bp.enabled;
|
||||
return (uint)false;
|
||||
}
|
||||
|
@ -868,49 +893,49 @@ extern "C" DLL_EXPORT uint _dbg_sendmessage(DBGMSG type, void* param1, void* par
|
|||
|
||||
case DBG_SET_AUTO_COMMENT_AT:
|
||||
{
|
||||
return (uint)commentset((uint)param1, (const char*)param2, false);
|
||||
return (uint)CommentSet((uint)param1, (const char*)param2, false);
|
||||
}
|
||||
break;
|
||||
|
||||
case DBG_DELETE_AUTO_COMMENT_RANGE:
|
||||
{
|
||||
commentdelrange((uint)param1, (uint)param2);
|
||||
CommentDelRange((uint)param1, (uint)param2);
|
||||
}
|
||||
break;
|
||||
|
||||
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;
|
||||
|
||||
case DBG_SET_AUTO_BOOKMARK_AT:
|
||||
{
|
||||
return (uint)bookmarkset((uint)param1, false);
|
||||
return (uint)BookmarkSet((uint)param1, false);
|
||||
}
|
||||
break;
|
||||
|
||||
case DBG_DELETE_AUTO_BOOKMARK_RANGE:
|
||||
{
|
||||
bookmarkdelrange((uint)param1, (uint)param2);
|
||||
BookmarkDelRange((uint)param1, (uint)param2);
|
||||
}
|
||||
break;
|
||||
|
||||
case DBG_SET_AUTO_FUNCTION_AT:
|
||||
{
|
||||
return (uint)functionadd((uint)param1, (uint)param2, false);
|
||||
return (uint)FunctionAdd((uint)param1, (uint)param2, false);
|
||||
}
|
||||
break;
|
||||
|
||||
case DBG_DELETE_AUTO_FUNCTION_RANGE:
|
||||
{
|
||||
functiondelrange((uint)param1, (uint)param2);
|
||||
FunctionDelRange((uint)param1, (uint)param2);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ DLL_EXPORT bool _dbg_addrinfoget(duint addr, SEGMENTREG segment, ADDRINFO* addri
|
|||
DLL_EXPORT bool _dbg_addrinfoset(duint addr, ADDRINFO* addrinfo);
|
||||
DLL_EXPORT int _dbg_bpgettypeat(duint addr);
|
||||
DLL_EXPORT bool _dbg_getregdump(REGDUMP* regdump);
|
||||
DLL_EXPORT bool _dbg_valtostring(const char* string, duint* value);
|
||||
DLL_EXPORT bool _dbg_valtostring(const char* string, duint value);
|
||||
DLL_EXPORT int _dbg_getbplist(BPXTYPE type, BPMAP* list);
|
||||
DLL_EXPORT uint _dbg_getbranchdestination(uint addr);
|
||||
DLL_EXPORT bool _dbg_functionoverlaps(uint start, uint end);
|
||||
|
|
|
@ -1,15 +1,44 @@
|
|||
/**
|
||||
\file _global.cpp
|
||||
\brief Implements the global class.
|
||||
*/
|
||||
|
||||
#include "_global.h"
|
||||
#include <objbase.h>
|
||||
#include <shlobj.h>
|
||||
#include <new>
|
||||
|
||||
/**
|
||||
\brief x64dbg 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 x64dbg 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);
|
||||
|
@ -21,13 +50,20 @@ void* emalloc(size_t size, const char* reason)
|
|||
memset(a, 0, size);
|
||||
emalloc_count++;
|
||||
/*
|
||||
FILE* file=fopen(alloctrace, "a+");
|
||||
FILE* file = fopen(alloctrace, "a+");
|
||||
fprintf(file, "DBG%.5d: alloc:"fhex":%s:"fhex"\n", emalloc_count, a, reason, size);
|
||||
fclose(file);
|
||||
*/
|
||||
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)
|
||||
|
@ -40,34 +76,63 @@ void* erealloc(void* ptr, size_t size, const char* reason)
|
|||
}
|
||||
memset(a, 0, size);
|
||||
/*
|
||||
FILE* file=fopen(alloctrace, "a+");
|
||||
FILE* file = fopen(alloctrace, "a+");
|
||||
fprintf(file, "DBG%.5d:realloc:"fhex":%s:"fhex"\n", emalloc_count, a, reason, size);
|
||||
fclose(file);
|
||||
*/
|
||||
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--;
|
||||
/*
|
||||
FILE* file=fopen(alloctrace, "a+");
|
||||
FILE* file = fopen(alloctrace, "a+");
|
||||
fprintf(file, "DBG%.5d: free:"fhex":%s\n", emalloc_count, ptr, reason);
|
||||
fclose(file);
|
||||
*/
|
||||
GlobalFree(ptr);
|
||||
}
|
||||
|
||||
void* json_malloc(size_t size)
|
||||
{
|
||||
return emalloc(size, "json:ptr");
|
||||
}
|
||||
|
||||
void json_free(void* ptr)
|
||||
{
|
||||
efree(ptr, "json: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,6 +160,12 @@ 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)
|
||||
{
|
||||
if(_stricmp(a, b))
|
||||
|
@ -102,6 +173,10 @@ bool scmp(const char* a, const char* b)
|
|||
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);
|
||||
|
@ -111,9 +186,13 @@ void formathex(char* string)
|
|||
for(int i = 0, j = 0; i < len; i++)
|
||||
if(isxdigit(string[i]))
|
||||
j += sprintf(new_string + j, "%c", string[i]);
|
||||
strcpy(string, new_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);
|
||||
|
@ -123,21 +202,37 @@ void formatdec(char* string)
|
|||
for(int i = 0, j = 0; i < len; i++)
|
||||
if(isdigit(string[i]))
|
||||
j += sprintf(new_string + j, "%c", string[i]);
|
||||
strcpy(string, new_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"";
|
||||
|
@ -147,6 +242,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;
|
||||
|
@ -157,10 +258,15 @@ 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;
|
||||
HANDLE hFile = CreateFileW(StringUtils::Utf8ToUtf16(szFileName).c_str(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
|
||||
Handle hFile = CreateFileW(StringUtils::Utf8ToUtf16(szFileName).c_str(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
|
||||
if(hFile != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
unsigned char data[0x1000];
|
||||
|
@ -185,15 +291,18 @@ arch GetFileArchitecture(const char* szFileName)
|
|||
}
|
||||
}
|
||||
}
|
||||
CloseHandle(hFile);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Query if x64dbg is running in Wow64 mode.
|
||||
\return true if running in Wow64, false otherwise.
|
||||
*/
|
||||
bool IsWow64()
|
||||
{
|
||||
BOOL bIsWow64Process = FALSE;
|
||||
//x64_dbg supports WinXP SP3 and later only, so ignore the GetProcAddress crap :D
|
||||
//x64dbg supports WinXP SP3 and later only, so ignore the GetProcAddress crap :D
|
||||
IsWow64Process(GetCurrentProcess(), &bIsWow64Process);
|
||||
return !!bIsWow64Process;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef _GLOBAL_H
|
||||
#define _GLOBAL_H
|
||||
|
||||
#define _WIN32_WINNT 0x0501
|
||||
#define _WIN32_WINNT 0x0600
|
||||
#define WINVER 0x0501
|
||||
#define _WIN32_IE 0x0500
|
||||
|
||||
|
@ -11,23 +11,21 @@
|
|||
#include <stdlib.h>
|
||||
#include <conio.h>
|
||||
#include <windows.h>
|
||||
#include <psapi.h>
|
||||
#include <shlwapi.h>
|
||||
#include <stdarg.h>
|
||||
#include <psapi.h>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <tlhelp32.h>
|
||||
#include "..\x64_dbg_bridge\bridgemain.h"
|
||||
#include "jansson\jansson.h"
|
||||
#include "jansson\jansson_x64dbg.h"
|
||||
#include "yara\yara.h"
|
||||
#include "DeviceNameResolver\DeviceNameResolver.h"
|
||||
#include "handle.h"
|
||||
#include "stringutils.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
#include "dbghelp\dbghelp.h"
|
||||
#else
|
||||
#include <dbghelp.h>
|
||||
#endif //__GNUC__
|
||||
#include "dbghelp_safe.h"
|
||||
|
||||
#ifndef __GNUC__
|
||||
#define and &&
|
||||
|
@ -56,42 +54,6 @@ typedef unsigned long uint;
|
|||
typedef long sint;
|
||||
#endif // _WIN64
|
||||
|
||||
enum BITMASK
|
||||
{
|
||||
BIT1 = 0x1,
|
||||
BIT2 = 0x2,
|
||||
BIT3 = 0x4,
|
||||
BIT4 = 0x8,
|
||||
BIT5 = 0x10,
|
||||
BIT6 = 0x20,
|
||||
BIT7 = 0x40,
|
||||
BIT8 = 0x80,
|
||||
BIT9 = 0x100,
|
||||
BIT10 = 0x200,
|
||||
BIT11 = 0x400,
|
||||
BIT12 = 0x800,
|
||||
BIT13 = 0x1000,
|
||||
BIT14 = 0x2000,
|
||||
BIT15 = 0x4000,
|
||||
BIT16 = 0x8000,
|
||||
BIT17 = 0x10000,
|
||||
BIT18 = 0x20000,
|
||||
BIT19 = 0x40000,
|
||||
BIT20 = 0x80000,
|
||||
BIT21 = 0x100000,
|
||||
BIT22 = 0x200000,
|
||||
BIT23 = 0x400000,
|
||||
BIT24 = 0x800000,
|
||||
BIT25 = 0x1000000,
|
||||
BIT26 = 0x2000000,
|
||||
BIT27 = 0x4000000,
|
||||
BIT28 = 0x8000000,
|
||||
BIT29 = 0x10000000,
|
||||
BIT30 = 0x20000000,
|
||||
BIT31 = 0x40000000,
|
||||
BIT32 = 0x80000000
|
||||
};
|
||||
|
||||
enum arch
|
||||
{
|
||||
notfound,
|
||||
|
@ -110,6 +72,8 @@ extern char dbpath[3 * deflen];
|
|||
void* emalloc(size_t size, const char* reason = "emalloc:???");
|
||||
void* erealloc(void* ptr, size_t size, const char* reason = "erealloc:???");
|
||||
void efree(void* ptr, const char* reason = "efree:???");
|
||||
void* json_malloc(size_t size);
|
||||
void json_free(void* ptr);
|
||||
int memleaks();
|
||||
void setalloctrace(const char* file);
|
||||
bool arraycontains(const char* cmd_list, const char* cmd);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -41,6 +41,9 @@ typedef struct
|
|||
//provided by the debugger
|
||||
HWND hwndDlg; //gui window handle
|
||||
int hMenu; //plugin menu handle
|
||||
int hMenuDisasm; //plugin disasm menu handle
|
||||
int hMenuDump; //plugin dump menu handle
|
||||
int hMenuStack; //plugin stack menu handle
|
||||
} PLUG_SETUPSTRUCT;
|
||||
|
||||
//callback structures
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -10,7 +10,7 @@ typedef std::pair<int, ModuleRange> DepthModuleRange; //depth + modulerange
|
|||
|
||||
struct RangeCompare
|
||||
{
|
||||
bool operator()(const Range & a, const Range & b) const //a before b?
|
||||
bool operator()(const Range & a, const Range & b) //a before b?
|
||||
{
|
||||
return a.second < b.first;
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ struct RangeCompare
|
|||
|
||||
struct OverlappingRangeCompare
|
||||
{
|
||||
bool operator()(const Range & a, const Range & b) const //a before b?
|
||||
bool operator()(const Range & a, const Range & b) //a before b?
|
||||
{
|
||||
return a.second < b.first || a.second < b.second;
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ struct OverlappingRangeCompare
|
|||
|
||||
struct ModuleRangeCompare
|
||||
{
|
||||
bool operator()(const ModuleRange & a, const ModuleRange & b) const
|
||||
bool operator()(const ModuleRange & a, const ModuleRange & b)
|
||||
{
|
||||
if(a.first < b.first) //module hash is smaller
|
||||
return true;
|
||||
|
@ -38,7 +38,7 @@ struct ModuleRangeCompare
|
|||
|
||||
struct DepthModuleRangeCompare
|
||||
{
|
||||
bool operator()(const DepthModuleRange & a, const DepthModuleRange & b) const
|
||||
bool operator()(const DepthModuleRange & a, const DepthModuleRange & b)
|
||||
{
|
||||
if(a.first < b.first) //module depth is smaller
|
||||
return true;
|
||||
|
@ -52,72 +52,6 @@ struct DepthModuleRangeCompare
|
|||
}
|
||||
};
|
||||
|
||||
//structures
|
||||
struct MODSECTIONINFO
|
||||
{
|
||||
uint addr; //va
|
||||
uint size; //virtual size
|
||||
char name[50];
|
||||
};
|
||||
|
||||
struct MODINFO
|
||||
{
|
||||
uint base; //module base
|
||||
uint size; //module size
|
||||
uint hash; //full module name hash
|
||||
uint entry; //entry point
|
||||
char name[MAX_MODULE_SIZE]; //module name (without extension)
|
||||
char extension[MAX_MODULE_SIZE]; //file extension
|
||||
std::vector<MODSECTIONINFO> sections;
|
||||
};
|
||||
typedef std::map<Range, MODINFO, RangeCompare> ModulesInfo;
|
||||
|
||||
struct COMMENTSINFO
|
||||
{
|
||||
char mod[MAX_MODULE_SIZE];
|
||||
uint addr;
|
||||
char text[MAX_COMMENT_SIZE];
|
||||
bool manual;
|
||||
};
|
||||
typedef std::map<uint, COMMENTSINFO> CommentsInfo;
|
||||
|
||||
struct LABELSINFO
|
||||
{
|
||||
char mod[MAX_MODULE_SIZE];
|
||||
uint addr;
|
||||
char text[MAX_LABEL_SIZE];
|
||||
bool manual;
|
||||
};
|
||||
typedef std::map<uint, LABELSINFO> LabelsInfo;
|
||||
|
||||
struct BOOKMARKSINFO
|
||||
{
|
||||
char mod[MAX_MODULE_SIZE];
|
||||
uint addr;
|
||||
bool manual;
|
||||
};
|
||||
typedef std::map<uint, BOOKMARKSINFO> BookmarksInfo;
|
||||
|
||||
struct FUNCTIONSINFO
|
||||
{
|
||||
char mod[MAX_MODULE_SIZE];
|
||||
uint start;
|
||||
uint end;
|
||||
bool manual;
|
||||
};
|
||||
typedef std::map<ModuleRange, FUNCTIONSINFO, ModuleRangeCompare> FunctionsInfo;
|
||||
|
||||
struct LOOPSINFO
|
||||
{
|
||||
char mod[MAX_MODULE_SIZE];
|
||||
uint start;
|
||||
uint end;
|
||||
uint parent;
|
||||
int depth;
|
||||
bool manual;
|
||||
};
|
||||
typedef std::map<DepthModuleRange, LOOPSINFO, DepthModuleRangeCompare> LoopsInfo;
|
||||
|
||||
//typedefs
|
||||
typedef void (*EXPORTENUMCALLBACK)(uint base, const char* mod, const char* name, uint addr);
|
||||
|
||||
|
@ -125,62 +59,6 @@ void dbsave();
|
|||
void dbload();
|
||||
void dbclose();
|
||||
|
||||
bool modload(uint base, uint size, const char* fullpath);
|
||||
bool modunload(uint base);
|
||||
void modclear();
|
||||
bool modnamefromaddr(uint addr, char* modname, bool extension);
|
||||
uint modbasefromaddr(uint addr);
|
||||
uint modhashfromva(uint va);
|
||||
uint modhashfromname(const char* mod);
|
||||
uint modbasefromname(const char* modname);
|
||||
uint modsizefromaddr(uint addr);
|
||||
bool modsectionsfromaddr(uint addr, std::vector<MODSECTIONINFO>* sections);
|
||||
uint modentryfromaddr(uint addr);
|
||||
int modpathfromaddr(duint addr, char* path, int size);
|
||||
int modpathfromname(const char* modname, char* path, int size);
|
||||
|
||||
bool apienumexports(uint base, EXPORTENUMCALLBACK cbEnum);
|
||||
|
||||
bool commentset(uint addr, const char* text, bool manual);
|
||||
bool commentget(uint addr, char* text);
|
||||
bool commentdel(uint addr);
|
||||
void commentdelrange(uint start, uint end);
|
||||
void commentcachesave(JSON root);
|
||||
void commentcacheload(JSON root);
|
||||
bool commentenum(COMMENTSINFO* commentlist, size_t* cbsize);
|
||||
|
||||
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);
|
||||
|
||||
bool bookmarkset(uint addr, bool manual);
|
||||
bool bookmarkget(uint addr);
|
||||
bool bookmarkdel(uint addr);
|
||||
void bookmarkdelrange(uint start, uint end);
|
||||
void bookmarkcachesave(JSON root);
|
||||
void bookmarkcacheload(JSON root);
|
||||
bool bookmarkenum(BOOKMARKSINFO* bookmarklist, size_t* cbsize);
|
||||
|
||||
bool functionadd(uint start, uint end, bool manual);
|
||||
bool functionget(uint addr, uint* start, uint* end);
|
||||
bool functionoverlaps(uint start, uint end);
|
||||
bool functiondel(uint addr);
|
||||
void functiondelrange(uint start, uint end);
|
||||
void functioncachesave(JSON root);
|
||||
void functioncacheload(JSON root);
|
||||
bool functionenum(FUNCTIONSINFO* functionlist, size_t* cbsize);
|
||||
|
||||
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);
|
||||
|
||||
#endif // _ADDRINFO_H
|
||||
|
|
|
@ -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(command, 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(arguments, 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(arguments, 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(arguments, 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(cmd, 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(temp, 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(temp, 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(arg, temp);
|
||||
return true;
|
||||
}
|
||||
for(int i = 0, j = 0; i < len; i++)
|
||||
{
|
||||
if(!temp[i])
|
||||
j++;
|
||||
if(j == arg_num)
|
||||
{
|
||||
strcpy(arg, temp + i + 1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
#ifndef _ARGUMENT_H
|
||||
#define _ARGUMENT_H
|
||||
|
||||
#include "_global.h"
|
||||
|
||||
//functions
|
||||
bool argget(const char* cmd, char* arg, int arg_num, bool optional);
|
||||
int arggetcount(const char* cmd);
|
||||
void argformat(char* cmd);
|
||||
|
||||
#endif
|
|
@ -1,3 +1,9 @@
|
|||
/**
|
||||
@file assemble.cpp
|
||||
|
||||
@brief Implements the assemble class.
|
||||
*/
|
||||
|
||||
#include "assemble.h"
|
||||
#include "memory.h"
|
||||
#include "debugger.h"
|
||||
|
@ -30,11 +36,11 @@ bool assemble(uint addr, unsigned char* dest, int* size, const char* instruction
|
|||
#endif
|
||||
parse.cbUnknown = cbUnknown;
|
||||
parse.cip = addr;
|
||||
strcpy(parse.instr, instruction);
|
||||
strcpy_s(parse.instr, instruction);
|
||||
if(XEDParseAssemble(&parse) == XEDPARSE_ERROR)
|
||||
{
|
||||
if(error)
|
||||
strcpy(error, parse.error);
|
||||
strcpy_s(error, MAX_ERROR_SIZE, parse.error);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -63,12 +69,12 @@ bool assembleat(uint addr, const char* instruction, int* size, char* error, bool
|
|||
if(size)
|
||||
*size = destSize;
|
||||
|
||||
bool ret = mempatch(fdProcessInfo->hProcess, (void*)addr, dest, destSize, 0);
|
||||
bool ret = MemPatch((void*)addr, dest, destSize, 0);
|
||||
if(ret && fillnop && nopsize)
|
||||
{
|
||||
if(size)
|
||||
*size += nopsize;
|
||||
if(!mempatch(fdProcessInfo->hProcess, (void*)(addr + destSize), nops, nopsize, 0))
|
||||
if(!MemPatch((void*)(addr + destSize), nops, nopsize, 0))
|
||||
ret = false;
|
||||
}
|
||||
GuiUpdatePatches();
|
||||
|
|
|
@ -0,0 +1,206 @@
|
|||
#include "bookmark.h"
|
||||
#include "threading.h"
|
||||
#include "module.h"
|
||||
#include "debugger.h"
|
||||
#include "memory.h"
|
||||
|
||||
std::unordered_map<uint, BOOKMARKSINFO> bookmarks;
|
||||
|
||||
bool BookmarkSet(uint Address, bool Manual)
|
||||
{
|
||||
// CHECK: Export call
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
|
||||
// Validate the incoming address
|
||||
if(!MemIsValidReadPtr(Address))
|
||||
return false;
|
||||
|
||||
BOOKMARKSINFO bookmark;
|
||||
ModNameFromAddr(Address, bookmark.mod, true);
|
||||
bookmark.addr = Address - ModBaseFromAddr(Address);
|
||||
bookmark.manual = Manual;
|
||||
|
||||
// Exclusive lock to insert new data
|
||||
EXCLUSIVE_ACQUIRE(LockBookmarks);
|
||||
|
||||
if(!bookmarks.insert(std::make_pair(ModHashFromAddr(Address), bookmark)).second)
|
||||
return BookmarkDelete(Address);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BookmarkGet(uint Address)
|
||||
{
|
||||
// CHECK: Export call
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
|
||||
SHARED_ACQUIRE(LockBookmarks);
|
||||
return (bookmarks.count(ModHashFromAddr(Address)) > 0);
|
||||
}
|
||||
|
||||
bool BookmarkDelete(uint Address)
|
||||
{
|
||||
// CHECK: Export call
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
|
||||
EXCLUSIVE_ACQUIRE(LockBookmarks);
|
||||
return (bookmarks.erase(ModHashFromAddr(Address)) > 0);
|
||||
}
|
||||
|
||||
void BookmarkDelRange(uint Start, uint End)
|
||||
{
|
||||
// CHECK: Export call
|
||||
if(!DbgIsDebugging())
|
||||
return;
|
||||
|
||||
// Are all bookmarks going to be deleted?
|
||||
// 0x00000000 - 0xFFFFFFFF
|
||||
if(Start == 0 && End == ~0)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockBookmarks);
|
||||
bookmarks.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Make sure 'Start' and 'End' reference the same module
|
||||
uint moduleBase = ModBaseFromAddr(Start);
|
||||
|
||||
if(moduleBase != ModBaseFromAddr(End))
|
||||
return;
|
||||
|
||||
// Virtual -> relative offset
|
||||
Start -= moduleBase;
|
||||
End -= moduleBase;
|
||||
|
||||
EXCLUSIVE_ACQUIRE(LockBookmarks);
|
||||
for(auto itr = bookmarks.begin(); itr != bookmarks.end();)
|
||||
{
|
||||
// Ignore manually set entries
|
||||
if(itr->second.manual)
|
||||
{
|
||||
itr++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// [Start, End)
|
||||
if(itr->second.addr >= Start && itr->second.addr < End)
|
||||
itr = bookmarks.erase(itr);
|
||||
else
|
||||
itr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BookmarkCacheSave(JSON Root)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockBookmarks);
|
||||
|
||||
const JSON jsonBookmarks = json_array();
|
||||
const JSON jsonAutoBookmarks = json_array();
|
||||
|
||||
// Save to the JSON root
|
||||
for(auto & itr : bookmarks)
|
||||
{
|
||||
JSON currentBookmark = json_object();
|
||||
|
||||
json_object_set_new(currentBookmark, "module", json_string(itr.second.mod));
|
||||
json_object_set_new(currentBookmark, "address", json_hex(itr.second.addr));
|
||||
|
||||
if(itr.second.manual)
|
||||
json_array_append_new(jsonBookmarks, currentBookmark);
|
||||
else
|
||||
json_array_append_new(jsonAutoBookmarks, currentBookmark);
|
||||
}
|
||||
|
||||
if(json_array_size(jsonBookmarks))
|
||||
json_object_set(Root, "bookmarks", jsonBookmarks);
|
||||
|
||||
if(json_array_size(jsonAutoBookmarks))
|
||||
json_object_set(Root, "autobookmarks", jsonAutoBookmarks);
|
||||
|
||||
json_decref(jsonBookmarks);
|
||||
json_decref(jsonAutoBookmarks);
|
||||
}
|
||||
|
||||
void BookmarkCacheLoad(JSON Root)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockBookmarks);
|
||||
|
||||
// Inline lambda to parse each JSON entry
|
||||
auto AddBookmarks = [](const JSON Object, bool Manual)
|
||||
{
|
||||
size_t i;
|
||||
JSON value;
|
||||
|
||||
json_array_foreach(Object, i, value)
|
||||
{
|
||||
BOOKMARKSINFO bookmarkInfo;
|
||||
memset(&bookmarkInfo, 0, sizeof(BOOKMARKSINFO));
|
||||
|
||||
// Load the module name
|
||||
const char* mod = json_string_value(json_object_get(value, "module"));
|
||||
|
||||
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;
|
||||
|
||||
const uint key = ModHashFromName(bookmarkInfo.mod) + bookmarkInfo.addr;
|
||||
bookmarks.insert(std::make_pair(key, bookmarkInfo));
|
||||
}
|
||||
};
|
||||
|
||||
// Remove existing entries
|
||||
bookmarks.clear();
|
||||
|
||||
const JSON jsonBookmarks = json_object_get(Root, "bookmarks");
|
||||
const JSON jsonAutoBookmarks = json_object_get(Root, "autobookmarks");
|
||||
|
||||
// Load user-set bookmarks
|
||||
if(jsonBookmarks)
|
||||
AddBookmarks(jsonBookmarks, true);
|
||||
|
||||
// Load auto-set bookmarks
|
||||
if(jsonAutoBookmarks)
|
||||
AddBookmarks(jsonAutoBookmarks, false);
|
||||
}
|
||||
|
||||
bool BookmarkEnum(BOOKMARKSINFO* List, size_t* Size)
|
||||
{
|
||||
// The array container must be set, or the size must be set, or both
|
||||
if(!List && !Size)
|
||||
return false;
|
||||
|
||||
SHARED_ACQUIRE(LockBookmarks);
|
||||
|
||||
// Return the size if set
|
||||
if(Size)
|
||||
{
|
||||
*Size = bookmarks.size() * sizeof(BOOKMARKSINFO);
|
||||
|
||||
if(!List)
|
||||
return true;
|
||||
}
|
||||
|
||||
// Copy struct and adjust the relative offset to a virtual address
|
||||
for(auto & itr : bookmarks)
|
||||
{
|
||||
*List = itr.second;
|
||||
List->addr += ModBaseFromName(List->mod);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void BookmarkClear()
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockBookmarks);
|
||||
bookmarks.clear();
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
#include "_global.h"
|
||||
|
||||
struct BOOKMARKSINFO
|
||||
{
|
||||
char mod[MAX_MODULE_SIZE];
|
||||
uint addr;
|
||||
bool manual;
|
||||
};
|
||||
|
||||
bool BookmarkSet(uint Address, bool Manual);
|
||||
bool BookmarkGet(uint Address);
|
||||
bool BookmarkDelete(uint Address);
|
||||
void BookmarkDelRange(uint Start, uint End);
|
||||
void BookmarkCacheSave(JSON Root);
|
||||
void BookmarkCacheLoad(JSON Root);
|
||||
bool BookmarkEnum(BOOKMARKSINFO* List, size_t* Size);
|
||||
void BookmarkClear();
|
|
@ -1,272 +1,399 @@
|
|||
/**
|
||||
@file breakpoint.cpp
|
||||
|
||||
@brief Implements the breakpoint class.
|
||||
*/
|
||||
|
||||
#include "breakpoint.h"
|
||||
#include "debugger.h"
|
||||
#include "addrinfo.h"
|
||||
#include "console.h"
|
||||
#include "memory.h"
|
||||
#include "threading.h"
|
||||
#include "module.h"
|
||||
|
||||
static BreakpointsInfo breakpoints;
|
||||
typedef std::pair<BP_TYPE, uint> BreakpointKey;
|
||||
std::map<BreakpointKey, BREAKPOINT> breakpoints;
|
||||
|
||||
int bpgetlist(std::vector<BREAKPOINT>* list)
|
||||
BREAKPOINT* BpInfoFromAddr(BP_TYPE Type, uint Address)
|
||||
{
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
BREAKPOINT curBp;
|
||||
int count = 0;
|
||||
CriticalSectionLocker locker(LockBreakpoints);
|
||||
for(BreakpointsInfo::iterator i = breakpoints.begin(); i != breakpoints.end(); ++i)
|
||||
{
|
||||
curBp = i->second;
|
||||
curBp.addr += modbasefromname(curBp.mod);
|
||||
curBp.active = memisvalidreadptr(fdProcessInfo->hProcess, curBp.addr);
|
||||
count++;
|
||||
if(list)
|
||||
list->push_back(curBp);
|
||||
}
|
||||
return count;
|
||||
//
|
||||
// NOTE: THIS DOES _NOT_ USE LOCKS
|
||||
//
|
||||
auto found = breakpoints.find(BreakpointKey(Type, ModHashFromAddr(Address)));
|
||||
|
||||
// Was the module found with this address?
|
||||
if(found == breakpoints.end())
|
||||
return nullptr;
|
||||
|
||||
return &found->second;
|
||||
}
|
||||
|
||||
bool bpnew(uint addr, bool enabled, bool singleshoot, short oldbytes, BP_TYPE type, DWORD titantype, const char* name)
|
||||
int BpGetList(std::vector<BREAKPOINT>* List)
|
||||
{
|
||||
if(!DbgIsDebugging() or !memisvalidreadptr(fdProcessInfo->hProcess, addr) or bpget(addr, type, name, 0))
|
||||
// CHECK: Exported function
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
|
||||
SHARED_ACQUIRE(LockBreakpoints);
|
||||
|
||||
// Did the caller request an output?
|
||||
if(List)
|
||||
{
|
||||
// Enumerate all breakpoints in the global list, fixing the relative
|
||||
// offset to a virtual address
|
||||
for(auto & i : breakpoints)
|
||||
{
|
||||
BREAKPOINT currentBp = i.second;
|
||||
currentBp.addr += ModBaseFromName(currentBp.mod);
|
||||
currentBp.active = MemIsValidReadPtr(currentBp.addr);
|
||||
|
||||
List->push_back(currentBp);
|
||||
}
|
||||
}
|
||||
|
||||
return (int)breakpoints.size();
|
||||
}
|
||||
|
||||
bool BpNew(uint Address, bool Enable, bool Singleshot, short OldBytes, BP_TYPE Type, DWORD TitanType, const char* Name)
|
||||
{
|
||||
// CHECK: Command function
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
|
||||
// Fail if the address is a bad memory region
|
||||
if(!MemIsValidReadPtr(Address))
|
||||
return false;
|
||||
|
||||
// Fail if the breakpoint already exists
|
||||
if(BpGet(Address, Type, Name, nullptr))
|
||||
return false;
|
||||
|
||||
// Default to an empty name if one wasn't supplied
|
||||
if(!Name)
|
||||
Name = "";
|
||||
|
||||
BREAKPOINT bp;
|
||||
modnamefromaddr(addr, bp.mod, true);
|
||||
uint modbase = modbasefromaddr(addr);
|
||||
memset(&bp, 0, sizeof(BREAKPOINT));
|
||||
|
||||
ModNameFromAddr(Address, bp.mod, true);
|
||||
strcpy_s(bp.name, Name);
|
||||
|
||||
bp.active = true;
|
||||
bp.addr = addr - modbase;
|
||||
bp.enabled = enabled;
|
||||
if(name and * name)
|
||||
strcpy_s(bp.name, name);
|
||||
else
|
||||
*bp.name = '\0';
|
||||
bp.oldbytes = oldbytes;
|
||||
bp.singleshoot = singleshoot;
|
||||
bp.titantype = titantype;
|
||||
bp.type = type;
|
||||
CriticalSectionLocker locker(LockBreakpoints);
|
||||
breakpoints.insert(std::make_pair(BreakpointKey(type, modhashfromva(addr)), bp));
|
||||
bp.addr = Address - ModBaseFromAddr(Address);
|
||||
bp.enabled = Enable;
|
||||
bp.oldbytes = OldBytes;
|
||||
bp.singleshoot = Singleshot;
|
||||
bp.titantype = TitanType;
|
||||
bp.type = Type;
|
||||
|
||||
// Insert new entry to the global list
|
||||
EXCLUSIVE_ACQUIRE(LockBreakpoints);
|
||||
|
||||
breakpoints.insert(std::make_pair(BreakpointKey(Type, ModHashFromAddr(Address)), bp));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bpget(uint addr, BP_TYPE type, const char* name, BREAKPOINT* bp)
|
||||
bool BpGet(uint Address, BP_TYPE Type, const char* Name, BREAKPOINT* Bp)
|
||||
{
|
||||
// CHECK: Export/Command function
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
BREAKPOINT curBp;
|
||||
CriticalSectionLocker locker(LockBreakpoints);
|
||||
if(!name)
|
||||
|
||||
SHARED_ACQUIRE(LockBreakpoints);
|
||||
|
||||
// Name is optional
|
||||
if(!Name || Name[0] == '\0')
|
||||
{
|
||||
BreakpointsInfo::iterator found = breakpoints.find(BreakpointKey(type, modhashfromva(addr)));
|
||||
if(found == breakpoints.end()) //not found
|
||||
// Perform a lookup by address only
|
||||
BREAKPOINT* bpInfo = BpInfoFromAddr(Type, Address);
|
||||
|
||||
if(!bpInfo)
|
||||
return false;
|
||||
if(!bp)
|
||||
|
||||
// Succeed even if the user didn't request anything
|
||||
if(!Bp)
|
||||
return true;
|
||||
curBp = found->second;
|
||||
curBp.addr += modbasefromaddr(addr);
|
||||
curBp.active = memisvalidreadptr(fdProcessInfo->hProcess, curBp.addr);
|
||||
*bp = curBp;
|
||||
|
||||
*Bp = *bpInfo;
|
||||
Bp->addr += ModBaseFromAddr(Address);
|
||||
Bp->active = MemIsValidReadPtr(Bp->addr);
|
||||
return true;
|
||||
}
|
||||
for(BreakpointsInfo::iterator i = breakpoints.begin(); i != breakpoints.end(); ++i)
|
||||
|
||||
// Do a lookup by breakpoint name
|
||||
for(auto & i : breakpoints)
|
||||
{
|
||||
curBp = i->second;
|
||||
if(name and * name)
|
||||
// Do the names match?
|
||||
if(strcmp(Name, i.second.name) != 0)
|
||||
continue;
|
||||
|
||||
// Fill out the optional user buffer
|
||||
if(Bp)
|
||||
{
|
||||
if(!strcmp(name, curBp.name))
|
||||
{
|
||||
if(bp)
|
||||
{
|
||||
curBp.addr += modbasefromname(curBp.mod);
|
||||
curBp.active = memisvalidreadptr(fdProcessInfo->hProcess, curBp.addr);
|
||||
*bp = curBp;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
*Bp = i.second;
|
||||
Bp->addr += ModBaseFromAddr(Address);
|
||||
Bp->active = MemIsValidReadPtr(Bp->addr);
|
||||
}
|
||||
|
||||
// Return true if the name was found at all
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bpdel(uint addr, BP_TYPE type)
|
||||
bool BpDelete(uint Address, BP_TYPE Type)
|
||||
{
|
||||
// CHECK: Command function
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
CriticalSectionLocker locker(LockBreakpoints);
|
||||
return (breakpoints.erase(BreakpointKey(type, modhashfromva(addr))) > 0);
|
||||
|
||||
// Erase the index from the global list
|
||||
EXCLUSIVE_ACQUIRE(LockBreakpoints);
|
||||
|
||||
return (breakpoints.erase(BreakpointKey(Type, ModHashFromAddr(Address))) > 0);
|
||||
}
|
||||
|
||||
bool bpenable(uint addr, BP_TYPE type, bool enable)
|
||||
bool BpEnable(uint Address, BP_TYPE Type, bool Enable)
|
||||
{
|
||||
// CHECK: Command function
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
CriticalSectionLocker locker(LockBreakpoints);
|
||||
BreakpointsInfo::iterator found = breakpoints.find(BreakpointKey(type, modhashfromva(addr)));
|
||||
if(found == breakpoints.end()) //not found
|
||||
|
||||
EXCLUSIVE_ACQUIRE(LockBreakpoints);
|
||||
|
||||
// Check if the breakpoint exists first
|
||||
BREAKPOINT* bpInfo = BpInfoFromAddr(Type, Address);
|
||||
|
||||
if(!bpInfo)
|
||||
return false;
|
||||
breakpoints[found->first].enabled = enable;
|
||||
|
||||
bpInfo->enabled = Enable;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bpsetname(uint addr, BP_TYPE type, const char* name)
|
||||
bool BpSetName(uint Address, BP_TYPE Type, const char* Name)
|
||||
{
|
||||
if(!DbgIsDebugging() or !name or !*name)
|
||||
// CHECK: Future(?); This is not used anywhere
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
CriticalSectionLocker locker(LockBreakpoints);
|
||||
BreakpointsInfo::iterator found = breakpoints.find(BreakpointKey(type, modhashfromva(addr)));
|
||||
if(found == breakpoints.end()) //not found
|
||||
|
||||
// If a name wasn't supplied, set to nothing
|
||||
if(!Name)
|
||||
Name = "";
|
||||
|
||||
EXCLUSIVE_ACQUIRE(LockBreakpoints);
|
||||
|
||||
// Check if the breakpoint exists first
|
||||
BREAKPOINT* bpInfo = BpInfoFromAddr(Type, Address);
|
||||
|
||||
if(!bpInfo)
|
||||
return false;
|
||||
strcpy_s(breakpoints[found->first].name, name);
|
||||
|
||||
strcpy_s(bpInfo->name, Name);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bpsettitantype(uint addr, BP_TYPE type, int titantype)
|
||||
bool BpSetTitanType(uint Address, BP_TYPE Type, int TitanType)
|
||||
{
|
||||
// CHECK: Command function
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
CriticalSectionLocker locker(LockBreakpoints);
|
||||
BreakpointsInfo::iterator found = breakpoints.find(BreakpointKey(type, modhashfromva(addr)));
|
||||
if(found == breakpoints.end()) //not found
|
||||
|
||||
EXCLUSIVE_ACQUIRE(LockBreakpoints);
|
||||
|
||||
// Set the TitanEngine type, separate from BP_TYPE
|
||||
BREAKPOINT* bpInfo = BpInfoFromAddr(Type, Address);
|
||||
|
||||
if(!bpInfo)
|
||||
return false;
|
||||
breakpoints[found->first].titantype = titantype;
|
||||
|
||||
bpInfo->titantype = TitanType;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bpenumall(BPENUMCALLBACK cbEnum, const char* module)
|
||||
bool BpEnumAll(BPENUMCALLBACK EnumCallback, const char* Module)
|
||||
{
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
bool retval = true;
|
||||
BREAKPOINT curBp;
|
||||
CriticalSectionLocker locker(LockBreakpoints);
|
||||
BreakpointsInfo::iterator i = breakpoints.begin();
|
||||
while(i != breakpoints.end())
|
||||
|
||||
SHARED_ACQUIRE(LockBreakpoints);
|
||||
|
||||
// Loop each entry, executing the user's callback
|
||||
bool callbackStatus = false;
|
||||
|
||||
for(auto & i : breakpoints)
|
||||
{
|
||||
BreakpointsInfo::iterator j = i;
|
||||
++i;
|
||||
curBp = j->second;
|
||||
curBp.addr += modbasefromname(curBp.mod); //RVA to VA
|
||||
curBp.active = memisvalidreadptr(fdProcessInfo->hProcess, curBp.addr); //TODO: wtf am I doing?
|
||||
if(module and * module)
|
||||
// If a module name was sent, check it
|
||||
if(Module && Module[0] != '\0')
|
||||
{
|
||||
if(!strcmp(curBp.mod, module))
|
||||
{
|
||||
if(!cbEnum(&curBp))
|
||||
retval = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!cbEnum(&curBp))
|
||||
retval = false;
|
||||
if(strcmp(i.second.mod, Module) != 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
BREAKPOINT bpInfo = i.second;
|
||||
bpInfo.addr += ModBaseFromName(bpInfo.mod);
|
||||
bpInfo.active = MemIsValidReadPtr(bpInfo.addr);
|
||||
|
||||
// Execute the callback
|
||||
if(!EnumCallback(&bpInfo))
|
||||
callbackStatus = false;
|
||||
}
|
||||
return retval;
|
||||
|
||||
return callbackStatus;
|
||||
}
|
||||
|
||||
bool bpenumall(BPENUMCALLBACK cbEnum)
|
||||
bool BpEnumAll(BPENUMCALLBACK EnumCallback)
|
||||
{
|
||||
return bpenumall(cbEnum, 0);
|
||||
return BpEnumAll(EnumCallback, nullptr);
|
||||
}
|
||||
|
||||
int bpgetcount(BP_TYPE type, bool enabledonly)
|
||||
int BpGetCount(BP_TYPE Type, bool EnabledOnly)
|
||||
{
|
||||
SHARED_ACQUIRE(LockBreakpoints);
|
||||
|
||||
// Count the number of enabled/disabled breakpoint types
|
||||
int count = 0;
|
||||
CriticalSectionLocker locker(LockBreakpoints);
|
||||
for(BreakpointsInfo::iterator i = breakpoints.begin(); i != breakpoints.end(); ++i)
|
||||
|
||||
for(auto & i : breakpoints)
|
||||
{
|
||||
if(i->first.first == type && (!enabledonly || i->second.enabled))
|
||||
count++;
|
||||
// Check if the type matches
|
||||
if(i.first.first != Type)
|
||||
continue;
|
||||
|
||||
// If it's not enabled, skip it
|
||||
if(EnabledOnly && !i.second.enabled)
|
||||
continue;
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
void bptobridge(const BREAKPOINT* bp, BRIDGEBP* bridge)
|
||||
void BpToBridge(const BREAKPOINT* Bp, BRIDGEBP* BridgeBp)
|
||||
{
|
||||
if(!bp or !bridge)
|
||||
//
|
||||
// Convert a debugger breakpoint to an open/exported
|
||||
// bridge breakpoint
|
||||
//
|
||||
// TOOD: ASSERT(?) These should never be null
|
||||
if(!Bp || !BridgeBp)
|
||||
return;
|
||||
memset(bridge, 0, sizeof(BRIDGEBP));
|
||||
bridge->active = bp->active;
|
||||
bridge->addr = bp->addr;
|
||||
bridge->enabled = bp->enabled;
|
||||
strcpy(bridge->mod, bp->mod);
|
||||
strcpy(bridge->name, bp->name);
|
||||
bridge->singleshoot = bp->singleshoot;
|
||||
switch(bp->type)
|
||||
|
||||
memset(BridgeBp, 0, sizeof(BRIDGEBP));
|
||||
strcpy_s(BridgeBp->mod, Bp->mod);
|
||||
strcpy_s(BridgeBp->name, Bp->name);
|
||||
|
||||
BridgeBp->active = Bp->active;
|
||||
BridgeBp->addr = Bp->addr;
|
||||
BridgeBp->enabled = Bp->enabled;
|
||||
BridgeBp->singleshoot = Bp->singleshoot;
|
||||
|
||||
switch(Bp->type)
|
||||
{
|
||||
case BPNORMAL:
|
||||
bridge->type = bp_normal;
|
||||
BridgeBp->type = bp_normal;
|
||||
break;
|
||||
case BPHARDWARE:
|
||||
bridge->type = bp_hardware;
|
||||
BridgeBp->type = bp_hardware;
|
||||
break;
|
||||
case BPMEMORY:
|
||||
bridge->type = bp_memory;
|
||||
break; //so that's why it didn't show in the gui.
|
||||
BridgeBp->type = bp_memory;
|
||||
break;
|
||||
default:
|
||||
bridge->type = bp_none;
|
||||
BridgeBp->type = bp_none;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bpcachesave(JSON root)
|
||||
void BpCacheSave(JSON Root)
|
||||
{
|
||||
CriticalSectionLocker locker(LockBreakpoints);
|
||||
const JSON jsonbreakpoints = json_array();
|
||||
for(BreakpointsInfo::iterator i = breakpoints.begin(); i != breakpoints.end(); ++i)
|
||||
EXCLUSIVE_ACQUIRE(LockBreakpoints);
|
||||
|
||||
// Create a JSON array to store each sub-object with a breakpoint
|
||||
const JSON jsonBreakpoints = json_array();
|
||||
|
||||
// Loop all breakpoints
|
||||
for(auto & i : breakpoints)
|
||||
{
|
||||
const BREAKPOINT curBreakpoint = i->second;
|
||||
if(curBreakpoint.singleshoot)
|
||||
continue; //skip
|
||||
JSON curjsonbreakpoint = json_object();
|
||||
json_object_set_new(curjsonbreakpoint, "address", json_hex(curBreakpoint.addr));
|
||||
json_object_set_new(curjsonbreakpoint, "enabled", json_boolean(curBreakpoint.enabled));
|
||||
if(curBreakpoint.type == BPNORMAL)
|
||||
json_object_set_new(curjsonbreakpoint, "oldbytes", json_hex(curBreakpoint.oldbytes));
|
||||
json_object_set_new(curjsonbreakpoint, "type", json_integer(curBreakpoint.type));
|
||||
json_object_set_new(curjsonbreakpoint, "titantype", json_hex(curBreakpoint.titantype));
|
||||
json_object_set_new(curjsonbreakpoint, "name", json_string(curBreakpoint.name));
|
||||
json_object_set_new(curjsonbreakpoint, "module", json_string(curBreakpoint.mod));
|
||||
json_array_append_new(jsonbreakpoints, curjsonbreakpoint);
|
||||
auto & breakpoint = i.second;
|
||||
|
||||
// Ignore single-shot breakpoints
|
||||
if(breakpoint.singleshoot)
|
||||
continue;
|
||||
|
||||
JSON jsonObj = json_object();
|
||||
json_object_set_new(jsonObj, "address", json_hex(breakpoint.addr));
|
||||
json_object_set_new(jsonObj, "enabled", json_boolean(breakpoint.enabled));
|
||||
|
||||
// "Normal" breakpoints save the old data
|
||||
if(breakpoint.type == BPNORMAL)
|
||||
json_object_set_new(jsonObj, "oldbytes", json_hex(breakpoint.oldbytes));
|
||||
|
||||
json_object_set_new(jsonObj, "type", json_integer(breakpoint.type));
|
||||
json_object_set_new(jsonObj, "titantype", json_hex(breakpoint.titantype));
|
||||
json_object_set_new(jsonObj, "name", json_string(breakpoint.name));
|
||||
json_object_set_new(jsonObj, "module", json_string(breakpoint.mod));
|
||||
json_array_append_new(jsonBreakpoints, jsonObj);
|
||||
}
|
||||
if(json_array_size(jsonbreakpoints))
|
||||
json_object_set(root, "breakpoints", jsonbreakpoints);
|
||||
json_decref(jsonbreakpoints);
|
||||
|
||||
if(json_array_size(jsonBreakpoints))
|
||||
json_object_set(Root, "breakpoints", jsonBreakpoints);
|
||||
|
||||
// Notify garbage collector
|
||||
json_decref(jsonBreakpoints);
|
||||
}
|
||||
|
||||
void bpcacheload(JSON root)
|
||||
void BpCacheLoad(JSON Root)
|
||||
{
|
||||
CriticalSectionLocker locker(LockBreakpoints);
|
||||
EXCLUSIVE_ACQUIRE(LockBreakpoints);
|
||||
|
||||
// Remove all existing elements
|
||||
breakpoints.clear();
|
||||
const JSON jsonbreakpoints = json_object_get(root, "breakpoints");
|
||||
if(jsonbreakpoints)
|
||||
|
||||
// Get a handle to the root object -> breakpoints subtree
|
||||
const JSON jsonBreakpoints = json_object_get(Root, "breakpoints");
|
||||
|
||||
// Return if there was nothing to load
|
||||
if(!jsonBreakpoints)
|
||||
return;
|
||||
|
||||
size_t i;
|
||||
JSON value;
|
||||
json_array_foreach(jsonBreakpoints, i, value)
|
||||
{
|
||||
size_t i;
|
||||
JSON value;
|
||||
json_array_foreach(jsonbreakpoints, i, value)
|
||||
{
|
||||
BREAKPOINT curBreakpoint;
|
||||
memset(&curBreakpoint, 0, sizeof(BREAKPOINT));
|
||||
curBreakpoint.type = (BP_TYPE)json_integer_value(json_object_get(value, "type"));
|
||||
if(curBreakpoint.type == BPNORMAL)
|
||||
curBreakpoint.oldbytes = (short)json_hex_value(json_object_get(value, "oldbytes"));
|
||||
curBreakpoint.addr = (uint)json_hex_value(json_object_get(value, "address"));
|
||||
curBreakpoint.enabled = json_boolean_value(json_object_get(value, "enabled"));
|
||||
curBreakpoint.titantype = (DWORD)json_hex_value(json_object_get(value, "titantype"));
|
||||
const char* name = json_string_value(json_object_get(value, "name"));
|
||||
if(name)
|
||||
strcpy_s(curBreakpoint.name, name);
|
||||
const char* mod = json_string_value(json_object_get(value, "module"));
|
||||
if(mod && *mod && strlen(mod) < MAX_MODULE_SIZE)
|
||||
strcpy_s(curBreakpoint.mod, mod);
|
||||
const uint key = modhashfromname(curBreakpoint.mod) + curBreakpoint.addr;
|
||||
breakpoints.insert(std::make_pair(BreakpointKey(curBreakpoint.type, key), curBreakpoint));
|
||||
}
|
||||
BREAKPOINT breakpoint;
|
||||
memset(&breakpoint, 0, sizeof(BREAKPOINT));
|
||||
|
||||
if(breakpoint.type == BPNORMAL)
|
||||
breakpoint.oldbytes = (short)json_hex_value(json_object_get(value, "oldbytes"));
|
||||
breakpoint.type = (BP_TYPE)json_integer_value(json_object_get(value, "type"));
|
||||
breakpoint.addr = (uint)json_hex_value(json_object_get(value, "address"));
|
||||
breakpoint.enabled = json_boolean_value(json_object_get(value, "enabled"));
|
||||
breakpoint.titantype = (DWORD)json_hex_value(json_object_get(value, "titantype"));
|
||||
|
||||
// Name
|
||||
const char* name = json_string_value(json_object_get(value, "name"));
|
||||
|
||||
if(name)
|
||||
strcpy_s(breakpoint.name, name);
|
||||
|
||||
// Module
|
||||
const char* mod = json_string_value(json_object_get(value, "module"));
|
||||
|
||||
if(mod && *mod && strlen(mod) < MAX_MODULE_SIZE)
|
||||
strcpy_s(breakpoint.mod, mod);
|
||||
|
||||
// Build the hash map key: MOD_HASH + ADDRESS
|
||||
const uint key = ModHashFromName(breakpoint.mod) + breakpoint.addr;
|
||||
breakpoints.insert(std::make_pair(BreakpointKey(breakpoint.type, key), breakpoint));
|
||||
}
|
||||
}
|
||||
|
||||
void bpclear()
|
||||
void BpClear()
|
||||
{
|
||||
CriticalSectionLocker locker(LockBreakpoints);
|
||||
BreakpointsInfo().swap(breakpoints);
|
||||
EXCLUSIVE_ACQUIRE(LockBreakpoints);
|
||||
breakpoints.clear();
|
||||
}
|
|
@ -1,10 +1,8 @@
|
|||
#ifndef _BREAKPOINT_H
|
||||
#define _BREAKPOINT_H
|
||||
#pragma once
|
||||
|
||||
#include "_global.h"
|
||||
#include "TitanEngine\TitanEngine.h"
|
||||
|
||||
//macros
|
||||
#define TITANSETDRX(titantype, drx) titantype &= 0x0FF; titantype |= (drx<<8)
|
||||
#define TITANGETDRX(titantype) (titantype >> 8) & 0xF
|
||||
#define TITANSETTYPE(titantype, type) titantype &= 0xF0F; titantype |= (type<<4)
|
||||
|
@ -12,7 +10,6 @@
|
|||
#define TITANSETSIZE(titantype, size) titantype &= 0xFF0; titantype |= size;
|
||||
#define TITANGETSIZE(titantype) titantype & 0xF
|
||||
|
||||
//enums
|
||||
enum BP_TYPE
|
||||
{
|
||||
BPNORMAL = 0,
|
||||
|
@ -20,7 +17,6 @@ enum BP_TYPE
|
|||
BPMEMORY = 2
|
||||
};
|
||||
|
||||
//structs
|
||||
struct BREAKPOINT
|
||||
{
|
||||
uint addr;
|
||||
|
@ -34,25 +30,21 @@ struct BREAKPOINT
|
|||
char mod[MAX_MODULE_SIZE];
|
||||
};
|
||||
|
||||
//typedefs
|
||||
// Breakpoint enumeration callback
|
||||
typedef bool (*BPENUMCALLBACK)(const BREAKPOINT* bp);
|
||||
typedef std::pair<BP_TYPE, uint> BreakpointKey;
|
||||
typedef std::map<BreakpointKey, BREAKPOINT> BreakpointsInfo;
|
||||
|
||||
//functions
|
||||
int bpgetlist(std::vector<BREAKPOINT>* list);
|
||||
bool bpnew(uint addr, bool enabled, bool singleshoot, short oldbytes, BP_TYPE type, DWORD titantype, const char* name);
|
||||
bool bpget(uint addr, BP_TYPE type, const char* name, BREAKPOINT* bp);
|
||||
bool bpdel(uint addr, BP_TYPE type);
|
||||
bool bpenable(uint addr, BP_TYPE type, bool enable);
|
||||
bool bpsetname(uint addr, BP_TYPE type, const char* name);
|
||||
bool bpsettitantype(uint addr, BP_TYPE type, int titantype);
|
||||
bool bpenumall(BPENUMCALLBACK cbEnum);
|
||||
bool bpenumall(BPENUMCALLBACK cbEnum, const char* module);
|
||||
int bpgetcount(BP_TYPE type, bool enabledonly = false);
|
||||
void bptobridge(const BREAKPOINT* bp, BRIDGEBP* bridge);
|
||||
void bpcachesave(JSON root);
|
||||
void bpcacheload(JSON root);
|
||||
void bpclear();
|
||||
|
||||
#endif // _BREAKPOINT_H
|
||||
BREAKPOINT* BpInfoFromAddr(BP_TYPE Type, uint Address);
|
||||
int BpGetList(std::vector<BREAKPOINT>* List);
|
||||
bool BpNew(uint Address, bool Enable, bool Singleshot, short OldBytes, BP_TYPE Type, DWORD TitanType, const char* Name);
|
||||
bool BpGet(uint Address, BP_TYPE Type, const char* Name, BREAKPOINT* Bp);
|
||||
bool BpDelete(uint Address, BP_TYPE Type);
|
||||
bool BpEnable(uint Address, BP_TYPE Type, bool Enable);
|
||||
bool BpSetName(uint Address, BP_TYPE Type, const char* Name);
|
||||
bool BpSetTitanType(uint Address, BP_TYPE Type, int TitanType);
|
||||
bool BpEnumAll(BPENUMCALLBACK EnumCallback, const char* Module);
|
||||
bool BpEnumAll(BPENUMCALLBACK EnumCallback);
|
||||
int BpGetCount(BP_TYPE Type, bool EnabledOnly = false);
|
||||
void BpToBridge(const BREAKPOINT* Bp, BRIDGEBP* BridgeBp);
|
||||
void BpCacheSave(JSON Root);
|
||||
void BpCacheLoad(JSON Root);
|
||||
void BpClear();
|
|
@ -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,10 +101,16 @@ 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] = "";
|
||||
strcpy_s(new_cmd, cmd);
|
||||
strcpy_s(new_cmd, deflen, cmd);
|
||||
int len = (int)strlen(new_cmd);
|
||||
int start = 0;
|
||||
while(new_cmd[start] != ' ' and start < len)
|
||||
|
@ -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_s(command, StringUtils::Trim(cmd).c_str());
|
||||
COMMAND* found = cmdfindmain(cmd_list, command);
|
||||
if(!found or !found->cbCommand)
|
||||
return STATUS_ERROR;
|
||||
if(found->debugonly and !DbgIsDebugging())
|
||||
return STATUS_ERROR;
|
||||
int argcount = arggetcount(command);
|
||||
Command cmdParsed(command);
|
||||
int argcount = cmdParsed.GetArgCount();
|
||||
char** argv = (char**)emalloc((argcount + 1) * sizeof(char*), "cmddirectexec:argv");
|
||||
argv[0] = command;
|
||||
for(int i = 0; i < argcount; i++)
|
||||
{
|
||||
argv[i + 1] = (char*)emalloc(deflen, "cmddirectexec:argv[i+1]");
|
||||
*argv[i + 1] = 0;
|
||||
argget(command, argv[i + 1], i, true);
|
||||
strcpy_s(argv[i + 1], deflen, cmdParsed.GetArg(i).c_str());
|
||||
}
|
||||
CMDRESULT res = found->cbCommand(argcount + 1, argv);
|
||||
for(int i = 0; i < argcount; i++)
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
#include "commandparser.h"
|
||||
|
||||
Command::Command(const String & command)
|
||||
{
|
||||
ParseState state = Default;
|
||||
int len = (int)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() ? (int)_tokens.size() - 1 : 0;
|
||||
}
|
||||
|
||||
const String Command::GetArg(int argnum)
|
||||
{
|
||||
return (int)_tokens.size() < argnum + 1 ? String() : _tokens[argnum + 1];
|
||||
}
|
||||
|
||||
void Command::dataAppend(const char ch)
|
||||
{
|
||||
_data += ch;
|
||||
}
|
||||
|
||||
void Command::dataFinish()
|
||||
{
|
||||
if(_data.length())
|
||||
{
|
||||
_tokens.push_back(_data);
|
||||
_data = "";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
#ifndef _COMMANDPARSER_H
|
||||
#define _COMMANDPARSER_H
|
||||
|
||||
#include "_global.h"
|
||||
|
||||
class Command
|
||||
{
|
||||
public:
|
||||
Command(const String & command);
|
||||
const String GetText();
|
||||
const String GetArg(const int argnum);
|
||||
const int GetArgCount();
|
||||
|
||||
private:
|
||||
String _data;
|
||||
std::vector<String> _tokens;
|
||||
|
||||
enum ParseState
|
||||
{
|
||||
Default,
|
||||
Escaped,
|
||||
Text,
|
||||
TextEscaped
|
||||
};
|
||||
|
||||
void dataFinish();
|
||||
void dataAppend(const char ch);
|
||||
};
|
||||
|
||||
#endif // _COMMANDPARSER_H
|
|
@ -0,0 +1,248 @@
|
|||
#include "comment.h"
|
||||
#include "threading.h"
|
||||
#include "module.h"
|
||||
#include "debugger.h"
|
||||
#include "memory.h"
|
||||
|
||||
std::unordered_map<uint, COMMENTSINFO> comments;
|
||||
|
||||
bool CommentSet(uint Address, const char* Text, bool Manual)
|
||||
{
|
||||
// CHECK: Exported/Command function
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
|
||||
// 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_COMMENT_SIZE - 1)
|
||||
return false;
|
||||
|
||||
// Delete the comment if no text was supplied
|
||||
if(Text[0] == '\0')
|
||||
return CommentDelete(Address);
|
||||
|
||||
// Fill out the structure
|
||||
COMMENTSINFO comment;
|
||||
strcpy_s(comment.text, Text);
|
||||
ModNameFromAddr(Address, comment.mod, true);
|
||||
|
||||
comment.manual = Manual;
|
||||
comment.addr = Address - ModBaseFromAddr(Address);
|
||||
|
||||
// Insert into list
|
||||
const uint key = ModHashFromAddr(Address);
|
||||
|
||||
EXCLUSIVE_ACQUIRE(LockComments);
|
||||
|
||||
// Insert if possible, otherwise replace
|
||||
if(!comments.insert(std::make_pair(key, comment)).second)
|
||||
comments[key] = comment;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CommentGet(uint Address, char* Text)
|
||||
{
|
||||
// CHECK: Exported/Command function
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
|
||||
SHARED_ACQUIRE(LockComments);
|
||||
|
||||
// Get an existing comment and copy the string buffer
|
||||
auto found = comments.find(ModHashFromAddr(Address));
|
||||
|
||||
// Was it found?
|
||||
if(found == comments.end())
|
||||
return false;
|
||||
|
||||
strcpy_s(Text, MAX_COMMENT_SIZE, found->second.text);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CommentDelete(uint Address)
|
||||
{
|
||||
// CHECK: Command/Sub function
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
|
||||
EXCLUSIVE_ACQUIRE(LockComments);
|
||||
return (comments.erase(ModHashFromAddr(Address)) > 0);
|
||||
}
|
||||
|
||||
void CommentDelRange(uint Start, uint End)
|
||||
{
|
||||
// CHECK: Export function
|
||||
if(!DbgIsDebugging())
|
||||
return;
|
||||
|
||||
// Are all comments going to be deleted?
|
||||
// 0x00000000 - 0xFFFFFFFF
|
||||
if(Start == 0 && End == ~0)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockComments);
|
||||
comments.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Make sure 'Start' and 'End' reference the same module
|
||||
uint moduleBase = ModBaseFromAddr(Start);
|
||||
|
||||
if(moduleBase != ModBaseFromAddr(End))
|
||||
return;
|
||||
|
||||
// Virtual -> relative offset
|
||||
Start -= moduleBase;
|
||||
End -= moduleBase;
|
||||
|
||||
EXCLUSIVE_ACQUIRE(LockComments);
|
||||
for(auto itr = comments.begin(); itr != comments.end();)
|
||||
{
|
||||
// Ignore manually set entries
|
||||
if(itr->second.manual)
|
||||
{
|
||||
itr++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// [Start, End)
|
||||
if(itr->second.addr >= Start && itr->second.addr < End)
|
||||
itr = comments.erase(itr);
|
||||
else
|
||||
itr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CommentCacheSave(JSON Root)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockComments);
|
||||
|
||||
const JSON jsonComments = json_array();
|
||||
const JSON jsonAutoComments = json_array();
|
||||
|
||||
// Build the JSON array
|
||||
for(auto & itr : comments)
|
||||
{
|
||||
JSON currentComment = json_object();
|
||||
|
||||
json_object_set_new(currentComment, "module", json_string(itr.second.mod));
|
||||
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)
|
||||
json_array_append_new(jsonComments, currentComment);
|
||||
else
|
||||
json_array_append_new(jsonAutoComments, currentComment);
|
||||
}
|
||||
|
||||
// Save to the JSON root
|
||||
if(json_array_size(jsonComments))
|
||||
json_object_set(Root, "comments", jsonComments);
|
||||
|
||||
if(json_array_size(jsonAutoComments))
|
||||
json_object_set(Root, "autocomments", jsonAutoComments);
|
||||
|
||||
json_decref(jsonComments);
|
||||
json_decref(jsonAutoComments);
|
||||
}
|
||||
|
||||
void CommentCacheLoad(JSON Root)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockComments);
|
||||
|
||||
// Inline lambda to parse each JSON entry
|
||||
auto AddComments = [](const JSON Object, bool Manual)
|
||||
{
|
||||
size_t i;
|
||||
JSON value;
|
||||
|
||||
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 && strlen(mod) < MAX_MODULE_SIZE)
|
||||
strcpy_s(commentInfo.mod, mod);
|
||||
else
|
||||
commentInfo.mod[0] = '\0';
|
||||
|
||||
// Address/Manual
|
||||
commentInfo.addr = (uint)json_hex_value(json_object_get(value, "address"));
|
||||
commentInfo.manual = Manual;
|
||||
|
||||
// String value
|
||||
const char* text = json_string_value(json_object_get(value, "text"));
|
||||
|
||||
if(text)
|
||||
strcpy_s(commentInfo.text, text);
|
||||
else
|
||||
{
|
||||
// Skip blank comments
|
||||
continue;
|
||||
}
|
||||
|
||||
const uint key = ModHashFromName(commentInfo.mod) + commentInfo.addr;
|
||||
comments.insert(std::make_pair(key, commentInfo));
|
||||
}
|
||||
};
|
||||
|
||||
// Remove existing entries
|
||||
comments.clear();
|
||||
|
||||
const JSON jsonComments = json_object_get(Root, "comments");
|
||||
const JSON jsonAutoComments = json_object_get(Root, "autocomments");
|
||||
|
||||
// Load user-set comments
|
||||
if(jsonComments)
|
||||
AddComments(jsonComments, true);
|
||||
|
||||
// Load auto-set comments
|
||||
if(jsonAutoComments)
|
||||
AddComments(jsonAutoComments, false);
|
||||
}
|
||||
|
||||
bool CommentEnum(COMMENTSINFO* List, size_t* Size)
|
||||
{
|
||||
// CHECK: Command function
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
|
||||
// At least 1 parameter must be supplied
|
||||
if(!List && !Size)
|
||||
return false;
|
||||
|
||||
SHARED_ACQUIRE(LockComments);
|
||||
|
||||
// Check if the user requested size only
|
||||
if(Size)
|
||||
{
|
||||
*Size = comments.size() * sizeof(COMMENTSINFO);
|
||||
|
||||
if(!List)
|
||||
return true;
|
||||
}
|
||||
|
||||
// Populate the returned array
|
||||
for(auto & itr : comments)
|
||||
{
|
||||
*List = itr.second;
|
||||
List->addr += ModBaseFromName(List->mod);
|
||||
|
||||
List++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CommentClear()
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockComments);
|
||||
comments.clear();
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
#pragma once
|
||||
|
||||
#include "_global.h"
|
||||
|
||||
struct COMMENTSINFO
|
||||
{
|
||||
char mod[MAX_MODULE_SIZE];
|
||||
uint addr;
|
||||
char text[MAX_COMMENT_SIZE];
|
||||
bool manual;
|
||||
};
|
||||
|
||||
bool CommentSet(uint Address, const char* Text, bool Manual);
|
||||
bool CommentGet(uint Address, char* Text);
|
||||
bool CommentDelete(uint Address);
|
||||
void CommentDelRange(uint Start, uint End);
|
||||
void CommentCacheSave(JSON Root);
|
||||
void CommentCacheLoad(JSON Root);
|
||||
bool CommentEnum(COMMENTSINFO* List, size_t* Size);
|
||||
void CommentClear();
|
|
@ -1,18 +1,41 @@
|
|||
/**
|
||||
\file console.cpp
|
||||
\brief Implements the console class.
|
||||
*/
|
||||
|
||||
#include "console.h"
|
||||
#include "threading.h"
|
||||
|
||||
static char msg[66000] = "";
|
||||
|
||||
void dputs(const char* text)
|
||||
/**
|
||||
\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);
|
||||
dprintf("%s\n", Text);
|
||||
}
|
||||
|
||||
void dprintf(const char* format, ...)
|
||||
/**
|
||||
\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, ...)
|
||||
{
|
||||
CriticalSectionLocker locker(LockDprintf);
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vsnprintf(msg, sizeof(msg), format, args);
|
||||
GuiAddLogMessage(msg);
|
||||
|
||||
va_start(args, Format);
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
#ifndef _CONSOLE_H
|
||||
#define _CONSOLE_H
|
||||
#pragma once
|
||||
|
||||
#include "_global.h"
|
||||
|
||||
//functions
|
||||
void dputs(const char* text);
|
||||
void dprintf(const char* format, ...);
|
||||
|
||||
#endif // _CONSOLE_H
|
||||
void dputs(const char* Text);
|
||||
void dprintf(const char* Format, ...);
|
||||
void dprintf_args(const char* Format, va_list Args);
|
|
@ -0,0 +1,159 @@
|
|||
#include "_global.h"
|
||||
#include "dbghelp_safe.h"
|
||||
#include "threading.h"
|
||||
|
||||
DWORD
|
||||
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(
|
||||
__in HANDLE hProcess,
|
||||
__in DWORD64 BaseOfDll
|
||||
)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockSym);
|
||||
return SymUnloadModule64(hProcess, BaseOfDll);
|
||||
}
|
||||
BOOL
|
||||
SafeSymSetSearchPath(
|
||||
__in HANDLE hProcess,
|
||||
__in_opt PCSTR SearchPath
|
||||
)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockSym);
|
||||
return SymSetSearchPath(hProcess, SearchPath);
|
||||
}
|
||||
DWORD
|
||||
SafeSymSetOptions(
|
||||
__in DWORD SymOptions
|
||||
)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockSym);
|
||||
return SymSetOptions(SymOptions);
|
||||
}
|
||||
BOOL
|
||||
SafeSymInitialize(
|
||||
__in HANDLE hProcess,
|
||||
__in_opt PCSTR UserSearchPath,
|
||||
__in BOOL fInvadeProcess
|
||||
)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockSym);
|
||||
return SymInitialize(hProcess, UserSearchPath, fInvadeProcess);
|
||||
}
|
||||
BOOL
|
||||
SafeSymRegisterCallback64(
|
||||
__in HANDLE hProcess,
|
||||
__in PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction,
|
||||
__in ULONG64 UserContext
|
||||
)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockSym);
|
||||
return SymRegisterCallback64(hProcess, CallbackFunction, UserContext);
|
||||
}
|
||||
DWORD64
|
||||
SafeSymLoadModuleEx(
|
||||
__in HANDLE hProcess,
|
||||
__in_opt HANDLE hFile,
|
||||
__in_opt PCSTR ImageName,
|
||||
__in_opt PCSTR ModuleName,
|
||||
__in DWORD64 BaseOfDll,
|
||||
__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(
|
||||
__in HANDLE hProcess,
|
||||
__in DWORD64 qwAddr,
|
||||
__out PIMAGEHLP_MODULE64 ModuleInfo
|
||||
)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockSym);
|
||||
return SymGetModuleInfo64(hProcess, qwAddr, ModuleInfo);
|
||||
}
|
||||
BOOL
|
||||
SafeSymGetSearchPath(
|
||||
__in HANDLE hProcess,
|
||||
__out_ecount(SearchPathLength) PSTR SearchPath,
|
||||
__in DWORD SearchPathLength
|
||||
)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockSym);
|
||||
return SymGetSearchPath(hProcess, SearchPath, SearchPathLength);
|
||||
}
|
||||
BOOL
|
||||
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
|
||||
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(
|
||||
__in HANDLE hProcess,
|
||||
__in PCSTR Name,
|
||||
__inout PSYMBOL_INFO Symbol
|
||||
)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockSym);
|
||||
return SymFromName(hProcess, Name, Symbol);
|
||||
}
|
||||
BOOL
|
||||
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(
|
||||
__in HANDLE hProcess
|
||||
)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockSym);
|
||||
return SymCleanup(hProcess);
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
#ifndef _DBGHELP_SAFE_H
|
||||
#define _DBGHELP_SAFE_H
|
||||
|
||||
#ifdef __GNUC__
|
||||
#include "dbghelp\dbghelp.h"
|
||||
#else
|
||||
#include <dbghelp.h>
|
||||
#endif //__GNUC__
|
||||
|
||||
DWORD
|
||||
SafeUnDecorateSymbolName(
|
||||
__in PCSTR name,
|
||||
__out_ecount(maxStringLength) PSTR outputString,
|
||||
__in DWORD maxStringLength,
|
||||
__in DWORD flags
|
||||
);
|
||||
BOOL
|
||||
SafeSymUnloadModule64(
|
||||
__in HANDLE hProcess,
|
||||
__in DWORD64 BaseOfDll
|
||||
);
|
||||
BOOL
|
||||
SafeSymSetSearchPath(
|
||||
__in HANDLE hProcess,
|
||||
__in_opt PCSTR SearchPath
|
||||
);
|
||||
DWORD
|
||||
SafeSymSetOptions(
|
||||
__in DWORD SymOptions
|
||||
);
|
||||
BOOL
|
||||
SafeSymInitialize(
|
||||
__in HANDLE hProcess,
|
||||
__in_opt PCSTR UserSearchPath,
|
||||
__in BOOL fInvadeProcess
|
||||
);
|
||||
BOOL
|
||||
SafeSymRegisterCallback64(
|
||||
__in HANDLE hProcess,
|
||||
__in PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction,
|
||||
__in ULONG64 UserContext
|
||||
);
|
||||
DWORD64
|
||||
SafeSymLoadModuleEx(
|
||||
__in HANDLE hProcess,
|
||||
__in_opt HANDLE hFile,
|
||||
__in_opt PCSTR ImageName,
|
||||
__in_opt PCSTR ModuleName,
|
||||
__in DWORD64 BaseOfDll,
|
||||
__in DWORD DllSize,
|
||||
__in_opt PMODLOAD_DATA Data,
|
||||
__in_opt DWORD Flags
|
||||
);
|
||||
BOOL
|
||||
SafeSymGetModuleInfo64(
|
||||
__in HANDLE hProcess,
|
||||
__in DWORD64 qwAddr,
|
||||
__out PIMAGEHLP_MODULE64 ModuleInfo
|
||||
);
|
||||
BOOL
|
||||
SafeSymGetSearchPath(
|
||||
__in HANDLE hProcess,
|
||||
__out_ecount(SearchPathLength) PSTR SearchPath,
|
||||
__in DWORD SearchPathLength
|
||||
);
|
||||
BOOL
|
||||
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
|
||||
SafeSymGetLineFromAddr64(
|
||||
__in HANDLE hProcess,
|
||||
__in DWORD64 qwAddr,
|
||||
__out PDWORD pdwDisplacement,
|
||||
__out PIMAGEHLP_LINE64 Line64
|
||||
);
|
||||
BOOL
|
||||
SafeSymFromName(
|
||||
__in HANDLE hProcess,
|
||||
__in PCSTR Name,
|
||||
__inout PSYMBOL_INFO Symbol
|
||||
);
|
||||
BOOL
|
||||
SafeSymFromAddr(
|
||||
__in HANDLE hProcess,
|
||||
__in DWORD64 Address,
|
||||
__out_opt PDWORD64 Displacement,
|
||||
__inout PSYMBOL_INFO Symbol
|
||||
);
|
||||
BOOL
|
||||
SafeSymCleanup(
|
||||
__in HANDLE hProcess
|
||||
);
|
||||
|
||||
#endif //_DBGHELP_SAFE_H
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,3 +1,9 @@
|
|||
/**
|
||||
@file disasm_fast.cpp
|
||||
|
||||
@brief Implements the disasm fast class.
|
||||
*/
|
||||
|
||||
#include "disasm_fast.h"
|
||||
#include "debugger.h"
|
||||
#include "memory.h"
|
||||
|
@ -23,7 +29,7 @@ void fillbasicinfo(DISASM* disasm, BASIC_INSTRUCTION_INFO* basicinfo)
|
|||
//zero basicinfo
|
||||
memset(basicinfo, 0, sizeof(BASIC_INSTRUCTION_INFO));
|
||||
//copy instruction text
|
||||
strcpy(basicinfo->instruction, disasm->CompleteInstr);
|
||||
strcpy_s(basicinfo->instruction, disasm->CompleteInstr);
|
||||
//find immidiat
|
||||
if(disasm->Instruction.BranchType == 0) //no branch
|
||||
{
|
||||
|
@ -55,7 +61,7 @@ void fillbasicinfo(DISASM* disasm, BASIC_INSTRUCTION_INFO* basicinfo)
|
|||
{
|
||||
basicinfo->type |= TYPE_MEMORY;
|
||||
basicinfo->memory.value = (ULONG_PTR)disasm->Argument1.Memory.Displacement;
|
||||
strcpy(basicinfo->memory.mnemonic, disasm->Argument1.ArgMnemonic);
|
||||
strcpy_s(basicinfo->memory.mnemonic, disasm->Argument1.ArgMnemonic);
|
||||
}
|
||||
basicinfo->memory.size = argsize2memsize(disasm->Argument1.ArgSize);
|
||||
}
|
||||
|
@ -65,7 +71,7 @@ void fillbasicinfo(DISASM* disasm, BASIC_INSTRUCTION_INFO* basicinfo)
|
|||
{
|
||||
basicinfo->type |= TYPE_MEMORY;
|
||||
basicinfo->memory.value = (ULONG_PTR)disasm->Argument2.Memory.Displacement;
|
||||
strcpy(basicinfo->memory.mnemonic, disasm->Argument2.ArgMnemonic);
|
||||
strcpy_s(basicinfo->memory.mnemonic, disasm->Argument2.ArgMnemonic);
|
||||
}
|
||||
basicinfo->memory.size = argsize2memsize(disasm->Argument2.ArgSize);
|
||||
}
|
||||
|
@ -82,14 +88,14 @@ void fillbasicinfo(DISASM* disasm, BASIC_INSTRUCTION_INFO* basicinfo)
|
|||
{
|
||||
basicinfo->type |= TYPE_MEMORY;
|
||||
basicinfo->memory.value = (ULONG_PTR)disasm->Instruction.AddrValue;
|
||||
strcpy(basicinfo->memory.mnemonic, disasm->Argument1.ArgMnemonic);
|
||||
strcpy_s(basicinfo->memory.mnemonic, disasm->Argument1.ArgMnemonic);
|
||||
basicinfo->memory.size = argsize2memsize(disasm->Argument1.ArgSize);
|
||||
}
|
||||
else if((disasm->Argument2.ArgType & RELATIVE_) == RELATIVE_)
|
||||
{
|
||||
basicinfo->type |= TYPE_MEMORY;
|
||||
basicinfo->memory.value = (ULONG_PTR)disasm->Instruction.AddrValue;
|
||||
strcpy(basicinfo->memory.mnemonic, disasm->Argument2.ArgMnemonic);
|
||||
strcpy_s(basicinfo->memory.mnemonic, disasm->Argument2.ArgMnemonic);
|
||||
basicinfo->memory.size = argsize2memsize(disasm->Argument2.ArgSize);
|
||||
}
|
||||
}
|
||||
|
@ -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(fdProcessInfo->hProcess, (const void*)addr, data, sizeof(data), 0))
|
||||
if(!MemRead((void*)addr, data, sizeof(data), nullptr))
|
||||
return false;
|
||||
return disasmfast((unsigned char*)data, addr, basicinfo);
|
||||
}
|
|
@ -1,3 +1,9 @@
|
|||
/**
|
||||
@file disasm_helper.cpp
|
||||
|
||||
@brief Implements the disasm helper class.
|
||||
*/
|
||||
|
||||
#include "disasm_helper.h"
|
||||
#include "BeaEngine\BeaEngine.h"
|
||||
#include "value.h"
|
||||
|
@ -127,9 +133,9 @@ const char* disasmtext(uint addr)
|
|||
int len = Disasm(&disasm);
|
||||
static char instruction[INSTRUCT_LENGTH] = "";
|
||||
if(len == UNKNOWN_OPCODE)
|
||||
strcpy(instruction, "???");
|
||||
strcpy_s(instruction, "???");
|
||||
else
|
||||
strcpy(instruction, disasm.CompleteInstr);
|
||||
strcpy_s(instruction, disasm.CompleteInstr);
|
||||
return instruction;
|
||||
}
|
||||
|
||||
|
@ -166,7 +172,7 @@ static bool HandleArgument(ARGTYPE* Argument, INSTRTYPE* Instruction, DISASM_ARG
|
|||
if(!*argmnemonic)
|
||||
return false;
|
||||
arg->memvalue = 0;
|
||||
strcpy(arg->mnemonic, argmnemonic);
|
||||
strcpy_s(arg->mnemonic, argmnemonic);
|
||||
if((argtype & MEMORY_TYPE) == MEMORY_TYPE)
|
||||
{
|
||||
arg->type = arg_memory;
|
||||
|
@ -233,7 +239,7 @@ void disasmget(unsigned char* buffer, uint addr, DISASM_INSTR* instr)
|
|||
disasm.VirtualAddr = addr;
|
||||
disasm.EIP = (UIntPtr)buffer;
|
||||
int len = Disasm(&disasm);
|
||||
strcpy(instr->instruction, disasm.CompleteInstr);
|
||||
strcpy_s(instr->instruction, disasm.CompleteInstr);
|
||||
if(len == UNKNOWN_OPCODE)
|
||||
{
|
||||
instr->instr_size = 1;
|
||||
|
@ -321,11 +327,11 @@ bool disasmispossiblestring(uint addr)
|
|||
{
|
||||
unsigned char data[11];
|
||||
memset(data, 0, sizeof(data));
|
||||
if(!memread(fdProcessInfo->hProcess, (const void*)addr, data, sizeof(data) - 3, 0))
|
||||
if(!MemRead((void*)addr, data, sizeof(data) - 3, 0))
|
||||
return false;
|
||||
uint test = 0;
|
||||
memcpy(&test, data, sizeof(uint));
|
||||
if(memisvalidreadptr(fdProcessInfo->hProcess, test)) //imports/pointers
|
||||
if(MemIsValidReadPtr(test)) //imports/pointers
|
||||
return false;
|
||||
if(isasciistring(data, sizeof(data)) or isunicodestring(data, _countof(data)))
|
||||
return true;
|
||||
|
@ -340,11 +346,11 @@ bool disasmgetstringat(uint addr, STRING_TYPE* type, char* ascii, char* unicode,
|
|||
return false;
|
||||
Memory<unsigned char*> data((maxlen + 1) * 2, "disasmgetstringat:data");
|
||||
memset(data, 0, (maxlen + 1) * 2);
|
||||
if(!memread(fdProcessInfo->hProcess, (const void*)addr, data, (maxlen + 1) * 2, 0))
|
||||
if(!MemRead((void*)addr, data, (maxlen + 1) * 2, 0))
|
||||
return false;
|
||||
uint test = 0;
|
||||
memcpy(&test, data, sizeof(uint));
|
||||
if(memisvalidreadptr(fdProcessInfo->hProcess, test))
|
||||
if(MemIsValidReadPtr(test))
|
||||
return false;
|
||||
if(isasciistring(data, maxlen))
|
||||
{
|
||||
|
@ -442,7 +448,7 @@ int disasmgetsize(uint addr, unsigned char* data)
|
|||
int disasmgetsize(uint addr)
|
||||
{
|
||||
char data[16];
|
||||
if(!memread(fdProcessInfo->hProcess, (const void*)addr, data, sizeof(data), 0))
|
||||
if(!MemRead((void*)addr, data, sizeof(data), 0))
|
||||
return 1;
|
||||
return disasmgetsize(addr, (unsigned char*)data);
|
||||
}
|
|
@ -1,64 +1,73 @@
|
|||
#ifndef _DYNAMICMEM_H
|
||||
#define _DYNAMICMEM_H
|
||||
#pragma once
|
||||
|
||||
template<typename T>
|
||||
class Memory
|
||||
{
|
||||
public:
|
||||
Memory(const char* reason = "Memory:???")
|
||||
//
|
||||
// This class guarantees that the returned allocated memory
|
||||
// will always be zeroed
|
||||
//
|
||||
Memory(const char* Reason = "Memory:???")
|
||||
{
|
||||
mPtr = 0;
|
||||
mSize = 0;
|
||||
mReason = reason;
|
||||
m_Ptr = nullptr;
|
||||
m_Size = 0;
|
||||
m_Reason = Reason;
|
||||
}
|
||||
|
||||
Memory(size_t size, const char* reason = "Memory:???")
|
||||
Memory(size_t Size, const char* Reason = "Memory:???")
|
||||
{
|
||||
mPtr = reinterpret_cast<T>(emalloc(size));
|
||||
mSize = size;
|
||||
mReason = reason;
|
||||
memset(mPtr, 0, size);
|
||||
m_Ptr = reinterpret_cast<T>(emalloc(Size));
|
||||
m_Size = Size;
|
||||
m_Reason = Reason;
|
||||
|
||||
memset(m_Ptr, 0, Size);
|
||||
}
|
||||
|
||||
~Memory()
|
||||
{
|
||||
efree(mPtr);
|
||||
if(m_Ptr)
|
||||
efree(m_Ptr);
|
||||
}
|
||||
|
||||
T realloc(size_t size, const char* reason = "Memory:???")
|
||||
T realloc(size_t Size, const char* Reason = "Memory:???")
|
||||
{
|
||||
mPtr = reinterpret_cast<T>(erealloc(mPtr, size));
|
||||
mSize = size;
|
||||
mReason = reason;
|
||||
memset(mPtr, 0, size);
|
||||
return mPtr;
|
||||
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;
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
operator U()
|
||||
{
|
||||
return (U)mPtr;
|
||||
return (U)m_Ptr;
|
||||
}
|
||||
|
||||
operator T()
|
||||
{
|
||||
return mPtr;
|
||||
return m_Ptr;
|
||||
}
|
||||
|
||||
T operator()()
|
||||
{
|
||||
return mPtr;
|
||||
return m_Ptr;
|
||||
}
|
||||
|
||||
size_t size()
|
||||
template<typename U>
|
||||
T operator+(const U & Other)
|
||||
{
|
||||
return mSize;
|
||||
return m_Ptr + Other;
|
||||
}
|
||||
|
||||
private:
|
||||
T mPtr;
|
||||
size_t mSize;
|
||||
const char* mReason;
|
||||
};
|
||||
|
||||
#endif //_DYNAMICMEM_H
|
||||
T m_Ptr;
|
||||
size_t m_Size;
|
||||
const char* m_Reason;
|
||||
};
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,4 @@
|
|||
#pragma once
|
||||
|
||||
void ErrorCodeInit();
|
||||
const char* ErrorCodeToName(unsigned int ErrorCode);
|
|
@ -0,0 +1,80 @@
|
|||
#include "exception.h"
|
||||
#include <unordered_map>
|
||||
|
||||
std::unordered_map<unsigned int, const char*> ExceptionNames;
|
||||
|
||||
void ExceptionCodeInit()
|
||||
{
|
||||
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"));
|
||||
ExceptionNames.insert(std::make_pair(0x4000001D, "STATUS_WX86_CONTINUE"));
|
||||
ExceptionNames.insert(std::make_pair(0x4000001E, "STATUS_WX86_SINGLE_STEP"));
|
||||
ExceptionNames.insert(std::make_pair(0x4000001F, "STATUS_WX86_BREAKPOINT"));
|
||||
ExceptionNames.insert(std::make_pair(0x40000020, "STATUS_WX86_EXCEPTION_CONTINUE"));
|
||||
ExceptionNames.insert(std::make_pair(0x40000021, "STATUS_WX86_EXCEPTION_LASTCHANCE"));
|
||||
ExceptionNames.insert(std::make_pair(0x40000022, "STATUS_WX86_EXCEPTION_CHAIN"));
|
||||
ExceptionNames.insert(std::make_pair(0x40000028, "STATUS_WX86_CREATEWX86TIB"));
|
||||
ExceptionNames.insert(std::make_pair(0x40010003, "DBG_TERMINATE_THREAD"));
|
||||
ExceptionNames.insert(std::make_pair(0x40010004, "DBG_TERMINATE_PROCESS"));
|
||||
ExceptionNames.insert(std::make_pair(0x40010005, "DBG_CONTROL_C"));
|
||||
ExceptionNames.insert(std::make_pair(0x40010006, "DBG_PRINTEXCEPTION_C"));
|
||||
ExceptionNames.insert(std::make_pair(0x40010007, "DBG_RIPEXCEPTION"));
|
||||
ExceptionNames.insert(std::make_pair(0x40010008, "DBG_CONTROL_BREAK"));
|
||||
ExceptionNames.insert(std::make_pair(0x40010009, "DBG_COMMAND_EXCEPTION"));
|
||||
ExceptionNames.insert(std::make_pair(0x406D1388, "MS_VC_EXCEPTION"));
|
||||
ExceptionNames.insert(std::make_pair(0x80000001, "EXCEPTION_GUARD_PAGE"));
|
||||
ExceptionNames.insert(std::make_pair(0x80000002, "EXCEPTION_DATATYPE_MISALIGNMENT"));
|
||||
ExceptionNames.insert(std::make_pair(0x80000003, "EXCEPTION_BREAKPOINT"));
|
||||
ExceptionNames.insert(std::make_pair(0x80000004, "EXCEPTION_SINGLE_STEP"));
|
||||
ExceptionNames.insert(std::make_pair(0x80000026, "STATUS_LONGJUMP"));
|
||||
ExceptionNames.insert(std::make_pair(0x80000029, "STATUS_UNWIND_CONSOLIDATE"));
|
||||
ExceptionNames.insert(std::make_pair(0x80010001, "DBG_EXCEPTION_NOT_HANDLED"));
|
||||
ExceptionNames.insert(std::make_pair(0xC0000005, "EXCEPTION_ACCESS_VIOLATION"));
|
||||
ExceptionNames.insert(std::make_pair(0xC0000006, "EXCEPTION_IN_PAGE_ERROR"));
|
||||
ExceptionNames.insert(std::make_pair(0xC0000008, "EXCEPTION_INVALID_HANDLE"));
|
||||
ExceptionNames.insert(std::make_pair(0xC000000D, "STATUS_INVALID_PARAMETER"));
|
||||
ExceptionNames.insert(std::make_pair(0xC0000017, "STATUS_NO_MEMORY"));
|
||||
ExceptionNames.insert(std::make_pair(0xC000001D, "EXCEPTION_ILLEGAL_INSTRUCTION"));
|
||||
ExceptionNames.insert(std::make_pair(0xC0000025, "EXCEPTION_NONCONTINUABLE_EXCEPTION"));
|
||||
ExceptionNames.insert(std::make_pair(0xC0000026, "EXCEPTION_INVALID_DISPOSITION"));
|
||||
ExceptionNames.insert(std::make_pair(0xC000008C, "EXCEPTION_ARRAY_BOUNDS_EXCEEDED"));
|
||||
ExceptionNames.insert(std::make_pair(0xC000008D, "EXCEPTION_FLT_DENORMAL_OPERAND"));
|
||||
ExceptionNames.insert(std::make_pair(0xC000008E, "EXCEPTION_FLT_DIVIDE_BY_ZERO"));
|
||||
ExceptionNames.insert(std::make_pair(0xC000008F, "EXCEPTION_FLT_INEXACT_RESULT"));
|
||||
ExceptionNames.insert(std::make_pair(0xC0000090, "EXCEPTION_FLT_INVALID_OPERATION"));
|
||||
ExceptionNames.insert(std::make_pair(0xC0000091, "EXCEPTION_FLT_OVERFLOW"));
|
||||
ExceptionNames.insert(std::make_pair(0xC0000092, "EXCEPTION_FLT_STACK_CHECK"));
|
||||
ExceptionNames.insert(std::make_pair(0xC0000093, "EXCEPTION_FLT_UNDERFLOW"));
|
||||
ExceptionNames.insert(std::make_pair(0xC0000094, "EXCEPTION_INT_DIVIDE_BY_ZERO"));
|
||||
ExceptionNames.insert(std::make_pair(0xC0000095, "EXCEPTION_INT_OVERFLOW"));
|
||||
ExceptionNames.insert(std::make_pair(0xC0000096, "EXCEPTION_PRIV_INSTRUCTION"));
|
||||
ExceptionNames.insert(std::make_pair(0xC00000FD, "EXCEPTION_STACK_OVERFLOW"));
|
||||
ExceptionNames.insert(std::make_pair(0xC0000135, "STATUS_DLL_NOT_FOUND"));
|
||||
ExceptionNames.insert(std::make_pair(0xC0000138, "STATUS_ORDINAL_NOT_FOUND"));
|
||||
ExceptionNames.insert(std::make_pair(0xC0000139, "STATUS_ENTRYPOINT_NOT_FOUND"));
|
||||
ExceptionNames.insert(std::make_pair(0xC000013A, "STATUS_CONTROL_C_EXIT"));
|
||||
ExceptionNames.insert(std::make_pair(0xC0000142, "STATUS_DLL_INIT_FAILED"));
|
||||
ExceptionNames.insert(std::make_pair(0xC000014A, "STATUS_ILLEGAL_FLOAT_CONTEXT"));
|
||||
ExceptionNames.insert(std::make_pair(0xC0000194, "EXCEPTION_POSSIBLE_DEADLOCK"));
|
||||
ExceptionNames.insert(std::make_pair(0xC00001A5, "STATUS_INVALID_EXCEPTION_HANDLER"));
|
||||
ExceptionNames.insert(std::make_pair(0xC00002B4, "STATUS_FLOAT_MULTIPLE_FAULTS"));
|
||||
ExceptionNames.insert(std::make_pair(0xC00002B5, "STATUS_FLOAT_MULTIPLE_TRAPS"));
|
||||
ExceptionNames.insert(std::make_pair(0xC00002C5, "STATUS_DATATYPE_MISALIGNMENT_ERROR"));
|
||||
ExceptionNames.insert(std::make_pair(0xC00002C9, "STATUS_REG_NAT_CONSUMPTION"));
|
||||
ExceptionNames.insert(std::make_pair(0xC0000409, "STATUS_STACK_BUFFER_OVERRUN"));
|
||||
ExceptionNames.insert(std::make_pair(0xC0000417, "STATUS_INVALID_CRUNTIME_PARAMETER"));
|
||||
ExceptionNames.insert(std::make_pair(0xC000041D, "STATUS_USER_CALLBACK"));
|
||||
ExceptionNames.insert(std::make_pair(0xC0000420, "STATUS_ASSERTION_FAILURE"));
|
||||
ExceptionNames.insert(std::make_pair(0xE0434352, "CLR_EXCEPTION"));
|
||||
ExceptionNames.insert(std::make_pair(0xE06D7363, "CPP_EH_EXCEPTION"));
|
||||
}
|
||||
|
||||
const char* ExceptionCodeToName(unsigned int ExceptionCode)
|
||||
{
|
||||
if(!ExceptionNames.count(ExceptionCode))
|
||||
return nullptr;
|
||||
|
||||
return ExceptionNames[ExceptionCode];
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
#pragma once
|
||||
|
||||
void ExceptionCodeInit();
|
||||
const char* ExceptionCodeToName(unsigned int ExceptionCode);
|
|
@ -0,0 +1,265 @@
|
|||
#include "function.h"
|
||||
#include "module.h"
|
||||
#include "debugger.h"
|
||||
#include "memory.h"
|
||||
#include "threading.h"
|
||||
|
||||
std::map<ModuleRange, FUNCTIONSINFO, ModuleRangeCompare> functions;
|
||||
|
||||
bool FunctionAdd(uint Start, uint End, bool Manual)
|
||||
{
|
||||
// CHECK: Export/Command function
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
|
||||
// Make sure memory is readable
|
||||
if(!MemIsValidReadPtr(Start))
|
||||
return false;
|
||||
|
||||
// Fail if boundary exceeds module size
|
||||
const uint moduleBase = ModBaseFromAddr(Start);
|
||||
|
||||
if(moduleBase != ModBaseFromAddr(End))
|
||||
return false;
|
||||
|
||||
// Fail if 'Start' and 'End' are incompatible
|
||||
if(Start > End || FunctionOverlaps(Start, End))
|
||||
return false;
|
||||
|
||||
FUNCTIONSINFO function;
|
||||
ModNameFromAddr(Start, function.mod, true);
|
||||
function.start = Start - moduleBase;
|
||||
function.end = End - moduleBase;
|
||||
function.manual = Manual;
|
||||
|
||||
// Insert to global table
|
||||
EXCLUSIVE_ACQUIRE(LockFunctions);
|
||||
|
||||
functions.insert(std::make_pair(ModuleRange(ModHashFromAddr(moduleBase), Range(function.start, function.end)), function));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FunctionGet(uint Address, uint* Start, uint* End)
|
||||
{
|
||||
// CHECK: Exported function
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
|
||||
const uint moduleBase = ModBaseFromAddr(Address);
|
||||
|
||||
// Lookup by module hash, then function range
|
||||
SHARED_ACQUIRE(LockFunctions);
|
||||
|
||||
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 + moduleBase;
|
||||
|
||||
if(End)
|
||||
*End = found->second.end + moduleBase;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FunctionOverlaps(uint Start, uint End)
|
||||
{
|
||||
// CHECK: Exported function
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
|
||||
// A function can't end before it begins
|
||||
if(Start > End)
|
||||
return false;
|
||||
|
||||
const uint moduleBase = ModBaseFromAddr(Start);
|
||||
|
||||
SHARED_ACQUIRE(LockFunctions);
|
||||
return (functions.count(ModuleRange(ModHashFromAddr(moduleBase), Range(Start - moduleBase, End - moduleBase))) > 0);
|
||||
}
|
||||
|
||||
bool FunctionDelete(uint Address)
|
||||
{
|
||||
// CHECK: Exported function
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
|
||||
const uint moduleBase = ModBaseFromAddr(Address);
|
||||
|
||||
EXCLUSIVE_ACQUIRE(LockFunctions);
|
||||
return (functions.erase(ModuleRange(ModHashFromAddr(moduleBase), Range(Address - moduleBase, Address - moduleBase))) > 0);
|
||||
}
|
||||
|
||||
void FunctionDelRange(uint Start, uint End)
|
||||
{
|
||||
// CHECK: Exported function
|
||||
if(!DbgIsDebugging())
|
||||
return;
|
||||
|
||||
// Should all functions be deleted?
|
||||
// 0x00000000 - 0xFFFFFFFF
|
||||
if(Start == 0 && End == ~0)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockFunctions);
|
||||
functions.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
// The start and end address must be in the same module
|
||||
uint moduleBase = ModBaseFromAddr(Start);
|
||||
|
||||
if(moduleBase != ModBaseFromAddr(End))
|
||||
return;
|
||||
|
||||
// Convert these to a relative offset
|
||||
Start -= moduleBase;
|
||||
End -= moduleBase;
|
||||
|
||||
EXCLUSIVE_ACQUIRE(LockFunctions);
|
||||
for(auto itr = functions.begin(); itr != functions.end();)
|
||||
{
|
||||
// Ignore manually set entries
|
||||
if(itr->second.manual)
|
||||
{
|
||||
itr++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// [Start, End]
|
||||
if(itr->second.end >= Start && itr->second.start <= End)
|
||||
itr = functions.erase(itr);
|
||||
else
|
||||
itr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FunctionCacheSave(JSON Root)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockFunctions);
|
||||
|
||||
// Allocate JSON object array
|
||||
const JSON jsonFunctions = json_array();
|
||||
const JSON jsonAutoFunctions = json_array();
|
||||
|
||||
for(auto & i : functions)
|
||||
{
|
||||
JSON currentFunction = json_object();
|
||||
|
||||
json_object_set_new(currentFunction, "module", json_string(i.second.mod));
|
||||
json_object_set_new(currentFunction, "start", json_hex(i.second.start));
|
||||
json_object_set_new(currentFunction, "end", json_hex(i.second.end));
|
||||
|
||||
if(i.second.manual)
|
||||
json_array_append_new(jsonFunctions, currentFunction);
|
||||
else
|
||||
json_array_append_new(jsonAutoFunctions, currentFunction);
|
||||
}
|
||||
|
||||
if(json_array_size(jsonFunctions))
|
||||
json_object_set(Root, "functions", jsonFunctions);
|
||||
|
||||
if(json_array_size(jsonAutoFunctions))
|
||||
json_object_set(Root, "autofunctions", jsonAutoFunctions);
|
||||
|
||||
// Decrease reference count to avoid leaking memory
|
||||
json_decref(jsonFunctions);
|
||||
json_decref(jsonAutoFunctions);
|
||||
}
|
||||
|
||||
void FunctionCacheLoad(JSON Root)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockFunctions);
|
||||
|
||||
// Delete existing entries
|
||||
functions.clear();
|
||||
|
||||
// Inline lambda to enumerate all JSON array indices
|
||||
auto InsertFunctions = [](const JSON Object, bool Manual)
|
||||
{
|
||||
size_t i;
|
||||
JSON value;
|
||||
json_array_foreach(Object, i, value)
|
||||
{
|
||||
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(functionInfo.mod, mod);
|
||||
else
|
||||
functionInfo.mod[0] = '\0';
|
||||
|
||||
// Function address
|
||||
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(functionInfo.end < functionInfo.start)
|
||||
continue;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
bool FunctionEnum(FUNCTIONSINFO* List, size_t* Size)
|
||||
{
|
||||
// CHECK: Exported function
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
|
||||
// If a list isn't passed and the size not requested, fail
|
||||
if(!List && !Size)
|
||||
return false;
|
||||
|
||||
SHARED_ACQUIRE(LockFunctions);
|
||||
|
||||
// Did the caller request the buffer size needed?
|
||||
if(Size)
|
||||
{
|
||||
*Size = functions.size() * sizeof(FUNCTIONSINFO);
|
||||
|
||||
if(!List)
|
||||
return true;
|
||||
}
|
||||
|
||||
// Fill out the buffer
|
||||
for(auto & itr : functions)
|
||||
{
|
||||
// Adjust for relative to virtual addresses
|
||||
uint moduleBase = ModBaseFromName(itr.second.mod);
|
||||
|
||||
*List = itr.second;
|
||||
List->start += moduleBase;
|
||||
List->end += moduleBase;
|
||||
|
||||
List++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FunctionClear()
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockFunctions);
|
||||
functions.clear();
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
|
||||
#include "addrinfo.h"
|
||||
|
||||
struct FUNCTIONSINFO
|
||||
{
|
||||
char mod[MAX_MODULE_SIZE];
|
||||
uint start;
|
||||
uint end;
|
||||
bool manual;
|
||||
};
|
||||
|
||||
bool FunctionAdd(uint Start, uint End, bool Manual);
|
||||
bool FunctionGet(uint Address, uint* Start, uint* End);
|
||||
bool FunctionOverlaps(uint Start, uint End);
|
||||
bool FunctionDelete(uint Address);
|
||||
void FunctionDelRange(uint Start, uint End);
|
||||
void FunctionCacheSave(JSON Root);
|
||||
void FunctionCacheLoad(JSON Root);
|
||||
bool FunctionEnum(FUNCTIONSINFO* List, size_t* Size);
|
||||
void FunctionClear();
|
|
@ -12,10 +12,16 @@ public:
|
|||
}
|
||||
|
||||
~Handle()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
void Close()
|
||||
{
|
||||
DWORD dwFlags = 0;
|
||||
if(GetHandleInformation(mHandle, &dwFlags) && !(dwFlags & HANDLE_FLAG_PROTECT_FROM_CLOSE))
|
||||
CloseHandle(mHandle);
|
||||
mHandle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
const HANDLE & operator=(const HANDLE & h)
|
||||
|
|
|
@ -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"
|
||||
|
@ -12,6 +17,14 @@
|
|||
#include "disasm_fast.h"
|
||||
#include "reference.h"
|
||||
#include "disasm_helper.h"
|
||||
#include "comment.h"
|
||||
#include "label.h"
|
||||
#include "bookmark.h"
|
||||
#include "function.h"
|
||||
#include "loop.h"
|
||||
#include "patternfind.h"
|
||||
#include "module.h"
|
||||
#include "stringformat.h"
|
||||
|
||||
static bool bRefinit = false;
|
||||
|
||||
|
@ -78,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] == '$')
|
||||
|
@ -152,7 +166,7 @@ CMDRESULT cbInstrMov(int argc, char* argv[])
|
|||
}
|
||||
//Check the destination
|
||||
uint dest;
|
||||
if(!valfromstring(argv[1], &dest) || !memisvalidreadptr(fdProcessInfo->hProcess, dest))
|
||||
if(!valfromstring(argv[1], &dest) || !MemIsValidReadPtr(dest))
|
||||
{
|
||||
dprintf("invalid destination \"%s\"\n", argv[1]);
|
||||
return STATUS_ERROR;
|
||||
|
@ -169,7 +183,7 @@ CMDRESULT cbInstrMov(int argc, char* argv[])
|
|||
data[j] = res;
|
||||
}
|
||||
//Move data to destination
|
||||
if(!memwrite(fdProcessInfo->hProcess, (void*)dest, data, data.size(), 0))
|
||||
if(!MemWrite((void*)dest, data, data.size(), 0))
|
||||
{
|
||||
dprintf("failed to write to "fhex"\n", dest);
|
||||
return STATUS_ERROR;
|
||||
|
@ -190,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
|
||||
|
@ -206,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))
|
||||
|
@ -235,7 +250,7 @@ CMDRESULT cbInstrVarList(int argc, char* argv[])
|
|||
if(variables[i].alias.length())
|
||||
continue;
|
||||
char name[deflen] = "";
|
||||
strcpy(name, variables[i].name.c_str());
|
||||
strcpy_s(name, variables[i].name.c_str());
|
||||
uint value = (uint)variables[i].value.u.value;
|
||||
if(variables[i].type != VAR_HIDDEN)
|
||||
{
|
||||
|
@ -288,7 +303,7 @@ CMDRESULT cbInstrCmt(int argc, char* argv[])
|
|||
uint addr = 0;
|
||||
if(!valfromstring(argv[1], &addr, false))
|
||||
return STATUS_ERROR;
|
||||
if(!commentset(addr, argv[2], true))
|
||||
if(!CommentSet(addr, argv[2], true))
|
||||
{
|
||||
dputs("error setting comment");
|
||||
return STATUS_ERROR;
|
||||
|
@ -306,7 +321,7 @@ CMDRESULT cbInstrCmtdel(int argc, char* argv[])
|
|||
uint addr = 0;
|
||||
if(!valfromstring(argv[1], &addr, false))
|
||||
return STATUS_ERROR;
|
||||
if(!commentdel(addr))
|
||||
if(!CommentDelete(addr))
|
||||
{
|
||||
dputs("error deleting comment");
|
||||
return STATUS_ERROR;
|
||||
|
@ -325,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;
|
||||
|
@ -344,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;
|
||||
|
@ -362,7 +377,7 @@ CMDRESULT cbInstrBookmarkSet(int argc, char* argv[])
|
|||
uint addr = 0;
|
||||
if(!valfromstring(argv[1], &addr, false))
|
||||
return STATUS_ERROR;
|
||||
if(!bookmarkset(addr, true))
|
||||
if(!BookmarkSet(addr, true))
|
||||
{
|
||||
dputs("failed to set bookmark!");
|
||||
return STATUS_ERROR;
|
||||
|
@ -381,7 +396,7 @@ CMDRESULT cbInstrBookmarkDel(int argc, char* argv[])
|
|||
uint addr = 0;
|
||||
if(!valfromstring(argv[1], &addr, false))
|
||||
return STATUS_ERROR;
|
||||
if(!bookmarkdel(addr))
|
||||
if(!BookmarkDelete(addr))
|
||||
{
|
||||
dputs("failed to delete bookmark!");
|
||||
return STATUS_ERROR;
|
||||
|
@ -424,7 +439,7 @@ CMDRESULT cbAssemble(int argc, char* argv[])
|
|||
bool fillnop = false;
|
||||
if(argc > 3)
|
||||
fillnop = true;
|
||||
char error[256] = "";
|
||||
char error[MAX_ERROR_SIZE] = "";
|
||||
int size = 0;
|
||||
if(!assembleat(addr, argv[2], &size, error, fillnop))
|
||||
{
|
||||
|
@ -448,7 +463,7 @@ CMDRESULT cbFunctionAdd(int argc, char* argv[])
|
|||
uint end = 0;
|
||||
if(!valfromstring(argv[1], &start, false) or !valfromstring(argv[2], &end, false))
|
||||
return STATUS_ERROR;
|
||||
if(!functionadd(start, end, true))
|
||||
if(!FunctionAdd(start, end, true))
|
||||
{
|
||||
dputs("failed to add function");
|
||||
return STATUS_ERROR;
|
||||
|
@ -468,7 +483,7 @@ CMDRESULT cbFunctionDel(int argc, char* argv[])
|
|||
uint addr = 0;
|
||||
if(!valfromstring(argv[1], &addr, false))
|
||||
return STATUS_ERROR;
|
||||
if(!functiondel(addr))
|
||||
if(!FunctionDelete(addr))
|
||||
{
|
||||
dputs("failed to delete function");
|
||||
return STATUS_ERROR;
|
||||
|
@ -797,10 +812,9 @@ struct VALUERANGE
|
|||
uint end;
|
||||
};
|
||||
|
||||
//reffind value[,page]
|
||||
static bool cbRefFind(DISASM* disasm, BASIC_INSTRUCTION_INFO* basicinfo, REFINFO* refinfo)
|
||||
{
|
||||
if(!disasm && !basicinfo) //initialize
|
||||
if(!disasm || !basicinfo) //initialize
|
||||
{
|
||||
GuiReferenceInitialize(refinfo->name);
|
||||
GuiReferenceAddColumn(2 * sizeof(uint), "Address");
|
||||
|
@ -880,16 +894,20 @@ 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
|
||||
if(!disasm || !basicinfo) //initialize
|
||||
{
|
||||
GuiReferenceInitialize(refinfo->name);
|
||||
GuiReferenceAddColumn(2 * sizeof(uint), "Address");
|
||||
|
@ -945,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;
|
||||
|
@ -1047,7 +1065,7 @@ CMDRESULT cbInstrCopystr(int argc, char* argv[])
|
|||
dprintf("invalid address \"%s\"!\n", argv[1]);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
if(!mempatch(fdProcessInfo->hProcess, (void*)addr, string, strlen(string), 0))
|
||||
if(!MemPatch((void*)addr, string, strlen(string), 0))
|
||||
{
|
||||
dputs("memwrite failed!");
|
||||
return STATUS_ERROR;
|
||||
|
@ -1071,21 +1089,21 @@ CMDRESULT cbInstrFind(int argc, char* argv[])
|
|||
char pattern[deflen] = "";
|
||||
//remove # from the start and end of the pattern (ODBGScript support)
|
||||
if(argv[2][0] == '#')
|
||||
strcpy(pattern, argv[2] + 1);
|
||||
strcpy_s(pattern, argv[2] + 1);
|
||||
else
|
||||
strcpy(pattern, argv[2]);
|
||||
strcpy_s(pattern, argv[2]);
|
||||
int len = (int)strlen(pattern);
|
||||
if(pattern[len - 1] == '#')
|
||||
pattern[len - 1] = '\0';
|
||||
uint size = 0;
|
||||
uint base = memfindbaseaddr(addr, &size, true);
|
||||
uint base = MemFindBaseAddr(addr, &size, true);
|
||||
if(!base)
|
||||
{
|
||||
dprintf("invalid memory address "fhex"!\n", addr);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
Memory<unsigned char*> data(size, "cbInstrFind:data");
|
||||
if(!memread(fdProcessInfo->hProcess, (const void*)base, data, size, 0))
|
||||
if(!MemRead((void*)base, data, size, 0))
|
||||
{
|
||||
dputs("failed to read memory!");
|
||||
return STATUS_ERROR;
|
||||
|
@ -1101,7 +1119,7 @@ CMDRESULT cbInstrFind(int argc, char* argv[])
|
|||
}
|
||||
else
|
||||
find_size = size - start;
|
||||
uint foundoffset = memfindpattern(data + start, find_size, pattern);
|
||||
uint foundoffset = patternfind(data + start, find_size, pattern);
|
||||
uint result = 0;
|
||||
if(foundoffset != -1)
|
||||
result = addr + foundoffset;
|
||||
|
@ -1123,21 +1141,21 @@ CMDRESULT cbInstrFindAll(int argc, char* argv[])
|
|||
char pattern[deflen] = "";
|
||||
//remove # from the start and end of the pattern (ODBGScript support)
|
||||
if(argv[2][0] == '#')
|
||||
strcpy(pattern, argv[2] + 1);
|
||||
strcpy_s(pattern, argv[2] + 1);
|
||||
else
|
||||
strcpy(pattern, argv[2]);
|
||||
strcpy_s(pattern, argv[2]);
|
||||
int len = (int)strlen(pattern);
|
||||
if(pattern[len - 1] == '#')
|
||||
pattern[len - 1] = '\0';
|
||||
uint size = 0;
|
||||
uint base = memfindbaseaddr(addr, &size, true);
|
||||
uint base = MemFindBaseAddr(addr, &size, true);
|
||||
if(!base)
|
||||
{
|
||||
dprintf("invalid memory address "fhex"!\n", addr);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
Memory<unsigned char*> data(size, "cbInstrFindAll:data");
|
||||
if(!memread(fdProcessInfo->hProcess, (const void*)base, data, size, 0))
|
||||
if(!MemRead((void*)base, data, size, 0))
|
||||
{
|
||||
dputs("failed to read memory!");
|
||||
return STATUS_ERROR;
|
||||
|
@ -1160,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&");
|
||||
|
@ -1174,7 +1198,7 @@ CMDRESULT cbInstrFindAll(int argc, char* argv[])
|
|||
while(refCount < 5000)
|
||||
{
|
||||
int patternsize = 0;
|
||||
uint foundoffset = memfindpattern(data + start + i, find_size - i, pattern, &patternsize);
|
||||
uint foundoffset = patternfind(data + start + i, find_size - i, pattern, &patternsize);
|
||||
if(foundoffset == -1)
|
||||
break;
|
||||
i += foundoffset + 1;
|
||||
|
@ -1186,7 +1210,7 @@ CMDRESULT cbInstrFindAll(int argc, char* argv[])
|
|||
if(findData)
|
||||
{
|
||||
Memory<unsigned char*> printData(patternsize, "cbInstrFindAll:printData");
|
||||
memread(fdProcessInfo->hProcess, (const void*)result, printData, patternsize, 0);
|
||||
MemRead((void*)result, printData, patternsize, 0);
|
||||
for(int j = 0, k = 0; j < patternsize; j++)
|
||||
{
|
||||
if(j)
|
||||
|
@ -1195,7 +1219,10 @@ CMDRESULT cbInstrFindAll(int argc, char* argv[])
|
|||
}
|
||||
}
|
||||
else
|
||||
GuiGetDisassembly(result, msg);
|
||||
{
|
||||
if(!GuiGetDisassembly(result, msg))
|
||||
strcpy_s(msg, "[Error disassembling]");
|
||||
}
|
||||
GuiReferenceSetCellContent(refCount, 1, msg);
|
||||
result++;
|
||||
refCount++;
|
||||
|
@ -1206,10 +1233,9 @@ 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
|
||||
if(!disasm || !basicinfo) //initialize
|
||||
{
|
||||
GuiReferenceInitialize(refinfo->name);
|
||||
GuiReferenceAddColumn(2 * sizeof(uint), "Address");
|
||||
|
@ -1222,7 +1248,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)
|
||||
{
|
||||
|
@ -1249,7 +1275,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;
|
||||
|
@ -1264,14 +1290,14 @@ CMDRESULT cbInstrCommentList(int argc, char* argv[])
|
|||
GuiReferenceAddColumn(0, "Comment");
|
||||
GuiReferenceReloadData();
|
||||
size_t cbsize;
|
||||
commentenum(0, &cbsize);
|
||||
CommentEnum(0, &cbsize);
|
||||
if(!cbsize)
|
||||
{
|
||||
dputs("no comments");
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
Memory<COMMENTSINFO*> comments(cbsize, "cbInstrCommentList:comments");
|
||||
commentenum(comments, 0);
|
||||
CommentEnum(comments, 0);
|
||||
int count = (int)(cbsize / sizeof(COMMENTSINFO));
|
||||
for(int i = 0; i < count; i++)
|
||||
{
|
||||
|
@ -1299,14 +1325,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++)
|
||||
{
|
||||
|
@ -1333,14 +1359,14 @@ CMDRESULT cbInstrBookmarkList(int argc, char* argv[])
|
|||
GuiReferenceAddColumn(0, "Disassembly");
|
||||
GuiReferenceReloadData();
|
||||
size_t cbsize;
|
||||
bookmarkenum(0, &cbsize);
|
||||
BookmarkEnum(0, &cbsize);
|
||||
if(!cbsize)
|
||||
{
|
||||
dputs("no bookmarks");
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
Memory<BOOKMARKSINFO*> bookmarks(cbsize, "cbInstrBookmarkList:bookmarks");
|
||||
bookmarkenum(bookmarks, 0);
|
||||
BookmarkEnum(bookmarks, 0);
|
||||
int count = (int)(cbsize / sizeof(BOOKMARKSINFO));
|
||||
for(int i = 0; i < count; i++)
|
||||
{
|
||||
|
@ -1368,14 +1394,14 @@ CMDRESULT cbInstrFunctionList(int argc, char* argv[])
|
|||
GuiReferenceAddColumn(0, "Label/Comment");
|
||||
GuiReferenceReloadData();
|
||||
size_t cbsize;
|
||||
functionenum(0, &cbsize);
|
||||
FunctionEnum(0, &cbsize);
|
||||
if(!cbsize)
|
||||
{
|
||||
dputs("no functions");
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
Memory<FUNCTIONSINFO*> functions(cbsize, "cbInstrFunctionList:functions");
|
||||
functionenum(functions, 0);
|
||||
FunctionEnum(functions, 0);
|
||||
int count = (int)(cbsize / sizeof(FUNCTIONSINFO));
|
||||
for(int i = 0; i < count; i++)
|
||||
{
|
||||
|
@ -1389,12 +1415,12 @@ 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
|
||||
{
|
||||
char comment[MAX_COMMENT_SIZE] = "";
|
||||
if(commentget(functions[i].start, comment))
|
||||
if(CommentGet(functions[i].start, comment))
|
||||
GuiReferenceSetCellContent(i, 3, comment);
|
||||
}
|
||||
}
|
||||
|
@ -1414,14 +1440,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++)
|
||||
{
|
||||
|
@ -1435,12 +1461,12 @@ 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
|
||||
{
|
||||
char comment[MAX_COMMENT_SIZE] = "";
|
||||
if(commentget(loops[i].start, comment))
|
||||
if(CommentGet(loops[i].start, comment))
|
||||
GuiReferenceSetCellContent(i, 3, comment);
|
||||
}
|
||||
}
|
||||
|
@ -1462,10 +1488,9 @@ 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
|
||||
if(!disasm || !basicinfo) //initialize
|
||||
{
|
||||
GuiReferenceInitialize(refinfo->name);
|
||||
GuiReferenceAddColumn(2 * sizeof(uint), "Address");
|
||||
|
@ -1508,7 +1533,7 @@ CMDRESULT cbInstrFindAsm(int argc, char* argv[])
|
|||
|
||||
unsigned char dest[16];
|
||||
int asmsize = 0;
|
||||
char error[256] = "";
|
||||
char error[MAX_ERROR_SIZE] = "";
|
||||
if(!assemble(addr + size / 2, dest, &asmsize, argv[1], error))
|
||||
{
|
||||
dprintf("failed to assemble \"%s\" (%s)!\n", argv[1], error);
|
||||
|
@ -1519,12 +1544,267 @@ 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
|
||||
{
|
||||
fclose(rulesFile);
|
||||
dputs("errors in the rules file!");
|
||||
}
|
||||
yr_compiler_destroy(yrCompiler);
|
||||
}
|
||||
else
|
||||
{
|
||||
fclose(rulesFile);
|
||||
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;
|
||||
}
|
||||
|
||||
#include "capstone\capstone.h"
|
||||
#include "capstone_wrapper.h"
|
||||
|
||||
|
|
|
@ -62,6 +62,9 @@ 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[]);
|
||||
|
||||
CMDRESULT cbInstrCapstone(int argc, char* argv[]);
|
||||
|
||||
|
|
|
@ -15,18 +15,17 @@
|
|||
#include "jansson_config.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* version */
|
||||
|
||||
#define JANSSON_MAJOR_VERSION 2
|
||||
#define JANSSON_MINOR_VERSION 6
|
||||
#define JANSSON_MINOR_VERSION 7
|
||||
#define JANSSON_MICRO_VERSION 0
|
||||
|
||||
/* Micro version is omitted if it's 0 */
|
||||
#define JANSSON_VERSION "2.6"
|
||||
#define JANSSON_VERSION "2.7"
|
||||
|
||||
/* Version as a 3-byte hex number, e.g. 0x010201 == 1.2.1. Use this
|
||||
for numeric comparisons, e.g. #if JANSSON_VERSION_HEX >= ... */
|
||||
|
@ -55,8 +54,6 @@ typedef struct json_t
|
|||
size_t refcount;
|
||||
} json_t;
|
||||
|
||||
typedef json_t* JSON;
|
||||
|
||||
#ifndef JANSSON_USING_CMAKE /* disabled if using cmake */
|
||||
#if JSON_INTEGER_IS_LONG_LONG
|
||||
#ifdef _WIN32
|
||||
|
@ -93,17 +90,6 @@ __declspec(dllimport) json_t* json_stringn(const char* value, size_t len);
|
|||
__declspec(dllimport) json_t* json_string_nocheck(const char* value);
|
||||
__declspec(dllimport) json_t* json_stringn_nocheck(const char* value, size_t len);
|
||||
__declspec(dllimport) json_t* json_integer(json_int_t value);
|
||||
static JSON_INLINE
|
||||
json_t* json_hex(json_int_t value)
|
||||
{
|
||||
char hexvalue[20];
|
||||
#ifdef _WIN64
|
||||
sprintf(hexvalue, "0x%llX", value);
|
||||
#else //x64
|
||||
sprintf(hexvalue, "0x%X", value);
|
||||
#endif //_WIN64
|
||||
return json_string(hexvalue);
|
||||
}
|
||||
__declspec(dllimport) json_t* json_real(double value);
|
||||
__declspec(dllimport) json_t* json_true(void);
|
||||
__declspec(dllimport) json_t* json_false(void);
|
||||
|
@ -222,21 +208,6 @@ int json_array_insert(json_t* array, size_t ind, json_t* value)
|
|||
__declspec(dllimport) const char* json_string_value(const json_t* string);
|
||||
__declspec(dllimport) size_t json_string_length(const json_t* string);
|
||||
__declspec(dllimport) json_int_t json_integer_value(const json_t* integer);
|
||||
static JSON_INLINE
|
||||
json_int_t json_hex_value(const json_t* hex)
|
||||
{
|
||||
json_int_t ret;
|
||||
const char* hexvalue;
|
||||
hexvalue = json_string_value(hex);
|
||||
if(!hexvalue)
|
||||
return 0;
|
||||
#ifdef _WIN64
|
||||
sscanf(hexvalue, "0x%llX", &ret);
|
||||
#else //x64
|
||||
sscanf(hexvalue, "0x%X", &ret);
|
||||
#endif //_WIN64
|
||||
return ret;
|
||||
}
|
||||
__declspec(dllimport) double json_real_value(const json_t* real);
|
||||
__declspec(dllimport) double json_number_value(const json_t* json);
|
||||
|
||||
|
@ -291,7 +262,8 @@ __declspec(dllimport) json_t* json_load_callback(json_load_callback_t callback,
|
|||
|
||||
/* encoding */
|
||||
|
||||
#define JSON_INDENT(n) ((n) & 0x1F)
|
||||
#define JSON_MAX_INDENT 0x1F
|
||||
#define JSON_INDENT(n) ((n) & JSON_MAX_INDENT)
|
||||
#define JSON_COMPACT 0x20
|
||||
#define JSON_ENSURE_ASCII 0x40
|
||||
#define JSON_SORT_KEYS 0x80
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
typedef json_t* JSON;
|
||||
|
||||
static JSON_INLINE
|
||||
json_t* json_hex(unsigned json_int_t value)
|
||||
{
|
||||
char hexvalue[20];
|
||||
#ifdef _WIN64
|
||||
sprintf(hexvalue, "0x%llX", value);
|
||||
#else //x64
|
||||
sprintf(hexvalue, "0x%X", value);
|
||||
#endif //_WIN64
|
||||
return json_string(hexvalue);
|
||||
}
|
||||
|
||||
static JSON_INLINE
|
||||
unsigned json_int_t json_hex_value(const json_t* hex)
|
||||
{
|
||||
unsigned json_int_t ret;
|
||||
const char* hexvalue;
|
||||
hexvalue = json_string_value(hex);
|
||||
if(!hexvalue)
|
||||
return 0;
|
||||
#ifdef _WIN64
|
||||
sscanf(hexvalue, "0x%llX", &ret);
|
||||
#else //x64
|
||||
sscanf(hexvalue, "0x%X", &ret);
|
||||
#endif //_WIN64
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,282 @@
|
|||
#include "label.h"
|
||||
#include "threading.h"
|
||||
#include "module.h"
|
||||
#include "memory.h"
|
||||
#include "debugger.h"
|
||||
|
||||
std::unordered_map<uint, LABELSINFO> labels;
|
||||
|
||||
bool LabelSet(uint Address, const char* Text, bool Manual)
|
||||
{
|
||||
// CHECK: Exported/Command function
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
|
||||
// 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* Address)
|
||||
{
|
||||
// CHECK: Future? (Not used)
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
|
||||
SHARED_ACQUIRE(LockLabels);
|
||||
|
||||
for(auto & itr : labels)
|
||||
{
|
||||
// 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 Address, char* Text)
|
||||
{
|
||||
// CHECK: Export function
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
|
||||
SHARED_ACQUIRE(LockLabels);
|
||||
|
||||
// Was the label at this address exist?
|
||||
auto found = labels.find(ModHashFromAddr(Address));
|
||||
|
||||
if(found == labels.end())
|
||||
return false;
|
||||
|
||||
// Copy to user buffer
|
||||
if(Text)
|
||||
strcpy_s(Text, MAX_LABEL_SIZE, found->second.text);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LabelDelete(uint Address)
|
||||
{
|
||||
// CHECK: Export function
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
|
||||
EXCLUSIVE_ACQUIRE(LockLabels);
|
||||
return (labels.erase(ModHashFromAddr(Address)) > 0);
|
||||
}
|
||||
|
||||
void LabelDelRange(uint Start, uint End)
|
||||
{
|
||||
// CHECK: Export function
|
||||
if(!DbgIsDebugging())
|
||||
return;
|
||||
|
||||
// Are all comments going to be deleted?
|
||||
// 0x00000000 - 0xFFFFFFFF
|
||||
if(Start == 0 && End == ~0)
|
||||
{
|
||||
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();)
|
||||
{
|
||||
// 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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LabelCacheSave(JSON Root)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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, jsonLabel);
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
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");
|
||||
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* List, size_t* Size)
|
||||
{
|
||||
// CHECK: Export function
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
|
||||
// At least 1 parameter is required
|
||||
if(!List && !Size)
|
||||
return false;
|
||||
|
||||
EXCLUSIVE_ACQUIRE(LockLabels);
|
||||
|
||||
// See if the user requested a size
|
||||
if(Size)
|
||||
{
|
||||
*Size = labels.size() * sizeof(LABELSINFO);
|
||||
|
||||
if(!List)
|
||||
return true;
|
||||
}
|
||||
|
||||
// Fill out the return list while converting the offset
|
||||
// to a virtual address
|
||||
for(auto & itr : labels)
|
||||
{
|
||||
*List = itr.second;
|
||||
List->addr += ModBaseFromName(itr.second.mod);
|
||||
List++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void LabelClear()
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockLabels);
|
||||
labels.clear();
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
|
||||
#include "_global.h"
|
||||
|
||||
struct LABELSINFO
|
||||
{
|
||||
char mod[MAX_MODULE_SIZE];
|
||||
uint addr;
|
||||
char text[MAX_LABEL_SIZE];
|
||||
bool manual;
|
||||
};
|
||||
|
||||
bool LabelSet(uint Address, const char* Text, bool Manual);
|
||||
bool LabelFromString(const char* Text, uint* Address);
|
||||
bool LabelGet(uint Address, char* Text);
|
||||
bool LabelDelete(uint Address);
|
||||
void LabelDelRange(uint Start, uint End);
|
||||
void LabelCacheSave(JSON root);
|
||||
void LabelCacheLoad(JSON root);
|
||||
bool LabelEnum(LABELSINFO* List, size_t* Size);
|
||||
void LabelClear();
|
|
@ -1,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
|
|
@ -0,0 +1,275 @@
|
|||
#include "loop.h"
|
||||
#include "debugger.h"
|
||||
#include "memory.h"
|
||||
#include "threading.h"
|
||||
#include "module.h"
|
||||
|
||||
std::map<DepthModuleRange, LOOPSINFO, DepthModuleRangeCompare> loops;
|
||||
|
||||
bool LoopAdd(uint Start, uint End, bool Manual)
|
||||
{
|
||||
// CHECK: Export function
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
|
||||
// Loop must begin before it ends
|
||||
if(Start > End)
|
||||
return false;
|
||||
|
||||
// Memory addresses must be valid
|
||||
if(!MemIsValidReadPtr(Start) || !MemIsValidReadPtr(End))
|
||||
return false;
|
||||
|
||||
// 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
|
||||
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 address
|
||||
bool LoopGet(int Depth, uint Address, uint* Start, uint* End)
|
||||
{
|
||||
// CHECK: Exported function
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
|
||||
// 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;
|
||||
|
||||
// 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)
|
||||
{
|
||||
// CHECK: Export function
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
|
||||
// Determine module addresses and lookup keys
|
||||
const uint moduleBase = ModBaseFromAddr(Start);
|
||||
const uint key = ModHashFromAddr(moduleBase);
|
||||
|
||||
uint curStart = Start - moduleBase;
|
||||
uint curEnd = End - moduleBase;
|
||||
|
||||
SHARED_ACQUIRE(LockLoops);
|
||||
|
||||
// Check if the new loop fits in the old loop
|
||||
for(auto & itr : loops)
|
||||
{
|
||||
// Only look in the current module
|
||||
if(itr.first.second.first != key)
|
||||
continue;
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// Did the user request t the loop depth?
|
||||
if(FinalDepth)
|
||||
*FinalDepth = Depth;
|
||||
|
||||
// Check for loop overlaps
|
||||
for(auto & itr : loops)
|
||||
{
|
||||
// Only look in the current module
|
||||
if(itr.first.second.first != key)
|
||||
continue;
|
||||
|
||||
// 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 LoopDelete(int Depth, uint Address)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void LoopCacheSave(JSON Root)
|
||||
{
|
||||
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 & 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, currentJson);
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
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");
|
||||
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)
|
||||
{
|
||||
// If list or size is not requested, fail
|
||||
if(!List && !Size)
|
||||
return false;
|
||||
|
||||
SHARED_ACQUIRE(LockLoops);
|
||||
|
||||
// See if the caller requested an output size
|
||||
if(Size)
|
||||
{
|
||||
*Size = loops.size() * sizeof(LOOPSINFO);
|
||||
|
||||
if(!List)
|
||||
return true;
|
||||
}
|
||||
|
||||
for(auto & itr : loops)
|
||||
{
|
||||
*List = itr.second;
|
||||
|
||||
// Adjust the offset to a real virtual address
|
||||
uint modbase = ModBaseFromName(List->mod);
|
||||
List->start += modbase;
|
||||
List->end += modbase;
|
||||
|
||||
List++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void LoopClear()
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockLoops);
|
||||
loops.clear();
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
#ifndef _LOOP_H
|
||||
#define _LOOP_H
|
||||
|
||||
#include "addrinfo.h"
|
||||
|
||||
struct LOOPSINFO
|
||||
{
|
||||
char mod[MAX_MODULE_SIZE];
|
||||
uint start;
|
||||
uint end;
|
||||
uint parent;
|
||||
int depth;
|
||||
bool manual;
|
||||
};
|
||||
|
||||
bool LoopAdd(uint Start, uint End, bool Manual);
|
||||
bool LoopGet(int Depth, uint Address, uint* Start, uint* End);
|
||||
bool LoopOverlaps(int Depth, uint Start, uint End, int* FinalDepth);
|
||||
bool LoopDelete(int Depth, uint Address);
|
||||
void LoopCacheSave(JSON Root);
|
||||
void LoopCacheLoad(JSON Root);
|
||||
bool LoopEnum(LOOPSINFO* List, size_t* Size);
|
||||
void LoopClear();
|
||||
|
||||
#endif //_LOOP_H
|
|
@ -1,3 +1,9 @@
|
|||
/**
|
||||
@file main.cpp
|
||||
|
||||
@brief Implements the main class.
|
||||
*/
|
||||
|
||||
#include "_global.h"
|
||||
|
||||
extern "C" DLL_EXPORT BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
|
||||
|
|
|
@ -1,33 +1,73 @@
|
|||
/**
|
||||
@file math.cpp
|
||||
|
||||
@brief Implements various functionalities that have to do with handling expression text.
|
||||
*/
|
||||
|
||||
#include "math.h"
|
||||
#include "value.h"
|
||||
|
||||
/**
|
||||
\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;
|
||||
int isset; //0=free, 1=open, 2=close
|
||||
|
||||
/**
|
||||
\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
|
||||
1 ( )
|
||||
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)
|
||||
{
|
||||
if(ch == '(' or ch == ')')
|
||||
|
@ -49,9 +89,9 @@ int mathisoperator(char ch)
|
|||
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)
|
||||
{
|
||||
|
@ -64,8 +104,10 @@ void mathformat(char* text)
|
|||
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)
|
||||
{
|
||||
|
@ -115,6 +157,14 @@ static inline int mulhi(int x, int y)
|
|||
}
|
||||
#endif //__MINGW64__
|
||||
|
||||
/**
|
||||
\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)
|
||||
{
|
||||
switch(op)
|
||||
|
@ -164,6 +214,14 @@ bool mathdounsignedoperation(char op, uint left, uint right, uint* result)
|
|||
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)
|
||||
{
|
||||
switch(op)
|
||||
|
@ -213,6 +271,12 @@ bool mathdosignedoperation(char op, sint left, sint right, sint* result)
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
\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++)
|
||||
|
@ -233,8 +297,14 @@ static void fillpair(EXPRESSION* expstruct, int pos, int layer)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
static 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);
|
||||
|
@ -262,6 +332,11 @@ static int matchpairs(EXPRESSION* expstruct, char* expression, int endlayer)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
\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);
|
||||
|
@ -285,6 +360,14 @@ static int expressionformat(char* exp)
|
|||
return open;
|
||||
}
|
||||
|
||||
/**
|
||||
\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++)
|
||||
|
@ -296,6 +379,15 @@ static void adjustpairs(EXPRESSION* exps, int cur_open, int cur_close, int cur_l
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\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++)
|
||||
|
@ -320,12 +412,18 @@ static bool printlayer(char* exp, EXPRESSION* exps, int layer, bool silent, bool
|
|||
|
||||
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)
|
||||
{
|
||||
EXPRESSION expstruct;
|
||||
|
@ -340,7 +438,7 @@ bool mathhandlebrackets(char* expression, bool silent, bool baseonly)
|
|||
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, 0);
|
||||
matchpairs(&expstruct, expression);
|
||||
int deepest = 0;
|
||||
for(int i = 0; i < expstruct.total_pairs; i++)
|
||||
if(expstruct.pairs[i].layer > deepest)
|
||||
|
@ -352,8 +450,15 @@ bool mathhandlebrackets(char* expression, bool silent, bool baseonly)
|
|||
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)
|
||||
{
|
||||
|
@ -410,4 +515,3 @@ bool mathfromstring(const char* string, uint* value, bool silent, bool baseonly,
|
|||
math_ok = mathdounsignedoperation(string[highestop_pos], left, right, value);
|
||||
return math_ok;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,13 +1,26 @@
|
|||
/**
|
||||
@file memory.cpp
|
||||
|
||||
@brief Implements the memory class.
|
||||
*/
|
||||
|
||||
#include "memory.h"
|
||||
#include "debugger.h"
|
||||
#include "patches.h"
|
||||
#include "console.h"
|
||||
#include "threading.h"
|
||||
#include "module.h"
|
||||
|
||||
MemoryMap memoryPages;
|
||||
#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))
|
||||
|
||||
std::map<Range, MEMPAGE, RangeCompare> memoryPages;
|
||||
bool bListAllPages = false;
|
||||
|
||||
void memupdatemap(HANDLE hProcess)
|
||||
void MemUpdateMap(HANDLE hProcess)
|
||||
{
|
||||
CriticalSectionLocker locker(LockMemoryPages);
|
||||
MEMORY_BASIC_INFORMATION mbi;
|
||||
|
@ -26,7 +39,7 @@ void memupdatemap(HANDLE hProcess)
|
|||
curAllocationBase = (uint)mbi.AllocationBase;
|
||||
MEMPAGE curPage;
|
||||
*curPage.info = 0;
|
||||
modnamefromaddr(MyAddress, curPage.info, true);
|
||||
ModNameFromAddr(MyAddress, curPage.info, true);
|
||||
memcpy(&curPage.mbi, &mbi, sizeof(mbi));
|
||||
pageVector.push_back(curPage);
|
||||
}
|
||||
|
@ -49,11 +62,11 @@ void memupdatemap(HANDLE hProcess)
|
|||
if(!pageVector.at(i).info[0] || (scmp(curMod, pageVector.at(i).info) && !bListAllPages)) //there is a module
|
||||
continue; //skip non-modules
|
||||
strcpy(curMod, pageVector.at(i).info);
|
||||
uint base = modbasefromname(pageVector.at(i).info);
|
||||
uint base = ModBaseFromName(pageVector.at(i).info);
|
||||
if(!base)
|
||||
continue;
|
||||
std::vector<MODSECTIONINFO> sections;
|
||||
if(!modsectionsfromaddr(base, §ions))
|
||||
if(!ModSectionsFromAddr(base, §ions))
|
||||
continue;
|
||||
int SectionNumber = (int)sections.size();
|
||||
if(!SectionNumber) //no sections = skip
|
||||
|
@ -122,202 +135,187 @@ void memupdatemap(HANDLE hProcess)
|
|||
}
|
||||
}
|
||||
|
||||
uint memfindbaseaddr(uint addr, uint* size, bool refresh)
|
||||
uint MemFindBaseAddr(uint Address, uint* Size, bool Refresh)
|
||||
{
|
||||
if(refresh)
|
||||
memupdatemap(fdProcessInfo->hProcess); //update memory map
|
||||
CriticalSectionLocker locker(LockMemoryPages);
|
||||
MemoryMap::iterator found = memoryPages.find(std::make_pair(addr, addr));
|
||||
// Update the memory map if needed
|
||||
if(Refresh)
|
||||
MemUpdateMap(fdProcessInfo->hProcess);
|
||||
|
||||
SHARED_ACQUIRE(LockMemoryPages);
|
||||
|
||||
// Search for the memory page address
|
||||
auto found = memoryPages.find(std::make_pair(Address, Address));
|
||||
|
||||
if(found == memoryPages.end())
|
||||
return 0;
|
||||
if(size)
|
||||
*size = found->second.mbi.RegionSize;
|
||||
|
||||
// Return the allocation region size when requested
|
||||
if(Size)
|
||||
*Size = found->second.mbi.RegionSize;
|
||||
|
||||
return found->first.first;
|
||||
}
|
||||
|
||||
bool memread(HANDLE hProcess, const void* lpBaseAddress, void* lpBuffer, SIZE_T nSize, SIZE_T* lpNumberOfBytesRead)
|
||||
bool MemRead(void* BaseAddress, void* Buffer, SIZE_T Size, SIZE_T* NumberOfBytesRead)
|
||||
{
|
||||
if(!hProcess or !lpBaseAddress or !lpBuffer or !nSize) //generic failures
|
||||
// Fast fail if address is invalid
|
||||
if(!MemIsCanonicalAddress((uint)BaseAddress))
|
||||
return false;
|
||||
SIZE_T read = 0;
|
||||
DWORD oldprotect = 0;
|
||||
bool ret = MemoryReadSafe(hProcess, (void*)lpBaseAddress, lpBuffer, nSize, &read); //try 'normal' RPM
|
||||
if(ret and read == nSize) //'normal' RPM worked!
|
||||
{
|
||||
if(lpNumberOfBytesRead)
|
||||
*lpNumberOfBytesRead = read;
|
||||
|
||||
// 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(!NumberOfBytesRead)
|
||||
NumberOfBytesRead = &bytesReadTemp;
|
||||
|
||||
// Normal single-call read
|
||||
bool ret = MemoryReadSafe(fdProcessInfo->hProcess, BaseAddress, Buffer, Size, NumberOfBytesRead);
|
||||
|
||||
if(ret && *NumberOfBytesRead == Size)
|
||||
return true;
|
||||
}
|
||||
for(uint i = 0; i < nSize; i++) //read byte-per-byte
|
||||
|
||||
// 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)
|
||||
{
|
||||
unsigned char* curaddr = (unsigned char*)lpBaseAddress + i;
|
||||
unsigned char* curbuf = (unsigned char*)lpBuffer + i;
|
||||
ret = MemoryReadSafe(hProcess, curaddr, curbuf, 1, 0); //try 'normal' RPM
|
||||
if(!ret) //we failed
|
||||
// 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;
|
||||
|
||||
for(SIZE_T i = 0; i < pageCount; i++)
|
||||
{
|
||||
if(lpNumberOfBytesRead)
|
||||
*lpNumberOfBytesRead = i;
|
||||
SetLastError(ERROR_PARTIAL_COPY);
|
||||
return false;
|
||||
SIZE_T bytesRead = 0;
|
||||
|
||||
if(MemoryReadSafe(fdProcessInfo->hProcess, (PVOID)readBase, ((PBYTE)Buffer + offset), readSize, &bytesRead))
|
||||
*NumberOfBytesRead += bytesRead;
|
||||
|
||||
offset += readSize;
|
||||
readBase += readSize;
|
||||
|
||||
Size -= readSize;
|
||||
readSize = (Size > PAGE_SIZE) ? PAGE_SIZE : Size;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
SetLastError(ERROR_PARTIAL_COPY);
|
||||
return (*NumberOfBytesRead > 0);
|
||||
}
|
||||
|
||||
bool memwrite(HANDLE hProcess, void* lpBaseAddress, const void* lpBuffer, SIZE_T nSize, SIZE_T* lpNumberOfBytesWritten)
|
||||
bool MemWrite(void* BaseAddress, void* Buffer, SIZE_T Size, SIZE_T* NumberOfBytesWritten)
|
||||
{
|
||||
if(!hProcess or !lpBaseAddress or !lpBuffer or !nSize) //generic failures
|
||||
// Fast fail if address is invalid
|
||||
if(!MemIsCanonicalAddress((uint)BaseAddress))
|
||||
return false;
|
||||
SIZE_T written = 0;
|
||||
DWORD oldprotect = 0;
|
||||
bool ret = MemoryWriteSafe(hProcess, lpBaseAddress, lpBuffer, nSize, &written);
|
||||
if(ret and written == nSize) //'normal' WPM worked!
|
||||
{
|
||||
if(lpNumberOfBytesWritten)
|
||||
*lpNumberOfBytesWritten = written;
|
||||
|
||||
// Buffer must be supplied and size must be greater than 0
|
||||
if(!Buffer || Size <= 0)
|
||||
return false;
|
||||
|
||||
// If the 'bytes written' parameter is null, use a temp
|
||||
SIZE_T bytesWrittenTemp = 0;
|
||||
|
||||
if(!NumberOfBytesWritten)
|
||||
NumberOfBytesWritten = &bytesWrittenTemp;
|
||||
|
||||
// Try a regular WriteProcessMemory call
|
||||
bool ret = MemoryWriteSafe(fdProcessInfo->hProcess, BaseAddress, Buffer, Size, NumberOfBytesWritten);
|
||||
|
||||
if(ret && *NumberOfBytesWritten == Size)
|
||||
return true;
|
||||
}
|
||||
for(uint i = 0; i < nSize; i++) //write byte-per-byte
|
||||
|
||||
// Write page-by-page (Skip if only 1 page exists)
|
||||
// See: MemRead
|
||||
SIZE_T pageCount = BYTES_TO_PAGES(Size);
|
||||
|
||||
if(pageCount > 1)
|
||||
{
|
||||
unsigned char* curaddr = (unsigned char*)lpBaseAddress + i;
|
||||
unsigned char* curbuf = (unsigned char*)lpBuffer + i;
|
||||
ret = MemoryWriteSafe(hProcess, curaddr, curbuf, 1, 0); //try 'normal' WPM
|
||||
if(!ret) //we failed
|
||||
// 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;
|
||||
|
||||
for(SIZE_T i = 0; i < pageCount; i++)
|
||||
{
|
||||
if(lpNumberOfBytesWritten)
|
||||
*lpNumberOfBytesWritten = i;
|
||||
SetLastError(ERROR_PARTIAL_COPY);
|
||||
return false;
|
||||
SIZE_T bytesWritten = 0;
|
||||
|
||||
if(MemoryWriteSafe(fdProcessInfo->hProcess, (PVOID)writeBase, ((PBYTE)Buffer + offset), writeSize, &bytesWritten))
|
||||
*NumberOfBytesWritten += bytesWritten;
|
||||
|
||||
offset += writeSize;
|
||||
writeBase += writeSize;
|
||||
|
||||
Size -= writeSize;
|
||||
writeSize = (Size > PAGE_SIZE) ? PAGE_SIZE : Size;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
SetLastError(ERROR_PARTIAL_COPY);
|
||||
return (*NumberOfBytesWritten > 0);
|
||||
}
|
||||
|
||||
bool mempatch(HANDLE hProcess, void* lpBaseAddress, const void* lpBuffer, SIZE_T nSize, SIZE_T* lpNumberOfBytesWritten)
|
||||
bool MemPatch(void* BaseAddress, void* Buffer, SIZE_T Size, SIZE_T* NumberOfBytesWritten)
|
||||
{
|
||||
if(!hProcess or !lpBaseAddress or !lpBuffer or !nSize) //generic failures
|
||||
// Buffer and size must be valid
|
||||
if(!Buffer || Size <= 0)
|
||||
return false;
|
||||
Memory<unsigned char*> olddata(nSize, "mempatch:olddata");
|
||||
if(!memread(hProcess, lpBaseAddress, olddata, nSize, 0))
|
||||
return memwrite(hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesWritten);
|
||||
unsigned char* newdata = (unsigned char*)lpBuffer;
|
||||
for(uint i = 0; i < nSize; i++)
|
||||
patchset((uint)lpBaseAddress + i, olddata[i], newdata[i]);
|
||||
return memwrite(hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesWritten);
|
||||
|
||||
// Allocate the memory
|
||||
Memory<unsigned char*> oldData(Size, "mempatch:oldData");
|
||||
|
||||
if(!MemRead(BaseAddress, oldData, Size, nullptr))
|
||||
{
|
||||
// If no memory can be read, no memory can be written. Fail out
|
||||
// of this function.
|
||||
return false;
|
||||
}
|
||||
|
||||
for(SIZE_T i = 0; i < Size; i++)
|
||||
PatchSet((uint)BaseAddress + i, oldData[i], ((unsigned char*)Buffer)[i]);
|
||||
|
||||
return MemWrite(BaseAddress, Buffer, Size, NumberOfBytesWritten);
|
||||
}
|
||||
|
||||
bool memisvalidreadptr(HANDLE hProcess, uint addr)
|
||||
bool MemIsValidReadPtr(uint Address)
|
||||
{
|
||||
unsigned char a = 0;
|
||||
return memread(hProcess, (void*)addr, &a, 1, 0);
|
||||
return MemRead((void*)Address, &a, sizeof(unsigned char), nullptr);
|
||||
}
|
||||
|
||||
void* memalloc(HANDLE hProcess, uint addr, SIZE_T size, DWORD fdProtect)
|
||||
bool MemIsCanonicalAddress(uint Address)
|
||||
{
|
||||
return VirtualAllocEx(hProcess, (void*)addr, size, MEM_RESERVE | MEM_COMMIT, fdProtect);
|
||||
}
|
||||
|
||||
void memfree(HANDLE hProcess, uint addr)
|
||||
{
|
||||
VirtualFreeEx(hProcess, (void*)addr, 0, MEM_RELEASE);
|
||||
}
|
||||
|
||||
static int formathexpattern(char* string)
|
||||
{
|
||||
int len = (int)strlen(string);
|
||||
_strupr(string);
|
||||
Memory<char*> new_string(len + 1, "formathexpattern:new_string");
|
||||
memset(new_string, 0, len + 1);
|
||||
for(int i = 0, j = 0; i < len; i++)
|
||||
if(string[i] == '?' or isxdigit(string[i]))
|
||||
j += sprintf(new_string + j, "%c", string[i]);
|
||||
strcpy(string, new_string);
|
||||
return (int)strlen(string);
|
||||
}
|
||||
|
||||
static bool patterntransform(const char* text, std::vector<PATTERNBYTE>* pattern)
|
||||
{
|
||||
if(!text or !pattern)
|
||||
return false;
|
||||
pattern->clear();
|
||||
int len = (int)strlen(text);
|
||||
if(!len)
|
||||
return false;
|
||||
Memory<char*> newtext(len + 2, "transformpattern:newtext");
|
||||
strcpy(newtext, text);
|
||||
len = formathexpattern(newtext);
|
||||
if(len % 2) //not a multiple of 2
|
||||
{
|
||||
newtext[len] = '?';
|
||||
newtext[len + 1] = '\0';
|
||||
len++;
|
||||
}
|
||||
PATTERNBYTE newByte;
|
||||
for(int i = 0, j = 0; i < len; i++)
|
||||
{
|
||||
if(newtext[i] == '?') //wildcard
|
||||
{
|
||||
newByte.n[j].all = true; //match anything
|
||||
newByte.n[j].n = 0;
|
||||
j++;
|
||||
}
|
||||
else //hex
|
||||
{
|
||||
char x[2] = "";
|
||||
*x = newtext[i];
|
||||
unsigned int val = 0;
|
||||
sscanf(x, "%x", &val);
|
||||
newByte.n[j].all = false;
|
||||
newByte.n[j].n = val & 0xF;
|
||||
j++;
|
||||
}
|
||||
|
||||
if(j == 2) //two nibbles = one byte
|
||||
{
|
||||
j = 0;
|
||||
pattern->push_back(newByte);
|
||||
}
|
||||
}
|
||||
#ifndef _WIN64
|
||||
// 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;
|
||||
#endif // _WIN64
|
||||
}
|
||||
|
||||
static bool patternmatchbyte(unsigned char byte, PATTERNBYTE* pbyte)
|
||||
void* MemAllocRemote(uint Address, SIZE_T Size, DWORD Protect)
|
||||
{
|
||||
unsigned char n1 = (byte >> 4) & 0xF;
|
||||
unsigned char n2 = byte & 0xF;
|
||||
int matched = 0;
|
||||
if(pbyte->n[0].all)
|
||||
matched++;
|
||||
else if(pbyte->n[0].n == n1)
|
||||
matched++;
|
||||
if(pbyte->n[1].all)
|
||||
matched++;
|
||||
else if(pbyte->n[1].n == n2)
|
||||
matched++;
|
||||
return (matched == 2);
|
||||
return VirtualAllocEx(fdProcessInfo->hProcess, (void*)Address, Size, MEM_RESERVE | MEM_COMMIT, Protect);
|
||||
}
|
||||
|
||||
uint memfindpattern(unsigned char* data, uint size, const char* pattern, int* patternsize)
|
||||
void MemFreeRemote(uint Address)
|
||||
{
|
||||
std::vector<PATTERNBYTE> searchpattern;
|
||||
if(!patterntransform(pattern, &searchpattern))
|
||||
return -1;
|
||||
int searchpatternsize = (int)searchpattern.size();
|
||||
if(patternsize)
|
||||
*patternsize = searchpatternsize;
|
||||
for(uint i = 0, pos = 0; i < size; i++) //search for the pattern
|
||||
{
|
||||
if(patternmatchbyte(data[i], &searchpattern.at(pos))) //check if our pattern matches the current byte
|
||||
{
|
||||
pos++;
|
||||
if(pos == searchpatternsize) //everything matched
|
||||
return i - searchpatternsize + 1;
|
||||
}
|
||||
else if(pos > 0) //fix by Computer_Angel
|
||||
{
|
||||
i -= pos; // return to previous byte
|
||||
pos = 0; //reset current pattern position
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
VirtualFreeEx(fdProcessInfo->hProcess, (void*)Address, 0, MEM_RELEASE);
|
||||
}
|
|
@ -1,33 +1,17 @@
|
|||
#ifndef _MEMORY_H
|
||||
#define _MEMORY_H
|
||||
#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;
|
||||
|
||||
struct PATTERNNIBBLE
|
||||
{
|
||||
unsigned char n;
|
||||
bool all;
|
||||
};
|
||||
|
||||
struct PATTERNBYTE
|
||||
{
|
||||
PATTERNNIBBLE n[2];
|
||||
};
|
||||
|
||||
void memupdatemap(HANDLE hProcess);
|
||||
uint memfindbaseaddr(uint addr, uint* size, bool refresh = false);
|
||||
bool memread(HANDLE hProcess, const void* lpBaseAddress, void* lpBuffer, SIZE_T nSize, SIZE_T* lpNumberOfBytesRead);
|
||||
bool memwrite(HANDLE hProcess, void* lpBaseAddress, const void* lpBuffer, SIZE_T nSize, SIZE_T* lpNumberOfBytesWritten);
|
||||
bool mempatch(HANDLE hProcess, void* lpBaseAddress, const void* lpBuffer, SIZE_T nSize, SIZE_T* lpNumberOfBytesWritten);
|
||||
bool memisvalidreadptr(HANDLE hProcess, uint addr);
|
||||
void* memalloc(HANDLE hProcess, uint addr, SIZE_T size, DWORD fdProtect);
|
||||
void memfree(HANDLE hProcess, uint addr);
|
||||
uint memfindpattern(unsigned char* data, uint size, const char* pattern, int* patternsize = 0);
|
||||
|
||||
#endif // _MEMORY_H
|
||||
void MemUpdateMap(HANDLE hProcess);
|
||||
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);
|
||||
bool MemIsValidReadPtr(uint Address);
|
||||
bool MemIsCanonicalAddress(uint Address);
|
||||
void* MemAllocRemote(uint Address, SIZE_T Size, DWORD Protect);
|
||||
void MemFreeRemote(uint Address);
|
|
@ -0,0 +1,274 @@
|
|||
#include "module.h"
|
||||
#include "debugger.h"
|
||||
#include "threading.h"
|
||||
#include "symbolinfo.h"
|
||||
#include "murmurhash.h"
|
||||
|
||||
std::map<Range, MODINFO, RangeCompare> modinfo;
|
||||
|
||||
bool ModLoad(uint Base, uint Size, const char* FullPath)
|
||||
{
|
||||
//
|
||||
// Handle a new module being loaded
|
||||
//
|
||||
// TODO: Do loaded modules always require a path?
|
||||
if(!Base || !Size || !FullPath)
|
||||
return false;
|
||||
|
||||
MODINFO info;
|
||||
|
||||
// Copy the module path in the struct
|
||||
strcpy_s(info.path, FullPath);
|
||||
|
||||
// Break the module path into a directory and file name
|
||||
char dir[MAX_PATH] = "";
|
||||
char file[MAX_MODULE_SIZE] = "";
|
||||
strcpy_s(dir, FullPath);
|
||||
_strlwr(dir);
|
||||
char* fileStart = strrchr(dir, '\\');
|
||||
if(fileStart)
|
||||
{
|
||||
strcpy_s(file, fileStart + 1);
|
||||
*fileStart = '\0';
|
||||
}
|
||||
|
||||
//calculate module hash from full file name
|
||||
info.hash = ModHashFromName(file);
|
||||
|
||||
// Copy the extension into the module struct
|
||||
{
|
||||
char* extensionPos = strrchr(file, '.');
|
||||
|
||||
if(extensionPos)
|
||||
{
|
||||
strcpy_s(info.extension, extensionPos);
|
||||
extensionPos[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
// Copy the name to the module struct
|
||||
strcpy_s(info.name, file);
|
||||
|
||||
// Module base address/size
|
||||
info.base = Base;
|
||||
info.size = Size;
|
||||
|
||||
// Process module sections
|
||||
info.sections.clear();
|
||||
|
||||
WString wszFullPath = StringUtils::Utf8ToUtf16(FullPath);
|
||||
if(StaticFileLoadW(wszFullPath.c_str(), UE_ACCESS_READ, false, &info.Handle, &info.FileMapSize, &info.MapHandle, &info.FileMapVA))
|
||||
{
|
||||
// Get the entry point
|
||||
info.entry = GetPE32DataFromMappedFile(info.FileMapVA, 0, UE_OEP) + info.base;
|
||||
|
||||
// Enumerate all PE sections
|
||||
int sectionCount = (int)GetPE32DataFromMappedFile(info.FileMapVA, 0, UE_SECTIONNUMBER);
|
||||
|
||||
for(int i = 0; i < sectionCount; i++)
|
||||
{
|
||||
MODSECTIONINFO curSection;
|
||||
|
||||
curSection.addr = GetPE32DataFromMappedFile(info.FileMapVA, i, UE_SECTIONVIRTUALOFFSET) + info.base;
|
||||
curSection.size = GetPE32DataFromMappedFile(info.FileMapVA, i, UE_SECTIONVIRTUALSIZE);
|
||||
const char* sectionName = (const char*)GetPE32DataFromMappedFile(info.FileMapVA, i, UE_SECTIONNAME);
|
||||
|
||||
// Escape section name when needed
|
||||
strcpy_s(curSection.name, StringUtils::Escape(sectionName).c_str());
|
||||
|
||||
// Add entry to the vector
|
||||
info.sections.push_back(curSection);
|
||||
}
|
||||
}
|
||||
|
||||
// Add module to list
|
||||
EXCLUSIVE_ACQUIRE(LockModules);
|
||||
modinfo.insert(std::make_pair(Range(Base, Base + Size - 1), info));
|
||||
EXCLUSIVE_RELEASE();
|
||||
|
||||
SymUpdateModuleList();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ModUnload(uint Base)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockModules);
|
||||
|
||||
// Find the iterator index
|
||||
const auto found = modinfo.find(Range(Base, Base));
|
||||
|
||||
if(found == modinfo.end())
|
||||
return false;
|
||||
|
||||
// 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
|
||||
SymUpdateModuleList();
|
||||
return true;
|
||||
}
|
||||
|
||||
void ModClear()
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockModules);
|
||||
modinfo.clear();
|
||||
EXCLUSIVE_RELEASE();
|
||||
|
||||
// Tell the symbol updater
|
||||
SymUpdateModuleList();
|
||||
}
|
||||
|
||||
MODINFO* ModInfoFromAddr(uint Address)
|
||||
{
|
||||
//
|
||||
// NOTE: THIS DOES _NOT_ USE LOCKS
|
||||
//
|
||||
auto found = modinfo.find(Range(Address, Address));
|
||||
|
||||
// Was the module found with this address?
|
||||
if(found == modinfo.end())
|
||||
return nullptr;
|
||||
|
||||
return &found->second;
|
||||
}
|
||||
|
||||
bool ModNameFromAddr(uint Address, char* Name, bool Extension)
|
||||
{
|
||||
if(!Name)
|
||||
return false;
|
||||
|
||||
SHARED_ACQUIRE(LockModules);
|
||||
|
||||
// Get a pointer to module information
|
||||
auto module = ModInfoFromAddr(Address);
|
||||
|
||||
if(!module)
|
||||
return false;
|
||||
|
||||
// Copy initial module name
|
||||
strcpy_s(Name, MAX_MODULE_SIZE, module->name);
|
||||
|
||||
if(Extension)
|
||||
strcat_s(Name, MAX_MODULE_SIZE, module->extension);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint ModBaseFromAddr(uint Address)
|
||||
{
|
||||
SHARED_ACQUIRE(LockModules);
|
||||
|
||||
auto module = ModInfoFromAddr(Address);
|
||||
|
||||
if(!module)
|
||||
return 0;
|
||||
|
||||
return module->base;
|
||||
}
|
||||
|
||||
uint ModHashFromAddr(uint Address)
|
||||
{
|
||||
//
|
||||
// Returns a unique hash from a virtual address
|
||||
//
|
||||
SHARED_ACQUIRE(LockModules);
|
||||
|
||||
auto module = ModInfoFromAddr(Address);
|
||||
|
||||
if(!module)
|
||||
return Address;
|
||||
|
||||
return module->hash + (Address - module->base);
|
||||
}
|
||||
|
||||
uint ModHashFromName(const char* Module)
|
||||
{
|
||||
//
|
||||
// return MODINFO.hash (based on the name)
|
||||
//
|
||||
if(!Module || Module[0] == '\0')
|
||||
return 0;
|
||||
|
||||
return murmurhash(Module, (int)strlen(Module));
|
||||
}
|
||||
|
||||
uint ModBaseFromName(const char* Module)
|
||||
{
|
||||
if(!Module || strlen(Module) >= MAX_MODULE_SIZE)
|
||||
return 0;
|
||||
|
||||
SHARED_ACQUIRE(LockModules);
|
||||
|
||||
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);
|
||||
|
||||
// Test with and without extension
|
||||
if(!_stricmp(currentModule, Module) || !_stricmp(itr->second.name, Module))
|
||||
return itr->second.base;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint ModSizeFromAddr(uint Address)
|
||||
{
|
||||
SHARED_ACQUIRE(LockModules);
|
||||
|
||||
auto module = ModInfoFromAddr(Address);
|
||||
|
||||
if(!module)
|
||||
return 0;
|
||||
|
||||
return module->size;
|
||||
}
|
||||
|
||||
bool ModSectionsFromAddr(uint Address, std::vector<MODSECTIONINFO>* Sections)
|
||||
{
|
||||
SHARED_ACQUIRE(LockModules);
|
||||
|
||||
auto module = ModInfoFromAddr(Address);
|
||||
|
||||
if(!module)
|
||||
return false;
|
||||
|
||||
// Copy vector <-> vector
|
||||
*Sections = module->sections;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint ModEntryFromAddr(uint Address)
|
||||
{
|
||||
SHARED_ACQUIRE(LockModules);
|
||||
|
||||
auto module = ModInfoFromAddr(Address);
|
||||
|
||||
if(!module)
|
||||
return 0;
|
||||
|
||||
return module->entry;
|
||||
}
|
||||
|
||||
int ModPathFromAddr(duint Address, char* Path, int Size)
|
||||
{
|
||||
SHARED_ACQUIRE(LockModules);
|
||||
|
||||
auto module = ModInfoFromAddr(Address);
|
||||
|
||||
if(!module)
|
||||
return 0;
|
||||
|
||||
strcpy_s(Path, Size, module->path);
|
||||
return (int)strlen(Path);
|
||||
}
|
||||
|
||||
int ModPathFromName(const char* Module, char* Path, int Size)
|
||||
{
|
||||
return ModPathFromAddr(ModBaseFromName(Module), Path, Size);
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
#pragma once
|
||||
|
||||
#include "_global.h"
|
||||
#include "addrinfo.h"
|
||||
|
||||
struct MODSECTIONINFO
|
||||
{
|
||||
uint addr; // Virtual address
|
||||
uint size; // Virtual size
|
||||
char name[50]; // Escaped section name
|
||||
};
|
||||
|
||||
struct MODINFO
|
||||
{
|
||||
uint base; // Module base
|
||||
uint size; // Module size
|
||||
uint hash; // Full module name hash
|
||||
uint entry; // Entry point
|
||||
|
||||
char name[MAX_MODULE_SIZE]; // Module name (without extension)
|
||||
char extension[MAX_MODULE_SIZE]; // File extension
|
||||
char path[MAX_PATH]; // File path (in UTF8)
|
||||
|
||||
HANDLE Handle; // Handle to the file opened by TitanEngine
|
||||
HANDLE MapHandle; // Handle to the memory map
|
||||
ULONG_PTR FileMapVA; // File map virtual address (Debugger local)
|
||||
DWORD FileMapSize; // File map virtual size
|
||||
|
||||
std::vector<MODSECTIONINFO> sections;
|
||||
};
|
||||
|
||||
bool ModLoad(uint Base, uint Size, const char* FullPath);
|
||||
bool ModUnload(uint Base);
|
||||
void ModClear();
|
||||
MODINFO* ModInfoFromAddr(uint Address);
|
||||
bool ModNameFromAddr(uint Address, char* Name, bool Extension);
|
||||
uint ModBaseFromAddr(uint Address);
|
||||
uint ModHashFromAddr(uint Address);
|
||||
uint ModHashFromName(const char* Module);
|
||||
uint ModBaseFromName(const char* Module);
|
||||
uint ModSizeFromAddr(uint Address);
|
||||
bool ModSectionsFromAddr(uint Address, std::vector<MODSECTIONINFO>* Sections);
|
||||
uint ModEntryFromAddr(uint Address);
|
||||
int ModPathFromAddr(duint Address, char* Path, int Size);
|
||||
int ModPathFromName(const char* Module, char* Path, int Size);
|
|
@ -14,7 +14,7 @@ static void msgfree(MESSAGE* msg)
|
|||
}
|
||||
|
||||
//allocate a message stack
|
||||
MESSAGE_STACK* msgallocstack()
|
||||
MESSAGE_STACK* MsgAllocStack()
|
||||
{
|
||||
MESSAGE_STACK* msgstack = (MESSAGE_STACK*)emalloc(sizeof(MESSAGE_STACK), "msgallocstack:msgstack");
|
||||
if(!msgstack)
|
||||
|
@ -25,7 +25,7 @@ MESSAGE_STACK* msgallocstack()
|
|||
}
|
||||
|
||||
//free a message stack
|
||||
void msgfreestack(MESSAGE_STACK* msgstack)
|
||||
void MsgFreeStack(MESSAGE_STACK* msgstack)
|
||||
{
|
||||
DeleteCriticalSection(&msgstack->cr);
|
||||
int stackpos = msgstack->stackpos;
|
||||
|
@ -35,7 +35,7 @@ void msgfreestack(MESSAGE_STACK* msgstack)
|
|||
}
|
||||
|
||||
//add a message to the stack
|
||||
bool msgsend(MESSAGE_STACK* msgstack, int msg, uint param1, uint param2)
|
||||
bool MsgSend(MESSAGE_STACK* msgstack, int msg, uint param1, uint param2)
|
||||
{
|
||||
CRITICAL_SECTION* cr = &msgstack->cr;
|
||||
EnterCriticalSection(cr);
|
||||
|
@ -61,7 +61,7 @@ bool msgsend(MESSAGE_STACK* msgstack, int msg, uint param1, uint param2)
|
|||
}
|
||||
|
||||
//get a message from the stack (will return false when there are no messages)
|
||||
bool msgget(MESSAGE_STACK* msgstack, MESSAGE* msg)
|
||||
bool MsgGet(MESSAGE_STACK* msgstack, MESSAGE* msg)
|
||||
{
|
||||
CRITICAL_SECTION* cr = &msgstack->cr;
|
||||
EnterCriticalSection(cr);
|
||||
|
@ -82,8 +82,8 @@ bool msgget(MESSAGE_STACK* msgstack, MESSAGE* msg)
|
|||
}
|
||||
|
||||
//wait for a message on the specified stack
|
||||
void msgwait(MESSAGE_STACK* msgstack, MESSAGE* msg)
|
||||
void MsgWait(MESSAGE_STACK* msgstack, MESSAGE* msg)
|
||||
{
|
||||
while(!msgget(msgstack, msg))
|
||||
while(!MsgGet(msgstack, msg))
|
||||
Sleep(1);
|
||||
}
|
||||
|
|
|
@ -23,10 +23,10 @@ struct MESSAGE_STACK
|
|||
};
|
||||
|
||||
//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* 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);
|
||||
|
||||
#endif // _MSGQUEUE_H
|
||||
|
|
|
@ -16,19 +16,56 @@
|
|||
|
||||
#if defined(_MSC_VER)
|
||||
|
||||
/**
|
||||
@def FORCE_INLINE
|
||||
|
||||
@brief A macro that defines force inline.
|
||||
*/
|
||||
|
||||
#define FORCE_INLINE __forceinline
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/**
|
||||
@def ROTL32(x,y) _rotl(x,y)
|
||||
|
||||
@brief A macro that defines rotl 32.
|
||||
|
||||
@param x The void to process.
|
||||
@param y The void to process.
|
||||
*/
|
||||
|
||||
#define ROTL32(x,y) _rotl(x,y)
|
||||
|
||||
/**
|
||||
@def ROTL64(x,y) _rotl64(x,y)
|
||||
|
||||
@brief A macro that defines rotl 64.
|
||||
|
||||
@param x The void to process.
|
||||
@param y The void to process.
|
||||
*/
|
||||
|
||||
#define ROTL64(x,y) _rotl64(x,y)
|
||||
|
||||
/**
|
||||
@def BIG_CONSTANT(x) (x)
|
||||
|
||||
@brief A macro that defines big constant.
|
||||
|
||||
@param x The void to process.
|
||||
*/
|
||||
|
||||
#define BIG_CONSTANT(x) (x)
|
||||
|
||||
// Other compilers
|
||||
|
||||
#else // defined(_MSC_VER)
|
||||
|
||||
/**
|
||||
@brief The force inline.
|
||||
*/
|
||||
|
||||
#define FORCE_INLINE inline __attribute__((always_inline))
|
||||
|
||||
inline uint32_t rotl32(uint32_t x, int8_t r)
|
||||
|
@ -41,29 +78,84 @@ inline uint64_t rotl64(uint64_t x, int8_t r)
|
|||
return (x << r) | (x >> (64 - r));
|
||||
}
|
||||
|
||||
/**
|
||||
@def ROTL32(x,y) rotl32(x,y)
|
||||
|
||||
@brief A macro that defines rotl 32.
|
||||
|
||||
@param x The void to process.
|
||||
@param y The void to process.
|
||||
*/
|
||||
|
||||
#define ROTL32(x,y) rotl32(x,y)
|
||||
|
||||
/**
|
||||
@def ROTL64(x,y) rotl64(x,y)
|
||||
|
||||
@brief A macro that defines rotl 64.
|
||||
|
||||
@param x The void to process.
|
||||
@param y The void to process.
|
||||
*/
|
||||
|
||||
#define ROTL64(x,y) rotl64(x,y)
|
||||
|
||||
/**
|
||||
@def BIG_CONSTANT(x) (x##LLU)
|
||||
|
||||
@brief A macro that defines big constant.
|
||||
|
||||
@param x The void to process.
|
||||
*/
|
||||
|
||||
#define BIG_CONSTANT(x) (x##LLU)
|
||||
|
||||
#endif // !defined(_MSC_VER)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Block read - if your platform needs to do endian-swapping or can only
|
||||
// handle aligned reads, do the conversion here
|
||||
/**
|
||||
@fn FORCE_INLINE uint32_t getblock32(const uint32_t* p, int i)
|
||||
|
||||
@brief -----------------------------------------------------------------------------
|
||||
Block read - if your platform needs to do endian-swapping or can only handle aligned reads, do
|
||||
the conversion here.
|
||||
|
||||
@param p The const uint32_t* to process.
|
||||
@param i Zero-based index of the.
|
||||
|
||||
@return An uint32_t.
|
||||
*/
|
||||
|
||||
FORCE_INLINE uint32_t getblock32(const uint32_t* p, int i)
|
||||
{
|
||||
return p[i];
|
||||
}
|
||||
|
||||
/**
|
||||
@fn FORCE_INLINE uint64_t getblock64(const uint64_t* p, int i)
|
||||
|
||||
@brief Getblock 64.
|
||||
|
||||
@param p The const uint64_t* to process.
|
||||
@param i Zero-based index of the.
|
||||
|
||||
@return An uint64_t.
|
||||
*/
|
||||
|
||||
FORCE_INLINE uint64_t getblock64(const uint64_t* p, int i)
|
||||
{
|
||||
return p[i];
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Finalization mix - force all bits of a hash block to avalanche
|
||||
/**
|
||||
@fn FORCE_INLINE uint32_t fmix32(uint32_t h)
|
||||
|
||||
@brief -----------------------------------------------------------------------------
|
||||
Finalization mix - force all bits of a hash block to avalanche.
|
||||
|
||||
@param h The uint32_t to process.
|
||||
|
||||
@return An uint32_t.
|
||||
*/
|
||||
|
||||
FORCE_INLINE uint32_t fmix32(uint32_t h)
|
||||
{
|
||||
|
@ -78,6 +170,16 @@ FORCE_INLINE uint32_t fmix32(uint32_t h)
|
|||
|
||||
//----------
|
||||
|
||||
/**
|
||||
@fn FORCE_INLINE uint64_t fmix64(uint64_t k)
|
||||
|
||||
@brief Fmix 64.
|
||||
|
||||
@param k The uint64_t to process.
|
||||
|
||||
@return An uint64_t.
|
||||
*/
|
||||
|
||||
FORCE_INLINE uint64_t fmix64(uint64_t k)
|
||||
{
|
||||
k ^= k >> 33;
|
||||
|
@ -91,6 +193,17 @@ FORCE_INLINE uint64_t fmix64(uint64_t k)
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
@fn void MurmurHash3_x86_32(const void* key, int len, uint32_t seed, void* out)
|
||||
|
||||
@brief Murmur hash 3 x coordinate 86 32.
|
||||
|
||||
@param key The key.
|
||||
@param len The length.
|
||||
@param seed The seed.
|
||||
@param [in,out] out If non-null, the out.
|
||||
*/
|
||||
|
||||
void MurmurHash3_x86_32(const void* key, int len,
|
||||
uint32_t seed, void* out)
|
||||
{
|
||||
|
@ -153,6 +266,17 @@ void MurmurHash3_x86_32(const void* key, int len,
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
@fn void MurmurHash3_x86_128(const void* key, const int len, uint32_t seed, void* out)
|
||||
|
||||
@brief Murmur hash 3 x coordinate 86 128.
|
||||
|
||||
@param key The key.
|
||||
@param len The length.
|
||||
@param seed The seed.
|
||||
@param [in,out] out If non-null, the out.
|
||||
*/
|
||||
|
||||
void MurmurHash3_x86_128(const void* key, const int len,
|
||||
uint32_t seed, void* out)
|
||||
{
|
||||
|
@ -182,7 +306,7 @@ void MurmurHash3_x86_128(const void* key, const int len,
|
|||
uint32_t k4 = getblock32(blocks, i * 4 + 3);
|
||||
|
||||
k1 *= c1;
|
||||
k1 = ROTL32(k1, 15);
|
||||
k1 = ROTL32(k1, 15);
|
||||
k1 *= c2;
|
||||
h1 ^= k1;
|
||||
|
||||
|
@ -191,7 +315,7 @@ void MurmurHash3_x86_128(const void* key, const int len,
|
|||
h1 = h1 * 5 + 0x561ccd1b;
|
||||
|
||||
k2 *= c2;
|
||||
k2 = ROTL32(k2, 16);
|
||||
k2 = ROTL32(k2, 16);
|
||||
k2 *= c3;
|
||||
h2 ^= k2;
|
||||
|
||||
|
@ -200,7 +324,7 @@ void MurmurHash3_x86_128(const void* key, const int len,
|
|||
h2 = h2 * 5 + 0x0bcaa747;
|
||||
|
||||
k3 *= c3;
|
||||
k3 = ROTL32(k3, 17);
|
||||
k3 = ROTL32(k3, 17);
|
||||
k3 *= c4;
|
||||
h3 ^= k3;
|
||||
|
||||
|
@ -209,7 +333,7 @@ void MurmurHash3_x86_128(const void* key, const int len,
|
|||
h3 = h3 * 5 + 0x96cd1c35;
|
||||
|
||||
k4 *= c4;
|
||||
k4 = ROTL32(k4, 18);
|
||||
k4 = ROTL32(k4, 18);
|
||||
k4 *= c1;
|
||||
h4 ^= k4;
|
||||
|
||||
|
@ -237,7 +361,7 @@ void MurmurHash3_x86_128(const void* key, const int len,
|
|||
case 13:
|
||||
k4 ^= tail[12] << 0;
|
||||
k4 *= c4;
|
||||
k4 = ROTL32(k4, 18);
|
||||
k4 = ROTL32(k4, 18);
|
||||
k4 *= c1;
|
||||
h4 ^= k4;
|
||||
|
||||
|
@ -250,7 +374,7 @@ void MurmurHash3_x86_128(const void* key, const int len,
|
|||
case 9:
|
||||
k3 ^= tail[ 8] << 0;
|
||||
k3 *= c3;
|
||||
k3 = ROTL32(k3, 17);
|
||||
k3 = ROTL32(k3, 17);
|
||||
k3 *= c4;
|
||||
h3 ^= k3;
|
||||
|
||||
|
@ -263,7 +387,7 @@ void MurmurHash3_x86_128(const void* key, const int len,
|
|||
case 5:
|
||||
k2 ^= tail[ 4] << 0;
|
||||
k2 *= c2;
|
||||
k2 = ROTL32(k2, 16);
|
||||
k2 = ROTL32(k2, 16);
|
||||
k2 *= c3;
|
||||
h2 ^= k2;
|
||||
|
||||
|
@ -276,7 +400,7 @@ void MurmurHash3_x86_128(const void* key, const int len,
|
|||
case 1:
|
||||
k1 ^= tail[ 0] << 0;
|
||||
k1 *= c1;
|
||||
k1 = ROTL32(k1, 15);
|
||||
k1 = ROTL32(k1, 15);
|
||||
k1 *= c2;
|
||||
h1 ^= k1;
|
||||
};
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -339,7 +474,7 @@ void MurmurHash3_x64_128(const void* key, const int len,
|
|||
uint64_t k2 = getblock64(blocks, i * 2 + 1);
|
||||
|
||||
k1 *= c1;
|
||||
k1 = ROTL64(k1, 31);
|
||||
k1 = ROTL64(k1, 31);
|
||||
k1 *= c2;
|
||||
h1 ^= k1;
|
||||
|
||||
|
@ -348,7 +483,7 @@ void MurmurHash3_x64_128(const void* key, const int len,
|
|||
h1 = h1 * 5 + 0x52dce729;
|
||||
|
||||
k2 *= c2;
|
||||
k2 = ROTL64(k2, 33);
|
||||
k2 = ROTL64(k2, 33);
|
||||
k2 *= c1;
|
||||
h2 ^= k2;
|
||||
|
||||
|
@ -382,7 +517,7 @@ void MurmurHash3_x64_128(const void* key, const int len,
|
|||
case 9:
|
||||
k2 ^= ((uint64_t)tail[ 8]) << 0;
|
||||
k2 *= c2;
|
||||
k2 = ROTL64(k2, 33);
|
||||
k2 = ROTL64(k2, 33);
|
||||
k2 *= c1;
|
||||
h2 ^= k2;
|
||||
|
||||
|
@ -403,7 +538,7 @@ void MurmurHash3_x64_128(const void* key, const int len,
|
|||
case 1:
|
||||
k1 ^= ((uint64_t)tail[ 0]) << 0;
|
||||
k1 *= c1;
|
||||
k1 = ROTL64(k1, 31);
|
||||
k1 = ROTL64(k1, 31);
|
||||
k1 *= c2;
|
||||
h1 ^= k1;
|
||||
};
|
||||
|
|
|
@ -1,202 +1,319 @@
|
|||
/**
|
||||
@file patches.cpp
|
||||
|
||||
@brief Implements the patches class.
|
||||
*/
|
||||
|
||||
#include "patches.h"
|
||||
#include "addrinfo.h"
|
||||
#include "memory.h"
|
||||
#include "debugger.h"
|
||||
#include "console.h"
|
||||
#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(fdProcessInfo->hProcess, 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 = modhashfromva(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
|
||||
// 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(modhashfromva(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(modhashfromva(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(fdProcessInfo->hProcess, (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)
|
||||
{
|
||||
// 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(fdProcessInfo->hProcess, (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(LOOPSINFO);
|
||||
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(error, "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(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(error, "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(error, "StaticFileUnload failed");
|
||||
return -1;
|
||||
}
|
||||
return patched;
|
||||
strcpy_s(Error, MAX_ERROR_SIZE, "StaticFileLoad failed");
|
||||
return -1;
|
||||
}
|
||||
strcpy(error, "StaticFileLoad failed");
|
||||
return -1;
|
||||
|
||||
// Begin iterating all patches, applying them to a file
|
||||
int patchCount = 0;
|
||||
|
||||
for(int i = 0; i < Count; i++)
|
||||
{
|
||||
// Convert the virtual address to an offset within disk file data
|
||||
unsigned char* ptr = (unsigned char*)ConvertVAtoFileOffsetEx(fileMapVa, loadedSize, moduleBase, List[i].addr, false, true);
|
||||
|
||||
// Skip patches that do not have a raw address
|
||||
if(!ptr)
|
||||
continue;
|
||||
|
||||
dprintf("patch%.4d|%s[%.8X]:%.2X/%.2X->%.2X\n", i + 1, moduleName, ptr - fileMapVa, *ptr, List[i].oldbyte, List[i].newbyte);
|
||||
*ptr = List[i].newbyte;
|
||||
patchCount++;
|
||||
}
|
||||
|
||||
// Unload the file from memory and commit changes to disk
|
||||
if(!StaticFileUnloadW(StringUtils::Utf8ToUtf16(FileName).c_str(), true, fileHandle, loadedSize, fileMap, fileMapVa))
|
||||
{
|
||||
if(Error)
|
||||
strcpy_s(Error, MAX_ERROR_SIZE, "StaticFileUnload failed");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Zero the error message and return count
|
||||
if(Error)
|
||||
memset(Error, 0, MAX_ERROR_SIZE * sizeof(char));
|
||||
|
||||
return patchCount;
|
||||
}
|
||||
|
||||
void PatchClear(const char* Module)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockPatches);
|
||||
|
||||
// Was a module specified?
|
||||
if(!Module || Module[0] == '\0')
|
||||
{
|
||||
// No specific entries to delete, so remove all of them
|
||||
patches.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise iterate over each patch and check the owner
|
||||
// module for the address
|
||||
for(auto itr = patches.begin(); itr != patches.end();)
|
||||
{
|
||||
if(!_stricmp(itr->second.mod, Module))
|
||||
itr = patches.erase(itr);
|
||||
else
|
||||
itr++;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
#ifndef _PATCHES_H
|
||||
#define _PATCHES_H
|
||||
#pragma once
|
||||
|
||||
#include "_global.h"
|
||||
|
||||
|
@ -10,14 +9,11 @@ struct PATCHINFO
|
|||
unsigned char oldbyte;
|
||||
unsigned char newbyte;
|
||||
};
|
||||
typedef std::map<uint, PATCHINFO> PatchesInfo;
|
||||
|
||||
bool patchset(uint addr, unsigned char oldbyte, unsigned char newbyte);
|
||||
bool patchget(uint addr, PATCHINFO* patch);
|
||||
bool patchdel(uint addr, bool restore);
|
||||
void patchdelrange(uint start, uint end, bool restore);
|
||||
void patchclear(const char* mod = 0);
|
||||
bool patchenum(PATCHINFO* patchlist, size_t* cbsize);
|
||||
int patchfile(const PATCHINFO* patchlist, int count, const char* szFileName, char* error);
|
||||
|
||||
#endif //_PATCHES_H
|
||||
bool PatchSet(uint Address, unsigned char OldByte, unsigned char NewByte);
|
||||
bool PatchGet(uint Address, PATCHINFO* Patch);
|
||||
bool PatchDelete(uint Address, bool Restore);
|
||||
void PatchDelRange(uint Start, uint End, bool Restore);
|
||||
bool PatchEnum(PATCHINFO* List, size_t* Size);
|
||||
int PatchFile(const PATCHINFO* List, int Count, const char* FileName, char* Error);
|
||||
void PatchClear(const char* Module = nullptr);
|
|
@ -0,0 +1,169 @@
|
|||
#include "patternfind.h"
|
||||
#include <cctype>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct PatternByte
|
||||
{
|
||||
struct PatternNibble
|
||||
{
|
||||
unsigned char data;
|
||||
bool wildcard;
|
||||
} nibble[2];
|
||||
};
|
||||
|
||||
static string formathexpattern(string patterntext)
|
||||
{
|
||||
string result;
|
||||
int len = (int)patterntext.length();
|
||||
for(int i = 0; i < len; i++)
|
||||
if(patterntext[i] == '?' || isxdigit(patterntext[i]))
|
||||
result += toupper(patterntext[i]);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int hexchtoint(char ch)
|
||||
{
|
||||
if(ch >= '0' && ch <= '9')
|
||||
return ch - '0';
|
||||
else if(ch >= 'A' && ch <= 'F')
|
||||
return ch - 'A' + 10;
|
||||
else if(ch >= 'a' && ch <= 'f')
|
||||
return ch - 'a' + 10;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool patterntransform(string patterntext, vector<PatternByte> & pattern)
|
||||
{
|
||||
pattern.clear();
|
||||
patterntext = formathexpattern(patterntext);
|
||||
int len = (int)patterntext.length();
|
||||
if(!len)
|
||||
return false;
|
||||
|
||||
if(len % 2) //not a multiple of 2
|
||||
{
|
||||
patterntext += '?';
|
||||
len++;
|
||||
}
|
||||
|
||||
PatternByte newByte;
|
||||
for(int i = 0, j = 0; i < len; i++)
|
||||
{
|
||||
if(patterntext[i] == '?') //wildcard
|
||||
{
|
||||
newByte.nibble[j].wildcard = true; //match anything
|
||||
}
|
||||
else //hex
|
||||
{
|
||||
newByte.nibble[j].wildcard = false;
|
||||
newByte.nibble[j].data = hexchtoint(patterntext[i]) & 0xF;
|
||||
}
|
||||
|
||||
j++;
|
||||
if(j == 2) //two nibbles = one byte
|
||||
{
|
||||
j = 0;
|
||||
pattern.push_back(newByte);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool patternmatchbyte(unsigned char byte, const PatternByte & pbyte)
|
||||
{
|
||||
int matched = 0;
|
||||
|
||||
unsigned char n1 = (byte >> 4) & 0xF;
|
||||
if(pbyte.nibble[0].wildcard)
|
||||
matched++;
|
||||
else if(pbyte.nibble[0].data == n1)
|
||||
matched++;
|
||||
|
||||
unsigned char n2 = byte & 0xF;
|
||||
if(pbyte.nibble[1].wildcard)
|
||||
matched++;
|
||||
else if(pbyte.nibble[1].data == n2)
|
||||
matched++;
|
||||
|
||||
return (matched == 2);
|
||||
}
|
||||
|
||||
size_t patternfind(unsigned char* data, size_t datasize, const char* pattern, int* patternsize)
|
||||
{
|
||||
vector<PatternByte> searchpattern;
|
||||
if(!patterntransform(pattern, searchpattern))
|
||||
return -1;
|
||||
size_t searchpatternsize = searchpattern.size();
|
||||
if(patternsize)
|
||||
*patternsize = (int)searchpatternsize;
|
||||
for(size_t i = 0, pos = 0; i < datasize; i++) //search for the pattern
|
||||
{
|
||||
if(patternmatchbyte(data[i], searchpattern.at(pos))) //check if our pattern matches the current byte
|
||||
{
|
||||
pos++;
|
||||
if(pos == searchpatternsize) //everything matched
|
||||
return i - searchpatternsize + 1;
|
||||
}
|
||||
else if(pos > 0) //fix by Computer_Angel
|
||||
{
|
||||
i -= pos;
|
||||
pos = 0; //reset current pattern position
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t patternfind(unsigned char* data, size_t datasize, unsigned char* pattern, size_t patternsize)
|
||||
{
|
||||
if(patternsize > datasize)
|
||||
patternsize = datasize;
|
||||
for(size_t i = 0, pos = 0; i < datasize; i++)
|
||||
{
|
||||
if(data[i] == pattern[pos])
|
||||
{
|
||||
pos++;
|
||||
if(pos == patternsize)
|
||||
return i - patternsize + 1;
|
||||
}
|
||||
else if(pos > 0)
|
||||
{
|
||||
i -= pos;
|
||||
pos = 0; //reset current pattern position
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void patternwritebyte(unsigned char* byte, const PatternByte & pbyte)
|
||||
{
|
||||
unsigned char n1 = (*byte >> 4) & 0xF;
|
||||
unsigned char n2 = *byte & 0xF;
|
||||
if(!pbyte.nibble[0].wildcard)
|
||||
n1 = pbyte.nibble[0].data;
|
||||
if(!pbyte.nibble[1].wildcard)
|
||||
n2 = pbyte.nibble[1].data;
|
||||
*byte = ((n1 << 4) & 0xF0) | (n2 & 0xF);
|
||||
}
|
||||
|
||||
void patternwrite(unsigned char* data, size_t datasize, const char* pattern)
|
||||
{
|
||||
vector<PatternByte> writepattern;
|
||||
if(!patterntransform(pattern, writepattern))
|
||||
return;
|
||||
size_t writepatternsize = writepattern.size();
|
||||
if(writepatternsize > datasize)
|
||||
writepatternsize = datasize;
|
||||
for(size_t i = 0; i < writepatternsize; i++)
|
||||
patternwritebyte(&data[i], writepattern.at(i));
|
||||
}
|
||||
|
||||
bool patternsnr(unsigned char* data, size_t datasize, const char* searchpattern, const char* replacepattern)
|
||||
{
|
||||
size_t found = patternfind(data, datasize, searchpattern);
|
||||
if(found == -1)
|
||||
return false;
|
||||
patternwrite(data + found, datasize - found, replacepattern);
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
#ifndef _PATTERNFIND_H
|
||||
#define _PATTERNFIND_H
|
||||
|
||||
//returns: offset to data when found, -1 when not found
|
||||
size_t patternfind(
|
||||
unsigned char* data, //data
|
||||
size_t datasize, //size of data
|
||||
const char* pattern, //pattern to search
|
||||
int* patternsize = 0 //outputs the number of bytes the pattern is
|
||||
);
|
||||
|
||||
//returns: offset to data when found, -1 when not found
|
||||
size_t patternfind(
|
||||
unsigned char* data, //data
|
||||
size_t datasize, //size of data
|
||||
unsigned char* pattern, //bytes to search
|
||||
size_t patternsize //size of bytes to search
|
||||
);
|
||||
|
||||
//returns: nothing
|
||||
void patternwrite(
|
||||
unsigned char* data, //data
|
||||
size_t datasize, //size of data
|
||||
const char* pattern //pattern to write
|
||||
);
|
||||
|
||||
//returns: true on success, false on failure
|
||||
bool patternsnr(
|
||||
unsigned char* data, //data
|
||||
size_t datasize, //size of data
|
||||
const char* searchpattern, //pattern to search
|
||||
const char* replacepattern //pattern to write
|
||||
);
|
||||
|
||||
#endif // _PATTERNFIND_H
|
|
@ -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
|
||||
|
@ -162,7 +190,7 @@ void pluginload(const char* pluginDir)
|
|||
int hNewMenu = GuiMenuAdd(GUI_PLUGIN_MENU, pluginData.initStruct.pluginName);
|
||||
if(hNewMenu == -1)
|
||||
{
|
||||
dprintf("[PLUGIN] GuiMenuAdd failed for plugin: %s\n", pluginData.initStruct.pluginName);
|
||||
dprintf("[PLUGIN] GuiMenuAdd(GUI_PLUGIN_MENU) failed for plugin: %s\n", pluginData.initStruct.pluginName);
|
||||
pluginData.hMenu = -1;
|
||||
}
|
||||
else
|
||||
|
@ -172,7 +200,55 @@ void pluginload(const char* pluginDir)
|
|||
newMenu.hEntryPlugin = -1;
|
||||
newMenu.pluginHandle = pluginData.initStruct.pluginHandle;
|
||||
pluginMenuList.push_back(newMenu);
|
||||
pluginData.hMenu = hNewMenu;
|
||||
pluginData.hMenu = newMenu.hEntryMenu;
|
||||
}
|
||||
//add disasm plugin menu
|
||||
hNewMenu = GuiMenuAdd(GUI_DISASM_MENU, pluginData.initStruct.pluginName);
|
||||
if(hNewMenu == -1)
|
||||
{
|
||||
dprintf("[PLUGIN] GuiMenuAdd(GUI_DISASM_MENU) failed for plugin: %s\n", pluginData.initStruct.pluginName);
|
||||
pluginData.hMenu = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
PLUG_MENU newMenu;
|
||||
newMenu.hEntryMenu = hNewMenu;
|
||||
newMenu.hEntryPlugin = -1;
|
||||
newMenu.pluginHandle = pluginData.initStruct.pluginHandle;
|
||||
pluginMenuList.push_back(newMenu);
|
||||
pluginData.hMenuDisasm = newMenu.hEntryMenu;
|
||||
}
|
||||
//add dump plugin menu
|
||||
hNewMenu = GuiMenuAdd(GUI_DUMP_MENU, pluginData.initStruct.pluginName);
|
||||
if(hNewMenu == -1)
|
||||
{
|
||||
dprintf("[PLUGIN] GuiMenuAdd(GUI_DUMP_MENU) failed for plugin: %s\n", pluginData.initStruct.pluginName);
|
||||
pluginData.hMenu = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
PLUG_MENU newMenu;
|
||||
newMenu.hEntryMenu = hNewMenu;
|
||||
newMenu.hEntryPlugin = -1;
|
||||
newMenu.pluginHandle = pluginData.initStruct.pluginHandle;
|
||||
pluginMenuList.push_back(newMenu);
|
||||
pluginData.hMenuDump = newMenu.hEntryMenu;
|
||||
}
|
||||
//add stack plugin menu
|
||||
hNewMenu = GuiMenuAdd(GUI_STACK_MENU, pluginData.initStruct.pluginName);
|
||||
if(hNewMenu == -1)
|
||||
{
|
||||
dprintf("[PLUGIN] GuiMenuAdd(GUI_STACK_MENU) failed for plugin: %s\n", pluginData.initStruct.pluginName);
|
||||
pluginData.hMenu = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
PLUG_MENU newMenu;
|
||||
newMenu.hEntryMenu = hNewMenu;
|
||||
newMenu.hEntryPlugin = -1;
|
||||
newMenu.pluginHandle = pluginData.initStruct.pluginHandle;
|
||||
pluginMenuList.push_back(newMenu);
|
||||
pluginData.hMenuStack = newMenu.hEntryMenu;
|
||||
}
|
||||
pluginList.push_back(pluginData);
|
||||
//setup plugin
|
||||
|
@ -180,7 +256,10 @@ void pluginload(const char* pluginDir)
|
|||
{
|
||||
PLUG_SETUPSTRUCT setupStruct;
|
||||
setupStruct.hwndDlg = GuiGetWindowHandle();
|
||||
setupStruct.hMenu = hNewMenu;
|
||||
setupStruct.hMenu = pluginData.hMenu;
|
||||
setupStruct.hMenuDisasm = pluginData.hMenuDisasm;
|
||||
setupStruct.hMenuDump = pluginData.hMenuDump;
|
||||
setupStruct.hMenuStack = pluginData.hMenuStack;
|
||||
pluginData.plugsetup(&setupStruct);
|
||||
}
|
||||
curPluginHandle++;
|
||||
|
@ -189,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();
|
||||
|
@ -202,6 +285,9 @@ static void plugincmdunregisterall(int pluginHandle)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Unloads all plugins.
|
||||
*/
|
||||
void pluginunload()
|
||||
{
|
||||
int pluginCount = (int)pluginList.size();
|
||||
|
@ -219,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
|
||||
|
@ -230,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();
|
||||
|
@ -244,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();
|
||||
|
@ -252,19 +353,27 @@ void plugincbcall(CBTYPE cbType, void* callbackInfo)
|
|||
if(pluginCallbackList.at(i).cbType == cbType)
|
||||
{
|
||||
CBPLUGIN cbPlugin = pluginCallbackList.at(i).cbPlugin;
|
||||
if(memisvalidreadptr(GetCurrentProcess(), (uint)cbPlugin))
|
||||
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"))
|
||||
return false;
|
||||
PLUG_COMMAND plugCmd;
|
||||
plugCmd.pluginHandle = pluginHandle;
|
||||
strcpy(plugCmd.command, command);
|
||||
strcpy_s(plugCmd.command, command);
|
||||
if(!dbgcmdnew(command, (CBCOMMAND)cbCommand, debugonly))
|
||||
return false;
|
||||
pluginCommandList.push_back(plugCmd);
|
||||
|
@ -272,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"))
|
||||
|
@ -291,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))
|
||||
|
@ -315,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)
|
||||
|
@ -346,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;
|
||||
|
@ -363,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;
|
||||
|
@ -380,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)
|
||||
|
@ -405,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;
|
||||
|
@ -415,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;
|
||||
|
|
|
@ -24,6 +24,9 @@ struct PLUG_DATA
|
|||
PLUGSTOP plugstop;
|
||||
PLUGSETUP plugsetup;
|
||||
int hMenu;
|
||||
int hMenuDisasm;
|
||||
int hMenuDump;
|
||||
int hMenuStack;
|
||||
PLUG_INITSTRUCT initStruct;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,85 +1,118 @@
|
|||
/**
|
||||
@file reference.cpp
|
||||
|
||||
@brief Implements the reference class.
|
||||
*/
|
||||
|
||||
#include "reference.h"
|
||||
#include "debugger.h"
|
||||
#include "memory.h"
|
||||
#include "console.h"
|
||||
#include "module.h"
|
||||
|
||||
int reffind(uint addr, uint size, CBREF cbRef, void* userinfo, bool silent, const char* name)
|
||||
int RefFind(uint Address, uint Size, CBREF Callback, void* UserData, bool Silent, const char* Name)
|
||||
{
|
||||
uint start_addr;
|
||||
uint start_size;
|
||||
uint base;
|
||||
uint base_size;
|
||||
base = memfindbaseaddr(addr, &base_size, true);
|
||||
if(!base or !base_size)
|
||||
uint regionSize = 0;
|
||||
uint regionBase = MemFindBaseAddr(Address, ®ionSize, true);
|
||||
|
||||
// If the memory page wasn't found, fail
|
||||
if(!regionBase || !regionSize)
|
||||
{
|
||||
if(!silent)
|
||||
dputs("invalid memory page");
|
||||
if(!Silent)
|
||||
dprintf("Invalid memory page 0x%p", Address);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!size) //assume the whole page
|
||||
// Assume the entire range is used
|
||||
uint scanStart = regionBase;
|
||||
uint scanSize = regionSize;
|
||||
|
||||
// Otherwise use custom boundaries if size was supplied
|
||||
if(Size)
|
||||
{
|
||||
start_addr = base;
|
||||
start_size = base_size;
|
||||
uint maxsize = Size - (Address - regionBase);
|
||||
|
||||
// Make sure the size fits in one page
|
||||
scanStart = Address;
|
||||
scanSize = min(Size, maxsize);
|
||||
}
|
||||
else //custom boundaries
|
||||
|
||||
// Allocate and read a buffer from the remote process
|
||||
Memory<unsigned char*> data(scanSize, "reffind:data");
|
||||
|
||||
if(!MemRead((PVOID)scanStart, data, scanSize, nullptr))
|
||||
{
|
||||
start_addr = addr;
|
||||
uint maxsize = size - (start_addr - base);
|
||||
if(size < maxsize) //check if the size fits in the page
|
||||
start_size = size;
|
||||
else
|
||||
start_size = maxsize;
|
||||
}
|
||||
Memory<unsigned char*> data(start_size, "reffind:data");
|
||||
if(!memread(fdProcessInfo->hProcess, (const 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.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;
|
||||
}
|
||||
|
||||
GuiReferenceSetProgress(100);
|
||||
GuiReferenceReloadData();
|
||||
return refinfo.refcount;
|
||||
return refInfo.refcount;
|
||||
}
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
#ifndef _REFERENCE_H
|
||||
#define _REFERENCE_H
|
||||
#pragma once
|
||||
|
||||
#include "_global.h"
|
||||
#include "disasm_fast.h"
|
||||
|
||||
//structs
|
||||
struct REFINFO
|
||||
{
|
||||
int refcount;
|
||||
|
@ -12,10 +10,7 @@ struct REFINFO
|
|||
const char* name;
|
||||
};
|
||||
|
||||
//typedefs
|
||||
// Reference callback typedef
|
||||
typedef bool (*CBREF)(DISASM* disasm, BASIC_INSTRUCTION_INFO* basicinfo, REFINFO* refinfo);
|
||||
|
||||
//functions
|
||||
int reffind(uint page, uint size, CBREF cbRef, void* userinfo, bool silent, const char* name);
|
||||
|
||||
#endif //_REFERENCE_H
|
||||
int RefFind(uint Address, uint Size, CBREF Callback, void* UserData, bool Silent, const char* Name);
|
|
@ -1,24 +1,34 @@
|
|||
/**
|
||||
@file simplescript.cpp
|
||||
|
||||
@brief Implements the simplescript class.
|
||||
*/
|
||||
|
||||
#include "simplescript.h"
|
||||
#include "value.h"
|
||||
#include "console.h"
|
||||
#include "argument.h"
|
||||
#include "variable.h"
|
||||
#include "threading.h"
|
||||
#include "x64_dbg.h"
|
||||
#include "debugger.h"
|
||||
#include "commandparser.h"
|
||||
|
||||
static std::vector<LINEMAPENTRY> linemap;
|
||||
|
||||
static std::vector<SCRIPTBP> scriptbplist;
|
||||
|
||||
static std::vector<int> scriptstack;
|
||||
|
||||
static int scriptIp = 0;
|
||||
|
||||
static bool volatile bAbort = false;
|
||||
|
||||
static bool volatile bIsRunning = false;
|
||||
|
||||
static SCRIPTBRANCHTYPE scriptgetbranchtype(const char* text)
|
||||
{
|
||||
char newtext[MAX_SCRIPT_LINE_SIZE] = "";
|
||||
strcpy_s(newtext, text);
|
||||
argformat(newtext); //format jump commands
|
||||
strcpy_s(newtext, StringUtils::Trim(text).c_str());
|
||||
if(!strstr(newtext, " "))
|
||||
strcat(newtext, " ");
|
||||
if(!strncmp(newtext, "jmp ", 4) or !strncmp(newtext, "goto ", 5))
|
||||
|
@ -62,7 +72,7 @@ static int scriptinternalstep(int fromIp) //internal step routine
|
|||
|
||||
static bool scriptcreatelinemap(const char* filename)
|
||||
{
|
||||
HANDLE hFile = CreateFileW(StringUtils::Utf8ToUtf16(filename).c_str(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
|
||||
Handle hFile = CreateFileW(StringUtils::Utf8ToUtf16(filename).c_str(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
|
||||
if(hFile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
GuiScriptError(0, "CreateFile failed...");
|
||||
|
@ -71,7 +81,6 @@ static bool scriptcreatelinemap(const char* filename)
|
|||
unsigned int filesize = GetFileSize(hFile, 0);
|
||||
if(!filesize)
|
||||
{
|
||||
CloseHandle(hFile);
|
||||
GuiScriptError(0, "Empty script...");
|
||||
return false;
|
||||
}
|
||||
|
@ -80,11 +89,10 @@ static bool scriptcreatelinemap(const char* filename)
|
|||
DWORD read = 0;
|
||||
if(!ReadFile(hFile, filedata, filesize, &read, 0))
|
||||
{
|
||||
CloseHandle(hFile);
|
||||
GuiScriptError(0, "ReadFile failed...");
|
||||
return false;
|
||||
}
|
||||
CloseHandle(hFile);
|
||||
hFile.Close();
|
||||
int len = (int)strlen(filedata);
|
||||
char temp[256] = "";
|
||||
LINEMAPENTRY entry;
|
||||
|
@ -98,7 +106,7 @@ static bool scriptcreatelinemap(const char* filename)
|
|||
int add = 0;
|
||||
while(temp[add] == ' ')
|
||||
add++;
|
||||
strcpy(entry.raw, temp + add);
|
||||
strcpy_s(entry.raw, temp + add);
|
||||
*temp = 0;
|
||||
j = 0;
|
||||
i++;
|
||||
|
@ -110,7 +118,7 @@ static bool scriptcreatelinemap(const char* filename)
|
|||
int add = 0;
|
||||
while(temp[add] == ' ')
|
||||
add++;
|
||||
strcpy(entry.raw, temp + add);
|
||||
strcpy_s(entry.raw, temp + add);
|
||||
*temp = 0;
|
||||
j = 0;
|
||||
linemap.push_back(entry);
|
||||
|
@ -121,7 +129,7 @@ static bool scriptcreatelinemap(const char* filename)
|
|||
int add = 0;
|
||||
while(temp[add] == ' ')
|
||||
add++;
|
||||
strcpy(entry.raw, temp + add);
|
||||
strcpy_s(entry.raw, temp + add);
|
||||
*temp = 0;
|
||||
j = 0;
|
||||
linemap.push_back(entry);
|
||||
|
@ -132,7 +140,7 @@ static bool scriptcreatelinemap(const char* filename)
|
|||
if(*temp)
|
||||
{
|
||||
memset(&entry, 0, sizeof(entry));
|
||||
strcpy(entry.raw, temp);
|
||||
strcpy_s(entry.raw, temp);
|
||||
linemap.push_back(entry);
|
||||
}
|
||||
unsigned int linemapsize = (unsigned int)linemap.size();
|
||||
|
@ -152,7 +160,7 @@ static bool scriptcreatelinemap(const char* filename)
|
|||
{
|
||||
if(*(comment - 1) == ' ') //space before comment
|
||||
{
|
||||
strcpy(line_comment, comment);
|
||||
strcpy_s(line_comment, comment);
|
||||
*(comment - 1) = '\0';
|
||||
}
|
||||
else //no space before comment
|
||||
|
@ -170,13 +178,13 @@ static bool scriptcreatelinemap(const char* filename)
|
|||
else if(!strncmp(cur.raw, "//", 2)) //comment
|
||||
{
|
||||
cur.type = linecomment;
|
||||
strcpy(cur.u.comment, cur.raw);
|
||||
strcpy_s(cur.u.comment, cur.raw);
|
||||
}
|
||||
else if(cur.raw[rawlen - 1] == ':') //label
|
||||
{
|
||||
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,20 +211,19 @@ static bool scriptcreatelinemap(const char* filename)
|
|||
cur.type = linebranch;
|
||||
cur.u.branch.type = scriptgetbranchtype(cur.raw);
|
||||
char newraw[MAX_SCRIPT_LINE_SIZE] = "";
|
||||
strcpy(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] == ' ')
|
||||
{
|
||||
strcpy(cur.u.branch.branchlabel, newraw + i + 1);
|
||||
strcpy_s(cur.u.branch.branchlabel, newraw + i + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cur.type = linecommand;
|
||||
strcpy(cur.u.command, cur.raw);
|
||||
strcpy_s(cur.u.command, cur.raw);
|
||||
}
|
||||
|
||||
//append the comment to the raw line again
|
||||
|
@ -246,8 +253,8 @@ static bool scriptcreatelinemap(const char* filename)
|
|||
{
|
||||
memset(&entry, 0, sizeof(entry));
|
||||
entry.type = linecommand;
|
||||
strcpy(entry.raw, "ret");
|
||||
strcpy(entry.u.command, "ret");
|
||||
strcpy_s(entry.raw, "ret");
|
||||
strcpy_s(entry.u.command, "ret");
|
||||
linemap.push_back(entry);
|
||||
}
|
||||
return true;
|
||||
|
@ -343,8 +350,7 @@ static CMDRESULT scriptinternalcmdexec(const char* cmd)
|
|||
else if(scriptisinternalcommand(cmd, "nop")) //do nothing
|
||||
return STATUS_CONTINUE;
|
||||
char command[deflen] = "";
|
||||
strcpy_s(command, cmd);
|
||||
argformat(command);
|
||||
strcpy_s(command, StringUtils::Trim(cmd).c_str());
|
||||
COMMAND* found = cmdfindmain(dbggetcommandlist(), command);
|
||||
if(!found) //invalid command
|
||||
return STATUS_ERROR;
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
/**
|
||||
@file stackinfo.cpp
|
||||
|
||||
@brief Implements the stackinfo class.
|
||||
*/
|
||||
|
||||
#include "stackinfo.h"
|
||||
#include "debugger.h"
|
||||
#include "memory.h"
|
||||
|
@ -6,22 +12,23 @@
|
|||
#include "BeaEngine\BeaEngine.h"
|
||||
#include "addrinfo.h"
|
||||
#include "_exports.h"
|
||||
#include "module.h"
|
||||
|
||||
bool stackcommentget(uint addr, STACK_COMMENT* comment)
|
||||
{
|
||||
uint data = 0;
|
||||
memset(comment, 0, sizeof(STACK_COMMENT));
|
||||
memread(fdProcessInfo->hProcess, (const void*)addr, &data, sizeof(uint), 0);
|
||||
if(!memisvalidreadptr(fdProcessInfo->hProcess, data)) //the stack value is no pointer
|
||||
MemRead((void*)addr, &data, sizeof(uint), 0);
|
||||
if(!MemIsValidReadPtr(data)) //the stack value is no pointer
|
||||
return false;
|
||||
|
||||
uint size = 0;
|
||||
uint base = memfindbaseaddr(data, &size);
|
||||
uint base = MemFindBaseAddr(data, &size);
|
||||
uint readStart = data - 16 * 4;
|
||||
if(readStart < base)
|
||||
readStart = base;
|
||||
unsigned char disasmData[256];
|
||||
memread(fdProcessInfo->hProcess, (const void*)readStart, disasmData, sizeof(disasmData), 0);
|
||||
MemRead((void*)readStart, disasmData, sizeof(disasmData), 0);
|
||||
uint prev = disasmback(disasmData, 0, sizeof(disasmData), data - readStart, 1);
|
||||
uint previousInstr = readStart + prev;
|
||||
|
||||
|
@ -41,9 +48,9 @@ bool stackcommentget(uint addr, STACK_COMMENT* comment)
|
|||
ADDRINFO addrinfo;
|
||||
addrinfo.flags = flaglabel;
|
||||
if(_dbg_addrinfoget(data, SEG_DEFAULT, &addrinfo))
|
||||
strcpy(label, addrinfo.label);
|
||||
strcpy_s(label, addrinfo.label);
|
||||
char module[MAX_MODULE_SIZE] = "";
|
||||
modnamefromaddr(data, module, false);
|
||||
ModNameFromAddr(data, module, false);
|
||||
char returnToAddr[MAX_COMMENT_SIZE] = "";
|
||||
if(*module)
|
||||
sprintf(returnToAddr, "%s.", module);
|
||||
|
@ -57,9 +64,9 @@ bool stackcommentget(uint addr, STACK_COMMENT* comment)
|
|||
*label = 0;
|
||||
addrinfo.flags = flaglabel;
|
||||
if(_dbg_addrinfoget(data, SEG_DEFAULT, &addrinfo))
|
||||
strcpy(label, addrinfo.label);
|
||||
strcpy_s(label, addrinfo.label);
|
||||
*module = 0;
|
||||
modnamefromaddr(data, module, false);
|
||||
ModNameFromAddr(data, module, false);
|
||||
char returnFromAddr[MAX_COMMENT_SIZE] = "";
|
||||
if(*module)
|
||||
sprintf(returnFromAddr, "%s.", module);
|
||||
|
@ -70,7 +77,7 @@ bool stackcommentget(uint addr, STACK_COMMENT* comment)
|
|||
}
|
||||
else
|
||||
sprintf_s(comment->comment, "return to %s from ???", returnToAddr);
|
||||
strcpy(comment->color, "#ff0000");
|
||||
strcpy_s(comment->color, "#ff0000");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -91,9 +98,9 @@ bool stackcommentget(uint addr, STACK_COMMENT* comment)
|
|||
ADDRINFO addrinfo;
|
||||
addrinfo.flags = flaglabel;
|
||||
if(_dbg_addrinfoget(data, SEG_DEFAULT, &addrinfo))
|
||||
strcpy(label, addrinfo.label);
|
||||
strcpy_s(label, addrinfo.label);
|
||||
char module[MAX_MODULE_SIZE] = "";
|
||||
modnamefromaddr(data, module, false);
|
||||
ModNameFromAddr(data, module, false);
|
||||
char addrInfo[MAX_COMMENT_SIZE] = "";
|
||||
if(*module) //module
|
||||
{
|
||||
|
@ -117,12 +124,12 @@ void stackgetcallstack(uint csp, CALLSTACK* callstack)
|
|||
callstack->total = 0;
|
||||
if(!DbgIsDebugging() or csp % sizeof(uint)) //alignment problem
|
||||
return;
|
||||
if(!memisvalidreadptr(fdProcessInfo->hProcess, csp))
|
||||
if(!MemIsValidReadPtr(csp))
|
||||
return;
|
||||
std::vector<CALLSTACKENTRY> callstackVector;
|
||||
DWORD ticks = GetTickCount();
|
||||
uint stacksize = 0;
|
||||
uint stackbase = memfindbaseaddr(csp, &stacksize, false);
|
||||
uint stackbase = MemFindBaseAddr(csp, &stacksize, false);
|
||||
if(!stackbase) //super-fail (invalid stack address)
|
||||
return;
|
||||
//walk up the stack
|
||||
|
@ -130,16 +137,16 @@ void stackgetcallstack(uint csp, CALLSTACK* callstack)
|
|||
while(i != stackbase + stacksize)
|
||||
{
|
||||
uint data = 0;
|
||||
memread(fdProcessInfo->hProcess, (const void*)i, &data, sizeof(uint), 0);
|
||||
if(memisvalidreadptr(fdProcessInfo->hProcess, data)) //the stack value is a pointer
|
||||
MemRead((void*)i, &data, sizeof(uint), 0);
|
||||
if(MemIsValidReadPtr(data)) //the stack value is a pointer
|
||||
{
|
||||
uint size = 0;
|
||||
uint base = memfindbaseaddr(data, &size);
|
||||
uint base = MemFindBaseAddr(data, &size);
|
||||
uint readStart = data - 16 * 4;
|
||||
if(readStart < base)
|
||||
readStart = base;
|
||||
unsigned char disasmData[256];
|
||||
memread(fdProcessInfo->hProcess, (const void*)readStart, disasmData, sizeof(disasmData), 0);
|
||||
MemRead((void*)readStart, disasmData, sizeof(disasmData), 0);
|
||||
uint prev = disasmback(disasmData, 0, sizeof(disasmData), data - readStart, 1);
|
||||
uint previousInstr = readStart + prev;
|
||||
BASIC_INSTRUCTION_INFO basicinfo;
|
||||
|
@ -150,9 +157,9 @@ void stackgetcallstack(uint csp, CALLSTACK* callstack)
|
|||
ADDRINFO addrinfo;
|
||||
addrinfo.flags = flaglabel;
|
||||
if(_dbg_addrinfoget(data, SEG_DEFAULT, &addrinfo))
|
||||
strcpy(label, addrinfo.label);
|
||||
strcpy_s(label, addrinfo.label);
|
||||
char module[MAX_MODULE_SIZE] = "";
|
||||
modnamefromaddr(data, module, false);
|
||||
ModNameFromAddr(data, module, false);
|
||||
char returnToAddr[MAX_COMMENT_SIZE] = "";
|
||||
if(*module)
|
||||
sprintf(returnToAddr, "%s.", module);
|
||||
|
@ -173,9 +180,9 @@ void stackgetcallstack(uint csp, CALLSTACK* callstack)
|
|||
*label = 0;
|
||||
addrinfo.flags = flaglabel;
|
||||
if(_dbg_addrinfoget(data, SEG_DEFAULT, &addrinfo))
|
||||
strcpy(label, addrinfo.label);
|
||||
strcpy_s(label, addrinfo.label);
|
||||
*module = 0;
|
||||
modnamefromaddr(data, module, false);
|
||||
ModNameFromAddr(data, module, false);
|
||||
char returnFromAddr[MAX_COMMENT_SIZE] = "";
|
||||
if(*module)
|
||||
sprintf(returnFromAddr, "%s.", module);
|
||||
|
|
|
@ -0,0 +1,142 @@
|
|||
#include "stringformat.h"
|
||||
#include "console.h"
|
||||
#include "value.h"
|
||||
#include "disasm_helper.h"
|
||||
|
||||
namespace ValueType
|
||||
{
|
||||
enum ValueType
|
||||
{
|
||||
Unknown,
|
||||
SignedDecimal,
|
||||
UnsignedDecimal,
|
||||
Hex,
|
||||
Pointer,
|
||||
String
|
||||
};
|
||||
}
|
||||
|
||||
static String printValue(FormatValueType value, ValueType::ValueType type)
|
||||
{
|
||||
uint valuint = 0;
|
||||
bool validval = valfromstring(value, &valuint);
|
||||
char result[deflen] = "???";
|
||||
switch(type)
|
||||
{
|
||||
case ValueType::Unknown:
|
||||
break;
|
||||
case ValueType::SignedDecimal:
|
||||
if(validval)
|
||||
sprintf_s(result, "%"fext"d", valuint);
|
||||
break;
|
||||
case ValueType::UnsignedDecimal:
|
||||
if(validval)
|
||||
sprintf_s(result, "%"fext"u", valuint);
|
||||
break;
|
||||
case ValueType::Hex:
|
||||
if(validval)
|
||||
sprintf_s(result, "%"fext"X", valuint);
|
||||
break;
|
||||
case ValueType::Pointer:
|
||||
if(validval)
|
||||
sprintf_s(result, "0x%"fhex, valuint);
|
||||
break;
|
||||
case ValueType::String:
|
||||
if(validval)
|
||||
{
|
||||
STRING_TYPE strtype;
|
||||
char string[512] = "";
|
||||
if(disasmgetstringat(valuint, &strtype, string, string, 500))
|
||||
strcpy_s(result, string);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static unsigned int getArgNumType(const String & formatString, ValueType::ValueType & type)
|
||||
{
|
||||
int add = 0;
|
||||
switch(formatString[0])
|
||||
{
|
||||
case 'd':
|
||||
type = ValueType::SignedDecimal;
|
||||
add++;
|
||||
break;
|
||||
case 'u':
|
||||
type = ValueType::UnsignedDecimal;
|
||||
add++;
|
||||
break;
|
||||
case 'p':
|
||||
type = ValueType::Pointer;
|
||||
add++;
|
||||
break;
|
||||
case 's':
|
||||
type = ValueType::String;
|
||||
add++;
|
||||
break;
|
||||
default:
|
||||
type = ValueType::Hex;
|
||||
}
|
||||
unsigned int argnum = 0;
|
||||
if(sscanf(formatString.c_str() + add, "%u", &argnum) != 1)
|
||||
type = ValueType::Unknown;
|
||||
return argnum;
|
||||
}
|
||||
|
||||
static String handleFormatString(const String & formatString, const FormatValueVector & values)
|
||||
{
|
||||
String result;
|
||||
ValueType::ValueType type = ValueType::Unknown;
|
||||
unsigned int argnum = getArgNumType(formatString, type);
|
||||
if(argnum < values.size())
|
||||
return printValue(values.at(argnum), type);
|
||||
return "[Formatting Error]";
|
||||
}
|
||||
|
||||
String stringformat(String format, const FormatValueVector & values)
|
||||
{
|
||||
StringUtils::ReplaceAll(format, "\\n", "\n");
|
||||
int len = (int)format.length();
|
||||
String output;
|
||||
String formatString;
|
||||
bool inFormatter = false;
|
||||
for(int i = 0; i < len; i++)
|
||||
{
|
||||
//handle escaped format sequences "{{" and "}}"
|
||||
if(format[i] == '{' && (i + 1 < len && format[i + 1] == '{'))
|
||||
{
|
||||
output += "{";
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
else if(format[i] == '}' && (i + 1 < len && format[i + 1] == '}'))
|
||||
{
|
||||
output += "}";
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
//handle actual formatting
|
||||
if(format[i] == '{' && !inFormatter) //opening bracket
|
||||
{
|
||||
inFormatter = true;
|
||||
formatString.clear();
|
||||
}
|
||||
else if(format[i] == '}' && inFormatter) //closing bracket
|
||||
{
|
||||
inFormatter = false;
|
||||
if(formatString.length())
|
||||
{
|
||||
output += handleFormatString(formatString, values);
|
||||
formatString.clear();
|
||||
}
|
||||
}
|
||||
else if(inFormatter) //inside brackets
|
||||
formatString += format[i];
|
||||
else //outside brackets
|
||||
output += format[i];
|
||||
}
|
||||
if(inFormatter && formatString.size())
|
||||
output += handleFormatString(formatString, values);
|
||||
return output;
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
#ifndef _STRINGFORMAT_H
|
||||
#define _STRINGFORMAT_H
|
||||
|
||||
#include "_global.h"
|
||||
|
||||
typedef const char* FormatValueType;
|
||||
typedef std::vector<FormatValueType> FormatValueVector;
|
||||
|
||||
String stringformat(String format, const FormatValueVector & values);
|
||||
|
||||
#endif //_STRINGFORMAT_H
|
|
@ -122,4 +122,25 @@ WString StringUtils::Utf8ToUtf16(const String & str)
|
|||
WString StringUtils::Utf8ToUtf16(const char* str)
|
||||
{
|
||||
return Utf8ToUtf16(str ? String(str) : String());
|
||||
}
|
||||
|
||||
//Taken from: http://stackoverflow.com/a/24315631
|
||||
void StringUtils::ReplaceAll(String & s, const String & from, const String & to)
|
||||
{
|
||||
size_t start_pos = 0;
|
||||
while((start_pos = s.find(from, start_pos)) != std::string::npos)
|
||||
{
|
||||
s.replace(start_pos, from.length(), to);
|
||||
start_pos += to.length(); // Handles case where 'to' is a substring of 'from'
|
||||
}
|
||||
}
|
||||
|
||||
void StringUtils::ReplaceAll(WString & s, const WString & from, const WString & to)
|
||||
{
|
||||
size_t start_pos = 0;
|
||||
while((start_pos = s.find(from, start_pos)) != std::string::npos)
|
||||
{
|
||||
s.replace(start_pos, from.length(), to);
|
||||
start_pos += to.length(); // Handles case where 'to' is a substring of 'from'
|
||||
}
|
||||
}
|
|
@ -22,6 +22,8 @@ public:
|
|||
static String Utf16ToUtf8(const wchar_t* wstr);
|
||||
static WString Utf8ToUtf16(const String & str);
|
||||
static WString Utf8ToUtf16(const char* str);
|
||||
static void ReplaceAll(String & s, const String & from, const String & to);
|
||||
static void ReplaceAll(WString & s, const WString & from, const WString & to);
|
||||
|
||||
private:
|
||||
static const String WHITESPACE;
|
||||
|
|
|
@ -1,7 +1,15 @@
|
|||
/**
|
||||
@file symbolinfo.cpp
|
||||
|
||||
@brief Implements the symbolinfo class.
|
||||
*/
|
||||
|
||||
#include "symbolinfo.h"
|
||||
#include "debugger.h"
|
||||
#include "addrinfo.h"
|
||||
#include "console.h"
|
||||
#include "module.h"
|
||||
#include "label.h"
|
||||
|
||||
struct SYMBOLCBDATA
|
||||
{
|
||||
|
@ -9,166 +17,287 @@ struct SYMBOLCBDATA
|
|||
void* user;
|
||||
};
|
||||
|
||||
static BOOL CALLBACK EnumSymbols(PSYMBOL_INFO pSymInfo, ULONG SymbolSize, PVOID UserContext)
|
||||
static BOOL CALLBACK EnumSymbols(PSYMBOL_INFO SymInfo, ULONG SymbolSize, PVOID UserContext)
|
||||
{
|
||||
int len = (int)strlen(pSymInfo->Name);
|
||||
SYMBOLINFO curSymbol;
|
||||
memset(&curSymbol, 0, sizeof(SYMBOLINFO));
|
||||
curSymbol.addr = (duint)pSymInfo->Address;
|
||||
curSymbol.decoratedSymbol = (char*)BridgeAlloc(len + 1);
|
||||
strcpy(curSymbol.decoratedSymbol, pSymInfo->Name);
|
||||
|
||||
curSymbol.addr = (duint)SymInfo->Address;
|
||||
curSymbol.decoratedSymbol = (char*)BridgeAlloc(strlen(SymInfo->Name) + 1);
|
||||
curSymbol.undecoratedSymbol = (char*)BridgeAlloc(MAX_SYM_NAME);
|
||||
if(strstr(pSymInfo->Name, "Ordinal"))
|
||||
strcpy_s(curSymbol.decoratedSymbol, strlen(SymInfo->Name) + 1, SymInfo->Name);
|
||||
|
||||
// Skip bad ordinals
|
||||
if(strstr(SymInfo->Name, "Ordinal"))
|
||||
{
|
||||
//skip bad ordinals
|
||||
if(pSymInfo->Address == pSymInfo->ModBase)
|
||||
// Does the symbol point to the module base?
|
||||
if(SymInfo->Address == SymInfo->ModBase)
|
||||
return TRUE;
|
||||
}
|
||||
if(!UnDecorateSymbolName(pSymInfo->Name, curSymbol.undecoratedSymbol, MAX_SYM_NAME, UNDNAME_COMPLETE))
|
||||
|
||||
// Convert a mangled/decorated C++ name to a readable format
|
||||
if(!SafeUnDecorateSymbolName(SymInfo->Name, curSymbol.undecoratedSymbol, MAX_SYM_NAME, UNDNAME_COMPLETE))
|
||||
{
|
||||
BridgeFree(curSymbol.undecoratedSymbol);
|
||||
curSymbol.undecoratedSymbol = 0;
|
||||
curSymbol.undecoratedSymbol = nullptr;
|
||||
}
|
||||
else if(!strcmp(curSymbol.decoratedSymbol, curSymbol.undecoratedSymbol))
|
||||
{
|
||||
BridgeFree(curSymbol.undecoratedSymbol);
|
||||
curSymbol.undecoratedSymbol = 0;
|
||||
curSymbol.undecoratedSymbol = nullptr;
|
||||
}
|
||||
|
||||
SYMBOLCBDATA* cbData = (SYMBOLCBDATA*)UserContext;
|
||||
cbData->cbSymbolEnum(&curSymbol, cbData->user);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void symenum(uint base, CBSYMBOLENUM cbSymbolEnum, void* user)
|
||||
void SymEnum(uint Base, CBSYMBOLENUM EnumCallback, void* UserData)
|
||||
{
|
||||
SYMBOLCBDATA symbolCbData;
|
||||
symbolCbData.cbSymbolEnum = cbSymbolEnum;
|
||||
symbolCbData.user = user;
|
||||
char mask[] = "*";
|
||||
SymEnumSymbols(fdProcessInfo->hProcess, base, mask, EnumSymbols, &symbolCbData);
|
||||
symbolCbData.cbSymbolEnum = EnumCallback;
|
||||
symbolCbData.user = UserData;
|
||||
|
||||
// Enumerate every single symbol for the module in 'base'
|
||||
if(!SafeSymEnumSymbols(fdProcessInfo->hProcess, Base, "*", EnumSymbols, &symbolCbData))
|
||||
dputs("SymEnumSymbols failed!");
|
||||
}
|
||||
|
||||
#ifdef _WIN64
|
||||
static BOOL CALLBACK EnumModules(LPCTSTR ModuleName, DWORD64 BaseOfDll, PVOID UserContext)
|
||||
#else
|
||||
static BOOL CALLBACK EnumModules(LPCTSTR ModuleName, ULONG BaseOfDll, PVOID UserContext)
|
||||
#endif //_WIN64
|
||||
bool SymGetModuleList(std::vector<SYMBOLMODULEINFO>* List)
|
||||
{
|
||||
SYMBOLMODULEINFO curModule;
|
||||
memset(&curModule, 0, sizeof(SYMBOLMODULEINFO));
|
||||
curModule.base = BaseOfDll;
|
||||
modnamefromaddr(BaseOfDll, curModule.name, true);
|
||||
((std::vector<SYMBOLMODULEINFO>*)UserContext)->push_back(curModule);
|
||||
return TRUE;
|
||||
//
|
||||
// Inline lambda enum
|
||||
//
|
||||
auto EnumModules = [](LPCTSTR ModuleName, DWORD64 BaseOfDll, PVOID UserContext) -> BOOL
|
||||
{
|
||||
SYMBOLMODULEINFO curModule;
|
||||
curModule.base = (duint)BaseOfDll;
|
||||
|
||||
// Terminate module name if one isn't found
|
||||
if(!ModNameFromAddr(curModule.base, curModule.name, true))
|
||||
curModule.name[0] = '\0';
|
||||
|
||||
((std::vector<SYMBOLMODULEINFO>*)UserContext)->push_back(curModule);
|
||||
return TRUE;
|
||||
};
|
||||
|
||||
// Execute the symbol enumerator (Force cast to STDCALL)
|
||||
if(!SafeSymEnumerateModules64(fdProcessInfo->hProcess, EnumModules, List))
|
||||
{
|
||||
dputs("SymEnumerateModules64 failed!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void symupdatemodulelist()
|
||||
void SymUpdateModuleList()
|
||||
{
|
||||
// Build the vector of modules
|
||||
std::vector<SYMBOLMODULEINFO> modList;
|
||||
modList.clear();
|
||||
SymEnumerateModules(fdProcessInfo->hProcess, EnumModules, &modList);
|
||||
int modcount = (int)modList.size();
|
||||
SYMBOLMODULEINFO* modListBridge = (SYMBOLMODULEINFO*)BridgeAlloc(sizeof(SYMBOLMODULEINFO) * modcount);
|
||||
for(int i = 0; i < modcount; i++)
|
||||
memcpy(&modListBridge[i], &modList.at(i), sizeof(SYMBOLMODULEINFO));
|
||||
GuiSymbolUpdateModuleList(modcount, modListBridge);
|
||||
}
|
||||
|
||||
void symdownloadallsymbols(const char* szSymbolStore)
|
||||
{
|
||||
if(!szSymbolStore)
|
||||
szSymbolStore = "http://msdl.microsoft.com/download/symbols";
|
||||
std::vector<SYMBOLMODULEINFO> modList;
|
||||
modList.clear();
|
||||
SymEnumerateModules(fdProcessInfo->hProcess, EnumModules, &modList);
|
||||
int modcount = (int)modList.size();
|
||||
if(!modcount)
|
||||
if(!SymGetModuleList(&modList))
|
||||
{
|
||||
GuiSymbolUpdateModuleList(0, nullptr);
|
||||
return;
|
||||
char szOldSearchPath[MAX_PATH] = "";
|
||||
if(!SymGetSearchPath(fdProcessInfo->hProcess, szOldSearchPath, MAX_PATH)) //backup current path
|
||||
}
|
||||
|
||||
// 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));
|
||||
|
||||
// Send the module data to the GUI for updating
|
||||
GuiSymbolUpdateModuleList((int)moduleCount, data);
|
||||
}
|
||||
|
||||
void SymDownloadAllSymbols(const char* SymbolStore)
|
||||
{
|
||||
// Default to Microsoft's symbol server
|
||||
if(!SymbolStore)
|
||||
SymbolStore = "http://msdl.microsoft.com/download/symbols";
|
||||
|
||||
// Build the vector of modules
|
||||
std::vector<SYMBOLMODULEINFO> modList;
|
||||
|
||||
if(!SymGetModuleList(&modList))
|
||||
return;
|
||||
|
||||
// Skip loading if there aren't any found modules
|
||||
if(modList.size() <= 0)
|
||||
return;
|
||||
|
||||
// Backup the current symbol search path
|
||||
char oldSearchPath[MAX_PATH];
|
||||
|
||||
if(!SafeSymGetSearchPath(fdProcessInfo->hProcess, oldSearchPath, MAX_PATH))
|
||||
{
|
||||
dputs("SymGetSearchPath failed!");
|
||||
return;
|
||||
}
|
||||
char szServerSearchPath[MAX_PATH * 2] = "";
|
||||
sprintf_s(szServerSearchPath, "SRV*%s*%s", szSymbolCachePath, szSymbolStore);
|
||||
if(!SymSetSearchPath(fdProcessInfo->hProcess, szServerSearchPath)) //update search path
|
||||
|
||||
// Use the custom server path and directory
|
||||
char customSearchPath[MAX_PATH * 2];
|
||||
sprintf_s(customSearchPath, "SRV*%s*%s", szSymbolCachePath, SymbolStore);
|
||||
|
||||
if(!SafeSymSetSearchPath(fdProcessInfo->hProcess, customSearchPath))
|
||||
{
|
||||
dputs("SymSetSearchPath (1) failed!");
|
||||
return;
|
||||
}
|
||||
for(int i = 0; i < modcount; i++) //reload all modules
|
||||
|
||||
// Reload
|
||||
for(auto & module : modList)
|
||||
{
|
||||
dprintf("downloading symbols for %s...\n", modList.at(i).name);
|
||||
uint modbase = modList.at(i).base;
|
||||
wchar_t szModulePath[MAX_PATH] = L"";
|
||||
if(!GetModuleFileNameExW(fdProcessInfo->hProcess, (HMODULE)modbase, szModulePath, MAX_PATH))
|
||||
dprintf("Downloading symbols for %s...\n", module.name);
|
||||
|
||||
wchar_t modulePath[MAX_PATH];
|
||||
if(!GetModuleFileNameExW(fdProcessInfo->hProcess, (HMODULE)module.base, modulePath, MAX_PATH))
|
||||
{
|
||||
dprintf("GetModuleFileNameExW("fhex") failed!\n", modbase);
|
||||
dprintf("GetModuleFileNameExW("fhex") failed!\n", module.base);
|
||||
continue;
|
||||
}
|
||||
if(!SymUnloadModule64(fdProcessInfo->hProcess, (DWORD64)modbase))
|
||||
|
||||
if(!SafeSymUnloadModule64(fdProcessInfo->hProcess, (DWORD64)module.base))
|
||||
{
|
||||
dprintf("SymUnloadModule64("fhex") failed!\n", modbase);
|
||||
dprintf("SymUnloadModule64("fhex") failed!\n", module.base);
|
||||
continue;
|
||||
}
|
||||
if(!SymLoadModuleEx(fdProcessInfo->hProcess, 0, StringUtils::Utf16ToUtf8(szModulePath).c_str(), 0, (DWORD64)modbase, 0, 0, 0))
|
||||
|
||||
if(!SafeSymLoadModuleEx(fdProcessInfo->hProcess, 0, StringUtils::Utf16ToUtf8(modulePath).c_str(), 0, (DWORD64)module.base, 0, 0, 0))
|
||||
{
|
||||
dprintf("SymLoadModuleEx("fhex") failed!\n", modbase);
|
||||
dprintf("SymLoadModuleEx("fhex") failed!\n", module.base);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if(!SymSetSearchPath(fdProcessInfo->hProcess, szOldSearchPath)) //restore search path
|
||||
{
|
||||
|
||||
// Restore the old search path
|
||||
if(!SafeSymSetSearchPath(fdProcessInfo->hProcess, oldSearchPath))
|
||||
dputs("SymSetSearchPath (2) failed!");
|
||||
}
|
||||
}
|
||||
|
||||
bool symfromname(const char* name, uint* addr)
|
||||
bool SymAddrFromName(const char* Name, uint* Address)
|
||||
{
|
||||
if(!name or !strlen(name) or !addr or !_strnicmp(name, "ordinal", 7)) //skip 'OrdinalXXX'
|
||||
if(!Name || Name[0] == '\0')
|
||||
return false;
|
||||
|
||||
if(!Address)
|
||||
return false;
|
||||
|
||||
// Skip 'OrdinalXXX'
|
||||
if(!_strnicmp(Name, "Ordinal", 7))
|
||||
return false;
|
||||
|
||||
// According to MSDN:
|
||||
// Note that the total size of the data is the SizeOfStruct + (MaxNameLen - 1) * sizeof(TCHAR)
|
||||
char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(char)];
|
||||
PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
|
||||
pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
||||
pSymbol->MaxNameLen = MAX_LABEL_SIZE;
|
||||
if(!SymFromName(fdProcessInfo->hProcess, name, pSymbol))
|
||||
|
||||
PSYMBOL_INFO symbol = (PSYMBOL_INFO)&buffer;
|
||||
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
||||
symbol->MaxNameLen = MAX_LABEL_SIZE;
|
||||
|
||||
if(!SafeSymFromName(fdProcessInfo->hProcess, Name, symbol))
|
||||
return false;
|
||||
*addr = (uint)pSymbol->Address;
|
||||
|
||||
*Address = (uint)symbol->Address;
|
||||
return true;
|
||||
}
|
||||
|
||||
const char* symgetsymbolicname(uint addr)
|
||||
const char* SymGetSymbolicName(uint Address)
|
||||
{
|
||||
//[modname.]symbolname
|
||||
static char symbolicname[MAX_MODULE_SIZE + MAX_SYM_NAME] = "";
|
||||
char label[MAX_SYM_NAME] = "";
|
||||
bool retval = false;
|
||||
if(labelget(addr, label)) //user labels have priority
|
||||
retval = true;
|
||||
else //no user labels
|
||||
//
|
||||
// This resolves an address to a module and symbol:
|
||||
// [modname.]symbolname
|
||||
//
|
||||
char label[MAX_SYM_NAME];
|
||||
|
||||
// User labels have priority, but if one wasn't found,
|
||||
// default to a symbol lookup
|
||||
if(!LabelGet(Address, label))
|
||||
{
|
||||
DWORD64 displacement = 0;
|
||||
char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(char)];
|
||||
PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
|
||||
pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
||||
pSymbol->MaxNameLen = MAX_LABEL_SIZE;
|
||||
if(SymFromAddr(fdProcessInfo->hProcess, (DWORD64)addr, &displacement, pSymbol) and !displacement)
|
||||
{
|
||||
pSymbol->Name[pSymbol->MaxNameLen - 1] = '\0';
|
||||
if(!bUndecorateSymbolNames or !UnDecorateSymbolName(pSymbol->Name, label, MAX_SYM_NAME, UNDNAME_COMPLETE))
|
||||
strcpy_s(label, pSymbol->Name);
|
||||
retval = true;
|
||||
}
|
||||
|
||||
PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer;
|
||||
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
||||
symbol->MaxNameLen = MAX_LABEL_SIZE;
|
||||
|
||||
// Perform a symbol lookup
|
||||
DWORD64 displacement = 0;
|
||||
|
||||
if(!SafeSymFromAddr(fdProcessInfo->hProcess, (DWORD64)Address, &displacement, symbol))
|
||||
return nullptr;
|
||||
|
||||
// If the symbol wasn't at offset 0 (start from the beginning) ignore it
|
||||
if(displacement != 0)
|
||||
return nullptr;
|
||||
|
||||
// Terminate the string for sanity
|
||||
symbol->Name[symbol->MaxNameLen - 1] = '\0';
|
||||
|
||||
if(!bUndecorateSymbolNames || !SafeUnDecorateSymbolName(symbol->Name, label, MAX_SYM_NAME, UNDNAME_COMPLETE))
|
||||
strcpy_s(label, symbol->Name);
|
||||
}
|
||||
if(retval)
|
||||
{
|
||||
char modname[MAX_MODULE_SIZE] = "";
|
||||
if(modnamefromaddr(addr, modname, false))
|
||||
sprintf(symbolicname, "%s.%s", modname, label);
|
||||
else
|
||||
sprintf(symbolicname, "<%s>", label);
|
||||
return symbolicname;
|
||||
}
|
||||
return 0;
|
||||
|
||||
// TODO: FIXME: STATIC VARIABLE
|
||||
static char symbolicname[MAX_MODULE_SIZE + MAX_SYM_NAME];
|
||||
char modname[MAX_MODULE_SIZE];
|
||||
|
||||
if(ModNameFromAddr(Address, modname, false))
|
||||
sprintf_s(symbolicname, "%s.%s", modname, label);
|
||||
else
|
||||
sprintf_s(symbolicname, "<%s>", label);
|
||||
|
||||
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;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue