8

Perl、Python、または Ruby を使用して、別のプロセスのメモリ (おそらくデータとコード データの両方のヒープ) で 0x12345678 を探し、見つかった場合は変更するようにプログラムを作成できるかどうか疑問に思います。 0x00000000? これは、Windows でそのようなことを行うことができるCheat Engineに似たものです。

4

6 に答える 6

13

最初はこれは不可能だと思っていましたが、Brian のコメントを見て、CPAN を検索したところ、見よ、Win32::Process::Memoryがあります。

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

モジュールは明らかにReadProcessMemory関数を使用しています: ここに私の試みの1つがあります:

#!/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 }

出力:

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
于 2009-06-18T16:52:57.927 に答える
8

プログラムをデバッガーとしてプロセスにアタッチしている場合、適切な API のラッパーが存在する場合、または ctypes (python の場合) などを介して Windows 関数に直接アクセスすることによって、これらの言語で可能である必要があります。ただし、高レベルの言語では、高レベルのデータ型を低レベルのデータ型に変換する方法などに注意する必要があるため、より低レベルの言語で行う方が簡単な場合があります。

デバッグするプロセスでOpenProcessを呼び出し、適切なアクセスを要求することから始めます (マシンの管理者である必要があり、アクセスするにはかなり高い権限が必要です)。その後、 ReadProcessMemoryWriteProcessMemoryなどの関数を呼び出して、そのプロセスのメモリから読み書きできるようになります。

[編集] これは、別のプロセスのアドレス空間からメモリを正常に読み取る関数の概念の簡単な 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)

ものを探すためにメモリ内のどこを決定する必要があることに注意してください - プログラムコード、dllなどを探すための標準的なオフセットがあるとはいえ、そのアドレス空間のほとんどはマップされていません.

于 2009-06-18T18:42:44.583 に答える
6

楽しい部分は、他のプロセスのメモリにアクセスすることです。CheatEngine は、メモリ保護を無効にできる仮想マシンで OS 全体を実行することによってそれを行います。また、「デバッガーの下で実行する」モデルもあります。これは、一般に、ターゲット アプリケーションを変更アプリケーションの子プロセスとして、昇格された特権で開始することを意味します。それに関する多くの楽しいことについては、 Win32 APIを参照してください。

Perl では、必要なアクセス権を取得したら、おそらくWin32::Security::Rawを使用して操作したいと思うでしょう。

于 2009-06-18T17:07:15.570 に答える
4

プロセス インジェクション、遅延ロード ライブラリなどを使用してこれを行う方法があります。

あなたがリストしたツールからそれをやっているとは思いません。これは C とアセンブラの国であり、ウイルス作成の領域にあなたを導き始めています。動作するようになると、ウイルス対策パッケージは実行を拒否し、隔離しようとします。だから、あなたは本当にこれをしたいのです。

「力には多くのことが伴う....」

幸運を

于 2009-06-18T16:59:45.550 に答える
0

リストされた言語のいずれかでプロセス全体を実装することは可能ですが、コンパイルされた言語の方がメモリ スキャンに適しています (他に何もない場合でも速度を考慮する必要があります)。SigScan と呼ばれる dll (ソース付き) が利用可能で、特定のゲーム用に調整されていますが、最小限の労力でニーズに合わせて変更できる可能性があります。

ブライアンの正解に基づいて、dll を使用して Python 内からアドレスを取得する簡単で汚い例を次に示します。もちろん、これは DLL の実装に固有のものです。「モジュール名」は通常、チート エンジンの「DLL とシンボルの列挙」ダイアログに表示される DLL 名です。

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)
于 2009-08-01T11:49:49.733 に答える