Can Keylogger apps able to see the messages sent via SendMessage()? - c#

I am creating a c# app to send a message in a notepad using the SendMessage() function. I have successfuly passed the strings to notepad. The strings are very important and i was wondering if a keylogger program can see this message?
If yes, do you have any other ideas on how i can send the strings securely?
Below is a sample code i used.
[DllImport("user32.dll", EntryPoint = "FindWindowEx")]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("User32.dll")]
public static extern int SendMessage(IntPtr hWnd, int uMsg, int wParam, string lParam);
Process[] notepads = Process.GetProcessesByName("notepad");
if (notepads.Length == 0) return;
if (notepads[0] != null)
{
IntPtr child = FindWindowEx(notepads[0].MainWindowHandle, new IntPtr(0), "Edit", null);
SendMessage(child, 0x000C, 0, TextBox1.Text);
}

What you're doing is not secure; there are multiple ways a SendMessage call can be spied on by anyone who wants to do so.
SetWindowsHookEx with WH_CALLWNDPROC or WH_CALLWNDPROCRET will let an attacker monitor all messages being sent to a given thread, or they can monitor all messages across the system and just filter out the ones headed to your SendMessage target.
Alternately, an attacker can inject themselves into your recipient process, using WriteProcessMemory to write a DLL name into the recipient process, then CreateRemoteThread and LoadLibrary to load the DLL into the target process. After that, monitoring the process's messages should be fairly trivial.
To avoid using a DLL, an attacker could also use WriteProcessMemory to write code directly into the target process's memory space, then CreateRemoteThread to call it.
All three of these monitoring methods are documented in this CodeProject article. It's admittedly a little old, but the methods should still be relevant, particularly the SetWindowsHookEx one.
An attacker could also hook various Windows APIs directly; it's difficult and somewhat risky, but depending on the sensitivity of your data an attacker might find it a worthwhile approach.
Trying to protect your data will be very difficult, honestly. You can look at how KeePass keeps passwords secure; it's got a setting (at least in the 1.x branch; KeePass 2.x is an entirely different app) to "allow pasting only once and protect against clipboard spies", which might be of some benefit to you. Taking another cue from KeePass, you can also look into Windows' Data Protection API.
As a side note, you may want to replace
SendMessage(child, 0x000C, 0, TextBox1.Text);
with
SendMessage(child, WM_SETTEXT, 0, TextBox1.Text);
for readability. Not many people will recognize 0x000C by itself, although it's possible to guess what the message is based on context.

Related

Whats the difference between open and native handle in c#

I am looking for the difference between
IntPtr handle_1 = process.Handle;
Gets the native handle of the associated process.
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr OpenProcess(
uint processAccess,
bool bInheritHandle,
uint processId
);
IntPtr handle_2 = OpenProcess(0x0010,false,process.Id);
If the function succeeds, the return value is an open handle to the specified process.
Both got different values. But i can still read the memory with those. I would like to understand the difference between those two, to prevent making mistakes.
I am using them in the context:
ReadProcessMemory(handle_x, addr, data, data.Length, IntPtr.Zero);
Both are process handles, and as such can be used in the same manner.
A Process object contains a process handle through its Handle property. When you call Dispose on that object, you close that handle.
When you call OpenProcess on the process' ID, you get a different handle (so it has a different value) that refers to the same process. You must separately close that handle when you're done with it (using the Win32 function CloseHandle): disposing the Process object won't magically close the handle you got from OpenProcess.
So why would you call OpenProcess when you already have a perfectly functional handle in Process? Well, access rights, really. The handle obtained by Process has PROCESS_ALL_ACCESS (i.e. full access rights). If you want an handle with fewer rights, you can use OpenProcess for that.
But really, for most purposes, there isn't really a need to mess around with native APIs when you need a process handle.

SendKeys with games: with some characters it works, but with some it doesn't

I want to simulate input in games with SendKeys, but I have a hard time.
If I use it with i.e. the letter T, while the cursor in Minecraft is in a textbox (in the main menu), it works, the letter T is written in the textbox.
But with {ESC} it doesn't work. Nothing happens. If I press it manually, it backs to the previous menu. (as it should)
With some applications ESC works:
It works with Discord, Sourcetree, Slack, Chrome, CS2D,
but for some reason it doesn't work with Minecraft, Spelunky, Half-Life.
All of the applications mentioned above were in windowed mode.
Another issue:
If I send 2 to Minecraft while in a text field, it works correctly, 2 is written.
But if I send it while I'm playing, there is no effect. (The character should switch to Item Slot #2)
Same with " " (whitespace). In text fields it works, but the character won't jump in the game.
Code:
[DllImport("USER32.DLL", CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("USER32.DLL")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
public Form1()
{
InitializeComponent();
IntPtr minecraftHandle = FindWindow("GLFW30", "Minecraft* 1.15.2");
if (minecraftHandle == IntPtr.Zero)
{
MessageBox.Show("Minecraft is not running.");
return;
}
SetForegroundWindow(minecraftHandle);
SendKeys.SendWait("{ESC}");
}
I tried it without focus switching: by assigning the SendKey calls to a hotkey, so the target application can be in focus when the SendKeys are called.
The results are the same :\
Do not use SendKeys.Send to messaging between processes working on different runtimes
SendKeys.Send method is from System.Windows.Forms namespace.
This means it is not a Windows Input simulator, but just a little helper for Windows Forms applications. There is no guarantee this method work with another process on different (not .NET) runtime system.
Despite the fact that SendKeys.Send method uses native Windows API, it send key pressing message only of fixed period of time, so game frame handling may not have time to catch this message to manage it. So you may need for separate commands to send message about key down and key up events.
Do not use SendKeys API for messaging with another processes, especially with games.
Also, games can use protection system to rid of automatic bots that can blocks any messages from operation system programming input
So, what you can use?
First, you can try to use PostMessage of user32.dll system library:
const uint WM_KEYDOWN = 0x0100;
const uint WM_KEYUP = 0x0101;
[DllImport("user32.dll")]
static extern bool PostMessage(IntPtr hWnd, uint msg, int wParam, int lParam);
// hWnd - Window handler (can be getted by using GetForegroundWindow/FindWindow methods)
// msg - Key up/down message (WM_KEYUP / WM_KEYDOWN)
// wParam - Virual key code you need to pass to the window
// lParam - Additional parameter for set up key message behaviour.
All virtual key codes can be found on microsoft docs website:
https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
Don't forget that you need to wait some time before key releasing. This is needed because games cache inputs between frames, and frame has fixed time to catch input. Just write some delay between key down and up messages.
Also you can set up key message behaviour by lParam. See WM_KEYDOWN and WM_KEYUP parameters. Special thing about WM_KEYDOWN message is if you pressing key on real keyboard long time, operation system repeating WM_KEYDOWN message accordingly. Repeating count can be setted up through lParam. Use it if window you messaging does not react on single keydown message.
PostMessage is low-level system command that can be used for messaging between processes. This command has a low probability to be blocked by protection system (but not zero) and high probability to be received by the game/process you working with. Also it provides opportunity to separate key up and key down messages.
What if PostMessage didn't work?
Try to use hardware scan code instead of virtual key code. Detailed explanation how you can do that described in this answer.
If protection system is really good and PostMessage is blocking even if you use hardware scan code, one thing you can try is to use another keyboard input driver or write it yourself. That driver must replace default system keyboard driver. And you can message it to interact with game. This is the 100% guarantee way to interact with other process through keyboard. But if you use public custom keyboard drivers, there is some probability that protection system blocks it. So you need to write your own driver to message between processes.

SetConsoleActiveScreenBuffer does not display screen buffer

I am currently trying to write a console application in C# with two screen buffers, which should be swapped back and forth (much like VSync on a modern GPU). Since the System.Console class does not provide a way to switch buffers, I had to P/Invoke several methods from kernel32.dll.
This is my current code, grossly simplified:
static void Main(string[] args)
{
IntPtr oldBuffer = GetStdHandle(-11); //Gets the handle for the default console buffer
IntPtr newBuffer = CreateConsoleScreenBuffer(0, 0x00000001, IntPtr.Zero, 1, 0); //Creates a new console buffer
/* Write data to newBuffer */
SetConsoleActiveScreenBuffer(newBuffer);
}
The following things occured:
The screen remains empty, even though it should be displaying newBuffer
When written to oldBuffer instead of newBuffer, the data appears immediately. Thus, my way of writing into the buffer should be correct.
Upon calling SetConsoleActiveScreenBuffer(newBuffer), the error code is now 6, which means invalid handle. This is strange, as the handle is not -1, which the documentation discribes as invalid.
I should note that I very rarely worked with the Win32 API directly and have very little understanding of common Win32-related problems. I would appreciate any sort of help.
As IInspectable points out in the comments, you're setting dwDesiredAccess to zero. That gives you a handle with no access permissions. There are some edge cases where such a handle is useful, but this isn't one of them.
The only slight oddity is that you're getting "invalid handle" rather than "access denied". I'm guessing you're running Windows 7, so the handle is a user-mode object (a "pseudohandle") rather than a kernel handle.
At any rate, you need to set dwDesiredAccess to GENERIC_READ | GENERIC_WRITE as shown in the sample code.
Also, as Hans pointed out in the comments, the declaration on pinvoke.net was incorrect, specifying the last argument as a four-byte integer rather than a pointer-sized integer. I believe the correct declaration is
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr CreateConsoleScreenBuffer(
uint dwDesiredAccess,
uint dwShareMode,
IntPtr lpSecurityAttributes,
uint dwFlags,
IntPtr lpScreenBufferData
);

C# string to long pointer

I am working with an application in C# that need to send a message to a C++ application.
I imported
[DllImport("user32.dll")]
public static extern IntPtr SendMessage(
int hWnd, // handle to destination window
uint Msg, // message
IntPtr wParam, // first message parameter
IntPtr lParam // second message parameter
);
but now, my problem is that I need to passe string to wParam and lParam. I tried unsafe code, but it seems string just doesnt work like the rest of variables. How can I achieve that? Thanks.
The declaration is wrong, the wParam and lParam arguments are IntPtr, not long.
There is a complication because you are trying to send strings. What matters if the target window is Unicode enabled or not. There are two versions of SendMessage, SendMessageA() and SendMessageW(). The former needs to be used if the program is dated and uses 8-bit character strings rather than UTF-16 encoded strings.
You can find out by using Spy++. Use the finder tool to select the window of the application. In the General property tab, you'll see "Window proc". It will say (Unicode) if the window is Unicode enabled. If you don't see it then the strings have to be translated to 8-bit characters.
To generate the string pointers you need to pass, you can use Marshal.StringToHGlobalAnsi or StringToHGlobalUni (respectively 8-bit and Unicode). You can however play a trick to let the P/Invoke marshaller translate the string for you. Saves you the hassle of having to free the strings after the call. For the Ansi version, you can declare the API function like this:
[DllImport("user32.dll", CharSet = CharSet.Ansi, EntryPoint = "SendMessageA", ExactSpelling = true)]
private static extern IntPtr SendMessageStrings(IntPtr hWnd, int msg, string wParam, string lParam);
And the Unicode version like this:
[DllImport("user32.dll", CharSet = CharSet.Unicode, EntryPoint = "SendMessageW", ExactSpelling = true)]
private static extern IntPtr SendMessageStrings(IntPtr hWnd, int msg, string wParam, string lParam);
One final note: this will not work as-is if the window belongs to another application, you'll crash it. The pointer values you pass are only valid in your own process, not in the C++ process. To work around that, you have to allocate memory in the target process so that the pointer is valid. That requires OpenProcess to get a handle to the process, VirtualAllocEx() to allocate memory in the target process, big enough to store the string, WriteProcessMemory to write the string. Now you can call SendMessage(), use a version that is declared with IntPtr for the wParam and lParam arguments, pass the value you got from VirtualAllocEx. Next use VirtualFreeEx() to release the memory and CloseHandle to clean up. Or keep the memory around for the next time if you do this often.
Quite a lot of P/Invoke to get wrong there. Not to mention security issues, WriteProcessMemory requires admin privileges, UAC elevation is required.
Passing the address of the string would involve unsafe code,
since Win32 API calls expect addresses (in a C/C++ native envrion). What windows message are you sending that requires a string in wParam or lParam?
We ended up using "WmCpyDta_d.dll" to deal with all that.

Create window as child in third party application

I'm trying to get my C# form to be parented correctly in a third party app, I have the handle to the control that I would like my form parented to but just can't seem to get it to work.
alt text http://img693.imageshack.us/img693/8871/examplec.jpg
I would like to create my form so that it is part of the MDIClient, handle 005E0ED6. Just like Window 01D7157D.
Is this possible? If so can it be done in C#?
How have you tried doing it? Did you try SetParent? See the following StackOverflow question to see if it helps. Embedding HWND into external process using SetParent
This code seems to work:
[DllImport("user32.dll")]
private static extern
IntPtr GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);
[DllImport("user32.dll")]
private static extern
IntPtr AttachThreadInput(IntPtr idAttach, IntPtr idAttachTo, int fAttach);
WinAPI.SetParent(this.Handle, otherappshandle);
IntPtr otherprocessID = GetWindowThreadProcessId(otherappshandle, new IntPtr(0));
IntPtr threadID = new IntPtr(AppDomain.GetCurrentThreadId());
AttachThreadInput(threadID , otherprocessID , 1);
Good luck. I've gone down that road, and found that there's enough little irritating gotchas that I eventually gave up on it.
SetParent() and the like will get you part of the way there, but there's a bunch of little gotchas to watch as far as the overall system (message pump blocking etc.) that just make it a time sink.
With WinForms, especially, I'd highly recommend just running your UI in the main process (if you can), and if you want to isolate your processing in another process do that instead.

Categories

Resources