VC++の関数のアドレス

C言語で、関数のアドレスはポインタとして取得できるはずだが、Visual C++の場合、それは実際にはスタブでそこからジャンプ命令で関数の本体のアドレスに飛ぶ。引数のある関数の場合、その引数のアドレスの前が戻り先のアドレスであるはずなので、下記のようなコードで、関数の呼び出し元の関数を推定できる。アドレスが分かったら、[デバッグ]>[ウィンドウ]>[逆アセンブル]で調べてみると良い。

#include<stdio.h>
typedef unsigned int UINT;
typedef unsigned char BYTE;

void hoge(int a);

void piyo(void)
{
    printf("piyo\n");
    hoge(1);
}
void fuga(void)
{
    printf("fuga\n");
    hoge(2);
}

void hoge(int a)
{
    // 引数のアドレスの前にこの関数からの戻り先のアドレスが格納されているはず
    UINT p = *(UINT*)(((BYTE*)&a)-4);
    printf("hoge is called from %08X\n", p);
}

int main(void)
{
    // これが関数のアドレスのはずだが、実はスタブで…
    UINT ptr_piyo = (UINT)(void*)piyo;
    // この相対アドレスにジャンプする
    UINT offset_piyo = *(UINT*)((BYTE*)ptr_piyo + 1);
    // なので、関数の本体のアドレスはここ
    UINT real_piyo = (UINT)((BYTE*)ptr_piyo + offset_piyo + 5);  
    printf("piyo %08X\n", real_piyo);

    UINT ptr_fuga = (UINT)(void*)fuga;
    UINT offset_fuga = *(UINT*)((BYTE*)ptr_fuga + 1);
    UINT real_fuga = (UINT)((BYTE*)ptr_fuga + offset_fuga + 5);
    printf("fuga %08X\n", real_fuga);

    piyo();
    fuga();
    
    getchar();
    return 0;
}