1

この素晴らしいサイトから非常に多くの Google 検索結果が表示された後、初めてここに投稿します。

基本的に、特定のメモリアドレスに格納されている変数の名前を見つけたいと思います。私が書いた単一の値を編集するメモリ編集アプリケーションがあります。問題は、この値を保持するアプリケーションにパッチが適用されるたびに、新しいメモリ アドレスをアプリケーションにハードコードして再コンパイルする必要があることです。これには非常に時間がかかります。それを維持することはほとんど価値がありません。

私がやりたいのは、特定のメモリアドレスに格納されている変数の名前を取得することです。これにより、実行時にそのアドレスを見つけて、それを編集するメモリアドレスとして使用できます。

これはすべて C++ で記述されています。

前もって感謝します!

編集:

.txt ファイルからデータをストリーミングすることにしましたが、WriteProcessMemory() でメモリ アドレスとして使用するために文字列を LPVOID に変換する方法がわかりません。これは私が試したことです:

    string fileContents;

    ifstream memFile("mem_address.txt");
        getline(memFile, fileContents);
    memFile.close();

    LPVOID memAddress = (LPVOID)fileContents.c_str();

    //Lots of code..

    WriteProcessMemory(WindowsProcessHandle, memAddress, &BytesToBeWrote, sizeof(BytesToBeWrote), &NumBytesWrote);

コードは構文に関してはすべて正しく、コンパイルして実行できますが、WriteProcessMemory エラーが発生し、LPVOID 変数に問題があるとしか思えません。質問の使用を拡張することが規則に違反している場合はお詫び申し上げます。違反している場合は編集を削除します。

4

7 に答える 7

7

いわゆるmapファイルをコンパイルして生成します。/MAPこれは、Visual-C++ (リンカー オプション)を使用して簡単に実行できます。そこには、シンボル (関数など) とその開始アドレスが表示されます。このマップ ファイル (注意: 再コンパイルするたびに更新する必要があります) を使用すると、アドレスを名前に一致させることができます。

これは、実際にはそれほど簡単ではありません。なぜなら、アドレスは優先ロード アドレスに相対的であり、おそらく (ランダム化) は実際のロード アドレスとは異なるからです。

正しい住所を取得するための古いヒントがいくつかここにあります: http://home.hiwaay.net/~georgech/WhitePapers/MapFiles/MapFiles.htm

于 2010-08-23T21:48:13.593 に答える
3

一般に、プログラムのコンパイル時に変数の名前は保持されません。コンパイルプロセスを制御している場合は、通常、すべてのグローバル変数のメモリ内の場所を一覧表示するマップファイルを生成するようにリンカーとコンパイラを構成できます。ただし、この場合は、ダイレクトメモリアクセスを使用せずに、外部プログラムが呼び出すことができる適切なコマンドプロトコルを作成することで、目標をより簡単に達成できる可能性があります。

他のプログラムのコンパイルプロセスを制御できない場合は、プログラムにマップファイルまたはデバッグシンボルが付属していない限り、おそらく運が悪いでしょう。どちらも、アドレスから変数の名前を取得するために使用できます。 。

スタック変数の場合、それらの名前を取得するには完全なデバッグシンボルが必要であり、非常に重要なプロセスであることに注意してください。ヒープ変数には名前がないので、当然、そこには運がありません。さらに、@ jdehaanの回答で述べたように、マップファイルは、最良の場合に操作するのが少し難しい場合があります。全体として、他のプログラムのメモリの内容にまったく依存しないようにするために使用できる適切な制御プロトコルを用意するのが最善です。

最後に、他のプログラムを制御できない場合は、変数の場所を別のデータファイルに配置することをお勧めします。このようにして、毎回再コンパイルする必要がなくなり、突っついているプログラムの複数のバージョンをサポートすることもできます。必要に応じて、ある種の自動更新サービスを使用して、このデータファイルの新しいバージョンをサーバーから取得することもできます。

于 2010-08-23T21:53:34.893 に答える
1

問題のアプリケーションを実際に所有していない限り、これを行うための標準的な方法はありません。アプリケーションを所有している場合は、@jdehaanの回答をフォローできます。

いずれにせよ、メモリアドレスをアプリケーションにハードコーディングする代わりに、ターゲットアプリケーションのバージョンごとに変更する必要のあるメモリアドレスでいつでも更新できる単純なフィードをどこかにホストしてみませんか?このように、毎回アプリを再コンパイルする代わりに、新しいバージョンを操作できるようにする必要があるときに、そのフィードを更新するだけで済みます。

于 2010-08-23T21:53:28.447 に答える
1

これを直接行うことはできません。変数名は、コンパイルされたバイナリには実際には存在しません。コンパイルされたバイナリに変数に関する情報を格納するJavaやC#などのプログラムが作成されている場合は、これを実行できる可能性があります。

さらに、ターゲットプログラム内の値の最新のコピーがメモリではなくCPUレジスタ内にある可能性があるため、これは一般的には不可能です。これは、問題のプログラムが最適化をオンにしてリリースモードでコンパイルされている場合に発生する可能性が高くなります。

ターゲットプログラムがデバッグモードでコンパイルされていることを確認できる場合は、アドレスを変数にマップするためにコンパイラーによって発行されたデバッグシンボル(.pdbファイル)を使用できるはずですが、その場合はターゲットを起動する必要がありますデバッグされているかのように処理します。プレーンなReadProcessMemoryメソッドとWriteProcessMemoryメソッドは機能しません。

最後に、あなたの質問は非常に重要な考慮事項を無視しています。そのような情報が保存されている場合でも、特定のアドレスに対応する変数は必要ありません。

于 2010-08-23T21:54:08.860 に答える
0

WinDBG には特に便利なコマンドがあります

ここ

メモリの場所を指定すると、その場所にあるシンボルの名前が表示されます。適切なデバッグ情報があれば、デバッガー (つまり、デバッグを行う人:)) の恩恵です。

私のシステム(XP SP3)でのサンプル出力は次のとおりです。

0:000> ln 7c90e514 (7c90e514)
ntdll!KiFastSystemCallRet | (7c90e520) ntdll!KiIntSystemCall 完全一致: ntdll!KiFastSystemCallRet ()

于 2010-08-24T07:05:16.603 に答える
0

問題のアプリのソースがあり、最適なメモリ使用量が問題にならない場合は、次のようなデバッグしやすい構造内で興味深い変数を宣言できます。

typedef struct {
    const char head_tag[15] = "VARIABLE_START";
          char var_name[32];
          int  value;
    const char tail_tag[13] = "VARIABLE_END";
} debuggable_int;

これで、アプリはプログラムのメモリ空間を検索し、head タグと tail タグを探すことができるはずです。デバッグ可能な変数の 1 つを見つけると、var_nameおよびvalueメンバーを使用してそれを識別および変更できます。

ただし、この長さまで行く場合は、デバッグ シンボルを有効にして通常のデバッガを使用してビルドする方がよいでしょう。

于 2010-08-23T22:05:02.590 に答える
0

ビリー・オニールは正しい方向に向かい始めましたが、(IMO) 本当の目標には到達しませんでした。ターゲットが Windows であると仮定すると、より簡単な方法は、Windows シンボル ハンドラ関数を使用することです。特にSymFromName、これにより、シンボルの名前を指定でき、(とりわけ) そのシンボルのアドレスが返されます。

もちろん、これを行うは、デバッグを許可されたアカウントで実行する必要があります。ただし、少なくともグローバル変数の場合、シンボルやアドレスなどを見つけるためにターゲット プロセスを停止する必要は必ずしもありません。これらの関数を知るための私の初期の実験のいくつかは、まさにそれを行いました)。これは私が何年も前に書いたデモコードで、少なくとも一般的なアイデアを提供します (しかし、それは を使用するのに十分古いものでSymGetSymbolFromNameあり、これは の数世代遅れていSymFromNameます)。デバッグ情報を使用してコンパイルし、後戻りします。かなり多くの出力が生成されます。

#define UNICODE
#define _UNICODE
#define DBGHELP_TRANSLATE_TCHAR
#include <windows.h>
#include <imagehlp.h>
#include <iostream>
#include <ctype.h>
#include <iomanip>
#pragma comment(lib, "dbghelp.lib")

int y;

int junk() {
    return 0;
}

struct XXX { 
    int a;
    int b;
} xxx;

BOOL CALLBACK 
sym_handler(wchar_t const *name, ULONG_PTR address, ULONG size, void *) {
    if (name[0] != L'_')
        std::wcout << std::setw(40) << name 
            << std::setw(15) << std::hex << address 
            << std::setw(10) << std::dec << size << L"\n";
    return TRUE;
}

int 
main() {
    char const *names[] = { "y", "xxx"};

    IMAGEHLP_SYMBOL info;

    SymInitializeW(GetCurrentProcess(), NULL, TRUE);

    SymSetOptions(SYMOPT_UNDNAME);

    SymEnumerateSymbolsW(GetCurrentProcess(), 
        (ULONG64)GetModuleHandle(NULL),
        sym_handler,
        NULL);

    info.SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);

    for (int i=0; i<sizeof(names)/sizeof(names[0]); i++) {
        if ( !SymGetSymFromName(GetCurrentProcess(), names[i], &info)) {
            std::wcerr << L"Couldn't find symbol 'y'";
            return 1;
        }

        std::wcout << names[i] << L" is at: " << std::hex << info.Address << L"\n";
    }

    SymCleanup(GetCurrentProcess());
    return 0;
}
于 2010-08-23T23:17:24.093 に答える