関数先頭にあるMOV EDI,EDIって何だろう?

 Windows環境において、多くのAPI関数の先頭に存在するMOV EDI,EDIという命令。たとえばMessageBoxWの先頭2バイトを次のようなプログラムで調べてみる。

// VC++ 2010 Express版
#include <stdio.h>
#include <Windows.h>

int main()
{
    HMODULE user32 = ::LoadLibrary(L"user32.dll");
    auto pMessageBoxW = reinterpret_cast<decltype(MessageBoxW)*>
        (GetProcAddress(user32, "MessageBoxW"));
    
    BYTE bBuff[8];
    memcpy(bBuff, (void *)pMessageBoxW, 2);

    TCHAR szStr[1024];
    wsprintf(szStr, 
        L"MessageBoxW first 2byte is '%02x %02x'.", 
        bBuff[0], bBuff[1]);

    pMessageBoxW(GetForegroundWindow(), szStr, L"MESSAGE", MB_OK);
    return 0;
}

f:id:b07c00:20130806163637p:plain

 先頭2バイトは8b ff。つまりmov edi, edi。これ自体はなんの意味もない命令な気がするけどなんで各API関数の先頭に常にあるの? みたいな疑問。その答えはこちら。

 Why do Windows functions all begin with a pointless MOV EDI, EDI instruction?

It's a hot-patch point.

 どうやらパッチ用のようです。

 もっと具体的にいうとAPIフック用。先頭2バイトがmov edi, ediなので、まずはここをeb f9:jmp -7に変える。デバッガとかで確認すると、mov edi, ediの上には5バイト連続でnop辺りが埋まってるはず。ここに飛ぶようにして、この5バイトの領域にe9 XX XX XX XX:jmp 0xXXXXXXXXみたいなコードを入れると任意の場所にジャンプできる。つまり手軽にAPIフックが実現できる。便利。なのでmov edi, ediと上の5バイトはセットみたいなもんなのかな。

 ちなみに有名なAPIフックライブラリであるDetoursはこの手法を使ってないです。