function InterceptedMessageBoxA(hWnd: HWND; lpText, lpCaption: PAnsiChar; uType: UINT): Integer; stdcall; begin // TODO... end;  procedure InterceptedFunc; begin // TODO... end;  function TTestClas.InterceptedApplicationMessageBox( const Text, Caption: PChar; Flags: Longint): Integer; begin // TODO... end;  function InterceptedApplicationMessageBox( Self: TObject; const Text, Caption: PChar; Flags: Longint): Integer; begin // TODO... end;  function TTestClas.InterceptedApplicationMessageBox( const Text, Caption: PChar; Flags: Longint): Integer; begin ShowMessage(Self.ClassName); end;  unit uSubClass; interface uses Windows, Messages, Classes, Controls, Forms, StdCtrls; type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); end; var Form1: TForm1; implementation {$R *.dfm} function MainFormSubclassProc(hwnd: THandle; uMsg: UINT; wParam: WPARAM; lParam: WPARAM): LRESULT; stdcall; var OldWndProc: Pointer; begin if uMsg = WM_WINDOWPOSCHANGING then PWindowPos(lParam)^.flags := PWindowPos(lParam)^.flags or SWP_NOSIZE or SWP_NOMOVE; OldWndProc := Pointer(GetWindowLong(hwnd, GWL_USERDATA)); Result := CallWindowProc(OldWndProc, hwnd, uMsg, wParam, lParam); end; procedure TForm1.Button1Click(Sender: TObject); var OldWndProc: THandle; begin OldWndProc := GetWindowLong(Handle, GWL_WNDPROC); SetWindowLong(Handle, GWL_USERDATA, OldWndProc); SetWindowLong(Handle, GWL_WNDPROC, Integer(@MainFormSubclassProc)); MessageBox(Handle, '      ', PChar(Application.Title), MB_ICONINFORMATION); end; end.  unit uVMT; interface uses Windows, Classes, Controls, Forms, StdCtrls; type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); end; var Form1: TForm1; implementation {$R *.dfm} function NewCanResizeHandler(Self: TObject; var NewWidth, NewHeight: Integer): Boolean; begin Result := True; if NewWidth > 500 then NewWidth := 500; end; procedure TForm1.Button1Click(Sender: TObject); var VMTAddr: PPointer; OldProtect: Cardinal; begin asm mov eax, Self mov eax, [eax] //    VMT  add eax, VMTOFFSET TForm.CanResize //     TForm.CanResize mov VMTAddr, eax end; //     VirtualProtect(VMTAddr, 4, PAGE_EXECUTE_READWRITE, OldProtect); try //    VMTAddr^ := @NewCanResizeHandler; finally //    VirtualProtect(Pointer(VMTAddr), 4, OldProtect, OldProtect); FlushInstructionCache(GetCurrentProcess, VMTAddr, 4); end; if Width > 500 then Width := 500; MessageBox(Handle, '     500 ', PChar(Application.Title), MB_ICONINFORMATION); end; end. Two additional directives and VMTFFSET and DMTINDEX.
It’s a way to get a virtual guideline. For example, TExample.VirtualMethod.
 VMT := Pointer(Self)^;  {$EXTERNALSYM MessageBox} function MessageBox(hWnd: HWND; lpText, lpCaption: PChar; uType: UINT): Integer; stdcall; ... function MessageBox; external user32 name 'MessageBoxA';  function ReplaceIATEntry(const OldProc, NewProc: FARPROC): Boolean; var ImportEntry: PImageImportDescriptor; Thunk: PImageThunkData; Protect: DWORD; ImageBase: Cardinal; DOSHeader: PImageDosHeader; NTHeader: PImageNtHeaders; begin Result := False; if OldProc = nil then Exit; if NewProc = nil then Exit; ImageBase := GetModuleHandle(nil); //     DOSHeader := PImageDosHeader(ImageBase); NTHeader := PImageNtHeaders(DWORD(DOSHeader) + DWORD(DOSHeader^._lfanew)); ImportEntry := PImageImportDescriptor(DWORD(ImageBase) + DWORD(NTHeader^.OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)); //     ... while ImportEntry^.Name <> 0 do begin Thunk := PImageThunkData(DWORD(ImageBase) + DWORD(ImportEntry^.FirstThunk)); // ...     ... while Pointer(Thunk^._function) <> nil do begin // ...      . if Pointer(Thunk^._function) = OldProc then begin //   if VirtualProtect(@Thunk^._function, SizeOf(DWORD), PAGE_EXECUTE_READWRITE, Protect) then try //   ... //Thunk^._function := DWORD(NewProc); // ...   . InterlockedExchange(Integer(Thunk^._function), Integer(NewProc)); Result := True; finally VirtualProtect(@Thunk^._function, SizeOf(DWORD), Protect, Protect); FlushInstructionCache(GetCurrentProcess, @Thunk^._function, SizeOf(DWORD)); end; end else Inc(PAnsiChar(Thunk), SizeOf(TImageThunkData32)); end; ImportEntry := Pointer(Integer(ImportEntry) + SizeOf(TImageImportDescriptor)); end; end;  var OrigAddr: Pointer = nil; function InterceptedMessageBoxA(Wnd: HWND; lpText, lpCaption: PAnsiChar; uType: UINT): Integer; stdcall; type TOrigMessageBoxA = function(Wnd: HWND; lpText, lpCaption: PAnsiChar; uType: UINT): Integer; stdcall; var S: AnsiString; begin S := AnsiString('Function interepted. Original message: ' + lpText); Result := TOrigMessageBoxA(OrigAddr)(Wnd, PAnsiChar(S), lpCaption, uType); end; procedure TForm1.FormCreate(Sender: TObject); begin OrigAddr := GetProcAddress(GetModuleHandle(user32), 'MessageBoxA'); ReplaceIATEntry(OrigAddr, @InterceptedMessageBoxA); end; procedure TForm1.Button1Click(Sender: TObject); begin MessageBoxA(0, 'Test Message', nil, 0); end;   function DelayedMessageBoxA(hWnd: HWND; lpText, lpCaption: PAnsiChar; uType: UINT): Integer; stdcall; external user32 name 'MessageBoxA' delayed; procedure TForm1.Button1Click(Sender: TObject); begin DelayedMessageBoxA(0, 'Test Message', nil, 0); end;  procedure TForm1.Button2Click(Sender: TObject); type TOrigMessageBoxA = function(Wnd: HWND; lpText, lpCaption: PAnsiChar; uType: UINT): Integer; stdcall; var OrigMessageBoxA: TOrigMessageBoxA; begin @OrigMessageBoxA := GetProcAddress(GetModuleHandle(user32), 'MessageBoxA'); OrigMessageBoxA(0, 'Test Message', nil, 0); end;  unit uEAT; interface uses Windows, Classes, Controls, Forms, StdCtrls; type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); procedure FormCreate(Sender: TObject); end; var Form1: TForm1; implementation {$R *.dfm} uses DeclaredTypes; function ReplaceEATEntry(const DllName: string; OldProc, NewProc: FARPROC): Boolean; var ImageBase: Cardinal; DOSHeader: PImageDosHeader; NTHeader: PImageNtHeaders; ExportDirectory: PImageExportDirectory; pFuntionAddr: PDWORD; OrdinalCursor: PWORD; Ordinal, Protect: DWORD; FuntionAddr: FARPROC; I: Integer; begin Result := False; if OldProc = nil then Exit; if NewProc = nil then Exit; ImageBase := GetModuleHandle(PChar(DllName)); //     DOSHeader := PImageDosHeader(ImageBase); NTHeader := PImageNtHeaders(DWORD(DOSHeader) + DWORD(DOSHeader^._lfanew)); ExportDirectory := PImageExportDirectory(DWORD(ImageBase) + DWORD(NTHeader^.OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress)); I := 1; //     OrdinalCursor := Pointer(ImageBase + DWORD(ExportDirectory^.AddressOfNameOrdinals)); while I < Integer(ExportDirectory^.NumberOfNames) do begin //       Ordinal := OrdinalCursor^; //       FuntionAddr := Pointer(ImageBase + DWORD(ExportDirectory^.AddressOfFunctions)); FuntionAddr := Pointer(ImageBase + PDWORD(DWORD(FuntionAddr) + Ordinal * 4)^); // ,    ? if FuntionAddr = OldProc then begin //  ,  ,      pFuntionAddr := PDWORD(ImageBase + DWORD(ExportDirectory^.AddressOfFunctions) + Ordinal * 4); //        hInstance  NewProc := Pointer(DWORD(NewProc) - ImageBase); //    if VirtualProtect(pFuntionAddr, SizeOf(DWORD), PAGE_EXECUTE_READWRITE, Protect) then try //   ... //pFuntionAddr^ := Integer(NewProc); // ...   . InterlockedExchange(Integer(PImageThunkData(pFuntionAddr)^._function), Integer(NewProc)); Result := True; finally VirtualProtect(pFuntionAddr, SizeOf(DWORD), Protect, Protect); FlushInstructionCache(GetCurrentProcess, pFuntionAddr, SizeOf(DWORD)); end; Break; end; Inc(I); Inc(OrdinalCursor); end; end; var OrigAddr: Pointer = nil; function InterceptedMessageBoxA(Wnd: HWND; lpText, lpCaption: PAnsiChar; uType: UINT): Integer; stdcall; type TOrigMessageBoxA = function(Wnd: HWND; lpText, lpCaption: PAnsiChar; uType: UINT): Integer; stdcall; var S: AnsiString; begin S := AnsiString('Function interepted. Original message: ' + lpText); Result := TOrigMessageBoxA(OrigAddr)(Wnd, PAnsiChar(S), lpCaption, uType); end; procedure TForm1.FormCreate(Sender: TObject); begin OrigAddr := GetProcAddress(GetModuleHandle(user32), 'MessageBoxA'); ReplaceEATEntry(user32, OrigAddr, @InterceptedMessageBoxA); end; procedure TForm1.Button1Click(Sender: TObject); type TOrigMessageBoxA = function(Wnd: HWND; lpText, lpCaption: PAnsiChar; uType: UINT): Integer; stdcall; var OrigMessageBoxA: TOrigMessageBoxA; begin @OrigMessageBoxA := GetProcAddress(GetModuleHandle(user32), 'MessageBoxA'); OrigMessageBoxA(0, 'Test Message', nil, 0); end; end.  procedure SliceNearJmp(OldProc, NewProc: FARPROC); var SpliceRec: packed record JmpOpcode: Byte; Offset: DWORD; end; Tmp: DWORD; begin SpliceRec.JmpOpcode := $E9; SpliceRec.Offset := DWORD(NewProc) - DWORD(OldProc) - SizeOf(SpliceRec); VirtualProtect(OldProc, SizeOf(SpliceRec), PAGE_EXECUTE_READWRITE, OldProtect); Move(SpliceRec, OldProc^, SizeOf(SpliceRec)); VirtualProtect(OldProc, SizeOf(SpliceRec), OldProtect, OldProtect); end;  procedure SlicePushRet(OldProc, NewProc: FARPROC); var SpliceRec: packed record PushOpcode: Byte; Offset: FARPROC; RetOpcode: Byte; end; begin SpliceRec.PushOpcode := $68; SpliceRec.Offset := NewProc; SpliceRec.RetOpcode := $C3; VirtualProtect(OldProc, SizeOf(SpliceRec), PAGE_EXECUTE_READWRITE, OldProtect); Move(SpliceRec, OldProc^, SizeOf(SpliceRec)); VirtualProtect(OldProc, SizeOf(SpliceRec), OldProtect, OldProtect); end; 
 procedure SliceHotPath(OldProc, NewProc: FARPROC); var SpliceRec: packed record JmpOpcode: Byte; Offset: DWORD; end; NopAddr: Pointer; OldProtect: DWORD; begin SpliceRec.JmpOpcode := $E9; NopAddr := PAnsiChar(OldProc) - SizeOf(SpliceRec); SpliceRec.Offset := DWORD(NewProc) - DWORD(NopAddr) - SizeOf(SpliceRec); VirtualProtect(NopAddr, 7, PAGE_EXECUTE_READWRITE, OldProtect); Move(SpliceRec, NopAddr^, SizeOf(SpliceRec)); asm mov ax, $F9EB mov ecx, OldProc lock xchg word ptr [ecx], ax end; VirtualProtect(NopAddr, 7, OldProtect, OldProtect); end;  unit uNearJmpSplice; interface uses Windows, Classes, Controls, Forms, StdCtrls; type TForm1 = class(TForm) Button1: TButton; procedure FormCreate(Sender: TObject); procedure Button1Click(Sender: TObject); end; var Form1: TForm1; implementation {$R *.dfm} type //      JMP NEAR OFFSET TNearJmpSpliceRec = packed record JmpOpcode: Byte; Offset: DWORD; end; //         JMP NEAR OFFSET TNearJmpSpliceData = packed record FuncAddr: FARPROC; OldData: TNearJmpSpliceRec; NewData: TNearJmpSpliceRec; end; var NearJmpSpliceRec: TNearJmpSpliceData; //         procedure SpliceNearJmp(FuncAddr: Pointer; NewData: TNearJmpSpliceRec); var OldProtect: DWORD; begin VirtualProtect(FuncAddr, SizeOf(TNearJmpSpliceRec), PAGE_EXECUTE_READWRITE, OldProtect); try //   !!! Move(NewData, FuncAddr^, SizeOf(TNearJmpSpliceRec)); finally VirtualProtect(FuncAddr, SizeOf(TNearJmpSpliceRec), OldProtect, OldProtect); FlushInstructionCache(GetCurrentProcess, FuncAddr, SizeOf(TNearJmpSpliceRec)); end; end; //    MessageBoxA function InterceptedMessageBoxA(Wnd: HWND; lpText, lpCaption: PAnsiChar; uType: UINT): Integer; stdcall; var S: AnsiString; begin //   SpliceNearJmp(NearJmpSpliceRec.FuncAddr, NearJmpSpliceRec.OldData); try //    S := AnsiString('Function interepted. Original message: ' + lpText); Result := MessageBoxA(Wnd, PAnsiChar(S), lpCaption, uType); finally //   SpliceNearJmp(NearJmpSpliceRec.FuncAddr, NearJmpSpliceRec.NewData); end; end; procedure InitNearJmpSpliceRec; begin //      NearJmpSpliceRec.FuncAddr := GetProcAddress(GetModuleHandle(user32), 'MessageBoxA'); //      ,     Move(NearJmpSpliceRec.FuncAddr^, NearJmpSpliceRec.OldData, SizeOf(TNearJmpSpliceRec)); //   JMP NEAR NearJmpSpliceRec.NewData.JmpOpcode := $E9; //    NearJmpSpliceRec.NewData.Offset := PAnsiChar(@InterceptedMessageBoxA) - PAnsiChar(NearJmpSpliceRec.FuncAddr) - SizeOf(TNearJmpSpliceRec); end; procedure TForm1.FormCreate(Sender: TObject); begin //     InitNearJmpSpliceRec; //  MessageBoxA SpliceNearJmp(NearJmpSpliceRec.FuncAddr, NearJmpSpliceRec.NewData); end; procedure TForm1.Button1Click(Sender: TObject); begin MessageBoxA(0, 'Test MessageBoxA Message', nil, 0); end; end.  unit CommonHotPatch; interface uses Windows; const LOCK_JMP_OPKODE: Word = $F9EB; type //      JMP NEAR OFFSET TNearJmpSpliceRec = packed record JmpOpcode: Byte; Offset: DWORD; end; THotPachSpliceData = packed record FuncAddr: FARPROC; SpliceRec: TNearJmpSpliceRec; LockJmp: Word; end; var HotPathSpliceRec: THotPachSpliceData; procedure InitHotPatchSpliceRec; procedure SpliceNearJmp(FuncAddr: Pointer; NewData: TNearJmpSpliceRec); procedure SpliceLockJmp(FuncAddr: Pointer; NewData: Word); implementation //         procedure SpliceNearJmp(FuncAddr: Pointer; NewData: TNearJmpSpliceRec); var OldProtect: DWORD; begin VirtualProtect(FuncAddr, SizeOf(TNearJmpSpliceRec), PAGE_EXECUTE_READWRITE, OldProtect); try Move(NewData, FuncAddr^, SizeOf(TNearJmpSpliceRec)); finally VirtualProtect(FuncAddr, SizeOf(TNearJmpSpliceRec), OldProtect, OldProtect); FlushInstructionCache(GetCurrentProcess, FuncAddr, SizeOf(TNearJmpSpliceRec)); end; end; //         procedure SpliceLockJmp(FuncAddr: Pointer; NewData: Word); var OldProtect: DWORD; begin VirtualProtect(FuncAddr, 2, PAGE_EXECUTE_READWRITE, OldProtect); try asm mov ax, NewData mov ecx, FuncAddr lock xchg word ptr [ecx], ax end; finally VirtualProtect(FuncAddr, 2, OldProtect, OldProtect); FlushInstructionCache(GetCurrentProcess, FuncAddr, 2); end; end; function InterceptedMessageBoxA(Wnd: HWND; lpText, lpCaption: PAnsiChar; uType: UINT): Integer; stdcall; var S: AnsiString; begin //   SpliceLockJmp(HotPathSpliceRec.FuncAddr, HotPathSpliceRec.LockJmp); try //    S := AnsiString('Function interepted. Original message: ' + lpText); Result := MessageBoxA(Wnd, PAnsiChar(S), lpCaption, uType); finally //   SpliceLockJmp(HotPathSpliceRec.FuncAddr, LOCK_JMP_OPKODE); end; end; procedure InitHotPatchSpliceRec; begin //      HotPathSpliceRec.FuncAddr := GetProcAddress(GetModuleHandle(user32), 'MessageBoxA'); //      ,     Move(HotPathSpliceRec.FuncAddr^, HotPathSpliceRec.LockJmp, 2); //   JMP NEAR HotPathSpliceRec.SpliceRec.JmpOpcode := $E9; //    HotPathSpliceRec.SpliceRec.Offset := PAnsiChar(@InterceptedMessageBoxA) + 5 - PAnsiChar(HotPathSpliceRec.FuncAddr) - SizeOf(TNearJmpSpliceRec); end; end.  unit uHotPachSplice; interface uses Windows, Classes, Controls, Forms, StdCtrls; type TForm1 = class(TForm) Button1: TButton; procedure FormCreate(Sender: TObject); procedure Button1Click(Sender: TObject); end; var Form1: TForm1; implementation uses CommonHotPatch; {$R *.dfm} procedure TForm1.FormCreate(Sender: TObject); begin //     InitHotPatchSpliceRec; //     NOP- SpliceNearJmp(PAnsiChar(HotPathSpliceRec.FuncAddr) - 5, HotPathSpliceRec.SpliceRec); //  MessageBoxW SpliceLockJmp(HotPathSpliceRec.FuncAddr, LOCK_JMP_OPKODE); end; procedure TForm1.Button1Click(Sender: TObject); const TestStr: AnsiString = 'Test MessageBoxA Message'; begin MessageBoxA(0, PAnsiChar(TestStr), nil, 0); end; end.  program hook_loader; {$APPTYPE CONSOLE} uses Windows; var hLib: THandle; HookProcAddr: Pointer; HookHandle: HHOOK; begin hLib := LoadLibrary('hook_splice_lib.dll'); try HookProcAddr := GetProcAddress(hLib, 'HookProc'); Writeln('MessageBoxA intercepted, press ENTER to resume...'); HookHandle := SetWindowsHookEx(WH_GETMESSAGE, HookProcAddr, hLib, 0); Readln; UnhookWindowsHookEx(HookHandle); finally FreeLibrary(hLib); end; end.  library hook_splice_lib; uses Windows, CommonHotPatch in '..\common\CommonHotPatch.pas'; {$R *.res} procedure DLLEntryPoint(dwReason: DWORD); begin case dwReason of DLL_PROCESS_ATTACH: begin //     InitHotPatchSpliceRec; //     NOP- SpliceNearJmp(PAnsiChar(HotPathSpliceRec.FuncAddr) - 5, HotPathSpliceRec.SpliceRec); //  MessageBoxW SpliceLockJmp(HotPathSpliceRec.FuncAddr, LOCK_JMP_OPKODE); end; DLL_PROCESS_DETACH: begin //      SpliceLockJmp(HotPathSpliceRec.FuncAddr, HotPathSpliceRec.LockJmp); end; end; end; function HookProc(Code: Integer; WParam: WPARAM; LParam: LPARAM): LRESULT; stdcall; begin Result := CallNextHookEx(0, Code, WParam, LParam); end; exports HookProc; begin DLLProc := @DLLEntryPoint; DLLEntryPoint(DLL_PROCESS_ATTACH); end.  program test_console8; {$APPTYPE CONSOLE} uses Windows; begin Writeln('Press enter to show message...'); Readln; MessageBoxA(0, 'First message', '', 0); Writeln('Press enter to show message...'); Readln; MessageBoxA(0, 'Second message', '', 0); end.  procedure SelfUnload(lpParametr: Pointer); stdcall; begin FreeLibraryAndExitThread(HInstance, 0); end; exports SelfUnload;  const DllName = 'thread_splice_lib.dll'; function InjectLib(ProcessID: Integer): Boolean; var Process: HWND; ThreadRtn: FARPROC; DllPath: AnsiString; RemoteDll: Pointer; BytesWriten: DWORD; Thread: DWORD; ThreadId: DWORD; begin Result := False; //   Process := OpenProcess(PROCESS_CREATE_THREAD or PROCESS_VM_OPERATION or PROCESS_VM_WRITE, True, ProcessID); if Process = 0 then Exit; try //       DllPath := AnsiString(ExtractFilePath(ParamStr(0)) + DLLName) + #0; RemoteDll := VirtualAllocEx(Process, nil, Length(DllPath), MEM_COMMIT or MEM_TOP_DOWN, PAGE_READWRITE); if RemoteDll = nil then Exit; try //         if not WriteProcessMemory(Process, RemoteDll, PChar(DllPath), Length(DllPath), BytesWriten) then Exit; if BytesWriten <> DWORD(Length(DllPath)) then Exit; //     Kernel32.dll ThreadRtn := GetProcAddress(GetModuleHandle('Kernel32.dll'), 'LoadLibraryA'); if ThreadRtn = nil then Exit; //    Thread := CreateRemoteThread(Process, nil, 0, ThreadRtn, RemoteDll, 0, ThreadId); if Thread = 0 then Exit; try //     ... Result := WaitForSingleObject(Thread, INFINITE) = WAIT_OBJECT_0; finally CloseHandle(Thread); end; finally VirtualFreeEx(Process, RemoteDll, 0, MEM_RELEASE); end; finally CloseHandle(Process); end; end;  function ResumeLib(ProcessID: Integer): Boolean; var hLibHandle: THandle; hModuleSnap: THandle; ModuleEntry: TModuleEntry32; OpCodeData: Word; Process: HWND; BytesWriten: DWORD; Thread: DWORD; ThreadId: DWORD; ExitCode: DWORD; PLibHandle: PDWORD; OpCode: PWORD; CurrUnloadAddrOffset: DWORD; UnloadAddrOffset: DWORD; begin Result := False; //          hLibHandle := LoadLibrary(PChar(DLLName)); try UnloadAddrOffset := DWORD(GetProcAddress(hLibHandle, 'SelfUnload')) - hLibHandle; if UnloadAddrOffset = -hLibHandle then Exit; finally FreeLibrary(hLibHandle); end; //        hModuleSnap := CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, ProcessID); if hModuleSnap <> INVALID_HANDLE_VALUE then try FillChar(ModuleEntry, SizeOf(TModuleEntry32), #0); ModuleEntry.dwSize := SizeOf(TModuleEntry32); if not Module32First(hModuleSnap, ModuleEntry) then Exit; repeat if AnsiUpperCase(ModuleEntry.szModule) = AnsiUpperCase(DLLName) then begin //     CurrUnloadAddrOffset := ModuleEntry.hModule + UnloadAddrOffset; Break; end; until not Module32Next(hModuleSnap, ModuleEntry); finally CloseHandle(hModuleSnap); end; //   Process := OpenProcess(PROCESS_CREATE_THREAD or PROCESS_VM_OPERATION or PROCESS_VM_WRITE, True, ProcessID); if Process = 0 then Exit; try //   jmp [ebx] OpCode := VirtualAllocEx(Process, nil, 2, MEM_COMMIT or MEM_TOP_DOWN, PAGE_READWRITE); if OpCode = nil then Exit; try OpCodeData := $23FF; if not WriteProcessMemory(Process, OpCode, @OpCodeData, 2, BytesWriten) then Exit; //     (    EBX   ) PLibHandle := VirtualAllocEx(Process, nil, 4, MEM_COMMIT or MEM_TOP_DOWN, PAGE_READWRITE); if PLibHandle = nil then Exit; try if not WriteProcessMemory(Process, PLibHandle, @CurrUnloadAddrOffset, 4, BytesWriten) then Exit; //   Thread := CreateRemoteThread(Process, nil, 0, OpCode, PLibHandle, 0, ThreadId); if Thread = 0 then Exit; try //     ... if (WaitForSingleObject(Thread, INFINITE) = WAIT_OBJECT_0) then if GetExitCodeThread(Thread, ExitCode) then Result := ExitCode = 0; finally CloseHandle(Thread); end; finally VirtualFreeEx(Process, PLibHandle, 0, MEM_RELEASE); end; finally VirtualFreeEx(Process, OpCode, 0, MEM_RELEASE); end; finally CloseHandle(Process); end; end; Source: https://habr.com/ru/post/178393/
All Articles