Laatst bijgewerkt: 16 sept., 2026

PPTX Reverse Engineering: Understanding PowerPoint Files Internally

Reverse Engineering PPTX Bestanden: Een gids voor ontwikkelaars

Moderne presentatiedeks drijven alles aan, van investeerderspitches tot interne kwartaalcijfers. Maar als je ooit programmatisch tekst moest extraheren, sjablonen tijdens runtime moest vervangen, geautomatiseerde dia-generatoren moest bouwen, of vertrouwelijke presentaties moest saneren, heb je waarschijnlijk al snel iets gerealiseerd: standaard high‑level presentatielibraries kunnen aanvoelen als een onvoorspelbare black box.

Wanneer bibliotheken zoals python-pptx, Apache POI of OpenXML SDK hun grenzen bereiken — of ongedocumenteerde lay-outbugs introduceren — is de enige uitweg erdoorheen. Je moet begrijpen wat een PowerPoint‑presentatie eigenlijk is op byte‑ en schema‑niveau.

In deze diepgaande duik zullen we het gordijn oplichten over het .pptx‑formaat, de interne structuur uitpakken, de relatiegrafiek volgen, de tekenhiërarchieën ontleden, en kijken naar praktische strategieën voor reverse engineering, inspectie en manipulatie van presentaties met ruwe code.

1. Wat is een .pptx-bestand echt?

In essentie is een .pptx-bestand geen propriëtair monolithisch binair bestand zoals het oude .ppt-formaat uit de jaren 90. Sinds Microsoft Office Open XML (ECMA-376 en ISO/IEC 29500) heeft geïntroduceerd, zijn moderne Office-documenten Open Packaging Conventions (OPC)-archieven.

In eenvoudige bewoordingen: een .pptx-bestand is simpelweg een zip-archief dat XML-documenten en media‑assets bevat, georganiseerd in een deterministische mapstructuur.

Je kunt dit in enkele seconden aantonen met standaard terminalgereedschap:

# Rename the extension and unpack it
cp presentation.pptx presentation.zip
unzip presentation.zip -d presentation_unpacked/
cd presentation_unpacked/
tree -L 2

De resulterende mapstructuur ziet er opmerkelijk consistent uit:

.
├── [Content_Types].xml
├── _rels/
│   └── .rels
├── docProps/
│   ├── app.xml
│   └── core.xml
└── ppt/
    ├── presentation.xml
    ├── _rels/
    ├── slides/
    ├── slideLayouts/
    ├── slideMasters/
    ├── theme/
    └── media/

Elk afzonderlijk visueel asset, elke overgang, slide‑master‑overerving, tekstvakcoördinaat en vectorafbeelding is gecodeerd in deze bestandshiërarchie.

2. Anatomie van het pakket: belangrijke subsystemen

Om presentaties effectief te reverse‑engineeren, moet je de verantwoordelijkheden van elk top‑level component begrijpen.

[Content_Types].xml

Dit is het ingangsmanifest voor de OPC-lezer. Het koppelt bestandsextensies en expliciete interne onderdeelnamen aan gestandaardiseerde MIME-/contenttypes. Als je een nieuwe dia maakt of een afbeelding toevoegt en deze niet declareert in [Content_Types].xml, zal PowerPoint de presentatie als corrupt aangeven en om herstel vragen.

Voorbeeldfragment:

<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
  <Default Extension="xml" ContentType="application/xml"/>
  <Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
  <Default Extension="png" ContentType="image/png"/>
  <Override PartName="/ppt/presentation.xml" 
            ContentType="application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml"/>
</Types>

De _rels/ Relatiegrafiek

Een van de belangrijkste concepten in OpenXML is indirectie via relaties. Onderdelen verwijzen zelden rechtstreeks naar ruwe bestands­paden. In plaats daarvan heeft een bestand (bijv. slide1.xml) een bijbehorend relatiebestand dat zich bevindt in een broederlijke _rels map (bijv. _rels/slide1.xml.rels).

Relaties definiëren:

  • Hyperlinks (r:id=\"rId2\", TargetMode="External")
  • Afbeeldingen en audiotracks opgeslagen in ppt/media/
  • Layout‑erfenis‑pointers (slideLayout1.xml)
  • Notitieslides, opmerkingen en ingesloten lettertypen

docProps/ (Metadata)

  • core.xml: Dublin Core‑metadata—auteur, titel, aanmaakdatum, wijzigings‑tijdstempel.
  • app.xml: Toepassingsspecifieke statistieken—PowerPoint‑versie, totaal aantal dia’s, aantal verborgen dia’s, woordtelling, namen van presentatiesjablonen.

ppt/ (De presentatiemotor)

Dit is waar de daadwerkelijke presentatie zich bevindt:

  • presentation.xml: De master‑ruggengraat. Het registreert dia‑ID’s, dia‑afmetingsdimensies, notitie‑masterreferenties en standaardlettertype‑instellingen.
  • slides/: De individuele dia’s (slide1.xml, slide2.xml, enz.).
  • slideLayouts/: Master‑structuur‑presets (Titel-dia, Twee‑kolom, Sectiekop).
  • slideMasters/: Globale stijlen, standaardpaletten, achtergrondvullingen en plaatsaanduidings‑overerving.
  • theme/: Kleurpaletten (accent 1 tot 6, donkere/licht variaties) en lettertype‑schema’s (hoofd‑/sublettertypen).
  • media/: Raw images (PNG, JPEG, SVG), audio, and video files.

3. Een dia ontleden: de PresentationML (p:) & DrawingML (a:) dialecten

Wanneer je ppt/slides/slide1.xml opent, kom je twee primaire XML‑naamruimtes tegen:

  1. PresentationML (p:): Governs structural presentation elements (slides, shape trees, canvas groups).
  2. DrawingML (a:): Governs typography, geometry, 2D coordinates, gradient fills, and vector rendering.

Hier is een vereenvoudigd voorbeeld van hoe een standaard tekstvorm eruitziet:

<p:sp>
  <!-- 1. Non-visual shape properties (Identifiers, names) -->
  <p:nvSpPr>
    <p:cNvPr id="4" name="Title Box 1"/>
    <p:cNvSpPr>
      <a:spLocks noGrp="1"/>
    </p:cNvSpPr>
    <p:nvPr>
      <p:ph type="title"/>
    </p:nvPr>
  </p:nvSpPr>

  <!-- 2. Visual shape properties (Position, size, geometry) -->
  <p:spPr>
    <a:xfrm>
      <a:off x="1524000" y="1143000"/>
      <a:ext cx="9144000" cy="1828800"/>
    </a:xfrm>
    <a:prstGeom prst="rect">
      <a:avLst/>
    </a:prstGeom>
    <a:solidFill>
      <a:schemeClr val="accent1"/>
    </a:solidFill>
  </p:spPr>

  <!-- 3. Text Body (Paragraphs, runs, styling) -->
  <p:txBody>
    <a:bodyPr rtlCol="0" anchor="ctr"/>
    <a:lstStyle/>
    <a:p>
      <a:r>
        <a:rPr lang="en-US" sz="3200" b="1"/>
        <a:t>Mission Critical Architecture</a:t>
      </a:r>
    </a:p>
  </p:txBody>
</p:sp>

Cruciale meeteenheden: EMU’s en honderdsten van een punt

Let op de coördinatennummers in <a:xfrm>:

  • x="1524000"
  • cx="9144000"

Dit zijn English Metric Units (EMUs).

  • $1 \text{ inch} = 914,400 \text{ EMUs}$
  • $1 \text{ cm} = 360,000 \text{ EMUs}$
  • $1 \text{ pt} = 12,700 \text{ EMUs}$

EMU’s stellen gehele getallen in staat exacte breuken van zowel inches als millimeters weer te geven zonder afrondingsfouten van floating‑point getallen op verschillende hardware‑architecturen.

Let ook op de lettergrootte:

  • sz="3200" means 32.00 pt. Font sizes in DrawingML are measured in hundredths of a point.

4. De overervingsketen: waarom vormen onzichtbare stijlen overerven

Een van de meest voorkomende valkuilen bij het reverse engineeren van PPTX‑bestanden is ervan uitgaan dat de visuele styling van een vorm volledig is gedeclareerd in zijn eigen slideX.xml.

In werkelijkheid vertrouwt OpenXML op een strikt 4‑laag cascaderend overervingsmodel:

[Theme: ppt/theme/theme1.xml]
[Slide Master: ppt/slideMasters/slideMaster1.xml]
[Slide Layout: ppt/slideLayouts/slideLayout1.xml]
[Slide: ppt/slides/slide1.xml]

Als een tekstvak op slide1.xml bevat:

<a:p>
  <a:r>
    <a:t>Revenue Projections</a:t>
  </a:r>
</a:p>

Er is geen lettertypefamilie, geen expliciete kleur en geen grootte gedeclareerd in de run (<a:r>). Om te achterhalen hoe PowerPoint deze tekst rendert, moet uw parser:

  1. Identify the placeholder type (<p:ph type="title"/>).
  2. Read the layout referenced in slide1.xml.rels.
  3. Check if slideLayout1.xml provides styling overrides for that placeholder.
  4. Fall back to slideMaster1.xml for default title text body styles.
  5. Trace color tokens like accent1 or tx1 into theme1.xml to find the hexadecimal color code.

Als u deze overervingsgrafiek overslaat, zal uw parser stijlen verkeerd lezen, waardoor lettertypen, lettergroottes en lay-outankers ontbreken.

5. Praktische Reverse Engineering-werkwijze

Wanneer u moet onderzoeken hoe een bepaalde PowerPoint-functie onder de motorkap werkt (bijv. morph-transities, complexe tabellen, vectorpaden), volg dan deze empirische aanpak:

Stap 1: Maak een minimale “Diff Pair”

  1. Open PowerPoint and create a blank slide.
  2. Save it as before.pptx.
  3. Apply the exact single change you wish to reverse engineer (e.g., add a drop shadow to a circle, change a bullet style, insert an embedded video).
  4. Save it as after.pptx.

Stap 2: Pak beide archieven uit

unzip before.pptx -d before/
unzip after.pptx -d after/

Stap 3: Formatteer de XML

Ruwe XML in Office-archieven wordt meestal ontdaan van inspringing en regeleinde-tekens. Formatteer de bestanden vóór het vergelijken:

find before/ after/ -name "*.xml" -exec xmllint --format {} --output {} \;

Stap 4: Voer een Unified Diff uit

diff -uNr before/ after/ > changes.patch

Het bekijken van changes.patch onthult de exacte tagnaam, namespace-attribuut en containerhiërarchie die PowerPoint heeft geïntroduceerd. Dit is de snelste manier om ongedocumenteerde of obscure schema-eigenschappen te ontdekken zonder door duizenden pagina’s ECMA-376-documentatie te graven.

6. Een aangepaste micro-engine bouwen: uitpakken, wijzigen, opnieuw inpakken

Soms wil je geen zware enterprise-afhankelijkheid zoals Apache POI of de Microsoft OpenXML SDK—vooral niet in lichtgewicht serverless-omgevingen (AWS Lambda, Cloudflare Workers, edge-nodes).

Hier is een zelfstandige Python-patroon dat laat zien hoe je veilig een in-memory PPTX kunt uitpakken, aangepaste gegevens kunt injecteren met standaardbibliotheek-tools, en het vervolgens opnieuw kunt verpakken:

import zipfile
import io
import xml.etree.ElementTree as ET

def modify_slide_title(input_pptx_bytes: bytes, new_title: str) -> bytes:
    input_zip = zipfile.ZipFile(io.BytesIO(input_pptx_bytes))
    output_buffer = io.BytesIO()
    
    with zipfile.ZipFile(output_buffer, "w", zipfile.ZIP_DEFLATED) as output_zip:
        for item in input_zip.infolist():
            content = input_zip.read(item.filename)
            
            # Target slide 1
            if item.filename == "ppt/slides/slide1.xml":
                namespaces = {
                    'p': 'http://schemas.openxmlformats.org/presentationml/2006/main',
                    'a': 'http://schemas.openxmlformats.org/drawingml/2006/main'
                }
                
                # Register namespaces to preserve prefixes
                for prefix, uri in namespaces.items():
                    ET.register_namespace(prefix, uri)
                    
                root = ET.fromstring(content)
                
                # Find title placeholder text run
                for title_run in root.findall(".//p:sp[p:nvSpPr/p:nvPr/p:ph[@type='title']]//a:t", namespaces):
                    title_run.text = new_title
                    break
                
                content = ET.tostring(root, encoding="utf-8", xml_declaration=True)
            
            output_zip.writestr(item, content)
            
    return output_buffer.getvalue()

Belangrijke valkuilen bij het wijzigen van bestanden op byte-niveau:

  1. Namespace Preservation: XML parsers often rewrite prefixes (xmlns:p might become xmlns:ns0). While valid XML, PowerPoint’s strict internal schema validation occasionally rejects non-standard prefix aliases. Register namespaces explicitly.
  2. ZIP Compression Methods: Ensure you write files back using standard deflate compression (zipfile.ZIP_DEFLATED).
  3. Stream Flushing: Always check that your zip buffer closes and flushes completely before sending bytes downstream.
  4. Preserve Relationships: If you remove a slide, you must also remove its entry from ppt/presentation.xml, delete its relationship in ppt/_rels/presentation.xml.rels, and scrub its content type from [Content_Types].xml.

7. Prestaties- en beveiligingsoverwegingen

Reverse engineering van PPTX-bestanden gaat niet alleen over het bewerken van dia’s; het gaat ook over het auditen van wat je systemen binnenkomt.

Beveiliging: Miljard Lachjes & XXE

Omdat PPTX-bestanden XML parseren, is elke server-side pipeline die door gebruikers ingediende presentaties verwerkt kwetsbaar voor:

  • XML External Entity (XXE) Injection: Malicious XML attempting to access /etc/passwd or query internal cloud metadata endpoints (http://169.254.169.254/).
  • Entity Expansion Attacks (Billion Laughs): Exponential entity loops exhausting system RAM.

Mitigatie: Schakel altijd resolve_entities, load_dtd en externe netwerkresolutie uit in uw XML-parser (bijv. met defusedxml in Python).

Beveiliging: Macro Payloads en Verborgen Streams

Inspecteer bestanden op .pptm-inhoud die zich voordoet als .pptx-extensies. Let op ppt/vbaProject.bin, dat gecompileerde Visual Basic-code bevat. In standaard .pptx-bestanden is VBA-code verboden; het vinden van binaire payload-referenties in relaties moet onmiddellijk quarantaine‑signalen activeren.

Conclusie

Reverse engineering van .pptx-bestanden ontrafelt presentatiesoftware. Zodra u beseft dat PowerPoint‑bestanden simpelweg gestructureerde zip‑pakketten zijn gevuld met coördinaten, schemareferenties en XML‑relatie‑bomen, bent u niet langer beperkt door bestaande derden‑abstracties.

Of u nu de doorvoersnelheid van slide‑generatie optimaliseert, aangepaste geautomatiseerde sanitizers schrijft, of renderingsfouten oplost, direct naar de onderliggende OpenXML‑architectuur kijken geeft u volledige controle over de presentatiestroom.

Veelgestelde vragen (FAQ)

**Q: Kunt u een .pptx converteren naar een standaard map en bestanden rechtstreeks in een IDE bewerken?

A1: Ja, u kunt het archief uitpakken, de XML bewerken in een editor zoals VS Code, en de mapinhoud opnieuw zippen om het weer te openen in PowerPoint.

**Q: Waarom zegt PowerPoint dat mijn handmatig aangepaste PPTX‑bestand reparatie nodig heeft?

A2: Dit gebeurt meestal als je misvormde XML hebt geïntroduceerd, een nieuw asset hebt weggelaten uit [Content_Types].xml, of een zwevende verwijzing hebt achtergelaten in een bijbehorend .rels‑bestand.

**Q: Welke meeteenheid gebruikt PowerPoint voor de positie en marges van vormen?

A3: PowerPoint gebruikt Engelse metrische eenheden (EMU’s), waarbij 1 inch gelijk is aan 914.400 EMU’s en 1 punt gelijk is aan 12.700 EMU’s.

**Q: Hoe kan ik alle afbeeldingen uit een presentatie programmeermatig extraheren zonder externe bibliotheken?

A4: Open eenvoudig het .pptx‑bestand met een standaard zip‑hulpmiddel en extraheer alle binaire bestanden die zich bevinden in de map ppt/media/.

**Q: Is het veilig om door gebruikers geüploade PPTX‑bestanden te parseren met standaard XML‑parsers?

A5: Nee, je moet je parser versterken of veilige wrappers gebruiken zoals defusedxml om XML External Entity (XXE)‑ en zip‑bom‑aanvallen te blokkeren.

Zie ook