potisanのプログラミングメモ

プログラミング素人です。昔の自分を育ててくれたネット情報に少しでも貢献できるよう、情報を貯めていこうと思っています。Windows環境のC++やC#がメインです。

C++&Win32 API 実行ファイルデータ、スタックのアドレスを取得する

実行ファイルデータのアドレスはWin32 APIGetModuleHandle関数やWinMain関数の引数、スタックのアドレスはローカル変数のアドレスとして取得できます。また、関数のアドレスを取得することで関数が実行ファイルデータとして配置されることが推測できます。

// x64環境
#define STRICT
#define NOMINMAX
#include <Windows.h>

int main()
{
    auto base_address = ::GetModuleHandleW(nullptr); // 実行ファイルデータのアドレス
    auto main_fn_address = &main;                    // 関数のアドレス
    auto stack_address1 = &base_address;             // スタックのアドレス1
    auto stack_address2 = &main_fn_address;          // スタックのアドレス2
}

アドレスはメモリ配置設定(ASLR等)に依存しており、また実行の度に変わりますが、一例は以下の通りです。

auto base_address   = ::GetModuleHandleW(nullptr); // 0x00007ff622d20000
auto main_fn_address = &main;                      // 0x00007ff622d3124e
auto stack_address1 = &base_address;               // 0x0000007e885af8d8
auto stack_address2 = &main_fn_address;            // 0x0000007e885af8f8

実行ファイルデータのアドレスinstance_handleと関数のアドレスmain_fn_addressは差が小さく、メモリ上でまとまって配置されていると推測できます(具体的にはテキスト領域)。また、スタックのアドレスstack_address1stack_address2は実行ファイルデータのアドレス、関数のアドレスとは差が大きく、それらと離れて配置されていると推測できます(具体的にはスタック領域)。

なお、グローバル変数のアドレスもテキスト領域に配置されるため、実行ファイルデータのアドレスおよび関数のアドレスと近い値になります。