2013年4月17日水曜日

[Windows] About virtualization of Registry

Windows Vista 以降のクライアント Windowsでは、特定のKeyへのアクセスがリダイレクトされる
この件について調べてみた

リダイレクトの挙動の概要は下記である。


                 ---------------  Yes  ---------------- Yes
Start ->---| 64bitカーネルの |-----| 32bitバイナリか? |-----> rule A 適用
                |  Windowsか ?     |        |                         |
                ----------------        ----------------
                         | No 32bit                       | No 64bitバイナリである
                         |     カーネルである          |
                         |------------------------------------> rule B 適用


[rule A]

64bit カーネルのWindowsにおいて32bitバイナリは、32bitプロセスとしてWOW 64(Windows On Windows 64)に32bit systemをエミュレートしてもらってその上を走るのでこのルールが適用されます。


HKEY_LOCAL_MACHINE\Software 配下等特定のレジストリキーへのアクセスは、Wow6432Nodeに含まれるロケーションにリダイレクトされます。

    HKEY_LOCAL_MACHINE\Software -> (リダイレクト先) HKEY_LOCAL_MACHINE\Software\Wow6432Node

[rule B]

  UACによるリダイレクト が行われる

  
HKEY_LOCAL_MACHINE\SOFTWARE ->(リダイレクト先) HKEY_CURRENT_USER\Software\Classes\VirtualStore




[WOW64環境で走っているかどうかの確認]
WOW64.pas


unit WOW64;

// wether OS is windows
{$IFDEF MSWINDOWS}
// wether target platform is Windows 32bit
{$IFDEF WIN32}
{$DEFINE MYTARGET}
{$ENDIF}
{$ENDIF}

interface

{$IFDEF MYTARGET}
uses Windows;
{$ENDIF}

function IsWOW64 : Boolean;

{$IFDEF MYTARGET}
var
  IsWow64Process : function(hProcess : THandle; var Wow64Process : BOOL) : BOOL stdcall;
{$ENDIF}

implementation

function IsWOW64 : Boolean;
{$IFDEF MYTARGET}
var
  Flg : BOOL;
begin
  Result := False;
  @IsWow64Process := GetProcAddress(GetModuleHandle('kernel32.dll'), 'IsWow64Process');
  if @IsWow64Process <> nil then begin
    if IsWow64Process(GetCurrentProcess, Flg) then Result := Flg;
  end;
{$ELSE}
begin
  Result := False;
{$ENDIF}
end;

end.


WOW64test.pas // エラーハンドリング をしていません。レジストリ書き込みを伴います。
unit wow64test;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, WOW64,Registry;

type
  TForm4 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form4: TForm4;

implementation

{$R *.dfm}

procedure TForm4.Button1Click(Sender: TObject);
const
 appKey = 'Software\RegTest';
var
 RegIni : TRegIniFile;
 val : string;
begin

  if IsWOW64 then begin
    showMessage('This process is running on Wow64');
  end else begin
    showMessage('This process is not running on Wow64');
  end;

  RegIni := TRegIniFile.Create(appKey);
  RegIni.RootKey := HKEY_CURRENT_USER;
  RegIni.WriteInteger('settings', 'value', 3);
end;

end.


XP (32bit) での実行結果


7 Pro (64bit) での実行結果

しかし、レジストリは、 HKEY_CURRENT_USER\RegTest\settings に書き込まれる。なぜ?






 なお、UAC制限によるリダイレクトは、Interactive process の場合は行われないらしいが、
Interactive process とは何なのか? 想像するにコマンドラインプログラムは、Interactive processではなさそうだが真相は不明

0 件のコメント:

コメントを投稿