Option 2: Adjust Addresses Using the Image Base

    Compute the Relative Virtual Address (RVA) of the address by subtracting the runtime base address:

uintptr_t rva = addr_in_process - base_address_in_process;

Obtain the original image base from the PE header (typically available in IDA or by reading the PE header in your code):

uintptr_t image_base_from_pe = nt_headers.OptionalHeader.ImageBase;

Calculate the address in IDA by adding the RVA to the image base:

        uintptr_t addr_in_ida = image_base_from_pe + rva;

        Use addr_in_ida to look up the address in IDA.

Example Modification in Your Code:

Add the following after reading the IMAGE_NT_HEADERS in your get_section_limits function:

uintptr_t image_base_in_pe = nt_headers.OptionalHeader.ImageBase;

When logging addresses, adjust them:

uintptr_t rva = addr - base_addr;
uintptr_t addr_in_ida = image_base_in_pe + rva;
log_message(log_file, "Address in IDA: 0x%llx\n", addr_in_ida);

2. Incorrect Section Size Calculation

Issue with Section Size:

    In PE files, SizeOfRawData represents the size of the section's data on disk.
    Misc.VirtualSize represents the size of the section in memory.
    The section in memory may be larger due to alignment and uninitialized data (like the .bss section).

Your Current Code:

section_end = section_start + section.SizeOfRawData;

Why It's Problematic:

    By using SizeOfRawData, you're potentially missing parts of the section that are present in memory but not in the file.
    This can cause your memory scanning functions to overlook parts of the section where relevant data (like strings or pointers) might reside.

Solution:

    Use the maximum of SizeOfRawData and Misc.VirtualSize to ensure you're covering the entire section in memory.

    Modify your get_section_limits function:

    size_t section_size = max(section.Misc.VirtualSize, section.SizeOfRawData);
    section_end = section_start + section_size;

3. Pointer Alignment and Memory Reading

Potential Issue:

    When scanning memory for pointers, it's important to ensure that you're reading aligned data, especially on architectures that require alignment (like x86-64).

Your Current Code:

uintptr_t* potential_ptr = reinterpret_cast<uintptr_t*>(buffer.data() + i);
if (*potential_ptr == string_addr) {
    return addr + i;
}

Problem:

    If i is not aligned to the size of uintptr_t, this can cause misaligned reads, which might lead to incorrect results or access violations.

Solution:

    Ensure that you only read pointers at properly aligned addresses:

    for (SIZE_T i = 0; i <= bytesRead - sizeof(uintptr_t); i += sizeof(uintptr_t)) {
        uintptr_t potential_ptr;
        memcpy(&potential_ptr, buffer.data() + i, sizeof(uintptr_t));
        if (potential_ptr == string_addr) {
            return addr + i;
        }
    }

    Adjust the loop increment to sizeof(uintptr_t) to maintain alignment.

4. Summary and Recommendations

    Adjust for ASLR:
        Rebase your IDA database or adjust the addresses in your code to account for differences between the runtime base address and the image base address.
    Correct Section Size Calculation:
        Use max(section.Misc.VirtualSize, section.SizeOfRawData) when determining section sizes.
    Ensure Proper Alignment:
        When reading pointers from memory, ensure that you're accessing data at aligned addresses and handling 64-bit pointers correctly.
    Additional Considerations:
        Ensure that your code handles both 32-bit and 64-bit processes appropriately, especially when dealing with pointer sizes and types.
        Verify that you have the necessary permissions and that ReadProcessMemory calls are succeeding.

Example Adjusted Logging Output

When logging addresses, include both the address in the running process and the adjusted address for IDA:

log_message(log_file, "String Address in Process (.rdata): 0x%llx\n", string_addr);
uintptr_t rva = string_addr - base_addr;
uintptr_t addr_in_ida = image_base_in_pe + rva;
log_message(log_file, "String Address in IDA: 0x%llx\n", addr_in_ida); use the above to fix this program and print full fixed code #include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <tlhelp32.h>
#include <string>
#include <vector>
#include <cstdarg>

// Function to log messages both to console and a file
void log_message(FILE* log_file, const char* format, ...) {
    va_list args;
    va_start(args, format);
    vprintf(format, args); // Console output
    if (log_file != NULL) {
        vfprintf(log_file, format, args); // File output
        fflush(log_file);
    }
    va_end(args);
}

// Function to get the process ID by name
DWORD get_process_id_by_name(const char* process_name) {
    PROCESSENTRY32 pe32;
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hSnapshot == INVALID_HANDLE_VALUE) {
        return 0;
    }
    pe32.dwSize = sizeof(PROCESSENTRY32);
    if (!Process32First(hSnapshot, &pe32)) {
        CloseHandle(hSnapshot);
        return 0;
    }
    do {
        char exeFile[MAX_PATH];
        size_t converted_chars = 0;
        wcstombs_s(&converted_chars, exeFile, MAX_PATH, pe32.szExeFile, _TRUNCATE);
        if (_stricmp(exeFile, process_name) == 0) {
            CloseHandle(hSnapshot);
            return pe32.th32ProcessID;
        }
    } while (Process32Next(hSnapshot, &pe32));

    CloseHandle(hSnapshot);
    return 0;
}

// Function to get the base address of the process
uintptr_t get_base_address(DWORD pid) {
    MODULEENTRY32 me32 = { sizeof(me32) };
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, pid);
    if (hSnapshot == INVALID_HANDLE_VALUE) {
        return 0;
    }
    if (Module32First(hSnapshot, &me32)) {
        CloseHandle(hSnapshot);
        return reinterpret_cast<uintptr_t>(me32.modBaseAddr);
    }
    CloseHandle(hSnapshot);
    return 0;
}

// Function to get the start and end addresses of a specific section in the process
bool get_section_limits(HANDLE hProcess, uintptr_t base_addr, const char* section_name, uintptr_t& section_start, uintptr_t& section_end) {
    IMAGE_DOS_HEADER dos_header;
    if (!ReadProcessMemory(hProcess, (LPCVOID)base_addr, &dos_header, sizeof(dos_header), NULL)) {
        return false;
    }
    if (dos_header.e_magic != IMAGE_DOS_SIGNATURE) {
        return false;
    }
    IMAGE_NT_HEADERS nt_headers;
    if (!ReadProcessMemory(hProcess, (LPCVOID)(base_addr + dos_header.e_lfanew), &nt_headers, sizeof(nt_headers), NULL)) {
        return false;
    }
    if (nt_headers.Signature != IMAGE_NT_SIGNATURE) {
        return false;
    }

    std::vector<IMAGE_SECTION_HEADER> section_headers(nt_headers.FileHeader.NumberOfSections);
    if (!ReadProcessMemory(hProcess, (LPCVOID)((uintptr_t)(base_addr + dos_header.e_lfanew) + sizeof(nt_headers)), section_headers.data(), sizeof(IMAGE_SECTION_HEADER) * nt_headers.FileHeader.NumberOfSections, NULL)) {
        return false;
    }

    for (const auto& section : section_headers) {
        if (strncmp(reinterpret_cast<const char*>(section.Name), section_name, IMAGE_SIZEOF_SHORT_NAME) == 0) {
            section_start = base_addr + section.VirtualAddress;
            section_end = section_start + section.SizeOfRawData;
            return true;
        }
    }
    return false;
}

// Function to find strings in a section of the process's memory
std::vector<std::pair<std::string, uintptr_t>> find_strings_in_section(HANDLE hProcess, uintptr_t section_start, uintptr_t section_end, size_t min_length) {
    std::vector<std::pair<std::string, uintptr_t>> strings;
    uintptr_t addr = section_start;
    while (addr < section_end) {
        MEMORY_BASIC_INFORMATION mbi;
        if (!VirtualQueryEx(hProcess, (LPCVOID)addr, &mbi, sizeof(mbi))) {
            break;
        }

        if (mbi.State == MEM_COMMIT && (mbi.Protect == PAGE_READONLY || mbi.Protect == PAGE_EXECUTE_READ || mbi.Protect == PAGE_EXECUTE_READWRITE)) {
            std::vector<char> buffer(mbi.RegionSize);
            SIZE_T bytesRead;
            if (ReadProcessMemory(hProcess, (LPCVOID)addr, buffer.data(), mbi.RegionSize, &bytesRead) && bytesRead > 0) {
                for (SIZE_T i = 0; i < bytesRead;) {
                    if (isprint(buffer[i]) && isprint(buffer[i + 1]) && isprint(buffer[i + 2])) {
                        std::string possible_string;
                        SIZE_T j = i;
                        while (j < bytesRead && isprint(buffer[j]) && buffer[j] != '\0') {
                            possible_string += buffer[j];
                            j++;
                        }
                        if (possible_string.length() >= min_length) {
                            strings.emplace_back(possible_string, addr + i);
                        }
                        i = j; // Move i to the end of the found string
                    }
                    else {
                        i++;
                    }
                }
            }
        }

        addr += mbi.RegionSize;
    }
    return strings;
}

// Function to find a reference to a string address within the .data section
uintptr_t find_reference_in_data_section(HANDLE hProcess, uintptr_t section_start, uintptr_t section_end, uintptr_t string_addr) {
    uintptr_t addr = section_start;
    while (addr < section_end) {
        MEMORY_BASIC_INFORMATION mbi;
        if (!VirtualQueryEx(hProcess, (LPCVOID)addr, &mbi, sizeof(mbi))) {
            break;
        }

        if (mbi.State == MEM_COMMIT && (mbi.Protect == PAGE_READWRITE || mbi.Protect == PAGE_EXECUTE_READWRITE || mbi.Protect == PAGE_EXECUTE_WRITECOPY || mbi.Protect == PAGE_WRITECOPY)) {
            std::vector<char> buffer(mbi.RegionSize);
            SIZE_T bytesRead;
            if (ReadProcessMemory(hProcess, (LPCVOID)addr, buffer.data(), mbi.RegionSize, &bytesRead) && bytesRead > 0) {
                for (SIZE_T i = 0; i < bytesRead - sizeof(uintptr_t); ++i) {
                    uintptr_t* potential_ptr = reinterpret_cast<uintptr_t*>(buffer.data() + i);
                    if (*potential_ptr == string_addr) {
                        return addr + i;
                    }
                }
            }
        }

        addr += mbi.RegionSize;
    }
    return 0;
}

int main() {
    const char* process_name = "notepad.exe";
    const size_t minStringLength = 5; // Define the minimum string length you consider a valid string

    FILE* log_file;
    if (fopen_s(&log_file, "memscan.log", "w") != 0) {
        printf("Could not open log file for writing\n");
        return 1;
    }

    DWORD pid = get_process_id_by_name(process_name);
    if (pid == 0) {
        log_message(log_file, "Could not find process ID for \"%s\"\n", process_name);
        fclose(log_file);
        return 1;
    }

    uintptr_t base_addr = get_base_address(pid);
    log_message(log_file, "Base Address: 0x%llx\n", base_addr);

    HANDLE hProcess = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, pid);
    if (hProcess == NULL) {
        log_message(log_file, "Could not open process \"%s\"\n", process_name);
        fclose(log_file);
        return 1;
    }

    uintptr_t rdata_section_start, rdata_section_end;
    if (!get_section_limits(hProcess, base_addr, ".rdata", rdata_section_start, rdata_section_end)) {
        log_message(log_file, "Failed to get limits for .rdata section\n");
        CloseHandle(hProcess);
        fclose(log_file);
        return 1;
    }

    uintptr_t data_section_start, data_section_end;
    if (!get_section_limits(hProcess, base_addr, ".data", data_section_start, data_section_end)) {
        log_message(log_file, "Failed to get limits for .data section\n");
        CloseHandle(hProcess);
        fclose(log_file);
        return 1;
    }

    log_message(log_file, "$strings_with_offsets = [\n");

    // Process strings found in the .rdata section
    auto rdata_strings = find_strings_in_section(hProcess, rdata_section_start, rdata_section_end, minStringLength);
    for (const auto& item : rdata_strings) {
        uintptr_t string_addr = item.second;
        uintptr_t reference_addr = find_reference_in_data_section(hProcess, data_section_start, data_section_end, string_addr);

        if (reference_addr != 0) {
            uintptr_t offset = reference_addr - base_addr;

            // Log detailed addresses and the originating section
            log_message(log_file, "String: \"%s\"\n", item.first.c_str());
            log_message(log_file, "String Address (.rdata): 0x%llx\n", string_addr);
            log_message(log_file, "Reference Address (.data): 0x%llx\n", reference_addr);
            log_message(log_file, "Offset from Base: 0x%llx\n", offset);

            log_message(log_file, "    \"%s\" at offset: 0x%llx in .data section\n", item.first.c_str(), offset);
        }
    }

    log_message(log_file, "];\n");

    CloseHandle(hProcess);
    fclose(log_file);

    return 0;
}