GetThreadContext returning error 6, Invalid Handle? - c++

#include <iostream>
#include <Windows.h>
using std::cout;
using std::endl;
using std::cin;
int main()
{
cout << "1." << GetLastError() << endl;
PROCESS_INFORMATION processInfo;
STARTUPINFOA startupInfo = {0};
CONTEXT context;
context.ContextFlags = CONTEXT_FULL;
cout << "3." << GetLastError() << endl;
if (CreateProcess((PCHAR)"rsclient.exe", NULL, NULL, NULL, false, CREATE_SUSPENDED, NULL, NULL, &startupInfo, &processInfo) == false) {
cout << "CreateProcess error: " << GetLastError() << endl;
}
cout << "4." << GetLastError() << endl;
if (GetThreadContext(processInfo.hProcess, &context) == false) {
cout << "GetThreadContext error:" << GetLastError() << endl;
}
return 0;
}
output:
1.2
3.2
4.1813
GetThreadContext error:6
I can see the suspended process in task manager yet I'm getting an invalid handle error?
Also why does GetLastError() give an ERROR_FILE_NOT_FOUND at the start of the program?

You should use processInfo.hThread as that is the handle to the primary thread of the new process. processInfo.hProcess is a process handle, not a thread handle.
As for GetLastError() returning ERROR_FILE_NOT_FOUND, presumably someone else called an API that called SetLastError(ERROR_FILE_NOT_FOUND). From the documentation of GetLastError():
Return value
The return value is the calling thread's last-error code.
The Return Value section of the documentation for each function that
sets the last-error code notes the conditions under which the function
sets the last-error code. Most functions that set the thread's
last-error code set it when they fail. However, some functions also
set the last-error code when they succeed. If the function is not
documented to set the last-error code, the value returned by this
function is simply the most recent last-error code to have been set;
some functions set the last-error code to 0 on success and others do
not.

As you are calling GetThreadContext with process id as input, so Windows is not able to find any such kind of thread, so returning ERROR_FILE_NOT_FOUND. Better you give the main thread of newly created process and you will get the desired result.

Related

GetProcessId doesn't find any process

I'm using the following code to try to get the PID of notepad.exe, but it doesn't find the process.
I'm currently running on Windows 10 and compiling using VS Studio 19 as Release x64.
Also tried to find other processes, like chrome.exe, calculator.exe, etc, but couldn't find anything.
DWORD GetProcessId(LPCTSTR ProcessName)
{
PROCESSENTRY32 pt;
HANDLE hsnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
std::wcout << "Error: " << GetLastError() << std::endl; // Error: 0
pt.dwSize = sizeof(PROCESSENTRY32);
std::wcout << "Error: " << GetLastError() << std::endl; // Error: 0
if (Process32First(hsnap, &pt)) { // must call this first
do {
if (!lstrcmpi(pt.szExeFile, ProcessName)) {
CloseHandle(hsnap);
return pt.th32ProcessID;
}
} while (Process32Next(hsnap, &pt));
}
std::wcout << "Error: " << GetLastError() << std::endl; // Error: 24
CloseHandle(hsnap); // close handle on failure
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
DWORD processId;
processId = GetProcessId(TEXT("notepad.exe"));
std::wcout << "processId: " << processId << std::endl;
return 0;
}
While debugging, I see the code is skipping the do while and jumping directly to CloseHandle(hsnap)
GetLastError() returns 24 at this line.
The image you posted of your debug output window shows pt.dwSize is set to 2168. This looks wrong. pt.dwSize is important, it used by Windows for version control.
On my computer sizeof(PROCESSENTRY32) is 556 (it depends on Windows version, I am using Windows 10). If project is not Unicode, the size should about half that. In VS, you can right click on PROCESSENTRY32 and it takes you to this definition:
typedef struct tagPROCESSENTRY32W
{
DWORD dwSize;
DWORD cntUsage;
DWORD th32ProcessID; // this process
ULONG_PTR th32DefaultHeapID;
DWORD th32ModuleID; // associated exe
DWORD cntThreads;
DWORD th32ParentProcessID; // this process's parent process
LONG pcPriClassBase; // Base priority of process's threads
DWORD dwFlags;
WCHAR szExeFile[MAX_PATH]; // Path
} PROCESSENTRY32W;
MAX_PATH should be 260. My guess is that you have redefined MAX_PATH or you have put the wrong #pragma statement somewhere. Or there is something weird happening. Try restarting Windows (use Restart instead of shutdown/start)
Also, zero the memory with PROCESSENTRY32 pt = {0}
PROCESSENTRY32 pt = { 0 };
pt.dwSize = sizeof(PROCESSENTRY32);
if (!Process32First(hsnap, &pt))
{
DWORD err = GetLastError();
std::cout << "Process32First failed\n";
std::cout << pt.dwSize << " GetLastError : " << err << "\n";
CloseHandle(hsnap);
return DWORD(-1);
}
The only expected GetLastError is ERROR_NO_MORE_FILES as shown in Windows documentation. If the error is something else, it means the function has totally failed.
If your project is Unicode, as it should be, consider avoiding those T macros. Just use GetProcessId(L"notepad.exe"); and LPCWSTR etc.
Ps, I ran your code and it was fine in my computer. The only difference was sizeof(PROCESSENTRY32)

In c++'s SetWindowsHookEx function

I'm Korean student.
Now this is my first question after signing up.
DWORD getProcessId() {
PROCESSENTRY32 process_infor;
process_infor.dwSize = sizeof(PROCESSENTRY32);
HANDLE snap_handle = CreateToolhelp32Snapshot(
TH32CS_SNAPALL, //스냅 단계
NULL //스냅할 pid
);
if (snap_handle != INVALID_HANDLE_VALUE) {
Process32First(snap_handle, &process_infor);
do {
wchar_t* temp = process_infor.szExeFile;
wstring ws(temp);
string name(ws.begin(), ws.end());
if (name == "notepad.exe") {
cout << name << " : " << process_infor.th32ProcessID << endl;
return process_infor.th32ProcessID;
}
} while (Process32Next(snap_handle, &process_infor));
}
CloseHandle(snap_handle);
return FALSE;
}
BOOL inject() {
HMODULE dll_handle;
HOOKPROC func;
HHOOK process_hook;
dll_handle = LoadLibrary(L"hello.dll");
func = (HOOKPROC) GetProcAddress(dll_handle, "injectSuccess");
cout << "handle : " << dll_handle << endl;
cout << "pid : " << getProcessId() << endl;
process_hook = SetWindowsHookEx(
WH_KEYBOARD,
func,
dll_handle,
getProcessId()
);
cout << "pook : " << process_hook << endl;
cout << "err : " << GetLastError() << endl;
FreeLibrary(dll_handle);
return FALSE;
}
There seems to be a problem with SetWindowsHookEx of the inject function in this case. The dll file loads well, and the injectSuccess function inside is well fetched. (I tried running it, but it worked)
And I wondered if the argument values ​​of SetWindowsHookEx were entered incorrectly, so I compared them and checked them continuously, but I couldn't find any difference. So, I tried GetLastError() with the return value of SetWindowsHookEx below, but the return value is 0 and the error code is 87 ("the parameter is incorrect").
So I searched, but I can't speak English well and I'm a beginner, so I'm not sure.
According to the SetWindowsHookExW:
dwThreadId
A handle to the DLL containing the hook procedure pointed to by the lpfn parameter. The hMod parameter must be set to NULL if the dwThreadId parameter specifies a thread created by the current process and if the hook procedure is within the code associated with the current process.
So what SetWindowsHookExW needs is the thread ID, and you pass in the process ID of notepad.exe, so the parameter is wrong.
I creat a sample and test the following code:
BOOL inject() {
HMODULE dll_handle;
HOOKPROC func;
HHOOK process_hook;
dll_handle = LoadLibrary(L"hello.dll");
if (dll_handle) func = (HOOKPROC)GetProcAddress(dll_handle, "injectSuccess");
else return FALSE;
cout << "handle : " << dll_handle << endl;
cout << "pid : " << getProcessId() << endl;
HWND h = FindWindow(L"notepad", NULL);
DWORD pid;
threadID = GetWindowThreadProcessId(h, NULL);
cout << "threadID = " << threadID << endl;
process_hook = SetWindowsHookEx(
WH_KEYBOARD,
func,
dll_handle,
threadID
);
cout << "pook : " << process_hook << endl;
cout << "err : " << GetLastError() << endl;
if(dll_handle) FreeLibrary(dll_handle);
return FALSE;
}
This example worked for me, and you can see the difference between pid and threadID:
Edit
According to the document:
An application installs the hook procedure by specifying the
WH_KEYBOARD hook type and a pointer to the hook procedure in a call to
the SetWindowsHookEx function. This hook may be called in the context
of the thread that installed it. The call is made by sending a message
to the thread that installed the hook. Therefore, the thread that
installed the hook must have a message loop. So if you want to run
this func, you need to add a message loop.
You can refer to the following code:
int main()
{
inject();
MSG msg;
while (GetMessageW(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
}
When you press the button, the message box will pop up:
Because there are two messages for each key press and release, func is triggered twice each time.If you only want to trigger every time a button is pressed, you can modify the following code:
if ((0x80000000 & lParam) == 0)//This means that when the key is pressed
{
MessageBox(NULL, L"Success (dll injection)", L"Window", MB_OK);
}
You can refer to KeyboardProc to view the messages for each value in lParam.

How to get the returned exit value of an invoked program to store it internally? [duplicate]

This question already has an answer here:
checking the return value of a command executed using CreateProcess
(1 answer)
Closed 2 years ago.
This question is related to a previously asked question found here:
I'm able to invoke another executable within my runProgram() function. However, before this runProgram() function returns back to main() and closes the handle for the process. I need to retrieve the value that the executable returns when it exits...
Here is my current application:
#include <Windows.h>
#include <exception>
#include <stdio.h>
#include <tchar.h>
#include <cstdint>
#include <iostream>
uint32_t runProgram(LPCSTR lpApplicationName) {
STARTUPINFOA si;
PROCESS_INFORMATION pi;
// Set the size of the structures
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
// Run the program
CreateProcessA(
lpApplicationName, // the path
NULL, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
CREATE_NEW_CONSOLE, // Opens file in seperate console
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi // Pointer to PROCESS_INFORMATION structure
);
uint32_t error = GetLastError();
if ( error != 0)
std::cerr << error << "\n";
// How to retrieve and store the result from the exiting program above...?
uint32_t cache_size = 0;
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return cache_size;
}
int main() {
try {
const uint32_t cache_size = runProgram("CacheQuerry.exe");
std::cout << cache_size << '\n';
}
catch (const std::exception& e) {
std::cerr << e.what() << "\n\n";
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
And I want to store the return value from this executable into runProgram()'s local variable: cache_size.
Here is the main.cpp from the invoked program:
#include "CacheQuerry.h"
int main() {
int error = cache_info();
if (error != 0)
std::cout << error << '\n';
else
std::cout << '\n';
std::cout << "l1d_cache_size = " << l1d_cache_size() << std::endl;
std::cout << "cache line size = " << cache_line_size() << '\n';
return l1d_cache_size();
}
The invoked program will return the value produced by l1d_cache_size() when this program exits. This is the value that I want to store within runProgram()'s cache_size variable. How do I get this return value after the program exits? The implementation of the function call found in "CacheQuerry.h" shouldn't be relevant here, but if you need to see it's implementation don't hesitate to ask. These are two separate projects within the same solution. The 1st main.cpp which is in its own project relies on the 2nd main.cpp within its own project.
You can get it by calling GetExitCodeProcess (pi.hProcess), after waiting on the handle but before you close it.
The exact code you need is:
DWORD exit_code;
BOOL ok = GetExitCodeProcess (pi.hProcess, &exit_code);
Strange this is not mentioned in the Remarks section for CreateProcess at all.

Exceptions constantly thrown when launching app with my custom WINAPI Debugger

I'm in the process of experimenting with creating my own custom debugger with C++ in Visual Studio 2017. Testing a few console applications it is fine. However when I launch notepad with it, it is OK until I hit File -> Open dialog and it goes into constant loop with output these two exceptions code and the open dialog box doesn't open:
Exception: 3221356611
Exception: 998
When same process was launched under WinDbg these exceptions didn't occur.
The code is compiled as x86 and launching 32-bit process on Windows 10 1803 build 17134.523 x64.
Any suggestions on what might cause these?
#include "targetver.h"
#include <stdio.h>
#include <tchar.h>
#include <string>
#include <iostream>
#include <map>
std::map < LPVOID, std::wstring > DllNameMap;
int main()
{
std::wstring filename(L"c:\\windows\\syswow64\\notepad.exe");
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
DEBUG_EVENT debugEvent;
// Start the child process.
if (!CreateProcess(NULL, // No module name (use command line)
(LPWSTR)filename.c_str(), // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
CREATE_SUSPENDED, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi) // Pointer to PROCESS_INFORMATION structure
)
{
printf("CreateProcess failed (%d).\n", GetLastError());
return -1;
}
if (DebugActiveProcess(pi.dwProcessId))
{
ResumeThread(pi.hThread);
std::cout << "Debugger attached!" << std::endl;
EnterDebugLoop(&debugEvent,pi.hProcess);
}
return 0;
}
void EnterDebugLoop(const LPDEBUG_EVENT DebugEv,HANDLE hProcess)
{
DWORD dwContinueStatus = DBG_CONTINUE; // exception continuation
for (;;)
{
// Wait for a debugging event to occur. The second parameter indicates
// that the function does not return until a debugging event occurs.
WaitForDebugEvent(DebugEv, INFINITE);
// Process the debugging event code.
switch (DebugEv->dwDebugEventCode)
{
case EXCEPTION_DEBUG_EVENT:
// Process the exception code. When handling
// exceptions, remember to set the continuation
// status parameter (dwContinueStatus). This value
// is used by the ContinueDebugEvent function.
std::cout << "Exception: " << DebugEv->u.Exception.ExceptionRecord.ExceptionCode << std::endl;
switch (DebugEv->u.Exception.ExceptionRecord.ExceptionCode)
{
case EXCEPTION_ACCESS_VIOLATION:
std::cout << "ACCESS VIOLATION" << std::endl;
// First chance: Pass this on to the system.
// Last chance: Display an appropriate error.
break;
case EXCEPTION_BREAKPOINT:
std::cout << "BREAKPOINT" << std::endl;
// First chance: Display the current
// instruction and register values.
break;
case EXCEPTION_DATATYPE_MISALIGNMENT:
std::cout << "DATATYPE MISALIGNMENT" << std::endl;
// First chance: Pass this on to the system.
// Last chance: Display an appropriate error.
break;
case EXCEPTION_SINGLE_STEP:
std::cout << "SINGLE STEP" << std::endl;
// First chance: Update the display of the
// current instruction and register values.
break;
case DBG_CONTROL_C:
std::cout << "CTRL+C" << std::endl;
// First chance: Pass this on to the system.
// Last chance: Display an appropriate error.
break;
default:
// Handle other exceptions.
break;
}
break;
case CREATE_THREAD_DEBUG_EVENT:
std::cout << "Create Thread" << std::endl;
// As needed, examine or change the thread's registers
// with the GetThreadContext and SetThreadContext functions;
// and suspend and resume thread execution with the
// SuspendThread and ResumeThread functions.
break;
case CREATE_PROCESS_DEBUG_EVENT:
std::cout << "Create Process" << std::endl;
// As needed, examine or change the registers of the
// process's initial thread with the GetThreadContext and
// SetThreadContext functions; read from and write to the
// process's virtual memory with the ReadProcessMemory and
// WriteProcessMemory functions; and suspend and resume
// thread execution with the SuspendThread and ResumeThread
// functions. Be sure to close the handle to the process image
// file with CloseHandle.
//dwContinueStatus = OnCreateProcessDebugEvent(DebugEv);
break;
case EXIT_THREAD_DEBUG_EVENT:
// Display the thread's exit code.
std::cout << "Exit Thread Exit Code " << DebugEv->u.ExitThread.dwExitCode << std::endl;
//dwContinueStatus = OnExitThreadDebugEvent(DebugEv);
break;
case EXIT_PROCESS_DEBUG_EVENT:
// Display the process's exit code.
std::cout << "Exit process Exit Code " << DebugEv->u.ExitProcess.dwExitCode << std::endl;
///dwContinueStatus = OnExitProcessDebugEvent(DebugEv);
break;
case LOAD_DLL_DEBUG_EVENT:
{
PVOID pDllPath = NULL;
PUCHAR DllPath[(MAX_PATH + 1) * sizeof(WCHAR)];
DWORD dwLen = 0;
ZeroMemory(DllPath, sizeof(DllPath));
if (DebugEv->u.LoadDll.lpImageName == NULL)
{
break;
}
// read DLL name pointer value
if (ReadProcessMemory(
hProcess,
DebugEv->u.LoadDll.lpImageName,
&pDllPath, sizeof(PVOID),
&dwLen) && pDllPath)
{
dwLen = (DebugEv->u.LoadDll.fUnicode ? MAX_PATH * sizeof(WCHAR) : MAX_PATH);
// read DLL name
if (ReadProcessMemory(
hProcess,
pDllPath,
DllPath, dwLen,
&dwLen))
{
char szDllPath[MAX_PATH], *lpszDllName = NULL;
if (DebugEv->u.LoadDll.fUnicode)
{
std::wstring path((wchar_t*)DllPath);
DllNameMap.insert(std::make_pair(DebugEv->u.LoadDll.lpBaseOfDll, path));
std::wcout << "Image loaded (Unicode): " << path.c_str() << std::endl;
}
else
{
// todo: Add to DllNameMAp
std::wcout << "Image loaded: " << DllPath << std::endl;
}
}
else
{
std::cout << "Error processing memory : " << GetLastError() << std::endl;
}
}
else
{
std::wcout << "ERROR reading process memory : " << GetLastError() << std::endl;
}
}
// Read the debugging information included in the newly
// loaded DLL. Be sure to close the handle to the loaded DLL
// with CloseHandle.
///dwContinueStatus = OnLoadDllDebugEvent(DebugEv);
break;
case UNLOAD_DLL_DEBUG_EVENT:
std::wcout << "Unload DLL: " << DllNameMap[DebugEv->u.UnloadDll.lpBaseOfDll] << std::endl;
break;
case OUTPUT_DEBUG_STRING_EVENT:
// Display the output debugging string.
std::wcout << "Debug Event" << std::endl;
if (DebugEv->u.DebugString.fUnicode)
{
std::wcout << (wchar_t)DebugEv->u.DebugString.lpDebugStringData << std::endl;
}
//dwContinueStatus = OnOutputDebugStringEvent(DebugEv);
break;
case RIP_EVENT:
//dwContinueStatus = OnRipEvent(DebugEv);
break;
}
// Resume executing the thread that reported the debugging event.
ContinueDebugEvent(DebugEv->dwProcessId,
DebugEv->dwThreadId,
dwContinueStatus);
}
}
3221356611 this is 0xC0020043 - RPC_NT_INTERNAL_ERROR
998 this is 0x3e6 - ERROR_NOACCESS (Invalid access to memory
location)
your main error that you unconditionally return DBG_CONTINUE always. but on EXCEPTION_DEBUG_EVENT you mast return this code only if you handle exception. otherwise (and if dwFirstChance == TRUE so this is first chance exception) you must return DBG_EXCEPTION_NOT_HANDLED. if you return DBG_CONTINUE - the program begin continue execute from current context. if you return DBG_EXCEPTION_NOT_HANDLED - the KiUserExceptionDispatcher will be called in target process, which call RtlDispatchException and where will be called exception handlers. read more - Structured Exception Handling
but because you never return DBG_EXCEPTION_NOT_HANDLED - program exception handlers never called. by your 2 exceptions codes even easy locate place, where this happens:
the RpcpRaiseException is called, which internal call RaiseException(ERROR_NOACCESS..) so you view 998 exception. if you return DBG_EXCEPTION_NOT_HANDLED here - application byself handle this exception and never return from RaiseException call. context will be swithched to __except{} block. but because you return DBG_CONTINUE - the RaiseException return control and RpcReportFatalError called, which internal call RaiseException(RPC_NT_INTERNAL_ERROR..) so you and view 3221356611 (0xC0020043)
your next error that you not close hFile on LOAD_DLL_DEBUG_EVENT - When the debugger is finished with this file, it should close the handle using the CloseHandle function. the same error on CREATE_PROCESS_DEBUG_EVENT
also your error in how you begin debug process - you must not use CREATE_SUSPENDED flag, must not use DebugActiveProcess and ResumeThread. you need only set DEBUG_PROCESS or DEBUG_ONLY_THIS_PROCESS and all. not need create process in suspended state and main not call DebugActiveProcess here. this api call is bad designed, it create additional thread in target process. for say xp at this stage this at all was fatal.

Why do I need to acquire the debug privilege to use OpenProcess with minimal permissions when running as an admin?

One of my programs attempts to call OpenProcess on another of my programs, which is a service. The first program is running either as the local Administrator account or as another member of the Administrators group, and the service is running as the SYSTEM user.
I've found that in at least one environment (but not all) the call to OpenProcess fails with ERROR_ACCESS_DENIED. Furthermore, I've found that if I use AdjustTokenPrivileges to acquire the SE_DEBUG_NAME privilege, then OpenProcess succeeds. I've reproduced the behavior using the program below. The environment where it fails is running Windows 8.1, but off hand I don't know what the successful systems are running.
The only permission the program requests is PROCESS_QUERY_LIMITED_INFORMATION (because it eventually calls QueryFullProcessImageName). Nothing I've read suggests that debug privileges are required for that, only for more "intrusive" access like PROCESS_VM_READ or PROCESS_ALL_ACCESS, which I'm not interested in.
I've read about protected processes, and even though the service I'm targeting isn't designated as a protected process, documentation says that PROCESS_QUERY_LIMITED_INFORMATION isn't among the permissions that are forbidden from being granted for protected processes anyway.
Why would the original call to OpenProcess fail, and why does the debugging privilege make a difference?
#include <Windows.h>
#include <iostream>
#include <sstream>
#include <string>
int main(int argc, char* argv[])
{
std::istringstream pid_s(argv[1]);
DWORD pid;
pid_s >> pid;
bool debug = !!argv[2];
if (debug) {
TOKEN_PRIVILEGES NewState;
NewState.PrivilegeCount = 1;
if (!LookupPrivilegeValue(nullptr, SE_DEBUG_NAME, &NewState.Privileges[0].Luid)) {
std::clog << "Could not acquire debug-privilege name: " << GetLastError() << "\n";
return EXIT_FAILURE;
}
HANDLE token;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token)) {
std::clog << "Could not acquire process token: " << GetLastError() << "\n";
return EXIT_FAILURE;
}
NewState.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (!AdjustTokenPrivileges(token, FALSE, &NewState, sizeof(NewState), nullptr, nullptr)) {
std::clog << "Could not enable debug privilege: " << GetLastError() << "\n";
return EXIT_FAILURE;
}
std::clog << "Acquired debug privilege\n";
} else {
std::clog << "Not acquiring debug privilege\n";
}
HANDLE proc = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, false, pid);
if (proc) {
std::clog << "Acquired process handle\n";
CloseHandle(proc);
return EXIT_SUCCESS;
} else {
std::clog << "Failed to acquire process handle: " << GetLastError();
return EXIT_FAILURE;
}
}