WaitForSingleObject with FindFirstChangeNotification not behaving as expected [duplicate] - c++

This question already has answers here:
FindFirstChangeNotification is notifying about changes twice
(2 answers)
Closed 1 year ago.
I have to find out if there is a new file in a directory on Windows. Following this MSDN example (Obtaining Directory Change Notifications), I came up with the following test program:
#include <iostream>
#include <Windows.h>
#include <vector>
#include <string>
std::string FindNewFile(std::vector<std::string>& vsNewFileList, std::vector<std::string>& vsOldFileList)
{
std::string sNewFileName;
int nScore = 0;
for (auto& newFile : vsNewFileList)
{
nScore = 0;
for (auto& oldFile : vsOldFileList)
if(!newFile.compare(oldFile))
nScore++;
if (nScore!=1)
{
sNewFileName = newFile;
break;
}
}
return sNewFileName;
}
void GetCurrentFilesInDir(std::string sDir, std::vector<std::string>& vsFileList)
{
WIN32_FIND_DATA ffd;
sDir += "\\*";
std::wstring wStr = std::wstring(sDir.begin(), sDir.end());
LPCWSTR lpcwsDir = (LPCWSTR)wStr.c_str();
HANDLE hFind = FindFirstFile(lpcwsDir, &ffd);
if (hFind == INVALID_HANDLE_VALUE)
{
std::cout << "Nope\n";
return;
}
vsFileList.clear();
do
{
int nSize = WideCharToMultiByte(CP_ACP, 0, ffd.cFileName, -1, 0, 0, 0, 0);
char* pcStr = new char[nSize];
WideCharToMultiByte(CP_ACP, 0, ffd.cFileName, -1, pcStr, nSize, 0, 0);
//std::cout << pcStr << "\n";
vsFileList.push_back(std::string(pcStr));
delete[] pcStr;
} while (FindNextFile(hFind, &ffd) != 0);
}
int main()
{
// watch the foo directory for new files
std::string sDir = "C:\\foo";
std::vector<std::string> vsOldFileList, vsNewFileList;
GetCurrentFilesInDir(sDir, vsOldFileList);
std::wstring wStr = std::wstring(sDir.begin(), sDir.end());
LPCWSTR lpcwsDir = (LPCWSTR)wStr.c_str();
DWORD dwWaitStatus;
HANDLE dwChangeHandle;
dwChangeHandle = FindFirstChangeNotification(
lpcwsDir,
FALSE,
FILE_NOTIFY_CHANGE_FILE_NAME);
while (TRUE)
{
// returns multiple times before and after new file appears!!
dwWaitStatus = WaitForSingleObject(dwChangeHandle, INFINITE);
switch(dwWaitStatus)
{
case WAIT_OBJECT_0:
GetCurrentFilesInDir(sDir, vsNewFileList);
std::string sNewFileName = FindNewFile(vsNewFileList, vsOldFileList);
std::cout << sNewFileName << "\n";
GetCurrentFilesInDir(sDir, vsOldFileList);
FindNextChangeNotification(dwChangeHandle);
break;
}
}
}
The problem is that, when I save a new file in C:\foo (for instance, using Notepad++ to "Save As" an open .txt file in C:\foo), the call to WaitForSingleObject() in the while loop will return 0 multiple times. Since my FindNewFile() method returns an empty string if there is no new file in the directory, I will get output like:
a.txt
or:
b.txt
Or even:
c.txt
c.txt
Can someone explain what I am missing here?

Using FindNextChangeNotification can not tell you what actually happened, and the operation of the file may involve multiple changes.
You can try to use ReadDirectoryChangesW and here is a sample:
#include <windows.h>
#include <iostream>
using namespace std;
wstring getname(FILE_NOTIFY_INFORMATION* tmp)
{
wstring s = L"";
for (int i = 0; i < tmp->FileNameLength / 2; i++)
s += tmp->FileName[i];
return s;
}
int main(int argc, const char* argv[])
{
HANDLE hDir;
char notify[1024];
DWORD cbBytes;
LPTSTR path;
FILE_NOTIFY_INFORMATION* pnotify = (FILE_NOTIFY_INFORMATION*)notify;
FILE_NOTIFY_INFORMATION* tmp;
// GetCurrentDirectory(MAX_PATH,path.GetBuffer(MAX_PATH+1));
path = (LPTSTR)L"D:\\test";
hDir = CreateFile(path, FILE_LIST_DIRECTORY,
FILE_SHARE_READ |
FILE_SHARE_WRITE |
FILE_SHARE_DELETE, NULL,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS |
FILE_FLAG_OVERLAPPED, NULL);
wcout << L"===CreateFile complete===" << endl;
if (hDir == INVALID_HANDLE_VALUE)
{
wcout << L"invalid handle value" << endl;
return -1;
}
FILE_NOTIFY_INFORMATION buffer[1024];
FILE_NOTIFY_INFORMATION* pbuffer;
while (TRUE)
{
wcout << L"waiting..." << endl;
WaitForSingleObject(hDir, INFINITE);
if (ReadDirectoryChangesW(hDir, &buffer, sizeof(buffer),
TRUE, FILE_NOTIFY_CHANGE_FILE_NAME,
&cbBytes, NULL, NULL))
{
pbuffer = buffer;
do {
tmp = pbuffer;
switch (tmp->Action)
{
case FILE_ACTION_ADDED:
wcout << L"Directory/File added - " << getname(tmp) << endl;
break;
case FILE_ACTION_REMOVED:
wcout << L"Directory/File removed - " << getname(tmp) << endl;
break;
case FILE_ACTION_MODIFIED:
wcout << L"Directory/File modfied - " << getname(tmp) << endl;
break;
case FILE_ACTION_RENAMED_OLD_NAME:
wcout << L"Directory/File old name - " << getname(tmp) << endl;
break;
case FILE_ACTION_RENAMED_NEW_NAME:
wcout << L"Directory/File new name - " << getname(tmp) << endl;
break;
default:
wcout << L"unknown action\n" << endl;
break;
}
pbuffer += pbuffer->NextEntryOffset;
} while (pbuffer->NextEntryOffset);
}
else
{
wcout << "readChangesW failed now return" << endl;
return -1;
}
}
}
When you do the Save As operation, you will find:
Therefore, multiple file operations were triggered when actually saving as, and you also performed multiple comparisons when processing new file comparisons, so empty characters were output.
More reference: FindFirstChangeNotification is notifying about changes twice

Related

How can I read and write to pipes created for a child process in c++

I am making a tester program that opens a console application and reads it's standard input writes to it's standard output, but am having issues with the pipes. I am using named pipes since I might have to run this threaded or even open multiple executables to communicate with at once. These will need to remain running and continuously take input and give out put, as in a console calculator that asks if you if you want another calculation or to exit after each calculation.
Using error checking I have found that The pipes are created successfully, I apply them to the startupInfo struct and successfully open the executable. A note here, if I set a break point in visual studio just after the call to createProcess, the child process does show up in my task manager, the check STILL_ACTIVE is true and peaking at the pipe reveals an empty pipe. If no break point is set then I don't see it, and the check STILL_ACTIVE is false.
To simplify the problem I went back to basics, a simple hello world executable in c++. The calculator will be the next test. This prints hello world to the console and via a cin:get() waits for the enter key to be pressed. I ran this with the tester and tried to read the "Hello World" from the child process. I get nothing.
The end project will be open source, I don't want the user to have to download any other libraries to compile the project, and Boost::Process actually requires 2 install since process is not standard yet.
I know that I am close, here is my simple tester as one file with the process class extracted to be inline in the main. Note: I have enabled c++20 in my compiler.
// Tester.cpp
#include <string>
#include <string_view>
#include <vector>
#include <iostream>
#include <fstream>
#include <filesystem>
#include <io.h>
#include <fcntl.h>
#include <windows.h>
int main()
{
std::string data = "";
int id = 1;
std::string executable = "HelloWorld.exe";
if (_access((executable).c_str(), 0) != -1)
{
std::cerr << "Error: Executable file not found: " << executable << std::endl;
exit(0);
}
SECURITY_ATTRIBUTES saAttr{};
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
//Pipe names
std::wstring pipeErr = L"\\\\.\\pipe\\err_" + std::to_wstring(id);
std::wstring pipeOut = L"\\\\.\\pipe\\out_" + std::to_wstring(id);
std::wstring pipeIn = L"\\\\.\\pipe\\in_" + std::to_wstring(id);
// The Child error pipe for reading
CreateNamedPipeW(pipeErr.c_str(), PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 1, 1024, 1024, 0, NULL);
HANDLE err_pipe = CreateFileW(pipeErr.c_str(), GENERIC_READ | GENERIC_WRITE, 0, &saAttr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
// The Child out pipe for reading
CreateNamedPipeW(pipeOut.c_str(), PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 1, 1024, 1024, 0, NULL);
HANDLE out_pipe = CreateFileW(pipeOut.c_str(), GENERIC_READ | GENERIC_WRITE, 0, &saAttr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
// The Child in pipe for writing
CreateNamedPipeW(pipeIn.c_str(), PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 1024, 1024, 0, NULL);
HANDLE in_pipe = CreateFileW(pipeIn.c_str(), GENERIC_READ | GENERIC_WRITE, 0, &saAttr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
if (in_pipe == INVALID_HANDLE_VALUE || out_pipe == INVALID_HANDLE_VALUE || err_pipe == INVALID_HANDLE_VALUE)
{
std::cout << "Error Creating Handles, Code: " << GetLastError() << std::endl;
return 0;
}
// Make sure the handles' inheritance is set correctly
if (!SetHandleInformation(in_pipe, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT) ||
!SetHandleInformation(out_pipe, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT) ||
!SetHandleInformation(err_pipe, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT))
{
std::cerr << "Error: Failed to set handle information for the child process" << std::endl;
return 0;
}
// Set up the startup info struct
STARTUPINFOA startupInfo;
memset(&startupInfo, 0, sizeof(startupInfo));
startupInfo.cb = sizeof(STARTUPINFOA);
startupInfo.hStdInput = in_pipe;
startupInfo.hStdOutput = out_pipe;
startupInfo.hStdError = err_pipe;
startupInfo.dwFlags |= STARTF_USESTDHANDLES;
// Set up the process info struct
PROCESS_INFORMATION processInfo;
memset(&processInfo, 0, sizeof(processInfo));
// Create the child process
if (CreateProcessA(NULL, executable.data(), NULL, NULL, TRUE, 0, NULL, NULL, &startupInfo, &processInfo) == 0)
{
std::cerr << "Error: Failed to create the child process" << std::endl;
return 0;
}
// Set the pipes to non-blocking mode
DWORD mode = PIPE_NOWAIT;
SetNamedPipeHandleState(out_pipe, &mode, NULL, NULL);
SetNamedPipeHandleState(err_pipe, &mode, NULL, NULL);
SetNamedPipeHandleState(in_pipe, &mode, NULL, NULL);
Sleep(500); //wait for child to start, may not be neccesary
// Get the exit code of the child process
DWORD exitCode;
GetExitCodeProcess(processInfo.hProcess, &exitCode);
if (exitCode == STILL_ACTIVE) {
// Set up the read buffer
char buffer[1024];
memset(buffer, 0, sizeof(buffer));
DWORD bytesRead = 0;
DWORD bytesAvail = 0;
// Check if there is data available to read from the pipe
if (!PeekNamedPipe(out_pipe, buffer, sizeof(buffer), &bytesRead, &bytesAvail, NULL)) {
std::cerr << "PeekNamedPipe failed (" << GetLastError() << ").\n";
return 0;
}
if (bytesAvail == 0)
{
std::cerr << "Pipe is empty" << std::endl;
}
if (!ReadFile(out_pipe, buffer, sizeof(buffer) - 1, &bytesRead, NULL))
{
std::cerr << "Failed to read from pipe. Error code: " << GetLastError() << std::endl;
return 0;
}
data = buffer;
}
if (data == "") {
std::cout << "Something went wrong. Code: " << GetLastError() << std::endl;
}
else {
std::cout << data << std::endl;
}
std::cout << "Press any key." << std::endl;
std::cin.get();
return 0;
}
and, for reference, here is helloworld.exe:
// HelloWorld.cpp
#include <iostream>
int main()
{
std::cout << "Hello World!" << std::endl;
std::cin.get();
}
Thanks to #Igor Tandetnik!
Here is the working Tester.cpp:
// Tester.cpp
#include <string>
#include <string_view>
#include <vector>
#include <iostream>
#include <fstream>
#include <filesystem>
#include <io.h>
#include <fcntl.h>
#include <windows.h>
#include <aclapi.h>
constexpr auto BUFSIZE = 4096;
int main()
{
std::string data = "";
int id = 1;
std::wstring executable = L"HelloWorld.exe";
std::wstring argv = L"";
std::string name_c = "";
std::string path_c = "";
HANDLE hChildStd_IN_Rd = NULL;
HANDLE hChildStd_IN_Wr = NULL;
HANDLE hChildStd_OUT_Rd = NULL;
HANDLE hChildStd_OUT_Wr = NULL;
HANDLE hChildStd_ERR_Rd = NULL;
HANDLE hChildStd_ERR_Wr = NULL;
size_t size;
wcstombs_s(&size, nullptr, 0, executable.c_str(), executable.length());
name_c.resize(size);
wcstombs_s(&size, name_c.data(), name_c.size(), executable.c_str(), executable.length());
wchar_t current_dir[FILENAME_MAX];
if (_wgetcwd(current_dir, FILENAME_MAX) == nullptr) {
std::cerr << "Error getting current working directory. Code:" << GetLastError() << std::endl;
exit(0);
}
wchar_t path_exe[MAX_PATH];
GetModuleFileName(NULL, path_exe, MAX_PATH);
std::wstring path = path_exe;
path = std::filesystem::path(path).parent_path();
path += L"\\";
path += executable;
wcstombs_s(&size, nullptr, 0, path.c_str(), path.length());
path_c.resize(size);
wcstombs_s(&size, path_c.data(), path_c.size(), path.c_str(), path.length());
int found = _waccess_s(path.c_str(), 0);
if (found != 0)
{
std::cerr << "Error: Executable file not found: " << name_c << std::endl;
exit(0);
}
SECURITY_ATTRIBUTES sa_attr{};
sa_attr.nLength = sizeof(SECURITY_ATTRIBUTES);
sa_attr.bInheritHandle = TRUE;
sa_attr.lpSecurityDescriptor = NULL;
// Create the pipes
if (!CreatePipe(&hChildStd_OUT_Rd, &hChildStd_OUT_Wr, &sa_attr, 0)
|| !CreatePipe(&hChildStd_IN_Rd, &hChildStd_IN_Wr, &sa_attr, 0)
|| !CreatePipe(&hChildStd_ERR_Rd, &hChildStd_ERR_Wr, &sa_attr, 0)) {
std::cout << "Error Creating Pipes, Code: " << GetLastError() << std::endl;
return 1;
}
if (hChildStd_OUT_Rd == INVALID_HANDLE_VALUE || hChildStd_OUT_Wr == INVALID_HANDLE_VALUE
|| hChildStd_IN_Rd == INVALID_HANDLE_VALUE || hChildStd_IN_Wr == INVALID_HANDLE_VALUE
|| hChildStd_ERR_Rd == INVALID_HANDLE_VALUE || hChildStd_ERR_Wr == INVALID_HANDLE_VALUE)
{
std::cout << "Error Creating Handles, Code: " << GetLastError() << std::endl;
return 1;
}
// Set up the startup info struct
STARTUPINFOW startup_info;
ZeroMemory(&startup_info, sizeof(STARTUPINFOW));
startup_info.cb = sizeof(STARTUPINFOW);
startup_info.hStdOutput = hChildStd_OUT_Wr;
startup_info.hStdError = hChildStd_ERR_Wr;
startup_info.hStdInput = hChildStd_IN_Rd;
startup_info.dwFlags |= STARTF_USESTDHANDLES;
// Set up the process info struct
PROCESS_INFORMATION process_info;
memset(&process_info, 0, sizeof(process_info));
// Create the child process
if (!CreateProcess(path.data(), NULL, &sa_attr, NULL, TRUE, 0, NULL, NULL, &startup_info, &process_info))
{
std::cerr << "Error: Failed to create the child process. Code: " << GetLastError() << std::endl;
return 1;
}
// Get the exit code of the child process
DWORD exitCode;
GetExitCodeProcess(process_info.hProcess, &exitCode);
if (exitCode != STILL_ACTIVE) {
std::wcout << "Unable to Start Process: " << executable.c_str() << std::endl;
return 1;
}
std::wcout << "Started Process: " << executable.c_str() << std::endl;
Sleep(500); //wait for child to start, may not be neccesary
// Get the exit code of the child process
GetExitCodeProcess(process_info.hProcess, &exitCode);
if (exitCode == STILL_ACTIVE) {
// Set up the read buffer
DWORD bytesRead{}, dwWritten{};
CHAR buffer[BUFSIZE]{};
BOOL bSuccess = FALSE;
HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
bSuccess = ReadFile(hChildStd_OUT_Rd, buffer, BUFSIZE, &bytesRead, NULL);
if (!bSuccess || bytesRead == 0)
{
std::cerr << "Failed to read from pipe. Error code: " << GetLastError() << std::endl;
return 1;
}
std::vector<char> v_data(buffer, buffer + bytesRead);
data = std::string(v_data.data(), v_data.size());
}
std::cout << "Recieved from Child: " << data << std::endl;
if (data == "") {
std::cout << "Something went wrong. Code: " << GetLastError() << std::endl;
return 1;
}
else {
std::cout << data << std::endl;
}
CloseHandle(process_info.hThread);
std::cout << "Press any key." << std::endl;
std::cin.get();
return 0;
}

C++ winapi VirtualQueryEx function gives me "000000"

I am trying to display information about the virtual memory of each process on the system:
#include <windows.h>
#include <conio.h>
#include <tlhelp32.h>
#include <iostream>
using namespace std;
void main() {
HANDLE CONST hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
PROCESSENTRY32 proc;
TCHAR Buffer[1024];
TCHAR Buffer2[1024];
DWORD temp;
HANDLE CONST hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (INVALID_HANDLE_VALUE == hSnap)
{
return;
}
proc.dwSize = sizeof(PROCESSENTRY32);
Process32First(hSnap, &proc);
do {
MEMORY_BASIC_INFORMATION mbi = {};
wsprintf(Buffer, L" %s %d \n ", proc.szExeFile, proc.th32ProcessID);
WriteConsole(hStdOut, Buffer, lstrlen(Buffer), &temp, NULL);
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, proc.th32ProcessID);
VirtualQueryEx(hProcess, 0, &mbi, sizeof(MEMORY_BASIC_INFORMATION));
printf("Alloc = %p, base = %p , size = %d, type = %d, state = %p\n", mbi.AllocationBase, mbi.BaseAddress, mbi.RegionSize, mbi.Type,mbi.State);
} while (Process32Next(hSnap, &proc));
CloseHandle(hSnap);
}
Output looks like this:
output
I get base address and alloc equal to 0000000 and type 0
How do I get normal values? I mean size and state seem to be ok but the rest is "0000000"
I do not know what's the problem
You're currently only retrieving information about the first block of memory for each process. A process will typically have a lot of memory blocks, not just one (thousands to tens of thousands would be pretty typical).
Here's some code that retrieves and prints out the status of each block of data in a specified process.
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <iostream>
#include <string>
unsigned long show_module(MEMORY_BASIC_INFORMATION info) {
unsigned long usage = 0;
std::cout << info.BaseAddress << "(" << info.RegionSize / 1024 << ")\t";
switch (info.State) {
case MEM_COMMIT:
std::cout << "Committed";
break;
case MEM_RESERVE:
std::cout << "Reserved";
break;
case MEM_FREE:
std::cout << "Free";
break;
}
std::cout << "\t";
switch (info.Type) {
case MEM_IMAGE:
std::cout << "Code Module";
break;
case MEM_MAPPED:
std::cout << "Mapped ";
break;
case MEM_PRIVATE:
std::cout << "Private ";
}
std::cout << "\t";
int guard = 0, nocache = 0;
if ( info.AllocationProtect & PAGE_NOCACHE)
nocache = 1;
if ( info.AllocationProtect & PAGE_GUARD )
guard = 1;
info.AllocationProtect &= ~(PAGE_GUARD | PAGE_NOCACHE);
if ((info.State == MEM_COMMIT) && (info.AllocationProtect == PAGE_READWRITE || info.AllocationProtect == PAGE_READONLY))
usage += info.RegionSize;
switch (info.AllocationProtect) {
case PAGE_READONLY:
std::cout << "Read Only";
break;
case PAGE_READWRITE:
std::cout << "Read/Write";
break;
case PAGE_WRITECOPY:
std::cout << "Copy on Write";
break;
case PAGE_EXECUTE:
std::cout << "Execute only";
break;
case PAGE_EXECUTE_READ:
std::cout << "Execute/Read";
break;
case PAGE_EXECUTE_READWRITE:
std::cout << "Execute/Read/Write";
break;
case PAGE_EXECUTE_WRITECOPY:
std::cout << "COW Executable";
break;
}
if (guard)
std::cout << "\tguard page";
if (nocache)
std::cout << "\tnon-cacheable";
std::cout << "\n";
return usage;
}
unsigned long show_modules(HANDLE process) {
unsigned long usage = 0;
unsigned char* p = NULL;
MEMORY_BASIC_INFORMATION info;
for ( p = NULL;
VirtualQueryEx(process, p, &info, sizeof(info)) == sizeof(info);
p += info.RegionSize )
{
usage += show_module(info);
}
return usage;
}
int main(int argc, char **argv) {
int pid;
if (argc != 2) {
std::cerr << "Usage: " << argv[0] << " <process ID>\n";
return EXIT_FAILURE;
}
pid = std::stoi(argv[1]);
HANDLE process = OpenProcess(
PROCESS_VM_READ | PROCESS_QUERY_INFORMATION,
false,
pid);
unsigned long mem_used = show_modules(process);
std::cout << "Total memory used: " << mem_used / 10224 << "KB\n";
}
To give an idea of the result, here are the first few lines of output from a process on my system:
0000000000000000(64) Free
0000000000010000(64) Committed Mapped Read/Write
0000000000020000(4) Committed Mapped Read Only
0000000000021000(60) Free
0000000000030000(4) Committed Private
0000000000031000(60) Reserved Private
But be aware: you're likely to get a lot more output than that for most typical processes. That particular process (Thunderbird) produced a total of 3,686 lines of output. A quick test with Chrome (using a couple gigabytes of memory) produces over 46,000 lines of output (i.e., over 46,000 separate memory blocks being tracked by the system for it).
If you're going to print something out for every process in the system, you'll probably want to summarize the data quite a bit (but without knowing why you want this, it's hard to guess what sort of result you're likely to want).

How to stop c++ console from outputting "tick"

I haven't been able to find anything else about this online at all. I have a simple authenticator program, with a .dll injector written into it. If the key matches the one in the database, it will run the injector, and constantly check to make sure that the key is still active. For some reason, my console window outputs "tick" about every second. When the injector is taken out, and it is just the authenticator it will not do this.
#include <iostream>
#include <string>
#include <Windows.h>
#include <thread>
#include <WinInet.h>
#include <TlHelp32.h>
#include <fcntl.h>
#include <io.h>
#include <fcntl.h>
#include <cstdio>
#include <chrono>
#include "include/c0gnito.h"
std::string Key;
std::string hwid = GetHardwareID(); //Gets the hwid
char* StringToChar(std::string string) //A function to convert a string to a char
{
return _strdup(string.c_str());
}
template <class T>
void msg(T msg)
{
std::cout << msg << std::endl;
}
bool FileExists(const std::string& fileName)
{
struct stat buffer;
return (stat(fileName.c_str(), &buffer) == 0);
}
void WriteStringToIni(std::string string, std::string file, std::string app, std::string key)
{
WritePrivateProfileStringA(app.c_str(), key.c_str(), string.c_str(), file.c_str());
}
std::string ReadStringFromIni(std::string file, std::string app, std::string key)
{
char buf[100];
GetPrivateProfileStringA(app.c_str(), key.c_str(), "NULL", buf, 100, file.c_str());
return (std::string)buf;
}
LONG address = 0x0;
BYTE newvalue[] = { 0x0 };
HWND hwnd;
HANDLE phandle;
DWORD pid;
DWORD GetProcId(const char* procName)
{
DWORD procId = 0;
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnap != INVALID_HANDLE_VALUE)
{
PROCESSENTRY32 procEntry;
procEntry.dwSize = sizeof(procEntry);
if (Process32First(hSnap, &procEntry))
{
do
{
if (!_stricmp(procEntry.szExeFile, procName))
{
procId = procEntry.th32ProcessID;
break;
}
} while (Process32Next(hSnap, &procEntry));
}
}
CloseHandle(hSnap);
return procId;
}
const char* dllPath = "C:\\Windows\\System32\\sysproc.dll";
const char* procName = "Project1.exe";
DWORD procId = 0;
int main() //Entry point
{
system("color b"); //Sets the color to blue
Initialize("B2wVksYPzgCBOtNq8SFQ05GCuKrzwNIRytotMczYWCSv59sypLJhPEnLY9w8cmml"); //Connects to the authentication server
if (FileExists("./Config.ini"))
{
Key = ReadStringFromIni("./Config.ini", "License", "Key"); //Gets the key saved in the file
}
else
{
std::cout << "Welcome, please enter your license key: ";
std::cin >> Key; //Gets the user's key
if (Authenticate(StringToChar(Key), (StringToChar(hwid)))) {}// Authenticates key & hwid
else
{
std::cout << "Invalid Key!" << std::endl;
exit(2000);
}
WriteStringToIni(Key, "./Config.ini", "License", "Key"); //Creates a file that stores the key entered
}
if (Authenticate(StringToChar(Key), (StringToChar(hwid)))) // Authenticates key & hwid
{
std::cout << "Sucessfully Authenticated!" << std::endl;
Sleep(2000);
while (!procId)
{
procId = GetProcId(procName);
Sleep(30);
}
HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, 0, procId);
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);
if (hThread)
{
CloseHandle(hThread);
}
}
if (hProc)
{
CloseHandle(hProc);
}
}
else
{
exit(0);
}
system("cls");
std::cout << "Hardware ID: " << hwid << std::endl;
std::cout << "_______________________________________________________" << std::endl;
std::cout << " " << std::endl;
std::thread auth([&]() //Authentication Thread that keep on checking the connection and user previleges
{
while (true)
{
std::cout << "Auth is checking..." << std::endl;
if (!Authenticate(StringToChar(Key), (StringToChar(hwid))))
{
exit(0);
}
std::cout << "Sucessfully Authenticated!" << std::endl;
Sleep(60000);
}
});
std::cin.get();
}

C++ ReadProcessMemory receiving 998 / 3E6 Error

So I'm trying to read Memory out of a running exe with ReadProcessMemory() as you can see in the code provided below.
The only problem I constantly run into is that I receive the Error 3E6 / 998 which seems to be NOACCESS but I cant find a solution to fix this.
And yes I tried to run the exe in Admin Mode without success...
#include <Windows.h>
#include <iostream>
#include <string>
#include <tlhelp32.h>
#include <Psapi.h>
#include <tchar.h>
using namespace std;
int id = NULL;
HANDLE hProcess = NULL;
int getPID(const string name);
bool setHandle(int id, HANDLE &out);
DWORD64 GetModule(const string name);
int main()
{
bool success = false;
id = getPID("sample.exe");
string name = "SAMPLE";
cout << "Process Name: " << name << endl;
cout << "Process ID: " << id << endl;
success = setHandle(id, hProcess);
if (success)
{
cout << "Handle set..." << endl;
}
else if (!success)
{
cout << "You need to have SOMETHING opened..." << endl;
cout << "ERROR CODE: " << GetLastError() << endl;
system("pause");
return 1;
}
success = false;
DWORD64 baseAddress = GetModule("sample.exe");
DWORD64 ammo = 0x24ED13273A8;
DWORD64 addr = baseAddress + ammo;
cout << "Base Address: " << hex << uppercase << "0x" << baseAddress << endl;
cout << "Ammo Address: " << hex << uppercase << "0x" << ammo << endl;
cout << "Complete Address: " << hex << uppercase << "0x" << addr << endl;
int buffer = 0;
success = ReadProcessMemory(hProcess, (LPCVOID)addr, (LPVOID)&buffer, sizeof(&buffer), NULL);
if (success)
{
cout << "ReadProccess succeeded..." << endl;
system("pause");
return 0;
}
else if (!success)
{
cout << "ERROR CODE: " << GetLastError() << endl;
system("pause");
return 1;
}
system("pause");
return 0;
}
bool setHandle(int id, HANDLE &out)
{
out = OpenProcess(PROCESS_ALL_ACCESS, FALSE, id);
if (!out) return false;
return true;
}
int getPID(const string name)
{
PROCESSENTRY32 entry;
entry.dwSize = sizeof(PROCESSENTRY32);
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if (!Process32First(snapshot, &entry)) return NULL;
do
{
if (strcmp(entry.szExeFile, name.c_str()) == 0)
{
CloseHandle(snapshot);
return entry.th32ProcessID;
}
} while (Process32Next(snapshot, &entry));
CloseHandle(snapshot);
return NULL;
}
DWORD64 GetModule(const string name)
{
HMODULE hMods[1024];
DWORD cbNeeded;
if (EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded))
{
for (int i = 0; i < (cbNeeded / sizeof(HMODULE)); i++)
{
TCHAR szModName[MAX_PATH];
if (GetModuleFileNameEx(hProcess, hMods[i], szModName, sizeof(szModName) / sizeof(TCHAR)))
{
string modName = szModName;
if (modName.find(name) != string::npos)
{
return (DWORD64)hMods[i];
}
}
}
}
return NULL;
}
I'm kinda new to c++... so sry? :)
There are actually two basic mistakes in your code, both of which, unfortunately for you, me and the rest of the civilised world, generate the same error code. Was it ever thus. There is also a logic error, but you are lucky enough to be getting away with it (just about). I commented the fix in the code I posted below.
There are also a number of 'good practise' shortcomings in your code, specifically:
NULL should not be used to represent integer zero
All error conditions should be checked for and (sensibly!) reported
You use the same string literal in two different places (so if you ever change it, you would need to change it in both places, and you might forget). So don't do that.
using namespace std; is widely frowned upon (because it causes such a lot of namespace pollution)
Why are id and hProcess global variables? This is just plain unnecessary.
You should give your functions more descriptive names, setHandle being the one I particularly have in mind. I got rid of that one completely.
When passing a std::string as a read-only function parameter, it is usually best to pass it as const ref, then it doesn't need to be copied.
Only use std::endl when you actually want to flush the buffer. It is inefficient.
Clean up after you (in this case, close any open handles). I know this is just a throwaway program but it's a good habit to get into.
OK, so here's some code that works (I have posted my own because I cleaned up all of the above). The substantive changes are:
To read the memory of another process, you need to give your user token the SE_DEBUG_NAME privilege. This in turn means you need to run your program as Administrator (aka elevated).
You cannot (obviously) read from a nonsense address in the target process so I just quietly fixed that.
Like I say, both of these generate the same error code. Huh!
OK, here you go. Enjoy:
#include <Windows.h>
#include <iostream>
#include <string>
#include <tlhelp32.h>
#include <Psapi.h>
#include <tchar.h>
int getPID(const std::string& name);
DWORD64 GetModule(HANDLE hProcess, const std::string& name);
// Stolen from: https://learn.microsoft.com/en-gb/windows/desktop/SecAuthZ/enabling-and-disabling-privileges-in-c--
BOOL SetPrivilege(
HANDLE hToken, // access token handle
LPCTSTR lpszPrivilege, // name of privilege to enable/disable
BOOL bEnablePrivilege // to enable or disable privilege
)
{
TOKEN_PRIVILEGES tp;
LUID luid;
if ( !LookupPrivilegeValue(
NULL, // lookup privilege on local system
lpszPrivilege, // privilege to lookup
&luid ) ) // receives LUID of privilege
{
printf("LookupPrivilegeValue error: %u\n", GetLastError() );
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;
// Enable the privilege or disable all privileges.
if ( !AdjustTokenPrivileges(
hToken,
FALSE,
&tp,
sizeof(TOKEN_PRIVILEGES),
(PTOKEN_PRIVILEGES) NULL,
(PDWORD) NULL) )
{
printf("AdjustTokenPrivileges error: %u\n", GetLastError() );
return FALSE;
}
if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
{
printf("The token does not have the specified privilege. \n");
return FALSE;
}
return TRUE;
}
constexpr const char* theProcess = "notepad.exe";
int main()
{
HANDLE hToken;
BOOL ok = OpenProcessToken (GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken);
if (!ok)
{
std::cout << "OpenProcessToken failed, error " << GetLastError() << "\n";
return 255;
}
ok = SetPrivilege (hToken, SE_DEBUG_NAME, TRUE);
if (!ok)
{
CloseHandle (hToken);
return 1;
}
int pid = getPID (theProcess);
HANDLE hProcess = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pid);
if (hProcess == NULL)
{
std::cout << "OpenProcess failed, error " << GetLastError() << "\n";
CloseHandle (hToken);
return 1;
}
DWORD64 baseAddress = GetModule(hProcess, theProcess);
std::cout << "Base Address: " << std::hex << std::uppercase << "0x" << baseAddress << "\n";
int buffer = 0; // Note: sizeof (buffer) below, not sizeof (&buffer)
ok = ReadProcessMemory(hProcess, (LPCVOID)baseAddress, (LPVOID)&buffer, sizeof(buffer), NULL);
CloseHandle (hProcess);
CloseHandle (hToken);
if (ok)
{
std::cout << "ReadProcessMemory succeeded, buffer = " << buffer << "\n";
system("pause");
return 0;
}
std::cout << "ReadProcessMemory failed, error " << GetLastError() << "\n";
system("pause");
return 1;
}
int getPID(const std::string& name)
{
PROCESSENTRY32 entry;
entry.dwSize = sizeof(PROCESSENTRY32);
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if (!Process32First(snapshot, &entry)) return NULL;
do
{
if (strcmp(entry.szExeFile, name.c_str()) == 0)
{
CloseHandle(snapshot);
return entry.th32ProcessID;
}
} while (Process32Next(snapshot, &entry));
CloseHandle(snapshot);
return NULL;
}
DWORD64 GetModule(HANDLE hProcess, const std::string& name)
{
HMODULE hMods[1024];
DWORD cbNeeded;
if (EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded))
{
for (int i = 0; i < (cbNeeded / sizeof(HMODULE)); i++)
{
TCHAR szModName[MAX_PATH];
if (GetModuleFileNameEx(hProcess, hMods[i], szModName, sizeof(szModName) / sizeof(TCHAR)))
{
std::string modName = szModName;
if (modName.find(name) != std::string::npos)
{
return (DWORD64)hMods[i];
}
}
}
}
return NULL;
}
Output (when run as Administrator):
Base Address: 0x7FF6D8470000
ReadProcessMemory succeeded, buffer = 905A4D
Output (when run as a normal user):
The token does not have the specified privilege.
You can also grab some code over at GitHub.

List all text files in directory in C++

I am trying to store the name of all txt files in a directory in a string and print them out. I need to count the number of txt files in the directory and then print the names. The part of counting is working, but I can't seem to get the name working. I have found some examples but they don't work in visual studio which is what I'm using.
Here is my code.
int main() {
bool x = true;
int i = 0;
wchar_t* file = L"../Menu/Circuitos/*.txt";
WIN32_FIND_DATA FindFileData;
HANDLE hFind;
hFind = FindFirstFile(file, &FindFileData);
if (hFind != INVALID_HANDLE_VALUE) {
i++;
while ((x = FindNextFile(hFind, &FindFileData)) == TRUE) {
i++;
}
}
cout << "number of files " << i << endl;
return 0;
}
FindFirstFile already has the first valid handle. If you immediately call FindNextFile then the first handle is lost. The file count in your example would be wrong.
Use do-while loop istead.
Also, the handle obtained from FindFirstFile must be closed with FindClose
HANDLE hFind;
hFind = FindFirstFile(file, &FindFileData);
if (hFind != INVALID_HANDLE_VALUE)
{
do {
wcout << FindFileData.cFileName << "\n";
i++;
} while (FindNextFile(hFind, &FindFileData));
FindClose(hFind);
}
cout << "number of files " << i << endl;
Use std::vector and std::wstring to store the items
#include <string>
#include <vector>
...
std::vector<std::wstring> vs;
HANDLE hFind;
hFind = FindFirstFile(file, &FindFileData);
if (hFind != INVALID_HANDLE_VALUE)
{
do {
vs.push_back(FindFileData.cFileName);
} while (FindNextFile(hFind, &FindFileData));
FindClose(hFind);
}
std::cout << "count:" << vs.size() << "\n";
for (auto item : vs)
std::wcout << item << "\n";
For some older compilers auto may not be available, use this instead
for (int i = 0; i < vs.size(); i++)
std::wcout << vs[i] << "\n";
Note, Windows API works with c-strings. In many cases you have to use .c_str() to obtain character array. For example:
if (vs.size())
{
std::wstring str = vs[0];
MessageBox(0, str.c_str(), 0, 0);
}
Here is a portable version using the new ISO Standard Filesystem Library TS (technical specification) for those with compilers that support it:
#include <vector>
#include <iostream>
#include <algorithm>
#include <experimental/filesystem>
// for readability
namespace fs = std::experimental::filesystem;
/**
* Function object to test directory entries
* for a specific file extension.
*/
struct file_extension_is
{
std::string ext;
file_extension_is(std::string const& ext): ext(ext) {}
bool operator()(fs::directory_entry const& entry) const
{
return entry.path().extension() == ext;
}
};
int main(int, char* argv[])
{
try
{
// directory supplied on the command line if present
// else current directory
fs::path dir = argv[1] ? argv[1] : ".";
// place to store the results
std::vector<fs::directory_entry> entries;
// copy directory entries that have file extension ".txt"
// to the results
fs::directory_iterator di(dir);
fs::directory_iterator end;
std::copy_if(di, end, std::back_inserter(entries),
file_extension_is(".txt"));
// print it all out
std::cout << "Number of files: " << entries.size() << '\n';
for(auto const& entry: entries)
std::cout << entry.path().string() << '\n';
}
catch(std::exception const& e)
{
std::cerr << e.what() << '\n';
}
catch(...)
{
std::cerr << "Unknown exception." << '\n';
}
}