Methods to run code after a Windows process is gracefully closing? - c

I'm curious if there are methods to run code after the main() program has closed?
So far, I've found atexit()
int atexit( void (*func)(void) );
Registers the function pointed to by func to be called on normal
program termination (via exit() or returning from main()). The
functions will be called in reverse order they were registered, i.e.
the function registered last will be executed first.
For example, Chrome browser with pid 358440 calls the injected atexit(). Closing the browser normally launches the Windows calculator. Perhaps there are less intrusive ways?
Bunny.c
// Windows x86-64: Create a remote thread to run atexit().
// Configuration: MSVC 2019 Debug x64.
#include <Windows.h>
#include <stdio.h>
#include <stdint.h>
#include <intrin.h>
typedef uint64_t QWORD;
typedef void (*funcPtr)(void);
typedef void (*AtexitPtr)(funcPtr);
// ------------------------------------------------------------
#define kExitFunctionAddress_offset 16
#define kWinExecAddress_offset 30
#define kAtExitAddress_offset 44
#define kRunAtexit_offset 58
// ------------------------------------------------------------
DWORD WINAPI start_of_function_code(void)
{
// ------------------------------------------------------------
QWORD kExitFunctionAddress = 0xDEADBEEFBAADF00D;
QWORD kWinExecAddress = 0xDEADBEEFBAADF00D;
QWORD kAtExitAddress = 0xDEADBEEFBAADF00D;
QWORD kRunAtexit = 0xDEADBEEFBAADF00D;
// ------------------------------------------------------------
if (kRunAtexit)
{
AtexitPtr atexit_ptr = (AtexitPtr)kAtExitAddress;
atexit_ptr((funcPtr)kExitFunctionAddress);
}
else
{
const char kCalculator[] = { 'c','a','l','c','.','e','x','e','\0' };
((FARPROC(WINAPI*)(LPCSTR, UINT))(kWinExecAddress))(kCalculator, SW_SHOW);
}
return 0;
}
int main(int argc, char* argv[])
{
DWORD targetPID;
HANDLE hTargetProc;
LPTHREAD_START_ROUTINE pfnThreadRoutine;
HANDLE hRemoteThread;
DWORD sizeoffunccode;
QWORD onoff = 0;
BYTE RETURN_OPCODE = 0xC3;
// Get the target PID
if (argc < 2) {
printf("Usage: %s <target PID>\n", argv[0]);
return 1;
}
targetPID = atoi(argv[1]);
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, targetPID);
if (hProcess == NULL)
{
printf("[+] Invalid PID %d\n", targetPID);
exit(1);
}
CloseHandle(hProcess);
// Get Function Code Size
BYTE* end_of_function_code = (BYTE*)start_of_function_code;
while (*end_of_function_code++ != RETURN_OPCODE) {};
sizeoffunccode = (DWORD)(end_of_function_code - (BYTE*)start_of_function_code);
printf("[+] Function Size %d bytes\n", sizeoffunccode);
// Get function addresses for Winexec() and atexit()
HMODULE kernel32 = LoadLibrary("Kernel32.dll");
FARPROC winexec = GetProcAddress(kernel32, "WinExec");
printf("[+] Winexec() Address %p\n", winexec);
HMODULE msvcrt = LoadLibrary("msvcrt.dll");
FARPROC atexit = GetProcAddress(msvcrt, "atexit");
printf("[+] atexit() Address %p\n", atexit);
// Write the thread function to the target process
hTargetProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, targetPID);
pfnThreadRoutine = (LPTHREAD_START_ROUTINE)VirtualAllocEx(hTargetProc, NULL, sizeoffunccode, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
WriteProcessMemory(hTargetProc, pfnThreadRoutine, (BYTE*)start_of_function_code, sizeoffunccode, NULL);
WriteProcessMemory(hTargetProc, (BYTE*)pfnThreadRoutine + kExitFunctionAddress_offset, &pfnThreadRoutine, sizeof(pfnThreadRoutine), NULL);
WriteProcessMemory(hTargetProc, (BYTE*)pfnThreadRoutine + kWinExecAddress_offset, &winexec, sizeof(winexec), NULL);
WriteProcessMemory(hTargetProc, (BYTE*)pfnThreadRoutine + kAtExitAddress_offset, &atexit, sizeof(atexit), NULL);
printf("[+] Function Address %p (PID: %d)\n", pfnThreadRoutine, targetPID);
// Create the remote thread and call atexit()
hRemoteThread = CreateRemoteThread(hTargetProc, NULL, 0, pfnThreadRoutine, NULL, 0, NULL);
WaitForSingleObject(hRemoteThread, INFINITE);
printf("[+] atexit() Executed\n");
// Toggle condition so WinExec() is called upon process exit
WriteProcessMemory(hTargetProc, (BYTE*)pfnThreadRoutine + kRunAtexit_offset, &onoff, sizeof(onoff), NULL);
printf("[+] WinExec() Primed\n");
// Cleanup
CloseHandle(hTargetProc);
CloseHandle(hRemoteThread);
printf("[+] Done.\n");
return 0;
}

Related

GetProcessImageFileNameA "Access violation writing location" runtime error

I'm using the EnumProcesses function to get all process IDs on the system. Then I iterate over each process ID and pass it to OpenProcess to get a process handle, which I then pass to GetProcessImageFileNameA to get the process name.
Here's a code snippet:
#include <stdio.h>
#include <tchar.h>
#include <Windows.h>
#include <Psapi.h>
DWORD GetProcessName(DWORD processID, TCHAR lpFileName, DWORD nSize)
{
HANDLE hProcess;
DWORD pLength;
// Get process handle
hProcess = OpenProcess(
PROCESS_VM_READ | PROCESS_QUERY_INFORMATION,
FALSE,
processID
);
if ( !hProcess )
return NULL;
// Write process name to buffer
if ( pLength = GetProcessImageFileNameA(hProcess, lpFileName, nSize) )
{
CloseHandle(hProcess);
return pLength;
}
CloseHandle(hProcess);
}
int main(void)
{
DWORD processIDs[PROC_ID_SIZE], cbNeeded, cProcess;
unsigned int i;
// Get process IDs
if ( !EnumProcesses(processIDs, sizeof(processIDs), &cbNeeded) )
return 1;
// Get process ID count
cProcess = cbNeeded / sizeof(DWORD);
printf("Number of Processes: %u | Size of Process Array: %d\n", cProcess, (int)sizeof(processIDs));
// Get the process name of each process
for (i = 0; i < cProcess; i++)
{
if ( processIDs[i] != 0 )
{
// The access violation is happening here
TCHAR processName[MAX_PATH];
GetProcessName(processIDs[i], processName, sizeof(processName));
printf("Process name: %s\n", (char*)processName);
}
}
return 0;
}
It compiles fine, but I get this runtime error:
Exception thrown at 0x00007FF985433338 (KernelBase.dll) in QuickSave.exe: 0xC0000005: Access violation writing location 0x000000000000F8D0.
I have a suspicion it's because I'm declaring processName from outside of the function's scope. When I create another function and declare processName within that function's scope, it works. I'm not entirely sure why.
DWORD PrintProcessName(DWORD processID)
{
HANDLE hProcess;
TCHAR processName[MAX_PATH];
DWORD pLength;
// Get process handle
hProcess = OpenProcess(
PROCESS_VM_READ | PROCESS_QUERY_INFORMATION,
FALSE,
processID
);
if (!hProcess)
return NULL;
// Write process name to buffer and print it
if ( pLength = GetProcessImageFileNameA(hProcess, processName, sizeof(processName)) )
{
printf("Process name: %s\n", (char*)processName);
return pLength;
}
CloseHandle(hProcess);
}
I'm still learning C so I'm probably making a newbie mistake, but hopefully someone can help me make sense of what's going on here.
I have fixed your code. The main errors was bad declaration of GetProcessName, wrong size passed for processName size, incorrect printf format specification, function doesn't always return a value, missing error checks.
#include <stdio.h>
#include <tchar.h>
#include <Windows.h>
#include <Psapi.h>
#define PROC_ID_SIZE 1000
DWORD GetProcessName(DWORD processID, TCHAR *lpFileName, DWORD nSize)
{
HANDLE hProcess;
DWORD pLength;
// Get process handle
hProcess = OpenProcess(
PROCESS_QUERY_LIMITED_INFORMATION,
FALSE,
processID
);
if (!hProcess)
return 0;
// Write process name to buffer
pLength = GetProcessImageFileNameW(hProcess, lpFileName, nSize);
CloseHandle(hProcess);
return pLength;
}
int main(void)
{
DWORD processIDs[PROC_ID_SIZE], cbNeeded, cProcess;
unsigned int i;
// Get process IDs
if (!EnumProcesses(processIDs, sizeof(processIDs), &cbNeeded))
return 1;
// Get process ID count
cProcess = cbNeeded / sizeof(DWORD);
printf("Number of Processes: %u | Size of Process Array: %d\n", cProcess, (int)sizeof(processIDs));
// Get the process name of each process
for (i = 0; i < cProcess; i++)
{
if (processIDs[i] != 0)
{
// The access violation is happening here
TCHAR processName[MAX_PATH];
if (GetProcessName(processIDs[i], processName, sizeof(processName)/sizeof(processName[0])))
printf("Process name: %ls\n", processName);
}
}
return 0;
}

CreateRemoteThread, doesn't start a thread

I use this function as usual, but the debug traces (OutputDebugString) don't work from injecting dlls. And in the target application no thread is created (I look through the process hacker)
GetlastError says 0
CreateRemoteThread says tid
but WaitForSingleObject exits immediately (why if all ok!?)
... I'm confused %
OS windows 10 x64
app and dll - x86
code dll is:
#include <stdio.h>
#include <windows.h>
WINAPI DllMain(HINSTANCE h, DWORD reason, LPVOID res)
{
CHAR pszMessage[1024] = { 0 };
sprintf(pszMessage, ("L2Proj: GetCurrentProcessId() %d, hModule 0x%p, nReason %d\r\n"), GetCurrentProcessId(), h, reason);
OutputDebugString(pszMessage);
switch(reason) {
case DLL_PROCESS_ATTACH:
//MessageBoxA(NULL, "inject success", "done", MB_OK);
TerminateProcess(GetCurrentProcess(), -1);
break;
}
return TRUE;
}
PS TerminateProcess in dll doesn't work either
PPS GetExitCodeThread() after WaitForSingleObject ends is 0
What it the problem with?
ADDED
APP code is:
NOTE: This is just test code (no control over return values ​​/ wrong label name codestyle etc.), pls do not tell me about it.
I wrote step by step in the comments which functions return which values
// process of course has access
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, entry.th32ProcessID);
// handle is valid
if(!hProcess) {
return GetLastError();
}
DWORD id;
char str[] = "G:\\workspace\\proj\\test.dll";
void *l = (void*)GetProcAddress(
GetModuleHandle("kernel32.dll"), "LoadLibraryA");
// addr is valid
if(!l) {
return 35;
}
DWORD str_size = strlen(str) + 1;
// memory addr is valid
LPVOID lp = VirtualAllocEx(hProcess, NULL, str_size, MEM_COMMIT |
MEM_RESERVE, PAGE_READWRITE);
BOOL res = WriteProcessMemory(hProcess, lp, str, str_size, NULL);
// res is true
HANDLE h = CreateRemoteThread(hProcess,
NULL,
0,
(LPTHREAD_START_ROUTINE)l,
lp,
0,
&id);
// handle is valid
// id is valid (tid remote thread)
if(!h) {
return GetLastError();
}
DWORD err = GetLastError();
CHAR pszMessage[1024] = { 0 };
sprintf(pszMessage, ("L2Proj: GetProcessId() %d\r\n"), id);
OutputDebugString(pszMessage);
// ends immediately (no waiting)
WaitForSingleObject(h, INFINITE);
GetExitCodeThread(h, &id);
//id is 0 (exit code)
sprintf(pszMessage, ("L2Proj: GetExitCodeThread() %d (GetLastError=%d)\r\n"), id, err);
OutputDebugString(pszMessage);
// the only error after this function (VirtualFreeEx)
// GetLastError gives 87 (0x57) - ERROR_INVALID_PARAMETER
VirtualFreeEx(hProcess, lp, 0, MEM_RELEASE);
CloseHandle(h);
CloseHandle(hProcess);
I forgot, i use g++ (GCC) 9.3.0 - maybe the problem is because of this?
I solved the problem, just change the compiler.
Yes, the problem was with the compiler, everything works fine on the Microsoft compiler.
Thanks for answers.
problem in you not use debugger – RbMm yesterday
and yes, I always use the debugger, thanks a lot ...

Windows DLL injector in C doesn't inject the DLL

I am trying to write a DLL injector to perform a DLL injector on a calculator process.
I wrote the DLL injector program in C and the DLL but the injector dosent inject the DLL or any other DLL (I tried to take some random windows DLL that the calculator doesn't use).
#include <stdio.h>
#include <Windows.h>
int main() {
LPCSTR dllpath = "C:\\Users\\......\\Dll1.dll";
printf("#### Starting ####\n");
printf("step 1: attaching the target process memory\n");
HANDLE hProcess = OpenProcess(
PROCESS_ALL_ACCESS,
FALSE,
6456 // target process id
);
if (hProcess != NULL) {
printf("step 2: allocate the target memory process\n");
LPVOID dllPathMemoryAddr = VirtualAllocEx(
hProcess,
NULL,
strlen(dllpath),
MEM_RESERVE | MEM_COMMIT,
PAGE_EXECUTE_READWRITE
);
if (dllPathMemoryAddr != NULL) {
printf("step 3: write to the process memory\n");
BOOL succeededWriting = WriteProcessMemory(
hProcess,
dllPathMemoryAddr,
dllpath,
strlen(dllpath),
NULL
);
if (succeededWriting) {
printf("step 4: execute.\n");
FARPROC loadLibAddr = GetProcAddress(
GetModuleHandle(TEXT("kernel32.dll")),
"LoadLibraryA"
);
HANDLE rThread = CreateRemoteThread(
hProcess,
NULL,
0,
(LPTHREAD_START_ROUTINE)loadLibAddr,
dllPathMemoryAddr,
0,
NULL
);
}
}
CloseHandle(hProcess);
}
return TRUE;
}
after running the injector I get this output:
#### Starting ####
step 1: attaching the target process memory
step 2: allocate the target memory process
step 3: write to the process memory
step 4: execute.
after that, I am still unable to see in process explorer the new DLL.
You are calling GetProcAddress() to get the address of LoadLibraryA(), this is returning the address of LoadLibraryA in your local process not the injected one. This is not guaranteed to be correct in the external process. You do not need to get the address manually, CreateRemoteThread will resolve the address for you.
Here is a very simple injector example that will explain how to do it
#include <iostream>
#include <Windows.h>
#include <TlHelp32.h>
DWORD GetPid(char * targetProcess)
{
HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (snap && snap != INVALID_HANDLE_VALUE)
{
PROCESSENTRY32 pe;
pe.dwSize = sizeof(pe);
if (Process32First(snap, &pe))
{
do
{
if (!_stricmp(pe.szExeFile, targetProcess))
{
CloseHandle(snap);
return pe.th32ProcessID;
}
} while (Process32Next(snap, &pe));
}
}
return 0;
}
int main()
{
char * dllpath = "C:\\Users\\me\\Desktop\\dll.dll";
char * processToInject = "csgo.exe";
long pid = 0;
while (!pid)
{
pid = GetPid(processToInject);
Sleep(10);
}
HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
if (hProc && hProc != INVALID_HANDLE_VALUE)
{
void * loc = VirtualAllocEx(hProc, 0, MAX_PATH, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
WriteProcessMemory(hProc, loc, dllpath, strlen(dllpath) + 1, 0);
HANDLE hThread = CreateRemoteThread(hProc, 0, 0, (LPTHREAD_START_ROUTINE)LoadLibraryA, loc, 0, 0);
CloseHandle(hThread);
}
CloseHandle(hProc);
return 0;
}
I found the problem. I compiled the DLL as 64 but accidentally compiled the DLL injector has complied as 32 bit.

Getting process id via EnumWindows... Can someone please explain me why this code is working?

I'm trying to get handles of windows. Then I was trying to get associated process id for every handle. But somehow, I'm magically get process_id out of nowhere. Please guide me here.
If I try to initialize process_id using GetWindowThreadProcessId() function, I encounter a runtime error.
However, if I comment out that part of code and let process_id print in both printf() functions, the programs runs successfully, displays data and exits cleanly. It should be garbage value here.
#include <stdio.h>
#include <windows.h>
WNDENUMPROC DisplayData(HWND str, LPARAM p) {
LPDWORD process_id;
DWORD P_ID;
printf("PID :: %x\n", process_id);
//this is where error occurs
//P_ID = GetWindowThreadProcessId(str, process_id);
printf("Found: %x, P_ID: %x\n", str, process_id);
return TRUE;
}
int main() {
EnumWindows( (WNDENUMPROC) DisplayData, 1);
return 0;
}
#include <stdio.h>
#include <windows.h>
LPDWORD target = (LPDWORD) 0; // Replace 0 with PID of the task from taskmgr.
HWND target_handle = NULL; // stores the handle of the target process
WNDENUMPROC DisplayData(HWND str, LPARAM p) {
LPDWORD thread_id;
DWORD process_id;
char title[30];
GetWindowTextA(str, (LPSTR) &title, 29);
process_id = GetWindowThreadProcessId(str, (PDWORD) &thread_id);
if( thread_id == target & IsWindowVisible(str) ) {
// Target thread with associated handle
// printf("Handle Addr: %lu, Thread ID: %lu, Process ID: %lu, Title: %s\n", str, thread_id, process_id, title );
target_handle = str;
}
return TRUE;
}
int main() {
EnumWindows( (WNDENUMPROC) DisplayData, 1);
ShowWindow(target_handle, SW_HIDE);
Sleep(1000);
ShowWindow(target_handle, SW_SHOW);
return 0;
}
The Thread ID shown by this code is the one that is displayed in Task Manager as PID. target_handle variable contains handle address after the execution of EnumWindows() function, just as required.

Does QEMU user mode emulation exit in a way that would prevent pthread_join from blocking?

I'm trying to run QEMU's user mode emulator as a thread in a larger program that I'm writing. I've modified the linux-user/main.c file so that the standard int main(int argc, char **argv, char **envp function is now called void *qemu_user_mode_func(void *arg). I've also added pthread_exit(NULL) to the end of that function, as is standard practice for pthreads (or so I've been told).
However, when I try to run a second thread that contains my own test function (shown below in void *test_func(void *arg)), the process exits before the second thread completes, even with a call to pthread_join(tid), which I've read blocks the calling thread until thread tid returns. Does QEMU's user mode emulation exit in such a way that would prevent pthread_join from exiting, or am I just using threads wrong?
Here's my code (not including the bulk of qemu_user_mode_func):
void *qemu_user_mode_func(void *arg)
{
thread_data_t *thread_data;
int argc;
char **argv;
char **envp;
/** QEMU's normal code **/
//return 0;
pthread_exit(NULL);
}
void *test_func(void *arg) {
struct timespec time;
time.tv_sec = 7;
time.tv_nsec = 0;
nanosleep(&time, NULL);
printf("hello, world - from a thread\n");
pthread_exit(NULL);
}
int main(int argc, char**argv, char **envp) {
//Initialize variables to create thread
int rc;
pthread_t threads[2];
thread_data_t main_args;
main_args.tid = 1;
main_args.argc = argc;
main_args.argv = argv;
main_args.envp = envp;
//Create thread
if ((rc = pthread_create(&(threads[0]), NULL, test_func, NULL))) {
fprintf(stderr, "error: pthread_create, rc: %d\n", rc);
return EXIT_FAILURE;
}
if ((rc = pthread_create(&(threads[1]), NULL, qemu_user_mode_func, (void *)&main_args))) {
fprintf(stderr, "error: pthread_create, rc: %d\n", rc);
return EXIT_FAILURE;
}
//Wait for thread to finish, then terminate process
for (rc = 0; rc < 2; rc++) {
pthread_join(threads[rc], NULL);
}
return 0;
}
EDIT: I've discovered in the void cpu_loop(CPUX86State *env) function that when the emulated program reaches its conclusion, QEMU calls syscall 231, which is sys_exit_group (as per 1). So I'm guessing this syscall is terminating the entire process that I'm running. I'd appreciate any tips on how to get around that!
If you turn a complicated preexisting application into thread there are going to be issues. One is that the application can call exit or its variants which will terminate your entire program. There are numerous other issues that could be causing a problem. I would suggest using gdb to determine what is making your program exit.
Problem was solved by editing the following section in void cpu_loop(CPUX86State *env). I capture either sys_exit_group and sys_exit system calls before they are executed, and just return from the function instead.
Original:
void cpu_loop(CPUX86State *env)
{
CPUState *cs = CPU(x86_env_get_cpu(env));
int trapnr;
abi_ulong pc;
target_siginfo_t info;
for(;;) {
cpu_exec_start(cs);
trapnr = cpu_x86_exec(env);
cpu_exec_end(cs);
switch(trapnr) {
case 0x80:
/* linux syscall from int $0x80 */
env->regs[R_EAX] = do_syscall(env,
env->regs[R_EAX],
env->regs[R_EBX],
env->regs[R_ECX],
env->regs[R_EDX],
env->regs[R_ESI],
env->regs[R_EDI],
env->regs[R_EBP],
0, 0);
break;
#ifndef TARGET_ABI32
case EXCP_SYSCALL:
/* linux syscall from syscall instruction */
env->regs[R_EAX] = do_syscall(env,
env->regs[R_EAX],
env->regs[R_EDI],
env->regs[R_ESI],
env->regs[R_EDX],
env->regs[10],
env->regs[8],
env->regs[9],
0, 0);
break;
#endif
Modified:
void cpu_loop(CPUX86State *env)
{
CPUState *cs = CPU(x86_env_get_cpu(env));
int trapnr;
abi_ulong pc;
target_siginfo_t info;
for(;;) {
cpu_exec_start(cs);
trapnr = cpu_x86_exec(env);
cpu_exec_end(cs);
switch(trapnr) {
case 0x80:
/* linux syscall from int $0x80 */
env->regs[R_EAX] = do_syscall(env,
env->regs[R_EAX],
env->regs[R_EBX],
env->regs[R_ECX],
env->regs[R_EDX],
env->regs[R_ESI],
env->regs[R_EDI],
env->regs[R_EBP],
0, 0);
break;
#ifndef TARGET_ABI32
case EXCP_SYSCALL:
/* linux syscall from syscall instruction */
----> if ((env->regs[R_EAX] == __NR_exit_group) || (env->regs[R_EAX] == __NR_exit)) {
return;
}
env->regs[R_EAX] = do_syscall(env,
env->regs[R_EAX],
env->regs[R_EDI],
env->regs[R_ESI],
env->regs[R_EDX],
env->regs[10],
env->regs[8],
env->regs[9],
0, 0);
break;
#endif

Resources