Skip to content

Instantly share code, notes, and snippets.

@caiorss
Last active December 3, 2022 01:37
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save caiorss/166265f6dc85c8d9cc2dc00253caae78 to your computer and use it in GitHub Desktop.
Save caiorss/166265f6dc85c8d9cc2dc00253caae78 to your computer and use it in GitHub Desktop.
Unix/Linux memory mapped files sample code
#include <iostream>
#include <string>
#include <fstream>
#include <cstdint>
#include <cassert>
// --- Unix/Posix headers ---------//
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
constexpr size_t IMAGE_SIZEOF_SHORT_NAME = 8;
constexpr size_t IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16;
// using LONG = long;
using LONG = std::int32_t;
using WORD = std::uint16_t; // unsigned short;
using DWORD = std::uint32_t; // unsigned long;
using BYTE = std::uint8_t; //unsigned char;
using ULONGLONG = std::uint64_t; // unsigned long long
// Source: <winttt.h> => Original: typedef struct _IMAGE_DOS_HEADER
struct IMAGE_DOS_HEADER {
WORD e_magic;
WORD e_cblp;
WORD e_cp;
WORD e_crlc;
WORD e_cparhdr;
WORD e_minalloc;
WORD e_maxalloc;
WORD e_ss;
WORD e_sp;
WORD e_csum;
WORD e_ip;
WORD e_cs;
WORD e_lfarlc;
WORD e_ovno;
WORD e_res[4];
WORD e_oemid;
WORD e_oeminfo;
WORD e_res2[10];
// Offset to the PE header from the beginning of the file.
LONG e_lfanew;
};
struct PE_HEADER
{
DWORD Signature;
WORD Machine;
WORD NumberOfSections;
DWORD TimeDateStamp;
DWORD PointerToSymbolTable;
DWORD NumberOfSymbols;
WORD SizeOfOptionalHeader;
WORD Characteristics;
};
/** Class for encapsulating memory mapped files*/
class FileMapping
{
int m_fd = -1;
void* m_addr = nullptr;
ssize_t m_size = -1;
ssize_t get_file_size(int fd)
{
struct stat file_stat;
if( fstat(fd, &file_stat) == -1 )
throw std::runtime_error("Error: unable to get file size");
return file_stat.st_size;
}
public:
// Disable copy constructor
FileMapping(FileMapping const&) = delete;
// Disable copy assignment operator
FileMapping& operator=(FileMapping const&) = delete;
/**
* @param file_path - File to be memory-mapped to current process.
*/
FileMapping(std::string file_path)
{
// Get read-only file descriptor of file
m_fd = open(file_path.c_str(), O_RDONLY);
if(m_fd == -1){
throw std::runtime_error("Unable to open file");
}
m_size = get_file_size(m_fd);
if(m_size == -1)
throw std::runtime_error("Unable to get file size");
m_addr = ::mmap( nullptr
, m_size
, PROT_READ
, MAP_PRIVATE
, m_fd
, 0x00
);
if( m_addr == MAP_FAILED)
{
throw std::runtime_error("Error: failed to map file to memory");
}
}
~FileMapping()
{
// Unmap memory segment
munmap(m_addr, m_size);
// Release file-descriptor resource
close(m_fd);
m_fd = -1;
m_addr = nullptr;
m_size = -1;
}
/** @brief Returns pointer file mapping address. */
void* addr() const { return m_addr; }
/** @brief Get casted pointer to an offset of the file mapping address. */
template<typename T>
T addr_rel(std::ptrdiff_t offset) const {
return reinterpret_cast<T>( reinterpret_cast<uintptr_t>(m_addr) + offset);
}
}; // --- End of class FileMapping ---- //
int main(int argc, char** argv)
{
// ----------- Validate arguments ----------------------------//
if(argc < 2)
{
std::fprintf(stderr, "Usage: /unix-mmap <FILE> \n");
return EXIT_FAILURE;
}
FileMapping fmap(argv[1]);
// --------- Process file -----------------------------------------//
const auto bmap = fmap.addr_rel<unsigned char*>(0x00);
// char file_signature [2] = { bmap[0], bmap[1], bmap[2], bmap[3], 0x00 };
std::printf(" File signature = %c %c 0x%X 0x%X \n", bmap[0], bmap[1], bmap[2], bmap[3]);
IMAGE_DOS_HEADER* dos_header = fmap.addr_rel<IMAGE_DOS_HEADER*>(0x00);
PE_HEADER* pe_header = fmap.addr_rel<PE_HEADER*>( dos_header->e_lfanew);
assert( pe_header->Signature == 0x4550 );
std::printf("\n ========= [DOS HEADER] =================\n");
std::printf(" MAGIC NUMBER = 0x%X (hex) \n", dos_header->e_magic);
std::printf(" MAGIC NUMBER = %c %c (str) \n", dos_header->e_magic & 0xFF, (dos_header->e_magic >> 8) & 0xFF);
std::printf(" e_lfanew = 0x%X \n", dos_header->e_lfanew);
std::printf("\n ======== [PE - Header] ================\n");
std::printf(" Note: if machine is 0x8664 => the processor is AMD-Intel x86-64 \n");
std::printf("\n");
std::printf(" Signature = 0x%X \n", pe_header->Signature);
std::printf(" Machine = 0x%X \n", pe_header->Machine);
std::printf(" Number of sections = %d \n", pe_header->NumberOfSections);
return 0;
} // --- End of main() ----//
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <assert.h>
// --- Unix/Posix headers ---------//
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#define IMAGE_SIZEOF_SHORT_NAME 8
#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
typedef int32_t LONG;
typedef uint16_t WORD;
typedef uint32_t DWORD;
typedef uint8_t BYTE;
typedef uint64_t ULONGLONG;;
// Source: <winttt.h> => Original: typedef struct _IMAGE_DOS_HEADER
typedef struct {
WORD e_magic;
WORD e_cblp;
WORD e_cp;
WORD e_crlc;
WORD e_cparhdr;
WORD e_minalloc;
WORD e_maxalloc;
WORD e_ss;
WORD e_sp;
WORD e_csum;
WORD e_ip;
WORD e_cs;
WORD e_lfarlc;
WORD e_ovno;
WORD e_res[4];
WORD e_oemid;
WORD e_oeminfo;
WORD e_res2[10];
// Offset to the PE header from the beginning of the file.
LONG e_lfanew;
} IMAGE_DOS_HEADER;
typedef struct {
DWORD Signature;
WORD Machine;
WORD NumberOfSections;
DWORD TimeDateStamp;
DWORD PointerToSymbolTable;
DWORD NumberOfSymbols;
WORD SizeOfOptionalHeader;
WORD Characteristics;
} PE_HEADER;
ssize_t get_file_size(int fd)
{
struct stat file_stat;
if( fstat(fd, &file_stat) == -1 )
return -1;
return file_stat.st_size;
}
int main(int argc, char** argv)
{
// ----------- Validate arguments ----------------------------//
if(argc < 2)
{
fprintf(stderr, "Usage: /unix-mmap <FILE> \n");
return EXIT_FAILURE;
}
// ----------- Get file descriptor ----------------------------//
// Get read-only file descriptor of file
int fd = open(argv[1], O_RDONLY);
if(fd == -1){
fprintf(stderr, " Error: unable to open file. check ERRNO variable \n");
return EXIT_FAILURE;
}
ssize_t size = get_file_size(fd);
if(size == -1){
fprintf(stderr, " Error: unable to get file size \n");
return EXIT_FAILURE;
}
// ----------- Map file in to process' virtual memory ---------------------------//
void* fmap = mmap( NULL /* Often set to zero, aka nullpointer */
, size /* Size of file mapping in bytes */
, PROT_READ /* Open in read-only mode */
, MAP_PRIVATE /* Only this process can access this memory-map */
, fd /* File descriptor of file to be memory mapped */
, 0x00 /* Offset from the beggining of the file */
);
if( fmap == MAP_FAILED)
{
fprintf(stderr, " Error: memory mapped failed. check ERRNO \n");
return EXIT_FAILURE;
}
// --------- Process file -----------------------------------------//
unsigned char* bmap = (unsigned char*) fmap;
// char file_signature [2] = { bmap[0], bmap[1], bmap[2], bmap[3], 0x00 };
printf(" File signature = %c %c 0x%X 0x%X \n", bmap[0], bmap[1], bmap[2], bmap[3]);
IMAGE_DOS_HEADER* dos_header = (IMAGE_DOS_HEADER*) fmap;
PE_HEADER* pe_header = fmap + dos_header->e_lfanew;
assert( pe_header->Signature == 0x4550 );
printf("\n ========= [DOS HEADER] =================\n");
printf(" MAGIC NUMBER = 0x%X (hex) \n", dos_header->e_magic);
printf(" MAGIC NUMBER = %c %c (str) \n", dos_header->e_magic & 0xFF, (dos_header->e_magic >> 8) & 0xFF);
printf(" e_lfanew = 0x%X \n", dos_header->e_lfanew);
printf("\n ======== [PE - Header] ================\n");
printf(" Note: if machine is 0x8664 => the processor is AMD-Intel x86-64 \n");
printf("\n");
printf(" Signature = 0x%X \n", pe_header->Signature);
printf(" Machine = 0x%X \n", pe_header->Machine);
printf(" Number of sections = %d \n", pe_header->NumberOfSections);
// ---------- Release Resource ------------------------------------//
// Unmap memory segment
munmap(fmap, size);
// Release file-descriptor resource
close(fd);
return 0;
} // --- End of main() ----//
#include <iostream>
#include <string>
#include <fstream>
#include <cstdint>
#include <cassert>
// --- Unix/Posix headers ---------//
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
constexpr size_t IMAGE_SIZEOF_SHORT_NAME = 8;
constexpr size_t IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16;
// using LONG = long;
using LONG = std::int32_t;
using WORD = std::uint16_t; // unsigned short;
using DWORD = std::uint32_t; // unsigned long;
using BYTE = std::uint8_t; //unsigned char;
using ULONGLONG = std::uint64_t; // unsigned long long
// Source: <winttt.h> => Original: typedef struct _IMAGE_DOS_HEADER
struct IMAGE_DOS_HEADER {
WORD e_magic;
WORD e_cblp;
WORD e_cp;
WORD e_crlc;
WORD e_cparhdr;
WORD e_minalloc;
WORD e_maxalloc;
WORD e_ss;
WORD e_sp;
WORD e_csum;
WORD e_ip;
WORD e_cs;
WORD e_lfarlc;
WORD e_ovno;
WORD e_res[4];
WORD e_oemid;
WORD e_oeminfo;
WORD e_res2[10];
// Offset to the PE header from the beginning of the file.
LONG e_lfanew;
};
struct PE_HEADER
{
DWORD Signature;
WORD Machine;
WORD NumberOfSections;
DWORD TimeDateStamp;
DWORD PointerToSymbolTable;
DWORD NumberOfSymbols;
WORD SizeOfOptionalHeader;
WORD Characteristics;
};
ssize_t get_file_size(int fd)
{
struct stat file_stat;
if( fstat(fd, &file_stat) == -1 )
throw std::runtime_error("Error: unable to get file size");
return file_stat.st_size;
}
int main(int argc, char** argv)
{
// ----------- Validate arguments ----------------------------//
if(argc < 2)
{
std::fprintf(stderr, "Usage: /unix-mmap <FILE> \n");
return EXIT_FAILURE;
}
// ----------- Get file descriptor ----------------------------//
// Get read-only file descriptor of file
int fd = open(argv[1], O_RDONLY);
if(fd == -1){
std::fprintf(stderr, " Error: unable to open file. check ERRNO variable \n");
return EXIT_FAILURE;
}
ssize_t size = get_file_size(fd);
// ----------- Map file in to process' virtual memory ---------------------------//
void* fmap = mmap( nullptr /* Often set to zero, aka nullpointer */
, size /* Size of file mapping in bytes */
, PROT_READ /* Open in read-only mode */
, MAP_PRIVATE /* Only this process can access this memory-map */
, fd /* File descriptor of file to be memory mapped */
, 0x00 /* Offset from the beggining of the file */
);
if( fmap == MAP_FAILED)
{
std::fprintf(stderr, " Error: memory mapped failed. check ERRNO \n");
return EXIT_FAILURE;
}
// --------- Process file -----------------------------------------//
const auto bmap = reinterpret_cast<unsigned char*>(fmap);
// char file_signature [2] = { bmap[0], bmap[1], bmap[2], bmap[3], 0x00 };
std::printf(" File signature = %c %c 0x%X 0x%X \n", bmap[0], bmap[1], bmap[2], bmap[3]);
IMAGE_DOS_HEADER* dos_header = reinterpret_cast<IMAGE_DOS_HEADER*>(fmap);
PE_HEADER* pe_header = reinterpret_cast<PE_HEADER*>( (uintptr_t) fmap + dos_header->e_lfanew);
assert( pe_header->Signature == 0x4550 );
std::printf("\n ========= [DOS HEADER] =================\n");
std::printf(" MAGIC NUMBER = 0x%X (hex) \n", dos_header->e_magic);
std::printf(" MAGIC NUMBER = %c %c (str) \n", dos_header->e_magic & 0xFF, (dos_header->e_magic >> 8) & 0xFF);
std::printf(" e_lfanew = 0x%X \n", dos_header->e_lfanew);
std::printf("\n ======== [PE - Header] ================\n");
std::printf(" Note: if machine is 0x8664 => the processor is AMD-Intel x86-64 \n");
std::printf("\n");
std::printf(" Signature = 0x%X \n", pe_header->Signature);
std::printf(" Machine = 0x%X \n", pe_header->Machine);
std::printf(" Number of sections = %d \n", pe_header->NumberOfSections);
// ---------- Release Resource ------------------------------------//
// Unmap memory segment
munmap(fmap, size);
// Release file-descriptor resource
close(fd);
return 0;
} // --- End of main() ----//
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment