Vogliamo automatizzare il processo di rimozione della protezione dai file Word utilizzando il nostro amato Python. Questo articolo si ricollega al procedimento già illustrato in precedenza in [word] Rimuovere “Limita modifica” da un file docx di Word
Per i dettagli della procedura rimando all’articolo precedente, qui vedremo esclusivamente la parte che riguarda Python.
In Python vogliamo realizzare uno script che permetta o dal prompt dei comandi, oppure trascinandoci sopra un file, di sbloccare un file Word al quale sia applicata la protezione contro le modifiche.
Quello che vogliamo ottenere alla fine è qualcosa di simile:
Oppure un eseguibile sopra il quale sia possibile trascinare il file da sbloccare.
Seguono i commenti nel codice:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
import sys import zipfile import os import shutil # costruiamo il main def main(): # in caso di un qualsiasi errore non gestito try: # controlliamo se c'è il secondo argomento, ricordando che gli argomenti sono: # 0 - nome dello script o dell'eseguibile # 1 - primo argomento, in questo caso il percorso del file # la lunghezza quindi degli argomenti passati dev'essere almeno 2 if len(sys.argv) < 2: print("Trascina un file sull'eseguibile") return # se c'è il secondo argomento supponiamo che sia il percorso al file else: # preleviamo il percorso al file file_path = sys.argv[1] print(f"Percorso del file: {file_path}") print("Inizio modifica file...") # definiamo una cartella temporanea per l'estrazione temp_dir = "temp_extract" try: # creiamo tale cartella, se già esiste andiamo avanti os.makedirs(temp_dir, exist_ok=True) except: print("Errore 1: impossibile creare cartella, permesso negato") return try: # estraiamo tutto il file docx, trattandolo come se fosse un file zip # ricordiamoci che a tutti gli effetti è un file zip rinominato with zipfile.ZipFile(file_path, 'r') as fp: fp.extractall(temp_dir) except: print("Errore 2: impossibile scompattare!") return # in ogni file word corretto dovrà essere il file settings.xml che andremo a modificare xml_file = "temp_extract/word/settings.xml" try: # apriamo il file xml e leggiamo tutto il contenuto with open(xml_file,'r') as fp: contenuto = fp.read() # sostituiamo il parametro enforcement impostandolo su false # ricordiamoci che il parametro può comparire configurato o come true o come 1 # quindi tentiamo entrambe le sostituzioni, ovviamente avremmo potuto usare # la librerira xml, oppure un riconoscimento con stringhe regolari, ma perché # scomodarsi se possiamo fare le cose in modo bovino? contenuto = contenuto.replace('w:enforcement="true"','w:enforcement="false"') contenuto = contenuto.replace('w:enforcement="1"','w:enforcement="false"') # riscriviamo il file xml with open(xml_file,'w') as fp: fp.write(contenuto) print("Chiusura file modificato...") except: print("Errore 3: impossibile modificare il file!") return # predisponiamo il nome del file sbloccato file_name = "sbloccato-" + os.path.basename(file_path) try: # ricreiamo tutto il file zip di prima, con il nuovo nome, applicando la compressione # ATTENZIONE: senza il parametro di compressione il file risultante potrebbe essere # molto più grande di quello di partenza (circa 10x) with zipfile.ZipFile(file_name,'w', compression=zipfile.ZIP_DEFLATED) as fp: # percorriamo le cartelle in cerca di file for root, _, files in os.walk(temp_dir): # per ogni file che troviamo for file in files: # creiamo il percorso del file fpath = os.path.join(root,file) # prendiamo il percorso reale arcname = os.path.relpath(fpath,temp_dir) # aggiungiamo il file allo zip fp.write(fpath, arcname) except: print("Errore 4: impossibile ricomporre!") return try: # cancelliamo la cartella temporanea, usando shutil possiamo rimuovere tutta la cartella # anche se dentro ci sono altri file e cartelle, cosa che os.rmdir non permette di fare shutil.rmtree(temp_dir) except Exception as e: print(f"Errore 5: impossibile pulire! {e}") return print("File modificato con successo in: %s" % file_name) except: print("Errore 0: impossibile eseguire") if __name__ == "__main__": print("WordUnlocker v1.0.0") # eseguiamo il file main main() # questo ci serve solo per tenere aperto il prompt quanto basta per informare l'utente # alla pressione di INVIO il programma effettivamente terminerà scelta = input("Premi invio per chiudere...") |
Una volta scritto il codice in un file WordUnlocker.py
salviamo il tutto e procediamo a creare il file eseguibile.
Per creare l’eseguibile utilizziamo pyinstaller. Possiamo installarlo utilizzando il comando PIP:
1 |
pip install -U pyinstaller |
Dobbiamo preparare un file di versione che chiameremo file_version_info.txt
, che sarà strutturato nel modo seguente:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
VSVersionInfo( ffi=FixedFileInfo( filevers=(1, 0, 0, 0), prodvers=(1, 0, 0, 0), mask=0x3f, flags=0x0, OS=0x40004, fileType=0x1, subtype=0x0, date=(0, 0) ), kids=[ StringFileInfo( [ StringTable( u'040904B0', [StringStruct(u'CompanyName', u'Petar Karan'), StringStruct(u'FileDescription', u'MS Office Word Unlocker'), StringStruct(u'FileVersion', u'1.0.0.0 (20 febbraio 2025)'), StringStruct(u'InternalName', u'wordunlocker'), StringStruct(u'LegalCopyright', u'\xa9 Petar Karan. All rights reserved. https://petarkaran.it/'), StringStruct(u'OriginalFilename', u'WordUnlocker.exe'), StringStruct(u'ProductName', u'Word Unlocker'), StringStruct(u'ProductVersion', u'1.0.0.0')]) ]), VarFileInfo([VarStruct(u'Translation', [1033, 1200])]) ] ) |
Adesso possiamo compilare l’eseguibile con il seguente commando eseguito dal terminale sulla cartella del file di Python:
1 |
pyinstaller --clean --onefile .\WordUnlocker.py -i wordunlocker.png --version-file file_version_info.txt |
Fatto tutto questo non ci rimane che firmare digitalmente l’eseguibile. Per farlo abbiamo bisogno del comando signtool
disponibile in Windows SDK.
Affinché signtool
funzioni è necessario aggiungerlo al PATH di sistema, per farlo apriamo il Pannello di controllo > Sistema > Impostazioni avanzate > Variabili di ambiente e aggiungiamo a PATH il percorso di installazione corretto C:\Program Files (x86)\Windows Kits\10\App Certification Kit
Questo percorso potrebbe cambiare in base all’installazione del SDK fatta in precedenza.
Una volta che tutto è pronto spostiamoci nella cartella dove abbiamo il nostro eseguibile compilato ed eseguiamo:
1 |
signtool sign /a /t http://timestamp.digicert.com /fd SHA256 /v .\WordUnlocker.exe |
Fatto tutto questo avremo il nostro file correttamente firmato. E’ possibile scaricare il file eseguibile dal link seguente: