„Elevated“ Programme unter Vista / Windows 7 / Windows 8 / Windows 10 haben auf einmal keine gemappten Laufwerke mehr

Ist man Administrator unter Vista, Windows 7, Windows 8 oder Windows 10 und UAC ist aktiviert, dann existieren technisch zwei Sicherheits -Tokens. Ein Token mit den vollen Administrativen Rechten und ein reduziertes gefiltertes Token, ohne Admin-Rechte.

Wenn man sich anmeldet und Netzwerklaufwerke (Freigaben/Shares) zugeordnet werden, dann erfolgen diese Laufwerksmappings in dem Token mit den reduzierten Rechten.

Startet man nun eine Session mit angehobenen, vollen administrativen Rechten, dann sind die vorher zugeordneten Netzwerklaufwerke in dieser Session nicht sichtbar.
Ein etwas ungewöhnliches aber durchaus logisches Verhalten.
Das Logon Skript läuft eben nicht in dem selben Sicherheitskontext, wie Prozesse, die man mit vollen angehobenen Rechten startet. Defakto sind es wirklich zwei verschiedene Logon’s mit zwei verschiedenen Logon-ID’s.

Mit einem einfachen setzen eines Registry Keys kann man jedoch erreichen, dass auch die angehobenen Admin-Sessions die gleichen Laufwerkmappings erhalten:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System
EnableLinkedConnections = 1 (DWord)

Aber leider ist dieser Schalter nicht als Standard gesetzt.
Ärgerlich wird dies, wenn man ein kleines Setup-Programm schreiben will, dass einige Daten aus dem Nezwerk kopieren soll und dem man ein entsprechendes requireAdministrator-Manifest gibt. Startet man dieses Programm findet es auf einmal nicht mehr die Laufwerke, die eben noch verfügbar waren. Umgehen kann man das ganze nur in dem man UNC-Dateinamen verwendet.

Beschrieben wird dies auch hier auch in diesem KB Artikel und besonders dieser TechNet Artikel.

Was UAC besser verdaulich gemacht hätte!

In den Einstellungen für einen Programm-Link fehlt die Einstellung Mit normalen Benutzerrechten starten. Von mir aus könnte diese Option auch in den Kompatibilitätseinstellungen drin sein.

Wie es die Option „Als Administrator ausführen“ gibt, fehlt eben das Gegenteil:
Führe das Programm als normaler Benutzer aus.

Was soll diese Option bewirken? Diese Option soll das Programm so starten, wie es unter Windows 2000 oder XP unter normalen Benutzerrechten (ohne Adminrechte) auch laufen würde.

D.h. es würde auch das Admin-Token nicht zugewisen bekommen und bei einem Zugriff schreibend auf HKLM oder C:\Program Files, würde das Programm einfach „Kein Zugriff“ gemeldet bekommen. UAC würde für diesen Fall einfach außen vor bleiben.

Alle Programme, die ich geschrieben habe, kommen damit klar. Eigentlich ärgerlich ist ja nur, dass diese Programme unter Vista nun auf einemal schreiben könne, auch wenn es eben dann nur im Virtualstore landet.

Tausende von Kompatibiltätsproblemen durch das stille Virtualisieren könnte man so umgehen.

Gründe für den R6034 bei der VC 8.0 DLL CRT

Warum lässt sich die neue VC 8.0 CRT eigentlich nicht ohne Manifest verwenden?
Schauen wir uns also mal an was passiert wenn eine Applikation oder eine DLL geladen wird, die die VC 8.0 CRT als DLL verwendet:

Die DllMain der CRT wird aufgerufen. Bei der C-Runtime DLL ist dies die Funktion _CRTDLL_INIT die sofort die Funktion __CRTDLL_INIT aufruft.

Diese Funktion sorgt nun der Reihe nach dafür, dass:

  • die aktuelle Windows Version bestimmt wird
  • der Heap initialisiert wird
  • die TLS Bereiche für multithreading angelegt werden
  • das Environment und die Befehlszeile bestimmt werden
  • die MBCS Umwandlungstabellen angelegt werden
  • alles was mit atexit, floating-point math etc. initialisiert wird
  • und… jetzt wird es spannend… die Funktion _check_manifest aufgerufen wird.

In der Funktion _check_manifest wird der Code ausgeführt der zum Runtime Fehler R6034 „The application has attempted to load the runtime library incorrectly. Contact support for more information“ führen kann, nämlich genau dann, wenn diese Funktion FALSE zurück gibt.

Was macht diese Funktion nun?
Im Source-Code der CRT ist dies wunderbar dokumentiert:

  1. if (pre-fusion OS)
      return TRUE; [no need to check]

    Das bedeutet nichts anderes, als das die nachfolgenden Tests nur auf XP/Vista/2003 und folgenden OS durchgeführt werden. Also im Klartext unter Windows 2000 kann dieser Runtime Error nicht auftreten.
  2. if dll is being loaded by instrumented-mscoree.dll.
      return TRUE;
    OK. Ein Speziallfall. Im Kontext der .NET CLR und des Profilers ist auch ales erlaubt. Also wenn sich MSCoree.dll (Microsoft .NET Runtime Execution Engine) und PGORT80.dll (Profile Guided Optimization Instrumentation Runtime) im Speicher befinden ist auch alles paletti.
  3. if (dll is loaded from system32)
      return FALSE;
    Dies ist interessant. In keinem Fall darf diese DLL im Windows\System32 stehen! Oder wenn Sie von dort geladen wird fielgt einem der R6045 um die Ohren.
  4. if (!(loaded through a manifest))
      return FALSE;

    Hier wird über die Funktion FindActCtxSectionStringW geprüft ob diese DLL über ein Manifest geladen wird. ActCtx ist die Abkürzung für Activation Context.
    Wurde kein solcher Activation Context gefunden (also kein Manifest), dass für diese DLL verantwortlich ist, dann heißt das auch R6045.
  5. if (loaded from %SystemRoot%\WinSxS)
      return TRUE; [loaded from the WinSxS cache]

    Wird die DLL aus den Side by Side Verzeichnissen geladen ist schon alles gut.
    Aber auch das geht nur mit gültigem Manifest.
  6. if (manifest is in the same folder as the dll)
      return TRUE;
    Auch das ist interessant. Das Manifest muss zwingend im selben Verzeichnis wie diese DLL liegen, denn sonst sind wir fertig
  7. return FALSE; [loaded with another manifest]
    und nun schlägt das Laden fehl, da das Manifest offensichtlich nicht im DLL Verzeichnis liegt. Auch hier ein R6045.

Zurück noch mal zum Fall 2. Was macht dieser Test „if dll is being loaded by instrumented-mscoree.dll“? Er macht nichts anderes als zu prüfen ob die beiden DLLs im Speicher sind.

BTW: Man könnte nun ganz frech zwei leere DLLs mit diesen Namen erzeugen und diese in ein Projekt implizit laden lassen… und siehe da, die Applikation benötigt auf einmal kein Manifest mehr…
Aber warum sich das ganze verbietet ist auch klar. DLLs mit den oben genannten Namen zu erzeugen, kann ganz schön verwirrend und problematisch werden.
Und warum zwei leere DLLs in einen Prozess laden, wenn es reicht ein Manifest zu ergänzen? 😉

UAC und CreateNamedPipe mit lpSecurityAttributes==NULL

Das Leben steckt einfach voller Überraschungen. Da hat man einen Service der im LocalSystem Account läuft. Mit diesem Service wird über Named Pipes kommuniziert.

Das Programm, das diesen Service steuert soll nur für Administratoren verfügbar sein und greift lesend und schreibend auf diese Pipe zu. Der Admin nutzt dieses Programm oft, muss man dazu sagen.

In der Vergangenheit war da nicht viel zu tun. Einfach lpSecurityAttributes auf NULL setzen und OK. Der Admin hat dann einfach das Steuerungsprogramm gestartet und war glücklich.
Nun unter Vista läuft aber das Steuerungsprogramm nicht mehr mit administrativen Privilegien.

  • Ist das Programm nicht Vista aware (also hat kein Trustinfo Manifest), dann hat man keinen Zugriff auf die Pipe. Den in diesem Fall wird der Admin Token ausgefiltert!
  • Ist es Vista aware und man setzt asInvoker als Trustinfo, dann hat man auch keinen Zugriff. Logo.
  • Nur requireAdministrator führt zum gewünschten Ziel. Natürlich wieder mit der (manchmal) lästigen Meldung für ein Programm das häufig benutzt wird.


❗ Also liebe Programmierer Gemeinde! Bitte die SECURITY_ATTRIBUTES richtig ausfüllen mit einer DACL die eben nicht mehr nur den lokalen Admin enthält.  Diese bei CreateNamedPipe verwenden und dann kann das Programm auch normal mit asInvoker gestartet werden.

Ach ja! Und ehe ich es vergessen ein NULL DACL ist hier nicht im Sinne des Erfinders… 🙂

😐 Insgesamt ärgerlich:
Man möchte es dem Benutzer möglichst einfach machen Programme zu nutzen. Der Vista-Admin-Privileg Dialog stört da manchmal (nicht immer). Also was macht man? Man setzt die Rechte für die Names Pipes und andere Objekte dieser Welt herunter, weil der Admin Token eben nicht mehr Bestandteil der Rechte ist für Programme die mit asInvoker gestartet werden.
Die Folge: Die Programme werden mit weniger Sicherheitsschranken gebaut, als zuvor.
War das im Sinne des Erfinders?

BTW: Da man sich mittlerweile schon blind angewöhnt hat, diesen Dialog zu bestätigen kann man sich fragen ob da noch ein Sicherheitsaspekt verbleibt, weil keiner mehr liest, welches Programm eigentlich administrative Rechte haben will.

UAC Trustinfo Manifest in ein VC-2005 SP1 Projekt einfügen

An sich ist die Sache ganz einfach. Man erzeugt eine Manifest-Datei z.B. mit dem Namen Trustinfo.manifest, die nur den entsprechenden <trustinfo> Block enthält (und nicht mehr). Um die anderen Manifest Daten für CRT und COMCTL32 v6.0 kümmert man sich erstmal nicht, das soll ja MT.EXE und der Linker machen. Diese Datei fügt man in das Projekt ein. VS erkennt die Endung und der Manifest-Compiler soll diese Datei nun mit den anderen Manifest Daten mischen und das finale Manifest erzeugen.
Man wirft den Compiler an und… 🙄 … erhält die Fehlermeldung:
.\TrustInfo.manifest : manifest authoring warning 81010002: Unrecognized Element „requestedPrivileges“ in namespace „urn:schemas-microsoft-com:asm.v3“.

Entsprechende Recherche ergab, dass nur die MT.EXE aus dem Vista SDK dieses Manifest korrekt einmischt. Die funktionierende MT.EXE hat es nicht in das 2005 SP1 gepackt 🙁 .

OK also Vista SDK herunterladen installieren. MT.EXE ansehen und… 🙄
Die MT.EXE aus 2005 SP1 ist vom 2006-12-02 07:17,
die MT.EXE aus dem Vista SDK ist vom 2006-10-19 14:52,
beide haben eine Größe von 727.552 Bytes und haben die gleiche Versionsnummer 5.2.3790.2075. Es ist nicht zu fassen.

OK packen wir also trotzdem die MT.EXE aus dem Vista SDK in das Verzeichnis C:\Program Files\Microsoft Visual Studio 8\VC\bin

Nun kompilieren wir das Projekt noch einmal und nun… :mrgreen:
wunderbar, das Projekt kompiliert wie erwartet. Das Manifest wird eingefügt. Die erzeugte EXE hat alle entsprechenden Manifeste eingebettet.

Wen es interessiert, die Bug-Meldung bzgl. der Versionsnummer ist hier zu finden:
https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=258108

Es sei noch angemerkt: Mein Testrechner ist ein Vista-Ultimate Laptop. Installiert war auch das VS-2005 SP1 Beta für Vista. Auch diese Version enthält keine kompatible MT.EXE!
Danke Jochen für den Hinweis!

Der VirtualStore und seine Schattenseiten

Es ist ja bekannt, dass Programme, die nicht mit einem entsprechenden Trustinfo Manifest ausgestattet sind, unter Vista besonders behandelt werden. Werden diese Programme nicht im administrativen Rechten ausgeführt werden alle Zugriffe auf das Verzeichne C:\Program Files und auf HKEY_LOCAL_MACHINE\Software in der Registry umgeleitet.

Ein Registry Zugriff landet dann in HKEY_CURRENT_USER auf HKEY_CURRENT_USER\Software\Classes\VirtualStore\MACHINE\SOFTWARE. Ein Dateizugriff auf C:\Program Files wird umgeleitet nach C:\Users\Username\AppData\Local\VirtualStore\Program Files.

Was passiert aber nun, wenn der Administrator nun tatsächlich die „richtigen“ Daten in HKLM und C:\Program Files ändert UND es existieren bereits entsprechende Daten im VirtualStore?

Die Antwort ist logisch! Eine Änderung der Daten bleibt ohne Wirkung! Denn die Daten aus dem VirtualStore werden hier mit Vorrang behandelt. Sonst macht das ganze ja keinen Sinn, denn der VirtualStore soll ja scheinbar Schreibzugriffe erlauben.

Im Klartext: Existieren Daten sowohl im VirtualStore als auch in den eigentlichen originalen Positionen, dann werden immer die Daten des VirtualStore verwendet. Nur wenn der entsprechende Registry Key nicht vorhanden/gelöscht wird oder die entsprechende Datei nicht vorhanden/gelöscht ist, dann werden die Daten aus den original Verzeichnissen bzw. Registryästen verwendet.

Nur daraus folgt ein Problem:
Macht der Admin Korrekturen an den realen Daten UND es existieren Daten im VirtualStore, dann bleiben die Änderungen des Admins wirkungslos, bis er die Daten aus dem VirtualStore entfernt. Das kann eine spannende Aufgabe werden.
Vielleicht ist dies eine profane Erkenntnis, aber die Implikationen sind meines Erachtens immens.

PS: Gemein ist einfach, dass Software die bisher mit einer Fehlermeldung gerechnet hat, wenn ein Schreibversuch nach HKLM oder C:\Program Files erfolgte, nun auf einmal erfolgreich schreiben kann. Da kann man sich noch so sehr an alle Empfehlungen halten, hier wird man von Vista reingelegt und man muss schleunigst das entsprechende Trustinfo Manifest nachrüsten.

Vista und die Notwendigkeit eines Manifestes für die UAC

Bei den vorbereiten von Software für Vista (Certified for Vista) ist mir die UAC (User Access Control) untergekommen. Unter Vista verschärft sich das ganze noch einmal gegenüber Windows 2000.

Einen der wichtigsten Punkte möchte einfach mal hier darlegen.
Unsere Software ist so geschrieben, dass ein Admin entsprechende Einstellungen in bestimmten Dateien im Programmverzeichnis ablegen kann und auch Einstellungen vornehmen kann die in HKLM abgelegt werden. Unter anderem dienen diese Dateien/Registry Einstellungen eben zur Kontrolle von Services und IPC. Sie müssen eben in einem allgemein zugänglichem Bereich liegen. Das ist ja nichts ungewöhnliches.

Brav wie wir sind haben wir entsprechende Prüfungen eingebaut und sagen dem Anwender, wenn er keine Rechte hat in HKLM zu schreiben, oder die entsprechenden Dateien im Programmverzeichnis zu ändern, z.B. INI Dateien die mit WritePrivateProfileString geschrieben werden.

Vista ist es nun egal, dass wir brave Entwickler sind. Vista behandelt uns per UAC Richtlinie wie einen Bösewicht und leitet alle Änderungen in den lokalen Bereich des Anwenders. Meine Software hat keine Chance zu erkennen, dass das schreiben in HKLM und den Programm-Datei Ordner eigentlich nicht erlaubt ist.

Man muss also zwingend ein Manifest für die UAC hinzufügen:

<?xml version=“1.0″ encoding=“utf-8″?>
<assembly xmlns=“urn:schemas-microsoft-com:asm.v1″ manifestVersion=“1.0″>
  <trustInfo xmlns=“urn:schemas-microsoft-com:asm.v3″>
    <security>
      <requestedPrivileges>
        <requestedExecutionLevel level=“asInvoker“ />
      </requestedPrivileges>
    </security>
  </trustInfo>
</assembly>

Erst mit diesem Manifest verhält sich meinem Programm wieder so, wie ich es auch erwarte!

Eine gute Anleitung hierfür:
– How To: Tell Vista’s UAC What Privelege Level Your App Requires
http://channel9.msdn.com/Showpost.aspx?postid=211271

Weitere Infos, Dokus und Hilfsprogramme:
– Understanding and Configuring User Account Control in Windows Vista
http://technet.microsoft.com/en-us/windowsvista/aa905117.aspx
– Windows Vista Application Development Requirements for User Account Control Compatibility
http://www.microsoft.com/downloads/details.aspx?FamilyID=BA73B169-A648-49AF-BC5E-A2EEBB74C16B&displaylang=en
– Microsoft Application Verifier
http://www.microsoft.com/downloads/details.aspx?familyid=BD02C19C-1250-433C-8C1B-2619BD93B3A2&displaylang=en
– Microsoft Standard User Analyze
http://www.microsoft.com/downloads/details.aspx?familyid=DF59B474-C0B7-4422-8C70-B0D9D3D2F575&displaylang=en