Win API ReadProcessMemory 位于返回意外数据的 DLL 的基地址

Win API ReadProcessMemory at base address of DLL returning unexpected data

我正在尝试从内存中读取 DLL 的内容以进行一些学术研究。具体来说,NTDSA.DLL 库的目的是改变特定指令以模拟编程错误以迫使系统失败。然后将记录失败以训练机器学习算法以预测未来的失败(这是对先前发表的研究进行概括的尝试 seen here)。

我正在通过概述的过程 here 获得我认为是 lsass.exe 进程(加载目标 DLL)的虚拟内存中的基址。然后,我使用分配的缓冲区调用 ReadProcessMemory,并通过设置 'PROCESS_ALL_ACCESS' 调用 OpenProcess 获得 lsass 的句柄。错误代码为 299 的 ReadProcessMemory returns 80% 的时间(部分读取)读取零字节。我的假设是,在拨打电话时,我尝试访问的区域正在使用中。幸运的是,它偶尔会 return 我请求的字节数。不幸的是,与 System32 目录中的静态 DLL 相比,数据 returned 与磁盘上的内容不匹配。

所以问题是,ReadProcessMemory 是在用我给它的地址做一些有趣的事情,还是我的虚拟地址有误?是否有另一种方法可以找出该 DLL 加载到内存中的位置?有什么想法吗?任何帮助或建议将不胜感激。

添加代码:

// FaultInjection.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#include <windows.h>
#include <psapi.h>

#include <string>
#include <iostream>
#include <fstream>
#include <stdio.h>
#include <io.h>
#include <tchar.h>

using namespace std;

int _tmain(int argc, _TCHAR* argv[]) {

    // Declarations
    int pid = 0;
    __int64* start_addr;
    DWORD size_of_ntdsa;
    DWORD aProcesses[1024], cbNeeded, cProcesses;
    TCHAR szProcessName[MAX_PATH] = TEXT("<unknown>");
    HMODULE hmods[1024];
    unsigned int i;

    // Get All pids
    if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded)){
        cout << "Failed to get all PIDs: " << GetLastError() << endl;
        return -1;
    }

    // Find pid for lsass.exe
    cProcesses = cbNeeded / sizeof(DWORD);
    for (i = 0; i < cProcesses; i++) {
        if (aProcesses[i] != 0) {
            HANDLE hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, aProcesses[i]);
            if (hProc != NULL) {
                HMODULE hMod;
                DWORD cbNeededMod;
                if (EnumProcessModules(hProc, &hMod, sizeof(hMod), &cbNeededMod)) {
                    GetModuleBaseName(hProc, hMod, szProcessName, sizeof(szProcessName) / sizeof(TCHAR));
                }

                if (wstring(szProcessName).find(L"lsass.exe") != string::npos) {
                    pid = aProcesses[i];
                }
                CloseHandle(hProc);
            }
        }
    }

    cout << "lsass pid: " << pid << endl;

    HANDLE h_lsass = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
    if (!h_lsass) {
        cout << "Failed to open process (are you root?): " << GetLastError() << endl;
        return -1;
    }

    // Get Process Image File Name
    char filename[MAX_PATH];
    if (GetProcessImageFileName(h_lsass, (LPTSTR)&filename, MAX_PATH) == 0) {
        cout << "Failed to get image file name: " << GetLastError() << endl;
        CloseHandle(h_lsass);
        return -1;
    }

    // Enumerate modules within process
    if (EnumProcessModules(h_lsass, hmods, sizeof(hmods), &cbNeeded)) {
        for (i = 0; i < (cbNeeded / sizeof(HMODULE)); i++) {
            TCHAR szModName[MAX_PATH];
            if (GetModuleFileNameEx(h_lsass, hmods[i], szModName, sizeof(szModName) / sizeof(TCHAR))) {
                if (wstring(szModName).find(L"NTDSA.dll") != string::npos) {
                    _tprintf(TEXT("%s\n"), szModName);
                    MODULEINFO lModInfo = { 0 };
                    if (GetModuleInformation(h_lsass, hmods[i], &lModInfo, sizeof(lModInfo))){
                        cout << "\t Base Addr: " << lModInfo.lpBaseOfDll << endl;
                        cout << "\t Entry Point: " << lModInfo.EntryPoint << endl;
                        cout << "\t Size of image: " << lModInfo.SizeOfImage << endl;

                        start_addr = (__int64*)lModInfo.lpBaseOfDll;
                        size_of_ntdsa = lModInfo.SizeOfImage;
                    }
                    else {
                        cout << "Failed to Print enumerated list of modules: " << GetLastError() << endl;
                    }
                }
            } else {
                cout << "Failed to Print enumerated list of modules: " << GetLastError() << endl;
            }
        }
    }
    else {
        cout << "Failed to enum the modules: " << GetLastError() << endl;
    }

    // Ready to continue?
    string cont = "";
    cout << "Continue? [Y|n]: ";
    getline(cin, cont);
    if (cont.find("n") != string::npos || cont.find("N") != string::npos) {
        CloseHandle(h_lsass);
        return 0;
    }

    void* buf = malloc(size_of_ntdsa);
    if (!buf) {
        cout << "Failed to allocate space for memory contents: " << GetLastError() << endl;
        CloseHandle(h_lsass);
        return -1;
    }

    SIZE_T num_bytes_read = 0;
    int count = 0;

    if (ReadProcessMemory(h_lsass, &start_addr, buf, size_of_ntdsa, &num_bytes_read) != 0) {
        cout << "Read success. Got " << num_bytes_read << " bytes: " << endl;
    } else {
        int error_code = GetLastError();
        if (error_code == 299) {
            cout << "Partial read. Got " << num_bytes_read << " bytes: " << endl;
        } else  {
            cout << "Failed to read memory: " << GetLastError() << endl;
            CloseHandle(h_lsass);
            free(buf);
            return -1;
        }
    }

    if (num_bytes_read > 0) {
        FILE *fp;
        fopen_s(&fp, "C:\ntdsa_new.dll", "w");
        SIZE_T bytes_written = 0;
        while (bytes_written < num_bytes_read) {
            bytes_written += fwrite(buf, 1, num_bytes_read, fp);
        }
        fclose(fp);
        cout << "Wrote " << bytes_written << " bytes." << endl;
    }

    CloseHandle(h_lsass);
    free(buf);

    return 0;
}

代码按照描述工作,减去了我发送变量地址的业余错误,我用来存储目标应用程序虚拟内存中的位置地址。在上面的代码中,更改:

if (ReadProcessMemory(h_lsass, &start_addr, buf, size_of_ntdsa, &num_bytes_read) != 0) {

if (ReadProcessMemory(h_lsass, start_addr, buf, size_of_ntdsa, &num_bytes_read) != 0) {

很有魅力。谢谢ssbssa指出错误,抱歉浪费大家的时间。