Get the process handle of a process by image name - c

I need the simplest way from C using Win32 to get the process handle of another process by its executable file name.
The process I am looking for does not have any registered window classes. I also know that if it is running there will be only one instance of it running.

Use CreateToolhelp32Snapshot, Process32First, and Process32Next to enumerate all of the processes.
Inside the PROCESSENTRY32 you can find a szExeFile member.
You can get the process handle by calling OpenProcess with the process ID th32ProcessID within the same struct.
Once you find a process matching your exe name, you can break out of your loop and obtain the handle.
Note: If you need to enumerate EVERY process no matter what the session is, you should acquire the SE_DEBUG privilege.
At the top of your main call this:
acquirePrivilegeByName(SE_DEBUG_NAME);// SeDebugPrivilege
And here is the definition of acquirePrivilegeByName:
BOOL acquirePrivilegeByName(
const TCHAR *szPrivilegeName)
{
HANDLE htoken;
TOKEN_PRIVILEGES tkp;
DWORD dwerr;
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()
In addition to what I said above, there is an example on how to use the above Win32 API here.

Related

SetSecurityInfo returns access denied

Using C, I'm trying to establish a pipe connection between a process and it's child process, while the child process has a lower mandatory(integrity) level (low, while the parent process is high).
I wrote the following program (it's a simplified version if it), but it fails with: ERROR_ACCESS_DENIED (0x5)
INT wmain(IN SIZE_T nArgc, IN PWSTR *pArgv)
{
SECURITY_ATTRIBUTES securityArrtibutes = { 0 };
HANDLE hPipeRead = NULL;
HANDLE hPipeWrite = NULL;
tSecurityArrtibutes.nLength = sizeof(tSecurityArrtibutes);
tSecurityArrtibutes.bInheritHandle = TRUE;
SetSeSecurityNamePrivilege();
CreatePipe(&hPipeRead, &hPipeWrite, &securityArrtibutes, 0);
ChangeMandatoryLabelHandle(hPipeRead);
}
VOID ChangeMandatoryLabelHandle(HANDLE hObject)
{
BOOL bRetval = FALSE;
DWORD dwError = 0;
PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL;
PACL ptSacl = NULL;
BOOL bSaclPresent = FALSE;
BOOL bSaclDefaulted = FALSE;
PWSTR pSDDL = NULL;
SDDL = L"S:(ML;;LW;;;NW)";
bRetval = ConvertStringSecurityDescriptorToSecurityDescriptorW(pSDDL, SDDL_REVISION_1, &pSecurityDescriptor, NULL);
if (FALSE == bRetval)
... // Handle failure
bRetval = GetSecurityDescriptorSacl(pSecurityDescriptor, &bSaclPresent, &ptSacl, &bSaclDefaulted);
if (FALSE == bRetval)
... // Handle failure
// getting ERROR_ACCESS_DENIED (0x5)
dwErr = SetSecurityInfo(hObject, SE_KERNEL_OBJECT, LABEL_SECURITY_INFORMATION, NULL, NULL, NULL, ptSacl);
if (ERROR_SUCCESS != dwErr)
... // Handle failure
... // Cleanup
}
I followed https://msdn.microsoft.com/en-us/library/windows/desktop/aa379588(v=vs.85).aspx and the remark that
To set the SACL of an object, the caller must have the SE_SECURITY_NAME privilege enabled. :
BOOL SetSeSecurityNamePrivilege()
{
HANDLE hToken;
TOKEN_PRIVILEGES tp;
LUID luid;
if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_IMPERSONATE, &hToken)
return FALSE
if (!LookupPrivilegeValue(NULL, SE_SECURITY_NAME, &luid))
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))
return FALSE;
if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
return FALSE;
return TRUE;
}
note: I get the same result when I try to execute it with files, with CreateFile instead of CreatePipe.
In addition if I try to do that with files, and I replace SetSecurityInfo with SetNamedSecurityInfoW, and give it the full path of the file, it works great.
Does anyone have an idea how to make it work? Thanks!
A few notes before addressing the cause of your immediate problem.
First and foremost, you do not need to change the security descriptor at all, and doing so is unlikely to help you achieve your ultimate goal. The security descriptor is only checked when you attempt to open a handle to an object; if you already have a handle, the security descriptor has no effect. Since you are creating an unnamed pipe, you must be passing the handle, not the pipe name, to the child, so you do not need the ChangeMandatoryLabelHandle function at all.
Secondly, the SE_SECURITY_NAME privilege is not needed when setting LABEL_SECURITY_INFORMATION. The mandatory label is logically distinct from the rest of the SACL, and is treated as a special case.
Thirdly, your "S:(ML;;LW;;;NW)" is invalid.
I tried to use it in ConvertStringSecurityDescriptorToSecurityDescriptorW and got error 1336, The access control list (ACL) structure is invalid. Instead, use"D:NO_ACCESS_CONTROLS:(ML;;;;;LW)" or better still use the following code to create a security descriptor with a low label and no DACL:
ULONG cb = MAX_SID_SIZE;
PSID LowLabelSid = (PSID)alloca(MAX_SID_SIZE);
ULONG dwError = NOERROR;
if (CreateWellKnownSid(WinLowLabelSid, 0, LowLabelSid, &cb))
{
PACL Sacl = (PACL)alloca(cb += sizeof(ACL) + sizeof(ACE_HEADER) + sizeof(ACCESS_MASK));
if (InitializeAcl(Sacl, cb, ACL_REVISION) &&
AddMandatoryAce(Sacl, ACL_REVISION, 0, 0, LowLabelSid))
{
SECURITY_DESCRIPTOR sd;
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE);
SetSecurityDescriptorSacl(&sd, TRUE, Sacl, FALSE);
SECURITY_ATTRIBUTES sa = { sizeof(sa), &sd, TRUE };
// todo something here
}
else
{
dwError = GetLastError();
}
}
else
{
dwError = GetLastError();
}
But again, you need to understand that there is (almost) never any sense in creating a security descriptor for an unnamed object. The security descriptor is only checked when opening an object, and (in user mode) you cannot open an object that does not have a name.
(From kernel mode we can open an object by pointer using ObOpenObjectByPointer.)
(In older versions of Windows, CreatePipe actually created a pipe with a random name, but starting from Windows 7 the pipe really is unnamed, so it cannot be opened with CreateFile or any similar method.)
In any case, it is my opinion that using CreatePipe in this context was a bad choice. This function is not well designed and has too few parameters. There is no option to create a bidirectional pipe or to open the pipe in asynchronous mode. I think it is better to use CreateNamedPipeW and CreateFileW.
(Alternatively, from Windows 7 onwards, you can use ZwCreateNamedPipeFile and ZwOpenFile to create and open an unnamed pipe.)
The proximate problem with the code as posted is that SetSecurityInfo and SetKernelObjectSecurity return ERROR_ACCESS_DENIED when called with the handle returned by CreatePipe. This is because, as described in the documentation for LABEL_SECURITY_INFORMATION:
Right required to set: WRITE_OWNER
Since CreatePipe does not give you the option to select the access rights that the handles are opened with, you have no way of doing this. If you instead use CreateNamedPipe you can set WRITE_OWNER in dwOpenMode.
However, you should note that if you wish to create an object with a special security descriptor, it is preferable to provide that security descriptor when the object is created. There is no point in creating the object with a default security descriptor and then changing it; why do in two operations what you can do in one? In this case, the SECURITY_ATTRIBUTES structure you pass to CreatePipe or CreateNamedPipe can be used to specify the security descriptor, providing another way of addressing your immediate problem, although as previously mentioned this will not in fact be useful.

How to retrieve system proxy settings in Win 7 for windows service in C

I am writing an application that will run as a service and will pick system proxy settings for communication with the outside world .I tried WinHttpGetIEProxyConfigForCurrentUser but it fails to retrieve proxy settings for current user which is obvious since service is running under the domain of Local System. To realize the same I have to made the user to logon to the service which I don't want application user to do. I read about SERVICE_USER_OWN_PROCESS parameter which can be passed to CreateService() but neither I found its declaration in WinNT.h nor I am sure if it will work. Development of application is stuck because of this issue. Can anybody please help.
I had similar situation with running a program in the context of the current user.
First of all - somewhere in a global scope - define following variables:
HANDLE hUsrToken;
HANDLE hDupToken;
int sessionId;
You need to get the session Id of the current user:
int getInteractiveSessinoId()
{
PWTS_SESSION_INFO pSessInfo;
ulong count; // Number of current user sessions
int result = -1;
if (!WTSEnumerateSessions(WTS_CURRENT_SERVER, 0, 1, &pSessInfo, &count))
{
printf("Getting session information failed with error %d\n", << GetLastError());
WTSFreeMemory(pSessInfo);
return -2;
}
for (ulong loop = 0; loop < count; loop++)
{
if (pSessInfo[loop].State == WTSActive)
{
printf("Session %d is currently active\n", pSessInfo[loop].SessionId);
result = pSessInfo[loop].SessionId;
break;
}
}
WTSFreeMemory(pSessInfo);
return result;
}
Next you need to impersonate the current user (I called it "attach to the session"):
bool attachToSession(int sessionId)
{
// We need to duplicate the token of the session's user
if (!WTSQueryUserToken(sessionId, &hUsrToken))
{
pritnf("Query the user token failed with error %d\n", GetLastError());
return false;
}
if (!DuplicateTokenEx(hUsrToken, TOKEN_ALL_ACCESS, NULL, SecurityImpersonation, TokenImpersonation , &hDupToken))
{
printf("Duplicating a token failed with error %d\n", GetLastError());
return false;
}
if (!ImpersonateLoggedOnUser(hDupToken))
{
printf("Impersonating the user failed with error %d\n", GetLastError();
return false;
}
return true;
}
Now do whatever you want to do want to do within the current user's context, when done, revert (or "detach") from the user's context:
bool detachFromSession()
{
if (!RevertToSelf())
{
printf("Reverting the token failed with error %d\n", GetLastError());
return false;
}
(void)CloseHandle(hDupToken);
(void)CloseHandle(hUsrToken);
return true;
}
I'm not sure if it is good idea to apply the token to the current (service) thread. I think it is a better idea to create a new thread which executes whatever you want to do in the user's context and apply the impersonated token to it. So your code part may look like this:
HANDLE hUsrToken;
HANDLE hDupToken;
HANDLE hThread;
int sessionId;
DWORD threadId;
DWORD WINAPI MyThreadFunction(LPVOID lpParam)
{
// WinHttpGetIEProxyConfigForCurrentUser(...
}
sessionId = getInterActiveSessionId();
if (attachToSession(int sessionId) == false)
{
// Error handling
return;
}
hThread = CreateThread(NULL, // default security attributes
0, // use default stack size
MyThreadFunction, // thread function name
NULL, // argument to thread function
CREATE_SUSPENDED, // Delay execution
&threadId);
if (SetThreadToken(hThread, hDupToken) == false)
{
// Error handling
return;
}
ResumeThread(hThread);
I cannot garantee that this will resolve your problem, but I hope it does. Good luck!

PsGetContextThread returning C0000005(ACCESS_VIOLATION)

I'm trying to use an undocumented function called PsGetContextThread to retrieve the context of a usermode thread from a driver, I know this is possible from usermode but I have my reasons to do this from the kernel and this is not negotiable so please do not sidetrack into that. Now back on topic, the code below when debugged contains a valid thread and everything looks good to me, but it returns invalid with error code C0000005 which is ACCESS_VIOLATION but I do not know how this code could trigger that and would love some help to figure this out as I have been stuck for quite a while on this.
NTSTATUS GetThreadContext(PETHREAD thread) {
KPROCESSOR_MODE mode = UserMode;
CONTEXT context;
UNICODE_STRING setContextString, getContextString;
pPsGetContextThread PsGetContextThread;
NTSTATUS status = STATUS_SUCCESS;
RtlInitUnicodeString(&getContextString, L"PsGetContextThread");
RtlZeroMemory(&context, sizeof(CONTEXT));
PsGetContextThread = (pPsGetContextThread)MmGetSystemRoutineAddress(&getContextString);
context.ContextFlags = CONTEXT_FULL;
status = PsGetContextThread(thread, &context, mode);
if (!NT_SUCCESS(status)) {
return STATUS_UNSUCCESSFUL;
}
return STATUS_SUCCESS;
}
If anyone knows what to try next or got any suggestions please do post below.
yes, #HarryJohnston right that when we specifying UserMode PsGetContextThread check that &context is a valid user-mode pointer. so we need pass valid user mode pointer for this. we can get it by call ZwAllocateVirtualMemory - use this code - this is works
NTSTATUS GetThreadContext(PETHREAD thread, PCONTEXT ctx)
{
#if 0
typedef NTSTATUS (NTAPI* GETSETCONTEXTTHREAD)(PETHREAD, PCONTEXT,MODE);
static GETSETCONTEXTTHREAD PsGetContextThread;
static BOOLEAN bInit;
if (!bInit)
{
STATIC_UNICODE_STRING(aPsGetContextThread, "PsGetContextThread");
PsGetContextThread = (GETSETCONTEXTTHREAD)MmGetSystemRoutineAddress(&aPsGetContextThread);
bInit = TRUE;
}
if (!PsGetContextThread)
{
return STATUS_PROCEDURE_NOT_FOUND;
}
#endif
CONTEXT * BaseAddress = 0;
SIZE_T Size = sizeof(CONTEXT);
NTSTATUS status = ZwAllocateVirtualMemory(NtCurrentProcess(), (void**)&BaseAddress, 0, &Size, MEM_COMMIT, PAGE_READWRITE);
if (0 <= status)
{
BaseAddress->ContextFlags = ctx->ContextFlags;
if (0 <= (status = PsGetContextThread(thread, BaseAddress, UserMode)))
{
memcpy(ctx, BaseAddress, sizeof(CONTEXT));
}
ZwFreeVirtualMemory(NtCurrentProcess(), (void**)&BaseAddress, &Size, MEM_RELEASE);
}
return status;
}
and think you not need use MmGetSystemRoutineAddress but static import PsGetContextThread, but if you anyway want get this pointer in runtime - not need do this every time - but only once. make pointer to function static
You confused the third parameter - it does not state whether you fetch User mode thread context or Kernel mode thread context, it only implies whether the original call was made from User or Kernel mode. As such you don't need to call the function with user mode and copy data from user to kernel. Simply call it with KernelMode and use kernel memory.
NTSTATUS GetThreadContext(PETHREAD thread, PCONTEXT ctx)
{
#if 0
typedef NTSTATUS (NTAPI* GETSETCONTEXTTHREAD)(PETHREAD, PCONTEXT,MODE);
static GETSETCONTEXTTHREAD PsGetContextThread = NULL;
if (NULL == PsGetContextThread )
{
STATIC_UNICODE_STRING(aPsGetContextThread, "PsGetContextThread");
PsGetContextThread = (GETSETCONTEXTTHREAD)MmGetSystemRoutineAddress(&aPsGetContextThread);
}
if (NULL == PsGetContextThread)
{
return STATUS_PROCEDURE_NOT_FOUND;
}
#endif
return PsGetContextThread(thread, ctx, KernelMode);
}

Creating an asynchronous "ReadFileMany()" on top of ReadFile()

I'm trying to make a function, ReadFileMany, which imitates ReadFile's interface, which is given a list of (offset, length) pairs to read from, and which reads all portions of the file asynchronously.
I'm doing this inside ReadFileMany by using RegisterWaitForSingleObject to direct a thread pool thread to wait for I/O to complete, so that it can call ReadFile again to read the next portion of the file, etc.
The trouble I'm running into is that I can't seem to be able to mimic a certain behavior of ReadFile.
Specifically, file handles can themselves be used like events, without the need for an event handle:
OVERLAPPED ov = {0};
DWORD nw;
if (ReadFile(hFile, buf, buf_size, &nw, &ov))
{
if (WaitForSingleObject(hFile, INFINITE) == WAIT_OBJECT_0)
{
...
}
}
but of course, if the user waits on a file handle, he might get a notification that an intermediate read has complete, rather than the final read.
So, inside ReadFileMany, I have no choice but to pass an hEvent parameter to ReadFile for all but the last portion.
The question is, is there any way to still allow the user to wait for the file handle to become signaled when all the portions have been read?
At first the answer seems obvious: just avoid passing an event handle when reading the last portion!
That works fine if the read will be successful, but not if there are errors. If ReadFile starts suddenly returning an error on the last read, I will need to set the file handle to a signaled state manually in order to allow the reader to wake up from his potential call to WaitForSingleObject(hFile).
But there seems to be no way to set a file handle to a signaled state without performing actual I/O... so this is where I get stuck: is there any way for me to write this function so that it behaves like ReadFile on the outside, or is it impossible to do it correctly?
Assuming you are trying to read multiple sections of a single file, I would simply allocate an array of OVERLAPPED structures, one for each requested section of the file, kick off all of the ReadFile() calls at one time, and then use WaitForMultipleObjects() to wait for all of the I/Os to finish, eg:
struct sReadInfo
{
OVERLAPPED ov;
LPVOID pBuffer;
DWORD dwNumBytes;
DWORD dwNumBytesRead;
bool bPending;
sReadInfo()
{
memset(&ov, 0, sizeof(OVERLAPPED));
pBuffer = NULL;
dwNumBytes = 0;
dwNumBytesRead = 0;
bPending = false;
ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!ov.hEvent) throw std::exception();
}
~sReadInfo()
{
CloseHandle(hEvent);
}
};
.
bool error = false;
try
{
std::vector<sReadInfo> ri(numSections);
std::vector<HANDLE> h;
h.reserve(numSections);
for(int i = 0; i < numSections; ++i)
{
ULARGE_INTEGER ul;
ul.QuadPart = ...; // desired file offset to read from
sReadInfo *r = &ri[i];
r->ov.Offset = ul.LowPart;
r->ov.OffsetHigh = ul.HighPart;
r->pBuffer = ...; // desired buffer to read into
r->dwNumBytes = ...; // desired number of bytes to read
if (!ReadFile(hFile, r->pBuffer, r->dwNumBytes, &r->dwNumBytesRead, &r->ov))
{
if (GetLastError() != ERROR_IO_PENDING)
throw std::exception();
r->bPending = true;
h.push_back(r->ov.hEvent);
}
}
if (!h.empty())
{
if (WaitForMultipleObjects(h.size(), &h[0], TRUE, INFINITE) != WAIT_OBJECT_0)
throw std::exception();
}
for (int i = 0; i < numSections; ++i)
{
sReadInfo *r = &ri[i];
if (r->bPending)
GetOverlappedResult(hFile, &r->ov, &r->dwNumBytesRead, FALSE);
// ...
}
}
catch (const std::exception &)
{
CancelIo(hFile);
return false;
}
return true;

Suspend/Resume all user processes - Is that possible?

I have PC's with a lot of applications running at once, i was thinking is it possible to SUSPEND all applications, i want to do that to run periodically one other application that is using a lot the CPU so want it to have all the processor time.
The thing is i want to suspend all applications run my thing that uses the CPU a lot, then when my thingy exit, to resume all applications and all work to be resumed fine....
Any comments are welcome.
It's possible but not recommended at all.
Set the process and thread priority so your application will be given a larger slice of the CPU.
This also means it won't kill the desktop, any network connections, antivirus, start menu, the window manager, etc as your method will.
You could possibly keep a list that you yourself manually generate of programs that are too demanding (say, for (bad) example, Steam.exe, chrome.exe, 90GB-video-game.exe, etc). Basically, you get the entire list of all running processes, search that list for all of the blacklisted names, and NtSuspendProcess/NtResumeProcess (should you need to allow it to run again in the future).
I don't believe suspending all user processes is a good idea. Much of those are weirdly protected and probably should remain running, anyway, and it's an uphill battle with very little to gain.
As mentioned in another answer, you can of course just adjust your processes priority up if you have permission to do so. This sorts the OS-wide process list in favor of your process, so you get CPU time first.
Here's an example of something similar to your original request. I'm writing a program in C++ that needed this exact feature, so I figured I'd help out. This will find Steam.exe or chrome.exe, and suspend the first one it finds for 10 seconds.. then will resume it. This will show as "not responding" on Windows if you try to interact with the window whilst it's suspended. Some applications may not like being suspended, YMMV.
/*Find, suspend, resume Win32 C++
*Written by jimmio92. No rights reserved. Public domain.
*NO WARRANTY! NO LIABILITY! (obviously)
*/
#include <windows.h>
#include <psapi.h>
typedef LONG (NTAPI *NtSuspendProcess)(IN HANDLE ProcessHandle);
typedef LONG (NTAPI *NtResumeProcess)(IN HANDLE ProcessHandle);
NtSuspendProcess dSuspendProcess = nullptr;
NtResumeProcess dResumeProcess = nullptr;
int get_the_pid() {
DWORD procs[4096], bytes;
int out = -1;
if(!EnumProcesses(procs, sizeof(procs), &bytes)) {
return -1;
}
for(size_t i = 0; i < bytes/sizeof(DWORD); ++i) {
TCHAR name[MAX_PATH] = "";
HMODULE mod;
HANDLE p = nullptr;
bool found = false;
p = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, procs[i]);
if(p == nullptr)
continue;
DWORD unused_bytes_for_all_modules = 0;
if(EnumProcessModules(p, &mod, sizeof(mod), &unused_bytes_for_all_modules)) {
GetModuleBaseName(p, mod, name, sizeof(name));
//change this to use an array of names or whatever fits your need better
if(strcmp(name, "Steam.exe") == 0 || strcmp(name, "chrome.exe") == 0) {
out = procs[i];
found = true;
}
}
CloseHandle(p);
if(found) break;
}
return out;
}
void suspend_process_by_id(int pid) {
HANDLE h = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
if(h == nullptr)
return;
dSuspendProcess(h);
CloseHandle(h);
}
void resume_process_by_id(int pid) {
HANDLE h = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
if(h == nullptr)
return;
dResumeProcess(h);
CloseHandle(h);
}
void init() {
//load NtSuspendProcess from ntdll.dll
HMODULE ntmod = GetModuleHandle("ntdll");
dSuspendProcess = (NtSuspendProcess)GetProcAddress(ntmod, "NtSuspendProcess");
dResumeProcess = (NtResumeProcess)GetProcAddress(ntmod, "NtResumeProcess");
}
int main() {
init();
int pid = get_the_pid();
if(pid < 0) {
printf("Steam.exe and chrome.exe not found");
}
suspend_process_by_id(pid);
//wait ten seconds for demonstration purposes
Sleep(10000);
resume_process_by_id(pid);
return 0;
}

Resources