Related
This program enumerate all handles and get their names.
For pID 4 OpenProcess gets error 5 with SeDebugPrivilege.
UAC off. Running from Admin.
Enable SeDebugPrivilege
BOOL EnableDebugPrivilege(BOOL bEnable)
{
HANDLE hToken = nullptr;
LUID luid;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) return FALSE;
if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) return FALSE;
TOKEN_PRIVILEGES tokenPriv;
tokenPriv.PrivilegeCount = 1;
tokenPriv.Privileges[0].Luid = luid;
tokenPriv.Privileges[0].Attributes = bEnable ? SE_PRIVILEGE_ENABLED : 0;
if (!AdjustTokenPrivileges(hToken, FALSE, &tokenPriv, sizeof(TOKEN_PRIVILEGES), NULL, NULL)) return FALSE;
_tprintf(_T("Privileges error: %d\n", GetLastError()));
return TRUE;
}
Enumerate handles
DWORD EnumerateFileHandles(ULONG pid)
{
HINSTANCE hNtDll = LoadLibrary(_T("ntdll.dll"));
assert(hNtDll != NULL);
PFN_NTQUERYSYSTEMINFORMATION NtQuerySystemInformation =
(PFN_NTQUERYSYSTEMINFORMATION)GetProcAddress(hNtDll,
"NtQuerySystemInformation");
assert(NtQuerySystemInformation != NULL);
PFN_NTQUERYINFORMATIONFILE NtQueryInformationFile =
(PFN_NTQUERYINFORMATIONFILE)GetProcAddress(hNtDll,
"NtQueryInformationFile");
DWORD nSize = 4096, nReturn;
PSYSTEM_HANDLE_INFORMATION pSysHandleInfo = (PSYSTEM_HANDLE_INFORMATION)
HeapAlloc(GetProcessHeap(), 0, nSize);
while (NtQuerySystemInformation(SystemExtendedHandleInformation, pSysHandleInfo,
nSize, &nReturn) == STATUS_INFO_LENGTH_MISMATCH)
{
HeapFree(GetProcessHeap(), 0, pSysHandleInfo);
nSize += 4096;
pSysHandleInfo = (SYSTEM_HANDLE_INFORMATION*)HeapAlloc(
GetProcessHeap(), 0, nSize);
}
DWORD dwFiles = 0;
_tprintf(_T("Handles Number: %d\n"), pSysHandleInfo->NumberOfHandles);
for (ULONG i = 0; i < pSysHandleInfo->NumberOfHandles; i++)
{
PSYSTEM_HANDLE pHandle = &(pSysHandleInfo->Handles[i]);
if (pHandle->ProcessId == 4)
{
HANDLE hProcess = OpenProcess(
PROCESS_DUP_HANDLE, FALSE, pHandle->ProcessId);
if (hProcess == NULL)
{
_tprintf(_T("OpenProcess failed w/err 0x%08lx\n"), GetLastError());
continue;
}
HANDLE hCopy;
if (!DuplicateHandle(hProcess, (HANDLE)pHandle->Handle,
GetCurrentProcess(), &hCopy, MAXIMUM_ALLOWED, FALSE, 0))
continue;
TCHAR buf[MAX_PATH];
if (GetFinalPathNameByHandle(hCopy, buf, sizeof(buf), VOLUME_NAME_DOS))
wprintf(L"p%d:h%d:t%d:\t%s\n", pHandle->ProcessId, pHandle->Handle, pHandle->ObjectTypeNumber, buf);
CloseHandle(hProcess);
CloseHandle(hCopy);
}
}
HeapFree(GetProcessHeap(), 0, pSysHandleInfo);
return dwFiles;
}
On windows 7 x64 it's work fine.
But on Windows 10 x64 OpenProcess returns error 5 with SeDebugPrivilege.
How open system process(pID 4) on windows 10.
You can't open a handle for it as the documentation for OpenProcess specifically says it'll fail:
If the specified process is the Idle process or one of the CSRSS
processes, this function fails and the last error code is
ERROR_ACCESS_DENIED because their access restrictions prevent
user-level code from opening them.
If you want to get system process names, you could try to use CreateToolhelp32Snapshot() to get the snapshot of the process, then use Process32First() and Process32Next() to enumerate the all process.
Here is an example:
#include <iostream>
#include <stdio.h>
#include <windows.h>
#include <string>
#include <TlHelp32.h>
using namespace std;
int main()
{
PROCESSENTRY32 pe32;
pe32.dwSize = sizeof(pe32);
HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);//get the snapshot
if (hProcessSnap == INVALID_HANDLE_VALUE)
{
cout << "CreateToolhelp32Snapshot Error!" << endl;
return false;
}
BOOL bResult = Process32First(hProcessSnap, &pe32);
int num(0);
while(bResult)
{
cout << "[" << ++num << "] : " << "Process Name:"<< pe32.szExeFile << " " << "ProcessID:" << pe32.th32ProcessID << endl;
bResult = Process32Next(hProcessSnap, &pe32);
}
CloseHandle(hProcessSnap);
}
Hope it could help you!
With DLL injection, grabbing the base address of the process was as easy as using
GetModuleHandleW(0);
So I'm trying to grab the address without injection and I can't seem to get it to work. I've Googled some solutions and found others from stackoverflow but they don't seem to work. Here's what I'm using right now. I have the right headers and it compiles. It just doesn't work.
DWORD_PTR dwGetModuleBaseAddress(DWORD dwProcID, TCHAR *szModuleName)
{
DWORD_PTR dwModuleBaseAddress = 0;
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, dwProcID);
if (hSnapshot != INVALID_HANDLE_VALUE)
{
MODULEENTRY32 ModuleEntry32;
ModuleEntry32.dwSize = sizeof(MODULEENTRY32);
if (Module32First(hSnapshot, &ModuleEntry32))
{
do
{
if (_tcsicmp(ModuleEntry32.szModule, szModuleName) == 0)
{
dwModuleBaseAddress = (DWORD_PTR)ModuleEntry32.modBaseAddr;
break;
}
} while (Module32Next(hSnapshot, &ModuleEntry32));
}
CloseHandle(hSnapshot);
}
return dwModuleBaseAddress;
}
I try to cout this address and it just gives me 0. I think it might be the fact that I don't understand the second parameter. I'm just copying what I saw. Here's my main function.
int main() {
HWND hwnd = FindWindowA(NULL, gameName);
int x;
if (hwnd == NULL) {
cout << "Cannot find " << (string)gameName << " window" << endl;
cin >> x;
exit(-1);
}
DWORD procID;
GetWindowThreadProcessId(hwnd, &procID);
HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, procID);
DWORD playerAddr = 0;
playerAddr = dwGetModuleBaseAddress(procID, _T("starbound.exe"));
cout << hex << playerAddr;
}
Some of this may be redundant because I'm just adding it to what I had before. I'm just not sure why it's not working.
Your code is correct, there is nothing wrong with it, I just tested it on x86 and x64.
Your problem is you need to run as administrator so you have correct security permissions to access the other process and you also should build your project as the same architecture, x86 or x64, as the target process.
If neither of those solutions fix it, then your 'gameName' variable or your module name are defined incorrectly.
If you use your dwModuleBaseAddress as a debug tool, it may be easier to spot the call that fails...
DWORD_PTR dwGetModuleBaseAddress(DWORD dwProcID, TCHAR *szModuleName)
{
DWORD_PTR dwModuleBaseAddress = (DWORD_PTR)-1; // unlikely value...
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, dwProcID);
if (hSnapshot != INVALID_HANDLE_VALUE)
{
MODULEENTRY32 ModuleEntry32;
ModuleEntry32.dwSize = sizeof(MODULEENTRY32);
dwModuleBaseAddress = (DWORD_PTR)-2;
if (Module32First(hSnapshot, &ModuleEntry32))
{
do
{
--dwModuleBaseAddress;
if (_tcsicmp(ModuleEntry32.szModule, szModuleName) == 0)
{
dwModuleBaseAddress = (DWORD_PTR)ModuleEntry32.modBaseAddr;
break;
}
} while (Module32Next(hSnapshot, &ModuleEntry32));
}
CloseHandle(hSnapshot);
}
return dwModuleBaseAddress;
}
You can also check the error that caused the issue using GetLastError()
void PrintLastError()
{
LPTSTR psz;
DWORD dwError = GetLastError();
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
dwError,
0,
(LPTSTR)&psz,
1024,
NULL);
_tprintf(_T("Windows reports error: (0x%08X): %s\n"), dwError, (psz) ? psz : _T("(null)"));
if (psz)
{
LocalFree(psz);
}
}
If all else fails, try running this example from msdn https://msdn.microsoft.com/fr-fr/library/windows/desktop/ms686849(v=vs.85).aspx
It will print the exact string you want to match, the problem may come from there.
I'm trying to create an unelevated process from an elevated process on Windows 7-10.
I used the following as a reference:
FAQ: How do I start a program as the desktop user from an elevated app?
Now, this method works wonderfully, however due to a possible legacy check, it seems that CreateProcessWithTokenW() only allows the cmdline argument to be less than or equal to 1024 characters.
The cmdline I'm required to pass through is far more than that, which causes an E_INVALIDARG error.
Has anyone run into the same issue as me? If so, how did you work around this absolutely ridiculous 1024 character limit?
for exec not elevated process from our elevated (in same session) we need do next:
create restricted token from our elevated token by
CreateRestrictedToken with LUA_TOKEN
set medium intergity level in new token
call CreateProcessAsUser - note that
If hToken is a restricted version of the caller's primary token, the
SE_ASSIGNPRIMARYTOKEN_NAME privilege is not required.
ULONG LowExec(PCWSTR lpApplicationName, PWSTR lpCommandLine)
{
HANDLE hToken, hLowToken;
ULONG cb = GetSidLengthRequired(1);
TOKEN_MANDATORY_LABEL tml = { { (PSID)alloca(cb) } };
ULONG dwError = NOERROR;
if (CreateWellKnownSid(WinMediumLabelSid, 0, tml.Label.Sid, &cb) &&
OpenProcessToken(NtCurrentProcess(), TOKEN_DUPLICATE | TOKEN_QUERY |
TOKEN_ADJUST_DEFAULT | TOKEN_ASSIGN_PRIMARY, &hToken))
{
BOOL fOk = CreateRestrictedToken(hToken, LUA_TOKEN, 0, 0, 0, 0, 0, 0, &hLowToken);
if (!fOk)
{
dwError = GetLastError();
}
CloseHandle(hToken);
if (fOk)
{
if (SetTokenInformation(hLowToken, ::TokenIntegrityLevel, &tml, sizeof(tml)))
{
STARTUPINFOW si = { sizeof(si)};
PROCESS_INFORMATION pi;
if (CreateProcessAsUser(hLowToken, lpApplicationName, lpCommandLine, 0, 0, TRUE, 0, 0, 0, &si, &pi))
{
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
}
else
{
dwError = GetLastError();
}
}
else
{
dwError = GetLastError();
}
CloseHandle(hLowToken);
}
}
else
{
dwError = GetLastError();
}
return dwError;
}
Maybe try using CreateProcessAsUserW() instead? I know it requires special privileges, but if your process is running as administrator, there is a way to overcome it.
The idea is to impersonate a powerful token before calling the API. A powerful token is defined as a token that possesses all desired privileges.
First, enumerate process ID via API like NtQuerySystemInformation(). For each process ID, open the process token and use GetTokenInformation(hToken, TokenPrivileges, ...) to get information of what privileges are possessed by the token. If the token possesses all privileges we want, we may duplicate an impersonation token out from it by DuplicateTokenEx(..., TokenImpersonation, &hTokenImp) (and stop enumerating of course).
Now that we have the powerful token, we shall examine the desired privileges of it, see if they are all enabled. Check status with PrivilegeCheck() and enable it with AdjustTokenPrivileges(). Finally, let current thread impersonate the token by SetThreadToken(NULL, hTokenImp), call the CreateProcessAsUserW() however you like, and stop impersonation by SetThreadToken(NULL, NULL).
As for the token for CreateProcessAsUserW(), I would recommend you to use primary token of current user session by WTSQueryUserToken(), because it would work as expected even if you do OTS elevation. Last time I tried to use Linked Token as described here, and found it would not work with OTS elevation.
Here is a test code in ANSI C. When running as administrator, it will run another instance of itself un-elevated and show the command line length. And yes, CreateProcessAsUserW() supports command-line longer than 1024. :)
#include <stdio.h>
#include <Windows.h>
#include <objbase.h>
#include "EnumProcessesId.h"
#define MY_LuidEqual(a, b) \
( ((a)->HighPart == (b)->HighPart) && ((a)->LowPart == (b)->LowPart) )
static LPVOID MyAllocZero(SIZE_T cb)
{
LPVOID ptr = CoTaskMemAlloc(cb);
if (ptr) { ZeroMemory(ptr, cb); }
return ptr;
}
static void MyFree(LPVOID ptr)
{
CoTaskMemFree(ptr);
}
static DWORD MyWTSGetActiveConsoleSessionId(void)
{
typedef DWORD(WINAPI *fn_t)(void);
fn_t fn = (fn_t)GetProcAddress(LoadLibraryA("kernel32"),
"WTSGetActiveConsoleSessionId");
if (fn) { return fn(); }
return 0;
}
static BOOL MyWTSQueryUserToken(DWORD sessId, HANDLE *phToken)
{
typedef BOOL(WINAPI *fn_t)(DWORD, HANDLE*);
fn_t fn = (fn_t)GetProcAddress(LoadLibraryA("wtsapi32"),
"WTSQueryUserToken");
if (fn) {
return fn(sessId, phToken);
}
return FALSE;
}
static BOOL MyPrivIsEnabled(HANDLE hToken, LUID const *pPrivLuid)
{
BOOL isEnabled = FALSE;
PRIVILEGE_SET ps = { 0 };
ps.PrivilegeCount = 1;
ps.Privilege[0].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT;
PrivilegeCheck(hToken, &ps, &isEnabled);
if (!isEnabled) {
ps.Privilege[0].Attributes = SE_PRIVILEGE_ENABLED;
PrivilegeCheck(hToken, &ps, &isEnabled);
}
return isEnabled;
}
static HRESULT MyEnablePriv(HANDLE hToken, LUID const *pPrivLuid, BOOL enable)
{
BOOL ok = FALSE;
TOKEN_PRIVILEGES tp = { 0 };
tp.PrivilegeCount = 1;
tp.Privileges[0].Attributes = enable ? SE_PRIVILEGE_ENABLED : 0;
tp.Privileges[0].Luid = *pPrivLuid;
ok = AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL);
return ok ? S_OK : HRESULT_FROM_WIN32(GetLastError());
}
typedef struct {
/* in : */
LUID const *pLuidAPT;
LUID const *pLuidIQN;
LUID const *pLuidTCB;
/* out : */
HANDLE hptPowerful;
} MyEnumPowerfulTokenData_t;
static BOOL CALLBACK MyEnumPowerfulTokenProc(DWORD pid, void * user)
{
DWORD const ProcessQueryLimitedInfo = 0x1000;
MyEnumPowerfulTokenData_t *pData = user;
BOOL ok = FALSE, wantContinue = TRUE;
HANDLE hProc = NULL;
HANDLE hProcToken = NULL;
DWORD i = 0, cbTP = 0;
TOKEN_PRIVILEGES *pTP = NULL;
BOOL gotAPT = FALSE, gotIQN = FALSE, gotTCB = FALSE;
/* Get process token */
hProc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
if (!hProc) {
hProc = OpenProcess(ProcessQueryLimitedInfo, FALSE, pid);
}
if (!hProc) goto eof;
ok = OpenProcessToken(hProc, TOKEN_QUERY | TOKEN_DUPLICATE, &hProcToken);
if (!ok) goto eof;
/* Check if token possesses desired privileges */
GetTokenInformation(hProcToken, TokenPrivileges, NULL, 0, &cbTP);
if (!cbTP) goto eof;
pTP = MyAllocZero(cbTP);
if (!pTP) goto eof;
ok = GetTokenInformation(hProcToken, TokenPrivileges, pTP, cbTP, &cbTP);
if (!ok) goto eof;
for (i = 0; i < pTP->PrivilegeCount; ++i)
{
LUID const *pThat = &(pTP->Privileges[i].Luid);
if (gotAPT && gotIQN && gotTCB) {
wantContinue = FALSE;
pData->hptPowerful = hProcToken;
hProcToken = NULL; /* to avoid eof CloseHandle() */
break;
}
else if (!gotAPT && MY_LuidEqual(pThat, pData->pLuidAPT)) {
gotAPT = TRUE;
}
else if (!gotIQN && MY_LuidEqual(pThat, pData->pLuidIQN)) {
gotIQN = TRUE;
}
else if (!gotTCB && MY_LuidEqual(pThat, pData->pLuidTCB)) {
gotTCB = TRUE;
}
}
eof:
if (pTP) { MyFree(pTP); }
if (hProcToken) { CloseHandle(hProcToken); }
if (hProc) { CloseHandle(hProc); }
return wantContinue;
}
static HRESULT MyCreateProcess(LPWSTR szCmdLine)
{
HRESULT hr = 0;
BOOL ok = FALSE;
LUID luidAPT = { 0 }; /* SE_ASSIGNPRIMARYTOKEN_NAME */
LUID luidIQN = { 0 }; /* SE_INCREASE_QUOTA_NAME */
LUID luidTCB = { 0 }; /* SE_TCB_NAME */
MyEnumPowerfulTokenData_t enumData = { 0 };
HANDLE hptPowerful = NULL; /* primary/process token */
HANDLE hitPowerful = NULL; /* impersonation token */
HANDLE hptCurrSessUser = NULL;
DWORD dwCurrSessId = 0;
STARTUPINFOW si = { sizeof(si) };
PROCESS_INFORMATION pi = { 0 };
ok = LookupPrivilegeValue(NULL, SE_ASSIGNPRIMARYTOKEN_NAME, &luidAPT)
&& LookupPrivilegeValue(NULL, SE_INCREASE_QUOTA_NAME, &luidIQN)
&& LookupPrivilegeValue(NULL, SE_TCB_NAME, &luidTCB);
if (!ok) {
hr = HRESULT_FROM_WIN32(GetLastError()); goto eof;
}
enumData.pLuidAPT = &luidAPT;
enumData.pLuidIQN = &luidIQN;
enumData.pLuidTCB = &luidTCB;
hr = EnumProcessesId_WinNT(MyEnumPowerfulTokenProc, &enumData);
if (FAILED(hr)) goto eof;
hptPowerful = enumData.hptPowerful;
if (!hptPowerful) {
hr = E_UNEXPECTED; goto eof;
}
ok = DuplicateTokenEx(hptPowerful, TOKEN_ADJUST_PRIVILEGES | TOKEN_IMPERSONATE,
NULL, SecurityImpersonation, TokenImpersonation, &hitPowerful);
if (!ok) {
hr = HRESULT_FROM_WIN32(GetLastError()); goto eof;
}
if (!MyPrivIsEnabled(hitPowerful, &luidAPT))
{
hr = MyEnablePriv(hitPowerful, &luidAPT, TRUE);
if (FAILED(hr)) goto eof;
}
if (!MyPrivIsEnabled(hitPowerful, &luidIQN))
{
hr = MyEnablePriv(hitPowerful, &luidIQN, TRUE);
if (FAILED(hr)) goto eof;
}
if (!MyPrivIsEnabled(hitPowerful, &luidTCB))
{
hr = MyEnablePriv(hitPowerful, &luidTCB, TRUE);
if (FAILED(hr)) goto eof;
}
ok = SetThreadToken(NULL, hitPowerful);
if (!ok) {
hr = HRESULT_FROM_WIN32(GetLastError()); goto eof;
}
dwCurrSessId = MyWTSGetActiveConsoleSessionId();
ok = MyWTSQueryUserToken(dwCurrSessId, &hptCurrSessUser);
if (!ok) {
hr = HRESULT_FROM_WIN32(GetLastError()); goto eof;
}
ok = CreateProcessAsUserW(hptCurrSessUser, NULL, szCmdLine, 0, 0, 0, 0, 0, 0, &si, &pi);
if (!ok) {
hr = HRESULT_FROM_WIN32(GetLastError()); goto eof;
}
eof:
SetThreadToken(NULL, NULL);
if (hptCurrSessUser) { CloseHandle(hptCurrSessUser); }
if (hitPowerful) { CloseHandle(hitPowerful); }
if (hptPowerful) { CloseHandle(hptPowerful); }
if (FAILED(hr)) {
printf("HRESULT = 0x%.8X \n", hr);
}
return 0;
}
int main(int argc, char **argv)
{
if (argc > 1)
{
WCHAR szMsg[999] = {0};
wsprintfW(szMsg,
L"lstrlenW(GetCommandLineW()) = %i \n",
lstrlenW(GetCommandLineW()));
MessageBoxW(NULL, szMsg, L"Test", MB_ICONINFORMATION);
}
else
{
WCHAR szMyExePath[MAX_PATH] = {0};
WCHAR szCmdLine[9999] = {0}, *p;
GetModuleFileNameW(NULL, szMyExePath, MAX_PATH);
wsprintfW(szCmdLine, L"\"%s\" ", szMyExePath);
for (p = szCmdLine; *p; ++p);
while (p < (szCmdLine + 9999 - 1))
{
*p++ = 'a';
}
MyCreateProcess(szCmdLine);
}
return 0;
}
I will leave the implementation of EnumProcessesId_WinNT() to you. The prototype of the function is:
/* return TRUE to continue */
typedef BOOL(CALLBACK *EnumProcessesId_Callback_t)
(DWORD pid, void * user);
EXTERN_C
HRESULT __stdcall
EnumProcessesId_WinNT(
EnumProcessesId_Callback_t fnCallback,
void *user
);
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;
}
I am trying to list all modules on a specific process, but I am getting "Access denied", even when I set token privileges.
Here is the code:
#include <cstdlib>
#include <iostream>
#include <windows.h>
#include <psapi.h>
#include <Tlhelp32.h>
using namespace std;
#pragma comment(lib, "cmcfg32.lib")
BOOL SetPrivilege(HANDLE hToken, LPCTSTR lpszPrivilege, BOOL bEnablePrivilege)
{
TOKEN_PRIVILEGES tp;
LUID luid;
if (!LookupPrivilegeValue(NULL, lpszPrivilege, &luid))
{
char buf[256];
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, 255, NULL);
cout << "LookupPrivilegeValue error: " << buf;
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; }
if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES) NULL, (PDWORD)NULL))
{
char buf[256];
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, 255, NULL);
cout << "AdjustTokenPrivileges error: " << buf;
return FALSE;
}
if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
{
printf("The token does not have the specified privilege. \n");
return FALSE;
}
return TRUE;
}
int GetPID(char pname[])
{
PROCESSENTRY32 pEntry;
HANDLE hSnapshot = NULL;
pEntry.dwSize = sizeof(PROCESSENTRY32);
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
Process32First(hSnapshot,&pEntry);
do { if(strcmp(pEntry.szExeFile, pname) == 0) { return pEntry.th32ProcessID; } } while(Process32Next(hSnapshot,&pEntry));
return 0;
}
int main()
{
HANDLE currentToken;
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, ¤tToken);
if (!SetPrivilege(currentToken, SE_DEBUG_NAME, TRUE))
{
MessageBox(0, "Unable to adjust privileges", "Error", MB_ICONERROR);
}
DWORD ID = GetPID("test.exe");
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, ID);
if(!hProcess)
{
MessageBox(0, "Process not found", "Error", MB_ICONERROR);
}
else
{
HMODULE hMods[2048];
DWORD cbNeeded;
if(EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded))
{
for (unsigned int i = 0; i < (cbNeeded/sizeof(HMODULE)); i++)
{
TCHAR szModName[MAX_PATH];
if (GetModuleFileNameEx(hProcess, hMods[i], szModName, sizeof(szModName)/sizeof(TCHAR)))
{
cout << "DLL: " << szModName << " Handle: " << hMods[i] << endl;
}
}
}
else
{
char buf[256];
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, 255, NULL);
cout << "Error: " << buf;
}
system("pause");
}
CloseHandle(hProcess);
return 0;
}
Note that I can list process modules of any other process, but I can't with a specific one.
Both process are running with the same user credentials.
Can you tell me if I am doing something wrong?
Use Process Explorer to see the Security of kernel objects you are interested in. May be the target process has set its owner/DACL information such that it disallows READ for other processes. AntiVirus programs, services, file-system/kernel-driver are such kind of processes denying such actions.
And more importantly: it depends on the elevation/admin/ring-level of your own process.
ADDED:
Privileges doesn't directly apply to objects, but to the system as a whole. Try opening with TOKEN_ALL_ACCESS and see if it succeeds.