study this program then write a new program your way  #include <windows.h>
#include <tlhelp32.h>
#include <stdio.h>
#include <string>
#include <vector>
#include <cstdarg>
#include <memory>
#include <ctime>
#include <iostream>
#include <fstream>
#include <iomanip>
#include <thread>
#include <mutex>
#include <algorithm>
#include <Shlwapi.h>

// Link with Shlwapi.lib for StrStrIA
#pragma comment(lib, "Shlwapi.lib")

// Logging levels
enum LogLevel {
    LOG_INFO,
    LOG_WARNING,
    LOG_ERROR,
    LOG_DEBUG
};

// Mutex for thread-safe logging
std::mutex log_mutex;

// Function to log messages to console and to a file
void log_message(std::ofstream& log_file, LogLevel level, const char* format, ...) {
    std::lock_guard<std::mutex> lock(log_mutex);

    const char* level_str = "";
    switch (level) {
    case LOG_INFO:
        level_str = "[INFO]";
        break;
    case LOG_WARNING:
        level_str = "[WARNING]";
        break;
    case LOG_ERROR:
        level_str = "[ERROR]";
        break;
    case LOG_DEBUG:
        level_str = "[DEBUG]";
        break;
    }

    va_list args;
    va_start(args, format);

    // Prepare message
    char buffer[1024];
    vsnprintf_s(buffer, sizeof(buffer), _TRUNCATE, format, args);

    // Get current time
    time_t t = time(nullptr);
    struct tm tm_info;
    localtime_s(&tm_info, &t);
    char time_buffer[64];
    strftime(time_buffer, sizeof(time_buffer), "%Y-%m-%d %H:%M:%S", &tm_info);

    // Output to console
    std::cout << time_buffer << " " << level_str << " " << buffer;

    // Output to log file
    if (log_file.is_open()) {
        log_file << time_buffer << " " << level_str << " " << buffer;
        log_file.flush();
    }

    va_end(args);
}

// Function to get the Process ID (PID) by process name
DWORD get_process_id_by_name(const std::string& process_name) {
    PROCESSENTRY32 pe32;
    pe32.dwSize = sizeof(PROCESSENTRY32);

    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hSnapshot == INVALID_HANDLE_VALUE) {
        return 0;
    }

    if (!Process32First(hSnapshot, &pe32)) {
        CloseHandle(hSnapshot);
        return 0;
    }

    DWORD pid = 0;

    do {
        // Convert process name to ANSI
        char exeFile[MAX_PATH];
        size_t converted_chars = 0;
        wcstombs_s(&converted_chars, exeFile, pe32.szExeFile, _TRUNCATE);

        if (_stricmp(exeFile, process_name.c_str()) == 0) {
            pid = pe32.th32ProcessID;
            CloseHandle(hSnapshot);
            return pid;
        }
    } while (Process32Next(hSnapshot, &pe32));

    CloseHandle(hSnapshot);
    return 0;
}

// Function to get the base address of the main module (e.g., Fallout76.exe)
uintptr_t get_base_address(DWORD pid, const std::string& module_name) {
    MODULEENTRY32 me32;
    me32.dwSize = sizeof(MODULEENTRY32);

    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, pid);
    if (hSnapshot == INVALID_HANDLE_VALUE) {
        return 0;
    }

    if (!Module32First(hSnapshot, &me32)) {
        CloseHandle(hSnapshot);
        return 0;
    }

    uintptr_t base_address = 0;

    do {
        // Convert module name to ANSI
        char moduleName[MAX_PATH];
        size_t converted_chars = 0;
        wcstombs_s(&converted_chars, moduleName, me32.szModule, _TRUNCATE);

        if (_stricmp(moduleName, module_name.c_str()) == 0) {
            base_address = reinterpret_cast<uintptr_t>(me32.modBaseAddr);
            CloseHandle(hSnapshot);
            return base_address;
        }
    } while (Module32Next(hSnapshot, &me32));

    CloseHandle(hSnapshot);
    return 0;
}

// Function to get the start and end addresses of a specific section
bool get_section_limits(HANDLE hProcess, uintptr_t base_addr, const char* section_name, uintptr_t& section_start, uintptr_t& section_end) {
    // Read DOS header
    IMAGE_DOS_HEADER dos_header;
    SIZE_T bytesRead = 0;
    if (!ReadProcessMemory(hProcess, reinterpret_cast<LPCVOID>(base_addr), &dos_header, sizeof(dos_header), &bytesRead) ||
        bytesRead != sizeof(dos_header)) {
        return false;
    }

    if (dos_header.e_magic != IMAGE_DOS_SIGNATURE) {
        return false;
    }

    // Read NT headers
    IMAGE_NT_HEADERS64 nt_headers;
    if (!ReadProcessMemory(hProcess, reinterpret_cast<LPCVOID>(base_addr + dos_header.e_lfanew), &nt_headers, sizeof(nt_headers), &bytesRead) ||
        bytesRead != sizeof(nt_headers)) {
        return false;
    }

    if (nt_headers.Signature != IMAGE_NT_SIGNATURE) {
        return false;
    }

    // Verify 64-bit
    bool is64Bit = nt_headers.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC;

    // Calculate section headers address
    uintptr_t section_header_addr = base_addr + dos_header.e_lfanew +
        offsetof(IMAGE_NT_HEADERS64, OptionalHeader) + nt_headers.FileHeader.SizeOfOptionalHeader;

    // Read section headers
    std::unique_ptr<IMAGE_SECTION_HEADER[]> section_headers(new IMAGE_SECTION_HEADER[nt_headers.FileHeader.NumberOfSections]);
    SIZE_T section_headers_size = nt_headers.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
    if (!ReadProcessMemory(hProcess, reinterpret_cast<LPCVOID>(section_header_addr), section_headers.get(), section_headers_size, &bytesRead) ||
        bytesRead != section_headers_size) {
        return false;
    }

    // Find the desired section
    for (WORD i = 0; i < nt_headers.FileHeader.NumberOfSections; ++i) {
        if (strncmp(reinterpret_cast<const char*>(section_headers[i].Name), section_name, IMAGE_SIZEOF_SHORT_NAME) == 0) {
            section_start = base_addr + section_headers[i].VirtualAddress;
            section_end = section_start + section_headers[i].Misc.VirtualSize;
            return true;
        }
    }

    return false;
}

// Function to find the address of a given ANSI string within a memory section
uintptr_t find_string_in_section(HANDLE hProcess, uintptr_t section_start, uintptr_t section_end, const std::string& target_string) {
    SIZE_T section_size = section_end - section_start;
    std::unique_ptr<BYTE[]> buffer(new BYTE[section_size]);

    SIZE_T bytes_read = 0;

    // Read the entire section into the buffer
    if (!ReadProcessMemory(hProcess, reinterpret_cast<LPCVOID>(section_start), buffer.get(), section_size, &bytes_read)) {
        return 0;
    }

    // Search for the target string within the buffer
    for (SIZE_T i = 0; i <= bytes_read - target_string.length(); ++i) {
        if (memcmp(buffer.get() + i, target_string.c_str(), target_string.length()) == 0) {
            // Ensure the string is null-terminated
            if (i + target_string.length() < bytes_read && buffer[i + target_string.length()] == '\0') {
                return section_start + i;
            }
        }
    }

    return 0;
}

// Function to find the address that references a given string address
uintptr_t find_pointer_to_address(HANDLE hProcess, uintptr_t section_start, uintptr_t section_end, uintptr_t target_address) {
    SIZE_T section_size = section_end - section_start;
    std::unique_ptr<BYTE[]> buffer(new BYTE[section_size]);

    SIZE_T bytes_read = 0;
    if (!ReadProcessMemory(hProcess, reinterpret_cast<LPCVOID>(section_start), buffer.get(), section_size, &bytes_read)) {
        return 0;
    }

    SIZE_T pointer_size = sizeof(uintptr_t);
    for (SIZE_T i = 0; i <= bytes_read - pointer_size; i += 1) {
        uintptr_t ptr_value = 0;
        memcpy(&ptr_value, buffer.get() + i, pointer_size);
        if (ptr_value == target_address) {
            return section_start + i;
        }
    }

    return 0;
}

int main(int argc, char* argv[]) {
    // Parse command-line arguments
    std::string process_name = "Fallout76.exe";
    std::string output_file = "memscan.log";
    std::string settings_file = "gameSettings.txt";

    // Load game settings from file
    std::vector<std::string> gameSettings;

    // Open settings file
    std::ifstream settings_input(settings_file);
    if (!settings_input.is_open()) {
        std::cerr << "Error: Could not open settings file: " << settings_file << std::endl;
        return 1;
    }

    std::string line;
    while (std::getline(settings_input, line)) {
        if (!line.empty()) {
            gameSettings.push_back(line);
        }
    }
    settings_input.close();

    // Open output log file
    std::ofstream log_file(output_file, std::ios::out);
    if (!log_file.is_open()) {
        std::cerr << "Error: Could not open log file: " << output_file << std::endl;
        return 1;
    }

    // Log start time
    time_t t = time(NULL);
    struct tm tm_info;
    localtime_s(&tm_info, &t);

    log_message(log_file, LOG_INFO, "Memory scan started at: %04d-%02d-%02d %02d:%02d:%02d\n",
        tm_info.tm_year + 1900, tm_info.tm_mon + 1, tm_info.tm_mday,
        tm_info.tm_hour, tm_info.tm_min, tm_info.tm_sec);

    // Check for administrative privileges
    BOOL isAdmin = IsUserAnAdmin();
    if (!isAdmin) {
        log_message(log_file, LOG_ERROR, "Error: Program requires administrative privileges to access process memory.\n");
        return 1;
    }

    // Get process ID
    DWORD pid = get_process_id_by_name(process_name);
    if (pid == 0) {
        log_message(log_file, LOG_ERROR, "Error: Could not find process %s.\n", process_name.c_str());
        return 1;
    } else {
        log_message(log_file, LOG_INFO, "Process %s found with PID %u.\n", process_name.c_str(), pid);
    }

    // Get base address
    uintptr_t base_addr = get_base_address(pid, process_name);
    if (base_addr == 0) {
        log_message(log_file, LOG_ERROR, "Error: Could not find base address of process %s.\n", process_name.c_str());
        return 1;
    } else {
        log_message(log_file, LOG_INFO, "Base address of %s: 0x%p\n", process_name.c_str(), (void*)base_addr);
    }

    // Open process
    HANDLE hProcess = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, pid);
    if (hProcess == NULL) {
        log_message(log_file, LOG_ERROR, "Error: Could not open process %u. Error code: %u\n", pid, GetLastError());
        return 1;
    }

    // Get section limits
    uintptr_t data_start, data_end;
    if (!get_section_limits(hProcess, base_addr, ".data", data_start, data_end)) {
        log_message(log_file, LOG_ERROR, "Error: Could not get .data section limits.\n");
        return 1;
    } else {
        log_message(log_file, LOG_INFO, ".data section: Start = 0x%p, End = 0x%p\n", (void*)data_start, (void*)data_end);
    }

    uintptr_t rdata_start, rdata_end;
    if (!get_section_limits(hProcess, base_addr, ".rdata", rdata_start, rdata_end)) {
        log_message(log_file, LOG_ERROR, "Error: Could not get .rdata section limits.\n");
        return 1;
    } else {
        log_message(log_file, LOG_INFO, ".rdata section: Start = 0x%p, End = 0x%p\n", (void*)rdata_start, (void*)rdata_end);
    }

    // Begin results
    log_file << "\n$gameSettings = {\n";

    // For each game setting, perform the scan
    for (const auto& setting : gameSettings) {
        log_message(log_file, LOG_INFO, "Processing setting: %s\n", setting.c_str());

        // Search for the string in .data and .rdata
        uintptr_t string_addr = 0;

        // Search both sections
        if (!(string_addr = find_string_in_section(hProcess, data_start, data_end, setting))) {
            string_addr = find_string_in_section(hProcess, rdata_start, rdata_end, setting);
        }

        if (string_addr == 0) {
            log_message(log_file, LOG_WARNING, "Warning: Could not find string '%s'. Skipping.\n", setting.c_str());
            continue;
        }

        log_message(log_file, LOG_INFO, "Found string '%s' at address 0x%p.\n", setting.c_str(), (void*)string_addr);

        // Find pointer to string address
        uintptr_t pointer_addr = 0;

        // Search in .data and .rdata
        if (!(pointer_addr = find_pointer_to_address(hProcess, data_start, data_end, string_addr))) {
            pointer_addr = find_pointer_to_address(hProcess, rdata_start, rdata_end, string_addr);
        }

        if (pointer_addr == 0) {
            log_message(log_file, LOG_WARNING, "Warning: Could not find pointer to string '%s'. Skipping.\n", setting.c_str());
            continue;
        }

        log_message(log_file, LOG_INFO, "Found pointer to '%s' at address 0x%p.\n", setting.c_str(), (void*)pointer_addr);

        // Calculate offset relative to base address
        uintptr_t offset = pointer_addr - base_addr;

        log_message(log_file, LOG_INFO, "Calculated offset for '%s': 0x%p\n", setting.c_str(), (void*)offset);

        // Log result
        log_file << "    \"" << setting << "\" => 0x" << std::hex << offset << ",\n";
    }

    log_file << "};\n\n";

    // Log end time
    t = time(NULL);
    localtime_s(&tm_info, &t);
    log_message(log_file, LOG_INFO, "Memory scan ended at: %04d-%02d-%02d %02d:%02d:%02d\n",
        tm_info.tm_year + 1900, tm_info.tm_mon + 1, tm_info.tm_mday,
        tm_info.tm_hour, tm_info.tm_min, tm_info.tm_sec);

    // Cleanup
    CloseHandle(hProcess);
    log_file.close();

    return 0;
}