SSI Win32 Dongle Protection
Initial workaround for difficult Win32 targets

 
Dongleling

22 January 1998

by Spyder

 


Oh my dongle! Just one day after the spectacular essay by Quine here we have another incredibly interesting essay by Spyder... Dongle protection schemes 'as wrappers' seem to be all the rage now, and here you have another very sound approach to 'unwrapping' inn order to undongle... and I know that some friends working on Cubase will be VERY happy to read these recent essays...
Moreover I'm happy to notice that we are (finally) moving from the boring 'how I cracked this specific proggy gna gna gna' (who cares?) to the much more interesting, and important for anybody, 'object oriented' cracking (in this case 'Sentinel Oriented' of course :-)
I like a lot this work by Spider... may be a little note about this passage he wrote:

"...I haven't looked at the exact details of the 

main encryption, but it isn't weak. 

I'm pretty sure it is a rolling encryption...

I believe it would be interesting to have an add-on on this 'rolling encryption': is it a characteristic of Sentinel's schemes? How does it work? How is it implemented? Which tricks are 'rolling' inside it? Unless it is a banal "byte shifting" kind of rolling, which would indeed prove to be unimportant...
So... and now I'll leave you to this tasty reading, prepared for your reversing pleasure by our +contributor Shadow, that gave us a couple of months ago his sound essay about a fundamental tool of the trade: BoundsChecker.
Enjoy!


Related:

Packers

 

There is a crack, a crack in everything That's how the light gets in

 

Rating

( )Beginner (x)Intermediate (x)Advanced ( )Expert

 


This essay describes a method to work around a rather awkward dongle protection for Win32 programs using Sentinel dongles.


SSI Win32 Dongle Protection
Initial workaround for difficult Win32 targets
Written by Spyder

Introduction




This isn't a complete crack of anything, just a workaround which makes

a seemingly impossible crack possible.



I know little about dongles, or about the companies that make them. 

For this target the company is called "Sentinel", and if you see 

references to Sentinel, or SSI, then we are talking about the same 

thing. If you tried for a dead listing and found megabytes of garbage 

that's also a good (or bad?) sign.



I know little about the actual dongle code - never had to look at it -

setting breakpoints on printer port I/O or something is the *last* way

to start cracking any dongle-protected (aka dongled) program (IMHO).



Tools required

Borland Turbo debug.
Borland Tdump is handy.
A good binary editor
A good disassembler (can you say IDA?).


Target's URL/FTP

There is no specific target.

Essay


Why was this crack going to be so impossible? Well the dongle code is a

wrapper for a semi-protected executable. When the wrapper is applied

it encrypts most of the executable code, in fact it attaches to the end 

of the program and takes over the program entry point.



When the program is run, the dongle code gets control, and if it is happy

with the dongle it will decrypt the executable and pass control to it.

The executable can then call back into the dongle code to make whatever

specific dongle checks it wants, in  order to confirm that the dongle 

is still present at various times during execution.



So even if you crack the initial dongle code you will still need to

understand and patch the main executable. The encryption makes

understanding difficult and patching almost impossible. Fully cracking

the dongle code is unlikely to be an option. These types of dongles do

things like returning a value from a variable string passed to them, the

algorithm and keys to do this are actually sitting inside the dongle - 

there is no easy way of patching the dongle driver code to get the same 

result.



I haven't looked at the exact details of the main encryption, but it

isn't weak. I'm pretty sure it is a rolling encryption where changing

one byte will affect all following bytes which is why patching is so

hard.



I am also pretty sure that the encryption keys come out of the dongle

(they should work this way if the dongle suppliers have any sense) 

which means you are going to need the dongle at least for a couple of 

hours, but, you might also have SOME LUCK. "Cracking without luck it's 

as impossible as cracking without feeling".



If the program has a demo mode, or perhaps some kind of option for network

licensing, then it has to be decrypted without the dongle present, 

so it can run and then decide if it really needs a dongle or a network 

license or whatever in order to run fully.



So, knowing this, how do we work around it?



My approach is to undo what was done when the wrapper was applied,

re-creating something near enough to the original program before it was

wrapped, so that normal reversing techniques can be used.



Lets look at  some interesting bits of a tdump for a sample program:-



Entry RVA                0003D950

Image base               00400000



Object table:

#   Name      VirtSize    RVA     PhysSize  Phys off  Flags

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

01  .text     0001E200  00001000  0001E200  00000400  E0000020 [CERW]

02  .rdata    00000800  00020000  00000800  0001E600  C0000040 [IRW]

03  .data     00013E24  00021000  0000D200  0001EE00  C0000040 [IRW]

04  .PAD000   00000E00  00035000  00000E00  00000000  C0000080 [URW]

05  .SSINod   00007A00  00036000  00007A00  0002C000  E0000040 [IERW]

06  .rsrc     00000800  0003E000  00000800  00033A00  C0000040 [IRW]

07  .idata    00000C00  0003F000  00000C00  00034200  C0000040 [IRW]

08  .reloc    00000200  00040000  00000200  00034E00  42000040 [IDR]

 



SSINod is the added dongle code, PAD000 is where the original program

.reloc segment (which contains import addresses patched up during

program load) was. Image base is where the program gets loaded in a flat

memory model (most addresses are relative to this base). Entry RVA is

the program start address.



The next step is to get the program loaded and decrypted and into Turbo

debug. If the program runs and stays running while it presents an error

message then the best operating way is to fire up TD32 in a dos window 

and attach to the program. One of the wonders of Win32 debugging (dunno 

how it works): just pick File | Attach and select the window, after a 

while TD32 will get control of the program and you can look around. 

You might also be able to start the program with TD32 but getting 

control once it has run and decrypted isn't so easy. 

You may even be able to trust the memory image when the program has 

terminated or maybe look at the stack and find some locations where 

an hardware breakpoint can be set. 

I'm sure it's a lot easier with softice but softice (as far as I know) 

can't do what TD32 is about to.



Anyhow I assume you somehow managed to get control of the program 

using TD32. 



Have a look at the image base + .text RVA and make sure it looks 

like code, to confirm that the program was decrypted, if not then 

maybe you need to borrow a dongle from some friends and start again.



Now open up a dump window, go to (Ctrl-G) the image base address and

start marking a block by holding shift and dragging the mouse from the

required hex byte (block marking in TD32 is a bit strange and shift

cursor keys don't always work). Now go to the end of the .text segment

(which should extend the marked block). Select Block | write (Ctrl-B, W)

and TD32 will kindly dump the executable header and whole decrypted

.text segment to a file for you. 

TD32 seems to write such blocks at about 1-2kB per second, which is 

pretty slow, so you might take a coffee/cocktail break. 

(Sorry if I am being too specific about "driving TD32" but the first 

time I did this I didn't realise TD32 could dump memory blocks to

disk and I spent hours writing memory dump 'panes' to the log file 

and then I wrote a whole own-made program to turn the dumps back into 

binary, so I want to make sure that my readers will know this trick 

- a little knowledge sometimes goes a long way).



Now one more thing before we are done with TD32. Take a look at the

PAD000 segment. It will be mostly zeros and you will see a block of 

32 bit addresses.

These are the import entries which were patched up at load time in 

the .reloc segment and part of the dongle code copies them here, 

where the main executable expects them to be. 

The order and number of entries is not the same as in the .reloc 

segment so you can't do a simple copy of it, nor fiddle with RVAs 

to get them in the right place. 



Set an hardware memory write breakpoint on any of these locations 

and then restart the program from TD32 (Ctrl-F2).



TD32 should break in the middle of the dongle code which is copying

across these entries. Take a look at the code and -if it is like the

stuff I have seen- you will find a table of pairs (couples) of 32 bit 

addresses pointed to by ebx. 

These are pairs of relative (to image load) addresses inside .reloc, 

with the required relative address in .PAD000 for the same

import. Mark this table and dump to disk as before.



Now we are done with TD32 and -probably- with the dongle.



Putting it back together.



Now we have to insert the decrypted dump back into the executable, which

is really just binary editing of a sort, but rather tricky. 

Take another look at the tdump object table and understand what it 

means...



Entry RVA                0003D950

Image base               00400000



Object table:

#   Name      VirtSize    RVA     PhysSize  Phys off  Flags

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

01  .text     0001E200  00001000  0001E200  00000400  E0000020 [CERW]

02  .rdata    00000800  00020000  00000800  0001E600  C0000040 [IRW]

03  .data     00013E24  00021000  0000D200  0001EE00  C0000040 [IRW]

04  .PAD000   00000E00  00035000  00000E00  00000000  C0000080 [URW]

05  .SSINod   00007A00  00036000  00007A00  0002C000  E0000040 [IERW]

06  .rsrc     00000800  0003E000  00000800  00033A00  C0000040 [IRW]

07  .idata    00000C00  0003F000  00000C00  00034200  C0000040 [IRW]

08  .reloc    00000200  00040000  00000200  00034E00  42000040 [IDR]





The .text segment RVA is 1000 which means that in memory this is 

started at the image base + 1000 = 401000. 

The Phys off is where .text lives in the executable file. 

That means the decrypted dump has c00 bytes between 400 and 1000, 

which need to be cut. 

The executable file header is not encrypted, and in my experience 

it is always identical in the memory image. 

With you favorite editor, hack out the c00 bytes and paste

the dumped image on top of the executable.


Fixing the imports.



We have this dump of pairs of addresses to move import addresses between

.reloc and .PAD000 segments at start up. We should have plenty of space

for code in the .SSINod segment as once the program is really cracked it

shouldn't ever have to call inside there.



I turned the binary dump into hex, then manually edited it into db

assembler statements for any old assembler that can create a binary

output file. Add A1h in front of the first address for a mov eax,[????]

and A3h in front of the next for a mov [????],eax. Remember to add the

Image load address to all addresses as they are also relative. Double

check that you are loading from .reloc and storing into .PAD000.



I just dumped this binary fragment into the executable at the start of

the .SSINod segment. You might then want to patch up the Entry RVA in

the executable header to point at this code (or patch a jump in later).


Where are we now?



At this stage you should have an executable that has no encryption and

will start running a lump of code that moves import addresses to where

the original program expects them. The entry point probably points at

this code but don't run it as the import patch is currently followed by

dongle garbage. The executable should be exactly the same size as the

original - if not I'm afraid you messed up the editing somewhere.



Now you have something you can start cracking, fine for dead listing, 

but you will have to find the original program entry point and patch 

inside it a jump at the end of the import patching code before you 

can try to run it.



If you are using IDA it may well discover the program entry point as

a standard runtime library startup function although IDA seems not to

automatically recognize the compiler in these reconstructed executables

(select a signature manually). The other alternative is to debug another

program built with the same tools to find what the entry point 

code looks like. You could even search for likely looking code, 

startup code will anyway probably call GetVersion pretty quickly.



Once you have found and patched inside the original program entry 

point, the workaround is done. You have now an executable with the 

same function as the original before it was wrapped.



The chances are that this program will still call into the dongle 

code but as the authors expected the dongle wrapper to make examination 

difficult and patching impossible they are unlikely to have done 

anything too sophisticated, and if they have, that suit us well: even 

more challenges!




Final Notes


Well I hope you found this interesting and perhaps useful. I haven't

seen this particular sentinel dongle encrypt anything more than the 

.text segment, indeed, it doesn't always encrypt the whole 

text segment.



The same recovery technique could be used for other encryption based

schemes but things get tricky where more than the .text segment is

encrypted. You would have to break and capture an image before the

program runs enough to 'smudge' its own data segments, the .reloc 

segment is particularly painful as the OS 'corrupts' that during 

loading (however, this kind of stuff is equally difficult for 

the protectors).



After having written this essay I read Quine's excellent HASP essay,  

published yesterday by fravia+, where Quine shows how to dump 

large areas of memory with SOFTICE, among other marvels. 

The HASP protection sounds quite similar to my Sentinel one.

I suspect the Sentinel rolling encryption is more robust. I have also

seen Win32 HASP protected targets with no encryption (possibly because

they also had network licensing options).



Spyder




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.