Prevent process from being closed in task manager - c++

I am developing a little program for becoming more productive. It should disconnect the user from the Internet or shut your computer down after a preset number of minutes. The program shouldn't be closed with task manager. I could compile the program and it run, but I could close it with task manager. I got my inspiration from this page:
#include <iostream>
#include <Windows.h>
#include <AccCtrl.h>
#include <AclAPI.h>
#include <tchar.h>
#include "shutdown.cpp"
#include "disconnect.cpp"
static const bool ProtectProcess()
{
HANDLE hProcess = GetCurrentProcess();
EXPLICIT_ACCESS denyAccess = {0};
DWORD dwAccessPermissions = GENERIC_WRITE|PROCESS_ALL_ACCESS|WRITE_DAC|DELETE|WRITE_OWNER|READ_CONTROL;
BuildExplicitAccessWithName( &denyAccess, _T("CURRENT_USER"), dwAccessPermissions, DENY_ACCESS, NO_INHERITANCE );
PACL pTempDacl = NULL;
DWORD dwErr = 0;
dwErr = SetEntriesInAcl( 1, &denyAccess, NULL, &pTempDacl );
// check dwErr...
dwErr = SetSecurityInfo( hProcess, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, pTempDacl, NULL );
// check dwErr...
LocalFree( pTempDacl );
CloseHandle( hProcess );
return dwErr == ERROR_SUCCESS;
}
int main()
{
using namespace std;
int abfrage;
ProtectProcess();
for (;;)
{
cout << "10.Cut your Internet connection" << endl
<< "11.Cut your Internet connection after 'x' minutes of surfing" << endl
<< "20.Shutdown" << endl;
cin >> abfrage;
switch(abfrage)
{
case 10: disconnectnow(); break;
case 11: disconnectlater(); break;
case 20: shutdown(); break;
default: cout << "nothing to see here" << endl;
}
}
return EXIT_SUCCESS;
}

This functionality is, deliberately, unsupported and actively made intractable:
Why can't you trap TerminateProcess?
If a user fires up Task Manager and clicks the End Task button on the Applications tab, Windows first tries to shut down your program nicely, by sending WM_CLOSE messages to GUI programs and CTRL_CLOSE_EVENT events to console programs. But you don't get a chance to intercept TerminateProcess. Why not?
TerminateProcess is the low-level process-killing function. It bypasses DLL_PROCESS_DETACH and anything else in the process. When you kill with TerminateProcess, no more user-mode code will run in that process. It's gone. Do not pass go. Do not collect $200.
If you could intercept TerminateProcess, you would be escalating the arms race between programs and users. Suppose you could intercept it. Well, then if you wanted to make your program unkillable, you would just hand in your TerminateProcess handler! And then people would ask for "a way to kill a process that is refusing to be killed with TerminateProcess," and we'd be back to where we started.
In practice, programs attempting to evade detection and task kill try to rename themselves to near isoforms of the Windows system processes. Don't do this. It guarantees your program will be submitted as malware and will kill your credibility dead.

Related

Run command in c++ via CreateProcess and handle its input and output

I am trying to create a program in which you can execute commands. The output of these commands should be displayed in a GUI. For this I use QT (because I want to get familiar with WinAPI I don't use QProcess). In the current program it is already possible to redirect the output of a command with a handle. Now my question, how is it possible to interrupt the ReadFile if the command expects a user input.
As an example, I want to run the command yarn run from C++.
This returns as output that this command does not exist and asks which command I want to execute instead. At the moment the command aborts there (comparable with CTRL+C) and returns error No command specified. At this point, however, a user input should be possible.
Expected outcome of the program:
The output I get instead:
As you can see in picture 1 yarn asks the user for input. In image 2 there is no question at all. This behaviour is for example possible if you press CTRL+C if the question input shows up.
So how is it possible to make a user input in the gui (for now it would be enough to redirect the value of a variable into the input) and redirect it back to the process. The process should wait until it gets the input.
Command.h
#ifndef COMMAND_H
#define COMMAND_H
#include <string>
#include <cstdlib>
#include <cstdio>
#include <io.h>
#include <fcntl.h>
#include <stdexcept>
#include <windows.h>
#include <iostream>
#define BUFSIZE 256
class Project;
class Command
{
private:
int exitStatus;
const Project * project;
std::string cmd;
HANDLE g_hChildStd_IN_Rd = nullptr;
HANDLE g_hChildStd_IN_Wr = nullptr;
HANDLE g_hChildStd_OUT_Rd = nullptr;
HANDLE g_hChildStd_OUT_Wr = nullptr;
HANDLE g_hInputFile = nullptr;
void setupWindowsPipes();
void createWindowsError(const std::string &errorText);
void readFromPipe();
public:
Command() = delete;
explicit Command(std::string cmd, const Project *project);
void exec();
};
#endif // COMMAND_H
Command.cpp (the entry point which is called by the gui is exec())
#include "command.h"
#include "project.h"
Command::Command(std::string cmd, const Project *project) : exitStatus(0), project(project), cmd(std::move(cmd)) {}
void Command::createWindowsError(const std::string &errorText) {
DWORD code = GetLastError();
LPSTR lpMsgBuf;
if(code == 0) return;
auto size = FormatMessageA(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
code,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPSTR) &lpMsgBuf,
0, NULL );
std::string msg(lpMsgBuf, size);
LocalFree(lpMsgBuf);
throw std::runtime_error(errorText + "()" + std::to_string(code) + ": " + msg);
}
void Command::setupWindowsPipes(){
SECURITY_ATTRIBUTES saAttr;
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = true;
saAttr.lpSecurityDescriptor = nullptr;
if(!CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0))
createWindowsError("StdOutRd CreatePipe");
if(!SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0))
createWindowsError("StdOut SetHandleInformation");
if(!CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0))
createWindowsError("StdInRd CreatePipe");
if(!SetHandleInformation(g_hChildStd_IN_Rd, HANDLE_FLAG_INHERIT, 0))
createWindowsError("StdIn SetHandleInformation");
}
void Command::readFromPipe() {
DWORD dwRead;
char chBuf[BUFSIZE];
bool bSuccess = false;
for (;;)
{
dwRead = 0;
for(int i = 0;i<BUFSIZE;++i) {
chBuf[i] = '\0';
}
bSuccess = ReadFile( g_hChildStd_OUT_Rd, chBuf, BUFSIZE, &dwRead, NULL);
if( ! bSuccess || dwRead <= 0 ) break;
std::cout << chBuf;
}
std::cout << std::endl;
}
void Command::exec() {
std::cout << "CMD to run: " << this->cmd << std::endl;
this->setupWindowsPipes();
STARTUPINFOA si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
si.hStdError = g_hChildStd_OUT_Wr;
si.hStdOutput = g_hChildStd_OUT_Wr;
si.hStdInput = g_hChildStd_IN_Rd;
si.dwFlags |= STARTF_USESTDHANDLES;
ZeroMemory(&pi, sizeof(pi));
char* dir = nullptr;
if(this->project != nullptr) {
auto n = this->project->getLocalUrl().size() + 1;
auto nString = this->project->getLocalUrl().replace("/", "\\");
dir = new char[n];
std::strncpy(dir, nString.toStdString().c_str(), n);
}
std::string cmdString = "cmd /c ";
cmdString.append(this->cmd);
char cmdCopy[cmdString.size() + 1];
cmdString.copy(cmdCopy, cmdString.size());
cmdCopy[cmdString.size() + 1] = '\0';
bool rc = CreateProcessA( nullptr,
cmdCopy,
nullptr,
nullptr,
true,
CREATE_NO_WINDOW,
nullptr,
dir,
&si,
&pi);
delete []dir;
if(!rc)
createWindowsError("Failed to create process");
std::cout << "PID: " << pi.dwProcessId << std::endl;
CloseHandle(g_hChildStd_OUT_Wr);
CloseHandle(g_hChildStd_IN_Rd);
readFromPipe();
std::cout << "fin reading pipe" << std::endl;
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
It sounds like you have an XY problem, luckily you described X so we can address it.
The issue is not your failure to call WriteFile to store the response into the redirected input pipe. If the program were trying to read input, it would wait.
The issue is that the program is not requesting input at all. It has detected that interactive input is not possible, because it detects a pipe and assumes that a pipe is not interactive. So it doesn't perform the prompt or try to read from standard input at all. You can't provide an answer to a question that the program didn't ask!
(To confirm this is the behavior of the yarn program you are spawning, you can launch it from cmd.exe using a pipe to provide the input. cmd.exe has well-tested buffering logic for redirected input and output handles and you can be sure that any suspected deadlock in your code doesn't affect cmd.exe)
On Unix-like systems, this is solved by redirecting to a pseudo-tty (ptty) special file instead of a pipe special file, which causes the isatty() function to return true.
On Windows, this used to be effectively impossible, as the console API, implemented at kernel level, was permanently associated to the console subsystem csrss.exe which only exchanged data with the official Console Host process (owner of console windows).
Now however, Windows API supports pseudo-consoles. You can find a complete introduction on the Microsoft Dev Blog
Windows Command-Line: Introducing the Windows Pseudo Console (ConPTY)
The important function you need (in case that link breaks) is CreatePseudoConsole supported starting with Windows 10 version 1809 (October 2018 update).
When you use CreatePseudoConsole to promote the pipes and then supply this console to CreateProcess (instead of attaching pipes to your subprocess standard I/O streams), the subprocess will detect an interactive console, can use console API functions such as AttachConsole, can open the special filenames CONIN$ etc. And the data comes to you (and from you) instead of being linked to a console window.
There's also a complete sample on GitHub.
That same blog post also discusses the workaround used by "Terminal" and "remote shell" type software prior to the addition of CreatePseudoConsole in Windows 10, namely setting up the subprocess with a detached console, hiding the associated console window, and screen-scraping the console screen buffer.

SeDebugPrivilege issue on Windows 8.1 and windows 10

a few days ago I posted a question about ReadProcessMemory not returning the correct value, now I been aware of why it worked on my windows 7 machine and not for windows 8.1 and windows 10, and that is SeDebugPriviledge. I did some research on it, and found a function to enable privledges for it, it return that it has been a success.
void sample()
{
HANDLE hToken = NULL;
TOKEN_PRIVILEGES tokenPriv;
LUID luidDebug;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken) != FALSE)
{
if (LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luidDebug) != FALSE)
{
tokenPriv.PrivilegeCount = 1;
tokenPriv.Privileges[0].Luid = luidDebug;
tokenPriv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (AdjustTokenPrivileges(hToken, FALSE, &tokenPriv, 0, NULL, NULL) != FALSE)
{
// Always successful, even in the cases which lead to OpenProcess failure
cout << "SUCCESSFULLY CHANGED TOKEN PRIVILEGES" << endl;
}
else
{
cout << "FAILED TO CHANGE TOKEN PRIVILEGES, CODE: " << GetLastError() << endl;
}
}
}
CloseHandle(hToken);
}
But what happened next is that instead of printing out 0 in the console, it started printing out this negative number, -858993445. Then I decided to try it on a diffrent process, and a different computer, this time on windows 10 instead of windows 8.1, and the same exact number was printed, on three different processes and two different computers running two different OS's. I tried coding the program on windows 7 instead and putting it on a usb and running it on windows 8.1, it was then fully working. But when I coded it and debugged it, it didn't work. Does anyone have any experience with this issue and how I can bypass this, I know it is there for security reasons, but I need PROCESS_ALL_ACCESS for practising reverse engineering.
DISCLAIMER: THIS IS NOT FOR HACKING OR MALWARE DEVELOPMENT PURPOSES, IF I WANTED TO CHEAT IN A VIDEO GAME I COULD JUST DOWNLOAD A CHEAT ONLINE
EDIT: I should add that my computer can't find secpol.msc
The ReadProcessMemory function:
int main()
{
int points;
sample();
DWORD pID;
HWND hWnd = FindWindowA(0, ("Call of Duty®: Black Ops"));
GetWindowThreadProcessId(hWnd, &pID);
HANDLE pHandle = OpenProcess(PROCESS_VM_READ, FALSE, pID);
ReadProcessMemory(pHandle, (LPVOID)0x1C0A6C8, &points, sizeof(points), 0);
cout << points << endl;
system("pause");
}
I did no changes to my code or computer, but out of no where it started working again, strange.

c++ my program cannot initialize a handle on a process

I'm trying to edit memory in a program. For the most part the code works, but when I try to initiate a handle on the process, it returns NULL.
#include <iostream>
#include <windows.h>
using namespace std;
int main() {
int playerTotalRam = 761;
HWND hwnd = FindWindowA(NULL, "generic game"); // specifies the window to act
upon
// error message if the window isn't found
if (hwnd == NULL) {
cout << "window not found!\n";
system("PAUSE");
} else {
DWORD processID;
// stores the process id of the window
GetWindowThreadProcessId(hwnd, &processID);
// gets the process id of the window
HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processID);
// opens the process with full access
if (!handle) {
cout << "couldnt initiate a handle on the process!\n";
system("PAUSE");
}
// error message if the process ID isn't found
if (processID == NULL) {
cout << "cannot find process!\n";
system("PAUSE");
} else {
WriteProcessMemory(handle, (LPVOID)0x044A52C8, &playerTotalRam,
4, 0); // this writes the new value to the listed address
}
}
return 0;
}
The program outputs "couldnt initiate a handle on the process!"
I have this same error with other programs.
What i want to know is what am I doing wrong, and how can I fix this.
My system is windows 10 home.
Either FindWindowA is failing, resulting in an incorrect process id because you have the wrong window title text or you're not running your program as administrator. You need to run as administrator to get PROCESS_ALL_ACCESS permissions and make sure your title text is correct. This will solve your problem.

C++ Alternative to OpenProcess() (Program not willing to grant me permission)

I'm fairly new to C++ so my question is: Is there an alternative to OpenProcess()?The game does not let me get access to it, tried asking for smaller access than PROCESS_ACCESS_ALL since that might be a huge red flag. But here's my source code:
#include "stdafx.h"
#include <iostream>
#include <string.h>
#include <Windows.h>
int main()
{
HWND hWnd = FindWindow(NULL, "Growtopia");
if (hWnd == NULL)
{
std::cout << "ERROR: Unable to find window process" << std::endl;
Sleep(2500);
exit(-1);
}
DWORD pID;
GetWindowThreadProcessId(hWnd, &pID);
HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, false, pID);
if (!hProc)
{
std::cout << "Error: Unable to gain access to window" << std::endl;
Sleep(2500);
exit(-1);
}
return 0;
}
PS: The game I'm trying to gain access to is Growtopia if you couldn't find it out by the FindWindow() function :)
Thanks in advance.
Edit: My purpouse of the program is to edit a value of an adress
My purpouse of the program is to edit a value of an adress
That requires the use of WriteProcessMemory(), which requires PROCESS_VM_WRITE and PROCESS_VM_OPERATION permissions to the target process:
HANDLE hProc = OpenProcess(PROCESS_VM_WRITE | PROCESS_VM_OPERATION, false, pID);
To open a process with those permissions, the calling thread needs the "SeDebugPrivilege" privilege enabled, which means it has to be running as a user that is allowed to obtain debug privileges, such as an admin.
Run your app as a debug user (or dynamically impersonate such a user), then use OpenThreadToken() to open the calling thread's current access token and adjust it with AdjustTokenPrivileges() to make sure the "SeDebugPrivilege" privilege is active, before then calling OpenProcess():
Changing Privileges in a Token
How to obtain a handle to any process with SeDebugPrivilege

open cmd and read and write into it

I need to start a process that starts the commandline (it should not pop up, so something like a background process).
Then I need to write stuff to it and periodically read the last line of the cmd.
Since my C++ skills aren't that great I don't know how to achieve this.
In a pseudocode way I thought about something like this:
startProcess();
writeToCmd();
readFromCmd() { // Call that every given interval (e.g. 1000 ms)
if(returnValue >= 100) {
stopProcess();
}
}
I'm pretty sure it'll not be that easy. It would be really great if someone can help me out here.
The programm is for windows.
Edit after the suggestions:
This is what I've done so far (I did it a little bit different.)
int errorCode;
// Variables for CreateProcess()
SECURITY_ATTRIBUTES sa;
STARTUPINFO si;
PROCESS_INFORMATION pi;
PHANDLE hInRead, hInWrite;
LPDWORD bytesWritten, bytesRead;
// The CommandLine input
TCHAR tcsCommandLine[] = _T("cmd /c format H: /fs:FAT32 /V:device");
//TCHAR tcsCommandLine[] = _T("cmd /c start D:\\foo.txt");
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = true;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
si.wShowWindow = SW_SHOW; // SW_HIDE FOR PRODUCTION
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
si.hStdInput = hInRead;
si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
ZeroMemory(&pi, sizeof(pi));
errorCode = CreatePipe(hInRead, hInWrite, &sa, 0);
info = GetDriveInfo(m_wsNANDMountPoint);
if(info.m_uSizeInMB > 2048) {
log("Wrong Mounting Point. Device has more than 2GB space.");
return false;
}
else {
// Start Formatting
if(!CreateProcess(NULL, tcsCommandLine,
NULL, NULL,
TRUE, CREATE_NEW_CONSOLE | NORMAL_PRIORITY_CLASS, NULL, NULL,
&si,
&pi)) {
log("CreateProcess failed. Could not format Drive");
return false;
}
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
WriteFile(hInWrite, "#13#10'J'#13#10", 5, bytesWritten, NULL);
CloseHandle(hInWrite);
// Wait until child process exits
WaitForSingleObject(pi.hProcess, 1100);
}
return true;
After a little bit of debugging, I recognized that the code doesn't break at ZeroMemory(), but on
errorCode = CreatePipe(hInRead, hInWrite, &sa, 0);
with an Access violation writing location error. I have no idea what I'm doing wrong.
It would be really great if you guys could help me out.
What you need to do in this instance is to create a console with a hidden window. If you use CreateProcess to launch the console, you should be able to set the visibility of the window through the STARTUPINFO structure.
The next step is to redirect the input and output of your console. You can do this by attaching the 3 console handles (input, output, error) to pipes and reading that from your parent process. This MSDN article describes how to do exactly this.
The command line consists of two parts you would be interested in.
A place to execute programs
A buffer for whatever is written on the screen
Since you don't need the screen to be visible, then you need these two things in your program. So from here on, forget about cmd.
To execute programs in your program, you have many ways. If you want the execution lines to look exactly the way you write it in cmd, you can use system (although Windows versions of fork/exec make more sense). For example:
system("my_prog.exe --option file.txt");
Which executes my_prog.exe with --option and file.txt as arguments.
Now the second one, you said you wanted to read the last line from cmd. The idea to realize this is to have the output of everything in a file, instead of in cmd.
If you are only interested in the last line at every instance, you can redirect the output of your programs to a file like this:
system("my_prog.exe --option file.txt > output.txt");
or if you want to keep the whole history, you can append instead of overwrite:
system("my_prog.exe --option file.txt >> output.txt");
If you also want to redirect stderr, you can write:
system("my_prog.exe --option file.txt &> output.txt");
The notation may be linuxy, try it in your windows see if it works (manually in a normal cmd). You could also search google for "shell redirect" and you get a lot of results.
Anyway, if you want the last line of cmd to also include the command itself, you can overwrite/append the command line to that particular yourself in the program.
Let me add this to these excellent answers:
This great link demonstrates console read and write : http://www.adrianxw.dk/SoftwareSite/Consoles/Consoles2.html
To do stuff periodically, use SetTimer().
http://msdn.microsoft.com/en-us/library/windows/desktop/ms644906(v=vs.85).aspx
The SetTimer function executes a function every x milliseconds.
Example:
The following console program works like this: It sets a timer using SetTimer
then loops in a message loop. The message loop receives and processes WM_TIMER messages
and the timer callback also is called for each time interval.
Simply put the stuff you want done in the TimerProc() function.
#define STRICT 1
#include <windows.h>
#include <iostream.h>
VOID CALLBACK TimerProc(HWND hWnd, UINT nMsg, UINT nIDEvent, DWORD dwTime)
{
//put the stuff you want done in here
cout << "Doing stuff Time: " << dwTime << '\n';
cout << "--------------------------------------------------\n" ;
cout.flush();
}
int main(int argc, char *argv[], char *envp[])
{
int Counter=0;
int usage_Time_millisec=1000;
MSG Msg;
UINT TimerId = SetTimer(NULL, 0, usage_Time_millisec, &TimerProc); //bind TimerProc() to SetTimer()
cout << "TimerId: " << TimerId << '\n';
if (!TimerId) return 16;
while (GetMessage(&Msg, NULL, 0, 0))
{
++Counter;
if (Msg.message == WM_TIMER)
cout << "Doing stuff Counter: " << Counter << "; timer message\n";
else
cout << "Doing stuff Counter: " << Counter << "; message: " << Msg.message << '\n';
DispatchMessage(&Msg);
}
KillTimer(NULL, TimerId);
return 0;
}