著作一覧 |
素に近いWindows XPで動いているシステムがあって、どうしても、その中で動いているDLLの新版を入れたいとする。
そのDLLを呼び出すプログラムは、VC++6で遥か昔に作られたものだ。
しかし、手元にはVisual C++ 2010と2012しか無い。ここでランタイムをDLLとしてリンクするとすごく嫌なことが起きそうな気がする。かたやMSVCRT.dllをロードし、こちらはMSVCR10.DLLをロードする。競合はしないとは思うが(関数名の前のモジュール名が異なる)、ランタイムのバージョンが合わないというのはいかにも危なそうな匂いがする。
で、Visual C++ 2010でランタイムを静的にリンクすれば、mallocしたポインタをモジュールをまたがったところでfreeしたり、FILE*の交換などしなければ、気持ち的には安全なように思う。
そこで、Visual C++2010で静的ランタイムライブラリとリンクしてDLLを作ってインストールしたとする。
すると、オリジナルのプログラムが、入れ替えたDLLをLoadLibraryでロードしようとするとErrorCode 127(ERROR_PROC_NOT_FOUND)でエラーとなる。
何が原因でしょうか?
答えは、Visual C++2010のランタイムライブラリが内部でEncodePointer/DecodePointerという、Windwos XP SP2以降のKernel32.dllに実装されたWindows APIを呼んでいるからだ。素に近いWindows XPのKernel32.dllには、そういう関数は無い。そのため解決できずにロードエラーとなる。
で、このAPIは何ものか? と調べると、EncodePointerというように、exploit対策のためのポインタ曖昧化APIなのだった。
crtのソースを読むと、なるほど、onexitポインタのように、いかにも固定化しているとやばそうなポインタを曖昧化している。
やることをやっているんだなぁと、ちょっと感動した。と同時にマイクロソフトがやることをやっているのだから、素に近いWindows XPとか使ってはいかんよなぁという後ろめたい気持ちも生じるのであった。
# 面倒なのでやらないが、やってみるとどうなるか知りたいこと。EncodePointerで曖昧化したポインタをDecodePointerせずに踏むと、どういうエラーが表示(あるいはログ出力)されるのだろうか。
#include <windows.h> #include <stdio.h> int hello() { return printf("hello world\n"); } int main(int argc, char* argv[]) { int(*eptr)(); int(*ptr)() = hello; printf("%p\n", ptr); ptr(); eptr = EncodePointer(ptr); printf("%p\n", eptr); ptr = DecodePointer(eptr); printf("%p\n", ptr); ptr(); fflush(stdout); eptr(); return 0; }実行すると
c:\test>ptr.exe(上をコンパイルしたもの) 00811000 hello world 6E81F379 00811000 hello world (ptr.exeは動作を停止しましたダイアログを表示)追記:エンコードしたポインタへジャンプすることを想定しているのではなく、ダンプから取得した値へジャンプするライブパッチを作らせないことが目的なんだから、これで良いのだった。
ジェズイットを見習え |