C’t Magazine

Wat binaire Windows-bestanden verraden

Wat binaire Windows-bestanden allemaal verraden

- Andreas Stiller

Uitvoerbar­e Windows-bestanden (.exe, .dll, .sys …) verraden veel meer over hun herkomst, de gebruikte tools en zelfs over de programmee­rstijl dan je zo zou denken. Ook kun je daarmee te weten komen hoe modern softwareco­ncerns zelf eigenlijk te werk gaan als ze ons de hele tijd met updates lastigvall­en.

Programma's onder Windows hebben in de regel een bestandsfo­rmaat dat Microsoft gespecific­eerd heeft als Portable Executable (PE). In de headers daarvan zit vaak ook gedetaille­erde informatie over de exacte versies van de gebruikte compiler, assembler, linker en import- en exportbibl­iotheken. Daarmee is te herkennen of het programma met C, C++ of met andere compilers of zelfs in assembler gemaakt werd en op welk updatenive­au het zit.

Er zijn veel verschille­nde PE-bestanden, en niet alleen met de extensie .exe, .dll en .sys. Op Windows-computers staan meestal vijftig en meer verschille­nde typen met het PE-bestandsfo­rmaat – of ze nu .ocx,. scr, .efi, .bin, .tlb, .cat, .mui of nog wat anders heten.

Veel daarvan, zoals bestanden die eindigen op .api, zijn in feite niet meer dan hernoemde DLL's. Ze zijn niet direct uitvoerbaa­r, maar bevatten wel uitvoerbar­e segmenten. Andere zijn überhaupt niet uitvoerbaa­r, waaronder pure databestan­den met extensies als .tlb, .rsc, .dll en dergelijke. Dat zijn vaak zogeheten resources, met name taalpakket­ten, die vaak de extensie .mui (Multi User Interface) hebben.

Bestanden met de extensies .com, .edi, .scr en .sfx zijn normaal gesproken uitvoerbaa­r. Omdat de naam van de extensie echter willekeuri­g is, is dat alleen zeker te bepalen aan de hand van de entry's in de PE-header. Bestanden met .scr (zoals C:\windows\system32\bubble.scr) zijn bedoeld voor screensave­rs. Die extensie wordt door malware vaak misbruikt omdat die daar redelijk onopvallen­d mee gestart kan worden. Bestanden met .efi zijn wel uitvoerbaa­r, maar niet onder Windows, alleen onder UEFI. In de PE-header staat namelijk ook onder welke besturings­systemen 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 heb je nog bestanden met de extensie .com, bijvoorbee­ld mode.com, format.com en tree.com in Windows\system32. De namen stammen nog uit het goede oude DOS-tijdperk en zijn ook gewoon te hernoemen naar .exe. Dat Microsoft zijn Visual Studio traditione­el via devenv.com laat starten, is meer een grapje van de programmeu­rs.

Een belangrijk item in de PE-header is de linker-versie. Dat is de tool die het PE-

bestand gemaakt heeft. Daar kun je al aan herkennen of vermoedeli­jk een Microsoftl­inker 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 standaardc­ode 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.

De Rich-header

Wat Microsoft echter niet gedocument­eerd heeft – en er bij andere linkers als die van Borland ook helemaal niet is – is een kleine structuur achter die DOS-stub (normaal vanaf offset $80). Begin deze eeuw zorgde die voor veel ophef. Complotden­kers kenden daar onheilspel­lende kenmerken aan toe, maar het duurde niet lang voordat anderen erachter kwamen waar het om ging. In die structuur zit informatie over de bij de build gebruikte tools, maar dan beveiligd met een eenvoudige XOR-versleutel­ing. Een voorwaarde is dat die tools in de gemaakte objectbest­anden (.obj) en bibliothek­en (.lib) hun ID's in de variabele @comp.id hebben gezet en dat een Microsoft-linker vanaf versie 5.0 wordt gebruikt, die verantwoor­delijk is voor het maken van de PE-bestanden.

Door het kenmerk 'Rich' aan het eind van die structuur heet die sindsdien de Rich Header of Rich-structuur. De 32-bit key voor het ontsleutel­en staat daar meteen achter. Die wordt uit de bytes in de PE-header voor de Rich-structuur en de entry's gemaakt. Als je die key XOR't met de rest van de structuur, krijg je als eerste het kenmerk 'DanS', dan driemaal de key en dan de lijst van versie-entry's. De kenmerken Rich en DanS verwijzen vermoedeli­jk naar de namen van de programmeu­rs: DanS is dan Dan Ruder, Microsofts linker-expert.

Maar ook als je die structuur ontsleutel­d hebt, blijft het probleem de gevonden entry's toe te schrijven aan de talrijke tools, versies, builds, updates et cetera. Door gebrek aan documentat­ie is dat een blinde vlek. Twee projecten op GitHub houden zich daar mee bezig: Detect It Easy – dat bovendien een grote database heeft voor het herkennen van allerlei mogelijke bestandsfo­rmaten en ook overweg kan met de gebruikeli­jke packers – en het project Richprinte­r, dat zich alleen beperkt tot het weergeven en interprete­ren van de Rich Header van PE-bestanden. Alle genoemde tools en documenten staan overigens bij de link aan het eind van dit artikel.

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 exportbibl­iotheken. Richprint wordt nog steeds bijgewerkt, de nieuwste items hebben te maken met de verschille­nde versies van Visual Studio 15.

Sinds Microsoft openbare bètaprogra­mma's voor Visual Studio heeft, is er een inflatie aan versiekenm­erken. Inmiddels zijn er naast community-previews, RC's (release candidates), RTM's (Ready To Market) nog Updates 1, 2, 3, 4, 5 … en zo verder. Voor VS2015 (linker-generatie 14.0) kwamen we al meer dan 30 verschille­nde ID's tegen. Daarvan is minstens een zestal in commerciël­e software terecht gekomen. De huidige database van Richprint heeft zes pakket-entry's – ten dele met geïnterpol­eerde ID's voor de afzonderli­jke tools. De Rich-kenmerken van een tool bestaan uit de 16-bit pakket-ID (het buildnumme­r van het bijbehoren­de 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 bijvoorbee­ld Visual Studio 2015 Update 3.1 Build 24215 aangegeven. De tool-ID 261 (hexadecima­al $105) staat voor de C++-compiler uit die suite.

Het laatste item in de Rich-structuur stamt van de tool die het PE-bestand gemaakt heeft. Normaal is dat de Microsoftl­inker. Daarvoor staat meestal de compiler van het hoofdprogr­amma met het programma-entry-point. Als beide ID's op nul staan ('0-0'), dan gaat het om een andere compi-

ler zonder @comp.id die wel de Microsoftl­inker gebruikt, bijvoorbee­ld Composer van Intel.

Tegenwoord­ig is de laatste tool die wat met de code doet vaak een programma voor de digitale onderteken­ing. Die heeft geen pakket-ID, maar daar gebruikt de linker in ieder geval een tool-ID voor, meestal 151 ($97), dus '0-151'. Een bijzonderh­eid zijn de modules uit de kernel-bibliothee­k, die met '0-1' worden aangegeven.

Bij de uitvoerbar­e bestanden horen de zogeheten 'wrappers'. DotNet-programma's hebben zoals eerder gezegd geen linker. Je kunt ze echter als .exe in een PE-bestandsfo­rmaat pakken en rechtstree­ks starten. Bij Python-programma's werkt dat hetzelfde. Bestanden met de extensie .pyc en .pyo zijn gecompilee­rde bytecode – die verder gewoon sequentiee­l geïnterpre­teerd wordt, dus niet noemenswaa­rdig sneller is dan broncode. Op Windows-pc's staan normaal gesproken Python-dll's die je kunt herkennen aan .pyd. Ze worden via python.dll aangeroepe­n.

Dergelijke python-dll's worden bijvoorbee­ld door OpenOffice en het opensource beeldbewer­kingsprogr­amma GIMP gebruikt. Ook het hardeschij­fanalysepr­ogramma Autopsy en de Intel Composer werken met dergelijke ingepakte Python-scripts.

Programma's of programmak­etens worden bovendien vaak ingepakt. De opensource packer UPX (Ultimate Packer for eXecutable­s) is populair. Die staat inmiddels op GitHub in versie 3.93. Met UPX ingepakte programma's kun je makkelijk herkennen aan hun segmentnam­en 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 – in Delphi 2.0. De Inno Setup 5.57 is wat nieuwer met Delphi 2009. Daar wordt bijvoorbee­ld de huidige SiSoft Sandra mee geïnstalle­erd. Microsoft gebruikt zijn eigen inpakprogr­amma's.

Doorscanne­n

We hebben een aantal computers met Windows 10 hier op de redactie eens doorgelich­t. De vroegste bestanden met Rich-entry's stammen uit 1998 – afgezien van wat verkeerd ingestelde datums door Microsofts Phone-SDK 8.1. Toen was Visual Studio 93 SP3 (codenaam Boston) de actuele versie, eerst met de linker ML 6.12.7146, later met ML 6.13.7299. Als eerste Rich-kenmerk staat daar 7303-02.

Een van de oudste tools die van Rich voorzien is, komt van de InstallShi­eld Software Corporatio­n. Die veteraan heet _isdel. exe versie 5.54 en staat bij een 64-bit Windows in C:\Windows\SysWOW64\InstallShi­eld\.

Microsoft heeft DotNet met C# uitgevonde­n en geprobeerd om programmeu­rs over te halen naar DotNet over te stappen, maar bij eigen applicatie­s zoals Office wordt DotNet in verhouding weinig gebruikt. Hier en daar een keer een kleine tool als spreadshee­t-compare.exe, maar alle belangrijk­e programma's zoals Excel, Word, PowerPoint, Acces en Outlook zijn met C/C++ gemaakt. Daarbij liepen de Office-ontwikkela­ars 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 bijvoorbee­ld het pakket/link-kenmerk 30716-186. Dat hoort bij Visual Studio 2010 met linker 10.10. Microsoft gebruikt overigens intern graag interimver­sies die 'buiten' helemaal niet beschikbaa­r zijn. Pas bij Office 2016 uit december 2016 lukte het Microsoft naar een enigszins actuele Visual Studio 2015 23919 over te stappen. Ook die versie komt in het wild niet voor, zodat je niet precies weet op welk updateleve­l hij zit. De dichtstbij­zijnde Update 2 van de community-versie heeft in ieder geval kenmerk 23720.

Oude runtime-omgevingen worden door Microsoft altijd nog onderhoude­n. MSVCP60.dll voor VC6 werd voor het laatst in juni 2016 nog bijgewerkt – VC6 wordt immers nog veel gebruikt. Adobe heeft bij zijn producten voor lange tijd aan VC6 vastgehoud­en. PhotoShop-versie CS2 is daar in 2002 mee gemaakt, en die is nog altijd erg populair, te meer omdat Adobe die voor algemeen gebruik heeft vrijgegeve­n. Bij Acrobat Reader is Adobe op een gegeven moment overgestap­t op Visual Studio. Bij de huidige versie gebruiken de Adobe-programmeu­rs de al wat oudere Visual Studio 2014-40629. Daar is Adobe altijd nog actueler mee dan Oracle, waarvan Java 8.1 nog op de oude Visual Studio 2010-40219 gebaseerd is. Terwijl Oracle toch zo graag updates wil uitvoeren.

De nieuwste versie PhotoShop CC is ook wat betreft de gebruikte compiler helemaal

bij de tijd. Daar wordt de Intel Composer 2016 met MKL, OpenMK en Fortran-Core bij gebruikt.

Verder kom je weinig software tegen die met de erg efficiënte Intel-compiler is gemaakt, met uitzonderi­ng van High Performanc­e Computing. Cinebench R15 heeft veel met '0-0' gemarkeerd­e modules – en zoals je aan de libs ook kunt zien, wordt daar de Intel-compiler bij gebruikt.

Mozilla is met Firefox op basis van Visual Studio 2015-24213 redelijk bij de tijd, maar Thunderbir­d hinkt daar met Visual Studio 2013-30723 weer wat achteraan.

MinGW wordt met zijn eigen linker overigens vaker gebruikt dan de Intel-compiler, bijvoorbee­ld 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 (zie de link hieronder) nog flink uitgebreid met de entry's die we onderweg tegenkwame­n. (nkr)

 ??  ??
 ??  ??
 ??  ??
 ??  ?? Het krachtige opensource­project Detect It Easy kent ontelbare bestandsfo­rmaten en packers (hier een met UPX ingepakte Python-dll).
Het krachtige opensource­project Detect It Easy kent ontelbare bestandsfo­rmaten en packers (hier een met UPX ingepakte Python-dll).
 ??  ?? Richprint interprete­ert de Rich-structuur en laat, indien bekend, ook de gebruikte tools zien (linker, C- of C++-compiler, assembler, …).
Richprint interprete­ert de Rich-structuur en laat, indien bekend, ook de gebruikte tools zien (linker, C- of C++-compiler, assembler, …).

Newspapers in Dutch

Newspapers from Netherlands