const LOCK_JMP_OPKODE: Word = $F9EB; JMP_OPKODE: Word = $E9; type // JMP NEAR OFFSET TNearJmpSpliceRec = packed record JmpOpcode: Byte; Offset: DWORD; end; THotPachSpliceData = packed record FuncAddr: FARPROC; SpliceRec: TNearJmpSpliceRec; LockJmp: Word; end; const NearJmpSpliceRecSize = SizeOf(TNearJmpSpliceRec); LockJmpOpcodeSize = SizeOf(Word);
// procedure SpliceNearJmp(FuncAddr: Pointer; NewData: TNearJmpSpliceRec); var OldProtect: DWORD; begin VirtualProtect(FuncAddr, NearJmpSpliceRecSize, PAGE_EXECUTE_READWRITE, OldProtect); try Move(NewData, FuncAddr^, NearJmpSpliceRecSize); finally VirtualProtect(FuncAddr, NearJmpSpliceRecSize, OldProtect, OldProtect); end; end; // procedure SpliceLockJmp(FuncAddr: Pointer; NewData: Word); var OldProtect: DWORD; begin VirtualProtect(FuncAddr, LockJmpOpcodeSize, PAGE_EXECUTE_READWRITE, OldProtect); try asm mov ax, NewData mov ecx, FuncAddr lock xchg word ptr [ecx], ax end; finally VirtualProtect(FuncAddr, LockJmpOpcodeSize, OldProtect, OldProtect); end; end;
// procedure InitHotPatchSpliceRec(const LibraryName, FunctionName: string; InterceptHandler: Pointer; out HotPathSpliceRec: THotPachSpliceData); begin // HotPathSpliceRec.FuncAddr := GetProcAddress(GetModuleHandle(PChar(LibraryName)), PChar(FunctionName)); // , Move(HotPathSpliceRec.FuncAddr^, HotPathSpliceRec.LockJmp, LockJmpOpcodeSize); // JMP NEAR HotPathSpliceRec.SpliceRec.JmpOpcode := JMP_OPKODE; // ( NearJmpSpliceRecSize , // .. ) HotPathSpliceRec.SpliceRec.Offset := PAnsiChar(InterceptHandler) - PAnsiChar(HotPathSpliceRec.FuncAddr); end;
var HotPathSpliceRec: THotPachSpliceData; WindowList: TStringList;
procedure TForm1.FormCreate(Sender: TObject); begin // InitHotPatchSpliceRec(user32, 'CreateWindowExW', @InterceptedCreateWindowExW, HotPathSpliceRec); // NOP- SpliceNearJmp(PAnsiChar(HotPathSpliceRec.FuncAddr) - NearJmpSpliceRecSize, HotPathSpliceRec.SpliceRec); end;
function InterceptedCreateWindowExW(dwExStyle: DWORD; lpClassName: PWideChar; lpWindowName: PWideChar; dwStyle: DWORD; X, Y, nWidth, nHeight: Integer; hWndParent: HWND; hMenu: HMENU; hInstance: HINST; lpParam: Pointer): HWND; stdcall; var S: string; Index: Integer; begin // SpliceLockJmp(HotPathSpliceRec.FuncAddr, HotPathSpliceRec.LockJmp); try // Index := -1; if not IsBadReadPtr(lpClassName, 1) then begin S := 'ClassName: ' + string(lpClassName); S := IntToStr(WindowList.Count + 1) + ': ' + S; Index := WindowList.Add(S); end; // Result := CreateWindowExW(dwExStyle, lpClassName, lpWindowName, dwStyle, X, Y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam); // if Index >= 0 then begin S := S + ', handle: ' + IntToStr(Result); WindowList[Index] := S; end; finally // SpliceLockJmp(HotPathSpliceRec.FuncAddr, LOCK_JMP_OPKODE); end; end;
procedure TForm1.Button1Click(Sender: TObject); begin // CreateWindowExW SpliceLockJmp(HotPathSpliceRec.FuncAddr, LOCK_JMP_OPKODE); try // WindowList := TStringList.Create; try // OpenDialog1.Execute; // Memo1.Lines.Text := WindowList.Text; finally WindowList.Free; end; finally // SpliceLockJmp(HotPathSpliceRec.FuncAddr, HotPathSpliceRec.LockJmp); end; end;
type TdlgWindowTree = class(TForm) WindowTreeView: TTreeView; procedure FormCreate(Sender: TObject); private procedure Sys_Windows_Tree(Node: TTreeNode; AHandle: HWND; ALevel: Integer); end; ... procedure TdlgWindowTree.FormCreate(Sender: TObject); begin Sys_Windows_Tree(nil, GetDesktopWindow, 0); end; procedure TdlgWindowTree.Sys_Windows_Tree(Node: TTreeNode; AHandle: HWND; ALevel: Integer); type TRootNodeData = record Node: TTreeNode; PID: Cardinal; end; var szClassName, szCaption, szLayoutName: array[0..MAXCHAR - 1] of Char; szFileName : array[0..MAX_PATH - 1] of Char; Result: String; PID, TID: Cardinal; I: Integer; RootItems: array of TRootNodeData; IsNew: Boolean; begin // while AHandle <> 0 do begin // GetClassName(AHandle, szClassName, MAXCHAR); // ( Caption) GetWindowText(AHandle, szCaption, MAXCHAR); // if GetWindowModuleFilename(AHandle, szFileName, SizeOf(szFileName)) = 0 then FillChar(szFileName, 256, #0); TID := GetWindowThreadProcessId(AHandle, PID); // AttachThreadInput(GetCurrentThreadId, TID, True); VerLanguageName(GetKeyboardLayout(TID) and $FFFF, szLayoutName, MAXCHAR); AttachThreadInput(GetCurrentThreadId, TID, False); // Result := Format('%s [%s] Caption = %s, Handle = %d, Layout = %s', [String(szClassName), String(szFileName), String(szCaption), AHandle, String(szLayoutName)]); // if ALevel in [0..1] then begin IsNew := True; for I := 0 to Length(RootItems) - 1 do if RootItems[I].PID = PID then begin Node := RootItems[I].Node; IsNew := False; Break; end; if IsNew then begin SetLength(RootItems, Length(RootItems) + 1); RootItems[Length(RootItems) - 1].PID := PID; RootItems[Length(RootItems) - 1].Node := WindowTreeView.Items.AddChild(nil, 'PID: ' + IntToStr(PID)); Node := RootItems[Length(RootItems) - 1].Node; end; end; // Sys_Windows_Tree(WindowTreeView.Items.AddChild(Node, Result), GetWindow(AHandle, GW_CHILD), ALevel + 1); // ( ) AHandle := GetNextWindow(AHandle, GW_HWNDNEXT); end; end;
type TCreateWindowExW = function(dwExStyle: DWORD; lpClassName: PWideChar; lpWindowName: PWideChar; dwStyle: DWORD; X, Y, nWidth, nHeight: Integer; hWndParent: HWND; AMenu: HMENU; hInstance: HINST; lpParam: Pointer): HWND; stdcall; function InterceptedCreateWindowExW(dwExStyle: DWORD; lpClassName: PWideChar; lpWindowName: PWideChar; dwStyle: DWORD; X, Y, nWidth, nHeight: Integer; hWndParent: HWND; hMenu: HMENU; hInstance: HINST; lpParam: Pointer): HWND; stdcall; var S: string; Index: Integer; ACreateWindowExW: TCreateWindowExW; begin // Index := -1; if not IsBadReadPtr(lpClassName, 1) then begin S := 'ClassName: ' + string(lpClassName); S := IntToStr(WindowList.Count + 1) + ': ' + S; Index := WindowList.Add(S); end; // @ACreateWindowExW := PAnsiChar(HotPathSpliceRec.FuncAddr) + LockJmpOpcodeSize; Result := ACreateWindowExW(dwExStyle, lpClassName, lpWindowName, dwStyle, X, Y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam); // if Index >= 0 then begin S := S + ', handle: ' + IntToStr(Result); WindowList[Index] := S; end; end;
function TrampolineRtlCreateUnicodeString(DestinationString: PUNICODE_STRING; SourceString: PWideChar): Integer; stdcall; begin asm db $90, $90, $90, $90, $90, $90, $90 end; end; function InterceptedRtlCreateUnicodeString(DestinationString: PUNICODE_STRING; SourceString: PWideChar): Integer; stdcall; begin Result := TrampolineRtlCreateUnicodeString(DestinationString, SourceString); ShowMessage(DestinationString^.Buffer); end;
function TrampolineRtlCreateUnicodeString(DestinationString: PUNICODE_STRING; SourceString: PWideChar): Integer; stdcall; begin asm push $0C // jmp $77B062FB // end; end;
// procedure InitHotPatchSpliceRecEx(const LibraryName, FunctionName: string; InterceptHandler, Trampoline: Pointer; out HotPathSpliceRec: THotPachSpliceData); var OldProtect: DWORD; TrampolineSplice: TNearJmpSpliceRec; begin // HotPathSpliceRec.FuncAddr := GetProcAddress(GetModuleHandle(PChar(LibraryName)), PChar(FunctionName)); // , Move(HotPathSpliceRec.FuncAddr^, HotPathSpliceRec.LockJmp, LockJmpOpcodeSize); // VirtualProtect(Trampoline, LockJmpOpcodeSize + NearJmpSpliceRecSize, PAGE_EXECUTE_READWRITE, OldProtect); try Move(HotPathSpliceRec.LockJmp, Trampoline^, LockJmpOpcodeSize); TrampolineSplice.JmpOpcode := JMP_OPKODE; TrampolineSplice.Offset := PAnsiChar(HotPathSpliceRec.FuncAddr) - PAnsiChar(Trampoline) - NearJmpSpliceRecSize; Trampoline := PAnsiChar(Trampoline) + LockJmpOpcodeSize; Move(TrampolineSplice, Trampoline^, SizeOf(TNearJmpSpliceRec)); finally VirtualProtect(Trampoline, LockJmpOpcodeSize + NearJmpSpliceRecSize, OldProtect, OldProtect); end; // JMP NEAR HotPathSpliceRec.SpliceRec.JmpOpcode := JMP_OPKODE; // ( NearJmpSpliceRecSize , // .. ) HotPathSpliceRec.SpliceRec.Offset := PAnsiChar(InterceptHandler) - PAnsiChar(HotPathSpliceRec.FuncAddr); end;
type UNICODE_STRING = record Length: WORD; MaximumLength: WORD; Buffer: PWideChar; end; PUNICODE_STRING = ^UNICODE_STRING; function RtlCreateUnicodeString(DestinationString: PUNICODE_STRING; SourceString: PWideChar): BOOLEAN; stdcall; external 'ntdll.dll'; ... procedure TForm2.FormCreate(Sender: TObject); begin // InitHotPatchSpliceRecEx('ntdll.dll', 'RtlCreateUnicodeString', @InterceptedRtlCreateUnicodeString, @TrampolineRtlCreateUnicodeString, HotPathSpliceRec); // NOP- SpliceNearJmp(PAnsiChar(HotPathSpliceRec.FuncAddr) - NearJmpSpliceRecSize, HotPathSpliceRec.SpliceRec); end; procedure TForm2.Button1Click(Sender: TObject); var US: UNICODE_STRING; begin // RtlCreateUnicodeString SpliceLockJmp(HotPathSpliceRec.FuncAddr, LOCK_JMP_OPKODE); try RtlCreateUnicodeString(@US, 'Test UNICODE String'); finally // SpliceLockJmp(HotPathSpliceRec.FuncAddr, HotPathSpliceRec.LockJmp); end; end;
Source: https://habr.com/ru/post/181157/
All Articles