├── 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 |
--------------------------------------------------------------------------------