Linux cracking: the live approach (acrobat reader)
(Linux advanced reverse engineering: imported functions)

by SiuL+Hacky
+cracker!

(12 November 1997)


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: THE LIVE APPROACH. ACROBAT READER.



I.Introduction

---------------



In my first linux essay you could get an introduction on how to port our

windoze techniques to the linuz world. It was mainly dedicated to dead

approach, because it is really powerful for some kind of programs. But

sadly, as you'll see, huge and overbloated programs are getting into Linux

and if you want to reverse engineer your target you need some debugging 

(unless you are a 'senior' mental cracker).



With this essay I'll try to introduce you the linux graphic environment,

XWindows (no kind of porno environment eh !). It may look like Windoze but

internally is very different in some aspects. The main difference is that it

uses the ubiquitous client-server scheme. Anyway, I don't have the time nor

the knowledge (+ hcu 1999 ?) to teach you thoroughly how it works, but

I'll show the starting point for cracking X applications. In linux you can

use several X servers, the most popular is XFree86 server but I hope that 

any of them will do it.



+ORC's proposal for cracking acrobat-pdf tools is a good opportunity for

practising these methods. I told you, as I told him, that I think is not

worthy losing time writing a text-to-pdf converter, because it does exist

and there are still several uncracked (and important) protection schemes. 

So, here I'm gonna crack Acrobat Reader (yes, it is available for linux, 

though the same windoze restrictions apply) with two main goals :



- I want to see always Menu and Toolbars.

- I don't want copy text restrictions and so on.



I got it from a Spanish magazine, but I suppose it is freely available at 

Adobe's site. You realise this is not reverse engineering pdf-format but 

Acrobat Reader. (I would like to see other people reverse engineer the 

pdf-format).





II. ToolX of the Trade.

------------------------



Obviously here you'll find some X-specific tools. Most of the tools I told

you in my first essay apply for X-RE. Especially useful is gonna be DASM,

because, though we are gonna use the live approach, the assembler listing is

again invaluable. I repeat you that this will give the clues, but for a

better use of them, READ the manual pages of them.





* xwininfo    -----------------------------------------------------------------



 This utility gives you information about a specific window. By default it asks 

to click on the target window you want to gather information. Be careful, and 

don't think here about "window" in the Windoze way. When I click with the mouse 

on a window, I'm clicking on the "physical" window, on the super-parent window 

(called root window) if you want to put it that way. Each window (buttons for 

instance are child windows) has an identifier. These are some useful switches:



- tree: Display all windows (root, parent and children) in a recursive way. It 

displays the identifier (known as Drawables) , the size, position and show on. 

Here is an example taken for Acrobat Reader:



xwininfo: Window id: 0x2800128 "Acrobat Reader"

 Root window id: 0x26 (the root window) (has no name)

   Parent window id: 0x8001ad (has no name)

        1 child:

             0x2800129 (has no name): ()  272x367+0+0  +527+121

             

             ... some other windows ...

             

 0x2800148 (has no name): ()  24x24+3+3  +530+183; << toolbar button

 0x2800147 (has no name): ()  24x24+27+3  +554+183;<< toolbar button

 0x2800146 (has no name): ()  24x24+51+3  +578+183;<< toolbar button

 0x2800145 (has no name): ()  6x24+75+3 +602+183

 0x2800144 (has no name): ()  24x24+81+3  +608+183;<< toolbar button

 0x2800143 (has no name): ()  24x24+105+3  +632+183;<<toolbar button

 0x2800142 (has no name): ()  24x24+129+3 +656+183; << and more ...

 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            

 

            ... some other windows ...

            



Of course, the first hex number is the window identifier, that will be

especially useful for other, or even this, tool.



-id : with this option you don't need to click on a specific window but you

can gather information for any window in particular.



-all: display all the information available.





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



This utility reports all the events involved with some window. Switches:



-id: If you don't give it an identifier, xev will display a test window,

where you can test mouse, keyboard and other kinds of event.



In some cases you may use this program for matching identifiers. For example

if run xev -id 0x2800148

But you don't know what window (child window) has this identifier! Just

move your mouse over the windows and you'll get messages just when 

you'll be over the window you are looking for (BTW MotionNotify events).





* xxgdb  --------------------------------------------------------------------



It is just the Xwindows front end for gdb. The only addition is a ButtonBar

with some useful commands. We'll see some useful commands while debugging

acrobat reader. I hope, in a future essay, to show some more friendly tools,

but as for now this is the most widespread and stable tool I know of.





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



Working with Windoze programs, it turned important to know some "regular"

API calls like MessageBox, GetDlgItemText and so on. Well, the same apply, 

or will apply, for XWindows. You may get the call definitions in the .h files

located usually in the directory /usr/X11R6/include/X11. I found particularly

interesting a document available at xfree86 site (ftp.xfree86.org), or, even better, 

look for a mirror in a ftpsearch:



xlib.PS.Z   (971 Kb)



This is a 400 pages PostScript document where you'll find a lot of information.

It's hard to find books about Xwindows programming, so if you know some

tutorial or some document useful for our purposes,  send them to the +HCU to 

be included in the next revision of this essay.





* Text-to-pdf converters -----------------------------------------------------



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 

  

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?