Fare il parsing dei file .lnk

Probabilmente saprete che, tra le mille cose che faccio, c'è il mantenimento (e la direzione generale) di Icaros Desktop, LA distribuzione del sistema operativo open source AROS. Quest'ultima, in 10 anni, ha collezionato una grandissima quantità di script e di funzioni specializzate per fare questo e quello, nell'ottica di ampliare le feature del sistema e di renderle il più possibile, per quanto possibile - insomma: io ci provo ma non sempre ci riesco - user-friendly. Alcuni di questi script vanno a comporre una tecnologia che io ho chiamato HostBridge, e che permette di avviare da AROS applicazioni che girano su Windows o su Linux, quando il primo dei tre funziona in modalità "hosted", vale a dire come se fosse un programma come tutti gli altri. HostBridge funziona così: da AROS gli si indica un eseguibile "alieno", e lui va a creare uno script di esecuzione che, a sua volta, si occuperà di passare al programma eventuali parametri e percorsi di file da aprire. Non è una tecnologia proprio banale, perché bisogna considerare che AROS, Linux e Windows vedono i percorsi dei file in maniera piuttosto diversa tra loro, con Windows che addirittura si diverte a invertire la direzione delle barrette inclinate che separano le directory. L'accrocchione in ogni caso funziona e io ero contentissimo così, dopo aver dato la possibilità agli utenti di 'integrare' un programma Linux o Windows per volta. 


Un paio di anni fa, tuttavia, ricevetti un fantastico regalo da Nicola Scendoni: uno script per Linux in grado di realizzare - in una sola passata - gli script di HostBridge per tutte le applicazioni Linux installate sul sistema. Rapido, efficace, duraturo. Decisi così di dividere il suo script in due parti, in modo da mantenere separato il "nocciolo" che convertiva un file .desktop di Linux in uno script per HostBridge, dal loop che invece si occupava di lanciarlo per tutti i file .desktop che trovava. Ma cosa sono i file .desktop? In pratica, sulle distribuzioni Debian, Ubuntu e simili, possiamo considerarli il corrispettivo Linux dei file .lnk che richiamano i programmi dal menu Start di Windows. E qui veniamo al punto, perché nelle ultime settimane mi ero ripromesso (ho fatto anche il madornale errore di lasciarlo intendere a chiare lettere su icarosdesktop.org) di convertire la comoda funzione realizzata da Nicola da Linux a Windows, così da garantire anche agli utenti di Icaros Desktop che la usano sotto Windows la possibilità di importare tutti i programmi installati senza smaronarsi a farlo uno per volta. Evviva.

Quello a cui non avevo pensato in quel momento, è la famigerata ottusità del prompt di comando di Windows, che mi tocca usare al posto della powershell per banali questioni di ubiquità: Icaros è usata da gente che può avere Windows 10, 7, 8 o anche addirittura XP, per cui devo sempre cercare di adottare il massimo comune divisore di questi sistemi, eventualmente trovando soluzioni che girino su tutti loro. 

I FILE LNK, QUESTO CASINO

Parliamo quindi di questi file .lnk. Come suggerisce il nome, si tratta fondamentalmente di link e per tanto, direte, che problema ci sarà mai a gestirli? In fondo devono solo contenere alcune informazioni del cazzo, tipo il nome del programma da lanciare, il percorso su cui si trova, magari qualche parametro d'avvio e poco altro. No? No. Microsoft amava fare le cose complicate e sono certo che questi file non siano altro che il retaggio di un passato oscuro in cui qualcuno si preoccupasse di rendere il sistema quanto più inutilmente complesso possibile, anche nei suoi aspetti più futili, allo scopo di venderti qualche software in grado di gestire ogni banalità. Non si spiegherebbe altrimenti la necessità di creare dei file .lnk binari, e quindi con i testi non in chiaro. Gli analoghi file .desktop di Linux, per dire, non sono altro che banali file di testo con una serie di parametri chiari come il sole, almeno per chi vuole fare la fatica minima necessaria a comprenderli. Gli .lnk, invece, hanno bisogno di qualche disperata utility di sistema per essere analizzati ma, se vogliamo operare su di loro con la riga di comando, possiamo anche attaccarci al tram o cercare soluzioni di terzi. Cosa che ovviamente ho fatto con l'aiuto di Google e, in tempo quasi zero, ho trovato un meraviglioso programma chiamato lnkanalyser, un vecchio programma di un tizio chiamato Mark Woan che non smetterò mai di ringraziare. Grazie al suo tool ho potuto apprendere che i file .lnk non si limitano a dire a Windows che eseguibile lanciare, ma trattengono anche numerose informazioni utili (si fa per dire) come la data di installazione, il MAC address da cui è avvenuta e cose del genere, più diversi metadati che possono certamente giungere in aiuto nelle ispezioni forensi, ma che per i miei scopi sono fin troppo "oltre".

Comunque sia, quello che veramente serve a me nei file .lnk si trova nella loro intestazione. Per esempio:

Path: C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Movie Maker.lnk
Flags:
Attributes: Archive
Show Command: SW_SHOWNORMAL
Name: @C:\Program Files (x86)\Windows Live\Photo Gallery\MovieMakerLang.dll,-1135
Relative Path: ..\..\..\..\..\Program Files (x86)\Windows Live\Photo Gallery\MovieMaker.exe
Working Path: C:\Program Files (x86)\Windows Live\Photo Gallery\
Arguments:
Icon Location:

Ci sono tre righe interessanti qui, che potrebbero servire a me per i miei scopi: Relative path, Working path e Arguments. Il motivo per cui Windows debba registrare un path relativo invece di uno assoluto mi sfugge nella maniera più completa, visto che questo costringerà il sistema ad aggiornare il contenuto stesso della riga ogni volta che il file .lnk cambia directory, ma fa niente. Questo abbiamo in ogni caso e, analizzando diversi file lnk, è quello su cui solitamente viene scritto il nome dell'eseguibile nella forma che serve a me, e cioè nomeprogramma.exe con tanto di percorso d'avvio. Al massimo, dovrò trasformarlo in qualche modo in un percorso assoluto.

Non bisogna però sottostimare l'importanza di Working path e di Arguments visto che, analizzando i file lnk sul mio PC, mi sono accorto di una certa incoerenza. La stessa Microsoft, per diversi tool di sistema, lascia vuoti i primi due campi per inserire l'eseguibile nel campo argomenti. Per dire, questo è il collegamento a Paint:

Path: C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Accessories\Paint.lnk
Flags:
Attributes:
Show Command: SW_SHOWNORMAL
Name: @%SystemRoot%\system32\shell32.dll,-22566
Relative Path:
Working Path:
Arguments: %windir%\system32\mspaint.exe
Icon Location:

Bello eh? Quindi una cosa è certa: quando scriverò il mio parser di file .lnk, mi toccherà prevedere diverse strade per andare a prendere l'eseguibile. E temo proprio che difficilmente riuscirò a supportarle tutte. Ma torniamo a noi.

I TOOL NECESSARI

Il prompt di comando di Windows è notoriamente sottostimato. Sa fare un mucchio di cose, ma di solito il modo per farle fare è arcicomplicato e legnoso, motivo per cui oggi si usa la PowerShell per fare molte, molte più cose, con una sintassi forse ancora più cervellotica ma con una flessibilità indubbiamente maggiore. Per noi veri zucconi del prompt di comando, tuttavia, l'alternativa a una morte lenta e dolorosa a suon di variabili che si espandono al momento sbagliato, è trovare i tool che si usano normalmente su Linux compilati per Win32. Google il Santo mi ha indirizzato subito su diverse alternative, tra cui UnxUtils, una raccolta di software GNU che non ha bisogno di balzane librerie esterne per funzionare. Ho così potuto riabbracciare vecchi amici come grep, gsar, sed, head e compagnia bella, che mi serviranno parecchio per trasformare i dati raccolti da lnkanalyser in qualcosa di effettivamente utile. È una roba vecchia come il cucù e non viene più mantenuta da quando le torri gemelle erano ancora in piedi, ma fa ancora egregiamente il suo dovere. Per di più, è libera per l'uso e la distribuzione, il che per me è fondamentale.

Ho così messo tutti i programmi necessari nella stessa directory e ho scritto uno scriptino verboso e ridondante, che alla fine produce risultati come questi:

-------------------------------------------------------------
[C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Access.lnk]
-------------------------------------------------------------
temporary files
Relative Path: ..\..\..\..\..\Program Files (x86)\Microsoft Office\root\Office16\MSACCESS.EXE
C:\Program Files (x86)\Microsoft Office\root\Office16\MSACCESS.EXE
-------------------------------------------------------------
Arguments: C:\Program Files (x86)\Microsoft Office\Root\VFS\Windows\Installer\{90160000-000F-0000-0000-0000000FF1CE}\accicons.exe
 C:\Program Files (x86)\Microsoft Office\Root\VFS\Windows\Installer\{90160000-000F-0000-0000-0000000FF1CE}\accicons.exe
=======-------=========-----------=========----------========
Executable: "C:\Program Files (x86)\Microsoft Office\root\Office16\MSACCESS.EXE"
-------------------------------------------------------------
Arguments: " C:\Program Files (x86)\Microsoft Office\Root\VFS\Windows\Installer\{90160000-000F-0000-0000-0000000FF1CE}\accicons.exe"
=============================================================


-------------------------------------------------------------
[C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Acrobat Reader DC.lnk]
-------------------------------------------------------------
temporary files
Relative Path: ..\..\..\..\..\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe
C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe
-------------------------------------------------------------
Arguments: C:\WINDOWS\Installer\{AC76BA86-7AD7-1040-7B44-AC0F074E4100}\SC_Reader.ico
 C:\WINDOWS\Installer\{AC76BA86-7AD7-1040-7B44-AC0F074E4100}\SC_Reader.ico
=======-------=========-----------=========----------========
Executable: "C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe"
-------------------------------------------------------------
Arguments: " C:\WINDOWS\Installer\{AC76BA86-7AD7-1040-7B44-AC0F074E4100}\SC_Reader.ico"
=============================================================

Basta dargli in pasto un file .lnk e al resto ci pensa lui. Ovviamente ho dovuto piangere in tutte le lingue e provare e riprovare settordici volte ogni cosa, ma alla fine ho lo stretto indispensabile per partire: qualcosa in grado di darmi esattamente le info di cui ho bisogno in una forma molto simile a quella che mi servirà per portare questa componente di HostBridge su Windows. 

Ho già risolto anche il problema dell'estrazione dell'icona dai programmi, ma su quello non mi voglio per il momento dilungare.