#include <windows.h>
#include <iostream>
#include <sstream>
#include <fstream>
#include <vector>

#include <mem/pattern.h>
#include <mem/module.h>
#include <mem/mem.h>

static IMAGE_NT_HEADERS *m_NtHeaders;
static IMAGE_OPTIONAL_HEADER64 *m_OptionalHeader;
static IMAGE_SECTION_HEADER *m_FirstSectionHeader;

std::vector<uint8_t> mmapFile(const char *filename, DWORD &fileSize)
{
    HANDLE hFile = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE)
    {
        std::cerr << "Failed to open file\n";
        return {};
    }

    fileSize = GetFileSize(hFile, NULL);
    if (fileSize == INVALID_FILE_SIZE)
    {
        CloseHandle(hFile);
        std::cerr << "Failed to get file size\n";
        return {};
    }

    HANDLE hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
    if (!hMapping)
    {
        CloseHandle(hFile);
        std::cerr << "Failed to create file mapping\n";
        return {};
    }

    uint8_t *data = (uint8_t *)MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0);
    if (!data)
    {
        CloseHandle(hMapping);
        CloseHandle(hFile);
        std::cerr << "Failed to map view of file\n";
        return {};
    }

    std::vector<uint8_t> buffer(data, data + fileSize);

    UnmapViewOfFile(data);
    CloseHandle(hMapping);
    CloseHandle(hFile);

    return buffer;
}

uintptr_t translateFileOffsetToVirtualAddress(uintptr_t FileOffset)
{
    for (unsigned int currentSectionIndex = 0; currentSectionIndex < m_NtHeaders->FileHeader.NumberOfSections; currentSectionIndex++)
    {
        IMAGE_SECTION_HEADER *currentSectionHeader = m_FirstSectionHeader + currentSectionIndex;

        if ((currentSectionHeader->PointerToRawData) <= FileOffset && (currentSectionHeader->PointerToRawData + currentSectionHeader->SizeOfRawData) >= FileOffset)
        {
            return (currentSectionHeader->VirtualAddress) + (FileOffset - currentSectionHeader->PointerToRawData) + (m_OptionalHeader->ImageBase);
        }
    }

    return -1;
}

uintptr_t translateVirtualAddressToFileOffset(uintptr_t VirtualAddress)
{
    for (unsigned int currentSectionIndex = 0; currentSectionIndex < m_NtHeaders->FileHeader.NumberOfSections; currentSectionIndex++)
    {
        IMAGE_SECTION_HEADER *currentSectionHeader = m_FirstSectionHeader + currentSectionIndex;
        uintptr_t currentSectionVirtualAddress = currentSectionHeader->VirtualAddress + m_OptionalHeader->ImageBase;

        if (currentSectionVirtualAddress <= VirtualAddress && (currentSectionVirtualAddress + currentSectionHeader->SizeOfRawData) >= VirtualAddress)
        {
            return VirtualAddress - currentSectionVirtualAddress + currentSectionHeader->PointerToRawData;
        }
    }

    return -1;
}

uintptr_t translateBufferAddressToVirtualAddress(uintptr_t ptrAddress, uintptr_t fileBufferAddress, size_t size)
{
    uintptr_t endAddress = fileBufferAddress + size;
    if (ptrAddress >= fileBufferAddress && ptrAddress <= endAddress)
    {
        return translateFileOffsetToVirtualAddress(ptrAddress - fileBufferAddress);
    }

    return -1;
}

int main()
{
    const char *filename = "C:/Users/Julien/Documents/gta/dumps/GTA5_3337_dump.exe";
    DWORD fileSize;

    std::vector<uint8_t> fileData = mmapFile(filename, fileSize);
    const uint8_t *fileBuffer = fileData.data();

    IMAGE_DOS_HEADER *dosHeader = (IMAGE_DOS_HEADER *)fileBuffer;
    if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE)
    {
        std::cerr << "Not a valid PE file\n";
        return 1;
    }

    IMAGE_NT_HEADERS *ntHeaders = (IMAGE_NT_HEADERS *)(fileBuffer + dosHeader->e_lfanew);
    if (ntHeaders->Signature != IMAGE_NT_SIGNATURE)
    {
        std::cerr << "Not a valid NT header\n";
        return 1;
    }

    auto m_FileHeader = &ntHeaders->FileHeader;
    m_OptionalHeader = &ntHeaders->OptionalHeader;
    m_FirstSectionHeader = reinterpret_cast<IMAGE_SECTION_HEADER *>(
        reinterpret_cast<unsigned long long>(m_OptionalHeader) + m_FileHeader->SizeOfOptionalHeader);

    mem::pattern pat("48 89 5C 24 ? 48 89 6C 24 ? 48 89 74 24 ? 57 48 83 EC ? 48 8B 81 ? ? ? ? 0F 57 C0"); // has glow
    mem::pointer ptr = mem::scan(pat, mem::region(mem::pointer(fileBuffer), fileData.size()));
    auto rawOffset = ptr.any();
    if (rawOffset == 0)
    {
        printf("No pattern found\n");
        return 1;
    }

    printf("%lli", translateBufferAddressToVirtualAddress(rawOffset, (uintptr_t)fileBuffer, fileData.size()));

    // auto va = translateFileOffsetToVirtualAddress(rawOffset - fileBuffer, ntHeaders, m_OptionalHeader, m_FirstSectionHeader);
    // auto t = translateVirtualAddressToFileOffset(va, ntHeaders, m_OptionalHeader, m_FirstSectionHeader);
    // std::stringstream ss;
    // ss << std::hex << t;

    // HasGlow: 0x6c585c
    // printf("final offset: 0x%s\n", ss.str().c_str());
    return 0;
}


Do you spot a mistake here ?