从我在C++中没有的应用程序中读取内存(vb.net中的示例)

Reading memory from an application I do not own in C++ (example in vb.net)

本文关键字:vb net 内存 应用程序 C++ 读取      更新时间:2023-10-16

几个月前,在我开始学习C++之前,我在VB.net中制作了一个从外部程序读取内存的应用程序。这可以是任何东西,从记事本到windows媒体播放器等。

我一直在试图找到一种在C++中做同样事情的方法,但令我惊讶的是,我在这个主题上找不到任何直截了当的东西。谷歌只会在几个论坛上发布帖子,人们的普遍反应是"Windows不允许你从你不拥有的内存中读取"。但如果它在VB.net中工作,它也可以在C++中工作。

不要被代码的数量所欺骗,它非常简单。

声明

Imports System.Math
Imports System.Threading
Imports System.Runtime.InteropServices
//Guess what this does ;D
Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Integer, ByVal bInheritHandle As Integer, ByVal dwProcessId As Integer) As Integer
//Allows us to read a float from the memory.
Private Declare Function ReadProcessMemory Lib "kernel32" _
Alias "ReadProcessMemory" (ByVal hProcess As Integer, _
                           ByVal lpBaseAddress As Integer, _
                           ByRef lpBuffer As Single, _
                           ByVal nSize As Integer, _
                           ByRef lpNumberOfBytesWritten As Integer) As Integer
//Allows us to read an integer or string from the memory. String will require a loop.
Private Declare Function ReadProcessMemoryInt Lib "kernel32" _
    Alias "ReadProcessMemory" (ByVal hProcess As Integer, _
                               ByVal lpBaseAddress As Integer, _
                               ByRef lpBuffer As Integer, _
                               ByVal nSize As Integer, _
                               ByRef lpNumberOfBytesWritten As Integer) As Integer
//Allows us to find a memory address when provided with a pointer and offsets
Private Declare Function ReadProcessMemoryPointer Lib "kernel32" Alias "ReadProcessMemory" ( _
   ByVal hProcess As IntPtr, _
   ByVal lpBaseAddress As IntPtr, _
   <Out()> ByVal lpBuffer() As Byte, _
   ByVal dwSize As Integer, _
   ByRef lpNumberOfBytesRead As Integer) As Boolean
//Close a handle
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Integer) As Integer
//Shortcut to get read & write access to an application
Const PROCESS_ALL_ACCESS = &H1F0FFF

使用这些声明的函数

//Function to get string from memory
Public Function memstring(ByVal address As Long, ByVal length As Int32, ByVal processHandle As IntPtr)
    Dim stringinmemory As Long
    Dim ret1 As Byte() = Nothing
    Dim tStr(length) As Char
    Dim retStr As String = ""
    For i As Int32 = 0 To length - 1
        ReadProcessMemoryInt(processHandle, address + i, stringinmemory, 1, 0)
        ret1 = BitConverter.GetBytes(stringinmemory)
        tStr(i) = System.Text.Encoding.ASCII.GetString(ret1) : retStr += tStr(i)
    Next
    Return retStr
End Function
//Function to get float from memory. I don't know what those comments are all about, it's been a long time since I used this code.
Public Function memfloat(ByVal address As Long, ByVal processHandle As IntPtr)
    Dim floatvalueinmemory As Single
    ReadProcessMemory(processHandle, address, floatvalueinmemory, 4, 0)
    //Floatvalueinmemory didn't give the desired result, so going to try to TryParse
    Dim letstryagain As Single
    Single.TryParse(floatvalueinmemory, letstryagain)
    //Unfortunately returns the same result as floatvalueinmemory did
    Return CStr(letstryagain)
End Function
//Function to get int from memory
Public Function memInt(ByVal address As Long, ByVal processHandle As IntPtr)
    Dim intvalueinmemory As Integer
    ReadProcessMemoryInt(processHandle, address, intvalueinmemory, 4, 0)
    Return CStr(intvalueinmemory)
End Function
//Function to find a memory address when provided with a pointer and offsets
Private Function FindAddress(ByVal pHandle As IntPtr, ByVal BaseAddress As IntPtr, ByVal StaticPointer As IntPtr, ByVal Offsets() As IntPtr) As IntPtr
    // Create a buffer that is 4 bytes on a 32-bit system or 8 bytes on a 64-bit system.
    Dim tmp(IntPtr.Size - 1) As Byte
    Dim Address As IntPtr = BaseAddress
    // We must check for 32-bit vs 64-bit.
    If IntPtr.Size = 4 Then
        Address = New IntPtr(Address.ToInt32 + StaticPointer.ToInt32)
    Else
        Address = New IntPtr(Address.ToInt64 + StaticPointer.ToInt64)
    End If
    // Loop through each offset to find the address
    For i As Integer = 0 To Offsets.Length - 1
        ReadProcessMemoryPointer(pHandle, Address, tmp, IntPtr.Size, 0)
        If IntPtr.Size = 4 Then
            Address = BitConverter.ToInt32(tmp, 0) + Offsets(i).ToInt32()
        Else
            Address = BitConverter.ToInt64(tmp, 0) + Offsets(i).ToInt64()
        End If
    Next
    Return Address
End Function

示例用法

Sub somesub()
    //Get process handle.
    Dim myProcesses As Process() = Process.GetProcessesByName("SomeProgram")
    Dim processHandle As IntPtr = OpenProcess(PROCESS_ALL_ACCESS, 0, myProcesses(0).Id)
    //We'll need the base address when we need to find an address through pointers.
    BaseAddressSet = myProcesses(0).MainModule.BaseAddress
    //Get float from memory.
    somefloat = memfloat(&H12980D8, processHandle)
    //Get string from memory.
    somestring = memstring(&H12955E0, 15, processHandle)
    //Get float from memory through a pointer.
    Dim sptr As IntPtr = &HF28EE4 //Static pointer for float address we want to get
    Dim Offsets As IntPtr() = {&H61C, &H19C, &H2AC, &HDC, &H198} //Offsets for float address we want to get
    Dim addr As IntPtr = FindAddress(processHandle, BaseAddressSet, sptr, Offsets)
    somefloat = memfloat(addr, processHandle)
    //All done.
    CloseHandle(processHandle)
 End Sub

页脚

Partial Public Class NativeMethods
    <DllImport("user32.dll")> _
    Public Shared Function ReadProcessMemory(ByVal hProcess As System.IntPtr, ByVal lpBaseAddress As IntPtr, ByVal lpBuffer As System.IntPtr, ByVal nSize As UInteger, ByVal lpNumberOfBytesRead As IntPtr) As Boolean
    End Function
End Class

请建议如何在C++中做到这一点,或者在哪里我可以学习如何做到这一步。

下面是一个小程序,用于在指定目标进程的内存块中搜索指定字符串。

#include <iostream>
#include <vector>
#include <string>
#include <windows.h>
#include <algorithm>
#include <iterator>
template <class outIter>
void find_locs(HANDLE process, std::string const &pattern, outIter output) {
    unsigned char *p = NULL;
    MEMORY_BASIC_INFORMATION info;
    for ( p = NULL;
        VirtualQueryEx(process, p, &info, sizeof(info)) == sizeof(info);
        p += info.RegionSize ) 
    {
        std::vector<char> buffer;
        std::vector<char>::iterator pos;
        if (info.State == MEM_COMMIT && 
            (info.Type == MEM_MAPPED || info.Type == MEM_PRIVATE)) 
        {
            DWORD bytes_read;
            buffer.resize(info.RegionSize);
            ReadProcessMemory(process, p, &buffer[0], info.RegionSize, &bytes_read);
            buffer.resize(bytes_read);
            for ( pos = buffer.begin();
                buffer.end()!=(pos=std::search(pos, buffer.end(), pattern.begin(), pattern.end()));
                ++pos)
            {
                *output++ = p+(pos-buffer.begin());
            }
        }
    }
}
int main(int argc, char **argv) {
    if (argc != 3) {
        fprintf(stderr, "Usage: %s <process ID> <pattern>", argv[0]);
        return 1;
    }
    int pid;
    sscanf(argv[1], "%i", &pid);
    std::string pattern(argv[2]);
    HANDLE process = OpenProcess( 
        PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, 
        false,
        pid);
    find_locs(process, pattern, 
        std::ostream_iterator<void *>(std::cout, "n"));
    return 0;
}

要构建它,您需要为链接器指定正确的库:

cl search_proc.cpp kernel32.lib