首页 > 解决方案 > AccessException:试图读取或写入受保护/损坏的内存——已知异常,未知原因?

问题描述

是的,我知道这个异常有一百万个线程,我可能已经查看了其中的 20-25 个,但遗憾的是,似乎没有一个原因与此相关(因此标题,已知异常,未知原因)。

我最近对 ​​InfoSec 产生了兴趣。作为我的第一个学习者项目,我将创建一个基本的 DLL 注入器。到目前为止似乎进展顺利,但是,这个例外让我很沮丧,经过一些相对广泛的研究,我很困惑。奇怪的是,在函数完全完成后异常也会上升。

我自己无法真正弄清楚这一点,因为外部调试器无法与我的目标应用程序一起使用,这是一个全新的不相关问题。

到目前为止建议和尝试的解决方案:

无论如何,这是我的一大块代码:

#pragma once

#include "pch.h"
#include "injection.h" // only specifies UserInject as an exportable proto. 

DWORD __stdcall UserInject(DWORD ProcessId, PCSTR DllPath, BOOL UseExtended) {
    DWORD length;
    CHAR* buffer;
    LPVOID memry;
    SIZE_T write;
    HANDLE hProc;
    HMODULE kr32;
    HANDLE thread;

    length = GetFullPathName(
        DllPath,
        NULL,
        NULL,
        NULL
    );
    AssertNonNull(length, INVALID_PATH);

    kr32 = GetModuleHandle("kernel32.dll");
    AssertNonNull(kr32, YOUREALLYMESSEDUP);

    buffer = new CHAR[length];

    GetFullPathName(
        DllPath,
        length,
        buffer,
        NULL
    );
    AssertNonNull(buffer, ERR_DEAD_BUFFER);

    hProc = OpenProcess(
        ADMIN,
        FALSE,
        ProcessId
    );
    AssertNonNull(hProc, INVALID_PROCID);

    memry = VirtualAllocEx(
        hProc,
        nullptr,
        sizeof buffer,
        SHELLCODE_ALLOCATION,
        PAGE_EXECUTE_READWRITE
    );
    AssertNonNull(memry, INVALID_BUFSIZE);

    WriteProcessMemory(
        hProc,
        memry,
        DllPath,
        sizeof DllPath,
        &write
    );
    AssertNonNull(write, ERR_SOLID_BUFFER);

    auto decidePrototype = [](BOOL UseExtended, HMODULE kr32) -> decltype(auto) {
        LPVOID procAddress; 

        if (!UseExtended) {
            procAddress = (LPVOID)GetProcAddress(kr32, LOADLIB_ORD);
        }
        else {
            procAddress = (LPVOID)GetProcAddress(kr32, LOADLIBX_ORD);
        };

        return (LPTHREAD_START_ROUTINE)procAddress;
    };

    auto loadLibraryAddress = decidePrototype(UseExtended, kr32);

    thread = CreateRemoteThread(
        hProc,
        NULL,
        NULL,
        loadLibraryAddress,
        memry,
        NULL,
        NULL
    );
    AssertNonNull(thread, INVALID_ROUTINE);

    WaitForSingleObject(thread, INFINITE);

    // The status stuff is quite weird; it was an attempt at debugging. The error occurs with or without this code.
    // I left it because 50% of the comments below wouldn't make sense. Just be assured this code is positively *not* the problem (sadly). 
    // LPDWORD status = (LPDWORD)1;
    // GetExitCodeThread(thread, status);

    return TRUE // *status;
}

一个不起眼的宏是“ADMIN”,它扩展为“PROCESS_ALL_ACCESS”,缩短以更好地适应。另一个是“AssertNonNull”:

#define AssertNonNull(o, p)      if (o == NULL) return p;

我已经尝试过调试这段代码,但它不会在任何特定点停止。除了完整性检查之外,我还对每个操作(例如分配、写入)进行了 MessageBox 测试,但没有得到任何有趣的响应。

很抱歉,我无法添加太多广泛的细节,但我在这里真的很僵硬,不知道该怎么做,要获得什么信息,或者是否有什么要获得的。简而言之,我只是不确定要寻找什么。

这也是从 C# 中调用的,1% 的伪代码。

[DllImport(path, CallingConvention = CallingConvention.StdCall)]
static extern int UserInject(uint ProcId, string DllPath, bool UseExtended);

uint validProcId;    // integrity tested 
string validDllPath; // integrity tested

UserInject(validProcId, validDllPath, true);

如果您对我的测试应用程序感兴趣(用于复制)

#include <iostream>
#include <Windows.h>

static const std::string toPrint = "Hello, World!\n";

int main() 
{
    while (true) 
    {
        Sleep(1000);

        std::cout << toPrint;
    }
}

标签: c++securitywinapi

解决方案


令我惊讶的是,这对于代码来说并没有像测试应用程序那样严重。

我使用的基本注入技术被 Visual Studio 2010+ 应用于任何以发布模式构建的应用程序的各种漏洞利用保护和安全缓解措施所阻止。

如果我在调试模式下构建我的测试应用程序,也不例外。如果我使用非 VS 构建的应用程序,也不例外。

我仍然需要修复创建线程的方式,因为没有创建线程,但我已经弄清楚了,这应该很容易。


推荐阅读