I need to know if the current process is running as system. In C# I use WindowsIdentity.GetCurrent().IsSystem to do that, what is the equivalent in C++?
I'm trying to avoid comparing usernames, because different OS has different usernames for SYSTEM account.
I have created an example based on Eryk's idea, and it works:
BOOL IsSystem()
{
HANDLE hToken = NULL;
BOOL result = false;
TOKEN_USER *tokenUser = NULL;
DWORD dwLength = 0;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken) == 0)
{
DbgPrint("OpenProcessToken(): %d", GetLastError());
goto cleanup;
}
if (GetTokenInformation(hToken, TokenUser, (LPVOID) tokenUser, 0, &dwLength) == 0)
{
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
{
DbgPrint("GetTokenInformation(): %d", GetLastError());
goto cleanup;
}
tokenUser = (TOKEN_USER *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLength);
if (tokenUser == NULL)
{
goto cleanup;
}
if (GetTokenInformation(hToken, TokenUser, (LPVOID) tokenUser, dwLength, &dwLength) == 0)
{
DbgPrint("GetTokenInformation(): %d", GetLastError());
goto cleanup;
}
result = IsWellKnownSid(tokenUser->User.Sid, WinLocalSystemSid);
}
cleanup:
if (tokenUser != NULL)
{
HeapFree(GetProcessHeap(), NULL, tokenUser);
}
return result;
}
Related
I have some code which i have wrote. I need to modify DACL ( security descriptor) in Windows 10 to prevent kill process without Debug Privilege of user. How can i do this one? I learned at the internet algorithm, looked for some functions for that, but process still closes without any problems. I tried debug it a lot of time, code works without errors, but unsuccessfully.
How should i solve this problem? For my example below,i Add ACE for Denied PROCESS_TERMINATE. Is it right way?
Also advice me how can i check that. I know that i will get MessageBox of Permission Denied, yep?
My code (p.s. updated):
#include <iostream>
#include <Windows.h>
PSECURITY_DESCRIPTOR GetProcessSecurityDescriptor(HANDLE processHandle, DWORD &buffSizeNeeded);
void SecurityDescriptorModifier(HANDLE hProcess);
int main()
{
DWORD pID;
std::cin >> pID;
HANDLE processHandle = OpenProcess(PROCESS_ALL_ACCESS, false, pID);
SecurityDescriptorModifier(processHandle);
HANDLE pHandle = OpenProcess(PROCESS_TERMINATE, false, pID);
return 0;
}
void SecurityDescriptorModifier(HANDLE hProcess)
{
DWORD SIDLength = 0;
PSID SID;
PACL pACL;
PACL pNewAcl;
BOOL bDaclExist;
BOOL bDaclPresent;
PSECURITY_DESCRIPTOR pSecurityDescriptor;
PSECURITY_DESCRIPTOR pSecurityDescriptorNew;
ACL_SIZE_INFORMATION aclSizeInfo;
DWORD dwNewAclSize;
ACCESS_ALLOWED_ACE* pACE;
PVOID pTempAce;
DWORD buffSizeNeeded = -1;
// "everyone" group
//CreateWellKnownSid(WinWorldSid, NULL, NULL, &SIDLength);
// Allocate enough memory for the largest possible SID.
SIDLength = SECURITY_MAX_SID_SIZE;
if (!(SID = LocalAlloc(LMEM_FIXED, SIDLength)))
{
fprintf(stderr, "Could not allocate memory.\n");
exit(1);
}
//SID = new byte[SECURITY_MAX_SID_SIZE];
if (!CreateWellKnownSid(WinWorldSid, NULL, SID, &SIDLength))
{
fprintf(stderr,
"CreateWellKnownSid Error %u",
GetLastError());
LocalFree(SID);
}
pSecurityDescriptor = GetProcessSecurityDescriptor(hProcess, buffSizeNeeded);
BOOL executionResult = GetSecurityDescriptorDacl(pSecurityDescriptor, &bDaclPresent, &pACL, &bDaclExist);
if(!executionResult)
{
fprintf(stderr, "GetSecurityDescriptorDacl() failed, error %d\n", GetLastError());
exit(1);
}
pSecurityDescriptorNew = (PSECURITY_DESCRIPTOR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buffSizeNeeded);
if (pSecurityDescriptorNew == NULL)
exit(1);
else
printf("Heap allocated for psdNew!\n");
// Create a new security descriptor
if (!InitializeSecurityDescriptor(pSecurityDescriptorNew, SECURITY_DESCRIPTOR_REVISION))
{
fprintf(stderr, "InitializeSecurityDescriptor() failed, error %d\n", GetLastError());
exit(1);
}
// Obtain the DACL from the security descriptor
if (!GetSecurityDescriptorDacl(pSecurityDescriptor, &bDaclPresent, &pACL, &bDaclExist))
{
fprintf(stderr, "GetSecurityDescriptorDacl() failed, error %d\n", GetLastError());
exit(1);
}
// Initialize
ZeroMemory(&aclSizeInfo, sizeof(ACL_SIZE_INFORMATION));
aclSizeInfo.AclBytesInUse = sizeof(ACL);
// Call only if NULL DACL
if (pACL != NULL)
{
// Determine the size of the ACL information
if (!GetAclInformation(pACL, (LPVOID)& aclSizeInfo, sizeof(ACL_SIZE_INFORMATION), AclSizeInformation))
{
fprintf(stderr, "GetAclInformation() failed, error %d\n", GetLastError());
exit(1);
}
}
// Compute the size of the new ACL
dwNewAclSize = aclSizeInfo.AclBytesInUse + sizeof(ACCESS_DENIED_ACE) + GetLengthSid(SID) - sizeof(DWORD);
// Allocate buffer for the new ACL
pNewAcl = (PACL)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwNewAclSize);
if (pNewAcl == NULL)
exit(1);
// Initialize the new ACL
if (!InitializeAcl(pNewAcl, dwNewAclSize, ACL_REVISION))
{
fprintf(stderr, "InitializeAcl() failed, error %d\n", GetLastError());
exit(1);
}
static const DWORD dwPoison = PROCESS_TERMINATE;
BOOL bResult = AddAccessDeniedAce(pNewAcl, ACL_REVISION, dwPoison, SID);
if (FALSE == bResult)
{
printf("AddAccessDenied Error %d\n", GetLastError());
}
// If DACL is present, copy it to a new DACL
if (!bDaclPresent)
{
// Copy the ACEs to the new ACL.
if (aclSizeInfo.AceCount)
{
for (int i = 0; i < aclSizeInfo.AceCount; i++)
{
// Get an ACE.
if (!GetAce(pACL, i, &pTempAce))
{
fprintf(stderr, "GetAce() failed, error %d\n", GetLastError());
exit(1);
}
else
fprintf(stderr, "GetAce working\n");
// Add the ACE to the new ACL.
if (!AddAce(pNewAcl, ACL_REVISION, MAXDWORD, pTempAce, ((PACE_HEADER)pTempAce)->AceSize))
{
fprintf(stderr, "AddAce() failed, error %d\n", GetLastError());
exit(1);
}
else
fprintf(stderr, "AddAce() is working!\n");
}
}
}
if (!SetSecurityDescriptorDacl(pSecurityDescriptorNew, TRUE, pNewAcl, FALSE))
{
printf("SetSecurityDescriptorDacl() failed, error %d\n", GetLastError());
exit(1);
}
else
printf("SetSecurityDescriptorDacl() is working!\n");
// Set the new security descriptor for the window station
if (!SetKernelObjectSecurity(hProcess, DACL_SECURITY_INFORMATION, pSecurityDescriptorNew))
{
printf("SetUserObjectSecurity() failed, error %d\n", GetLastError());
exit(1);
}
else
printf("SetUserObjectSecurity() is working!\n");
}
PSECURITY_DESCRIPTOR GetProcessSecurityDescriptor(HANDLE processHandle, DWORD &buffSizeNeeded)
{
PSECURITY_DESCRIPTOR pSD = new byte[0];
SECURITY_INFORMATION si = DACL_SECURITY_INFORMATION;
// To understand actual needed size for pSD
// GetKernelObject, what diff?
GetKernelObjectSecurity(processHandle, si, pSD, 0, &buffSizeNeeded);
if (buffSizeNeeded <= 0)
{
fprintf(stderr, ":GetKernelObjectSecurity ERROR: %u\n", GetLastError());
exit(1);
}
pSD = (PSECURITY_DESCRIPTOR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buffSizeNeeded);
if (pSD == NULL)
exit(1);
else
printf("Heap allocated for psdNew!\n");
//Allocate Memory & get DACL
if (!GetKernelObjectSecurity(processHandle, si, pSD, buffSizeNeeded, &buffSizeNeeded))
{
fprintf(stderr, ":GetKernelObjectSecurity(With Alloc) ERROR: %u\n", GetLastError());
exit(1);
}
return pSD;
}
I am compiling to 64-bit and calling the functions on a 32-bit(Wow64) processes thread. No errors are being returned for any functions.
But for some reason the CPU register members in the WOW64_CONTEXTstruct passed to Wow64GetThreadContext are always the same values each and every time the function is called. Even though I initialize every member in the struct to 0, WOW64_CONTEXT wow64ctxt = {0}.
As far as I know I am doing everything correctly but I always get the same values for each member in WOW64_CONTEXT.
Here's my code:
#define _WIN32_WINNT _WIN32_IE_WIN8
#include <windows.h>
#include <tlhelp32.h>
#include <stdio.h>
int main()
{
DWORD dwPid = 0;
BOOL found = FALSE;
BOOL wow64 = FALSE;
HANDLE hProcess = NULL;
HANDLE hThread = NULL;
HANDLE hSnapshot = INVALID_HANDLE_VALUE;
THREADENTRY32 th32;
WOW64_CONTEXT wow64ctxt = {0};
printf("PID: ");
scanf("%lu", &dwPid);
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid);
if(hProcess == NULL)
{
printf("Error getting handle to process: %lu\n", GetLastError());
return 1;
}
if(!IsWow64Process(hProcess, &wow64))
{
printf("Error determining bitness of process: %lu\n", GetLastError());
return 1;
}
if(!wow64)
{
printf("Error, not a 32-bit process... closing program\n");
return 1;
}
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, dwPid);
if(hSnapshot == INVALID_HANDLE_VALUE)
{
printf("Error getting thread snapshot: %lu\n", GetLastError());
return 1;
}
th32.dwSize = sizeof(THREADENTRY32);
if(!Thread32First(hSnapshot, &th32))
{
printf("Error Thread32First: %lu\n", GetLastError());
return 1;
}
while(Thread32Next(hSnapshot, &th32))
{
if(th32.th32OwnerProcessID == dwPid)
{
found = TRUE;
break;
}
}
if(!found)
{
printf("Thread could not be found\n");
return 1;
}
hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, th32.th32ThreadID);
if(hThread == NULL)
{
printf("Error getting a handle to thread %lu: %lu\n", th32.th32ThreadID, GetLastError());
return 1;
}
if(Wow64SuspendThread(hThread) == -1)
{
printf("Error suspending thread: %lu\n", GetLastError());
return 1;
}
wow64ctxt.ContextFlags = WOW64_CONTEXT_FULL;
if(!Wow64GetThreadContext(hThread, &wow64ctxt))
{
printf("Error getting thread context: %lu\n", GetLastError());
}
ResumeThread(hThread);
printf("EAX: %lu\n", wow64ctxt.Eax);
printf("EBP: %lu\n", wow64ctxt.Ebp);
printf("EIP: %lu\n", wow64ctxt.Eip);
return 0;
}
My Windows has several accounts like "test1", "test2" and "test3" that belong to the Administrators group. I am developing an application program and I want that program to know if itself is run under an account that belong to the Administrators group by designing a boolean function: isCurrentUserAdminMember(), the isCurrentUserAdminMember() funtion should only return TRUE if the process is run by "test1", "test2", "test3" or the built-in Administrator account no matter whether the process is elevated.
I found some code in http://www.codeproject.com/Articles/320748/Haephrati-Elevating-during-runtime as below, but it seems only to check if the current process is elevated as an Administrator. I don't care if the process is elevated, I just want to know if the start account of the process is a member of Administrators group. And I hope the determination itself is not privilege required. Is that possible? thanks.
BOOL IsAppRunningAsAdminMode()
{
BOOL fIsRunAsAdmin = FALSE;
DWORD dwError = ERROR_SUCCESS;
PSID pAdministratorsGroup = NULL;
// Allocate and initialize a SID of the administrators group.
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
if (!AllocateAndInitializeSid(
&NtAuthority,
2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&pAdministratorsGroup))
{
dwError = GetLastError();
goto Cleanup;
}
// Determine whether the SID of administrators group is enabled in
// the primary access token of the process.
if (!CheckTokenMembership(NULL, pAdministratorsGroup, &fIsRunAsAdmin))
{
dwError = GetLastError();
goto Cleanup;
}
Cleanup:
// Centralized cleanup for all allocated resources.
if (pAdministratorsGroup)
{
FreeSid(pAdministratorsGroup);
pAdministratorsGroup = NULL;
}
// Throw the error if something failed in the function.
if (ERROR_SUCCESS != dwError)
{
throw dwError;
}
return fIsRunAsAdmin;
}
At last, we achieved the goal to check the Administrators group membership as the code below, however it is USELESS as the answer and comment said, just leave here for reference in case anybody needs it for other use.
// PermTest.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "stdio.h"
#include "iostream"
using namespace std;
#include "windows.h"
#include <lm.h>
#pragma comment(lib, "netapi32.lib")
BOOL IsUserInGroup(const wchar_t* groupe)
{
BOOL result = FALSE;
SID_NAME_USE snu;
WCHAR szDomain[256];
DWORD dwSidSize = 0;
DWORD dwSize = sizeof szDomain / sizeof * szDomain;
if ((LookupAccountNameW(NULL, groupe, 0, &dwSidSize, szDomain, &dwSize, &snu) == 0)
&& (ERROR_INSUFFICIENT_BUFFER == GetLastError()))
{
SID* pSid = (SID*)malloc(dwSidSize);
if (LookupAccountNameW(NULL, groupe, pSid, &dwSidSize, szDomain, &dwSize, &snu))
{
BOOL b;
if (CheckTokenMembership(NULL, pSid, &b))
{
if (b == TRUE)
{
result = TRUE;
}
}
else
{
result = FALSE;
}
}
//Si tout vas bien (la presque totalitée des cas), on delete notre pointeur
//avec le bon operateur.
free(pSid);
}
return result;
}
void getUserInfo(WCHAR *domainName, WCHAR *userName)
{
LPUSER_INFO_3 pBuf = NULL;
int j = 0;
DWORD nStatus = NetUserGetInfo(domainName, userName, 3, (LPBYTE *) &pBuf);
LPUSER_INFO_2 pBuf2 = NULL;
pBuf2 = (LPUSER_INFO_2) pBuf;
if (pBuf)
{
wprintf(L"User account name: %s\\%s\n", domainName, pBuf2->usri2_name);
wprintf(L"Privilege level: %d\n\n", pBuf2->usri2_priv);
}
// wprintf(L"\tPassword: %s\n", pBuf2->usri2_password);
// wprintf(L"\tPassword age (seconds): %d\n",
// pBuf2->usri2_password_age);
// wprintf(L"Privilege level: %d\n\n", pBuf2->usri2_priv);
// #define USER_PRIV_GUEST 0
// #define USER_PRIV_USER 1
// #define USER_PRIV_ADMIN 2
// wprintf(L"\tHome directory: %s\n", pBuf2->usri2_home_dir);
// wprintf(L"\tComment: %s\n", pBuf2->usri2_comment);
// wprintf(L"\tFlags (in hex): %x\n", pBuf2->usri2_flags);
// wprintf(L"\tScript path: %s\n", pBuf2->usri2_script_path);
// wprintf(L"\tAuth flags (in hex): %x\n",
// pBuf2->usri2_auth_flags);
// wprintf(L"\tFull name: %s\n", pBuf2->usri2_full_name);
// wprintf(L"\tUser comment: %s\n", pBuf2->usri2_usr_comment);
// wprintf(L"\tParameters: %s\n", pBuf2->usri2_parms);
// wprintf(L"\tWorkstations: %s\n", pBuf2->usri2_workstations);
// wprintf
// (L"\tLast logon (seconds since January 1, 1970 GMT): %d\n",
// pBuf2->usri2_last_logon);
// wprintf
// (L"\tLast logoff (seconds since January 1, 1970 GMT): %d\n",
// pBuf2->usri2_last_logoff);
// wprintf
// (L"\tAccount expires (seconds since January 1, 1970 GMT): %d\n",
// pBuf2->usri2_acct_expires);
// wprintf(L"\tMax storage: %d\n", pBuf2->usri2_max_storage);
// wprintf(L"\tUnits per week: %d\n",
// pBuf2->usri2_units_per_week);
// wprintf(L"\tLogon hours:");
// for (j = 0; j < 21; j++)
// {
// printf(" %x", (BYTE) pBuf2->usri2_logon_hours[j]);
// }
// wprintf(L"\n");
// wprintf(L"\tBad password count: %d\n",
// pBuf2->usri2_bad_pw_count);
// wprintf(L"\tNumber of logons: %d\n",
// pBuf2->usri2_num_logons);
// wprintf(L"\tLogon server: %s\n", pBuf2->usri2_logon_server);
// wprintf(L"\tCountry code: %d\n", pBuf2->usri2_country_code);
// wprintf(L"\tCode page: %d\n", pBuf2->usri2_code_page);
}
#include <comdef.h>
#define MAX_NAME 256
BOOL GetLogonFromToken (HANDLE hToken, _bstr_t& strUser, _bstr_t& strdomain)
{
DWORD dwSize = MAX_NAME;
BOOL bSuccess = FALSE;
DWORD dwLength = 0;
strUser = "";
strdomain = "";
PTOKEN_USER ptu = NULL;
//Verify the parameter passed in is not NULL.
if (NULL == hToken)
goto Cleanup;
if (!GetTokenInformation(
hToken, // handle to the access token
TokenUser, // get information about the token's groups
(LPVOID) ptu, // pointer to PTOKEN_USER buffer
0, // size of buffer
&dwLength // receives required buffer size
))
{
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
goto Cleanup;
ptu = (PTOKEN_USER)HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY, dwLength);
if (ptu == NULL)
goto Cleanup;
}
if (!GetTokenInformation(
hToken, // handle to the access token
TokenUser, // get information about the token's groups
(LPVOID) ptu, // pointer to PTOKEN_USER buffer
dwLength, // size of buffer
&dwLength // receives required buffer size
))
{
goto Cleanup;
}
SID_NAME_USE SidType;
char lpName[MAX_NAME];
char lpDomain[MAX_NAME];
if( !LookupAccountSidA( NULL , ptu->User.Sid, lpName, &dwSize, lpDomain, &dwSize, &SidType ) )
{
DWORD dwResult = GetLastError();
if( dwResult == ERROR_NONE_MAPPED )
strcpy (lpName, "NONE_MAPPED" );
else
{
printf("LookupAccountSid Error %u\n", GetLastError());
}
}
else
{
// printf( "Current user is %s\\%s\n",
// lpDomain, lpName );
strUser = lpName;
strdomain = lpDomain;
bSuccess = TRUE;
}
Cleanup:
if (ptu != NULL)
HeapFree(GetProcessHeap(), 0, (LPVOID)ptu);
return bSuccess;
}
HRESULT GetUserFromProcess( _bstr_t& strUser, _bstr_t& strdomain)
{
//HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION,FALSE,procId);
HANDLE hProcess = GetCurrentProcess();
if(hProcess == NULL)
return E_FAIL;
HANDLE hToken = NULL;
if( !OpenProcessToken( hProcess, TOKEN_QUERY, &hToken ) )
{
CloseHandle( hProcess );
return E_FAIL;
}
BOOL bres = GetLogonFromToken (hToken, strUser, strdomain);
CloseHandle( hToken );
CloseHandle( hProcess );
return bres?S_OK:E_FAIL;
}
int _tmain(int argc, _TCHAR* argv[])
{
//cout << IsUserInGroup(L"administrators");
getUserInfo(L"adtest.net", L"Administrator");
getUserInfo(NULL, L"Administrator");
getUserInfo(NULL, L"test");
getUserInfo(NULL, L"test2");
getUserInfo(NULL, L"testnormal");
_bstr_t username;
_bstr_t domain;
GetUserFromProcess(username, domain);
cout << "Current account running this program is: " << endl << domain << "\\" << username << endl;
getchar();
return 0;
}
You can do this by opening your process token (OpenProcessToken, listing the SIDs using GetTokenInformation and comparing each SID to the Administrators SID.
Microsoft have sample code here: Searching for a SID in an Access Token in C++
However, this is rarely a useful thing to do. Even if the user is not a member of the Administrators group, they can still elevate by providing an administrative username and password, so you should not (for example) only offer elevation if the user is in the Administrators group.
bool IsMemberOfGroup(const char *pszGroupName){
bool bFound = false;
HANDLE hToken=INVALID_HANDLE_VALUE;
BOOL bSuccess = OpenProcessToken( GetCurrentProcess(),
TOKEN_QUERY,//|TOKEN_QUERY_SOURCE,
&hToken);
if ( bSuccess )
{
DWORD dwSizeToken=0;
DWORD dwSizeName=0;
DWORD dwSizeReferencedDomainName = 0;
// Get group information:
GetTokenInformation(hToken, TokenGroups, NULL, dwSizeToken, &dwSizeToken);
{
const int MAX_NAME = 256;
char *psName = new char[MAX_NAME];
char *psDomain = new char[MAX_NAME];
char *pBuf = new char[dwSizeToken+10];
TOKEN_GROUPS *pGroupInfo = (TOKEN_GROUPS *)pBuf;
bSuccess = GetTokenInformation(hToken, TokenGroups, pGroupInfo, dwSizeToken, &dwSizeToken);
if ( bSuccess )
{
// find the group name we are looking for
for ( UINT uiGroupNdx = 0; uiGroupNdx < pGroupInfo->GroupCount && !bFound; uiGroupNdx++ )
{
SID_NAME_USE SidType;
dwSizeName = MAX_NAME;
dwSizeReferencedDomainName = MAX_NAME;
bSuccess = LookupAccountSid(NULL, // local system,
pGroupInfo->Groups[uiGroupNdx].Sid,
psName,
&dwSizeName,
psDomain,
&dwSizeReferencedDomainName,
&SidType);
if ( bSuccess )
{
if ( SidTypeGroup == SidType )
{
if ( !lstrcmpi(pszGroupName, psName) )
{
bFound = true;
}
}
}
}
}
delete [] pBuf;
delete [] psName;
delete [] psDomain;
}
CloseHandle(hToken);
}
return bFound;
}
I want to terminate one process, when I open this process, it built in my account and system.
Then I want to terminate this process using c++ program. My code could only terminate the process in my account, not in system. How could I change to terminate both?
My code is like:
PROCESSENTRY32 entry;
entry.dwSize = sizeof(PROCESSENTRY32);
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if (Process32First(snapshot, &entry) == TRUE)
{
while (Process32Next(snapshot, &entry) == TRUE)
{
if (stricmp(entry.szExeFile, "tvnserver.exe") == 0)
{
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, entry.th32ProcessID);
TerminateProcess(hProcess, 1);
CloseHandle(hProcess);
}
}
}
CloseHandle(snapshot);
Unless you have the required privileges to obtain a handle to the process, you can use the administrators special debug privileges to terminate the target process
Assuming you run as administrator you can enable the SE_DEBUG_NAME privilege on the current process, and you'll be able to terminate the target process. Alternatively could also take ownership of the target process as documented here https://social.msdn.microsoft.com/Forums/vstudio/en-US/3fb9cb5d-8891-4ba6-a945-06009be51e40/terminating-a-process-from-system-account-when-privileges-are-not-sufficient?forum=vcgeneral
This uses the first solution, and works for me, when running it as administrator.
#include <stdio.h>
#include <windows.h>
#include <TlHelp32.h>
NTSTATUS EnablePrivilege(wchar_t *privilege)
{
HANDLE token;
TOKEN_PRIVILEGES *tp = NULL;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token))
goto error;
tp = (TOKEN_PRIVILEGES*)new char[offsetof(TOKEN_PRIVILEGES, Privileges[1])];
if (!tp)
goto error;
tp->PrivilegeCount = 1;
tp->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (!LookupPrivilegeValueW(0, privilege, &tp->Privileges[0].Luid))
goto error;
if (!AdjustTokenPrivileges(token, 0, tp, 0, 0, 0) || GetLastError() != ERROR_SUCCESS)
goto error;
CloseHandle(token);
return 0x0;
error:
if(tp)
delete[] tp;
return 0xC0000001;
}
int main()
{
PROCESSENTRY32 entry;
entry.dwSize = sizeof(PROCESSENTRY32);
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if (Process32First(snapshot, &entry) == TRUE)
{
while (Process32Next(snapshot, &entry) == TRUE)
{
if (wcscmp(entry.szExeFile, L"spoolsv.exe") == 0)
{
NTSTATUS result = EnablePrivilege(SE_DEBUG_NAME);
if (result != 0)
{
printf("could not set SE_DEBUG_NAME Privilege\n");
getchar();
return -1;
}
HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, entry.th32ProcessID);
if (hProcess == NULL)
{
printf("couldn't open process\n");
getchar();
return -1;
}
TerminateProcess(hProcess, 1);
CloseHandle(hProcess);
}
}
}
CloseHandle(snapshot);
printf("success!\n");
getchar();
return 0;
}
//writing to mailslot
#include <windows.h>
#include <stdio.h>
LPTSTR SlotName = TEXT("\\\\.\\mailslot\\sample_mailslot");
BOOL WriteSlot(HANDLE hSlot, LPTSTR lpszMessage)
{
BOOL fResult;
DWORD cbWritten;
fResult = WriteFile(hSlot,
lpszMessage,
(DWORD) (lstrlen(lpszMessage)+1)*sizeof(TCHAR),
&cbWritten,
(LPOVERLAPPED) NULL);
if (!fResult)
{
printf("WriteFile failed with %d.\n", GetLastError());
return FALSE;
}
printf("Slot written to successfully.\n");
return TRUE;
}
int main()
{
HANDLE hFile;
hFile = CreateFile(SlotName,
GENERIC_WRITE,
FILE_SHARE_READ,
(LPSECURITY_ATTRIBUTES) NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
(HANDLE) NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
printf("CreateFile failed with %d.\n", GetLastError());
return FALSE;
}
WriteSlot(hFile, TEXT("Message one for mailslot."));
WriteSlot(hFile, TEXT("Message two for mailslot."));
Sleep(5000);
WriteSlot(hFile, TEXT("Message three for mailslot."));
CloseHandle(hFile);
return TRUE;
}
//reading from mailslot
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <strsafe.h>
HANDLE hSlot;
LPTSTR SlotName = TEXT("\\\\.\\mailslot\\sample_mailslot");
BOOL ReadSlot()
{
DWORD cbMessage, cMessage, cbRead;
BOOL fResult;
LPTSTR lpszBuffer;
TCHAR achID[80];
DWORD cAllMessages;
HANDLE hEvent;
OVERLAPPED ov;
cbMessage = cMessage = cbRead = 0;
hEvent = CreateEvent(NULL, FALSE, FALSE, TEXT("ExampleSlot"));
if( NULL == hEvent )
return FALSE;
ov.Offset = 0;
ov.OffsetHigh = 0;
ov.hEvent = hEvent;
fResult = GetMailslotInfo( hSlot, // mailslot handle
(LPDWORD) NULL, // no maximum message size
&cbMessage, // size of next message
&cMessage, // number of messages
(LPDWORD) NULL); // no read time-out
if (!fResult)
{
printf("GetMailslotInfo failed with %d.\n", GetLastError());
return FALSE;
}
if (cbMessage == MAILSLOT_NO_MESSAGE)
{
printf("Waiting for a message...\n");
return TRUE;
}
cAllMessages = cMessage;
while (cMessage != 0) // retrieve all messages
{
// Create a message-number string.
StringCchPrintf((LPTSTR) achID,
80,
TEXT("\nMessage #%d of %d\n"),
cAllMessages - cMessage + 1,
cAllMessages);
// Allocate memory for the message.
lpszBuffer = (LPTSTR) GlobalAlloc(GPTR,
lstrlen((LPTSTR) achID)*sizeof(TCHAR) + cbMessage);
if( NULL == lpszBuffer )
return FALSE;
lpszBuffer[0] = '\0';
fResult = ReadFile(hSlot,
lpszBuffer,
cbMessage,
&cbRead,
&ov);
if (!fResult)
{
printf("ReadFile failed with %d.\n", GetLastError());
GlobalFree((HGLOBAL) lpszBuffer);
return FALSE;
}
// Concatenate the message and the message-number string.
StringCbCat(lpszBuffer,
lstrlen((LPTSTR) achID)*sizeof(TCHAR)+cbMessage,
(LPTSTR) achID);
// Display the message.
_tprintf(TEXT("Contents of the mailslot: %s\n"), lpszBuffer);
GlobalFree((HGLOBAL) lpszBuffer);
fResult = GetMailslotInfo(hSlot, // mailslot handle
(LPDWORD) NULL, // no maximum message size
&cbMessage, // size of next message
&cMessage, // number of messages
(LPDWORD) NULL); // no read time-out
if (!fResult)
{
printf("GetMailslotInfo failed (%d)\n", GetLastError());
return FALSE;
}
}
CloseHandle(hEvent);
return TRUE;
}
BOOL WINAPI MakeSlot(LPTSTR lpszSlotName)
{
hSlot = CreateMailslot(lpszSlotName,
0, // no maximum message size
MAILSLOT_WAIT_FOREVER, // no time-out for operations
(LPSECURITY_ATTRIBUTES) NULL); // default security
if (hSlot == INVALID_HANDLE_VALUE)
{
printf("CreateMailslot failed with %d\n", GetLastError());
return FALSE;
}
return TRUE;
}
void main()
{
MakeSlot(SlotName);
while(TRUE)
{
ReadSlot();
Sleep(3000);
}
}
Go through the Visual Studio C++ Guided Tour on MSDN or watch this introductory video explaining how to create a basic Win32 application in C++. They should be enough of a starting point. From there on just browse the MSDN library to advance your knowledge or search for issues you encounter.