Ruby で外部プロセスからメモリ値を読み取るにはどうすればよいですか?
-
26-09-2019 - |
質問
したがって、私がやりたいのは、別のプロセスの仮想メモリ内の既知のメモリ アドレスから値を読み取る Ruby プログラムを作成することだけです。メモリ内で実行中のプロセスの x86 アセンブリを 16 進数編集するための研究と基本的な知識を通じて、メモリ内で必要な値のベース アドレスとオフセットを見つけました。私はそれらを変更したくありません。ただ読みたいだけです。私はメモリ エディタの開発者に、Windows プラットフォームを前提としてこの言語の抽象的なアプローチにどのようにアプローチするかを尋ねました。彼は、OpenProcess、CreateProcess、ReadProcessMemory、および WriteProcessMemory の Win32API 呼び出しは、C または C++ を使用する方法だと言いました。Win32API クラスを使用し、その 2 つのインスタンスをマッピングするだけが解決策だと思います。ユーザーがすでにプロセスを実行しているかどうかに応じて、OpenProcess または CreateProcess のいずれかに 1 つと、別のインスタンスが ReadProcessMemory にマップされます。おそらく、実行中のプロセスのリストを取得する関数を見つける必要があります。これにより、実行中のプロセスがすでに実行されている場合に、必要な実行中のプロセスを知ることができます。
これをすべてまとめるには多少の作業が必要ですが、コードを作成するのはそれほど悪くないと考えています。私にとって、これはプログラミングの新しい分野です。なぜなら、私は高級言語 (まあ、いずれにしても C よりも高いレベル) からこの低レベルを開発したことがないからです。これにアプローチする方法を考えているだけです。大量のまたは Win32API 呼び出しを使用することもできますが、それは、システムに依存する一連の文字列と配列のパックと解凍を処理する必要があることを意味します。読み取り中のプロセスが生成されているため、最終的にはこれをクロスプラットフォームで機能させたいと考えています。複数のプラットフォーム ビルドを含む実行可能ファイル (メモリ アドレスがシステムごとに異なることはわかっています。アイデアは、すべてのメモリ マッピングを含むフラット ファイルを用意して、Ruby プログラムが現在のプラットフォーム環境を一致するメモリ マッピングに一致させるだけで済むようにすることです。) しかし、見た目からすると、すべてをラップするクラスを作成する必要があるだけです。現在のプラットフォームのシステム共有ライブラリ メモリ関連の関数呼び出し。
私が知っている限りでは、これらすべてを処理してくれる Ruby gem がすでに存在する可能性がありますが、私が見つけていないだけです。また、各ビルドの実行可能ファイルを編集して、読み取りたいメモリ値がプロセスによって書き込まれるたびに、何らかの方法で共有メモリ内のスペースに新しい値のコピーを書き込むようにすることもできます。 Ruby は、その共有メモリ アドレスへのポインタであるクラスのインスタンスを内部で作成し、値が更新されたので再ロードする必要があることを何らかの方法で Ruby プログラムに通知します。基本的には割り込みベースのシステムが適していますが、これらの値を読み取る目的は中央サーバーからブロードキャストされるスコアボードに送信することだけであるため、一定の時間間隔で更新を送信するポーリングベースのシステムに固執することもできます。Ruby を完全に放棄して C または C++ に進むこともできますが、私はそれらについてもほとんど知りません。実際、私は C++ よりも x86 の知識があり、C についてはシステムに依存しない ANSI C までしか知識がなく、これまで共有システム ライブラリを扱ったことはありません。
それでは、これをすでに実行している利用可能な gem またはあまり知られていないモジュールはありますか?そうでない場合は、これを実現する方法に関する追加情報があれば幸いです。要するに、これをどうやってやればいいのでしょうか?
よろしくお願いします、GRG
追伸:また、これらの Win32API 呼び出しが kernel32.dll ライブラリを対象とする必要があることを確認するとよいでしょう。
解決
win32utils のを見てみましょう。私は、少なくとも自分の足であなたを取得し、あなたの宝石自身があなたのための作業をしない場合は、API自体に掘るする方法の例を与えるべきであると考えています。あなたは弾丸をかむとCでモジュールを記述する必要があります。
他のヒント
Ruby-FFI を使用します。
C と Win32 API を知っている場合は、より簡単に使用できると思われます。 Ruby-FFI
宝石。 Ruby-FFI
C 関数を透過的にラップし、任意の Win32 関数を使用できるようにします。
名前付き共有メモリの場合、Win32 は以下を提供します。 CreateFileMapping( )
そして MapViewOfFile( )
.
これらにはヘッダーがあります
# WINBASEAPI HANDLE WINAPI CreateFileMappingA(HANDLE,LPSECURITY_ATTRIBUTES,DWORD,DWORD,DWORD,LPCSTR);
# WINBASEAPI PVOID WINAPI MapViewOfFile(HANDLE,DWORD,DWORD,DWORD,DWORD);
無効なファイルハンドルを渡すことによって 0xFFFFFFFF
の中へ CreateFileMapping
, を使用すると、ファイルをまったく扱う必要がなく、配列とポインタを使用して共有メモリを定義するだけで済みます。
以下は、共有メモリから読み取る単純化された例です。(製品品質のバージョンでは、リーダーとライターのセマフォと循環バッファーを使用して、両方のプロセスが非同期で進行できるようにしながら、リーダーが読み取りを完了するまでライターがバッファーを上書きしないようにします。)
簡略化された Ruby の例:
require 'ffi'
module Win32
extend FFI::Library
ffi_lib 'kernel32' # see winbase.h
attach_function :CreateFileMapping,
:CreateFileMappingA,[ :uint, :pointer, :long, :long, :long, :pointer ], :pointer
# suffix A indicates the ASCII version
attach_function :MapViewOfFile,
:MapViewOfFile,[ :pointer, :long, :long, :long, :long ], :pointer
end
memoryName = "Share Memory Name"
sz_buf = 1000 # bytes (250 ints, 4 bytes each)
num_ints = sz_buf / 4
# Windows constants
PAGE_READWRITE = 0x0004
FILE_MAP_WRITE = 2
# Get handle to shared memory
hMemory = Win32.CreateFileMapping(0xFFFFFFFF, nil, PAGE_READWRITE, 0, sz_buf, memoryName)
# Create pointer into shared memory in the reader's memory space
pMemory = FFI::MemoryPointer.new(:int, num_ints )
pMemory = Win32.MapViewOfFile(hMemory, FILE_MAP_WRITE, 0, 0, sz_buf)
# Read from shared memory buffer
puts pMemory.read_array_of_int(sz_buf).join(" ")
役立つ情報:
- よくやった C / Win32 での共有メモリ コード (上記のような) の例。 実際、ここで紹介した Writer モジュールを使用して上記のコードをテストできます。タイプを次から変更するだけです。
char *
にint
. - アクセス同期のためのセマフォ