Tastatur Hook
-
quasimodule schrieb:
DarkShadow44 schrieb:
Du hast ja die Adresse der Funktion, bzw. kannst sie einfach rausfinden. Dann einfach das erste Byte einlesen und schauen welchem Opcode das enspricht, daran siehst du dann die Länger der Anweisung.
Wenn es doch so einfach wäre
Dokumentiert hier:
http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/NT%20Objects/Process/NtCreateProcess.htmlEDIT:
Ein Bsp. für CreateProcessW() (für NtCreateProcess musst Du halt den Code ein bisschen anpassen) dass Dir zeigt wie man in etwa auf Win x86 inline api hooking betreibt (aus diesem Code muss eine Dll erstellt werden + eine Prozess der die exportierten Funktionen in dieser DLL aufruft -> installhook()). Geht natürlich auch noch anders zbsp. IAT hooking, aber das ist hier nicht Thema. Und für mich ist das hier auch der letzte Post, da ich schon zu viel gelabert habe.
Du musst Dich halt einfach mit dem Thema befassen. Bücher lesen oder Tutorials die etwas taugen. Auf X64 funktioniert der Code nicht da ein 0xE9 == jmp (unconditional jump) nur 32Bit Sprungweiten unterstützt. Auf X64 arbeitet man zusätzlich mit Trampolin Techniken.Aber wenn man mit der Materie nicht vertraut ist wird man bei einem X64 inline Api hook graue Haare bekommen...
Es gibt aber auch diverse Libs die alles einfacher machen. Zu empfehlen wäre da Mhook 2.3 -> http://codefromthe70s.org/mhook23.aspx läuf unter x86 und x64 !
#include <windows.h> #include <psapi.h> #include <stdio.h> #include "hooking_dll.h" #pragma data_seg("shared") HINSTANCE hinstanc = 0; HHOOK hkb = 0; #pragma data_seg() #pragma comment(linker, "/Section:shared,rws") #define SIZE 5 typedef BOOL (WINAPI *pCreateProcessW) (LPCTSTR lpApplicationName ,LPTSTR lpCommandLine ,LPSECURITY_ATTRIBUTES lpProcessAttributes ,LPSECURITY_ATTRIBUTES lpThreadAttributes ,BOOL bInheritHandles ,DWORD dwCreationFlags ,LPVOID lpEnvironment ,LPCTSTR lpCurrentDirectory ,LPSTARTUPINFO lpStartupInfo ,LPPROCESS_INFORMATION lpProcessInformation); BOOL WINAPI MyCreateProcessW(LPCTSTR lpApplicationName ,LPTSTR lpCommandLine ,LPSECURITY_ATTRIBUTES lpProcessAttributes ,LPSECURITY_ATTRIBUTES lpThreadAttributes ,BOOL bInheritHandles ,DWORD dwCreationFlags ,LPVOID lpEnvironment ,LPCTSTR lpCurrentDirectory ,LPSTARTUPINFO lpStartupInfo ,LPPROCESS_INFORMATION lpProcessInformation); void BeginRedirect(LPVOID newFunction); pCreateProcessW pOrigMBAddress = NULL; BYTE oldBytes[SIZE] = {0}; BYTE JMP[SIZE] = {0}; DWORD oldProtect, myProtect = PAGE_EXECUTE_READWRITE; int WINAPI DllMain(HMODULE hDLL ,DWORD Reason ,LPVOID Reserved) { switch(Reason) { case DLL_PROCESS_ATTACH: hinstanc = hDLL; pOrigMBAddress = (pCreateProcessW) GetProcAddress( GetModuleHandleA("Kernel32.dll") ,"CreateProcessW"); if(pOrigMBAddress != NULL) { BeginRedirect(MyCreateProcessW); OutputDebugStringA("redirect"); } else { OutputDebugStringA("no redirect"); } break; case DLL_PROCESS_DETACH: if(pOrigMBAddress != NULL) { VirtualProtect((LPVOID)pOrigMBAddress ,SIZE ,myProtect ,&oldProtect); memcpy(pOrigMBAddress ,oldBytes ,SIZE); VirtualProtect((LPVOID) pOrigMBAddress ,SIZE ,oldProtect ,NULL); } break; } return TRUE; } LRESULT CALLBACK CBTProc(int nCode ,WPARAM wParam ,LPARAM lParam ) { return CallNextHookEx(hkb, nCode, wParam, lParam ); } EXPORT BOOL CALLBACK installhook() { hkb = SetWindowsHookEx(WH_CBT ,CBTProc ,hinstanc ,0); return 0; } EXPORT BOOL CALLBACK uninstallhook() { return UnhookWindowsHookEx(hkb); } void BeginRedirect(LPVOID newFunction) { BYTE tempJMP[SIZE] = {0xE9 ,0x90 ,0x90 ,0x90 ,0x90 }; DWORD JMPSize; memcpy(JMP, tempJMP, SIZE); JMPSize = ((DWORD)newFunction - (DWORD)pOrigMBAddress - SIZE); VirtualProtect((LPVOID)pOrigMBAddress ,SIZE ,PAGE_EXECUTE_READWRITE ,&oldProtect); memcpy(oldBytes ,pOrigMBAddress ,SIZE); memcpy(&JMP[1] ,&JMPSize ,4); memcpy(pOrigMBAddress ,JMP ,SIZE); VirtualProtect((LPVOID) pOrigMBAddress ,SIZE ,oldProtect ,NULL); } BOOL WINAPI MyCreateProcessW(LPCTSTR lpApplicationName ,LPTSTR lpCommandLine ,LPSECURITY_ATTRIBUTES lpProcessAttributes ,LPSECURITY_ATTRIBUTES lpThreadAttributes ,BOOL bInheritHandles ,DWORD dwCreationFlags ,LPVOID lpEnvironment ,LPCTSTR lpCurrentDirectory ,LPSTARTUPINFO lpStartupInfo ,LPPROCESS_INFORMATION lpProcessInformation) { BOOL retValue; wchar_t msg[1000] = {0}; int ret = 0; VirtualProtect((LPVOID)pOrigMBAddress ,SIZE ,myProtect ,NULL); memcpy(pOrigMBAddress ,oldBytes ,SIZE); --> Hier kannst Du den Prozess übernehmen. bzw. die Ausführung verhindern! retValue = (pOrigMBAddress) (lpApplicationName ,lpCommandLine ,lpProcessAttributes ,lpThreadAttributes ,bInheritHandles ,dwCreationFlags ,lpEnvironment ,lpCurrentDirectory ,lpStartupInfo ,lpProcessInformation); memcpy(pOrigMBAddress ,JMP ,SIZE); VirtualProtect((LPVOID) pOrigMBAddress ,SIZE ,oldProtect ,NULL); return retValue; }
-
Der Windows Explorer zum Bsp. braucht aber intern NtCreateProcessEx das aber praktisch nirgendwo Dokumentiert ist. Die Funktion müsstest Du hooken um denn Prozessstart vom Explorer.exe zu überwachen um den Processstart ganz früh zu erkennen!
Api Monitor v2.0 ist eine Hervorragendes Stück Code das sich in alle laufende Prozesse einklinkt und die Api Call's der Prozesse überwacht. Das tool kennt alle Funktionen der libs von MS, auch die meisten undokumentierten!
Ablauf:
1. Api Monitor v2.0 starten.
2. Auswählen welcher Prozess überwacht werden soll.
3. Filter anwenden. NtCreateprocessEx in unserem Fall. -> ntdll.dll
4. Jetzt kannst Du ein Programm Deiner Wahl starten via Desktop/Explorer.Und jetzt solltest Du den function call sehen den Explorer.exe absetzt sowie vieles mehr. Danach denn Hook zu schreiben ist ein Kinderspiel!
voila
-
-lowbyte- schrieb:
quasimodule schrieb:
DarkShadow44 schrieb:
Du hast ja die Adresse der Funktion, bzw. kannst sie einfach rausfinden. Dann einfach das erste Byte einlesen und schauen welchem Opcode das enspricht, daran siehst du dann die Länger der Anweisung.
Wenn es doch so einfach wäre
Dokumentiert hier:
http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/NT%20Objects/Process/NtCreateProcess.htmlPasst irgendwie nicht ganz zusammen
-lowbyte- schrieb:
Ein Bsp. für CreateProcessW() (für NtCreateProcess musst Du halt den Code ein bisschen anpassen) dass Dir zeigt wie man in etwa auf Win x86 inline api hooking betreibt (aus diesem Code muss eine Dll erstellt werden + eine Prozess der die exportierten Funktionen in dieser DLL aufruft -> installhook()). Geht natürlich auch noch anders zbsp. IAT hooking, aber das ist hier nicht Thema. Und für mich ist das hier auch der letzte Post, da ich schon zu viel gelabert habe.
Du musst Dich halt einfach mit dem Thema befassen. Bücher lesen oder Tutorials die etwas taugen. Auf X64 funktioniert der Code nicht da ein 0xE9 == jmp (unconditional jump) nur 32Bit Sprungweiten unterstützt. Auf X64 arbeitet man zusätzlich mit Trampolin Techniken.Aber wenn man mit der Materie nicht vertraut ist wird man bei einem X64 inline Api hook graue Haare bekommen...
Es gibt aber auch diverse Libs die alles einfacher machen. Zu empfehlen wäre da Mhook 2.3 -> http://codefromthe70s.org/mhook23.aspx läuf unter x86 und x64 !
Eindeutig, du hast zu viel gelabert ... wiederlegt aber nicht die Tatsache, dass nur bei den wenigsten Befehle in der x86 Architekturen, die Größe aus den Opcode-Bytes ermitteln werden kann. (Mal davon abgesehen, das das erste Byte auch eins der 4 möglichen Präfixes sein kann).
Trotzdem danke dass mich über eine Methode belehrt hast, die nur dann funktioniert, wenn das Zielprogramm die IAT auch während der Laufzeit benutzt
-
edit
-
quasimodule schrieb:
wiederlegt aber nicht die Tatsache, dass nur bei den wenigsten Befehle in der x86 Architekturen, die Größe aus den Opcode-Bytes ermitteln werden kann. (Mal davon abgesehen, das das erste Byte auch eins der 4 möglichen Präfixes sein kann).
Doch das geht verdammt gut. Wie sollte man sonst Anwendungen disassemblieren können ? Schau dir mal Debugger wie OllyDbg an, der kann das ziemlich gut
Die Prefixe sind AFAIK eindeutig, d.h. kein Opcode ist gleich einem Prefix, insofern stellen die kein Problem da.
-
quasimodule schrieb:
Trotzdem danke dass mich über eine Methode belehrt hast, die nur dann funktioniert, wenn das Zielprogramm die IAT auch während der Laufzeit benutzt
Wie bitte? Irgendwie scheinst Du da was durcheinander zu bringen!
Die meisten Funktionen auf x86 windows systemen haben ein Prolog der 5byte ist und so aussehen:
8bff mov edi, edi 55 push ebp 8bec mov ebp, esp
Die überschreibst Du dann mit dem jmp (E9 ,? ,? ,? ,?)zu deiner funktion.
Bei explizit gebundenen Funktionen, mittels LoadLibrary und GetProcAddress, wird kein IAT-Eintrag erstellt.
Inline Hooking bietet nicht nur die Möglichkeit, API-Funktionen zu hooken, sondern es lässt sich mit dieser Methode jede beliebige Funktion hooken. Im Gegensatz zur Modifikation der IAT ist es beim Inline Hooking irrelevant, ob die Bibliothek, welche die zu hookende Funktion exportiert, implizit oder explizit geladen wurde. Und im Gegensatz zur Modifikation der EAT hat diese Art, Hooks zu installieren, auch Einfluss auf Prozesse, welche bereits komplett geladen wurden, da direkt der Code der Funktion im Speicher verändert wird, anstatt nur eine modifizierte Kopie der zu hookenden Funktion zu erstellen. Außerdem besteht beim Inline Hooking nicht das Problem des kleinen Zeitfensters. All das macht das Inline Hooking wohl zu einer der effektivsten und effizientesten Methoden, einen Hook zu installieren.
-
DarkShadow44 schrieb:
quasimodule schrieb:
wiederlegt aber nicht die Tatsache, dass nur bei den wenigsten Befehle in der x86 Architekturen, die Größe aus den Opcode-Bytes ermitteln werden kann. (Mal davon abgesehen, das das erste Byte auch eins der 4 möglichen Präfixes sein kann).
Doch das geht verdammt gut. Wie sollte man sonst Anwendungen disassemblieren können ?
Sicherlich nicht indem man das erste Byte zur Ermittlung der Befehlsgröße heranzieht! - das ist genau der Punk den ich in meine ursprünglichen Post hervorheben wollte.
-lowbyte- schrieb:
Wie bitte? Irgendwie scheinst Du da was durcheinander zu bringen!
Entschuldigung, ich hatte deine zusammenhangslosen Post nur überflogen und war der Meinung es handelt sich um einen IAT Hook.
-lowbyte- schrieb:
Die meisten Funktionen auf x86 windows systemen haben ein Prolog der 5byte ist und so aussehen
Und auf diese Annahme soll man sich dann verlassen? Freie Disassmbler librarys gibt genug, also kein Notwendigkeit um sich auf Annahmen zu verlassen.
-
quasimodule schrieb:
-lowbyte- schrieb:
Die meisten Funktionen auf x86 windows systemen haben ein Prolog der 5byte ist und so aussehen
Und auf diese Annahme soll man sich dann verlassen? Freie Disassmbler librarys gibt genug, also kein Notwendigkeit um sich auf Annahmen zu verlassen.
Ja das stimmt, deswegen schaut man sich das ganze ja auch vorher mit dem debugger an.
-
-lowbyte- schrieb:
Ja das stimmt, deswegen schaut man sich das ganze ja auch vorher mit dem debugger an.
Und das macht man dann nach jedem Update...
-
quasimodule schrieb:
-lowbyte- schrieb:
Ja das stimmt, deswegen schaut man sich das ganze ja auch vorher mit dem debugger an.
Und das macht man dann nach jedem Update...
Bei 99% der Updates kannst Du sicher sein dass sich nichts ändert! Aber verlässlich ist das natürlich nicht da haste schon recht...Um die Bytes herauszufinden macht man das Professionell natürlich mit einer Disassembler library. Oder man schreibt sich selber eine