From ef13e15de632e71695d62f45ec61b555a8379ddb Mon Sep 17 00:00:00 2001 From: Ansgar Becker Date: Wed, 1 Nov 2017 19:38:29 +0000 Subject: [PATCH] New attempt to fix menu and buttons flicker on Win10, this time by with the help of Delphi Detours library. See https://www.heidisql.com/forum.php?t=19141 --- components/detours/Clean.bat | 35 + .../Demo/DetoursDemo/COM/Demo1/Demo1.dpr | 18 + .../Demo/DetoursDemo/COM/Demo1/Demo1.dproj | 539 ++++ .../Demo/DetoursDemo/COM/Demo1/Demo1.res | Bin 0 -> 62704 bytes .../Demo/DetoursDemo/COM/Demo1/uMain.dfm | 54 + .../Demo/DetoursDemo/COM/Demo1/uMain.pas | 78 + .../Hook_Overloaded_Method.dpr | 47 + .../Hook_Overloaded_Method.dproj | 625 ++++ .../Delphi/Interfaces/Demo1/Demo1.dpr | 18 + .../Delphi/Interfaces/Demo1/Demo1.dproj | 521 +++ .../Delphi/Interfaces/Demo1/uMain.dfm | 44 + .../Delphi/Interfaces/Demo1/uMain.pas | 81 + .../Delphi/Objects/Demo1/Demo1.dpr | 18 + .../Delphi/Objects/Demo1/Demo1.dproj | 521 +++ .../Delphi/Objects/Demo1/uMain.dfm | 52 + .../Delphi/Objects/Demo1/uMain.pas | 62 + .../DetoursDemo/Delphi/RTL/Demo1/Demo1.dpr | 18 + .../DetoursDemo/Delphi/RTL/Demo1/Demo1.dproj | 539 ++++ .../DetoursDemo/Delphi/RTL/Demo1/Demo1.res | Bin 0 -> 62704 bytes .../DetoursDemo/Delphi/RTL/Demo1/uMain.dfm | 38 + .../DetoursDemo/Delphi/RTL/Demo1/uMain.pas | 93 + .../DetoursDemo/MultiHook/Demo1/Demo1.dpr | 17 + .../DetoursDemo/MultiHook/Demo1/Demo1.dproj | 521 +++ .../DetoursDemo/MultiHook/Demo1/uMain.dfm | 91 + .../DetoursDemo/MultiHook/Demo1/uMain.pas | 122 + .../Demo/DetoursDemo/win32api/Demo1/Demo1.dpr | 17 + .../DetoursDemo/win32api/Demo1/Demo1.dproj | 521 +++ .../Demo/DetoursDemo/win32api/Demo1/uMain.dfm | 44 + .../Demo/DetoursDemo/win32api/Demo1/uMain.pas | 61 + .../Demo/DetoursDemo/win32api/Demo2/Demo2.dpr | 18 + .../DetoursDemo/win32api/Demo2/Demo2.dproj | 521 +++ .../Demo/DetoursDemo/win32api/Demo2/uMain.dfm | 61 + .../Demo/DetoursDemo/win32api/Demo2/uMain.pas | 65 + .../Demo/InstDecodeDemo/Demo1/Demo1.dpr | 57 + .../Demo/InstDecodeDemo/Demo1/Demo1.dproj | 623 ++++ components/detours/Source/CPUID.pas | 279 ++ components/detours/Source/DDetours.pas | 2861 +++++++++++++++++ components/detours/Source/Defs.inc | 48 + components/detours/Source/InstDecode.pas | 2383 ++++++++++++++ .../detours/Source/ModRmFlagsTables.inc | 140 + components/detours/Source/OpCodesTables.inc | 1158 +++++++ .../detours/packages/DelphiXE5/detours.dpk | 38 + .../detours/packages/DelphiXE5/detours.dproj | 173 + .../packages/DelphiXE5/detours.dproj.local | 2 + .../detours/packages/DelphiXE5/detours.res | Bin 0 -> 448 bytes packages/delphiXE5/heidisql.dpr | 3 +- packages/delphiXE5/heidisql.dproj | 45 +- packages/delphiXE5/heidisql.groupproj | 18 +- source/Vcl.FormsFix.pas | 123 + source/main.pas | 2 +- 50 files changed, 13399 insertions(+), 14 deletions(-) create mode 100644 components/detours/Clean.bat create mode 100644 components/detours/Demo/DetoursDemo/COM/Demo1/Demo1.dpr create mode 100644 components/detours/Demo/DetoursDemo/COM/Demo1/Demo1.dproj create mode 100644 components/detours/Demo/DetoursDemo/COM/Demo1/Demo1.res create mode 100644 components/detours/Demo/DetoursDemo/COM/Demo1/uMain.dfm create mode 100644 components/detours/Demo/DetoursDemo/COM/Demo1/uMain.pas create mode 100644 components/detours/Demo/DetoursDemo/Delphi/Hook_Overloaded_Method/Hook_Overloaded_Method.dpr create mode 100644 components/detours/Demo/DetoursDemo/Delphi/Hook_Overloaded_Method/Hook_Overloaded_Method.dproj create mode 100644 components/detours/Demo/DetoursDemo/Delphi/Interfaces/Demo1/Demo1.dpr create mode 100644 components/detours/Demo/DetoursDemo/Delphi/Interfaces/Demo1/Demo1.dproj create mode 100644 components/detours/Demo/DetoursDemo/Delphi/Interfaces/Demo1/uMain.dfm create mode 100644 components/detours/Demo/DetoursDemo/Delphi/Interfaces/Demo1/uMain.pas create mode 100644 components/detours/Demo/DetoursDemo/Delphi/Objects/Demo1/Demo1.dpr create mode 100644 components/detours/Demo/DetoursDemo/Delphi/Objects/Demo1/Demo1.dproj create mode 100644 components/detours/Demo/DetoursDemo/Delphi/Objects/Demo1/uMain.dfm create mode 100644 components/detours/Demo/DetoursDemo/Delphi/Objects/Demo1/uMain.pas create mode 100644 components/detours/Demo/DetoursDemo/Delphi/RTL/Demo1/Demo1.dpr create mode 100644 components/detours/Demo/DetoursDemo/Delphi/RTL/Demo1/Demo1.dproj create mode 100644 components/detours/Demo/DetoursDemo/Delphi/RTL/Demo1/Demo1.res create mode 100644 components/detours/Demo/DetoursDemo/Delphi/RTL/Demo1/uMain.dfm create mode 100644 components/detours/Demo/DetoursDemo/Delphi/RTL/Demo1/uMain.pas create mode 100644 components/detours/Demo/DetoursDemo/MultiHook/Demo1/Demo1.dpr create mode 100644 components/detours/Demo/DetoursDemo/MultiHook/Demo1/Demo1.dproj create mode 100644 components/detours/Demo/DetoursDemo/MultiHook/Demo1/uMain.dfm create mode 100644 components/detours/Demo/DetoursDemo/MultiHook/Demo1/uMain.pas create mode 100644 components/detours/Demo/DetoursDemo/win32api/Demo1/Demo1.dpr create mode 100644 components/detours/Demo/DetoursDemo/win32api/Demo1/Demo1.dproj create mode 100644 components/detours/Demo/DetoursDemo/win32api/Demo1/uMain.dfm create mode 100644 components/detours/Demo/DetoursDemo/win32api/Demo1/uMain.pas create mode 100644 components/detours/Demo/DetoursDemo/win32api/Demo2/Demo2.dpr create mode 100644 components/detours/Demo/DetoursDemo/win32api/Demo2/Demo2.dproj create mode 100644 components/detours/Demo/DetoursDemo/win32api/Demo2/uMain.dfm create mode 100644 components/detours/Demo/DetoursDemo/win32api/Demo2/uMain.pas create mode 100644 components/detours/Demo/InstDecodeDemo/Demo1/Demo1.dpr create mode 100644 components/detours/Demo/InstDecodeDemo/Demo1/Demo1.dproj create mode 100644 components/detours/Source/CPUID.pas create mode 100644 components/detours/Source/DDetours.pas create mode 100644 components/detours/Source/Defs.inc create mode 100644 components/detours/Source/InstDecode.pas create mode 100644 components/detours/Source/ModRmFlagsTables.inc create mode 100644 components/detours/Source/OpCodesTables.inc create mode 100644 components/detours/packages/DelphiXE5/detours.dpk create mode 100644 components/detours/packages/DelphiXE5/detours.dproj create mode 100644 components/detours/packages/DelphiXE5/detours.dproj.local create mode 100644 components/detours/packages/DelphiXE5/detours.res create mode 100644 source/Vcl.FormsFix.pas 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 0000000000000000000000000000000000000000..0f3facb9cfa933a493c5f938866266d85d282161 GIT binary patch literal 62704 zcmZ6y1yo$YvM9O-cXxsYcM{y)-QC?S5P}U32?V#`5FCQLI|K+G+=9FN0DsQC|NOW9 z>$Q4M@9wJVYOATLt_=VHKncxnZ~vR2#s6Ot1O2xh3km~$fhG5aZaR5kAdjEyjf#P@o zo=|L8DCU0>C%^`U`ELfGIRAlHgF?9iR=_8~658wkjrD)yNI~gejG zn*SM<7PQqI+N&p&b8{%w|HA_^+z#A+IRH>X>Abzc{(tj}h4p{tH(E_a79E8I1qy;L zFDIq(zq14akPx6XMjoX$08su*UP@f+^YV!?q8Z+&zdzP9=q?6gS1!e@jrLokoB+fgV#lEbWbiX}M{y7^zajKK&p%Tks6U@lY zZn_Sv?xqjsaVX?zvyt~`Rn3cCE{$cQXatFoHcoRZIRjHN&R*!6q<~RxgT>*DQ)GX_ zv3tAcXfD4?vthYTh3oH$$>9y{f0v(U=9sh{w7k4R?~S$fkqIhpsh4E)mFPSvME!|k z=w=D(PCOP*ZL4&S4-E=0cMM&-145k6DA^}>yC|IJ+#F!R%-~d3M*w}$syc4vUYZXv@vA5LgW(+!Q`|QV-|LHb|Jq# zrQq2^A!QNK$L=%}14W+ZgtTLijcy(k73e^I+bt#1z8I_6QbbG5)CWXjtXWuC2prxb zsFf$@%{%mazpD${sEho4c7fzpzl7$UN#@|_nD_JN&f-=mA|{TqMfa%P>dO(SYb8~t zUOqaW0eT~-$C}RSbMx3IT^*G_&S6WgG10L_F~2m*q?)Va^jl-rrY41R+Qjp^CPPnG zZ0gm`N*UNA71P*Gg}&^J?EU`z+jQOkxN3gK614%;XI;nx*qIx&*{QP^{N6}OPrgxe zFnEeZjz-R#JrrX~L2w$g<~ys4pKb|SKm>Z5%Hmp&1tIbs=|t&o2=UF4f}hSHVjdoKy;#JfNmnfOo*7+i zbS`VaCURSBP_sYStViq!79mwlu(a$~L|>o8?Dx}^1syFd|NEhyV8u~cIy>0V8tB#w zOCVr3TKpz7uIh8P`iO}vFMpU2c4)1UaqihXtW0sCHuqS83Jff42?nOkqhVpS+>h;g zi*tiQQTP9(IIVOAOf1#g?)zUImShHBk~U-@o997inwmA8m)(Fa30+Q3$-hi862sVH z``<(2`spR7NLmQzNh1=_cRKPybFU_|{&J6fZtAN~e6rSlzZ3lOY)jy@RA;rDW@-X% zdKX5gP6}`(Mj7WS6CL*dT5EfuVr8A^xn16tWKF)2D33cNg#m6~j2CKK_l*d-{~}JQ z0h>S2FGO38fdfIuqOnKhv9fC=$j7kfQ6*Awc*7roI>gxc{r&n+trw4+=MzJlmH5%$g-NMpE*$n8c{@ zVS0yb}#IP_94oBY|RkckicT4fOH#|i#{3q{95 znuA07X+rO;tj+DT*0wudP0HiX@nt-{dZgUI&Xb@C1eimdI!#1>d8Ylsv@j9D89HO! zZZ}?6;|7BV8#4_ooZG9sT*N4h!7DN$L+giO2L_PNMVnOxK1au*sW z8q<)%#?EB;K})ACVj&w_Fu(*C&085a6AHrTQ=(e_ptE=W_iH|$fkurE15dZds)_82 zTO@EHjyM1TtKO6-Gqa=jGX#Q`VxYXRC28I)=-(WU3IvvIZ~%5?3}Otqh%2c@dkA2& zVliWNuv#|wlRfZy?pKOXGV36gZ-r9pq{F<2m0YFQdUYC|M8}FaBgkNt^sdtbYeJJFR`e`;}kW=ZF9h{K*xiWM_A!OL$7qaD|Bu zmGjSBL$)KY8)roTZe-x?Kz%-cl$~vW(zo*-PX`ucP0!F>0M5{b2;gEv8-WK>M<4fq zw~suInuY42DkawAFlnfT@TvIBI{tiLP8Nx+`k7h~3gC5xfpIF0+^H;+&M%@-^S*Ki z^UZqtNva;w0N{s{r5Z|}_F{A~A1}X3asdYlZ4NO5dIwrl-T z@0QzRdJYH>wL}Gh*J-dt#XJQ;lFuucFiL4;ANjIXN=r+B9@p6I^@V?1Kj&N_j-})C ze{k!0^g3C@rlwB6pcgrN7$_+!dN4?mo~5JnVB!p4`}RO5Zk#Xr+V%wGajFAWCv81F zZ)DzN*R3*DAxHsmojhr}q@;*An!47u;40?# z+MT-R(tw4(`yY99am~7iZ6R&|U|J`cow)AQB&Mv)I`@}kYdqs4*Yxg4Lg5XSH{S`D zFfoN$suRz*;Vm~lWFkJJK#!!;%iXQ4xG*8efIy-=a^cvB;;(rbhA1m3KlzXa)+F;~ z)@}L8$;pzc@w)nY@#=-(UNfLd2X{ah%b?sf@8^CHIaE-MPXGX}_GSpkhxBa>6JU{+ zmJa!SOvA#)7C{jNxojsi{cAX$7q_O64ZJQBJ+AM8aOEyZJRC%HzEmLC*2TyBYidJ!aqNP0luut%? zxMsF6dD_Hj)5@9)seThbhY(#tixo=7Z2t5YD}&f^Ji-bcM=lcKE&omtjS8)Dno@J~ z%=)u6KQRXf6dHPZ9J8pr@cxGn zer1jISn4%%x6$KM7Id5-P3O<^T<=@U0ki48aMk_Y-Pnmgqnslnp=UHP5}!j`)!1=S zK|R&zQA@8UJ~TZkueTt;C!mwumkn3ISWUwKfe;mSYq1u0k>DFgORR!-WWNj-QN@~x zfsF=!nqJW^zRI`xa<8^EY$?5CG%4)`Y<%P60DGvehFh$qV4X*OK3?uxJiGc_lyDCXK&E&+!t7ok8)EwSX9<8CiSEHS2{D-Mo>4@^F{wE#3x+GWd zNP0R^s7^&1t{J6SJi_Tpb7*oho}66Nwf2QOh%&vH5+cL}do z`<%{;1wcdqwxsL+Afu98JiXawDk^?9WMTP{&vf;~zmaCo*P1C*vW29zygyohrd|Tk zw!h91Csnj8syO+iNWx4D6e*C%|8&4JXA6}OH&K|vP2moaGqv)D*BS9O{otYO;Su|x zx*-ikIra1M^#&og_L>y~L5j7&^~yR5ZI7#UT%{sFzu=p3$;ltdCnJ0O@xNWc9zW7;zA zPe}P8F`b8mPWNX=2U;qt;oVDKZ|F1)Ls&%*P0K&f<~RNNg6QnGPxs`)E>sSTFPBPE zM}k=@!AF16o&t;0Pyn&Mm8M@blv^GF145HZ>%H#OTbN`556$%PB7E>^L8?X;2Q|XA zLyrztmfEqKSkVN+pm*kD!`hco>Lg<0%UTD04Gn(}4}}JWqJ%u}sWMIa0;-*-jtdJw zEf+z}ha7B5dcl6}{MIu9^8kPakdOf>nGbZqDd|ZSU2m@k5AsPl%b`3=_~f)L1t7Ea zEdGIY)yKreY+}8eU@{8_2j$mqNpc|$fQ0;{_BCu#x8B2KP>k7*Unx-PLw@=I`;6He zjZ4qaU)UhKZ#0+xzOgZ!aBY_-Q@l`%0e6n1M_0%f+cEQlQ2A}8!iJjs`pkd>hTR9f zXnjk%1(gO^hDHP766e&JZz{IYtiOSrhPj8ixfr-u8D^?tQm@0AjC8coIVGraUGpO( zednInnH-ZTlf>a!L_Fr z{Y0jqk67R{B%}4z!`^K}g$85!xepRR1#q0luuWQfyL>xp`zcBRK*lP)Y@t5%nm{$8nMb(czdE1K_5}dFj#^cNc zh8j>I^9}`=Sx+~_NxM_nj_S@;9;4K~MsCa~hxp{cRGZPb0cvszoKapE_s{M@~UUz&GzCX{H?0Fpl z`X5@z`+q9&(sNP(qNV^Nhc(G;6nX--S8GctQn7L-kNN7u<@=FbX}9p;9{l?(>^+K& zcGcYf$P^7#?x8_<3syhIf52wiQzdav%F_dzRp43IKvB2p(X1?bw&hN+$fqY3r;RSy z-(w0r7M$<5{iuCTez6I8%E;VE1$;YkRN!GA^E_ zEix!lD3g%SB{K(eWn&aXe~t4N7C8S^N|Bd=3?j>pCQ@gp*Wb!p@;c;e`J?aQnds@U zTr@m5sMzLxsxSd-CDwH#ixYtmUJU-$Rd{os2{$hI6xT97*@0NB=^0l-(@iCSIQ?c- z&fUjr8q|1Lq-z=w;qOKA3u^mWs34Gv&prM1ong%$pAts|doe zok+(fBPM=SJnsr>aI zIY(QhquHyoQnqX$=^zzGqdUnVB5;qUK#RW6_>{SZ68*!MjUJsbhbvQA(5V=9Z(Iom z&X@o4Qob%n*iT%?rj5OKq~hd}frDw2-~nD}{l;Dt3GVprgg!q$LBcCJM+SxC&FW>j zk#H!6?0NAO7SUUh`J8XAJXfCL`u=cMSvj5J<1xJ(+6cjs?l#TA@4fVF7ba?tmiLi zgmuHpV3#|2^O^GyH!rh1lkw|Empwl6*VZDt_1`XlR%Vou)-7HEHl&*INqAt3p;-(C zE?6$~yA4Kxe2dHJ^0)Ug-~IoMOcxpk%Tu_dP)<4IDqFpVg@u{6d7rPNCrM>t5b8PK z+G_>d0R0e+?}e&5kqfzRg&t(GDcbW=|IQ<>_y34FJEI>&Kb`BhcYTqarZw)+p`WCW z+4zGcpY4~PPfw^d-l+Z=sTCd6Sg!rx48XIxN(1qFzKt|JG#m$?^0XLx9h!RDJ~^_-zT-Zks3L|lpasUIMqQ&I zMY`uEYg{DgtUKoY{`p22VKK`Gn@aq z2zn4bt5yg~$w(shK@N8M@rX%i>1Z}N$WZom?6=G?7 z&^`3afN8|V#Y*98et<~)4 z_v37abyhBuCY`U}6E_Y$c)^buW0%8sv<2m&nYf$Hk1t`ENy8JspRNGJ&COoex%z6V zqvD-s?s?L&uV_nOLVs#%acSS${*T|A5zzY% zda&)Jr-OBFcc`x|vnVn)q={>(&d1a<#~z$+m(w)pg_%dnbK>0V-PzNF?$5zu3E@#r~Fix9N%Yt4*j0X*b_xTL$GU0ux( zCuP4uD?oCErY?0hmW3`=`;l_t_(yS>QsAz z>8eBNu;jT7w&FeK6j+GCJx=O@iB#bNf8)D99l)KU#boCbg*}Q zZgadp`#5bP8SUi5rF2z4PGNMLc4Yv5)DS7#xySNq>bpB#*;;L_=PJ(q{FD_isVcg} zjDHp7GF>~xN|&k-kZm-bI^YS9O^2(E?Q9m>dUuik^I;j1)A?+U>=8%4W?wDIh=NcJ z?#Z1$$Gvd-+0EP|Kf;aJ@=8O)sSKpO_abRy{mz*yWIt1B|Ix-@NkjlKt<`(8PISU_ zJc~b1apBk4wta3O^&=U2##oPSAl+mx>GA%`OC@2twLgSvY>e4_rKxHslCg*>=-*`b z9K`J=icY^;*Nc99BVqB`S>x?Dt(9h_n2T4Pha$*-J=%IxGv)rk}k$r&2nH`AwGZwMgigk(if0$n0)BqqEM_2ltzY-*|@q*+{Lf`Fp^HEo|{G4^jP5 zGx~R&vCp#J+YwdF715~cTjuCzCtV38`4W+ZwXDn)jH|2V>C}BRq>+xvRC=*fS>+y6 zg_FIo7-1?w1ot-s^w}3XMRD<4s1sB4)82T-ZBGoXpfFtbF1e!S)}3VLUD88@pC;Nw=Ek&$9DywoZ+ zv*zy~(KHeEnpdSW}jl`nVyugzp!k~ns z%_+dI?fYy51??53nFhvGt|Ka~iG7=~27z1aZR5^oo6p}kRwH9Ji1rA14mV-J zEnf3EKh4N!RbOlODVh+8XXYr$wU_9NKw5+O2);ygTS-6_r>toie={me_J~ii#p@5f z-k;pyIGI(=rLTySM3qG_fXLI2zj+O-WZMo63{CY%{(_HQh-ooUhdYC3GAv#C>9Q|DbT1Ov!I=<+cQ_DX)~G5?a0vJW|b$M zd!I2|au2;ZF@ZXtqbJspt`#MlpQIh`TC2JikpM%2-w?HNOidjfjOV*kP*NGe91p3M za*j!BW0OFes||tq>*pWC)v3m7CV~BhK_LF7zZ&Hsu3;)1DFP4sBX~aqM23|+s=62x zHU`|!V3K2dbe@8{y>_Y{OjL4{oe8Pem!NTOtbkr z*_EJ}k`vcF12$mwfgdRV#;9zP8&NNok`HkEF(2QZqEKvbvsk-*r(P)AS?|5p_P8@? zVMkSB_6?>-cP#Dvc(F)PSD<9FzneHmARavZG}!sN>eBsS(cbgHo5cKe#$!=2o#Oeb zC|SFw>#&|F`h_sS*hNsRQ51icyZQ<%mum)K)THm(t$9#be?~fyjYF)|{d5d-8M<*( zO{rup>;=aHhsJ`0z|GC-{oToY`byXjeky#0G(H`aS=B-RIttK^hvbx`2MpS zjbyjX71xqf-M-Z5T;1$O!@^&#xtN{N%W=kE ze!<)3-ZdFg?uouRTyFpP`-YODX^T*qCL<;Guhg9K+gF@7>OaJM-XY*#of@Y#(68UW z3HVJb`a!0yD{b450H2k1$5X+n{L*xmFtHvx7+@8KYAXv=8yFINP4@_Ickrvv zmgpIYMZeB!b}CL(CP?ht99jbsfHfZ^29-Ri^fWYTL-%3_N`y{$jVmLhfDSQp`{|e9rX_q0-OoII#xp{TpZZ%BTFgAgKiGY z9j>9u5NY}XLN1;p9_wYdDcH>Xu?A%0RvReLQXTqBuYD5>l;HotktM^U*hmpD9 zi`EocI}JUUZ(4J^F%EDPQ)LaqIvrK=0gqkuu!A4 zP3Xgiul#t!OFC(@adGjG^;eu|Q`pT26SZ4j5@ol83vqz}`m%<1O|fLAzT-|YXC>3U zpVrzWscZSGG4|5H<%+UVEfu1r(M+sVJ)bX4Cp8-l<lb++*%!`|RLWGiE)Xlb;EZ#fh1V+e5ICn|_wJ->>K?(!7rU*88-t z3QZj~C~Yt>CUHnr^NXS8IR=lJ^ro9W@O`o43?VJAs4&|pRsWb;trrX{TjNoquM}*v zjiB}Nab{N4GDox@@--q`PfP~?ZLqQRVsCqD=)G(lc+etj#NmAw34fc1pYta#(MF7? zq7q35l|T5C5Dn^JFRAdqx83MF$jDu{2Q=+BxoJ|}NnGY=Biq{sC+{4)o(LQW*irSW zDK6-vAY-`(JMZ45v2jj^u?qIM-#KmHOL8%Js&iIWR;}*%zP6@gkO}yVkJ`)H;?$@! zz=47uRFMF=U`dCTAkSv=(Nimu4RYZxbFY2h*b5jh-g6}}PC32f3_4qNg=$Hcl-etd z*U##c+hxxJ15=6mySmRWmU%)0f18ss2RXXGQu^$sN2fTl=fs^U(gc}ilYj8Lg&RyE z*{5Il=HNe&?E`L8WoPmYvs$ai{4GL;Ut^M!iXvYqVqdHIDK%MQ`qy6-w;lYUO3UOv z_O7NX^?|i>iImn0#$&(7vUzjXRz*@-nHGKWKvuOh$MZ_hilPrv`ebWk9Zbhq%gy)!z^7%lJTvAl1sw&PfH#C~!- z2@lt#FFHFmA^pn8(gEP()8gT25VG>d>2>R@7#4<;a$(1duivh+3|FHsQZi~Hdx5&-`}dZsT3ndFvZD8@Q)}*q-?AhnN2Hycu3ZiD zzVsFdd{ZxtkZ%Amr(t4T(mY#Mc;15JL?DL#{slt({KWnfKgIu52<_6tT+Rj!ih-9@ zJ{#p30L2aGYpoS`RaECfKCh6++!5JyJZv6K%9AWk&!?NXHlO3y?&9E(x^PZt4!=EUylE@E-P#9_xI^D!${ zhJo~!cror>g^!`EIwv10yT&hOcY&(cRu-Z2ngn0Aq3IE?pG#BonkIm-D0cJZ!6Wd`jPqTna>zs)~JQJ1My|QoBhF zLxXq4XKc0>1h!%LXDs4Wp9;C_S!=I84q6aq9JPl=xex(8v7rFSxZe{{fM0f|#G3N3 zicBHDwlJsaxO+NwCFlDbU&`VIYi+uBQwV8%eY4wsmK22=Z9zjrz81!jsWIcd zf~t;cVW#b2o5#X2dXpsA{V?lGYjh}CQZ&tB0qU3M=E+IZZ%o*y-E5jXM_L17Jrrk! z=qph>-D0wC6{kEkm=wC5n{(46$DJzOpQ#_+r6NC6lZ~J~xfz?xMgfV%KJ0xD15M|D zX{R0yiIcEv&_E zVBmwJfaNhiHyoq ziX=jxj2*i>yVXx$X;P0s7LranWff_*m@@!>y?1&%1J!Ad&=Qy>*BhtgsXIVQ1Cx^9 z{4P2xJ7CHyn1Kq~dcx|O?(2S^D-(y<8yo7E*&U_oKx7aIExQq6KUbiHi0+F16HiOs2 z0V2ZpM=W(*ij1rd4A+qv-dl22+i zNVVQ1wY`mmt@8txkd2Dn45#_`L;Ox+CZPn=_J=f`BZ7P??Q8b1xqHPCc-cdoZ{g8!sMrM#l(Q^{+(q z1Mq&NQxOpWdR<c1NjhzPM3a8%7k=e6jI>hiXdJW z!>kK9UE~K{yxIu6NRGJQy-SXTuvpoe2JFy`pY!!kvPex1moFa$EXS?K%E`-*^^Sm( z$&lGW-z_tJZBf<+fSzY~tfy|sia<00_)pE6-yKoz)4pgfUBzEe64j!e!v`SmX7YT| z-6l*&Hr-U518gl75&d%hFA^OA=2gp-w3~YJ0ApGvxR7h6Nk`T{~p(#iNaY^1pPLYo%rs95Ha69 zjo0_J_iOaQ396~QaD<>UA|_&`Y*3G#;>6d;Vx>U2!oQ=1g`LrciDtz>?!YlDgi11X z3UkwAvDc2LcOV+K+n~cNqnu*QA)|^B?|!dB$;LFj?8}lusqrPgt1+ZKRD8Znvffy6;)?z7n<6K>2<9?r zwPTZIgaVQZ)anC2His0Svmh<0Wc>^b2U{jBuoo{|Uge*UCMIcmZd>3&Ccl6QdaCiP zjHXe^7Aae*d*fKCIhbgUc0cVNN>$=3|2D-a|MB^IuG8ObJ{0zl`cl1{kMA4= zSItdc7jMd7lNHb(`4>4FB1_=sj8P~SxuiR z(kjSY$?U4f8qqdHy|bhb3H;6i`J_Dm=WdqH#<4LXePqOLgFcwCFOZ(UJ0=|yrq2YX zC41K8RvIqn<-VJ=3Z4rE5Xt4M4QlV`XiPwWmBV*%Rj_<%FK1psj+W|15{83c^$HO3$1uzVfwPU?)_oBs`TmIV9byKeb)w&jXB-X!W*pVdt$) z)Z=-*x$v*k3w4HWBh)6+ zOeH50Q>GH%->%YK8IkiF?DOzkVW}#q8a$@?tdr+a_o<$Z~DDnM|0sO_j!lXCyTCgSL1hgVM`HTPgvw09s;KKXjsMPmhKr7Kutro2he5DbLy5rpRvHh^Y%Nad2~ zm47UB8a8*2x*_CBY%4;xsI!QWqPQO}d~R>=uZMfd7nc?Dlf`ciJvr`E7Rp)3eddg% zp7t5FZ|`n3vE>(y^nF+uKg^U)u;X8InCD!{u?z(1zw4vGYwqb^yDXc5- zAUW}<&lR!$r&AiLyKARONtN-{tC~q6a%#v$#3Eo}Fkb57!V$St>prpKc|_kvvEAp3Q59fkXYf z{p-YZy0G|0>!1XrOfPU26*u%ku0%E0y94r@8CFq2krVa^Cae^m3kjh6PVuIc_9wf9 zS)0k=Oc6DRvgKwULmKJbIjvbB=0{(AkXV(DMBkq^j;&72^3fuhg45hWwFs^zQerIv zd!&9<*1Gc!Z!F%2*f0Gi^QZ)pr_G`le~bQP5;vjn55rs7be!>iq&{m$EXesRRJrhV zE#Rw30ICoH>I>;Urdg=^p*2ITO=29!R@rV=fcUxMCv-9u942G0jBle zdHq?prqSsjh))**)&bg$1IUHG#n`(BH`WsphAdhMIbwFg2u7EZl=ux@o0E)>_xsJR z8{rX*YA=LxH_%9+H;ayy!sYWzpGWb%VV<#r$AylY;>Ydxhz&${l83HH?%)z?VW=bL z61}xD9?5fUI)PsO@8rPVgkin~gl4^MXLP$SH5V++rx(+&u`1{q+@@GkW8(U_7;U!H zHu0PmX7tRQcSii`G}MOFPNp3wqTH~twM*S3Z#S|aW-{wEbQ@&E_r{Yp_FfvRbOR0R z4*`-3!qnx?I!OkrVY5!h)6;P}QV97=CwLeMTd{m8ae#?)qC`b7n-RUa& zsZBc0kRmz-Zb5cXrQ~pG>`i2`%da}n4&h;m%`Ju~?Qv-pi1sPa;rQ4i$ptvY>Pnw2 z#ow=I);KQw8nxnHX1x7Qgh>oUJ&D%(HM>kI+O@M6-3Ozlt{+^c2qUDtlFQus_>Bc* zt00cxYY4;{3tj{qKMSJHy+q#(ufHas6K%v^A8M0blitA2OCPOwB3-{>(x7KCyIn5r z_Zn~K&V?3-wi$jluu8!o70=Y9G+$wNdc$Wc7!;}QglB`XkV{`p=7Vg<_p-m+;rkSE zxU>Kb!621L58C44trQlm8}e#)Ud!E^I6U`i6CXNFX1##tFhrFMS)DP%W(9kXHqDkP zp%Snz^I9KiC5sTfuWEMI8v$xQZ}oZF+uI+0=2<+^)Z5cbyRqGX{n_nW`~%Tw2Zoxu z0n7c0i{;Df;BSSrk56Yvusb*dXxdMj)O(?Ail2W3Tj&_yTu<_(KPIS!6wp{BYkF~N z^S<-CY$f!EXPkZuAn?|wE((n4zUut*$GQkuu`XPp5b+qeskY4x$bbZ^ zlzzL-)|JbW{`m$Jys|HlQrj=ak=|IbFC`}X zoDE^@uSD*dFMfm!h-4n94|fH#l~$ESAVY)cU)<-*&39l~R!i$eC}{x7ySES*EO?@cO{m`G{Z#&bjnogj`etl#VR$&w-IO;d04j!erMg{TmVg=GBBo@ z6)ojrlePG}x=Vn^WtEQ$_GkhPExH~0t$|v0>JNuJ&=*GDn|)!f>K~)shE#x?p}%iW zB$3q9*kR9Lvi|i}5xb3kdl~nUVdEErvlXH~A@C4ESy)9O>+;(Hq8YLvjO^R-A>DbJ zcaw2T7~A$D`@1)Mj1Mnu*i53f9{5wW=~5?w`lx95gFkcX5-ed*N)6tdLny8R5=A?{ z@zZJh2}#$Ez~+gFkcO0uyyrysiZX(RZ=R3f!{DikffON_h%M1lUkW<{Gv&z-``R;>TS;8PR@_BcbT>5 z+Je~}l(YHYZn3@L`_9DB^W7$Awo{KCp6-I7Zat?fk=D)!99fJ)^GU#?wZ~W+Bj*Rx z#hgy)u%4tABI@T6)Oo+SSyxlV9R-x3ruW0W)=eRir6oTyT@bXp11Y0p^6OuIeB;P& ze&=_m&E4AST#xGw>T?lOE;^6pj{NoJVPD+8HRCH3JPp)l0YOE1L6CF?0Bet4lx+^{ zqdR0EnpwA6|6_9H8s?{T&@D{Q!=y;2)ZE)!!P7a_j3`IeaMrur#|&fCOp*@*-MUX7 z-!$7zs~040nv6MYHhUamrAT~BR50yPtdrVO%rxU8Zni!`cFj4^9xQRc6Upu7D*v=B zPv|T9McB!MlocM{fWqnfkErdBu`wv8K*EhMNq3a?!feIMC;h~(3d1V8j51mk#$JO& zZq$!&9OinDRV_FpfEry3x^lQ!Hwj!RN-k-In~y=KC+_{q3zmh35ft$QVqpErD(nke z1PMyOY-Gy0#HOcU@Ea!7LL>9*x9pWuuDLEt8{V7D^brweWsOZ`@z{fK;;aSzGfKuO zXFM5ocMh_lklOuw%z$*T{&`rW)U2>hG~qRXyZ87-k~Uff{YZsOa$Uq_iqt&UDs%~) zjvs~h-6or;fZ6|_X>u!icRM~8*@xawXI%Vhp(s5+WEAj6X6nR#B%sbzdQ+-%c>!po z_74~a74@nym5~^s!!tGZ61{d23T<1{zMd{sRou^yL;IMPQIim8n5-UWwAj=ac=jJ4 zs}<F!Foxk7-A6VE5dBzs&E218kMNxXc5I!De5PDa!Z+@ws?!oX1Rl z`uJrSp-fLF+?t?Xp!cKCL6cHaOZHup^a4&7sdrs@N_D-IyfBjncYIh!9{D zDdo=nd|A3bho7yJ&QtgbQ&!;qnoyIdgi#msE`IkD9XMXoRg^Do0s|jcw1mvBnx;>@ zps7$fm$_%gJhM?t@Yu86pi1!*zkX0U(Y5Cb=%02-p!ite5;~3rf|iy}-!nxZpY!>8 zCtn?LJACvI+c9Kt=sWp~%>tWo#27w`2Z|A}`Q-%^CilnZwRXjQ91fHDr7@2xQNVmu zfr!sMi%~a!W^EmAKR2Gk)i`B=ZRfOqtpit4)_#G!S|F$C;#)+;Bp>P7II^nst=vPsXMhDBXCNvhrr z^C|utXV;-6LIPTbKq>{SDw&*?voqFX>)`@SaK~_9``nM ziNO4Lwi2amxpsm`sgZ|a46xu5rJDc-{vkjr1SztmYm+4fYt93x+vkx zz|VZHN&B_S{c7F2Uu8TB?^KGTF*kk^$iNAK0LmZua&kxJSsnlJRFYr4KHDKwQdQ&B zUYFtmsVoLN@=9{RjZT{wG+6H;3IBn9WNooM+eg1pTU<#AkAcl3B$qs>?qBHyj;E>= z%?=jn$E<|?h$iGXzZYw@`$PPu?Pn67ct@3YFUSlt8pp3NHqto)Fn`E0O9@5&c|#!N za7MH{uQ0r=zjq6|pfQ7o9*ao9d5)%T>B4H9&IHv-7b#M`%V6FVl_h6<4rhtjUaV~E z#>E$W;GO-bZ6MH10ak{=!9-N(l}}xDD=S4J_k&ypTg{`Gk%YsksX_ndg5Flg#~TGK z+S^9igkhTSK8UVmlwQXzMOZ$~N<^fm%c)gpW693FHH(m1(s&0AunH8sMlKq+P|abP zinTNX+mpw64o`$${I8vDes}F-Uwd19$!_;}eO(c83a51Y{ex^5gTQ zgW8oI%SzfFO;8Tg6%#v1_mURS+@3d0n*bH#N}I7e1o*z(s<$`?u~D&OecWvJ%L#mf zez$8-%=n!WR&5n;vk5=xD-7_}kUEpJs zRyt|2BsKOgK+oBFzvi2JtV9|3;en{Q;PCKGPgJNyckSI#_c=8w5q4C-t@PB*F>b2m zifT?oV(eO^9)SsFp~$)bHQ7i$tnfdAsKr>~NX8(|LU z{&9A*%`L)6tAE&ei8;nh$RD)&_ix%ZMNHq}BVnQR=Bo5K*kspQ+sua}|BE};1zb8@ zAg&mS#glT&F z5IQnlRH+a>_w=#H=KC9jnR65&FK2IoGIAvl%vBQlxelZJj*Y(XDl&;4B~*&VR)}<@m9|*9jF0QTe5|Yy0T}wzvcQ?{V z=fdv0?>Csau9-P!&bja3`R>0etx=a+n^fe%#g8{!OJy`sEZS;0gR$?p&l z7JQ(>LyYu99cFw_ZxfB3jnWeP{ct&u;S@Inc(I*IlJ4lh6*g|FHi(FLwehZ;-(<7V z_#s`D?C6!RR-PQlt z4~mrZK5kduhumnNB5@DlcjR`&qoi#QFcJ+&k9CN+mowR%>u%L-memMDN&wT>%`wSQ zuRlPtA?U%+XvD(!vn@pnJM=^KvvDe7mSpjhu&Sz;6$=c7d^I<}?|@EX`DrFIHJ%e4 zNI_X)*!OH@KEBzi7n2mwTlZ)dq4lAtG)XdpCkbX=MBA4_N9U&UZs4n>`oUh((Or+2 zBzoETkI35*FV5p%*`1qWtQMI0Ht|9NKFljK6j!mcQ$Q^dBn#r65nS})bc zPCf?zk~Q%)mr<+If$!Ji0pArGu zi?vO&xJmvf-(oO=GP3Dv zN8b9sIdMzeyRye@Sbjzr*kZ#1%FmAZ#;@pPt3f|4a_`T!mF|M2_n2Oh|l^a(0=0-({qe^=rgE{ z4W@Wyip@9*_Ed^AAd=4OMrNZQCwL*Nn~QDV!Ft?!zMDZK0?-M2*vez(O~W?RF26e5 zL9Q!a%0OSIPgc7g-GG&<6AilnAwg|Gub9{^H~zTqWiG_0o}oEbBZ%Pq2_gm31K?EvU!T?r<$o~>6(p871sUN@7~D=7}7-q zBi<%KlycfJ%TIE|-}MHc;S{gXi$mB!puZizwAm#A>Igk|DqNSQkol#^N== z)$fmHr~unm#wd=cB(8f_!1e>__77jA#|Hs%&pTzEmzi&}Kab{$_4zJC0-WJVgmGU} z+e`6hKId6ZH1-F-J+Yq{a1Bn&J{+Yy7Jn%HPK>ukP{ww_;x*?*^QTIh3M0r0R_%98 zB9CBz9j=j5CY%a`IcZc)bRYS>d^t)PQMr@5`TL;*{jo+AvqTjft0I{1>r;JnPYGNr zOZ%E(s#t*r7?SrSk?gyVs+wkAQ0Wc@Tx7V#h4a_rLpXny0Caz5swDt^4K-8eHJ?e$ zvjM$Lx5v0LP?~#4ReZQHmUo>=^ftC{EPGm56|usuZDI}?_SNoy@)?eP_82nnET zx=K-y(|L6r@<~q2kzc*K@U`oq&IPvgLxt& zLvviS85gli34PFIIo)KMxS~_~T@M<1G#PjHLQLG#88nj~goLn-rPItTX({?9P7FJf zHbx2r`41TYKYF}pyABC+utK=E)tsmh1#9L@yTi^o&QOIkU6ZJpUfX0==*@kA_&clQ z3=*&`3x_jt^1~9V=YFz|^W}0ShM~EIJA~)=07!e3t1FD`Xrg%LXM;msqn~cNOu@=O zFOp}#4LM=m$Iq;U95D$$iF{hgg%>=Ln;3Mt0{{2!)rO<3C=3aa6rQE?oy1Nixz)ir z@p4nxaQE3;4KtLF`BJEKH|eWOI3y<-ZHOmUnaJFJ2Q|Fm($vEF?RXU!VxwumV;=r! zL5xJvErj?m%hyRRFW$UN7eovoK2vi#{23X@et@X8;^NX6ei6B!r z-=Y}ASpSgV6*xfwIwYei$}nXsMomDs?f(1OH|O?{W_QZdtv{IZ$Z-SyJQGjJMFoKNN^<>N_PJNwgYqxy$Dn{7cJxx*8I6o@L;;_EMizhDV zbXgAdSZ*HmFaSJrf+R3f02I8h6rp3nD>WNdT)gh{m-b7DzE&$mnnn}83%ZC`ubBeN z{_sf7tDDW#5#P%1Nt}*qulzM_(BUmCl#kiO0S4~SUtsVMgq-Byia3qhll*9=_#g4e z4Q=T_yQ4>DlDI-Ef784BzOz4{(A6F8?&*f`P2#;FfBEGx2kz!Q$wHv74Dcza(6&D& zK9x}SC)wqax9OCfh32F`C4Qf7k>MmLN!U|-hqXa&^RTjB?(*82DF1j}*hJ_w$*!aB zE>bcr;EUA1tL?wkuRG9ZVym(b-xl%N&rs6TFAtP2wRaM-Lz7OKbf?)(KK8O?HvAKH zVOgRW4)XZ5AUsXE17%FBPLA|VQ6RuNic^o;;;Gvr`JWU*1l#2vA!EWfLadoj{2*pe zUG<6I%f_k{wEP19A19Q&J(AJe=I)CumOcJ-w2`HV^6DEgEsl-=*yaDD>!s#@lcPfi zsJ_JkHsUsMpI46)0vw3DNrvmo@4W-s3yzgulz^(EJVBygP} z#-%x8)n@XJ@Y0#~v(vne3RDtRL6%(HrG)iRe=cO8dhP{zT9R(pymJj&6M7^br7;5OEKdgR#2~z_J%}6 zndEs}Wb1c%5H#W(>o6h#(wes>h+$LH#)3C1Bl_Ghs)_hD)^Ay}iRs}UDQ&G3swNq4DbUH`5_?-EllH2D@W^327%yg-5^kr{!MsfI!jI6bE z`ScGkAjb}&^RRo8G-#D1={O&zFL!@VXWUHQ!I`OFYqcWG8W!^S%izol ze?WFCQD-ZWn)7J3QAQIqjZKNdT4fq|jI+LW&cXSx{i)As_xpRw+RaaxB~$ZACdLNw zWyZig*DoW-UfCE)vJ1YBer$|efG@pUyx^6|b*Gc5$=klG6(EaDP%4+JzAx{y7%OtcwXX6hp!WMZ%=r)K~i&bT^^4$wM*BuV_s`}%DApGO||{E zV46g~>3lqZ^#vP|Ad~5KatXi1ixQ=^yR0q0Q2%kP5GV~??{rawU+zy3d<=U65IWmc zP?=pKWCd3*dAg`a_p|&1q$JVmQXZnDjB>-X>e-)nvZn*fLUj=r6w50)ZFk~Sdv}Q5 z0yXwXVb~@{27D`bmmaXi{g$E(N8Zpl&Ns7#H7y|dT-%UO1%RnapRE$Jr%Edg{1iy1 zu=TaI8W?FbKW2H?6Zax@VDLU=z?fSmWgCYovx9PAvY!vcJzm%X$81zP+(@D6}jppk5u z3cD1tP-M;eU6ePJeca^aGQ2F%l;3M9YvQR8Zh>7EA?)@PFZ17WsTv9ya7l;06b2zw zbv*jQH+QK&7gQnq=LR$D_&ppb)xtOV8woFuXbHY1{_uFTu;^|Oxft#ew|~v%;$ZU7 z@TcG}qGzF6GJ8YTg!u8Q@1tN2>ubC%G&*D6kH-w=Y<*eMBwBm>3)bg;N6C5Zdhe%)FX&+{qX za$w^)tN36v<}oK1%+r&T3^d&)+IPDfy;8_Jsv@6HOAIP%_6R+HK+;uJUbSYCNu?P4 z>{LNXGA&GLpq0~#ozpXfi`VUOGLzWQOe3bISB7!oC zwu_Lke6*1Kmk5n%WVn4}6s+hUT_U2ofE##QE_^F%2;UJf<==O|Ja~bH-4GK4ekju< z5-6T2ae89CFwYY*Jf|nz+`dQI(Jl_x2Adu!H?-lhta1VVTFsvIBp|5Z-742BYQ#2< z83-CV3~;yI@J~#Bp<)KZnz38>wL!s*Sc7UnB{0X??z$yBBB1w2J7C>|riYZXM;Q-K zyUtDGe@IhZdeSFQMRegaUH{LZAn5KvrpQ_}BnwV9?OdffZIs8vAAc!;VjP zV&3C97L9Xr-v2*O0c}f^gSciUx~DI-)WQaNIf-^Qzj;mamX`@HmW#oD{0e>f_LU(8 z1Mc@|ImRDL=EXL+fqg8=%eNkxT6~4+K%myhBEh2*Jqj5ued83os|`1_)~MJqO2sAs zlb}#j<2B$jPasGWtMnVOeu+vB{PiuTD$vre!c*gOxT~l6c?M3B;2&p} ziKu@e3H*}GJxR_#<`$jQ4(6&8_W(dl`}y`8yxW_xBN8(J$ZRPgod{Hk)Bo5XS>!4W zB&lQ16o5z;Y@h1k`?31Gy`3_mf&`*+vCUgQU{CO*Pz@^ck$hVAPW89^PYL{9M1GA6 zgP{5!&&HT%7SGZijB-B`>yo}@KGuuOZz#fCn$EA{FkAi*Iug7J6~y0a*r;0nu_APF zSDL!0be~81mc>w-c_Q(z*wTZ#e@aREw#lc3JJz#rTC9$e2mB*DUrsqCYF4?M)GB1X z6#uA92smZjk3<8<{=oZTSZ%8G$CpI$RKPWgTH8A3b;av`$8Q_tqNDd7CUO z3KAA*)jnkBJcC;pAt`=0&iVzYDLd3d11(1sQOuTb)yZ*zWgLAu&k#z@)l<@ zW4x`hIf*K5ApSGMYSXP{B=Fy&Q@$$9}s827Eg7q0-quRsM~rz-_o5-6j9@g<5t z0A5_+082&GCvy^`3Tye>w)jISwI6oi7Or&@lbVVfJ7K-HAC4bStSP zlB-#GE|*RS`wTInq? z>cECQxh}XLa7=#~Os}%te+5 zK=lh$a@U2Z(#>c8S4UfhqiQP2Iw{i}e3CDsBfVqnGULM#mufl)N59y<3{~1x5rW_1 zk8vu^8&VdQ`F|82a_PDaSU8=#8|lBWBZwko`ZxBn59<{YuOJqPH}rPU^t@*ta{4pd zmP#^gjQ11rLGYjxPkP{7=0k)}0*l)Q}zA_CsForvkAXcX-@ByB-zT1Up`3@k&aS zQRu6n_0r|j;jZdoCiYu~p1Ub+L0Hhj=$toGtk*7HkqUb1{R|V2IqF$&*wo;MEC^xm zw|?h#ikz?lD><>=Y18BbHOeL)=D_Eiv{sgu`Tv&v^_1>aK5FdT6RgtWo}>km0^A>T zM+5XZ2~|UVIRMNDU=(f zL<5D#GfIN_GKGrE?S}m_ydE~==4zz9weE(WAfwbGBxF9F^WXM2@g} zhaq4`w9Q*OeI8r%;-Y125f2nJj5#f~DBSlK-pi6Q`C285Dx6mrk5NVdF==UOP4|$;s*3#vwqxG0fd;V{zgPZ)MS@ECzYAW0<2yF@wYMoAZ^7ozwE9Q7e9AY{$ZXhn7gA$SiBM6V6^vQi;k9IBija(C^ zBrLu^D8ANwQRppbqgVV2<0_l=al&v+OX=5@ASXFZ{Sw7^L&y)AG5bMERSkr?5{~L} z^)_KI!RnSfZYOG$n2mI22G~@>LF$;<+CI6v@8{YlK8u=)!ZBF!LUjcwLKWgN8(GJ>VFAT&J0RzuO0 z(x1NacjA^@@J^M-^elqO+t!fQCjH^;qZuRCM*dV#Z%TPVmw=f#55F&~G;$@m<>~FB zM(f>ZknBT#WA!NHxWwzo@$qM|mj@C|!W6K#gdA32mugUg8_@<%0R^xH0aQuBznX%BgAZB=?DAj#E`UlYXHYRERFjD< zc&l@Nqn0x3F0pIqiu;}h+4eyzSDBg;etV9mB_T+Md;J}7qJi0oHZNSU5R%NCQ~=YD}G(r|LqA*d6|h zateF{iMUORPagmdKk<+{%8w2vy&5-^Y!{gOhaZ@m2|TE((18Ol+@OU=$-F=W*@+taMZ zEY=*2TT&+bcJQ{7t6Gl#*=xy)u1Z&tSpx#Qhbh)8fUS>KbLt7rfUvubXvGMnrQbrYQHk%gkT-_FVrQuq?#SaBZ z(%&kBtDm#2bp)(FAxoVIR}-A?$lj@P{7ol}F;(S-)o`pi$RFq)w7E#;9KH&EC39Xc zDRuFVwn>>O(0YmA0(DXRfiq6O3xJtf=)mm-ofIIkZv}v`)=H62s(_&7=?9B9R#v0$ zp+}}c6F+pIkO?5k5*Oj8s->1g=T>#ZSNqhS=iFg)9-MpHsuF1(%$a_Z!_6IakrRp9RY%Sbb!aBuVZ;($jm1iNN?l2SoMuaK}f? zjkXIwFXyy)a(Osk`%!X9$9}6PG&BwI>9ssPU1la&hsXRLtlRfTEBySc@H|Ck!%FEE zLqe`06LHFv0)Tjoe1-YcGPdHCkf3<7kHhxN_??A(&nuZbTw_uAEoZ6822~ik#yPt1 zN_-8ft@!{OUsv-jop8e~Rjp zGK-R;79y{3=*2t_ZtpG+oxQT~k^4oAN;t{RbF{nXD16w)ub=FNsAr-=xO1`xHuie3t$ z@iDdsN(zsF5QXtgckEmA1lv&;TaXC#TxVfSFr!CvSYGR7)4XdkWD4A$x6Zg8Xc3rC zlL`lPIQzgKvR#}&go1H_^u$b*Q8~I$;12FP1EPPCe7|xTyG+6c0&|3LGUt3LD6pQ9 z3Vj{jemLA&I8ze-S9-rN74LU-Vs$#VSr*Z_uK*EWOia2%?4hM6W(8$s<>l#VEH5BL-plWA@PiqQ4j-g7!~qr1#a4YJZ13L7mPkEhx=c)>`q|5!0YE2 zLn&aoI6AkXroX?-E9gqo&^{RNM;85+Lq=XLn`RV`JGv#0pE9IY29a!;q zl=gCr-?tG^3_BpLBBb3yen?zT@=gvN-P4yH_)OxP@kQf_Q5wkESmeQ{qT!7{dhvw+&K~llPVl=7tELz1%Xu%L8Ku{lc7pG7X)j2(yKOj4r zno+t4I2cl?rdcR_9nC?=CS9bGR85 zviL~O%(G_as<46SIP3_n1}NWOux7paggkWblw$RB+1Y=rP8+oN4$*$Ms|`;Q47l5` ztgJNiXt=wpo8)LT@OKOSFJ-!Ih#!6*D zxjipKV_fcQ&7{5F7c-m0UfeUCW4u@|^0FD7eE)&^ujrjH_RS@2WmD?5)q@4GKI>F4 zuc>dDjKVd{Bb+20QtjE~hh7fQaUzTQSAE7FR#hUw&FPD=L))K!*}tMdTtrgrKYw1W zOU}eiX^E~Rsi0vvCZzQPvBg+$cPI)IleE;?j7?`um;L5OoPWr?IomdUhOH_5B|14V z^YXcS+`;Q7e}xA(gn(%Z(5c5~XhcV7FqDt)LCesPi`k!&Jdx?GkYNo1Wt-bA*j=rG z!kve~gjxrm{97z7%PX+RjK0>@@hvY0NUwdtVkh50+#YyA`64yK6sy zCLp0e4DiI)+SogI*rQq9KBi-VoL)^!AmzaQLGWQ3q!Dn_v9?sW6ERQ#+u_ZfnhR}B3c1{=NXCaZp6v<6?fRoSdkfCgNe4@3M(!1V z$_aSx)wZ8|?b3-b3NE8?xedn)3A$b;SO!ip%ba~98#`LTU$q-1mgG9toE}x0FeRKO zW6|+B>}5Td`j|&$XTSeK@lz0%AO0TVg@X_IQaiGr$KkRy$k6cja^Z#v;rQVrUVGfa z*$U>?;AXY6(?J-+%%7#%OO5Co-f#%O!wr$+U`}fJq3{N-fv*srdHT(3wQ)Pco_l;Z zE_}D|%M?)-Y<`cVH*G-k+wU^0xBc}QfC9Lc%%7#|Tf_en^&8jHnY=LaXV38gjkas+ zxw_-lsf>Sn*CYh?r808{OPG~`1$Km)yz+#bSP+gO(I>Z#o<-x-fmf1J=%Y)TgNEH( zYPuzlZN%v*v0(CO3zgP7nD8GlFUwedOyi3=uhBO0X0Jmx>Fb^B$iCOC;Gg&hBmrFE zaM_E=x>s1ZRF^?8oE6=r3IPmgOWqLc28HSeZjR7fe68VqTRau?{+{!CXIjecb42d9 z=kCK1F1cfb_g>Dp+jYif_ulNYq7LBg@9U!#G~NX-wL?Sf-1tML*9FI$uV*3!@GU`Ku6|t) zWMEocw!Si)owP+#w(;)a!8)wi#>$Wd^G`VlVWSVtt|huU%tmp{{yTnbAbj948!JQ= zGp<(Jaoci+PoJ+vo|<}#Us1Y3IQ{MCF5hb|J^%kM{)l^nyD_(h5v|95758TWdk|{H zg5~D=dyVST97LT2bK;b8$a5UQd{zQipBts0Ha(v8l(KHFO`5bk2To3*)(77sV|+Tm zDE?gozG{YVLPEcP&nD>`-qTHkRViUHha(-9*894&tv6Qv_3DYgaE{?0&gk?*Ajtcx zW#6Nm&(x-!I+?w_k`G#zR|yfA;J9t?T2`9CJ-NbN*!9{e0XZUmlIC{JzDJ|7-M&a< zaId?{O!A>ihhkN^6a_1rQpIOGf=lLRWUtqYN31LapL0z8$hljx?24a>1T*7<*X(Cp z-J;N2H;1Rjoyj0(G8!kbqvT$fcfkoUuo0G_r3CSknPe*`lb@5LX1~Z`t^-GiLyAXS zW-!0p19*8NsJ`n@7+?zbUzpE;n`oq?qa4sFmk{vv#*&w*sQKNsb6jj(;K`H6e$TRS zA@PJ9901`t#x<@Z8GSHH@Ubskbv zq%n|py;=&V=Z{9Oz89o)X|$`*>2fjAmW}=}(**~P5oi$Fh4*BB{{=e4*QjCJYaaEq zE|FP_=V#<_w0(hxZov~)2Hm}{Z~xHo-L>_9fjUf*$3A1O+-*k`man%4cOxy49U_3Az%cBJ)%HS;zC?62dk*fD z7_1C9wQi8p1n`3ARYfs+4-44~O#J>eDk^^Yg8%x$l4^uPR`EF7!*X`%V4I>04 zKEXhm%uW8HkrA#t>BeLvmXIt@jrf~BlHpciBjA>BlUPB?zoroHXJ5wDHMI3 z=8xwY$G~+C%MRXmh50dnEZc(9T^!m!S9TN!e!q{&)BdS!+%KCuDoclUeZ}}Im1uQ@ z3itNY>Z&{>1EO+Z&!wlCWR7YmTo$jUeh$9a{)%Wb^;<0R7m{^C&2+_<7e*=v{tH`} zV?D?A1zRp!4qU%p$q{|wxLIQ#`^7#8=v_Pvkez(^Yo8Sc5oj^m?kZErAAfPeYvCh~teL@*xDp{BQyyWhS*Ycmja%V)7 zWSq^#RVW1EekXTcIkFFWI-NJ`aJ*&Yd}vhZ_E-`~j6D<%kpTZbI%?SXQy9kuPfOJZ zQBphb(2_}f3?OuX4?t{c_n`A}9Xh$iEnV%c|dY#uj($B}~)>dzIA&;Bg^ zo}k;*|3&fT?;t2IX)O2>uN#dZoT(Z?wtAFqqGEVS;ogiihdOE7VmN)3dj6+2+vX0i zpxjQ!z}|I4lfG}q{>~JxB$cJMtgg`3`rOQ#df&pte=_%AaH zdz%9OHDbwNOvsmY2_K3Rmf7irB29dUViSL=hni-^>W<_RLSf)6TqHW1v-hDi?me)% zE+B`~Y-MUbzgxkXW*-rnqh+TXD0E*kW8yT`mM&w2yqQA9mJ?A2b>@<@*U*^~qr%leN!t%PT{o_dWlIyN&>;Rzxyc>d%N&Ei+!vF zqIZU}Km9j<&ElIFs7b&s?36c^; zC``Du2`g$cxJ}Tc9?Q&02@vU*IEWD%o z{Pi*I5eb}$BQWFg$_~tokYTVDNxW+iZf%?+otpBHXRJ%T9g##mQdf&BBySUhq6slcs=@#> zx8k_RV?t;*0n!J3{}BiA7{{IeeVoo90V2EC{4AlpOu%*SHK)67I8-U81nF|@fMG~o zd6|zQ&IZZ;OpwIM{S&-<^Q~L`RF6k+?+fFq;2_f62#D!NF^I=P4+bl37?uneMZdEJ8re z(hY{D+L}JNb@J|RL+=%D1$cXBKCVDSVSFfo!ez>azpzoadwm2({_;h^sXcoP%mM|dCi>oUD@+h^Wkj1pZY=5@WqIcD< zY>Gr`0GFg)kVu~U?xm%fPM{nW(vr~XgO$!}L|ff8*3oxRUF*&0X!wdN1yo3J$DpUS zX20#K*N{`bI%z=W4r;Ywj#~2f{X1#2Wof?a{F*vlCF`D*9-k@# z_gcXLgN^aLjC(~Lnv)nT7Cecz?et5@z4jH!728qcei=Mf%%Z1DvXs_c$QA9q(GfF1 zh${!WrVbKc!zN6nSoEpH^VM0RS+6N)4XMNFoX_2)syjhHreZTG8RWMg$j!x$WF+7| z*(Qryj`kDV@Yfy&8hC>t6kBuU+B1cFs?R1ntS)(b2Pk< zWUg9N1`!Wm>CaFnyrC2|8lg)Ef|vq{f1!&rO#|SDOq;cDGtE!&F13H|lg)B))W)TR zK&iHuaBV5>bN@K~?jEn_4gN~cLVbZ{F( zZ;^u7t(?oUL5R%e90m3JY#foSi() zWd|oQN3;UA)R0q?-UWd_oRsFF(7Lm{xG*UgNrgawiD!46-QJ7Lp7y6#BK!78&4^(G zf6n!l%7kgyL|wMt)14QnQP^? zGlewbX74S}7oi=iM*m-Iz=c2jZo^O>wk7w&uSVl|v@iIfdAb0C8 zXEIK&XqAF=C|DI&vIlo(8~xLRn>%iH-|x~9t?m8ujV*whGqrvtkd_M|(@1K;XNh_~ zYqaVjKtx#Kd{D5bzU=+H%gGBnl&WGbf}}MGF#Ltio;TI^Bwi%N$p}Du|F+J6M-|Ii zc^wiMdP2VyxE~m84>ddP#XpH0BZaACayo1=mgDt7U@^~QS~am9%&#S+)7BN%tR=1J zym`Z(1kb2p!Z58Jdft$LN!7laO&Og6qpe`rb6^N0u^PdDVdJUPXpQnQi|9cpXcrSm z4NS^A{{4$rB}*bIBkne#d(>g<5DyJf8&wB)j0T_@MMT8J^4i)c4@8H#dPk0qZ|9W& ztB=oxr>1l-Fe~M)b(Y&@#;k!#H|6wWCf-CNawrG2wM_Y4p0BRGJt~WA*iS$ec&uZ# z-qf^CVe|!mk$U-AtDak*tCL0vn^EcRc??vG^d)?+lJ+q8{_+qLpdq?X9vMJde=p%M zf*yv6%Y_Kah_7Fj7UGJHacsPVi49>Yc5}e=hw~{&~Vkp7@nxcI{n!n9HI(8z|x3({Ua|=ux>Z4y-x`e zTtsR$UeKcZF{F_x#o%Y^RhdBcCavK5B1XR<%~eOy;POHuzpYgb=@$;97na0Ph4>B+1#AT>fSujgv~~ucj9)6wLklAQ>X|HKOR%bRd2h&|A-N~*@lL^!ce{vC~I%~ z*F?gfDq{ZvzcFc)bX0k4?ngP^s$$?N2QW!AD<(ka?!)Xzx7E67c=WWFqM7UAdk+TV zOuS5@(d}Ri!hA6);>d$pid++O&yB=p|j zz>!97Ff`xh*%Z1W(vumT3o^j8{CZS%E2j97y1e$pwp|uJp>1+)6nh(4z%8fwX%^3Z zrnI`H#)ZuX<9e||{0tlBYeIl{jF|KCN(Ak(cCZOW*z6~_du1ovzvYB9F+d&8Yhsmf z*LuS=d^fj`yLT|AKWokBj4Mxj$)$!xx*3}kNMJi(!eA>SvLCETs2a4=gSJN65L*I? zzy!y{nSc)9+pq%X6p1kZ+y18V}fb zUfq;+7T^qZ%RlpdnNOgCy8*(Mx%##kp#ipe2%rA^xwm)-a+>O7leXn_CS2d+l4OgerKa{yzJexW%d<_o;Gd;{u z#g+1_(mEcEf%ynxKTv3Z5CXczhMIGBLqymQVY{tmFiE|msP^c?jVehAfy~kf=2)B) zc2s}cKM7sXGO@f6Wu586c%mYv8);m9=+>jD3pZdM@>A@je^8J)xO5^nZCbT}FQCog`}nfe7T!}Tzg=VC=` zU-=#bzwxTAG+SojxrnHcI|xQi&?_f^O5VE# zzLaoK+ur$>_Droo=DQ##>wA2)YY3B*i!(nF6|O$Uy$P>1diKhsD(H1WIw3`kg$A=G z=};1ATp)Hu*%v!VvGFl19GZgTh8$Lyj{V|^V!@8_yKR|!XyAL{>bj@=ntFB1^oC9F znmRPm8ASW-P=Eu`6DBDrCMK`%A;SCV?&Qec&Q9<=yms*~B=k1g=G%Xceml-0&UnPg^vAX%tAY>O)cXkiQKt3FZw*LiOtZT$BMwy>Kn`# z>e>kvyrg)O&+rJ)@HV?J*b&Z57VgUcA5=>OO8iH%oRUXw%=aCLAeeK$_2RL_zuo~D< zR@I&GlJnHwRNf5Ma8xK~gBo~)R?8BJ&AGntm>FtxnJ$TTaYC>>$6*)83GIwNz9QLF zLs0v%F>vH@C>km=`VSkJQsgBkO1268bl*4^`rHw7b?If-H?rWW#9T0f4 z{wlLp-L}($gf{*wy(lm9K3In&0{^9x2Z_@|S`7e=`YiDf`07_FFbGS*BS1$gIq? zrfS#vN(sVngm}5}9Gr?;t>yQNsME+@`1~}c*=Aen&r9r|ym|J??Ec2|UJTC>wfBdy zg7_o))hym+o6Fy5C7^SL+4G_BKej>Y%j zIOf+c;Ysk<%I_0KzdNG|IS49kyLi5H#w>{uP{mTc4PUL?a5??6|FeFM??h&dEh6Hx z2&9xVQ}^srtmmkiboTrKb+GVwUc%PAcP5i$lYY3BXbJAfp7UeV>^6jReTK+yg-tql zirFTuLQ#5sO-)Um*Tzr(+$7T8{gA}i6%UW@wPQzlNTE;8C+M$wQ!pYB%N^~AItb#n zr|}~zHWitsF2LI%Rn{pAss*0B*=R-I`3CLb#<#G-c4xpfjAWY>EUL`GG$XB~ro1Na z5`O7gU(VP_l?J=`0`2y0c77ETdb4wlBy0}?kKx@1??#uWzeK4KCQ`pEmj=m3x~utY z)McAVxq7-&K9fOL*mh4DaAvvuNSDTA5o5QxJdC43|0qLig{S>L;F^XMW2Q?RPP6Z$ zjp2r=R&#H5)x4={5p0S(4W_L^{6&>7#`9oM%_J&NPj{n}0zH+|YhY!Y)AZfP-(<&I zC+u65w@D4cwN1XlkZ<4~dYPrB$9;R{Y45l*SnitTf}S~>6_YbNZ2?0h*G>i`(X;n1 z(gOMBJyqp#uij#xV1OF_squm2J$R#?ZEwnSR*;4o?)M=>#`m(u`$DBg-}5b>+14P} z`}boMus56B(mms^K$JwsXb>Li6Ef2;;@d__EQ=iIuYrm4vd#0}ZwG97h|Rr~A&98V zr%|2J!5ja5a*Y~bJ2E=f`>v623LSPE){^jvOAI3L&l zB3yV_S=9EZn+B=*7z#?^FZmz>O4Sr>C_tpKBd)Rc`J`{9xR3G~0c3pl-z!k?EA0b} zQ`7B79r{|~M^FOnSEE|L_p;<2crb4&wp@ZoBLtV+^J2zXWHFL9g#b$o3@^frty>5O z>uX(m<4$7wdbd|1apaC^9Wij(GmW1Ha3x>WZ$AH0B`8dgwxAsXoq|VnWyh32NQD`9 z2=2A=qfMD4uTf{1+z;_SwJ={a@lok@S)I=RsCx^rs+zTLd{Y7{qF{r9lnRO{qGHep zDy1M`Q7TdbB8t+DL5YIWAV_zYv~-trNOx`6o1Fj5=3qY0InR5(_xrBvzpiVTy*6vj z{hNF4nYnB26)9a_IDNn49qG`BKaF&bu#uQpFgdenrPE0!jFRR-9<~j~Kg#v{S-u^V zjP_qGyK?wYcj%S!T#@S*{>qKGx;B9i)p|RV;s*Wq71!RVu&nx$+G%dm)%38fHEWT% zb@Y|Q!mR&llJ0WaBVo-i{%7|R%Pe}^O?C5-#81guU?l0}b1j!m#V_~FY=Lf(N8@@I z{5|&1IyTYGy}WI8)riD+rFN-{w&v<^9tBQevNn+UTCP5$J(&rORB_Qs$(968BD)rm z7*WGzGC2!>#<5-O%T|L-Z!z+l;Nv4*uY0q*6ti}dF^sNQSf7eoeKGI0YtCKa_HkUk zCwJEsN$KLt+h;5cFU;X%1jo$g<0-dj zUm0%Tddh8qG0zEpcgBK7&WN0i_3*|-!F>lM6(3%rp7-P1GGV0bVP4r|Kcbg9_raC1 zb!EZ(YsBV9kJudwh{)#|XwKl%6mtY<1xVXgYZX>hoBZ4QEi=6KD&kwU>0V#C%oUTd zx!JAj6px}tH5qr0U*_cMYC9z@+u>R%g@~ZDSv7lhr`=B`ak|K=xkaTpUcY(k2z9{0 z>DR1r6SZWGy8fqwazacNNU$6B6&B4oHZtS|7u$TU-B>DXUt${A6iUu~Tk)_W^BoG? zdOQ05hc|1^k{wEkFzQO`cci;3k_k!zY2w-*M%|q3&01~ltsbOe!eqo!e>7N~o;tCg zi*~m3%4*dNgL&A>P_IjTE48X^ zYw3!?7cU@7c#Z zEQGCQC}R;}?^lhzQdFWv1X-(|5=&lf`6I=M*MY)Sn1s}o2aHs-IvSqwAk{ix%5Lm5~EFxL2GnGX0G@ZzfNKE!1?i7(AD1_b$YkH%rRRMbvk ztZ&DIM?s;w9xHi=Ck=R?+40;wcf)po#^h8{04B< z^Q3D0PDU0ozGDJ5r58sqltWL>?&i}Xz45SR_c=F#*~Z88UGLrVWqg%fdcR}@zh}I$ z(kl|l&vX4nfasikuz60VN}wTH8Qt zMD_568^jaTN^eXnuj|=oxSQO1R_H8t!zcdvOm$@MOZJUJ*tVPp{AXS^m9{QeH7SV? zU{x1Nxud9G=$F(&|qBs@!$k0DH*eI$UzRInM_A)@)0#DwfC?rM6Jy zdm|vpd6@;n`)v~snYDsMptPk@J3DrhhG0RoaoE6J`)>FK%;m^vy)MBp&vVrodAhY* zYDajEw~HrKiCiqcN$Lz4Njt^KGfqCr{gHy-QmR z+R6B}UGDL$sm%P_QI6dkL==6b!HpCJfw_czxr!OmQUXplAMX47#P@1={oyz>TxW*~ z5%=oy(a*feU6Pa+o+bBw(v)k%xv11^zZLxN|( zzSxh>Zkrmr1#K=aKdtg{A|c;$vgVE4M9E>7{Jwx(%I#XDX%X>MqHicpvQvefJVL4B zR#Wq)V0qUWH-TXvZ}0hYI*-V1eoo*Pb3AZWGifiAB4Q zVtGUVLB~pm4^}taVv|o@_;4eK_`J49S+-J+eN+t3!>9VGoAzSp?Ks{?%-y)5wcTJd z&hv%G;UwH17Z-}iV*Zwc&5m|qLgx8j_w4dMap&5#Z_g)`!A;%77I`8%+%dbS`pcBH zZ#D%@CzNw~Ta=EqNFOZx@`kpL#DPO`x9#DAZ-dXd1;_9ouM%awIDVYslI82|0ihST zxoPb;Z?cVbCB3Yh7T#l9{^q1Wq^#j}g`SDc=imErN%C^hxSEGA>u(?TrM6-^y6K}` zYS#Al$!rm*+^H0+jM2C6s}Z-&0Y*T!sDGfYBBj9LRbWPh*Y&0J8|Dob!qAi6>f1H4 z>rUd)ZRYUt`%I40o|THDIgi2WO4#DvvSX(fb#PwO&McVoPs1|Qa;corJ zgGVBK@7wMuB`UDqE3q=CO`>&~^rWo544>q#fva;9v`HQl;4=!iRx3Q93G(O99 zP~cd7xFU}hQ`j+oy2eMQ^4w`%#(pWA-kRG`YneAw`NfPm$SXpWoy2okx!z& z5LoO_J^g%l17`Q$P#hPLva?(;n-)Jc&Ff;(>tF}}s^ZdgsQTkGm2vM>^f(z6?2ER$koh9oHE z4e4G=%6A#QmsXN*-j8LgIiVrjd*DeE#qh3D7;D)jY8=-_7K2-*%HFu}=)nL<=x|e` z2F5=KB!I)Ti~Y6k40Zq?PrJI`eDlNpN*Nda0 z6))J4S{?^m_JlX=$v)nDKWDLV*>lhrXQ*{~Bb9fvZyo!CFcMKEnH!RFnT1nwh+JK*Zl@f4=S4iLo4wEhUwyt>rov@OccFJ;D%(+? z-F@p`Cy%omhDTzz1aIl3zAB?gv0yVpQq0UEV_r~Md2ZjSag}H(y)o+{0cpEz>5VMX z?pLT!Sx#ghWUaR`o8#$Tow+l0y%e`vFyEcbF>jbYq8yGX=Z(xhJ;YtFxpDO6-GlIb zoV)KNg%wm6Hpas_R{$g2xMq^lc+goy1#g()cG_B_Oj@#<5I zOk`B2Oi1jJ4QTxG<>O?)TPY!z4e8hNL&&SMH^|Ydllo1$b{W<0or(fiPqh~pB!%xD z3)RlVj=HlJ@<=MBo)8RFrS*5F?K#G0@XoibcoUx`$&_VnAz}pI=-?qv+EJs;4X1}ycGsD*D0{csh*TNeD z`acp4(a9`$J0A+v7}~n~%$cpRMfVQ0@jPzt@;$4$Kdh0p*T-t&hIspDm5OTH!bc~D z^C(LLd~+-#;wx6ibC=X{@|)bDBOkTNZw!!ew(>@cgDFFrp! z5Jugw!Ek#Z_2K8>yJ{XF50~HBlk{5->U3mLNrVX4Ge}PNZ%Q=nWbD!7&~S?SD#=VadP;}O z3|}iYG_Jf!$0BD->XHrrm9GL{j~&y)@_fCW7!?-hniBXVZO=!gH!{C$`g4OY`L-WXA=!RaREUJzv=wcUH&hqVMieoHs_|TmmiUX-j=le#)ZDTxo8w(Sl(RtIZ!!?;<&W_<~vM zZ0FLX-jQR+inGl%aJ`56rCe;D_BT3Noa_0xi4)(8)vVutMfyt6MVF42MOw~&=Ba8r znW?=*SBSIT#;J%CZQjRsGVF5IQa{ZZ5eaJpm--KpO?#<6FAyIP_q$E8m>sU#Wn;r1 zpVDOz?6ZYroL!E6$AG!s=a@3DlU7X+f)Xcdtb}E5-xjjt3wuj_5Wn1A^^~mlUcIlj zcF$XB{*LD`sc^gb?S zfmsuyf|Z@*PLh&SEf4(nHK%KTy{U3{#XAuGSeKfi1IOOE_=>LEMjhYaCZnWta zaD7JtgXKX?x|(Ca@q6uCuaO;PQR7b2$CqF|>klw<7v#7UtCRGP>J?iIEqU z!fynU52amah)b&$tR|12i_ZpF7Y>DwWiDIzqb6gmr3@Ee*4~M^zjsgCbP*l@Zf>oH zd$(WK${D71CovMeXnRTKeq&?)X`zP#U+gFrX!@3yiMXCFHw$EAl#Ynd#jOq>z-4^S zq=Odc=7tR!qV=_$_MF_?uq~x>-FJ8--;rkQ)fhd!eFu;9;*c+k-J8mrg8JbW|kE7mSkn?OFp#b{PKb%7`0uNr(~)FfCY zK^yPm&OPVUD_HhjFQ%mAssZPd=w zH6oQaiC9{)Hk{b9%{~-ptW~ZE>tE^Xtq6IfKe37P*D5ZdCOQnYZ!VI;Jxk=f>NN+TqV9@Y7wBah2Tn z*cNmCs;QhGhUva0wi;h0@1Vm?gu7fn zBrDsXm27`b>eyLws?EJq&U@}N;Hv0EI;c;oL`OtfOVXvtc(=t)8CloNPNnJh<7AR8 zCbP{vj%6{z?Ch8`b}FqZ^D-R%^xm8+IF9Rzm|}<6yN7HN9s4Iq zD0B>FDYC4Wbj(jnWAe?O7c)-M?LKpep=ytrbIuYMacJ&|(NjXb)}c|E?B&tn?ALF8 zy!L5mj@s~u*JsD_6NWFIHkaViN#aL%<<-ltYNt5<19Pcd_5L6YE>9njKCz{Nll3Bo6e864ziw_N#3#Vjv zPk2w!x=T{2Nb}N_MCa!wSF_^da`{bZE-jbzsKLAqh1|eFqdB7JWb#_;nu&br)tK^1 z%A9gCn2nxlI^C!MJ^pXRb`Du9TAVQ)+W_rSS>-pqTff?PF7c|@3-6>jJrXLm2vWKRzH zdQyXKWRFXSS(SM4(0f0ZuY>nw<%_#0&dvB7jLBJaziuH0VCwyDGp+g6M;aaMt=*k!E~j^12bPMkPlJwv_~z7j@Y3I3!W7`XN1 zy6$@>*`Q0#*AMOZe8a9TZZT`(W^$32N%7GLtJKQZv}bWsr}OUljo&g7diZc3>2@>Y zU8W~OPoCiqUZKFy*__c)U%YkqTx{j7lz^$bVbludhKu`1PUYm>+Q@%_;m!)tP0U`V zti>`8U{+P~X0Z5?yXi)E=j6s97EE{uvyhNVVjljT44VkuRvN)>mV|rT=x8_5R{N5g zJ$`I$Mk>zUM?C$ob3@~?9QC7o&uYFA`5(XX$$7MKqvG(H-bbfLi=6J;gK_CcMLoie z8)H-)6z0myt8xdNZsn>a$Jv}B)xGc(??I8@6-q*p+xy6>Lp|_-=;O!SQC)F8*s{jR z?+&>J>TWNcf#!0B&zJn0K{eM51d`USMo@S=TV+hT7C^ ziBn>m+N-;q&FHSPU7uyIQ#_YiAJ?HHM}ldsn{y772#1A}O(rn(6n;ykyP_R&TT5nl zJx`&C%(6iVrds1u@k6T$38Php$)*P@BWle4>BauHQp>5neEDKX5!$G=sc&@CPPv>Z zhpTgK-k5eya*kzEDmL09%Gt}g6BkTmrcyE9L-j}9Og{=rGh;~I1pLEgL)v*C<=bX* zbDs#~7I^t7^Q;X&HRE35?ouY#UAZyrrnBUMr*gf?)E+XP8SK~?D&TPh>LizD2Uh*Ewgt8V<8R$+9wSPCQz^HFK)rxNc;K3RgX7jhwsj zRY_Bhg+)I{tUI%5+uZ6@AhSMxN|nMZW)n^NA`NqY%hDT40Y?prJS|OPm)Gv&ugWf0 z=(%h)H|EP&BuS!4vedxGseawYr0Dwo{d-F%zPL28(9?Ar z0(&Sdb0~;=i%GJH0!OO#-zt5P5}KwAt`=|Dhbi#z`lfw6{y3Lv9qG{5ScW00MOR#1 z?`a+zy}|uqV2ZY_l!`9e$x$p&_R!{Vt>iZvU5>}7R}lzuvw_D3~pq6_abndG*|f9g(+O^=J=a?^G2s@ zr1%a>`RE_Hm2Eoe`D){le$k#TqC2;n>-S>ihy@ragM&YX_?=t&_*&`6kwZhFwHjd? z0&2ftnrL7eitSZm`KkU(mKOe7SBsZL%i`|bZ+^vX|A2Dwggm{J?^&`s?m9vEw8s8o zhs1$0j@(Rb>V~LWdPkL4KYuPA&3m5=-(JEe_^B>D^Xjv0npK5dQm@}XVpqF+;nJX_ zLVuN)ruYXg`A`XIoWI@yt~U`LAB5?e^sGllZgLI^9pK~Kw0X6Mw|~O=a#&^ZF(L}9 zuNxwk6;F zu2z_o_F?y;wR|YKu*CUWfPs~0YS+eb;_^3^KD?G&V>+5zW_3XFeC-|)Wk=27K$Cao9#a&Kul+!72iF-aO70tlL-*qZ;Jej*giE|&Fg0WA$ zQBvRT^b3NoW2bBq29;S886qDnFfvvMg~ozAC(JRTyMX{pbChIvQlgV_g*=B&XVwCC zgh!hzt9TQC$h;bPSIjXx9WvvyL{nWvPs)h6L!@(n&l~2!kkC(>@paVXFNz8ex?Y#x zC4|YpE)1jW>60`pmM$&0XEu#S6WKXej{BQT+~vXK_*+Ga1ho=<)$S~o^cLk-{TBQZ ziuRRa-`B|`$D4<&ZEkz+obux&QGT2lJ6*F)tUixfH?m+NK3aK_RqITeS;K>>Ma~wg zoOtQLsl(|7hfJ+E?WTV1WN^GY{L%~ZjyNVe!BB-F7rLNV)upvxs2L)zZ%w!s{OMv? zCSzo18yOW9+aYFuy(N!*D)DOk0u##|>5H50hjAs!klhK)?~-5*B(m+)+e6en$v8Hy zr+LDvd_34mFj8Cl!l?P`LXF=AlbTuwE&fhFM!Kq*i4@gr@iTN3mgG;iz_)f|y)HqI zQM#T#-|!&;aneVWmsGe4MWTrqnci4_z~FEBVelnHF{`T!Q`Xs!$D-e}k_*y}lI&s5{qYkK#wmlWm!;!>o1n|B?>KmOX#u-S=? zmi}Pmxh>6MQDOHecWp|xWLC}?xqEGgK2G$&&8iaWl*#LYIX75{w{CjQLbKHwpKrRV z&a})Y)z5$Rrq+#gt;YFRuU`4)o?V0RM=keVcJ0_9>D(_t zEG%(kTfn`u{Bf)>NpW+6tZJ5}rpm;87NGqQm-y zT!tD44%ia8y7_F>9M)7}8A&-_w0n;7mB{|u`OMTC54-2n0>4SHHk@vdeX?4U$GkdG zZu&AAEJuXl6Dj5BDQoyy%Nj&pI6OQ=%ED+$U%J_KmV`oi*Di+}UUYfGD%Z_7U0pC5 zYqpv;a~x$LmB$}Xq`viR?u?1@#s_pnj8h85*q&9|gA!?G6+^YD_ku%5WoUE51utDX zETZzQ`B)b*arY%lXNUQ7lq7p>dMMz}!J447KdnruSNz-v9i7lVKHdfH3^GxTOYdwbPI z;%+N8!Bg>{4pyH9%VICtFDOtMf{;mo#p@+gCDjjgs)E6!Y{LDO^}&V%+g@A}xV%Z@I>E7b5cW&>3 z`|Ay9-_{@CWfk?n;M??XVi-7e4il-|_M8;kx~%A9+85Ltj&JmTc@00TJY&4FPk+cs zU~2d-#chl^Q@6aTA4T)vP57|*6z;a11KYiLhwBtHDMFVR@n&^5F~0D1TEsD|`=Qfx zqx#30rQIGcM)&SL51*gPyKb@T`E&j_4hzZ_{pOw{I)RY z55$#}I=gps?h(C`WbIgyt>VaYIpT%EP0X>R^F(oh1uDb=^Zd46w9C`Bdj+_Nxa7k2 z#JZXiNAhc*qR4Eqw`UJmXA<`z>b$*`Z-Z2g`^FngD*n9+j|Ihd^t}-5H^Lq!qxBj- zELhU*kdUN^|%(k1dU<|Qy z8pkYHmT4#~9hB*I!{5-*W0Uy6b?gEwt5oIl%-&vFMvl#mGD$bE=Nj3nYjL<|*T%E@wg*fr3jFUL5+vQq6jipB29q~y3V+NpmnclmUW-_b zIKbj^{z1kD;%7b7Vwh_#D>=-(#|GGF6{B_b^Ghv8M}$9G#@0(`N_%*youGa?me&ZP zl;&)zt}9qra^kboun$-d9&};2V2m9vu;1dl?e0AV3yFhLQsuT-EVia^f49OzsT~ij z$rOgNglSYJ#iTJrPC{oqUTqueo$lJ@O?|C+(>7BIPLqKNiaJf+z##C#Z<84D<@9&j z_q{I(uxfneln3w^kxz!`rN~h8>oMJUc&a)3Zt-*n=_zk2G6q@`{kd4%MAJstZZt^aikkDm9JG0R59 zahL(B&GdXa&5gnio6|$2yRutua*|MUQ*b9Fym+1~L)Hun5=~YdB z_P&iO^zs$Sb4HVVhBJMawi|CZ-)^eYYW2v>r*+}A;+!3xl@>#t-Mh6abN_kGZ-re{ zhmT~PIn2u|AFZ}Rv^RRoiF(RyEUb20G1gR6C(J7uZypt(->}^q^Nj9{R4(NqiHmM0 zNbtQ={Yplo+g{(O6Tq( z_ng4&PC?Qf^a|kJbsQU-n#9gAG_L4&#D@meUcnFrB;6(6R<-Gv7nf>&d!U_NBF$Sj zwd+1XGFM(O^6*fVJifj2MsCotDk|3*G7% z;MA^96ITM?V}z{goL7lhtcit4AKNo-V__?r*+ycxla1|@kilj417uEx5%dvcQy~J{ z6ar=24()u#8*M3ehQ?KP#jZNp1M|#X>Cp1Yn*lU2L+mfjY_40(bCc0p78l6GW`Aif zbXQ9BGkaUw*Szlt{ty->hII$|S~Qv9f<%uIl`wyxD01;^X_A9IXMbbK_bV9L@sXKwteSLrSqoEaV^7| znubzDUHcS2)ykX@7Z(rSWvC&-SfdjBiInjHu}B%&Ry(A~Xz;1uV!Z@su=dgk|Ki*<8{t^N> zH$|^Du=Ug)foMhtot2BuyB`V4%Qx}f8;z~k;`zXR%!kc(mBdM2TKKir6P2fyaz_P{ zUJ5)sVCfMC^71Q8<`x?H4Ci)D+UTEs*llpObRfXb1U%@CpxY-E8k&`rWv>(JvVGUx z_Wfl06c(-}xRYeI2EDR;l%tfV$7)O&U?wQGfq0Zd;Kb0Cl&qcthiZu{l1EFbswN(= zcvJkl8+mwkh*XL>?BB?{ap|y%f|;pf%7vKu2a>YRF;K1z>1#A!tdzKJ zu93(+B;=pf-dn>o^# z6kolLPB~uF#ev=T0+KWhu*LdY`T!pv^MT{XSvfhY zx^kt5gk4E8GZJuSg3>ca&;13udCA6WqA5(zu0GH6)i^i2>6Qz8=IWN0L`XUF^jWVF2pYL=Z!J@Y9c$0_QFvewaU1#NTrtUbb3#m_dzLsNw#3F z^QTUox=^GcAt5PQSvNWtzhU!XL)zxCrw$#usf|rdP20|8*XqQd^gI8YX8h@P4ceBy zX}5faDmoQ1Sut4uCcyFJVg7bH%tU9#QkhTR|xwOSjc&;s1y zGfq~V%{QavL$5~0^J+z!KX~6ZZje62BEfKV!L0J0=)n=|ufzJy`?f5)bX>$l9o(;X zHBPeqs0D+<({rgkCi-@hJMg;Jkav3ot_cV>Jx<*)ku9GT7%N!N@!+%l*j>|XojK? z6)iKWnFZJ!u8|qJ;gn%Mp-&E_<2tn3NG<;BiS*N+d=|#TpaFior0#F90Bc zg&6%0vvn&aDd7YBa|jkLSX5wvZ@Ytk|L+}V&YanC;R4?UK|w*4iy|WW7ez%~M1_T2 zgarj%g!y5CH98l+DCTnU;zfNyK_L}%J-YAz9;*M`@}*0cowPKy#;h%@fSr{!urf6T zMvor@J#B5Eaqk|ur>qQAZ{G%LN=iUoO^xt9`ainP-r5?V`|jUYA4Bc@XKMd@SIElB z#aUTeE&6=;06aZBz#C_0@Y2ri5BvzX@~vCn@#|=407HF!U}9th`)dW9UcLnGuCCyn ziwiI{Fw{j74<*r2c>QjjF0z zwkM>4aEFJ4fRFzE1l}Y32!jX2kn{O7_}bVAD$2$|dC3?k$X)tgvNOj(CH($tQxnMj zoDDuetj@0-31hd8AMu006WErj>fP-BGsJ6m%gSD-d-~+*7?P7fUtfTDkFXRL%W#i!v>k@BgdHcMUFAihYvE*g~0Eko7tHvhjj1H zttQ1R!oCi|`%zy!2<;*4{$5@nz{iJB8yP(tL-haKe#px!(pi{Wj3FK)yr^wdqmrMK z3))&HfrW9$3^RR1H{1U7xg#vC;GdL(jJXR;bf3O)FjWm%Jja8Ys!5Qan@8Y1!v1ry zv$Y#TIR2-7xN+kaovpPE0XxEv#v6@6XwWCn($WKbK6K48(T5HE6TJWK8fN;aQFf;C z0hgC}$d7LzA~cLJ&Oi6T-rjx;;rXBR!Q9;ZJ9dO0VUGw42OVwG;QXnio+B*HtN#wy z@BiaD(Fs)br@+N4{ebge+aKeE}qMz6o`q8`lAmP7S?0`6u-W{LH3$_dk}CV zxy*rcuB2!l9A*w1{vF#tIlp#m1Q^(1fsO?h+c8xTw&RlF#S)k{(jBzBke%b6btf7 z@nC#%5tup80TtazaD?^G`NGary?lh_>qN4x+-t0sLV`LP4^H@cp}SfSx&Q zL})0K!%#Smk>GPi7HDsq0*9CqXMV?p&Uuax03NP>aGawDa2@UfT#w>*%Zk^<6_ zlL^K1gBSMi@EaHy#wEqZ0#wlTIa!}USH~bYb~tS4udt)$08Nuw zkn|Z3mLPUiT>a+3tq0?OiG7{UL59zBqUYyVTbc$zQ9%LhM=n98&>n+u{#74f!s239 zdOFC?%mf8_`JlP689X!0>R)g3@9J~BqX6OjtA0q!PZMN*YG#puy}NIb!21h)-~KIr zL<_F5UC;G#aLs53RpsSyPb?vn__+AR-|=f}>pJCRWq~}npA_cj!~Lin)K(8bS#0^Y zbk6a1gPRYgft1`7xO!t6h=@)C0fDu`cYXpqc#Z`j@wo52f8#$7)E-U!+ctmZ69-fE za8bb|fT0smTUA9U6=h`r;r+P}?>*j+p)o?Gw5SNQHn)H)ViA2mx3&J+*J}cSAXmRnRr=}5jpHIMF3@R(y7TB2^|5)RnJ{kn; z$J>uMVC6OsB9a$CY{mjuU0wgrTJ7+D9(ab#gIVknp+<97P`LLWV_)YN+}{Svibe_e z*T(?Kx48JFEocn%^d327Wn_SCC_e=J#U;SZB&m1({`LAScRR2)9|j-ZjRSArX#y{E zO4j5#HE;13@NM18g#VXRF8~wAIVeXn;QYCs|1ow%n~6T8&(#qNnjrtHD=MIDmw~e4 zVx;4-Bm8!D_7&-=sQ{JFaPHRE)xk9KFZw0)AWAoU44m@#~1FCvc0PO+m?fg$`c9zCfk+U-^Z7nSX+{J~302OU*9T9}z z^Sx(pa(p~UPD}(Dun(0LmH5A+QILxzfE*fJ0?%GxK}`Ar(6^ZbX+QCPWPF9dcO>@@ zEwSLf(F_n4?E~DLf9|(`MdR+O^=&90nQ3Vt3-bAqp1uac9~%=3b+a%+ ziG}^JwTk*f_HWC70~6yvgaqM9$yo$CkjFpI+ro+^Lf>9{;lSv`+Js(&Qv=P1^!!EO z5sU+m;9iXGM+NB-0)qc&FX(>bI07=^zM2g8S5%%nHYDJWhWcLUr%!|u6&?X@$c6r~ zZmO&FedlrWS3Ch@ER>%|wsYUVU;ofIxB_e--_bar{`}Q}iUoPk?!d4ISG;>?r5mfq4HQy zkAOcWDjJ0Si~o^O$CJGD=@0w@ydBWLFbwTiJfRR6}6ZFk+$opt0KPtBa|Im3v z`8vVK$Pb)xakId}bsl_y^5F^b;c$QQcfC)Gi>rjOKyw1knFV-`j=a)EVB<0iPI3O{ zwH3*aqs;(FjfnxVP%kFPkHMP!M@2*ubmb`6uUI%2OrM4RF@L!^+Q8)G+WZ|IT>_Dz zP!|6+A4{s2Kxo1Oz%TrL9}wR5o)yA)eF(vUZv!hJJZS-#T2FyH3ccWp$iJ5%sLORn zeCk@0e>et7upj#Wk{@qRZ^HVYh~_oi2f{)k{&M~F^_)O3fXnMqFg3YC!0Qu^C&+hs z-4Y0jMfSoY3Bf#=_AD2lNa^3HVVTISFc^ZTx$ar1z zGGR|ca`9JVu>!k>`swJ61J;f+;3ZrG)b9^`$B+6TbNR1zJ8q7=F0^+MaKbh8Gu#98 z_4En*uaS|lQ!cbsa*_TF?E|#8ojwu$i~hiUq>Vu5u2L_7_v;<_+K2~TU5g+lZH=dh zw?&mpprU>W+FPpthhGH)!z%#Em?xAQg#GceF+y8vO8r1dvG*7Js1L&DJAYY^kUjQ9 zcW5OaV#`K)8Z79uhK4pl|G9PRHV^VcAv*{4u^84?=6=8I0b&AO1UjL?Q|r(PbyC6% zz|OA8On3hZ`0#NKxcK1+@_}Szy`X(7yLb^yOu_ZYWBd=y2={uqDfg`n__2yu1QI|3rImaL}i*a;VdlL*2g;+BtA67CD$3R*)Q>0@IuXuet$HC0ZpYyt=3J1`>zTWQ7^(CRT^@w$U^0bF*JE(xXE&K9? zP**|y8R1>Wj%p}FbkK*l*icggP-%oZbZOz26%OXc6>-5e+4;HsN7@6>U$y}4;~(}6 z>PSDdZ-e}Q%y0A^(wpA7j-ii#9DTiuz(D8MIgIG6;}<$#K2iqxT?6f3R1jYg&Y!Wb ze|B=$GQBb@7)f3LGLval`i8dO@L zuN&3kB3?s?A3wLh{`raiAZUQ{^0N+VVLS{FUw=MOzpPA#!QjA;J^Yvd!v=gltj+72 za^JwQL)mkV_D!H3$^ydO0$Bstq0vfP~m-Fa_5aw9h5Q&-@IJ@VTRX0a(C3tgQUGPY(|-5$?IK+y_L?H?Q25 zufaCMSOSs(R1kJ#e<6Io^ZfU7UthoMj@DLyN>_V3=jNW$gFsHkfAnX(fA<-!jrLZgwunN;d;X{!cKYdxbB=PdqnF8*PKKIta%X@gB)e1H_H67k&9MhH(5-%)ejf z=;%mSkY6y?)7eRw2g8uY#5mfIX29(1EGR20pD}zC)GsBTi~Fa2k(H=j6gnR?;P@hA zxEr=RJ~jqMhK4}jw{HZwX@P48DsY`2L-c>g^xvFEMMY%~LF{M_AbMyF5Pp~v3FhbL zVLc1=gwkox_c8r{qrH837WE&N zsmaMT{IK11+4%<7i>Sz`e>_+JX@A_`x!;5FPweEx#2@%^I2>45SOAOA*{}?a-xavv zul{ROK=mp-N8h9Wpe2>kyY zKLPVU#ElzqvO3C z)%`F2t@9J!$bk5`&ToQJHQf}p_2)b;5`^lHJT6A~od7KVTX|eC2TNW?O3Lo4v`q9> zDXHu$mo8;r5)&iTSEZ%1ugP46-^mb?xmE+vG^K?qLmEvB%e7Wcj^9fMyj_LE~ zKwn1(+*eg4#hId6m#l`EBXBVMV(L{Mm5U{fTj~#Io&AP3JxSrT(?;Fg_#@<*Q^B&oa#ou#c{Jnet%qOb&PkeyBscb|W6`v2DurKXP+?)aV>`b*w zf8|^I{X29W<6gfw#=X9J0;jrXbF%tCP(Z+U9C{D+{+18-@7;gy19LtQ-%#E~WLP_v zjWO&Of70*t(7Br41W?r(|0TEM5aXAbeY+g*u`^Y4CdZEv{NyMH4Eg)j??3oM9z;bi z()s)NEutK;Sm;+zO{tzae4yYj<6%EzIDN7U7{9`T{4zYyHktV)M}~vBewluklRAup zb{6CgLf=mkNP)4okl;^?h~Cd*VPb3&hjJHC9zbPT;|d3B{N&GcPIC5w)7(R_48S<~ zC=eE&0Q`ItKuvc76jv?4RcQ$r*v$UI19blyhF3TEPk)m|&-m_3d1Cm~3FY0O{DGX$#lPg6Apf?scsG!_J_J}%9 z2BPAVKuL23`uFhwJHG^s9A^J*JO#-l%z^7_sOtlD(6@k!j<${j;(_BU_^=oB!J?cK zb+wT1@`mEhz26o=5A;u3xXuycf;~OUP(d7uwtWr9NgEH=-u$K6T$Uhf?8YZX9WsHKIaH=-X8V*)6S8Xg+{i|-lv)R6DP z5XPfjd~t+WBBCD+eaGNrKK=ODGfN-+C?Gy zD2@^q8Uo(9czw^SLvgF{kSWmLzeI?an>x*XR|{?4&V$6y3!t(A#!uq$z!dWTq4_L$ z@OTnP$qxRl9H4a)t=Y(rnh5)BV{S>HkMiR_1$_k1jaJZ0Y^&hR-Ec;>ui=muH!uHoz!=B6d9dDRd6~;G^PXNVkQT%OvEYSE%U(PB) zG59n{&(h4CApdTzZz@m>=5u=b3O8r!{QC9Iuiz^!gVuazZSAoAu(eo3e%T`EANs*_ z6obrw{eS%)%8BdjFaD|PF!qG{g4%?6x%H2<8|P6j0OEnEu?b=RTUuHSZ-(n9-ux)Cd>omgZwLBh|t-! z`N^=yGcq%!iVzPefqQ_V;S&io|Im?_owJBy2pOqqb4OX5S0yiY6X;h}tgShTaXa_x|GRTXnXbIFbg>2cu%HirMU+2gcD)VclXQ9gBaV=fIt#{s%E>@+ z#dRJa9LvkAz~k+YSk-x+?8(9=!}$SY74X&I z0QsXO#0uwZ%rpCuUvteL+W>+-2K}x6w~iwrA)%rZ(nr2m=$l)9ZuIFN`Ht7|p;|&L zd>|{MVvdkM2mO&v&=(K$7c16j{HGf3N!iH%J~S`@ke{cfx^Bk!S?GwuwbI3(>HPdz zPO5h4`qjwc=*X;*G3e_XfWB|!k8X$K`6(#)Klb}~Or9S+pLch4FCzNLXNdeD`L?Iy|zr+~-TYCR5?gQN<0Qw*-R-tzWxf+n$0s1h=yP+E* z7rGACizNnw`KM+59#nV3c2Ik$UDQ6JgXj_H!m)cn`LiE`6oZc6pGVsbzvF`Czx89l z=d74jRa7lim6Sto-?));{p!`?Yf{q1ir23fE8n@3qRb3cl&z&DFwoT{_$5?s-vL_c>M%}h2wvFQLi^bjSejdm+`D`4ANfY^-McU3 z^y>BGCulQzLwhtfDjoy}mM$4TEt+_uUxhW$t-~7Xm5;x+Z(N89%O&_B&~?amH8U}d zfX~m6|6O08{VDG1=(vb%`{;;hxK~up^PR53!aWk^P5+wP&(2)GdiX%;%mdZ0*o2r$ z!ZSeV84*hhi!AtT$R9M|GZb8JTwE4Ez-N&X;#lfr8s@hwf~0I5{QlS68&0+g?C10@Lau9Mc*MwhAK>#DohSz+E(Ybf zuJHur7~F$;(|!F(pz&}9T#=pvl2TLPeegUXfBWxjT4lx7dGyR!4a^I$v$a=(`#IO= zj7;za>Qx$ds|h;fF{t+iLEYd}%se5lx4CmomrH;;a^hzk(0nrax6eYLG0)5HA>$`V~$1|W^>+a^31oJ~JLxO{096j{Ajvo^_1@~1Pc;k;F*mJ0Tlz$bT zyk<`zJqjI2*Oa|8`dx$8Tyh2-vXgH?p_6}iv}ePC<$M`g_d%=^QG)Z7I^E);6}E7ZT;1K{%rPse~V)VGi>A||k= z>vJ$SgV*+D^T^J2fBViG=Gjm|`CLT#MCvN}^GG(4eYBq2T~!J9c9=7km_AR)>kf^@ zfri#4xTh|{yp$h0J<3N$IcY~(OJ_c(m4GjBKD~8&XO8BW*9XrqlqZuIn}g>)(YA{4 zpj?-#ig~zRtm&)h`3ZD<>sf#?<29L@g*iqj=D)5>A-~HbosxN!k5yh=vI=vCm{I#M zf8|I`MddQet1y0&KC1xnqkB*;TVnh)!7fC$2_C;@kRX~1uutefvgGGI4iJ8E!7tdd z;u=CuOmb3kIBI+S2n!8+(GK$;x}pB5r&WMo$AoGlgF)~f>h+c7YrcT_`4vL$2%=Y3 zG6&^+49H3}E~ck6ETdeY@{-a?nD?<~z3ufnEj29*>4iu?dtq0Ay(QmG;MF><2Wow= z{{w`AY`VKjYj)i|rQ*4gFU`xyj(|S2MSp*Pq4hR@u3_Ar{Bu@T);Fj>kByGPHKPe{ zZd^HcL$>vg+=ZKRovUiMOJ+a*f2|yCOcYme(HavI+y3-NquYg8r5jn#@G zq98=urakW#*mAcEyL-ps7ueXe)}mDsqb0poELKvKB4R@|Rg0;GP(Y3H*aQLjYD`2j{A=bP0fCn%e6EV=d@4}5dUcdYV)_xiO?Kb}|P*}WTd>4x9yF9WYZbz)o> zw4GC1TYK2!>G9)PC!TX^y5FNwopTU$-quU4*Wuaajtl8C8o`<3)T*kgwA)>`ouJPa z!pl?$dTwDuLxUB3F#fZ@kEsIIN6ldSsmbgOY9f0^O<`;yg^6N;9#R5Kco1il+E3GSZO(_V%$8q#?6v=xbovmlnD9?o{$CHoHb$>OPj zts5^5Y;iXATeGU}Y}>lO^W%boP9-hlTc)oW!^Qrwq2cEDGmegHYrP3F!X zc&v-K+N+Cb>zO;t`^YeVn9Q3!4C~qhag;~NzT#s4>Q$>=*Wka{{<){7s+y!M|Fb{* zmGbV$@RpIt@QZ57R=P&=HdK4!W1D&r#|LQxU<<4v1)H|iAw1Yki!fF$H~Z{u^ijol z4C9;KWZAM_lAO{9F?+-0lU-g_Ud)_Pdk1ms{InPJw*%J^{_B#Gj-P5yt9%^&+aOe! z*f-xN*}^@tZPy?t$=bHZD_h~xXRnrjGu0_5=0xA$E{IfORK{bfT0WqSMH zU=s$}oBr;TvLs^qkNpV0*?IaF!k2@sb52B~5A9>;ejOxxAg-_z>`53ePzLtQJzouw z4dCCMzD~o__E1vE3zAm6huJ z;TS599BEHU`lU_dnRRCef_{>yQ#^PO7z_HWrzJJ_{ZZcv&%acCe-Pf`aKs%ycI?Xg zYflAnpq&S4qMtGPRpx-N>DtueH(MJ2A|QACiY(7WSnYB;^5Ve1>~it$L)9OytGo4H z+EuV|b%2by;^(>Y_LD!Kzl%H%bV83^vHz>jLiyptJDZxCy1;JZT04aCO|D=GsbJAyh|G|X7pWD%(h{g7NQT7W zZWQ2F$d%l%p9rI300HLkTPPDKnjXyo`KbD)cPyfAMrGgc~? zY*4yF>r+%ZFIdDpIckw;vx$OkktisVXq7`Cg7Xm{6@$N!svP@zD{o%T<)@0-9L!jJ z+#7N0<74%)v1W6I-jWg0)M^qk?WRni9T`%ZBZ+2CmPLt`%vrp`nH9UFHi_1T9<9yB zlVdjo%SUI)phyr_mLOz^<9r757>$I?ne7rx-Poi`T&^9S4QEM~cn5FgGC4U|33DE- zUhD)=1zwg!&cRv7CYh$KSYTvKa)RK1xsgJ~Ow)FrHRG_2OoquSbBs1vd~Sy5Aoiz- z8={}+sv$Z!X6T(ET6+~BgX@B#4C=c+g-WIpVWp)~OJJ3)hE + + {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 0000000000000000000000000000000000000000..0f3facb9cfa933a493c5f938866266d85d282161 GIT binary patch literal 62704 zcmZ6y1yo$YvM9O-cXxsYcM{y)-QC?S5P}U32?V#`5FCQLI|K+G+=9FN0DsQC|NOW9 z>$Q4M@9wJVYOATLt_=VHKncxnZ~vR2#s6Ot1O2xh3km~$fhG5aZaR5kAdjEyjf#P@o zo=|L8DCU0>C%^`U`ELfGIRAlHgF?9iR=_8~658wkjrD)yNI~gejG zn*SM<7PQqI+N&p&b8{%w|HA_^+z#A+IRH>X>Abzc{(tj}h4p{tH(E_a79E8I1qy;L zFDIq(zq14akPx6XMjoX$08su*UP@f+^YV!?q8Z+&zdzP9=q?6gS1!e@jrLokoB+fgV#lEbWbiX}M{y7^zajKK&p%Tks6U@lY zZn_Sv?xqjsaVX?zvyt~`Rn3cCE{$cQXatFoHcoRZIRjHN&R*!6q<~RxgT>*DQ)GX_ zv3tAcXfD4?vthYTh3oH$$>9y{f0v(U=9sh{w7k4R?~S$fkqIhpsh4E)mFPSvME!|k z=w=D(PCOP*ZL4&S4-E=0cMM&-145k6DA^}>yC|IJ+#F!R%-~d3M*w}$syc4vUYZXv@vA5LgW(+!Q`|QV-|LHb|Jq# zrQq2^A!QNK$L=%}14W+ZgtTLijcy(k73e^I+bt#1z8I_6QbbG5)CWXjtXWuC2prxb zsFf$@%{%mazpD${sEho4c7fzpzl7$UN#@|_nD_JN&f-=mA|{TqMfa%P>dO(SYb8~t zUOqaW0eT~-$C}RSbMx3IT^*G_&S6WgG10L_F~2m*q?)Va^jl-rrY41R+Qjp^CPPnG zZ0gm`N*UNA71P*Gg}&^J?EU`z+jQOkxN3gK614%;XI;nx*qIx&*{QP^{N6}OPrgxe zFnEeZjz-R#JrrX~L2w$g<~ys4pKb|SKm>Z5%Hmp&1tIbs=|t&o2=UF4f}hSHVjdoKy;#JfNmnfOo*7+i zbS`VaCURSBP_sYStViq!79mwlu(a$~L|>o8?Dx}^1syFd|NEhyV8u~cIy>0V8tB#w zOCVr3TKpz7uIh8P`iO}vFMpU2c4)1UaqihXtW0sCHuqS83Jff42?nOkqhVpS+>h;g zi*tiQQTP9(IIVOAOf1#g?)zUImShHBk~U-@o997inwmA8m)(Fa30+Q3$-hi862sVH z``<(2`spR7NLmQzNh1=_cRKPybFU_|{&J6fZtAN~e6rSlzZ3lOY)jy@RA;rDW@-X% zdKX5gP6}`(Mj7WS6CL*dT5EfuVr8A^xn16tWKF)2D33cNg#m6~j2CKK_l*d-{~}JQ z0h>S2FGO38fdfIuqOnKhv9fC=$j7kfQ6*Awc*7roI>gxc{r&n+trw4+=MzJlmH5%$g-NMpE*$n8c{@ zVS0yb}#IP_94oBY|RkckicT4fOH#|i#{3q{95 znuA07X+rO;tj+DT*0wudP0HiX@nt-{dZgUI&Xb@C1eimdI!#1>d8Ylsv@j9D89HO! zZZ}?6;|7BV8#4_ooZG9sT*N4h!7DN$L+giO2L_PNMVnOxK1au*sW z8q<)%#?EB;K})ACVj&w_Fu(*C&085a6AHrTQ=(e_ptE=W_iH|$fkurE15dZds)_82 zTO@EHjyM1TtKO6-Gqa=jGX#Q`VxYXRC28I)=-(WU3IvvIZ~%5?3}Otqh%2c@dkA2& zVliWNuv#|wlRfZy?pKOXGV36gZ-r9pq{F<2m0YFQdUYC|M8}FaBgkNt^sdtbYeJJFR`e`;}kW=ZF9h{K*xiWM_A!OL$7qaD|Bu zmGjSBL$)KY8)roTZe-x?Kz%-cl$~vW(zo*-PX`ucP0!F>0M5{b2;gEv8-WK>M<4fq zw~suInuY42DkawAFlnfT@TvIBI{tiLP8Nx+`k7h~3gC5xfpIF0+^H;+&M%@-^S*Ki z^UZqtNva;w0N{s{r5Z|}_F{A~A1}X3asdYlZ4NO5dIwrl-T z@0QzRdJYH>wL}Gh*J-dt#XJQ;lFuucFiL4;ANjIXN=r+B9@p6I^@V?1Kj&N_j-})C ze{k!0^g3C@rlwB6pcgrN7$_+!dN4?mo~5JnVB!p4`}RO5Zk#Xr+V%wGajFAWCv81F zZ)DzN*R3*DAxHsmojhr}q@;*An!47u;40?# z+MT-R(tw4(`yY99am~7iZ6R&|U|J`cow)AQB&Mv)I`@}kYdqs4*Yxg4Lg5XSH{S`D zFfoN$suRz*;Vm~lWFkJJK#!!;%iXQ4xG*8efIy-=a^cvB;;(rbhA1m3KlzXa)+F;~ z)@}L8$;pzc@w)nY@#=-(UNfLd2X{ah%b?sf@8^CHIaE-MPXGX}_GSpkhxBa>6JU{+ zmJa!SOvA#)7C{jNxojsi{cAX$7q_O64ZJQBJ+AM8aOEyZJRC%HzEmLC*2TyBYidJ!aqNP0luut%? zxMsF6dD_Hj)5@9)seThbhY(#tixo=7Z2t5YD}&f^Ji-bcM=lcKE&omtjS8)Dno@J~ z%=)u6KQRXf6dHPZ9J8pr@cxGn zer1jISn4%%x6$KM7Id5-P3O<^T<=@U0ki48aMk_Y-Pnmgqnslnp=UHP5}!j`)!1=S zK|R&zQA@8UJ~TZkueTt;C!mwumkn3ISWUwKfe;mSYq1u0k>DFgORR!-WWNj-QN@~x zfsF=!nqJW^zRI`xa<8^EY$?5CG%4)`Y<%P60DGvehFh$qV4X*OK3?uxJiGc_lyDCXK&E&+!t7ok8)EwSX9<8CiSEHS2{D-Mo>4@^F{wE#3x+GWd zNP0R^s7^&1t{J6SJi_Tpb7*oho}66Nwf2QOh%&vH5+cL}do z`<%{;1wcdqwxsL+Afu98JiXawDk^?9WMTP{&vf;~zmaCo*P1C*vW29zygyohrd|Tk zw!h91Csnj8syO+iNWx4D6e*C%|8&4JXA6}OH&K|vP2moaGqv)D*BS9O{otYO;Su|x zx*-ikIra1M^#&og_L>y~L5j7&^~yR5ZI7#UT%{sFzu=p3$;ltdCnJ0O@xNWc9zW7;zA zPe}P8F`b8mPWNX=2U;qt;oVDKZ|F1)Ls&%*P0K&f<~RNNg6QnGPxs`)E>sSTFPBPE zM}k=@!AF16o&t;0Pyn&Mm8M@blv^GF145HZ>%H#OTbN`556$%PB7E>^L8?X;2Q|XA zLyrztmfEqKSkVN+pm*kD!`hco>Lg<0%UTD04Gn(}4}}JWqJ%u}sWMIa0;-*-jtdJw zEf+z}ha7B5dcl6}{MIu9^8kPakdOf>nGbZqDd|ZSU2m@k5AsPl%b`3=_~f)L1t7Ea zEdGIY)yKreY+}8eU@{8_2j$mqNpc|$fQ0;{_BCu#x8B2KP>k7*Unx-PLw@=I`;6He zjZ4qaU)UhKZ#0+xzOgZ!aBY_-Q@l`%0e6n1M_0%f+cEQlQ2A}8!iJjs`pkd>hTR9f zXnjk%1(gO^hDHP766e&JZz{IYtiOSrhPj8ixfr-u8D^?tQm@0AjC8coIVGraUGpO( zednInnH-ZTlf>a!L_Fr z{Y0jqk67R{B%}4z!`^K}g$85!xepRR1#q0luuWQfyL>xp`zcBRK*lP)Y@t5%nm{$8nMb(czdE1K_5}dFj#^cNc zh8j>I^9}`=Sx+~_NxM_nj_S@;9;4K~MsCa~hxp{cRGZPb0cvszoKapE_s{M@~UUz&GzCX{H?0Fpl z`X5@z`+q9&(sNP(qNV^Nhc(G;6nX--S8GctQn7L-kNN7u<@=FbX}9p;9{l?(>^+K& zcGcYf$P^7#?x8_<3syhIf52wiQzdav%F_dzRp43IKvB2p(X1?bw&hN+$fqY3r;RSy z-(w0r7M$<5{iuCTez6I8%E;VE1$;YkRN!GA^E_ zEix!lD3g%SB{K(eWn&aXe~t4N7C8S^N|Bd=3?j>pCQ@gp*Wb!p@;c;e`J?aQnds@U zTr@m5sMzLxsxSd-CDwH#ixYtmUJU-$Rd{os2{$hI6xT97*@0NB=^0l-(@iCSIQ?c- z&fUjr8q|1Lq-z=w;qOKA3u^mWs34Gv&prM1ong%$pAts|doe zok+(fBPM=SJnsr>aI zIY(QhquHyoQnqX$=^zzGqdUnVB5;qUK#RW6_>{SZ68*!MjUJsbhbvQA(5V=9Z(Iom z&X@o4Qob%n*iT%?rj5OKq~hd}frDw2-~nD}{l;Dt3GVprgg!q$LBcCJM+SxC&FW>j zk#H!6?0NAO7SUUh`J8XAJXfCL`u=cMSvj5J<1xJ(+6cjs?l#TA@4fVF7ba?tmiLi zgmuHpV3#|2^O^GyH!rh1lkw|Empwl6*VZDt_1`XlR%Vou)-7HEHl&*INqAt3p;-(C zE?6$~yA4Kxe2dHJ^0)Ug-~IoMOcxpk%Tu_dP)<4IDqFpVg@u{6d7rPNCrM>t5b8PK z+G_>d0R0e+?}e&5kqfzRg&t(GDcbW=|IQ<>_y34FJEI>&Kb`BhcYTqarZw)+p`WCW z+4zGcpY4~PPfw^d-l+Z=sTCd6Sg!rx48XIxN(1qFzKt|JG#m$?^0XLx9h!RDJ~^_-zT-Zks3L|lpasUIMqQ&I zMY`uEYg{DgtUKoY{`p22VKK`Gn@aq z2zn4bt5yg~$w(shK@N8M@rX%i>1Z}N$WZom?6=G?7 z&^`3afN8|V#Y*98et<~)4 z_v37abyhBuCY`U}6E_Y$c)^buW0%8sv<2m&nYf$Hk1t`ENy8JspRNGJ&COoex%z6V zqvD-s?s?L&uV_nOLVs#%acSS${*T|A5zzY% zda&)Jr-OBFcc`x|vnVn)q={>(&d1a<#~z$+m(w)pg_%dnbK>0V-PzNF?$5zu3E@#r~Fix9N%Yt4*j0X*b_xTL$GU0ux( zCuP4uD?oCErY?0hmW3`=`;l_t_(yS>QsAz z>8eBNu;jT7w&FeK6j+GCJx=O@iB#bNf8)D99l)KU#boCbg*}Q zZgadp`#5bP8SUi5rF2z4PGNMLc4Yv5)DS7#xySNq>bpB#*;;L_=PJ(q{FD_isVcg} zjDHp7GF>~xN|&k-kZm-bI^YS9O^2(E?Q9m>dUuik^I;j1)A?+U>=8%4W?wDIh=NcJ z?#Z1$$Gvd-+0EP|Kf;aJ@=8O)sSKpO_abRy{mz*yWIt1B|Ix-@NkjlKt<`(8PISU_ zJc~b1apBk4wta3O^&=U2##oPSAl+mx>GA%`OC@2twLgSvY>e4_rKxHslCg*>=-*`b z9K`J=icY^;*Nc99BVqB`S>x?Dt(9h_n2T4Pha$*-J=%IxGv)rk}k$r&2nH`AwGZwMgigk(if0$n0)BqqEM_2ltzY-*|@q*+{Lf`Fp^HEo|{G4^jP5 zGx~R&vCp#J+YwdF715~cTjuCzCtV38`4W+ZwXDn)jH|2V>C}BRq>+xvRC=*fS>+y6 zg_FIo7-1?w1ot-s^w}3XMRD<4s1sB4)82T-ZBGoXpfFtbF1e!S)}3VLUD88@pC;Nw=Ek&$9DywoZ+ zv*zy~(KHeEnpdSW}jl`nVyugzp!k~ns z%_+dI?fYy51??53nFhvGt|Ka~iG7=~27z1aZR5^oo6p}kRwH9Ji1rA14mV-J zEnf3EKh4N!RbOlODVh+8XXYr$wU_9NKw5+O2);ygTS-6_r>toie={me_J~ii#p@5f z-k;pyIGI(=rLTySM3qG_fXLI2zj+O-WZMo63{CY%{(_HQh-ooUhdYC3GAv#C>9Q|DbT1Ov!I=<+cQ_DX)~G5?a0vJW|b$M zd!I2|au2;ZF@ZXtqbJspt`#MlpQIh`TC2JikpM%2-w?HNOidjfjOV*kP*NGe91p3M za*j!BW0OFes||tq>*pWC)v3m7CV~BhK_LF7zZ&Hsu3;)1DFP4sBX~aqM23|+s=62x zHU`|!V3K2dbe@8{y>_Y{OjL4{oe8Pem!NTOtbkr z*_EJ}k`vcF12$mwfgdRV#;9zP8&NNok`HkEF(2QZqEKvbvsk-*r(P)AS?|5p_P8@? zVMkSB_6?>-cP#Dvc(F)PSD<9FzneHmARavZG}!sN>eBsS(cbgHo5cKe#$!=2o#Oeb zC|SFw>#&|F`h_sS*hNsRQ51icyZQ<%mum)K)THm(t$9#be?~fyjYF)|{d5d-8M<*( zO{rup>;=aHhsJ`0z|GC-{oToY`byXjeky#0G(H`aS=B-RIttK^hvbx`2MpS zjbyjX71xqf-M-Z5T;1$O!@^&#xtN{N%W=kE ze!<)3-ZdFg?uouRTyFpP`-YODX^T*qCL<;Guhg9K+gF@7>OaJM-XY*#of@Y#(68UW z3HVJb`a!0yD{b450H2k1$5X+n{L*xmFtHvx7+@8KYAXv=8yFINP4@_Ickrvv zmgpIYMZeB!b}CL(CP?ht99jbsfHfZ^29-Ri^fWYTL-%3_N`y{$jVmLhfDSQp`{|e9rX_q0-OoII#xp{TpZZ%BTFgAgKiGY z9j>9u5NY}XLN1;p9_wYdDcH>Xu?A%0RvReLQXTqBuYD5>l;HotktM^U*hmpD9 zi`EocI}JUUZ(4J^F%EDPQ)LaqIvrK=0gqkuu!A4 zP3Xgiul#t!OFC(@adGjG^;eu|Q`pT26SZ4j5@ol83vqz}`m%<1O|fLAzT-|YXC>3U zpVrzWscZSGG4|5H<%+UVEfu1r(M+sVJ)bX4Cp8-l<lb++*%!`|RLWGiE)Xlb;EZ#fh1V+e5ICn|_wJ->>K?(!7rU*88-t z3QZj~C~Yt>CUHnr^NXS8IR=lJ^ro9W@O`o43?VJAs4&|pRsWb;trrX{TjNoquM}*v zjiB}Nab{N4GDox@@--q`PfP~?ZLqQRVsCqD=)G(lc+etj#NmAw34fc1pYta#(MF7? zq7q35l|T5C5Dn^JFRAdqx83MF$jDu{2Q=+BxoJ|}NnGY=Biq{sC+{4)o(LQW*irSW zDK6-vAY-`(JMZ45v2jj^u?qIM-#KmHOL8%Js&iIWR;}*%zP6@gkO}yVkJ`)H;?$@! zz=47uRFMF=U`dCTAkSv=(Nimu4RYZxbFY2h*b5jh-g6}}PC32f3_4qNg=$Hcl-etd z*U##c+hxxJ15=6mySmRWmU%)0f18ss2RXXGQu^$sN2fTl=fs^U(gc}ilYj8Lg&RyE z*{5Il=HNe&?E`L8WoPmYvs$ai{4GL;Ut^M!iXvYqVqdHIDK%MQ`qy6-w;lYUO3UOv z_O7NX^?|i>iImn0#$&(7vUzjXRz*@-nHGKWKvuOh$MZ_hilPrv`ebWk9Zbhq%gy)!z^7%lJTvAl1sw&PfH#C~!- z2@lt#FFHFmA^pn8(gEP()8gT25VG>d>2>R@7#4<;a$(1duivh+3|FHsQZi~Hdx5&-`}dZsT3ndFvZD8@Q)}*q-?AhnN2Hycu3ZiD zzVsFdd{ZxtkZ%Amr(t4T(mY#Mc;15JL?DL#{slt({KWnfKgIu52<_6tT+Rj!ih-9@ zJ{#p30L2aGYpoS`RaECfKCh6++!5JyJZv6K%9AWk&!?NXHlO3y?&9E(x^PZt4!=EUylE@E-P#9_xI^D!${ zhJo~!cror>g^!`EIwv10yT&hOcY&(cRu-Z2ngn0Aq3IE?pG#BonkIm-D0cJZ!6Wd`jPqTna>zs)~JQJ1My|QoBhF zLxXq4XKc0>1h!%LXDs4Wp9;C_S!=I84q6aq9JPl=xex(8v7rFSxZe{{fM0f|#G3N3 zicBHDwlJsaxO+NwCFlDbU&`VIYi+uBQwV8%eY4wsmK22=Z9zjrz81!jsWIcd zf~t;cVW#b2o5#X2dXpsA{V?lGYjh}CQZ&tB0qU3M=E+IZZ%o*y-E5jXM_L17Jrrk! z=qph>-D0wC6{kEkm=wC5n{(46$DJzOpQ#_+r6NC6lZ~J~xfz?xMgfV%KJ0xD15M|D zX{R0yiIcEv&_E zVBmwJfaNhiHyoq ziX=jxj2*i>yVXx$X;P0s7LranWff_*m@@!>y?1&%1J!Ad&=Qy>*BhtgsXIVQ1Cx^9 z{4P2xJ7CHyn1Kq~dcx|O?(2S^D-(y<8yo7E*&U_oKx7aIExQq6KUbiHi0+F16HiOs2 z0V2ZpM=W(*ij1rd4A+qv-dl22+i zNVVQ1wY`mmt@8txkd2Dn45#_`L;Ox+CZPn=_J=f`BZ7P??Q8b1xqHPCc-cdoZ{g8!sMrM#l(Q^{+(q z1Mq&NQxOpWdR<c1NjhzPM3a8%7k=e6jI>hiXdJW z!>kK9UE~K{yxIu6NRGJQy-SXTuvpoe2JFy`pY!!kvPex1moFa$EXS?K%E`-*^^Sm( z$&lGW-z_tJZBf<+fSzY~tfy|sia<00_)pE6-yKoz)4pgfUBzEe64j!e!v`SmX7YT| z-6l*&Hr-U518gl75&d%hFA^OA=2gp-w3~YJ0ApGvxR7h6Nk`T{~p(#iNaY^1pPLYo%rs95Ha69 zjo0_J_iOaQ396~QaD<>UA|_&`Y*3G#;>6d;Vx>U2!oQ=1g`LrciDtz>?!YlDgi11X z3UkwAvDc2LcOV+K+n~cNqnu*QA)|^B?|!dB$;LFj?8}lusqrPgt1+ZKRD8Znvffy6;)?z7n<6K>2<9?r zwPTZIgaVQZ)anC2His0Svmh<0Wc>^b2U{jBuoo{|Uge*UCMIcmZd>3&Ccl6QdaCiP zjHXe^7Aae*d*fKCIhbgUc0cVNN>$=3|2D-a|MB^IuG8ObJ{0zl`cl1{kMA4= zSItdc7jMd7lNHb(`4>4FB1_=sj8P~SxuiR z(kjSY$?U4f8qqdHy|bhb3H;6i`J_Dm=WdqH#<4LXePqOLgFcwCFOZ(UJ0=|yrq2YX zC41K8RvIqn<-VJ=3Z4rE5Xt4M4QlV`XiPwWmBV*%Rj_<%FK1psj+W|15{83c^$HO3$1uzVfwPU?)_oBs`TmIV9byKeb)w&jXB-X!W*pVdt$) z)Z=-*x$v*k3w4HWBh)6+ zOeH50Q>GH%->%YK8IkiF?DOzkVW}#q8a$@?tdr+a_o<$Z~DDnM|0sO_j!lXCyTCgSL1hgVM`HTPgvw09s;KKXjsMPmhKr7Kutro2he5DbLy5rpRvHh^Y%Nad2~ zm47UB8a8*2x*_CBY%4;xsI!QWqPQO}d~R>=uZMfd7nc?Dlf`ciJvr`E7Rp)3eddg% zp7t5FZ|`n3vE>(y^nF+uKg^U)u;X8InCD!{u?z(1zw4vGYwqb^yDXc5- zAUW}<&lR!$r&AiLyKARONtN-{tC~q6a%#v$#3Eo}Fkb57!V$St>prpKc|_kvvEAp3Q59fkXYf z{p-YZy0G|0>!1XrOfPU26*u%ku0%E0y94r@8CFq2krVa^Cae^m3kjh6PVuIc_9wf9 zS)0k=Oc6DRvgKwULmKJbIjvbB=0{(AkXV(DMBkq^j;&72^3fuhg45hWwFs^zQerIv zd!&9<*1Gc!Z!F%2*f0Gi^QZ)pr_G`le~bQP5;vjn55rs7be!>iq&{m$EXesRRJrhV zE#Rw30ICoH>I>;Urdg=^p*2ITO=29!R@rV=fcUxMCv-9u942G0jBle zdHq?prqSsjh))**)&bg$1IUHG#n`(BH`WsphAdhMIbwFg2u7EZl=ux@o0E)>_xsJR z8{rX*YA=LxH_%9+H;ayy!sYWzpGWb%VV<#r$AylY;>Ydxhz&${l83HH?%)z?VW=bL z61}xD9?5fUI)PsO@8rPVgkin~gl4^MXLP$SH5V++rx(+&u`1{q+@@GkW8(U_7;U!H zHu0PmX7tRQcSii`G}MOFPNp3wqTH~twM*S3Z#S|aW-{wEbQ@&E_r{Yp_FfvRbOR0R z4*`-3!qnx?I!OkrVY5!h)6;P}QV97=CwLeMTd{m8ae#?)qC`b7n-RUa& zsZBc0kRmz-Zb5cXrQ~pG>`i2`%da}n4&h;m%`Ju~?Qv-pi1sPa;rQ4i$ptvY>Pnw2 z#ow=I);KQw8nxnHX1x7Qgh>oUJ&D%(HM>kI+O@M6-3Ozlt{+^c2qUDtlFQus_>Bc* zt00cxYY4;{3tj{qKMSJHy+q#(ufHas6K%v^A8M0blitA2OCPOwB3-{>(x7KCyIn5r z_Zn~K&V?3-wi$jluu8!o70=Y9G+$wNdc$Wc7!;}QglB`XkV{`p=7Vg<_p-m+;rkSE zxU>Kb!621L58C44trQlm8}e#)Ud!E^I6U`i6CXNFX1##tFhrFMS)DP%W(9kXHqDkP zp%Snz^I9KiC5sTfuWEMI8v$xQZ}oZF+uI+0=2<+^)Z5cbyRqGX{n_nW`~%Tw2Zoxu z0n7c0i{;Df;BSSrk56Yvusb*dXxdMj)O(?Ail2W3Tj&_yTu<_(KPIS!6wp{BYkF~N z^S<-CY$f!EXPkZuAn?|wE((n4zUut*$GQkuu`XPp5b+qeskY4x$bbZ^ zlzzL-)|JbW{`m$Jys|HlQrj=ak=|IbFC`}X zoDE^@uSD*dFMfm!h-4n94|fH#l~$ESAVY)cU)<-*&39l~R!i$eC}{x7ySES*EO?@cO{m`G{Z#&bjnogj`etl#VR$&w-IO;d04j!erMg{TmVg=GBBo@ z6)ojrlePG}x=Vn^WtEQ$_GkhPExH~0t$|v0>JNuJ&=*GDn|)!f>K~)shE#x?p}%iW zB$3q9*kR9Lvi|i}5xb3kdl~nUVdEErvlXH~A@C4ESy)9O>+;(Hq8YLvjO^R-A>DbJ zcaw2T7~A$D`@1)Mj1Mnu*i53f9{5wW=~5?w`lx95gFkcX5-ed*N)6tdLny8R5=A?{ z@zZJh2}#$Ez~+gFkcO0uyyrysiZX(RZ=R3f!{DikffON_h%M1lUkW<{Gv&z-``R;>TS;8PR@_BcbT>5 z+Je~}l(YHYZn3@L`_9DB^W7$Awo{KCp6-I7Zat?fk=D)!99fJ)^GU#?wZ~W+Bj*Rx z#hgy)u%4tABI@T6)Oo+SSyxlV9R-x3ruW0W)=eRir6oTyT@bXp11Y0p^6OuIeB;P& ze&=_m&E4AST#xGw>T?lOE;^6pj{NoJVPD+8HRCH3JPp)l0YOE1L6CF?0Bet4lx+^{ zqdR0EnpwA6|6_9H8s?{T&@D{Q!=y;2)ZE)!!P7a_j3`IeaMrur#|&fCOp*@*-MUX7 z-!$7zs~040nv6MYHhUamrAT~BR50yPtdrVO%rxU8Zni!`cFj4^9xQRc6Upu7D*v=B zPv|T9McB!MlocM{fWqnfkErdBu`wv8K*EhMNq3a?!feIMC;h~(3d1V8j51mk#$JO& zZq$!&9OinDRV_FpfEry3x^lQ!Hwj!RN-k-In~y=KC+_{q3zmh35ft$QVqpErD(nke z1PMyOY-Gy0#HOcU@Ea!7LL>9*x9pWuuDLEt8{V7D^brweWsOZ`@z{fK;;aSzGfKuO zXFM5ocMh_lklOuw%z$*T{&`rW)U2>hG~qRXyZ87-k~Uff{YZsOa$Uq_iqt&UDs%~) zjvs~h-6or;fZ6|_X>u!icRM~8*@xawXI%Vhp(s5+WEAj6X6nR#B%sbzdQ+-%c>!po z_74~a74@nym5~^s!!tGZ61{d23T<1{zMd{sRou^yL;IMPQIim8n5-UWwAj=ac=jJ4 zs}<F!Foxk7-A6VE5dBzs&E218kMNxXc5I!De5PDa!Z+@ws?!oX1Rl z`uJrSp-fLF+?t?Xp!cKCL6cHaOZHup^a4&7sdrs@N_D-IyfBjncYIh!9{D zDdo=nd|A3bho7yJ&QtgbQ&!;qnoyIdgi#msE`IkD9XMXoRg^Do0s|jcw1mvBnx;>@ zps7$fm$_%gJhM?t@Yu86pi1!*zkX0U(Y5Cb=%02-p!ite5;~3rf|iy}-!nxZpY!>8 zCtn?LJACvI+c9Kt=sWp~%>tWo#27w`2Z|A}`Q-%^CilnZwRXjQ91fHDr7@2xQNVmu zfr!sMi%~a!W^EmAKR2Gk)i`B=ZRfOqtpit4)_#G!S|F$C;#)+;Bp>P7II^nst=vPsXMhDBXCNvhrr z^C|utXV;-6LIPTbKq>{SDw&*?voqFX>)`@SaK~_9``nM ziNO4Lwi2amxpsm`sgZ|a46xu5rJDc-{vkjr1SztmYm+4fYt93x+vkx zz|VZHN&B_S{c7F2Uu8TB?^KGTF*kk^$iNAK0LmZua&kxJSsnlJRFYr4KHDKwQdQ&B zUYFtmsVoLN@=9{RjZT{wG+6H;3IBn9WNooM+eg1pTU<#AkAcl3B$qs>?qBHyj;E>= z%?=jn$E<|?h$iGXzZYw@`$PPu?Pn67ct@3YFUSlt8pp3NHqto)Fn`E0O9@5&c|#!N za7MH{uQ0r=zjq6|pfQ7o9*ao9d5)%T>B4H9&IHv-7b#M`%V6FVl_h6<4rhtjUaV~E z#>E$W;GO-bZ6MH10ak{=!9-N(l}}xDD=S4J_k&ypTg{`Gk%YsksX_ndg5Flg#~TGK z+S^9igkhTSK8UVmlwQXzMOZ$~N<^fm%c)gpW693FHH(m1(s&0AunH8sMlKq+P|abP zinTNX+mpw64o`$${I8vDes}F-Uwd19$!_;}eO(c83a51Y{ex^5gTQ zgW8oI%SzfFO;8Tg6%#v1_mURS+@3d0n*bH#N}I7e1o*z(s<$`?u~D&OecWvJ%L#mf zez$8-%=n!WR&5n;vk5=xD-7_}kUEpJs zRyt|2BsKOgK+oBFzvi2JtV9|3;en{Q;PCKGPgJNyckSI#_c=8w5q4C-t@PB*F>b2m zifT?oV(eO^9)SsFp~$)bHQ7i$tnfdAsKr>~NX8(|LU z{&9A*%`L)6tAE&ei8;nh$RD)&_ix%ZMNHq}BVnQR=Bo5K*kspQ+sua}|BE};1zb8@ zAg&mS#glT&F z5IQnlRH+a>_w=#H=KC9jnR65&FK2IoGIAvl%vBQlxelZJj*Y(XDl&;4B~*&VR)}<@m9|*9jF0QTe5|Yy0T}wzvcQ?{V z=fdv0?>Csau9-P!&bja3`R>0etx=a+n^fe%#g8{!OJy`sEZS;0gR$?p&l z7JQ(>LyYu99cFw_ZxfB3jnWeP{ct&u;S@Inc(I*IlJ4lh6*g|FHi(FLwehZ;-(<7V z_#s`D?C6!RR-PQlt z4~mrZK5kduhumnNB5@DlcjR`&qoi#QFcJ+&k9CN+mowR%>u%L-memMDN&wT>%`wSQ zuRlPtA?U%+XvD(!vn@pnJM=^KvvDe7mSpjhu&Sz;6$=c7d^I<}?|@EX`DrFIHJ%e4 zNI_X)*!OH@KEBzi7n2mwTlZ)dq4lAtG)XdpCkbX=MBA4_N9U&UZs4n>`oUh((Or+2 zBzoETkI35*FV5p%*`1qWtQMI0Ht|9NKFljK6j!mcQ$Q^dBn#r65nS})bc zPCf?zk~Q%)mr<+If$!Ji0pArGu zi?vO&xJmvf-(oO=GP3Dv zN8b9sIdMzeyRye@Sbjzr*kZ#1%FmAZ#;@pPt3f|4a_`T!mF|M2_n2Oh|l^a(0=0-({qe^=rgE{ z4W@Wyip@9*_Ed^AAd=4OMrNZQCwL*Nn~QDV!Ft?!zMDZK0?-M2*vez(O~W?RF26e5 zL9Q!a%0OSIPgc7g-GG&<6AilnAwg|Gub9{^H~zTqWiG_0o}oEbBZ%Pq2_gm31K?EvU!T?r<$o~>6(p871sUN@7~D=7}7-q zBi<%KlycfJ%TIE|-}MHc;S{gXi$mB!puZizwAm#A>Igk|DqNSQkol#^N== z)$fmHr~unm#wd=cB(8f_!1e>__77jA#|Hs%&pTzEmzi&}Kab{$_4zJC0-WJVgmGU} z+e`6hKId6ZH1-F-J+Yq{a1Bn&J{+Yy7Jn%HPK>ukP{ww_;x*?*^QTIh3M0r0R_%98 zB9CBz9j=j5CY%a`IcZc)bRYS>d^t)PQMr@5`TL;*{jo+AvqTjft0I{1>r;JnPYGNr zOZ%E(s#t*r7?SrSk?gyVs+wkAQ0Wc@Tx7V#h4a_rLpXny0Caz5swDt^4K-8eHJ?e$ zvjM$Lx5v0LP?~#4ReZQHmUo>=^ftC{EPGm56|usuZDI}?_SNoy@)?eP_82nnET zx=K-y(|L6r@<~q2kzc*K@U`oq&IPvgLxt& zLvviS85gli34PFIIo)KMxS~_~T@M<1G#PjHLQLG#88nj~goLn-rPItTX({?9P7FJf zHbx2r`41TYKYF}pyABC+utK=E)tsmh1#9L@yTi^o&QOIkU6ZJpUfX0==*@kA_&clQ z3=*&`3x_jt^1~9V=YFz|^W}0ShM~EIJA~)=07!e3t1FD`Xrg%LXM;msqn~cNOu@=O zFOp}#4LM=m$Iq;U95D$$iF{hgg%>=Ln;3Mt0{{2!)rO<3C=3aa6rQE?oy1Nixz)ir z@p4nxaQE3;4KtLF`BJEKH|eWOI3y<-ZHOmUnaJFJ2Q|Fm($vEF?RXU!VxwumV;=r! zL5xJvErj?m%hyRRFW$UN7eovoK2vi#{23X@et@X8;^NX6ei6B!r z-=Y}ASpSgV6*xfwIwYei$}nXsMomDs?f(1OH|O?{W_QZdtv{IZ$Z-SyJQGjJMFoKNN^<>N_PJNwgYqxy$Dn{7cJxx*8I6o@L;;_EMizhDV zbXgAdSZ*HmFaSJrf+R3f02I8h6rp3nD>WNdT)gh{m-b7DzE&$mnnn}83%ZC`ubBeN z{_sf7tDDW#5#P%1Nt}*qulzM_(BUmCl#kiO0S4~SUtsVMgq-Byia3qhll*9=_#g4e z4Q=T_yQ4>DlDI-Ef784BzOz4{(A6F8?&*f`P2#;FfBEGx2kz!Q$wHv74Dcza(6&D& zK9x}SC)wqax9OCfh32F`C4Qf7k>MmLN!U|-hqXa&^RTjB?(*82DF1j}*hJ_w$*!aB zE>bcr;EUA1tL?wkuRG9ZVym(b-xl%N&rs6TFAtP2wRaM-Lz7OKbf?)(KK8O?HvAKH zVOgRW4)XZ5AUsXE17%FBPLA|VQ6RuNic^o;;;Gvr`JWU*1l#2vA!EWfLadoj{2*pe zUG<6I%f_k{wEP19A19Q&J(AJe=I)CumOcJ-w2`HV^6DEgEsl-=*yaDD>!s#@lcPfi zsJ_JkHsUsMpI46)0vw3DNrvmo@4W-s3yzgulz^(EJVBygP} z#-%x8)n@XJ@Y0#~v(vne3RDtRL6%(HrG)iRe=cO8dhP{zT9R(pymJj&6M7^br7;5OEKdgR#2~z_J%}6 zndEs}Wb1c%5H#W(>o6h#(wes>h+$LH#)3C1Bl_Ghs)_hD)^Ay}iRs}UDQ&G3swNq4DbUH`5_?-EllH2D@W^327%yg-5^kr{!MsfI!jI6bE z`ScGkAjb}&^RRo8G-#D1={O&zFL!@VXWUHQ!I`OFYqcWG8W!^S%izol ze?WFCQD-ZWn)7J3QAQIqjZKNdT4fq|jI+LW&cXSx{i)As_xpRw+RaaxB~$ZACdLNw zWyZig*DoW-UfCE)vJ1YBer$|efG@pUyx^6|b*Gc5$=klG6(EaDP%4+JzAx{y7%OtcwXX6hp!WMZ%=r)K~i&bT^^4$wM*BuV_s`}%DApGO||{E zV46g~>3lqZ^#vP|Ad~5KatXi1ixQ=^yR0q0Q2%kP5GV~??{rawU+zy3d<=U65IWmc zP?=pKWCd3*dAg`a_p|&1q$JVmQXZnDjB>-X>e-)nvZn*fLUj=r6w50)ZFk~Sdv}Q5 z0yXwXVb~@{27D`bmmaXi{g$E(N8Zpl&Ns7#H7y|dT-%UO1%RnapRE$Jr%Edg{1iy1 zu=TaI8W?FbKW2H?6Zax@VDLU=z?fSmWgCYovx9PAvY!vcJzm%X$81zP+(@D6}jppk5u z3cD1tP-M;eU6ePJeca^aGQ2F%l;3M9YvQR8Zh>7EA?)@PFZ17WsTv9ya7l;06b2zw zbv*jQH+QK&7gQnq=LR$D_&ppb)xtOV8woFuXbHY1{_uFTu;^|Oxft#ew|~v%;$ZU7 z@TcG}qGzF6GJ8YTg!u8Q@1tN2>ubC%G&*D6kH-w=Y<*eMBwBm>3)bg;N6C5Zdhe%)FX&+{qX za$w^)tN36v<}oK1%+r&T3^d&)+IPDfy;8_Jsv@6HOAIP%_6R+HK+;uJUbSYCNu?P4 z>{LNXGA&GLpq0~#ozpXfi`VUOGLzWQOe3bISB7!oC zwu_Lke6*1Kmk5n%WVn4}6s+hUT_U2ofE##QE_^F%2;UJf<==O|Ja~bH-4GK4ekju< z5-6T2ae89CFwYY*Jf|nz+`dQI(Jl_x2Adu!H?-lhta1VVTFsvIBp|5Z-742BYQ#2< z83-CV3~;yI@J~#Bp<)KZnz38>wL!s*Sc7UnB{0X??z$yBBB1w2J7C>|riYZXM;Q-K zyUtDGe@IhZdeSFQMRegaUH{LZAn5KvrpQ_}BnwV9?OdffZIs8vAAc!;VjP zV&3C97L9Xr-v2*O0c}f^gSciUx~DI-)WQaNIf-^Qzj;mamX`@HmW#oD{0e>f_LU(8 z1Mc@|ImRDL=EXL+fqg8=%eNkxT6~4+K%myhBEh2*Jqj5ued83os|`1_)~MJqO2sAs zlb}#j<2B$jPasGWtMnVOeu+vB{PiuTD$vre!c*gOxT~l6c?M3B;2&p} ziKu@e3H*}GJxR_#<`$jQ4(6&8_W(dl`}y`8yxW_xBN8(J$ZRPgod{Hk)Bo5XS>!4W zB&lQ16o5z;Y@h1k`?31Gy`3_mf&`*+vCUgQU{CO*Pz@^ck$hVAPW89^PYL{9M1GA6 zgP{5!&&HT%7SGZijB-B`>yo}@KGuuOZz#fCn$EA{FkAi*Iug7J6~y0a*r;0nu_APF zSDL!0be~81mc>w-c_Q(z*wTZ#e@aREw#lc3JJz#rTC9$e2mB*DUrsqCYF4?M)GB1X z6#uA92smZjk3<8<{=oZTSZ%8G$CpI$RKPWgTH8A3b;av`$8Q_tqNDd7CUO z3KAA*)jnkBJcC;pAt`=0&iVzYDLd3d11(1sQOuTb)yZ*zWgLAu&k#z@)l<@ zW4x`hIf*K5ApSGMYSXP{B=Fy&Q@$$9}s827Eg7q0-quRsM~rz-_o5-6j9@g<5t z0A5_+082&GCvy^`3Tye>w)jISwI6oi7Or&@lbVVfJ7K-HAC4bStSP zlB-#GE|*RS`wTInq? z>cECQxh}XLa7=#~Os}%te+5 zK=lh$a@U2Z(#>c8S4UfhqiQP2Iw{i}e3CDsBfVqnGULM#mufl)N59y<3{~1x5rW_1 zk8vu^8&VdQ`F|82a_PDaSU8=#8|lBWBZwko`ZxBn59<{YuOJqPH}rPU^t@*ta{4pd zmP#^gjQ11rLGYjxPkP{7=0k)}0*l)Q}zA_CsForvkAXcX-@ByB-zT1Up`3@k&aS zQRu6n_0r|j;jZdoCiYu~p1Ub+L0Hhj=$toGtk*7HkqUb1{R|V2IqF$&*wo;MEC^xm zw|?h#ikz?lD><>=Y18BbHOeL)=D_Eiv{sgu`Tv&v^_1>aK5FdT6RgtWo}>km0^A>T zM+5XZ2~|UVIRMNDU=(f zL<5D#GfIN_GKGrE?S}m_ydE~==4zz9weE(WAfwbGBxF9F^WXM2@g} zhaq4`w9Q*OeI8r%;-Y125f2nJj5#f~DBSlK-pi6Q`C285Dx6mrk5NVdF==UOP4|$;s*3#vwqxG0fd;V{zgPZ)MS@ECzYAW0<2yF@wYMoAZ^7ozwE9Q7e9AY{$ZXhn7gA$SiBM6V6^vQi;k9IBija(C^ zBrLu^D8ANwQRppbqgVV2<0_l=al&v+OX=5@ASXFZ{Sw7^L&y)AG5bMERSkr?5{~L} z^)_KI!RnSfZYOG$n2mI22G~@>LF$;<+CI6v@8{YlK8u=)!ZBF!LUjcwLKWgN8(GJ>VFAT&J0RzuO0 z(x1NacjA^@@J^M-^elqO+t!fQCjH^;qZuRCM*dV#Z%TPVmw=f#55F&~G;$@m<>~FB zM(f>ZknBT#WA!NHxWwzo@$qM|mj@C|!W6K#gdA32mugUg8_@<%0R^xH0aQuBznX%BgAZB=?DAj#E`UlYXHYRERFjD< zc&l@Nqn0x3F0pIqiu;}h+4eyzSDBg;etV9mB_T+Md;J}7qJi0oHZNSU5R%NCQ~=YD}G(r|LqA*d6|h zateF{iMUORPagmdKk<+{%8w2vy&5-^Y!{gOhaZ@m2|TE((18Ol+@OU=$-F=W*@+taMZ zEY=*2TT&+bcJQ{7t6Gl#*=xy)u1Z&tSpx#Qhbh)8fUS>KbLt7rfUvubXvGMnrQbrYQHk%gkT-_FVrQuq?#SaBZ z(%&kBtDm#2bp)(FAxoVIR}-A?$lj@P{7ol}F;(S-)o`pi$RFq)w7E#;9KH&EC39Xc zDRuFVwn>>O(0YmA0(DXRfiq6O3xJtf=)mm-ofIIkZv}v`)=H62s(_&7=?9B9R#v0$ zp+}}c6F+pIkO?5k5*Oj8s->1g=T>#ZSNqhS=iFg)9-MpHsuF1(%$a_Z!_6IakrRp9RY%Sbb!aBuVZ;($jm1iNN?l2SoMuaK}f? zjkXIwFXyy)a(Osk`%!X9$9}6PG&BwI>9ssPU1la&hsXRLtlRfTEBySc@H|Ck!%FEE zLqe`06LHFv0)Tjoe1-YcGPdHCkf3<7kHhxN_??A(&nuZbTw_uAEoZ6822~ik#yPt1 zN_-8ft@!{OUsv-jop8e~Rjp zGK-R;79y{3=*2t_ZtpG+oxQT~k^4oAN;t{RbF{nXD16w)ub=FNsAr-=xO1`xHuie3t$ z@iDdsN(zsF5QXtgckEmA1lv&;TaXC#TxVfSFr!CvSYGR7)4XdkWD4A$x6Zg8Xc3rC zlL`lPIQzgKvR#}&go1H_^u$b*Q8~I$;12FP1EPPCe7|xTyG+6c0&|3LGUt3LD6pQ9 z3Vj{jemLA&I8ze-S9-rN74LU-Vs$#VSr*Z_uK*EWOia2%?4hM6W(8$s<>l#VEH5BL-plWA@PiqQ4j-g7!~qr1#a4YJZ13L7mPkEhx=c)>`q|5!0YE2 zLn&aoI6AkXroX?-E9gqo&^{RNM;85+Lq=XLn`RV`JGv#0pE9IY29a!;q zl=gCr-?tG^3_BpLBBb3yen?zT@=gvN-P4yH_)OxP@kQf_Q5wkESmeQ{qT!7{dhvw+&K~llPVl=7tELz1%Xu%L8Ku{lc7pG7X)j2(yKOj4r zno+t4I2cl?rdcR_9nC?=CS9bGR85 zviL~O%(G_as<46SIP3_n1}NWOux7paggkWblw$RB+1Y=rP8+oN4$*$Ms|`;Q47l5` ztgJNiXt=wpo8)LT@OKOSFJ-!Ih#!6*D zxjipKV_fcQ&7{5F7c-m0UfeUCW4u@|^0FD7eE)&^ujrjH_RS@2WmD?5)q@4GKI>F4 zuc>dDjKVd{Bb+20QtjE~hh7fQaUzTQSAE7FR#hUw&FPD=L))K!*}tMdTtrgrKYw1W zOU}eiX^E~Rsi0vvCZzQPvBg+$cPI)IleE;?j7?`um;L5OoPWr?IomdUhOH_5B|14V z^YXcS+`;Q7e}xA(gn(%Z(5c5~XhcV7FqDt)LCesPi`k!&Jdx?GkYNo1Wt-bA*j=rG z!kve~gjxrm{97z7%PX+RjK0>@@hvY0NUwdtVkh50+#YyA`64yK6sy zCLp0e4DiI)+SogI*rQq9KBi-VoL)^!AmzaQLGWQ3q!Dn_v9?sW6ERQ#+u_ZfnhR}B3c1{=NXCaZp6v<6?fRoSdkfCgNe4@3M(!1V z$_aSx)wZ8|?b3-b3NE8?xedn)3A$b;SO!ip%ba~98#`LTU$q-1mgG9toE}x0FeRKO zW6|+B>}5Td`j|&$XTSeK@lz0%AO0TVg@X_IQaiGr$KkRy$k6cja^Z#v;rQVrUVGfa z*$U>?;AXY6(?J-+%%7#%OO5Co-f#%O!wr$+U`}fJq3{N-fv*srdHT(3wQ)Pco_l;Z zE_}D|%M?)-Y<`cVH*G-k+wU^0xBc}QfC9Lc%%7#|Tf_en^&8jHnY=LaXV38gjkas+ zxw_-lsf>Sn*CYh?r808{OPG~`1$Km)yz+#bSP+gO(I>Z#o<-x-fmf1J=%Y)TgNEH( zYPuzlZN%v*v0(CO3zgP7nD8GlFUwedOyi3=uhBO0X0Jmx>Fb^B$iCOC;Gg&hBmrFE zaM_E=x>s1ZRF^?8oE6=r3IPmgOWqLc28HSeZjR7fe68VqTRau?{+{!CXIjecb42d9 z=kCK1F1cfb_g>Dp+jYif_ulNYq7LBg@9U!#G~NX-wL?Sf-1tML*9FI$uV*3!@GU`Ku6|t) zWMEocw!Si)owP+#w(;)a!8)wi#>$Wd^G`VlVWSVtt|huU%tmp{{yTnbAbj948!JQ= zGp<(Jaoci+PoJ+vo|<}#Us1Y3IQ{MCF5hb|J^%kM{)l^nyD_(h5v|95758TWdk|{H zg5~D=dyVST97LT2bK;b8$a5UQd{zQipBts0Ha(v8l(KHFO`5bk2To3*)(77sV|+Tm zDE?gozG{YVLPEcP&nD>`-qTHkRViUHha(-9*894&tv6Qv_3DYgaE{?0&gk?*Ajtcx zW#6Nm&(x-!I+?w_k`G#zR|yfA;J9t?T2`9CJ-NbN*!9{e0XZUmlIC{JzDJ|7-M&a< zaId?{O!A>ihhkN^6a_1rQpIOGf=lLRWUtqYN31LapL0z8$hljx?24a>1T*7<*X(Cp z-J;N2H;1Rjoyj0(G8!kbqvT$fcfkoUuo0G_r3CSknPe*`lb@5LX1~Z`t^-GiLyAXS zW-!0p19*8NsJ`n@7+?zbUzpE;n`oq?qa4sFmk{vv#*&w*sQKNsb6jj(;K`H6e$TRS zA@PJ9901`t#x<@Z8GSHH@Ubskbv zq%n|py;=&V=Z{9Oz89o)X|$`*>2fjAmW}=}(**~P5oi$Fh4*BB{{=e4*QjCJYaaEq zE|FP_=V#<_w0(hxZov~)2Hm}{Z~xHo-L>_9fjUf*$3A1O+-*k`man%4cOxy49U_3Az%cBJ)%HS;zC?62dk*fD z7_1C9wQi8p1n`3ARYfs+4-44~O#J>eDk^^Yg8%x$l4^uPR`EF7!*X`%V4I>04 zKEXhm%uW8HkrA#t>BeLvmXIt@jrf~BlHpciBjA>BlUPB?zoroHXJ5wDHMI3 z=8xwY$G~+C%MRXmh50dnEZc(9T^!m!S9TN!e!q{&)BdS!+%KCuDoclUeZ}}Im1uQ@ z3itNY>Z&{>1EO+Z&!wlCWR7YmTo$jUeh$9a{)%Wb^;<0R7m{^C&2+_<7e*=v{tH`} zV?D?A1zRp!4qU%p$q{|wxLIQ#`^7#8=v_Pvkez(^Yo8Sc5oj^m?kZErAAfPeYvCh~teL@*xDp{BQyyWhS*Ycmja%V)7 zWSq^#RVW1EekXTcIkFFWI-NJ`aJ*&Yd}vhZ_E-`~j6D<%kpTZbI%?SXQy9kuPfOJZ zQBphb(2_}f3?OuX4?t{c_n`A}9Xh$iEnV%c|dY#uj($B}~)>dzIA&;Bg^ zo}k;*|3&fT?;t2IX)O2>uN#dZoT(Z?wtAFqqGEVS;ogiihdOE7VmN)3dj6+2+vX0i zpxjQ!z}|I4lfG}q{>~JxB$cJMtgg`3`rOQ#df&pte=_%AaH zdz%9OHDbwNOvsmY2_K3Rmf7irB29dUViSL=hni-^>W<_RLSf)6TqHW1v-hDi?me)% zE+B`~Y-MUbzgxkXW*-rnqh+TXD0E*kW8yT`mM&w2yqQA9mJ?A2b>@<@*U*^~qr%leN!t%PT{o_dWlIyN&>;Rzxyc>d%N&Ei+!vF zqIZU}Km9j<&ElIFs7b&s?36c^; zC``Du2`g$cxJ}Tc9?Q&02@vU*IEWD%o z{Pi*I5eb}$BQWFg$_~tokYTVDNxW+iZf%?+otpBHXRJ%T9g##mQdf&BBySUhq6slcs=@#> zx8k_RV?t;*0n!J3{}BiA7{{IeeVoo90V2EC{4AlpOu%*SHK)67I8-U81nF|@fMG~o zd6|zQ&IZZ;OpwIM{S&-<^Q~L`RF6k+?+fFq;2_f62#D!NF^I=P4+bl37?uneMZdEJ8re z(hY{D+L}JNb@J|RL+=%D1$cXBKCVDSVSFfo!ez>azpzoadwm2({_;h^sXcoP%mM|dCi>oUD@+h^Wkj1pZY=5@WqIcD< zY>Gr`0GFg)kVu~U?xm%fPM{nW(vr~XgO$!}L|ff8*3oxRUF*&0X!wdN1yo3J$DpUS zX20#K*N{`bI%z=W4r;Ywj#~2f{X1#2Wof?a{F*vlCF`D*9-k@# z_gcXLgN^aLjC(~Lnv)nT7Cecz?et5@z4jH!728qcei=Mf%%Z1DvXs_c$QA9q(GfF1 zh${!WrVbKc!zN6nSoEpH^VM0RS+6N)4XMNFoX_2)syjhHreZTG8RWMg$j!x$WF+7| z*(Qryj`kDV@Yfy&8hC>t6kBuU+B1cFs?R1ntS)(b2Pk< zWUg9N1`!Wm>CaFnyrC2|8lg)Ef|vq{f1!&rO#|SDOq;cDGtE!&F13H|lg)B))W)TR zK&iHuaBV5>bN@K~?jEn_4gN~cLVbZ{F( zZ;^u7t(?oUL5R%e90m3JY#foSi() zWd|oQN3;UA)R0q?-UWd_oRsFF(7Lm{xG*UgNrgawiD!46-QJ7Lp7y6#BK!78&4^(G zf6n!l%7kgyL|wMt)14QnQP^? zGlewbX74S}7oi=iM*m-Iz=c2jZo^O>wk7w&uSVl|v@iIfdAb0C8 zXEIK&XqAF=C|DI&vIlo(8~xLRn>%iH-|x~9t?m8ujV*whGqrvtkd_M|(@1K;XNh_~ zYqaVjKtx#Kd{D5bzU=+H%gGBnl&WGbf}}MGF#Ltio;TI^Bwi%N$p}Du|F+J6M-|Ii zc^wiMdP2VyxE~m84>ddP#XpH0BZaACayo1=mgDt7U@^~QS~am9%&#S+)7BN%tR=1J zym`Z(1kb2p!Z58Jdft$LN!7laO&Og6qpe`rb6^N0u^PdDVdJUPXpQnQi|9cpXcrSm z4NS^A{{4$rB}*bIBkne#d(>g<5DyJf8&wB)j0T_@MMT8J^4i)c4@8H#dPk0qZ|9W& ztB=oxr>1l-Fe~M)b(Y&@#;k!#H|6wWCf-CNawrG2wM_Y4p0BRGJt~WA*iS$ec&uZ# z-qf^CVe|!mk$U-AtDak*tCL0vn^EcRc??vG^d)?+lJ+q8{_+qLpdq?X9vMJde=p%M zf*yv6%Y_Kah_7Fj7UGJHacsPVi49>Yc5}e=hw~{&~Vkp7@nxcI{n!n9HI(8z|x3({Ua|=ux>Z4y-x`e zTtsR$UeKcZF{F_x#o%Y^RhdBcCavK5B1XR<%~eOy;POHuzpYgb=@$;97na0Ph4>B+1#AT>fSujgv~~ucj9)6wLklAQ>X|HKOR%bRd2h&|A-N~*@lL^!ce{vC~I%~ z*F?gfDq{ZvzcFc)bX0k4?ngP^s$$?N2QW!AD<(ka?!)Xzx7E67c=WWFqM7UAdk+TV zOuS5@(d}Ri!hA6);>d$pid++O&yB=p|j zz>!97Ff`xh*%Z1W(vumT3o^j8{CZS%E2j97y1e$pwp|uJp>1+)6nh(4z%8fwX%^3Z zrnI`H#)ZuX<9e||{0tlBYeIl{jF|KCN(Ak(cCZOW*z6~_du1ovzvYB9F+d&8Yhsmf z*LuS=d^fj`yLT|AKWokBj4Mxj$)$!xx*3}kNMJi(!eA>SvLCETs2a4=gSJN65L*I? zzy!y{nSc)9+pq%X6p1kZ+y18V}fb zUfq;+7T^qZ%RlpdnNOgCy8*(Mx%##kp#ipe2%rA^xwm)-a+>O7leXn_CS2d+l4OgerKa{yzJexW%d<_o;Gd;{u z#g+1_(mEcEf%ynxKTv3Z5CXczhMIGBLqymQVY{tmFiE|msP^c?jVehAfy~kf=2)B) zc2s}cKM7sXGO@f6Wu586c%mYv8);m9=+>jD3pZdM@>A@je^8J)xO5^nZCbT}FQCog`}nfe7T!}Tzg=VC=` zU-=#bzwxTAG+SojxrnHcI|xQi&?_f^O5VE# zzLaoK+ur$>_Droo=DQ##>wA2)YY3B*i!(nF6|O$Uy$P>1diKhsD(H1WIw3`kg$A=G z=};1ATp)Hu*%v!VvGFl19GZgTh8$Lyj{V|^V!@8_yKR|!XyAL{>bj@=ntFB1^oC9F znmRPm8ASW-P=Eu`6DBDrCMK`%A;SCV?&Qec&Q9<=yms*~B=k1g=G%Xceml-0&UnPg^vAX%tAY>O)cXkiQKt3FZw*LiOtZT$BMwy>Kn`# z>e>kvyrg)O&+rJ)@HV?J*b&Z57VgUcA5=>OO8iH%oRUXw%=aCLAeeK$_2RL_zuo~D< zR@I&GlJnHwRNf5Ma8xK~gBo~)R?8BJ&AGntm>FtxnJ$TTaYC>>$6*)83GIwNz9QLF zLs0v%F>vH@C>km=`VSkJQsgBkO1268bl*4^`rHw7b?If-H?rWW#9T0f4 z{wlLp-L}($gf{*wy(lm9K3In&0{^9x2Z_@|S`7e=`YiDf`07_FFbGS*BS1$gIq? zrfS#vN(sVngm}5}9Gr?;t>yQNsME+@`1~}c*=Aen&r9r|ym|J??Ec2|UJTC>wfBdy zg7_o))hym+o6Fy5C7^SL+4G_BKej>Y%j zIOf+c;Ysk<%I_0KzdNG|IS49kyLi5H#w>{uP{mTc4PUL?a5??6|FeFM??h&dEh6Hx z2&9xVQ}^srtmmkiboTrKb+GVwUc%PAcP5i$lYY3BXbJAfp7UeV>^6jReTK+yg-tql zirFTuLQ#5sO-)Um*Tzr(+$7T8{gA}i6%UW@wPQzlNTE;8C+M$wQ!pYB%N^~AItb#n zr|}~zHWitsF2LI%Rn{pAss*0B*=R-I`3CLb#<#G-c4xpfjAWY>EUL`GG$XB~ro1Na z5`O7gU(VP_l?J=`0`2y0c77ETdb4wlBy0}?kKx@1??#uWzeK4KCQ`pEmj=m3x~utY z)McAVxq7-&K9fOL*mh4DaAvvuNSDTA5o5QxJdC43|0qLig{S>L;F^XMW2Q?RPP6Z$ zjp2r=R&#H5)x4={5p0S(4W_L^{6&>7#`9oM%_J&NPj{n}0zH+|YhY!Y)AZfP-(<&I zC+u65w@D4cwN1XlkZ<4~dYPrB$9;R{Y45l*SnitTf}S~>6_YbNZ2?0h*G>i`(X;n1 z(gOMBJyqp#uij#xV1OF_squm2J$R#?ZEwnSR*;4o?)M=>#`m(u`$DBg-}5b>+14P} z`}boMus56B(mms^K$JwsXb>Li6Ef2;;@d__EQ=iIuYrm4vd#0}ZwG97h|Rr~A&98V zr%|2J!5ja5a*Y~bJ2E=f`>v623LSPE){^jvOAI3L&l zB3yV_S=9EZn+B=*7z#?^FZmz>O4Sr>C_tpKBd)Rc`J`{9xR3G~0c3pl-z!k?EA0b} zQ`7B79r{|~M^FOnSEE|L_p;<2crb4&wp@ZoBLtV+^J2zXWHFL9g#b$o3@^frty>5O z>uX(m<4$7wdbd|1apaC^9Wij(GmW1Ha3x>WZ$AH0B`8dgwxAsXoq|VnWyh32NQD`9 z2=2A=qfMD4uTf{1+z;_SwJ={a@lok@S)I=RsCx^rs+zTLd{Y7{qF{r9lnRO{qGHep zDy1M`Q7TdbB8t+DL5YIWAV_zYv~-trNOx`6o1Fj5=3qY0InR5(_xrBvzpiVTy*6vj z{hNF4nYnB26)9a_IDNn49qG`BKaF&bu#uQpFgdenrPE0!jFRR-9<~j~Kg#v{S-u^V zjP_qGyK?wYcj%S!T#@S*{>qKGx;B9i)p|RV;s*Wq71!RVu&nx$+G%dm)%38fHEWT% zb@Y|Q!mR&llJ0WaBVo-i{%7|R%Pe}^O?C5-#81guU?l0}b1j!m#V_~FY=Lf(N8@@I z{5|&1IyTYGy}WI8)riD+rFN-{w&v<^9tBQevNn+UTCP5$J(&rORB_Qs$(968BD)rm z7*WGzGC2!>#<5-O%T|L-Z!z+l;Nv4*uY0q*6ti}dF^sNQSf7eoeKGI0YtCKa_HkUk zCwJEsN$KLt+h;5cFU;X%1jo$g<0-dj zUm0%Tddh8qG0zEpcgBK7&WN0i_3*|-!F>lM6(3%rp7-P1GGV0bVP4r|Kcbg9_raC1 zb!EZ(YsBV9kJudwh{)#|XwKl%6mtY<1xVXgYZX>hoBZ4QEi=6KD&kwU>0V#C%oUTd zx!JAj6px}tH5qr0U*_cMYC9z@+u>R%g@~ZDSv7lhr`=B`ak|K=xkaTpUcY(k2z9{0 z>DR1r6SZWGy8fqwazacNNU$6B6&B4oHZtS|7u$TU-B>DXUt${A6iUu~Tk)_W^BoG? zdOQ05hc|1^k{wEkFzQO`cci;3k_k!zY2w-*M%|q3&01~ltsbOe!eqo!e>7N~o;tCg zi*~m3%4*dNgL&A>P_IjTE48X^ zYw3!?7cU@7c#Z zEQGCQC}R;}?^lhzQdFWv1X-(|5=&lf`6I=M*MY)Sn1s}o2aHs-IvSqwAk{ix%5Lm5~EFxL2GnGX0G@ZzfNKE!1?i7(AD1_b$YkH%rRRMbvk ztZ&DIM?s;w9xHi=Ck=R?+40;wcf)po#^h8{04B< z^Q3D0PDU0ozGDJ5r58sqltWL>?&i}Xz45SR_c=F#*~Z88UGLrVWqg%fdcR}@zh}I$ z(kl|l&vX4nfasikuz60VN}wTH8Qt zMD_568^jaTN^eXnuj|=oxSQO1R_H8t!zcdvOm$@MOZJUJ*tVPp{AXS^m9{QeH7SV? zU{x1Nxud9G=$F(&|qBs@!$k0DH*eI$UzRInM_A)@)0#DwfC?rM6Jy zdm|vpd6@;n`)v~snYDsMptPk@J3DrhhG0RoaoE6J`)>FK%;m^vy)MBp&vVrodAhY* zYDajEw~HrKiCiqcN$Lz4Njt^KGfqCr{gHy-QmR z+R6B}UGDL$sm%P_QI6dkL==6b!HpCJfw_czxr!OmQUXplAMX47#P@1={oyz>TxW*~ z5%=oy(a*feU6Pa+o+bBw(v)k%xv11^zZLxN|( zzSxh>Zkrmr1#K=aKdtg{A|c;$vgVE4M9E>7{Jwx(%I#XDX%X>MqHicpvQvefJVL4B zR#Wq)V0qUWH-TXvZ}0hYI*-V1eoo*Pb3AZWGifiAB4Q zVtGUVLB~pm4^}taVv|o@_;4eK_`J49S+-J+eN+t3!>9VGoAzSp?Ks{?%-y)5wcTJd z&hv%G;UwH17Z-}iV*Zwc&5m|qLgx8j_w4dMap&5#Z_g)`!A;%77I`8%+%dbS`pcBH zZ#D%@CzNw~Ta=EqNFOZx@`kpL#DPO`x9#DAZ-dXd1;_9ouM%awIDVYslI82|0ihST zxoPb;Z?cVbCB3Yh7T#l9{^q1Wq^#j}g`SDc=imErN%C^hxSEGA>u(?TrM6-^y6K}` zYS#Al$!rm*+^H0+jM2C6s}Z-&0Y*T!sDGfYBBj9LRbWPh*Y&0J8|Dob!qAi6>f1H4 z>rUd)ZRYUt`%I40o|THDIgi2WO4#DvvSX(fb#PwO&McVoPs1|Qa;corJ zgGVBK@7wMuB`UDqE3q=CO`>&~^rWo544>q#fva;9v`HQl;4=!iRx3Q93G(O99 zP~cd7xFU}hQ`j+oy2eMQ^4w`%#(pWA-kRG`YneAw`NfPm$SXpWoy2okx!z& z5LoO_J^g%l17`Q$P#hPLva?(;n-)Jc&Ff;(>tF}}s^ZdgsQTkGm2vM>^f(z6?2ER$koh9oHE z4e4G=%6A#QmsXN*-j8LgIiVrjd*DeE#qh3D7;D)jY8=-_7K2-*%HFu}=)nL<=x|e` z2F5=KB!I)Ti~Y6k40Zq?PrJI`eDlNpN*Nda0 z6))J4S{?^m_JlX=$v)nDKWDLV*>lhrXQ*{~Bb9fvZyo!CFcMKEnH!RFnT1nwh+JK*Zl@f4=S4iLo4wEhUwyt>rov@OccFJ;D%(+? z-F@p`Cy%omhDTzz1aIl3zAB?gv0yVpQq0UEV_r~Md2ZjSag}H(y)o+{0cpEz>5VMX z?pLT!Sx#ghWUaR`o8#$Tow+l0y%e`vFyEcbF>jbYq8yGX=Z(xhJ;YtFxpDO6-GlIb zoV)KNg%wm6Hpas_R{$g2xMq^lc+goy1#g()cG_B_Oj@#<5I zOk`B2Oi1jJ4QTxG<>O?)TPY!z4e8hNL&&SMH^|Ydllo1$b{W<0or(fiPqh~pB!%xD z3)RlVj=HlJ@<=MBo)8RFrS*5F?K#G0@XoibcoUx`$&_VnAz}pI=-?qv+EJs;4X1}ycGsD*D0{csh*TNeD z`acp4(a9`$J0A+v7}~n~%$cpRMfVQ0@jPzt@;$4$Kdh0p*T-t&hIspDm5OTH!bc~D z^C(LLd~+-#;wx6ibC=X{@|)bDBOkTNZw!!ew(>@cgDFFrp! z5Jugw!Ek#Z_2K8>yJ{XF50~HBlk{5->U3mLNrVX4Ge}PNZ%Q=nWbD!7&~S?SD#=VadP;}O z3|}iYG_Jf!$0BD->XHrrm9GL{j~&y)@_fCW7!?-hniBXVZO=!gH!{C$`g4OY`L-WXA=!RaREUJzv=wcUH&hqVMieoHs_|TmmiUX-j=le#)ZDTxo8w(Sl(RtIZ!!?;<&W_<~vM zZ0FLX-jQR+inGl%aJ`56rCe;D_BT3Noa_0xi4)(8)vVutMfyt6MVF42MOw~&=Ba8r znW?=*SBSIT#;J%CZQjRsGVF5IQa{ZZ5eaJpm--KpO?#<6FAyIP_q$E8m>sU#Wn;r1 zpVDOz?6ZYroL!E6$AG!s=a@3DlU7X+f)Xcdtb}E5-xjjt3wuj_5Wn1A^^~mlUcIlj zcF$XB{*LD`sc^gb?S zfmsuyf|Z@*PLh&SEf4(nHK%KTy{U3{#XAuGSeKfi1IOOE_=>LEMjhYaCZnWta zaD7JtgXKX?x|(Ca@q6uCuaO;PQR7b2$CqF|>klw<7v#7UtCRGP>J?iIEqU z!fynU52amah)b&$tR|12i_ZpF7Y>DwWiDIzqb6gmr3@Ee*4~M^zjsgCbP*l@Zf>oH zd$(WK${D71CovMeXnRTKeq&?)X`zP#U+gFrX!@3yiMXCFHw$EAl#Ynd#jOq>z-4^S zq=Odc=7tR!qV=_$_MF_?uq~x>-FJ8--;rkQ)fhd!eFu;9;*c+k-J8mrg8JbW|kE7mSkn?OFp#b{PKb%7`0uNr(~)FfCY zK^yPm&OPVUD_HhjFQ%mAssZPd=w zH6oQaiC9{)Hk{b9%{~-ptW~ZE>tE^Xtq6IfKe37P*D5ZdCOQnYZ!VI;Jxk=f>NN+TqV9@Y7wBah2Tn z*cNmCs;QhGhUva0wi;h0@1Vm?gu7fn zBrDsXm27`b>eyLws?EJq&U@}N;Hv0EI;c;oL`OtfOVXvtc(=t)8CloNPNnJh<7AR8 zCbP{vj%6{z?Ch8`b}FqZ^D-R%^xm8+IF9Rzm|}<6yN7HN9s4Iq zD0B>FDYC4Wbj(jnWAe?O7c)-M?LKpep=ytrbIuYMacJ&|(NjXb)}c|E?B&tn?ALF8 zy!L5mj@s~u*JsD_6NWFIHkaViN#aL%<<-ltYNt5<19Pcd_5L6YE>9njKCz{Nll3Bo6e864ziw_N#3#Vjv zPk2w!x=T{2Nb}N_MCa!wSF_^da`{bZE-jbzsKLAqh1|eFqdB7JWb#_;nu&br)tK^1 z%A9gCn2nxlI^C!MJ^pXRb`Du9TAVQ)+W_rSS>-pqTff?PF7c|@3-6>jJrXLm2vWKRzH zdQyXKWRFXSS(SM4(0f0ZuY>nw<%_#0&dvB7jLBJaziuH0VCwyDGp+g6M;aaMt=*k!E~j^12bPMkPlJwv_~z7j@Y3I3!W7`XN1 zy6$@>*`Q0#*AMOZe8a9TZZT`(W^$32N%7GLtJKQZv}bWsr}OUljo&g7diZc3>2@>Y zU8W~OPoCiqUZKFy*__c)U%YkqTx{j7lz^$bVbludhKu`1PUYm>+Q@%_;m!)tP0U`V zti>`8U{+P~X0Z5?yXi)E=j6s97EE{uvyhNVVjljT44VkuRvN)>mV|rT=x8_5R{N5g zJ$`I$Mk>zUM?C$ob3@~?9QC7o&uYFA`5(XX$$7MKqvG(H-bbfLi=6J;gK_CcMLoie z8)H-)6z0myt8xdNZsn>a$Jv}B)xGc(??I8@6-q*p+xy6>Lp|_-=;O!SQC)F8*s{jR z?+&>J>TWNcf#!0B&zJn0K{eM51d`USMo@S=TV+hT7C^ ziBn>m+N-;q&FHSPU7uyIQ#_YiAJ?HHM}ldsn{y772#1A}O(rn(6n;ykyP_R&TT5nl zJx`&C%(6iVrds1u@k6T$38Php$)*P@BWle4>BauHQp>5neEDKX5!$G=sc&@CPPv>Z zhpTgK-k5eya*kzEDmL09%Gt}g6BkTmrcyE9L-j}9Og{=rGh;~I1pLEgL)v*C<=bX* zbDs#~7I^t7^Q;X&HRE35?ouY#UAZyrrnBUMr*gf?)E+XP8SK~?D&TPh>LizD2Uh*Ewgt8V<8R$+9wSPCQz^HFK)rxNc;K3RgX7jhwsj zRY_Bhg+)I{tUI%5+uZ6@AhSMxN|nMZW)n^NA`NqY%hDT40Y?prJS|OPm)Gv&ugWf0 z=(%h)H|EP&BuS!4vedxGseawYr0Dwo{d-F%zPL28(9?Ar z0(&Sdb0~;=i%GJH0!OO#-zt5P5}KwAt`=|Dhbi#z`lfw6{y3Lv9qG{5ScW00MOR#1 z?`a+zy}|uqV2ZY_l!`9e$x$p&_R!{Vt>iZvU5>}7R}lzuvw_D3~pq6_abndG*|f9g(+O^=J=a?^G2s@ zr1%a>`RE_Hm2Eoe`D){le$k#TqC2;n>-S>ihy@ragM&YX_?=t&_*&`6kwZhFwHjd? z0&2ftnrL7eitSZm`KkU(mKOe7SBsZL%i`|bZ+^vX|A2Dwggm{J?^&`s?m9vEw8s8o zhs1$0j@(Rb>V~LWdPkL4KYuPA&3m5=-(JEe_^B>D^Xjv0npK5dQm@}XVpqF+;nJX_ zLVuN)ruYXg`A`XIoWI@yt~U`LAB5?e^sGllZgLI^9pK~Kw0X6Mw|~O=a#&^ZF(L}9 zuNxwk6;F zu2z_o_F?y;wR|YKu*CUWfPs~0YS+eb;_^3^KD?G&V>+5zW_3XFeC-|)Wk=27K$Cao9#a&Kul+!72iF-aO70tlL-*qZ;Jej*giE|&Fg0WA$ zQBvRT^b3NoW2bBq29;S886qDnFfvvMg~ozAC(JRTyMX{pbChIvQlgV_g*=B&XVwCC zgh!hzt9TQC$h;bPSIjXx9WvvyL{nWvPs)h6L!@(n&l~2!kkC(>@paVXFNz8ex?Y#x zC4|YpE)1jW>60`pmM$&0XEu#S6WKXej{BQT+~vXK_*+Ga1ho=<)$S~o^cLk-{TBQZ ziuRRa-`B|`$D4<&ZEkz+obux&QGT2lJ6*F)tUixfH?m+NK3aK_RqITeS;K>>Ma~wg zoOtQLsl(|7hfJ+E?WTV1WN^GY{L%~ZjyNVe!BB-F7rLNV)upvxs2L)zZ%w!s{OMv? zCSzo18yOW9+aYFuy(N!*D)DOk0u##|>5H50hjAs!klhK)?~-5*B(m+)+e6en$v8Hy zr+LDvd_34mFj8Cl!l?P`LXF=AlbTuwE&fhFM!Kq*i4@gr@iTN3mgG;iz_)f|y)HqI zQM#T#-|!&;aneVWmsGe4MWTrqnci4_z~FEBVelnHF{`T!Q`Xs!$D-e}k_*y}lI&s5{qYkK#wmlWm!;!>o1n|B?>KmOX#u-S=? zmi}Pmxh>6MQDOHecWp|xWLC}?xqEGgK2G$&&8iaWl*#LYIX75{w{CjQLbKHwpKrRV z&a})Y)z5$Rrq+#gt;YFRuU`4)o?V0RM=keVcJ0_9>D(_t zEG%(kTfn`u{Bf)>NpW+6tZJ5}rpm;87NGqQm-y zT!tD44%ia8y7_F>9M)7}8A&-_w0n;7mB{|u`OMTC54-2n0>4SHHk@vdeX?4U$GkdG zZu&AAEJuXl6Dj5BDQoyy%Nj&pI6OQ=%ED+$U%J_KmV`oi*Di+}UUYfGD%Z_7U0pC5 zYqpv;a~x$LmB$}Xq`viR?u?1@#s_pnj8h85*q&9|gA!?G6+^YD_ku%5WoUE51utDX zETZzQ`B)b*arY%lXNUQ7lq7p>dMMz}!J447KdnruSNz-v9i7lVKHdfH3^GxTOYdwbPI z;%+N8!Bg>{4pyH9%VICtFDOtMf{;mo#p@+gCDjjgs)E6!Y{LDO^}&V%+g@A}xV%Z@I>E7b5cW&>3 z`|Ay9-_{@CWfk?n;M??XVi-7e4il-|_M8;kx~%A9+85Ltj&JmTc@00TJY&4FPk+cs zU~2d-#chl^Q@6aTA4T)vP57|*6z;a11KYiLhwBtHDMFVR@n&^5F~0D1TEsD|`=Qfx zqx#30rQIGcM)&SL51*gPyKb@T`E&j_4hzZ_{pOw{I)RY z55$#}I=gps?h(C`WbIgyt>VaYIpT%EP0X>R^F(oh1uDb=^Zd46w9C`Bdj+_Nxa7k2 z#JZXiNAhc*qR4Eqw`UJmXA<`z>b$*`Z-Z2g`^FngD*n9+j|Ihd^t}-5H^Lq!qxBj- zELhU*kdUN^|%(k1dU<|Qy z8pkYHmT4#~9hB*I!{5-*W0Uy6b?gEwt5oIl%-&vFMvl#mGD$bE=Nj3nYjL<|*T%E@wg*fr3jFUL5+vQq6jipB29q~y3V+NpmnclmUW-_b zIKbj^{z1kD;%7b7Vwh_#D>=-(#|GGF6{B_b^Ghv8M}$9G#@0(`N_%*youGa?me&ZP zl;&)zt}9qra^kboun$-d9&};2V2m9vu;1dl?e0AV3yFhLQsuT-EVia^f49OzsT~ij z$rOgNglSYJ#iTJrPC{oqUTqueo$lJ@O?|C+(>7BIPLqKNiaJf+z##C#Z<84D<@9&j z_q{I(uxfneln3w^kxz!`rN~h8>oMJUc&a)3Zt-*n=_zk2G6q@`{kd4%MAJstZZt^aikkDm9JG0R59 zahL(B&GdXa&5gnio6|$2yRutua*|MUQ*b9Fym+1~L)Hun5=~YdB z_P&iO^zs$Sb4HVVhBJMawi|CZ-)^eYYW2v>r*+}A;+!3xl@>#t-Mh6abN_kGZ-re{ zhmT~PIn2u|AFZ}Rv^RRoiF(RyEUb20G1gR6C(J7uZypt(->}^q^Nj9{R4(NqiHmM0 zNbtQ={Yplo+g{(O6Tq( z_ng4&PC?Qf^a|kJbsQU-n#9gAG_L4&#D@meUcnFrB;6(6R<-Gv7nf>&d!U_NBF$Sj zwd+1XGFM(O^6*fVJifj2MsCotDk|3*G7% z;MA^96ITM?V}z{goL7lhtcit4AKNo-V__?r*+ycxla1|@kilj417uEx5%dvcQy~J{ z6ar=24()u#8*M3ehQ?KP#jZNp1M|#X>Cp1Yn*lU2L+mfjY_40(bCc0p78l6GW`Aif zbXQ9BGkaUw*Szlt{ty->hII$|S~Qv9f<%uIl`wyxD01;^X_A9IXMbbK_bV9L@sXKwteSLrSqoEaV^7| znubzDUHcS2)ykX@7Z(rSWvC&-SfdjBiInjHu}B%&Ry(A~Xz;1uV!Z@su=dgk|Ki*<8{t^N> zH$|^Du=Ug)foMhtot2BuyB`V4%Qx}f8;z~k;`zXR%!kc(mBdM2TKKir6P2fyaz_P{ zUJ5)sVCfMC^71Q8<`x?H4Ci)D+UTEs*llpObRfXb1U%@CpxY-E8k&`rWv>(JvVGUx z_Wfl06c(-}xRYeI2EDR;l%tfV$7)O&U?wQGfq0Zd;Kb0Cl&qcthiZu{l1EFbswN(= zcvJkl8+mwkh*XL>?BB?{ap|y%f|;pf%7vKu2a>YRF;K1z>1#A!tdzKJ zu93(+B;=pf-dn>o^# z6kolLPB~uF#ev=T0+KWhu*LdY`T!pv^MT{XSvfhY zx^kt5gk4E8GZJuSg3>ca&;13udCA6WqA5(zu0GH6)i^i2>6Qz8=IWN0L`XUF^jWVF2pYL=Z!J@Y9c$0_QFvewaU1#NTrtUbb3#m_dzLsNw#3F z^QTUox=^GcAt5PQSvNWtzhU!XL)zxCrw$#usf|rdP20|8*XqQd^gI8YX8h@P4ceBy zX}5faDmoQ1Sut4uCcyFJVg7bH%tU9#QkhTR|xwOSjc&;s1y zGfq~V%{QavL$5~0^J+z!KX~6ZZje62BEfKV!L0J0=)n=|ufzJy`?f5)bX>$l9o(;X zHBPeqs0D+<({rgkCi-@hJMg;Jkav3ot_cV>Jx<*)ku9GT7%N!N@!+%l*j>|XojK? z6)iKWnFZJ!u8|qJ;gn%Mp-&E_<2tn3NG<;BiS*N+d=|#TpaFior0#F90Bc zg&6%0vvn&aDd7YBa|jkLSX5wvZ@Ytk|L+}V&YanC;R4?UK|w*4iy|WW7ez%~M1_T2 zgarj%g!y5CH98l+DCTnU;zfNyK_L}%J-YAz9;*M`@}*0cowPKy#;h%@fSr{!urf6T zMvor@J#B5Eaqk|ur>qQAZ{G%LN=iUoO^xt9`ainP-r5?V`|jUYA4Bc@XKMd@SIElB z#aUTeE&6=;06aZBz#C_0@Y2ri5BvzX@~vCn@#|=407HF!U}9th`)dW9UcLnGuCCyn ziwiI{Fw{j74<*r2c>QjjF0z zwkM>4aEFJ4fRFzE1l}Y32!jX2kn{O7_}bVAD$2$|dC3?k$X)tgvNOj(CH($tQxnMj zoDDuetj@0-31hd8AMu006WErj>fP-BGsJ6m%gSD-d-~+*7?P7fUtfTDkFXRL%W#i!v>k@BgdHcMUFAihYvE*g~0Eko7tHvhjj1H zttQ1R!oCi|`%zy!2<;*4{$5@nz{iJB8yP(tL-haKe#px!(pi{Wj3FK)yr^wdqmrMK z3))&HfrW9$3^RR1H{1U7xg#vC;GdL(jJXR;bf3O)FjWm%Jja8Ys!5Qan@8Y1!v1ry zv$Y#TIR2-7xN+kaovpPE0XxEv#v6@6XwWCn($WKbK6K48(T5HE6TJWK8fN;aQFf;C z0hgC}$d7LzA~cLJ&Oi6T-rjx;;rXBR!Q9;ZJ9dO0VUGw42OVwG;QXnio+B*HtN#wy z@BiaD(Fs)br@+N4{ebge+aKeE}qMz6o`q8`lAmP7S?0`6u-W{LH3$_dk}CV zxy*rcuB2!l9A*w1{vF#tIlp#m1Q^(1fsO?h+c8xTw&RlF#S)k{(jBzBke%b6btf7 z@nC#%5tup80TtazaD?^G`NGary?lh_>qN4x+-t0sLV`LP4^H@cp}SfSx&Q zL})0K!%#Smk>GPi7HDsq0*9CqXMV?p&Uuax03NP>aGawDa2@UfT#w>*%Zk^<6_ zlL^K1gBSMi@EaHy#wEqZ0#wlTIa!}USH~bYb~tS4udt)$08Nuw zkn|Z3mLPUiT>a+3tq0?OiG7{UL59zBqUYyVTbc$zQ9%LhM=n98&>n+u{#74f!s239 zdOFC?%mf8_`JlP689X!0>R)g3@9J~BqX6OjtA0q!PZMN*YG#puy}NIb!21h)-~KIr zL<_F5UC;G#aLs53RpsSyPb?vn__+AR-|=f}>pJCRWq~}npA_cj!~Lin)K(8bS#0^Y zbk6a1gPRYgft1`7xO!t6h=@)C0fDu`cYXpqc#Z`j@wo52f8#$7)E-U!+ctmZ69-fE za8bb|fT0smTUA9U6=h`r;r+P}?>*j+p)o?Gw5SNQHn)H)ViA2mx3&J+*J}cSAXmRnRr=}5jpHIMF3@R(y7TB2^|5)RnJ{kn; z$J>uMVC6OsB9a$CY{mjuU0wgrTJ7+D9(ab#gIVknp+<97P`LLWV_)YN+}{Svibe_e z*T(?Kx48JFEocn%^d327Wn_SCC_e=J#U;SZB&m1({`LAScRR2)9|j-ZjRSArX#y{E zO4j5#HE;13@NM18g#VXRF8~wAIVeXn;QYCs|1ow%n~6T8&(#qNnjrtHD=MIDmw~e4 zVx;4-Bm8!D_7&-=sQ{JFaPHRE)xk9KFZw0)AWAoU44m@#~1FCvc0PO+m?fg$`c9zCfk+U-^Z7nSX+{J~302OU*9T9}z z^Sx(pa(p~UPD}(Dun(0LmH5A+QILxzfE*fJ0?%GxK}`Ar(6^ZbX+QCPWPF9dcO>@@ zEwSLf(F_n4?E~DLf9|(`MdR+O^=&90nQ3Vt3-bAqp1uac9~%=3b+a%+ ziG}^JwTk*f_HWC70~6yvgaqM9$yo$CkjFpI+ro+^Lf>9{;lSv`+Js(&Qv=P1^!!EO z5sU+m;9iXGM+NB-0)qc&FX(>bI07=^zM2g8S5%%nHYDJWhWcLUr%!|u6&?X@$c6r~ zZmO&FedlrWS3Ch@ER>%|wsYUVU;ofIxB_e--_bar{`}Q}iUoPk?!d4ISG;>?r5mfq4HQy zkAOcWDjJ0Si~o^O$CJGD=@0w@ydBWLFbwTiJfRR6}6ZFk+$opt0KPtBa|Im3v z`8vVK$Pb)xakId}bsl_y^5F^b;c$QQcfC)Gi>rjOKyw1knFV-`j=a)EVB<0iPI3O{ zwH3*aqs;(FjfnxVP%kFPkHMP!M@2*ubmb`6uUI%2OrM4RF@L!^+Q8)G+WZ|IT>_Dz zP!|6+A4{s2Kxo1Oz%TrL9}wR5o)yA)eF(vUZv!hJJZS-#T2FyH3ccWp$iJ5%sLORn zeCk@0e>et7upj#Wk{@qRZ^HVYh~_oi2f{)k{&M~F^_)O3fXnMqFg3YC!0Qu^C&+hs z-4Y0jMfSoY3Bf#=_AD2lNa^3HVVTISFc^ZTx$ar1z zGGR|ca`9JVu>!k>`swJ61J;f+;3ZrG)b9^`$B+6TbNR1zJ8q7=F0^+MaKbh8Gu#98 z_4En*uaS|lQ!cbsa*_TF?E|#8ojwu$i~hiUq>Vu5u2L_7_v;<_+K2~TU5g+lZH=dh zw?&mpprU>W+FPpthhGH)!z%#Em?xAQg#GceF+y8vO8r1dvG*7Js1L&DJAYY^kUjQ9 zcW5OaV#`K)8Z79uhK4pl|G9PRHV^VcAv*{4u^84?=6=8I0b&AO1UjL?Q|r(PbyC6% zz|OA8On3hZ`0#NKxcK1+@_}Szy`X(7yLb^yOu_ZYWBd=y2={uqDfg`n__2yu1QI|3rImaL}i*a;VdlL*2g;+BtA67CD$3R*)Q>0@IuXuet$HC0ZpYyt=3J1`>zTWQ7^(CRT^@w$U^0bF*JE(xXE&K9? zP**|y8R1>Wj%p}FbkK*l*icggP-%oZbZOz26%OXc6>-5e+4;HsN7@6>U$y}4;~(}6 z>PSDdZ-e}Q%y0A^(wpA7j-ii#9DTiuz(D8MIgIG6;}<$#K2iqxT?6f3R1jYg&Y!Wb ze|B=$GQBb@7)f3LGLval`i8dO@L zuN&3kB3?s?A3wLh{`raiAZUQ{^0N+VVLS{FUw=MOzpPA#!QjA;J^Yvd!v=gltj+72 za^JwQL)mkV_D!H3$^ydO0$Bstq0vfP~m-Fa_5aw9h5Q&-@IJ@VTRX0a(C3tgQUGPY(|-5$?IK+y_L?H?Q25 zufaCMSOSs(R1kJ#e<6Io^ZfU7UthoMj@DLyN>_V3=jNW$gFsHkfAnX(fA<-!jrLZgwunN;d;X{!cKYdxbB=PdqnF8*PKKIta%X@gB)e1H_H67k&9MhH(5-%)ejf z=;%mSkY6y?)7eRw2g8uY#5mfIX29(1EGR20pD}zC)GsBTi~Fa2k(H=j6gnR?;P@hA zxEr=RJ~jqMhK4}jw{HZwX@P48DsY`2L-c>g^xvFEMMY%~LF{M_AbMyF5Pp~v3FhbL zVLc1=gwkox_c8r{qrH837WE&N zsmaMT{IK11+4%<7i>Sz`e>_+JX@A_`x!;5FPweEx#2@%^I2>45SOAOA*{}?a-xavv zul{ROK=mp-N8h9Wpe2>kyY zKLPVU#ElzqvO3C z)%`F2t@9J!$bk5`&ToQJHQf}p_2)b;5`^lHJT6A~od7KVTX|eC2TNW?O3Lo4v`q9> zDXHu$mo8;r5)&iTSEZ%1ugP46-^mb?xmE+vG^K?qLmEvB%e7Wcj^9fMyj_LE~ zKwn1(+*eg4#hId6m#l`EBXBVMV(L{Mm5U{fTj~#Io&AP3JxSrT(?;Fg_#@<*Q^B&oa#ou#c{Jnet%qOb&PkeyBscb|W6`v2DurKXP+?)aV>`b*w zf8|^I{X29W<6gfw#=X9J0;jrXbF%tCP(Z+U9C{D+{+18-@7;gy19LtQ-%#E~WLP_v zjWO&Of70*t(7Br41W?r(|0TEM5aXAbeY+g*u`^Y4CdZEv{NyMH4Eg)j??3oM9z;bi z()s)NEutK;Sm;+zO{tzae4yYj<6%EzIDN7U7{9`T{4zYyHktV)M}~vBewluklRAup zb{6CgLf=mkNP)4okl;^?h~Cd*VPb3&hjJHC9zbPT;|d3B{N&GcPIC5w)7(R_48S<~ zC=eE&0Q`ItKuvc76jv?4RcQ$r*v$UI19blyhF3TEPk)m|&-m_3d1Cm~3FY0O{DGX$#lPg6Apf?scsG!_J_J}%9 z2BPAVKuL23`uFhwJHG^s9A^J*JO#-l%z^7_sOtlD(6@k!j<${j;(_BU_^=oB!J?cK zb+wT1@`mEhz26o=5A;u3xXuycf;~OUP(d7uwtWr9NgEH=-u$K6T$Uhf?8YZX9WsHKIaH=-X8V*)6S8Xg+{i|-lv)R6DP z5XPfjd~t+WBBCD+eaGNrKK=ODGfN-+C?Gy zD2@^q8Uo(9czw^SLvgF{kSWmLzeI?an>x*XR|{?4&V$6y3!t(A#!uq$z!dWTq4_L$ z@OTnP$qxRl9H4a)t=Y(rnh5)BV{S>HkMiR_1$_k1jaJZ0Y^&hR-Ec;>ui=muH!uHoz!=B6d9dDRd6~;G^PXNVkQT%OvEYSE%U(PB) zG59n{&(h4CApdTzZz@m>=5u=b3O8r!{QC9Iuiz^!gVuazZSAoAu(eo3e%T`EANs*_ z6obrw{eS%)%8BdjFaD|PF!qG{g4%?6x%H2<8|P6j0OEnEu?b=RTUuHSZ-(n9-ux)Cd>omgZwLBh|t-! z`N^=yGcq%!iVzPefqQ_V;S&io|Im?_owJBy2pOqqb4OX5S0yiY6X;h}tgShTaXa_x|GRTXnXbIFbg>2cu%HirMU+2gcD)VclXQ9gBaV=fIt#{s%E>@+ z#dRJa9LvkAz~k+YSk-x+?8(9=!}$SY74X&I z0QsXO#0uwZ%rpCuUvteL+W>+-2K}x6w~iwrA)%rZ(nr2m=$l)9ZuIFN`Ht7|p;|&L zd>|{MVvdkM2mO&v&=(K$7c16j{HGf3N!iH%J~S`@ke{cfx^Bk!S?GwuwbI3(>HPdz zPO5h4`qjwc=*X;*G3e_XfWB|!k8X$K`6(#)Klb}~Or9S+pLch4FCzNLXNdeD`L?Iy|zr+~-TYCR5?gQN<0Qw*-R-tzWxf+n$0s1h=yP+E* z7rGACizNnw`KM+59#nV3c2Ik$UDQ6JgXj_H!m)cn`LiE`6oZc6pGVsbzvF`Czx89l z=d74jRa7lim6Sto-?));{p!`?Yf{q1ir23fE8n@3qRb3cl&z&DFwoT{_$5?s-vL_c>M%}h2wvFQLi^bjSejdm+`D`4ANfY^-McU3 z^y>BGCulQzLwhtfDjoy}mM$4TEt+_uUxhW$t-~7Xm5;x+Z(N89%O&_B&~?amH8U}d zfX~m6|6O08{VDG1=(vb%`{;;hxK~up^PR53!aWk^P5+wP&(2)GdiX%;%mdZ0*o2r$ z!ZSeV84*hhi!AtT$R9M|GZb8JTwE4Ez-N&X;#lfr8s@hwf~0I5{QlS68&0+g?C10@Lau9Mc*MwhAK>#DohSz+E(Ybf zuJHur7~F$;(|!F(pz&}9T#=pvl2TLPeegUXfBWxjT4lx7dGyR!4a^I$v$a=(`#IO= zj7;za>Qx$ds|h;fF{t+iLEYd}%se5lx4CmomrH;;a^hzk(0nrax6eYLG0)5HA>$`V~$1|W^>+a^31oJ~JLxO{096j{Ajvo^_1@~1Pc;k;F*mJ0Tlz$bT zyk<`zJqjI2*Oa|8`dx$8Tyh2-vXgH?p_6}iv}ePC<$M`g_d%=^QG)Z7I^E);6}E7ZT;1K{%rPse~V)VGi>A||k= z>vJ$SgV*+D^T^J2fBViG=Gjm|`CLT#MCvN}^GG(4eYBq2T~!J9c9=7km_AR)>kf^@ zfri#4xTh|{yp$h0J<3N$IcY~(OJ_c(m4GjBKD~8&XO8BW*9XrqlqZuIn}g>)(YA{4 zpj?-#ig~zRtm&)h`3ZD<>sf#?<29L@g*iqj=D)5>A-~HbosxN!k5yh=vI=vCm{I#M zf8|I`MddQet1y0&KC1xnqkB*;TVnh)!7fC$2_C;@kRX~1uutefvgGGI4iJ8E!7tdd z;u=CuOmb3kIBI+S2n!8+(GK$;x}pB5r&WMo$AoGlgF)~f>h+c7YrcT_`4vL$2%=Y3 zG6&^+49H3}E~ck6ETdeY@{-a?nD?<~z3ufnEj29*>4iu?dtq0Ay(QmG;MF><2Wow= z{{w`AY`VKjYj)i|rQ*4gFU`xyj(|S2MSp*Pq4hR@u3_Ar{Bu@T);Fj>kByGPHKPe{ zZd^HcL$>vg+=ZKRovUiMOJ+a*f2|yCOcYme(HavI+y3-NquYg8r5jn#@G zq98=urakW#*mAcEyL-ps7ueXe)}mDsqb0poELKvKB4R@|Rg0;GP(Y3H*aQLjYD`2j{A=bP0fCn%e6EV=d@4}5dUcdYV)_xiO?Kb}|P*}WTd>4x9yF9WYZbz)o> zw4GC1TYK2!>G9)PC!TX^y5FNwopTU$-quU4*Wuaajtl8C8o`<3)T*kgwA)>`ouJPa z!pl?$dTwDuLxUB3F#fZ@kEsIIN6ldSsmbgOY9f0^O<`;yg^6N;9#R5Kco1il+E3GSZO(_V%$8q#?6v=xbovmlnD9?o{$CHoHb$>OPj zts5^5Y;iXATeGU}Y}>lO^W%boP9-hlTc)oW!^Qrwq2cEDGmegHYrP3F!X zc&v-K+N+Cb>zO;t`^YeVn9Q3!4C~qhag;~NzT#s4>Q$>=*Wka{{<){7s+y!M|Fb{* zmGbV$@RpIt@QZ57R=P&=HdK4!W1D&r#|LQxU<<4v1)H|iAw1Yki!fF$H~Z{u^ijol z4C9;KWZAM_lAO{9F?+-0lU-g_Ud)_Pdk1ms{InPJw*%J^{_B#Gj-P5yt9%^&+aOe! z*f-xN*}^@tZPy?t$=bHZD_h~xXRnrjGu0_5=0xA$E{IfORK{bfT0WqSMH zU=s$}oBr;TvLs^qkNpV0*?IaF!k2@sb52B~5A9>;ejOxxAg-_z>`53ePzLtQJzouw z4dCCMzD~o__E1vE3zAm6huJ z;TS599BEHU`lU_dnRRCef_{>yQ#^PO7z_HWrzJJ_{ZZcv&%acCe-Pf`aKs%ycI?Xg zYflAnpq&S4qMtGPRpx-N>DtueH(MJ2A|QACiY(7WSnYB;^5Ve1>~it$L)9OytGo4H z+EuV|b%2by;^(>Y_LD!Kzl%H%bV83^vHz>jLiyptJDZxCy1;JZT04aCO|D=GsbJAyh|G|X7pWD%(h{g7NQT7W zZWQ2F$d%l%p9rI300HLkTPPDKnjXyo`KbD)cPyfAMrGgc~? zY*4yF>r+%ZFIdDpIckw;vx$OkktisVXq7`Cg7Xm{6@$N!svP@zD{o%T<)@0-9L!jJ z+#7N0<74%)v1W6I-jWg0)M^qk?WRni9T`%ZBZ+2CmPLt`%vrp`nH9UFHi_1T9<9yB zlVdjo%SUI)phyr_mLOz^<9r757>$I?ne7rx-Poi`T&^9S4QEM~cn5FgGC4U|33DE- zUhD)=1zwg!&cRv7CYh$KSYTvKa)RK1xsgJ~Ow)FrHRG_2OoquSbBs1vd~Sy5Aoiz- z8={}+sv$Z!X6T(ET6+~BgX@B#4C=c+g-WIpVWp)~OJJ3)hE + + {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 0000000000000000000000000000000000000000..27efe49b5f5b31b0c6298daa89904be58dbfef3a GIT binary patch literal 448 zcmZ9I%Sr=55Jk`EEQ~8Z!G&uXVK#!01bh(iMKWY7LwpdB3?#bqWBd{S#=U>wc)G_X znu6-CuDbVDbph<_ZQHrwKO1DJz9+_qR?y26XpohLQzqPbo-sBWal^Imk>|N_u#f!f z8v?)6NOwP0Aqb|*Z;JProAAPtISZatoAbZM$ptONLZ&XJf96hVJviA60I(v%kCFHuVGYJ2#pD literal 0 HcmV?d00001 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