Win32 API + C - Overwrite Bytes at Specific Offset - c

I am pretty new to C, but using the standard library I would use something like the following code if I wanted to open a file and write data to a certain offset without overwriting the entire file.
ptrdiff_t offset = 0x44; // start offset of data I want to overwrite
FILE* f = fopen("file.sra", "r+b"); // open file in read/update mode
fseek(f, offset, SEEK_SET);
fwrite(buffer, 8, 1, f);
fclose(f);
I am learning how to use the Win32 API, and I can't seem to get equivalent functionality from the CreateFile() function. I have searched for similar questions, like these:
https://cboard.cprogramming.com/windows-programming/30783-overwrite-data-file.html
C++ Insert text at specific position in append with Windows API
Inserting text into file at specific offset using Win32 API
These posters seem to be asking the same general question, but the threads all dead end with no real answer.
Of course, I could just call fopen()/fwrite() and be done with it, but since I'm trying to learn the basics of Win32 API, I'd like to know if there is a way to achieve read/update functionality with just the Windows functions, particularly CreateFile().
Also, I know I can read the data and append and shift and all that, but that's not what I'm after. I want to achieve similar functionality to the example C code above by figuring out how to set CreateFile() to have a similar read/update mode.
Windows code I tried:
HANDLE hFile = CreateFile(pszFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL, NULL);
....<irrelevant code>....
SetFilePointer(hFile, offset, NULL, FILE_BEGIN);
if(WriteFile(hFile, buffer, 8, NULL, NULL))
bSuccess = TRUE;
}
CloseHandle(hFile);

Thanks to Simon in the comments, I was able to figure this out. The key was to replace CREATE_ALWAYS with OPEN_EXISTING like so:
HANDLE hFile = CreateFile(pszFileName, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
....<irrelevant code>....
SetFilePointer(hFile, offset, NULL, FILE_BEGIN);
if(WriteFile(hFile, buffer, 8, NULL, NULL))
bSuccess = TRUE;
}
CloseHandle(hFile);
This opens an existing file, sets the file pointer to a certain offset, and then writes 8 bytes to the existing file, overwriting only the previous 8 bytes at that location, leaving the rest of the file intact.

Related

AllocConsole issue when manually mapping PE + fetching output

I am working on a project that involves manually mapping and executing a PE inside of the project process. The main project whose code I am using as a basis for this can be found here: https://github.com/aaaddress1/RunPE-In-Memory/blob/master/RunPE-In-Memory/RunPEinMemory/RunPEinMemory.cpp
The project above compiles and runs fine. During the mapping of the PE that this project is used to run, it will hook the API's related to processing commandline arguments, allowing the user to manually specify arguments to the mapped PE rather than the mapped PE trying to use the arguments provided to RunPEinMemory.exe (since this is all happening inside the same process).
The project I am working towards differs from this base project in that:
I (have successfully already) hooked API's like ExitProcess and exit() and redirect them to ExitThread to prevent the mapped PE ending the RunPEinMemory.exe process
I need to eventually send the output from whatever the mapped PE is elsewhere. To do this, I am redirecting stdout/stderr to anonymous pipes that I later read from in RunPEinMemory prior to running the mapped PE.
I am struggling on the second account.
My project needs to be compiled as a GUI app (subsystem=windows) rather than a Console app (subsystem=console).
The issue arises in that in order to manipulate the stdin/stdout/stderr handles, a console needs to be attached to the process. There are numerous StackOverflow posts about this topic that cover using AllocConsole and then reopening the std handles in order to redirect output to the new console (or elsewhere). A prominent post on this matter can be seen here: Redirecting stdout in win32 does not redirect stdout
I have implemented this code and can successfully manually map/run powershell.exe (passing 'gci' as an argument for example). The stdout/stderr is redirected to anonymous pipes and then read, after which is it written out to a file (for testing purposes currently). This successful test is done with my project.exe compiled for subsystem=windows as intended.
This falls apart when I try to do the same thing with cmd.exe (passing '/c dir' as arguments). I this case, the output fails to make it to stdout or stderr, and there are no bytes to read from the anonymous pipes.
Now when I instead compile this project as a Console program (subsystem=console) and I remove the AllocConsole call (so using the console that Windows allocates for me), the program succeeds. I notice that the cmd.exe output goes to stderr, rather than stdout. But regardless, I am able to successfully redirect that output to one of the anonymous pipes, read it, and then write it out to file.
This leads me to believe that I am missing something when it comes to calling AllocConsole, some follow-on step to fully set up the environment so that certain programs can successfully send output to stdout/stderr. This post mentions a bit about cmd.exe using win32Api's to write to stdout/stderr (as opposed to the other ways to do so as mentioned in a previous link), so I'm wondering if I'm not successfully setting something up when manually allocating a console: https://stackoverflow.com/a/66689266/18776214
The relevant code is as such:
//Allocate console. This line is the one that gets commented out between console/windows test
BOOL suc = AllocConsole();
//Reopen streams after allocating console + disable buffering
FILE* fout;
FILE* ferr;
freopen_s(&fout, "CONOUT$", "r+", stdout);
freopen_s(&ferr, "CONOUT$", "r+", stderr);
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);
//Open anonymous pipes for stdout and stderr
HANDLE hreadout;
HANDLE hwriteout;
HANDLE hreaderr;
HANDLE hwriteerr;
SECURITY_ATTRIBUTES sao = { sizeof(sao),NULL,TRUE };
SECURITY_ATTRIBUTES sae = { sizeof(sae),NULL,TRUE };
CreatePipe(&hreadout, &hwriteout, &sao, 0);
CreatePipe(&hreaderr, &hwriteerr, &sae, 0);
printf("CreatePipe last error: %d\n", GetLastError());
printf("hreadout is: %p\n", hreadout);
printf("hwriteout is: %p\n", hwriteout);
printf("hreaderr is: %p\n", hreaderr);
printf("hwriterr is: %p\n", hwriteerr);
//Set std_output_handle and std_error_handle to the write-ends of anonymous pipes
SetStdHandle(STD_OUTPUT_HANDLE, hwriteout);
SetStdHandle(STD_ERROR_HANDLE, hwriteerr);
//Convert write-ends of anonymous pipes to file descriptors and use _dup2 to set stdout/stderr to anonymous pipes
int fo = _open_osfhandle((intptr_t)(hwriteout), _O_TEXT);
int fe = _open_osfhandle((intptr_t)(hwriteerr), _O_TEXT);
int res = _dup2(fo, _fileno(fout)); //_fileno(fout)
int res2 = _dup2(fe, _fileno(ferr)); //_fileno(ferr)
printf("fo is: %d\n", fo);
printf("fe is: %d\n", fe);
printf("res is: %d\n", res);
printf("res1 is: %d\n", res2);
//Execute manually mapped PE now that stdout/stderr have been redirected
Sleep(2000);
HANDLE hThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)retAddr, 0, 0, 0);
WaitForSingleObject(hThread, 5000);
Sleep(2000);
//Reopen streams again to set stdout/stderr back to console
freopen_s(&fout, "CONOUT$", "r+", stdout);
freopen_s(&ferr, "CONOUT$", "r+", stderr);
//check how much data there is to be read from pipe + allocate buffer
DWORD cbBytesAvailOut;
PeekNamedPipe(hreadout, NULL, NULL, NULL, &cbBytesAvailOut, NULL);
printf("PeekNamedPipe last error: %d\n", GetLastError());
printf("stdout bytes avail is: %d\n", cbBytesAvailOut);
DWORD cbBytesAvailErr;
PeekNamedPipe(hreaderr, NULL, NULL, NULL, &cbBytesAvailErr, NULL);
printf("PeekNamedPipe last error: %d\n", GetLastError());
printf("stderr bytes avail is: %d\n", cbBytesAvailErr);
//Allocate buffer based on number of bytes available to read
wchar_t* pipeBuf = calloc(cbBytesAvailErr + 2, sizeof(wchar_t));
char* convertBuf;
Sleep(2000);
//Currently only reading from a single pipe, edit this block as needed to get data when it exists
//Read from pipe
DWORD bytesRead;
printf("right before readfile!\n");
BOOL fSuccess = ReadFile(hreaderr, pipeBuf, (cbBytesAvailErr + 2) * sizeof(wchar_t), &bytesRead, NULL);
printf("fSuccess is: %d\n", fSuccess);
printf("ReadFile last error: %d\n", GetLastError());
printf("wide string: %ls\n", pipeBuf);
printf("normal string: %s\n", pipeBuf);
printf("bytesread is: %d\n", bytesRead);
//Write buffer out to disk
Sleep(2000);
char* filename = "C:\\Users\\User\\Inline-Execute-PE-main\\Inline-Execute-PE\\x64\\Release\\outfile.txt";
DWORD byteswritten;
HANDLE hFileOut = CreateFileA(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
WriteFile(hFileOut, pipeBuf, bytesRead, &byteswritten, NULL);
So the two scenarios are this:
Compile as console app with the above code with the first line (AllocConsole()) commented out, everything else the same, manually mapping cmd.exe with commandline args "cmd.exe /c dir" -> works, cmd.exe output is sent to stderr pipe and can be read
Compile as windows app with the above code, using AllocConsole(), manually mapping cmd.exe with commandline args "cmd.exe /c dir" -> fails, cmd.exe output is not captured
Again using powershell.exe works just fine. I'm thinking because maybe it uses a different means to write to stdout/stderr than cmd.exe does.
Does anyone have any ideas?
Edit: As an update, I tried putting the AllocConsole() call BEFORE the PE is mapped into memory by the RunPEinMemory project. This results in the output from cmd.exe displaying to the outputted console, however it isn't being redirected to the pipe still. That is progress at least, but it seems like the stdout/stderr from cmd.exe still isn't linked or connected to the overall process for some reason
I was finally able to resolve this problem.
The issue appears to be WHEN I was calling AllocConsole and redirecting the stdout/stderr.
Previously the order was:
Manually map PE
Fix IAT of PE
AllocConsole
Redirect stdout/stderr using freopen_s and SetStdHandle
Transform Win32 handles to C std handles using open_osfhandle and _dup2
CreateThread to run PE
The working order was:
AllocConsole
Redirect stdout/stderr using freopen_s and SetStdHandle
Manually map PE
Fix IAT of PE
Transform Win32 handles to C std handles using open_osfhandle and _dup2
CreateThread to run PE
So it looks like when the IAT of the mapped PE gets fixed/setup the console needs to already be there and properly set up first.

How do I open a zip within a zip with libzip

I am trying to open a zip inside a zip
#include "zip.h"
#include "gtk.h"
zip_t *mainzipfile = zip_open(g_file_get_path(file), ZIP_CHECKCONS, &error);
zip_file_t *childzip = zip_fopen(mainzipfile, "child.zip", ZIP_RDONLY);// this segfaults
zip_file_t *childofchild = zip_fopen_index((zip_t*)childzip, 1, ZIP_RDONLY);
From what I am seeing childzip is not being read as a zip so its seg faulting.
I tried casting because I know childzip is a zip file but the program is failing to see it as so
How do I set the zip_file_t as zip_t so that I can also extract its children
There is no generic support for opening a ZIP file inside a zip. To some extent, this is because reading ZIP file require direct access to the data (the ability to seek by offset). However, compressed ZIP files do not support the ability to read by offset. The only way to read a specific offset is to rewind the zip_file_t object, and skip over bytes.
The leaves two possible scenarios (assuming the goal is to avoid extracting the inside zip into a file).
1. Reading from uncompressed zip.
In most cases, when a ZIP archive is placed into another ZIP archive, the zip program will realize that compression will not be effective, and will use the 'store' method. In those situation, it is possible to use zip_source_zip method to create (seekable) zip_source, which then be opened
See https://libzip.org/documentation/zip_source.html
// Find index
zip_int64_t child_idx= zip_name_locate(main_zip, "child.zip", flags);
// Create zip_source from the complete child.zip
zip_source_t *src = zip_source_zip(archive, main_zip, child_idx, flags, 0, 0);
// Create zip_t
zip_t child_zip = zip_open_from_source(src, flags, &error);
// work with the child zip
2. Unzipping into memory.
As an alternative, and assuming that the ZIP can fit in memory, consider reading the whole child zip into memory, than using the same context of zip_source to create a zip_source, which can be opened. In theory, simpler to implement.
zip_stat (...) ;
N = size_of_child_zip(...) ;
zip_file_t *child_file = zip_fopen(main_zip, "child.zip", flags);
char *buffer = calloc(1, N);
zip_fread(child_file, buffer, N) ;
zip_source = zip_source_buffer_create(buffer, N, ...)
// Create zip_t
zip_t child_zip = zip_open_from_source(zip_source, flags, &error);
// work with the child zip

Using MapViewOfFile, pointer eventually walks out of memory space

All,
I'm using MapViewOfFile to hold part of a file in memory. There is a stream that points to this file and writes to it, and then is rewound. I use the pointer to the beginning of the mapped file, and read until I get to the null char I write as the final character.
int fd;
yyout = tmpfile();
fd = fileno(yyout);
#ifdef WIN32
HANDLE fm;
HANDLE h = (HANDLE) _get_osfhandle (fd);
fm = CreateFileMapping(
h,
NULL,
PAGE_READWRITE|SEC_RESERVE,
0,
4096,
NULL);
if (fm == NULL) {
fprintf (stderr, "%s: Couldn't access memory space! %s\n", argv[0], strerror (GetLastError()));
exit(GetLastError());
}
bp = (char*)MapViewOfFile(
fm,
FILE_MAP_ALL_ACCESS,
0,
0,
0);
if (bp == NULL) {
fprintf (stderr, "%s: Couldn't fill memory space! %s\n", argv[0], strerror (GetLastError()));
exit(GetLastError());
}
Data is sent to the yyout stream, until flushData() is called. This writes a null to the stream, flushes, and then rewinds the stream. Then I start from the beginning of the mapped memory, and read chars until I get to the null.
void flushData(void) {
/* write out data in the stream and reset */
fprintf(yyout, "%c%c%c", 13, 10, '\0');
fflush(yyout);
rewind(yyout);
if (faqLine == 1) {
faqLine = 0; /* don't print faq's to the data file */
}
else {
char * ps = bp;
while (*ps != '\0') {
fprintf(outstream, "%c%c", *ps, blank);
ps++;
}
fflush(outfile);
}
fflush(yyout);
rewind(yyout);
}
After flushing, more data is written to the stream, which should be set to the start of the memory area. As near as I can determine with gdb, the stream is not getting rewound, and eventually fills up the allocated space.
Since the stream points to the underlying file, this does not cause a problem initially. But, when I attempt to walk the memory, I never find the null. This leads to a SIGSEV. If you want more details of why I need this, see here.
Why am I not reusing the memory space as expected?
I think this line from the MSDN documentation for CreateFileMapping might be the clue.
A mapped file and a file that is accessed by using the input and output (I/O) functions (ReadFile and WriteFile) are not necessarily coherent.
You're not apparently using Read/WriteFile, but the documentation should be understood in terms of mapped views versus explicit I/O calls. In any case, the C RTL is surely implemented using the Win32 API.
In short, this approach is problematic.
I don't know why changing the view/file size helps; perhaps it just shifts the undefined behaviour in a direction that happens to be beneficial.
Well, after working on this for a while, I have a working solution. I don't know why this succeeds, so if someone comes up with something better, I'll be happy to accept their answer instead.
fm = CreateFileMapping(
h,
NULL,
PAGE_READWRITE|SEC_RESERVE,
0,
16384,
NULL);
As you can see, the only change is to the size declared from 4096 to 16384. Why this works when the total chars input at a time is no more than 1200, I don't know. If someone could provide details on this, I would appreciate it.
When you're done with the map, simply un-map it.
UnmapViewOfFile(bp);

CreateFile always override the specified file

I'm trying to log the actions made by a service I wrote using the Windows-API & C-language, so I made a log file system.
The problem is that at each CreateFile call, the file is overridden instead of just opening it and write at the end of the file.
Here's the code of my WriteInLogfile function :
void WriteInLogFile(LPCTSTR log_string)
{
HANDLE hFile;
DWORD dBytesWritten;
if ((hFile = CreateFile(LOG_FILE_PATH, GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE
&& (GetLastError() == ERROR_FILE_NOT_FOUND))
{
if ((hFile = CreateFile(LOG_FILE_PATH, GENERIC_WRITE, 0, NULL,
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE)
{
if (!WriteFile(hFile, log_string, strlen(log_string), &dBytesWritten, NULL))
aff_error("WriteInLogFile");
CloseHandle(hFile);
}
}
else
{
if (!WriteFile(hFile, log_string, strlen(log_string), &dBytesWritten, NULL))
aff_error("WriteInLogFile");
CloseHandle(hFile);
}
}
Do someone know where the issue comes from ?
Thanks ;)
Even though you're opening the existing file you're not specifying that you want to append to it. Hence it opens as a generic write and you end up overwriting the contents. You need to pass the FILE_APPEND_DATA flag to the CreateFile method. This is best done by using the FILE_GENERIC_WRITE flag which includes FILE_APPEND_DATA
if ((hFile = CreateFile(LOG_FILE_PATH, FILE_GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE
&& (GetLastError() == ERROR_FILE_NOT_FOUND))
{
When you open a file, the pointer will always be positioned to the beginning of the file. To append, you need to explicitly seek to the end (SetFilePointer(hFile, 0, 0, FILE_END);).
Although it may not be causing your actual problem, I'd replace your current logic trying to use CreateFile with OPEN_EXSTING, then with CREATE_NEW if the first attempt fails. Instead, just pass the OPEN_ALWAYS flag, which pretty much automates that logic -- open an existing file if it exists, and create a new one if it doesn't.
You need to set the file pointer to the end of the file before writing with SetFilePointer. See the MSDN example.
I couldn't see anything obvious about opening for Append in the CreateFile documentation, but you could use the SetFilePointer
function to seek to the end of the file before writing.

How do I retrieve the FILE* of a CreateFile result?

See title.
How do I achieve the opposite of this question: How do I get the file HANDLE from the fopen FILE structure?
I create the handle with
HANDLE h = CreateFile(name,
GENERIC_WRITE,
0,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
and then try to write some data to it using fputs.
The call to fputs fails on the line
_VALIDATE_STREAM_ANSI_RETURN(stream, EINVAL, EOF);
where stream is the handle I obtained from CreateFile.
The reason why I'm doing that is that I use an external library that uses FILE* handles and I'm not opening a plain file (as until now) but trying to write to a pipe instead. And changing the external library is not an option.
Don't know if this is the best way but see _open_osfhandle():
http://msdn.microsoft.com/en-us/library/bdts1c9x(v=vs.71).aspx
int fd = _open_osfhandle(h, ...);
It returns a file descriptor which you'll have to open using fdopen to get a FILE*.
FILE* fp = _fdopen(fd, ...);

Resources