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