std::cout << buffer << std::endl;
if (lastTitle != buffer) {
//write new title;
WriteFile(file, "\n\nWindow: ", sizeof("\n\nWindow: "), NULL, NULL);
WriteFile(file, buffer.c_str(), sizeof(buffer), NULL, NULL);
WriteFile(file, "\n", sizeof("\n"), NULL, NULL);
std::cout << GetLastError(); //this is showing 0, which means no error
Cout is outputting:
C:\Users\riseo\Desktop\C++\my_proj\Debug\my_proj.exe
The file that is being written to is showing:
Window: C:\Users\riseo\Desktop\C++\m
I'm not quite sure why this is being truncated, it should be the same as what cout is printing. Im sorry this post doesn't show much research, but I've been getting burned by various string-format related gotchas all day and I have no clue what is happening here. All I can think of is maybe something with c_str() is going wrong.
You are seriously misusing sizeof(). WriteFile() operates on bytes, but you are passing it character data. String literals contain a null terminator that sizeof() would include, which you don't want in this case. And std::string() contains a pointer to the character data, so sizeof(std::string) does not account for the true character length.
You need to do this instead:
//write new title;
WriteFile(file, "\n\nWindow: ", strlen("\n\nWindow: "), NULL, NULL);
WriteFile(file, buffer.c_str(), buffer.length(), NULL, NULL);
WriteFile(file, "\n", strlen("\n"), NULL, NULL);
A wrapper function would be better:
bool WriteStringToFile(HANDLE hFile, const std::string &str)
{
return WriteFile(hFile, str.c_str(), str.length(), NULL, NULL);
}
...
//write new title;
WriteStringToFile(file, "\n\nWindow: ");
WriteStringToFile(file, buffer);
WriteStringToFile(file, "\n");
A std::ofstream would be even better:
std::ofstream ofs("myfile.txt", std::ios_base::binary);
...
ofs << "\n\nWindow: " << buffer << "\n";
Related
I am writing a method to add data to registry key using RegSetValueEx() after checking the registry the value has not been written to the key. All 3 functions I use to load the hive, key and add value are returning ERROR_SUCCESS which has got me stumped. I have read this and this, however both of these questions suggest I should be receiving an error if I were coming across these problems.
I feel I am missing something to do with wide strings, ANSI and Unicode, although I cannot understand what. I could be way off base here though. I will also add that Visual Studio is running as Admin.
This is the code I have written so far:
#include <iostream>
#include <Windows.h>
int addValuetoRegistryKey(std::string executable) {
LPCWSTR registryKey = L"Software\\Classes\\mscfile\\shell\\open\\command\\";
HKEY hiveHandle;
HKEY keyHandle;
if (RegOpenCurrentUser(KEY_SET_VALUE, &hiveHandle) != ERROR_SUCCESS) {
wchar_t buf[256];
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
buf, (sizeof(buf) / sizeof(wchar_t)), NULL);
/* Display error */
std::wcout << "Opening hive failed: " << buf << std::endl;
return -1;
}
else {
std::wcout << "HKCU Hive opened successfully" << std::endl;
}
if (RegOpenKeyEx(hiveHandle, registryKey, 0, KEY_SET_VALUE, &keyHandle) != ERROR_SUCCESS) {
wchar_t buf[256];
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
buf, (sizeof(buf) / sizeof(wchar_t)), NULL);
/* Display error */
std::wcout << "Opening key failed: " << buf << std::endl;
return -1;
}
else {
std::wcout << registryKey << " opened successfully" << std::endl;
}
if (RegSetValueEx(keyHandle, NULL, 0, REG_SZ, (LPCBYTE)executable.c_str(), executable.size() + 1) != ERROR_SUCCESS) {
wchar_t buf[256];
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
buf, (sizeof(buf) / sizeof(wchar_t)), NULL);
/* Display error */
std::wcout << "Writing value to key failed: " << buf << std::endl;
return -1;
}
else {
std::wcout << executable.c_str() << " written to key" << std::endl;
}
RegCloseKey(keyHandle);
RegCloseKey(hiveHandle);
return 0;
}
int main() {
addValuetoRegistryKey("C:\\Windows\\System32\\cmd.exe");
}
Full disclosure: I am a computer security graduate, and some users may notice that I am trying to implement a method for UAC bypass. This is simply for educational purposes, instead of implementing metasploit modules, I would like to write the code and understand the workflow myself.
This is the data returned to the console:
Thanks for dxiv for pointing me toward the right resources.
Firstly, after reading the Microsoft information, I decided to change all strings to wide strings, as ANSI no longer needs to be supported in new applications, or when NOT taking user input.
std::string executable to LPCWSTR executable,
std::wcout << executable.c_str() << " written to key" << std::endl; to std::wcout << executable << " written to key" << std::endl;
addValuetoRegistryKey("C:\\Windows\\System32\\cmd.exe"); to addValuetoRegistryKey(L"C:\\Windows\\System32\\cmd.exe");
Next I chose to use the specific wide character implementation of RegSetValueEx, RegSetValueExW.
Using (wcslen(executable) + 1) * sizeof(wchar_t) to calculate the length of executable for the final parameter.
The final code is below:
#include <iostream>
#include <Windows.h>
int addValuetoRegistryKey(LPCWSTR executable) {
LPCWSTR registryKey = L"Software\\Classes\\mscfile\\shell\\open\\command\\";
HKEY hiveHandle;
HKEY keyHandle;
if (RegOpenCurrentUser(KEY_SET_VALUE, &hiveHandle) != ERROR_SUCCESS) {
wchar_t buf[256];
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
buf, (sizeof(buf) / sizeof(wchar_t)), NULL);
/* Display error */
std::wcout << "Opening hive failed: " << buf << std::endl;
return -1;
}
else {
std::wcout << "HKCU Hive opened successfully" << std::endl;
}
if (RegOpenKeyEx(hiveHandle, registryKey, 0, KEY_SET_VALUE, &keyHandle) != ERROR_SUCCESS) {
wchar_t buf[256];
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
buf, (sizeof(buf) / sizeof(wchar_t)), NULL);
/* Display error */
std::wcout << "Opening key failed: " << buf << std::endl;
return -1;
}
else {
std::wcout << registryKey << " opened successfully" << std::endl;
}
if (RegSetValueExW(keyHandle, NULL, 0, REG_SZ, (LPCBYTE) executable, (wcslen(executable) + 1) * sizeof(wchar_t)) != ERROR_SUCCESS) {
wchar_t buf[256];
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
buf, (sizeof(buf) / sizeof(wchar_t)), NULL);
/* Display error */
std::wcout << "Writing value to key failed: " << buf << std::endl;
return -1;
}
else {
std::wcout << executable << " written to key" << std::endl;
}
RegCloseKey(keyHandle);
RegCloseKey(hiveHandle);
return 0;
}
int main() {
addValuetoRegistryKey("C:\\Windows\\System32\\cmd.exe");
}
The value is now written to the registry correctly. Upon reading more of the Microsoft docs, the function RegSetKeyValueW was suggested. I have implemented this method, however, I wanted to work out how to do this correctly, and post here.
For anyone who stumbles upon this question, and would like an example of how to implement the RegSetKeyValueW function, you can find the code below:
if (RegSetKeyValueW(keyHandle, NULL, 0, REG_SZ, executable, (wcslen(executable) + 1) * sizeof(wchar_t)) != ERROR_SUCCESS) {
wchar_t buf[256];
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
buf, (sizeof(buf) / sizeof(wchar_t)), NULL);
/* Display error */
std::wcout << "Writing value to key failed: " << buf << std::endl;
return -1;
}
else {
std::wcout << executable << " written to key" << std::endl;
}
So my task goes like this:
The program needs 2 processes in one main function
First process creates or opens a file "log.txt" which is in the same directory where the program is located. Then it adds user input to this file.
Second process is a "monitor" of this file. It checks if the file exists, shows its size and shows how many characters were entered since the second process started.
Note that I am aware that the program itself is a process, but it needs to be done like that. There are some "tips" to use a file as mutex (CreateFile parameters) that would be the dsShareMode with FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE parameter.
Now my question is: how do you create 2 processes to handle its own line of code? I've seen many examples of CreateProcess function but I don't really understand the first two parameters of this function
lpApplicationName
and
lpCommandLine
What am I supposed to pass to it in order to run 2 processes, one to handle the user input and the other to be the "monitor"?
The first process is meant to handle those lines of code:
std::string buffer;
std::cout << "Enter your text:" << std::endl;
getline(std::cin, buffer);
HANDLE hFile = CreateFile("log.txt", FILE_APPEND_DATA, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
DWORD written = 0;
WriteFile(hFile, buffer.c_str(), buffer.size(), &written, NULL);
While the second process should only care about this:
hFile = CreateFile("log.txt", FILE_READ_ATTRIBUTES, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (hFile == INVALID_HANDLE_VALUE)
{
std::cout << "CreateFile error " << GetLastError() << std::endl;
}
else
{
DWORD size = GetFileSize(hFile, NULL);
std::cout << "\nCurrent file size: " << size << std::endl;
CloseHandle(hFile);
}
int stringLength = 0;
for(int i=0; buffer[i]; i++)
stringLength++;
std::cout << "\nCharacters given since last startup: " << stringLength << std::endl;
Assuming you have a separate helper.exe, you can do:
CreateProcess(nullptr, "helper logger-mode", ...)
and
CreateProcess(nullptr, "helper monitor-mode", ...)
This will create two processes that see either logger-mode or monitor-mode in their second argument (argv[1]).
The question appears to demand having the same program being run as two separate processes. If that is the case, the program will need to handle command line arguments and tailor its functionality accordingly.
#Botje I've managed to do something like that. Could you take a look at tell me if such solution is acceptable?
int main(int argc, char *argv[])
{
std::string cmdline1 = "main Proc1";
std::string cmdline2 = "main Proc2";
std::string buffer;
HANDLE hFile;
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
ZeroMemory(&pi, sizeof(pi));
si.cb = sizeof(si);
CreateProcess(argv[0], const_cast<char *>(cmdline1.c_str()), NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
CreateProcess(argv[0], const_cast<char *>(cmdline2.c_str()), NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
if(strcmp(argv[1], "Proc1"))
{
while(1)
{
std::cout << "Enter your text:" << std::endl;
getline(std::cin, buffer);
hFile = CreateFile("log.txt", FILE_APPEND_DATA, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
DWORD written = 0;
WriteFile(hFile, buffer.c_str(), buffer.size(), &written, NULL);
}
}
if(strcmp(argv[1], "Proc2"))
{
DWORD charactersGiven = 0;
while(1)
{
hFile = CreateFile("log.txt", GENERIC_READ, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (hFile == INVALID_HANDLE_VALUE)
{
std::cout << "CreateFile error " << GetLastError() << std::endl;
}
else
{
DWORD size = GetFileSize(hFile, NULL);
std::cout << "\nCurrent file size: " << size << std::endl;
if(charactersGiven == 0)
charactersGiven = size;
std::cout << "Characters given since last startup: " << size - charactersGiven << std::endl;
}
Sleep(4000);
}
}
return 0;
}
INTRODUCTION:
I am reading from text file with ReadFile. Buffer passed to ReadFile is sent to standard output with cout. Standard output is redirected to a text file.
PROBLEM:
Although my code "works", no data is lost, resulting file is larger than the original one.
When opened in notepad, everything seems fine, but when opened in Notepad++ I can clearly see extra lines added. These lines are new lines (\n).
MVCE that reproduces this behavior is submitted below.
#include <iostream>
#include <Windows.h>
int main()
{
HANDLE hFile = ::CreateFile("C:\\123.txt",
GENERIC_READ,
FILE_SHARE_READ |
FILE_SHARE_WRITE |
FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (INVALID_HANDLE_VALUE == hFile)
return ::GetLastError();
char buffer[256];
DWORD bytesRead = 1, // dummy value so while loop can work
bytesWritten = 0; // needed for WriteFile, not for cout version
//======== so WriteFile outputs to console, not needed for cout version
HANDLE hStandardOutput = ::GetStdHandle(STD_OUTPUT_HANDLE);
if (INVALID_HANDLE_VALUE == hStandardOutput)
{
std::cout << "GetStdHandle error code = " << ::GetLastError() << std::endl;
::CloseHandle(hFile);
return ::GetLastError();
}
//============================
while(bytesRead)
{
// '\0' terminate buffer, needed for cout only
::memset(buffer, '\0', sizeof(buffer));
if (!::ReadFile(hFile,
buffer,
sizeof(buffer) - 1, // - 1 for '\0', not needed when using WriteFile
&bytesRead, NULL))
{
std::cout << "ReadFile error code = " << ::GetLastError() << std::endl;
break;
}
/*============= Works fine
if(!::WriteFile(hStandardOutput, buffer, bytesRead, &bytesWritten, NULL))
{
std::cout << "WriteFile error code = " << ::GetLastError() << std::endl;
break;
}*/
//------------- comment out when testing WriteFile
std::cout << buffer; // extra lines...
// std::cout.write(buffer, bytesRead); // extra lines as well...
//----------------------------------------
}
::CloseHandle(hFile);
return 0;
}
QUESTION:
What is causing above described behavior? How to fix it?
MY EFFORTS TO SOLVE THE PROBLEM:
As I type this post I am Googling aimlessly, hoping for some clue to show up.
I suspect that the problem lies when outputting \n, it seems that Windows inserts \r as well, but I am not sure.
The \n character has special meaning to STL character streams. It represents a newline, which gets translated to the platform-specific line break upon output. This is discussed here:
Binary and text modes
A text stream is an ordered sequence of characters composed into lines (zero or more characters plus a terminating '\n'). Whether the last line requires a terminating '\n' is implementation-defined. Characters may have to be added, altered, or deleted on input and output to conform to the conventions for representing text in the OS (in particular, C streams on Windows OS convert \n to \r\n on output, and convert \r\n to \n on input) .
So it is likely that std::cout outputs \r\n when it is given \n, even if a preceding \r was also given, thus an input of \r\n could become \r\r\n on output. It is not standardized behavior on Windows how individual apps handle bare-CR characters. They might be ignored, or they might be treated as line breaks. In your case, it sounds like the latter.
There is no standard way to use std::cout in binary mode so \n is output as \n instead of as \r\n. However, see How to make cout behave as in binary mode? for some possible ways that you might be able to make std::cout output in binary mode on Windows, depending on your compiler and STL implementation. Or, you could try using std::cout.rdbuf() to substitute in your own std::basic_streambuf object that performs binary output to the console.
That being said, the way your code is handling the data buffer is a little off, it should look more like this instead (not accounting for the above info):
#include <iostream>
#include <Windows.h>
int main()
{
HANDLE hFile = ::CreateFile("C:\\123.txt",
GENERIC_READ,
FILE_SHARE_READ |
FILE_SHARE_WRITE |
FILE_SHARE_DELETE, // why??
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (INVALID_HANDLE_VALUE == hFile)
return ::GetLastError();
char buffer[256];
DWORD bytesRead, bytesWritten, err;
//======== so WriteFile outputs to console, not needed for cout version
HANDLE hStandardOutput = ::GetStdHandle(STD_OUTPUT_HANDLE);
if (INVALID_HANDLE_VALUE == hStandardOutput)
{
err = ::GetLastError();
std::cout << "GetStdHandle error code = " << err << std::endl;
::CloseHandle(hFile);
return err;
}
//============================
do
{
if (!::ReadFile(hFile, buffer, sizeof(buffer), &bytesRead, NULL))
{
err = ::GetLastError();
std::cout << "ReadFile error code = " << err << std::endl;
::CloseHandle(hFile);
return err;
}
if (bytesRead == 0) // EOF reached
break;
/*============= Works fine
if (!::WriteFile(hStandardOutput, buffer, bytesRead, &bytesWritten, NULL))
{
err = ::GetLastError();
std::cout << "WriteFile error code = " << err << std::endl;
::CloseHandle(hFile);
return err;
}
*/
//------------- comment out when testing WriteFile
std::cout.write(buffer, bytesRead);
//----------------------------------------
}
while (true);
::CloseHandle(hFile);
return 0;
}
So, i'm injecting a code in the memory of another process like this:
void RemoteInj::ExecuteFunction(DWORD Start, DWORD End, DWORD Entry, RemoteArgs* Args)
{
unsigned long Id;
int size = End - Start;
cout << size << endl;
void* Func = VirtualAllocEx(hProcess, NULL, size+10, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
void* ep = (void*)(Entry-Start+(DWORD)(Func));
WriteProcessMemory(hProcess, Func, (void*)Start, size, NULL);
void* Data = VirtualAllocEx(hProcess, NULL, sizeof(RemoteArgs)+1, MEM_COMMIT, PAGE_READWRITE);
WriteProcessMemory(hProcess, Data, (void*)Args, sizeof(RemoteArgs), NULL);
cout << hex << Func << endl;
cout << "Function: 0x" << hex << Start << endl << "End: 0x" << hex << End << endl;
system("PAUSE");
CreateRemoteThread(hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)ep, Data, NULL, NULL);
CloseHandle(hProcess);
}
My problem is: If i use calls in that thread, for example:
void F(RemoteArgs* arg)
{
while (true)
{
arg->pSleep(50); //Works
Sleep(50); //doesnt work
}
return;
}
No need to explain why it doesn't work, i know, it's another process....My question is: Is there a way to make function like this(Sleep()) work, i could try importing to the process also the IAT with the proper distance, do you have a better idea?Thanks!
As you suspect, the reason this doesn't work right off the bat is that the call to Sleep in your process actually goes to a location in your import address table (IAT) which has a jump to the real Sleep implementation in kernel32.dll. Even though the other process also imports kernel32.dll (all processes do), it obviously does not have an identical IAT.
There are ways, but none that I know of are trivial.
I am using ReadFile to read a simple string that I wrote to a file using WriteFile.
Have a simple string: "Test string, testing windows functions".
Used WriteFile to write that to a file.
Now I want to use ReadFile to confirm that it was written to the file. I need to compare what I read to the original string above. To Read from the file I have
DWORD dwBytesRead;
char buff[128];
if(!ReadFile(hFile, buff, 128, &dwBytesRead, NULL))
//Fail
The function returns true so it is reading from the file. The problem is buff is full of just ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ. I've never come across LPVOID before so I don't know if it is something there or what. Is there a way to do this string comparison?
EDIT: The code i use to write to the file is quite simple:
if(!WriteFile(hFile, sentence.c_str(), sentence.length(), &bytesWritten, NULL))
{
//FAIL
}
The file pointer needs rewound after the WriteFile() and before the ReadFile(). As it stands, ReadFile() does not fail but reads zero bytes thus buff is unchanged. As buff is uninitialised it contains junk. To rewind the file pointer to the beginning of the file use SetFilePointer():
#include <windows.h>
#include <iostream>
#include <string>
int main()
{
HANDLE hFile = CreateFile ("myfile.txt",
GENERIC_WRITE | GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFile)
{
std::string sentence("a test");
DWORD bytesWritten;
if (WriteFile(hFile,
sentence.c_str(),
sentence.length(),
&bytesWritten,
NULL))
{
if (INVALID_SET_FILE_POINTER != SetFilePointer(hFile,
0,
0,
FILE_BEGIN))
{
char buf[128] = { 0 }; /* Initialise 'buf'. */
DWORD bytesRead;
/* Read one less char into 'buf' to ensure null termination. */
if (ReadFile(hFile, buf, 127, &bytesRead, NULL))
{
std::cout << "[" << buf << "]\n";
}
else
{
std::cerr << "Failed to ReadFile: " <<
GetLastError() << "\n";
}
}
else
{
std::cerr << "Failed to SetFilePointer: " <<
GetLastError() << "\n";
}
}
else
{
std::cerr << "Failed to WriteFile: " << GetLastError() << "\n";
}
CloseHandle(hFile);
}
else
{
std::cerr << "Failed to open file: " << GetLastError() << "\n";
}
return 0;
}
The function returns true so it is reading from the file. The problem is buff is full of just ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ.
ReadFile only fills the buffer up to the value of dwBytesRead. If you're trying to work with a string, you'll have to null terminate it yourself after ReadFile returns:
buff [dwBytesRead] = 0;
You should not use 128 as the nNumberOfBytesToRead, since you can get out of bounds while printing the string (or otherwise considering buff as a 0-terminated string). Also check dwBytesRead if it really reads that many bytes, and 0-terminate the string as suggested by #James McLaughlin.