Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi KeyboardLayout einer fremden Anwendung ändern (https://www.delphipraxis.net/133744-keyboardlayout-einer-fremden-anwendung-aendern.html)

Zacherl 7. Mai 2009 21:46


KeyboardLayout einer fremden Anwendung ändern
 
Hey,

ich versuche bei einem Spiel das Keyboard Layout aus meiner eigenen Anwendung heraus zu ändern. LoadKeyboardLayout() wirkt sich aber nur auf den aufrufenden Thread aus und auch meine Versuche mit DLL Injection und dem KLF_SETFORPROCESS Flag schlagen fehl. (MSDN sagt, dass dieses Flag bei Vista auch nicht verfügbar ist)

Hat jemand eine Idee, möglichst ohne den Kontext des Zielthreads zu manipulieren? Die Eingabeschemagebietsleiste muss das Ganze ja auch irgendwie schaffen!

Gruß Zacherl

Hobby-Programmierer 7. Mai 2009 22:08

Re: KeyboardLayout einer fremden Anwendung ändern
 
rein theoretisch: Würde das nicht funktionieren die Keys zu hooken und statt den Key weiterzuleiten (CallNextHook) einen eigenen Key zu simulieren?

igel457 8. Mai 2009 15:37

Re: KeyboardLayout einer fremden Anwendung ändern
 
Wie ließt das Spiel seine Zeichen von der Tastatur ein? Viele Spiele verwenden hierzu DirectInput, welches IMHO nur die physikalische Tastennummer übermittelt und nicht unbedingt direkt an das Keyboardlayout gekoppelt ist.

Zacherl 8. Mai 2009 16:11

Re: KeyboardLayout einer fremden Anwendung ändern
 
Ja vermute es ist DirectInput, da das Spiel auch auf DX basiert.

Zacherl 8. Mai 2009 16:39

Re: KeyboardLayout einer fremden Anwendung ändern
 
Folgendermaßen ist jetzt mein Ansatz: Dieser funktioniert, wenn der Zielprozess schon einige Zeit aktiv war. Bei Verwendung von CREATE_SUSPENDED im CreateProcess() schmiert die Zielanwendung nach meinem Hijack allerdings sofort ab.

Delphi-Quellcode:
function W32HijackThread(hProcess, hThread: Cardinal; Code: Pointer;
  CodeLen: DWord): Boolean;
var
  lpRoutine: Pointer;
  dwWritten: DWord;
  lpNewContext: TContext;
  ASMStub: Array[0..4] of Byte;
begin
  Result := false;
  SuspendThread(hThread);
  try
    FillChar(lpNewContext, SizeOf(TContext), #0);
    lpNewContext.ContextFlags := CONTEXT_CONTROL;
    if not GetThreadContext(hThread, lpNewContext) then
      Exit;
    lpRoutine := VirtualAllocEx(hProcess, nil, CodeLen + 5, MEM_COMMIT,
      PAGE_EXECUTE_READWRITE);
    if not Assigned(lpRoutine) then
      Exit;
    ASMStub[0] := $68;
    CopyMemory(@ASMStub[1], @lpNewContext.Eip, 4);
    if not WriteProcessMemory(hProcess, lpRoutine, @AsmStub[0], 5,
      dwWritten) then
      Exit;
    if not WriteProcessMemory(hProcess, Pointer(Cardinal(lpRoutine) + 5), Code,
      CodeLen, dwWritten) then
      Exit;
    lpNewContext.Eip := DWord(lpRoutine);
    Result := SetThreadContext(hThread, lpNewContext);
  finally
    ResumeThread(hThread);
  end;
end;
Delphi-Quellcode:
procedure HijackProc; assembler;
asm
  pusha
  nop
  push dword ptr 129
  push dword ptr $FFFFFFFF
  mov eax, $FFFFFFFF
  //call eax
  popa
end;
procedure HijackProcEnd; begin end;

const
  LANGUAGEID: PAnsiChar = '00000409' + #0;

var
  dwHijackSize,
  dwOldProtect,
  dwAddress,
  dwWritten: DWord;
  lpLang: Pointer;
  lpProcessInfo: TProcessInformation;
  lpStartupInfo: TStartupInfo;
begin
  FillChar(lpStartupInfo, SizeOf(TStartupInfo), #0);
  if CreateProcess('C:\Program Files (x86)\Subagames\CrossFire\crossfire.exe', nil, nil, nil, false, CREATE_SUSPENDED,
    nil, nil, lpStartupInfo, lpProcessInfo) then
  begin
    W32InjectModule('user32.dll', lpProcessInfo.hProcess);
    lpLang := VirtualAllocEx(lpProcessInfo.hProcess, nil, 9, MEM_COMMIT,
      PAGE_EXECUTE_READWRITE);
    if Assigned(lpLang) and WriteProcessMemory(lpProcessInfo.hProcess, lpLang,
      LANGUAGEID, 9, dwWritten) then
    begin
      dwHijackSize := Cardinal(@HijackProcEnd) - Cardinal(@HijackProc);
      if VirtualProtect(@HijackProc, dwHijackSize, PAGE_EXECUTE_READWRITE,
        dwOldProtect) then
      begin
        dwAddress := DWord(lpLang);
        CopyMemory(Pointer(Cardinal(@HijackProc) + 9), @dwAddress, 4);
        dwAddress := DWord(GetProcAddress(LoadLibrary('user32.dll'),
          'LoadKeyboardLayoutA'));
        CopyMemory(Pointer(Cardinal(@HijackProc) + 14), @dwAddress, 4);
        W32HijackThread(lpProcessInfo.hProcess, lpProcessInfo.hThread,
          @HijackProc, dwHijackSize);
      end;
    end;  
    ResumeThread(lpProcessInfo.hThread);
  end;
end;
Hat jemand ne Idee, woran das liegen könnte?

Gruß Zacherl

Apollonius 8. Mai 2009 16:50

Re: KeyboardLayout einer fremden Anwendung ändern
 
Ein Teil der Prozess-Initialisation wird vom ersten Thread des Prozesses durchgeführt, der erfolgreich startet, bevor er die eigentliche Thread-Funktion ausführt. Vermutlich wird durch das SetThreadContext diese Initialisation unterbunden. Das ist allerdings nur geraten.

Zacherl 9. Mai 2009 12:38

Re: KeyboardLayout einer fremden Anwendung ändern
 
An sowas in der Art dachte ich auch. Nur wie setzt MS das Layout für fremde Prozesse?

Zacherl 11. Mai 2009 10:43

Re: KeyboardLayout einer fremden Anwendung ändern
 
* push *


Alle Zeitangaben in WEZ +1. Es ist jetzt 19:23 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz