Linux cracking: l'approccio live (acrobat reader)
(Linux reverse engineering avanzato: imported functions)

by SiuL+Hacky
(12 November 1997)
(Tradotto e riadattato da Quequero)

Courtesy of fravia's page of reverse engineering

Well, another VERY remarkable essay, that I am proud to present. SiuL+Hacky tackles here once more UNCOVERED ground, and teaches all of you more elements of Linux reverse engineering... you may want to check his good first essay about Linux reverse engineering... a bad omen of these commercial times... even Linux is getting more and more soiled by commercial overbloated applications :-(




LINUX CRACKING: L'APPROCCIO LIVE. ACROBAT READER.

I.Introduzione
---------------

Nel mio primo essay su linux avete capito come fare un porting delle tecniche di windows al mondo di linux. Era stato pirncipalmente dedicato al dead approach perch� � estremamente potente per alcuni tipi di programmi. Ma tristemente, come vedrai, enormi e sovraccaricati programmi stanno entrando nel mondo di linux e se vuoi reversare reversare qualche target hai bisogno  di un po' di debugging (a meno che tu non sia un "signore" del cracking).
 
Con questo essay prover� ad introdurvi nell'ambiente grafico di linux, XWindows (nessun genere di ambiente porno eh!). Potrebbe sembrare come Windoze ma internamente � MOLTO differente per alcuni aspetti. La differenza principale � che usa l'onnipresente schema client-server. Ad ogni modo, non ho n� il tempo ne la conoscenza per insegnarvi in modo esauriente come lavora, ma vi mostrer� il punto di partenza per il cracking della appplicazioni sotto X. In linux potete usare diversi server X, il pi� popolare � XFree86.

Il proposito di +ORC per il cracking dei tools acrobat-pdf � una buona opportunit� per impratichirsi di questi metodi. Vi ho detto, come dissi a lui, che penso che non � giusto perder tempo scrivendo un convertitore da testo a pdf, perch� gi� esiste e ci sono ancora molti (ed importanti) schemi di protezione non ancora crackati. Cos� ecco che sto crackando Adobe Acrobat (si, � disponibile per linux, bench� applichi le stesse restrizioni della versione per windoze) con due obiettivi principali:
 
- Voglio vedere sempre il Menu e la Barra degli strumenti.
- Non voglio copiare le restrizioni del testo e cos� via.
 
L'ho preso da un magazine Spagnolo, ma suppongo che sia liberamente distribuibile al sito della Acrobat. Vorrei vedere altre persone reversare il formato pdf.

II. ToolX del Mestiere.
------------------------

Ovviamente qui troverai alcuni tools specifici per X. Molti dei tool li ho nominati nel primo essay applicandoli per X-RE. Molto utile, sarebbe avere il DASM, perch� nonostante andremo ad usare l'approccio live, il listato assembler resta sempre di inestimabile valore. Vi ripeto che il listato ci dar� importanti tracce da seguire, ma per un uso migliore leggi le pagine del manuale.

* xwininfo     -----------------------------------------------------------------
Questa utility ti da tutte le informazioni di una specifica finestra. Per default ti chiede di clickare sulla finestra dalla quale vuoi raccogliere informazioni. State molto attenti e non pensate alla "finestra" come fareste per WindoTonno. When clickiamo su una finestra con il mouse, stiamo clickando sulla finestra "fisica", sulla finestra super-genitore (chiamata finestra di root). Ogni finestra (i bottoni per esempio sono finestre figlie) ha un identificatore. Ecco alcuni utili parametri:
 
- tree: Mostra tutte le finestre (root, parent e child) in maniera ricorsiva. Mostra l'identificatore (conosciuto come Drawables), la dimensione e la posizione.
Ecco un esempio preso per l'Acrobat Reader:
 
xwininfo: Window id: 0x2800128 "Acrobat Reader"
Root window id: 0x26 (la finestra root) (non ha nome)
   Parent window id: 0x8001ad (non ha nome)
        1 child:
             0x2800129 (non ha nome): ()  272x367+0+0  +527+121
            
             ... alcune altre finestre ...
            
0x2800148 (has no name): ()  24x24+3+3  +530+183; << bottone della barra degli strumenti
0x2800147 (has no name): ()  24x24+27+3  +554+183;<< bottone della barra degli strumenti
0x2800146 (has no name): ()  24x24+51+3  +578+183;<< bottone della barra degli strumenti
0x2800145 (has no name): ()  6x24+75+3 +602+183
0x2800144 (has no name): ()  24x24+81+3  +608+183;<< bottone della barra degli strumenti
0x2800143 (has no name): ()  24x24+105+3  +632+183;<< bottone della barra degli strumenti
0x2800142 (has no name): ()  24x24+129+3 +656+183; << e ancora........
0x2800141 (has no name): ()  6x24+153+3  +680+183
0x2800140 (has no name): ()  24x24+159+3  +686+183
0x280013f (has no name): ()  24x24+183+3 +710+183
0x280013e (has no name): ()  24x24+207+3  +734+183
0x280013d (has no name): ()  24x24+231+3  +758+183
0x280013c (has no name): ()  6x24+255+3 +782+183
0x280013b (has no name): ()  24x24+3+30  +530+210
0x280013a (has no name): ()  24x24+27+30  +554+210
0x2800139 (has no name): ()  6x24+51+30 +578+210
0x2800138 (has no name): ()  24x24+57+30  +584+210
0x2800137 (has no name): ()  24x24+81+30  +608+210
0x2800136 (has no name): ()  24x24+105+30 +632+210
0x2800135 (has no name): ()  6x24+129+30  +656+210
0x2800134 (has no name): ()  24x24+135+30  +662+210
0x2800133 (has no name): ()  6x24+159+30+68 6+210            

            ... alcune altre finestre ...
           
Ovviamente, il primo numero esadecimale � l'identificatore della finestra, che sar� particolarmente utile per altri (o anche questo) tools.
 
-id: con questa opzione non abbiamo bisogno di clickare su una specifica finestra ma possiamo ottenere informazioni per ogni particolare finestra.
 
-all: mostra tutte le opzioni disponibili

* xev  ----------------------------------------------------------------------

Questa utility riporta tutti gli eventi coinvolti con qualche finestra. Parametri:
 
-id: se non gli passiamo un identificatore, xev ci mostrer� una finestra di test nella quale possiamo testare il mouse, la tastiera o qualunque altro tipo di evento.

In alcuni casi possiamo usare questo programma per confrontare gli identificatori. Per esempio se facciamo:
xev -id 0x2800148
xev parte ma noi non sappiamo a quale finestra (figlia) appartiene questo identificatore! Appena muoviamo il mouse sopra le finestre otterremo un messaggio di notifica quando passeremo sopra la finestra che possiede quell'identificatore (MotionNotify).
 
* xxgdb  --------------------------------------------------------------------

� la versione per Xwindows di gdb. L'unica miglioria � la ButtonBar con alcuni utili comandi. Vedremo alcuni comandi durante il debugging dell'acrobat reader. Spero, in un essay futuro, di mostrarvi alcuni tools un po' pi� amichevoli, ma per ora questo � il pi� diffuso e stabile tool che conosco.

* XWindows API Reference  ----------------------------------------------------

Lavorando con i programmi per WinCesso, � diventato importante conoscere la sintassi di alcune API "regolari" come MessageBox, GetDlgItemText e cos� via. Bene, lo stesso dobbiamo fare con XWindows. Possiamo prendere tutte le definizioni delle chiamate nei file .h che si trovano generalmente nella directiry /usr/X11R6/include/X11. Ho trovato particolarmente interessanti alcuni documenti disponibili al sito di xfree86 (ftp.xfree86.org) o, ancora meglio ne potete trovare cercandoli in un mirror di ftpsearch:
 
xlib.PS.Z   (971 Kb)
Questo � un documento PostScript di 400 pagine dove troverete molte informazioni. � infatti difficile trovare dei libri sulla programmazione sotto XWindows, cos� se conosci qualche tutorial o qualche documento per i nostri scopi, mandali alla +HCU per essere inseriti nella prossima versione dell'essay (ed anche alla UIC of coz :) NdQuequero

* Convertitori Text-to-pdf -----------------------------------------------------

This does exist (there's a good document about it at fravia's pdf project
page), and you'll need it for testing Acrobat Reader. It is necessary to
get a fully unprotected document and test it against protected ones.
I converted text to pdf passing through a PostScript intermediate stage.

mpage: this program converts text to PostScript easily.

GhostScript: this is not only a PostScript viewer, but it has a built-in
PostScript to pdf converter. If you don't want to go into GhostScript
internals (a hell for me), use pstoedit, for example, to manage this task.


III. Reverse Engineering Acrobat Reader.
-----------------------------------------

Let's suppose Acrobat is the base directory where it is installed. You'll
find easily that it is invoked with "acrobat", a file in Acrobat/bin
directory with just 8467 bytes. Impossible for this huge monster (you'll
see). It is just a Shell Script that calls the huge monster
Acrobat/Reader/intellinux/acroread, 2.511.477 bytes full of nops (believe
me, I had a look). Ok, dasm it and the monster will be a ghastly hideous
creature of 38.625.635 bytes and almost 1 million lines.
I do recommend you not to edit it, and use the "less" viewer (with the
searching capabilities you need).

Have a look at the symbol table (with the name of the functions, inside and
outside the program. Very nice gift from the Adobe's guys), and what should
be a reverser bliss will be a cracker curse: MORE THAN 16000 functions (many
of them repeated) with names as amazing as :

DefaultAnnotHandlerNotifyAnnotAddedToSelection
_XmAllowAcceleratedInsensitiveUnmanagedMenuItems
_XmVirtKeys_siemensWx200FallbackBindingString
_XmVirtKeys_dblclkFallbackBindingString

and bla, bla, bla.

I started writing down some name that could be interesting, then I started
skimming through and finally I scrolled them away. I am going to show you the
functions I saw suspicious. At the end of the essay you'll realise it could
have been very easy with a little Zen cracking, but I was not completely
lucky (and for once I didn't want to be lucky) and I used the methodical
approach that always saves you when your Zen is broken. Look at the
following names:

UnixMenubarInitialize
UnixMenuRemoved
UnixPageViewCancelToolButtons
UnixToolbarHide
AVCrypt
DecryptPerms0
DecryptPerms1
UnixDlgSecurityGetValues
UnixCryptGetPasswd

I had a look at the code of these functions, and thne I tested them with
the debugger, setting breakpoints and watching returned values. I got
nothing, so I just searched once more, this time for the string "Hide".
I wrote down these functions:

AVToolBarHide
AVMenuBarHide
UnixMenubarWidgetHide

Looking the code of the last one I was lucky, help yourself:

Referenced from jump/call at 08062c64 ;

08048500 <UnixMenubarWidgetHide>    pushl  %ebp
08048501 <UnixMenubarWidgetHide+1>  movl   %esp,%ebp
08048503 <UnixMenubarWidgetHide+3>  subl   $0x10,%esp
08048506 <UnixMenubarWidgetHide+6>  pushl  %ebx
08048507 <UnixMenubarWidgetHide+7>  movl   0x10(%ebp),%ebx
0804850a <UnixMenubarWidgetHide+a>  movb   %bl,0xffffffff(%ebp)
0804850d <UnixMenubarWidgetHide+d>  movl   0x8(%ebp),%eax
08048510 <UnixMenubarWidgetHide+10> pushl  %eax

Reference to function : AVMenubarGetServerData

08048511 <UnixMenubarWidgetHide+11> call   08089090  << I always thought that        
                                                     << this function could be
                                                     << important... I was wrong
....  code and code ....

08048590 <UnixMenubarWidgetHide+90> movl   0xfffffff8(%ebp),%eax
08048593 <UnixMenubarWidgetHide+93> cmpb   $0x0,0x4(%eax)         << compare something
08048597 <UnixMenubarWidgetHide+97> jne    080485bc               << if not zero return and do nothing
08048599 <UnixMenubarWidgetHide+99> cmpb   $0x0,0xffffffff(%ebp) << if local var = 0 some SHOWING
0804859d <UnixMenubarWidgetHide+9d> je     080485b0               << else some HIDING
0804859f <UnixMenubarWidgetHide+9f> movl   0xc(%ebp),%eax
080485a2 <UnixMenubarWidgetHide+a2> pushl  %eax

Reference to function : UnixMenubarWidgetHideInternal

080485a3 <UnixMenubarWidgetHide+a3> call   08048480
080485a8 <UnixMenubarWidgetHide+a8> addl   $0x4,%esp
080485ab <UnixMenubarWidgetHide+ab> jmp    080485bc
080485ad <UnixMenubarWidgetHide+ad> nop   
080485ae <UnixMenubarWidgetHide+ae> nop   
080485af <UnixMenubarWidgetHide+af> nop   

Referenced from jump/call at 0804859d ;

080485b0 <UnixMenubarWidgetHide+b0> movl   0xc(%ebp),%eax
080485b3 <UnixMenubarWidgetHide+b3> pushl  %eax

Reference to function : UnixMenubarWidgetShowInternal

080485b4 <UnixMenubarWidgetHide+b4> call   080484d0
080485b9 <UnixMenubarWidgetHide+b9> addl   $0x4,%esp

Referenced from jump/call at 08048597 ; 080485ab ;

080485bc <UnixMenubarWidgetHide+bc> movl   0xffffffec(%ebp),%ebx
080485bf <UnixMenubarWidgetHide+bf> movl   %ebp,%esp
080485c1 <UnixMenubarWidgetHide+c1> popl   %ebp
080485c2 <UnixMenubarWidgetHide+c2> ret

What happen with that important variable ? If you look at instruction
804850, it is copied from one of the parameters of the function. With some
basic parameter theory (if not, read fravia's+ good filemon series)
you know that :

1st parameter is located at [bp+0x8]
2nd parameter is located at [bp+0xc]
3rd parameter is located at [bp+0x10]

(of course, if we consider one parameter = one word length). Ok, let's have
a look at the caller (this function is called from 08062c64). Pay attention
to the parameters please:


(... some lines not important ...)
Reference to function : AVDocGetKioskBool

08062c24 <UnixDocViewUpdateVisibility+44> call   0807d290      <<<< the function returns 1 or 0 into  eax
08062c29 <UnixDocViewUpdateVisibility+49> addl   $0x8,%esp
08062c2c <UnixDocViewUpdateVisibility+4c> movl   %eax,%edx
08062c2e <UnixDocViewUpdateVisibility+4e> movsbl %dl,%eax      << the returned value is in eax again
08062c31 <UnixDocViewUpdateVisibility+51> jmp    08062c42      << look at these nops,
08062c33 <UnixDocViewUpdateVisibility+53> nop                  << nop                  << kind of mega-pentium alignment or room for patching?
08062c33 <UnixDocViewUpdateVisibility+53> nop   
08062c34 <UnixDocViewUpdateVisibility+54> nop   
08062c35 <UnixDocViewUpdateVisibility+55> nop   
08062c36 <UnixDocViewUpdateVisibility+56> nop   
08062c37 <UnixDocViewUpdateVisibility+57> nop   
08062c38 <UnixDocViewUpdateVisibility+58> nop   
08062c39 <UnixDocViewUpdateVisibility+59> nop   
08062c3a <UnixDocViewUpdateVisibility+5a> nop   
08062c3b <UnixDocViewUpdateVisibility+5b> nop
08062c3c <UnixDocViewUpdateVisibility+5c> nop   
08062c3d <UnixDocViewUpdateVisibility+5d> nop   
08062c3e <UnixDocViewUpdateVisibility+5e> nop   
08062c3f <UnixDocViewUpdateVisibility+5f> nop   

Referenced from jump/call at 08062c0b ;

08062c40 <UnixDocViewUpdateVisibility+60> xorl   %eax,%eax

Referenced from jump/call at 08062c31 ;           << we are JUMPING TO HERE !!!!!!!!!!
                                                 << more nooping, if +orc would see this :-(
08062c42 <UnixDocViewUpdateVisibility+62> jmp    08062c55
... (10 more nops)...   
08062c4f <UnixDocViewUpdateVisibility+6f> nop   

Referenced from jump/call at 08062c05 ;
08062c50 <UnixDocViewUpdateVisibility+70> movl   $0x1,%eax

Referenced from jump/call at 08062c42 ;        << we are JUMPING HERE!!!
08062c55 <UnixDocViewUpdateVisibility+75> pushl  %eax     <<saved 3rd parameter
                                                            << remember eax= returned value
08062c56 <UnixDocViewUpdateVisibility+76> movl   0x8(%ebp),%eax
08062c59 <UnixDocViewUpdateVisibility+79> movl   0x10(%eax),%edx
08062c5c <UnixDocViewUpdateVisibility+7c> pushl  %edx     <<saved 2nd parameter
08062c5d <UnixDocViewUpdateVisibility+7d> movl   0x8(%ebp),%eax
08062c60 <UnixDocViewUpdateVisibility+80> movl   0xc(%eax),%edx
08062c63 <UnixDocViewUpdateVisibility+83> pushl  %edx      <<saved 1st parameter
Reference to function : UnixMenubarWidgetHide
08062c64 <UnixDocViewUpdateVisibility+84> call   08048500

It is pretty clear, if the function AVDocGetKioskBool returns 0 we are GOOD
GUYS. Let's make this function return always 0. You could patch it the old
way, but now we are going to learn some xxgdb capabilities:

1) Fire acrobat reader of course. Look its Process Identifier (PID)
2) Fire xxgdb
3) Execute command "file (your path)/Acrobat/Reader/intellinux/bin/acroread,
   that will load the symbols. Don't worry if xxgdb complains about
   something.
4) Now we are gonna "join" the debugger to a running process. For this
   reason, execute the command "attach PID", where PID IS A NUMBER, the
   process identifier of acroread (use ps for checking)
5) You'll land probably in the middle of a system call, it is OK.
6) Run "cont" command to continue execution.
7) When you want to break, press Control-C.

This is the important code of AVDocGetKioskBool:

0807d3d2 movl   %edx,%eax
0807d3d4 jmp    0807d3e0

(... another dozen of nops ...)

Referenced from jump/call at 0807d2bb ; 0807d3d4 ;

0807d3e0 leal   0xfffffff0(%ebp),%esp
0807d3e3 popl   %ebx
0807d3e4 popl   %esi
0807d3e5 movl   %ebp,%esp
0807d3e7 popl   %ebp
0807d3e8 ret 

The instruction at 807d3e0 is always reached from 807d3d4, the other
reference is just a "fast return" when gets an error. This will do the
crack while working with the debugger. You'll see that this is a really
powerful debugger, with features supported by softice not a long time
ago.
(xxgdb) is the prompt:

(xxgdb) br *0x0807d3d2 if $edx==1
Breakpoint 1 at 0x0807d3d2
(xxgdb) commands
>silent
>set $edx=0
>cont
>end
(xxgdb)

Really powerful eh ? If you want to know the breakpoint status run
"info br".
Well if you now execute "cont", you'll always have menu, toolbars and
so on visible, even if ghiribizo or whoever doesn't want :-).
I think that the above code is pretty easy to understand.

And now what's up with the second part ? Specifically: 'copying text'.
As I told you, I was not so lucky. Firstly I tried to play the same
game, try and error, feel a little, look at suspicious functions... and 
I got lost in the mare magnum of silly functions. I navigated over tons
of functions, and I was close to solve it, and you'll see that names are
indeed again pretty obvious, but until you grasp this target as a whole
you don't really realise what is going on.
I was confused always by X buffering, coz graphic events are not
implemented immediately, and 5 or 6 buttons from the toolbar
were painted all together at once.

After one day of useless testing I decided to act methodically, and after
starting from one obvious point, reach the code I was seeking. I just wanted
to locate where the button was disabled and then, from there, trace back:
Reverse Engineering as we have all learned it.
I studied some Xwindows API, and I got information about events.
For fixing the problem of  graphic buffered events I read the main page
of X server:

"All  applications written with the X Toolkit Intrinsics automatically
accept the following options:
  [...]
-synchronous
       This  option indicates that requests to the X server should
       be sent synchronously, instead of asynchronously.  
       Since Xlib normally buffers requests to the
       server, errors do not  necessarily  get   reported immediately
       after they occur.  This option turns off the buffering so that
       the application can be debugged.  It should never be used
       with a working program."
      
So from now on run: acrobat -synchronous
      
Perfect, now I had to find the X call. I didn't find the function I was
looking for, so I decided to start from one solid function and then
test the calling tree until the target function was found.
This seemed to be a very solid function:

AVAppSelectLegalTool

How do I get this name ? Well, as I told you I looked for names about
ToolBar, one of the most suspicious is UnixToolBarUpdateButtonStates,
which is called from AVAppSelectLegalTool.

One tip that will be useful in X debugging: I found a bug (I don't know if it
is a gdb problem or X server problem or window manager prob) when you break the
program and is busy with certain graphic interface task, focus cannot be
successfully returned to xxgdb, and all X applications freezes. In that case you
just need to open a new virtual console and kill xxgdb process (and then
restart it). If you want to prevent this situation, you must break the program
in some previous "safe" instruction (probably inside another function) with no
focus-back problem. Then xxgdb will get the focus and when you restart execution
("cont" command) focus will not be back to acrobat (it will be in background)
and you can safely break inside that "dangerous code". I am telling you this
right now because the beginning of this function will be ok as a safe breakpoint
in our goal of finding out who shades and disables the text button.

Now here's an schematic of AVAppSelectLegalTool:

0x806ccc0 AVAppSelectLegalTool

  AVAppGetActiveDoc         (1 parameter)
  AvAppGetActiveTool
  ToolIsEnabled              (7 parameters)
  AVAppGetDefaultTool
  AVAppSetActiveTool        (7 parameters)
  AVAppGetToolBar
  AVToolBarUpdateButtonStates
 
0x806cd19 end

Very cool names but nothing else. After some hours the only fact is that
buttons were updated (BTW for the first time if no protection, and if
protected, they were just "rewritten"; in that case, "clean" the window
covering it, or changing the desktop) in AVToolBarUpdateButtonStates. For
this searching task temporary breakpoints are really useful to use, you
know, use and throw away breakpoints.
For example writing this will do it:

(xxgdb)br *AVAppSelectLegalTool
(xxgdb)cont
  ... do something like load some pdf evil file. It will break
 
(xxgdb)tbr *AvAppGetActiveTool
(xxgdb)cont

  ... a temp. breakpoint is set. Now you can see what happen while
  ... AVAppGetActiveDoc is being executed. It breaks at AvAppGetActiveTool
 
(xxgdb)tbr *ToolIsEnabled
(xxgdb)cont

... and so on. You dig it ?

Ok, let's go down to AVToolBarUpdateButtonStates. Here is the good stuff:

  080bbf7 AVToolBarUpdateButtonStates
  080bbfa0 call   *%ebx
  080bbfb3 call   08038ed8 <_init+2168>
 
or if you want

  080bbf7 AVToolBarUpdateButtonStates
  080bbfa0 call UnixEnumChildWidget
  080bbfb3 call ASListEnum
 
Be sure that the first function makes what we are looking for. If you watch
the listing of that function it just makes an indirect call to a VERY
important function named SetStateEnumProc. Here is the code commented:

0805ecf0  pushl  %ebp
0805ecf1  movl   %esp,%ebp
0805ecf3  subl   $0x8,%esp
0805ecf6  pushl  %ebx
0805ecf7  movl   0x8(%ebp),%eax
0805ecfa  movl   0x4(%eax),%edx
0805ecfd  movb   0x14(%edx),%al
0805ed00  andb   $0x8,%al
0805ed02  testb  %al,%al
0805ed04  jne    0805ed10
0805ed06  jmp    0805ed70
0805ed08  nop   
...   
0805ed0f  nop   

Referenced from jump/call at 0805ed04 ;

0805ed10  movl   0x8(%ebp),%eax
0805ed13  movl   %eax,0xfffffff8(%ebp)
0805ed16  movl   $0x0,0xfffffffc(%ebp)

Referenced from jump/call at 0805ed63 ;    <LOOPING HERE

0805ed1d  movl   0xfffffff8(%ebp),%eax:
0805ed20  movl   0xfffffffc(%ebp),%edx;   <<WE CONTINUE HERE !!
0805ed30  movl   0x10(%ebp),%eax; << LOAD SOMETHING
0805ed33  pushl  %eax;                     << SAVE IT
0805ed34  movl   0xfffffff8(%ebp),%eax; << LOAD SOMETHING
0805ed37  movl   0xfffffffc(%ebp),%edx;     << LOAD INDEX
0805ed3a  movl   %edx,%ecx;       << MOVING INDEX TO ECX
0805ed3c  leal   0x0(,%ecx,4),%edx; << CREATE POINTER IN EDX
0805ed43  movl   0x74(%eax),%eax; << LOAD SECOND INDEX
0805ed46  movl   (%eax,%edx,1),%edx;<< DOUBLE INDEXING HERE
0805ed49  pushl  %edx;           <SAVE VALUE
0805ed4a  movl   0xc(%ebp),%ebx; << LOAD FUNCTION ADDRESS
0805ed4d  call   *%ebx;           <<CALL SetStateEnumProc
0805ed4f  addl   $0x8,%esp,           << RETURNS IN EAX
0805ed52  movb   %al,%al
0805ed54  testb  %al,%al
0805ed56  jne    0805ed60;  << JUMPING BELOW IF RETURNED != 0
0805ed58  jmp    0805ed70;  << ELSE JUMP TO END FUNCTION
0805ed5a  nop   
...   
0805ed5c  nop   

Referenced from jump/call at 0805ed56 ;

0805ed60  incl   0xfffffffc(%ebp); << INCREMENT POINTER
0805ed63  jmp    0805ed1d;    << LOOP AWAY


One call to SetStateEnumProc for each button. For the first time, we got
some 'action' (we still don't know which) for a particular button. I don't
like essays that carry a too heavy listing, so here is the schematic of the
function and I shall give you afterwards the needed details:

0805aec0 SetStateEnumProc
  call XtVaGetValues
  call AVToolButtonIsSeparator
  call AVToolButtonIsEnabled
  call XtSetSensitive
  call XtIsSubclass   
  call AVToolButtonIsMarked
  call XacroToolButtonSetMarked
end

XtSetSensitive IS OUR FUNCTION. It enables or disables buttons. If we look
for in the API:

extern void XtSetSensitive(
    Widget               /* widget */,
    _XtBoolean          /* sensitive */
);
       
Hence we are interested in the second parameter, that is pushed in the first
place. Some assembler details of the function:

Reference to function : AVToolButtonIsEnabled

0805aef4  call   080bb3a0; << returns 1 or 0 into eax
0805aef9  addl   $0x4,%esp
0805aefc  movl   %eax,%eax
0805aefe  movzwl %ax,%edx; << returned value in edx now
0805af01  pushl  %edx;  << here is our parameter ****
0805af02  movl   0x8(%ebp),%eax
0805af05  pushl  %eax

Reference to function : XtSetSensitive

0805af06<SetStateEnumProc+46> call   08037dc8 <_init+1058>

Now you understand what I told you about zen and luck. If I would listen to
that function ... (actually I had played with it before, but acrobat was in
its asynchronous behaviour and I was confused, you know life is tough). So
this function is  the judge that sort good and evil buttons. This is the
*hot* part of the function :

AVToolButtonIsEnabled       (... bad instructions for your health ...)

080bb43a  call   *%ebx      << this indirect call is calling StdComputeEnabledSelChange
                            << the returned value is saved in eax as usual
            
080bb43c  addl   $0x4,%esp
080bb43f  movl   %eax,%eax;              << I don't understand it
080bb441  movw   %ax,0xfffffffe(%ebp);  << save the boolean value
080bb445  addl   $0xfffffff8,0x820b904
080bb44c  jmp    080bb45d;                << jumping
080bb44e  nop   
080bb44f  nop   

Referenced from jump/call at 080bb42b ;

080bb450  addl   $0xfffffff8,0x820b904
080bb457  movw   $0x0,0xfffffffe(%ebp)

Referenced from jump/call at 080bb44c ;   <we are jumping here !!!
080bb45d  pushl  $0x0

Reference to function : AVAppSetBusy

080bb45f  call   080700f0 <AVAppSetBusy>;  <<bla bla bla
080bb464  addl   $0x4,%esp

Referenced from jump/call at 080bb3dd ; 080bb3f2 ;

080bb467  movw   0xfffffffe(%ebp),%ax;  << move to eax the boolean value
080bb46b  movzwl %ax,%edx;              << more stupid instructions
080bb46e  movl   %edx,%eax
080bb470  jmp    080bb480;             << jump to end
 
Don't worry this is not endless, we are close to the crack, but we must go to
this "academic" function StdComputeEnabledSelChange. BTW, you may see that
this function has one parameter. For any button but "text-button" the
parameter saved is 0, and for the evil button the parameter is 0x10. Now
you'll see how everything makes sense:

080baef0 StdComputeEnabledSelChange

(... bla bla bla ...)
080baf22  movl   0x8(%ebp),%eax;    << take the parameter
080baf25  pushl  %eax;               << forward the parameter
080baf26  movl   0xfffffffc(%ebp),%eax;
080baf29  pushl  %eax;               << save another parameter

Reference to function : AVDocCheckPermission

080baf2a  call   0807c8f0 <AVDocCheckPermission>

And last but not least (don't forget the parameter of the first push):

(... bla bla bla ...)
Reference to function : AVDocGetPDDoc
0807c944  call   0807ca90 << get pointer in eax of some pdf structure
0807c949  addl   $0x4,%esp
0807c94c  movl   %eax,%eax
0807c94e  pushl  %eax:  << save pointer


Reference to function : PDDocGetPermissions
0807c94f  call   08038828 <_init+1ab8>       << this function returns en eax the permis. word
0807c954  addl   $0x4,%esp
0807c957  movl   %eax,%eax
0807c959  movl   %eax,%edx   << copy permissions to edx
0807c95b  andl   0xc(%ebp),%edx; << AND with the parameter !!!!
0807c95e  cmpl   %edx,0xc(%ebp)
0807c961  sete   %al
0807c964  movzbl %al,%edx
0807c967  movl   %edx,%eax
0807c969  jmp    0807c970
0807c96b  nop   
0807c96c  nop   
0807c96d  nop   
0807c96e  nop   
0807c96f  nop   

Referenced from jump/call at 0807c93d ; 0807c969 ;
0807c970  movl   %ebp,%esp
0807c972  popl   %ebp
0807c973  ret  

We are at the end of our long way. The permission word for an unprotected
document is 0x7fff (rather curious :-).

For an explanation of this 7FF, check +Zer0's essay:

Actually the value has been transformed a bit high order byte to 7F 
and low order byte incremented by 1 so the desired value at this position 
is 7FFD instead of FFFC. 

You may realise that PDDocGetPermissions is not inside acroread. 
It is an imported function. 
The code is located in a library (Acrobat/Reader/intellinux/lib/libreadcore.so.3). 
You can disassemble it (I'm not gonna punish you any more inside this essay :-) 
and the function just returns the input parameter+0x78, hence the offset of 
the permission is 0x78.
Now you can crack it any way you want. You may patch the library, overwrite
some nops. If you are working with xxgdb I propose you patch quietly
AVDocGetPDDoc, and not only return the pointer but "initialise" permissions.
These are the commands:

(xxgdb)br *0807cac3   (the ret point of the function AVDocGetPDDoc)
(xxgdb)commands
>silent
>set *($eax+0x78)=0x7fff
>cont
>end

There are a lot of things to do (delving into permission word, encryption
routines, ...) but you will allow me not to do them right now. 
I hope this essay will help you with the Windoze version, or at least will 
help you if you are up to crack some other linux commercial application.

For this particular crack I would like to thank Quine for his obstination.
Regards also to all +HCUkers and all other friends.

"Long is the way and hard, that out of Hell leads up to the light"

(c) SiuL+Hacky 1997. All rights reversed

You are deep inside fravia's page of reverse engineering,  
choose your way out:


redBack to the PDF-project

redhomepage
redlinks 
redanonymity 
+ORC

redstudents' essays

redacademy database


redtools

redcocktails

redantismut CGI-scripts

redsearch_forms

redmail_fravia


redIs reverse engineering legal?