Linux cracking: the live approach (acrobat reader)
(Linux advanced reverse engineering: imported functions)
by SiuL+Hacky
(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:
Back to the PDF-project
homepage
links
anonymity
+ORC
students' essays
academy database
tools
cocktails
antismut CGI-scripts
search_forms
mail_fravia
Is reverse engineering legal?