Freigeben über


ISV-Sicherheit für Windows Vista

 

Michael Howard und Matt Thomlinson
Microsoft Corporation

April 2007

Einführung

Windows Vista bietet zahlreiche defensive Verbesserungen, mit denen Kunden vor Malware geschützt werden sollen. Anwendungen, die auf der Plattform ausgeführt werden, sollten diese Schutzmaßnahmen nutzen, da sie grundsätzlich kostenlos sind und zudem einen Codefehler von einer bedrohlichen Schwachstelle in einen Fehler umwandeln können, der einen Absturz herbeiführt.

Für Internet Explorer spielen einige der Windows Vista-Schutzmaßnahmen nur eine Rolle, wenn alle vom Browser genutzten Komponenten die Schutzmaßnahmen unterstützen. Da Browser zu den am häufigsten angegriffenen (und am meisten beeinträchtigten) Softwarekomponenten gehören, ist es wichtig, dass bekannte vom Browser genutzte Komponenten die Möglichkeiten dieser Schutzmaßnahmen vollständig ausschöpfen. In diesem kurzen Artikel sollen die Schutzmaßnahmen ausführlich beschrieben sowie die Möglichkeiten der Nutzung dieser Schutzmaßnahmen für Softwarehersteller zum Schutz unserer gemeinsamen Kunden erklärt werden.

Bei diesem Artikel handelt es sich um eine stark verkürzte Version des Buchs „Writing Secure Code for Windows Vista“ von Howard und LeBlanc. In diesem Artikel wird auf nicht verwalteten (nicht-.Net) C- und C++-Code eingegangen.

Schutzmaßnahmen in Windows Vista

Windows Vista enthält zahlreiche defensive Strategien zum Schutz der Kunden vor Schwachstellen. Einige dieser Schutzmaßnahmen befinden sich im zentralen Betriebssystem, und andere werden über den Microsoft Visual C++ Compiler zur Verfügung gestellt. Die Schutzmaßnahmen umfassen Folgendes:

  • /GS-Stapelpuffer-Überlauferkennung
  • /SafeSEH-Ausnahmebehandlungsschutz
  • No eXecute (NX)/Data Execution Prevention (DEP)/eXecute Disable (XD)
  • Address Space Layout Randomization (ASLR)
  • Zufällige Heapanordnung
  • Zufällige Stapelanordnung
  • Heapbeschädigungserkennung

Im restlichen Teil dieses Dokuments werden diese Schutzmaßnahmen kurz beschrieben. Darüber hinaus erhalten Sie Anleitungen für die Bereitstellung sowie Testanleitungen.

/GS-Stapelpuffer-Überlauferkennung

Diese Funktion wurde im C/C++-Compiler in Visual Studio .NET 2002 eingeführt und in Visual Studio .NET 2003 und Visual Studio 2005 aktualisiert. /GS ist ein Compilerschalter, der den Compiler anweist, Startcode und Funktionsepilog sowie Prologcode hinzuzufügen, um eine Zufallszahl zu generieren und zu prüfen, die sich im Stapel einer Funktion befindet. Wenn dieser Wert beschädigt ist, wird eine Handlerfunktion aufgerufen, um die Anwendung zu beenden. Darüber hinaus wird die Wahrscheinlichkeit herabgesetzt, dass Shellcode, der versucht, einen Pufferüberlauf auszunutzen, korrekt ausgeführt wird.

/GS wird durch Hinzufügen des /GS-Schalters zur Compilerbefehlszeile aktiviert. In Visual C++ wird diese Option standardmäßig aktiviert, selbst wenn /GS nicht in der Befehlszeile enthalten ist.

Hinweis   Die Auswirkungen von /GS auf die Leistung können nur schwer gemessen werden, weil sie stark vom Codierstil abhängig sind. An Code mit großen Mengen stapelbasierter Zeichenfolgenpuffer und Argumente machen sich die Auswirkungen bemerkbar. Bei Code ohne diese Eigenschaften lassen sich keine Auswirkungen feststellen. Schätzungen zufolge liegen die Leistungsauswirkungen bei 3 %. Dies wird jedoch teilweise in späteren Versionen des Compilers durch andere Optimierungen ausgeglichen. Der größte Teil potenziell anfälligen Codes führt allerdings Netzwerk- und Festplatten-E/A-Vorgänge durch, die deutlich langsamer als die kleinen /GS-Überprüfungen sind.

Beachten Sie, dass Visual C++ 2005 auch Daten im Stapel verschiebt, um die Beschädigung von Daten zu erschweren. Beispiele:

  • Verschieben von Puffern in höhere Speicher als Nichtpuffer. Dieser Schritt kann helfen, Funktionszeiger im Stapel zu schützen
  • Verschieben von Zeiger- und Pufferargumenten in untere Speicher zur Laufzeit, um das Risiko mehrerer Pufferüberlaufangriffe zu verringern.

ISV-Anforderungen

  • ISVs sollten ihren Code mit dem aktuellsten Compiler kompilieren: Visual C++ 2005.
  • ISVs sollten mit dem /GS-Kennzeichen kompilieren.
  • ISVs sollten eine Verknüpfung zu Bibliotheken herstellen, die /GS verwenden.

/SafeSEH-Ausnahmebehandlungsschutz

Ein Ausnahmehandler ist eine Codeeinheit, die ausgeführt wird, wenn eine außergewöhnliche Bedingung, wie z. B. eine Teilung durch Null auftritt. Die Adresse des Handlers wird auf dem Stapelrahmen der Funktion gehalten und ist deshalb durch Beschädigung und Befehlsaneignung gefährdet. Der Linker ist in Visual Studio 2003 und späteren Versionen enthalten und bietet eine Option zum Speichern der Liste gültiger Ausnahmehandler im PE-Header des Abbilds zur Kompilierzeit. Wenn zur Laufzeit eine Ausnahme ausgelöst wird, zeigt das Betriebssystem (Windows XP SP2, Windows Server 2003, Windows Vista, und Windows „Longhorn“ Server und höher) nur auf eine Adresse in dem Abbild, bei der es sich um eine der Ausnahmehandleradressen im PE-Header handelt.

Hinweis   /SafeSEH hat im Codepfad ohne Ausnahme keine Auswirkungen auf die Leistung.

ISV-Anforderungen

  • ISVs sollten ihre Abbilder mit /SafeSEH verknüpfen.
  • ISVs sollten eine Verknüpfung mit Bibliotheken herstellen, die auch mit /SafeSEH verknüpft sind.

Data Execution Prevention (DEP)/No eXecute (NX)/eXecute Disable (XD)

Diese Technologie hat unterschiedliche Namen. Von AMD wird sie als NX, von Microsoft als Datenausführungsverhinderung (Data Execution Prevention, DEP) und von Intel als XD bezeichnet. Sie benötigt CPU-Unterstützung, die verhindert, dass Code in Datensegmenten ausgeführt wird. Heutzutage unterstützen die modernsten CPUs von Intel diese Funktion, und alle aktuellen AMD-CPUs unterstützen NX. Die DEP-Unterstützung wurde zuerst in Windows XP SP2 eingeführt und stellt in Windows Vista eine besonders wichtige Schutzmaßnahme dar, insbesondere zusammen mit ASLR. Dieser Aspekt wird unten näher erläutert.

Ein Nachteil von DEP besteht darin, dass DEP in einer Anwendung Fehler verursacht, wenn die Anwendung selbstverändernden Code enthält oder eine Just-In-Time-Kompilierung ausführt. Zur Behebung dieses Problems sollten Anbieter von Anwendungen trotzdem DEP aktivieren (siehe Linkerschalter unten) und alle Daten, die für JITing verwendet werden, folgendermaßen markieren:

PVOID pBuff = VirtualAlloc(NULL,4096,MEM_COMMIT,PAGE_READWRITE );
if (pBuff) {
    // Copy executable ASM code to buffer
    CopyMemory(pBuff,...) 
    
    // Buffer is ready to go so mark as executable and protect from writes
    DWORD dwOldProtect = 0;
    if (!VirtualProtect(pBuff,sizeof scode,PAGE_EXECUTE_READ,&dwOldProtect)) 
        // oops
    else
        // Call into pBuff
    VirtualFree(pBuff,0,MEM_RELEASE);
}

Hinweis   DEP/NX/XD wirkt sich nicht auf die Leistung aus.

ISV-Anforderungen

  • ISVs sollten ihre Anwendungen auf einer DEP-fähigen CPU testen und Fehler aufgrund von NX beachten und beheben.
  • ISVs sollten ihren Code mit /NXCOMPAT verknüpfen, sobald der DEP-Test erfolgreich abgeschlossen wurde.

Address Space Layout Randomization (ASLR)

ASLR verschiebt Abbilder beim Systemstart wahllos, was die erfolgreiche Ausführung von Shellcode erschwert. Damit eine Komponente ASLR unterstützen kann, müssen alle geladenen Komponenten ebenfalls ASLR unterstützen. Wenn zum Beispiel A.EXE die Komponenten B.DLL und C.DLL nutzt, müssen alle drei ASLR unterstützen. Standardmäßig steuert Windows Vista System-DLLs und EXEs nach dem Zufallsprinzip. DLLs und EXEs, die von ISVs erstellt werden, müssen jedoch für die Unterstützung von ASLR aktiviert werden.

Hinweis   ASLR wirkt sich im Allgemeinen nicht auf die Leistung aus. Es ist vielmehr sogar eine kleine Leistungsverbesserung in 32-Bit Systemen feststellbar. Allerdings kann es in stark überlasteten Systemen mit vielen zufälligen Abbildern zu einem Leistungsabbau kommen, der aber nur schwer quantifiziert werden kann, weil die Auswirkungen von der Anzahl und der Größe der Abbilder abhängig sind.

ISV-Anforderungen

  • ISVs sollten ihre Anwendung unter Windows Vista testen und Fehler aufgrund von ASLR beachten und beheben.
  • ISVs sollten ASLR-Unterstützung für alle Abbilder wählen, indem eine Verknüpfung mit einem aktualisierten Microsoft-Linker (Version 8.00.50727.161 oder höher) hergestellt wird.
  • ISVs sollten mit dem Linkerschalter /DYNAMICBASE eine Verknüpfung herstellen.

Zufällige Heapanordnung

Wenn eine Anwendung einen Heap in Windows Vista erstellt, erzeugt der Heapmanager den Heap an einem zufälligen Ort, um die Wahrscheinlichkeit zu reduzieren, dass es zu einem Heapüberlauf kommt. Die zufällige Heapanordnung ist standardmäßig für alle Windows Vista-Anwendungen aktiviert.

Hinweis   Die Auswirkungen auf die Leistung sind geringfügig.

  • ISVs sollten ihre Anwendung unter Windows Vista testen und Fehler aufgrund der zufälligen Heapanordnung beachten und beheben.

Zufällige Stapelanordnung

Wenn ein Thread in einem mit /DYNAMICBASE kompilierten Prozess startet, wird in Windows Vista der Stapel des Threads an einen zufälligen Ort verschoben. Dadurch wird das Risiko verringert, dass ein stapelbasierter Pufferüberlauf entsteht.

Hinweis   Die Auswirkungen auf die Leistung sind geringfügig.

  • ISVs sollten ihren Code mit /DYNAMICBASE verknüpfen und ihre Anwendung unter Windows Vista testen, um Fehler aufgrund der zufälligen Stapelanordnung zu beachten und zu beheben.

Heapbeschädigungserkennung

Mithilfe der Heapbeschädigungserkennung können in einer Anwendung Fehler verursacht werden, wenn der Heapmanager erkennt, dass die Anwendung den Heap beschädigt hat oder der Heap inkonsistent wird. Mit dieser Einstellung werden nicht nur Heapüberläufe, sondern auch bestimmte illegale Vorgänge erkannt. So verursacht beispielsweise die Freigabe eines Zeigers an den falschen Heap auch Fehler in der Anwendung.

Für die Anwendungskompatibilität mit der Heapbeschädigungserkennung ist eine kleine Codeänderung erforderlich, die nur Windows Vista betrifft. Der folgende Code verursacht ordnungsgemäß Fehler auf Windows-Plattformen, die die Funktion nicht unterstützen (beispielsweise Windows 2000). Zudem aktiviert er unter Windows Vista für die aufrufende Anwendung die Option zur Heapbeschädigungserkennung.

BOOL SetHeapOptions() {
   HMODULE hLib = LoadLibrary(L"kernel32.dll");
   if (hLib == NULL) return FALSE;

   typedef BOOL (WINAPI *HSI)
          (HANDLE, HEAP_INFORMATION_CLASS ,PVOID, SIZE_T);
   HSI pHsi = (HSI)GetProcAddress(hLib,"HeapSetInformation");
   if (!pHsi) {
      FreeLibrary(hLib);
      return FALSE;
   }

#ifndef HeapEnableTerminationOnCorruption
#   define HeapEnableTerminationOnCorruption (HEAP_INFORMATION_CLASS)1
#endif

   BOOL fRet = (pHsi)(NULL,HeapEnableTerminationOnCorruption,NULL,0) 
            ? TRUE 
            : FALSE;
   if (hLib) FreeLibrary(hLib);

   return fRet;
}

Identifizieren einer Heapbeschädigungserkennung

Wenn eine Anwendung Fehler aufweist und aufgrund einer Heapbeschädigung beendet wird, wird in einem Debugger unter Windows Vista eine Meldung ähnlich der Folgenden angezeigt:

HEAP[Crash.exe]: Heap block at 001B6758 modified at 001B678E past requested size of 2e
(1770.25ac): Break instruction exception - code 80000003 (first chance)
eax=001b6758 ebx=001b678e ecx=774614cd edx=0012fae9 esi=001b6758 edi=0000002e
eip=77482ea8 esp=0012fd2c ebp=0012fd30 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
ntdll!DbgBreakPoint:
77482ea8 cc              int     3
0:000> kb
ChildEBP RetAddr  Args to Child              
0012fd30 774dc900 001b6758 00000000 001b6758 ntdll!DbgBreakPoint
0012fd48 774c4b6e 00000000 001b6758 7748c67e ntdll!RtlImageRvaToVa+0x1c3
0012fd64 7745894a 001b0000 001b6758 7748c67e ntdll!RtlDeleteAce+0x1355f
0012fdd0 7614b019 001b0000 00000000 001b6760 ntdll!RtlValidateHeap+0x79
0012fde4 6557cb0a 001b0000 00000000 001b6760 kernel32!HeapValidate+0x14

Hinweis   Dies wirkt sich nicht auf die Leistung aus.

ISV-Anforderungen

  • ISVs sollten diesen Code in alle EXEs einfügen. Wenn es sich bei Ihrer Komponente um eine DLL oder ein ActiveX-Steuerelement handelt, muss weder dieser Code eingefügt werden noch muss das Kennzeichen für die Heapbeschädigungserkennung gesetzt werden.

Wichtigkeit und Priorität der Schutzmaßnahmen

Die folgende Tabelle zeigt die relative Wichtigkeit dieser Schutzmaßnahmen und die Priorität, mit der ISVs die einzelnen Schutzmaßnahmen unterstützen sollten.

Schutzmaßnahme Priorität
Aktivieren von Address Space Layout Randomization Kritisch
Auswählen von DEP Kritisch
/GS-Stapelpuffer-Überlauferkennung Hoch
/SafeSEH-Ausnahmebehandlungsschutz Hoch
Testen der zufälligen Stapelanordnung Mittel
Testen der zufälligen Heapanordnung Mittel
Heapbeschädigungserkennung Mittel

Vorgehensweise beim Testen

Nachdem Änderungen am Code und am Entwurf vorgenommen wurden, müssen Sie überprüfen, ob das Betriebssystem richtig konfiguriert ist und die Anwendung die entsprechenden Codeänderungen enthält.

Verwenden des C++-Compilers

Überprüfen Sie, ob die Version des Compilers 13.10 oder höher ist. Version 14.00 oder höher ist dringend zu empfehlen, weil diese Version im Lieferumfang von Visual Studio 2005 enthalten ist und die beste /GS-Implementierung bietet.

Verwenden von /GS

Öffnen Sie die dem Produkt zugeordneten Makedatei(ein). Wenn Sie Versionen von Visual C++ vor Visual C++ 2005 verwenden, überprüfen Sie, ob der gesamte Code mit /GS oder –GS kompiliert wurde. Wenn Sie Visual C++ 2005 verwenden, stellen Sie sicher, dass keine Verweise auf /GS- oder –GS- vorhanden sind. Bei Compilerschaltern ist die Klein- und Großschreibung zu beachten, d. h. –GS ist nicht mit –Gs identisch.

Verwenden von /SafeSEH

Öffnen Sie die dem Produkt zugeordneten Makedateien, und überprüfen Sie, ob der Linker /SafeSEH verwendet. Linkeroptionen unterscheiden nicht zwischen Groß- und Kleinschreibung.

DEP-Kompatibilität

Es gibt viele Möglichkeiten zu bestimmen, ob Ihre BIOS- und CPU-Kombination DEP unterstützt und aktiviert hat. Am einfachsten lässt sich dies über den folgenden Pfad prüfen: Systemsteuerung/System/Erweiterte Systemeinstellungen/Registerkarte „Erweitert“/Leistungseinstellungen/Registerkarte „Datenausführungsverhinderung“. Wenn DEP aktiviert ist, werden folgende Wörter angezeigt:

Der Prozessor des Computers unterstützt hardwarebasierte Datenausführungsverhinderung

Wenn Sie ermitteln möchten, ob DEP von der Befehlszeile aktiviert wird, führen Sie die folgenden Schritte aus, und finden Sie heraus, ob auf dem zum Testen der Produkte verwendeten Computer DEP aktiviert ist.

Befehl Mögliche Ergebnisse Erforderliches Ergebnis
wmic OS Get DataExecutionPrevention_
Available
TRUE – DEP ist verfügbar

FALSE – DEP ist nicht verfügbar

TRUE
wmic OS Get DataExecutionPrevention_
SupportPolicy
0 – DEP ist für alle Prozesse deaktiviert

1 – DEP ist für alle Prozesse aktiviert

2 – Windows-Systemkomponenten sind DEP-aktiviert

3 – DEP ist für alle Komponenten außer für deaktivierte Komponenten aktiviert

1
wmic OS Get DataExecutionPrevention_
32BitApplications
TRUE – DEP ist für Anwendungen aktiviert

FALSE – DEP ist für Anwendungen deaktiviert

TRUE
wmic OS Get DataExecutionPrevention_
Drivers
TRUE – DEP ist für Treiber aktiviert

FALSE – DEP ist für Treiber deaktiviert

TRUE

Auf einigen Computern müssen Sie DEP über eine BIOS-Einstellung aktivieren. Beachten Sie auch, dass in einigen Fällen NX möglicherweise noch nicht für Ihre Anwendung oder Komponente erzwungen wurde. Dies passiert häufig, wenn eine Anwendung mit einer Bibliothek verknüpft ist, die nicht-NX-aktiviert ist, beispielsweise die in Visual Studio enthaltenen älteren Versionen der abstrakten Typbibliothek (Abstract Type Library, ATL). Wenn ATL erforderlich ist, verwenden Sie die Version, die mit Visual Studio 2003 SP1 (ATL v7.1) oder Visual Studio 2005 (ATL v8.0) geliefert wird. Sie können die ATL-Version mithilfe des folgenden Debugcodes überprüfen:

  // Version in Visual Studio .NET 2003 
  assert(AtlGetVersion(NULL) >= 0x0710);

ASLR-Kompatibilität

Stellen Sie sicher, dass Ihre Makedateien das Linkerkennzeichen /DYNAMICBASE (ohne Berücksichtigung von Groß- und Kleinschreibung) verwenden. Überprüfen Sie als Nächstes, ob Ihre Anwendung im Speicher dynamisch zugeordnet wurde.

Überprüfen einer EXE

Wenn Ihre Anwendung eine EXE-Datei ist, können Sie die folgenden Aufgaben durchführen:

  • Führen Sie einen Debugger aus, debuggen Sie den entsprechenden Prozess, und beachten Sie die Ladeadresse.
  • Führen Sie einen Neustart durch.
  • Wiederholen Sie Schritt (1).

Wenn der Prozess für die zufällige Anordnung aktiviert wurde, sind die Ladeadressen bei den verschiedenen Startvorgängen unterschiedlich. Unten sehen Sie eine Beispielausgabe von cdb.exe:

Suchpfad für die ausführbare Datei: ModLoad: 01270000 0128b000   C:\junk\TestRand\TestRand.exe ModLoad: 77ee0000 77ff5000   C:\Windows\system32\ntdll.dll ModLoad: 77c30000 77d01000   C:\Windows\system32\kernel32,dll ModLoad: 769a0000 76a49000   C:\Windows\system32\msvcrt.dll

Suchpfad für die ausführbare Datei: ModLoad: 009e0000 009fb000   C:\junk\TestRand\TestRand.exe ModLoad: 77a40000 77b55000   C:\Windows\system32\ntdll.dll ModLoad: 77820000 778f1000   C:\Windows\system32\kernel32,dll ModLoad: 76620000 766c9000   C:\Windows\system32\msvcrt.dll

Kompatibilität mit der Heapbeschädigungserkennung

Die beste Methode zum Überprüfen der Kompatibilität besteht darin, den richtigen Aufruf von HeapSetInformation im Code zu suchen.

Testen der Kompatibilität mit der zufälligen Stapel- und Heapanordnung

Zum Überprüfen der Kompatibilität reicht es aus, die Anwendung unter Windows Vista auszuführen, da diese Schutzmaßnahmen standardmäßig für alle Anwendungen aktiviert sind.

Zusammenfassung

Browser sind zurzeit die am häufigsten angegriffene Software. Aus diesem Grund ist es unumgänglich, dass Browser die vom Betriebssystem bereitgestellten Schutzmaßnahmen optimal einsetzen. Das Gleiche gilt für Komponenten, die vom Browser verwendet werden. Wenn die Anleitungen in diesem Artikel befolgt werden, können ISVs Komponenten erstellen, die in Internet Explorer gehostet sicherer funktionieren.

Verweise