Hello readers, Today you will learn about the most interesting topic; "Processes". So before working on creating processes, you should know a little bit about processes.
A process is a program which is currently in execution. You might also see many information with associated with a process, so on system level, a process is a data structure which stores all the information about process and resources used by it.
In this I will show you how to create a program that does the following
- list processes
- kill process by pid
- create process
- get process details
This post gonna be a bit more lengthy than others 😃
In this you will see me using tchar.h and wmain (instead of main). This is because from now onward, I will be working with wide characters. char
is used for so called ANSI family of functions (ends with A), whereas wchar_t
is used for new so called Unicode (or Wide) family of functions (ends with W)
List Processes
You can enumerate all the processes in your system by using EnumProcesses function declared in Psapi.h header file.
BOOL EnumProcesses(
DWORD *lpidProcess,
DWORD cb,
LPDWORD lpcbNeeded
);
Function parameters
-
lpidProcess → A pointer to an array that receives the list of process ids (aka
pid
) -
cb → The size of the
lpidProcess
array, in bytes. -
lpcbNeeded → Bytes returned in the
lpidProcess
array.
You will get process ids of the running process in the lpidProcess
. To get the name of the process, you need to first open the process using OpenProcess, declared in processthreadsapi.h with PROCESS_QUERY_INFORMATION | PROCESS_VM_READ
permissions, enumerate the modules and at last get the base module name. This base module will contain the name of the process.
HANDLE OpenProcess(
DWORD dwDesiredAccess,
BOOL bInheritHandle,
DWORD dwProcessId
);
Function parameters
- dwDesiredAccess → The access to the process object. This parameter can be one or more of the process access rights
-
bInheritHandle → If this value is
TRUE
, processes created by this process will inherit the handle - dwProcessId → The identifier of the local process to be opened.
If function will run successfully, it will return you a valid process handle.
To get the name of executable, you need to enumerate the process modules and then get the base module name
A loadable module of the process that let's process function is known as process module. It can either be a .dll
or .exe
. A process can load multiple modules into memory.
So to get the process name, you will be needing EnumProcessModules and GetModuleBaseName from Psapi.h
BOOL EnumProcessModules(
HANDLE hProcess,
HMODULE *lphModule,
DWORD cb,
LPDWORD lpcbNeeded
);
Function parameters description as follows
- hProcess → A valid handle to the process.
- *lphModule → An array that receives the list of module handles.
-
cb → The size of the
lphModule
array, in bytes -
lpcbNeeded → The number of bytes required to store all module handles in the
lphModule
array
DWORD GetMappedFileNameW(
HANDLE hProcess,
LPVOID lpv,
LPWSTR lpFilename,
DWORD nSize
);
Function parameters description as follows
-
hProcess → A handle to the process. with
PROCESS_QUERY_INFORMATION
access right - lpv → The address of the module to be verified.
-
lFilename → A pointer to the buffer that receives the name of the memory-mapped file to
lpv
belongs. -
nSize → The size of the
lpFilename
buffer.
So the snippet for this will look like the following
int ListProcesses() {
DWORD processes[1024], cbNeeded, cbProcesses;
// enumerating all processes
// https://docs.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-enumprocesses
BOOL procBool = EnumProcesses(processes, sizeof(processes), &cbNeeded);
if (!procBool) {
_tprintf(_T("Unable to fetch processes\n"));
return 1;
}
cbProcesses = cbNeeded / sizeof(DWORD); // getting actual number of processes that function has returned
_tprintf(_T("Total Processes: %d\n\n"), cbProcesses);
for (int i = 0; i < cbProcesses; i++) {
GetProcessNameById(processes[i]); // printing process name
}
return 0;
}
void GetProcessNameById(DWORD pId)
{
// TCHAR is same as WCHAR (wchar_t)
TCHAR procName[MAX_PATH] = _T("<Unknown>");
// opening the process
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocess
HANDLE process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pId);
// checking if process is opened
// the processes running in same privilege will only be opened
if (process != NULL) {
HMODULE hMod;
DWORD cbNeeded;
// enumerating the process modules
// https://docs.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-enumprocessmodules
if (EnumProcessModules(process, &hMod, sizeof(hMod),
&cbNeeded))
{
// getting module base name, which is the name of the process
// https://docs.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-getmappedfilenamew
GetModuleBaseName(process, hMod, procName,
sizeof(procName) / sizeof(TCHAR));
}
}
// closing process handle
// https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle
CloseHandle(process);
_tprintf(_T("[%d] %s\n"), pId, procName);
}
You will see many processes (even the one running with same user) have name <Unknown>
. This is because your process does not have privileges to read the process memory and therefore enumerate all the modules.
In case you want to read their names, you need to set the SeDebugPrivilege for the current process.
Kill a Process by PID
You might have killed a running process from the task manager that is either lagging or corrupted. So programmatically, you can kill a process by TerminateProcess from processthreadsapi.h
BOOL TerminateProcess(
HANDLE hProcess,
UINT uExitCode
);
Function parameters description as follows
-
hProcess → A handle to the process with
PROCESS_TERMINATE
permissions. - uExitCode → The exit code to be used by the process and threads terminated as a result of this call.
Snippet of killing the process would look like the following
int KillProcess(DWORD pId) {
// opening process
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocess
HANDLE hProc = OpenProcess(PROCESS_TERMINATE, FALSE, pId);
if (hProc == NULL) {
_tprintf(_T("Unable to open process %d\n"), pId);
return 1;
}
// terminating the process
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-terminateprocess
BOOL tpBool = TerminateProcess(hProc, 2); // exit the program with non zero return code
if (!tpBool) {
_tprintf(_T("Unable to kill the process %d\n"), pId);
// closing process handle
// https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle
CloseHandle(hProc);
return 1;
}
else {
_tprintf(_T("Killed Process %d\n"), pId);
// closing process handle
// https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle
CloseHandle(hProc);
return 0;
}
}
Create Process
The CreateProcess function from processthreadsapi.h creates a new process, which runs independently of the creating process. However, for simplicity, the relationship is referred to as a parent-child relationship.
BOOL CreateProcessW(
LPCWSTR lpApplicationName,
LPWSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCWSTR lpCurrentDirectory,
LPSTARTUPINFOW lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
);
Function parameter description as follows
-
lpApplicationName → The name of the module to be executed. This module can be a Windows-based application. It can be some other type of module. The string can specify the full path and file name of the module to execute. If this is
NULL
, the module name must be the first white space–delimited token in thelpCommandLine
string. -
lpCommandLine → The command line to be executed. The maximum length of this string is 32,767 character and the module name portion of
lpCommandLine
is limited toMAX_PATH
characters. -
lpProcessAttributes → A pointer to a
SECURITY_ATTRIBUTES
structure that determines whether the returned handle to the new process object can be inherited by child processes. If this isNULL
, the process handle can't be inherited. -
lpThreadAttributes → A pointer to a
SECURITY_ATTRIBUTES
structure that determines whether the returned handle to the new thread object can be inherited by child processes. If this isNULL
, the process handle can't be inherited. -
bInheritHandles → If this parameter is
TRUE
, each inheritable handle in the calling process is inherited by the new process. If the parameter isFALSE
, the handles are not inherited - dwCreationFlags → The flags that control the priority class and the creation of the process. For a list of values, see Process Creation Flags.
-
lpEnvironment → A pointer to the environment block for the new process. If this parameter is
NULL
, the new process uses the environment of the calling process. -
lpCurrentDirectory → The full path to the current directory for the process. If this parameter is
NULL
, the new process will have the same current drive and directory as the calling process. -
lpStartupInfo → A pointer to a
STARTUPINFO
orSTARTUPINFOEX
structure -
lpProcessInformation → A pointer to a
PROCESS_INFORMATION
structure that receives identification information about the new process.
So the snippet will look like this
int _CreateProcess()
{
std::wstring path(L"C:\\Windows\\notepad.exe");
STARTUPINFO si;
si.cb = sizeof(si);
PROCESS_INFORMATION pi;
// initializing the variables
ZeroMemory(&si, sizeof(si));
ZeroMemory(&pi, sizeof(pi));
BOOL cpBool = CreateProcessW(
NULL, // creating an independent process
&path[0], // passing in the path of the executable
NULL, // don't want the process handle to be inherited
NULL, // don't want the thread handle to be inherited
FALSE, // setting inheritance handle to false
0x0, // normal creation flags
NULL, // using parent process environment config
NULL, // the new process will have the same current drive and directory as the calling process
&si, // passing in the startup information
&pi // passing in the process information
);
if (cpBool) {
_tprintf(_T("Process Created: %d"), pi.dwProcessId);
}
else {
_tprintf(_T("Unable to create process\n"));
return 1;
}
return 0;
}
Getting Process Details
In this you will see, I will print the process name, pid, executable path. You can use GetProcessImageFileNameW function from Psapi.h
DWORD GetProcessImageFileNameW(
HANDLE hProcess,
LPWSTR lpImageFileName,
DWORD nSize
);
Function parameter description
-
hProcess → A handle to the process with
PROCESS_QUERY_INFORMATION
orPROCESS_QUERY_LIMITED_INFORMATION
access right - lpImageFileName → A pointer to a buffer that receives the full path to the executable file
- nSize → The size of the lpImageFileName buffer, in characters.
If the function succeeds, it will return length of the string copied to the buffer.
The snippet for this module would be
int GetProcess(DWORD pId)
{
// opening process
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocess
HANDLE hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pId);
if (hProc == NULL || hProc == INVALID_HANDLE_VALUE)
{
_tprintf(_T("Unable to open process"));
return 1;
}
// initializing the variable
LPWSTR procName = (LPWSTR)malloc(MAX_PATH);
// getting process name by id
GetProcessNameById(pId);
// get process executable path
// https://docs.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-getprocessimagefilenamew
GetProcessImageFileNameW(hProc, &procName[0], MAX_PATH);
_tprintf(_T("Executable Path: %s\n"), procName);
// deallocate the variables
free(procName);
CloseHandle(hProc);
return 0;
}
So here comes the complete code of all above
#include <Windows.h>
#include <tchar.h>
#include <Psapi.h>
#include <iostream>
#include <processthreadsapi.h>
#include <handleapi.h>
/*
Function prototypes
*/
int ListProcesses();
int KillProcess(DWORD pId);
int _CreateProcess();
int GetProcess(DWORD pId);
void GetProcessNameById(DWORD pId);
int wmain(int argc, WCHAR** argv) {
int option;
_tprintf(_T("1. list processes\n"));
_tprintf(_T("2. kill process by pid\n"));
_tprintf(_T("3. create process\n"));
_tprintf(_T("4. get process details\n"));
_tprintf(_T("> "));
DWORD pid;
std::wcin >> option; // use wcin when you want to get wide charaters
switch (option) {
case 1:
return ListProcesses();
case 2:
_tprintf(_T("Enter Process PID: "));
std::wcin >> pid;
return KillProcess(pid);
break;
case 3:
return _CreateProcess();
break;
case 4:
_tprintf(_T("Enter Process PID: "));
std::wcin >> pid;
return GetProcess(pid);
break;
default:
_tprintf(_T("Please select options 1 2 3 4 only\n"));
return 1;
}
}
int ListProcesses() {
DWORD processes[1024], cbNeeded, cbProcesses;
// enumerating all processes
// https://docs.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-enumprocesses
BOOL procBool = EnumProcesses(processes, sizeof(processes), &cbNeeded);
if (!procBool) {
_tprintf(_T("Unable to fetch processes\n"));
return 1;
}
cbProcesses = cbNeeded / sizeof(DWORD); // getting actual number of processes that function has returned
_tprintf(_T("Total Processes: %d\n\n"), cbProcesses);
for (int i = 0; i < cbProcesses; i++) {
GetProcessNameById(processes[i]); // printing process name
}
return 0;
}
void GetProcessNameById(DWORD pId)
{
// TCHAR is same as WCHAR (wchar_t)
TCHAR procName[MAX_PATH] = _T("<Unknown>");
// opening the process
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocess
HANDLE process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pId);
// checking if process is opened
// the processes running in same privilege will only be opened
if (process != NULL) {
HMODULE hMod;
DWORD cbNeeded;
// enumerating the process modules
// https://docs.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-enumprocessmodules
if (EnumProcessModules(process, &hMod, sizeof(hMod),
&cbNeeded))
{
// getting module base name, which is the name of the process
// https://docs.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-getmappedfilenamew
GetModuleBaseName(process, hMod, procName,
sizeof(procName) / sizeof(TCHAR));
}
}
// closing process handle
// https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle
CloseHandle(process);
_tprintf(_T("[%d] %s\n"), pId, procName);
}
int KillProcess(DWORD pId) {
// opening process
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocess
HANDLE hProc = OpenProcess(PROCESS_TERMINATE, FALSE, pId);
if (hProc == NULL) {
_tprintf(_T("Unable to open process %d\n"), pId);
return 1;
}
// terminating the process
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-terminateprocess
BOOL tpBool = TerminateProcess(hProc, 2); // exit the program with non zero return code
if (!tpBool) {
_tprintf(_T("Unable to kill the process %d\n"), pId);
// closing process handle
// https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle
CloseHandle(hProc);
return 1;
}
else {
_tprintf(_T("Killed Process %d\n"), pId);
// closing process handle
// https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle
CloseHandle(hProc);
return 0;
}
}
int _CreateProcess()
{
std::wstring path(L"C:\\Windows\\notepad.exe");
STARTUPINFO si;
si.cb = sizeof(si);
PROCESS_INFORMATION pi;
// initializing the variables
// https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/aa366920(v=vs.85)
ZeroMemory(&si, sizeof(si));
ZeroMemory(&pi, sizeof(pi));
// creating process
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessw
BOOL cpBool = CreateProcessW(
NULL, // creating an independent process
&path[0], // passing in the path of the executable
NULL, // don't want the process handle to be inherited
NULL, // don't want the thread handle to be inherited
FALSE, // setting inheritance handle to false
0x0, // normal creation flags
NULL, // using parent process environment config
NULL, // the new process will have the same current drive and directory as the calling process
&si, // passing in the startup information
&pi // passing in the process information
);
if (cpBool) {
_tprintf(_T("Process Created: %d"), pi.dwProcessId);
}
else {
_tprintf(_T("Unable to create process\n"));
return 1;
}
return 0;
}
int GetProcess(DWORD pId)
{
// opening process
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocess
HANDLE hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pId);
if (hProc == NULL || hProc == INVALID_HANDLE_VALUE)
{
_tprintf(_T("Unable to open process"));
return 1;
}
// initializing the variable
LPWSTR procName = (LPWSTR)malloc(MAX_PATH);
// getting process name by id
GetProcessNameById(pId);
// get process executable path
// https://docs.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-getprocessimagefilenamew
GetProcessImageFileNameW(hProc, &procName[0], MAX_PATH);
_tprintf(_T("Executable Path: %s\n"), procName);
// deallocate the variables
free(procName);
CloseHandle(hProc);
return 0;
}
Thanks for reading this post. Follow the links to reach me
- Email: tbhaxor@gmail.com
- Twitter: @tbhaxor
- Facebook: @tbhaxor
- GitHub: @tbhaxor
- LinkedIn: @gurkirat--singh
- Instagram: @_tbhaxor_
Top comments (0)