├── README.md ├── csgo.c ├── input.h ├── main.c └── sources /README.md: -------------------------------------------------------------------------------- 1 | HIDInput 2 | ======== 3 | 4 | HIDInput was developed with the idea of synthesizing mouse and keyboard input from a system thread, as well as supplementing the task in the system thread with easy-to-use functions that made it feel like the end-coder was working in user-mode. Some examples are: ReadMemory(), SynthesizeMouse(), SynthesizeKeyboard(), AttachToProcess(), GetModuleBase(), and get key/mouse state functions in an asynchronous manner. 5 | 6 | In the end, the idea was to have a fully kernel based framework in which mouse and keyboard input can be synthesized based off of data probes to the attached process. 7 | 8 | In this way, the end-coder does not require a high knowledge of kernel driver development, and can use the easy to call functions just as if he or she was doing the same project, but targeted for a user-mode environment. 9 | -------------------------------------------------------------------------------- /csgo.c: -------------------------------------------------------------------------------- 1 | /* 2 | This program is free software: you can redistribute it and/or modify 3 | it under the terms of the GNU General Public License as published by 4 | the Free Software Foundation, either version 3 of the License, or 5 | (at your option) any later version. 6 | 7 | This program is distributed in the hope that it will be useful, 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | GNU General Public License for more details. 11 | 12 | You should have received a copy of the GNU General Public License 13 | along with this program. If not, see . 14 | 15 | */ 16 | 17 | #include "input.h" 18 | 19 | ////////////////////////////////// 20 | // // 21 | // FUNCTION LIST // 22 | // // 23 | /////////////////////////////////// 24 | 25 | /* 26 | Sleep(int milliseconds) - Just like usermode, takes this thread off the processor for the specified duration. 27 | 28 | AttachToProcess(char *imageName) - Attaches to the specified process. The image name is just the binary, not a fully qualified image path. 29 | 30 | GetModuleBase(wchar_t *moduleName, ULONGLONG *base) - obtains the linear base address for the specified module name. You must have previously and 31 | successfully called AttachToProcess() or this function will fail. 32 | 33 | ReadMemory(void *source, void *target, ULONGLONG size) - Speaks for itself I hope. You must have previously and successfully called AttachToProcess() 34 | or this function will fail. 35 | 36 | SynthesizeMouse(PMOUSE_INPUT_DATA a1) - Synthesizes the corresponding mouse input. 37 | 38 | SynthesizeKeyboard(PMOUSE_INPUT_DATA a1) - Synthesizes the corresponding keyboard input. 39 | 40 | GetKeyState(char scan) - Asynchronously retrieves the up or down state of the specified can code. 41 | 42 | GetMouseState(int key) - Asynchronously retrieves the up or down state of the specified mouse button. 43 | 44 | 0 - Left mouse 45 | 1 - Right mouse 46 | 2 - Middle button 47 | 3 - Mouse button 4 48 | 4 - Mouse button 5 49 | 50 | 51 | */ 52 | 53 | 54 | 55 | 56 | #define BaseEntity 0xA58734 57 | #define EntityList 0x49fa8f4 58 | #define EntityListDistance 0x10 59 | 60 | #define inCross 0x23d8 61 | #define iTeamNum 0xF0 62 | 63 | #define iTeamNum 0xF0 64 | typedef ULONGLONG QWORD; 65 | 66 | 67 | 68 | // 69 | // 70 | // 71 | QWORD GetLocalPlayer(QWORD clientDllBase){ 72 | 73 | QWORD localPlayer = NULL; 74 | 75 | QWORD ptr = (QWORD) ((clientDllBase) + BaseEntity); 76 | 77 | ReadMemory((void*)ptr,&localPlayer,4); 78 | 79 | return localPlayer; 80 | } 81 | 82 | 83 | // 84 | // 85 | // 86 | int GetPlayers(QWORD *players, QWORD clientDllBase){ 87 | 88 | int x = 0; 89 | 90 | for(x = 0; x < 64; x ++){ 91 | 92 | QWORD tempPlayerAddress = 0; 93 | 94 | QWORD ptr = (QWORD) (clientDllBase + EntityList + (x * EntityListDistance)); 95 | 96 | if(!ReadMemory((void*)ptr,&tempPlayerAddress,4)){ 97 | 98 | players[x] = tempPlayerAddress; 99 | 100 | }else{ 101 | //ERROR: Cannot read Player 102 | return TRUE; 103 | } 104 | } 105 | return FALSE; 106 | } 107 | 108 | // 109 | // 110 | // 111 | QWORD GetInCrossId(QWORD localPlayer){ 112 | 113 | QWORD ptr = (QWORD) ((QWORD) localPlayer + inCross); 114 | 115 | QWORD inCrossId = NULL; 116 | 117 | if(!ReadMemory((void*)ptr,&inCrossId,4)) 118 | { 119 | 120 | return inCrossId; 121 | 122 | } 123 | else 124 | { 125 | //ERROR: Cannot read InCrossId from 126 | return NULL; 127 | } 128 | } 129 | 130 | // 131 | // 132 | // 133 | int NotOnTeam(QWORD player, QWORD localPlayer){ 134 | 135 | QWORD playerTeamID = 0; 136 | QWORD localPlayerTeamID = 0; 137 | 138 | QWORD pPlayer = (QWORD) ((QWORD) player + iTeamNum); 139 | QWORD pLocalPlayer = (QWORD) ((QWORD) localPlayer + iTeamNum); 140 | 141 | if(!ReadMemory((void*)pPlayer,&playerTeamID,4)){ 142 | 143 | if(!ReadMemory((void*)pLocalPlayer,&localPlayerTeamID,4)){ 144 | 145 | if(playerTeamID == localPlayerTeamID) 146 | return FALSE; 147 | else 148 | return TRUE; 149 | 150 | }else{ 151 | //ERROR: Cannot read team for localPlayer 152 | return FALSE; 153 | } 154 | }else{ 155 | //ERROR: Cannot read team for player 156 | return TRUE; 157 | } 158 | } 159 | 160 | 161 | NTSTATUS SystemRoutine() 162 | { 163 | 164 | //YOUR WORK HERE: 165 | 166 | 167 | ULONGLONG base; 168 | ULONG trigger; 169 | int active=1; 170 | ULONGLONG page=0; 171 | 172 | 173 | mdata.Flags|=MOUSE_MOVE_RELATIVE; 174 | 175 | 176 | 177 | //Use these scan codes for GetKeyState() 178 | // 179 | //http://msdn.microsoft.com/en-us/library/aa299374%28v=vs.60%29.aspx 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | while(TRUE) 189 | { 190 | 191 | 192 | 193 | #define __P 25//reacquire 194 | #define __V 47 195 | 196 | if(GetKeyState(25)) 197 | { 198 | 199 | 200 | AttachToProcess("csgo.exe"); 201 | 202 | GetModuleBase(L"client.dll",&base); 203 | } 204 | 205 | 206 | 207 | if(active) 208 | { 209 | 210 | 211 | 212 | 213 | 214 | //if activated 215 | 216 | //=============================================================== 217 | // 218 | QWORD localPlayer = 0; 219 | 220 | QWORD players[64] = {0}; 221 | 222 | QWORD clientBase = (QWORD)base; 223 | 224 | QWORD inCrossId = 0; 225 | 226 | //=============================================================== 227 | // 228 | 229 | //Get local player address 230 | localPlayer = GetLocalPlayer((QWORD)clientBase); 231 | 232 | //Get player array 233 | GetPlayers(&players, (QWORD)clientBase); 234 | 235 | //Get id of player that is in cross, if any 236 | inCrossId = GetInCrossId(localPlayer); 237 | 238 | //=============================================================== 239 | // 240 | 241 | //Check for valid player index 242 | if(inCrossId >= 1 && inCrossId <= 64 ){ 243 | 244 | //Check to see if they are on the same team 245 | if(NotOnTeam(players[inCrossId - 1], localPlayer)){ 246 | 247 | mdata.ButtonFlags|=MOUSE_LEFT_BUTTON_DOWN; 248 | 249 | //send the input 250 | SynthesizeMouse(&mdata); 251 | 252 | //lets wait 1/10 seconds and send the release 253 | 254 | Sleep(50); 255 | 256 | //remove button down flag 257 | mdata.ButtonFlags&=~MOUSE_LEFT_BUTTON_DOWN; 258 | 259 | //send the button up 260 | mdata.ButtonFlags|=MOUSE_LEFT_BUTTON_UP; 261 | 262 | SynthesizeMouse(&mdata); 263 | 264 | } 265 | } 266 | } 267 | 268 | //we should sleep here for a bit so this thread isn't using a lot of cpu time. same as user-mode. 269 | 270 | Sleep(5); 271 | 272 | 273 | } 274 | 275 | 276 | return STATUS_SUCCESS; 277 | } 278 | -------------------------------------------------------------------------------- /input.h: -------------------------------------------------------------------------------- 1 | /* 2 | This program is free software: you can redistribute it and/or modify 3 | it under the terms of the GNU General Public License as published by 4 | the Free Software Foundation, either version 3 of the License, or 5 | (at your option) any later version. 6 | 7 | This program is distributed in the hope that it will be useful, 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | GNU General Public License for more details. 11 | 12 | You should have received a copy of the GNU General Public License 13 | along with this program. If not, see . 14 | */ 15 | #include "Ntifs.h" 16 | #include "Ntddmou.h" 17 | #include "Ntddkbd.h" 18 | #include "Kbdmou.h" 19 | 20 | 21 | 22 | 23 | #define KBDCLASS_CONNECT_REQUEST 0x0B0203 24 | #define MOUCLASS_CONNECT_REQUEST 0x0F0203 25 | #define MOU_STRING_INC 0x14 26 | #define KBD_STRING_INC 0x15 27 | 28 | 29 | 30 | 31 | struct DEVOBJ_EXTENSION_FIX 32 | { 33 | USHORT type; 34 | USHORT size; 35 | PDEVICE_OBJECT devObj; 36 | ULONGLONG PowerFlags; 37 | void *Dope; 38 | ULONGLONG ExtensionFlags; 39 | void *DeviceNode; 40 | PDEVICE_OBJECT AttachedTo; 41 | }; 42 | 43 | /* 44 | These routines are resolved after an adddevice call to mouclass and kbdclass. 45 | 46 | MouClass and KbdClass then respond with a KBDCLASS_CONNECT_REQUEST or MOUCLASS_CONNECT_REQUEST as an internal 47 | device request, giving us the linear address of the input functions. We then call them just like a real miniport driver 48 | would ;p 49 | */ 50 | typedef void(__fastcall *MouseServiceDpc)(PDEVICE_OBJECT mou, PMOUSE_INPUT_DATA a1, PMOUSE_INPUT_DATA a2, PULONG a3); 51 | typedef void(__fastcall *KeyboardServiceDpc)(PDEVICE_OBJECT kbd, PKEYBOARD_INPUT_DATA a1, PKEYBOARD_INPUT_DATA a2, PULONG a3); 52 | 53 | 54 | typedef NTSTATUS(__fastcall *MouseAddDevice)(PDRIVER_OBJECT a1, PDEVICE_OBJECT a2); 55 | typedef NTSTATUS(__fastcall *KeyboardAddDevice)(PDRIVER_OBJECT a1, PDEVICE_OBJECT a2); 56 | typedef NTSTATUS(__fastcall *MmCopyVirtualMemory)(PEPROCESS a1, void *a2, PEPROCESS *a3, void *a4, ULONGLONG a5, KPROCESSOR_MODE a6, ULONG *a7); 57 | typedef NTSTATUS(__fastcall *KbdclassRead)(PDEVICE_OBJECT device, PIRP irp); 58 | typedef NTSTATUS(__fastcall *MouclassRead)(PDEVICE_OBJECT device, PIRP irp); 59 | typedef NTSTATUS(__fastcall *kbdinput)(void *a1, void *a2, void *a3, void *a4, void *a5); 60 | typedef NTSTATUS(__fastcall *mouinput)(void *a1, void *a2, void *a3, void *a4, void *a5); 61 | typedef NTSTATUS(__fastcall *NtQuerySystemInformation)(ULONG infoclass, void *buffer, ULONG infolen, ULONG *plen); 62 | typedef char*(_fastcall *PsGetProcessImageFileName)(PEPROCESS target); 63 | typedef void*(_fastcall *PsGetProcessPeb)(PEPROCESS a1); 64 | typedef void*(_fastcall *PsGetProcessWow64Process)(PEPROCESS a1); 65 | 66 | extern NTSTATUS SystemRoutine(); 67 | 68 | 69 | PDEVICE_OBJECT mouTarget; 70 | PDEVICE_OBJECT kbdTarget; 71 | ULONG mouId=0; 72 | ULONG kbdId=0; 73 | PEPROCESS targetProcess=NULL; 74 | PEPROCESS currentProcess=NULL; 75 | char KEY_DATA[128]; 76 | char MOU_DATA[5]; 77 | 78 | MOUSE_INPUT_DATA mdata; 79 | KEYBOARD_INPUT_DATA kdata; 80 | 81 | KbdclassRead KbdClassReadRoutine; 82 | MouclassRead MouClassReadRoutine; 83 | MouseServiceDpc MouseDpcRoutine; 84 | KeyboardServiceDpc KeyboardDpcRoutine; 85 | MmCopyVirtualMemory MmCopyVirtualMemoryRoutine; 86 | NtQuerySystemInformation ZwQuerySystemInformation; 87 | kbdinput KeyboardInputRoutine=NULL; 88 | mouinput MouseInputRoutine=NULL; 89 | PsGetProcessImageFileName PsGetImageName; 90 | PsGetProcessPeb PsGetPeb64; 91 | PsGetProcessWow64Process PsGetPeb32; 92 | 93 | PKEYBOARD_INPUT_DATA mjRead=NULL; 94 | PMOUSE_INPUT_DATA mouIrp=NULL; 95 | 96 | 97 | /* 98 | This function calls the KeyboardClassServiceCallback routine given to us after we added our device, 99 | via the internal device request. Before branching to the actual input routine, we must raise 100 | our IRQL to dispatch level because we are pretending that it is a dpcforisr routine, not to mention 101 | these routines acquire dispatch level spinlocks without checking or modifying the previous IRQL. 102 | */ 103 | void SynthesizeKeyboard(PKEYBOARD_INPUT_DATA a1) 104 | { 105 | KIRQL irql; 106 | char *endptr; 107 | ULONG fill=1; 108 | 109 | 110 | endptr=(char*)a1; 111 | 112 | endptr+=sizeof(KEYBOARD_INPUT_DATA); 113 | 114 | a1->UnitId=kbdId; 115 | 116 | //huehuehue 117 | KeRaiseIrql(DISPATCH_LEVEL,&irql); 118 | 119 | KeyboardDpcRoutine(kbdTarget,a1,(PKEYBOARD_INPUT_DATA)endptr,&fill); 120 | 121 | KeLowerIrql(irql); 122 | 123 | } 124 | /* 125 | This function calls the MouseClassServiceCallback routine given to us after we added our device, 126 | via the internal device request. Before branching to the actual input routine, we must raise 127 | our IRQL to dispatch level because we are pretending that it is a dpcforisr routine, not to mention 128 | these routines acquire dispatch level spinlocks without checking or modifying the previous IRQL. 129 | */ 130 | void SynthesizeMouse(PMOUSE_INPUT_DATA a1) 131 | { 132 | KIRQL irql; 133 | char *endptr; 134 | ULONG fill=1; 135 | 136 | endptr=(char*)a1; 137 | 138 | endptr+=sizeof(MOUSE_INPUT_DATA); 139 | 140 | a1->UnitId=mouId; 141 | 142 | //huehuehue 143 | KeRaiseIrql(DISPATCH_LEVEL,&irql); 144 | 145 | MouseDpcRoutine(mouTarget,a1,(PMOUSE_INPUT_DATA)endptr,&fill); 146 | 147 | KeLowerIrql(irql); 148 | 149 | } 150 | 151 | /* 152 | This function asynchronously obtains the up/down keystate of the corresponding scan code. 153 | This global array is updated each time the user presses a key, it is updated via the hijacked 154 | InputApc queued to the CSRSS keyboard listener whenever the completion code calls IoCompleteRequest 155 | */ 156 | int GetKeyState(char scan) 157 | { 158 | if(KEY_DATA[scan-1]) return 1; 159 | 160 | return 0; 161 | } 162 | 163 | /* 164 | This function asynchronously obtains the up/down mouse button state of the corresponding mouse button. 165 | This global array is updated each time the user presses a mouse button, it is updated via the hijacked 166 | InputApc queued to the CSRSS mouse listener whenever the completion code calls IoCompleteRequest 167 | */ 168 | int GetMouseState(int key) 169 | { 170 | if(MOU_DATA[key]) return 1; 171 | 172 | return 0; 173 | } 174 | 175 | /* 176 | This is just an easy to use wrapper around MmCopyVirtualMemory, as you can see a TargetProcess is required 177 | or the call will just fail. Since MmCopyVirtualMemory contains it's own exception handling and data probes, 178 | the call will fail if the source is bogus. 179 | */ 180 | NTSTATUS ReadMemory(void *source, void *target, ULONGLONG size) 181 | { 182 | ULONG transferred; 183 | 184 | if(!targetProcess) return STATUS_INVALID_PARAMETER_1; 185 | 186 | return MmCopyVirtualMemoryRoutine(targetProcess,source,currentProcess,target,size,KernelMode,&transferred); 187 | 188 | } 189 | 190 | /* 191 | This is a wrapper around KeDelayExecutionThread. Since KeyDelayExecutionThread takes an input of 100ns units, we convert 192 | our ms input, and use a negative value for relative time. 193 | */ 194 | 195 | NTSTATUS Sleep(ULONGLONG milliseconds) 196 | { 197 | LARGE_INTEGER delay; 198 | ULONG *split; 199 | 200 | milliseconds*=1000000; 201 | 202 | milliseconds/=100; 203 | 204 | milliseconds=-milliseconds; 205 | 206 | split=(ULONG*)&milliseconds; 207 | 208 | delay.LowPart=*split; 209 | 210 | split++; 211 | 212 | delay.HighPart=*split; 213 | 214 | KeDelayExecutionThread(KernelMode,0,&delay); 215 | 216 | return STATUS_SUCCESS; 217 | } 218 | 219 | //Image name is also in this structure, but we use msdn provided info because it is less likely to change. 220 | struct SYSTEM_PROCESS_INFORMATION 221 | { 222 | ULONG NextEntryOffset; 223 | char Reserved1[52]; 224 | PVOID Reserved2[3]; 225 | HANDLE UniqueProcessId; 226 | PVOID Reserved3; 227 | ULONG HandleCount; 228 | char Reserved4[4]; 229 | PVOID Reserved5[11]; 230 | SIZE_T PeakPagefileUsage; 231 | SIZE_T PrivatePageCount; 232 | LARGE_INTEGER Reserved6[6]; 233 | }; 234 | 235 | //we could walk vads but since ldr_data's appearance on msdn it is less likely to change. 236 | 237 | /* 238 | This is a very nasty function to retrieve the linear address of the specified module. It walks the PEB loader 239 | lists of the target process and resolves the specified module name to a linear address. 240 | */ 241 | NTSTATUS GetModuleBase(wchar_t *ModuleName, ULONGLONG *base) 242 | { 243 | ULONGLONG ldr; 244 | ULONGLONG pdata=0; 245 | ULONGLONG buffer=0; 246 | ULONGLONG head=0; 247 | ULONGLONG string=0; 248 | wchar_t dllname[16]; 249 | int i=0; 250 | 251 | *base=0; 252 | 253 | if(!targetProcess) return STATUS_INVALID_PARAMETER_1; 254 | 255 | ldr=(ULONGLONG)PsGetPeb32(targetProcess); 256 | 257 | if(!ldr) 258 | { 259 | ldr=PsGetPeb64(targetProcess); 260 | 261 | ldr+=0x18; 262 | 263 | /**********************************************************/ 264 | 265 | 266 | if(ReadMemory((void*)ldr,&pdata,8)) return STATUS_INVALID_PARAMETER_1; 267 | 268 | pdata+=0x10; 269 | 270 | head=pdata; 271 | 272 | while(i<500) 273 | { 274 | if(ReadMemory((void*)pdata,&buffer,8)) return STATUS_INVALID_PARAMETER_1; 275 | 276 | if(buffer==head) return 1; 277 | 278 | buffer+=0x60; 279 | 280 | if(ReadMemory((void*)buffer,&string,8)) return STATUS_INVALID_PARAMETER_1; 281 | 282 | if(ReadMemory((void*)string,dllname,sizeof(dllname))) return STATUS_INVALID_PARAMETER_1; 283 | 284 | if(!wcscmp(ModuleName,dllname)) 285 | { 286 | buffer-=0x30; 287 | 288 | if(ReadMemory((void*)buffer,&pdata,8)) return STATUS_INVALID_PARAMETER_1; 289 | 290 | *base=pdata; 291 | 292 | return STATUS_SUCCESS; 293 | } 294 | 295 | i++; 296 | 297 | buffer-=0x60; 298 | 299 | pdata=buffer; 300 | 301 | 302 | } 303 | 304 | 305 | 306 | return STATUS_INVALID_PARAMETER_1; 307 | 308 | /**********************************************************/ 309 | 310 | } 311 | 312 | ldr+=0xc; 313 | 314 | if(ReadMemory((void*)ldr,&pdata,4)) return STATUS_INVALID_PARAMETER_1; 315 | 316 | pdata+=0xc; 317 | 318 | head=pdata; 319 | 320 | while(i<500) 321 | { 322 | if(ReadMemory((void*)pdata,&buffer,4)) return STATUS_INVALID_PARAMETER_1; 323 | 324 | if(buffer==head) return 1; 325 | 326 | buffer+=0x30; 327 | 328 | if(ReadMemory((void*)buffer,&string,4)) return STATUS_INVALID_PARAMETER_1; 329 | 330 | if(ReadMemory((void*)string,dllname,sizeof(dllname))) return STATUS_INVALID_PARAMETER_1; 331 | 332 | if(!wcscmp(ModuleName,dllname)) 333 | { 334 | buffer-=0x18; 335 | 336 | if(ReadMemory((void*)buffer,&pdata,4)) return STATUS_INVALID_PARAMETER_1; 337 | 338 | *base=pdata; 339 | 340 | return STATUS_SUCCESS; 341 | } 342 | 343 | i++; 344 | 345 | buffer-=0x30; 346 | 347 | pdata=buffer; 348 | 349 | 350 | } 351 | 352 | 353 | return STATUS_INVALID_PARAMETER_1; 354 | } 355 | 356 | /* 357 | This function uses ZwQuerySystemInformation and PsLookupProcessByProcessId to resolve the EPROCESS for the specified 358 | image name. 359 | */ 360 | 361 | NTSTATUS AttachToProcess(char *ImageName) 362 | { 363 | 364 | ULONG entryOffset; 365 | NTSTATUS status; 366 | ULONG lenActual; 367 | struct SYSTEM_PROCESS_INFORMATION *sysinfo; 368 | char *sys; 369 | char *zero; 370 | PEPROCESS pbuffer; 371 | ANSI_STRING filename; 372 | char found=0; 373 | 374 | currentProcess=PsGetCurrentProcess(); 375 | 376 | if(targetProcess) 377 | { 378 | ObDereferenceObject(targetProcess); 379 | 380 | targetProcess=0; 381 | } 382 | 383 | 384 | sys=(char*)ExAllocatePoolWithTag(PagedPool,0x50000,NULL); 385 | 386 | zero=sys; 387 | 388 | sysinfo=(struct SYSTEM_PROCESS_INFORMATION*)sys; 389 | 390 | status=ZwQuerySystemInformation(0x5,(void*)sys,0x50000,&lenActual); 391 | 392 | if(status) 393 | { 394 | ExFreePool((PVOID)sys); 395 | 396 | return STATUS_INVALID_PARAMETER_1; 397 | } 398 | 399 | while(1) //lul 400 | { 401 | 402 | if(!PsLookupProcessByProcessId(sysinfo->UniqueProcessId,&pbuffer)) 403 | { 404 | 405 | if(!strcmp(ImageName,PsGetImageName(pbuffer))) 406 | { 407 | targetProcess=pbuffer; 408 | 409 | found=1; 410 | 411 | break; 412 | } 413 | 414 | ObDereferenceObject(pbuffer); 415 | 416 | 417 | } 418 | 419 | if(!sysinfo->NextEntryOffset) break; 420 | 421 | sys+=sysinfo->NextEntryOffset; 422 | 423 | sysinfo=(struct SYSTEM_PROCESS_INFORMATION*)sys; 424 | 425 | } 426 | 427 | ExFreePool((PVOID)zero); 428 | 429 | if(!found) return STATUS_INVALID_PARAMETER_1; 430 | 431 | return STATUS_SUCCESS; 432 | } 433 | 434 | 435 | /* 436 | These are the hooks for win32k!InputApc which filter mouse and keyboard. ReadInstrumentation modifies the 437 | completion KAPC by hooking mouclass and kbdclass MJ_READ routines. This is how HID/8042 input is monitored. Yes 438 | this is nasty, but afaik only i8042 provides functions for filtering. The user could have 8042 or USB, or both. 439 | */ 440 | 441 | NTSTATUS KeyboardApc(void *a1, void *a2, void *a3, void *a4, void *a5) 442 | { 443 | unsigned char max=(unsigned char)mjRead->MakeCode; 444 | 445 | 446 | if(!mjRead->Flags) 447 | { 448 | KEY_DATA[(max)-1]=1; 449 | } 450 | else if(mjRead->Flags&KEY_BREAK) 451 | { 452 | KEY_DATA[(max)-1]=0; 453 | } 454 | 455 | return KeyboardInputRoutine(a1,a2,a3,a4,a5); 456 | } 457 | 458 | NTSTATUS MouseApc(void *a1, void *a2, void *a3, void *a4, void *a5) 459 | { 460 | if(mouIrp->ButtonFlags&MOUSE_LEFT_BUTTON_DOWN) 461 | { 462 | MOU_DATA[0]=1; 463 | } 464 | else if(mouIrp->ButtonFlags&MOUSE_LEFT_BUTTON_UP) 465 | { 466 | MOU_DATA[0]=0; 467 | } 468 | else if(mouIrp->ButtonFlags&MOUSE_RIGHT_BUTTON_DOWN) 469 | { 470 | MOU_DATA[1]=1; 471 | } 472 | else if(mouIrp->ButtonFlags&MOUSE_RIGHT_BUTTON_UP) 473 | { 474 | MOU_DATA[1]=0; 475 | } 476 | else if(mouIrp->ButtonFlags&MOUSE_MIDDLE_BUTTON_DOWN) 477 | { 478 | MOU_DATA[2]=1; 479 | } 480 | else if(mouIrp->ButtonFlags&MOUSE_MIDDLE_BUTTON_UP) 481 | { 482 | MOU_DATA[2]=0; 483 | } 484 | else if(mouIrp->ButtonFlags&MOUSE_BUTTON_4_DOWN) 485 | { 486 | MOU_DATA[3]=1; 487 | } 488 | else if(mouIrp->ButtonFlags&MOUSE_BUTTON_4_UP) 489 | { 490 | MOU_DATA[3]=0; 491 | } 492 | else if(mouIrp->ButtonFlags&MOUSE_BUTTON_5_DOWN) 493 | { 494 | MOU_DATA[4]=1; 495 | } 496 | else if(mouIrp->ButtonFlags&MOUSE_BUTTON_5_UP) 497 | { 498 | MOU_DATA[4]=0; 499 | } 500 | 501 | return MouseInputRoutine(a1,a2,a3,a4,a5); 502 | } 503 | 504 | /* 505 | These routines hijack the IRP's kapc for keyboard and mouse input respectively. 506 | 507 | */ 508 | 509 | NTSTATUS ReadInstrumentation(PDEVICE_OBJECT device, PIRP irp) 510 | { 511 | ULONGLONG *routine; 512 | 513 | routine=(ULONGLONG*)irp; 514 | 515 | routine+=0xb; 516 | 517 | 518 | if(!KeyboardInputRoutine) 519 | { 520 | KeyboardInputRoutine=(kbdinput)*routine; 521 | } 522 | 523 | *routine=(ULONGLONG)KeyboardApc; 524 | 525 | mjRead=(struct KEYBOARD_INPUT_DATA*)irp->UserBuffer; 526 | 527 | return KbdClassReadRoutine(device,irp); 528 | } 529 | 530 | NTSTATUS ReadInstrumentation1(PDEVICE_OBJECT device, PIRP irp) 531 | { 532 | ULONGLONG *routine; 533 | 534 | routine=(ULONGLONG*)irp; 535 | 536 | routine+=0xb; 537 | 538 | 539 | if(!MouseInputRoutine) 540 | { 541 | MouseInputRoutine=(mouinput)*routine; 542 | } 543 | 544 | *routine=(ULONGLONG)MouseApc; 545 | 546 | mouIrp=(struct KEYBOARD_INPUT_DATA*)irp->UserBuffer; 547 | 548 | return MouClassReadRoutine(device,irp); 549 | } 550 | 551 | NTSTATUS Edox_InvalidRequest(PDEVICE_OBJECT device, PIRP irp); 552 | 553 | 554 | /* 555 | This routine serves to respond to the connect request from kbdclass/mouclass after an 556 | adddevice call. The corresponding DPC routines are then saved in the global pointers described above. 557 | */ 558 | 559 | NTSTATUS Edox_InternalIoctl(PDEVICE_OBJECT device, PIRP irp) 560 | { 561 | PIO_STACK_LOCATION ios; 562 | PCONNECT_DATA cd; 563 | 564 | ios=IoGetCurrentIrpStackLocation(irp); 565 | 566 | if(ios->Parameters.DeviceIoControl.IoControlCode==MOUCLASS_CONNECT_REQUEST) 567 | { 568 | cd=ios->Parameters.DeviceIoControl.Type3InputBuffer; 569 | 570 | MouseDpcRoutine=(MouseServiceDpc)cd->ClassService; 571 | } 572 | else if(ios->Parameters.DeviceIoControl.IoControlCode==KBDCLASS_CONNECT_REQUEST) 573 | { 574 | cd=ios->Parameters.DeviceIoControl.Type3InputBuffer; 575 | 576 | KeyboardDpcRoutine=(KeyboardServiceDpc)cd->ClassService; 577 | } 578 | else 579 | { 580 | Edox_InvalidRequest(device,irp); 581 | } 582 | 583 | return STATUS_SUCCESS; 584 | } 585 | 586 | NTSTATUS Edox_InvalidRequest(PDEVICE_OBJECT device, PIRP irp) 587 | { 588 | return STATUS_SUCCESS; 589 | } 590 | 591 | 592 | /* 593 | This function recursively searches for a devnode to hijack in a device stack, this is so we can properly call 594 | mouclass/kbdclass adddevice routines and pretend we are an actual HID provider. This is just a giant hack and our driver should 595 | really be part of the USB stack. 596 | */ 597 | 598 | void *FindDevNodeRecurse(PDEVICE_OBJECT a1, ULONGLONG *a2) 599 | { 600 | struct DEVOBJ_EXTENSION_FIX *attachment; 601 | 602 | attachment=a1->DeviceObjectExtension; 603 | 604 | if((!attachment->AttachedTo)&&(!attachment->DeviceNode)) return; 605 | 606 | if((!attachment->DeviceNode)&&(attachment->AttachedTo)) 607 | { 608 | FindDevNodeRecurse(attachment->AttachedTo,a2); 609 | 610 | return; 611 | } 612 | 613 | *a2=(ULONGLONG)attachment->DeviceNode; 614 | 615 | return; 616 | } 617 | 618 | /*==============================================================================*/ 619 | 620 | ULONG filter(void* a1) 621 | { 622 | return 0; 623 | } 624 | 625 | NTSTATUS DriverEntry(IN PDRIVER_OBJECT driverObject, IN PUNICODE_STRING regPath) 626 | { 627 | UNICODE_STRING symbolicLink; 628 | UNICODE_STRING deviceName; 629 | PDEVICE_OBJECT devicePtr; 630 | int i=0; 631 | PDEVICE_OBJECT input_mouse; 632 | PDEVICE_OBJECT input_keyboard; 633 | CLIENT_ID nthread; 634 | PKTHREAD p=NULL; 635 | PEXCEPTION_POINTERS ptr; 636 | 637 | 638 | /*==============================*/ 639 | UNICODE_STRING classNameBuffer; 640 | UNICODE_STRING routineName; 641 | PDEVICE_OBJECT classObj; 642 | PFILE_OBJECT file; 643 | PDRIVER_OBJECT classDrv; 644 | MouseAddDevice MouseAddDevicePtr; 645 | KeyboardAddDevice KeyboardAddDevicePtr; 646 | struct DEVOBJ_EXTENSION_FIX *DevObjExtension; 647 | ULONGLONG node=0; 648 | SHORT *u; 649 | USHORT charBuff; 650 | wchar_t kbdname[23]=L"\\Device\\KeyboardClass0"; 651 | wchar_t mouname[22]=L"\\Device\\PointerClass0"; 652 | void *linear=(void*)ReadInstrumentation; 653 | HANDLE thread; 654 | /*==============================*/ 655 | 656 | memset((void*)&mdata,0,sizeof(mdata)); 657 | memset((void*)&kdata,0,sizeof(kdata)); 658 | memset((void*)MOU_DATA,0,sizeof(MOU_DATA)); 659 | 660 | RtlInitUnicodeString(&routineName,L"MmCopyVirtualMemory"); 661 | 662 | MmCopyVirtualMemoryRoutine=(MmCopyVirtualMemory)MmGetSystemRoutineAddress(&routineName); 663 | 664 | RtlInitUnicodeString(&routineName,L"ZwQuerySystemInformation"); 665 | 666 | ZwQuerySystemInformation=(NtQuerySystemInformation)MmGetSystemRoutineAddress(&routineName); 667 | 668 | RtlInitUnicodeString(&routineName,L"PsGetProcessImageFileName"); 669 | 670 | PsGetImageName=(PsGetProcessImageFileName)MmGetSystemRoutineAddress(&routineName); 671 | 672 | RtlInitUnicodeString(&routineName,L"PsGetProcessPeb"); 673 | 674 | PsGetPeb64=(PsGetProcessPeb)MmGetSystemRoutineAddress(&routineName); 675 | 676 | RtlInitUnicodeString(&routineName,L"PsGetProcessWow64Process"); 677 | 678 | PsGetPeb32=(PsGetProcessWow64Process)MmGetSystemRoutineAddress(&routineName); 679 | 680 | /**/ 681 | //RtlInitUnicodeString(&deviceName,L"\\Device\\edoxHID"); 682 | 683 | IoCreateDevice(driverObject,0,NULL,FILE_DEVICE_UNKNOWN,FILE_DEVICE_SECURE_OPEN,FALSE,&devicePtr); 684 | 685 | //RtlInitUnicodeString(&symbolicLink,L"\\DosDevices\\mkInput"); 686 | 687 | //IoCreateSymbolicLink(&symbolicLink,&deviceName); 688 | 689 | /**/ 690 | 691 | RtlInitUnicodeString(&deviceName,L"\\Device\\edoxMouse"); 692 | 693 | IoCreateDevice(driverObject,0,&deviceName,FILE_DEVICE_UNKNOWN,FILE_DEVICE_SECURE_OPEN,FALSE,&input_mouse); 694 | 695 | RtlInitUnicodeString(&deviceName,L"\\Device\\edoxKeyboard"); 696 | 697 | IoCreateDevice(driverObject,0,&deviceName,FILE_DEVICE_UNKNOWN,FILE_DEVICE_SECURE_OPEN,FALSE,&input_keyboard); 698 | 699 | 700 | for(i=0; iMajorFunction[i]=Edox_InvalidRequest; 702 | 703 | 704 | driverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL]=Edox_InternalIoctl; 705 | driverObject->MajorFunction[IRP_MJ_READ]=Edox_InvalidRequest; 706 | driverObject->MajorFunction[IRP_MJ_CREATE]=Edox_InvalidRequest; 707 | driverObject->MajorFunction[IRP_MJ_CLOSE]=Edox_InvalidRequest; 708 | driverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS]=Edox_InvalidRequest; 709 | driverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]=Edox_InvalidRequest; 710 | driverObject->MajorFunction[IRP_MJ_CLEANUP]=Edox_InvalidRequest; 711 | driverObject->MajorFunction[IRP_MJ_POWER]=Edox_InvalidRequest; 712 | driverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL]=Edox_InvalidRequest; 713 | driverObject->MajorFunction[IRP_MJ_PNP]=Edox_InvalidRequest; 714 | 715 | 716 | devicePtr->Flags|=DO_BUFFERED_IO; 717 | devicePtr->Flags&=~DO_DEVICE_INITIALIZING; 718 | 719 | 720 | input_mouse->Flags|=DO_BUFFERED_IO; 721 | input_mouse->Flags&=~DO_DEVICE_INITIALIZING; 722 | 723 | input_keyboard->Flags|=DO_BUFFERED_IO; 724 | input_keyboard->Flags&=~DO_DEVICE_INITIALIZING; 725 | 726 | /*==============================*/ 727 | 728 | //find a devnode we can hijack 729 | 730 | RtlInitUnicodeString(&classNameBuffer,mouname); 731 | 732 | u=mouname; 733 | 734 | 735 | while(1) 736 | { 737 | //run till we run out of devices or find a devnode 738 | 739 | if(IoGetDeviceObjectPointer(&classNameBuffer,FILE_ALL_ACCESS,&file,&classObj)) return STATUS_OBJECT_NAME_NOT_FOUND; 740 | 741 | ObDereferenceObject(file); 742 | 743 | node=FindDevNodeRecurse(classObj,&node); 744 | 745 | if(node) break; 746 | 747 | *(u+MOU_STRING_INC)+=1; 748 | 749 | mouId++; 750 | 751 | } 752 | 753 | mouTarget=classObj; 754 | 755 | classDrv=classObj->DriverObject; 756 | 757 | MouClassReadRoutine=(MouclassRead)classDrv->MajorFunction[IRP_MJ_READ]; 758 | 759 | classDrv->MajorFunction[IRP_MJ_READ]=ReadInstrumentation1; 760 | 761 | DevObjExtension=input_mouse->DeviceObjectExtension; 762 | 763 | DevObjExtension->DeviceNode=(void*)node; 764 | 765 | MouseAddDevicePtr=(MouseAddDevice)classDrv->DriverExtension->AddDevice; 766 | 767 | MouseAddDevicePtr(classDrv,input_mouse); 768 | 769 | //repeat same process for keyboard stacks 770 | 771 | RtlInitUnicodeString(&classNameBuffer,kbdname); 772 | 773 | u=kbdname; 774 | 775 | 776 | charBuff=*(u+KBD_STRING_INC); 777 | 778 | 779 | while(1) 780 | { 781 | //run till we run out of devices or find a devnode 782 | 783 | if(IoGetDeviceObjectPointer(&classNameBuffer,FILE_ALL_ACCESS,&file,&classObj)) return STATUS_OBJECT_NAME_NOT_FOUND; 784 | 785 | ObDereferenceObject(file); 786 | 787 | node=FindDevNodeRecurse(classObj,&node); 788 | 789 | if(node) break; 790 | 791 | *(u+KBD_STRING_INC)+=1; 792 | 793 | kbdId++; 794 | 795 | } 796 | 797 | 798 | *(u+KBD_STRING_INC)=charBuff; 799 | 800 | kbdTarget=classObj; 801 | 802 | classDrv=classObj->DriverObject; 803 | 804 | DevObjExtension=input_keyboard->DeviceObjectExtension; 805 | 806 | DevObjExtension->DeviceNode=(void*)node; 807 | 808 | KeyboardAddDevicePtr=(KeyboardAddDevice)classDrv->DriverExtension->AddDevice; 809 | 810 | KeyboardAddDevicePtr(classDrv,input_keyboard); 811 | 812 | /**/ 813 | KbdClassReadRoutine=(KbdclassRead)classDrv->MajorFunction[IRP_MJ_READ]; 814 | 815 | classDrv->MajorFunction[IRP_MJ_READ]=ReadInstrumentation; 816 | 817 | for(i=0; i<128; i++) KEY_DATA[i]=0; 818 | 819 | PsCreateSystemThread(&thread,STANDARD_RIGHTS_ALL,NULL,NULL,&nthread,(PKSTART_ROUTINE)SystemRoutine,NULL); 820 | 821 | 822 | ZwClose(thread); 823 | 824 | 825 | 826 | 827 | return STATUS_SUCCESS; 828 | } 829 | 830 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | /* 2 | This program is free software: you can redistribute it and/or modify 3 | it under the terms of the GNU General Public License as published by 4 | the Free Software Foundation, either version 3 of the License, or 5 | (at your option) any later version. 6 | 7 | This program is distributed in the hope that it will be useful, 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | GNU General Public License for more details. 11 | 12 | You should have received a copy of the GNU General Public License 13 | along with this program. If not, see . 14 | 15 | */ 16 | #include "input.h" 17 | 18 | 19 | ////////////////////////////////// 20 | // // 21 | // FUNCTION LIST // 22 | // // 23 | /////////////////////////////////// 24 | 25 | /* 26 | Sleep(int milliseconds) - Just like usermode, takes this thread off the processor for the specified duration. 27 | 28 | AttachToProcess(char *imageName) - Attaches to the specified process. The image name is just the binary, not a fully qualified image path. 29 | 30 | GetModuleBase(wchar_t *moduleName, ULONGLONG *base) - obtains the linear base address for the specified module name. You must have previously and 31 | successfully called AttachToProcess() or this function will fail. 32 | 33 | ReadMemory(void *source, void *target, ULONGLONG size) - Speaks for itself I hope. You must have previously and successfully called AttachToProcess() 34 | or this function will fail. 35 | 36 | SynthesizeMouse(PMOUSE_INPUT_DATA a1) - Synthesizes the corresponding mouse input. 37 | 38 | SynthesizeKeyboard(PMOUSE_INPUT_DATA a1) - Synthesizes the corresponding keyboard input. 39 | 40 | GetKeyState(char scan) - Asynchronously retrieves the up or down state of the specified can code. 41 | 42 | GetMouseState(int key) - Asynchronously retrieves the up or down state of the specified mouse button. 43 | 44 | 0 - Left mouse 45 | 1 - Right mouse 46 | 2 - Middle button 47 | 3 - Mouse button 4 48 | 4 - Mouse button 5 49 | 50 | 51 | */ 52 | 53 | 54 | 55 | NTSTATUS SystemRoutine() 56 | { 57 | //DO YOUR WORK HERE: 58 | 59 | return STATUS_SUCCESS; 60 | } 61 | -------------------------------------------------------------------------------- /sources: -------------------------------------------------------------------------------- 1 | TARGETNAME=HIDInput 2 | TARGETPATH=build 3 | TARGETTYPE=DRIVER 4 | 5 | SOURCES=input.h 6 | SOURCES=csgo.c 7 | 8 | --------------------------------------------------------------------------------