-
-
解决WPF使用HVNC的问题-HwndHook
-
发表于: 5天前 1197
-
这里就不多介绍HVNC了 因为单纯在之前的文章已经介绍过了
https://bbs.kanxue.com/thread-264956.htm
那么我们都知道 CPP中HVNC有现成的代码(github TinyNuke)可以直接抄
https://github.com/Sts0mrg0/TinyNuke
C#中也有比如
https://github.com/moom825/xeno-rat
核心代码在
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 | public class CustomPictureBox : PictureBox { Node client; public CustomPictureBox(Node _client) { client = _client; } [DllImport( "user32.dll" )] public static extern short GetKeyState( int nVirtKey); / / Constants for clipboard data formats public const uint CF_TEXT = 1 ; / / Text format public const uint CF_BITMAP = 2 ; / / Bitmap format public const uint CF_UNICODETEXT = 13 ; / / Unicode text format public const uint CF_HDROP = 15 ; / / File format / / Import the necessary WinAPI functions [DllImport( "user32.dll" )] [ return : MarshalAs(UnmanagedType. Bool )] public static extern bool IsClipboardFormatAvailable(uint format ); [DllImport( "user32.dll" )] [ return : MarshalAs(UnmanagedType. Bool )] public static extern bool OpenClipboard(IntPtr hWndNewOwner); [DllImport( "user32.dll" )] public static extern IntPtr GetClipboardData(uint uFormat); [DllImport( "user32.dll" )] [ return : MarshalAs(UnmanagedType. Bool )] public static extern bool CloseClipboard(); [DllImport( "user32.dll" )] static extern short VkKeyScan(char c); [DllImport( "user32.dll" )] public static extern int ToAscii(uint uVirtKey, uint uScanCode, byte[] lpKeyState, out uint lpChar, uint uFlags); public Point TranslateCoordinates(Point originalCoords, Size originalScreenSize, PictureBox targetControl) { / / Calculate the scaling factors float scaleX = ( float )targetControl.Image.Width / originalScreenSize.Width; float scaleY = ( float )targetControl.Image.Height / originalScreenSize.Height; / / Apply the scaling factors int scaledX = ( int )(originalCoords.X * scaleX); int scaledY = ( int )(originalCoords.Y * scaleY); / / Get the unzoomed and offset - adjusted coordinates Point translatedCoords = UnzoomedAndAdjusted(targetControl, new Point(scaledX, scaledY)); return translatedCoords; } public static void GetClipboardFormat() { if (!OpenClipboard(IntPtr.Zero)) return ; if (IsClipboardFormatAvailable(CF_TEXT)) { IntPtr hGlobal = GetClipboardData(CF_TEXT); string clipboardText = Marshal.PtrToStringUni(hGlobal); Marshal.FreeHGlobal(hGlobal); } else if (IsClipboardFormatAvailable(CF_BITMAP)) { IntPtr hBitmap = GetClipboardData(CF_BITMAP); System.Drawing.Bitmap clipboardBitmap = System.Drawing.Bitmap.FromHbitmap(hBitmap); Marshal.FreeHGlobal(hBitmap); } else if (IsClipboardFormatAvailable(CF_UNICODETEXT)) { IntPtr hGlobal = GetClipboardData(CF_UNICODETEXT); string clipboardText = Marshal.PtrToStringUni(hGlobal); Marshal.FreeHGlobal(hGlobal); } CloseClipboard(); } private Point UnzoomedAndAdjusted(PictureBox pictureBox, Point scaledPoint) { / / Calculate the zoom factor float zoomFactor = Math. Min ( ( float )pictureBox.ClientSize.Width / pictureBox.Image.Width, ( float )pictureBox.ClientSize.Height / pictureBox.Image.Height); / / Get the displayed rectangle of the image Rectangle displayedRect = GetImageDisplayRectangle(pictureBox); / / Offset and unzoom the coordinates int translatedX = ( int )((scaledPoint.X - displayedRect.X) / zoomFactor); int translatedY = ( int )((scaledPoint.Y - displayedRect.Y) / zoomFactor); return new Point(translatedX, translatedY); } private Rectangle GetImageDisplayRectangle(PictureBox pictureBox) { if (pictureBox.SizeMode = = PictureBoxSizeMode.Normal) { return new Rectangle( 0 , 0 , pictureBox.Image.Width, pictureBox.Image.Height); } else if (pictureBox.SizeMode = = PictureBoxSizeMode.StretchImage) { return pictureBox.ClientRectangle; } else { float zoomFactor = Math. Min ( ( float )pictureBox.ClientSize.Width / pictureBox.Image.Width, ( float )pictureBox.ClientSize.Height / pictureBox.Image.Height); int imageWidth = ( int )(pictureBox.Image.Width * zoomFactor); int imageHeight = ( int )(pictureBox.Image.Height * zoomFactor); int imageX = (pictureBox.ClientSize.Width - imageWidth) / 2 ; int imageY = (pictureBox.ClientSize.Height - imageHeight) / 2 ; return new Rectangle(imageX, imageY, imageWidth, imageHeight); } } public static char GetModifiedKey(char c) { short vkKeyScanResult = VkKeyScan(c); / / a result of - 1 indicates no key translates to input character if (vkKeyScanResult = = - 1 ) return c; / / vkKeyScanResult & 0xff is the base key, without any modifiers uint code = (uint)vkKeyScanResult & 0xff ; / / set shift key pressed byte[] b = new byte[ 256 ]; b[ 0x10 ] = 0x80 ; uint r; / / return value of 1 expected ( 1 character copied to r) if ( 1 ! = ToAscii(code, code, b, out r, 0 )) return c; return (char)r; } public static bool IsAlphaNumeric(char c) { return (c > = 'a' && c < = 'z' ) || (c > = 'A' && c < = 'Z' ) || (c > = '1' && c < = '9' ); } public void TriggerWndProc(ref Message m) { WndProc(ref m); } protected override void WndProc(ref Message m) { if (this.Image = = null) { base.WndProc(ref m); return ; } byte[] payload; switch (m.Msg) { case 0x0201 : / / WM_LBUTTONDOWN case 0x0202 : / / WM_LBUTTONUP case 0x0204 : / / WM_RBUTTONDOWN case 0x0205 : / / WM_RBUTTONUP case 0x0207 : / / WM_MBUTTONDOWN case 0x0208 : / / WM_MBUTTONUP case 0x0203 : / / WM_LBUTTONDBLCLK case 0x0206 : / / WM_RBUTTONDBLCLK case 0x0209 : / / WM_MBUTTONDBLCLK case 0x0200 : / / WM_MOUSEMOVE case 0x020A : / / WM_MOUSEWHEEL int x = ( int )(m.LParam.ToInt32() & 0xFFFF ); int y = ( int )((m.LParam.ToInt32() >> 16 ) & 0xFFFF ); Point newpoint = TranslateCoordinates(new Point(x, y), this.Image.Size, this); x = newpoint.X; y = newpoint.Y; m.LParam = (IntPtr)((y << 16 ) | (x & 0xFFFF )); uint msg = (uint)m.Msg; IntPtr wParam = m.WParam; IntPtr lParam = m.LParam; int Imsg = ( int )msg; int IwParam = ( int )wParam; int IlParam = ( int )lParam; Task.Run(async () = > { payload = client.sock.Concat(new byte[] { 3 }, client.sock.IntToBytes(Imsg)); payload = client.sock.Concat(payload, client.sock.IntToBytes(IwParam)); payload = client.sock.Concat(payload, client.sock.IntToBytes(IlParam)); await client.SendAsync(payload); }).Wait(); break ; case 0x0302 : / / WM_PASTE break ; case 0x0100 : / / WM_KEYDOWN case 0x0101 : / / WM_KEYUP msg = (uint)m.Msg; wParam = m.WParam; lParam = m.LParam; / / Check if the Shift or Caps Lock key is pressed bool isShiftPressed = (GetKeyState(( int )Keys.ShiftKey) & 0x8000 ) ! = 0 ; bool isCapsLockOn = Control.IsKeyLocked(Keys.CapsLock); if (isShiftPressed || isCapsLockOn) { / / Modify the wParam to include the SHIFT or CAPSLOCK flag const int VK_SHIFT = 0x10 ; const int VK_CAPITAL = 0x14 ; if (wParam.ToInt32() = = VK_SHIFT || wParam.ToInt32() = = VK_CAPITAL) { / / Skip processing SHIFT or CAPSLOCK key release break ; } if (isShiftPressed) { msg = 0x0102 ; uint scanCode = (uint)((lParam.ToInt32() >> 16 ) & 0xFF ); byte[] keyboardState = new byte[ 256 ]; ToAscii((uint)wParam.ToInt32(), scanCode, keyboardState, out uint charCode, 0 ); wParam = (IntPtr)Convert.ToInt32(GetModifiedKey((char)charCode)); } if (isCapsLockOn) { uint scanCode = (uint)((lParam.ToInt32() >> 16 ) & 0xFF ); byte[] keyboardState = new byte[ 256 ]; ToAscii((uint)wParam.ToInt32(), scanCode, keyboardState, out uint charCode, 0 ); if (IsAlphaNumeric((char)charCode)) { msg = 0x0102 ; } } } Imsg = ( int )msg; IwParam = ( int )wParam; IlParam = ( int )lParam; Task.Run(async () = > { payload = client.sock.Concat(new byte[] { 3 }, client.sock.IntToBytes(Imsg)); payload = client.sock.Concat(payload, client.sock.IntToBytes(IwParam)); payload = client.sock.Concat(payload, client.sock.IntToBytes(IlParam)); await client.SendAsync(payload); }).Wait(); break ; } base.WndProc(ref m); } } |
他创建了一个控件来解决这个问题
其实WPF中也可以用类似的创建控件的方法来解决
但是我们这里给出第二个方案
HwndHook
什么是HwndHook
HwndHook 是一个委托(Delegate),在 WPF (Windows Presentation Foundation) 中用于处理 Win32 消息。它定义了 HwndSourceHook 方法的签名,该方法可以被用来拦截和处理发送到 WPF 窗口的消息。HwndHook 委托允许开发者在 WPF 应用程序中自定义和扩展对 Win32 消息的处理
在 WPF 中,HwndSource 类代表一个 Win32 窗口句柄(HWND),并且提供了一个方法 AddHook,允许你将一个 HwndSourceHook 委托(即 HwndHook)添加到窗口消息队列中。这个委托会在每个 Win32 消息被分派到相应的 WPF 窗口之前被调用,从而允许开发者在消息到达目标窗口之前对其进行拦截和处理
结构如下
1 2 3 4 5 | IntPtr HwndSourceHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled); / / hwnd 参数是窗口句柄 / / msg 参数是消息的标识符 / / wParam 和 lParam 参数是与消息相关的参数 / / handled 参数是一个引用参数,用于指示消息是否已经被处理。如果设置为 true,则消息将不再被分派到窗口过程(WndProc) |
HwndHook有什么用
拦截消息:在消息到达目标控件之前拦截它。
自定义消息处理:根据需要自定义消息的处理逻辑。
修改消息参数:在消息被处理之前修改 wParam 和 lParam 参数。
阻止消息传播:通过设置 handled 参数为 true 来阻止消息继续传播到默认的窗口过程。
为什么使用HwndHook
在C# WPF中,使用HwndHook(通过HwndSource.AddHook方法)来将消息转化为Window消息,是因为WPF框架本身并不直接处理Win32消息,而是通过一个叫做HwndSource的类来与Win32 API进行交互。
HwndSource提供了一个桥梁,使得WPF应用程序能够接收和处理Win32消息
另外他还可以免除自写控件的痛苦等等 总而言之就是节省了时间
如何使用HwndHook
这里只说对单个控件的HwndHook 因为全窗口的HwndHook网上教程还是比较多的
首先定义HwndSource
1 2 3 | using System.Windows.Interop; / / 要引入这个 private HwndSource _hwndSource; |
接下来写HOOK主体
1 2 3 4 | private IntPtr HwndSourceHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled){ / / .......................................... return IntPtr.Zero; } |
接下来就是在Loaded写加载HwndHook的函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | private void InitializeHwndSource() { try { / / 获取名为 CapturedImage 的控件的 HwndSource PresentationSource presentationSource = PresentationSource.FromVisual(CapturedImage); _hwndSource = (HwndSource)presentationSource; if (_hwndSource ! = null) { _hwndSource.AddHook(HwndSourceHook); } else { throw new InvalidOperationException( "Unable to find HwndSource for CapturedImage." ); / / System.Windows.Forms.MessageBox.Show( "Unable to find HwndSource for CapturedImage." ); } } catch (Exception ex) { / / 处理异常 } } |
这里有个小坑需要注意一下
一般来说 有人喜欢在InitializeComponent();后直接就下HwndHook
这是不可行的
因为如果这样PresentationSource.FromVisual找不到对象
所以你要先等他Loaded
也就是
1 | this.Loaded + = (s, e) = > InitializeHwndSource(); / / 加载事件 |
最后回归主题 不需要多麻烦 直接抄袭别人的代码就行了 甚至不用更改多少
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | private IntPtr HwndSourceHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { try { switch (msg) { case 0x0201 : / / WM_LBUTTONDOWN case 0x0202 : / / WM_LBUTTONUP case 0x0204 : / / WM_RBUTTONDOWN case 0x0205 : / / WM_RBUTTONUP case 0x0207 : / / WM_MBUTTONDOWN case 0x0208 : / / WM_MBUTTONUP case 0x0203 : / / WM_LBUTTONDBLCLK case 0x0206 : / / WM_RBUTTONDBLCLK case 0x0209 : / / WM_MBUTTONDBLCLK case 0x0200 : / / WM_MOUSEMOVE case 0x020A : / / WM_MOUSEWHEEL if (EnabledMouse) { int x = ( int )(lParam.ToInt32() & 0xFFFF ); / / 提取 x 坐标 int y = ( int )((lParam.ToInt32() >> 16 ) & 0xFFFF ); / / 提取 y 坐标 / / 将屏幕坐标转换为相对于 CapturedImage 控件的坐标 Point p = new Point( x * DeskTopSize.Width / CapturedImage.ActualWidth, y * DeskTopSize.Height / CapturedImage.ActualHeight ); lParam = (IntPtr)((( int )p.Y << 16 ) | (( int )p.X & 0xFFFF )); int Imsg = ( int )msg; int IwParam = ( int )wParam; int IlParam = ( int )lParam; } break ; case 0x0302 : / / WM_PASTE break ; case 0x0100 : / / WM_KEYDOWN case 0x0101 : / / WM_KEYUP if (EnabledKeyBoard) { / / Check if the Shift or Caps Lock key is pressed bool isShiftPressed = (GetKeyState(( int )System.Windows.Forms.Keys.ShiftKey) & 0x8000 ) ! = 0 ; bool isCapsLockOn = System.Windows.Forms.Control.IsKeyLocked(System.Windows.Forms.Keys.CapsLock); if (isShiftPressed || isCapsLockOn) { / / Modify the wParam to include the SHIFT or CAPSLOCK flag const int VK_SHIFT = 0x10 ; const int VK_CAPITAL = 0x14 ; if (wParam.ToInt32() = = VK_SHIFT || wParam.ToInt32() = = VK_CAPITAL) { / / Skip processing SHIFT or CAPSLOCK key release break ; } if (isShiftPressed) { msg = 0x0102 ; uint scanCode = (uint)((lParam.ToInt32() >> 16 ) & 0xFF ); byte[] keyboardState = new byte[ 256 ]; ToAscii((uint)wParam.ToInt32(), scanCode, keyboardState, out uint charCode, 0 ); wParam = (IntPtr)Convert.ToInt32(GetModifiedKey((char)charCode)); } if (isCapsLockOn) { uint scanCode = (uint)((lParam.ToInt32() >> 16 ) & 0xFF ); byte[] keyboardState = new byte[ 256 ]; ToAscii((uint)wParam.ToInt32(), scanCode, keyboardState, out uint charCode, 0 ); if (IsAlphaNumeric((char)charCode)) { msg = 0x0102 ; } } } int Imsg = ( int )msg; int IwParam = ( int )wParam; int IlParam = ( int )lParam; } break ; } } catch(Exception e) { } return IntPtr.Zero; } |
本文仅供技术学习交流
赞赏
- 解决WPF使用HVNC的问题-HwndHook 1198
- 记一次调用ETW-TI 3132
- [分享]一个MiniFilter的遍历 3650
- 最近看到自制杀软自己的一些感悟 3241
- [原创]分析一个由DCRAT二开而得的远控木马 4002