It would seem that the normal good programming practices work against
you here. If I have one class that validates that one has registered,
someone can grab a Java decompiler, hack that one class, and *voila*
they have a cracked version no matter how difficult a scheme I create
for keys. Even after I put the app through RetroGuard (a bytecode
obfuscator -- http://www.retrologic.com/), this is still a pretty easy
thing to figure out. And even if I repeat the check in a number of
classes, with differently written routines [to make mutlifile searches
for license checks a bit tougher to locate] it's still just a short
matter of time to crack a Java app if someone is determined.
Has anyone on the group come to a good solution for releasing Java
shareware with license keys that's more effective than what's
ultimately the honor system?
Thanks,
Ruffin Bailey
*Any* license key system, even if implemented in hardware, can be cracked,
so *all* of them are "ultimately the honor system". If you give the
software to someone and they can run it on an open system, then they have
everything necessary for creating a modified version that runs without
the key.
The only way this could be avoided is by having rigid DRM in *all*
hardware, made mandatory by law so that any attempt to look inside
the box is a felony. You *don't* want to live in that world, believe me.
I am working on a new security mechanism that relies on a non persistant class
loader. Basically I encypt the bytecode, load it via network (never saving to
disk) and have the classloader load it and decrypt it.
Not perfect but quite painful to reverse engineer since you need to snoop the
packets and store them, etc...
Chris
And what loads the first class loader? There always seems to be an easier
point of attack than at first appears.
First, don't mistake me as saying theres anything out there bullet proof.
As for what loads the class loader, the JVM, so what? Basically to break it
they need
to:
1. decrypt and decompile source code.
2. write their own classloader to do the same as me, using sam algorithm to
decypt (or keys).
3. add the ability to save the classes to disk.
4. now repackage the app and run it locally (assuming its a local only app).
I do not see any easier way and from my experience this is inconvenient
enough. I used Hardlock
in one of my clients apps -- pretty easy to break anyhow, and costly to boot.
Chris
In this scheme, it seems to me that the weak link might be the debugger
interface (JVMDI). Someone using the standard debugger can get to your
classloader and/or your network-loaded class (methods, fields, bytecode,
etc) after it has been decrypted by your mechanism.
Wayne
I agree that this is inconvenient enough for most purposes. If your
application becomes very popular, then someone will break any protection.
The only real safety is in running all valuable code on servers over which
you have physical control. Unfortunately this doesn't suit all applications.
As for breaking your scheme, they can use your own code to do the
decryption. They don't need to actual crack the encryption.
Mark Thornton
As long as the user can pick the VM there can be no security. Any tricks
done in the language context can be thwarted outside it.
> *Any* license key system, even if implemented in hardware, can be cracked,
> so *all* of them are "ultimately the honor system". If you give the
> software to someone and they can run it on an open system, then they have
> everything necessary for creating a modified version that runs without
> the key.
But are there any ways particular to langauges like Java (interpreted langs)
that might make up for the trouble inherent in using such a lang? I mean
even Visual Basic is relatively tough to crack. Java bytecode, otoh, is
horribly easy to change. Any two-bit Java programmer who can type "google.com"
and "decompiler" has a pretty good chance of breaking protection.
Even though even a hardware dongle is crackable, the level of effort required
to hack Java is just so much lower I was wondering if there weren't some
typical tricks that might up the ante at least a bit.
I guess it's a pretty open battleground when it comes to Java app licensing, eh?
Kinda figured as much. Time to start creating the morass, I suppose.
Thanks,
Ruffin Bailey
--
Ruffin Bailey
http://myfreakinname.blogspot.com
Nope. They need to:
o Edit java.lang.ClassLoader to intercept the appropriate call to
defineClass, and write out the unencrypted classes. (This is easy to
do, as *all* classes have to go through a bit of Java in *unencrypted*
form.)
o Decompile those classes. (Trivial.)
o Modify your classloader to not decrypt and to load from disk.
(Reasonably trivial.)
o Repackage the app and run it locally. (Probably fairly simple.)
If you'd like me to see how long it would take me, I'm happy to give it
a go. (I've done this before for people. phLicence gave the best
protection that I've seen - that took me a few hours to crack.)
Of course, the above requires someone with a *reasonably* intimate
knowledge of Java.
--
Jon Skeet - <sk...@pobox.com>
http://www.pobox.com/~skeet/
If replying to the group, please do not mail me too
Java is not an interpreted language, and never has been. *Bytecode* has
often been interpreted, even though it rarely is now. The fact that it's
still present at all is what makes Java easier to decompile (as well as
easier to do other things with). Note that .NET has a similar problem,
but MS don't seem too worried about that.
> that might make up for the trouble inherent in using such a lang? I mean
> even Visual Basic is relatively tough to crack. Java bytecode, otoh, is
> horribly easy to change. Any two-bit Java programmer who can type
> "google.com" and "decompiler" has a pretty good chance of breaking protection.
Obfuscators make the code significantly less readable, which is good for
at least preventing other people from modifying your code in useful ways
and/or trying to build their own product on it. It won't help much if
they just want to get round a licence system.
They usually don't bother to crack dongles, but just disable the bits of
code which check for its presence. If there is sufficient interest in an
application it seems to only take a few days for a crack to appear.
Mark Thornton
Never having used an obfuscator or dealed with decompiled code, I can't
really talk from experience, but I've seen non-obfuscated, non-decompiled
source that was damn hard to understand. I'd say that a sufficiently
horrid and convoluted design of the classes involved in checking the
license key, combined with a good obfuscator should result in decompiled
code that's at least as useless as decompiled C code.
Absolutely. However, that also hampers the software engineers to start
with - you should be able to write *clean* code.
Even if there's a long code path to get the licence stuff, it can often
be chopped off at the top by a single line of code that does the
equivalent of saying "I've got an unlimited licence".
The goal of cracking is often not to understand the licence code, but to
bypass as much of it as possible.
A scheme I use is to dissociate the code that gets the license information from the code that checks if
the license is valid.
You can have one or many points in your code that get/update the license information into internal
data, then check that data in many *other* places.
Again, it still isn't hackerproof, keys and locks are made for honest people ;-) but he/she will have
more work to disable the license. The bottom line still is that if it's worth it then someone will
crack it.
Eduardo
Your last statement sums up the point for me exactly. 90% of the problems you
have with cracking
can be alleviated with a reasonably secure system. I'm not worried about the
people who are willing
to go to extremes.
Theres a simple way to describe software security. Basically you can see it as
the more control the
user has, the less secure an app. So the two extremes might be a
thick/unconnected client which is
very insecure to a thin client which is the most secure (in terms of controlling
distribution).
So the point is not to defeat everyone, its to make the software inconvenient
enough that you maintain
as much control of distribution as possible.
Chris
My way only requires a way of decrypting *once* - I don't need to have
anything that allows me to decrypt in the future, so long as I've
decrypted all the classes I need to use. I don't need to understand your
algorithms or anything like that. It makes it much easier - believe me!
> Your last statement sums up the point for me exactly. 90% of the problems you
> have with cracking can be alleviated with a reasonably secure system. I'm not
> worried about the people who are willing to go to extremes.
In that case just obfuscation does a pretty good job. In fact, depending
on your user base, you may not need to do anything. Even if Java (the
language) were *truly* interpreted, most people wouldn't be able to
understand it enough to rip it off.
> Theres a simple way to describe software security. Basically you can see it as
> the more control the
> user has, the less secure an app. So the two extremes might be a
> thick/unconnected client which is
> very insecure to a thin client which is the most secure (in terms of controlling
> distribution).
>
> So the point is not to defeat everyone, its to make the software inconvenient
> enough that you maintain as much control of distribution as possible.
Absolutely.
Jon Skeet wrote:
> Chris Lambert <chris_...@transcanada.com> wrote:
> > Yep, this is yet another way, but both work just fine. Personally I don't
> > see the need to much with the core API on this at all but whatever.
>
> My way only requires a way of decrypting *once* - I don't need to have
> anything that allows me to decrypt in the future, so long as I've
> decrypted all the classes I need to use. I don't need to understand your
> algorithms or anything like that. It makes it much easier - believe me!
Fair enough, I'll defer to your judgement here :)
>
>
> > Your last statement sums up the point for me exactly. 90% of the problems you
> > have with cracking can be alleviated with a reasonably secure system. I'm not
> > worried about the people who are willing to go to extremes.
>
> In that case just obfuscation does a pretty good job. In fact, depending
> on your user base, you may not need to do anything. Even if Java (the
> language) were *truly* interpreted, most people wouldn't be able to
> understand it enough to rip it off.
True, I'm understanding they want to license though, not just avoid reverse
engineering and
protect source code.
Ruffin,
all the insightful comments posted here are obviously right:
You can crack any protection easily, if you know Java well
and if you spend enough time.
The only thing you can do is cause as much pain for the
cracker as possible by adding tons of license checks to
your sourcecode and by camouflaging the pattern, so the
cracker has to debug-find every single one.
Some hints:
- use reflection for method calls
- override fillInStackTrace() in Exceptions, if this is
O.K. for your app security and debugging:
public Throwable fillInStackTrace() { return null;}
- Don't stop your application immediately if your code detects
that someone is obviously hacking the license check (no halt
after first license check, second one fails). Modify some
variables instead that will break execution at a far later
stage in the program.
- Add some useless Exceptions to your boot process to make
the cracker dizzy.
- The most difficult-to-read code execution is quite similar
to Chris Lambert's ClassLoader:
An encrypted byte array that represents a method call.
- Completely mad execution patterns may also cause some
cracking fun. Here is one example but you may like to event
your own:
- Get your own stacktrace.
- Invert the last line.
- Call a method with this name by reflection.
...of course it's not all easy to stay Obfuscator compatible,
but Retroguard is open source.
Personalized versions are also quite helpful to restrict people
from spreading your app:
If they know that their own name is hardwired into the code
somewhere, they won't pass it around as freely.
The optimum anti-cracker tool introduces a couple of 100 license
checks into a JAR file with a couple of 100 different patterns.
It might take a manyear to get the application running again.
The weak spot:
The license key.
Kind regards,
Carl
--
Carl Rosenberger
db4o - database for objects - http://www.db4o.com
There are now some very useful tools to aid that reverse engineering as
well. While they weren't designed with cracking in mind they do help a lot.
Mark Thornton
Or the weak spot might be the bit of code which actually says whether or
not a licence is valid. Unless you don't use encapsulation (so have a 100
different classes, each representing a licence key) I would suggest that
the most obvious point of attack is the licence key class.
Using reflection is indeed pretty nasty - especially if it uses *line
number* information which will of course change when the code is
decompiled, changed, and then recompiled. Of course, all of this makes
normal development somewhat tortuous.
I doubt that any application which would take a man-year to crack would
be maintainable. I suspect I could break most Java licence schemes in a
day, given *a* valid (potentially timed or tied to IP address etc)
licence. So far the longest time it's taken me is a few hours of
concerted effort.
--
Jon Skeet
sk...@pobox.com - http://www.pobox.com/~skeet
If replying to the group, please do not mail me at the same time
Cheers.
I thought about getting in contact with you, since
I would also be interested to work with a net
ClassLoader, but I am just too busy at this point
in time, to spare time for the licensing theme again.
At dinner I just figured out the simplest pattern
that could possibly work:
You can simply use the license key as a reflection
method call to continue execution of your application
somewhere deep down in your boot-up code.
No doubt, Jon's last comment is absolutely correct:
If you have a valid key, tracing where it gos will
take you to all license checks but you could still
cover some access calls with reflection.
I think it would be fun to build an obfuscator that
handles all this for you (build hundreds of hardwired
checks into a JAR). This could be a very nice product
in combination with online micropayment.
...but you would always have to stay moving to keep
ahead of crackers that work on counter-programs.
You want to make sure, not to work with a single check
and building the checks into your application needs to
be automated.
Here is a pattern that could be added to an obfuscator:
- Write the license key to a global variable, when it is
entered.
- Obfuscator replace some method name with some three figures
of the license key.
- Replace all calls to this method with:
- Get the license key from the global variable by reflection
- Try to call the method by reflection.
- If this fails, call some random other method, to camouflage
the check point.
The above could still be easily found with Eclipse Exception
breakpoints, so you would add some on-purpose-reflection-failures
also.
If your obfuscator builds somewhat 100 of the above into your
application, you would tire any cracker that doesn't earn money
with his work.
> Using reflection is indeed pretty nasty - especially if it uses *line
> number* information which will of course change when the code is
> decompiled, changed, and then recompiled. Of course, all of this makes
> normal development somewhat tortuous.
Doing all this by hand is certainly not feasible.
(I should have come to this conclusion, before investing
a week of work. :-) )
> I doubt that any application which would take a man-year to crack would
> be maintainable. I suspect I could break most Java licence schemes in a
> day, given *a* valid (potentially timed or tied to IP address etc)
> licence. So far the longest time it's taken me is a few hours of
> concerted effort.
I think it would be possible to raise the cracking time to a week,
if you invest three manmonths to enhance Retroguard. If you really
have a lot of checks in your application, the cracker is bound to
make mistakes also and since he has no way of controlling his work
before the application is up running, he may loose patience.
0. Assign user a private key and give your public.
1. Write a bootstrap (NO encryption code, etc, it just loads the app
from server).
2. The downloaded code (in memory only), would then be executed by the
bootstrap using a public key to decrypt each class.
I was thinking here theres no simple way to defeat this, its a lot of
work, and perhaps you could encrypt a class library by each users key
creating a uinque deploy for each key ....
Just a thought .... its where I'm heading, maybe time to massage my
current licensing code to a new form here ... whether or not using a
public/private encryption scheme is appropriate is my real question ....
I guess you could also just grab environment variables, build a jar full
of encrypted classes based on these, and deploy to user. But that has
the weaknesses discussed before ....
Chris
The class is still decrypted though, and that goes through the
ClassLoader code - so you can modify ClassLoader to write the decrypted
classes to disk. There's no way round this. Sun would make it harder for
crackers if defineClass (or whichever call it is) were native, instead of
defineClass0 being native and called by defineClass. When it gets to the
stage of having to modify the VM instead of just the JRE, it gets a
little trickier...
Modifying the code for ClassLoader? Depends what you mean by trivial.
About an hour, I think it took me when I did it. And of course, you've
only got to do it once and then it's there every time you want to crack
something...
Jon Skeet wrote:
>
> And of course, you've
> only got to do it once and then it's there every time you want to crack
> something...
Worse still, as with most cracks, most of the people doing it don't
actually write the code to do the tough stuff they simply use someone
elses. Jon, did you submit a request for enhancement to change
defineClass?
--
Shane
I hasten to add that I've never made such code available, nor would I do
so :)
> Jon, did you submit a request for enhancement to change
> defineClass?
No, I haven't, actually. Certainly could do though. One interesting point
is that resources grabbed by getResourceAsStream *don't* need to come
through any intermediate Java, so you'd have to find some way of getting
the decrypted version of all resources needed before throwing away the
licence.
Pleeeeeease don't !!!
I will need the hook in the future for some bytecode
tricks to modify user classes while they are loaded.
Can't you just use an appropriate classloader to do that? I believe that
actually modifying the JRE as part of a product is illegal anyway. (I may
have stepped slightly outside the law in what *I've* done, but at least
that's not meant to be part of a product or anything.) I assume you're
talking about a product?
Oooops, yes, I took a look again and you are right.
I can't hook into the final defineClass logic anywhere
without doing something "illegal".
There is a supersimple workaround though, but I won't tell here. :-)
> I believe that
> actually modifying the JRE as part of a product is illegal anyway.
Yes.
> (I may
> have stepped slightly outside the law in what *I've* done, but at least
> that's not meant to be part of a product or anything.)
I have sent three requests to Sun so far, asking for a statement
or a permission to do something which could possibly be against
the "rules". I had the impression it's difficult to get an
answer.
> I assume you're
> talking about a product?
Yes.
...and of course I am staying on the legal side.