Dit geven Windows PE-bestanden allemaal prijs

Noud van Kruysbergen
0

Inhoudsopgave

Uitvoerbare Windows PE-bestanden (.exe, .dll, .sys …) verraden veel meer over zichzelf dan je zo op het eerste gezicht zou denken. Behalve de herkomst, de gebruikte tools of de programmeerstijl kun je bijvoorbeeld achterhalen hoe moderne softwareconcerns zelf te werk gaan.

Als je dagelijks werkt met bestanden sta je er niet bij stil dat ook die aan allerlei afspraken zijn gebonden. Een computerbestand is niets meer of minder dan een geordende verzameling gegevens in elektronische vorm dat door elektronische apparatuur onder één naam kan worden behandeld en aangesproken. De wijze waarop het bestand is geordend is vaak te herkennen aan het achterste deel van de bestandsnaam, de bestandsextensie.

Windows PE

Microsoft heeft voor computerbestanden een eigen formaat gespecificeerd, het PE-formaat, een afkorting van Portable Executable. In de headers hiervan vind je vaak gedetailleerde informatie over de exacte versies van de gebruikte compiler, assembler, linker en import- en exportbibliotheken. Daarmee is te herkennen of het programma met C, C++ of met andere compilers of zelfs in assembler gemaakt werd en op welk updateniveau die zit.

Er zijn veel verschillende PE-bestanden, dus niet alleen extensies .exe, .dll of .sys. Op Windows-computers tref je meestal vijftig of meer verschillende typen in PE-formaat aan, waaronder .ocx,. scr, .efi, .bin, .tlb, .cat of .mui

Veel daarvan, zoals bestanden die eindigen op .api, zijn in feite niet meer dan hernoemde dynamic linked libraries, zogenaamde DLL’s. Deze zijn niet direct uitvoerbaar, maar bevatten wel uitvoerbare onderdelen. Andere zijn überhaupt niet uitvoerbaar, waaronder pure databestanden met extensies als .tlb, .rsc of .dll. Vaak zijn dit zogeheten resources, zoals taalpakketten, die vaak de extensie .mui (Multi User Interface) hebben.

Executable

Bestanden met de extensies .com, .edi, .scr en .sfx zijn normaal gesproken direct uitvoerbaar. Omdat de naam van de extensie willekeurig gekozen kan worden, kun je dat alleen met zekerheid vaststellen aan de hand van de informatie in de PE-header. Bestanden met .scr (zoals C:windowssystem32bubble.scr) zijn bedoeld voor screensavers. Die extensie wordt vaak door malware misbruikt omdat ze redelijk onopvallend gestart kunnen worden. Bestanden met de extensie .efi zijn wel uitvoerbaar, maar niet onder Windows, alleen onder UEFI. In de PE-header staat namelijk ook onder welke besturingssystemen een programma wil draaien en bij welk subsysteem het hoort (Windows-console, Windows-GUI, OS/2, CE, EFI-applicatie, EFI-driver, Xbox …).

Hier en daar tref je in Windows nog bestanden aan met de extensie .com, zoals mode.com, format.com en tree.com in Windowssystem32. Die namen stammen nog uit het good old DOS-tijdperk en kunnen ook gewoon hernoemd worden naar .exe. Dat Microsoft de ontwikkelsoftware Visual Studio traditioneel via devenv.com laat starten, is dan ook een geintje van de programmeurs.

Een belangrijk onderdeel van de PE-header is de linker-versie. De linker is de tool waarmee het PE-bestand gemaakt is. Daar kun je al aan herkennen of vermoedelijk een Microsoft-linker gebruikt werd (met gangbare waarden tussen 5.0 en 14.0) of Borland (meestal tussen 2 en 3) of wellicht helemaal geen linker, maar een ‘wrapper’ voor DotNet. Die zet daar al een paar jaar de versie van het gebruikte DotNet-framework in als 35 of 40 of meer. Ook aan de ‘DOS-stub’, een stukje code dat onder DOS draait en aangeeft dat het programma niet geschikt is voor DOS, kun je al een en ander herkennen. De standaardcode van Microsoft bevat de string “This program cannot be run in DOS mode”, terwijl Borlands Tlink32 daar “This program must be run under Win32” aangeeft.

Complottheorie

pebestt01

Rich-structuur: informatie over de tools die gebruikt zijn bij het maken van een programma staan versleuteld aan het begin van het bestand.

Wat Microsoft echter niet gedocumenteerd heeft, is een kleine structuur achter die DOS-stub (normaal vanaf offset $80). Bij andere linkers als die van Borland is die er ook helemaal niet. Begin deze eeuw zorgde die structuur voor veel ophef. Complotdenkers kenden daar onheilspellende kenmerken aan toe, maar het duurde niet lang voordat anderen erachter kwamen waar het om ging.

In die structuur zit informatie over de build tools, maar dan beveiligd met een eenvoudige XOR-versleuteling. Een voorwaarde is dat die tools in de gemaakte objectbestanden (.obj) en bibliotheken (.lib) hun ID’s in de variabele @comp.id hebben gezet en dat een Microsoft-linker vanaf versie 5.0 wordt gebruikt, die verantwoordelijk is voor het maken van de PE-bestanden.

De Rich Header

Door ‘Rich’ aan het eind van de structuur heet die sinds jaar en dag de Rich Header of Rich-structuur. De  32-bit key voor het ontsleutelen staat daar meteen achter. Die wordt uit de bytes in de PE-header voor de Rich-structuur en de bijbehorende waardes gemaakt. Als je die key XOR’t met de rest van de structuur, krijg je eerst ‘DanS’, dan driemaal de key en dan de lijst van versie-waardes. Rich en DanS verwijzen vermoedelijk naar de namen van de programmeurs: DanS is Dan Ruder, Microsofts linker-expert.

Maar ook als je die structuur ontsleuteld hebt, blijft het probleem de gevonden waardes toe te schrijven aan de talrijke tools, versies, builds, updates et cetera. Door gebrek aan documentatie is dat een blinde vlek. Twee projecten op GitHub houden zich daar al geruime tijd mee bezig: Detect It Easy en Richprint. Detect It Easy heeft een grote database voor het herkennen van allerlei mogelijke bestandsformaten en kan ook overweg met de gebruikelijke packers. Richprint beperkt zich alleen tot het weergeven en interpreteren van de Rich Header van PE-bestanden.

Richprint

pebest03

Het krachtige opensourceproject Detect It Easy kent ontelbare bestandsformaten
en packers (hier een met UPX ingepakte Python-dll).

Het project Richprint heeft in de loop der tijd een heleboel informatie verzameld om preciezer te kunnen zijn over de linker, compiler, assembler, resource-compiler en import- en exportbibliotheken. Het project wordt nog steeds bijgewerkt. De nieuwste toevoegingen hebben te maken met de verschillende versies van Visual Studio 15.

Sinds Microsoft publieke bètaprogramma’s voor Visual Studio heeft, is er een inflatie aan versiekenmerken. Inmiddels zijn er naast communitypreviews, RC’s (release candidates), RTM’s (Ready To Market) ook nog Updates 1, 2, 3, 4, 5 … en zo verder. Alleen voor VS2015 (linker-generatie 14.0) kwamen we al meer dan 30 verschillende ID’s tegen. Daarvan is minstens een zestal in commerciële software beland. De database van Richprint herkent zes verschillende pakketten – ten dele met geïnterpoleerde ID’s voor de afzonderlijke tools.

pebest02

Richprint interpreteert de Rich-structuur en laat, indien bekend, ook de gebruikte tools zien.

De Rich-kenmerken van een tool bestaan uit de 16-bit pakket-ID (het buildnummer van het bijbehorende Visual Studio-pakket), gevolgd door de eveneens 16-bit tool-ID. Die tool-ID was tot en met Visual Studio 2013 slechts 8-bit, inmiddels wordt ook het negende bit gebruikt. Daarna komt nog een teller die het aantal ermee gemaakte modules aangeeft. Met ‘24215’ wordt bijvoorbeeld Visual Studio 2015 Update 3.1 Build 24215 aangegeven. Tool-ID 261 (hexadecimaal $105) staat voor de C++-compiler uit die suite.

Microsoft-linker

Het laatste item in de Rich-structuur stamt van de tool die het PE-bestand gemaakt heeft. Normaal is dat de Microsoft-linker. Daarvoor staat meestal de compiler van het hoofdprogramma met het program entry point. Als beide ID’s op nul staan (‘0-0’), dan gaat het om een andere compiler zonder @comp.id die wel de Microsoft-linker gebruikt, bijvoorbeeld Composer van Intel.

Tegenwoordig is de laatste tool die wat met de code doet een programma dat de digitale ondertekening verzorgt. Dat programma heeft geen pakket-ID, maar daar gebruikt de linker in ieder geval een tool-ID voor, meestal 151 ($97), dus ‘0-151’. Een bijzonderheid zijn de modules uit de kernel library die met ‘0-1’ worden aangegeven.

Bij uitvoerbare bestanden horen de zogeheten ‘wrappers’. DotNet-programma’s hebben zoals eerder gezegd geen linker. Je kunt ze echter als .exe in een PE-bestandsformaat pakken en rechtstreeks starten. Bij Python-programma’s werkt dat hetzelfde. Bestanden met de extensie .pyc en .pyo zijn gecompileerde Python-bytecode. Die wordt verder gewoon sequentieel geïnterpreteerd, dus is niet noemenswaardig sneller dan de broncode. Op Windows-pc’s staan normaal gesproken Python-dll’s die je kunt herkennen aan .pyd. Ze worden via python.dll aangeroepen.

Dergelijke python-dll’s worden bijvoorbeeld door OpenOffice en het opensource beeldbewerkingsprogramma GIMP gebruikt. Ook het hardeschijfanalyseprogramma Autopsy en de Intel Composer werken met dergelijke ingepakte Python-scripts.

Programma’s of programmaketens worden bovendien vaak ingepakt. De opensource packer UPX (Ultimate Packer for eXecutables) is bijzonder populair. Op GitHub is deze inmiddels bij versie 3.93 aanbeland. Programma’s die met UPX zijn ingepakt s kun je makkelijk herkennen aan de segmentnamen UPX0, UPX1 … Voor de set-up, de (de)installer en packer kom je nog redelijk vaak de oeroude Inno Setup-module 5.3.10 tegen. De Inno Setup 5.57 is wat nieuwer met Delphi 2009. Daar wordt bijvoorbeeld de huidige SiSoft Sandra mee geïnstalleerd. Microsoft gebruikt zijn eigen inpakprogramma’s.

Doorlichten

We hebben een aantal computers met Windows 10 hier op de redactie eens doorgelicht. De oudste bestanden met Rich-headers stammen uit 1998 – afgezien van wat verkeerd ingestelde datums door Microsofts Phone SDK 8.1. Toen was Visual Studio 93 SP3 (codenaam Boston) de recentste versie. Eerst met de linker ML 6.12.7146, later met ML 6.13.7299. Als eerste Rich-kenmerk vind je dan 7303-02.

Een van de oudste tools die van Rich voorzien is, komt van InstallShield Software Corporation. Die veteraan heet _isdel. exe versie 5.54 en staat bij een 64-bit Windows in C:WindowsSysWOW64Install- Shield.

Microsoft heeft DotNet met C# uitgevonden en geprobeerd om programmeurs over te halen naar DotNet over te stappen. Maar bij eigen applicaties zoals Office wordt DotNet in verhouding weinig gebruikt. Hier en daar een keer een kleine tool als spreadsheet-compare.exe, maar alle belangrijke programma’s zoals Excel, Word, PowerPoint, Acces en Outlook zijn met C/C++ gemaakt. Daarbij liepen de Office-ontwikkelaars lange tijd altijd twee of drie generaties achter op de actuele eigen versies van Visual Studio. De build van juni vorig jaar van Office 15 heeft bijvoorbeeld het pakket/link-kenmerk 30716-186, dat hoort bij Visual Studio 2010 met linker 10.10.

Microsoft gebruikt overigens intern graag interimversies die buiten de firma helemaal niet beschikbaar zijn. Pas bij Office 2016 uit december 2016 lukte het Microsoft naar Visual Studio 2015 23919 over te stappen. Die versie was nog redelijk actueel, maar ook die komt niet in het wild voor, zodat je niet precies weet op welk updatelevel de tool zit. De dichtstbijzijnde Update 2 van de communityversie heeft in ieder geval kenmerk 23720.

Microsofts runtime-omgevingen

Oude runtime-omgevingen worden door Microsoft nog altijd onderhouden. MSVCP60.dll voor VC6 werd voor het laatst in juni 2016 bijgewerkt. VC6 wordt immers nog veel gebruikt. Zo heeft Adobe bij zijn producten lange tijd aan VC6 vastgehouden. In 2002 is bijvoorbeeld PhotoShop-versie CS2 er mee gemaakt. Die versie is nog altijd erg populair, onder meer omdat Adobe die versie gratis via internet aanbiedt. Bij Acrobat Reader is Adobe op een gegeven moment overgestapt op Visual Studio. Bij de huidige versie gebruiken de Adobe-programmeurs de al wat oudere Visual Studio 2014-40629. Daar is Adobe altijd nog actueler mee dan Oracle. Diens Java 8.1 is nog op de oude Visual Studio 2010-40219 gebaseerd.

De nieuwste versie PhotoShop CC is ook wat betreft de gebruikte compiler helemaal bij de tijd en gebruikt Intel Composer 2016 met MKL, OpenMK en Fortran-Core.

Buiten Photoshop tref je weinig software aan die met deze bijzonder efficiënte Intel-compiler is gemaakt. De uitzondering in bij High Performance Computing. Cinebench R15 heeft veel modules die met ‘0-0’ zijn gemarkeerd. En zoals je ook kunt zien aan de libs wordt daar de Intel-compiler bij gebruikt.

Mozilla is met Firefox op basis van Visual Studio 2015-24213 redelijk bij de tijd. Maar Thunderbird hinkt daar met Visual Studio 2013-30723 weer wat achteraan.

MinGW wordt met zijn eigen linker overigens vaker gebruikt dan de Intel-compiler, bijvoorbeeld bij GIMP 2.8.20. Versie 1.01 van Detect It Easy herkent ook de MinGW-versies. Samen met het project Richprint krijg je dan een redelijk beeld van de binaire bestanden op een Windows-computer. We hebben het door Richprint gebruikte bestand compid.txt nog flink uitgebreid met de informatie die we onderweg aantroffen.

Verraderlijke sporen

Vanuit forensisch oogpunt is de in de Rich-structuur vermelde versiemix een interessant aanknopingspunt voor de herkomst. Middels een vergelijking met andere producten is redelijk goed te achterhalen door welke ontwikkelaar een programma is gemaakt. Het is dus een soort vingerafdruk van de ontwikkelaar.

Die informatie helpt ook om de authenticiteit van een binair programma te controleren. Het populaire TrueCrypt 7.1 was met de juiste tools bijvoorbeeld eenduidig te reconstrueren uit de broncode. Daar moest men niet alleen de juiste tools voor hebben, maar ook de op het build-moment bekende hotfixes.

Er zijn al wel tools voor het verwijderen van de ‘verraderlijke’ data in de header. Slimme software als Detect It Easy doorzoekt de code bovendien naar talrijke sporen, segmentnamen, codefragmenten, ingebedde bibliotheken en nog meer om daar zo veel mogelijk informatie uit te halen.

Wetenschappers aan de universiteiten van Princeton, Braunschweig en Drexel hebben een methode ontwikkeld die van een compilaat heel betrouwbaar kan aangeven wie de programmeur is. Dat werd gefinancierd door het Amerikaanse militaire instituut DARPA en de Deutsche Forschungsgemeinschaft. Van Google Code Jam, van GitHub en van hackersfora als Nulled.IO werden 100 afzonderlijke programmeurs met 96 procent trefzekerheid herkend. Daarvoor classificeerden de onderzoekers 900 programma’s met in totaal 750.000 stilistische features. Maar ook bij een grotere verzameling was het resultaat nog zeker niet slecht te noemen. Het scoringspercentage bedroeg bij 600 kandidaten nog altijd 83 procent.

(Andreas Stiller / Noud van Kruysbergen)

Deel dit artikel

Noud van Kruysbergen
Noud van KruysbergenNoud heeft de 'American Dream' doorlopen van jongste bediende tot hoofdredacteur van c't, waar hij zo veel mogelijk de diepgang, betrouwbaarheid en diversiteit wil bewaken.

Lees ook

Chat GPT gebruiken: dit kun je allemaal doen met de chatbot van OpenAI

OpenAI heeft de ChatGPT-bot ontwikkeld als een taalmodel dat is getraind op een enorme hoeveelheid tekst op het internet. Je kunt ChatGPT gebruiken om...

Smart App Control: Windows 11 beveiligingsfunctie met beperkingen

De beveiligingsfunctie Smart App Control die bij de 2022-update geïntroduceerd is, moet Windows 11 eindelijk veilig maken. Het concept kan werken, maa...

0 Praat mee
avatar
  Abonneer  
Laat het mij weten wanneer er