W
Wave
Thread author
Hello everyone.
In this thread I will be discussing about some of the important Windows processes which come shipped with Windows (since at least Vista and on-wards). I will not be going through all of them of course, there are many important Windows processes which will not be discussed in this thread (such as smss.exe, svchost.exe), but some of them will be discussed.
Throughout this thread I do put in some code examples for some specific things and shift focus on discussion about security software development - hopefully this won't be a problem. Please do not attempt to use the code examples unless you know what you're doing to avoid any sort of problems - all code is clean though and not "harmful"/"dangerous", even if you did compile and run it.
Part 1 – lsass.exe
Lsass.exe is the Local Security Authority Subsystem Service and it serves many purposes; it is a very important process within Windows and the OS wouldn’t be able to function properly without it.
One of the most common jobs that lsass.exe is responsible for would be creating access tokens for executing processes on the systems – depending on the access token will depend on what the program can and cannot do. These access tokens are all related to the token privileges; programs can give themselves additional token privileges through a call to the native API function RtlAdjustPrivilege (exported by ntdll.dll), or alternatively they can use the standard Win32 API function AdjustTokenPrivileges (exported by advapi32.dll) – at the end of this part you will be able to find some example source code on using either of these functions from C++.
The Local Security Authority Subsystem Service is responsible for much more than access tokens. It is also responsible for: password changes for the user accounts; verifying the log-on to the user account; creating security logs (linked to the system audit policy – viewable under Event Viewer).
The Local Security Authority Subsystem Service process (lsass.exe) can actually be theoretically easily exploited since it is not a protected process – this means that any program with at least debugging rights can open a handle to the process, which opens up the opportunity to inject code into the process remotely and force-execute its functions to cause undesirable changes to the system (e.g. force-create an access token).
I will now show you an example of using either ntdll.dll!RtlAdjustPrivilege or advapi32.dll!AdjustTokenPrivileges to enable debugging rights. The following source code is written in C++:
I will note that the first method used in the enable_priv function (RtlAdjustPrivilege) will only work if the program has been run with administrative rights, whereas the second method (via AdjustTokenPrivilege) will work without running the program with administrative rights.
Part 2 – csrss.exe
Csrss.exe is the Client Service Runtime Subsystem Service, and its commonly known for being responsible for providing important functions to provide functionality to the Windows OS, and managing threading/console windows. As well as this, csrss.exe is marked as a critical process, therefore termination of this process will result in a BSOD crash with the error message CRITICAL_PROCESS_DIED.
Csrss.exe can have a good use when it comes to detecting hidden malicious processes being protected by rootkits, and also for process monitoring purposes (and this can be tweaked for another rootkit-protected process detection method also).
Process monitoring method via csrss.exe utilisation:
There are some interesting functions which are exported by a Windows Dynamic Link Library (*.DLL) called csrsrv.dll; csrss.exe imports this module and utilises some functions exported by this library. The two interesting functions which become exported by this library would be: CsrCreateProcess and CsrTerminateProcess.
If you are able to obtain a handle to csrss.exe and then utilise this handle to inject code into it (e.g. you can perform stealth code injection or you can work with standard DLL injection techniques to get your code running within the address space of csrss.exe on its own thread) then you can place a hook on those two interesting functions (CsrTerminateProcess and CsrTerminateProcess) which will allow you to log when a new process is created or when a process becomes terminated; through these hooks you will be able to essentially monitor all user-mode process execution attempts (at the least), and when a new process is created and your CsrTerminateProcess hook callback function becomes invoked, you will be greeted with access to a working and usable HANDLE to the newly starting up process, which you can use for whatever you want (terminate the process if you do not want to allow the execution, inject into it to control it, etc).
In a way, hooking CsrCreateProcess and CsrTerminateProcess would create similar functionality in user-mode of using the kernel-mode callback PsSetCreateProcessNotifyRoutine/Ex. The good thing about this method is that you will only need to inject into csrss.exe and hook CsrCreateProcess/CsrTerminateProcess once, you won’t need to inject into any other programs except csrss.exe for it to work.
However, this option may be good mainly for Windows Vista and Windows 7 only, and not for Windows 8/8.1 or Windows 10 – on Windows Vista and Windows 7, csrss.exe is not a protected process, and therefore you can obtain a handle to the SYSTEM process as long as you have enabled debugging rights, however on newer OS editions of Windows, csrss.exe will be a protected process and you will be unable to obtain a handle to it from user-mode. Of course, if you are developing software for Windows Vista and Windows 7 and you do not have experience with device driver development to use kernel-mode callbacks then this can be a good alternate from user-mode, however of course using a kernel-mode callback for process monitoring would be much more secure.
In terms of anti-rootkit development, this process monitoring method could be utilised; you could log all the process start-up notifications passing through the callback being invoked from the CsrCreateProcess hook (and obviously remove processes which were recorded after they become terminated via the callback invoke from the CsrTerminateProcess hook), and then you can regularly scan through the running processes from a normal program running as admin (not csrss.exe – you could work with IPC between csrss.exe from your injected code and another process running on the system which you own), and then you can compare if you logged any process creations which have not yet been terminated but cannot be found by the other process – this would signify a process is being hidden by a rootkit, most likely more useful for user-mode processes, since not all user-mode rootkits will intercept for csrss.exe also, but probably for normal typical applications such as Task Manager).
That being said, csrss.exe can be used for detection of hidden processes by enumerating all the running handles from code executing within csrss.exe itself. There are tools which have utilised csrss.exe for enumerating through handles to detect hidden rootkit processes before, such as CsrWalker (which can still detect some rootkit-protected processes).
Part 3 - winlogon.exe
Winlogon.exe is a critical Windows process and it is mainly responsible for logging in/out of the user accounts and the lock screen (working with the SAK, which stands for Secure Attention Key). Since winlogon.exe is a critical process, should the process be terminated, it will result in a system-wide crash (BSOD – the error message will be CRITICAL_PROCESS_DIED). That being said, winlogon.exe itself does not contain the user login credential information in its memory – this is sorted out by other external components within the OS.
Of course winlogon.exe can be a victim of malicious attacks, however based on my experience in malware analysis I tend to find explorer.exe and csrss.exe attacked more commonly than winlogon.exe.
Part 4 – explorer.exe
Explorer.exe is a very important process and heavily evolves around GUI aspects of the Windows OS – it is essentially the shell which provides the start menu, desktop items, taskbar, tray menu, and all the other GUI components shown in Windows by default like this. That being said, it is also responsible as being the primary main file manager software embedded within the OS; without explorer.exe there would be no GUI file explorer by default in Windows.
You may not expect it, however explorer.exe is not actually a critical process, regardless of its importance and binding to the Windows OS – you can freely terminate/restart it at any time without the system crashing, however without explorer.exe running you may not be able to use your system properly since you’ll lose the main GUI components such as the task bar and the such – although currently active running programs will still be operational as long as you don’t minimise them/lose their focus.
Explorer.exe is one of the most commonly attacked Windows processes when it comes to malicious software and while it less common these days, it used to be extremely common to regularly find malicious software attempting to pretend to be a genuine version of explorer.exe, as a method of tricking the user into believing the process was safe. Without that being said, the same applies to many other Windows processes of course, such as: csrss.exe, winlogon.exe, svchost.exe, smss.exe, etc.
Since explorer.exe runs under the standard user account and is a non-administrative process (not elevated), any standard running program can freely open up a handle to it and inject code into it. An example of opening a handle to the process from a standard-running program would be the following sample (C++):
In theory the code should be successful since the process is not elevated therefore you do not need to be elevated to obtain a handle to it, either. Once you have obtained a handle to the process, you can inject code into it, regardless of your process being elevated or not – another reason why it is important for security software to monitor unknown programs and prevent them from opening handles to sensitive processes which should be protected but are not protected by Windows by default, such as explorer.exe.
-------------------------------------------------
Hopefully this thread will be found useful by someone out there!
Stay safe,
Wave.
In this thread I will be discussing about some of the important Windows processes which come shipped with Windows (since at least Vista and on-wards). I will not be going through all of them of course, there are many important Windows processes which will not be discussed in this thread (such as smss.exe, svchost.exe), but some of them will be discussed.
Throughout this thread I do put in some code examples for some specific things and shift focus on discussion about security software development - hopefully this won't be a problem. Please do not attempt to use the code examples unless you know what you're doing to avoid any sort of problems - all code is clean though and not "harmful"/"dangerous", even if you did compile and run it.
Part 1 – lsass.exe
Lsass.exe is the Local Security Authority Subsystem Service and it serves many purposes; it is a very important process within Windows and the OS wouldn’t be able to function properly without it.
One of the most common jobs that lsass.exe is responsible for would be creating access tokens for executing processes on the systems – depending on the access token will depend on what the program can and cannot do. These access tokens are all related to the token privileges; programs can give themselves additional token privileges through a call to the native API function RtlAdjustPrivilege (exported by ntdll.dll), or alternatively they can use the standard Win32 API function AdjustTokenPrivileges (exported by advapi32.dll) – at the end of this part you will be able to find some example source code on using either of these functions from C++.
The Local Security Authority Subsystem Service is responsible for much more than access tokens. It is also responsible for: password changes for the user accounts; verifying the log-on to the user account; creating security logs (linked to the system audit policy – viewable under Event Viewer).
The Local Security Authority Subsystem Service process (lsass.exe) can actually be theoretically easily exploited since it is not a protected process – this means that any program with at least debugging rights can open a handle to the process, which opens up the opportunity to inject code into the process remotely and force-execute its functions to cause undesirable changes to the system (e.g. force-create an access token).
I will now show you an example of using either ntdll.dll!RtlAdjustPrivilege or advapi32.dll!AdjustTokenPrivileges to enable debugging rights. The following source code is written in C++:
Code:
#include <Windows.h>
#include <winternl.h>
#include <iostream>
using namespace std;
typedef NTSTATUS(NTAPI *pdef_RtlAdjustPrivilege)(ULONG Privilege, BOOLEAN bEnable, BOOLEAN bCurrentThread, PBOOLEAN pbEnabled);
bool enable_priv(int priv_method)
{
BOOL bResult = FALSE;
if (priv_method == 1) // use NTAPI
{
BOOLEAN bRes;
LPVOID RtlAdjustPrivilege_addr = GetProcAddress(LoadLibraryA("ntdll.dll"), "RtlAdjustPrivilege");
if (!RtlAdjustPrivilege_addr)
{
cout << "Unable to obtain the address of ntdll!RtlAdjustPrivilege!\n";
}
pdef_RtlAdjustPrivilege RtlHandle = (pdef_RtlAdjustPrivilege)RtlAdjustPrivilege_addr;
if (NT_SUCCESS(RtlHandle(20, TRUE, FALSE, &bRes)))
{
cout << "Successfully enabled Debugging Rights (SeDebugPrivilege) via ntdll!RtlAdjustPrivilege!\n";
bResult = TRUE;
}
else
{
cout << "Failed to enable Debugging Rights (SeDebugPrivilege) via ntdll!RtlAdjustPrivilege: " << GetLastError() << endl;
bResult = FALSE;
}
}
else if (priv_method == 2) // use Win32 API
{
HANDLE TokenHandle = { 0 };
TOKEN_PRIVILEGES TokenPriv = { 0 };
LUID lValueId = { 0 };
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &TokenHandle))
{
cout << "Failed to open the process token: " << GetLastError() << endl;
bResult = FALSE;
}
if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &lValueId))
{
cout << "Failed to lookup the privilege value: " << GetLastError() << endl;
bResult = FALSE;
}
TokenPriv.PrivilegeCount = 1;
TokenPriv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
TokenPriv.Privileges[0].Luid = lValueId;
if (AdjustTokenPrivileges(TokenHandle, FALSE, &TokenPriv, sizeof(TokenPriv), NULL, NULL))
{
cout << "Successfully adjusted the token privileges via AdjustTokenPrivileges!\n";
bResult = TRUE
}
else
{
cout << "Failed to adjust the token privileges: " << GetLastError() << endl;
bResult = FALSE;
}
}
return bResult;
}
int main()
{
BOOL bEnable = enable_priv(1);
getchar();
return 0;
}
I will note that the first method used in the enable_priv function (RtlAdjustPrivilege) will only work if the program has been run with administrative rights, whereas the second method (via AdjustTokenPrivilege) will work without running the program with administrative rights.
Part 2 – csrss.exe
Csrss.exe is the Client Service Runtime Subsystem Service, and its commonly known for being responsible for providing important functions to provide functionality to the Windows OS, and managing threading/console windows. As well as this, csrss.exe is marked as a critical process, therefore termination of this process will result in a BSOD crash with the error message CRITICAL_PROCESS_DIED.
Csrss.exe can have a good use when it comes to detecting hidden malicious processes being protected by rootkits, and also for process monitoring purposes (and this can be tweaked for another rootkit-protected process detection method also).
Process monitoring method via csrss.exe utilisation:
There are some interesting functions which are exported by a Windows Dynamic Link Library (*.DLL) called csrsrv.dll; csrss.exe imports this module and utilises some functions exported by this library. The two interesting functions which become exported by this library would be: CsrCreateProcess and CsrTerminateProcess.
If you are able to obtain a handle to csrss.exe and then utilise this handle to inject code into it (e.g. you can perform stealth code injection or you can work with standard DLL injection techniques to get your code running within the address space of csrss.exe on its own thread) then you can place a hook on those two interesting functions (CsrTerminateProcess and CsrTerminateProcess) which will allow you to log when a new process is created or when a process becomes terminated; through these hooks you will be able to essentially monitor all user-mode process execution attempts (at the least), and when a new process is created and your CsrTerminateProcess hook callback function becomes invoked, you will be greeted with access to a working and usable HANDLE to the newly starting up process, which you can use for whatever you want (terminate the process if you do not want to allow the execution, inject into it to control it, etc).
In a way, hooking CsrCreateProcess and CsrTerminateProcess would create similar functionality in user-mode of using the kernel-mode callback PsSetCreateProcessNotifyRoutine/Ex. The good thing about this method is that you will only need to inject into csrss.exe and hook CsrCreateProcess/CsrTerminateProcess once, you won’t need to inject into any other programs except csrss.exe for it to work.
However, this option may be good mainly for Windows Vista and Windows 7 only, and not for Windows 8/8.1 or Windows 10 – on Windows Vista and Windows 7, csrss.exe is not a protected process, and therefore you can obtain a handle to the SYSTEM process as long as you have enabled debugging rights, however on newer OS editions of Windows, csrss.exe will be a protected process and you will be unable to obtain a handle to it from user-mode. Of course, if you are developing software for Windows Vista and Windows 7 and you do not have experience with device driver development to use kernel-mode callbacks then this can be a good alternate from user-mode, however of course using a kernel-mode callback for process monitoring would be much more secure.
In terms of anti-rootkit development, this process monitoring method could be utilised; you could log all the process start-up notifications passing through the callback being invoked from the CsrCreateProcess hook (and obviously remove processes which were recorded after they become terminated via the callback invoke from the CsrTerminateProcess hook), and then you can regularly scan through the running processes from a normal program running as admin (not csrss.exe – you could work with IPC between csrss.exe from your injected code and another process running on the system which you own), and then you can compare if you logged any process creations which have not yet been terminated but cannot be found by the other process – this would signify a process is being hidden by a rootkit, most likely more useful for user-mode processes, since not all user-mode rootkits will intercept for csrss.exe also, but probably for normal typical applications such as Task Manager).
That being said, csrss.exe can be used for detection of hidden processes by enumerating all the running handles from code executing within csrss.exe itself. There are tools which have utilised csrss.exe for enumerating through handles to detect hidden rootkit processes before, such as CsrWalker (which can still detect some rootkit-protected processes).
Part 3 - winlogon.exe
Winlogon.exe is a critical Windows process and it is mainly responsible for logging in/out of the user accounts and the lock screen (working with the SAK, which stands for Secure Attention Key). Since winlogon.exe is a critical process, should the process be terminated, it will result in a system-wide crash (BSOD – the error message will be CRITICAL_PROCESS_DIED). That being said, winlogon.exe itself does not contain the user login credential information in its memory – this is sorted out by other external components within the OS.
Of course winlogon.exe can be a victim of malicious attacks, however based on my experience in malware analysis I tend to find explorer.exe and csrss.exe attacked more commonly than winlogon.exe.
Part 4 – explorer.exe
Explorer.exe is a very important process and heavily evolves around GUI aspects of the Windows OS – it is essentially the shell which provides the start menu, desktop items, taskbar, tray menu, and all the other GUI components shown in Windows by default like this. That being said, it is also responsible as being the primary main file manager software embedded within the OS; without explorer.exe there would be no GUI file explorer by default in Windows.
You may not expect it, however explorer.exe is not actually a critical process, regardless of its importance and binding to the Windows OS – you can freely terminate/restart it at any time without the system crashing, however without explorer.exe running you may not be able to use your system properly since you’ll lose the main GUI components such as the task bar and the such – although currently active running programs will still be operational as long as you don’t minimise them/lose their focus.
Explorer.exe is one of the most commonly attacked Windows processes when it comes to malicious software and while it less common these days, it used to be extremely common to regularly find malicious software attempting to pretend to be a genuine version of explorer.exe, as a method of tricking the user into believing the process was safe. Without that being said, the same applies to many other Windows processes of course, such as: csrss.exe, winlogon.exe, svchost.exe, smss.exe, etc.
Since explorer.exe runs under the standard user account and is a non-administrative process (not elevated), any standard running program can freely open up a handle to it and inject code into it. An example of opening a handle to the process from a standard-running program would be the following sample (C++):
Code:
#include <Windows.h>
#include <TlHelp32.h>
#include <iostream>
using namespace std;
DWORD retProcessId(std::string targetProcessName)
{
HANDLE hProcess;
PROCESSENTRY32 processEntry32;
processEntry32.dwSize = sizeof(PROCESSENTRY32);
hProcess = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
do {
if (!strcmp(processEntry32.szExeFile, targetProcessName.c_str()))
{
CloseHandle(hProcess);
return processEntry32.th32ProcessID;
}
} while (Process32Next(hProcess, &processEntry32));
CloseHandle(hProcess);
return 0;
}
int main()
{
HANDLE ProcessHandle = OpenProcess(PROCESS_VM_OPERATION, FALSE, retProcessId("explorer.exe"));
getchar();
return 0;
}
In theory the code should be successful since the process is not elevated therefore you do not need to be elevated to obtain a handle to it, either. Once you have obtained a handle to the process, you can inject code into it, regardless of your process being elevated or not – another reason why it is important for security software to monitor unknown programs and prevent them from opening handles to sensitive processes which should be protected but are not protected by Windows by default, such as explorer.exe.
-------------------------------------------------
Hopefully this thread will be found useful by someone out there!
Stay safe,
Wave.
Last edited by a moderator: