2012年4月1日現在、VisualC++11 Betaで作成したバイナリはXPで動作しません。
今回は、それを強引にXPで動くようにしてしまう方法を紹介します。
なぜXPで動かないのか?
理由は簡単で
- 動作対象OSがVista以上
- ランタイムでVista以降のAPIを使用
だから。
動作対象OSをXPに変更
exeファイルには動作対象のOSを指定するサブシステムバージョンというものが存在し、それに満たない環境では動作しないようになっています。
本来ならリンカオプションのsubsystemで変更できるのですが、VC++11からはXP(5.1)以下を選択できません。
なので、強引にexe冒頭で指定されているサブシステムバージョンを5.1に書き換えることで回避します。
具体的には
ここを05 00 01 00と書き換えるとXP以上という意味になります。
書き換えている場所について詳しく知りたい人は、IMAGE_NT_HEADERSのOptionalHeader.MajorSubsystemVersionとOptionalHeader.MinorSubsystemVersionでググってください。
Windowsのバージョン番号はwikipediaの「Windows のタイムライン」を参照
Vista以降のAPI呼び出しを止める
動作対象のOSをXP以上にしたとしても、XPに存在しないAPIを呼んでいては起動すらできません。
これを回避する方法はいくつかあるのですが、ここではダミーのKernel32.dllを作成し、そこに必要なAPIを独自実装することで回避することにします。
exeファイルには当然リンクするべきdll名が記述されています。
そのうちKERNEL32.dllを書き換え、ダミーのDLL名(ここではKernelXP.dllとします)に変更し、そのDLL越しにKERNEL32.dllを呼ぶように細工します。
これは単にexeファイル内からKERNEL32.dllという文字列を探し、書き換えるだけで可能です。
つぎにダミーのDLLの作り方ですが、まず完成品がこちら。
KernelXP.zip
作り方としては、XPのKERNEL32.dllでエクスポートされている関数の一覧を作り
※エクスポート関数一覧の取得方法はDllFuncList.zipなどを参照
それらをすべてKERNEL32.dllへ受け流すだけのDLLを作成。
その後exeファイルをXPで実行してみて、APIが見つからないエラーが出るたびに、そのダミー実装を作るを繰り返すだけ。
詳しくは、DLLインジェクションやダミーDLLなどでググると見つかるかと思います。
終わりに
今回はダミーのDLLを経由させる方法で実現しましたが、一般的にはIATを書き換える方が多いようです。
いつかそちらについても言及してみたいなと思いつつ、今回はここまで。
KernelXPのx64版は無いでしょうか?
ないです。
XPの64bit版自体ほぼ現存していないと思われるので作る予定もありません。
>>中の人様
本当は自分で何とかしたいところなのですが、
x64ではインラインアセンブラとnakedが使えないので、
同じことをするためにはどうしたらと悩んでおりました。
失礼いたしました。