2012-12-22 12 views
9

Od wydania wersji Win Vista firma Microsoft wprowadziła wirtualizację plików dla starszych aplikacji działających jako procesy 32-bitowe. Wydane jako część Kontroli konta użytkownika (UAC) każdej starszej aplikacji próbującej napisać do dowolnej lokalizacji uważanej za chronioną przez system operacyjny są przekierowywane do VirtualStore.Jak wykrywać przekierowanie plików do Windows VirtualStore?

W tym momencie podjęto kroki w celu zapewnienia, że ​​dana aplikacja działa teraz jako proces 64-bitowy, który jest znany z UAC, jednak niewiele to rozwiązuje problem migracji danych użytkowników do lokalizacji, która jest uważana za bezpieczny od wirtualizacji.

Podczas rozwiązywania tego problemu odkryłem, że podczas pracy z wieloma kontami użytkowników wprowadzono pewne zmiany w starszej ścieżce znajdującej się w C: \ Program Files (x86) \ MojaAplikacja \ Dane w tym samym czasie, zmiany zostały wykonane w VirtualStore zlokalizowanym w% localappdata% \ VirtualStore \ Programs \ MyApp \ Data. Pytanie brzmi: jak wykryć, czy ma miejsce wirtualizacja plików/folderów i jak scalić te dwie lokalizacje?

EDYCJA: Znalazłem kilka stron internetowych, które szczegółowo opisują problem i sposób jego duplikowania, ale nic, co zawiera sposób, aby to naprawić. Znalazłem to odniesienie FILE_ATTRIBUTE_VIRTUAL, które definiuje atrybut pliku, który wydaje się obiecujący - znalazłem gdzieś inne odniesienie, choć nie pamiętam gdzie, które stwierdza, że ​​jest to atrybut używany przez system Windows do wskazania, że ​​wirtualizacja plików ma miejsce i zaznacza wniosek o przekierowanie.

Te linki opisać problem:

http://www.c-sharpcorner.com/uploadfile/GemingLeader/windows-file-and-registry-virtualization/

http://www.codeproject.com/Articles/66275/Windows-Vista-File-and-Registry-Virtualization

http://download.microsoftvirtuallabs.com/download/8/a/7/8a71365b-4c80-4e60-8185-8f12f59bf1d4/UACDataRedirection.pdf

Odpowiedz

14

Nie było to łatwe, ale znalazłem sposób na wykrycie, czy wirtualizacja UAC jest włączona. Wywołanie GetTokenInformation() i przekazanie w TokenVirtualizationEnabled jako klasie informacji zwróci, czy włączona jest wirtualizacja plików i rejestru. Oto funkcja C to zrobić:

// Gets whether the current process has UAC virtualization enabled. 
// Returns TRUE on success and FALSE on failure. 
BOOL GetVirtualizationEnabled(BOOL *enabled) { 
    HANDLE token; 
    DWORD tmpEnabled; 
    DWORD returnLen; 
    BOOL retVal = TRUE; 

    if(!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) 
     return FALSE; 

    if(!GetTokenInformation(token, TokenVirtualizationEnabled, 
      &tmpEnabled, sizeof(tmpEnabled), &returnLen)) { 
     retVal = FALSE; 
     goto err; 
    } 

    *enabled = tmpEnabled; 

err: 
    CloseHandle(token); 

    return retVal; 
} 

Nieco gorzej z P/Invoke, ale to jest tutaj, w tym P/Invoke nagłówki:

enum TOKEN_INFORMATION_CLASS 
{ 
    TokenUser = 1, 
    TokenGroups, 
    TokenPrivileges, 
    TokenOwner, 
    TokenPrimaryGroup, 
    TokenDefaultDacl, 
    TokenSource, 
    TokenType, 
    TokenImpersonationLevel, 
    TokenStatistics, 
    TokenRestrictedSids, 
    TokenSessionId, 
    TokenGroupsAndPrivileges, 
    TokenSessionReference, 
    TokenSandBoxInert, 
    TokenAuditPolicy, 
    TokenOrigin, 
    TokenElevationType, 
    TokenLinkedToken, 
    TokenElevation, 
    TokenHasRestrictions, 
    TokenAccessInformation, 
    TokenVirtualizationAllowed, 
    TokenVirtualizationEnabled, 
    TokenIntegrityLevel, 
    TokenUIAccess, 
    TokenMandatoryPolicy, 
    TokenLogonSid, 
    MaxTokenInfoClass 
} 

public const UInt32 STANDARD_RIGHTS_REQUIRED = 0x000F0000; 
public const UInt32 STANDARD_RIGHTS_READ = 0x00020000; 
public const UInt32 TOKEN_ASSIGN_PRIMARY = 0x0001; 
public const UInt32 TOKEN_DUPLICATE = 0x0002; 
public const UInt32 TOKEN_IMPERSONATE = 0x0004; 
public const UInt32 TOKEN_QUERY = 0x0008; 
public const UInt32 TOKEN_QUERY_SOURCE = 0x0010; 
public const UInt32 TOKEN_ADJUST_PRIVILEGES = 0x0020; 
public const UInt32 TOKEN_ADJUST_GROUPS = 0x0040; 
public const UInt32 TOKEN_ADJUST_DEFAULT = 0x0080; 
public const UInt32 TOKEN_ADJUST_SESSIONID = 0x0100; 
public const UInt32 TOKEN_READ = (STANDARD_RIGHTS_READ | TOKEN_QUERY); 
public const UInt32 TOKEN_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | TOKEN_ASSIGN_PRIMARY | 
    TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_QUERY_SOURCE | 
    TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT | 
    TOKEN_ADJUST_SESSIONID); 

[DllImport("advapi32.dll", SetLastError=true)] 
static extern bool GetTokenInformation(
    IntPtr TokenHandle, 
    TOKEN_INFORMATION_CLASS TokenInformationClass, 
    IntPtr TokenInformation, 
    int TokenInformationLength, 
    out uint ReturnLength); 

[DllImport("advapi32.dll", SetLastError = true)] 
static extern bool SetTokenInformation(IntPtr TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, 
    ref uint TokenInformation, uint TokenInformationLength); 

[DllImport("advapi32.dll", SetLastError=true)] 
static extern bool OpenProcessToken(IntPtr ProcessHandle, 
    uint DesiredAccess, out IntPtr TokenHandle); 

[DllImport("kernel32.dll", SetLastError=true)] 
    static extern bool CloseHandle(IntPtr hObject); 

static bool TryGetVirtualizationEnabled(out bool enabled) { 
    IntPtr processHandle = Process.GetCurrentProcess().Handle; 
    IntPtr token; 
    uint returnLen; 
    object tmpEnabled = new uint(); 

    enabled = false; 
    GCHandle handle = GCHandle.Alloc(tmpEnabled, GCHandleType.Pinned); 

    try { 
     if(!OpenProcessToken(processHandle, TOKEN_QUERY, out token)) 
      return false; 

     try { 
      if(!GetTokenInformation(token, TOKEN_INFORMATION_CLASS.TokenVirtualizationEnabled, 
            handle.AddrOfPinnedObject(), Marshal.SizeOf(typeof(uint)), out returnLen)) 
       return false; 

      enabled = (uint)tmpEnabled != 0; 
     } finally { 
      CloseHandle(token); 
     } 
    } finally { 
     handle.Free(); 
    } 

    return true; 
} 

Próbowałem tokarskich UAC wirtualizację na a wyłączyć za pomocą Menedżera zadań i sprawdzić, czy zwracany jest poprawny wynik. Włączanie i wyłączanie wirtualizacji można wykonać, dzwoniąc pod numer SetTokenInformation().

Firma Microsoft twierdzi, że planuje usunąć wirtualizację UAC w przyszłej wersji systemu Windows, a programy nie będą na niej polegać. Widziałem sugestię, aby ktoś zrobił oddzielny program, który nie jest UAC świadomy, aby przenieść pliki z VirtualStore do AppData, ale nie wiem, czy to dobre rozwiązanie, czy nie.

+0

Czy ta metoda wykrywa, czy wirtualizacja jest włączona w ogóle, czy jest włączona dla określonego pliku/folderu? – Simpleton

+0

Ogólnie. Jeśli wirtualizacja jest włączona dla procesu, wszystkie zapisy z tego procesu do folderu Program Files, folderu Windows i HKEY_LOCAL_MACHINE w rejestrze są przekierowywane (i kilka innych). Nie można włączyć niektórych z tych folderów, a nie innych. –

+2

Ponowne odczytywanie początkowego pytania brzmi, jakbyś nie chciał wykrywać, czy wirtualizacja ma miejsce. Jeśli używasz 64-bitowego procesu, który jest znany z UAC, oznacza to, że wirtualizacja jest wyłączona. Aby uzyskać dostęp do danych umieszczonych w VirtualStore przez starszą wersję programu (z włączoną wirtualizacją), program może wyglądać w% LOCALAPPDATA% \ VirtualStore, aby sprawdzić, czy są tam jakieś jego dane. Jeśli tak, może przenieść dane w odpowiednie miejsce, w razie potrzeby scalając je. –

1

Brzmi jak próbujesz flagą jeśli "działa" od ścieżki lokalnej aplikacji danych, w takim przypadku:

var currentPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); 
var appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); 
Console.WriteLine(
    "Current path is:{0}, AppData Path is {1}, Current is subpath of appdata path:{2}", 
    currentPath, 
    appDataPath, 
    currentPath.StartsWith(appDataPath) 
); 
+0

Dzięki za odpowiedź!Szukam rozwiązania, które nie tylko będzie uśpione, ale również aktywnie wykryje, czy ma miejsce przekierowanie pliku lub wirtualizacja. Jeśli to możliwe, chciałbym móc wykryć tę pogodę, w której proces jest obecnie uruchomiony, ponieważ jest to aplikacja oparta na sieci. W tym momencie nie mogłem znaleźć żadnej metody identyfikacji, czy przekierowanie pliku do VirtualStore jest lub kiedykolwiek miało miejsce; bez wyszukiwania przez każdy profil użytkownika dla danych/plików VirtualStore, nie mogę wymyślić żadnego innego sposobu identyfikacji danych VirtualStore. – Simpleton

+0

@Splpleton Ah, rozumiem - przepraszam, nie jestem w pełni świadomy szczegółów VirtualStore, aby dać konkretną odpowiedź; ten blurb poinformuje Cię, gdy aplikacja się uruchomi. – JerKimball

3

FWIW, tutaj jest wersja kodu detekcji w Delphi:

unit checkvirtual; 

interface 
uses windows; 

function GetVirtualizationEnabled(var enabled:Boolean):Boolean; 

implementation 

// Gets whether the current process has UAC virtualization enabled. 
// Returns TRUE on success and FALSE on failure. 
function GetVirtualizationEnabled(var enabled:Boolean):Boolean; 
var 
    token:THandle; 
    tmpEnabled:DWORD; 
    returnLen:DWORD; 
begin 
    result:=false; 
    enabled:=false; 
    if not(OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, token)) then exit; 
    try 
    if not(GetTokenInformation(token, TokenVirtualizationEnabled, 
       @tmpEnabled, sizeof(tmpEnabled), returnLen)) then exit; 

    enabled:=tmpEnabled<>0; 
    result:=true; 
    finally 
    CloseHandle(token); 
    end; 
end; 

end. 
Powiązane problemy