简体   繁体   English

如何编写Perl,Python或Ruby程序来改变Windows上另一个进程的内存?

[英]How to write a Perl, Python, or Ruby program to change the memory of another process on Windows?

I wonder if Perl, Python, or Ruby can be used to write a program so that it will look for 0x12345678 in the memory of another process (probably the heap, for both data and code data) and then if it is found, change it to 0x00000000? 我想知道是否可以使用Perl,Python或Ruby来编写程序,以便它在另一个进程的内存中查找0x12345678(可能是堆,对于数据和代码数据)然后如果找到它,则更改它到0x00000000? It is something similar to Cheat Engine , which can do something like that on Windows. 它类似于Cheat Engine ,可以在Windows上执行类似的操作。

I initially thought this was not possible but after seeing Brian's comment, I searched CPAN and lo and behold, there is Win32::Process::Memory : 我最初认为这是不可能的,但在看到Brian的评论之后,我搜索了CPAN并且看到,有Win32 :: Process :: Memory

C:\> ppm install Win32::Process::Info
C:\> ppm install Win32::Process::Memory

The module apparently uses the ReadProcessMemory function: Here is one of my attempts: 该模块显然使用了ReadProcessMemory函数:这是我的一个尝试:

#!/usr/bin/perl
use strict; use warnings;

use Win32;
use Win32::Process;
use Win32::Process::Memory;

my $process;

Win32::Process::Create(
    $process,
    'C:/opt/vim/vim72/gvim.exe',
    q{},
    0,
    NORMAL_PRIORITY_CLASS,
    q{.}
) or die ErrorReport();

my $mem = Win32::Process::Memory->new({
    pid => $process->GetProcessID(),
    access => 'read/query',
});

$mem->search_sub( 'VIM', sub {
    print $mem->hexdump($_[0], 0x20), "\n";
});

sub ErrorReport{
    Win32::FormatMessage( Win32::GetLastError() );
}

END { $process->Kill(0) if $process }

Output: 输出:

C:\Temp> proc
0052A580 : 56 49 4D 20 2D 20 56 69 20 49 4D 70 72 6F 76 65 : VIM - Vi IMprove
0052A590 : 64 20 37 2E 32 20 28 32 30 30 38 20 41 75 67 20 : d 7.2 (2008 Aug

0052A5F0 :       56 49 4D 52 55 4E 54 49 4D 45 3A 20 22 00 :   VIMRUNTIME: ".
0052A600 : 20 20 66 61 6C 6C 2D 62 61 63 6B 20 66 6F 72 20 :   fall-back for
0052A610 : 24 56                                           : $V

It is possible to do so if you have attached your program as a debugger to the process, which should be possible in those languages if wrappers around the appropriate APIs exist, or by directly accessing the windows functions through something like ctypes (for python). 如果您已将程序作为调试程序附加到进程,则可以执行此操作,如果存在适当API的包装,则可以使用这些语言,或者通过类似ctypes(用于python)直接访问Windows函数。 However, it may be easier to do in a more low-level language, since in higher level ones you'll have to be concerned with how to translate highlevel datatypes to lower ones etc. 但是,使用更低级别的语言可能更容易,因为在更高级别的语言中,您必须关注如何将高级数据类型转换为较低级别的语言。

Start by calling OpenProcess on the process to debug, with the appropriate access requested (you'll need to be an Admin on the machine / have fairly high privileges to gain access). 首先调用要调试的进程上的OpenProcess ,并请求相应的访问权限(您需要成为计算机上的管理员/具有相当高的权限才能获得访问权限)。 You should then be able to call functions like ReadProcessMemory and WriteProcessMemory to read from and write to that process's memory. 然后,您应该能够调用ReadProcessMemoryWriteProcessMemory等函数来读取和写入该进程的内存。

[Edit] Here's a quick python proof of concept of a function that successfully reads memory from another process's address space: [编辑]这是一个快速python概念的功能概念,成功从另一个进程的地址空间读取内存:

import ctypes
import ctypes.wintypes
kernel32 = ctypes.wintypes.windll.kernel32

# Various access flag definitions:
class Access:
    DELETE      = 0x00010000
    READ_CONTROL= 0x00020000
    SYNCHRONIZE = 0x00100000
    WRITE_DAC   = 0x00040000
    WRITE_OWNER = 0x00080000
    PROCESS_VM_WRITE = 0x0020
    PROCESS_VM_READ = 0x0010
    PROCESS_VM_OPERATION = 0x0008
    PROCESS_TERMINATE = 0x0001
    PROCESS_SUSPEND_RESUME = 0x0800
    PROCESS_SET_QUOTA = 0x0100
    PROCESS_SET_INFORMATION = 0x0200
    PROCESS_QUERY_LIMITED_INFORMATION = 0x1000
    PROCESS_QUERY_INFORMATION = 0x0400
    PROCESS_DUP_HANDLE = 0x0040
    PROCESS_CREATE_THREAD = 0x0002
    PROCESS_CREATE_PROCESS = 0x0080

def read_process_mem(pid, address, size):
    """Read memory of the specified process ID."""
    buf = ctypes.create_string_buffer(size)
    gotBytes = ctypes.c_ulong(0)
    h = kernel32.OpenProcess(Access.PROCESS_VM_READ, False, pid)
    try:
        if kernel32.ReadProcessMemory(h, address, buf, size, ctypes.byref(gotBytes)):
            return buf
        else:
            # TODO: report appropriate error GetLastError
            raise Exception("Failed to access process memory.")
    finally:
        kernel32.CloseHandle(h)

Note that you'll need to determine where in memory to look for things - most of that address space is going to be unmapped, thought there are some standard offsets to look for things like the program code, dlls etc. 请注意,您需要确定在内存中查找内容的位置 - 大部分地址空间将被取消映射,认为有一些标准偏移量可用于查找程序代码,dll等内容。

Well, the fun part is getting access to the other process's memory. 好吧,有趣的部分是访问其他进程的内存。 CheatEngine does it by running your entire OS under a virtual machine that allows memory protection to be defeated. CheatEngine通过在虚拟机下运行整个操作系统来实现这一点,该虚拟机可以防止内存保护。 There's also the 'running under a debugger' model, generally meaning start the target application as a child process of the modifying application, with elevated privileges. 还有“在调试器下运行”模型,通常意味着将目标应用程序作为修改应用程序的子进程启动,并提升权限。 See the Win32 API for lots of fun stuff about that. 有关这方面的许多有趣的东西,请参阅Win32 API

In Perl, once you had the requisite access, you'd probably want to interact with it using Win32::Security::Raw . 在Perl中,一旦你获得了必要的访问权限,你可能想要使用Win32 :: Security :: Raw与它进行交互。

There are ways to do do this using Process injection, delay load library etc. 使用Process injection,延迟加载库等方法可以做到这一点。

I don't see you doing it from the tools you have listed. 我没有看到你从你列出的工具中做到这一点。 This is C and assembler country and beginning to get you into virus writing territory. 这是C和汇编国家,并开始让你进入病毒编写领域。 Once you get it to work, any anti-virus packages will veto it running and try and isolate it. 一旦你开始工作,任何反病毒软件包都会否决它运行并尝试隔离它。 So you better really want to do this. 所以你最好真的想要这样做。

"With power comes much ...." “随着力量的增加......”

Good luck 祝好运

It is possible to implement the entire process in one of the languages listed but a compiled language would be better for memory scanning (speed considerations if nothing else). 可以用列出的一种语言实现整个过程,但编译语言更适合内存扫描(如果没有别的话,速度考虑因素)。 There is a dll (with source) called SigScan available that, while tailored for a specific game, could probably be modified to suite your needs with minimal effort. 有一个名为SigScan的dll(带有源代码),虽然可以针对特定游戏量身定制,但可以通过最小的努力进行修改以满足您的需求。

Building on Brian's correct answer here's a quick and dirty example of using a dll to get your address from within python. 基于Brian的正确答案,这是一个使用dll从python中获取地址的快速而肮脏的例子。 This is, of course, specific to the DLLs implementation. 当然,这是特定于DLL的实现。 "Module name" would generally be the dll name as displayed in Cheat Engines "Enumerate DLLs and Symbols" dialog. “模块名称”通常是Cheat Engines“Enumerate DLLs and Symbols”对话框中显示的dll名称。

With Brian's example as a guideline and MSDN you could easily extend this with your own WriteProcessMemory method. 使用Brian的示例作为指南和MSDN,您可以使用自己的WriteProcessMemory方法轻松扩展它。

import win32defines
import win32process
import win32gui
from ctypes import *
SigScan = cdll.SigScan
kernel32 = windll.kernel32
addresses = {"Value1" : {"sigArg1" : "b0015ec390518b4c24088d4424005068", 
                          "sigArg2" : 36, 
                          "address" : None,
                          "size"    : 32
                         },
            "Value2" :{"sigArg1" : "3b05XXXXXXXX741285c0",
                          "sigArg2" : None, 
                          "address" : None,
                          "size"    : 32
                        }
        }

def read_process_mem(pid, address, size):
    """Read memory of the specified process ID."""
    buf = create_string_buffer(size)
    gotBytes = c_ulong(0)
    h = kernel32.OpenProcess(win32defines.PROCESS_VM_READ, False, pid)
    try:
        if kernel32.ReadProcessMemory(h, address, buf, size, byref(gotBytes)):
            return buf
        else:
            # TODO: report appropriate error GetLastError
            raise Exception("Failed to access process memory.")
    finally:
        kernel32.CloseHandle(h)
if __name__ == "__main__":
    pid, id = None, None
    ## HWND 
    hwnd = win32gui.FindWindowEx(0, 0, 0, "Window Name here")
    ## pid
    pid = win32process.GetWindowThreadProcessId(hwnd)[-1]
    ## Initialize the sigscan dll
    SigScan.InitializeSigScan(pid, "Module Name")
    ## Find all the addresses registered
    for key in addresses.keys():
        addresses[key]["address"] = SigScan.SigScan(addresses[key]["sigArg1"],
            addresses[key]["sigArg2"])
    ## Allow the scanner to clean up
    SigScan.FinalizeSigScan()
    for key in addresses.keys():
        if addresses[key]["address"] != None:
            print repr(read_process_mem(pid, addresses[key]["address"],
                            addresses[key]["size"]).raw)

I wrote Proc::Memory and its underlying library libvas for this purpose. 我为此目的编写了Proc :: Memory及其底层库libvas It just calls {Read,Write}ProcessMemory under the hood on Windows, but it also supports other platforms. 它只是在Windows上调用{Read,Write}ProcessMemory ,但它也支持其他平台。 Example: 例:

my $mem = Proc::Memory->new(pid => $$); 
$mem->poke(0x12345678, 'L') = 12;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM