Hi, how can i "simulate" a keypress on a directX programmed game?
Printable View
Hi, how can i "simulate" a keypress on a directX programmed game?
You can try using SendInput to simulate a keystroke. It also simulate mouse movements. If the game is using directInput for all of its input then this may not work.
Does this method works for system-wide input simulation? As i can see this function receives no "target" like a window handle...
Yes it works for system wide keyboard simulation. If you want to target specific keystrokes to an application, you might as well use SendMessage and specify the Windows Handle.
Again, if it uses DirectInput for the input then this approach wont work.
If the target is using DirectInput, then you'll probably have use use a DLL which will review the names of all running processes in search of the targeted process. The DLL will then inject code into the targeted process to override DirectInput8Create. Your DLL will now intercept requests to create GUID_SysKeyboardDevices and will return it's own device.
Now when IDirectInputDevice8::GetdeviceState is used to retrieve the keyboard state in immediate mode, your custom keyboard can return a keyboard state containing your simulated keypress.
I haven't verifed the accuracy of this method using code. So, any non verified coding theory and $2.00 will get you nothing more than a cup of coffee.
A sure fire way would be to write a Virtual Device Driver (VxD) that inserts key strokes directly into the keyboard buffer, fooling DirectInput. Another way, like you said, is to write a DLL that injects code into the DirectInput memory space.
Looking through the Microsoft DDK, there are examples of custom VxD files. Under keyb\samples\Vkxd\ there is an example of an easy keyboard emulation VxD. But that might be outdated. DirectInput deals directly with the keyboard buffer (and other devices) and completely ignores all input that has been passed through windows and converted into WM_* messages. So any sort of WM_* simulation will not work.
I wasn't able to find that sample... Maybe i have download a wrong DDk version? I got it from here: http://www.microsoft.com/whdc/devtools/ddk/default.mspx.
I think that the virtual device driver is the best way to do it, but i got curious, how would i do it in BobS0327's way?
I'm most likely using a very very old version of the DDK. Mind you, in order to do this you will have to write a keyboard driver; Something that I have not done before. But before diving into that, try using the keybd_event function, and passing in some scan codes (NOT Virtual Key Codes!). If that fails, then you should write the VxD.
I recommend against doing that.
Drivers are very complex pieces of code and one wrong line of code can crash the entire system. Not to mention it would probably cause headaches since it's low level. Plus you need to ship that driver to anyone who uses the app. So that means they are left at exposure, too, and they need admin powers to install the driver.
No. Try to avoid drivers.
Oh, the keybd_event function worked just fine outside directX games... But in directX games simply nothing happened... I'm stuck here, any sugestions? I think that BobS0327 method is pretty good but i don't know how to implement it... some help would be welcome =)
No easy solution I know of. It's tricky because DirectInput works on a low level with hardware and bypasses Windows keyboard handling.
I hope you realize that the description of my method gives the impression that this project is a simple task. It is definitely NOT going to be easy. It starts off somewhat easy but will become progressively more difficult as you near the end of the project. But for starters, the first order of business is to write the code to enumerate the tasks to find your targeted task. You should use CreateToolHelpSnapshot32 for this enumeration task. Also, you will have to set the debug privilege level using OpenProcessToken, LookupPrivilegeValue and AdjustTokenPrivileges. This privilege level has to be set first prior to querying the PID number for the targeted task to allow you to inject code into the process.Quote:
I think that BobS0327 method is pretty good but i don't know how to implement it... some help would be welcome =)
The next step will be open for discussion when you have this code working reliably.
Ok, im working on that, soon i should post my code here...
Ok, this is the code so far:
Process.h
Process.cppCode:#pragma once
#include <windows.h>
#include <Tlhelp32.h>
class Process
{
PROCESSENTRY32 processEntry;
public:
Process(const PROCESSENTRY32& processEntry);
Process();
~Process();
DWORD getPid();
DWORD getThreadsCount();
DWORD getParentPid();
DWORD getModuleId();
char* getExeFilename();
};
ProcessEnumerator.hCode:#include "Process.h"
Process::Process(const PROCESSENTRY32& processEntry)
{
this->processEntry = processEntry;
}
Process::Process()
{
}
Process::~Process()
{
}
DWORD Process::getPid()
{
return processEntry.th32ProcessID;
}
DWORD Process::getParentPid()
{
return processEntry.th32ParentProcessID;
}
DWORD Process::getThreadsCount()
{
return processEntry.cntThreads;
}
DWORD Process::getModuleId()
{
return processEntry.th32ModuleID;
}
char* Process::getExeFilename()
{
return processEntry.szExeFile;
}
ProcessEnumerator.cppCode:#pragma once
#include <windows.h>
#include <Tlhelp32.h>
#include "Process.h"
class ProcessEnumerator
{
HANDLE snapshot;
PROCESSENTRY32 processEntry;
public:
ProcessEnumerator();
~ProcessEnumerator();
bool getFirst(Process& process);
bool getNext(Process& process);
};
main.cppCode:#include "ProcessEnumerator.h"
ProcessEnumerator::ProcessEnumerator()
{
snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
processEntry.dwSize = sizeof(PROCESSENTRY32);
}
ProcessEnumerator::~ProcessEnumerator()
{
CloseHandle(snapshot);
}
bool ProcessEnumerator::getFirst(Process& process)
{
if (Process32First(snapshot, &processEntry))
{
process = Process(processEntry);
return true;
}
else
{
return false;
}
}
bool ProcessEnumerator::getNext(Process& process)
{
if (Process32Next(snapshot, &processEntry))
{
process = Process(processEntry);
return true;
}
else
{
return false;
}
}
It is worrking just fine, i can get any process and play with it, and get the PID too. I really dont know you indicated me those Token privileges functions, anything wrong with my code? If not, whats the next step?Code:#include <iostream>
#include "ProcessEnumerator.h"
int main()
{
ProcessEnumerator enumerator;
Process actual;
enumerator.getFirst(actual);
do
{
std::cout << "Process Name: " << actual.getExeFilename() << '\n';
std::cout << "Process ID : " << actual.getPid() << '\n';
} while (enumerator.getNext(actual));
std::cin.get();
return 0;
}
They're basically just wrapper, but I guess that's fine... You could make them more useful, but still...
You need to set debug privilege for your app in order to inject code into an executable.
Process.cpp
Main.cpp:Code:#include "Process.h"
LPCTSTR ProcessPrivileges::Tcb = SE_TCB_NAME;
LPCTSTR ProcessPrivileges::Debug = SE_DEBUG_NAME;
LPCTSTR ProcessPrivileges::Backup = SE_BACKUP_NAME;
LPCTSTR ProcessPrivileges::IncreaseQuota = SE_INCREASE_QUOTA_NAME;
Process::Process(const HANDLE& processHandle)
{
this->handle = processHandle;
this->handleOpened = true;
}
Process::Process(const PROCESSENTRY32& processEntry)
{
this->processEntry = processEntry;
this->handleOpened = false;
}
Process::Process()
{
}
Process::~Process()
{
if (handleOpened) CloseHandle(handle);
}
HANDLE Process::getHandle()
{
if (!handleOpened)
{
handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, getPid());
handleOpened = true;
}
return handle;
}
DWORD Process::getPid()
{
return processEntry.th32ProcessID;
}
DWORD Process::getParentPid()
{
return processEntry.th32ParentProcessID;
}
DWORD Process::getThreadsCount()
{
return processEntry.cntThreads;
}
DWORD Process::getModuleId()
{
return processEntry.th32ModuleID;
}
char* Process::getExeFilename()
{
return processEntry.szExeFile;
}
bool Process::setPrivilege(LPCTSTR privilege, bool enable)
{
LUID luid;
HANDLE token;
TOKEN_PRIVILEGES tokenPrivileges;
if (!OpenProcessToken(getHandle(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) return false;
if (!LookupPrivilegeValue(NULL, privilege, &luid)) return false;
tokenPrivileges.PrivilegeCount = 1;
tokenPrivileges.Privileges[0].Luid = luid;
if (enable) tokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
else tokenPrivileges.Privileges[0].Attributes = 0;
AdjustTokenPrivileges(token, FALSE, &tokenPrivileges, sizeof(TOKEN_PRIVILEGES), NULL, NULL);
DWORD error;
if ((error = GetLastError()) != ERROR_SUCCESS)
{
std::cout << error;
return false;
}
return true;
}
HANDLE Process::getCurrentProcessHandle()
{
return OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());
}
DWORD Process::getCurrentProcessId()
{
return GetCurrentProcessId();
}
Everything just fine, debug level has been seted, now whats the next step? (Do i have to close any handle that i havent or anything else in the actual code? )Code:#include <iostream>
#include "ProcessEnumerator.h"
int main()
{
ProcessEnumerator enumerator;
Process actual;
Process myProcess(Process::getCurrentProcessHandle());
myProcess.setPrivilege(ProcessPrivileges::Debug, true);
enumerator.getFirst(actual);
do
{
std::cout << "Process Name: " << actual.getExeFilename() << '\n';
std::cout << "Process ID : " << actual.getPid() << '\n';
} while (enumerator.getNext(actual));
std::cin.get();
return 0;
}
Yes, debug privilege require admin. This can be set in the manifest to require your program to run as admin. If you have Visual Studio 2008, you should be able to set this setting via project properties I think.
The next step is a little hush-hush. The easiest way to inject code is via a dll (though your set-up routine needs to be an application). This is a little tricky. First you have to allocate a string in the target process's memory. There are several ways of doing it. I'm not an expert, but VirtualAllocEx might be able to do the trick.
Inside this memory, copy the complete filename to your dll.
Then use CreateRemoteThread to create a remote thread in the target process. As for the start routine, you should use LoadLibrary and the argument should be the remotely allocated memory that points to your dll.
The result is that the target process will load your dll into memory!
From there, you can use the dll's init code to start a chain reaction of executing code inside the target application!
More than this... I don't know. Actually, I haven't tested the above, but it should work, because there are tutorials out there that guides you through how to do it exactly like that.
1) Ok, once i have done this what should i do? I mean, i have my code running inside the process, why have i done that? If it is to overwrite somre memory i could have done this by simply using WriteProcessMemory couldn't i? (Correct me if i am wrong).
2) How could i make the class Process more usefull as Elysia said?
Because otherwise you need to inject code into the process which is way trickier than forcing it to load a dll from which inside you can execute your own code.
You're actually going to have to re-direct a certain DirectInput function call to return your own device. So you need to overwrite the function address for the function. But the process can only execute code within its own virtual memory space.
Injecting code a little about anywhere is extremely difficult and error prone. An easier way is just to redirect the call to a similar function within a dll within the project's virtual memory space.
For example, it could enumerate all processes, store them in a vector. It could expose member functions to return properties for a specific process (as opposed to creating a new class and passing arguments around).Quote:
2) How could i make the class Process more usefull as Elysia said?
Essentially, make a class that is the enumeration itself. It can store a class which is the Process object itself. The process object is the ones you can manipulate, etc. The enumerator allows you to search and find processes easy.
Oh, i got it, and how can i know that function address?Quote:
You're actually going to have to re-direct a certain DirectInput function call to return your own device. So you need to overwrite the function address for the function.
It's stored somewhere in the executable header. Technical details I don't remember 100%, but since Windows can randomly load dlls and such, for performance reasons, it stores all the real function addresses in a header and simply makes the code jump into that area when doing function calls.
So you would have to walk the PE header and find the function you wanted to hook, then overwrite it with your own function address inside the dll. I don't remember how. But there are guides over at codeproject on how to do this. But be careful, this isn't exactly playing nice. Microsoft doesn't like it at all and that's typically why they made the KernelGuard in the first place.
This is a common method to "take over" the system, like many security softwares does.
The simplest adn easiest way is to use PostMessage() to send the appropriate keypress information to the application. There are API methods for enumerating all the windows and getting the titlebar info from them. Even a directX program runnign in full screen mode has a titlebar, even if it isnt visible. Then just PostMessage() to that window and boom, you have yoru macro generator.