RegLoadKey is giving error code 5 (Access Denied) - c++

Hi I'm trying to load a key from HKLM\\SYSTEM\\CurrentControlSet\\Services\\Fax but i'm getting error 5 (Access Denied). I'm not able to figure it out what is wrong with my code.
Here is my code
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
BOOL SetPrivilege(
HANDLE hToken, // access token handle
LPCTSTR lpszPrivilege, // name of privilege to enable/disable
BOOL bEnablePrivilege // to enable or disable privilege
)
{
TOKEN_PRIVILEGES tp;
LUID luid;
if ( !LookupPrivilegeValue(
NULL, // lookup privilege on local system
lpszPrivilege, // privilege to lookup
&luid ) ) // receives LUID of privilege
{
printf("LookupPrivilegeValue error: %u\n", GetLastError() );
return FALSE;
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
if (bEnablePrivilege)
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
else
tp.Privileges[0].Attributes = 0;
// Enable the privilege or disable all privileges.
if ( !AdjustTokenPrivileges(
hToken,
FALSE,
&tp,
sizeof(TOKEN_PRIVILEGES),
(PTOKEN_PRIVILEGES) NULL,
(PDWORD) NULL) )
{
printf("AdjustTokenPrivileges error: %u\n", GetLastError() );
return FALSE;
}
if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
{
printf("The token does not have the specified privilege. \n");
return FALSE;
}
return TRUE;
}
void _tmain(int argc, TCHAR *argv[])
{
HKEY hKey;
LONG lErrorCode;
HANDLE ProcessToken;
LPCWSTR subkey = L"SYSTEM\\CurrentControlSet\\Services\\Fax";
if (OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &ProcessToken))
{
SetPrivilege(ProcessToken, SE_BACKUP_NAME, TRUE);
SetPrivilege(ProcessToken, SE_RESTORE_NAME, TRUE);
SetPrivilege(ProcessToken, SE_RESTORE_NAME, TRUE);
}
lErrorCode = RegOpenKeyEx(HKEY_LOCAL_MACHINE,subkey ,
0, KEY_ALL_ACCESS, &hKey);
if (lErrorCode != ERROR_SUCCESS)
{
_tprintf(TEXT("Error in RegOpenKeyEx (%d).\n"), lErrorCode);
return;
}
else
{
_tprintf(TEXT("Key is successfully Opened\n"));
}
lErrorCode = RegSaveKey(hKey,L"c:\\load.reg",0);
if (lErrorCode != ERROR_SUCCESS)
{
_tprintf(TEXT("Error in RegSaveKey (%d).\n"), lErrorCode);
return;
}
else
{
_tprintf(TEXT("Key is successfully Saved \n"));
}
lErrorCode = RegLoadKey(HKEY_LOCAL_MACHINE,subkey,L"c:\\load.reg");
if (lErrorCode != ERROR_SUCCESS)
{
_tprintf(TEXT("Error in RegLoadKey (%d).\n"), lErrorCode);
return;
}
else
{
_tprintf(TEXT("Key is successfully loaded \n"));
}
lErrorCode = RegCloseKey(hKey);
if (lErrorCode != ERROR_SUCCESS)
{
_tprintf(TEXT("Error in closing the key (%d).\n"), lErrorCode);
return;
}
else
{
_tprintf(TEXT("Key is successfully closed \n"));
}
}
This is the output
Key is successfully Opened
Key is successfully Saved
Error in RegLoadKey (5).

RegLoadKey can only be used to load a new hive into the registry. You can't use it to overwrite a subkey of an existing hive.
You probably want to use RegRestoreKey instead.
Additional:
To the best of my knowledge, hives can only be loaded at a registry root, i.e., they must be HKEY_LOCAL_MACHINE\foo or HKEY_USERS\foo, never HKEY_LOCAL_MACHINE\foo\bar. Also, I don't think you can load a hive with a name that already exists, e.g., you can't load a hive into HKEY_LOCAL_MACHINE\SOFTWARE. Even if you could do these things, you'd be changing your view of the content, not merging it, and when the system was rebooted the original content would reappear. As previously mentioned, if you want to insert data into an existing hive, use RegRestoreKey rather than RegLoadKey.
You ask about the use cases for RegLoadKey: there aren't many. Mostly, it's used by the operating system; for example, that's how your personal hive is loaded into HKEY_USERS\username when you log in. There are some oddball cases, such as resetting a password offline or otherwise modifying the registry of another Windows instance. The process I use for the unattended installation of Windows on the computers in my teaching lab depends on modifying the registry of the Windows installation image to disable the keyboard and mouse.

Related

Token impersonation on Windows requires administrator permission Why?

#include <windows.h>
#include <iostream>
#include <Lmcons.h>
#include <conio.h>
BOOL SetPrivilege(
HANDLE hToken, // access
token handle
LPCTSTR lpszPrivilege, // name of
privilege to enable/disable
BOOL bEnablePrivilege // to
enable or disable privilege
)
{
TOKEN_PRIVILEGES tp;
LUID luid;
if (!LookupPrivilegeValue(
NULL, // lookup
privilege on local system
lpszPrivilege, // privilege
to lookup
&luid)) // receives
LUID of privilege
{
printf("[-]
LookupPrivilegeValue error: %u\n",
GetLastError());
return FALSE;
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
if (bEnablePrivilege)
tp.Privileges[0].Attributes =
SE_PRIVILEGE_ENABLED;
else
tp.Privileges[0].Attributes =
0;
// Enable the privilege or disable
all privileges.
if (!AdjustTokenPrivileges(
hToken,
FALSE,
&tp,
sizeof(TOKEN_PRIVILEGES),
(PTOKEN_PRIVILEGES)NULL,
(PDWORD)NULL))
{
printf("[-]
AdjustTokenPrivileges error:
%u\n",
GetLastError());
return FALSE;
}
if (GetLastError() ==
ERROR_NOT_ALL_ASSIGNED)
{
printf("[-] The token does not
have the specified privilege.
\n");
return FALSE;
}
return TRUE;
}
int main(int argc, char** argv) {
// Print whoami to compare to
thread later
printf("[+] Current user is:
%s\n"); //
(get_username()).c_str());
system("whoami");
// Grab PID from command line
argument
char *pid_c = argv[1];
DWORD PID_TO_IMPERSONATE = 900;
// Initialize variables and
structures
HANDLE tokenHandle = NULL;
HANDLE duplicateTokenHandle =
NULL;
STARTUPINFOW startupInfo;
PROCESS_INFORMATION
processInformation;
ZeroMemory(&startupInfo,
sizeof(STARTUPINFO));
ZeroMemory(&processInformation,
sizeof(PROCESS_INFORMATION));
startupInfo.cb =
sizeof(STARTUPINFO);
// Add SE debug privilege
HANDLE currentTokenHandle =
NULL;
BOOL getCurrentToken =
OpenProcessToken
(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES,
&currentTokenHandle);
if
(SetPrivilege
(currentTokenHandle,
"SeDebugPrivilege", TRUE))
{
printf("[+] SeDebugPrivilege
enabled!\n");
}
// Call OpenProcess(), print
return code and error code
HANDLE processHandle =
OpenProcess
(PROCESS_QUERY_INFORMATION,
true, PID_TO_IMPERSONATE);
if (GetLastError() == NULL)
printf("[+] OpenProcess()
success!\n");
else
{
printf("[-] OpenProcess()
Return Code: %i\n",
processHandle);
printf("[-] OpenProcess()
Error: %i\n",
GetLastError());
}
// Call OpenProcessToken(),
print return code and error
code
BOOL getToken =
OpenProcessToken
(processHandle,
TOKEN_DUPLICATE |
TOKEN_ASSIGN_PRIMARY |
TOKEN_QUERY, &tokenHandle);
if (GetLastError() == NULL)
printf("[+]
OpenProcessToken()
success!\n");
else
{
printf("[-]
OpenProcessToken() Return
Code: %i\n", getToken);
printf("[-] OpenProcessToken()
Error: %i\n",
GetLastError());
}
// Impersonate user in a
thread
BOOL impersonateUser =
ImpersonateLoggedOnUser
(tokenHandle);
if (GetLastError() == NULL)
{
printf("[+]
ImpersonatedLoggedOnUser()
success!\n");
// printf("[+] Current
user is: %s\n",
(get_username()).c_str());
system("whoami");
printf("[+] Reverting thread
to original user context\n");
RevertToSelf();
}
else
{
printf("[-]
ImpersonatedLoggedOnUser()
Return Code: %i\n", getToken);
printf("[-]
ImpersonatedLoggedOnUser()
Error: %i\n", GetLastError());
}
// Call DuplicateTokenEx(),
print return code and error
code
BOOL duplicateToken =
DuplicateTokenEx(tokenHandle,
TOKEN_ADJUST_DEFAULT |
TOKEN_ADJUST_SESSIONID |
TOKEN_QUERY | TOKEN_DUPLICATE
| TOKEN_ASSIGN_PRIMARY, NULL,
SecurityImpersonation,
TokenPrimary,
&duplicateTokenHandle);
if (GetLastError() == NULL)
printf("[+] DuplicateTokenEx()
success!\n");
else
{
printf("[-] DuplicateTokenEx()
Return Code: %i\n",
duplicateToken);
printf("[-] DupicateTokenEx()
Error: %i\n", GetLastError());
}
// Call
CreateProcessWithTokenW(),
print return code and error
code
BOOL createProcess =
CreateProcessWithTokenW
(duplicateTokenHandle,
LOGON_WITH_PROFILE,
L"C:\\Windows\
\System32\\cmd.exe", NULL,
0, NULL, NULL, &startupInfo,
&processInformation);
if (GetLastError() == NULL)
printf("[+] Process
spawned!\n");
else
{
printf("[-]
CreateProcessWithTokenW
Return Code: %i\n",
createProcess);
printf("[-]
CreateProcessWithTokenW Error:
%i\n", GetLastError());
}
getch();
return 0;
}
This is a code that impersonates Winlogon Access token on Windows to give me System rights but it requires me to run the program as administrator before I'm able to impersonate Winlogon...
I believe the reason is based on lack of privileges my program access token has.
If there's anyone that can give me an idea to do this without running as administrator first I'll appreciate.
What it actually requires is that the account holds the SE_IMPERSONATE_NAME privilege and the particular process having it enabled. Normally only highly trusted accounts (an elevated Administrator token or Local System used by default for services) have this privilege but you can assign it to others through the "Local Users and Groups" (or "Active Directory Users and Computers" if using AD) MMC snap-in.

OpenProcessBlocked even i use SetPrivilege(hToken, SE_DEBUG_NAME, true);

I have a problem, I want to read some values with ReadProcessMemory from a process, this process blocks OpenProcess, now I heard that I just need to Privilege the file who want to do OpenProcess with SE_DEBUG_NAME.
I googled and found this function :
BOOL SetPrivilege(
HANDLE hToken, // access token handle
LPCTSTR lpszPrivilege, // name of privilege to enable/disable
BOOL bEnablePrivilege){
TOKEN_PRIVILEGES tp;
LUID luid;
if (!LookupPrivilegeValue(
NULL, // lookup privilege on local system
lpszPrivilege, // privilege to lookup
&luid)) // receives LUID of privilege
{
printf("LookupPrivilegeValue error: %u\n", GetLastError());
return FALSE;
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
if (bEnablePrivilege)
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
else
tp.Privileges[0].Attributes = 0;
// Enable the privilege or disable all privileges.
if (!AdjustTokenPrivileges(
hToken,
FALSE,
&tp,
sizeof(TOKEN_PRIVILEGES),
(PTOKEN_PRIVILEGES)NULL,
(PDWORD)NULL))
{
printf("AdjustTokenPrivileges error: %u\n", GetLastError());
return FALSE;
}
if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
{
printf("The token does not have the specified privilege. \n");
return FALSE;
}
return TRUE;}
Now i tried the following :
bool bStart(std::string szProcessName)
{
if (szProcessName.empty())
return false;
HANDLE hToken;
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken);
SetPrivilege(hToken, SE_DEBUG_NAME, true);
if (!OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
return FALSE;
if (!SetPrivilege(hToken, SE_DEBUG_NAME, TRUE))
{
std::cout << "SetPrivilege";
// close token handle
CloseHandle(hToken);
// indicate failure
return false;
}
std::cout << "hi";
HANDLE hSnapshot = (CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0));
if (hSnapshot == INVALID_HANDLE_VALUE)
return false;
bool bFoundProcess = false;
PROCESSENTRY32 PE32 = { sizeof(PROCESSENTRY32) };
if (Process32First(hSnapshot, &PE32))
{
do
{
if (!szProcessName.compare(PE32.szExeFile))
{
m_dwProcessId = (XOR(PE32.th32ProcessID));
bFoundProcess = true;
break;
}
} while (Process32Next(hSnapshot, &PE32));
}
CloseHandle(m_hProcess);
if (!bFoundProcess)
return false;
m_hProcess = (XOR(OpenProcess(PROCESS_ALL_ACCESS, FALSE, m_dwProcessId)));
if (m_hProcess == INVALID_HANDLE_VALUE)
return false;
return true;
}
I don't get any error or anything, but for any reason, the OpenProcess doesn't work. Can someone please help me?
Thanks in advance!
this process blocks OpenProcess
This means the game's anticheat is blocking process handle creation via a kernel mode anticheat.
There is nothing you can do to bypass this from usermode, you must also make a kernel driver and disable their protection.
The most simple way for them to prevent handle creation is with ObRegisterCallbacks so you will need to reverse engineer their implementation of that.
Keep in mind this technique is from 5+ years ago, they have much more complicated protection now.

Not able to add Audit policy (ACE) for object access (Folder) in windows using c++

I was writing a c++ program to add ACE for object access Audit to SASL. Though all the functions return success, When I go and check the properties of the folder manually, I could not see any policy has been set.
Below is my code. I have modified the sample code given in MSDN site at the below link to add to SASL instead of DACL .
https://msdn.microsoft.com/en-us/library/windows/desktop/aa379283(v=vs.85).aspx
BOOL SetPrivilege(
HANDLE hToken, // access token handle
LPCTSTR lpszPrivilege, // name of privilege to enable/disable
BOOL bEnablePrivilege // to enable or disable privilege
)
{
TOKEN_PRIVILEGES tp;
LUID luid;
if (!LookupPrivilegeValue(
NULL, // lookup privilege on local system
lpszPrivilege, // privilege to lookup
&luid)) // receives LUID of privilege
{
printf("LookupPrivilegeValue error: %u\n", GetLastError());
return FALSE;
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
if (bEnablePrivilege)
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
else
tp.Privileges[0].Attributes = 0;
// Enable the privilege or disable all privileges.
if (!AdjustTokenPrivileges(
hToken,
FALSE,
&tp,
sizeof(TOKEN_PRIVILEGES),
(PTOKEN_PRIVILEGES)NULL,
(PDWORD)NULL))
{
printf("AdjustTokenPrivileges error: %u\n", GetLastError());
return FALSE;
}
if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
{
printf("The token does not have the specified privilege. \n");
return FALSE;
}
return TRUE;
}
DWORD AddAceToObjectsSecurityDescriptor(
LPTSTR pszObjName, // name of object
SE_OBJECT_TYPE ObjectType, // type of object
LPTSTR pszTrustee // trustee for new ACE
)
{
DWORD dwRes = 0;
PACL pOldSACL = NULL, pNewSACL = NULL;
PSECURITY_DESCRIPTOR pSD = NULL;
EXPLICIT_ACCESS ea;
HANDLE hToken;
if (NULL == pszObjName)
return ERROR_INVALID_PARAMETER;
// Open a handle to the access token for the calling process.
if (!OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES,
&hToken))
{
printf("OpenProcessToken failed: %u\n", GetLastError());
goto Cleanup;
}
// Enable the SE_SECURITY_NAME privilege.
if (!SetPrivilege(hToken, SE_SECURITY_NAME, TRUE))
{
printf("You must be logged on as Administrator.\n");
goto Cleanup;
}
// Get a pointer to the existing SACL.
dwRes = GetNamedSecurityInfo(pszObjName, ObjectType,
SACL_SECURITY_INFORMATION,
NULL, NULL, NULL, &pOldSACL, &pSD);
if (ERROR_SUCCESS != dwRes) {
printf("GetNamedSecurityInfo Error %u\n", dwRes);
goto Cleanup;
}
// Initialize an EXPLICIT_ACCESS structure for the new ACE.
ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
//ea.grfAccessPermissions = dwAccessRights;
ea.grfAccessPermissions = GENERIC_ALL;
//ea.grfAccessMode = AccessMode;
ea.grfAccessMode = SET_AUDIT_SUCCESS;
//ea.grfInheritance = dwInheritance;
ea.grfInheritance = INHERIT_ONLY;
//ea.Trustee.TrusteeForm = TrusteeForm;
ea.Trustee.TrusteeForm = TRUSTEE_IS_NAME;
ea.Trustee.ptstrName = pszTrustee;
ea.Trustee.TrusteeType = TRUSTEE_IS_USER;
// Create a new ACL that merges the new ACE
// into the existing SACL.
dwRes = SetEntriesInAcl(1, &ea, pOldSACL, &pNewSACL);
if (ERROR_SUCCESS != dwRes) {
printf("SetEntriesInAcl Error %u\n", dwRes);
goto Cleanup;
}
// Attach the new ACL as the object's SACL.
dwRes = SetNamedSecurityInfo(pszObjName, ObjectType,
SACL_SECURITY_INFORMATION,
NULL, NULL, NULL, pNewSACL);
if (ERROR_SUCCESS != dwRes) {
printf("SetNamedSecurityInfo Error %u\n", dwRes);
goto Cleanup;
}
// Disable the SE_SECURITY_NAME privilege.
if (!SetPrivilege(hToken, SE_SECURITY_NAME, FALSE))
{
printf("You must be logged on as Administrator.\n");
goto Cleanup;
}
Cleanup:
if (pSD != NULL)
LocalFree((HLOCAL)pSD);
if (pNewSACL != NULL)
LocalFree((HLOCAL)pNewSACL);
return dwRes;
}
int _tmain(int argc, _TCHAR* argv[])
{
LPTSTR objstrname = L"C:\\path\\to\\folder\\Test_Folder";
LPTSTR trusteeName = L"UserName"; // I have mentioned username here
AddAceToObjectsSecurityDescriptor(objstrname, SE_FILE_OBJECT, trusteeName);
return 0;
}
Though all the functions return success, I am not able to see any new audit policy is getting set. Might I am setting the parameters wrong, I that case I expect the functions to fail. Please help to resolve the issue.
I believe the problem is that you are setting the wrong inheritance flags.
INHERIT_ONLY means that the ACE should not apply to the object, but only be inherited by child objects.
However, you have not set either CONTAINER_INHERIT_ACE or OBJECT_INHERIT_ACE. So the ACE does not apply to child objects.
Since the ACE applies to neither the parent nor to children, it has no effect, so Windows discards it.

Get a process Owner (Citrix/Provisioning)

I'm using OpenProcessToken, GetTokenInformation and then LookupAccountSid to determine the owner of a certain process.
On a local machine (Win 7 and Win 8.1), on a RD Services session (Server 2012) it works fine. I do get the correct user name. The user name displayed in the task manager next to the process.
When I execute the same code in a Provisioning (ex Citrix) environment I only get the username "Administrator" although there is a different name displayed in the task manager.
Does anybody have an idea how to conquer this within a Provisioning environment?
Thanks a lot for any help
Martin
Here is the C++ Code I'm using:
BOOL DDEWinWord::processStartedFromLocalUser(DWORD procId)
{
#define MAX_NAME 256
DWORD dwSize = 0, dwResult = 0;
HANDLE hToken;
SID_NAME_USE SidType;
char lpName[MAX_NAME];
char lpDomain[MAX_NAME];
PTOKEN_OWNER tp;
// Open a handle to the access token for the calling process.
HANDLE processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, procId);
if (!OpenProcessToken(processHandle, TOKEN_QUERY, &hToken)) {
AfxMessageBox("processStartedFromLocalUser - OpenProcessToken fehlschlag.");
return FALSE;
}
// Call GetTokenInformation to get the buffer size.
if(!GetTokenInformation(hToken, TokenOwner, NULL, dwSize, &dwSize))
{
dwResult = GetLastError();
if (dwResult != ERROR_INSUFFICIENT_BUFFER)
{
AfxMessageBox("processStartedFromLocalUser - GetTokenInformation fehlschlag.");
return FALSE;
}
}
// Allocate the buffer.
tp = (PTOKEN_OWNER)GlobalAlloc(GPTR, dwSize);
// Call GetTokenInformation again to get the group information.
if (!GetTokenInformation(hToken, TokenOwner, tp, dwSize, &dwSize))
{
AfxMessageBox("processStartedFromLocalUser - GetTokenInformation mit tp fehlschlag.");
return FALSE;
}
if (!LookupAccountSid(NULL, tp->Owner, lpName, &dwSize, lpDomain, &dwSize, &SidType))
{
AfxMessageBox("processStartedFromLocalUser - LookupAccountSid fehlschlag.");
return FALSE;
}
else
{
AfxMessageBox(lpName);
}
return (m_stUserId.CompareNoCase(lpName) == 0);
}
You should be using TokenUser rather than TokenOwner.

How do I see if another process is running on windows?

I have a VC++ console app and I need to check to see if another process is running. I don't have the window title, all I have is the executable name. How do I get the process handle / PID for it? Can I enumerate the processes running with this .exe ?
Use the CreateToolhelp32Snapshot Function
hSnapShot = FCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
Followed by Process32First and Process32Next.
You will get a PROCESSENTRY32 struct as follows with an szExeFile member.
PROCESSENTRY32W processInfo;
processInfo.szExeFile
Make sure to first acquire the privilege SeDebugPrivilege before enumerating, that way you will get all processes across all sessions and users.
To acquire the privilege so you get all sessions:
acquirePrivilegeByName(SE_DEBUG_NAME);// SeDebugPrivilege
Where acquirePrivilegeByName is defined as:
BOOL acquirePrivilegeByName(
const TCHAR *szPrivilegeName)
{
HANDLE htoken;
TOKEN_PRIVILEGES tkp;
DWORD dwerr;
//---------------- adjust process token privileges to grant privilege
if (szPrivilegeName == NULL)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (!LookupPrivilegeValue(NULL, szPrivilegeName, &(tkp.Privileges[0].Luid)))
return FALSE;
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &htoken))
return FALSE;
if (!AdjustTokenPrivileges(htoken, FALSE, &tkp, 0, NULL, NULL) ||
GetLastError() != ERROR_SUCCESS) // may equal ERROR_NOT_ALL_ASSIGNED
{
dwerr = GetLastError();
CloseHandle(htoken);
SetLastError(dwerr);
return FALSE;
}
CloseHandle(htoken);
SetLastError(ERROR_SUCCESS);
return TRUE;
} //acquirePrivilegeByName()
If you need the full process image name you can use QueryFullProcessImageName, but the szExeFile member may be enough for your needs.
You can use EnumProcesses to enumerate the processes on a system.
You'll need to use OpenProcess to get a process handle, then QueryFullProcessImageName to get the processes executable.