diff --git a/components/detours/Clean.bat b/components/detours/Clean.bat new file mode 100644 index 00000000..a3f0c053 --- /dev/null +++ b/components/detours/Clean.bat @@ -0,0 +1,35 @@ +rem ***************************************** +rem * Delphi CleanUp Batch. * +rem * * +rem * Clean identcache,local,dcu,exe, * +rem * map,drc files. * +rem * Clean hidden __history folder. * +rem * * +rem * Author: Mahdi Safsafi * +rem ***************************************** + +@echo off +Setlocal EnableDelayedExpansion + +Del "*.identcache" /s/q +Del "*.local" /s/q +Del "*.dcu" /s/q +Del "*.exe" /s/q +Del "*.drc" /s/q +Del "*.map" /s/q + +set mustdel=false +For /r %%f in (.) do ( + set "mustdel=false" + if %%~nf==Win32 ( + if exist "%%~ff\Debug\" set "mustdel=true" + if exist "%%~ff\Release\" set "mustdel=true" +) else if %%~nf==Win64 ( + if exist "%%~ff\Debug\" set "mustdel=true" + if exist "%%~ff\Release\" set "mustdel=true" + ) +if %%~nf==__history set "mustdel=true" +if !mustdel!==true ( + if exist "%%~ff" rd /s/q "%%~ff" + ) +) \ No newline at end of file diff --git a/components/detours/Demo/DetoursDemo/COM/Demo1/Demo1.dpr b/components/detours/Demo/DetoursDemo/COM/Demo1/Demo1.dpr new file mode 100644 index 00000000..7b1c4b71 --- /dev/null +++ b/components/detours/Demo/DetoursDemo/COM/Demo1/Demo1.dpr @@ -0,0 +1,18 @@ +// JCL_DEBUG_EXPERT_GENERATEJDBG OFF +program Demo1; + +uses + Vcl.Forms, + uMain in 'uMain.pas' {Main}, + CPUID in '..\..\..\..\Source\CPUID.pas', + DDetours in '..\..\..\..\Source\DDetours.pas', + InstDecode in '..\..\..\..\Source\InstDecode.pas'; + +{$R *.res} + +begin + Application.Initialize; + Application.MainFormOnTaskbar := True; + Application.CreateForm(TMain, Main); + Application.Run; +end. diff --git a/components/detours/Demo/DetoursDemo/COM/Demo1/Demo1.dproj b/components/detours/Demo/DetoursDemo/COM/Demo1/Demo1.dproj new file mode 100644 index 00000000..e57be60d --- /dev/null +++ b/components/detours/Demo/DetoursDemo/COM/Demo1/Demo1.dproj @@ -0,0 +1,539 @@ + + + {18E3F860-77E5-45A6-BF0A-445D77BE5AC5} + 18.1 + VCL + Demo1.dpr + True + Debug + Win64 + 3 + Application + + + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Cfg_1 + true + true + + + true + Base + true + + + System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace) + $(BDS)\bin\delphi_PROJECTICON.ico + Demo1 + .\$(Platform)\$(Config) + .\$(Platform)\$(Config) + false + false + false + false + false + + + true + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) + FireDACSqliteDriver;FireDACDSDriver;DBXSqliteDriver;FireDACPgDriver;fmx;IndySystem;TeeDB;tethering;vclib;DBXInterBaseDriver;DataSnapClient;DataSnapCommon;DataSnapServer;DataSnapProviderClient;DBXSybaseASEDriver;DbxCommonDriver;vclimg;dbxcds;DatasnapConnectorsFreePascal;MetropolisUILiveTile;vcldb;vcldsnap;fmxFireDAC;DBXDb2Driver;DBXOracleDriver;CustomIPTransport;vclribbon;dsnap;IndyIPServer;fmxase;vcl;IndyCore;DBXMSSQLDriver;CloudService;IndyIPCommon;FmxTeeUI;FireDACIBDriver;DataSnapFireDAC;FireDACDBXDriver;soapserver;inetdbxpress;dsnapxml;FireDACInfxDriver;FireDACDb2Driver;adortl;FireDACASADriver;bindcompfmx;FireDACODBCDriver;RESTBackendComponents;emsclientfiredac;rtl;dbrtl;DbxClientDriver;FireDACCommon;bindcomp;inetdb;Tee;DBXOdbcDriver;vclFireDAC;xmlrtl;DataSnapNativeClient;ibxpress;svnui;IndyProtocols;DBXMySQLDriver;FireDACCommonDriver;bindcompdbx;bindengine;vclactnband;FMXTee;soaprtl;TeeUI;bindcompvcl;vclie;FireDACADSDriver;vcltouch;emsclient;VCLRESTComponents;FireDAC;DBXInformixDriver;FireDACMSSQLDriver;Intraweb;VclSmp;DataSnapConnectors;DataSnapServerMidas;DBXFirebirdDriver;dsnapcon;inet;fmxobj;FireDACMySQLDriver;soapmidas;vclx;svn;DBXSybaseASADriver;FireDACOracleDriver;fmxdae;RESTComponents;dbexpress;FireDACMSAccDriver;DataSnapIndy10ServerTransport;IndyIPClient;$(DCC_UsePackage) + 1033 + true + CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= + $(BDS)\bin\default_app.manifest + + + true + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace) + FireDACSqliteDriver;FireDACDSDriver;DBXSqliteDriver;FireDACPgDriver;fmx;IndySystem;TeeDB;tethering;vclib;DBXInterBaseDriver;DataSnapClient;DataSnapCommon;DataSnapServer;DataSnapProviderClient;DBXSybaseASEDriver;DbxCommonDriver;vclimg;dbxcds;DatasnapConnectorsFreePascal;MetropolisUILiveTile;vcldb;vcldsnap;fmxFireDAC;DBXDb2Driver;DBXOracleDriver;CustomIPTransport;vclribbon;dsnap;IndyIPServer;fmxase;vcl;IndyCore;DBXMSSQLDriver;CloudService;IndyIPCommon;FmxTeeUI;FireDACIBDriver;DataSnapFireDAC;FireDACDBXDriver;soapserver;inetdbxpress;dsnapxml;FireDACInfxDriver;FireDACDb2Driver;adortl;FireDACASADriver;bindcompfmx;FireDACODBCDriver;RESTBackendComponents;emsclientfiredac;rtl;dbrtl;DbxClientDriver;FireDACCommon;bindcomp;inetdb;Tee;DBXOdbcDriver;vclFireDAC;xmlrtl;DataSnapNativeClient;ibxpress;IndyProtocols;DBXMySQLDriver;FireDACCommonDriver;bindcompdbx;bindengine;vclactnband;FMXTee;soaprtl;TeeUI;bindcompvcl;vclie;FireDACADSDriver;vcltouch;emsclient;VCLRESTComponents;FireDAC;DBXInformixDriver;FireDACMSSQLDriver;Intraweb;VclSmp;DataSnapConnectors;DataSnapServerMidas;DBXFirebirdDriver;dsnapcon;inet;fmxobj;FireDACMySQLDriver;soapmidas;vclx;DBXSybaseASADriver;FireDACOracleDriver;fmxdae;RESTComponents;dbexpress;FireDACMSAccDriver;DataSnapIndy10ServerTransport;IndyIPClient;$(DCC_UsePackage) + 1033 + true + CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= + $(BDS)\bin\default_app.manifest + + + DEBUG;$(DCC_Define) + true + false + true + true + true + + + false + + + false + RELEASE;$(DCC_Define) + 0 + 0 + + + + MainSource + + +
Main
+ dfm +
+ + + + + Cfg_2 + Base + + + Base + + + Cfg_1 + Base + +
+ + Delphi.Personality.12 + Application + + + + Demo1.dpr + + + + + + Demo1.exe + true + + + + + Demo1.exe + true + + + + + Demo1.rsm + true + + + + + 1 + + + 1 + + + + + Contents\Resources + 1 + + + + + classes + 1 + + + + + res\drawable-xxhdpi + 1 + + + + + Contents\MacOS + 0 + + + 1 + + + Contents\MacOS + 1 + + + + + library\lib\mips + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 0 + + + 1 + + + Contents\MacOS + 1 + + + library\lib\armeabi-v7a + 1 + + + 1 + + + + + 0 + + + Contents\MacOS + 1 + .framework + + + + + 1 + + + 1 + + + 1 + + + + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + library\lib\armeabi + 1 + + + + + 0 + + + 1 + + + Contents\MacOS + 1 + + + + + 1 + + + 1 + + + 1 + + + + + res\drawable-normal + 1 + + + + + res\drawable-xhdpi + 1 + + + + + res\drawable-large + 1 + + + + + 1 + + + 1 + + + 1 + + + + + ..\ + 1 + + + ..\ + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + res\drawable-hdpi + 1 + + + + + Contents + 1 + + + + + ..\ + 1 + + + + + 1 + + + 1 + + + 1 + + + + + res\values + 1 + + + + + res\drawable-small + 1 + + + + + res\drawable + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + + + res\drawable + 1 + + + + + 0 + + + 0 + + + Contents\Resources\StartUp\ + 0 + + + 0 + + + 0 + + + 0 + + + + + library\lib\armeabi-v7a + 1 + + + + + 0 + .bpl + + + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + + + res\drawable-mdpi + 1 + + + + + res\drawable-xlarge + 1 + + + + + res\drawable-ldpi + 1 + + + + + 0 + .dll;.bpl + + + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + + + + + + + + + + + True + True + + + 12 + + + + +
diff --git a/components/detours/Demo/DetoursDemo/COM/Demo1/Demo1.res b/components/detours/Demo/DetoursDemo/COM/Demo1/Demo1.res new file mode 100644 index 00000000..0f3facb9 Binary files /dev/null and b/components/detours/Demo/DetoursDemo/COM/Demo1/Demo1.res differ diff --git a/components/detours/Demo/DetoursDemo/COM/Demo1/uMain.dfm b/components/detours/Demo/DetoursDemo/COM/Demo1/uMain.dfm new file mode 100644 index 00000000..f69a80af --- /dev/null +++ b/components/detours/Demo/DetoursDemo/COM/Demo1/uMain.dfm @@ -0,0 +1,54 @@ +object Main: TMain + Left = 0 + Top = 0 + BorderStyle = bsSizeToolWin + Caption = 'Hooking IFileOpenDialog.Show Method' + ClientHeight = 196 + ClientWidth = 447 + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + OldCreateOrder = False + PixelsPerInch = 96 + TextHeight = 13 + object BtnOpenDialog: TButton + Left = 304 + Top = 97 + Width = 121 + Height = 25 + Caption = 'Open File Dialog' + TabOrder = 0 + OnClick = BtnOpenDialogClick + end + object MemLog: TMemo + Left = 0 + Top = 0 + Width = 447 + Height = 81 + Align = alTop + Lines.Strings = ( + 'MemLog') + TabOrder = 1 + end + object BtnEnableHook: TButton + Left = 304 + Top = 128 + Width = 121 + Height = 25 + Caption = 'Enable Hook' + TabOrder = 2 + OnClick = BtnEnableHookClick + end + object BtnDisableHook: TButton + Left = 304 + Top = 159 + Width = 121 + Height = 25 + Caption = 'Disable Hook' + TabOrder = 3 + OnClick = BtnDisableHookClick + end +end diff --git a/components/detours/Demo/DetoursDemo/COM/Demo1/uMain.pas b/components/detours/Demo/DetoursDemo/COM/Demo1/uMain.pas new file mode 100644 index 00000000..e440045e --- /dev/null +++ b/components/detours/Demo/DetoursDemo/COM/Demo1/uMain.pas @@ -0,0 +1,78 @@ +unit uMain; + +interface + +uses + Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, + Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, DDetours; + +type + TMain = class(TForm) + BtnOpenDialog: TButton; + MemLog: TMemo; + BtnEnableHook: TButton; + BtnDisableHook: TButton; + procedure BtnOpenDialogClick(Sender: TObject); + procedure BtnEnableHookClick(Sender: TObject); + procedure BtnDisableHookClick(Sender: TObject); + private + { Private declarations } + public + { Public declarations } + end; + +var + Main: TMain; + +implementation + +uses ShlObj, ComObj; +{$R *.dfm} + +var + Trampoline_FileOpenDialog_Show: function(const Self; hwndParent: HWND): HRESULT; stdcall; + Trampoline_FileOpenDialog_SetTitle: function(const Self; pszTitle: LPCWSTR): HRESULT; stdcall; + +function FileOpenDialog_SetTitle_Hook(const Self; pszTitle: LPCWSTR): HRESULT; stdcall; +begin + Result := Trampoline_FileOpenDialog_SetTitle(Self, 'Hooked'); +end; + +function FileOpenDialog_Show_Hook(const Self; hwndParent: HWND): HRESULT; stdcall; +begin + Main.MemLog.Lines.Add('Execution FileOpenDialog.Show ..'); + Result := Trampoline_FileOpenDialog_Show(Self, hwndParent); +end; + +var + FileOpenDialog: IFileOpenDialog; + +procedure TMain.BtnOpenDialogClick(Sender: TObject); +begin + MemLog.Clear; + FileOpenDialog.SetTitle('Open..'); + FileOpenDialog.Show(Handle); +end; + +procedure TMain.BtnEnableHookClick(Sender: TObject); +begin + if not Assigned(Trampoline_FileOpenDialog_Show) then + @Trampoline_FileOpenDialog_Show := InterceptCreate(FileOpenDialog, 3, @FileOpenDialog_Show_Hook); + Trampoline_FileOpenDialog_SetTitle := InterceptCreate(FileOpenDialog, 17, @FileOpenDialog_SetTitle_Hook); +end; + +procedure TMain.BtnDisableHookClick(Sender: TObject); +begin + if Assigned(Trampoline_FileOpenDialog_Show) then + begin + InterceptRemove(@Trampoline_FileOpenDialog_Show); + Trampoline_FileOpenDialog_Show := nil; + end; + InterceptRemove(@Trampoline_FileOpenDialog_SetTitle) +end; + +initialization + +FileOpenDialog := CreateComObject(CLSID_FileOpenDialog) as IFileOpenDialog; + +end. diff --git a/components/detours/Demo/DetoursDemo/Delphi/Hook_Overloaded_Method/Hook_Overloaded_Method.dpr b/components/detours/Demo/DetoursDemo/Delphi/Hook_Overloaded_Method/Hook_Overloaded_Method.dpr new file mode 100644 index 00000000..c47f7367 --- /dev/null +++ b/components/detours/Demo/DetoursDemo/Delphi/Hook_Overloaded_Method/Hook_Overloaded_Method.dpr @@ -0,0 +1,47 @@ +program Hook_Overloaded_Method; + +{$APPTYPE CONSOLE} +{$R *.res} + +uses + System.SysUtils, + CPUID in '..\..\..\..\Source\CPUID.pas', + DDetours in '..\..\..\..\Source\DDetours.pas', + InstDecode in '..\..\..\..\Source\InstDecode.pas'; + +type + TShowMsg = procedure(Value: Integer); + +var + + TrampoShowMsg: TShowMsg; + { When hooking overloaded method , + Delphi does not reconize the desired method . + So we need to use this trick! + } + MyMethodPtr: TShowMsg; + +procedure ShowMsg(const S: String); overload; +begin + Writeln(S); +end; + +procedure ShowMsg(Value: Integer); overload; +begin + Writeln(Value); +end; + +procedure ShowMsgHooked(Value: Integer); +begin + Writeln('Method hooked successfully!'); + TrampoShowMsg(Value + 1); +end; + +begin + MyMethodPtr := ShowMsg; + @TrampoShowMsg := InterceptCreate(@MyMethodPtr, @ShowMsgHooked); + ShowMsg('Hi'); + ShowMsg(2015); + ReadLn; + +end. diff --git a/components/detours/Demo/DetoursDemo/Delphi/Hook_Overloaded_Method/Hook_Overloaded_Method.dproj b/components/detours/Demo/DetoursDemo/Delphi/Hook_Overloaded_Method/Hook_Overloaded_Method.dproj new file mode 100644 index 00000000..553aa9bd --- /dev/null +++ b/components/detours/Demo/DetoursDemo/Delphi/Hook_Overloaded_Method/Hook_Overloaded_Method.dproj @@ -0,0 +1,625 @@ + + + {E9A76233-969C-4733-B759-3191ED9B483B} + 18.1 + None + Hook_Overloaded_Method.dpr + True + Debug + Win32 + 1 + Console + + + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Cfg_1 + true + true + + + true + Base + true + + + $(BDS)\bin\delphi_PROJECTICON.ico + $(BDS)\bin\delphi_PROJECTICNS.icns + Hook_Overloaded_Method + System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace) + .\$(Platform)\$(Config) + .\$(Platform)\$(Config) + false + false + false + false + false + + + $(BDS)\bin\Artwork\Android\FM_LauncherIcon_144x144.png + true + true + $(BDS)\bin\Artwork\Android\FM_SplashImage_470x320.png + true + true + $(BDS)\bin\Artwork\Android\FM_SplashImage_960x720.png + true + $(BDS)\bin\Artwork\Android\FM_LauncherIcon_96x96.png + true + true + $(BDS)\bin\Artwork\Android\FM_SplashImage_640x480.png + $(BDS)\bin\Artwork\Android\FM_LauncherIcon_72x72.png + $(BDS)\bin\Artwork\Android\FM_LauncherIcon_48x48.png + $(BDS)\bin\Artwork\Android\FM_LauncherIcon_36x36.png + true + true + true + $(BDS)\bin\Artwork\Android\FM_SplashImage_426x320.png + + + $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_80x80.png + $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_60x60.png + $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_76x76.png + $(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_40x40.png + $(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_80x80.png + $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_120x120.png + $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImagePortrait_768x1024.png + $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageLandscape_1024x768.png + $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_152x152.png + $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageLandscape_2048x1536.png + $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImagePortrait_1536x2048.png + $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_40x40.png + + + $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_80x80.png + $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_60x60.png + $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_76x76.png + $(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_40x40.png + $(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_80x80.png + $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_120x120.png + $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImagePortrait_768x1024.png + $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageLandscape_1024x768.png + $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_152x152.png + $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageLandscape_2048x1536.png + $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImagePortrait_1536x2048.png + $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_40x40.png + + + $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_80x80.png + $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_60x60.png + $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_76x76.png + $(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_40x40.png + $(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_80x80.png + $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_120x120.png + $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImagePortrait_768x1024.png + $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageLandscape_1024x768.png + $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_152x152.png + $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageLandscape_2048x1536.png + $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImagePortrait_1536x2048.png + $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_40x40.png + + + FireDACSqliteDriver;FireDACDSDriver;DBXSqliteDriver;FireDACPgDriver;fmx;IndySystem;TeeDB;tethering;vclib;DBXInterBaseDriver;DataSnapClient;DataSnapCommon;DataSnapServer;DataSnapProviderClient;DBXSybaseASEDriver;DbxCommonDriver;vclimg;dbxcds;DatasnapConnectorsFreePascal;MetropolisUILiveTile;vcldb;vcldsnap;fmxFireDAC;DBXDb2Driver;DBXOracleDriver;CustomIPTransport;vclribbon;dsnap;IndyIPServer;fmxase;vcl;IndyCore;DBXMSSQLDriver;CloudService;IndyIPCommon;FmxTeeUI;FireDACIBDriver;DataSnapFireDAC;FireDACDBXDriver;soapserver;inetdbxpress;dsnapxml;FireDACInfxDriver;FireDACDb2Driver;adortl;FireDACASADriver;bindcompfmx;FireDACODBCDriver;RESTBackendComponents;emsclientfiredac;rtl;dbrtl;DbxClientDriver;FireDACCommon;bindcomp;inetdb;Tee;DBXOdbcDriver;vclFireDAC;xmlrtl;DataSnapNativeClient;ibxpress;svnui;IndyProtocols;DBXMySQLDriver;FireDACCommonDriver;bindcompdbx;bindengine;vclactnband;FMXTee;soaprtl;TeeUI;bindcompvcl;vclie;FireDACADSDriver;vcltouch;emsclient;VCLRESTComponents;FireDAC;DBXInformixDriver;FireDACMSSQLDriver;Intraweb;VclSmp;DataSnapConnectors;DataSnapServerMidas;DBXFirebirdDriver;dsnapcon;inet;fmxobj;FireDACMySQLDriver;soapmidas;vclx;svn;DBXSybaseASADriver;FireDACOracleDriver;fmxdae;RESTComponents;dbexpress;FireDACMSAccDriver;DataSnapIndy10ServerTransport;IndyIPClient;$(DCC_UsePackage) + true + CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= + 1033 + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) + + + true + FireDACSqliteDriver;FireDACDSDriver;DBXSqliteDriver;FireDACPgDriver;fmx;IndySystem;TeeDB;tethering;vclib;DBXInterBaseDriver;DataSnapClient;DataSnapCommon;DataSnapServer;DataSnapProviderClient;DBXSybaseASEDriver;DbxCommonDriver;vclimg;dbxcds;DatasnapConnectorsFreePascal;MetropolisUILiveTile;vcldb;vcldsnap;fmxFireDAC;DBXDb2Driver;DBXOracleDriver;CustomIPTransport;vclribbon;dsnap;IndyIPServer;fmxase;vcl;IndyCore;DBXMSSQLDriver;CloudService;IndyIPCommon;FmxTeeUI;FireDACIBDriver;DataSnapFireDAC;FireDACDBXDriver;soapserver;inetdbxpress;dsnapxml;FireDACInfxDriver;FireDACDb2Driver;adortl;FireDACASADriver;bindcompfmx;FireDACODBCDriver;RESTBackendComponents;emsclientfiredac;rtl;dbrtl;DbxClientDriver;FireDACCommon;bindcomp;inetdb;Tee;DBXOdbcDriver;vclFireDAC;xmlrtl;DataSnapNativeClient;ibxpress;IndyProtocols;DBXMySQLDriver;FireDACCommonDriver;bindcompdbx;bindengine;vclactnband;FMXTee;soaprtl;TeeUI;bindcompvcl;vclie;FireDACADSDriver;vcltouch;emsclient;VCLRESTComponents;FireDAC;DBXInformixDriver;FireDACMSSQLDriver;Intraweb;VclSmp;DataSnapConnectors;DataSnapServerMidas;DBXFirebirdDriver;dsnapcon;inet;fmxobj;FireDACMySQLDriver;soapmidas;vclx;DBXSybaseASADriver;FireDACOracleDriver;fmxdae;RESTComponents;dbexpress;FireDACMSAccDriver;DataSnapIndy10ServerTransport;IndyIPClient;$(DCC_UsePackage) + + + DEBUG;$(DCC_Define) + true + false + true + true + true + + + false + + + false + RELEASE;$(DCC_Define) + 0 + 0 + + + + MainSource + + + + + + Cfg_2 + Base + + + Base + + + Cfg_1 + Base + + + + Delphi.Personality.12 + Application + + + + Hook_Overloaded_Method.dpr + + + + + + Hook_Overloaded_Method.exe + true + + + + + true + + + + + true + + + + + true + + + + + true + + + + + 1 + + + 1 + + + + + Contents\Resources + 1 + + + + + classes + 1 + + + + + res\drawable-xxhdpi + 1 + + + + + Contents\MacOS + 0 + + + 1 + + + Contents\MacOS + 1 + + + + + library\lib\mips + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 0 + + + 1 + + + Contents\MacOS + 1 + + + library\lib\armeabi-v7a + 1 + + + 1 + + + + + 0 + + + Contents\MacOS + 1 + .framework + + + + + 1 + + + 1 + + + 1 + + + + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + library\lib\armeabi + 1 + + + + + 0 + + + 1 + + + Contents\MacOS + 1 + + + + + 1 + + + 1 + + + 1 + + + + + res\drawable-normal + 1 + + + + + res\drawable-xhdpi + 1 + + + + + res\drawable-large + 1 + + + + + 1 + + + 1 + + + 1 + + + + + ..\ + 1 + + + ..\ + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + res\drawable-hdpi + 1 + + + + + Contents + 1 + + + + + ..\ + 1 + + + + + 1 + + + 1 + + + 1 + + + + + res\values + 1 + + + + + res\drawable-small + 1 + + + + + res\drawable + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + + + res\drawable + 1 + + + + + 0 + + + 0 + + + Contents\Resources\StartUp\ + 0 + + + 0 + + + 0 + + + 0 + + + + + library\lib\armeabi-v7a + 1 + + + + + 0 + .bpl + + + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + + + res\drawable-mdpi + 1 + + + + + res\drawable-xlarge + 1 + + + + + res\drawable-ldpi + 1 + + + + + 0 + .dll;.bpl + + + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + + + + + + + + + + + False + False + False + False + False + True + False + + + 12 + + + + + diff --git a/components/detours/Demo/DetoursDemo/Delphi/Interfaces/Demo1/Demo1.dpr b/components/detours/Demo/DetoursDemo/Delphi/Interfaces/Demo1/Demo1.dpr new file mode 100644 index 00000000..6044c216 --- /dev/null +++ b/components/detours/Demo/DetoursDemo/Delphi/Interfaces/Demo1/Demo1.dpr @@ -0,0 +1,18 @@ +// JCL_DEBUG_EXPERT_GENERATEJDBG OFF +program Demo1; + +uses + Vcl.Forms, + uMain in 'uMain.pas' {Main}, + CPUID in '..\..\..\..\..\Source\CPUID.pas', + DDetours in '..\..\..\..\..\Source\DDetours.pas', + InstDecode in '..\..\..\..\..\Source\InstDecode.pas'; + +{$R *.res} + +begin + Application.Initialize; + Application.MainFormOnTaskbar := True; + Application.CreateForm(TMain, Main); + Application.Run; +end. diff --git a/components/detours/Demo/DetoursDemo/Delphi/Interfaces/Demo1/Demo1.dproj b/components/detours/Demo/DetoursDemo/Delphi/Interfaces/Demo1/Demo1.dproj new file mode 100644 index 00000000..5fc7f47a --- /dev/null +++ b/components/detours/Demo/DetoursDemo/Delphi/Interfaces/Demo1/Demo1.dproj @@ -0,0 +1,521 @@ + + + {A523E817-0A23-4476-91C8-42FA45FF0F64} + 18.1 + VCL + Demo1.dpr + True + Debug + Win32 + 1 + Application + + + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Cfg_1 + true + true + + + true + Base + true + + + System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace) + Demo1 + $(BDS)\bin\delphi_PROJECTICON.ico + .\$(Platform)\$(Config) + .\$(Platform)\$(Config) + false + false + false + false + false + + + true + FireDACSqliteDriver;FireDACDSDriver;DBXSqliteDriver;FireDACPgDriver;fmx;IndySystem;TeeDB;tethering;vclib;DBXInterBaseDriver;DataSnapClient;DataSnapCommon;DataSnapServer;DataSnapProviderClient;DBXSybaseASEDriver;DbxCommonDriver;vclimg;dbxcds;DatasnapConnectorsFreePascal;MetropolisUILiveTile;vcldb;vcldsnap;fmxFireDAC;DBXDb2Driver;DBXOracleDriver;CustomIPTransport;vclribbon;dsnap;IndyIPServer;fmxase;vcl;IndyCore;DBXMSSQLDriver;CloudService;IndyIPCommon;FmxTeeUI;FireDACIBDriver;DataSnapFireDAC;FireDACDBXDriver;soapserver;inetdbxpress;dsnapxml;FireDACInfxDriver;FireDACDb2Driver;adortl;FireDACASADriver;bindcompfmx;FireDACODBCDriver;RESTBackendComponents;emsclientfiredac;rtl;dbrtl;DbxClientDriver;FireDACCommon;bindcomp;inetdb;Tee;DBXOdbcDriver;vclFireDAC;xmlrtl;DataSnapNativeClient;ibxpress;svnui;IndyProtocols;DBXMySQLDriver;FireDACCommonDriver;bindcompdbx;bindengine;vclactnband;FMXTee;soaprtl;TeeUI;bindcompvcl;vclie;FireDACADSDriver;vcltouch;emsclient;VCLRESTComponents;FireDAC;DBXInformixDriver;FireDACMSSQLDriver;Intraweb;VclSmp;DataSnapConnectors;DataSnapServerMidas;DBXFirebirdDriver;dsnapcon;inet;fmxobj;FireDACMySQLDriver;soapmidas;vclx;svn;DBXSybaseASADriver;FireDACOracleDriver;fmxdae;RESTComponents;dbexpress;FireDACMSAccDriver;DataSnapIndy10ServerTransport;IndyIPClient;$(DCC_UsePackage) + 1033 + true + CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= + $(BDS)\bin\default_app.manifest + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) + + + FireDACSqliteDriver;FireDACDSDriver;DBXSqliteDriver;FireDACPgDriver;fmx;IndySystem;TeeDB;tethering;vclib;DBXInterBaseDriver;DataSnapClient;DataSnapCommon;DataSnapServer;DataSnapProviderClient;DBXSybaseASEDriver;DbxCommonDriver;vclimg;dbxcds;DatasnapConnectorsFreePascal;MetropolisUILiveTile;vcldb;vcldsnap;fmxFireDAC;DBXDb2Driver;DBXOracleDriver;CustomIPTransport;vclribbon;dsnap;IndyIPServer;fmxase;vcl;IndyCore;DBXMSSQLDriver;CloudService;IndyIPCommon;FmxTeeUI;FireDACIBDriver;DataSnapFireDAC;FireDACDBXDriver;soapserver;inetdbxpress;dsnapxml;FireDACInfxDriver;FireDACDb2Driver;adortl;FireDACASADriver;bindcompfmx;FireDACODBCDriver;RESTBackendComponents;emsclientfiredac;rtl;dbrtl;DbxClientDriver;FireDACCommon;bindcomp;inetdb;Tee;DBXOdbcDriver;vclFireDAC;xmlrtl;DataSnapNativeClient;ibxpress;IndyProtocols;DBXMySQLDriver;FireDACCommonDriver;bindcompdbx;bindengine;vclactnband;FMXTee;soaprtl;TeeUI;bindcompvcl;vclie;FireDACADSDriver;vcltouch;emsclient;VCLRESTComponents;FireDAC;DBXInformixDriver;FireDACMSSQLDriver;Intraweb;VclSmp;DataSnapConnectors;DataSnapServerMidas;DBXFirebirdDriver;dsnapcon;inet;fmxobj;FireDACMySQLDriver;soapmidas;vclx;DBXSybaseASADriver;FireDACOracleDriver;fmxdae;RESTComponents;dbexpress;FireDACMSAccDriver;DataSnapIndy10ServerTransport;IndyIPClient;$(DCC_UsePackage) + + + DEBUG;$(DCC_Define) + true + false + true + true + true + + + false + + + false + RELEASE;$(DCC_Define) + 0 + 0 + + + + MainSource + + +
Main
+ dfm +
+ + + + + Cfg_2 + Base + + + Base + + + Cfg_1 + Base + +
+ + Delphi.Personality.12 + Application + + + + Demo1.dpr + + + + + + Demo1.exe + true + + + + + 1 + + + 1 + + + + + Contents\Resources + 1 + + + + + classes + 1 + + + + + res\drawable-xxhdpi + 1 + + + + + Contents\MacOS + 0 + + + 1 + + + Contents\MacOS + 1 + + + + + library\lib\mips + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 0 + + + 1 + + + Contents\MacOS + 1 + + + library\lib\armeabi-v7a + 1 + + + 1 + + + + + 0 + + + Contents\MacOS + 1 + .framework + + + + + 1 + + + 1 + + + 1 + + + + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + library\lib\armeabi + 1 + + + + + 0 + + + 1 + + + Contents\MacOS + 1 + + + + + 1 + + + 1 + + + 1 + + + + + res\drawable-normal + 1 + + + + + res\drawable-xhdpi + 1 + + + + + res\drawable-large + 1 + + + + + 1 + + + 1 + + + 1 + + + + + ..\ + 1 + + + ..\ + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + res\drawable-hdpi + 1 + + + + + Contents + 1 + + + + + ..\ + 1 + + + + + 1 + + + 1 + + + 1 + + + + + res\values + 1 + + + + + res\drawable-small + 1 + + + + + res\drawable + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + + + res\drawable + 1 + + + + + 0 + + + 0 + + + Contents\Resources\StartUp\ + 0 + + + 0 + + + 0 + + + 0 + + + + + library\lib\armeabi-v7a + 1 + + + + + 0 + .bpl + + + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + + + res\drawable-mdpi + 1 + + + + + res\drawable-xlarge + 1 + + + + + res\drawable-ldpi + 1 + + + + + 0 + .dll;.bpl + + + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + + + + + + + + + + + True + False + + + 12 + + + + +
diff --git a/components/detours/Demo/DetoursDemo/Delphi/Interfaces/Demo1/uMain.dfm b/components/detours/Demo/DetoursDemo/Delphi/Interfaces/Demo1/uMain.dfm new file mode 100644 index 00000000..f7ca056a --- /dev/null +++ b/components/detours/Demo/DetoursDemo/Delphi/Interfaces/Demo1/uMain.dfm @@ -0,0 +1,44 @@ +object Main: TMain + Left = 0 + Top = 0 + BorderStyle = bsSizeToolWin + Caption = 'Hooking Method in interface' + ClientHeight = 133 + ClientWidth = 298 + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + OldCreateOrder = False + PixelsPerInch = 96 + TextHeight = 13 + object BtnCallShowMsg: TButton + Left = 32 + Top = 24 + Width = 241 + Height = 25 + Caption = 'Call ShowMsg' + TabOrder = 0 + OnClick = BtnCallShowMsgClick + end + object BtnHook: TButton + Left = 32 + Top = 55 + Width = 241 + Height = 25 + Caption = 'Hook ShowMsg' + TabOrder = 1 + OnClick = BtnHookClick + end + object BtnUnHook: TButton + Left = 32 + Top = 86 + Width = 241 + Height = 25 + Caption = 'UnHook ShowMsg ' + TabOrder = 2 + OnClick = BtnUnHookClick + end +end diff --git a/components/detours/Demo/DetoursDemo/Delphi/Interfaces/Demo1/uMain.pas b/components/detours/Demo/DetoursDemo/Delphi/Interfaces/Demo1/uMain.pas new file mode 100644 index 00000000..a0b194a1 --- /dev/null +++ b/components/detours/Demo/DetoursDemo/Delphi/Interfaces/Demo1/uMain.pas @@ -0,0 +1,81 @@ +unit uMain; + +interface + +uses + Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, + Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, DDetours; + +type + TMain = class(TForm) + BtnCallShowMsg: TButton; + BtnHook: TButton; + BtnUnHook: TButton; + procedure BtnCallShowMsgClick(Sender: TObject); + procedure BtnHookClick(Sender: TObject); + procedure BtnUnHookClick(Sender: TObject); + private + { Private declarations } + public + { Public declarations } + end; + +type + IMyInterface = Interface + procedure ShowMsg(const Msg: String); + End; + + TMyObject = class(TInterfacedObject, IMyInterface) + public + procedure ShowMsg(const Msg: String); + end; + +var + Main: TMain; + FMyInterface: IMyInterface; + +implementation + +{$R *.dfm} + +var + TrampolineShowMsg: procedure(const Self; const Msg: String) = nil; + +procedure TMain.BtnUnHookClick(Sender: TObject); +begin + if Assigned(TrampolineShowMsg) then + begin + InterceptRemove(@TrampolineShowMsg); + TrampolineShowMsg := nil; + end; +end; + +procedure TMain.BtnCallShowMsgClick(Sender: TObject); +begin + FMyInterface.ShowMsg('This is a test !'); +end; + +procedure InterceptShowMsg(const Self; const Msg: String); +begin + TrampolineShowMsg(Self, 'Hooked'); +end; +{ TMyObject } + +procedure TMyObject.ShowMsg(const Msg: String); +var + S: String; +begin + S := 'Your Message : ' + Msg; + ShowMessage(S); +end; + +procedure TMain.BtnHookClick(Sender: TObject); +begin + @TrampolineShowMsg := InterceptCreate(FMyInterface, 3, @InterceptShowMsg); +end; + +initialization + +FMyInterface := TMyObject.Create; + +end. diff --git a/components/detours/Demo/DetoursDemo/Delphi/Objects/Demo1/Demo1.dpr b/components/detours/Demo/DetoursDemo/Delphi/Objects/Demo1/Demo1.dpr new file mode 100644 index 00000000..6044c216 --- /dev/null +++ b/components/detours/Demo/DetoursDemo/Delphi/Objects/Demo1/Demo1.dpr @@ -0,0 +1,18 @@ +// JCL_DEBUG_EXPERT_GENERATEJDBG OFF +program Demo1; + +uses + Vcl.Forms, + uMain in 'uMain.pas' {Main}, + CPUID in '..\..\..\..\..\Source\CPUID.pas', + DDetours in '..\..\..\..\..\Source\DDetours.pas', + InstDecode in '..\..\..\..\..\Source\InstDecode.pas'; + +{$R *.res} + +begin + Application.Initialize; + Application.MainFormOnTaskbar := True; + Application.CreateForm(TMain, Main); + Application.Run; +end. diff --git a/components/detours/Demo/DetoursDemo/Delphi/Objects/Demo1/Demo1.dproj b/components/detours/Demo/DetoursDemo/Delphi/Objects/Demo1/Demo1.dproj new file mode 100644 index 00000000..7918447c --- /dev/null +++ b/components/detours/Demo/DetoursDemo/Delphi/Objects/Demo1/Demo1.dproj @@ -0,0 +1,521 @@ + + + {F786E6F9-BE54-4103-ADFF-11BC6C8629F0} + 18.1 + VCL + Demo1.dpr + True + Debug + Win32 + 1 + Application + + + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Cfg_1 + true + true + + + true + Base + true + + + System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace) + Demo1 + $(BDS)\bin\delphi_PROJECTICON.ico + .\$(Platform)\$(Config) + .\$(Platform)\$(Config) + false + false + false + false + false + + + true + FireDACSqliteDriver;FireDACDSDriver;DBXSqliteDriver;FireDACPgDriver;fmx;IndySystem;TeeDB;tethering;vclib;DBXInterBaseDriver;DataSnapClient;DataSnapCommon;DataSnapServer;DataSnapProviderClient;DBXSybaseASEDriver;DbxCommonDriver;vclimg;dbxcds;DatasnapConnectorsFreePascal;MetropolisUILiveTile;vcldb;vcldsnap;fmxFireDAC;DBXDb2Driver;DBXOracleDriver;CustomIPTransport;vclribbon;dsnap;IndyIPServer;fmxase;vcl;IndyCore;DBXMSSQLDriver;CloudService;IndyIPCommon;FmxTeeUI;FireDACIBDriver;DataSnapFireDAC;FireDACDBXDriver;soapserver;inetdbxpress;dsnapxml;FireDACInfxDriver;FireDACDb2Driver;adortl;FireDACASADriver;bindcompfmx;FireDACODBCDriver;RESTBackendComponents;emsclientfiredac;rtl;dbrtl;DbxClientDriver;FireDACCommon;bindcomp;inetdb;Tee;DBXOdbcDriver;vclFireDAC;xmlrtl;DataSnapNativeClient;ibxpress;svnui;IndyProtocols;DBXMySQLDriver;FireDACCommonDriver;bindcompdbx;bindengine;vclactnband;FMXTee;soaprtl;TeeUI;bindcompvcl;vclie;FireDACADSDriver;vcltouch;emsclient;VCLRESTComponents;FireDAC;DBXInformixDriver;FireDACMSSQLDriver;Intraweb;VclSmp;DataSnapConnectors;DataSnapServerMidas;DBXFirebirdDriver;dsnapcon;inet;fmxobj;FireDACMySQLDriver;soapmidas;vclx;svn;DBXSybaseASADriver;FireDACOracleDriver;fmxdae;RESTComponents;dbexpress;FireDACMSAccDriver;DataSnapIndy10ServerTransport;IndyIPClient;$(DCC_UsePackage) + 1033 + true + CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= + $(BDS)\bin\default_app.manifest + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) + + + FireDACSqliteDriver;FireDACDSDriver;DBXSqliteDriver;FireDACPgDriver;fmx;IndySystem;TeeDB;tethering;vclib;DBXInterBaseDriver;DataSnapClient;DataSnapCommon;DataSnapServer;DataSnapProviderClient;DBXSybaseASEDriver;DbxCommonDriver;vclimg;dbxcds;DatasnapConnectorsFreePascal;MetropolisUILiveTile;vcldb;vcldsnap;fmxFireDAC;DBXDb2Driver;DBXOracleDriver;CustomIPTransport;vclribbon;dsnap;IndyIPServer;fmxase;vcl;IndyCore;DBXMSSQLDriver;CloudService;IndyIPCommon;FmxTeeUI;FireDACIBDriver;DataSnapFireDAC;FireDACDBXDriver;soapserver;inetdbxpress;dsnapxml;FireDACInfxDriver;FireDACDb2Driver;adortl;FireDACASADriver;bindcompfmx;FireDACODBCDriver;RESTBackendComponents;emsclientfiredac;rtl;dbrtl;DbxClientDriver;FireDACCommon;bindcomp;inetdb;Tee;DBXOdbcDriver;vclFireDAC;xmlrtl;DataSnapNativeClient;ibxpress;IndyProtocols;DBXMySQLDriver;FireDACCommonDriver;bindcompdbx;bindengine;vclactnband;FMXTee;soaprtl;TeeUI;bindcompvcl;vclie;FireDACADSDriver;vcltouch;emsclient;VCLRESTComponents;FireDAC;DBXInformixDriver;FireDACMSSQLDriver;Intraweb;VclSmp;DataSnapConnectors;DataSnapServerMidas;DBXFirebirdDriver;dsnapcon;inet;fmxobj;FireDACMySQLDriver;soapmidas;vclx;DBXSybaseASADriver;FireDACOracleDriver;fmxdae;RESTComponents;dbexpress;FireDACMSAccDriver;DataSnapIndy10ServerTransport;IndyIPClient;$(DCC_UsePackage) + + + DEBUG;$(DCC_Define) + true + false + true + true + true + + + false + + + false + RELEASE;$(DCC_Define) + 0 + 0 + + + + MainSource + + +
Main
+ dfm +
+ + + + + Cfg_2 + Base + + + Base + + + Cfg_1 + Base + +
+ + Delphi.Personality.12 + Application + + + + Demo1.dpr + + + + + + Demo1.exe + true + + + + + 1 + + + 1 + + + + + Contents\Resources + 1 + + + + + classes + 1 + + + + + res\drawable-xxhdpi + 1 + + + + + Contents\MacOS + 0 + + + 1 + + + Contents\MacOS + 1 + + + + + library\lib\mips + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 0 + + + 1 + + + Contents\MacOS + 1 + + + library\lib\armeabi-v7a + 1 + + + 1 + + + + + 0 + + + Contents\MacOS + 1 + .framework + + + + + 1 + + + 1 + + + 1 + + + + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + library\lib\armeabi + 1 + + + + + 0 + + + 1 + + + Contents\MacOS + 1 + + + + + 1 + + + 1 + + + 1 + + + + + res\drawable-normal + 1 + + + + + res\drawable-xhdpi + 1 + + + + + res\drawable-large + 1 + + + + + 1 + + + 1 + + + 1 + + + + + ..\ + 1 + + + ..\ + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + res\drawable-hdpi + 1 + + + + + Contents + 1 + + + + + ..\ + 1 + + + + + 1 + + + 1 + + + 1 + + + + + res\values + 1 + + + + + res\drawable-small + 1 + + + + + res\drawable + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + + + res\drawable + 1 + + + + + 0 + + + 0 + + + Contents\Resources\StartUp\ + 0 + + + 0 + + + 0 + + + 0 + + + + + library\lib\armeabi-v7a + 1 + + + + + 0 + .bpl + + + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + + + res\drawable-mdpi + 1 + + + + + res\drawable-xlarge + 1 + + + + + res\drawable-ldpi + 1 + + + + + 0 + .dll;.bpl + + + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + + + + + + + + + + + True + False + + + 12 + + + + +
diff --git a/components/detours/Demo/DetoursDemo/Delphi/Objects/Demo1/uMain.dfm b/components/detours/Demo/DetoursDemo/Delphi/Objects/Demo1/uMain.dfm new file mode 100644 index 00000000..9702c526 --- /dev/null +++ b/components/detours/Demo/DetoursDemo/Delphi/Objects/Demo1/uMain.dfm @@ -0,0 +1,52 @@ +object Main: TMain + Left = 0 + Top = 0 + BorderStyle = bsSizeToolWin + Caption = 'Hooking TControl.SetTextBuf' + ClientHeight = 164 + ClientWidth = 178 + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + OldCreateOrder = False + PixelsPerInch = 96 + TextHeight = 13 + object BtnEnableHook: TButton + Left = 17 + Top = 90 + Width = 151 + Height = 25 + Caption = 'BtnEnableHook' + TabOrder = 0 + OnClick = BtnEnableHookClick + end + object BtnDisableHook: TButton + Left = 17 + Top = 116 + Width = 151 + Height = 25 + Caption = 'BtnDisableHook' + TabOrder = 1 + OnClick = BtnDisableHookClick + end + object Edit1: TEdit + Left = 17 + Top = 24 + Width = 151 + Height = 21 + TabOrder = 2 + Text = 'Hi' + end + object BtnClickMe: TButton + Left = 17 + Top = 51 + Width = 151 + Height = 25 + Caption = 'Click Me' + TabOrder = 3 + OnClick = BtnClickMeClick + end +end diff --git a/components/detours/Demo/DetoursDemo/Delphi/Objects/Demo1/uMain.pas b/components/detours/Demo/DetoursDemo/Delphi/Objects/Demo1/uMain.pas new file mode 100644 index 00000000..2de10be7 --- /dev/null +++ b/components/detours/Demo/DetoursDemo/Delphi/Objects/Demo1/uMain.pas @@ -0,0 +1,62 @@ +unit uMain; + +interface + +uses + Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, + Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, DDetours; + +type + TMain = class(TForm) + BtnEnableHook: TButton; + BtnDisableHook: TButton; + Edit1: TEdit; + BtnClickMe: TButton; + procedure BtnEnableHookClick(Sender: TObject); + procedure BtnDisableHookClick(Sender: TObject); + procedure BtnClickMeClick(Sender: TObject); + private + { Private declarations } + public + { Public declarations } + end; + +var + Main: TMain; + +implementation + +{$R *.dfm} + +var + TrampolineSetTextBuf: procedure(const Self; Buffer: PChar) = nil; + +procedure SetTextBufHooked(const Self; Buffer: PChar); +var + S: String; +begin + S := 'Hooked _' + String(Buffer); + TrampolineSetTextBuf(Self, PChar(S)); // Call the original function . +end; + +procedure TMain.BtnDisableHookClick(Sender: TObject); +begin + if Assigned(TrampolineSetTextBuf) then + begin + InterceptRemove(@TrampolineSetTextBuf); + TrampolineSetTextBuf := nil; + end; +end; + +procedure TMain.BtnEnableHookClick(Sender: TObject); +begin + Edit1.Text := 'Enter new text ..'; + @TrampolineSetTextBuf := InterceptCreate(@TControl.SetTextBuf, @SetTextBufHooked); +end; + +procedure TMain.BtnClickMeClick(Sender: TObject); +begin + BtnClickMe.Caption := Edit1.Text; +end; + +end. diff --git a/components/detours/Demo/DetoursDemo/Delphi/RTL/Demo1/Demo1.dpr b/components/detours/Demo/DetoursDemo/Delphi/RTL/Demo1/Demo1.dpr new file mode 100644 index 00000000..6044c216 --- /dev/null +++ b/components/detours/Demo/DetoursDemo/Delphi/RTL/Demo1/Demo1.dpr @@ -0,0 +1,18 @@ +// JCL_DEBUG_EXPERT_GENERATEJDBG OFF +program Demo1; + +uses + Vcl.Forms, + uMain in 'uMain.pas' {Main}, + CPUID in '..\..\..\..\..\Source\CPUID.pas', + DDetours in '..\..\..\..\..\Source\DDetours.pas', + InstDecode in '..\..\..\..\..\Source\InstDecode.pas'; + +{$R *.res} + +begin + Application.Initialize; + Application.MainFormOnTaskbar := True; + Application.CreateForm(TMain, Main); + Application.Run; +end. diff --git a/components/detours/Demo/DetoursDemo/Delphi/RTL/Demo1/Demo1.dproj b/components/detours/Demo/DetoursDemo/Delphi/RTL/Demo1/Demo1.dproj new file mode 100644 index 00000000..cf66ecf8 --- /dev/null +++ b/components/detours/Demo/DetoursDemo/Delphi/RTL/Demo1/Demo1.dproj @@ -0,0 +1,539 @@ + + + {FF06FC93-1560-45CE-9FF3-14F0C95618F4} + 18.1 + VCL + Demo1.dpr + True + Debug + Win64 + 3 + Application + + + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Cfg_1 + true + true + + + true + Base + true + + + System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace) + $(BDS)\bin\delphi_PROJECTICON.ico + Demo1 + .\$(Platform)\$(Config) + .\$(Platform)\$(Config) + false + false + false + false + false + + + true + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) + FireDACSqliteDriver;FireDACDSDriver;DBXSqliteDriver;FireDACPgDriver;fmx;IndySystem;TeeDB;tethering;vclib;DBXInterBaseDriver;DataSnapClient;DataSnapCommon;DataSnapServer;DataSnapProviderClient;DBXSybaseASEDriver;DbxCommonDriver;vclimg;dbxcds;DatasnapConnectorsFreePascal;MetropolisUILiveTile;vcldb;vcldsnap;fmxFireDAC;DBXDb2Driver;DBXOracleDriver;CustomIPTransport;vclribbon;dsnap;IndyIPServer;fmxase;vcl;IndyCore;DBXMSSQLDriver;CloudService;IndyIPCommon;FmxTeeUI;FireDACIBDriver;DataSnapFireDAC;FireDACDBXDriver;soapserver;inetdbxpress;dsnapxml;FireDACInfxDriver;FireDACDb2Driver;adortl;FireDACASADriver;bindcompfmx;FireDACODBCDriver;RESTBackendComponents;emsclientfiredac;rtl;dbrtl;DbxClientDriver;FireDACCommon;bindcomp;inetdb;Tee;DBXOdbcDriver;vclFireDAC;xmlrtl;DataSnapNativeClient;ibxpress;svnui;IndyProtocols;DBXMySQLDriver;FireDACCommonDriver;bindcompdbx;bindengine;vclactnband;FMXTee;soaprtl;TeeUI;bindcompvcl;vclie;FireDACADSDriver;vcltouch;emsclient;VCLRESTComponents;FireDAC;DBXInformixDriver;FireDACMSSQLDriver;Intraweb;VclSmp;DataSnapConnectors;DataSnapServerMidas;DBXFirebirdDriver;dsnapcon;inet;fmxobj;FireDACMySQLDriver;soapmidas;vclx;svn;DBXSybaseASADriver;FireDACOracleDriver;fmxdae;RESTComponents;dbexpress;FireDACMSAccDriver;DataSnapIndy10ServerTransport;IndyIPClient;$(DCC_UsePackage) + 1033 + true + CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= + $(BDS)\bin\default_app.manifest + + + true + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace) + FireDACSqliteDriver;FireDACDSDriver;DBXSqliteDriver;FireDACPgDriver;fmx;IndySystem;TeeDB;tethering;vclib;DBXInterBaseDriver;DataSnapClient;DataSnapCommon;DataSnapServer;DataSnapProviderClient;DBXSybaseASEDriver;DbxCommonDriver;vclimg;dbxcds;DatasnapConnectorsFreePascal;MetropolisUILiveTile;vcldb;vcldsnap;fmxFireDAC;DBXDb2Driver;DBXOracleDriver;CustomIPTransport;vclribbon;dsnap;IndyIPServer;fmxase;vcl;IndyCore;DBXMSSQLDriver;CloudService;IndyIPCommon;FmxTeeUI;FireDACIBDriver;DataSnapFireDAC;FireDACDBXDriver;soapserver;inetdbxpress;dsnapxml;FireDACInfxDriver;FireDACDb2Driver;adortl;FireDACASADriver;bindcompfmx;FireDACODBCDriver;RESTBackendComponents;emsclientfiredac;rtl;dbrtl;DbxClientDriver;FireDACCommon;bindcomp;inetdb;Tee;DBXOdbcDriver;vclFireDAC;xmlrtl;DataSnapNativeClient;ibxpress;IndyProtocols;DBXMySQLDriver;FireDACCommonDriver;bindcompdbx;bindengine;vclactnband;FMXTee;soaprtl;TeeUI;bindcompvcl;vclie;FireDACADSDriver;vcltouch;emsclient;VCLRESTComponents;FireDAC;DBXInformixDriver;FireDACMSSQLDriver;Intraweb;VclSmp;DataSnapConnectors;DataSnapServerMidas;DBXFirebirdDriver;dsnapcon;inet;fmxobj;FireDACMySQLDriver;soapmidas;vclx;DBXSybaseASADriver;FireDACOracleDriver;fmxdae;RESTComponents;dbexpress;FireDACMSAccDriver;DataSnapIndy10ServerTransport;IndyIPClient;$(DCC_UsePackage) + 1033 + true + CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= + $(BDS)\bin\default_app.manifest + + + DEBUG;$(DCC_Define) + true + false + true + true + true + + + false + + + false + RELEASE;$(DCC_Define) + 0 + 0 + + + + MainSource + + +
Main
+ dfm +
+ + + + + Cfg_2 + Base + + + Base + + + Cfg_1 + Base + +
+ + Delphi.Personality.12 + Application + + + + Demo1.dpr + + + + + + Demo1.exe + true + + + + + Demo1.exe + true + + + + + Demo1.rsm + true + + + + + 1 + + + 1 + + + + + Contents\Resources + 1 + + + + + classes + 1 + + + + + res\drawable-xxhdpi + 1 + + + + + Contents\MacOS + 0 + + + 1 + + + Contents\MacOS + 1 + + + + + library\lib\mips + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 0 + + + 1 + + + Contents\MacOS + 1 + + + library\lib\armeabi-v7a + 1 + + + 1 + + + + + 0 + + + Contents\MacOS + 1 + .framework + + + + + 1 + + + 1 + + + 1 + + + + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + library\lib\armeabi + 1 + + + + + 0 + + + 1 + + + Contents\MacOS + 1 + + + + + 1 + + + 1 + + + 1 + + + + + res\drawable-normal + 1 + + + + + res\drawable-xhdpi + 1 + + + + + res\drawable-large + 1 + + + + + 1 + + + 1 + + + 1 + + + + + ..\ + 1 + + + ..\ + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + res\drawable-hdpi + 1 + + + + + Contents + 1 + + + + + ..\ + 1 + + + + + 1 + + + 1 + + + 1 + + + + + res\values + 1 + + + + + res\drawable-small + 1 + + + + + res\drawable + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + + + res\drawable + 1 + + + + + 0 + + + 0 + + + Contents\Resources\StartUp\ + 0 + + + 0 + + + 0 + + + 0 + + + + + library\lib\armeabi-v7a + 1 + + + + + 0 + .bpl + + + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + + + res\drawable-mdpi + 1 + + + + + res\drawable-xlarge + 1 + + + + + res\drawable-ldpi + 1 + + + + + 0 + .dll;.bpl + + + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + + + + + + + + + + + True + True + + + 12 + + + + +
diff --git a/components/detours/Demo/DetoursDemo/Delphi/RTL/Demo1/Demo1.res b/components/detours/Demo/DetoursDemo/Delphi/RTL/Demo1/Demo1.res new file mode 100644 index 00000000..0f3facb9 Binary files /dev/null and b/components/detours/Demo/DetoursDemo/Delphi/RTL/Demo1/Demo1.res differ diff --git a/components/detours/Demo/DetoursDemo/Delphi/RTL/Demo1/uMain.dfm b/components/detours/Demo/DetoursDemo/Delphi/RTL/Demo1/uMain.dfm new file mode 100644 index 00000000..eb63a5c5 --- /dev/null +++ b/components/detours/Demo/DetoursDemo/Delphi/RTL/Demo1/uMain.dfm @@ -0,0 +1,38 @@ +object Main: TMain + Left = 0 + Top = 0 + BorderStyle = bsSizeToolWin + Caption = 'Hooking GetMemory' + ClientHeight = 167 + ClientWidth = 447 + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + OldCreateOrder = False + OnCreate = FormCreate + PixelsPerInch = 96 + TextHeight = 13 + object MemLog: TMemo + Left = 0 + Top = 0 + Width = 447 + Height = 113 + Align = alTop + Lines.Strings = ( + 'MemLog') + ScrollBars = ssVertical + TabOrder = 0 + end + object BtnTest: TButton + Left = 302 + Top = 136 + Width = 137 + Height = 25 + Caption = 'Test' + TabOrder = 1 + OnClick = BtnTestClick + end +end diff --git a/components/detours/Demo/DetoursDemo/Delphi/RTL/Demo1/uMain.pas b/components/detours/Demo/DetoursDemo/Delphi/RTL/Demo1/uMain.pas new file mode 100644 index 00000000..d64d766d --- /dev/null +++ b/components/detours/Demo/DetoursDemo/Delphi/RTL/Demo1/uMain.pas @@ -0,0 +1,93 @@ +unit uMain; + +interface + +uses + Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, + Vcl.Controls, Vcl.Forms, Vcl.Dialogs, DDetours, Vcl.StdCtrls; + +type + TMyForm = class(TForm) + private + class var FInit: Boolean; + class constructor Create; + end; + + TMain = class(TMyForm) + MemLog: TMemo; + BtnTest: TButton; + procedure FormCreate(Sender: TObject); + procedure BtnTestClick(Sender: TObject); + private + + { Private declarations } + public + { Public declarations } + end; + +var + Main: TMain; + +implementation + +{$R *.dfm} + +var + TrampolineGetMemory: function(Size: NativeInt): Pointer; +cdecl = nil; + +var + TrampolineFreeMemory: function(P: Pointer): Integer; +cdecl = nil; + +function GetMemory_Hooked(Size: NativeInt): Pointer; cdecl; +begin + Result := TrampolineGetMemory(Size); + if Main.FInit then + begin + Main.MemLog.Lines.Add(Format('Allocating %d bytes at %p.', [Size, Result])); + end; +end; + +function FreeMemory_Hooked(P: Pointer): Integer; cdecl; +begin + Result := TrampolineFreeMemory(P); + if Main.FInit then + begin + Main.MemLog.Lines.Add(Format('Freeing %p address.', [P])); + end; +end; + +procedure TMain.BtnTestClick(Sender: TObject); +var + P: PByte; +begin + P := GetMemory(16); + FreeMemory(P); + MemLog.Lines.Add('---------------------------------'); +end; + +procedure TMain.FormCreate(Sender: TObject); +begin + FInit := True; + MemLog.Clear; +end; + +{ TMyForm } + +class constructor TMyForm.Create; +begin + FInit := False; +end; + +initialization + +@TrampolineGetMemory := InterceptCreate(@GetMemory, @GetMemory_Hooked); +@TrampolineFreeMemory := InterceptCreate(@FreeMemory, @FreeMemory_Hooked); + +finalization + +InterceptRemove(@TrampolineGetMemory); +InterceptRemove(@TrampolineFreeMemory); + +end. diff --git a/components/detours/Demo/DetoursDemo/MultiHook/Demo1/Demo1.dpr b/components/detours/Demo/DetoursDemo/MultiHook/Demo1/Demo1.dpr new file mode 100644 index 00000000..7c8ff19d --- /dev/null +++ b/components/detours/Demo/DetoursDemo/MultiHook/Demo1/Demo1.dpr @@ -0,0 +1,17 @@ +program Demo1; + +uses + Vcl.Forms, + uMain in 'uMain.pas' {Main}, + CPUID in '..\..\..\..\Source\CPUID.pas', + DDetours in '..\..\..\..\Source\DDetours.pas', + InstDecode in '..\..\..\..\Source\InstDecode.pas'; + +{$R *.res} + +begin + Application.Initialize; + Application.MainFormOnTaskbar := True; + Application.CreateForm(TMain, Main); + Application.Run; +end. diff --git a/components/detours/Demo/DetoursDemo/MultiHook/Demo1/Demo1.dproj b/components/detours/Demo/DetoursDemo/MultiHook/Demo1/Demo1.dproj new file mode 100644 index 00000000..c1bd242b --- /dev/null +++ b/components/detours/Demo/DetoursDemo/MultiHook/Demo1/Demo1.dproj @@ -0,0 +1,521 @@ + + + {8D1CE223-B40B-479A-9234-47F5A8CD29FD} + 18.1 + VCL + Demo1.dpr + True + Debug + Win32 + 1 + Application + + + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Cfg_1 + true + true + + + true + Base + true + + + System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace) + $(BDS)\bin\delphi_PROJECTICON.ico + Demo1 + .\$(Platform)\$(Config) + .\$(Platform)\$(Config) + false + false + false + false + false + + + true + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) + FireDACSqliteDriver;FireDACDSDriver;DBXSqliteDriver;FireDACPgDriver;fmx;IndySystem;TeeDB;tethering;vclib;DBXInterBaseDriver;DataSnapClient;DataSnapCommon;DataSnapServer;DataSnapProviderClient;DBXSybaseASEDriver;DbxCommonDriver;vclimg;dbxcds;DatasnapConnectorsFreePascal;MetropolisUILiveTile;vcldb;vcldsnap;fmxFireDAC;DBXDb2Driver;DBXOracleDriver;CustomIPTransport;vclribbon;dsnap;IndyIPServer;fmxase;vcl;IndyCore;DBXMSSQLDriver;CloudService;IndyIPCommon;FmxTeeUI;FireDACIBDriver;DataSnapFireDAC;FireDACDBXDriver;soapserver;inetdbxpress;dsnapxml;FireDACInfxDriver;FireDACDb2Driver;adortl;FireDACASADriver;bindcompfmx;FireDACODBCDriver;RESTBackendComponents;emsclientfiredac;rtl;dbrtl;DbxClientDriver;FireDACCommon;bindcomp;inetdb;Tee;DBXOdbcDriver;vclFireDAC;xmlrtl;DataSnapNativeClient;ibxpress;svnui;IndyProtocols;DBXMySQLDriver;FireDACCommonDriver;bindcompdbx;bindengine;vclactnband;FMXTee;soaprtl;TeeUI;bindcompvcl;vclie;FireDACADSDriver;vcltouch;emsclient;VCLRESTComponents;FireDAC;DBXInformixDriver;FireDACMSSQLDriver;Intraweb;VclSmp;DataSnapConnectors;DataSnapServerMidas;DBXFirebirdDriver;dsnapcon;inet;fmxobj;FireDACMySQLDriver;soapmidas;vclx;svn;DBXSybaseASADriver;FireDACOracleDriver;fmxdae;RESTComponents;dbexpress;FireDACMSAccDriver;DataSnapIndy10ServerTransport;IndyIPClient;$(DCC_UsePackage) + 1033 + true + CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= + $(BDS)\bin\default_app.manifest + + + FireDACSqliteDriver;FireDACDSDriver;DBXSqliteDriver;FireDACPgDriver;fmx;IndySystem;TeeDB;tethering;vclib;DBXInterBaseDriver;DataSnapClient;DataSnapCommon;DataSnapServer;DataSnapProviderClient;DBXSybaseASEDriver;DbxCommonDriver;vclimg;dbxcds;DatasnapConnectorsFreePascal;MetropolisUILiveTile;vcldb;vcldsnap;fmxFireDAC;DBXDb2Driver;DBXOracleDriver;CustomIPTransport;vclribbon;dsnap;IndyIPServer;fmxase;vcl;IndyCore;DBXMSSQLDriver;CloudService;IndyIPCommon;FmxTeeUI;FireDACIBDriver;DataSnapFireDAC;FireDACDBXDriver;soapserver;inetdbxpress;dsnapxml;FireDACInfxDriver;FireDACDb2Driver;adortl;FireDACASADriver;bindcompfmx;FireDACODBCDriver;RESTBackendComponents;emsclientfiredac;rtl;dbrtl;DbxClientDriver;FireDACCommon;bindcomp;inetdb;Tee;DBXOdbcDriver;vclFireDAC;xmlrtl;DataSnapNativeClient;ibxpress;IndyProtocols;DBXMySQLDriver;FireDACCommonDriver;bindcompdbx;bindengine;vclactnband;FMXTee;soaprtl;TeeUI;bindcompvcl;vclie;FireDACADSDriver;vcltouch;emsclient;VCLRESTComponents;FireDAC;DBXInformixDriver;FireDACMSSQLDriver;Intraweb;VclSmp;DataSnapConnectors;DataSnapServerMidas;DBXFirebirdDriver;dsnapcon;inet;fmxobj;FireDACMySQLDriver;soapmidas;vclx;DBXSybaseASADriver;FireDACOracleDriver;fmxdae;RESTComponents;dbexpress;FireDACMSAccDriver;DataSnapIndy10ServerTransport;IndyIPClient;$(DCC_UsePackage) + + + DEBUG;$(DCC_Define) + true + false + true + true + true + + + false + + + false + RELEASE;$(DCC_Define) + 0 + 0 + + + + MainSource + + +
Main
+ dfm +
+ + + + + Cfg_2 + Base + + + Base + + + Cfg_1 + Base + +
+ + Delphi.Personality.12 + Application + + + + Demo1.dpr + + + + + + Demo1.exe + true + + + + + 1 + + + 1 + + + + + Contents\Resources + 1 + + + + + classes + 1 + + + + + res\drawable-xxhdpi + 1 + + + + + Contents\MacOS + 0 + + + 1 + + + Contents\MacOS + 1 + + + + + library\lib\mips + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 0 + + + 1 + + + Contents\MacOS + 1 + + + library\lib\armeabi-v7a + 1 + + + 1 + + + + + 0 + + + Contents\MacOS + 1 + .framework + + + + + 1 + + + 1 + + + 1 + + + + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + library\lib\armeabi + 1 + + + + + 0 + + + 1 + + + Contents\MacOS + 1 + + + + + 1 + + + 1 + + + 1 + + + + + res\drawable-normal + 1 + + + + + res\drawable-xhdpi + 1 + + + + + res\drawable-large + 1 + + + + + 1 + + + 1 + + + 1 + + + + + ..\ + 1 + + + ..\ + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + res\drawable-hdpi + 1 + + + + + Contents + 1 + + + + + ..\ + 1 + + + + + 1 + + + 1 + + + 1 + + + + + res\values + 1 + + + + + res\drawable-small + 1 + + + + + res\drawable + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + + + res\drawable + 1 + + + + + 0 + + + 0 + + + Contents\Resources\StartUp\ + 0 + + + 0 + + + 0 + + + 0 + + + + + library\lib\armeabi-v7a + 1 + + + + + 0 + .bpl + + + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + + + res\drawable-mdpi + 1 + + + + + res\drawable-xlarge + 1 + + + + + res\drawable-ldpi + 1 + + + + + 0 + .dll;.bpl + + + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + + + + + + + + + + + True + False + + + 12 + + + + +
diff --git a/components/detours/Demo/DetoursDemo/MultiHook/Demo1/uMain.dfm b/components/detours/Demo/DetoursDemo/MultiHook/Demo1/uMain.dfm new file mode 100644 index 00000000..06b7b7b8 --- /dev/null +++ b/components/detours/Demo/DetoursDemo/MultiHook/Demo1/uMain.dfm @@ -0,0 +1,91 @@ +object Main: TMain + Left = 0 + Top = 0 + Caption = 'Main' + ClientHeight = 264 + ClientWidth = 447 + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + OldCreateOrder = False + OnCreate = FormCreate + PixelsPerInch = 96 + TextHeight = 13 + object MemLog: TMemo + Left = 0 + Top = 0 + Width = 447 + Height = 89 + Align = alTop + Lines.Strings = ( + 'MemLog') + ScrollBars = ssVertical + TabOrder = 0 + end + object BtnEnableHook1: TButton + Left = 292 + Top = 120 + Width = 147 + Height = 25 + Caption = 'Enable Hook1' + TabOrder = 1 + OnClick = BtnEnableHook1Click + end + object BtnEnableHook2: TButton + Left = 292 + Top = 151 + Width = 147 + Height = 25 + Caption = 'Enable Hook2' + TabOrder = 2 + OnClick = BtnEnableHook2Click + end + object BtnEnableHook3: TButton + Left = 292 + Top = 182 + Width = 147 + Height = 25 + Caption = 'Enable Hook3' + TabOrder = 3 + OnClick = BtnEnableHook3Click + end + object BtnRemoveHook1: TButton + Left = 28 + Top = 120 + Width = 147 + Height = 25 + Caption = 'Remove Hook1' + TabOrder = 4 + OnClick = BtnRemoveHook1Click + end + object BtnRemoveHook2: TButton + Left = 28 + Top = 151 + Width = 147 + Height = 25 + Caption = 'Remove Hook2' + TabOrder = 5 + OnClick = BtnRemoveHook2Click + end + object BtnRemoveHook3: TButton + Left = 28 + Top = 182 + Width = 147 + Height = 25 + Caption = 'Remove Hook3' + TabOrder = 6 + OnClick = BtnRemoveHook3Click + end + object BtnTest: TButton + Left = 292 + Top = 231 + Width = 147 + Height = 25 + Caption = 'Test' + TabOrder = 7 + OnClick = BtnTestClick + end +end diff --git a/components/detours/Demo/DetoursDemo/MultiHook/Demo1/uMain.pas b/components/detours/Demo/DetoursDemo/MultiHook/Demo1/uMain.pas new file mode 100644 index 00000000..b21a3c7d --- /dev/null +++ b/components/detours/Demo/DetoursDemo/MultiHook/Demo1/uMain.pas @@ -0,0 +1,122 @@ +unit uMain; + +interface + +uses + Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, + Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, DDetours; + +type + TMain = class(TForm) + MemLog: TMemo; + BtnEnableHook1: TButton; + BtnEnableHook2: TButton; + BtnEnableHook3: TButton; + BtnRemoveHook1: TButton; + BtnRemoveHook2: TButton; + BtnRemoveHook3: TButton; + BtnTest: TButton; + procedure BtnEnableHook1Click(Sender: TObject); + procedure BtnEnableHook2Click(Sender: TObject); + procedure BtnEnableHook3Click(Sender: TObject); + procedure BtnRemoveHook1Click(Sender: TObject); + procedure BtnRemoveHook2Click(Sender: TObject); + procedure BtnRemoveHook3Click(Sender: TObject); + procedure BtnTestClick(Sender: TObject); + procedure FormCreate(Sender: TObject); + private + { Private declarations } + public + { Public declarations } + end; + +var + Main: TMain; + +implementation + +{$R *.dfm} + +type + TMsgBoxNextHookProc = function(hWnd: hWnd; lpText, lpCaption: LPCWSTR; uType: UINT): Integer; stdcall; + +var + NextHook1: TMsgBoxNextHookProc = nil; + NextHook2: TMsgBoxNextHookProc = nil; + NextHook3: TMsgBoxNextHookProc = nil; + +function MessageBox_Hook1(hWnd: hWnd; lpText, lpCaption: LPCWSTR; uType: UINT): Integer; stdcall; +begin + Main.MemLog.Lines.Add('Hook 1 executed successfully.'); + Result := NextHook1(hWnd, 'Hook1', lpCaption, uType); +end; + +function MessageBox_Hook2(hWnd: hWnd; lpText, lpCaption: LPCWSTR; uType: UINT): Integer; stdcall; +begin + Main.MemLog.Lines.Add('Hook 2 executed successfully.'); + Result := NextHook2(hWnd, lpText, 'Hook2', uType); +end; + +function MessageBox_Hook3(hWnd: hWnd; lpText, lpCaption: LPCWSTR; uType: UINT): Integer; stdcall; +begin + Main.MemLog.Lines.Add('Hook 3 executed successfully.'); + Result := NextHook3(hWnd, lpText, lpText, uType); +end; + +procedure TMain.BtnEnableHook1Click(Sender: TObject); +begin + if not Assigned(NextHook1) then + @NextHook1 := InterceptCreate(@MessageBox, @MessageBox_Hook1); +end; + +procedure TMain.BtnEnableHook2Click(Sender: TObject); +begin + if not Assigned(NextHook2) then + @NextHook2 := InterceptCreate(@MessageBox, @MessageBox_Hook2); +end; + +procedure TMain.BtnEnableHook3Click(Sender: TObject); +begin + if not Assigned(NextHook3) then + @NextHook3 := InterceptCreate(@MessageBox, @MessageBox_Hook3); +end; + +procedure TMain.BtnRemoveHook1Click(Sender: TObject); +begin + if Assigned(NextHook1) then + begin + InterceptRemove(@NextHook1); + NextHook1 := nil; + end; +end; + +procedure TMain.BtnRemoveHook2Click(Sender: TObject); +begin + if Assigned(NextHook2) then + begin + InterceptRemove(@NextHook2); + NextHook2 := nil; + end; +end; + +procedure TMain.BtnRemoveHook3Click(Sender: TObject); +begin + if Assigned(NextHook3) then + begin + InterceptRemove(@NextHook3); + NextHook3 := nil; + end; +end; + +procedure TMain.BtnTestClick(Sender: TObject); +begin + MemLog.Lines.Add('----------------------------'); + MessageBox(Handle, 'Msg Text', 'Msg Caption', MB_OK); +end; + +procedure TMain.FormCreate(Sender: TObject); +begin + MemLog.Clear; +end; + +end. diff --git a/components/detours/Demo/DetoursDemo/win32api/Demo1/Demo1.dpr b/components/detours/Demo/DetoursDemo/win32api/Demo1/Demo1.dpr new file mode 100644 index 00000000..7c8ff19d --- /dev/null +++ b/components/detours/Demo/DetoursDemo/win32api/Demo1/Demo1.dpr @@ -0,0 +1,17 @@ +program Demo1; + +uses + Vcl.Forms, + uMain in 'uMain.pas' {Main}, + CPUID in '..\..\..\..\Source\CPUID.pas', + DDetours in '..\..\..\..\Source\DDetours.pas', + InstDecode in '..\..\..\..\Source\InstDecode.pas'; + +{$R *.res} + +begin + Application.Initialize; + Application.MainFormOnTaskbar := True; + Application.CreateForm(TMain, Main); + Application.Run; +end. diff --git a/components/detours/Demo/DetoursDemo/win32api/Demo1/Demo1.dproj b/components/detours/Demo/DetoursDemo/win32api/Demo1/Demo1.dproj new file mode 100644 index 00000000..913d98cc --- /dev/null +++ b/components/detours/Demo/DetoursDemo/win32api/Demo1/Demo1.dproj @@ -0,0 +1,521 @@ + + + {94A98E21-0A68-459A-87DB-F12416300062} + 18.1 + VCL + Demo1.dpr + True + Debug + Win32 + 1 + Application + + + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Cfg_1 + true + true + + + true + Base + true + + + System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace) + $(BDS)\bin\delphi_PROJECTICON.ico + Demo1 + .\$(Platform)\$(Config) + .\$(Platform)\$(Config) + false + false + false + false + false + + + true + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) + FireDACSqliteDriver;FireDACDSDriver;DBXSqliteDriver;FireDACPgDriver;fmx;IndySystem;TeeDB;tethering;vclib;DBXInterBaseDriver;DataSnapClient;DataSnapCommon;DataSnapServer;DataSnapProviderClient;DBXSybaseASEDriver;DbxCommonDriver;vclimg;dbxcds;DatasnapConnectorsFreePascal;MetropolisUILiveTile;vcldb;vcldsnap;fmxFireDAC;DBXDb2Driver;DBXOracleDriver;CustomIPTransport;vclribbon;dsnap;IndyIPServer;fmxase;vcl;IndyCore;DBXMSSQLDriver;CloudService;IndyIPCommon;FmxTeeUI;FireDACIBDriver;DataSnapFireDAC;FireDACDBXDriver;soapserver;inetdbxpress;dsnapxml;FireDACInfxDriver;FireDACDb2Driver;adortl;FireDACASADriver;bindcompfmx;FireDACODBCDriver;RESTBackendComponents;emsclientfiredac;rtl;dbrtl;DbxClientDriver;FireDACCommon;bindcomp;inetdb;Tee;DBXOdbcDriver;vclFireDAC;xmlrtl;DataSnapNativeClient;ibxpress;svnui;IndyProtocols;DBXMySQLDriver;FireDACCommonDriver;bindcompdbx;bindengine;vclactnband;FMXTee;soaprtl;TeeUI;bindcompvcl;vclie;FireDACADSDriver;vcltouch;emsclient;VCLRESTComponents;FireDAC;DBXInformixDriver;FireDACMSSQLDriver;Intraweb;VclSmp;DataSnapConnectors;DataSnapServerMidas;DBXFirebirdDriver;dsnapcon;inet;fmxobj;FireDACMySQLDriver;soapmidas;vclx;svn;DBXSybaseASADriver;FireDACOracleDriver;fmxdae;RESTComponents;dbexpress;FireDACMSAccDriver;DataSnapIndy10ServerTransport;IndyIPClient;$(DCC_UsePackage) + 1033 + true + CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= + $(BDS)\bin\default_app.manifest + + + FireDACSqliteDriver;FireDACDSDriver;DBXSqliteDriver;FireDACPgDriver;fmx;IndySystem;TeeDB;tethering;vclib;DBXInterBaseDriver;DataSnapClient;DataSnapCommon;DataSnapServer;DataSnapProviderClient;DBXSybaseASEDriver;DbxCommonDriver;vclimg;dbxcds;DatasnapConnectorsFreePascal;MetropolisUILiveTile;vcldb;vcldsnap;fmxFireDAC;DBXDb2Driver;DBXOracleDriver;CustomIPTransport;vclribbon;dsnap;IndyIPServer;fmxase;vcl;IndyCore;DBXMSSQLDriver;CloudService;IndyIPCommon;FmxTeeUI;FireDACIBDriver;DataSnapFireDAC;FireDACDBXDriver;soapserver;inetdbxpress;dsnapxml;FireDACInfxDriver;FireDACDb2Driver;adortl;FireDACASADriver;bindcompfmx;FireDACODBCDriver;RESTBackendComponents;emsclientfiredac;rtl;dbrtl;DbxClientDriver;FireDACCommon;bindcomp;inetdb;Tee;DBXOdbcDriver;vclFireDAC;xmlrtl;DataSnapNativeClient;ibxpress;IndyProtocols;DBXMySQLDriver;FireDACCommonDriver;bindcompdbx;bindengine;vclactnband;FMXTee;soaprtl;TeeUI;bindcompvcl;vclie;FireDACADSDriver;vcltouch;emsclient;VCLRESTComponents;FireDAC;DBXInformixDriver;FireDACMSSQLDriver;Intraweb;VclSmp;DataSnapConnectors;DataSnapServerMidas;DBXFirebirdDriver;dsnapcon;inet;fmxobj;FireDACMySQLDriver;soapmidas;vclx;DBXSybaseASADriver;FireDACOracleDriver;fmxdae;RESTComponents;dbexpress;FireDACMSAccDriver;DataSnapIndy10ServerTransport;IndyIPClient;$(DCC_UsePackage) + + + DEBUG;$(DCC_Define) + true + false + true + true + true + + + false + + + false + RELEASE;$(DCC_Define) + 0 + 0 + + + + MainSource + + +
Main
+ dfm +
+ + + + + Cfg_2 + Base + + + Base + + + Cfg_1 + Base + +
+ + Delphi.Personality.12 + Application + + + + Demo1.dpr + + + + + + Demo1.exe + true + + + + + 1 + + + 1 + + + + + Contents\Resources + 1 + + + + + classes + 1 + + + + + res\drawable-xxhdpi + 1 + + + + + Contents\MacOS + 0 + + + 1 + + + Contents\MacOS + 1 + + + + + library\lib\mips + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 0 + + + 1 + + + Contents\MacOS + 1 + + + library\lib\armeabi-v7a + 1 + + + 1 + + + + + 0 + + + Contents\MacOS + 1 + .framework + + + + + 1 + + + 1 + + + 1 + + + + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + library\lib\armeabi + 1 + + + + + 0 + + + 1 + + + Contents\MacOS + 1 + + + + + 1 + + + 1 + + + 1 + + + + + res\drawable-normal + 1 + + + + + res\drawable-xhdpi + 1 + + + + + res\drawable-large + 1 + + + + + 1 + + + 1 + + + 1 + + + + + ..\ + 1 + + + ..\ + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + res\drawable-hdpi + 1 + + + + + Contents + 1 + + + + + ..\ + 1 + + + + + 1 + + + 1 + + + 1 + + + + + res\values + 1 + + + + + res\drawable-small + 1 + + + + + res\drawable + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + + + res\drawable + 1 + + + + + 0 + + + 0 + + + Contents\Resources\StartUp\ + 0 + + + 0 + + + 0 + + + 0 + + + + + library\lib\armeabi-v7a + 1 + + + + + 0 + .bpl + + + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + + + res\drawable-mdpi + 1 + + + + + res\drawable-xlarge + 1 + + + + + res\drawable-ldpi + 1 + + + + + 0 + .dll;.bpl + + + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + + + + + + + + + + + True + False + + + 12 + + + + +
diff --git a/components/detours/Demo/DetoursDemo/win32api/Demo1/uMain.dfm b/components/detours/Demo/DetoursDemo/win32api/Demo1/uMain.dfm new file mode 100644 index 00000000..87fb2f8b --- /dev/null +++ b/components/detours/Demo/DetoursDemo/win32api/Demo1/uMain.dfm @@ -0,0 +1,44 @@ +object Main: TMain + Left = 0 + Top = 0 + BorderStyle = bsSizeToolWin + Caption = 'Hooking MessageBox' + ClientHeight = 133 + ClientWidth = 188 + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + OldCreateOrder = False + PixelsPerInch = 96 + TextHeight = 13 + object BtnHook: TButton + Left = 16 + Top = 24 + Width = 153 + Height = 25 + Caption = 'Hook MessageBox' + TabOrder = 0 + OnClick = BtnHookClick + end + object BtnUnHook: TButton + Left = 16 + Top = 88 + Width = 153 + Height = 25 + Caption = 'UnHook MessageBox' + TabOrder = 1 + OnClick = BtnUnHookClick + end + object BtnTestMsgBox: TButton + Left = 16 + Top = 57 + Width = 153 + Height = 25 + Caption = 'Call MessageBox' + TabOrder = 2 + OnClick = BtnTestMsgBoxClick + end +end diff --git a/components/detours/Demo/DetoursDemo/win32api/Demo1/uMain.pas b/components/detours/Demo/DetoursDemo/win32api/Demo1/uMain.pas new file mode 100644 index 00000000..afe843af --- /dev/null +++ b/components/detours/Demo/DetoursDemo/win32api/Demo1/uMain.pas @@ -0,0 +1,61 @@ +unit uMain; + +interface + +uses + Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, + Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, DDetours; + +type + TMain = class(TForm) + BtnHook: TButton; + BtnUnHook: TButton; + BtnTestMsgBox: TButton; + procedure BtnHookClick(Sender: TObject); + procedure BtnUnHookClick(Sender: TObject); + procedure BtnTestMsgBoxClick(Sender: TObject); + private + { Private declarations } + public + { Public declarations } + end; + +var + Main: TMain; + +implementation + +{$R *.dfm} + +var + TrampolineMessageBoxW: function(hWnd: hWnd; lpText, lpCaption: LPCWSTR; uType: UINT): Integer; +stdcall = nil; + +function InterceptMessageBoxW(hWnd: hWnd; lpText, lpCaption: LPCWSTR; uType: UINT): Integer; stdcall; +begin + Result := TrampolineMessageBoxW(hWnd, 'Hooked', 'Hooked', MB_OK or MB_ICONEXCLAMATION); +end; + +procedure TMain.BtnHookClick(Sender: TObject); +begin + if not Assigned(TrampolineMessageBoxW) then + begin + @TrampolineMessageBoxW := InterceptCreate(@MessageBoxW, @InterceptMessageBoxW); + end; +end; + +procedure TMain.BtnTestMsgBoxClick(Sender: TObject); +begin + MessageBoxW(Handle, 'Text', 'Caption', MB_OK); +end; + +procedure TMain.BtnUnHookClick(Sender: TObject); +begin + if Assigned(TrampolineMessageBoxW) then + begin + InterceptRemove(@TrampolineMessageBoxW); + TrampolineMessageBoxW := nil; + end; +end; + +end. diff --git a/components/detours/Demo/DetoursDemo/win32api/Demo2/Demo2.dpr b/components/detours/Demo/DetoursDemo/win32api/Demo2/Demo2.dpr new file mode 100644 index 00000000..057f914c --- /dev/null +++ b/components/detours/Demo/DetoursDemo/win32api/Demo2/Demo2.dpr @@ -0,0 +1,18 @@ +// JCL_DEBUG_EXPERT_GENERATEJDBG OFF +program Demo2; + +uses + Vcl.Forms, + uMain in 'uMain.pas' {Main}, + CPUID in '..\..\..\..\Source\CPUID.pas', + DDetours in '..\..\..\..\Source\DDetours.pas', + InstDecode in '..\..\..\..\Source\InstDecode.pas'; + +{$R *.res} + +begin + Application.Initialize; + Application.MainFormOnTaskbar := True; + Application.CreateForm(TMain, Main); + Application.Run; +end. diff --git a/components/detours/Demo/DetoursDemo/win32api/Demo2/Demo2.dproj b/components/detours/Demo/DetoursDemo/win32api/Demo2/Demo2.dproj new file mode 100644 index 00000000..ada8d102 --- /dev/null +++ b/components/detours/Demo/DetoursDemo/win32api/Demo2/Demo2.dproj @@ -0,0 +1,521 @@ + + + {D20E30CF-BD39-428A-9E72-F6745BF708E6} + 18.1 + VCL + Demo2.dpr + True + Debug + Win32 + 1 + Application + + + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Cfg_1 + true + true + + + true + Base + true + + + System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace) + Demo2 + $(BDS)\bin\delphi_PROJECTICON.ico + .\$(Platform)\$(Config) + .\$(Platform)\$(Config) + false + false + false + false + false + + + true + FireDACSqliteDriver;FireDACDSDriver;DBXSqliteDriver;FireDACPgDriver;fmx;IndySystem;TeeDB;tethering;vclib;DBXInterBaseDriver;DataSnapClient;DataSnapCommon;DataSnapServer;DataSnapProviderClient;DBXSybaseASEDriver;DbxCommonDriver;vclimg;dbxcds;DatasnapConnectorsFreePascal;MetropolisUILiveTile;vcldb;vcldsnap;fmxFireDAC;DBXDb2Driver;DBXOracleDriver;CustomIPTransport;vclribbon;dsnap;IndyIPServer;fmxase;vcl;IndyCore;DBXMSSQLDriver;CloudService;IndyIPCommon;FmxTeeUI;FireDACIBDriver;DataSnapFireDAC;FireDACDBXDriver;soapserver;inetdbxpress;dsnapxml;FireDACInfxDriver;FireDACDb2Driver;adortl;FireDACASADriver;bindcompfmx;FireDACODBCDriver;RESTBackendComponents;emsclientfiredac;rtl;dbrtl;DbxClientDriver;FireDACCommon;bindcomp;inetdb;Tee;DBXOdbcDriver;vclFireDAC;xmlrtl;DataSnapNativeClient;ibxpress;svnui;IndyProtocols;DBXMySQLDriver;FireDACCommonDriver;bindcompdbx;bindengine;vclactnband;FMXTee;soaprtl;TeeUI;bindcompvcl;vclie;FireDACADSDriver;vcltouch;emsclient;VCLRESTComponents;FireDAC;DBXInformixDriver;FireDACMSSQLDriver;Intraweb;VclSmp;DataSnapConnectors;DataSnapServerMidas;DBXFirebirdDriver;dsnapcon;inet;fmxobj;FireDACMySQLDriver;soapmidas;vclx;svn;DBXSybaseASADriver;FireDACOracleDriver;fmxdae;RESTComponents;dbexpress;FireDACMSAccDriver;DataSnapIndy10ServerTransport;IndyIPClient;$(DCC_UsePackage) + 1033 + true + CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= + $(BDS)\bin\default_app.manifest + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) + + + FireDACSqliteDriver;FireDACDSDriver;DBXSqliteDriver;FireDACPgDriver;fmx;IndySystem;TeeDB;tethering;vclib;DBXInterBaseDriver;DataSnapClient;DataSnapCommon;DataSnapServer;DataSnapProviderClient;DBXSybaseASEDriver;DbxCommonDriver;vclimg;dbxcds;DatasnapConnectorsFreePascal;MetropolisUILiveTile;vcldb;vcldsnap;fmxFireDAC;DBXDb2Driver;DBXOracleDriver;CustomIPTransport;vclribbon;dsnap;IndyIPServer;fmxase;vcl;IndyCore;DBXMSSQLDriver;CloudService;IndyIPCommon;FmxTeeUI;FireDACIBDriver;DataSnapFireDAC;FireDACDBXDriver;soapserver;inetdbxpress;dsnapxml;FireDACInfxDriver;FireDACDb2Driver;adortl;FireDACASADriver;bindcompfmx;FireDACODBCDriver;RESTBackendComponents;emsclientfiredac;rtl;dbrtl;DbxClientDriver;FireDACCommon;bindcomp;inetdb;Tee;DBXOdbcDriver;vclFireDAC;xmlrtl;DataSnapNativeClient;ibxpress;IndyProtocols;DBXMySQLDriver;FireDACCommonDriver;bindcompdbx;bindengine;vclactnband;FMXTee;soaprtl;TeeUI;bindcompvcl;vclie;FireDACADSDriver;vcltouch;emsclient;VCLRESTComponents;FireDAC;DBXInformixDriver;FireDACMSSQLDriver;Intraweb;VclSmp;DataSnapConnectors;DataSnapServerMidas;DBXFirebirdDriver;dsnapcon;inet;fmxobj;FireDACMySQLDriver;soapmidas;vclx;DBXSybaseASADriver;FireDACOracleDriver;fmxdae;RESTComponents;dbexpress;FireDACMSAccDriver;DataSnapIndy10ServerTransport;IndyIPClient;$(DCC_UsePackage) + + + DEBUG;$(DCC_Define) + true + false + true + true + true + + + false + + + false + RELEASE;$(DCC_Define) + 0 + 0 + + + + MainSource + + +
Main
+ dfm +
+ + + + + Cfg_2 + Base + + + Base + + + Cfg_1 + Base + +
+ + Delphi.Personality.12 + Application + + + + Demo2.dpr + + + + + + Demo2.exe + true + + + + + 1 + + + 1 + + + + + Contents\Resources + 1 + + + + + classes + 1 + + + + + res\drawable-xxhdpi + 1 + + + + + Contents\MacOS + 0 + + + 1 + + + Contents\MacOS + 1 + + + + + library\lib\mips + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 0 + + + 1 + + + Contents\MacOS + 1 + + + library\lib\armeabi-v7a + 1 + + + 1 + + + + + 0 + + + Contents\MacOS + 1 + .framework + + + + + 1 + + + 1 + + + 1 + + + + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + library\lib\armeabi + 1 + + + + + 0 + + + 1 + + + Contents\MacOS + 1 + + + + + 1 + + + 1 + + + 1 + + + + + res\drawable-normal + 1 + + + + + res\drawable-xhdpi + 1 + + + + + res\drawable-large + 1 + + + + + 1 + + + 1 + + + 1 + + + + + ..\ + 1 + + + ..\ + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + res\drawable-hdpi + 1 + + + + + Contents + 1 + + + + + ..\ + 1 + + + + + 1 + + + 1 + + + 1 + + + + + res\values + 1 + + + + + res\drawable-small + 1 + + + + + res\drawable + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + + + res\drawable + 1 + + + + + 0 + + + 0 + + + Contents\Resources\StartUp\ + 0 + + + 0 + + + 0 + + + 0 + + + + + library\lib\armeabi-v7a + 1 + + + + + 0 + .bpl + + + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + + + res\drawable-mdpi + 1 + + + + + res\drawable-xlarge + 1 + + + + + res\drawable-ldpi + 1 + + + + + 0 + .dll;.bpl + + + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + + + + + + + + + + + True + False + + + 12 + + + + +
diff --git a/components/detours/Demo/DetoursDemo/win32api/Demo2/uMain.dfm b/components/detours/Demo/DetoursDemo/win32api/Demo2/uMain.dfm new file mode 100644 index 00000000..17a0c0b5 --- /dev/null +++ b/components/detours/Demo/DetoursDemo/win32api/Demo2/uMain.dfm @@ -0,0 +1,61 @@ +object Main: TMain + Left = 0 + Top = 0 + BorderStyle = bsSizeToolWin + Caption = 'Hooking GetSysColor function' + ClientHeight = 234 + ClientWidth = 219 + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + OldCreateOrder = False + OnCreate = FormCreate + PixelsPerInch = 96 + TextHeight = 13 + object Label1: TLabel + Left = 16 + Top = 141 + Width = 31 + Height = 13 + Caption = 'Label1' + end + object Memo1: TMemo + Left = 16 + Top = 40 + Width = 185 + Height = 89 + Lines.Strings = ( + 'Select me before hooking , and ' + 'reselect me after hooking !') + TabOrder = 0 + end + object Edit1: TEdit + Left = 16 + Top = 13 + Width = 185 + Height = 21 + TabOrder = 1 + Text = 'Select Me..' + end + object BtnEnableHook: TButton + Left = 16 + Top = 169 + Width = 185 + Height = 25 + Caption = 'Enable Hook' + TabOrder = 2 + OnClick = BtnEnableHookClick + end + object BtnDisableHook: TButton + Left = 16 + Top = 200 + Width = 185 + Height = 25 + Caption = 'Disable Hook' + TabOrder = 3 + OnClick = BtnDisableHookClick + end +end diff --git a/components/detours/Demo/DetoursDemo/win32api/Demo2/uMain.pas b/components/detours/Demo/DetoursDemo/win32api/Demo2/uMain.pas new file mode 100644 index 00000000..08577913 --- /dev/null +++ b/components/detours/Demo/DetoursDemo/win32api/Demo2/uMain.pas @@ -0,0 +1,65 @@ +unit uMain; + +interface + +uses + Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, + Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, DDetours; + +type + TMain = class(TForm) + Memo1: TMemo; + Edit1: TEdit; + BtnEnableHook: TButton; + BtnDisableHook: TButton; + Label1: TLabel; + procedure BtnEnableHookClick(Sender: TObject); + procedure BtnDisableHookClick(Sender: TObject); + procedure FormCreate(Sender: TObject); + private + { Private declarations } + public + { Public declarations } + end; + +var + Main: TMain; + +implementation + +{$R *.dfm} + +var + TrampolineGetSysColor: function(nIndex: Integer): DWORD; +stdcall = nil; + +function InterceptGetSysColor(nIndex: Integer): DWORD; stdcall; +begin + if nIndex = COLOR_HIGHLIGHT then + Result := clWebOrange + else + Result := TrampolineGetSysColor(nIndex); +end; + +procedure TMain.BtnEnableHookClick(Sender: TObject); +begin + @TrampolineGetSysColor := InterceptCreate(@GetSysColor, @InterceptGetSysColor); + Label1.Caption := 'GetSysColor is hooked.'; +end; + +procedure TMain.FormCreate(Sender: TObject); +begin + Label1.Caption := 'GetSysColor not hooked.'; +end; + +procedure TMain.BtnDisableHookClick(Sender: TObject); +begin + if Assigned(TrampolineGetSysColor) then + begin + InterceptRemove(@TrampolineGetSysColor); + TrampolineGetSysColor := nil; + Label1.Caption := 'GetSysColor not hooked.'; + end; +end; + +end. diff --git a/components/detours/Demo/InstDecodeDemo/Demo1/Demo1.dpr b/components/detours/Demo/InstDecodeDemo/Demo1/Demo1.dpr new file mode 100644 index 00000000..f6a418d9 --- /dev/null +++ b/components/detours/Demo/InstDecodeDemo/Demo1/Demo1.dpr @@ -0,0 +1,57 @@ +// JCL_DEBUG_EXPERT_GENERATEJDBG OFF +program Demo1; + +{$APPTYPE CONSOLE} +{$R *.res} + +uses + System.SysUtils, + InstDecode in '..\..\..\Source\InstDecode.pas'; + +procedure Foo; +asm + {$IFDEF CPUX64} + PUSH RAX + XOR EAX,EAX + MOV EAX,5 + ADD EAX,EDX + POP RAX + NOP + NOP + NOP + MOV RAX,1 + {$ELSE !CPUX64} + PUSH EAX + XOR EAX,EAX + MOV EAX,5 + ADD EAX,EDX + POP EAX + NOP + NOP + NOP + MOV EAX,1 + {$ENDIF CPUX64} +end; + +var + Inst: TInstruction; + nInst: Integer; + +begin + // Foo; + Inst := Default (TInstruction); + Inst.Archi := CPUX; + Inst.NextInst := @Foo; + nInst := 0; + while (Inst.OpType <> otRET) do + begin + inc(nInst); + Inst.Addr := Inst.NextInst; + DecodeInst(@Inst); + Writeln(Format('OpCode : 0x%.2x | Length : %d', [Inst.OpCode, Inst.InstSize])); + end; + Writeln('-------------------------------'); + Writeln(Format('Total instructions : %d', [nInst])); + ReadLn; + +end. diff --git a/components/detours/Demo/InstDecodeDemo/Demo1/Demo1.dproj b/components/detours/Demo/InstDecodeDemo/Demo1/Demo1.dproj new file mode 100644 index 00000000..df00068d --- /dev/null +++ b/components/detours/Demo/InstDecodeDemo/Demo1/Demo1.dproj @@ -0,0 +1,623 @@ + + + {6D1CA670-4437-4814-9FD1-01AC3CE12603} + 18.1 + None + Demo1.dpr + True + Debug + Win32 + 1 + Console + + + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Cfg_1 + true + true + + + true + Base + true + + + $(BDS)\bin\delphi_PROJECTICON.ico + $(BDS)\bin\delphi_PROJECTICNS.icns + Demo1 + System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace) + .\$(Platform)\$(Config) + .\$(Platform)\$(Config) + false + false + false + false + false + + + $(BDS)\bin\Artwork\Android\FM_LauncherIcon_144x144.png + true + true + $(BDS)\bin\Artwork\Android\FM_SplashImage_470x320.png + true + true + $(BDS)\bin\Artwork\Android\FM_SplashImage_960x720.png + true + $(BDS)\bin\Artwork\Android\FM_LauncherIcon_96x96.png + true + true + $(BDS)\bin\Artwork\Android\FM_SplashImage_640x480.png + $(BDS)\bin\Artwork\Android\FM_LauncherIcon_72x72.png + $(BDS)\bin\Artwork\Android\FM_LauncherIcon_48x48.png + $(BDS)\bin\Artwork\Android\FM_LauncherIcon_36x36.png + true + true + true + $(BDS)\bin\Artwork\Android\FM_SplashImage_426x320.png + + + $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_80x80.png + $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_60x60.png + $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_76x76.png + $(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_40x40.png + $(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_80x80.png + $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_120x120.png + $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImagePortrait_768x1024.png + $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageLandscape_1024x768.png + $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_152x152.png + $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageLandscape_2048x1536.png + $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImagePortrait_1536x2048.png + $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_40x40.png + + + $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_80x80.png + $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_60x60.png + $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_76x76.png + $(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_40x40.png + $(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_80x80.png + $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_120x120.png + $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImagePortrait_768x1024.png + $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageLandscape_1024x768.png + $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_152x152.png + $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageLandscape_2048x1536.png + $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImagePortrait_1536x2048.png + $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_40x40.png + + + $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_80x80.png + $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_60x60.png + $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_76x76.png + $(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_40x40.png + $(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_80x80.png + $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_120x120.png + $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImagePortrait_768x1024.png + $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageLandscape_1024x768.png + $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_152x152.png + $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageLandscape_2048x1536.png + $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImagePortrait_1536x2048.png + $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_40x40.png + + + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) + FireDACSqliteDriver;FireDACDSDriver;DBXSqliteDriver;FireDACPgDriver;fmx;IndySystem;TeeDB;tethering;vclib;DBXInterBaseDriver;DataSnapClient;DataSnapCommon;DataSnapServer;DataSnapProviderClient;DBXSybaseASEDriver;DbxCommonDriver;vclimg;dbxcds;DatasnapConnectorsFreePascal;MetropolisUILiveTile;vcldb;vcldsnap;fmxFireDAC;DBXDb2Driver;DBXOracleDriver;CustomIPTransport;vclribbon;dsnap;IndyIPServer;fmxase;vcl;IndyCore;DBXMSSQLDriver;CloudService;IndyIPCommon;FmxTeeUI;FireDACIBDriver;DataSnapFireDAC;FireDACDBXDriver;soapserver;inetdbxpress;dsnapxml;FireDACInfxDriver;FireDACDb2Driver;adortl;FireDACASADriver;bindcompfmx;FireDACODBCDriver;RESTBackendComponents;emsclientfiredac;rtl;dbrtl;DbxClientDriver;FireDACCommon;bindcomp;inetdb;Tee;DBXOdbcDriver;vclFireDAC;xmlrtl;DataSnapNativeClient;ibxpress;svnui;IndyProtocols;DBXMySQLDriver;FireDACCommonDriver;bindcompdbx;bindengine;vclactnband;FMXTee;soaprtl;TeeUI;bindcompvcl;vclie;FireDACADSDriver;vcltouch;emsclient;VCLRESTComponents;FireDAC;DBXInformixDriver;FireDACMSSQLDriver;Intraweb;VclSmp;DataSnapConnectors;DataSnapServerMidas;DBXFirebirdDriver;dsnapcon;inet;fmxobj;FireDACMySQLDriver;soapmidas;vclx;svn;DBXSybaseASADriver;FireDACOracleDriver;fmxdae;RESTComponents;dbexpress;FireDACMSAccDriver;DataSnapIndy10ServerTransport;IndyIPClient;$(DCC_UsePackage) + CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= + true + 1033 + + + FireDACSqliteDriver;FireDACDSDriver;DBXSqliteDriver;FireDACPgDriver;fmx;IndySystem;TeeDB;tethering;vclib;DBXInterBaseDriver;DataSnapClient;DataSnapCommon;DataSnapServer;DataSnapProviderClient;DBXSybaseASEDriver;DbxCommonDriver;vclimg;dbxcds;DatasnapConnectorsFreePascal;MetropolisUILiveTile;vcldb;vcldsnap;fmxFireDAC;DBXDb2Driver;DBXOracleDriver;CustomIPTransport;vclribbon;dsnap;IndyIPServer;fmxase;vcl;IndyCore;DBXMSSQLDriver;CloudService;IndyIPCommon;FmxTeeUI;FireDACIBDriver;DataSnapFireDAC;FireDACDBXDriver;soapserver;inetdbxpress;dsnapxml;FireDACInfxDriver;FireDACDb2Driver;adortl;FireDACASADriver;bindcompfmx;FireDACODBCDriver;RESTBackendComponents;emsclientfiredac;rtl;dbrtl;DbxClientDriver;FireDACCommon;bindcomp;inetdb;Tee;DBXOdbcDriver;vclFireDAC;xmlrtl;DataSnapNativeClient;ibxpress;IndyProtocols;DBXMySQLDriver;FireDACCommonDriver;bindcompdbx;bindengine;vclactnband;FMXTee;soaprtl;TeeUI;bindcompvcl;vclie;FireDACADSDriver;vcltouch;emsclient;VCLRESTComponents;FireDAC;DBXInformixDriver;FireDACMSSQLDriver;Intraweb;VclSmp;DataSnapConnectors;DataSnapServerMidas;DBXFirebirdDriver;dsnapcon;inet;fmxobj;FireDACMySQLDriver;soapmidas;vclx;DBXSybaseASADriver;FireDACOracleDriver;fmxdae;RESTComponents;dbexpress;FireDACMSAccDriver;DataSnapIndy10ServerTransport;IndyIPClient;$(DCC_UsePackage) + true + + + DEBUG;$(DCC_Define) + true + false + true + true + true + + + false + + + false + RELEASE;$(DCC_Define) + 0 + 0 + + + + MainSource + + + + Cfg_2 + Base + + + Base + + + Cfg_1 + Base + + + + Delphi.Personality.12 + Application + + + + Demo1.dpr + + + + + + Demo1.exe + true + + + + + true + + + + + true + + + + + true + + + + + true + + + + + 1 + + + 1 + + + + + Contents\Resources + 1 + + + + + classes + 1 + + + + + res\drawable-xxhdpi + 1 + + + + + Contents\MacOS + 0 + + + 1 + + + Contents\MacOS + 1 + + + + + library\lib\mips + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 0 + + + 1 + + + Contents\MacOS + 1 + + + library\lib\armeabi-v7a + 1 + + + 1 + + + + + 0 + + + Contents\MacOS + 1 + .framework + + + + + 1 + + + 1 + + + 1 + + + + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + library\lib\armeabi + 1 + + + + + 0 + + + 1 + + + Contents\MacOS + 1 + + + + + 1 + + + 1 + + + 1 + + + + + res\drawable-normal + 1 + + + + + res\drawable-xhdpi + 1 + + + + + res\drawable-large + 1 + + + + + 1 + + + 1 + + + 1 + + + + + ..\ + 1 + + + ..\ + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + res\drawable-hdpi + 1 + + + + + Contents + 1 + + + + + ..\ + 1 + + + + + 1 + + + 1 + + + 1 + + + + + res\values + 1 + + + + + res\drawable-small + 1 + + + + + res\drawable + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + + + res\drawable + 1 + + + + + 0 + + + 0 + + + Contents\Resources\StartUp\ + 0 + + + 0 + + + 0 + + + 0 + + + + + library\lib\armeabi-v7a + 1 + + + + + 0 + .bpl + + + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + + + res\drawable-mdpi + 1 + + + + + res\drawable-xlarge + 1 + + + + + res\drawable-ldpi + 1 + + + + + 0 + .dll;.bpl + + + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + + + + + + + + + + + False + False + False + False + False + True + False + + + 12 + + + + + diff --git a/components/detours/Source/CPUID.pas b/components/detours/Source/CPUID.pas new file mode 100644 index 00000000..e1ccaff2 --- /dev/null +++ b/components/detours/Source/CPUID.pas @@ -0,0 +1,279 @@ +// ************************************************************************************************** +// CPUID for Delphi. +// Unit CPUID +// https://github.com/MahdiSafsafi/delphi-detours-library + +// The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); +// you may not use this file except in compliance with the License. You may obtain a copy of the +// License at http://www.mozilla.org/MPL/ +// +// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF +// ANY KIND, either express or implied. See the License for the specific language governing rights +// and limitations under the License. +// +// The Original Code is CPUID.pas. +// +// The Initial Developer of the Original Code is Mahdi Safsafi [SMP3]. +// Portions created by Mahdi Safsafi . are Copyright (C) 2013-2017 Mahdi Safsafi . +// All Rights Reserved. +// +// ************************************************************************************************** + +unit CPUID; +{$IFDEF FPC} +{$MODE DELPHI} +{$ENDIF FPC} + +interface + +{$I Defs.inc} + +uses SysUtils; + +type + { Do not change registers order ! } + TCPUIDStruct = packed record + rEAX: UInt32; { EAX Register } + rEBX: UInt32; { EBX Register } + rEDX: UInt32; { EDX Register } + rECX: UInt32; { ECX Register } + end; + + PCPUIDStruct = ^TCPUIDStruct; + +procedure CallCPUID(const ID: NativeUInt; var CPUIDStruct: TCPUIDStruct); +function IsCPUIDSupported: Boolean; + +type + TCPUVendor = (vUnknown, vIntel, vAMD, vNextGen); + TCPUEncoding = set of (REX, VEX, EVEX); + TCPUInstructions = set of (iMultiNop); + +var + CPUVendor: TCPUVendor; + CPUEncoding: TCPUEncoding; + CPUInsts: TCPUInstructions; + +implementation + +var + CPUIDSupported: Boolean = False; + +function ___IsCPUIDSupported: Boolean; +asm + {$IFDEF CPUX86} + PUSH ECX + PUSHFD + POP EAX { EAX = EFLAGS } + MOV ECX, EAX { Save the original EFLAGS value . } + { + CPUID is supported only if we can modify + bit 21 of EFLAGS register ! + } + XOR EAX, $200000 + PUSH EAX + POPFD { Set the new EFLAGS value } + PUSHFD + POP EAX { Read EFLAGS } + { + Check if the 21 bit was modified ! + If so ==> Return True . + else ==> Return False. + } + XOR EAX, ECX + SHR EAX, 21 + AND EAX, 1 + PUSH ECX + POPFD { Restore original EFLAGS value . } + POP ECX + {$ELSE !CPUX86} + PUSH RCX + MOV RCX,RCX + PUSHFQ + POP RAX + MOV RCX, RAX + XOR RAX, $200000 + PUSH RAX + POPFQ + PUSHFQ + POP RAX + XOR RAX, RCX + SHR RAX, 21 + AND RAX, 1 + PUSH RCX + POPFQ + POP RCX + {$ENDIF CPUX86} +end; + +procedure ___CallCPUID(const ID: NativeInt; var CPUIDStruct); +asm + { + ALL REGISTERS (rDX,rCX,rBX) MUST BE SAVED BEFORE + EXECUTING CPUID INSTRUCTION ! + } + {$IFDEF CPUX86} + PUSH EDI + PUSH ECX + PUSH EBX + MOV EDI,EDX + CPUID + {$IFNDEF FPC} + MOV EDI.TCPUIDStruct.rEAX,EAX + MOV EDI.TCPUIDStruct.rEBX,EBX + MOV EDI.TCPUIDStruct.rECX,ECX + MOV EDI.TCPUIDStruct.rEDX,EDX + {$ELSE FPC} + MOV [EDI].TCPUIDStruct.rEAX,EAX + MOV [EDI].TCPUIDStruct.rEBX,EBX + MOV [EDI].TCPUIDStruct.rECX,ECX + MOV [EDI].TCPUIDStruct.rEDX,EDX + {$ENDIF !FPC} + POP EBX + POP ECX + POP EDI + {$ELSE !CPUX86} + PUSH R9 + PUSH RBX + PUSH RDX + MOV RAX,RCX + MOV R9,RDX + CPUID + MOV R9.TCPUIDStruct.rEAX,EAX + MOV R9.TCPUIDStruct.rEBX,EBX + MOV R9.TCPUIDStruct.rECX,ECX + MOV R9.TCPUIDStruct.rEDX,EDX + POP RDX + POP RBX + POP R9 + {$ENDIF CPUX86} +end; + +function ___IsAVXSupported: Boolean; +asm + { + Checking for AVX support requires 3 steps: + + 1) Detect CPUID.1:ECX.OSXSAVE[bit 27] = 1 + => XGETBV enabled for application use + + 2) Detect CPUID.1:ECX.AVX[bit 28] = 1 + => AVX instructions supported. + + 3) Issue XGETBV and verify that XCR0[2:1] = ‘11b’ + => XMM state and YMM state are enabled by OS. + + } + + { Steps : 1 and 2 } + {$IFDEF CPUX64} + MOV RAX, 1 + PUSH RCX + PUSH RBX + PUSH RDX + {$ELSE !CPUX64} + MOV EAX, 1 + PUSH ECX + PUSH EBX + PUSH EDX + {$ENDIF CPUX64} + CPUID + AND ECX, $018000000 + CMP ECX, $018000000 + JNE @@NOT_SUPPORTED + XOR ECX,ECX + { + Delphi does not support XGETBV ! + => We need to use the XGETBV opcodes ! + } + DB $0F DB $01 DB $D0 // XGETBV + { Step :3 } + AND EAX, $06 + CMP EAX, $06 + JNE @@NOT_SUPPORTED + MOV EAX, 1 + JMP @@END +@@NOT_SUPPORTED: + XOR EAX,EAX +@@END: + {$IFDEF CPUX64} + POP RDX + POP RBX + POP RCX + {$ELSE !CPUX64} + POP EDX + POP EBX + POP ECX + {$ENDIF CPUX64} +end; + +procedure CallCPUID(const ID: NativeUInt; var CPUIDStruct: TCPUIDStruct); +begin + FillChar(CPUIDStruct, SizeOf(TCPUIDStruct), #0); + if not CPUIDSupported then + raise Exception.Create('CPUID instruction not supported.') + else + ___CallCPUID(ID, CPUIDStruct); +end; + +function IsCPUIDSupported: Boolean; +begin + Result := CPUIDSupported; +end; + +type + TVendorName = array [0 .. 12] of AnsiChar; + +function GetVendorName: TVendorName; +var + Info: PCPUIDStruct; + P: PByte; +begin + Result := ''; + if not IsCPUIDSupported then + Exit; + Info := GetMemory(SizeOf(TCPUIDStruct)); + CallCPUID(0, Info^); + P := PByte(Info) + 4; // Skip EAX ! + Move(P^, PByte(@Result[0])^, 12); + FreeMemory(Info); +end; + +procedure __Init__; +var + vn: TVendorName; + Info: TCPUIDStruct; + r: UInt32; +begin + CPUVendor := vUnknown; +{$IFDEF CPUX64} + CPUEncoding := [REX]; +{$ELSE !CPUX64} + CPUEncoding := []; +{$ENDIF CPUX64} + CPUInsts := []; + if IsCPUIDSupported then + begin + vn := GetVendorName(); + if vn = 'GenuineIntel' then + CPUVendor := vIntel + else if vn = 'AuthenticAMD' then + CPUVendor := vAMD + else if vn = 'NexGenDriven' then + CPUVendor := vNextGen; + CallCPUID(1, Info); + r := Info.rEAX and $F00; + case r of + $F00, $600: Include(CPUInsts, iMultiNop); + end; + if ___IsAVXSupported then + Include(CPUEncoding, VEX); + end; +end; + +initialization + +CPUIDSupported := ___IsCPUIDSupported; +__Init__; + +end. diff --git a/components/detours/Source/DDetours.pas b/components/detours/Source/DDetours.pas new file mode 100644 index 00000000..b69c799d --- /dev/null +++ b/components/detours/Source/DDetours.pas @@ -0,0 +1,2861 @@ +// ************************************************************************************************** +// Delphi Detours Library. +// Unit DDetours +// https://github.com/MahdiSafsafi/delphi-detours-library + +// The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); +// you may not use this file except in compliance with the License. You may obtain a copy of the +// License at http://www.mozilla.org/MPL/ +// +// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF +// ANY KIND, either express or implied. See the License for the specific language governing rights +// and limitations under the License. +// +// The Original Code is DDetours.pas. +// +// Contributor(s): +// David Millington +// RRUZ +// +// The Initial Developer of the Original Code is Mahdi Safsafi [SMP3]. +// Portions created by Mahdi Safsafi . are Copyright (C) 2013-2017 Mahdi Safsafi . +// All Rights Reserved. +// +// ************************************************************************************************** + +{ ===============================> CHANGE LOG <====================================================== + + Jan 24,2015: + +Added support for vtable patching. + +Added GetNHook/IsHooked support for Interface. + + Jan 20,2015: + +Added support to hook Delphi Interface by name. + + Version2 , Mahdi Safsafi: + +Many bug fix. + +Added new hooking model architecture. + +Added multi hook support. + +Added COM hook support. + +Added instruction maping feature. + +Added hook detecting feature. + +Added BeginHooks/EndHooks. + +Added BeginUnHooks/EndUnHooks. + +Added IDetours interface. + +Added MultiNop instructions support. + +Generate better opcodes. + +Improved support for x64. + +Improved AllocMemAt function. + ====================================================================================================== } + +unit DDetours; + +{$IFDEF FPC} +{$MODE DELPHI} +{$ENDIF FPC} + +interface + +{$I Defs.inc} + +uses + InstDecode, + CPUID, + SysUtils, +{$IFDEF DXE2UP} + WinApi.Windows, +{$ELSE !DXE2UP} + Windows, +{$ENDIF DXE2UP} + Classes +{$IFDEF MustUseGenerics} + , Generics.Collections // + , Typinfo, RTTI +{$ENDIF MustUseGenerics} + ; + +type + InterceptException = Exception; +{$IFNDEF DXE2UP} + SIZE_T = NativeUInt; +{$ENDIF !DXE2UP} + +const + { Maximum allowed number of hooks. } + MAX_HOOKS = 7; + + { Options } + Root = 1; // Future use. + ST = 2; // Suspend Threads. + +{$IFDEF BuildThreadSafe} + { + Make the new version compatible with the old one ! + =================================================== + I don't guarantee that i will continue + supporting old release . + ==> You sould update your code + when you have some time ! + } + v1compatibility = ST; +{$ELSE !BuildThreadSafe} + v1compatibility = 0; +{$ENDIF BuildThreadSafe} + { ======================================================================================================================================================= } +function InterceptCreate(const TargetProc, InterceptProc: Pointer; Options: Byte = v1compatibility): Pointer; overload; +function InterceptCreate(const TargetInterface; MethodIndex: Integer; const InterceptProc: Pointer; Options: Byte = v1compatibility): Pointer; overload; +function InterceptCreate(const Module, MethodName: String; const InterceptProc: Pointer; ForceLoadModule: Boolean = True; Options: Byte = v1compatibility) + : Pointer; overload; +procedure InterceptCreate(const TargetProc, InterceptProc: Pointer; var TrampoLine: Pointer; Options: Byte = v1compatibility); overload; +function InterceptRemove(const Trampo: Pointer; Options: Byte = v1compatibility): Integer; +function GetNHook(const TargetProc: Pointer): ShortInt; overload; +function GetNHook(const TargetInterface; MethodIndex: Integer): ShortInt; overload; +function IsHooked(const TargetProc: Pointer): Boolean; overload; +function IsHooked(const TargetInterface; MethodIndex: Integer): Boolean; overload; +function PatchVt(const TargetInterface; MethodIndex: Integer; InterceptProc: Pointer): Pointer; +function UnPatchVt(const Trampo: Pointer): Boolean; + +{$IFDEF MustUseGenerics } +function InterceptCreate(const TargetInterface; const MethodName: String; const InterceptProc: Pointer; Options: Byte = v1compatibility): Pointer; overload; +function GetNHook(const TargetInterface; const MethodName: String): ShortInt; overload; +function IsHooked(const TargetInterface; const MethodName: String): Boolean; overload; +function BeginHooks(): Boolean; +function EndHooks(): Boolean; +function BeginUnHooks(): Boolean; +function EndUnHooks(): Boolean; + +type + DetourException = Exception; + + IGenericCast = interface(IInterface) + ['{B19D793C-3225-439C-A2F3-04A72D41879E}'] + function TToPointer(const _T: T): Pointer; + function PointerToT(const _P: Pointer): T; + end; + + IDetours = interface(IInterface) + ['{04552E96-C716-4378-BE9A-CD383D20AB91}'] + function NextHook: T; + function GetInstalled: Boolean; + function GetHookCount: ShortInt; + procedure SetHook(const TargetProc, InterceptProc: T); + procedure Enable; + procedure Disable; + property TrampoLine: T read NextHook; // Call the original + end; + + TDetours = class(TInterfacedObject, IGenericCast, IDetours) + private + FTargetProc: PByte; + FInterceptProc: PByte; + FNextHook: T; + function __TToPointer(const _T): Pointer; + function __PointerToT(const _P): T; + function TToPointer(const _T: T): Pointer; + function PointerToT(const _P: Pointer): T; + function NextHook: T; + function GetInstalled: Boolean; + function GetHookCount: ShortInt; + protected + function CheckTType: Boolean; + procedure SetHook(const TargetProc, InterceptProc: T); + public + constructor Create(const TargetProc, InterceptProc: T); + destructor Destroy; override; + procedure Enable; + procedure Disable; + property TrampoLine: T read NextHook; // Call the original + property Installed: Boolean read GetInstalled; + property nHook: ShortInt read GetHookCount; + end; + +const + SInvalidTType = '%s must be procedure.'; + SDetoursNotInstalled = 'Detour is not installed; trampoline pointer is nil'; +{$ENDIF MustUseGenerics } +{$IFDEF FPC} + +var + Critical: TRTLCriticalSection; +{$ENDIF FPC} + +implementation + +{$OVERFLOWCHECKS OFF} +{$IFNDEF FPC} + +{ Delphi } +uses +{$IFDEF DXE2UP} + WinApi.TLHelp32; +{$ELSE !DXE2UP} + TLHelp32; +{$ENDIF DXE2UP} +{$ELSE FPC} + +type + tagTHREADENTRY32 = record + dwSize: DWORD; + cntUsage: DWORD; + th32ThreadID: DWORD; // this thread + th32OwnerProcessID: DWORD; // Process this thread is associated with + tpBasePri: Longint; + tpDeltaPri: Longint; + dwFlags: DWORD; + end; + + THREADENTRY32 = tagTHREADENTRY32; + PTHREADENTRY32 = ^tagTHREADENTRY32; + LPTHREADENTRY32 = ^tagTHREADENTRY32; + TThreadEntry32 = tagTHREADENTRY32; + + TCreateToolhelp32Snapshot = function(dwFlags, th32ProcessID: DWORD): THandle stdcall; + TThread32First = function(hSnapshot: THandle; var lpte: TThreadEntry32): BOOL stdcall; + TThread32Next = function(hSnapshot: THandle; var lpte: TThreadEntry32): BOOL stdcall; + +var + CreateToolhelp32Snapshot: TCreateToolhelp32Snapshot; + Thread32First: TThread32First; + Thread32Next: TThread32Next; + +const + TH32CS_SNAPTHREAD = $00000004; +{$ENDIF !FPC} + +type + TOpenThread = function(dwDesiredAccess: DWORD; bInheritHandle: BOOL; dwThreadId: DWORD): THandle; stdcall; + +var + OpenThread: TOpenThread; + hKernel: THandle; + OpenThreadExist: Boolean = False; + FreeKernel: Boolean = False; + SizeOfAlloc: DWORD = 0; // See initialization ! + +const + { Instructions OpCodes } + opJmpRelz = $E9; + opJmpRelb = $EB; + opJmpMem = $25FF; + opTestb = $85; + opPrfOpSize = $66; + opPrfAddrSize = $67; + opNop = $90; + + fDscrHasTmp = $01; + DscrSigSize = $08; + TrampoSize = 64; + TmpSize = 32; + +type + TDscrSig = array [0 .. DscrSigSize - 1] of Byte; + TTrampoData = array [0 .. TrampoSize - 1] of Byte; + + TVirtualProtect = function(lpAddress: Pointer; dwSize: SIZE_T; flNewProtect: DWORD; var OldProtect: DWORD): BOOL; stdcall; + TVirtualAlloc = function(lpvAddress: Pointer; dwSize: SIZE_T; flAllocationType, flProtect: DWORD): Pointer; stdcall; + TVirtualQuery = function(lpAddress: Pointer; var lpBuffer: TMemoryBasicInformation; dwLength: SIZE_T): SIZE_T; stdcall; + TFlushInstructionCache = function(hProcess: THandle; const lpBaseAddress: Pointer; dwSize: SIZE_T): BOOL; stdcall; + TGetCurrentProcess = function: THandle; stdcall; + TVirtualFree = function(lpAddress: Pointer; dwSize: SIZE_T; dwFreeType: DWORD): BOOL; stdcall; + + TInternalFuncs = record + VirtualAlloc: TVirtualAlloc; + VirtualFree: TVirtualFree; + VirtualProtect: TVirtualProtect; + VirtualQuery: TVirtualQuery; + FlushInstructionCache: TFlushInstructionCache; + GetCurrentProcess: TGetCurrentProcess; + end; + +var + InternalFuncs: TInternalFuncs; + +const + { Descriptor Signature } +{$IFDEF CPUX64} + DscrSig: TDscrSig = ( // + $90, { NOP } + $40, { REX } + $40, { REX } + $40, { REX } + $0F, { ESCAPE TWO BYTE } + $1F, { HINT_NOP } + $F3, { PRF } + $F3 { PRF } + ); +{$ELSE !CPUX64} + DscrSig: TDscrSig = ( // + $90, { NOP } + $40, { INC EAX } + $48, { DEC EAX } + $90, { NOP } + $0F, { ESCAPE TWO BYTE } + $1F, { HINT_NOP } + $F3, { PRF } + $F3 { PRF } + ); +{$ENDIF CPUX64} + +type + TTrampoInfo = record + Addr: PByte; // Pointer to first trampoline instruction . + Size: Byte; // Stolen bytes size . + PData: PByte; // Original Stolen bytes. + end; + + PTrampoInfo = ^TTrampoInfo; + + TJmpMem = packed record + OpCode: WORD; // $0F$25 + Disp32: Integer; + end; + + PJmpMem = ^TJmpMem; + + TDescriptor = packed record + Sig: TDscrSig; { Table signature. } + DscrAddr: PByte; { Pointer that hold jmp address (if Used)! } + nHook: Byte; { Number of hooks . } + Flags: Byte; { Reserved for future use! } + ExMem: PByte; { Reserved for jmp (if used) & for Trampoline ! } + OrgPtr: PByte; { Original Target Proc address. } + Trampo: PTrampoInfo; { Pointer to TrampoInfo struct. } + { Array that hold jmp destination address. } + JmpAddrs: array [0 .. MAX_HOOKS] of PByte; + { + Mark the beginning of descriptor code executing . + ==> Must be NOP . + } + CodeEntry: Byte; + { Jmp Instruction for NextHook call and Trampoline call ! } + JmpMems: array [0 .. MAX_HOOKS] of TJmpMem; + end; + + PDescriptor = ^TDescriptor; + + TNextHook = packed record + ID: Byte; { Hook ID . } + PDscr: PDescriptor; + end; + + PNextHook = ^TNextHook; + + TThreadsIDList = class(TList); + + TInterceptMonitor = class(TObject) + class procedure InternalCreate; + class procedure InternalDestroy; + class var FLock: TObject; + class procedure Enter; + class procedure Leave; + end; + + TIntercept = class(TObject) + private + FOptions: Byte; + FList: TThreadsIDList; + class function GetRoot(P: PByte): PByte; + public + constructor Create(Options: Byte); virtual; + destructor Destroy; override; + + protected + function GetDescriptor(P: PByte): PDescriptor; + function IsValidDescriptor(P: PByte): Boolean; + function CreateNewDescriptor: PDescriptor; + procedure InsertDescriptor(PAt: PByte; PDscr: PDescriptor); + procedure RemoveDescriptor(PDscr: PDescriptor); + function InstallHook(TargetProc, InterceptProc: PByte; const Options: Byte = $00): PByte; + function AddHook(PDscr: PDescriptor; InterceptProc: PByte; const Options: Byte = $00): PByte; + function RemoveHook(Trampo: PByte): Integer; + end; + +const + { Error Str } + ErrFuncSize = 'Size of function is too small, risk to override others adjacent functions.'; + ErrJmpInvalid = 'Invalid JMP Type.'; + ErrJmpInvalid64 = 'Invalid JMP Type for x64.'; + ErrJmpInvalid32 = 'Invalid JMP Type for x32.'; + ErrJmpInvalidDstSave = 'Invalid DstSave Address pointer.'; + ErrMultiNopNotSup = 'Multi Bytes Nop Instructions not supported by your CPU.'; + ErrRipDisp = 'Failed to correcr RIP Displacement.'; + ErrTrampoSize = 'Exceed maximum TrampoSize.'; + ErrMaxHook = 'Exceed maximum allowed of hooks.'; + ErrTargetProc = 'Invalid TargetProc Pointer.'; + ErrInterceptProc = 'Invalid InterceptProc Pointer.'; + ErrInvalidDscr = 'Invalid Descriptor.'; + ErrInvalidTrampo = 'Invalid TrampoLine Pointer.'; + ErrBgnUnHooks = 'BeginUnHooks must be called outside BeginHooks/EndHooks.'; + + { JMP Type } + tJmpNone = 0; + tJmpRel8 = 1; + tJmpRel16 = 2; + tJmpRel32 = 3; + tJmpMem16 = 4; + tJmpMem32 = 5; + tJmpMem64 = 6; + tJmpRipZ = 7; + +{$IFDEF CPUX64} + tJmpMemN = tJmpMem64; +{$ELSE !CPUX64} + tJmpMemN = tJmpMem32; +{$ENDIF CPUX64} + { Jmp Type To Size } + JmpTypeToSize: array [0 .. 7] of Byte = ( // + 0, { None } + 2, { tJmpRel8 = $EB + Rel8 } + 4, { tJmpRel16 = OpSizePrf + $E9 + Rel16 } + 5, { tJmpRel32 = $E9 + Rel32 } + 7, { tJmpMem16 = OpSizePrf + $FF /4 + Disp32 } + 6, { tJmpMem32 = $FF /4 + Disp32 } + 6, { tJmpMem64 = $FF /4 + Disp32 } + 14 { tJmpRipZ = $FF /4 + Disp32 + DQ } + ); + + SizeToJmpType: array [0 .. 4] of Byte = ( // +{$IFDEF CPUX86} + tJmpRel8, { db } + tJmpRel16, { dw } + tJmpRel32, { dd } + tJmpMem32, { dd } + tJmpMem32 { dd } +{$ELSE !CPUX86} + tJmpRel8, { db } + tJmpRel32, { dw } + tJmpRel32, { dd } + tJmpMem64, { dq } + tJmpMem64 { dq } +{$ENDIF CPUX86} + ); + + { + // Useful function when debugging ! + procedure DbgPrint(const msg: string; Value: Int64); overload; + var + s: string; + begin + s := msg; + if s <> EmptyStr then + s := s + ' = ' + IntToStr(Value) + else + s := IntToStr(Value); + OutputDebugStringW(PChar(s)); + end; + + procedure DbgPrint(const msg: string); overload; + begin + OutputDebugStringW(PChar(msg)); + end; + + procedure ShowMsg(const msg: string); + begin + MessageBoxW(0, PChar(msg), nil, MB_OK); + end; + } +const + THREAD_SUSPEND_RESUME = $0002; + +function SuspendAllThreads(RTID: TThreadsIDList): Boolean; +var + hSnap: THandle; + PID: DWORD; + te: TThreadEntry32; + nCount: DWORD; + hThread: THandle; + Next: Boolean; + CurrentThreadId: Cardinal; +begin + PID := GetCurrentProcessId; + CurrentThreadId := GetCurrentThreadId; + hSnap := CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, PID); + Result := hSnap <> INVALID_HANDLE_VALUE; + if Result then + begin + te.dwSize := SizeOf(TThreadEntry32); + Next := Thread32First(hSnap, te); + while Next do + begin + if (te.th32OwnerProcessID = PID) and (te.th32ThreadID <> CurrentThreadId) then + begin + { Allow the caller thread to access the Detours . + => Suspend all threads, except the current thread . } + hThread := OpenThread(THREAD_SUSPEND_RESUME, False, te.th32ThreadID); + if hThread <> INVALID_HANDLE_VALUE then + begin + nCount := SuspendThread(hThread); + if nCount <> DWORD(-1) then // thread's previously was running . + { Only add threads that was running before suspending them ! } + RTID.Add(Pointer(NativeUInt(te.th32ThreadID))); + CloseHandle(hThread); + end; + end; + Next := Thread32Next(hSnap, te); + end; + CloseHandle(hSnap); + end; +end; + +function ResumeSuspendedThreads(RTID: TThreadsIDList): Boolean; +var + i: Integer; + TID: DWORD; + hThread: THandle; +begin + Result := False; + if Assigned(RTID) then + for i := 0 to RTID.Count - 1 do + begin + TID := DWORD(RTID.Items[i]); + if TID <> DWORD(-1) then + begin + Result := True; + hThread := OpenThread(THREAD_SUSPEND_RESUME, False, TID); + if hThread <> INVALID_HANDLE_VALUE then + begin + ResumeThread(hThread); + CloseHandle(hThread); + end; + end; + end; +end; + +function SetMemPermission(const P: Pointer; const Size: NativeUInt; const NewProtect: DWORD): DWORD; +const + PAGE_EXECUTE_FLAGS = PAGE_EXECUTE or PAGE_EXECUTE_READ or PAGE_EXECUTE_READWRITE or PAGE_EXECUTE_WRITECOPY; +begin + Result := 0; + if Assigned(P) and (Size > 0) and (NewProtect > 0) then + begin + if InternalFuncs.VirtualProtect(P, Size, NewProtect, Result) then + if (NewProtect and PAGE_EXECUTE_FLAGS <> 0) then + { + If the protected region will be executed + => We need to update the cpu cache ! + } + InternalFuncs.FlushInstructionCache(InternalFuncs.GetCurrentProcess(), P, Size); + end; +end; + +function GetDispDataSize(PInst: PInstruction): ShortInt; +begin + Result := 0; + if PInst^.Disp.Flags and dfUsed <> 0 then + begin + if PInst^.Archi = CPUX32 then + begin + if PInst^.Prefixes and Prf_OpSize <> 0 then + Exit(ops16bits) + else + Exit(ops32bits); + end else begin + case PInst^.OperandFlags of + opdD64: + begin + { + Defaults to O64 in PM64. + PrfOpSize results in O16. + } + if PInst^.Prefixes and Prf_OpSize <> 0 then + Exit(ops16bits) + else + Exit(ops64bits); + end; + opdF64, opdDv64: + begin + { The operand size is forced to a 64-bit operand size in PM64 ! } + Exit(ops64bits); + end; + opdDf64: + begin + { + Defaults to O64 in PM64. + PrfOpSize results in O16 in AMD64. + PrfOpSize is ignored in EM64T. + } + if (CPUVendor = vAMD) and (PInst^.Prefixes and Prf_OpSize <> 0) then + Exit(ops16bits) + else + Exit(ops64bits); + end; + else + begin + if PInst^.Rex.W then + Exit(ops64bits) + else if (PInst^.Prefixes and Prf_OpSize <> 0) then + Exit(ops16bits) + else + Exit(ops32bits); + end; + end; + end; + end; +end; + +function fDecodeInst(PInst: PInstruction): ShortInt; +var + IsNxtInstData: Boolean; +begin + { Include VEX decoding if the cpu support it! } + if (VEX in CPUEncoding) then + PInst.Options := DecodeVex; + + Result := DecodeInst(PInst); + +{$IFDEF CPUX64} + IsNxtInstData := ((PInst^.Disp.Flags and (dfUsed or dfRip) = (dfUsed or dfRip)) and (PInst^.Disp.Value = 0)); +{$ELSE !CPUX64} + IsNxtInstData := (PInst^.Disp.Value = UInt64(PInst^.NextInst)); +{$ENDIF CPUX64} + if IsNxtInstData then + begin + { + Check if the Next Instruction is data ! + If so , That's mean it's not a valid instruction . + We must skip this data .. + otherwise , disassembling next instructions will fail ! + } + Inc(Result, GetDispDataSize(PInst)); + PInst^.InstSize := Result; + end; +end; + +function RoundMultipleOf(const Value, n: NativeUInt): NativeUInt; {$IFDEF MustInline}inline; {$ENDIF} +begin + if Value = 0 then + Exit(n); + Result := ((Value + (n - 1)) and not(n - 1)); +end; + +function AllocMemAt(const Addr: Pointer; const MemSize, flProtect: DWORD): Pointer; +var + mbi: TMemoryBasicInformation; + SysInfo: TSystemInfo; + pBase: PByte; + P: PByte; + Q: PByte; + pMax, pMin: PByte; + dwAllocGran: DWORD; +begin + { Alloc memory on the specific nearest address from the Addr . } + + Result := nil; + P := PByte(Addr); + if not Assigned(P) then + begin + Result := InternalFuncs.VirtualAlloc(nil, MemSize, MEM_RESERVE or MEM_COMMIT, flProtect); + Exit; + end; + + GetSystemInfo(SysInfo); + pMin := SysInfo.lpMinimumApplicationAddress; + pMax := SysInfo.lpMaximumApplicationAddress; + dwAllocGran := SysInfo.dwAllocationGranularity; + + if (P < pMin) or (P > pMax) then + Exit; + if InternalFuncs.VirtualQuery(P, mbi, SizeOf(mbi)) = 0 then + Exit; + + pBase := mbi.BaseAddress; + Q := pBase; + while Q < pMax do + begin + if InternalFuncs.VirtualQuery(Q, mbi, SizeOf(mbi)) = 0 then + Exit; + if (mbi.State = MEM_FREE) and (mbi.RegionSize >= dwAllocGran) and (mbi.RegionSize >= MemSize) then + begin + { The address (P) must be multiple of the allocation granularity (dwAllocationGranularity) . } + P := PByte(RoundMultipleOf(NativeUInt(Q), dwAllocGran)); + Result := InternalFuncs.VirtualAlloc(P, MemSize, MEM_RESERVE or MEM_COMMIT, flProtect); + if Assigned(Result) then + Exit; + end; + Inc(Q, mbi.RegionSize); // Next Region . + end; + { + If thre is no memory available in the range [Addr - pMax] + try to allocate at the range [pMin - Addr] + } + Q := pBase; + while Q > pMin do + begin + if InternalFuncs.VirtualQuery(Q, mbi, SizeOf(mbi)) = 0 then + Exit; + if (mbi.State = MEM_FREE) and (mbi.RegionSize >= dwAllocGran) and (mbi.RegionSize >= MemSize) then + begin + P := PByte(RoundMultipleOf(NativeUInt(Q), dwAllocGran)); + Result := InternalFuncs.VirtualAlloc(P, MemSize, MEM_RESERVE or MEM_COMMIT, flProtect); + if Assigned(Result) then + Exit; + end; + Dec(Q, mbi.RegionSize); // Previous Region. + end; +end; + +function TryAllocMemAt(const Addr: Pointer; const MemSize, flProtect: DWORD): Pointer; +var + MEM_64: DWORD; +begin + MEM_64 := 0; + Result := AllocMemAt(Addr, MemSize, flProtect); + if not Assigned(Result) then + begin +{$IFDEF CPUX64} + { Allocates memory at the highest possible address } + if (UInt64(Addr) and $FFFFFFFF00000000 <> 0) then + MEM_64 := MEM_TOP_DOWN; +{$ENDIF CPUX64} + Result := InternalFuncs.VirtualAlloc(nil, MemSize, MEM_RESERVE or MEM_COMMIT or MEM_64, flProtect); + end; +end; + +function InsertJmp(Src, Dst: PByte; JmpType: Byte; const DstSave: PByte = nil): ShortInt; +var + Offset32: Int32; + Offset64: Int64; + JmpSize: Byte; +begin + Result := 1; + JmpSize := JmpTypeToSize[JmpType]; + Offset32 := Int32(UInt64(Dst) - UInt64(Src)) - JmpSize; + case JmpType of + tJmpNone: + begin + raise InterceptException.Create(ErrJmpInvalid); + end; + tJmpRel8: + begin + PByte(Src)^ := opJmpRelb; + Inc(Src); + PInt8(Src)^ := Int8(Offset32); + end; + tJmpRel16: + begin +{$IFDEF CPUX64} + { + JMP Rel16 + ==> Not supported on x64! + } + raise InterceptException.Create(ErrJmpInvalid64); +{$ENDIF CPUX64} + PByte(Src)^ := opPrfOpSize; + Inc(Src); + PByte(Src)^ := opJmpRelz; + Inc(Src); + PInt16(Src)^ := Int16(Offset32); + end; + tJmpRel32: + begin + PByte(Src)^ := opJmpRelz; + Inc(Src); + PInt32(Src)^ := Offset32; + end; + tJmpMem16: + begin +{$IFDEF CPUX64} + { + JMP WORD [012345] + ==> Not supported on x64! + } + raise InterceptException.Create(ErrJmpInvalid64); +{$ENDIF CPUX64} + if not Assigned(DstSave) then + raise InterceptException.Create(ErrJmpInvalidDstSave); + PByte(Src)^ := opPrfOpSize; + Inc(Src); + PWord(Src)^ := opJmpMem; + Inc(Src, 2); + PUInt32(Src)^ := UInt32(DstSave); + PUInt16(DstSave)^ := UInt16(Dst); + end; + tJmpMem32: + begin +{$IFDEF CPUX64} + { + JMP DWORD [012345] + ==> Not supported on x64! + } + raise InterceptException.Create(ErrJmpInvalid64); +{$ENDIF CPUX64} + if not Assigned(DstSave) then + raise InterceptException.Create(ErrJmpInvalidDstSave); + PWord(Src)^ := opJmpMem; + Inc(Src, 2); + PUInt32(Src)^ := UInt32(DstSave); + PUInt32(DstSave)^ := UInt32(Dst); + end; + tJmpMem64: + begin +{$IFDEF CPUX86} + { + JMP QWORD [0123456789] + ==> Not supported on x32! + } + raise InterceptException.Create(ErrJmpInvalid32); +{$ENDIF CPUX86} + if not Assigned(DstSave) then + raise InterceptException.Create(ErrJmpInvalidDstSave); + { RIP Disp ! } + PUInt64(DstSave)^ := UInt64(Dst); + Offset64 := Int64(UInt64(DstSave) - UInt64(Src)) - JmpSize; + Offset32 := Integer(Offset64); + { If the distance between DispAddr and Src exceed 32-bits then + the only way to insert a jump + is to use tJmpRipZ method ! } + if Offset32 <> Offset64 then + Exit(-1); + PWord(Src)^ := opJmpMem; + Inc(Src, 2); + PInt32(Src)^ := Offset32; + end; + tJmpRipZ: + begin +{$IFDEF CPUX86} + raise InterceptException.Create(ErrJmpInvalid32); +{$ENDIF CPUX86} + { + This is the most harder way to insert a jump ! + Why ? + because we are going to mix code & data ! + Thats mean when disassembling instructions after + this branch .. you will have a corrupted dissambled + structure ! + + The only way to detect this kind of jmp is: + to use fDecodeInst rather than DecodeInst routine . + + ==> We should avoid using this kind of jmp + in the original target proc . + + ==> It's Ok to use in others situation . + } + + PWord(Src)^ := opJmpMem; + Inc(Src, 2); + PInt32(Src)^ := $00; + Inc(Src, 4); + PUInt64(Src)^ := UInt64(Dst); + end; + end; +end; + +function GetUInt64Size(const Value: UInt64): Byte; +begin + if UInt8(Value) = Value then + Exit(1) + else if UInt16(Value) = Value then + Exit(2) + else if UInt32(Value) = Value then + Exit(4) + else + Exit(8); +end; + +function GetInt64Size(const Value: Int64): Byte; +begin + if Int8(Value) = Value then + Exit(1) + else if Int16(Value) = Value then + Exit(2) + else if Int32(Value) = Value then + Exit(4) + else + Exit(8); +end; + +function GetJmpType(Src, Dst, DstSave: PByte): Byte; +var + Offset: Int64; + OffsetSize: Byte; +begin + Offset := Int64(UInt64(Src) - UInt64(Dst)); + OffsetSize := GetInt64Size(Offset); + Result := SizeToJmpType[OffsetSize shr 1]; +{$IFDEF CPUX64} + if Result = tJmpMem64 then + begin + if not Assigned(DstSave) then + raise InterceptException.Create(ErrJmpInvalidDstSave); + Offset := Int64(UInt64(DstSave) - UInt64(Src)) - 7; + if Int32(Offset) <> Offset then + Exit(tJmpRipZ); + end; +{$ENDIF CPUX64} +end; + +{$IFDEF UseMultiBytesNop} + +const + Nop9: array [0 .. 8] of Byte = ($66, $0F, $1F, $84, $00, $00, $00, $00, $00); + Nop8: array [0 .. 7] of Byte = ($0F, $1F, $84, $00, $00, $00, $00, $00); + Nop7: array [0 .. 6] of Byte = ($0F, $1F, $80, $00, $00, $00, $00); + Nop6: array [0 .. 5] of Byte = ($66, $0F, $1F, $44, $00, $00); + Nop5: array [0 .. 4] of Byte = ($0F, $1F, $44, $00, $00); + Nop4: array [0 .. 3] of Byte = ($0F, $1F, $40, $00); + Nop3: array [0 .. 2] of Byte = ($0F, $1F, $00); + Nop2: array [0 .. 1] of Byte = ($66, $90); + Nop1: array [0 .. 0] of Byte = ($90); + MultiNops: array [0 .. 8] of PByte = ( // + @Nop1, { Standard Nop } + @Nop2, { 2 Bytes Nop } + @Nop3, { 3 Bytes Nop } + @Nop4, { 4 Bytes Nop } + @Nop5, { 5 Bytes Nop } + @Nop6, { 6 Bytes Nop } + @Nop7, { 7 Bytes Nop } + @Nop8, { 8 Bytes Nop } + @Nop9 { 9 Bytes Nop } + + ); + +function IsMultiBytesNop(const P: PByte; Len: ShortInt = 0): Boolean; +var + i: Integer; + nL: Integer; +begin + for i := Length(MultiNops) downto 1 do + begin + nL := i; + Result := CompareMem(MultiNops[i - 1], P, nL); + if Result then + begin + if Len < 0 then + Exit; + Result := (nL = Len); + if Result then + Exit; + end; + end; +end; + +procedure FillMultiNop(var Buff; Size: Integer); +var + i: Integer; + nL: Byte; + P: PByte; +begin + { Multi Bytes Nop Instructions seems to be + faster to execute rather than + the traditional (NOP x n) instructions. + + However it's not supported by all CPU ! + ==> Use FillNop(P,Size,True)! + + ==> CPUID implement a routine to detect + if the CPU support Multi Bytes Nop . + } + if not(iMultiNop in CPUInsts) then + raise InterceptException.Create(ErrMultiNopNotSup); + + P := PByte(@Buff); + for i := Length(MultiNops) downto 1 do + begin + nL := i; + if Size = 0 then + Break; + while Size >= nL do + begin + Move(MultiNops[i - 1]^, P^, nL); + Dec(Size, nL); + Inc(P, nL); + end; + end; +end; +{$ENDIF UseMultiBytesNop} + +function IsNop(const P: PByte; Len: ShortInt; MultiBytesNop: Boolean = False): Boolean; +var + i: Integer; + Q: PByte; +begin + { Return True if the first instructions are nop/multi nop ! } + Result := False; + Q := P; +{$IFDEF UseMultiBytesNop} + if (MultiBytesNop and (iMultiNop in CPUInsts)) then + Result := IsMultiBytesNop(P, Len) + else +{$ENDIF UseMultiBytesNop} + for i := 0 to Len - 1 do + begin + Result := (Q^ = opNop); + if not Result then + Exit; + Inc(Q); // Next Byte. + end; +end; + +procedure FillNop(var P; const Size: Integer; const MultiBytesNop: Boolean = False); {$IFDEF MustInline}inline; {$ENDIF} +begin +{$IFDEF UseMultiBytesNop} + if (MultiBytesNop and (iMultiNop in CPUInsts)) then + FillMultiNop(P, Size) + else +{$ENDIF UseMultiBytesNop} + FillChar(PByte(@P)^, Size, opNop); +end; + +function GetPrefixesCount(Prefixes: WORD): Byte; +var + Prf: WORD; + i: Byte; +begin + { Get prefixes count used by the instruction. } + Result := 0; + if Prefixes = 0 then + Exit; + + Prf := 0; + i := 0; + Prefixes := Prefixes and not Prf_VEX; + while Prf < $8000 do + begin + Prf := (1 shl i); + if (Prf and Prefixes = Prf) then + Inc(Result); + Inc(i); + end; +end; + +function GetInstOpCodes(PInst: PInstruction; P: PByte): ShortInt; +var + nPrfs: Byte; +begin + { + Return opcodes length + Instruction OpCodes in arg P . + } + Result := 0; + FillChar(P^, MAX_INST_LENGTH_N, $90); + nPrfs := GetPrefixesCount(PInst^.Prefixes); + Inc(Result, nPrfs); + case PInst^.OpTable of + tbTwoByte: + if PInst^.Prefixes and Prf_VEX3 = 0 then + Inc(Result); // $0F + tbThreeByte: + begin + if PInst^.Prefixes and Prf_VEX3 = 0 then + Inc(Result, 2); // 0F + 38|3A ! + end; + tbFPU: Inc(Result, 2); // [$D8..$D9] + ModRm ! + end; + if PInst^.Prefixes and Prf_Vex2 <> 0 then + Inc(Result); // VEX.P0 + if PInst^.Prefixes and Prf_VEX3 <> 0 then + Inc(Result, 2); // VEX.P0 + VEX.P1 + if PInst^.OpKind = kGrp then + Inc(Result, 2) // Group + ModRm + else + Inc(Result); // OpCode + if Assigned(P) then + Move(PInst^.Addr^, P^, Result); +end; + +function CorrectJ(PInst: PInstruction; NewAddr: PByte): Integer; +const + { Convert LOOP instruction to relative word jcc ! } + LOOP_To_JccZ: array [0 .. 3] of WORD = ($850F, $840F, $840F, $9090); + { Convert LOOP instruction to relative byte jcc ! } + LOOP_To_JccB: array [0 .. 3] of Byte = ($75, $74, $75, $90); +var + Offset: Int64; + POpc: PByte; + // Opcsz: Integer; + NOpc: DWORD; + PQ: PByte; + Relsz: Byte; + JmpType: Byte; + JmpSize: Byte; + function GetJccOpCode(RelSize: Byte): DWORD; + var + LOp: Byte; + Opc: array [0 .. 3] of Byte; + begin + FillChar(PByte(@Opc[0])^, 4, #0); + LOp := PInst^.OpCode and $F; + case RelSize of + ops8bits: + begin + Opc[0] := $70 or LOp; + end; + ops16bits: + begin + Opc[0] := opPrfOpSize; + Opc[1] := $0F; + Opc[2] := $80 or LOp; + end; + ops32bits: + begin + Opc[0] := $0F; + Opc[1] := $80 or LOp; + end; + end; + Result := PDWORD(@Opc[0])^; + end; + +begin + PQ := NewAddr; + JmpSize := 0; + GetMem(POpc, MAX_INST_LENGTH_N + 1); + try + // Opcsz := GetInstOpCodes(PInst, POpc); + Offset := Int64(UInt64(PInst^.Branch.Target) - UInt64(PQ) - 6); + Relsz := GetInt64Size(Offset); +{$IFDEF CPUX64} + if Relsz = ops16bits then + Relsz := ops32bits; +{$ENDIF CPUX64} + if PInst^.OpType and otJcc = 0 then + begin + { Not Jcc ! } + if PInst^.OpCode in [$E0 .. $E2] then + begin + { LOOPNE/LOOPZ/LOOP } + if Relsz = ops8bits then + begin + if PInst^.Prefixes and Prf_AddrSize <> 0 then + begin + PQ^ := opPrfAddrSize; + Inc(PQ); + end; + PQ^ := PInst^.OpCode; + Inc(PQ); + PQ^ := Int8(Offset); + Inc(PQ); + end + else + case PInst^.AddrMode of + am16: + begin + { Dec CX ! } +{$IFDEF CPUX64} + { . $49 result in REX + ==> Use $FF group ! + } + PQ^ := opPrfOpSize; + Inc(PQ); + PQ^ := $FF; + Inc(PQ); + PQ^ := $C9; + Inc(PQ); +{$ELSE !CPUX64} + PQ^ := opPrfOpSize; + Inc(PQ); + PQ^ := $49; + Inc(PQ); +{$ENDIF CPUX64} + end; + am32: + begin + { Dec ECX ! } +{$IFDEF CPUX64} + PQ^ := $FF; + Inc(PQ); + PQ^ := $C9; + Inc(PQ); +{$ELSE !CPUX64} + PQ^ := $49; + Inc(PQ); +{$ENDIF CPUX64} + end; + am64: + begin + { Dec RCX ! } + PQ^ := $48; // REX.W = True ! + Inc(PQ); + PQ^ := $FF; + Inc(PQ); + PQ^ := $C9; + Inc(PQ); + end; + end; + case Relsz of + ops16bits: + begin + Offset := Int64(UInt64(PInst^.Branch.Target) - UInt64(PQ) - 5); + PQ^ := opPrfOpSize; + Inc(PQ); + PWord(PQ)^ := LOOP_To_JccZ[PInst^.OpCode and 3]; + Inc(PQ, 2); + PInt16(PQ)^ := Int16(Offset); + Inc(PQ, 2); + end; + ops32bits: + begin + Offset := Int64(UInt64(PInst^.Branch.Target) - UInt64(PQ) - 6); + PWord(PQ)^ := LOOP_To_JccZ[PInst^.OpCode and 3]; + Inc(PQ, 2); + PInt32(PQ)^ := Int32(Offset); + Inc(PQ, 4); + end; + ops64bits: + begin + { + Dec RCX + Jcc @Tmp + Jmp @NextInst + @Tmp: + Jmp @LoopDst + } + { Insert Jcc ! } + PQ^ := LOOP_To_JccB[PInst^.OpCode and 3]; + Inc(PQ); + PQ^ := 2; + Inc(PQ); + { Insert Jmp NextInst } + PQ^ := opJmpRelb; + Inc(PQ); + PQ^ := 14; + Inc(PQ); + { Insert Jmp @LoopDst } + InsertJmp(PQ, PInst.Branch.Target, tJmpRipZ); + Inc(PQ, 14); + end; + end; + end + else if PInst^.OpCode = $E3 then + begin + { JCXZ/JECX/JRCX } + if Relsz = ops8bits then + begin + if PInst^.Prefixes and Prf_AddrSize <> 0 then + begin + PQ^ := opPrfAddrSize; + Inc(PQ); + end; + PQ^ := PInst^.OpCode; + Inc(PQ); + PQ^ := Int8(Offset); + Inc(PQ); + end + else + case PInst^.AddrMode of + am16: + begin + { TEST CX,CX } + PQ^ := opPrfOpSize; + Inc(PQ); + PQ^ := opTestb; + Inc(PQ); + PQ^ := $C9; // ModRm [Mod = 3; Reg = Rm = CX = 1] + Inc(PQ); + end; + am32: + begin + { TEST ECX,ECX } + PQ^ := opTestb; + Inc(PQ); + PQ^ := $C9; + Inc(PQ); + end; + am64: + begin + { TEST RCX,RCX } + PQ^ := $48; // REX.W = True ! + Inc(PQ); + PQ^ := opTestb; + Inc(PQ); + PQ^ := $C9; + Inc(PQ); + end; + end; + case Relsz of + ops16bits: + begin + { + TEST CX,CX + JZ @Dst + } + Offset := Int64(UInt64(PInst^.Branch.Target) - UInt64(PQ) - 5); + PQ^ := opPrfOpSize; + Inc(PQ); + PQ^ := $0F; + Inc(PQ); + PQ^ := $84; // JZ ! + Inc(PQ); + PInt16(PQ)^ := Int16(Offset); + Inc(PQ, 2); + end; + ops32bits: + begin + { + TEST ECX,ECX + JZ @Dst + } + Offset := Int64(UInt64(PInst^.Branch.Target) - UInt64(PQ) - 6); + PQ^ := $0F; + Inc(PQ); + PQ^ := $84; // JZ ! + Inc(PQ); + PInt32(PQ)^ := Int32(Offset); + Inc(PQ, 4); + end; + ops64bits: + begin + { + TEST RCX,RCX + JZ @Tmp + Jmp @NextInst + @Tmp: + Jmp @Dst + } + { Insert JZ ! } + PQ^ := $74; + Inc(PQ); + PQ^ := 2; + Inc(PQ); + { Insert Jmp NextInst } + PQ^ := opJmpRelb; + Inc(PQ); + PQ^ := 14; + Inc(PQ); + { Insert Jmp @Dst } + InsertJmp(PQ, PInst.Branch.Target, tJmpRipZ); + Inc(PQ, 14); + end; + end; + end; + end else begin + { Jcc ! } + NOpc := GetJccOpCode(Relsz); + case Relsz of + ops8bits: + begin + Offset := Int64(UInt64(PInst^.Branch.Target) - UInt64(PQ) - 2); + PInt8(PQ)^ := UInt8(NOpc); + Inc(PQ); + PInt8(PQ)^ := Int8(Offset); + Inc(PQ); + end; + ops16bits: + begin + Offset := Int64(UInt64(PInst^.Branch.Target) - UInt64(PQ) - 5); + PUInt32(PQ)^ := UInt32(NOpc); + Inc(PQ, 3); + PInt16(PQ)^ := Int16(Offset); + Inc(PQ, 2); + end; + ops32bits: + begin + Offset := Int64(UInt64(PInst^.Branch.Target) - UInt64(PQ) - 6); + PUInt16(PQ)^ := UInt16(NOpc); + Inc(PQ, 2); + PInt32(PQ)^ := Int32(Offset); + Inc(PQ, 4); + end; + ops64bits: + begin + { + Unfortunately there is no Jcc Rel 64bits ! + + ===>Original implementation<=== + test eax,eax + jz @DstAddr + + ===>New implementation<=== + test eax,eax + Q: jz @tmp + Q+2: jmp @NextInst + Q+4: @tmp: + Q+4: jmp @DstAddr + Q+4+jmpsize: [DstAddr] + @NextInstruction: + } + + { jz @tmp is guaranteed to be 2 Bytes in length ! } + { Trampo.NextInstruction = Q + 4 + jmp @DstAddr Size } + PQ^ := PInst^.OpCode; + Inc(PQ); + PQ^ := 2; + Inc(PQ); + JmpType := GetJmpType(NewAddr + 4, PInst^.Branch.Target, NewAddr + 4 + 6); + JmpSize := JmpTypeToSize[JmpSize]; + if JmpType > tJmpRel32 then + Inc(JmpSize, SizeOf(Pointer)); + + { Jmp To Next Valid Instruction ! } + PQ^ := opJmpRelb; + Inc(PQ); + PQ^ := JmpSize; + Inc(PQ); + + InsertJmp(NewAddr + 4, PInst^.Branch.Target, JmpType, NewAddr + 4 + 6); + Inc(PQ, JmpSize); + end; + end; + end; + finally + FreeMem(POpc); + end; + Result := PQ - NewAddr; + if Result = 00 then + begin + Move(PInst^.Addr^, NewAddr^, PInst^.InstSize); + Result := PInst^.InstSize; + end; +end; + +function MakeModRm(iMod, Reg, Rm: Byte): Byte; {$IFDEF MustInline}inline; {$ENDIF} +begin + Result := (iMod shl 6) or (Reg shl 3) or (Rm); +end; + +function CorrectRipDisp(PInst: PInstruction; NewAddr: PByte): Integer; +type + PNativeUInt = ^NativeUInt; +var + Offset: Int64; + P: PByte; + rReg: Byte; + POpc: PByte; + pMR: PByte; + pFrst: PByte; + L: ShortInt; +begin + pFrst := NewAddr; + P := PInst^.NextInst; + { + If AddressMode is 32-bits : + ===> EIP + Disp32 ! + else + If AddressMode is 64-bits: + ===> RIP + Disp32 ! + } + if PInst^.AddrMode = am32 then + P := PByte(UInt64(P) and $FFFFFFFF); + + P := P + Int64(PInst^.Disp.Value); + + Offset := Int64(UInt64(P) - UInt64(NewAddr) - PInst^.InstSize); + if Int32(Offset) <> Offset then + begin + rReg := rEAX; + if PInst^.ModRm.Flags and mfUsed <> 0 then + begin + Assert(PInst^.Disp.Flags and dfRip <> 0); + if PInst^.ModRm.Reg = rReg then + rReg := rECX; + + { PUSH UsedReg } + PByte(NewAddr)^ := $50 + (rReg and $7); + Inc(NewAddr); + +{$IFDEF CPUX64} + PByte(NewAddr)^ := $48; // REX.W! + Inc(NewAddr); +{$ENDIF CPUX64} + { MOV REG,Imm(NativeUInt) } + PByte(NewAddr)^ := $B8 + (rReg and $7); + Inc(NewAddr); + PNativeUInt(NewAddr)^ := NativeUInt(P); + Inc(NewAddr, SizeOf(NativeUInt)); + + { Set the original instruction opcodes } + POpc := GetMemory(MAX_INST_LENGTH_N); + L := GetInstOpCodes(PInst, POpc); + + Move(PByte(@POpc[0])^, NewAddr^, L); + Inc(NewAddr, L); + pMR := NewAddr; + if (PInst^.OpKind and kGrp <> 0) or (PInst^.OpTable = tbFPU) then + Dec(pMR); + + PByte(pMR)^ := MakeModRm($00, PInst^.ModRm.Reg, rReg); + Inc(pMR); + NewAddr := pMR; + + { POP UsedReg } + PByte(NewAddr)^ := $58 + (rReg and $7); + Inc(NewAddr); + + FreeMemory(POpc); + Exit(NewAddr - pFrst); + end + else + raise InterceptException.Create(ErrRipDisp); + end; + Move(PInst^.Addr^, NewAddr^, PInst^.InstSize); + Inc(NewAddr, PInst^.InstSize); + PInt32(NewAddr - SizeOf(Int32))^ := Int32(Offset); + + Result := PInst^.InstSize; +end; + +function CorrectJmpRel(PInst: PInstruction; NewAddr: PByte): Integer; +var + JmpType: Byte; +begin + JmpType := GetJmpType(NewAddr, PInst^.Branch.Target, NewAddr + 6); + InsertJmp(NewAddr, PInst^.Branch.Target, JmpType, NewAddr + 6); + Result := JmpTypeToSize[JmpType]; +end; + +function CorrectCallRel(PInst: PInstruction; NewAddr: PByte): Integer; +var + Offset: Int64; + Relsz: Byte; + P: PByte; +begin + P := NewAddr; + Offset := Int64(UInt64(PInst^.Branch.Target) - UInt64(P) - 6); + Relsz := GetInt64Size(Offset); +{$IFDEF CPUX64} + { Only 32-bits relative offset is supported on x64! } + if Relsz < ops32bits then + Relsz := ops32bits; +{$ELSE !CPUX64} + { Only 16/32-bits relative offset is supported on x32! } + if Relsz < ops16bits then + Relsz := ops32bits; +{$ENDIF CPUX64} + case Relsz of + ops16bits: + begin + Offset := Int64(UInt64(PInst^.Branch.Target) - UInt64(P) - 4); + P^ := opPrfOpSize; + Inc(P); + P^ := $E8; + Inc(P); + PInt16(P)^ := Int16(Offset); + Inc(P, 2); + end; + ops32bits: + begin + Offset := Int64(UInt64(PInst^.Branch.Target) - UInt64(P) - 5); + P^ := $E8; + Inc(P); + PInt32(P)^ := Int32(Offset); + Inc(P, 4); + end; + ops64bits: + begin + { + 64-bits Relative offset is not supported + ==> Map to a new opcode ! + } + { + CALL [02] + Jmp @NextValidInstruction + dq : Call dst address ! + @NextValidInstruction: + + } + P^ := $FF; // Group 5 ! + Inc(P); + { + ModRm.Mod = 00 + ModRm.Reg = 02 + ModRm.Rm = 05 + ==> ModRm = $15 ! + } + P^ := MakeModRm($00, $02, $05); + Inc(P); + P^ := 2; + Inc(P, 4); + + { Jmp Next Instruction ! } + P^ := opJmpRelb; + Inc(P); + P^ := $08; + Inc(P); + PUInt64(P)^ := UInt64(PInst^.Branch.Target); + Inc(P, SizeOf(UInt64)); + end; + end; + Result := P - NewAddr; + if Result = 0 then + begin + Move(PInst^.Addr^, P^, PInst^.InstSize); + Result := PInst^.InstSize; + end; +end; + +function MapInsts(Addr, NewAddr: PByte; Size: Integer): Integer; +var + P, Q: PByte; + PInst: PInstruction; + sz, iz, nz: Integer; +begin + { Map Data from Addr to NewAddr ! } + { This function will fix Relative offset & RIP displacement . } + Result := 0; + sz := 0; + P := Addr; + Q := NewAddr; + PInst := GetMemory(SizeOf(TInstruction)); + FillChar(PInst^, SizeOf(TInstruction), #0); + + PInst^.Archi := CPUX; + PInst^.NextInst := P; + PInst^.VirtualAddr := nil; + + while sz < Size do + begin + PInst^.Addr := PInst^.NextInst; + iz := fDecodeInst(PInst); + nz := iz; + if PInst^.Disp.Flags and (dfUsed or dfRip) = (dfUsed or dfRip) then + nz := CorrectRipDisp(PInst, Q) + else if (PInst^.Branch.Falgs and bfRel = bfRel) then + begin + { Instruction use relative offset } + if (PInst^.OpType = otJMP) then + nz := CorrectJmpRel(PInst, Q) + else if (PInst^.OpType = otCALL) then + nz := CorrectCallRel(PInst, Q) + else + nz := CorrectJ(PInst, Q) + end + else + Move(PInst^.Addr^, Q^, nz); + Inc(Q, nz); + Inc(Result, nz); + Inc(sz, iz); + end; + FreeMemory(PInst); +end; + +const + arNone = $00; + arPlus = $08; + arMin = $10; + arAdd = arPlus or $01; + arSub = arMin or $01; + arInc = arPlus or $02; + arDec = arMin or $02; + +{$WARN COMPARISON_TRUE OFF} + +function GetInstArithmeticType(PInst: PInstruction): Byte; + function IsInstAdd(PInst: PInstruction): Boolean; + begin + Result := False; + if PInst^.OpTable = tbOneByte then + begin + if (PInst^.OpCode >= $00) and (PInst^.OpCode < $06) then + Exit(True); + end; + if (PInst^.OpKind = kGrp) and (PInst^.ModRm.Reg = $00) then + begin + if (PInst^.OpCode > $7F) and (PInst^.OpCode < $84) then + Exit(True); + end; + end; + function IsInstSub(PInst: PInstruction): Boolean; + begin + Result := False; + if PInst^.OpTable = tbOneByte then + begin + if (PInst^.OpCode > $27) and (PInst^.OpCode < $2E) then + Exit(True); + end; + if (PInst^.OpKind = kGrp) and (PInst^.ModRm.Reg = $05) then + begin + if (PInst^.OpCode > $7F) and (PInst^.OpCode < $84) then + Exit(True); + end; + end; + function IsInstInc(PInst: PInstruction): Boolean; + begin + Result := False; + if (PInst^.Archi = CPUX32) and (PInst^.OpTable = tbOneByte) then + begin + if (PInst^.OpCode >= $40) and (PInst^.OpCode <= $47) then + Exit(True); + end; + if (PInst^.OpKind = kGrp) and (PInst^.ModRm.Reg = $00) then + begin + if (PInst^.OpCode = $FE) or (PInst^.OpCode = $FF) then + Exit(True); + end; + end; + function IsInstDec(PInst: PInstruction): Boolean; + begin + Result := False; + if (PInst^.Archi = CPUX32) and (PInst^.OpTable = tbOneByte) then + begin + if (PInst^.OpCode >= $48) and (PInst^.OpCode <= $4F) then + Exit(True); + end; + if (PInst^.OpKind = kGrp) and (PInst^.ModRm.Reg = $01) then + begin + if (PInst^.OpCode = $FE) or (PInst^.OpCode = $FF) then + Exit(True); + end; + end; + +begin + { Return Instruction Arithmetic (+ or - or ..) } + Result := arNone; + if IsInstAdd(PInst) then + Exit(arAdd); + if IsInstInc(PInst) then + Exit(arAdd); + if IsInstSub(PInst) then + Exit(arSub); + if IsInstDec(PInst) then + Exit(arSub); +end; +{$WARN COMPARISON_TRUE ON} + +function EvalArithU(Arith: Byte; Value: NativeUInt; Offset: NativeInt): NativeUInt; +begin + Result := Value; + case Arith of + arAdd: Inc(Result, Offset); + arInc: Inc(Result); + arSub: Dec(Result, Offset); + arDec: Dec(Result); + end; +end; + +{$HINTS OFF} + +function InterfaceToObj(const AIntf): TObject; +const + { + Delphi insert QueryInterface,_AddRef,_Release methods + as the last functions in the code entry. + => We must skip them to point to the first function declared in the interface. + } + Offset = SizeOf(Pointer) * 3; +{$IFDEF CPUX64} + ObjReg = rECX; +{$ELSE !CPUX64} + ObjReg = rEAX; +{$ENDIF CPUX64} +var + Pvt, PCode: PByte; + Inst: TInstruction; + PObj: PByte; + imm: Int64; + Arith: Byte; + Skip: Boolean; + sReg: ShortInt; +begin + + if not Assigned(@AIntf) then + Exit(nil); + + sReg := -1; + PObj := PByte(AIntf); +{$IFNDEF FPC} + Inst := default (TInstruction); +{$ENDIF !FPC} + Inst.Archi := CPUX; + Pvt := PPointer(AIntf)^; // vTable ! + PCode := PPointer(Pvt + Offset)^; // Code Entry ! + Inst.NextInst := PCode; + { + At the top of code entry delphi will generate : + int 3 + add/sub eax/rcx,offset <=== + jmp FirstFunction + } + + while True do + begin + Inst.imm.Value := 0; + Inst.Addr := Inst.NextInst; + fDecodeInst(@Inst); + { Keep looping until JMP/RET ! } + if (Inst.Branch.Falgs and bfUsed <> 0) or (Inst.OpType = otRET) then + Break; + + Arith := GetInstArithmeticType(@Inst); + Skip := (Arith = arNone); + + if not Skip then + begin +{$IFDEF CPUX86} + if Inst.ModRm.iMod <> $03 then + begin + { + ====> stdcall ! <==== + If the method (declared in interface) + calling convention is stdcall, + Delphi will generate : + add/sub [esp+offset],imm ! + } + if Inst.Sib.Flags and sfUsed <> 0 then + sReg := Inst.Sib.Index + else + sReg := Inst.ModRm.Rm; + Skip := not(sReg = rESP); + end + else +{$ENDIF CPUX86} + begin + if (Inst.ModRm.Flags and mfUsed <> 0) then + Skip := not((Inst.ModRm.iMod = $03) and (Inst.ModRm.Rm = ObjReg)) + else if Arith in [arInc, arDec] then + { Is Inc/Dec EAX/RCX ? } + Skip := (Inst.OpCode and $07 <> ObjReg); + end; + end; + + if not Skip then + begin + imm := Inst.imm.Value; + PObj := PByte(EvalArithU(Arith, NativeUInt(PObj), imm)); + end; + end; + + Result := TObject(PObj); +end; + +{$HINTS ON} + +function GetInterfaceMethodPtrByIndex(const PInterface; MethodIndex: Integer): PByte; +var + Pvt: PPointer; + P: PPointer; + PDst: PByte; + Inst: TInstruction; + i: Integer; +begin + { + Return original method ptr + => Return first instruction that was + implemented on Interface object ! + } +{$IFNDEF FPC} + Inst := default (TInstruction); +{$ENDIF !FPC} + Inst.Archi := CPUX; + Pvt := PPointer(PInterface)^; // Virtual Table ! + P := Pvt; + // Inc(PByte(P), MethodIndex * SizeOf(NativeUInt)); + Inc(P, MethodIndex); + P := PPointer(P)^; + PDst := PByte(P); + Inst.NextInst := PByte(P); + for i := 0 to 3 do + begin + Inst.Addr := Inst.NextInst; + fDecodeInst(@Inst); + if Assigned(Inst.Branch.Target) then + begin + PDst := Inst.Branch.Target; + Break; + end; + end; + Result := PDst; +end; + +{$IFDEF MustUseGenerics} + +function GetMethodPtrFromObjByName(Obj: TObject; const MethodName: String): Pointer; +var + LCtx: TRttiContext; + LType: TRttiType; + LMethods: TArray; + LMethod: TRttiMethod; +begin + Result := nil; + if (not Assigned(Obj)) or (MethodName = EmptyStr) then + Exit; + + LCtx := TRttiContext.Create; + LType := LCtx.GetType(Obj.ClassType); + LMethods := LType.GetMethods; + for LMethod in LMethods do + begin + if SameText(LMethod.Name, MethodName) then + Exit(LMethod.CodeAddress); + end; +end; + +function GetInterfaceMethodPtrByName(const PInterface; const MethodName: String): PByte; +var + Obj: TObject; +begin + Result := nil; + if (not Assigned(@PInterface)) or (MethodName = EmptyStr) then + Exit; + Obj := InterfaceToObj(PInterface); + if Assigned(Obj) then + begin + Result := GetMethodPtrFromObjByName(Obj, MethodName); + end; +end; + +var + GlobalThreadList: TDictionary; + +{$ENDIF MustUseGenerics} + { TIntercept } + +constructor TIntercept.Create(Options: Byte); +begin + FOptions := Options; + FList := nil; + + if (FOptions and ST = ST) +{$IFDEF MustUseGenerics} + and (not GlobalThreadList.ContainsKey(GetCurrentThread)) +{$ENDIF MustUseGenerics} + then + begin + { Suspend All threads ! } + if OpenThreadExist then + begin + FList := TThreadsIDList.Create; + SuspendAllThreads(FList); + end; + end; + + if not Assigned(FList) then + begin + TInterceptMonitor.Enter(); + end; +end; + +destructor TIntercept.Destroy; +begin + if Assigned(FList) then + begin + ResumeSuspendedThreads(FList); + FreeAndNil(FList); + end else begin + TInterceptMonitor.Leave(); + end; + inherited; +end; + +function TIntercept.GetDescriptor(P: PByte): PDescriptor; +var + Inst: TInstruction; + function IsDscrpInst(PInst: PInstruction): Boolean; + begin + Result := +{$IFDEF UseMultiBytesNop} + (IsNop(PInst.Addr, 6, True)) or +{$ELSE !UseMultiBytesNop} + (IsNop(PInst.Addr, 6)) or +{$ENDIF UseMultiBytesNop} + (Assigned(PInst.Branch.Target)); + end; + +begin + Result := nil; +{$IFNDEF FPC} + Inst := default (TInstruction); +{$ENDIF !FPC} + Inst.Archi := CPUX; + Inst.VirtualAddr := nil; + { Find last JMP ! } + P := GetRoot(P); + Inst.Addr := P; + fDecodeInst(@Inst); + + { The first instruction must be NOP ! } + if Inst.OpCode = opNop then + begin + Inst.Addr := Inst.NextInst; + fDecodeInst(@Inst); + if IsDscrpInst(@Inst) then + begin + Inc(P); // Skip CodeEntry ! + Inc(P, SizeOf(TJmpMem) * (MAX_HOOKS + 1)); // Skip JmpMems ! + { Go to the Top ! } + Dec(P, SizeOf(TDescriptor)); + if IsValidDescriptor(P) then + Result := PDescriptor(P); + end; + end; +end; + +class function TIntercept.GetRoot(P: PByte): PByte; +var + Inst: TInstruction; +begin + Result := P; +{$IFNDEF FPC} + Inst := default (TInstruction); +{$ENDIF !FPC} + Inst.Addr := P; + Inst.Archi := CPUX; + Inst.VirtualAddr := nil; + { + While the opcode is jmp and the jmp destination + address is known get the next jmp . + } + fDecodeInst(@Inst); + if (Inst.OpType = otJMP) and (Assigned(Inst.Branch.Target)) then + Result := GetRoot(Inst.Branch.Target); +end; + +function TIntercept.CreateNewDescriptor: PDescriptor; +begin + { Create a new descriptor tables ! } + Result := AllocMem(SizeOf(TDescriptor)); + { + Hahaha .. this stupid code (between commenet) + had take me 2h to figure why my libray does not works ! + I didn't know what i was thinking in when i wrote this code ! + :) + } + // SetMemPermission(Result, SizeOf(TDescriptor), PAGE_READWRITE); + // SetMemPermission(@Result^.JmpMems, SizeOf(TJmpMem) * (MAX_HOOKS + 1), PAGE_EXECUTE_READWRITE); + FillNop(Result^, SizeOf(TDescriptor)); + FillNop(Result^.JmpMems[0], SizeOf(TJmpMem) * (MAX_HOOKS + 1), True); + + { A valid descriptor have a valid signature . } + CopyMemory(Result, PByte(@DscrSig[0]), DscrSigSize); + Result^.nHook := 0; + Result^.Flags := 0; + Result^.ExMem := nil; +end; + +procedure TIntercept.InsertDescriptor(PAt: PByte; PDscr: PDescriptor); +const + { JMP from Target to Code Entry } + kJmpCE = 1; + { JMP from Target to Temporal address than JMP to Code Entry } + kJmpTmpJmpCE = 2; + { JMP from Target to Temporal address than JMP (Rip Zero) to Code Entry } + kJmpTmpJmpRipZCE = 3; + { JMP (Rip Zero) from Target to Code Entry } + kJmpRipZCE = 4; + +var + fJmpType: Byte; { First JMP } +{$IFDEF CPUX64} + sJmpType: Byte; { Second JMP (if used !) } + Tmp: PByte; +{$ENDIF CPUX64} + JmpKind: Byte; + P, T: PByte; + JmpSize: Byte; + Inst: TInstruction; + Sb: Byte; + OrgAccess: DWORD; + Tsz: Integer; + PExMem: PByte; + LPExMem: PByte; +begin + JmpKind := kJmpCE; + Sb := 0; + P := PAt; + PDscr^.OrgPtr := P; + fJmpType := GetJmpType(P, @PDscr^.CodeEntry, @PDscr^.DscrAddr); +{$IFDEF CPUX64} + Tmp := nil; + PExMem := TryAllocMemAt(P, SizeOfAlloc, PAGE_EXECUTE_READWRITE); +{$ELSE !CPUX64} + PExMem := TryAllocMemAt(nil, SizeOfAlloc, PAGE_EXECUTE_READWRITE); +{$ENDIF CPUX64} + LPExMem := PExMem; +{$IFDEF CPUX64} + sJmpType := tJmpNone; + JmpKind := kJmpRipZCE; + { Try to find the perfect jump instruction ! } + { + That's mean that we try to avoid using tJmpRelN on TargetProc . + ==> Because it use more than 6 bytes in length . + } + if JmpTypeToSize[fJmpType] > 6 then + begin + Tmp := PExMem; + Inc(PExMem, TmpSize); + if Assigned(Tmp) then + begin + JmpKind := kJmpRipZCE; + fJmpType := GetJmpType(P, Tmp, Tmp + 6); + if JmpTypeToSize[fJmpType] < 7 then + begin + JmpKind := kJmpTmpJmpRipZCE; + sJmpType := GetJmpType(Tmp, @PDscr^.CodeEntry, Tmp + 6 + 8); + if JmpTypeToSize[sJmpType] < 7 then + JmpKind := kJmpTmpJmpCE; + end; + end; + end else begin + JmpKind := kJmpCE; + end; +{$ENDIF CPUX64} +{$IFNDEF FPC} + Inst := default (TInstruction); +{$ENDIF !FPC} + Inst.Archi := CPUX; + Inst.NextInst := P; + Inst.VirtualAddr := nil; + + JmpSize := JmpTypeToSize[fJmpType]; + + while Sb < JmpSize do + begin + if Inst.OpType = otRET then + raise InterceptException.Create(ErrFuncSize); + Inst.Addr := Inst.NextInst; + Inc(Sb, fDecodeInst(@Inst)); + end; + + if Sb > TrampoSize then + raise InterceptException.Create(ErrTrampoSize); + + { Trampoline momory } + T := PExMem; + FillNop(T^, TrampoSize); + + PDscr^.Trampo := AllocMem(SizeOf(TTrampoInfo)); + PDscr^.Trampo^.PData := AllocMem(Sb + 6); + FillNop(PDscr^.Trampo^.PData^, Sb + 6); + { Save original target routine instruction . } + Move(P^, PDscr^.Trampo^.PData^, Sb); + PDscr^.Trampo^.Addr := T; // Pointer to the first trampoline instruction. + PDscr^.Trampo^.Size := Sb; // Size of stolen instructions . + + Tsz := MapInsts(P, T, Sb); + OrgAccess := SetMemPermission(P, Sb, PAGE_EXECUTE_READWRITE); + try + FillNop(P^, Sb); + case JmpKind of + kJmpCE: + begin + { A very good jump ! } + { + TargetProc : + JMP @PDscr^.CodeEntry + } + InsertJmp(P, @PDscr^.CodeEntry, fJmpType, @PDscr^.DscrAddr); + end; +{$IFDEF CPUX64} + kJmpTmpJmpCE: + begin + { + TargetProc : + JMP @Tmp ==> Tmp is allocated nearly from TargetProc ! + + Tmp: + JMP @PDscr^.CodeEntry + } + InsertJmp(P, Tmp, fJmpType, Tmp + 6); + InsertJmp(Tmp, @PDscr^.CodeEntry, sJmpType, Tmp + 6 + 8); + end; + kJmpTmpJmpRipZCE: + begin + { + TargetProc : + JMP @Tmp ==> Tmp is allocated nearly from TargetProc ! + + Tmp: + JMP @PDscr^.CodeEntry ==> tJmpRipZ + } + InsertJmp(P, Tmp, fJmpType, Tmp + 6); + InsertJmp(Tmp, @PDscr^.CodeEntry, tJmpRipZ, nil); + end; + kJmpRipZCE: + begin + { + Not a good jump ! + + TargetProc : + JMP @PDscr^.CodeEntry ==> tJmpRipZ + } + InsertJmp(P, @PDscr^.CodeEntry, tJmpRipZ, nil); + end; +{$ENDIF CPUX64} + end; + + { + Insert a JMP instruction after the stolen instructions + on the trampoline. + ==> This JMP will return to TargetProc to allow + executing originals instructions. + } +{$IFDEF CPUX64} + // InsertJmp(T + Tsz, P + JmpTypeToSize[fJmpType], tJmpRipZ); + InsertJmp(T + Tsz, P + Sb, tJmpRipZ); +{$ELSE !CPUX64} + InsertJmp(T + Tsz, P + Sb, tJmpMem32, T + Tsz + 6); +{$ENDIF CPUX64} + { Save LPExMem ==> we need it when deleting descriptor } + PDscr^.ExMem := LPExMem; + + SetMemPermission(LPExMem, SizeOfAlloc, PAGE_EXECUTE_READWRITE); + SetMemPermission(PDscr, SizeOf(TDescriptor), PAGE_EXECUTE_READWRITE); + finally + SetMemPermission(P, Sb, OrgAccess); + end; +end; + +function TIntercept.IsValidDescriptor(P: PByte): Boolean; +begin + Result := CompareMem(P, PByte(@DscrSig[0]), SizeOf(DscrSig)); +end; + +function TIntercept.AddHook(PDscr: PDescriptor; InterceptProc: PByte; const Options: Byte): PByte; +var + n: ShortInt; + NxHook: PByte; +begin + { + Return a pointer to a function that can + call next installed Hooks. + } + n := PDscr^.nHook; + if n + 1 > MAX_HOOKS then + raise InterceptException.Create(ErrMaxHook); + + { Alloc memory for the NextHook ! } + NxHook := AllocMem(TrampoSize); + Result := NxHook; + + FillNop(Result^, TrampoSize); + + PNextHook(Result)^.PDscr := PDscr; + PNextHook(Result)^.ID := n + 1; + Inc(Result, SizeOf(TNextHook)); + + { Redirect code to InterceptProc ! } + InsertJmp(@PDscr^.JmpMems[n], InterceptProc, tJmpMemN, @PDscr^.JmpAddrs[n]); + { Redirect code to TrampoLine ! } + InsertJmp(@PDscr^.JmpMems[n + 1], PDscr^.Trampo^.Addr, tJmpMemN, @PDscr^.JmpAddrs[n + 1]); + { Redirect code to next hook ! } + InsertJmp(Result, @PDscr^.JmpMems[n + 1], tJmpMemN, Result + 6); + Inc(PDscr^.nHook); + + SetMemPermission(Result, JmpTypeToSize[tJmpRipZ], PAGE_EXECUTE_READWRITE); +end; + +function TIntercept.InstallHook(TargetProc, InterceptProc: PByte; const Options: Byte = $00): PByte; +var + P: PByte; + PDscr: PDescriptor; +begin + if not Assigned(TargetProc) then + raise InterceptException.Create(ErrTargetProc); + + if not Assigned(InterceptProc) then + raise InterceptException.Create(ErrInterceptProc); + + PDscr := GetDescriptor(TargetProc); + if not Assigned(PDscr) then + begin + P := GetRoot(TargetProc); + PDscr := CreateNewDescriptor; + try + InsertDescriptor(P, PDscr); + except + FreeMem(PDscr); + raise; + end; + end; + Result := AddHook(PDscr, InterceptProc); +end; + +procedure TIntercept.RemoveDescriptor(PDscr: PDescriptor); +var + OrgAccess: DWORD; + P: PByte; + sz: Integer; + vr: Boolean; +begin + P := PDscr^.OrgPtr; + sz := PDscr^.Trampo^.Size; + + OrgAccess := SetMemPermission(P, sz, PAGE_EXECUTE_READWRITE); + try + SetMemPermission(PDscr^.ExMem, TrampoSize, PAGE_EXECUTE_READWRITE); + + { Restore the old stolen instructions ! } + Move(PDscr^.Trampo^.PData^, PDscr^.OrgPtr^, PDscr^.Trampo^.Size); + + FillNop(PDscr^.ExMem^, SizeOfAlloc); + FreeMem(PDscr^.Trampo^.PData); + FreeMem(PDscr^.Trampo); + + if Assigned(PDscr^.ExMem) then + begin + vr := InternalFuncs.VirtualFree(PDscr^.ExMem, 0, MEM_RELEASE); + if not vr then + RaiseLastOSError; + end; + + FillNop(PDscr^, SizeOf(TDescriptor)); + FreeMem(PDscr); + finally + SetMemPermission(P, sz, OrgAccess); + end; +end; + +function TIntercept.RemoveHook(Trampo: PByte): Integer; +var + PNxtHook: PNextHook; + PDscr: PDescriptor; + n: Byte; +begin + if not Assigned(Trampo) then + raise InterceptException.Create(ErrInvalidTrampo); + + PNxtHook := PNextHook(Trampo - SizeOf(TNextHook)); + if not Assigned(PNxtHook) then + raise InterceptException.Create(ErrInvalidTrampo); + + PDscr := PNxtHook^.PDscr; + if not IsValidDescriptor(PByte(PDscr)) then + raise InterceptException.Create(ErrInvalidDscr); + + n := PNxtHook^.ID; + Dec(PDscr^.nHook); + + PDscr^.JmpAddrs[n - 1] := nil; + { Remove JMP from descriptor table } + FillNop(PByte(@PDscr^.JmpMems[n - 1])^, SizeOf(TJmpMem), True); + + { + Return the number of hooks + that are still alive ! + } + Result := PDscr^.nHook; + + if Result = 0 then + RemoveDescriptor(PDscr); + + FreeMem(PNxtHook); +end; + +function InterceptCreate(const TargetProc, InterceptProc: Pointer; Options: Byte = v1compatibility): Pointer; +var + Intercept: TIntercept; +begin + Intercept := TIntercept.Create(Options); + try + Result := Intercept.InstallHook(TargetProc, InterceptProc, Options); + finally + Intercept.Free; + end; +end; + +{ =====> Support for Interface <===== } + +function InterceptCreate(const TargetInterface; MethodIndex: Integer; const InterceptProc: Pointer; Options: Byte = v1compatibility): Pointer; +var + P: PByte; +begin + Result := nil; + if not Assigned(@TargetInterface) then + Exit; + P := GetInterfaceMethodPtrByIndex(TargetInterface, MethodIndex); + if Assigned(P) then + begin + Result := InterceptCreate(P, InterceptProc, Options); + end; +end; + +{$IFDEF MustUseGenerics} + +function InterceptCreate(const TargetInterface; const MethodName: String; const InterceptProc: Pointer; Options: Byte = v1compatibility): Pointer; overload; +var + P: PByte; +begin + Result := nil; + if (not Assigned(@TargetInterface)) or (MethodName = EmptyStr) then + Exit; + + P := GetInterfaceMethodPtrByName(TargetInterface, MethodName); + if Assigned(P) then + Result := InterceptCreate(P, InterceptProc, Options); +end; +{$ENDIF MustUseGenerics} + +function InterceptCreate(const Module, MethodName: string; const InterceptProc: Pointer; ForceLoadModule: Boolean = True; + Options: Byte = v1compatibility): Pointer; +var + pOrgPointer: Pointer; + LModule: THandle; +begin + { RRUZ's idea ==> Looks great ! } + Result := nil; + LModule := GetModuleHandle(PChar(Module)); + if (LModule = 0) and ForceLoadModule then + LModule := LoadLibrary(PChar(Module)); + + if LModule <> 0 then + begin + pOrgPointer := GetProcAddress(LModule, PChar(MethodName)); + if Assigned(pOrgPointer) then + Result := InterceptCreate(pOrgPointer, InterceptProc, Options); + end; +end; + +procedure InterceptCreate(const TargetProc, InterceptProc: Pointer; var TrampoLine: Pointer; Options: Byte = v1compatibility); +var + Intercept: TIntercept; +begin + Intercept := TIntercept.Create(Options); + try + TrampoLine := Intercept.InstallHook(TargetProc, InterceptProc, Options); + finally + Intercept.Free; + end; +end; + +function InterceptRemove(const Trampo: Pointer; Options: Byte = v1compatibility): Integer; +var + Intercept: TIntercept; +begin + if not Assigned(Trampo) then + Exit(-1); + Intercept := TIntercept.Create(Options); + try + Result := Intercept.RemoveHook(Trampo); + finally + Intercept.Free; + end; +end; + +function GetNHook(const TargetProc: Pointer): ShortInt; +var + Intercept: TIntercept; + PDscr: PDescriptor; +begin + { + Return the number of installed hooks ! + Return -1 if no hooks installed ! + } + Result := -1; + if not Assigned(TargetProc) then + raise InterceptException.Create(ErrTargetProc); + + Intercept := TIntercept.Create(0); + try + PDscr := Intercept.GetDescriptor(TargetProc); + if Assigned(PDscr) then + Result := PDscr^.nHook; + finally + Intercept.Free; + end; +end; + +function GetNHook(const TargetInterface; MethodIndex: Integer): ShortInt; overload; +var + P: PByte; +begin + P := GetInterfaceMethodPtrByIndex(TargetInterface, MethodIndex); + Result := GetNHook(P); +end; + +{$IFDEF MustUseGenerics } + +function GetNHook(const TargetInterface; const MethodName: String): ShortInt; overload; +var + P: PByte; +begin + P := GetInterfaceMethodPtrByName(TargetInterface, MethodName); + Result := GetNHook(P); +end; +{$ENDIF MustUseGenerics } + +function IsHooked(const TargetProc: Pointer): Boolean; +begin + Result := GetNHook(TargetProc) > 0; +end; + +function IsHooked(const TargetInterface; MethodIndex: Integer): Boolean; overload; +var + P: PByte; +begin + P := GetInterfaceMethodPtrByIndex(TargetInterface, MethodIndex); + Result := IsHooked(P); +end; + +{$IFDEF MustUseGenerics } + +function IsHooked(const TargetInterface; const MethodName: String): Boolean; overload; +var + P: PByte; +begin + P := GetInterfaceMethodPtrByName(TargetInterface, MethodName); + Result := IsHooked(P); +end; +{$ENDIF MustUseGenerics } + +type + TTrampoDataVt = record + vAddr: Pointer; + Addr: Pointer; + end; + + PTrampoDataVt = ^TTrampoDataVt; + +function PatchVt(const TargetInterface; MethodIndex: Integer; InterceptProc: Pointer): Pointer; +var + vt: PPointer; + P, DstAddr: PPointer; + Q: PByte; + OrgAccess: DWORD; + PInfo: PTrampoDataVt; +begin + { + NB: PatchVt does not support multi hook !! + PatchVt will patch only vtable !! + } + Result := nil; + if not Assigned(@TargetInterface) then + Exit; + if not Assigned(InterceptProc) then + Exit; + + TInterceptMonitor.Enter; + try + vt := PPointer(TargetInterface)^; + P := vt; + Inc(P, MethodIndex); + DstAddr := P^; // address ! + + OrgAccess := SetMemPermission(P, 32, PAGE_EXECUTE_READWRITE); + try + P^ := InterceptProc; + finally + SetMemPermission(P, 32, OrgAccess); + end; + + Result := InternalFuncs.VirtualAlloc(nil, 32, MEM_COMMIT or MEM_RESERVE, PAGE_EXECUTE_READWRITE); + SetMemPermission(Result, 32, PAGE_EXECUTE_READWRITE); + PInfo := Result; + PInfo^.vAddr := P; + PInfo^.Addr := DstAddr; + Inc(PByte(Result), SizeOf(TTrampoDataVt)); + + Q := Result; +{$IFDEF CPUX64} + { Use JMP RipZero ! } + PWord(Q)^ := opJmpMem; + Inc(Q, 2); + PInt32(Q)^ := $00; + Inc(Q, 4); + PNativeUInt(Q)^ := NativeUInt(DstAddr); +{$ELSE !CPUX64} + PWord(Q)^ := opJmpMem; + Inc(Q, 2); + PUInt32(Q)^ := UInt32(Q + 4); + PUInt32(Q + 4)^ := UInt32(DstAddr); +{$ENDIF CPUX64} + finally + TInterceptMonitor.Leave; + end; +end; + +function UnPatchVt(const Trampo: Pointer): Boolean; +var + OrgAccess: DWORD; + PInfo: PTrampoDataVt; +begin + if not Assigned(Trampo) then + Exit(False); + + TInterceptMonitor.Enter; + try + PInfo := PTrampoDataVt(PByte(Trampo) - SizeOf(TTrampoDataVt)); + OrgAccess := SetMemPermission(PInfo^.vAddr, 32, PAGE_EXECUTE_READWRITE); + try + PPointer(PInfo^.vAddr)^ := PInfo^.Addr; + finally + SetMemPermission(PInfo^.vAddr, 32, OrgAccess); + end; + Result := InternalFuncs.VirtualFree(Trampo, 0, MEM_RELEASE); + finally + TInterceptMonitor.Leave; + end; +end; + +{ TInterceptMonitor } + +class procedure TInterceptMonitor.InternalCreate; +begin + FLock := TObject.Create; +end; + +class procedure TInterceptMonitor.InternalDestroy; +begin + FreeAndNil(FLock); +end; + +class procedure TInterceptMonitor.Enter; +begin + { + If the current thread is working with DDL (Insert/Remove hook).. + others threads must wait before accessing + detours (Insert/Remove/...). + } +{$IFNDEF FPC} + TMonitor.Enter(FLock); +{$ELSE FPC} + EnterCriticalSection(Critical); +{$ENDIF !FPC} +end; + +class procedure TInterceptMonitor.Leave; +begin + { + After the current thread finish it's + job with TIntercept .. others thread + can now access TIntercept . + } +{$IFNDEF FPC} + TMonitor.Exit(FLock); +{$ELSE} + LeaveCriticalSection(Critical); +{$ENDIF} +end; + +{$IFDEF MustUseGenerics } +{ ***** BEGIN LICENSE BLOCK ***** + * + * The initial developer of the original TDetour + * class is David Millington . + * + * ***** END LICENSE BLOCK ***** } + +{ TDetours } + +function TDetours.CheckTType: Boolean; +var + LPInfo: PTypeInfo; +begin + LPInfo := TypeInfo(T); + Result := SizeOf(T) = SizeOf(Pointer); + if Result then + Result := LPInfo.Kind = tkProcedure; + if not Result then + raise DetourException.CreateFmt(SInvalidTType, [LPInfo.Name]); +end; + +constructor TDetours.Create(const TargetProc, InterceptProc: T); +begin + inherited Create(); + CheckTType; + SetHook(TargetProc, InterceptProc); +end; + +destructor TDetours.Destroy; +begin + Disable; + inherited; +end; + +procedure TDetours.SetHook(const TargetProc, InterceptProc: T); +begin + FTargetProc := TToPointer(TargetProc); + FInterceptProc := TToPointer(InterceptProc); + FNextHook := T(nil); + Assert(Assigned(FTargetProc) and Assigned(FInterceptProc), 'Target or replacement methods are not assigned'); +end; + +procedure TDetours.Disable; +var + PTrampoline: Pointer; +begin + if Installed then + begin + PTrampoline := TToPointer(FNextHook); + DDetours.InterceptRemove(PTrampoline); + FNextHook := T(nil); + end; +end; + +procedure TDetours.Enable; +begin + if not Installed then + FNextHook := PointerToT(InterceptCreate(FTargetProc, FInterceptProc)); +end; + +function TDetours.GetHookCount: ShortInt; +begin + Result := GetNHook(FTargetProc); +end; + +function TDetours.GetInstalled: Boolean; +begin + Result := Assigned(TToPointer(FNextHook)); +end; + +function TDetours.NextHook: T; +begin + Assert(Installed, SDetoursNotInstalled); + Result := FNextHook; +end; + +function TDetours.PointerToT(const _P: Pointer): T; +begin + Result := __PointerToT(_P); +end; + +function TDetours.TToPointer(const _T: T): Pointer; +begin + Result := __TToPointer(_T); +end; + +function TDetours.__PointerToT(const _P): T; +begin + Result := T(_P); +end; + +function TDetours.__TToPointer(const _T): Pointer; +begin + Result := Pointer(_T); +end; + +{ --------------------------------------------------------------------------- } +function BeginHooks(): Boolean; +var + List: TThreadsIDList; +begin + List := TThreadsIDList.Create; + GlobalThreadList.Add(GetCurrentThread, List); + Result := SuspendAllThreads(List); +end; + +function EndHooks(): Boolean; +var + List: TThreadsIDList; + currThread: THandle; +begin + currThread := GetCurrentThread; + List := GlobalThreadList[currThread]; + Assert(Assigned(List)); + Result := ResumeSuspendedThreads(List); + GlobalThreadList.Remove(currThread); + FreeAndNil(List); +end; + +function BeginUnHooks(): Boolean; +begin + if GlobalThreadList.ContainsKey(GetCurrentThread) then + raise InterceptException.Create(ErrBgnUnHooks); + Result := BeginHooks; +end; + +function EndUnHooks(): Boolean; +begin + Result := EndHooks; +end; +{$ENDIF MustUseGenerics} + +var + SysInfo: TSystemInfo; + +procedure InitInternalFuncs(); + + function CloneFunc(Func: PByte): PByte; + var + mb, ns, Sb, fn: Byte; + P: PByte; + Inst: TInstruction; + begin + Sb := 0; + Func := TIntercept.GetRoot(Func); + Result := VirtualAlloc(nil, 64, MEM_RESERVE or MEM_COMMIT, PAGE_EXECUTE_READWRITE); + P := Result; + mb := JmpTypeToSize[tJmpRipZ]; +{$IFNDEF FPC} + Inst := default (TInstruction); +{$ENDIF !FPC} + Inst.Archi := CPUX; + Inst.NextInst := Func; + while Sb <= mb do + begin + Inst.Addr := Inst.NextInst; + ns := fDecodeInst(@Inst); + Inc(Sb, ns); + end; + fn := MapInsts(Func, P, Sb); + Inc(P, fn); +{$IFDEF CPUX64} + InsertJmp(P, Func + Sb, tJmpRipZ); +{$ELSE !CPUX64} + InsertJmp(P, Func + Sb, tJmpRel32); +{$ENDIF CPUX64} + end; + +begin +{$IFDEF HookInternalFuncs} + @InternalFuncs.VirtualAlloc := CloneFunc(@VirtualAlloc); + @InternalFuncs.VirtualFree := CloneFunc(@VirtualFree); + @InternalFuncs.VirtualProtect := CloneFunc(@VirtualProtect); + @InternalFuncs.VirtualQuery := CloneFunc(@VirtualQuery); + @InternalFuncs.FlushInstructionCache := CloneFunc(@FlushInstructionCache); + @InternalFuncs.GetCurrentProcess := CloneFunc(@GetCurrentProcess); +{$ELSE !HookInternalFuncs} + @InternalFuncs.VirtualAlloc := @VirtualAlloc; + @InternalFuncs.VirtualFree := @VirtualFree; + @InternalFuncs.VirtualProtect := @VirtualProtect; + @InternalFuncs.VirtualQuery := @VirtualQuery; + @InternalFuncs.FlushInstructionCache := @FlushInstructionCache; + @InternalFuncs.GetCurrentProcess := @GetCurrentProcess; +{$ENDIF HookInternalFuncs} +end; + +procedure FreeInternalFuncs; +begin +{$IFDEF HookInternalFuncs} + InternalFuncs.VirtualFree(@InternalFuncs.VirtualAlloc, 0, MEM_RELEASE); + InternalFuncs.VirtualFree(@InternalFuncs.VirtualProtect, 0, MEM_RELEASE); + InternalFuncs.VirtualFree(@InternalFuncs.VirtualQuery, 0, MEM_RELEASE); + InternalFuncs.VirtualFree(@InternalFuncs.FlushInstructionCache, 0, MEM_RELEASE); + InternalFuncs.VirtualFree(@InternalFuncs.GetCurrentProcess, 0, MEM_RELEASE); + // VirtualFree must be the last one ! + InternalFuncs.VirtualFree(@InternalFuncs.VirtualFree, 0, MEM_RELEASE); +{$ENDIF HookInternalFuncs} +end; + +initialization + +TInterceptMonitor.InternalCreate; +{$IFDEF MustUseGenerics} +GlobalThreadList := TDictionary.Create; +{$ENDIF MustUseGenerics} +GetSystemInfo(SysInfo); +SizeOfAlloc := SysInfo.dwPageSize; +if SizeOfAlloc < (TmpSize + TrampoSize + 64) then + SizeOfAlloc := (TmpSize + TrampoSize + 64); +{$IFDEF FPC} +OpenThread := nil; +InitializeCriticalSection(Critical); +{$ELSE !FPC} +@OpenThread := nil; +{$ENDIF !FPC} +FreeKernel := False; + +hKernel := GetModuleHandle(kernel32); +if hKernel <= 0 then +begin + hKernel := LoadLibrary(kernel32); + FreeKernel := (hKernel > 0); +end; + +if hKernel > 0 then +begin +{$IFDEF FPC} + @OpenThread := GetProcAddress(hKernel, 'OpenThread'); + @CreateToolhelp32Snapshot := GetProcAddress(hKernel, 'CreateToolhelp32Snapshot'); + @Thread32First := GetProcAddress(hKernel, 'Thread32First'); + @Thread32Next := GetProcAddress(hKernel, 'Thread32Next'); +{$ELSE !FPC} + @OpenThread := GetProcAddress(hKernel, 'OpenThread'); +{$ENDIF !FPC} +end; +{ The OpenThread function does not exist on OS version < Win XP } +OpenThreadExist := (@OpenThread <> nil); +InitInternalFuncs; + +finalization + +{$IFDEF MustUseGenerics} + GlobalThreadList.Free; +{$ENDIF MustUseGenerics} +if (FreeKernel) and (hKernel > 0) then + FreeLibrary(hKernel); +FreeInternalFuncs; +{$IFDEF FPC} +DeleteCriticalSection(Critical); +{$ENDIF FPC} +TInterceptMonitor.InternalDestroy; + +end. diff --git a/components/detours/Source/Defs.inc b/components/detours/Source/Defs.inc new file mode 100644 index 00000000..6ed587d5 --- /dev/null +++ b/components/detours/Source/Defs.inc @@ -0,0 +1,48 @@ +{$DEFINE UseInline} +{$DEFINE BuildThreadSafe} +{$DEFINE UseGenerics} +{$DEFINE UseMultiBytesNop} +//Define HookInternalFuncs if you want to hook internal functions used by DDL core! +{.$DEFINE HookInternalFuncs} +//---------------------------------------------- +{$IFDEF FPC} + {$IFDEF CPU64} + {$IFNDEF CPUX64} + {$DEFINE CPUX64} + {$ENDIF !CPUX64} + {$ENDIF CPU64} + {$ASMMODE INTEL} +{$ENDIF FPC} + +{$IFNDEF CPUX64} + {$IFNDEF CPUX86} + {$DEFINE CPUX86} + {$ENDIF !CPUX86} +{$ENDIF !CPUX64} + +{$IFDEF DEBUG} +{$R+} // Range check On +{$ENDIF} + +{$IFNDEF FPC} + {$IF CompilerVersion >17} + {$DEFINE CanInline} + {$IFEND} + {$IF CompilerVersion >=21} + {$DEFINE GenericsExist } + {$IFEND} + {$IF CompilerVersion >=23} + {$DEFINE DXE2UP } + {$IFEND} + {$IF CompilerVersion >=24} + {$DEFINE DXE3UP } + {$IFEND} +{$ENDIF !FPC} + +{$IF DEFINED(UseInline) and DEFINED(CanInline)} + {$DEFINE MustInline} +{$IFEND} + +{$IF DEFINED(GenericsExist) and DEFINED(UseGenerics)} + {$DEFINE MustUseGenerics} +{$IFEND} diff --git a/components/detours/Source/InstDecode.pas b/components/detours/Source/InstDecode.pas new file mode 100644 index 00000000..58efb5ab --- /dev/null +++ b/components/detours/Source/InstDecode.pas @@ -0,0 +1,2383 @@ +// ************************************************************************************************** +// Delphi Instruction Decode Library +// Unit InstDecode +// https://github.com/MahdiSafsafi/delphi-detours-library + +// The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); +// you may not use this file except in compliance with the License. You may obtain a copy of the +// License at http://www.mozilla.org/MPL/ +// +// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF +// ANY KIND, either express or implied. See the License for the specific language governing rights +// and limitations under the License. +// +// The Original Code is InstDecode.pas. +// +// The Initial Developer of the Original Code is Mahdi Safsafi [SMP3]. +// Portions created by Mahdi Safsafi . are Copyright (C) 2013-2017 Mahdi Safsafi . +// All Rights Reserved. +// +// ************************************************************************************************** + +{ ===============================> CHANGE LOG <====================================================== + ==> Dec 27,2014 , Mahdi Safsafi : + +BugFix : IN/INS/OUT/OUTS instructions decoding. + +BugFix : MOV with offset instructions decoding. + + ==> Version 2: + +Updated opcodes map . + +Added support to three byte escape Table + +Added support to vex decoding (vex three & two byte). + +Added support to groups opcodes instructions. + +Added support to decode invalid opcode . + +Added support to 16-bits ModRm . + +Added support to handling errors. + +Added support for mandatory prefixes. + +Improve Decoding Process .=> Very faster than the old one ! + +Reduce memory usage . + +Removing inused fields. + +Better support for REX prefix. + +Reduce OpCodesTable data size (the old : 8670 bytes => the new one : 1020 bytes !) + +BugFix : FPU instructions length. + +BugFix : Instructions that use two immediat . + +BugFix : Invalid instructions . + +BugFix : Invalid instructions for some mandatory prefixes. + +Many Bug Fix. + + ====================================================================================================== } + +unit InstDecode; + +{$IFDEF FPC} +{$MODE DELPHI} +{$ENDIF FPC} + +interface + +{$I Defs.inc} + +uses SysUtils; + +type + PInt8 = ^Int8; + PInt16 = ^Int16; + PInt32 = ^Int32; + PInt64 = ^Int64; + + PUInt8 = ^UInt8; + PUInt16 = ^UInt16; + PUInt32 = ^UInt32; + PUInt64 = ^UInt64; + +const + { CPUX } + CPUX32 = $00; { x86-32 } + CPUX64 = $01; { x86-64 } + CPUX = {$IFDEF CPUX64}CPUX64 {$ELSE}CPUX32 {$ENDIF}; + + { Address Mode } + am16 = $01; { 16-bit addressing mode } + am32 = $02; { 32-bit addressing mode } + am64 = $03; { 64-bit addressing mode } + { Default Addressing Mode Depending on CPUX (32/64)bit } + DefAddressMode: array [0 .. 1] of Byte = (am32, am64); + { Used to select Addressing Mode when Address Mode Prefix is used ! } + AddressMode: array [0 .. 1] of Byte = (am16, am32); + + { Tables } + tbOneByte = $01; { One Byte OpCodes Table } + tbTwoByte = $02; { Two Byte OpCodes Table } + tbThreeByte = $03; { Three Byte OpCodes Table } + tbFPU = $04; { FPU OpCodes Table } + + { Prefixs } + Prf_Seg_CS = $01; + Prf_Seg_DS = $02; + Prf_Seg_ES = $04; + Prf_Seg_GS = $08; + Prf_Seg_FS = $10; + Prf_Seg_SS = $20; + Prf_OpSize = $40; + Prf_AddrSize = $80; + Prf_Lock = $100; + Prf_Repe = $200; + Prf_Repne = $400; + Prf_Rex = $800; + Prf_VEX = $1000; + Prf_Vex2 = Prf_VEX or $2000; + Prf_Vex3 = Prf_VEX or $4000; + + { Segment Registers } + Seg_CS = $01; + Seg_DS = $02; + Seg_ES = $03; + Seg_GS = $04; + Seg_FS = $05; + Seg_SS = $06; + + { OpSize } + ops8bits = $01; + ops16bits = $02; + ops32bits = $04; + ops48bits = $06; + ops64bits = $08; + ops128bits = $10; + ops256bits = $20; + ops512bits = $40; + + { OpType } + otNone = $00; + otRET = $01; { RET Instruction } + otCALL = $02; { CALL Instruction } + otJMP = $04; { JMP Instruction } + otJ = $08; + otJcc = $10; { Conditional JUMP Instruction } + + { OpKind } + kGrp = $01; + // kFPU = $02; Use OpTable ! + + { Options } + DecodeVex = $01; + + { ModRm Flags } + mfUsed = $80; { ModRm Used } + + { Sib Flags } + sfUsed = $01; { Sib Used } + + { Displacement Flags } + dfUsed = $01; { Disp Used } + dfRip = $02; { RIP Disp } + dfSigned = $04; { Displacement can be signed ! } + dfDispOnly = $08; { Displacement Only without registers ! } + dfOffset = $10; { Offset coded after the opcode. } + + { Immediat Flags } + imfUsed = $01; { Imm Used } + + { Branch Flags } + bfUsed = $01; { JUMP/CALL Used } + bfRel = $02; { Relative Branch } + bfAbs = $04; { Absolute Branch } + bfIndirect = $08; { Indirect Branch } + bfReg = $10; + bfFar = bfAbs or $20; { Far Branch } + bfRip = $40; + + { Operand Flags } + opdD64 = $01; + opdF64 = $02; + opdDf64 = $03; + opdDv64 = $04; + + { Options } + UseVA = $01; + + { General Purpose Registers } + rEAX = $00; + rECX = $01; + rEDX = $02; + rEBX = $03; + rESP = $04; + rEBP = $05; + rESI = $06; + rEDI = $07; + + { Error } + NO_ERROR = $00; + INVALID_CPUX = $01; + INVALID_ADDRESS = $02; + INVALID_INSTRUCTION_LENGTH = $04; + ERROR_DISP_SIZE = $08; + ERROR_IMM_SIZE = $10; + ERROR_VEX_ESCAPE = $20; + INVALID_GROUP_OPCODE = $40; + + UnknownErrorStr = 'Unknown Error'; + InstErrorsStr: array [0 .. 7] of String = ( + { NO_ERROR } + 'No error', + { INVALID_CPUX } + 'Invalid cpux', + { INVALID_ADDRESS } + 'Invalid address', + { INVALID_INSTRUCTION_LENGTH } + 'Invalid instruction length', + { ERROR_DISP_SIZE } + 'Invalid displacement size', + { ERROR_IMM_SIZE } + 'Invalid immediat size', + { ERROR_VEX_ESCAPE } + 'Invalid vex mmmmm field', + { INVALID_GROUP_OPCODE } + 'Invalid group opcode'); + + _vex3_ = $03; + _opcode_ = $01; + _modrm_ = $01; + _sib_ = $01; + _disp32_ = $04; + _imm32_ = $04; + _imm64_ = $08; + { Intel define instruction length as a 15 bytes ! + However , it's possible to incode instructions + that exceed the defined length ! + } + MAX_INST_LENGTH_X32 = _vex3_ + _opcode_ + _modrm_ + _sib_ + _disp32_ + _imm32_; + MAX_INST_LENGTH_X64 = _vex3_ + _opcode_ + _modrm_ + _sib_ + _disp32_ + _imm64_; + CPUX_TO_INST_LENGTH: array [0 .. 1] of ShortInt = (MAX_INST_LENGTH_X32, MAX_INST_LENGTH_X64); +{$IFDEF CPUX64} + MAX_INST_LENGTH_N = MAX_INST_LENGTH_X64; +{$ELSE !CPUX64} + MAX_INST_LENGTH_N = MAX_INST_LENGTH_X32; +{$ENDIF CPUX64} + +var + { Raise Exception When Error Occurs ! } + RaiseExceptionOnError: Boolean = True; + +type + InstException = class(Exception); + + TModRM = record + iMod: Byte; { ModRm.Mod Field } + Reg: Byte; { ModRm.Reg Field } + Rm: Byte; { ModRm.Rm Field } + Value: Byte; { ModRm Value } + { ModRm.Flags => See ModRmFlagsTable.inc } + Flags: Byte; + end; + + PModRM = ^TModRM; + LPModRM = PModRM; + + TSib = record + Scale: Byte; { SIB.Scale Field } + Index: Byte; { Register Index } + Base: Byte; { Register Base } + Value: Byte; { SIB Value } + Flags: Byte; { SIB Flags } + end; + + PSib = ^TSib; + LPSib = PSib; + + TImmediat = record + Size: Byte; { Size of Immediat => opsxxxbits } + Value: Int64; { Immediat Value } + Flags: Byte; { Sets of imfxxx } + end; + + PImmediat = ^TImmediat; + + TDisplacement = record + Size: Byte; { Size of Displacement => opsxxxbits } + Value: Int64; { Displacement Value } + Flags: Byte; { Sets of dfxxx } + end; + + PDisplacement = ^TDisplacement; + + TBranch = record + Size: Byte; + Value: Int64; + Target: PByte; { Destination Address } + Falgs: Byte; { Sets of bfxxx } + end; + + PBranch = ^TBranch; + + TRex = record + R: Boolean; { REX.R Field } + X: Boolean; { REX.X Field } + B: Boolean; { REX.B Field } + W: Boolean; { REX.W Field } + Value: Byte; { REX Value = [$40..$4F] } + end; + + PRex = ^TRex; + + TVex = record + { + ==================> N.B <================== + 1 => ALL FIELD ARE IN NO INVERTED FORM ! + 2 => VEX.[R,X,B & W] ARE ACCESSIBLE THROUGH REX FIELD ! + + } + vvvv: Byte; { VEX.vvvv ==> Vector Register } + L: Boolean; { VEX.L ==> You should use VL instead ! } + PP: Byte; { VEX.PP ==> Implied Mandatory Prefixes } + mmmmm: Byte; { VEX.mmmmm ==> Implied Escape } + VL: Byte; { Vector Length } + end; + + PVex = ^TVex; + + TInternalData = record + MndPrf: Byte; { Mandatory Prefix } + zOpSize: Byte; { word or dword depending on opsize prefix ! } + vOpSize: Byte; { word or dword or qword depending on opsize & REX prefix ! } + end; + + PInternalData = ^TInternalData; + + TInstruction = record + Archi: Byte; { CPUX32 or CPUX64 ! } + AddrMode: Byte; { Address Mode } + Addr: PByte; + VirtualAddr: PByte; + NextInst: PByte; { Pointer to the Next Instruction } + OpCode: Byte; { OpCode Value } + OpType: Byte; + OpKind: Byte; + OpTable: Byte; { tbOneByte,tbTwoByte,... } + OperandFlags: Byte; + Prefixes: Word; { Sets of Prf_xxx } + ModRm: TModRM; + Sib: TSib; + Disp: TDisplacement; + Imm: TImmediat; { Primary Immediat } + ImmEx: TImmediat; { Secondary Immediat if used ! } + Branch: TBranch; { JMP & CALL } + SegReg: Byte; { Segment Register } + Rex: TRex; + Vex: TVex; + LID: TInternalData; { Internal Data } + Errors: Byte; + InstSize: Byte; + Options: Byte; + UserTag: UInt64; + end; + + PInstruction = ^TInstruction; + + TDecoderProc = procedure(PInst: PInstruction); + +function DecodeInst(PInst: PInstruction): ShortInt; + +{ Useful ModRm Routines } +function GetModRm_Mod(const Value: Byte): Byte; {$IFDEF MustInline}inline; {$ENDIF} +function GetModRm_Reg(const Value: Byte): Byte; {$IFDEF MustInline}inline; {$ENDIF} +function GetModRm_Rm(const Value: Byte): Byte; {$IFDEF MustInline}inline; {$ENDIF} +{ Useful Sib Routines } +function GetSib_Base(const Value: Byte): Byte; {$IFDEF MustInline}inline; {$ENDIF} +function GetSib_Index(const Value: Byte): Byte; {$IFDEF MustInline}inline; {$ENDIF} +function GetSib_Scale(const Value: Byte): Byte; {$IFDEF MustInline}inline; {$ENDIF} +function IsSibBaseRegValid(PInst: PInstruction): Boolean; {$IFDEF MustInline}inline; {$ENDIF} + +implementation + +{$I OpCodesTables.inc} +{$I ModRmFlagsTables.inc} +{ ================================== 00 ================================== } +procedure Decode_InvalidOpCode(PInst: PInstruction); forward; +{ ================================== 01 ================================== } +procedure Decode_NA_ModRm(PInst: PInstruction); forward; +{ ================================== 02 ================================== } +procedure Decode_NA_Ib(PInst: PInstruction); forward; +{ ================================== 03 ================================== } +procedure Decode_NA_Iz(PInst: PInstruction); forward; +{ ================================== 04 ================================== } +procedure Decode_NA_I64(PInst: PInstruction); forward; +{ ================================== 05 ================================== } +procedure Decode_Escape_2_Byte(PInst: PInstruction); forward; +{ ================================== 06 ================================== } +procedure Decode_ES_Prefix(PInst: PInstruction); forward; +{ ================================== 07 ================================== } +procedure Decode_CS_Prefix(PInst: PInstruction); forward; +{ ================================== 08 ================================== } +procedure Decode_SS_Prefix(PInst: PInstruction); forward; +{ ================================== 09 ================================== } +procedure Decode_DS_Prefix(PInst: PInstruction); forward; +{ ================================== 10 ================================== } +procedure Decode_REX_Prefix(PInst: PInstruction); forward; +{ ================================== 11 ================================== } +procedure Decode_NA_D64(PInst: PInstruction); forward; +{ ================================== 12 ================================== } +procedure Decode_NA_ModRm_I64(PInst: PInstruction); forward; +{ ================================== 13 ================================== } +procedure Decode_FS_Prefix(PInst: PInstruction); forward; +{ ================================== 14 ================================== } +procedure Decode_GS_Prefix(PInst: PInstruction); forward; +{ ================================== 15 ================================== } +procedure Decode_OPSIZE_Prefix(PInst: PInstruction); forward; +{ ================================== 16 ================================== } +procedure Decode_ADSIZE_Prefix(PInst: PInstruction); forward; +{ ================================== 17 ================================== } +procedure Decode_NA_Iz_D64(PInst: PInstruction); forward; +{ ================================== 18 ================================== } +procedure Decode_NA_ModRm_Iz(PInst: PInstruction); forward; +{ ================================== 19 ================================== } +procedure Decode_NA_Ib_D64(PInst: PInstruction); forward; +{ ================================== 20 ================================== } +procedure Decode_NA_ModRm_Ib(PInst: PInstruction); forward; +{ ================================== 21 ================================== } +procedure Decode_NA(PInst: PInstruction); forward; +{ ================================== 22 ================================== } +procedure Decode_NA_Jb_Df64(PInst: PInstruction); forward; +{ ================================== 23 ================================== } +procedure Decode_Group_1(PInst: PInstruction); forward; +{ ================================== 24 ================================== } +procedure Decode_Group_1A(PInst: PInstruction); forward; +{ ================================== 25 ================================== } +procedure Decode_NA_CALL_Ap_I64(PInst: PInstruction); forward; +{ ================================== 26 ================================== } +procedure Decode_NA_OfstV(PInst: PInstruction); forward; +{ ================================== 27 ================================== } +procedure Decode_NA_Iv(PInst: PInstruction); forward; +{ ================================== 28 ================================== } +procedure Decode_Group_2(PInst: PInstruction); forward; +{ ================================== 29 ================================== } +procedure Decode_NA_RET_Iw_Df64(PInst: PInstruction); forward; +{ ================================== 30 ================================== } +procedure Decode_NA_RET_Df64(PInst: PInstruction); forward; +{ ================================== 31 ================================== } +procedure Decode_VEX3_Prefix(PInst: PInstruction); forward; +{ ================================== 32 ================================== } +procedure Decode_VEX2_Prefix(PInst: PInstruction); forward; +{ ================================== 33 ================================== } +procedure Decode_Group_11(PInst: PInstruction); forward; +{ ================================== 34 ================================== } +procedure Decode_NA_Iw_Ib_D64(PInst: PInstruction); forward; +{ ================================== 35 ================================== } +procedure Decode_NA_RET_Iw(PInst: PInstruction); forward; +{ ================================== 36 ================================== } +procedure Decode_NA_RET(PInst: PInstruction); forward; +{ ================================== 37 ================================== } +procedure Decode_NA_Ib_I64(PInst: PInstruction); forward; +{ ================================== 38 ================================== } +procedure Decode_Escape_FPU_D8(PInst: PInstruction); forward; +{ ================================== 39 ================================== } +procedure Decode_Escape_FPU_D9(PInst: PInstruction); forward; +{ ================================== 40 ================================== } +procedure Decode_Escape_FPU_DA(PInst: PInstruction); forward; +{ ================================== 41 ================================== } +procedure Decode_Escape_FPU_DB(PInst: PInstruction); forward; +{ ================================== 42 ================================== } +procedure Decode_Escape_FPU_DC(PInst: PInstruction); forward; +{ ================================== 43 ================================== } +procedure Decode_Escape_FPU_DD(PInst: PInstruction); forward; +{ ================================== 44 ================================== } +procedure Decode_Escape_FPU_DE(PInst: PInstruction); forward; +{ ================================== 45 ================================== } +procedure Decode_Escape_FPU_DF(PInst: PInstruction); forward; +{ ================================== 46 ================================== } +procedure Decode_NA_CALL_Jz_Df64(PInst: PInstruction); forward; +{ ================================== 47 ================================== } +procedure Decode_NA_JMP_Jz_Df64(PInst: PInstruction); forward; +{ ================================== 48 ================================== } +procedure Decode_NA_JMP_Ap_I64(PInst: PInstruction); forward; +{ ================================== 49 ================================== } +procedure Decode_NA_JMP_Jb_Df64(PInst: PInstruction); forward; +{ ================================== 50 ================================== } +procedure Decode_LOCK_Prefix(PInst: PInstruction); forward; +{ ================================== 51 ================================== } +procedure Decode_REPNE_Prefix(PInst: PInstruction); forward; +{ ================================== 52 ================================== } +procedure Decode_REPE_Prefix(PInst: PInstruction); forward; +{ ================================== 53 ================================== } +procedure Decode_Group_3(PInst: PInstruction); forward; +{ ================================== 54 ================================== } +procedure Decode_Group_4_INC_DEC(PInst: PInstruction); forward; +{ ================================== 55 ================================== } +procedure Decode_Group_5_INC_DEC(PInst: PInstruction); forward; +{ ================================== 56 ================================== } +procedure Decode_Group_6(PInst: PInstruction); forward; +{ ================================== 57 ================================== } +procedure Decode_Group_7(PInst: PInstruction); forward; +{ ================================== 58 ================================== } +procedure Decode_NA_CALL(PInst: PInstruction); forward; +{ ================================== 59 ================================== } +procedure Decode_NA_66_F2_F3_ModRm(PInst: PInstruction); forward; +{ ================================== 60 ================================== } +procedure Decode_NA_66_ModRm(PInst: PInstruction); forward; +{ ================================== 61 ================================== } +procedure Decode_NA_66_F3_ModRm(PInst: PInstruction); forward; +{ ================================== 62 ================================== } +procedure Decode_Group_16(PInst: PInstruction); forward; +{ ================================== 63 ================================== } +procedure Decode_NA_ModRm_F64(PInst: PInstruction); forward; +{ ================================== 64 ================================== } +procedure Decode_Escape_3_Byte(PInst: PInstruction); forward; +{ ================================== 65 ================================== } +procedure Decode_NA_F3_ModRm(PInst: PInstruction); forward; +{ ================================== 66 ================================== } +procedure Decode_66_ModRm(PInst: PInstruction); forward; +{ ================================== 67 ================================== } +procedure Decode_NA_66_F2_F3_ModRm_Ib(PInst: PInstruction); forward; +{ ================================== 68 ================================== } +procedure Decode_Group_12(PInst: PInstruction); forward; +{ ================================== 69 ================================== } +procedure Decode_Group_13(PInst: PInstruction); forward; +{ ================================== 70 ================================== } +procedure Decode_Group_14(PInst: PInstruction); forward; +{ ================================== 71 ================================== } +procedure Decode_66_F2_ModRm(PInst: PInstruction); forward; +{ ================================== 72 ================================== } +procedure Decode_NA_Jz_Df64(PInst: PInstruction); forward; +{ ================================== 73 ================================== } +procedure Decode_Group_15(PInst: PInstruction); forward; +{ ================================== 74 ================================== } +procedure Decode_F3_ModRm(PInst: PInstruction); forward; +{ ================================== 75 ================================== } +procedure Decode_Group_10_UD2(PInst: PInstruction); forward; +{ ================================== 76 ================================== } +procedure Decode_Group_8(PInst: PInstruction); forward; +{ ================================== 77 ================================== } +procedure Decode_NA_66_ModRm_Ib(PInst: PInstruction); forward; +{ ================================== 78 ================================== } +procedure Decode_Group_9(PInst: PInstruction); forward; +{ ================================== 79 ================================== } +procedure Decode_66_F2_F3_ModRm(PInst: PInstruction); forward; +{ ================================== 80 ================================== } +procedure Decode_F2_ModRm(PInst: PInstruction); forward; +{ ================================== 81 ================================== } +procedure Decode_SP_T38_F0_F7(PInst: PInstruction); forward; +{ ================================== 82 ================================== } +procedure Decode_66_ModRm_Ib(PInst: PInstruction); forward; +{ ================================== 83 ================================== } +procedure Decode_F2_ModRm_Ib(PInst: PInstruction); forward; + +procedure JumpError(PInst: PInstruction); forward; +procedure JumpToTableTwoByte(PInst: PInstruction); forward; +procedure JumpToTableThreeByte_38(PInst: PInstruction); forward; +procedure JumpToTableThreeByte_3A(PInst: PInstruction); forward; + +procedure Decode_CALL_ModRm(PInst: PInstruction); forward; +procedure Decode_JMP_ModRm(PInst: PInstruction); forward; +procedure Decode_CALL_Mp(PInst: PInstruction); forward; +procedure Decode_JMP_Mp(PInst: PInstruction); forward; + +const + + { Convert PP To Mandatory Prefixes ! } + PPToMndPrf: array [0 .. 3] of Byte = ($00, $66, $F3, $F2); + + { Convert LL To OpSize ! } + LLToOpSize: array [0 .. 3] of Word = (ops128bits, ops256bits, ops512bits, 0); + + { Call escaping procedure ! } + mmmmmToEscProc: array [0 .. 4] of TDecoderProc = ( // + JumpError, { } + JumpToTableTwoByte, { 00001: implied 0F leading opcode byte } + JumpToTableThreeByte_38, { 00010: implied 0F 38 leading opcode bytes } + JumpToTableThreeByte_3A, { 00011: implied 0F 3A leading opcode bytes } + JumpError { } + ); + + DecoderProcTable: array [0 .. $54 - 1] of TDecoderProc = ( // + { 00 } Decode_InvalidOpCode, + { 01 } Decode_NA_ModRm, + { 02 } Decode_NA_Ib, + { 03 } Decode_NA_Iz, + { 04 } Decode_NA_I64, + { 05 } Decode_Escape_2_Byte, + { 06 } Decode_ES_Prefix, + { 07 } Decode_CS_Prefix, + { 08 } Decode_SS_Prefix, + { 09 } Decode_DS_Prefix, + { 10 } Decode_REX_Prefix, + { 11 } Decode_NA_D64, + { 12 } Decode_NA_ModRm_I64, + { 13 } Decode_FS_Prefix, + { 14 } Decode_GS_Prefix, + { 15 } Decode_OPSIZE_Prefix, + { 16 } Decode_ADSIZE_Prefix, + { 17 } Decode_NA_Iz_D64, + { 18 } Decode_NA_ModRm_Iz, + { 19 } Decode_NA_Ib_D64, + { 20 } Decode_NA_ModRm_Ib, + { 21 } Decode_NA, + { 22 } Decode_NA_Jb_Df64, + { 23 } Decode_Group_1, + { 24 } Decode_Group_1A, + { 25 } Decode_NA_CALL_Ap_I64, + { 26 } Decode_NA_OfstV, + { 27 } Decode_NA_Iv, + { 28 } Decode_Group_2, + { 29 } Decode_NA_RET_Iw_Df64, + { 30 } Decode_NA_RET_Df64, + { 31 } Decode_VEX3_Prefix, + { 32 } Decode_VEX2_Prefix, + { 33 } Decode_Group_11, + { 34 } Decode_NA_Iw_Ib_D64, + { 35 } Decode_NA_RET_Iw, + { 36 } Decode_NA_RET, + { 37 } Decode_NA_Ib_I64, + { 38 } Decode_Escape_FPU_D8, + { 39 } Decode_Escape_FPU_D9, + { 40 } Decode_Escape_FPU_DA, + { 41 } Decode_Escape_FPU_DB, + { 42 } Decode_Escape_FPU_DC, + { 43 } Decode_Escape_FPU_DD, + { 44 } Decode_Escape_FPU_DE, + { 45 } Decode_Escape_FPU_DF, + { 46 } Decode_NA_CALL_Jz_Df64, + { 47 } Decode_NA_JMP_Jz_Df64, + { 48 } Decode_NA_JMP_Ap_I64, + { 49 } Decode_NA_JMP_Jb_Df64, + { 50 } Decode_LOCK_Prefix, + { 51 } Decode_REPNE_Prefix, + { 52 } Decode_REPE_Prefix, + { 53 } Decode_Group_3, + { 54 } Decode_Group_4_INC_DEC, + { 55 } Decode_Group_5_INC_DEC, + { 56 } Decode_Group_6, + { 57 } Decode_Group_7, + { 58 } Decode_NA_CALL, + { 59 } Decode_NA_66_F2_F3_ModRm, + { 60 } Decode_NA_66_ModRm, + { 61 } Decode_NA_66_F3_ModRm, + { 62 } Decode_Group_16, + { 63 } Decode_NA_ModRm_F64, + { 64 } Decode_Escape_3_Byte, + { 65 } Decode_NA_F3_ModRm, + { 66 } Decode_66_ModRm, + { 67 } Decode_NA_66_F2_F3_ModRm_Ib, + { 68 } Decode_Group_12, + { 69 } Decode_Group_13, + { 70 } Decode_Group_14, + { 71 } Decode_66_F2_ModRm, + { 72 } Decode_NA_Jz_Df64, + { 73 } Decode_Group_15, + { 74 } Decode_F3_ModRm, + { 75 } Decode_Group_10_UD2, + { 76 } Decode_Group_8, + { 77 } Decode_NA_66_ModRm_Ib, + { 78 } Decode_Group_9, + { 79 } Decode_66_F2_F3_ModRm, + { 80 } Decode_F2_ModRm, + { 81 } Decode_SP_T38_F0_F7, + { 82 } Decode_66_ModRm_Ib, + { 83 } Decode_F2_ModRm_Ib); +{$REGION 'COMMON'} + { ========================== COMMON =============================== } + +procedure SetInstError(PInst: PInstruction; Error: Byte); +var + ErrStr: String; +begin + ErrStr := EmptyStr; + if Error = NO_ERROR then + begin + { Clear Errors ! } + PInst^.Errors := NO_ERROR; + Exit; + end; + PInst^.Errors := PInst^.Errors or Error; + + if RaiseExceptionOnError then + begin + if (Error > 0) and (Error < Length(InstErrorsStr)) then + ErrStr := InstErrorsStr[Error] + else + ErrStr := UnknownErrorStr; + raise InstException.Create(Format('Error %d : %s.', [Error, ErrStr])); + end; +end; + +function GetModRm_Mod(const Value: Byte): Byte; +begin + Result := Value shr 6; +end; + +function GetModRm_Reg(const Value: Byte): Byte; +begin + Result := (Value and $38) shr $03; +end; + +function GetModRm_Rm(const Value: Byte): Byte; +begin + Result := Value and 7; +end; + +function GetSib_Base(const Value: Byte): Byte; +begin + Result := Value and 7; +end; + +function GetSib_Index(const Value: Byte): Byte; +begin + Result := (Value and $38) shr $03; +end; + +function GetSib_Scale(const Value: Byte): Byte; +begin + Result := (1 shl (Value shr 6)); +end; + +function IsSibBaseRegValid(PInst: PInstruction): Boolean; +begin + Result := True; + if PInst^.Sib.Flags and sfUsed <> 0 then + Result := not((PInst^.ModRm.iMod = 0) and (PInst^.Sib.Base = 5)); +end; + +procedure SetOpCode(PInst: PInstruction); {$IFDEF MustInline}inline; {$ENDIF} +begin + PInst^.OpCode := PInst^.NextInst^; + Inc(PInst^.NextInst); +end; + +procedure SetGroup(PInst: PInstruction); {$IFDEF MustInline}inline; {$ENDIF} +begin + PInst^.OpKind := kGrp; +end; + +procedure ForceOpSize(PInst: PInstruction); {$IFDEF MustInline}inline; {$ENDIF} +begin + if PInst^.Archi = CPUX32 then + Exit; + PInst^.LID.vOpSize := ops64bits; +end; + +procedure DecodeSib(PInst: PInstruction); {$IFDEF MustInline}inline; {$ENDIF} +var + PSib: LPSib; +begin + PSib := @PInst^.Sib; + PSib.Flags := sfUsed; + PSib.Value := PInst^.NextInst^; + PSib.Base := GetSib_Base(PSib.Value); + PSib.Index := GetSib_Index(PSib.Value); + PSib.Scale := GetSib_Scale(PSib.Value); + Inc(PInst^.NextInst); // Skip SIB ! +end; + +procedure DecodeDisp(PInst: PInstruction); +var + Disp: Int64; + Size: Byte; + DispOnly: Boolean; +begin + Disp := $00; + Size := PInst^.Disp.Size; + PInst^.Disp.Flags := dfUsed; + DispOnly := (PInst^.ModRm.iMod = $00) and (PInst^.ModRm.Rm = $05); + + case Size of + ops8bits: Disp := (PUInt8(PInst^.NextInst)^); // and $FF; + ops16bits: Disp := (PUInt16(PInst^.NextInst)^); // and $FFFF; + ops32bits: + begin + Disp := (PUInt32(PInst^.NextInst)^); // and $FFFFFFFF; + if (PInst^.Archi = CPUX64) and DispOnly then + { RIP disp ! } + PInst^.Disp.Flags := PInst^.Disp.Flags or dfRip; + end; + else SetInstError(PInst, ERROR_DISP_SIZE); + end; + + if DispOnly then + PInst^.Disp.Flags := PInst^.Disp.Flags or dfDispOnly + else + PInst^.Disp.Flags := PInst^.Disp.Flags or dfSigned; + + PInst^.Disp.Value := Disp; + Inc(PInst^.NextInst, Size) // Skip Disp ! +end; + +procedure Decode_ModRm(PInst: PInstruction); +var + PModRM: LPModRM; + SibUsed: Boolean; +const + { Get Disp Size from ModRm . } + ModRMFlagsToDispSize: array [0 .. 4] of Byte = (0, ops8bits, ops16bits, 0, ops32bits); +begin + PModRM := @PInst^.ModRm; + PModRM.Value := PInst^.NextInst^; + PModRM.iMod := GetModRm_Mod(PModRM.Value); + PModRM.Reg := GetModRm_Reg(PModRM.Value); + PModRM.Rm := GetModRm_Rm(PModRM.Value); + PModRM.Flags := ModRMFlags[PInst^.AddrMode][PModRM.Value]; + + PInst^.Disp.Size := ModRMFlagsToDispSize[(PModRM.Flags shr 1) and 7]; + Inc(PInst^.NextInst); // Skip ModRM ! + + SibUsed := (PModRM.Flags and $10 > 0); { SibUsed ! } + + if SibUsed then + begin + DecodeSib(PInst); + { if the base is not valid ==> there is a disp32 . + But the disp can be 8bit ==> we need to check first + if the disp does not exist ! + } + if (PInst^.Disp.Size = 0) and (not IsSibBaseRegValid(PInst)) then + PInst^.Disp.Size := ops32bits; + end; + + if PInst^.Disp.Size > 0 then + DecodeDisp(PInst); + + { ModRm Exists ! } + PModRM.Flags := PModRM.Flags or mfUsed; +end; + +procedure Decode_Imm(PInst: PInstruction; immSize: Byte); +var + Imm: Int64; + PImm: PImmediat; +begin + Imm := $00; + case immSize of + ops8bits: Imm := (PInt8(PInst^.NextInst)^); + ops16bits: Imm := (PInt16(PInst^.NextInst)^); + ops32bits: Imm := (PInt32(PInst^.NextInst)^); + ops64bits: Imm := (PInt64(PInst^.NextInst)^); + else SetInstError(PInst, ERROR_IMM_SIZE); + end; + + { + If Imm field already used => get the extra Imm + } + if PInst^.Imm.Flags and imfUsed <> $00 then + PImm := @PInst^.ImmEx + else + PImm := @PInst^.Imm; + + PImm.Flags := imfUsed; + PImm.Value := Imm; + PImm.Size := immSize; + Inc(PInst^.NextInst, immSize); // Skip Immediat ! +end; + +procedure Decode_J(PInst: PInstruction; Size: Byte); +var + Value: Int64; + VA: PByte; +begin + Value := $00; + case Size of + ops8bits: Value := (PInt8(PInst^.NextInst)^); + ops16bits: Value := (PInt16(PInst^.NextInst)^); + ops32bits: Value := (PInt32(PInst^.NextInst)^); + ops64bits: Value := (PInt64(PInst^.NextInst)^); + end; + Inc(PInst^.NextInst, Size); + if PInst^.OpType = otNone then + PInst^.OpType := otJ; + if PInst^.OpCode in [$70 .. $8F] then + PInst^.OpType := otJ or otJcc; + if Assigned(PInst^.VirtualAddr) then + VA := PInst^.VirtualAddr + (PInst^.NextInst - PInst^.Addr) + else + VA := PInst^.NextInst; + PInst^.Branch.Size := Size; + PInst^.Branch.Falgs := bfUsed or bfRel; + PInst^.Branch.Value := Value; + PInst^.Branch.Target := VA + Value; +end; + +procedure Decode_Branch_ModRm(PInst: PInstruction); +var + P: PByte; + VA: PByte; +begin + SetOpCode(PInst); + Decode_ModRm(PInst); + PInst^.Branch.Value := PInst^.Disp.Value; + PInst^.Branch.Size := PInst^.Disp.Size; + PInst^.Branch.Falgs := bfUsed or bfIndirect or bfAbs; + if Assigned(PInst^.VirtualAddr) then + VA := PInst^.VirtualAddr + (PInst^.NextInst - PInst^.Addr) + else + VA := PInst^.NextInst; + if (PInst^.ModRm.iMod = $00) and (PInst^.ModRm.Rm = $05) then + begin + { Memory = Displacement } + if PInst^.Archi = CPUX64 then + begin + if PInst^.Prefixes and Prf_AddrSize <> 0 then + { Displacement = EIP + Offset } + VA := PByte(UInt64(VA) and $FFFFFFFF); + { Displacement = RIP + Offset } + PInst^.Branch.Falgs := PInst^.Branch.Falgs or bfRip; + P := VA + Int32(PInst^.Disp.Value); + { Memory 64-bits } + PInst^.Branch.Target := PByte(PUInt64(P)^); + end + else + begin + { No RIP } + P := PByte(UInt32(PInst^.Disp.Value)); + if PInst^.Prefixes and Prf_OpSize <> 0 then + { Memory 16-bits } + PInst^.Branch.Target := PByte(PUInt16(P)^) + else + { Memory 32-bits } + PInst^.Branch.Target := PByte(PUInt32(P)^); + end; + end + else + begin + { Memory = Displacement + Register } + PInst^.Branch.Falgs := PInst^.Branch.Falgs or bfReg; + PInst^.Branch.Target := nil; + end; +end; + +procedure Decode_Ap(PInst: PInstruction); +begin + SetOpCode(PInst); + PInst^.Branch.Falgs := bfUsed or bfFar; + { We must clear the upper word ! } + PInst^.Branch.Value := PUInt64(PInst^.NextInst)^ and $FFFFFFFFFFFF; + PInst^.Branch.Size := ops48bits; + PInst^.Branch.Target := nil; + Inc(PInst^.NextInst, ops48bits); +end; + +procedure Decode_Mp(PInst: PInstruction); +begin + SetOpCode(PInst); + PInst^.Branch.Falgs := bfUsed or bfFar; + Decode_ModRm(PInst); + PInst^.Branch.Value := PInst^.Disp.Value; + PInst^.Branch.Size := PInst^.Disp.Size; + PInst^.Branch.Target := nil; +end; + +procedure Decode_InvalidOpCode(PInst: PInstruction); {$IFDEF MustInline}inline; +{$ENDIF} +begin + SetOpCode(PInst); +end; + +procedure Decode_Invalid_Group(PInst: PInstruction); {$IFDEF MustInline}inline; +{$ENDIF} +begin + SetOpCode(PInst); + Inc(PInst^.NextInst); +end; + +procedure Decode_Invalid_FPU(PInst: PInstruction); {$IFDEF MustInline}inline; +{$ENDIF} +begin + SetOpCode(PInst); + Inc(PInst^.NextInst); +end; + +{$ENDREGION} +{$REGION 'PREFIXES'} +{ ========================== PREFIXES =============================== } + +procedure Decode_ES_Prefix(PInst: PInstruction); +begin + { ES Segment Override Prefix } + Inc(PInst^.NextInst); + PInst^.Prefixes := PInst^.Prefixes or Prf_Seg_ES; + PInst^.SegReg := Seg_ES; + DecoderProcTable[OneByteTable[PInst^.NextInst^]](PInst); +end; + +procedure Decode_CS_Prefix(PInst: PInstruction); +begin + { CS Segment Override Prefix } + Inc(PInst^.NextInst); + PInst^.Prefixes := PInst^.Prefixes or Prf_Seg_CS; + PInst^.SegReg := Seg_CS; + DecoderProcTable[OneByteTable[PInst^.NextInst^]](PInst); +end; + +procedure Decode_SS_Prefix(PInst: PInstruction); +begin + { SS Segment Override Prefix } + Inc(PInst^.NextInst); + PInst^.Prefixes := PInst^.Prefixes or Prf_Seg_SS; + PInst^.SegReg := Seg_SS; + DecoderProcTable[OneByteTable[PInst^.NextInst^]](PInst); +end; + +procedure Decode_DS_Prefix(PInst: PInstruction); +begin + { DS Segment Override Prefix } + Inc(PInst^.NextInst); + PInst^.Prefixes := PInst^.Prefixes or Prf_Seg_DS; + PInst^.SegReg := Seg_DS; + DecoderProcTable[OneByteTable[PInst^.NextInst^]](PInst); +end; + +procedure Decode_REX_Prefix(PInst: PInstruction); +begin + { REX Prefix valid only on PM64! } + if PInst^.Archi = CPUX32 then + begin + { INC/DEC REG } + Decode_NA(PInst); + Exit; + end; + PInst^.Prefixes := PInst^.Prefixes or Prf_Rex; + PInst^.Rex.Value := PInst^.NextInst^; + PInst^.Rex.B := (PInst^.Rex.Value and 1 <> 0); + PInst^.Rex.X := (PInst^.Rex.Value and 2 <> 0); + PInst^.Rex.R := (PInst^.Rex.Value and 4 <> 0); + PInst^.Rex.W := (PInst^.Rex.Value and 8 <> 0); + + if PInst^.Rex.W then + PInst^.LID.vOpSize := ops64bits; + + Inc(PInst^.NextInst); // Skip Rex . + DecoderProcTable[OneByteTable[PInst^.NextInst^]](PInst); +end; + +procedure Decode_FS_Prefix(PInst: PInstruction); +begin + { FS Segment Override Prefix } + Inc(PInst^.NextInst); + PInst^.Prefixes := PInst^.Prefixes or Prf_Seg_FS; + PInst^.SegReg := Seg_FS; + DecoderProcTable[OneByteTable[PInst^.NextInst^]](PInst); +end; + +procedure Decode_GS_Prefix(PInst: PInstruction); +begin + { GS Segment Override Prefix } + Inc(PInst^.NextInst); + PInst^.Prefixes := PInst^.Prefixes or Prf_Seg_GS; + PInst^.SegReg := Seg_GS; + DecoderProcTable[OneByteTable[PInst^.NextInst^]](PInst); +end; + +procedure Decode_OPSIZE_Prefix(PInst: PInstruction); +begin + PInst^.Prefixes := PInst^.Prefixes or Prf_OpSize; + PInst^.LID.vOpSize := ops16bits; + PInst^.LID.zOpSize := ops16bits; + PInst^.LID.MndPrf := $66; + Inc(PInst^.NextInst); + DecoderProcTable[OneByteTable[PInst^.NextInst^]](PInst); +end; + +procedure Decode_ADSIZE_Prefix(PInst: PInstruction); +begin + PInst^.Prefixes := PInst^.Prefixes or Prf_AddrSize; + Inc(PInst^.NextInst); + PInst^.AddrMode := AddressMode[PInst^.Archi]; + DecoderProcTable[OneByteTable[PInst^.NextInst^]](PInst); +end; + +procedure Decode_VEX3_Prefix(PInst: PInstruction); +var + P: Byte; + Q: PByte; + R, X: Boolean; +begin + if PInst^.Options and DecodeVex = 0 then + begin + Decode_NA_ModRm(PInst); + Exit; + end; + if PInst^.Archi = CPUX32 then + begin + Q := PInst^.NextInst; + Inc(Q); + R := (Q^ and $80 <> 0); + X := (Q^ and $40 <> 0); + { + if R & X are set ==> Vex prefix is valid ! + otherwise the instruction is LES . + } + if not(R and X) then + begin + { LES instruction } + Decode_NA_ModRm(PInst); + Exit; + end; + end; + + Inc(PInst^.NextInst); // Skip $C4 ! + PInst^.Prefixes := PInst^.Prefixes or Prf_Vex3; + P := PInst^.NextInst^; // P0 + PInst^.Rex.R := not(P and $80 <> 0); + PInst^.Rex.X := not(P and $40 <> 0); + PInst^.Rex.B := not(P and $20 <> 0); + PInst^.Vex.mmmmm := (P and $1F); + Inc(PInst^.NextInst); // Skip P0 + P := PInst^.NextInst^; // P1 + Inc(PInst^.NextInst); // Skip P1 + PInst^.Rex.W := (P and $80 <> 0); + PInst^.Vex.vvvv := $0F - ((P and $78) shr 3); + PInst^.Vex.L := (P and 4 <> 0); + PInst^.Vex.PP := (P and 3); + PInst^.Vex.VL := LLToOpSize[Byte(PInst^.Vex.L)]; + PInst^.LID.MndPrf := PPToMndPrf[PInst^.Vex.PP]; + mmmmmToEscProc[PInst^.Vex.mmmmm](PInst); +end; + +procedure Decode_VEX2_Prefix(PInst: PInstruction); +var + P: Byte; + Q: PByte; + R: Boolean; +begin + if PInst^.Options and DecodeVex = 0 then + begin + Decode_NA_ModRm(PInst); + Exit; + end; + if PInst^.Archi = CPUX32 then + begin + Q := PInst^.NextInst; + Inc(Q); + R := (Q^ and $80 <> 0); + { + if R is set ==> Vex prefix is valid ! + otherwise the instruction is LDS. + } + if not R then + begin + { LDS instruction } + Decode_NA_ModRm(PInst); + Exit; + end; + end; + + Inc(PInst^.NextInst); // Skip $C5 ! + PInst^.Prefixes := PInst^.Prefixes or Prf_Vex2; + P := PInst^.NextInst^; + PInst^.Rex.R := not(P and $80 <> 0); + PInst^.Vex.vvvv := $0F - ((P and $78) shr 3); + PInst^.Vex.L := (P and 4 <> 0); + PInst^.Vex.PP := (P and 3); + PInst^.Vex.VL := LLToOpSize[Byte(PInst^.Vex.L)]; + PInst^.LID.MndPrf := PPToMndPrf[PInst^.Vex.PP]; + Inc(PInst^.NextInst); // Skip P0 ! + DecoderProcTable[TwoByteTable[PInst^.NextInst^]](PInst); +end; + +procedure Decode_LOCK_Prefix(PInst: PInstruction); +begin + PInst^.Prefixes := PInst^.Prefixes or Prf_Lock; + Inc(PInst^.NextInst); + DecoderProcTable[OneByteTable[PInst^.NextInst^]](PInst); +end; + +procedure Decode_REPNE_Prefix(PInst: PInstruction); +begin + PInst^.Prefixes := PInst^.Prefixes or Prf_Repne; + PInst^.LID.MndPrf := $F2; + Inc(PInst^.NextInst); + DecoderProcTable[OneByteTable[PInst^.NextInst^]](PInst); +end; + +procedure Decode_REPE_Prefix(PInst: PInstruction); +begin + PInst^.Prefixes := PInst^.Prefixes or Prf_Repe; + PInst^.LID.MndPrf := $F3; + Inc(PInst^.NextInst); + DecoderProcTable[OneByteTable[PInst^.NextInst^]](PInst); +end; +{$ENDREGION} +{$REGION 'ESCAPE'} +{ ========================== ESCAPE =============================== } + +procedure JumpError(PInst: PInstruction); +begin + { Wrong Vex.mmmmm value ! } + SetInstError(PInst, ERROR_VEX_ESCAPE); +end; + +procedure JumpToTableTwoByte(PInst: PInstruction); +begin + { Implied $0F OpCode => Jump to table TwoByteTable } + PInst^.OpTable := tbTwoByte; + DecoderProcTable[TwoByteTable[PInst^.NextInst^]](PInst); +end; + +procedure JumpToTableThreeByte_38(PInst: PInstruction); +begin + { Implied $0F$38 OpCodes => Jump to table ThreeByteTable.38 } + PInst^.OpTable := tbThreeByte; + DecoderProcTable[ThreeByteTable38[PInst^.NextInst^]](PInst); +end; + +procedure JumpToTableThreeByte_3A(PInst: PInstruction); +begin + { Implied $0F$3A OpCodes => Jump to table ThreeByteTable.3A } + PInst^.OpTable := tbThreeByte; + DecoderProcTable[ThreeByteTable3A[PInst^.NextInst^]](PInst); +end; + +procedure Decode_Escape_2_Byte(PInst: PInstruction); +begin + { Two Byte OpCode Escape ! } + PInst^.OpTable := tbTwoByte; + Inc(PInst^.NextInst); + DecoderProcTable[TwoByteTable[PInst^.NextInst^]](PInst); +end; + +procedure Decode_Escape_3_Byte(PInst: PInstruction); +var + P: Byte; +begin + { Three Byte OpCode Escape ! } + PInst^.OpTable := tbThreeByte; + P := PInst^.NextInst^; + Inc(PInst^.NextInst); + if P = $38 then + DecoderProcTable[ThreeByteTable38[PInst^.NextInst^]](PInst) + else + DecoderProcTable[ThreeByteTable3A[PInst^.NextInst^]](PInst); +end; + +{$ENDREGION} +{$REGION 'FPU'} +{ ========================== FPU =============================== } + +procedure Decode_Escape_FPU_D8(PInst: PInstruction); +begin + { All OpCode are valid for $D8 ! } + PInst^.OpTable := tbFPU; + Decode_NA_ModRm(PInst); +end; + +procedure Decode_Escape_FPU_D9(PInst: PInstruction); +var + P: PByte; + ModRm: Byte; + Reg: Byte; +begin + PInst^.OpTable := tbFPU; + P := PInst^.NextInst; + Inc(P); + ModRm := P^; + Reg := GetModRm_Reg(ModRm); + if ModRm < $C0 then + begin + if Reg = $01 then + begin + Decode_Invalid_FPU(PInst); + Exit; + end; + end + else + begin + if ModRm in [$D1 .. $DF, $E2, $E3, $EF] then + begin + Decode_Invalid_FPU(PInst); + Exit; + end; + end; + Decode_NA_ModRm(PInst); +end; + +procedure Decode_Escape_FPU_DA(PInst: PInstruction); +var + P: PByte; + ModRm: Byte; +begin + PInst^.OpTable := tbFPU; + P := PInst^.NextInst; + Inc(P); + ModRm := P^; + if ModRm > $C0 then + begin + if ModRm in [$E0 .. $E8, $EA .. $EF, $F0 .. $FF] then + begin + Decode_Invalid_FPU(PInst); + Exit; + end; + end; + Decode_NA_ModRm(PInst); +end; + +procedure Decode_Escape_FPU_DB(PInst: PInstruction); +var + P: PByte; + ModRm: Byte; + Reg: Byte; +begin + PInst^.OpTable := tbFPU; + P := PInst^.NextInst; + Inc(P); + ModRm := P^; + Reg := GetModRm_Reg(ModRm); + if ModRm < $C0 then + begin + if (Reg = $04) or (Reg = $06) then + begin + Decode_Invalid_FPU(PInst); + Exit; + end; + end + else + begin + if ModRm in [$E0, $E1, $E4 .. $E7, $F8 .. $FF] then + begin + Decode_Invalid_FPU(PInst); + Exit; + end; + end; + Decode_NA_ModRm(PInst); +end; + +procedure Decode_Escape_FPU_DC(PInst: PInstruction); +var + P: PByte; + ModRm: Byte; +begin + PInst^.OpTable := tbFPU; + P := PInst^.NextInst; + Inc(P); + ModRm := P^; + if ModRm > $C0 then + begin + if ModRm in [$D0 .. $DF] then + begin + Decode_Invalid_FPU(PInst); + Exit; + end; + end; + Decode_NA_ModRm(PInst); +end; + +procedure Decode_Escape_FPU_DD(PInst: PInstruction); +var + P: PByte; + ModRm: Byte; + Reg: Byte; +begin + PInst^.OpTable := tbFPU; + P := PInst^.NextInst; + Inc(P); + ModRm := P^; + Reg := GetModRm_Reg(ModRm); + if ModRm < $C0 then + begin + if (Reg = $05) then + begin + Decode_Invalid_FPU(PInst); + Exit; + end; + end + else + begin + if ModRm in [$C8 .. $CF, $F0 .. $FF] then + begin + Decode_Invalid_FPU(PInst); + Exit; + end; + end; + Decode_NA_ModRm(PInst); +end; + +procedure Decode_Escape_FPU_DE(PInst: PInstruction); +var + P: PByte; + ModRm: Byte; +begin + PInst^.OpTable := tbFPU; + P := PInst^.NextInst; + Inc(P); + ModRm := P^; + if ModRm > $C0 then + begin + if ModRm in [$D0 .. $D8, $DA .. $DF] then + begin + Decode_Invalid_FPU(PInst); + Exit; + end; + end; + Decode_NA_ModRm(PInst); +end; + +procedure Decode_Escape_FPU_DF(PInst: PInstruction); +var + P: PByte; + ModRm: Byte; +begin + PInst^.OpTable := tbFPU; + P := PInst^.NextInst; + Inc(P); + ModRm := P^; + if ModRm > $C0 then + begin + if ModRm in [$C0 .. $CF, $D0 .. $DF, $E1 .. $E7, $F8 .. $FF] then + begin + Decode_Invalid_FPU(PInst); + Exit; + end; + end; + Decode_NA_ModRm(PInst); +end; + +{$ENDREGION} +{$REGION 'GROUPS'} +{ ========================== GROUPS =============================== } + +procedure Decode_Group_1(PInst: PInstruction); +begin + SetGroup(PInst); + if not(PInst^.NextInst^ in [$80 .. $83]) then + SetInstError(PInst, INVALID_GROUP_OPCODE); + if PInst^.NextInst^ = $81 then + Decode_NA_ModRm_Iz(PInst) + else + Decode_NA_ModRm_Ib(PInst); +end; + +procedure Decode_Group_1A(PInst: PInstruction); +var + P: PByte; + Reg: Byte; +begin + SetGroup(PInst); + if (PInst^.NextInst^ <> $8F) then + SetInstError(PInst, INVALID_GROUP_OPCODE); + P := PInst^.NextInst; + Inc(P); // ModRm ! + Reg := GetModRm_Reg(P^); + if (Reg = $00) then + begin + Decode_NA_ModRm(PInst); + Exit; + end; + Decode_Invalid_Group(PInst); +end; + +procedure Decode_Group_2(PInst: PInstruction); +begin + SetGroup(PInst); + if not(PInst^.NextInst^ in [$C0 .. $C1, $D0 .. $D3]) then + SetInstError(PInst, INVALID_GROUP_OPCODE); + if (PInst^.NextInst^ in [$C0, $C1]) then + Decode_NA_ModRm_Ib(PInst) + else + Decode_NA_ModRm(PInst); +end; + +procedure Decode_Group_3(PInst: PInstruction); +var + P: PByte; + Reg: Byte; +begin + SetGroup(PInst); + if not(PInst^.NextInst^ in [$F6, $F7]) then + SetInstError(PInst, INVALID_GROUP_OPCODE); + P := PInst^.NextInst; + Inc(P); + Reg := GetModRm_Reg(P^); + if (Reg < $02) then + begin + { [TEST Reg,Immb] & [TEST Reg,Immz] } + if PInst^.NextInst^ = $F6 then + Decode_NA_ModRm_Ib(PInst) + else + Decode_NA_ModRm_Iz(PInst); + Exit; + end; + Decode_NA_ModRm(PInst); +end; + +procedure Decode_Group_4_INC_DEC(PInst: PInstruction); +var + P: PByte; + Reg: Byte; +begin + SetGroup(PInst); + Assert(PInst^.NextInst^ = $FE); + P := PInst^.NextInst; + Inc(P); // ModRm + Reg := GetModRm_Reg(P^); + if (Reg < $02) then + begin + { INC/DEC REG } + Decode_NA_ModRm(PInst); + Exit; + end; + Decode_Invalid_Group(PInst); +end; + +procedure Decode_Group_5_INC_DEC(PInst: PInstruction); +var + Reg: Byte; + P: PByte; +const + GroupProc: array [0 .. 7] of TDecoderProc = ( // + { 00 } Decode_NA_ModRm, { INC Ev } + { 01 } Decode_NA_ModRm, { DEC Ev } + { 02 } Decode_CALL_ModRm, { CALL Ev } + { 03 } Decode_CALL_Mp, { CALL Mp } + { 04 } Decode_JMP_ModRm, { JMP Ev } + { 05 } Decode_JMP_Mp, { JMP Mp } + { 06 } Decode_NA_ModRm, { PUSH Ev } + { 07 } Decode_Invalid_Group { InvalidOpCode } + ); +begin + SetGroup(PInst); + if (PInst^.NextInst^ <> $FF) then + SetInstError(PInst, INVALID_GROUP_OPCODE); + P := PInst^.NextInst; + Inc(P); // ModRm + Reg := GetModRm_Reg(P^); + GroupProc[Reg](PInst); +end; + +procedure Decode_Group_6(PInst: PInstruction); +var + P: PByte; + Reg: Byte; +begin + SetGroup(PInst); + if (PInst^.OpTable <> tbTwoByte) and (PInst^.NextInst^ <> $00) then + SetInstError(PInst, INVALID_GROUP_OPCODE); + P := PInst^.NextInst; + Inc(P); + Reg := GetModRm_Reg(P^); + if Reg = $07 then + begin + Decode_Invalid_Group(PInst); + Exit; + end; + Decode_NA_ModRm(PInst); +end; + +procedure Decode_Group_7(PInst: PInstruction); +var + P: PByte; + iMod, Reg: Byte; +begin + SetGroup(PInst); + if (PInst^.OpTable <> tbTwoByte) and (PInst^.NextInst^ <> $01) then + SetInstError(PInst, INVALID_GROUP_OPCODE); + P := PInst^.NextInst; + Inc(P); + iMod := GetModRm_Mod(P^); + Reg := GetModRm_Reg(P^); + if (Reg = $04) or (Reg = $06) then + begin + Decode_NA_ModRm(PInst); + Exit; + end + else if Reg = $05 then + begin + Decode_Invalid_Group(PInst); + Exit; + end; + if iMod <> $03 then + begin + Decode_NA_ModRm(PInst); + Exit; + end; + Decode_Invalid_Group(PInst); +end; + +procedure Decode_Group_8(PInst: PInstruction); +var + P: PByte; + Reg: Byte; +begin + SetGroup(PInst); + if (PInst^.OpTable <> tbTwoByte) and (PInst^.NextInst^ <> $BA) then + SetInstError(PInst, INVALID_GROUP_OPCODE); + P := PInst^.NextInst; + Inc(P); + Reg := GetModRm_Reg(P^); + if Reg > $03 then + begin + Decode_NA_ModRm_Ib(PInst); + Exit; + end; + Decode_Invalid_Group(PInst); +end; + +procedure Decode_Group_9(PInst: PInstruction); +var + P: PByte; + iMod, Reg: Byte; +begin + SetGroup(PInst); + if (PInst^.OpTable <> tbTwoByte) and (PInst^.NextInst^ <> $C7) then + SetInstError(PInst, INVALID_GROUP_OPCODE); + P := PInst^.NextInst; + Inc(P); + iMod := GetModRm_Mod(P^); + Reg := GetModRm_Reg(P^); + if (iMod = $03) and (Reg > $05) then + begin + Decode_NA_ModRm(PInst); + Exit; + end; + + if (iMod <> $03) then + begin + { Mod = Mem } + if (((PInst^.LID.MndPrf = $00) and (Reg = $01)) or // + ((PInst^.LID.MndPrf = $66) and (Reg = $06)) or // + ((PInst^.LID.MndPrf = $F3) and (Reg > $05))) then + begin + Decode_NA_ModRm(PInst); + Exit; + end; + end; + Decode_Invalid_Group(PInst); +end; + +procedure Decode_Group_10_UD2(PInst: PInstruction); +begin + SetGroup(PInst); + Decode_InvalidOpCode(PInst); +end; + +procedure Decode_Group_11(PInst: PInstruction); +var + P: PByte; + Reg: Byte; +begin + SetGroup(PInst); + if not(PInst^.NextInst^ in [$C6, $C7]) then + SetInstError(PInst, INVALID_GROUP_OPCODE); + P := PInst^.NextInst; + Inc(P); + Reg := GetModRm_Reg(P^); + if PInst^.NextInst^ = $C6 then + begin + if (Reg = $00) then + begin + { XABORT Instruction } + Decode_NA_ModRm_Ib(PInst); + Exit; + end + else if (Reg = $07) then + begin + Decode_NA_Ib(PInst); + Exit; + end + end + else if PInst^.NextInst^ = $C7 then + begin + if Reg = $00 then + begin + Decode_NA_ModRm_Iz(PInst); + Exit; + end + else if Reg = $07 then + begin + { XBEGIN Instruction } + SetOpCode(PInst); + Inc(PInst^.NextInst); + Decode_J(PInst, PInst^.LID.zOpSize); + PInst^.OpType := $00; + Exit; + end; + end; + Decode_Invalid_Group(PInst); +end; + +procedure Decode_Group_12(PInst: PInstruction); +var + P: PByte; + iMod, Reg: Byte; +begin + SetGroup(PInst); + { Group 12 & 13 } + if (PInst^.OpTable <> tbTwoByte) and not(PInst^.NextInst^ in [$71, $72]) then + SetInstError(PInst, INVALID_GROUP_OPCODE); + P := PInst^.NextInst; + Inc(P); + iMod := GetModRm_Mod(P^); + Reg := GetModRm_Reg(P^); + if (iMod = $03) and (Reg in [$02, $04, $06]) then + begin + Decode_NA_ModRm_Ib(PInst); + Exit; + end; + Decode_Invalid_Group(PInst); +end; + +procedure Decode_Group_13(PInst: PInstruction); +begin + SetGroup(PInst); + { Group 13 has the same instructions signature as Group 12 ! } + Decode_Group_12(PInst); +end; + +procedure Decode_Group_14(PInst: PInstruction); +var + P: PByte; + iMod, Reg: Byte; +begin + SetGroup(PInst); + if (PInst^.OpTable <> tbTwoByte) and (PInst^.NextInst^ <> $73) then + SetInstError(PInst, INVALID_GROUP_OPCODE); + P := PInst^.NextInst; + Inc(P); + iMod := GetModRm_Mod(P^); + Reg := GetModRm_Reg(P^); + if iMod = $03 then + begin + if (Reg = $02) or (Reg = $06) then + begin + Decode_NA_ModRm_Ib(PInst); + Exit; + end; + if (PInst^.LID.MndPrf = $66) and ((Reg = $03) or (Reg = $07)) then + begin + Decode_NA_ModRm_Ib(PInst); + Exit; + end; + end; + Decode_Invalid_Group(PInst); +end; + +procedure Decode_Group_15(PInst: PInstruction); +var + P: PByte; + iMod, Reg: Byte; +begin + SetGroup(PInst); + if (PInst^.OpTable <> tbTwoByte) and (PInst^.NextInst^ <> $AE) then + SetInstError(PInst, INVALID_GROUP_OPCODE); + P := PInst^.NextInst; + Inc(P); + iMod := GetModRm_Mod(P^); + Reg := GetModRm_Reg(P^); + if (iMod = $03) and (PInst^.LID.MndPrf = $F3) and (Reg < $04) then + begin + Decode_NA_ModRm(PInst); + Exit; + end; + Decode_Invalid_Group(PInst); +end; + +procedure Decode_Group_16(PInst: PInstruction); +var + P: PByte; + iMod, Reg: Byte; +begin + SetGroup(PInst); + if (PInst^.OpTable <> tbTwoByte) and (PInst^.NextInst^ <> $18) then + SetInstError(PInst, INVALID_GROUP_OPCODE); + P := PInst^.NextInst; + Inc(P); + iMod := GetModRm_Mod(P^); + Reg := GetModRm_Reg(P^); + if (iMod <> $03) and (Reg < $04) then + begin + { Prefetch group instructions. } + Decode_NA_ModRm(PInst); + Exit; + end; + Decode_Invalid_Group(PInst); +end; + +procedure Decode_Group_17(PInst: PInstruction); +var + P: PByte; + Reg: Byte; +begin + SetGroup(PInst); + P := PInst^.NextInst; + Inc(P); + Reg := GetModRm_Reg(P^); + if (Reg > $00) and (Reg < $04) then + begin + Decode_NA_ModRm(PInst); + Exit; + end; + Decode_Invalid_Group(PInst); +end; + +{$ENDREGION} +{$REGION 'DECODERS'} +{ ========================== DECODERS PROC =============================== } + +procedure Decode_NA_CALL_Ap_I64(PInst: PInstruction); +begin + { Instruction is only valid for x32 ! } + if PInst^.Archi = CPUX64 then + begin + Decode_InvalidOpCode(PInst); + Exit; + end; + PInst^.OpType := otCALL; + Decode_Ap(PInst); +end; + +procedure Decode_NA_ModRm(PInst: PInstruction); +begin + { Only valid when mandatory prefix is : $00 } + if ((PInst^.OpTable <> tbOneByte) and not(PInst^.LID.MndPrf = $00)) then + begin + Decode_InvalidOpCode(PInst); + Exit; + end; + SetOpCode(PInst); + Decode_ModRm(PInst); +end; + +procedure Decode_NA_Ib(PInst: PInstruction); +begin + { Only valid when mandatory prefix is : $00 } + if ((PInst^.OpTable <> tbOneByte) and not(PInst^.LID.MndPrf = $00)) then + begin + Decode_InvalidOpCode(PInst); + Exit; + end; + SetOpCode(PInst); + Decode_Imm(PInst, ops8bits); +end; + +procedure Decode_NA_Iz(PInst: PInstruction); +begin + { Only valid when mandatory prefix is : $00 } + if ((PInst^.OpTable <> tbOneByte) and not(PInst^.LID.MndPrf = $00)) then + begin + Decode_InvalidOpCode(PInst); + Exit; + end; + SetOpCode(PInst); + Decode_Imm(PInst, PInst^.LID.zOpSize); +end; + +procedure Decode_NA_I64(PInst: PInstruction); +begin + { Instruction is invalid on PM64 } + { Only valid when mandatory prefix is : $00 } + if (PInst^.Archi = CPUX64) or ((PInst^.OpTable <> tbOneByte) and not(PInst^.LID.MndPrf = $00)) then + begin + Decode_InvalidOpCode(PInst); + Exit; + end; + SetOpCode(PInst); +end; + +procedure Decode_NA(PInst: PInstruction); +begin + { Only valid when mandatory prefix is : $00 } + if ((PInst^.OpTable <> tbOneByte) and not(PInst^.LID.MndPrf = $00)) then + begin + Decode_InvalidOpCode(PInst); + Exit; + end; + SetOpCode(PInst); +end; + +procedure Decode_NA_ModRm_I64(PInst: PInstruction); +begin + { Instruction is invalid on PM64 } + { Only valid when mandatory prefix is : $00 } + if (PInst^.Archi = CPUX64) or ((PInst^.OpTable <> tbOneByte) and not(PInst^.LID.MndPrf = $00)) then + begin + Decode_InvalidOpCode(PInst); + Exit; + end; + SetOpCode(PInst); + Decode_ModRm(PInst); +end; + +procedure Decode_NA_ModRm_Iz(PInst: PInstruction); +begin + { Only valid when mandatory prefix is : $00 } + if ((PInst^.OpTable <> tbOneByte) and not(PInst^.LID.MndPrf = $00)) then + begin + Decode_InvalidOpCode(PInst); + Exit; + end; + SetOpCode(PInst); + Decode_ModRm(PInst); + Decode_Imm(PInst, PInst^.LID.zOpSize); +end; + +procedure Decode_NA_ModRm_Ib(PInst: PInstruction); +begin + { Only valid when mandatory prefix is : $00 } + if ((PInst^.OpTable <> tbOneByte) and not(PInst^.LID.MndPrf = $00)) then + begin + Decode_InvalidOpCode(PInst); + Exit; + end; + SetOpCode(PInst); + Decode_ModRm(PInst); + Decode_Imm(PInst, ops8bits); +end; + +procedure Decode_NA_Jb_Df64(PInst: PInstruction); +begin + { Only valid when mandatory prefix is : $00 } + if ((PInst^.OpTable <> tbOneByte) and (PInst^.LID.MndPrf <> $00)) then + begin + Decode_InvalidOpCode(PInst); + Exit; + end; + SetOpCode(PInst); + PInst^.OperandFlags := opdDf64; + Decode_J(PInst, ops8bits); +end; + +procedure Decode_NA_RET(PInst: PInstruction); +begin + SetOpCode(PInst); + PInst^.OpType := otRET; + if PInst^.OpCode in [$C2, $CA] then + Decode_Imm(PInst, ops16bits); +end; + +procedure Decode_NA_Ib_I64(PInst: PInstruction); +begin + { Instruction is invalid on PM64 } + { Only valid when mandatory prefix is : $00 } + if (PInst^.Archi = CPUX64) or ((PInst^.OpTable <> tbOneByte) and not(PInst^.LID.MndPrf = $00)) then + begin + Decode_InvalidOpCode(PInst); + Exit; + end; + SetOpCode(PInst); + Decode_Imm(PInst, ops8bits); +end; + +procedure Decode_NA_CALL_Jz_Df64(PInst: PInstruction); +begin + SetOpCode(PInst); + PInst^.OpType := otCALL; + PInst^.OperandFlags := opdDf64; + Decode_J(PInst, PInst^.LID.zOpSize); +end; + +procedure Decode_NA_JMP_Jz_Df64(PInst: PInstruction); +begin + SetOpCode(PInst); + PInst^.OpType := otJMP; + PInst^.OperandFlags := opdDf64; + Decode_J(PInst, PInst^.LID.zOpSize); +end; + +procedure Decode_NA_JMP_Ap_I64(PInst: PInstruction); +begin + if PInst^.Archi = CPUX64 then + begin + Decode_InvalidOpCode(PInst); + Exit; + end; + PInst^.OpType := otJMP; + Decode_Ap(PInst); +end; + +procedure Decode_NA_JMP_Jb_Df64(PInst: PInstruction); +begin + SetOpCode(PInst); + PInst^.OpType := otJMP; + PInst^.OperandFlags := opdDf64; + Decode_J(PInst, ops8bits); +end; + +procedure Decode_CALL_ModRm(PInst: PInstruction); +begin + PInst^.OpType := otCALL; + Decode_Branch_ModRm(PInst); +end; + +procedure Decode_CALL_Mp(PInst: PInstruction); +begin + PInst^.OpType := otCALL; + Decode_Mp(PInst); +end; + +procedure Decode_JMP_ModRm(PInst: PInstruction); +begin + PInst^.OpType := otJMP; + Decode_Branch_ModRm(PInst); +end; + +procedure Decode_JMP_Mp(PInst: PInstruction); +begin + PInst^.OpType := otJMP; + Decode_Mp(PInst); +end; + +procedure Decode_NA_CALL(PInst: PInstruction); +begin + { SYSCALL! } + SetOpCode(PInst); +end; + +procedure Decode_NA_66_F2_F3_ModRm(PInst: PInstruction); +begin + SetOpCode(PInst); + Decode_ModRm(PInst); +end; + +procedure Decode_NA_66_ModRm(PInst: PInstruction); +begin + { Only valid when mandatory prefix is : $00 or $66 } + if ((PInst^.OpTable <> tbOneByte) and not(PInst^.LID.MndPrf in [$00, $66])) then + begin + Decode_InvalidOpCode(PInst); + Exit; + end; + SetOpCode(PInst); + Decode_ModRm(PInst); +end; + +procedure Decode_NA_66_F3_ModRm(PInst: PInstruction); +begin + { Only valid when mandatory prefix is : $00 or $66 or $F3 } + if ((PInst^.OpTable <> tbOneByte) and (PInst^.LID.MndPrf = $F2)) then + begin + Decode_InvalidOpCode(PInst); + Exit; + end; + SetOpCode(PInst); + Decode_ModRm(PInst); +end; + +procedure Decode_NA_F3_ModRm(PInst: PInstruction); +begin + { Only valid when mandatory prefix is : $00 or $F3 } + if ((PInst^.OpTable <> tbOneByte) and not(PInst^.LID.MndPrf in [$00, $F3])) then + begin + Decode_InvalidOpCode(PInst); + Exit; + end; + SetOpCode(PInst); + Decode_ModRm(PInst); +end; + +procedure Decode_66_ModRm(PInst: PInstruction); +begin + { Only valid when mandatory prefix is : $66 } + if ((PInst^.OpTable <> tbOneByte) and not(PInst^.LID.MndPrf = $66)) then + begin + Decode_InvalidOpCode(PInst); + Exit; + end; + SetOpCode(PInst); + Decode_ModRm(PInst); +end; + +procedure Decode_NA_66_F2_F3_ModRm_Ib(PInst: PInstruction); +begin + SetOpCode(PInst); + Decode_ModRm(PInst); + Decode_Imm(PInst, ops8bits); +end; + +procedure Decode_66_F2_ModRm(PInst: PInstruction); +begin + { Only valid when mandatory prefix is : $66 or $F2 } + if ((PInst^.OpTable <> tbOneByte) and not(PInst^.LID.MndPrf in [$66, $F2])) then + begin + Decode_InvalidOpCode(PInst); + Exit; + end; + SetOpCode(PInst); + Decode_ModRm(PInst); +end; + +procedure Decode_F3_ModRm(PInst: PInstruction); +begin + { Only valid when mandatory prefix is : $F3 } + if ((PInst^.OpTable <> tbOneByte) and not(PInst^.LID.MndPrf = $F3)) then + begin + Decode_InvalidOpCode(PInst); + Exit; + end; + SetOpCode(PInst); + Decode_ModRm(PInst); +end; + +procedure Decode_NA_66_ModRm_Ib(PInst: PInstruction); +begin + { Only valid when mandatory prefix is : $00 or $66 } + if ((PInst^.OpTable <> tbOneByte) and not(PInst^.LID.MndPrf in [$00, $66])) then + begin + Decode_InvalidOpCode(PInst); + Exit; + end; + SetOpCode(PInst); + Decode_ModRm(PInst); + Decode_Imm(PInst, ops8bits); +end; + +procedure Decode_66_F2_F3_ModRm(PInst: PInstruction); +begin + { Only valid when mandatory prefix is : $66 or $F2 or $F3 } + if ((PInst^.OpTable <> tbOneByte) and (PInst^.LID.MndPrf = $00)) then + begin + Decode_InvalidOpCode(PInst); + Exit; + end; + SetOpCode(PInst); + Decode_ModRm(PInst); +end; + +procedure Decode_F2_ModRm(PInst: PInstruction); +begin + { Only valid when mandatory prefix is : $F2 } + if ((PInst^.OpTable <> tbOneByte) and not(PInst^.LID.MndPrf = $F2)) then + begin + Decode_InvalidOpCode(PInst); + Exit; + end; + SetOpCode(PInst); + Decode_ModRm(PInst); +end; + +procedure Decode_SP_T38_F0_F7(PInst: PInstruction); +var + Prf66F2: Boolean; +begin + if PInst^.NextInst^ = $F3 then + begin + Decode_Group_17(PInst); + Exit; + end; + + { 66 & F2 } + Prf66F2 := PInst^.Prefixes and (Prf_OpSize or Prf_Repne) = (Prf_OpSize or Prf_Repne); + + if Prf66F2 then + begin + { Valid only for CRC32 instruction ! } + if (PInst^.NextInst^ = $F0) or (PInst^.NextInst^ = $F1) then + begin + Decode_NA_ModRm(PInst); + Exit; + end + else + begin + Decode_InvalidOpCode(PInst); + Exit; + end; + end + else if PInst^.LID.MndPrf = $00 then + begin + if (PInst^.NextInst^ = $F4) or (PInst^.NextInst^ = $F6) then + begin + Decode_InvalidOpCode(PInst); + Exit; + end; + end + else if PInst^.LID.MndPrf = $66 then + begin + if (PInst^.NextInst^ in [$F2 .. $F5]) then + begin + Decode_InvalidOpCode(PInst); + Exit; + end; + end + else if PInst^.LID.MndPrf = $F3 then + begin + if (PInst^.NextInst^ < $F5) then + begin + Decode_InvalidOpCode(PInst); + Exit; + end; + end + else if PInst^.LID.MndPrf = $F2 then + begin + if (PInst^.NextInst^ in [$F2 .. $F4]) then + begin + Decode_InvalidOpCode(PInst); + Exit; + end; + end; + Decode_NA_ModRm(PInst); +end; + +procedure Decode_66_ModRm_Ib(PInst: PInstruction); +begin + { Only valid when mandatory prefix is : $66 } + if ((PInst^.OpTable <> tbOneByte) and not(PInst^.LID.MndPrf = $66)) then + begin + Decode_InvalidOpCode(PInst); + Exit; + end; + SetOpCode(PInst); + Decode_ModRm(PInst); + Decode_Imm(PInst, ops8bits); +end; + +procedure Decode_F2_ModRm_Ib(PInst: PInstruction); +begin + { Only valid when mandatory prefix is : $F2 } + if ((PInst^.OpTable <> tbOneByte) and not(PInst^.LID.MndPrf = $F2)) then + begin + Decode_InvalidOpCode(PInst); + Exit; + end; + SetOpCode(PInst); + Decode_ModRm(PInst); + Decode_Imm(PInst, ops8bits); +end; + +procedure Decode_NA_RET_Iw_Df64(PInst: PInstruction); +begin + PInst^.OpType := otRET; + SetOpCode(PInst); + PInst^.OperandFlags := opdDf64; + Decode_Imm(PInst, ops16bits); +end; + +procedure Decode_NA_D64(PInst: PInstruction); +begin + { Only valid when mandatory prefix is : $00 } + if ((PInst^.OpTable <> tbOneByte) and (PInst^.LID.MndPrf <> $00)) then + begin + Decode_InvalidOpCode(PInst); + Exit; + end; + SetOpCode(PInst); + PInst^.OperandFlags := opdD64; +end; + +procedure Decode_NA_Iz_D64(PInst: PInstruction); +begin + { Only valid when mandatory prefix is : $00 } + if ((PInst^.OpTable <> tbOneByte) and (PInst^.LID.MndPrf <> $00)) then + begin + Decode_InvalidOpCode(PInst); + Exit; + end; + SetOpCode(PInst); + PInst^.OperandFlags := opdD64; + Decode_Imm(PInst, PInst^.LID.zOpSize); +end; + +procedure Decode_NA_Ib_D64(PInst: PInstruction); +begin + { Only valid when mandatory prefix is : $00 } + if ((PInst^.OpTable <> tbOneByte) and (PInst^.LID.MndPrf <> $00)) then + begin + Decode_InvalidOpCode(PInst); + Exit; + end; + SetOpCode(PInst); + PInst^.OperandFlags := opdD64; + Decode_Imm(PInst, ops8bits); +end; + +procedure Decode_NA_RET_Df64(PInst: PInstruction); +begin + PInst^.OpType := otRET; + PInst^.OperandFlags := opdDf64; + SetOpCode(PInst); +end; + +procedure Decode_NA_RET_Iw(PInst: PInstruction); +begin + PInst^.OpType := otRET; + SetOpCode(PInst); + Decode_Imm(PInst, ops16bits); +end; + +procedure Decode_NA_Iw_Ib_D64(PInst: PInstruction); +begin + { Only valid when mandatory prefix is : $00 } + if ((PInst^.OpTable <> tbOneByte) and (PInst^.LID.MndPrf <> $00)) then + begin + Decode_InvalidOpCode(PInst); + Exit; + end; + SetOpCode(PInst); + PInst^.OperandFlags := opdD64; + Decode_Imm(PInst, ops16bits); + Decode_Imm(PInst, ops8bits); +end; + +procedure Decode_NA_ModRm_F64(PInst: PInstruction); +begin + { Only valid when mandatory prefix is : $00 } + if ((PInst^.OpTable <> tbOneByte) and (PInst^.LID.MndPrf <> $00)) then + begin + Decode_InvalidOpCode(PInst); + Exit; + end; + SetOpCode(PInst); + PInst^.OperandFlags := opdF64; + Decode_ModRm(PInst); +end; + +procedure Decode_NA_Jz_Df64(PInst: PInstruction); +begin + { Only valid when mandatory prefix is : $00 } + if ((PInst^.OpTable <> tbOneByte) and (PInst^.LID.MndPrf <> $00)) then + begin + Decode_InvalidOpCode(PInst); + Exit; + end; + SetOpCode(PInst); + PInst^.OperandFlags := opdDf64; + Decode_J(PInst, PInst^.LID.zOpSize); +end; + +procedure Decode_NA_OfstV(PInst: PInstruction); +begin + SetOpCode(PInst); + Decode_Imm(PInst, PInst.LID.vOpSize); + PInst.Disp.Value := PInst.Imm.Value; + PInst.Disp.Size := PInst.Imm.Size; + PInst.Disp.Flags := dfUsed or dfOffset; + PInst.Imm.Size := $00; + PInst.Imm.Value := $00; + PInst.Imm.Flags := $00; +end; + +procedure Decode_NA_Iv(PInst: PInstruction); +begin + { Only valid when mandatory prefix is : $00 } + if ((PInst^.OpTable <> tbOneByte) and not(PInst^.LID.MndPrf = $00)) then + begin + Decode_InvalidOpCode(PInst); + Exit; + end; + SetOpCode(PInst); + Decode_Imm(PInst, PInst^.LID.vOpSize); +end; +{$ENDREGION} + +function DecodeInst(PInst: PInstruction): ShortInt; +var + P: PByte; + LArchi: Byte; + LAddr: PByte; + LErrors: Byte; + LVA: PByte; + LOptions: Byte; +begin + { No Errors } + SetInstError(PInst, NO_ERROR); + + if not(PInst^.Archi in [CPUX32, CPUX64]) then + SetInstError(PInst, INVALID_CPUX); + + if not Assigned(PInst^.Addr) then + SetInstError(PInst, INVALID_ADDRESS); + + { Init Instruction Structure } + LArchi := PInst^.Archi; + LAddr := PInst^.Addr; + LVA := PInst^.VirtualAddr; + LErrors := PInst^.Errors; + LOptions := PInst^.Options; + + FillChar(PInst^, SizeOf(TInstruction), #0); + + PInst^.Archi := LArchi; + PInst^.Addr := LAddr; + PInst^.Errors := LErrors; + PInst^.VirtualAddr := LVA; + PInst.Options := LOptions; + + P := PInst^.Addr; + PInst^.NextInst := P; + + PInst^.LID.zOpSize := ops32bits; + PInst^.LID.vOpSize := ops32bits; + PInst^.AddrMode := DefAddressMode[PInst^.Archi]; + + { Default Op Table is One Byte ! } + PInst^.OpTable := tbOneByte; + + DecoderProcTable[OneByteTable[P^]](PInst); + Result := PInst^.NextInst - P; + PInst^.InstSize := Result; + + if Result > CPUX_TO_INST_LENGTH[PInst^.Archi] then + SetInstError(PInst, INVALID_INSTRUCTION_LENGTH); +end; + +end. diff --git a/components/detours/Source/ModRmFlagsTables.inc b/components/detours/Source/ModRmFlagsTables.inc new file mode 100644 index 00000000..f51efb57 --- /dev/null +++ b/components/detours/Source/ModRmFlagsTables.inc @@ -0,0 +1,140 @@ +// ************************************************************************************************** +// Part of Delphi Instruction Decode Library [InstDecode] +// +// https://github.com/MahdiSafsafi/delphi-detours-library + +// The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); +// you may not use this file except in compliance with the License. You may obtain a copy of the +// License at http://www.mozilla.org/MPL/ +// +// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF +// ANY KIND, either express or implied. See the License for the specific language governing rights +// and limitations under the License. +// +// The Original Code is ModRmFlagsTables.inc. +// +// The Initial Developer of the Original Code is Mahdi Safsafi [SMP3]. +// Portions created by Mahdi Safsafi . are Copyright (C) 2013-2016 Mahdi Safsafi . +// All Rights Reserved. +// +// ************************************************************************************************** + + +{ Reference : Intel® 64 and IA-32 Architectures Software Developer’s Manual Vol 2 } + +type + TModRmFlagsArray = array [Byte] of Byte; + PModRmFlagsArray = ^TModRmFlagsArray; + { + ModRMFlags : + Bits:4 3 2 1 0 . + + Bit 0 : Set ==> Register Indirect Addressing Mode . + Bit 1 : Set ==> Displacement 8 bit . + Bit 2 : Set ==> Displacement 16 bit . + Bit 3 : Set ==> Displacement 32 bit. + Bit 4 : Set ==> SIB Used . + + + Values: + + $00 ==> Register . + $01 ==> Register Indirect Addressing Mode with No Displacement . + $03 ==> Register Indirect Addressing Mode + 8 bit Displacement . + $04 ==> 16 bit Displacement only without register . + $05 ==> Register Indirect Addressing Mode + 16 bit Displacement . + $08 ==> 32 bit Displacement only without register . + $09 ==> Register Indirect Addressing Mode + 32 bit Displacement . + $11 ==> Register Indirect Addressing Mode + SIB . + $13 ==> Register Indirect Addressing Mode + SIB + 8 bit Displacement . + $19 ==> Register Indirect Addressing Mode + SIB + 32 bit Displacement . + + } + +const + + ModRM16Flags: TModRmFlagsArray = ( + { => Mod=00b <= } + $01, $01, $01, $01, $01, $01, $04, $01, { 00 } + $01, $01, $01, $01, $01, $01, $04, $01, { 00 } + $01, $01, $01, $01, $01, $01, $04, $01, { 00 } + $01, $01, $01, $01, $01, $01, $04, $01, { 00 } + $01, $01, $01, $01, $01, $01, $04, $01, { 00 } + $01, $01, $01, $01, $01, $01, $04, $01, { 00 } + $01, $01, $01, $01, $01, $01, $04, $01, { 00 } + $01, $01, $01, $01, $01, $01, $04, $01, { 00 } + { => Mod=01b <= } + $03, $03, $03, $03, $03, $03, $03, $03, { 01 } + $03, $03, $03, $03, $03, $03, $03, $03, { 01 } + $03, $03, $03, $03, $03, $03, $03, $03, { 01 } + $03, $03, $03, $03, $03, $03, $03, $03, { 01 } + $03, $03, $03, $03, $03, $03, $03, $03, { 01 } + $03, $03, $03, $03, $03, $03, $03, $03, { 01 } + $03, $03, $03, $03, $03, $03, $03, $03, { 01 } + $03, $03, $03, $03, $03, $03, $03, $03, { 01 } + { => Mod=10b <= } + $05, $05, $05, $05, $05, $05, $05, $05, { 10 } + $05, $05, $05, $05, $05, $05, $05, $05, { 10 } + $05, $05, $05, $05, $05, $05, $05, $05, { 10 } + $05, $05, $05, $05, $05, $05, $05, $05, { 10 } + $05, $05, $05, $05, $05, $05, $05, $05, { 10 } + $05, $05, $05, $05, $05, $05, $05, $05, { 10 } + $05, $05, $05, $05, $05, $05, $05, $05, { 10 } + $05, $05, $05, $05, $05, $05, $05, $05, { 10 } + { => Mod=11b <= } + $00, $00, $00, $00, $00, $00, $00, $00, { 11 } + $00, $00, $00, $00, $00, $00, $00, $00, { 11 } + $00, $00, $00, $00, $00, $00, $00, $00, { 11 } + $00, $00, $00, $00, $00, $00, $00, $00, { 11 } + $00, $00, $00, $00, $00, $00, $00, $00, { 11 } + $00, $00, $00, $00, $00, $00, $00, $00, { 11 } + $00, $00, $00, $00, $00, $00, $00, $00, { 11 } + $00, $00, $00, $00, $00, $00, $00, $00 { 11 } + + ); + ModRM32Flags: TModRmFlagsArray = ( + { => Mod=00b <= } + $01, $01, $01, $01, $11, $08, $01, $01, { 00 } + $01, $01, $01, $01, $11, $08, $01, $01, { 00 } + $01, $01, $01, $01, $11, $08, $01, $01, { 00 } + $01, $01, $01, $01, $11, $08, $01, $01, { 00 } + $01, $01, $01, $01, $11, $08, $01, $01, { 00 } + $01, $01, $01, $01, $11, $08, $01, $01, { 00 } + $01, $01, $01, $01, $11, $08, $01, $01, { 00 } + $01, $01, $01, $01, $11, $08, $01, $01, { 00 } + { => Mod=01b <= } + $03, $03, $03, $03, $13, $03, $03, $03, { 01 } + $03, $03, $03, $03, $13, $03, $03, $03, { 01 } + $03, $03, $03, $03, $13, $03, $03, $03, { 01 } + $03, $03, $03, $03, $13, $03, $03, $03, { 01 } + $03, $03, $03, $03, $13, $03, $03, $03, { 01 } + $03, $03, $03, $03, $13, $03, $03, $03, { 01 } + $03, $03, $03, $03, $13, $03, $03, $03, { 01 } + $03, $03, $03, $03, $13, $03, $03, $03, { 01 } + { => Mod=10b <= } + $09, $09, $09, $09, $19, $09, $09, $09, { 10 } + $09, $09, $09, $09, $19, $09, $09, $09, { 10 } + $09, $09, $09, $09, $19, $09, $09, $09, { 10 } + $09, $09, $09, $09, $19, $09, $09, $09, { 10 } + $09, $09, $09, $09, $19, $09, $09, $09, { 10 } + $09, $09, $09, $09, $19, $09, $09, $09, { 10 } + $09, $09, $09, $09, $19, $09, $09, $09, { 10 } + $09, $09, $09, $09, $19, $09, $09, $09, { 10 } + { => Mod=11b <= } + $00, $00, $00, $00, $00, $00, $00, $00, { 11 } + $00, $00, $00, $00, $00, $00, $00, $00, { 11 } + $00, $00, $00, $00, $00, $00, $00, $00, { 11 } + $00, $00, $00, $00, $00, $00, $00, $00, { 11 } + $00, $00, $00, $00, $00, $00, $00, $00, { 11 } + $00, $00, $00, $00, $00, $00, $00, $00, { 11 } + $00, $00, $00, $00, $00, $00, $00, $00, { 11 } + $00, $00, $00, $00, $00, $00, $00, $00 { 11 } + + ); + + ModRmFlags: array [0 .. 3] of PModRmFlagsArray = ( // + nil, + @ModRM16Flags, { AddrMode 16-bits } + @ModRM32Flags, { AddrMode 32-bits } + @ModRM32Flags { AddrMode 64-bits } + ); \ No newline at end of file diff --git a/components/detours/Source/OpCodesTables.inc b/components/detours/Source/OpCodesTables.inc new file mode 100644 index 00000000..2a46dc94 --- /dev/null +++ b/components/detours/Source/OpCodesTables.inc @@ -0,0 +1,1158 @@ +// ************************************************************************************************** +// Part of Delphi Instruction Decode Library [InstDecode] +// +// https://github.com/MahdiSafsafi/delphi-detours-library + +// The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); +// you may not use this file except in compliance with the License. You may obtain a copy of the +// License at http://www.mozilla.org/MPL/ +// +// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF +// ANY KIND, either express or implied. See the License for the specific language governing rights +// and limitations under the License. +// +// The Original Code is OpCodesTables.inc. +// +// The Initial Developer of the Original Code is Mahdi Safsafi [SMP3]. +// Portions created by Mahdi Safsafi . are Copyright (C) 2013-2016 Mahdi Safsafi . +// All Rights Reserved. +// +// ************************************************************************************************** + +{ Reference : + -sandpile.org + -Intel® 64 and IA-32 Architectures Software Developer’s Manual Vol 2 +} + +{ ============================================ + Index -> DecoderProc + ============================================ } +{ 00 = Decode_InvalidOpCode} +{ 01 = Decode_NA_ModRm} +{ 02 = Decode_NA_Ib} +{ 03 = Decode_NA_Iz} +{ 04 = Decode_NA_I64} +{ 05 = Decode_Escape_2_Byte} +{ 06 = Decode_ES_Prefix} +{ 07 = Decode_CS_Prefix} +{ 08 = Decode_SS_Prefix} +{ 09 = Decode_DS_Prefix} +{ 10 = Decode_REX_Prefix} +{ 11 = Decode_NA_D64} +{ 12 = Decode_NA_ModRm_I64} +{ 13 = Decode_FS_Prefix} +{ 14 = Decode_GS_Prefix} +{ 15 = Decode_OPSIZE_Prefix} +{ 16 = Decode_ADSIZE_Prefix} +{ 17 = Decode_NA_Iz_D64} +{ 18 = Decode_NA_ModRm_Iz} +{ 19 = Decode_NA_Ib_D64} +{ 20 = Decode_NA_ModRm_Ib} +{ 21 = Decode_NA} +{ 22 = Decode_NA_Jb_Df64} +{ 23 = Decode_Group_1} +{ 24 = Decode_Group_1A} +{ 25 = Decode_NA_CALL_Ap_I64} +{ 26 = Decode_NA_OfstV} +{ 27 = Decode_NA_Iv} +{ 28 = Decode_Group_2} +{ 29 = Decode_NA_RET_Iw_Df64} +{ 30 = Decode_NA_RET_Df64} +{ 31 = Decode_VEX3_Prefix} +{ 32 = Decode_VEX2_Prefix} +{ 33 = Decode_Group_11} +{ 34 = Decode_NA_Iw_Ib_D64} +{ 35 = Decode_NA_RET_Iw} +{ 36 = Decode_NA_RET} +{ 37 = Decode_NA_Ib_I64} +{ 38 = Decode_Escape_FPU_D8} +{ 39 = Decode_Escape_FPU_D9} +{ 40 = Decode_Escape_FPU_DA} +{ 41 = Decode_Escape_FPU_DB} +{ 42 = Decode_Escape_FPU_DC} +{ 43 = Decode_Escape_FPU_DD} +{ 44 = Decode_Escape_FPU_DE} +{ 45 = Decode_Escape_FPU_DF} +{ 46 = Decode_NA_CALL_Jz_Df64} +{ 47 = Decode_NA_JMP_Jz_Df64} +{ 48 = Decode_NA_JMP_Ap_I64} +{ 49 = Decode_NA_JMP_Jb_Df64} +{ 50 = Decode_LOCK_Prefix} +{ 51 = Decode_REPNE_Prefix} +{ 52 = Decode_REPE_Prefix} +{ 53 = Decode_Group_3} +{ 54 = Decode_Group_4_INC_DEC} +{ 55 = Decode_Group_5_INC_DEC} +{ 56 = Decode_Group_6} +{ 57 = Decode_Group_7} +{ 58 = Decode_NA_CALL} +{ 59 = Decode_NA_66_F2_F3_ModRm} +{ 60 = Decode_NA_66_ModRm} +{ 61 = Decode_NA_66_F3_ModRm} +{ 62 = Decode_Group_16} +{ 63 = Decode_NA_ModRm_F64} +{ 64 = Decode_Escape_3_Byte} +{ 65 = Decode_NA_F3_ModRm} +{ 66 = Decode_66_ModRm} +{ 67 = Decode_NA_66_F2_F3_ModRm_Ib} +{ 68 = Decode_Group_12} +{ 69 = Decode_Group_13} +{ 70 = Decode_Group_14} +{ 71 = Decode_66_F2_ModRm} +{ 72 = Decode_NA_Jz_Df64} +{ 73 = Decode_Group_15} +{ 74 = Decode_F3_ModRm} +{ 75 = Decode_Group_10_UD2} +{ 76 = Decode_Group_8} +{ 77 = Decode_NA_66_ModRm_Ib} +{ 78 = Decode_Group_9} +{ 79 = Decode_66_F2_F3_ModRm} +{ 80 = Decode_F2_ModRm} +{ 81 = Decode_SP_T38_F0_F7} +{ 82 = Decode_66_ModRm_Ib} +{ 83 = Decode_F2_ModRm_Ib} + +{============================================ + OneByteTable +============================================} +const OneByteTable : array[Byte] of Byte =(// +{0x00} 01, {ADD} +{0x01} 01, {ADD} +{0x02} 01, {ADD} +{0x03} 01, {ADD} +{0x04} 02, {ADD} +{0x05} 03, {ADD} +{0x06} 04, {PUSH} +{0x07} 04, {POP} +{0x08} 01, {OR} +{0x09} 01, {OR} +{0x0A} 01, {OR} +{0x0B} 01, {OR} +{0x0C} 02, {OR} +{0x0D} 03, {OR} +{0x0E} 04, {PUSH} +{0x0F} 05, {Escape_2_Byte} +{0x10} 01, {ADC} +{0x11} 01, {ADC} +{0x12} 01, {ADC} +{0x13} 01, {ADC} +{0x14} 02, {ADC} +{0x15} 03, {ADC} +{0x16} 04, {PUSH} +{0x17} 04, {POP} +{0x18} 01, {SBB} +{0x19} 01, {SBB} +{0x1A} 01, {SBB} +{0x1B} 01, {SBB} +{0x1C} 02, {SBB} +{0x1D} 03, {SBB} +{0x1E} 04, {PUSH} +{0x1F} 04, {POP} +{0x20} 01, {AND} +{0x21} 01, {AND} +{0x22} 01, {AND} +{0x23} 01, {AND} +{0x24} 02, {AND} +{0x25} 03, {AND} +{0x26} 06, {ES_Prefix} +{0x27} 04, {DAA} +{0x28} 01, {SUB} +{0x29} 01, {SUB} +{0x2A} 01, {SUB} +{0x2B} 01, {SUB} +{0x2C} 02, {SUB} +{0x2D} 03, {SUB} +{0x2E} 07, {CS_Prefix} +{0x2F} 04, {DAS} +{0x30} 01, {XOR} +{0x31} 01, {XOR} +{0x32} 01, {XOR} +{0x33} 01, {XOR} +{0x34} 02, {XOR} +{0x35} 03, {XOR} +{0x36} 08, {SS_Prefix} +{0x37} 04, {AAA} +{0x38} 01, {CMP} +{0x39} 01, {CMP} +{0x3A} 01, {CMP} +{0x3B} 01, {CMP} +{0x3C} 02, {CMP} +{0x3D} 03, {CMP} +{0x3E} 09, {DS_Prefix} +{0x3F} 04, {AAS} +{0x40} 10, {INC/REX_Prefix} +{0x41} 10, {INC/REX_Prefix} +{0x42} 10, {INC/REX_Prefix} +{0x43} 10, {INC/REX_Prefix} +{0x44} 10, {INC/REX_Prefix} +{0x45} 10, {INC/REX_Prefix} +{0x46} 10, {INC/REX_Prefix} +{0x47} 10, {INC/REX_Prefix} +{0x48} 10, {DEC/REX_Prefix} +{0x49} 10, {DEC/REX_Prefix} +{0x4A} 10, {DEC/REX_Prefix} +{0x4B} 10, {DEC/REX_Prefix} +{0x4C} 10, {DEC/REX_Prefix} +{0x4D} 10, {DEC/REX_Prefix} +{0x4E} 10, {DEC/REX_Prefix} +{0x4F} 10, {DEC/REX_Prefix} +{0x50} 11, {PUSH} +{0x51} 11, {PUSH} +{0x52} 11, {PUSH} +{0x53} 11, {PUSH} +{0x54} 11, {PUSH} +{0x55} 11, {PUSH} +{0x56} 11, {PUSH} +{0x57} 11, {PUSH} +{0x58} 11, {POP} +{0x59} 11, {POP} +{0x5A} 11, {POP} +{0x5B} 11, {POP} +{0x5C} 11, {POP} +{0x5D} 11, {POP} +{0x5E} 11, {POP} +{0x5F} 11, {POP} +{0x60} 04, {PUSHAD/PUSHA} +{0x61} 04, {POPAD/POPA} +{0x62} 12, {BOUND} +{0x63} 01, {ARPL/MOVSXD} +{0x64} 13, {FS_Prefix} +{0x65} 14, {GS_Prefix} +{0x66} 15, {OPSIZE_Prefix} +{0x67} 16, {ADSIZE_Prefix} +{0x68} 17, {PUSH} +{0x69} 18, {IMUL} +{0x6A} 19, {PUSH} +{0x6B} 20, {IMUL} +{0x6C} 21, {INS} +{0x6D} 21, {INS} +{0x6E} 21, {OUTS} +{0x6F} 21, {OUTS} +{0x70} 22, {JO} +{0x71} 22, {JNO} +{0x72} 22, {JB} +{0x73} 22, {JNB} +{0x74} 22, {JZ} +{0x75} 22, {JNZ} +{0x76} 22, {JBE} +{0x77} 22, {JNBE} +{0x78} 22, {JS} +{0x79} 22, {JNS} +{0x7A} 22, {JP} +{0x7B} 22, {JNP} +{0x7C} 22, {JL} +{0x7D} 22, {JNL} +{0x7E} 22, {JLE} +{0x7F} 22, {JNLE} +{0x80} 23, {group_1} +{0x81} 23, {group_1} +{0x82} 23, {group_1*} +{0x83} 23, {group_1} +{0x84} 01, {TEST} +{0x85} 01, {TEST} +{0x86} 01, {XCHG} +{0x87} 01, {XCHG} +{0x88} 01, {MOV} +{0x89} 01, {MOV} +{0x8A} 01, {MOV} +{0x8B} 01, {MOV} +{0x8C} 01, {MOV} +{0x8D} 01, {LEA} +{0x8E} 01, {MOV} +{0x8F} 24, {group_1A} +{0x90} 21, {PAUSE/NOP} +{0x91} 21, {XCHG} +{0x92} 21, {XCHG} +{0x93} 21, {XCHG} +{0x94} 21, {XCHG} +{0x95} 21, {XCHG} +{0x96} 21, {XCHG} +{0x97} 21, {XCHG} +{0x98} 21, {CWDE/CBW/CDQE} +{0x99} 21, {CDQ/CWD/CQO} +{0x9A} 25, {CALL} +{0x9B} 21, {WAIT} +{0x9C} 11, {PUSHF} +{0x9D} 11, {POPF} +{0x9E} 21, {SAHF} +{0x9F} 21, {LAHF} +{0xA0} 26, {MOV} +{0xA1} 26, {MOV} +{0xA2} 26, {MOV} +{0xA3} 26, {MOV} +{0xA4} 21, {MOVS} +{0xA5} 21, {MOVS} +{0xA6} 21, {CMPS} +{0xA7} 21, {CMPS} +{0xA8} 02, {TEST} +{0xA9} 03, {TEST} +{0xAA} 21, {STOS} +{0xAB} 21, {STOS} +{0xAC} 21, {LODS} +{0xAD} 21, {LODS} +{0xAE} 21, {SCAS} +{0xAF} 21, {SCAS} +{0xB0} 02, {MOV} +{0xB1} 02, {MOV} +{0xB2} 02, {MOV} +{0xB3} 02, {MOV} +{0xB4} 02, {MOV} +{0xB5} 02, {MOV} +{0xB6} 02, {MOV} +{0xB7} 02, {MOV} +{0xB8} 27, {MOV} +{0xB9} 27, {MOV} +{0xBA} 27, {MOV} +{0xBB} 27, {MOV} +{0xBC} 27, {MOV} +{0xBD} 27, {MOV} +{0xBE} 27, {MOV} +{0xBF} 27, {MOV} +{0xC0} 28, {group_2} +{0xC1} 28, {group_2} +{0xC2} 29, {RET} +{0xC3} 30, {RET} +{0xC4} 31, {LES/VEX3_Prefix} +{0xC5} 32, {LDS/VEX2_Prefix} +{0xC6} 33, {group_11} +{0xC7} 33, {group_11} +{0xC8} 34, {ENTER} +{0xC9} 11, {LEAVE} +{0xCA} 35, {RET} +{0xCB} 36, {RET} +{0xCC} 21, {INT3} +{0xCD} 02, {INT} +{0xCE} 04, {INTO} +{0xCF} 36, {IRET} +{0xD0} 28, {group_2} +{0xD1} 28, {group_2} +{0xD2} 28, {group_2} +{0xD3} 28, {group_2} +{0xD4} 37, {AAM} +{0xD5} 37, {AAD} +{0xD6} 04, {SETALC} +{0xD7} 21, {XLAT} +{0xD8} 38, {Escape_FPU_D8} +{0xD9} 39, {Escape_FPU_D9} +{0xDA} 40, {Escape_FPU_DA} +{0xDB} 41, {Escape_FPU_DB} +{0xDC} 42, {Escape_FPU_DC} +{0xDD} 43, {Escape_FPU_DD} +{0xDE} 44, {Escape_FPU_DE} +{0xDF} 45, {Escape_FPU_DF} +{0xE0} 22, {LOOPNZ/LOOPNE} +{0xE1} 22, {LOOPZ/LOOPE} +{0xE2} 22, {LOOP} +{0xE3} 22, {JRCX/JECX/JCXZ} +{0xE4} 02, {IN} +{0xE5} 02, {IN} +{0xE6} 02, {OUT} +{0xE7} 02, {OUT} +{0xE8} 46, {CALL} +{0xE9} 47, {JMP} +{0xEA} 48, {JMP} +{0xEB} 49, {JMP} +{0xEC} 21, {IN} +{0xED} 21, {IN} +{0xEE} 21, {OUT} +{0xEF} 21, {OUT} +{0xF0} 50, {LOCK_Prefix} +{0xF1} 21, {INT1} +{0xF2} 51, {REPNE_Prefix} +{0xF3} 52, {REPE_Prefix} +{0xF4} 21, {HLT} +{0xF5} 21, {CMC} +{0xF6} 53, {group_3} +{0xF7} 53, {group_3} +{0xF8} 21, {CLC} +{0xF9} 21, {STC} +{0xFA} 21, {CLI} +{0xFB} 21, {STI} +{0xFC} 21, {CLD} +{0xFD} 21, {STD} +{0xFE} 54, {group_4_INC_DEC} +{0xFF} 55 {group_5_INC_DEC} +); +{============================================ + TwoByteTable +============================================} +const TwoByteTable : array[Byte] of Byte =(// +{0x00} 56, {group_6} +{0x01} 57, {group_7} +{0x02} 01, {LAR} +{0x03} 01, {LSL} +{0x04} 21, {LOADALL?/RESET?/HANG?} +{0x05} 58, {LOADALL/SYSCALL} +{0x06} 21, {CLTS} +{0x07} 36, {LOADALL/SYSRET} +{0x08} 21, {INVD} +{0x09} 21, {WBINVD} +{0x0A} 21, {CL1INVMB} +{0x0B} 21, {UD1} +{0x0C} 00, {InvalidOpCode} +{0x0D} 21, {3DNow} +{0x0E} 21, {3DNow} +{0x0F} 21, {3DNow} +{0x10} 59, {VMOVUPD/VMOVSD/VMOVSS/VMOVUPS} +{0x11} 59, {VMOVUPD/VMOVSD/VMOVSS/VMOVUPS} +{0x12} 59, {VMOVLPD/VMOVDDUP/VMOVSLDUP/VMOVLPS/VMOVHLPS} +{0x13} 60, {InvalidOpCode/VMOVLPD/VMOVLPS} +{0x14} 60, {InvalidOpCode/VUNPCKLPD/VUNPCKLPS} +{0x15} 60, {InvalidOpCode/VUNPCKHPD/VUNPCKHPS} +{0x16} 61, {InvalidOpCode/VMOVHPD/VMOVSHDUP/VMOVLHPS/VMOVHPS} +{0x17} 60, {InvalidOpCode/VMOVHPD/VMOVHPS} +{0x18} 62, {group_16} +{0x19} 62, {group_16} +{0x1A} 62, {group_16} +{0x1B} 62, {group_16} +{0x1C} 62, {group_16} +{0x1D} 62, {group_16} +{0x1E} 62, {group_16} +{0x1F} 62, {group_16} +{0x20} 63, {MOV} +{0x21} 63, {MOV} +{0x22} 63, {MOV} +{0x23} 63, {MOV} +{0x24} 63, {MOV} +{0x25} 00, {InvalidOpCode} +{0x26} 63, {MOV} +{0x27} 00, {InvalidOpCode} +{0x28} 60, {InvalidOpCode/VMOVAPD/VMOVAPS} +{0x29} 60, {InvalidOpCode/VMOVAPD/VMOVAPS} +{0x2A} 59, {VCVTSI2SD/CVTPI2PD/VCVTSI2SS/CVTPI2PS} +{0x2B} 59, {MOVNTSD/MOVNTSS/VMOVNTPD/VMOVNTPS} +{0x2C} 59, {CVTTPD2PI/VCVTTSD2SI/CVTTPS2PI/VCVTTSS2SI} +{0x2D} 59, {CVTPD2PI/VCVTSD2SI/CVTPS2PI/VCVTSS2SI} +{0x2E} 60, {InvalidOpCode/VUCOMISD/VUCOMISS} +{0x2F} 60, {InvalidOpCode/VCOMISD/VCOMISS} +{0x30} 21, {WRMSR} +{0x31} 21, {RDTSC} +{0x32} 21, {RDMSR} +{0x33} 21, {RDPMC} +{0x34} 21, {SYSENTER} +{0x35} 21, {SYSEXIT} +{0x36} 00, {InvalidOpCode} +{0x37} 21, {GETSEC} +{0x38} 64, {Escape_3_Byte} +{0x39} 00, {InvalidOpCode} +{0x3A} 64, {Escape_3_Byte} +{0x3B} 00, {InvalidOpCode} +{0x3C} 00, {InvalidOpCode} +{0x3D} 00, {InvalidOpCode} +{0x3E} 00, {InvalidOpCode} +{0x3F} 00, {InvalidOpCode} +{0x40} 01, {CMOVO} +{0x41} 01, {CMOVNO} +{0x42} 01, {CMOVB} +{0x43} 01, {CMOVNB} +{0x44} 01, {CMOVZ} +{0x45} 01, {CMOVNZ} +{0x46} 01, {CMOVBE} +{0x47} 01, {CMOVNBE} +{0x48} 01, {CMOVS} +{0x49} 01, {CMOVNS} +{0x4A} 01, {CMOVP} +{0x4B} 01, {CMOVNP} +{0x4C} 01, {CMOVL} +{0x4D} 01, {CMOVNL} +{0x4E} 01, {CMOVLE} +{0x4F} 01, {CMOVNLE} +{0x50} 60, {InvalidOpCode/VMOVMSKPD/VMOVMSKPS} +{0x51} 59, {VSQRTPD/VSQRTSD/VSQRTSS/VSQRTPS} +{0x52} 65, {InvalidOpCode/VRSQRTSS/VRSQRTPS} +{0x53} 65, {InvalidOpCode/VRCPSS/VRCPPS} +{0x54} 60, {InvalidOpCode/VANDPD/VANDPS} +{0x55} 60, {InvalidOpCode/VANDNPD/VANDNPS} +{0x56} 60, {InvalidOpCode/VORPD/VORPS} +{0x57} 60, {InvalidOpCode/VXORPD/VXORPS} +{0x58} 59, {VADDPD/VADDSD/VADDSS/VADDPS} +{0x59} 59, {VMULPD/VMULSD/VMULSS/VMULPS} +{0x5A} 59, {VCVTPD2PS/VCVTSD2SS/VCVTSS2SD/VCVTPS2PD} +{0x5B} 61, {InvalidOpCode/VCVTPS2DQ/VCVTTPS2DQ/VCVTDQ2PS} +{0x5C} 59, {VSUBPD/VSUBSD/VSUBSS/VSUBPS} +{0x5D} 59, {VMINPD/VMINSD/VMINSS/VMINPS} +{0x5E} 59, {VDIVPD/VDIVSD/VDIVSS/VDIVPS} +{0x5F} 59, {VMAXPD/VMAXSD/VMAXSS/VMAXPS} +{0x60} 60, {PUNPCKLBW/VPUNPCKLBW} +{0x61} 60, {PUNPCKLWD/VPUNPCKLWD} +{0x62} 60, {PUNPCKLDQ/VPUNPCKLDQ} +{0x63} 60, {PACKSSWB/VPACKSSWB} +{0x64} 60, {PCMPGTB/VPCMPGTB} +{0x65} 60, {PCMPGTW/VPCMPGTW} +{0x66} 60, {PCMPGTD/VPCMPGTD} +{0x67} 60, {PACKUSWB/VPACKUSWB} +{0x68} 60, {PUNPCKHBW/InvalidOpCode/VPUNPCKHBW} +{0x69} 60, {PUNPCKHWD/InvalidOpCode/VPUNPCKHWD} +{0x6A} 60, {PUNPCKHDQ/InvalidOpCode/VPUNPCKHDQ} +{0x6B} 60, {PACKSSDW/InvalidOpCode/VPACKSSDW} +{0x6C} 66, {InvalidOpCode/VPUNPCKLQDQ} +{0x6D} 66, {InvalidOpCode/VPUNPCKHQDQ} +{0x6E} 60, {MOVDQ/InvalidOpCode/VMOVDQ} +{0x6F} 61, {MOVQ/InvalidOpCode/VMOVDQA/VMOVDQU} +{0x70} 67, {VPSHUFD/VPSHUFLW/VPSHUFHW/PSHUFW} +{0x71} 68, {group_12} +{0x72} 69, {group_13} +{0x73} 70, {group_14} +{0x74} 60, {PCMPEQB/InvalidOpCode/VPCMPEQB} +{0x75} 60, {PCMPEQW/InvalidOpCode/VPCMPEQW} +{0x76} 60, {PCMPEQD/InvalidOpCode/VPCMPEQD} +{0x77} 21, {EMMS/VZEROUPPER/VZEROALL/InvalidOpCode} +{0x78} 01, {VMREAD/InvalidOpCode} +{0x79} 01, {VMWRITE/InvalidOpCode} +{0x7A} 21, {SSE5A/InvalidOpCode} +{0x7B} 21, {SSE5A/InvalidOpCode} +{0x7C} 71, {InvalidOpCode/VHADDPD/VHADDPS} +{0x7D} 71, {InvalidOpCode/VHSUBPD/VHSUBPS} +{0x7E} 61, {MOVDQ/InvalidOpCode/VMOVDQ/VMOVQ} +{0x7F} 61, {MOVQ/InvalidOpCode/VMOVDQA/VMOVDQU} +{0x80} 72, {JO} +{0x81} 72, {JNO} +{0x82} 72, {JB} +{0x83} 72, {JNB} +{0x84} 72, {JZ} +{0x85} 72, {JNZ} +{0x86} 72, {JBE} +{0x87} 72, {JNBE} +{0x88} 72, {JS} +{0x89} 72, {JNS} +{0x8A} 72, {JP} +{0x8B} 72, {JNP} +{0x8C} 72, {JL} +{0x8D} 72, {JNL} +{0x8E} 72, {JLE} +{0x8F} 72, {JNLE} +{0x90} 01, {SETO} +{0x91} 01, {SETNO} +{0x92} 01, {SETB} +{0x93} 01, {SETNB} +{0x94} 01, {SETZ} +{0x95} 01, {SETNZ} +{0x96} 01, {SETBE} +{0x97} 01, {SETNBE} +{0x98} 01, {SETS} +{0x99} 01, {SETNS} +{0x9A} 01, {SETP} +{0x9B} 01, {SETNP} +{0x9C} 01, {SETL} +{0x9D} 01, {SETNL} +{0x9E} 01, {SETLE} +{0x9F} 01, {SETNLE} +{0xA0} 11, {PUSH} +{0xA1} 11, {POP} +{0xA2} 21, {CPUID} +{0xA3} 01, {BT} +{0xA4} 20, {SHLD} +{0xA5} 01, {SHLD} +{0xA6} 00, {InvalidOpCode} +{0xA7} 00, {InvalidOpCode} +{0xA8} 11, {PUSH} +{0xA9} 11, {POP} +{0xAA} 21, {RSM} +{0xAB} 01, {BTS} +{0xAC} 20, {SHRD} +{0xAD} 01, {SHRD} +{0xAE} 73, {group_15} +{0xAF} 01, {IMUL} +{0xB0} 01, {CMPXCHG} +{0xB1} 01, {CMPXCHG} +{0xB2} 01, {LSS} +{0xB3} 01, {BTR} +{0xB4} 01, {LFS} +{0xB5} 01, {LGS} +{0xB6} 01, {MOVZX} +{0xB7} 01, {MOVZX} +{0xB8} 74, {POPCNT/InvalidOpCode} +{0xB9} 75, {group_10_UD2/InvalidOpCode} +{0xBA} 76, {group_8/InvalidOpCode} +{0xBB} 01, {BTC/InvalidOpCode} +{0xBC} 65, {BSF/TZCNT} +{0xBD} 65, {BSR/LZCNT} +{0xBE} 01, {MOVSX/InvalidOpCode} +{0xBF} 01, {MOVSX/InvalidOpCode} +{0xC0} 59, {XADD} +{0xC1} 59, {XADD} +{0xC2} 67, {VCMPccPD/VCMPccSD/VCMPccSS/VCMPccPS} +{0xC3} 01, {InvalidOpCode/MOVNTI} +{0xC4} 77, {InvalidOpCode/VPINSRW/PINSRW} +{0xC5} 77, {InvalidOpCode/VPEXTRW/PEXTRW} +{0xC6} 77, {InvalidOpCode/VSHUFPD/VSHUFPS} +{0xC7} 78, {group_9} +{0xC8} 21, {BSWAP} +{0xC9} 21, {BSWAP} +{0xCA} 21, {BSWAP} +{0xCB} 21, {BSWAP} +{0xCC} 21, {BSWAP} +{0xCD} 21, {BSWAP} +{0xCE} 21, {BSWAP} +{0xCF} 21, {BSWAP} +{0xD0} 71, {InvalidOpCode/VADDSUBPD/VADDSUBPS} +{0xD1} 60, {PSRLW/InvalidOpCode/VPSRLW} +{0xD2} 60, {PSRLD/InvalidOpCode/VPSRLD} +{0xD3} 60, {PSRLQ/InvalidOpCode/VPSRLQ} +{0xD4} 60, {InvalidOpCode/VPADDQ/PADDQ} +{0xD5} 60, {PMULLW/InvalidOpCode/VPMULLW} +{0xD6} 79, {InvalidOpCode/MOVDQ2Q/MOVQ2DQ/VMOVQ} +{0xD7} 60, {InvalidOpCode/VPMOVMSKB/PMOVMSKB} +{0xD8} 60, {PSUBUSB/VPSUBUSB} +{0xD9} 60, {PSUBUSW/VPSUBUSW} +{0xDA} 60, {VPMINUB/PMINUB} +{0xDB} 60, {PAND/VPAND} +{0xDC} 60, {PADDUSB/VPADDUSB} +{0xDD} 60, {PADDUSW/VPADDUSW} +{0xDE} 60, {VPMAXUB/PMAXUB} +{0xDF} 60, {PANDN/VPANDN} +{0xE0} 60, {InvalidOpCode/VPAVGB/PAVGB} +{0xE1} 60, {PSRAW/InvalidOpCode/VPSRAW} +{0xE2} 60, {PSRAD/InvalidOpCode/VPSRAD} +{0xE3} 60, {InvalidOpCode/VPAVGW/PAVGW} +{0xE4} 60, {InvalidOpCode/VPMULHUW/PMULHUW} +{0xE5} 60, {PMULHW/InvalidOpCode/VPMULHW} +{0xE6} 79, {InvalidOpCode/VCVTTPD2DQ/VCVTPD2DQ/VCVTDQ2PD} +{0xE7} 60, {InvalidOpCode/VMOVNTDQ/MOVNTQ} +{0xE8} 60, {PSUBSB/VPSUBSB} +{0xE9} 60, {PSUBSW/VPSUBSW} +{0xEA} 60, {VPMINSW/PMINSW} +{0xEB} 60, {POR/VPOR} +{0xEC} 60, {PADDSB/VPADDSB} +{0xED} 60, {PADDSW/VPADDSW} +{0xEE} 60, {VPMAXSW/PMAXSW} +{0xEF} 60, {PXOR/VPXOR} +{0xF0} 80, {InvalidOpCode/VLDDQU} +{0xF1} 60, {PSLLW/InvalidOpCode/VPSLLW} +{0xF2} 60, {PSLLD/InvalidOpCode/VPSLLD} +{0xF3} 60, {PSLLQ/InvalidOpCode/VPSLLQ} +{0xF4} 60, {InvalidOpCode/VPMULUDQ/PMULUDQ} +{0xF5} 60, {PMADDWD/InvalidOpCode/VPMADDWD} +{0xF6} 60, {InvalidOpCode/VPSADBW/PSADBW} +{0xF7} 60, {InvalidOpCode/VMASKMOVDQU/MASKMOVQ} +{0xF8} 60, {PSUBB/VPSUBB} +{0xF9} 60, {PSUBW/VPSUBW} +{0xFA} 60, {PSUBD/VPSUBD} +{0xFB} 60, {VPSUBQ/PSUBQ} +{0xFC} 60, {PADDB/VPADDB} +{0xFD} 60, {PADDW/VPADDW} +{0xFE} 60, {PADDD/VPADDD} +{0xFF} 00 {InvalidOpCode} +); +{============================================ + ThreeByteTable38 +============================================} +const ThreeByteTable38 : array[Byte] of Byte =(// +{0x00} 60, {VPSHUFB/PSHUFB} +{0x01} 60, {VPHADDW/PHADDW} +{0x02} 60, {VPHADDD/PHADDD} +{0x03} 60, {VPHADDSW/PHADDSW} +{0x04} 60, {VPMADDUBSW/PMADDUBSW} +{0x05} 60, {VPHSUBW/PHSUBW} +{0x06} 60, {VPHSUBD/PHSUBD} +{0x07} 60, {VPHSUBSW/PHSUBSW} +{0x08} 60, {VPSIGNB/PSIGNB} +{0x09} 60, {VPSIGNW/PSIGNW} +{0x0A} 60, {VPSIGND/PSIGND} +{0x0B} 60, {VPMULHRSW/PMULHRSW} +{0x0C} 66, {VPERMILPS/InvalidOpCode} +{0x0D} 66, {VPERMILPD/InvalidOpCode} +{0x0E} 66, {VTESTPS/InvalidOpCode} +{0x0F} 66, {VTESTPD/InvalidOpCode} +{0x10} 66, {InvalidOpCode/PBLENDVB} +{0x11} 00, {InvalidOpCode} +{0x12} 00, {InvalidOpCode} +{0x13} 66, {VCVTPH2PS/InvalidOpCode} +{0x14} 66, {InvalidOpCode/BLENDVPS} +{0x15} 66, {InvalidOpCode/BLENDVPD} +{0x16} 66, {VPERMPS/InvalidOpCode} +{0x17} 66, {InvalidOpCode/VPTEST} +{0x18} 66, {VBROADCASTSS/InvalidOpCode} +{0x19} 66, {VBROADCASTSD/InvalidOpCode} +{0x1A} 66, {VBROADCASTF128/InvalidOpCode} +{0x1B} 00, {InvalidOpCode} +{0x1C} 60, {VPABSB/PABSB} +{0x1D} 60, {VPABSW/PABSW} +{0x1E} 60, {VPABSD/PABSD} +{0x1F} 00, {InvalidOpCode} +{0x20} 66, {InvalidOpCode/VPMOVSXBW} +{0x21} 66, {InvalidOpCode/VPMOVSXBD} +{0x22} 66, {InvalidOpCode/VPMOVSXBQ} +{0x23} 66, {InvalidOpCode/VPMOVSXWD} +{0x24} 66, {InvalidOpCode/VPMOVSXWQ} +{0x25} 66, {InvalidOpCode/VPMOVSXDQ} +{0x26} 00, {InvalidOpCode} +{0x27} 00, {InvalidOpCode} +{0x28} 66, {InvalidOpCode/VPMULDQ} +{0x29} 66, {InvalidOpCode/VPCMPEQQ} +{0x2A} 66, {InvalidOpCode/VMOVNTDQA} +{0x2B} 66, {InvalidOpCode/VPACKUSDW} +{0x2C} 66, {VMASKMOVPS/InvalidOpCode} +{0x2D} 66, {VMASKMOVPD/InvalidOpCode} +{0x2E} 66, {VMASKMOVPS/InvalidOpCode} +{0x2F} 66, {VMASKMOVPD/InvalidOpCode} +{0x30} 66, {InvalidOpCode/VPMOVZXBW} +{0x31} 66, {InvalidOpCode/VPMOVZXBD} +{0x32} 66, {InvalidOpCode/VPMOVZXBQ} +{0x33} 66, {InvalidOpCode/VPMOVZXWD} +{0x34} 66, {InvalidOpCode/VPMOVZXWQ} +{0x35} 66, {InvalidOpCode/VPMOVZXDQ} +{0x36} 66, {VPERMD/InvalidOpCode} +{0x37} 66, {InvalidOpCode/VPCMPGTQ} +{0x38} 66, {InvalidOpCode/VPMINSB} +{0x39} 66, {InvalidOpCode/VPMINSD} +{0x3A} 66, {InvalidOpCode/VPMINUW} +{0x3B} 66, {InvalidOpCode/VPMINUD} +{0x3C} 66, {InvalidOpCode/VPMAXSB} +{0x3D} 66, {InvalidOpCode/VPMAXSD} +{0x3E} 66, {InvalidOpCode/VPMAXUW} +{0x3F} 66, {InvalidOpCode/VPMAXUD} +{0x40} 66, {InvalidOpCode/VPMULLD} +{0x41} 66, {InvalidOpCode/VPHMINPOSUW} +{0x42} 00, {InvalidOpCode} +{0x43} 00, {InvalidOpCode} +{0x44} 00, {InvalidOpCode} +{0x45} 66, {VPSRLVQ/InvalidOpCode} +{0x46} 66, {VPSRAVD/InvalidOpCode} +{0x47} 66, {VPSLLVQ/VPSLLVD/InvalidOpCode} +{0x48} 00, {InvalidOpCode} +{0x49} 00, {InvalidOpCode} +{0x4A} 00, {InvalidOpCode} +{0x4B} 00, {InvalidOpCode} +{0x4C} 00, {InvalidOpCode} +{0x4D} 00, {InvalidOpCode} +{0x4E} 00, {InvalidOpCode} +{0x4F} 00, {InvalidOpCode} +{0x50} 00, {InvalidOpCode} +{0x51} 00, {InvalidOpCode} +{0x52} 00, {InvalidOpCode} +{0x53} 00, {InvalidOpCode} +{0x54} 00, {InvalidOpCode} +{0x55} 00, {InvalidOpCode} +{0x56} 00, {InvalidOpCode} +{0x57} 00, {InvalidOpCode} +{0x58} 66, {VPBROADCASTD/InvalidOpCode} +{0x59} 66, {VPBROADCASTQ/InvalidOpCode} +{0x5A} 66, {VBROADCASTI128/InvalidOpCode} +{0x5B} 00, {InvalidOpCode} +{0x5C} 00, {InvalidOpCode} +{0x5D} 00, {InvalidOpCode} +{0x5E} 00, {InvalidOpCode} +{0x5F} 00, {InvalidOpCode} +{0x60} 00, {InvalidOpCode} +{0x61} 00, {InvalidOpCode} +{0x62} 00, {InvalidOpCode} +{0x63} 00, {InvalidOpCode} +{0x64} 00, {InvalidOpCode} +{0x65} 00, {InvalidOpCode} +{0x66} 00, {InvalidOpCode} +{0x67} 00, {InvalidOpCode} +{0x68} 00, {InvalidOpCode} +{0x69} 00, {InvalidOpCode} +{0x6A} 00, {InvalidOpCode} +{0x6B} 00, {InvalidOpCode} +{0x6C} 00, {InvalidOpCode} +{0x6D} 00, {InvalidOpCode} +{0x6E} 00, {InvalidOpCode} +{0x6F} 00, {InvalidOpCode} +{0x70} 00, {InvalidOpCode} +{0x71} 00, {InvalidOpCode} +{0x72} 00, {InvalidOpCode} +{0x73} 00, {InvalidOpCode} +{0x74} 00, {InvalidOpCode} +{0x75} 00, {InvalidOpCode} +{0x76} 00, {InvalidOpCode} +{0x77} 00, {InvalidOpCode} +{0x78} 66, {VPBROADCASTB/InvalidOpCode} +{0x79} 66, {VPBROADCASTW/InvalidOpCode} +{0x7A} 00, {InvalidOpCode} +{0x7B} 00, {InvalidOpCode} +{0x7C} 00, {InvalidOpCode} +{0x7D} 00, {InvalidOpCode} +{0x7E} 00, {InvalidOpCode} +{0x7F} 00, {InvalidOpCode} +{0x80} 66, {INVPCID} +{0x81} 66, {INVVPID} +{0x82} 66, {INVPCID} +{0x83} 00, {InvalidOpCode} +{0x84} 00, {InvalidOpCode} +{0x85} 00, {InvalidOpCode} +{0x86} 00, {InvalidOpCode} +{0x87} 00, {InvalidOpCode} +{0x88} 00, {InvalidOpCode} +{0x89} 00, {InvalidOpCode} +{0x8A} 00, {InvalidOpCode} +{0x8B} 00, {InvalidOpCode} +{0x8C} 66, {VPMASKMOVD/VPMASKMOVQ/InvalidOpCode} +{0x8D} 00, {InvalidOpCode} +{0x8E} 66, {VPMASKMOVD/VPMASKMOVQ/InvalidOpCode} +{0x8F} 00, {InvalidOpCode} +{0x90} 66, {VPGATHERDD/VPGATHERDQ} +{0x91} 66, {VPGATHERQD/VPGATHERQQ} +{0x92} 66, {VGATHERDPS/VGATHERDPD} +{0x93} 66, {VGATHERQPS/VGATHERQPD} +{0x94} 00, {InvalidOpCode} +{0x95} 00, {InvalidOpCode} +{0x96} 66, {VFMADDSUB132PS/VFMADDSUB132PD} +{0x97} 66, {VFMSUBADD132PS/VFMSUBADD132PD} +{0x98} 66, {VFMADD132PS/VFMADD132PD} +{0x99} 66, {VFMADD132SS/VFMADD132SD} +{0x9A} 66, {VFMSUB132PS/VFMSUB132PD} +{0x9B} 66, {VFMSUB132SS/VFMSUB132SD} +{0x9C} 66, {VFNMADD132PS/VFNMADD132PD} +{0x9D} 66, {VFNMADD132SS/VFNMADD132SD} +{0x9E} 66, {VFNMSUB132PS/VFNMSUB132PD} +{0x9F} 66, {VFNMSUB132SS/VFNMSUB132SD} +{0xA0} 00, {InvalidOpCode} +{0xA1} 00, {InvalidOpCode} +{0xA2} 00, {InvalidOpCode} +{0xA3} 00, {InvalidOpCode} +{0xA4} 00, {InvalidOpCode} +{0xA5} 00, {InvalidOpCode} +{0xA6} 66, {VFMADDSUB213PS/VFMADDSUB213PD} +{0xA7} 66, {VFMSUBADD213PS/VFMSUBADD213PD} +{0xA8} 66, {VFMADD213PS/VFMADD213PD} +{0xA9} 66, {VFMADD213SS/VFMADD213SD} +{0xAA} 66, {VFMSUB213PS/VFMSUB213PD} +{0xAB} 66, {VFMSUB213SS/VFMSUB213SD} +{0xAC} 66, {VFNMADD213PS/VFNMADD213PD} +{0xAD} 66, {VFNMADD213SS/VFNMADD213SD} +{0xAE} 66, {VFNMSUB213PS/VFNMSUB213PD} +{0xAF} 66, {VFNMSUB213SS/VFNMSUB213SD} +{0xB0} 00, {InvalidOpCode} +{0xB1} 00, {InvalidOpCode} +{0xB2} 00, {InvalidOpCode} +{0xB3} 00, {InvalidOpCode} +{0xB4} 00, {InvalidOpCode} +{0xB5} 00, {InvalidOpCode} +{0xB6} 66, {VFMADDSUB231PS/VFMADDSUB231PD} +{0xB7} 66, {VFMSUBADD231PS/VFMSUBADD231PD} +{0xB8} 66, {VFMADD231PS/VFMADD231PD} +{0xB9} 66, {VFMADD231SS/VFMADD231SD} +{0xBA} 66, {VFMSUB231PS/VFMSUB231PD} +{0xBB} 66, {VFMSUB231SS/VFMSUB231SD} +{0xBC} 66, {VFNMADD231PS/VFNMADD231PD} +{0xBD} 66, {VFNMADD231SS/VFNMADD231SD} +{0xBE} 66, {VFNMSUB231PS/VFNMSUB231PD} +{0xBF} 66, {VFNMSUB231SS/VFNMSUB231SD} +{0xC0} 00, {InvalidOpCode} +{0xC1} 00, {InvalidOpCode} +{0xC2} 00, {InvalidOpCode} +{0xC3} 00, {InvalidOpCode} +{0xC4} 00, {InvalidOpCode} +{0xC5} 00, {InvalidOpCode} +{0xC6} 00, {InvalidOpCode} +{0xC7} 00, {InvalidOpCode} +{0xC8} 01, {SHA1NEXTE} +{0xC9} 01, {SHA1MSG1} +{0xCA} 01, {SHA1MSG2} +{0xCB} 01, {SHA256RNDS2} +{0xCC} 01, {SHA256MSG1} +{0xCD} 01, {SHA256MSG2} +{0xCE} 00, {InvalidOpCode} +{0xCF} 00, {InvalidOpCode} +{0xD0} 00, {InvalidOpCode} +{0xD1} 00, {InvalidOpCode} +{0xD2} 00, {InvalidOpCode} +{0xD3} 00, {InvalidOpCode} +{0xD4} 00, {InvalidOpCode} +{0xD5} 00, {InvalidOpCode} +{0xD6} 00, {InvalidOpCode} +{0xD7} 00, {InvalidOpCode} +{0xD8} 00, {InvalidOpCode} +{0xD9} 00, {InvalidOpCode} +{0xDA} 00, {InvalidOpCode} +{0xDB} 66, {VAESIMC} +{0xDC} 66, {VAESENC} +{0xDD} 66, {VAESENCLAST} +{0xDE} 66, {VAESDEC} +{0xDF} 66, {VAESDECLAST} +{0xE0} 00, {InvalidOpCode} +{0xE1} 00, {InvalidOpCode} +{0xE2} 00, {InvalidOpCode} +{0xE3} 00, {InvalidOpCode} +{0xE4} 00, {InvalidOpCode} +{0xE5} 00, {InvalidOpCode} +{0xE6} 00, {InvalidOpCode} +{0xE7} 00, {InvalidOpCode} +{0xE8} 00, {InvalidOpCode} +{0xE9} 00, {InvalidOpCode} +{0xEA} 00, {InvalidOpCode} +{0xEB} 00, {InvalidOpCode} +{0xEC} 00, {InvalidOpCode} +{0xED} 00, {InvalidOpCode} +{0xEE} 00, {InvalidOpCode} +{0xEF} 00, {InvalidOpCode} +{0xF0} 81, {MOVBE/InvalidOpCode/CRC32} +{0xF1} 81, {MOVBE/InvalidOpCode/CRC32} +{0xF2} 81, {ANDNv/InvalidOpCode} +{0xF3} 81, {group_17} +{0xF4} 81, {InvalidOpCode} +{0xF5} 81, {PDEPv/PEXTv/BZHIv/InvalidOpCode} +{0xF6} 81, {MULXv/ADCX/ADOX/InvalidOpCode} +{0xF7} 81, {SHLXv/SHRXv/SARXv/BEXTRv/InvalidOpCode} +{0xF8} 00, {InvalidOpCode} +{0xF9} 00, {InvalidOpCode} +{0xFA} 00, {InvalidOpCode} +{0xFB} 00, {InvalidOpCode} +{0xFC} 00, {InvalidOpCode} +{0xFD} 00, {InvalidOpCode} +{0xFE} 00, {InvalidOpCode} +{0xFF} 00 {InvalidOpCode} +); +{============================================ + ThreeByteTable3A +============================================} +const ThreeByteTable3A : array[Byte] of Byte =(// +{0x00} 82, {VPERMQ/InvalidOpCode} +{0x01} 82, {VPERMPD/InvalidOpCode} +{0x02} 82, {VPBLENDD/InvalidOpCode} +{0x03} 00, {InvalidOpCode} +{0x04} 82, {VPERMILPS/InvalidOpCode} +{0x05} 82, {VPERMILPD/InvalidOpCode} +{0x06} 82, {VPERM2F128/InvalidOpCode} +{0x07} 00, {InvalidOpCode} +{0x08} 82, {InvalidOpCode/VROUNDPS} +{0x09} 82, {InvalidOpCode/VROUNDPD} +{0x0A} 82, {InvalidOpCode/VROUNDSS} +{0x0B} 82, {InvalidOpCode/VROUNDSD} +{0x0C} 82, {InvalidOpCode/VBLENDPS} +{0x0D} 82, {InvalidOpCode/VBLENDPD} +{0x0E} 82, {InvalidOpCode/VPBLENDW} +{0x0F} 77, {VPALIGNR/PALIGNR} +{0x10} 00, {InvalidOpCode} +{0x11} 00, {InvalidOpCode} +{0x12} 00, {InvalidOpCode} +{0x13} 00, {InvalidOpCode} +{0x14} 82, {InvalidOpCode/VPEXTRB} +{0x15} 82, {InvalidOpCode/VPEXTRW} +{0x16} 82, {InvalidOpCode/VPEXTRD} +{0x17} 82, {InvalidOpCode/VEXTRACTPS} +{0x18} 82, {VINSERTF128/InvalidOpCode} +{0x19} 82, {VEXTRACTF128/InvalidOpCode} +{0x1A} 00, {InvalidOpCode} +{0x1B} 00, {InvalidOpCode} +{0x1C} 00, {InvalidOpCode} +{0x1D} 82, {VCVTPS2PH/InvalidOpCode} +{0x1E} 00, {InvalidOpCode} +{0x1F} 00, {InvalidOpCode} +{0x20} 82, {InvalidOpCode/VINSERTPS} +{0x21} 82, {InvalidOpCode/VPINSRD} +{0x22} 00, {InvalidOpCode} +{0x23} 00, {InvalidOpCode} +{0x24} 00, {InvalidOpCode} +{0x25} 00, {InvalidOpCode} +{0x26} 00, {InvalidOpCode} +{0x27} 00, {InvalidOpCode} +{0x28} 00, {InvalidOpCode} +{0x29} 00, {InvalidOpCode} +{0x2A} 00, {InvalidOpCode} +{0x2B} 00, {InvalidOpCode} +{0x2C} 00, {InvalidOpCode} +{0x2D} 00, {InvalidOpCode} +{0x2E} 00, {InvalidOpCode} +{0x2F} 00, {InvalidOpCode} +{0x30} 00, {InvalidOpCode} +{0x31} 00, {InvalidOpCode} +{0x32} 00, {InvalidOpCode} +{0x33} 00, {InvalidOpCode} +{0x34} 00, {InvalidOpCode} +{0x35} 00, {InvalidOpCode} +{0x36} 00, {InvalidOpCode} +{0x37} 00, {InvalidOpCode} +{0x38} 82, {VINSERTI128/InvalidOpCode} +{0x39} 82, {VEXTRACTI128/InvalidOpCode} +{0x3A} 00, {InvalidOpCode} +{0x3B} 00, {InvalidOpCode} +{0x3C} 00, {InvalidOpCode} +{0x3D} 00, {InvalidOpCode} +{0x3E} 00, {InvalidOpCode} +{0x3F} 00, {InvalidOpCode} +{0x40} 82, {InvalidOpCode/VDPPS} +{0x41} 82, {InvalidOpCode/VDPPD} +{0x42} 82, {InvalidOpCode/VMPSADBW} +{0x43} 00, {InvalidOpCode} +{0x44} 82, {InvalidOpCode/VPCLMULQDQ} +{0x45} 00, {InvalidOpCode} +{0x46} 82, {VPERM2I128/InvalidOpCode} +{0x47} 00, {InvalidOpCode} +{0x48} 82, {VPERMILzz2PS/InvalidOpCode} +{0x49} 82, {VPERMILzz2PD/InvalidOpCode} +{0x4A} 66, {VBLENDVPS/InvalidOpCode} +{0x4B} 66, {VBLENDVPD/InvalidOpCode} +{0x4C} 66, {VPBLENDVB/InvalidOpCode} +{0x4D} 00, {InvalidOpCode} +{0x4E} 00, {InvalidOpCode} +{0x4F} 00, {InvalidOpCode} +{0x50} 00, {InvalidOpCode} +{0x51} 00, {InvalidOpCode} +{0x52} 00, {InvalidOpCode} +{0x53} 00, {InvalidOpCode} +{0x54} 00, {InvalidOpCode} +{0x55} 00, {InvalidOpCode} +{0x56} 00, {InvalidOpCode} +{0x57} 00, {InvalidOpCode} +{0x58} 00, {InvalidOpCode} +{0x59} 00, {InvalidOpCode} +{0x5A} 00, {InvalidOpCode} +{0x5B} 00, {InvalidOpCode} +{0x5C} 66, {VFMADDSUBPS/InvalidOpCode} +{0x5D} 66, {VFMADDSUBPD/InvalidOpCode} +{0x5E} 66, {VFMSUBADDPS/InvalidOpCode} +{0x5F} 66, {VFMSUBADDPD/InvalidOpCode} +{0x60} 82, {InvalidOpCode/VPCMPESTRM} +{0x61} 82, {InvalidOpCode/VPCMPESTRI} +{0x62} 82, {InvalidOpCode/VPCMPISTRM} +{0x63} 82, {InvalidOpCode/VPCMPISTRI} +{0x64} 00, {InvalidOpCode} +{0x65} 00, {InvalidOpCode} +{0x66} 00, {InvalidOpCode} +{0x67} 00, {InvalidOpCode} +{0x68} 66, {VFMADDPS/InvalidOpCode} +{0x69} 66, {VFMADDPD/InvalidOpCode} +{0x6A} 66, {VFMADDSS/InvalidOpCode} +{0x6B} 66, {VFMADDSD/InvalidOpCode} +{0x6C} 66, {VFMSUBPS/InvalidOpCode} +{0x6D} 66, {VFMSUBPD/InvalidOpCode} +{0x6E} 66, {VFMSUBSS/InvalidOpCode} +{0x6F} 66, {VFMSUBSD/InvalidOpCode} +{0x70} 00, {InvalidOpCode} +{0x71} 00, {InvalidOpCode} +{0x72} 00, {InvalidOpCode} +{0x73} 00, {InvalidOpCode} +{0x74} 00, {InvalidOpCode} +{0x75} 00, {InvalidOpCode} +{0x76} 00, {InvalidOpCode} +{0x77} 00, {InvalidOpCode} +{0x78} 66, {VFNMADDPS/InvalidOpCode} +{0x79} 66, {VFNMADDPD/InvalidOpCode} +{0x7A} 66, {VFNMADDSS/InvalidOpCode} +{0x7B} 66, {VFNMADDSD/InvalidOpCode} +{0x7C} 66, {VFNMSUBPS/InvalidOpCode} +{0x7D} 66, {VFNMSUBPD/InvalidOpCode} +{0x7E} 66, {VFNMSUBSS/InvalidOpCode} +{0x7F} 66, {VFNMSUBSD/InvalidOpCode} +{0x80} 00, {InvalidOpCode} +{0x81} 00, {InvalidOpCode} +{0x82} 00, {InvalidOpCode} +{0x83} 00, {InvalidOpCode} +{0x84} 00, {InvalidOpCode} +{0x85} 00, {InvalidOpCode} +{0x86} 00, {InvalidOpCode} +{0x87} 00, {InvalidOpCode} +{0x88} 00, {InvalidOpCode} +{0x89} 00, {InvalidOpCode} +{0x8A} 00, {InvalidOpCode} +{0x8B} 00, {InvalidOpCode} +{0x8C} 00, {InvalidOpCode} +{0x8D} 00, {InvalidOpCode} +{0x8E} 00, {InvalidOpCode} +{0x8F} 00, {InvalidOpCode} +{0x90} 00, {InvalidOpCode} +{0x91} 00, {InvalidOpCode} +{0x92} 00, {InvalidOpCode} +{0x93} 00, {InvalidOpCode} +{0x94} 00, {InvalidOpCode} +{0x95} 00, {InvalidOpCode} +{0x96} 00, {InvalidOpCode} +{0x97} 00, {InvalidOpCode} +{0x98} 00, {InvalidOpCode} +{0x99} 00, {InvalidOpCode} +{0x9A} 00, {InvalidOpCode} +{0x9B} 00, {InvalidOpCode} +{0x9C} 00, {InvalidOpCode} +{0x9D} 00, {InvalidOpCode} +{0x9E} 00, {InvalidOpCode} +{0x9F} 00, {InvalidOpCode} +{0xA0} 00, {InvalidOpCode} +{0xA1} 00, {InvalidOpCode} +{0xA2} 00, {InvalidOpCode} +{0xA3} 00, {InvalidOpCode} +{0xA4} 00, {InvalidOpCode} +{0xA5} 00, {InvalidOpCode} +{0xA6} 00, {InvalidOpCode} +{0xA7} 00, {InvalidOpCode} +{0xA8} 00, {InvalidOpCode} +{0xA9} 00, {InvalidOpCode} +{0xAA} 00, {InvalidOpCode} +{0xAB} 00, {InvalidOpCode} +{0xAC} 00, {InvalidOpCode} +{0xAD} 00, {InvalidOpCode} +{0xAE} 00, {InvalidOpCode} +{0xAF} 00, {InvalidOpCode} +{0xB0} 00, {InvalidOpCode} +{0xB1} 00, {InvalidOpCode} +{0xB2} 00, {InvalidOpCode} +{0xB3} 00, {InvalidOpCode} +{0xB4} 00, {InvalidOpCode} +{0xB5} 00, {InvalidOpCode} +{0xB6} 00, {InvalidOpCode} +{0xB7} 00, {InvalidOpCode} +{0xB8} 00, {InvalidOpCode} +{0xB9} 00, {InvalidOpCode} +{0xBA} 00, {InvalidOpCode} +{0xBB} 00, {InvalidOpCode} +{0xBC} 00, {InvalidOpCode} +{0xBD} 00, {InvalidOpCode} +{0xBE} 00, {InvalidOpCode} +{0xBF} 00, {InvalidOpCode} +{0xC0} 00, {InvalidOpCode} +{0xC1} 00, {InvalidOpCode} +{0xC2} 00, {InvalidOpCode} +{0xC3} 00, {InvalidOpCode} +{0xC4} 00, {InvalidOpCode} +{0xC5} 00, {InvalidOpCode} +{0xC6} 00, {InvalidOpCode} +{0xC7} 00, {InvalidOpCode} +{0xC8} 00, {InvalidOpCode} +{0xC9} 00, {InvalidOpCode} +{0xCA} 00, {InvalidOpCode} +{0xCB} 00, {InvalidOpCode} +{0xCC} 20, {SHA1RNDS4} +{0xCD} 00, {InvalidOpCode} +{0xCE} 00, {InvalidOpCode} +{0xCF} 00, {InvalidOpCode} +{0xD0} 00, {InvalidOpCode} +{0xD1} 00, {InvalidOpCode} +{0xD2} 00, {InvalidOpCode} +{0xD3} 00, {InvalidOpCode} +{0xD4} 00, {InvalidOpCode} +{0xD5} 00, {InvalidOpCode} +{0xD6} 00, {InvalidOpCode} +{0xD7} 00, {InvalidOpCode} +{0xD8} 00, {InvalidOpCode} +{0xD9} 00, {InvalidOpCode} +{0xDA} 00, {InvalidOpCode} +{0xDB} 00, {InvalidOpCode} +{0xDC} 00, {InvalidOpCode} +{0xDD} 00, {InvalidOpCode} +{0xDE} 00, {InvalidOpCode} +{0xDF} 82, {VAESKEYGENASSIST} +{0xE0} 00, {InvalidOpCode} +{0xE1} 00, {InvalidOpCode} +{0xE2} 00, {InvalidOpCode} +{0xE3} 00, {InvalidOpCode} +{0xE4} 00, {InvalidOpCode} +{0xE5} 00, {InvalidOpCode} +{0xE6} 00, {InvalidOpCode} +{0xE7} 00, {InvalidOpCode} +{0xE8} 00, {InvalidOpCode} +{0xE9} 00, {InvalidOpCode} +{0xEA} 00, {InvalidOpCode} +{0xEB} 00, {InvalidOpCode} +{0xEC} 00, {InvalidOpCode} +{0xED} 00, {InvalidOpCode} +{0xEE} 00, {InvalidOpCode} +{0xEF} 00, {InvalidOpCode} +{0xF0} 83, {RORXv} +{0xF1} 00, {InvalidOpCode} +{0xF2} 00, {InvalidOpCode} +{0xF3} 00, {InvalidOpCode} +{0xF4} 00, {InvalidOpCode} +{0xF5} 00, {InvalidOpCode} +{0xF6} 00, {InvalidOpCode} +{0xF7} 00, {InvalidOpCode} +{0xF8} 00, {InvalidOpCode} +{0xF9} 00, {InvalidOpCode} +{0xFA} 00, {InvalidOpCode} +{0xFB} 00, {InvalidOpCode} +{0xFC} 00, {InvalidOpCode} +{0xFD} 00, {InvalidOpCode} +{0xFE} 00, {InvalidOpCode} +{0xFF} 00 {InvalidOpCode} +); diff --git a/components/detours/packages/DelphiXE5/detours.dpk b/components/detours/packages/DelphiXE5/detours.dpk new file mode 100644 index 00000000..1b2deb9c --- /dev/null +++ b/components/detours/packages/DelphiXE5/detours.dpk @@ -0,0 +1,38 @@ +package detours; + +{$R *.res} +{$IFDEF IMPLICITBUILDING This IFDEF should not be used by users} +{$ALIGN 8} +{$ASSERTIONS ON} +{$BOOLEVAL OFF} +{$DEBUGINFO ON} +{$EXTENDEDSYNTAX ON} +{$IMPORTEDDATA ON} +{$IOCHECKS ON} +{$LOCALSYMBOLS ON} +{$LONGSTRINGS ON} +{$OPENSTRINGS ON} +{$OPTIMIZATION OFF} +{$OVERFLOWCHECKS OFF} +{$RANGECHECKS OFF} +{$REFERENCEINFO ON} +{$SAFEDIVIDE OFF} +{$STACKFRAMES ON} +{$TYPEDADDRESS OFF} +{$VARSTRINGCHECKS ON} +{$WRITEABLECONST OFF} +{$MINENUMSIZE 1} +{$IMAGEBASE $400000} +{$DEFINE DEBUG} +{$ENDIF IMPLICITBUILDING} +{$IMPLICITBUILD ON} + +requires + rtl; + +contains + CPUID in '..\..\Source\CPUID.pas', + DDetours in '..\..\Source\DDetours.pas', + InstDecode in '..\..\Source\InstDecode.pas'; + +end. diff --git a/components/detours/packages/DelphiXE5/detours.dproj b/components/detours/packages/DelphiXE5/detours.dproj new file mode 100644 index 00000000..cc0dee1a --- /dev/null +++ b/components/detours/packages/DelphiXE5/detours.dproj @@ -0,0 +1,173 @@ + + + {0B99D52D-E87E-4E6E-A53E-DD727D4A0EBA} + detours.dpk + 15.3 + None + True + Release + Win64 + 3 + Package + + + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Cfg_1 + true + true + + + true + Base + true + + + 1031 + All + System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace) + true + true + ..\..\build\$(Platform) + .\$(Platform)\$(Config) + + + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) + true + CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= + 1033 + + + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace) + true + CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= + 1033 + + + DEBUG;$(DCC_Define) + true + false + true + true + true + + + false + + + false + RELEASE;$(DCC_Define) + 0 + 0 + + + + MainSource + + + + + + + Cfg_2 + Base + + + Base + + + Cfg_1 + Base + + + + Delphi.Personality.12 + Package + + + + True + False + 1 + 0 + 0 + 0 + False + False + False + False + False + 1031 + 1252 + + + + + 1.0.0.0 + + + + + + 1.0.0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + Microsoft Office 2000 Beispiele für gekapselte Komponenten für Automatisierungsserver + Microsoft Office XP Beispiele für gekapselte Komponenten für Automation Server + + + detours.dpk + + + + + True + True + + + 12 + + + + diff --git a/components/detours/packages/DelphiXE5/detours.dproj.local b/components/detours/packages/DelphiXE5/detours.dproj.local new file mode 100644 index 00000000..d576f039 --- /dev/null +++ b/components/detours/packages/DelphiXE5/detours.dproj.local @@ -0,0 +1,2 @@ + + diff --git a/components/detours/packages/DelphiXE5/detours.res b/components/detours/packages/DelphiXE5/detours.res new file mode 100644 index 00000000..27efe49b Binary files /dev/null and b/components/detours/packages/DelphiXE5/detours.res differ diff --git a/packages/delphiXE5/heidisql.dpr b/packages/delphiXE5/heidisql.dpr index 501997dd..82a751d0 100644 --- a/packages/delphiXE5/heidisql.dpr +++ b/packages/delphiXE5/heidisql.dpr @@ -42,7 +42,8 @@ uses gnugettext in '..\..\source\gnugettext.pas', JumpList in '..\..\source\JumpList.pas', extra_controls in '..\..\source\extra_controls.pas', - change_password in '..\..\source\change_password.pas' {frmPasswordChange}; + change_password in '..\..\source\change_password.pas' {frmPasswordChange}, + Vcl.FormsFix in '..\..\source\Vcl.FormsFix.pas'; {$R ..\..\res\icon.RES} {$R ..\..\res\icon-question.RES} diff --git a/packages/delphiXE5/heidisql.dproj b/packages/delphiXE5/heidisql.dproj index f19373d0..0268a547 100644 --- a/packages/delphiXE5/heidisql.dproj +++ b/packages/delphiXE5/heidisql.dproj @@ -7,8 +7,8 @@ 3 Application VCL - 15.1 - Win32 + 15.3 + Win64 true @@ -28,6 +28,18 @@ Base true + + true + Cfg_1 + true + true + + + true + Cfg_1 + true + true + true Base @@ -39,12 +51,18 @@ true true + + true + Cfg_2 + true + true + false false ..\..\out\ ..\..\build\$(Platform) - ..\..\components\synedit\build\$(Platform);..\..\components\virtualtreeview\build\$(Platform);..\..\components\synedit\source;..\..\components\virtualtreeview\source;$(DCC_UnitSearchPath) + ..\..\components\synedit\build\$(Platform);..\..\components\virtualtreeview\build\$(Platform);..\..\components\synedit\source;..\..\components\virtualtreeview\source;..\..\components\detours\Source;..\..\components\detours\build\$(Platform);$(DCC_UnitSearchPath) $(BDS)\bin\default_app.manifest false false @@ -59,14 +77,11 @@ Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) - $(BDS)\bin\default_app.manifest true CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= - 1033 Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace) - $(BDS)\bin\default_app.manifest CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= true @@ -76,13 +91,21 @@ 0 0 + + true + CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= + + + true + CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= + - $(BDS)\bin\default_app.manifest true DEBUG;$(DCC_Define) false + None 2 3 madExcept;$(DCC_Define) @@ -90,6 +113,8 @@ CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= + true + None 2 madExcept;$(DCC_Define) true @@ -198,6 +223,7 @@
frmPasswordChange
dfm + Cfg_2 Base @@ -269,14 +295,15 @@ - Microsoft Office 2000 Sample Automation Server Wrapper Components - Microsoft Office XP Sample Automation Server Wrapper Components + Microsoft Office 2000 Beispiele für gekapselte Komponenten für Automatisierungsserver + Microsoft Office XP Beispiele für gekapselte Komponenten für Automation Server True True + False
12 diff --git a/packages/delphiXE5/heidisql.groupproj b/packages/delphiXE5/heidisql.groupproj index 0f5608e4..00d5f6e0 100644 --- a/packages/delphiXE5/heidisql.groupproj +++ b/packages/delphiXE5/heidisql.groupproj @@ -15,6 +15,9 @@ + + + @@ -62,6 +65,15 @@ + + + + + + + + + @@ -72,13 +84,13 @@ - + - + - + diff --git a/source/Vcl.FormsFix.pas b/source/Vcl.FormsFix.pas new file mode 100644 index 00000000..a2c012f9 --- /dev/null +++ b/source/Vcl.FormsFix.pas @@ -0,0 +1,123 @@ +unit Vcl.FormsFix; + +interface + +implementation + +uses + System.SysUtils, Winapi.Windows, Vcl.Forms, Vcl.Graphics, System.UITypes + // + , DDetours + // + ; + +var + trampoline_GetMetricSettings: Procedure = nil; + +type + TFontHelper = class helper for TFont + public + function Equals(const AOther: TFont): Boolean; + end; + +function TFontHelper.Equals(const AOther: TFont): Boolean; +begin + Result := (AOther.PixelsPerInch = self.PixelsPerInch) + and (AOther.Charset = self.Charset) + and (AOther.Color = self.Color) + and (AOther.Height = self.Height) + and (AOther.Name = self.Name) + and (AOther.Orientation = self.Orientation) + and (AOther.Pitch = self.Pitch) + and (AOther.Size = self.Size) + and (AOther.Style = self.Style) + and (AOther.Quality = self.Quality); +end; + +type + TScreenHelper = class Helper for TScreen + public + function getPtr_GetMetricSettings:Pointer; + end; + +function TScreenHelper.getPtr_GetMetricSettings:Pointer; +begin + result:=@TScreen.GetMetricSettings; +end; + +procedure HookedGetMetricSettings(const Self); + + procedure CheckedFontChange(const ACurrFont: TFont; const ANewFont: tagLOGFONTW); + var + TmpFont: TFont; + begin + TmpFont := TFont.Create; + try + TmpFont.Assign(ACurrFont); + TmpFont.Handle := CreateFontIndirect(ANewFont); + if not TmpFont.Equals(ACurrFont) then + begin + ACurrFont.Handle := CreateFontIndirect(ANewFont); + end; + finally + FreeAndNil(TmpFont); + end; + end; + +var + LSize: Cardinal; + LogFont: TLogFont; + NonClientMetrics: TNonClientMetrics; + SaveShowHint: Boolean; + +begin + SaveShowHint := False; + if Assigned(Application) then SaveShowHint := Application.ShowHint; + try + if Assigned(Application) then Application.ShowHint := False; +{$IF DEFINED(CLR)} + LSize := Marshal.SizeOf(TypeOf(TLogFont)); +{$ELSE} + LSize := SizeOf(TLogFont); +{$IFEND} + if SystemParametersInfo(SPI_GETICONTITLELOGFONT, LSize, {$IFNDEF CLR}@{$ENDIF}LogFont, 0) then + begin + CheckedFontChange(Screen.IconFont, LogFont); + end + else + Screen.IconFont.Handle := GetStockObject(SYSTEM_FONT); +{$IF DEFINED(CLR)} + LSize := Marshal.SizeOf(TypeOf(TNonClientMetrics)); +{$ELSE} + LSize := TNonClientMetrics.SizeOf; +{$IFEND} + NonClientMetrics.cbSize := LSize; + if SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, {$IFNDEF CLR}@{$ENDIF}NonClientMetrics, 0) then + begin + CheckedFontChange(Screen.HintFont, NonClientMetrics.lfStatusFont); + CheckedFontChange(Screen.MenuFont, NonClientMetrics.lfMenuFont); + CheckedFontChange(Screen.MessageFont, NonClientMetrics.lfMessageFont); + CheckedFontChange(Screen.CaptionFont, NonClientMetrics.lfCaptionFont); + end else + begin + Screen.HintFont.Size := 8; + Screen.MenuFont.Handle := GetStockObject(SYSTEM_FONT); + Screen.MessageFont.Handle := GetStockObject(SYSTEM_FONT); + Screen.CaptionFont.Handle := GetStockObject(SYSTEM_FONT); + end; + Screen.HintFont.Color := clInfoText; + Screen.MenuFont.Color := clMenuText; + Screen.MessageFont.Color := clWindowText; + finally + if Assigned(Application) then Application.ShowHint := SaveShowHint; + end; + +end; + +initialization + @trampoline_GetMetricSettings := InterceptCreate(Screen.getPtr_GetMetricSettings, @HookedGetMetricSettings); + +finalization + InterceptRemove(@trampoline_GetMetricSettings); + +end. diff --git a/source/main.pas b/source/main.pas index 983ef235..907ecce7 100644 --- a/source/main.pas +++ b/source/main.pas @@ -17,7 +17,7 @@ uses routine_editor, trigger_editor, event_editor, options, EditVar, helpers, createdatabase, table_editor, TableTools, View, Usermanager, SelectDBObject, connections, sqlhelp, dbconnection, insertfiles, searchreplace, loaddata, copytable, VTHeaderPopup, Cromis.DirectoryWatch, SyncDB, gnugettext, - JumpList, System.Actions, System.UITypes, pngimage; + JumpList, System.Actions, System.UITypes, pngimage, Vcl.FormsFix; type