Proper Way to write to shared memory Windows - c

I have 2 processes, 1 process needs to write to a shared memory segment, the other process needs to read from the shared memory segment. The writing process only writes to shared mem, the reading process only reads.
Writing process
HANDLE hMapFile;
LPCTSTR pBuf;
char* Message = "test";
int MessageSize = 5;
hMapFile = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_EXECUTE_READWRITE, 0, Size, SegmentName);
if (hMapFile == NULL)
{
printf("Could not create file mapping object (%d).\n", GetLastError());
return NULL;
}
pBuf = (LPTSTR)MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, Size);
if (pBuf == NULL)
{
printf("Could not map view of file (%d).\n", GetLastError());
//CloseHandle(hMapFile);
return NULL;
}
CopyMemory((PVOID)pBuf, Message, MessageSize);
Shortly after my reading process will read the message like so
HANDLE hMapFile;
LPCTSTR pBuf;
hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, SegmentName);
if (hMapFile == NULL)
{
printf("Could not open file mapping object MINER PROC (%d).\n", GetLastError());
exit(0);
//return RetVal;
}
RetVal = (LPTSTR)MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, Size);
if (RetVal == NULL)
{
printf("Could not map view of file (%d).\n", GetLastError());
CloseHandle(hMapFile);
exit(0);
//return RetVal;
}
UnmapViewOfFile(hMapFile);
CloseHandle(hMapFile);
This works perfectly for a 1 time write then read. I need the writing process to be able to change the values.
I've tried this in the writing process
memset((PVOID)pBuf, '\0', strlen(OriginalMessage));
CopyMemory(pBuf, "newmessage",
strlen("newmessage") + 1);
But this gives me random crashes in the writing process, although the reading process seems to be able to read the changes fine.
I've also tried to close the segment like this from the writing process immediately after CopyMemory() call
UnmapViewOfFile(pBuf);
CloseHandle(hMapFile);
But then the memory disappears and the reading process cannot read the segment name. I also tried calling UnmapViewOfFile() & CloseHandle() then creating a new memory segment with the same name and I keep getting random crashes after that.
What is the proper way to change a shared memory value of a given shared memory segment name without crashes? Thanks.
EDIT - I'd like to add that I tested this code using the described methods (creating new shared memory segments) on 4 Win10 machine, 2 Win7 machines and I got no crashes. The crashes only occur on a Win8.1 machine. it's quite odd.
EDIT2 - also, all functions are successful in both the reading and writing processes when the crash occurs.

Related

how to get heap start address of a elf binary

I have written a sample program in C that uses libelf to dump the different sections.
However i want to dump the heap & stack segment starting address which is only available when the process is "live" (running).
This is what i do for a binary i read from disk.
elf_fd = open(elf_fname, O_RDWR);
if(elf_fd < 0) {
fprintf(stderr, "Failed to open \"%s\" reason=%s\n", elf_fname, strerror(errno));
return -1;;
}
followed by
if(elf_version(EV_CURRENT) == EV_NONE) {
fprintf(stderr, "Failed to initialize libelf\n");
res = -1;
goto done;
}
elf->e = elf_begin(elf->fd, ELF_C_READ, NULL);
if(!elf->e) {
int err = elf_errno();
if (err != 0) {
fprintf(stderr, "Failed to open ELF file code=%d reason=%s\n", err,
elf_errmsg(err));
}
res = -1;
goto done;
}
This works fine when i read the binary image on disk
For run time what i tried is instead of doing this
That is using the elf_fd returned by open
elf_fd = open(elf_fname, O_RDWR);
if(elf_fd < 0) {
fprintf(stderr, "Failed to open \"%s\" reason=%s\n", elf_fname, strerror(errno));
return -1;;
}
I instead do this
That is i get a handle from the pid of the current process
elf_fd = pidfd_open(getpid(), 0);
if (elf_fd == -1) {
perror("pidfd_open");
fprintf(stderr, "failed to open self %d\n", elf_fd);
exit(EXIT_FAILURE);
}
It returns me a valid descriptor but when i use this descriptor with
elf->e = elf_begin(elf->fd, ELF_C_READ, NULL);
if(!elf->e) {
int err = elf_errno();
if (err != 0) {
fprintf(stderr, "Failed to open ELF file code=%d reason=%s\n", err,
elf_errmsg(err));
}
}
It says "Invalid descriptor".
Question is how can i get heap & stack base address of a live process from within it
Also yes i did also try at the very start in main call
sbrk(0) & that seems to print the heap start address but this may not always be reliable as there maybe no heap without a malloc call prior
for now it does seem to print it.
Question is how can i get heap & stack base address of a live process from within it
Note that neither heap, nor stack have anything to do with the ELF format, or libelf.
There is no such thing as "heap base address" -- most modern heap allocators will perform multiple mmap calls to obtain memory from the OS, then "dole" it out to various malloc requests.
i did also try at the very start in main call sbrk(0)
"Legacy" malloc used to obtain memory using sbrk(), but few modern ones do. If the malloc you are using does use sbrk, then calling sbrk(0) near the start of main is a usable approximation.
For the main thread stack, you would want to do the same. A good first approximation is taking &argc, and rounding it up to page boundary.
If you want to get better approximation, you could use the fact that on Linux (and possibly other ELF platforms) the kernel puts specific values on the stack before invoking the entry point. Iterating through the __environ values looking for the highest address will give a better approximation.

Mapping files into virtual memory in C on Windows

On POSIX systems, I am able to use the mmap function to read the contents of a file faster than getline, getc, etc. This is important in the program that I am developing as it is expected to read very large files into memory; iteratively collecting lines using getline is too costly. Portability is also a requirement of my software, so if I use mmap, I need to find a way to memory map files using the WinApi, as I'd rather not compile through cygwin/msys. From a cursory search I identified this MSDN article which describes very briefly a way to map files into memory, however, from trawling through documentation I can't make head nor tails of how to actually implement it, and I'm stuck on finding example snippets of code, like there are for POSIX mmap.
How do I use the WinApi's memory mapping options to read a file into a char*?
How do I use the WinApi's memory mapping options to read a file into a
char*?
Under Windows, when you map a file in memory, you get a pointer to the memory location where the first byte of the file has been mapped. You can cast that pointer to whatever datatype you like, including char*.
In other words, it is Windows which decide where the mapped data will be in memory. You cannot provide a char* and expect Windows will load data there.
This means that if you already have a char* and want the data from the file in the location pointed by that char*, then you have to copy it. Not a good idea in terms of performances.
Here is a simple program dumping a text file by mapping the file into memory and then displaying all ASCII characters. Tested with MSVC2019.
#include <stdio.h>
#include <Windows.h>
int main(int argc, char *argv[])
{
TCHAR *lpFileName = TEXT("hello.txt");
HANDLE hFile;
HANDLE hMap;
LPVOID lpBasePtr;
LARGE_INTEGER liFileSize;
hFile = CreateFile(lpFileName,
GENERIC_READ, // dwDesiredAccess
0, // dwShareMode
NULL, // lpSecurityAttributes
OPEN_EXISTING, // dwCreationDisposition
FILE_ATTRIBUTE_NORMAL, // dwFlagsAndAttributes
0); // hTemplateFile
if (hFile == INVALID_HANDLE_VALUE) {
fprintf(stderr, "CreateFile failed with error %d\n", GetLastError());
return 1;
}
if (!GetFileSizeEx(hFile, &liFileSize)) {
fprintf(stderr, "GetFileSize failed with error %d\n", GetLastError());
CloseHandle(hFile);
return 1;
}
if (liFileSize.QuadPart == 0) {
fprintf(stderr, "File is empty\n");
CloseHandle(hFile);
return 1;
}
hMap = CreateFileMapping(
hFile,
NULL, // Mapping attributes
PAGE_READONLY, // Protection flags
0, // MaximumSizeHigh
0, // MaximumSizeLow
NULL); // Name
if (hMap == 0) {
fprintf(stderr, "CreateFileMapping failed with error %d\n", GetLastError());
CloseHandle(hFile);
return 1;
}
lpBasePtr = MapViewOfFile(
hMap,
FILE_MAP_READ, // dwDesiredAccess
0, // dwFileOffsetHigh
0, // dwFileOffsetLow
0); // dwNumberOfBytesToMap
if (lpBasePtr == NULL) {
fprintf(stderr, "MapViewOfFile failed with error %d\n", GetLastError());
CloseHandle(hMap);
CloseHandle(hFile);
return 1;
}
// Display file content as ASCII charaters
char *ptr = (char *)lpBasePtr;
LONGLONG i = liFileSize.QuadPart;
while (i-- > 0) {
fputc(*ptr++, stdout);
}
UnmapViewOfFile(lpBasePtr);
CloseHandle(hMap);
CloseHandle(hFile);
printf("\nDone\n");
}

Linux C ext2fs_write_inode_full failing to write

after successfully reading the file inode with this:
retval = ext2fs_read_inode_full(current_fs, inode, inode_buf, EXT2_INODE_SIZE(current_fs->super));
if (retval) {
fprintf(stderr, "Failed to read inode\n");
free(fs);
free(inode_buf);
return retval;
}
(At this point I have verified the inode contains the correct data of the file in question)
I immediately attempt to write it back with this :
retval = ext2fs_write_inode_full(current_fs, inode, inode_buf, EXT2_INODE_SIZE(current_fs->super));
if (retval) {
fprintf(stderr, "Failed to write inode %d\n", retval);
}
(Of course it's my intention to change some date values in the inode before writing back)
But ext2fs_write_inode_full returns an error value 2133571349.
The program executes with root privileged!
The issue turned out to be the way crtime was opening the FS with ext2fs_open.
I needed to pass the EXT2_FLAG_RW flag otherwise the open is by default read only.

How to find the end of a memory mapped file in Windows platform without previously knowing the size of the file?

I have mapped a file of unknown size (around 4-6 GiB) in Windows platform and got a pointer to the start of the file data returned from the MapFileView function. But how can I know that I have reached the end of the file when I access the data using the pointer sequentially?
Here is the code I have so far written and it successfully maps the file and returns the pointer:
#include <Windows.h>
#include <stdio.h>
#include <inttypes.h>
int main()
{
HANDLE hFile = CreateFile("Test.bin",
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (!hFile)
{
printf("Could not create file (%lu).\n", GetLastError());
exit(1) ;
}
HANDLE hMapFile = CreateFileMappingA(hFile,
NULL,
PAGE_READWRITE,
0,
0,
NULL);
if (!hMapFile)
{
printf("Could not create file mapping object (%lu).\n", GetLastError());
CloseHandle(hFile);
exit(1);
}
int32_t* pBuf = (int32_t*) MapViewOfFile(hMapFile,
FILE_MAP_ALL_ACCESS,
0,
0,
0);
if (!pBuf)
{
printf("Could not map file (%lu).\n", GetLastError());
CloseHandle(hFile);
CloseHandle(hMapFile);
exit(1);
};
UnmapViewOfFile(pBuf);
CloseHandle(hFile);
CloseHandle(hMapFile);
exit(0);
}
So I wanted to read equal sized different parts of the file simultaneously in multiple threads. I believe mapped file is the right choice for this purpose. Advice about any other faster and possible approaches is highly appreciated.
I have researched some similar questions in the forum and I suppose this is the closest topic I could find:
Read all contents of memory mapped file or Memory Mapped View Accessor without knowing the size of it
But this answer is using C# and is not written using the WinAPI, therefore, I couldn't understand their process.
Thanks in advance :)
Call GetFileSizeEx to get the size of a file, and use this in combination with the base address and the current read address to determine where the end address is.

DLL injection using C crash notepad

I created a DLL injector program using C and a DLL. When I am trying to run the program the target process crash (I tried a notepad and cmd). I am compiling the injector as 64 bit and the DLL as well. the program and the DLL compiled with Visual Studio.
After some checks a saw if I remove the CreateRemoteThread The program will not crash, and the DLL injected (of course without executing the DLL).
I tried to use RUNDLL32.exe to check if the DLL is the problem and I have been able to see the message box.
Injector:
#include <Windows.h>
#include <stdio.h>
int main() {
// The DLL path we want to inject and the target process id.
LPCSTR dllpath = "C:\\Users\\....\\hello-world.dll";
int processID = 2980;
printf("#### Starting ####\n");
// Open target process handle
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processID);
if (hProcess == NULL) {
//close handles
CloseHandle(hProcess);
printf("[!] Unable to find the target process id: %d\n" , processID);
return 1;
}
printf("[+] Open target process handle\n");
// Getting targt memory address for the dll path
LPVOID dllpathMemoryAddr = VirtualAllocEx(hProcess, NULL, strlen(dllpath) + 1, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (dllpathMemoryAddr == NULL) {
//close handles
CloseHandle(hProcess);
printf("[!] Unable to get memory address of target process for the dllpath");
return 1;
}
printf("[+] Allocate the memory address to store the dllpath\n");
// Writing the dll path to the target memory address
BOOL succeedWrite = WriteProcessMemory(hProcess, dllpathMemoryAddr, dllpath, strlen(dllpath) + 1, NULL);
if (!succeedWrite) {
//close handles
CloseHandle(hProcess);
printf("[!] Unable to write to the memory address of target process the dllpath\n");
return 1;
}
printf("[+] Writed the dllpath to memory\n");
// Getting LoadLibreryA address
FARPROC loadLibAddr =
(GetModuleHandle(TEXT("kernel32.dll")), "LoadLibraryA");
if (loadLibAddr == NULL) {
// free the memory
VirtualFreeEx(hProcess, dllpathMemoryAddr, 0, MEM_RELEASE);
//close handles
CloseHandle(hProcess);
printf("[!] Unable to get the memory address of LoadLibraryA function\n");
return 1;
}
printf("[+] Allocate the memory address to LoadLibraryA function\n");
// Create remote thread on the remote process to load the dll
HANDLE rThread = CreateRemoteThread(hProcess, 0, 0, (LPTHREAD_START_ROUTINE)loadLibAddr, dllpathMemoryAddr, 0, NULL);
if (rThread == NULL) {
// free the memory
VirtualFreeEx(hProcess, dllpathMemoryAddr, 0, MEM_RELEASE);
//close handles
CloseHandle(hProcess);
printf("[!] Unable to create thread to execute the LoadLibraryA function\n the error: %u\n", GetLastError());
return 1;
}
printf("[+] Created remote thread to execute the dll\n");
// Waiting to opertion to complete
WaitForSingleObject(rThread, INFINITE);
// free the memory
VirtualFreeEx(hProcess, dllpathMemoryAddr, 0, MEM_RELEASE);
//close handles
CloseHandle(hProcess);
CloseHandle(rThread);
printf("#### DLL INJECTED ####\n");
return TRUE;
}
DLL
#define WIN32_LEAN_AND_MEAN
#include <stdio.h>
#include <windows.h>
extern "C" __declspec(dllexport)
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved) {
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
MessageBox(NULL, "Hello world!", "Hello World!", NULL);
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
output:
#### Starting ####
[+] Open target process handle
[+] Allocate the memory address to store the dllpath
[+] Writed the dllpath to memory
[+] Allocate the memory address to LoadLibraryA function
[+] Created remote thread to execute the dll
#### DLL INJECTED ####
If I understand the comments of the OP correctly, the main problem was that the OP had originally used the following line (before editing the question):
BOOL succeedWrite = WriteProcessMemory(hProcess, dllpathMemoryAddr, dllpath, strlen(dllpath), NULL);
By writing strlen(dllpath) instead of strlen(dllpath) + 1 bytes, the OP did not write the terminating null character of the string into the remote process. Therefore, the remote process likely crashed when that non-terminated string was passed as a function parameter to LoadLibraryA.
As pointed out in the comments section, there were also some other problems with the code, but it is unlikely that these were the cause of the crash.

Resources