Experience a brand new taste in cracking : 
Juggle with the PalmPilot's DragonBall 
papers 
+HCU papers 
16 May 1998 
by TeK 
 
Courtesy of Reverser's page of reverse engineering 
 
fra_00xx 
98xxxx 
handle 
1100 
NA 
PC
Mmmm! Juicy! Motorola disassembling! Was about time we all took a vacation from the dull routine of the intel routines!
Motorola, nice sweet sound of an almost extint, yet once glorious, really POWERFUL processor family!
Repeat it swinging slowly your hawajian shirt: MO-TO-RO-LA... hola-hop, Aloha, aloha, sommer sun, deep blue sea...Yeah! Let's crack our "palmtops" sitting in the shadow of the palms, or, if in Europe, feeling the breeze under our sail, while the boat rolls gently in the calm waters of the little greek harbour, and we are awaiting the opening hour of the bars for our wodka-martinis (or ouzos)... what the hell is an "Atomic Fire Ball"?
A great essay, that for once walks completely different paths... and comes to the same known conclusions: protections are useless against reversing magi like Tek, and I'm very happy that Tek volunteered (at the bottom) to start the new "other worlds" reversing section of my site :-)
The "tools" section of this essay is VERY important for any reverser, btw...
There is a crack, a crack in everything That's how the light gets in 
Rating 
( )Beginner (x)Intermediate (x)Advanced ( )Expert 

Crack on a new platform using the dead list approach. Experience the M68000 assembler. Make your own Java key generator for a Pilot application.


Experience a brand new taste in cracking :
Juggle with the PalmPilot's DragonBall
Written by TeK
 
Introduction 
 
Cracking Windows and DOS apps is fun. Cracking dongles is even more fun. But what about taking some holidays and cracking something that you've never cracked before ? In this essay, I will try to teach you how to crack applications running on the PalmPilot. Believe me, that will be like taking some holidays on the Azure Coast...
I couldn't find any tutorial or anything about Pilot cracking on the web, so I decided to write this essay. This is not intended to be a tutorial, even if I will try to go far enough to make you discover all the nice pieces of code that are hidden inside these little black-and-green babes.
I assume that you have some slight knowledge of the X86 assembler. Anyway, we won't talk much X86; we'll talk M68000.

 
Tools required 
 
As the platform changes, the tools change. It took me much time to find the right tools and the best tools to achieve my first Pilot crack
Here are the tools you'll need and where you'll find them :

Necessary :

Palm OS Emulator : you'll need this to use your PC to emulate the Pilot. You don't really need it if you already have a REAL Pilot. Anyway, this emulator is amazing.

PRC2BIN : this will extract all the resources linked in a Pilot .PRC executable file.

PilDis : the best Pilot disassembler around.

M68K Disassembler 1.1 : I experienced some problems with this one (it made me lose one hour of my life :(), but sometimes it disassembles a bit better than PilDis.

Pila : the Pilot assembler.
 
Hacker's View 5.66 : this is the hex-editor I prefer, but any other will do.

Optional :

ROM File : You'll find debug ROM's for the Palm OS Emulator at 3COM's, but with them I experienced some unexpected crashes (yes, usually I expect crashes under WinSuxx95 :). That's why I encourage you to take a released ROM. If you don't have a real Pilot, you'll find some on the Net. This URL might be down by the time you read these lines, but anyway, you know how to search, don't you.

ASDK : this is an almost complete toolbox that contains many very useful programs like PilDis, PRC2BIN and Pila.

The Copilot Home Page : there you'll find some infos about the original PalmPilot emulator.

Pilot Assembler Reference : excellent compilation of infos to program (and crack) Pilot apps.

CrossFire 5.10 : this program doesn't interest us much in itself, but it contains an excellent description of most M68000 instructions.

Pilot Programming FAQ : if you know how to program, you've done a good part of the way to the crack.

MC68328 DragonBall : official informations about Motorola's processor.

Atomic Fire Balls : you'll need these hot cinammon candies to fight against the DragonBall processor. If you cannot find them in Europe, you can place an order at CandyDirect. One ball should last long enough for you to read this essay. If you prefer the more classical Martini/Vodka, I advise you NOT to eat an Atomic Fire Ball while sipping your favorite cocktail...

A Good Bootleg : just put on a good concert of Lush, Garbage or Nirvana while cracking Pilot programs. You'll see, it helps to feel the code. If you fancy trading bootlegs with me, my list is here.

 
Target's URL/FTP 

You will find all the targets we'll treat in this essay and many other potential ones at : http://www.pilotgear.com

 
Program History 

Usually we don't care enough about the history of the applications we are going to crack, but the Pilot's history is important.
The Pilot has a multiple use : diary, address book, calculator, text editor, web browser, ... It is small but not limited as it is quite easily programmable.
The Pilot was first developped by USRobotics. When 3COM bought USR, they also got the license for the Pilot and they put their logo on it. The version 3.0 of the Pilot was released lately. A big advantage of the Pilot is that you can upgrade it just by changing its little ROM card. All Pilots contain the Motorola MC68328 DragonBall processor.
It may also interest you to know that IBM bought the Pilot's license. They rehashed it a bit (i.e. changed the logo) and they called it "WorkPad". The PalmPilot and the WorkPad are compatible.
The PalmPilot doesn't have a keyboard. It has a good built-in OCR, so you just have to write on the touch-screen with a pen and use a special font. You will spend much time to write your first characters but then you'll get used to it.
Of course you have the possibility to connect the Pilot to your PC. This is done through a protocol called HotSync. Note that there is a HotSync ID that is defined on the PC and which contains your user name. This ID will be used by one of our future targets...
You might experience a strange (but normal) behavior of the Palm OS. It isn't really multi-tasking, but it can execute the application launcher and one application in parallel. Pilot apps do not have a QUIT option. It seems that you have to run another app to quit the previous one. If someone has more infos about this feature (!?!), please drop me a line.
Let's talk a bit about the Copilot, the Pilot emulator for PC and Mac. This excellent program was written by Greg Hewgill and it was lately bought (or simply taken, I don't know) by 3COM who called it Palm OS Emulator. 3COM are acting exactly like Micro$hit; they suck everything they can. Fortunatelly, the Palm OS Emulator is free along with a debug ROM.

 
Essay 

We'll treat three applications in this essay. I chose them in order to give you a wide view of the cracking possiblities you have on the Pilot. We will begin with an easy crack to show how it works and we'll finish with a key generator written in Java.
Ok, before we begin, just put the Atomic Fire Ball in your mouth and play your favorite bootleg.
The first target will be Currency Calculator 3.12. You'll find it at PilotGear. Maybe there is a newer version there, but I know that you're smart enough to handle the offset changes by yourselves.
After unzipping the file, you'll find three .PRC files and two .PDB files. PDB files are databases and we won't have to deal with them. PRC files are compiled Pilot resources. They contain many internal parts such as : code, icons, forms, alert forms, menu bars, strings, ... If you're an experienced cracker, I'm sure that you can already see the light through it :)
CURRCAL1.PRC is compatible with the Palm OS 1.0 and CURRCAL2.PRC is a more powerful version of the program, but it needs the Palm OS 2.0 and MATHLIB.PRC must be installed in order to let it run. We'll work on CURRCAL1.PRC here, but the other version has exactly the same protection scheme located at a different offset.
As always, we must first analyse what is to be cracked. Run the emulator. It will create a Palm1024.ram file the first time you run it. This is the space you have to install programs on your emulated PalmPilot. You can see that there is also a palm.rom file. You can upgrade your virtual Pilot only by changing this file. If you have a real Pilot you can even download its ROM into your PC to use it with the emulator... wonderful, isn't it ?!
Now that the emulator is running, press the right mouse button to load CURRCAL1.PRC. I won't teach you how to use the Pilot. Just experience and read the docs. With the emulator you do not need to use the OCR. Just type in everything with the keyboard; that's much easier. Run CurrCalc. If you don't get the Info/Register panel, just click on the "i" logo in the upper left. Click "Register" and here we are : you have to enter your user name and registration number. As you can see, Pilot shareware programmers are as greedy as PC shareware programmers. I would say even more greedy. Anyway, at the end of this essay, this (nice) program will be cracked to the bone.
We will always use the dead list approach to deal with PalmPilot programs as a debugger would not help us much but would surely slow us down. The Copilot contained a quite nice debugger but it was built for version 1.0 of the OS. Unfortunatelly it was based on static memory addresses and when the OS changed, the memory locations changed too, which made the debugger crash. I tried it anyway but I could never go further than the welcome screen. You'll see that the dead list approach is so easy that we'll never miss the debugger. If you were planning to use SoftIce, you can forget it straight away. As the code is emulated, it would be the same as debugging InstallShield's SETUP.EXE. Note for the protectionists out there : interpreted code (i.e. compiled script) is an excellent protection. Try to crack a Java program by debugging JAVA.EXE... it would take you at least one month. Now take 30 minutes to decompile the program with WingDis and you'll need 5 minutes to get through it. NaTzGUL surely knows what I'm talking about...
After this little digression, let's enter something in both fields of the registration window. Click OK and note down the error message that says "Wrong registration number!". If we find the part of the code that fetches this error message to display it, the good_guy/bad_guy comparison cannot be far.
The first thing to do is to split the CURRCAL1.PRC into atomic resources to find our error message. Therefore we use PRC2BIN. It creates 68 resource files out of CURRCAL1.PRC (you'd better create a separate directory for these ones). A good thing to do is to browse all resources with HIEW to see what's inside. You can also make a quick string search over the directory to quickly locate the file that contains "Wrong registration number!". You'll find it in TALT05DC.BIN. This filename is not random at all.
ALT means ALERT. We will often have to deal with these forms as most "Registration Error" processes use them.
05DC is an hex number which represents the Resource ID (ResID) of the Alert Form. This handle is used to display the form. Remember this number.
Now we know what we're looking for : a call to resource 05DC.
Let's disassemble the code. There are two ways : either you use PilDis on CURRCAL.PRC (the packaged resources), either you use it on CODE0001.BIN (the code resource itself). The second approach is more logic, but I prefer the first one as the offsets in the disassembled output file will be the same as in the original .PRC and therefore easily patchable (you won't need to make a hex search throughout the .PRC). For this essay, I will use the first method.
CURRCAL1.PRC is now disassembled in CURRCAL.PRC.s. Take your prefered text viewer and open CURRCAL1.PRC.s (I personally use 4DOS's LIST... pretty quick for string searches).
Search for "05DC". You'll get some false positives; this is due to the fact that ALL the .PRC resource was disassembled and not only the code area. When your string search stops at a DC.? instruction (called DB, DW or DD with the X86) you know that you're in a data area. The search stops twice in the code area : at 00005D18 and 00007DFA.
Now it's time to introduce the Pilot API. The Palm OS contains a good lot of meaningful API's that are very well recognized by PilDis. There is a non-exhaustive list of API's that may be helpful to our cracking purpose in the Appendix section of this essay. Depending on the program's behavior, you can usually determine which API should be called. In our case, an Alert Form is displayed after entering a bad registration number. Guess what, there is an API called sysTrapFrmAlert... getting the picture ?
Let's examine the first occurrence of our ResID (05DC) at 00005D18 (as comments I translated the most important instructions into X86 assembler) :

00005d18 363c05dc                  MOVE.W #1500!$5dc,D3    ;mov word ptr D3, 05DCh
00005d1c 6052                      BRA L885                ;jmp L885
00005d1e 363c0640                  MOVE.W #1600!$640,D3
00005d22 604c                      BRA L885
00005d24 363c06a4                  MOVE.W #1700!$6a4,D3
00005d28 6046                      BRA L885
00005d2a 363c0708                  MOVE.W #1800!$708,D3
00005d2e 6040                      BRA L885
00005d30 363c076c                  MOVE.W #1900!$76c,D3
00005d34 603a                      BRA L885
00005d36 363c07d0                  MOVE.W #2000!$7d0,D3
00005d3a 6034                      BRA L885
00005d3c 363c0834                  MOVE.W #2100!$834,D3
00005d40 602e                      BRA L885
00005d42 363c0898                  MOVE.W #2200!$898,D3
00005d46 6028                      BRA L885
00005d48 363c08fc                  MOVE.W #2300!$8fc,D3
00005d4c 6022                      BRA L885
00005d4e 363c0960                  MOVE.W #2400!$960,D3
00005d52 601c                      BRA L885
00005d54 363c09c4                  MOVE.W #2500!$9c4,D3
00005d58 6016                      BRA L885
00005d5a 363c0a28                  MOVE.W #2600!$a28,D3
00005d5e 6010                      BRA L885
00005d60 363c0a8c                  MOVE.W #2700!$a8c,D3
00005d64 600a                      BRA L885
00005d66 363c0af0                  MOVE.W #2800!$af0,D3
00005d6a 6004                      BRA L885
00005d6c 363c0b54                  MOVE.W #2900!$b54,D3
00005d70 4a43                L885  TST.W D3                ;cmp word ptr D3, 0
00005d72 6708                      BEQ L886                ;jz L886
00005d74 3f03                      MOVE.W D3,-(A7)
00005d76 4e4f                      TRAP #15
00005d78 a195                      DC.W sysTrapFrmHelp     ;display a Help Form
00005d7a 544f                      ADDQ.W #2,A7
00005d7c 4cdf0438            L886  MOVEM.L (A7)+,D3-D5/A2
00005d80 4e75                      RTS                     ;ret

If you have never dealt with the M68000 assembler before, this piece of code needs some comments. You may have noticed that the second operand of each instruction is the target and not the source (contrary to the X86 assembler).
MOVE.W #1500!$5dc,D3 means that the value 1500d (= 05DCh) will be put into the register D3 using the space of a WORD. The M68000 processor contains 8 data registers (D0-D7), 7 address registers (A0-A6) and a stack pointer (A7). Registers have 32 bits.
Instructions that use registers are followed by a .B (byte : 8 bits), .W (word : 16 bits) or .L (long : 32 bits). This tells the processor how much bits of the register the instruction will act on (almost like our BYTE PTR, WORD PTR and DWORD PTR).
BRA means "branch". This is a simple unconditional jump to the specified location. The TST instruction may be useful to us : it tests if the register (here D3) equals zero and sets the flags accordingly. The flags are then checked by BEQ (Branch if EQual). This conditional jump will branch if the result of the TST instruction was zero.
Finally, there is the call to sysTrapFrmHelp preceded by the TRAP instruction (interrupt call) to display the Help Form and the RTS (ReTurn from Subroutine) to return to the caller.
If you're interested in getting more informations about the M68000 processor and assembler, please refer to the Tools section of this essay.
Seemingly, in our protection we do not expect a Help Form but an Alert Form. Let's have a look at the second occurrence of the ResID :

00007d8a 2c48                L1174 MOVEA.L A0,A6
00007d8c 2f0c                      MOVE.L A4,-(A7)
00007d8e 4e4f                      TRAP #15
00007d90 a139                      DC.W sysTrapFldGetTextPtr   ;get a pointer on the first text field (User Name)
00007d92 2808                      MOVE.L A0,D4
00007d94 2444                      MOVEA.L D4,A2
00007d96 2f0e                      MOVE.L A6,-(A7)
00007d98 4e4f                      TRAP #15
00007d9a a139                      DC.W sysTrapFldGetTextPtr   ;get a pointer on the second text field (Reg. Num.)
00007d9c 2a08                      MOVE.L A0,D5
00007d9e 4a84                      TST.L D4                    ;first text field pointer = null ?
00007da0 4fef000c                  LEA 12(A7),A7
00007da4 6748                      BEQ L1177                   ;if yes, branch to Bad_Guy
00007da6 4a85                      TST.L D5                    ;second text field pointer = null ?
00007da8 6610                      BNE L1176                   ;if no, calculate the right Reg. Num.
00007daa 6042                      BRA L1177                   ;if yes, branch to Bad_Guy
00007dac 1012                L1175 MOVE.B (A2),D0              ;calculate the right Reg. Num. from the User Name
00007dae 4880                      EXT.W D0
00007db0 d046                      ADD.W D6,D0
00007db2 064004a3                  ADDI.W #1187!$4a3,D0
00007db6 3c00                      MOVE.W D0,D6
00007db8 528a                      ADDQ.L #1,A2
00007dba 4a12                L1176 TST.B (A2)
00007dbc 66ee                      BNE L1175                   ;loop while not end of User Name string
00007dbe 2f05                      MOVE.L D5,-(A7)
00007dc0 4e4f                      TRAP #15
00007dc2 a0ce                      DC.W sysTrapStrAToI         ;convert the entered Reg. Num. to Integer
00007dc4 7200                      MOVEQ #0,D1
00007dc6 3206                      MOVE.W D6,D1
00007dc8 b280                      CMP.L D0,D1                 ;are the calculated and the entered Reg. Nums equal ?
00007dca 584f                      ADDQ.W #4,A7
00007dcc 6620                      BNE L1177                   ;no, then branch to Bad_Guy
00007dce 2f04                      MOVE.L D4,-(A7)             ;Good_Guy, the entered Reg. Num. is right
00007dd0 486dfc66                  PEA -922(A5)
00007dd4 4e4f                      TRAP #15
00007dd6 a0c5                      DC.W sysTrapStrCopy         ;save the User Name
00007dd8 2f05                      MOVE.L D5,-(A7)
00007dda 486dfc86                  PEA -890(A5)
00007dde 4e4f                      TRAP #15
00007de0 a0c5                      DC.W sysTrapStrCopy         ;save the Reg. Num.
00007de2 1b7c0001fc96              MOVE.B #1,-874(A5)          ;put on the "Registered" flag
00007de8 4fef0010                  LEA 16(A7),A7
00007dec 6016                      BRA L1178                   ;branch over Bad_Guy and continue normal execution
00007dee 422dfc66            L1177 CLR.B -922(A5)              ;Bad_Guy - clear the User Name variable
00007df2 422dfc86                  CLR.B -890(A5)              ;clear the Reg. Num. variable
00007df6 422dfc96                  CLR.B -874(A5)              ;clear the "Registered" flag
00007dfa 3f3c05dc                  MOVE.W #1500!$5dc,-(A7)     ;wowowow... here is our Bad_Guy ResID
00007dfe 4e4f                      TRAP #15
00007e00 a192                      DC.W sysTrapFrmAlert        ;display the Alert Form
00007e02 544f                      ADDQ.W #2,A7
00007e04 3f2dfeb2            L1178 MOVE.W -334(A5),-(A7)       ;keep on normal execution
00007e08 4e4f                      TRAP #15
00007e0a a19e                      DC.W sysTrapFrmReturnToForm

As you can see, the names of the sysTraps are meaningful enough for us to understand them. With our search for 05DC, we have landed right in the protection routine. We don't even need to understand EVERY instruction; a global view is more than enough for now. We'll spend more time on this protection at the end of this essay : we'll program a key generator for Currency Calculator.
What we have to patch is quite obvious : just put a No OPeration (NOP) at 00007DCC which will force the program to go to Good_Guy. Same scheme as always...
Now we have a big problem : we all know that on our beloved PC's the opcode of NOP is 90h. What is the opcode of NOP on the M68000 ? We can try to make a string search for NOP on the dead listing of CURRCAL1.PRC, but no NOP is found. A good solution (if, like me, you cannot afford buying a 70$ book containing all the M68000 opcodes) is to use Pila, the Pilot Assembler. Just put a NOP somewhere in the sample file, assemble and then disassemble with PilDis to find the opcode. I know that this technique is not so smart but it works fine though. We discover that NOP is 4E71h (yes Sir, 2 bytes).
The crack is finished. Use Hacker's View to replace the 6620h at 00007DCC with 4E71h. Load the cracked app from the emulator and enter anything in the fields. It works quite well. Zero-character strings are not accepted and will refuse you the registration. Don't patch the checks for null pointers at 00007DA4 and 00007DAA as it would crash your Pilot badly (this is "normal" as the called API cannot handle empty strings).
Note that your registration will not be kept in memory if you EXIT the emulator just after registering. You have to run another program in order to keep the memory as changed. I suppose that this is due to the fact that you cannot EXIT a real Pilot (this would be equal to a cold reset and the memory wouldn't be kept either). On the real Pilot, you just press the green button to turn it off, which doesn't throw away the changes that might have occurred inside the memory.
Now you can also patch CURRCAL2.PRC. You have to put the NOP at the offset 00004BE0.
 

Ok, let's move on to another target. I chose TealPaint 2.20 from TealPoint Software. This is an excellent drawing program (at least on the Pilot). TealPoint Software distribute many other applications like TealDoc or TealEcho. They seem to make a big business out of Pilot apps. That's why we'll crack TealPaint and that's why I encourage you to crack all other TealPoint apps, like I already did myself...
Once again, you may not find exactly the same version at PilotGear, but you can handle the offset changes. The important thing is to UNDERSTAND what happens inside the target.
Here we go : run the target and a nag-screen will appear just after you have entered a database name. Now you can press the Register button to see what happens. The registration process uses your HotSync ID as User Name and you have to enter the corresponding key. So boring...
Let's get the ResID of the Alert Form that contains "Make sure your HotSync ID matches the one in your Registration message" that is displayed after you have entered a bad key.
We can now use PRC2BIN and PilDis on TEALPNT.PRC. We find our Bad_Guy string in TALT07D1.BIN and you'll notice that TALT07D2.BIN contains "Thank You, Registration key accepted". Browsing ALL resource files is often helpful and not so time-consuming.
A string search for our ResID (07D1) in the disassembled file TEALPNT.PRC.s gives us only one occurrence in the code area at 000050CC which is directly followed by a call to sysTrapFrmAlert :

000050b6 528b                L293  ADDQ.L #1,A3
000050b8 0c130020                  CMPI.B #32!$20,(A3)
000050bc 6ef8                      BGT L293
000050be 16bc0000                  MOVE.B #0,(A3)
000050c2 4eba0026                  JSR L296                    ;call to L296
000050c6 4a00                      TST.B D0                    ;D0=0 ?
000050c8 6700000e                  BEQ L294                    ;if yes, branch to Good_Guy
000050cc 3f3c07d1                  MOVE.W #2001!$7d1,-(A7)     ;Bad_Guy
000050d0 4e4f                      TRAP #15
000050d2 a192                      DC.W sysTrapFrmAlert        ;display the Bad_Guy Alert Form
000050d4 548f                      ADDQ.L #2,A7
000050d6 600a                      BRA L295                    ;jump over Good_Guy
000050d8 3f3c07d2            L294  MOVE.W #2002!$7d2,-(A7)     ;Good_Guy
000050dc 4e4f                      TRAP #15
000050de a192                      DC.W sysTrapFrmAlert        ;display the "Thank You..." Alert Form
000050e0 548f                      ADDQ.L #2,A7
000050e2 4cdf1cf8            L295  MOVEM.L (A7)+,D3-D7/A2-A4   ;pop registers
000050e6 4e5e                      UNLK A6                     ;remove the stack frame
000050e8 4e75                      RTS                         ;return to the caller

This seems to be easy... let's replace the BEQ at 000050C8 by a BRA and the program will unconditionally branch to Good_Guy. This time, no need to assemble a BRA like we did with NOP. There are many BRA's in the program. Watch at offset 000050D6 : BRA is 60h plus the displacement (here 0Ah to reach L295). We have two possibilities : either replace the 67h at offset 000050C8 with 60h and it will make a far jump to L294 or put a 600Eh at the same offset to make a short jump. Both work fine.
Now you can reload the patched version of TEALPNT.PRC into your Palm emulator and try it. Press the Register button, enter something in the Key field, press OK and we can see that our crack works fine. Now run another program to force TealPaint to quit. Rerun TealPaint and... bad thing, the nag-screen is still here. Our crack is not so good. Why ? Because the key is checked each time the program executes. We only forced it to display the "Thank You ..." form, but now we must crack the check for the nag-screen.
What happens just before the TST, at 000050C2 ? The program makes a Jump to SubRoutine (i.e. a call to a procedure). We can assume that this procedure must return 0 in D0 if we want the BEQ to branch to Good_Guy. If the nag-screen is still displayed, that's because there is certainly another call to this subroutine somewhere else in the code. A search for L296 gives us :

0000438c 4eba0d5c            L243  JSR L296              ;call the registration check
00004390 1b400536                  MOVE.B D0,1334(A5)    ;store D0 in a variable
00004394 4a2d0536                  TST.B 1334(A5)        ;test the variable for 0
00004398 670000c0                  BEQ L246              ;jump over the nag-screen display routine if D0=0

Now we can be sure that the procedure must return 0 in D0. Let's have a look at this famous L296 :

000050ea 4e560000            L296  LINK A6,#0
000050ee 48e71f38                  MOVEM.L D3-D7/A2-A4,-(A7)
000050f2 486d090f                  PEA 2319(A5)
000050f6 4eba008c                  JSR L297
000050fa 588f                      ADDQ.L #4,A7
000050fc 3f3c0004                  MOVE.W #4,-(A7)
00005100 2f3c00005673              MOVE.L #22131!$5673,-(A7)
00005106 2f3c00001234              MOVE.L #4660!$1234,-(A7)
0000510c 486d090f                  PEA 2319(A5)
00005110 4eba009e                  JSR L298
00005114 4fef000e                  LEA 14(A7),A7
00005118 2800                      MOVE.L D0,D4
0000511a c8bc00003f3f              AND.L D4,#16191!$3f3f
00005120 45ed0568                  LEA 1384(A5),A2
00005124 2f0a                      MOVE.L A2,-(A7)
00005126 4e4f                      TRAP #15
00005128 a0c7                      DC.W sysTrapStrLen
0000512a 588f                      ADDQ.L #4,A7
0000512c 264a                      MOVEA.L A2,A3
0000512e d7c0                      ADDA.L D0,A3
00005130 528b                      ADDQ.L #1,A3
00005132 3f3c0005                  MOVE.W #5,-(A7)
00005136 2f3c0000e113              MOVE.L #57619!$e113,-(A7)
0000513c 2f3c0000f985              MOVE.L #63877!$f985,-(A7)
00005142 2f0a                      MOVE.L A2,-(A7)
00005144 4eba006a                  JSR L298
00005148 4fef000e                  LEA 14(A7),A7
0000514c c0bc0000003f              AND.L #63!$3f,D0
00005152 e188                      LSL.L #8,D0
00005154 2600                      MOVE.L D0,D3
00005156 3f3c0005                  MOVE.W #5,-(A7)
0000515a 2f3c0000e113              MOVE.L #57619!$e113,-(A7)
00005160 2f3c0000f985              MOVE.L #63877!$f985,-(A7)
00005166 2f0b                      MOVE.L A3,-(A7)
00005168 4eba0046                  JSR L298
0000516c 4fef000e                  LEA 14(A7),A7
00005170 c0bc0000003f              AND.L #63!$3f,D0
00005176 8083                      OR.L D3,D0
00005178 b084                      CMP.L D4,D0                ;compare D4 and D0
0000517a 56c0                      SNE D0                     ;if (D0=D4) then D0:=0; if (D0/=D4) then D0=FFh
0000517c 4cdf1cf8                  MOVEM.L (A7)+,D3-D7/A2-A4
00005180 4e5e                      UNLK A6
00005182 4e75                      RTS

Again, we don't need to understand every instruction. This procedure is quite complex (some JSR's, ...). We know it must return 0 in D0, so we can reverse it. We begin at the end and watch what happens with D0. The key to our problem seems to be located at 0000517A. We can put 0 in D0 ourselves with the instruction : MOVE.B #0, D0 . We use a MOVE.B as only a byte is tested for zero at 00004394 and 000050C6. Assemble this instruction, disassemble it and you'll find the opcode 103C0000h . As it takes 4 bytes, we can put it at 00005178 which will overwrite the CMP and the SNE.
The crack works fine now and there is no nag-screen anymore, even before we have entered a registration key... this behavior was expected as we patched the subroutine that is used for all checks to the key.
If you disassemble TealDoc, you'll see that its protection routine is almost the same as TealPaint's. I hope that someone will fancy writing a generic patcher for all TealPoint apps, all versions. This may involve writing a heuristic searcher to find and patch the protection part even if it has been slightly changed through different versions. This would be an excellent exercise.
 

Ok, we've seen enough easy protections. Our new target, PAL 1.31, doesn't have a "ready-to-crack" registration routine. PAL is a nice applications launcher that allows you to categorize your apps (even though the new Palm OS 3.0 would have the same feature built-in). At the bottom of the screen, the date blinks with an "UNREGISTERED" message. If it doesn't blink, click on the locker, turn on the Pilot with the green button and then it will blink.
What do we want to do ? Of course, you could put your handle instead of the "UNREGISTERED" message and it would be nice, but what we want is that the date stops blinking. We have no idea of which API could be used to display this string. As Palm programs are quite small, we can try a "brute" technique that is to perform a string search for "sysTrap". I told you it was brute... This way, we'll get ALL API calls that the program makes. It won't take you more than five minutes to browse all these calls, and you'll learn much.
I experienced some problems when disassembling PAL.PRC with PilDis. Some parts of the code area that are important to our cracking purpose were not correctly disassembled. Therefore you should use the M68K Disassembler for this target.
The disassembly done, let's browse the sysTrap calls. At the beginning you'll find many memory related sysTraps that are unuseful to us. A bit further, at 00000E8A, we land on a sysTrapTimeToAscii followed by a sysTrapWinEraseRectangle and a sysTrapWinDrawChars :

00000e84   e188            LSL.L #8,D0
00000e86   2f00            MOVE.L D0,-(A7)
00000e88   4e4f            TRAP #15
00000e8a   a268            sysTrapTimeToAscii        ;convert the current time to ASCII chars
00000e8c   4fef000c        LEA 12(A7),A7
00000e90   48780000        PEA $0000.W
00000e94   486f0038        PEA 56(A7)
00000e98   4e4f            TRAP #15
00000e9a   a219            sysTrapWinEraseRectangle  ;erase a rectangle part of the screen
00000e9c   504f            ADDQ.W #8,A7
00000e9e   2f3c004b0000    MOVE.L #4915200!$4b0000,-(A7)
00000ea4   486f0024        PEA 36(A7)
00000ea8   4e4f            TRAP #15
00000eaa   a0c7            sysTrapStrLen             ;get the length of the time string
00000eac   584f            ADDQ.W #4,A7
00000eae   7200            MOVEQ #0,D1
00000eb0   3200            MOVE.W D0,D1
00000eb2   7010            MOVEQ #16,D0
00000eb4   e1a9            LSL.L D0,D1
00000eb6   0041002c        ORI.W #44!$2c,D1
00000eba   2f01            MOVE.L D1,-(A7)
00000ebc   486f0028        PEA 40(A7)
00000ec0   4e4f            TRAP #15
00000ec2   a220            sysTrapWinDrawChars       ;draw the chars of the time string on the screen

Doesn't it look like a time-display routine ? We can assume that the same routine must exist for the date and for the "UNREGISTERED" message.
Let's keep on our search. At 00000EFA we have the sysTrapDateToAscii we were waiting for, and it is also followed by the same display API. Now we know that the display of the "UNREGISTERED" string should be made through sysTrapWinDrawChars.
The search for sysTrapWinDrawChars gives quite a lot of occurrences. This time, you really have to feel the code, unlike with our previous targets.
If you're an experienced cracker, you'll notice that only one occurrence of sysTrapWinDrawChars corresponds with the pattern above :

00001df0   4feffff4       L63 LEA -12(A7),A7
00001df4   3f7c00040004       MOVE.W #4,4(A7)
00001dfa   3f7c008a0006       MOVE.W #138!$8a,6(A7)
00001e00   3f7c00490008       MOVE.W #73!$49,8(A7)
00001e06   3f7c000b000a       MOVE.W #11!$b,10(A7)
00001e0c   2f3c01000000       MOVE.L #16777216!$1000000,-(A7)
00001e12   4e4f               TRAP #15
00001e14   a164               sysTrapFntSetFont
00001e16   584f               ADDQ.W #4,A7
00001e18   3f400002           MOVE.W D0,2(A7)
00001e1c   48780000           PEA $0000.W
00001e20   486f0008           PEA 8(A7)
00001e24   4e4f               TRAP #15
00001e26   a219               sysTrapWinEraseRectangle
00001e28   504f               ADDQ.W #8,A7
00001e2a   2f3c00890000       MOVE.L #8978432!$890000,-(A7)
00001e30   2f3c000c0005       MOVE.L #786437!$c0005,-(A7)
00001e36   486dff18           PEA -232(A5)
00001e3a   4e4f               TRAP #15
00001e3c   a220               sysTrapWinDrawChars
00001e3e   4fef000c           LEA 12(A7),A7
00001e42   7000               MOVEQ #0,D0
00001e44   302f0002           MOVE.W 2(A7),D0
00001e48   7218               MOVEQ #24,D1
00001e4a   e3a8               LSL.L D1,D0
00001e4c   2f00               MOVE.L D0,-(A7)
00001e4e   4e4f               TRAP #15
00001e50   a164               sysTrapFntSetFont
00001e52   4fef0010           LEA 16(A7),A7
00001e56   4e75               RTS

It's quite difficult to find the pointer to "UNREGISTERED" that must be passed to sysTrapWinDrawChars. I suppose that the PEA -232(A5) (Push Effective Address) does the trick. Anyway, now we have 2 solutions, either we prevent the call to L63 which is done at 0000307A, either we return from the procedure just after it has been called, that means we put a RTS intruction (ReTurn from Subroutine) at L63.
The opcode of RTS is 4E75h. We put it at 00001DF0 and we're done. The babe is perfectly cracked.
I must tell you that it took me about 30 minutes to figure out where was hidden the display of "UNREGISTERED" among the multiple calls to sysTrapWinDrawChars, but the first routine I patched was the right one; no luck here. I consider this as a hard crack for the pilot. Usually you can get through the protection in 5-10 minutes. I hope that now that I've written this essay some Pilot programmers will try making more funny protection (encrypted code would be MUCH fun). Maybe that one day Aladdin will make a PalmHASP... we can still dream.
 

Anyway, I think that now you've seen most techniques usable on the Pilot with only a dead listing approach. If you think that you've had enough for now, you can stop reading and begin you first Pilot crack, but if you're interested in understanding the M68000 assembler a bit better, there is still something funny we can do : a key generator. Therefore we'll get back to Currency Calculator. We'll write our own key gen using Java. Why Java ? It's portable Sir. It might be run on a PC as well as on a Mac or even on a Pilot ;) I'm not a Java guru at all, so please don't criticize my code too much; it runs and that's more than enough for me !
I will explain only succinctly the boring parts of the key gen process, as you are all able to figure out what I did.
Here is the protection part of CURRCAL1.PRC again :

00007d8a 2c48                L1174 MOVEA.L A0,A6
00007d8c 2f0c                      MOVE.L A4,-(A7)
00007d8e 4e4f                      TRAP #15
00007d90 a139                      DC.W sysTrapFldGetTextPtr   ;get a pointer on the first text field (User Name)
00007d92 2808                      MOVE.L A0,D4
00007d94 2444                      MOVEA.L D4,A2
00007d96 2f0e                      MOVE.L A6,-(A7)
00007d98 4e4f                      TRAP #15
00007d9a a139                      DC.W sysTrapFldGetTextPtr   ;get a pointer on the second text field (Reg. Num.)
00007d9c 2a08                      MOVE.L A0,D5
00007d9e 4a84                      TST.L D4                    ;first text field pointer = null ?
00007da0 4fef000c                  LEA 12(A7),A7
00007da4 6748                      BEQ L1177                   ;if yes, branch to Bad_Guy
00007da6 4a85                      TST.L D5                    ;second text field pointer = null ?
00007da8 6610                      BNE L1176                   ;if no, calculate the right Reg. Num.
00007daa 6042                      BRA L1177                   ;if yes, branch to Bad_Guy
00007dac 1012                L1175 MOVE.B (A2),D0              ;calculate the right Reg. Num. from the User Name
00007dae 4880                      EXT.W D0
00007db0 d046                      ADD.W D6,D0
00007db2 064004a3                  ADDI.W #1187!$4a3,D0
00007db6 3c00                      MOVE.W D0,D6
00007db8 528a                      ADDQ.L #1,A2
00007dba 4a12                L1176 TST.B (A2)                  ;ASCIIZ string : did we reach the 00h
00007dbc 66ee                      BNE L1175                   ;loop while not end of User Name string
00007dbe 2f05                      MOVE.L D5,-(A7)
00007dc0 4e4f                      TRAP #15
00007dc2 a0ce                      DC.W sysTrapStrAToI         ;convert the entered Reg. Num. to Integer
00007dc4 7200                      MOVEQ #0,D1
00007dc6 3206                      MOVE.W D6,D1
00007dc8 b280                      CMP.L D0,D1                 ;are the calculated and the entered Reg. Nums equal ?
00007dca 584f                      ADDQ.W #4,A7
00007dcc 6620                      BNE L1177                   ;no, then branch to Bad_Guy

Everything happens in L1175. From 00007D94 we know that A2 points to the beginning of the User Name string. Each character will be loaded into D0 (at 00007DAC) and D0 will be extended to a word. Then, D6 (which contains a number calculated previously) is added to D0, 04A3h (=1187d) is also added to D0 and D0 is copied to D6. The same algorithm is applied to each character of the User Name. Here is the code explained line by line :

00007dac 1012                L1175 MOVE.B (A2),D0              ;copy one character of the User Name to D0 (BYTE PTR)
00007dae 4880                      EXT.W D0                    ;extend D0 to a word
00007db0 d046                      ADD.W D6,D0                 ;add D6 to D0 (WORD PTR)
00007db2 064004a3                  ADDI.W #1187!$4a3,D0        ;add 04A3h to D0 (ADD Immediate value)
00007db6 3c00                      MOVE.W D0,D6                ;copy D0 to D6
00007db8 528a                      ADDQ.L #1,A2                ;inc A2
00007dba 4a12                L1176 TST.B (A2)                  ;did we reach the end of the User Name string ?
00007dbc 66ee                      BNE L1175                   ;if no, then loop back to L1175

A good question that you might ask is : what is the value of D6 at the beginning of the loop. Reversing the whole thing shows that at 00007C8A D6 is initialized to 0. Now everything is ok to make our key generator. Here is the Java code that I've written :
 

import java.awt.*;
import java.applet.*;
import java.lang.*;

public class CurrCalcKeyGen extends Applet
{
Font font;
Panel ThePanel = new Panel();
TextField UserNameField = new TextField(30);
String Generated = "";

        public void init()
        {
        setBackground(Color.white);
        ThePanel.add(new Label("User Name : ", Label.RIGHT));
        ThePanel.add(UserNameField);
        add(ThePanel);
        add(new Button("Generate The Registration Number"));
        resize(400, 170);
        }

        public boolean action(Event evt, Object arg)
        {
        int GeneratedRegNum=0;
        String UserName = UserNameField.getText();

        if (UserName.length()==0)
        {
                Generated="Maybe you should enter something...";
        }
        else
        {
                for (int i=0;i<UserName.length();i++)
                        GeneratedRegNum+=UserName.charAt(i)+1187;
                Generated="Your registration number is : "+GeneratedRegNum;
        }
        repaint();
        return true;
        }

        public void paint (Graphics g)
        {
                g.setColor(Color.blue);
                font=new Font("TimesRoman", Font.BOLD, 20);
                g.setFont(font);
                g.drawString(Generated, 50, 100);

                g.setColor(Color.black);
                font=new Font("TimesRoman", Font.BOLD, 10);
                g.setFont(font);
                g.drawString("Written by TeK", 300, 140);
        }

}
 

I think that there is nothing more to explain. That's quite easy. You can click here to view this code in action. The generator works fine, but you may experience problems if you use weird characters in the User Name (like accents). The Pilot character set is definatelly not the Unicode used by Java.
Furthermore, the registration number is a WORD. If your User Name contains more than 50-55 chars, the Reg. Num. may get bigger than 65535 and what happens then ? Well, it should come back to zero... but our Java key gen will not. As you can see, not all of what I call "limit cases" are treated here, but the key generator will work if it's used normally. The zero-char string case has been treated.

 
Final Notes 
 
I tried to give you a wide range of the possibilities you have when cracking on the PalmPilot. As you have seen, the protections are easy to defeat as long as you have some slight knowledge of the M68000 assembler. Now you should all be able to crack almost any Palm app. The dead list approach we used is not the only one. There are good Pilot debuggers out there, but I'm not sure that you'll crack much quicker with them. Another very good way to crack Pilot apps that I've experienced is the on-Pilot cracking. There is an excellent program called Insider that allows you to twiddle with the Pilot's memory and to disassemble the code on-the-fly. This is not a debugger; just a disassembler and patcher. Insider is shareware and you'll have to pay it to disassemble programs (the Disassemble routine doesn't seem to be in the code of the shareware version... don't even think of cracking it :). You can find it at PilotGear.
You'll find many sharewares out there which will display a nag-screen when you launch them. Usually the nag-display routine is located at the very beginning of the program. Pilot apps are quite linear as they are mostly programmed using assembler or C. This means that there is quite a good proximity between the procedure and its caller. This fact is not universal, but it may help you to crack some targets (like PAL) which need a good feeling of the code. The same property is usually applicable to HLL's where encapsulation is a proof of a well programmed (and easily crackable :) application, but this is not the subject of this essay.
If you have found some errata in this essay, if you have something interesting to tell me, if you think my english sucks (and I know it does), if you wanna trade some bootlegs or if you have found a target that uses the Aladdin PCS protection scheme, you can contact me at : tek@bootlegs.ml.org
Here are some quick greets and thanks :

"La culture ne s'hérite pas, elle se conquiert."
André Malraux

 
Appendix 
 
You will find an exhaustive list of all Pilot sysTraps in the file PILOT.INC of the ASDK package. Here are some system traps that you may want to pinpoint in your dead listing (they are often used in protection schemes) :
 
sysTrapDateDaysToDate
sysTrapDateToDays
sysTrapDateSecondsToDate
sysTrapDateToAscii
sysTrapDayOfMonth
sysTrapDayOfWeek
sysTrapDaysInMonth
sysTrapFldCopy
sysTrapFldCut
sysTrapFldDrawField
sysTrapFldEraseField
sysTrapFldGetTextPtr
sysTrapFldGetSelection
sysTrapFldGetTextLength
sysTrapFldGetTextHandle
sysTrapFldSetMaxChars
sysTrapFrmAlert
sysTrapFrmCustomAlert
sysTrapFrmHelp
sysTrapFrmDrawForm
sysTrapFrmEraseForm
sysTrapScrInit
sysTrapScrCopyRectangle
sysTrapScrDrawChars
sysTrapStrCopy
sysTrapStrCat
sysTrapStrLen
sysTrapStrCompare
sysTrapStrCaselessCompare
sysTrapStrIToA
sysTrapStrAToI
sysTrapStrIToH
sysTrapStrChr
sysTrapStrStr
sysTrapStrToLower
sysTrapSysRandom
sysTrapSysTimerRead
sysTrapTimeToAscii
sysTrapTimGetSeconds
sysTrapTimGetTicks
sysTrapTimSecondsToDateTime
sysTrapTimDateTimeToSeconds
sysTrapTimSleep
sysTrapTimWake
sysTrapWinCreateWindow
sysTrapWinDeleteWindow
sysTrapWinInitializeWindow
sysTrapWinAddWindow
sysTrapWinRemoveWindow
sysTrapWinCopyRectangle
sysTrapWinDrawRectangle
sysTrapWinEraseRectangle
sysTrapWinDrawChars
sysTrapWinEraseChars
 
 
Ob Duh 
I wont even bother explaining you that you should BUY this target program if you intend to use it for a longer period than the allowed one. Should you want to STEAL this software instead, you don't need to crack its protection scheme at all: you'll find it on most Warez sites, complete and already regged, farewell. 


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

papers
+HCU papers

redhomepage redlinks redsearch_forms red+ORC redstudents' essays redacademy database
redreality cracking redhow to search redjavascript wars
redtools redanonymity academy redcocktails redantismut CGI-scripts redmail_reverser
redIs reverse engineering legal?