Copy protection for a .NET application

W

William Stacey [MVP]

Not sure if this product works well or not, but thought it looked
interesting. Salamander .NET protector takes your code to produce native
code like:
00000000 mov eax,dword ptr ds:[20004000h]
00000006 mov ecx,dword ptr [eax]
00000008 mov eax,dword ptr ds:[200046C0h]
0000000e call dword ptr [eax]
00000020 ret

From this:
IL_0000: ldstr "Hello World using C#!"
IL_0005: call void [mscorlib]System.Console::WriteLine(string)
IL_00a: ret

Have not tried it, but sounds interesting. Anyone use it?
 
W

William Stacey [MVP]

Agreed. When using XenoCode with control flow obfus and IL cracking, I have
not been able to decomiple a clean enouph version to start really reading.
In some respect I guess, IL and obfuscation may be harder to crack then
native code without obfuscation - assuming one knows how to look at (and
change) both.
 
J

Jon Skeet [C# MVP]

William Stacey said:
Not sure if this product works well or not, but thought it looked
interesting. Salamander .NET protector takes your code to produce native
code like:
00000000 mov eax,dword ptr ds:[20004000h]
00000006 mov ecx,dword ptr [eax]
00000008 mov eax,dword ptr ds:[200046C0h]
0000000e call dword ptr [eax]
00000020 ret

From this:
IL_0000: ldstr "Hello World using C#!"
IL_0005: call void [mscorlib]System.Console::WriteLine(string)
IL_00a: ret

Have not tried it, but sounds interesting. Anyone use it?

Interesting - seems to be a variant on the linker, basically - except
using a "pseudo-native" code rather than real native code. I do wonder
to what extent it's security through obscurity though - just a
different format for what is still really MSIL. I'd need to know
exactly what it was doing to say for sure, of course, and I'm not about
to spend a huge heap of time or money on it...
 
J

Jon Skeet [C# MVP]

Jon Skeet said:
I'm off to bed now, but I'll be fascinated to see that executable
(along with exact details of how you produced it) in the morning...

Just for anyone following this thread - I haven't heard anything back.

I have, however, tried playing around with ngen just for kicks. I took
a normal, very simple C# application:

using System;

class Test
{
static void Main()
{
Console.WriteLine ("Hello");
}
}

I compiled and ran it, producing "Hello" as expected. With a binary hex
editor, I then changed the "Hello" to "Hallo" - ran it, and got the
obvious output. I then ran ngen on it, and edited the IL to "Hxllo"
afterwards. Ran it again, and "Hxllo" was produced, showing that the
normal assembly was still being used (as it couldn't have made it as
far as the native code). Whether that was due to the string table from
the normal assembly being used by the ngen code, or the framework
realising that there was a change, I don't know - but it doesn't really
matter, as it seems to disprove Robby's point, as far as I'm concerned.

Still, I suppose it's always fun to be told I've made grossly incorrect
statements ;)
 
G

Guest

Hi, all.

Well, reading all the thread, there's a really good way to make a copy
protection for a IL (or bytecode for Java) available. Besides obfuscation,
which is good for many of the cases, the approach I'll tell you is for *real*
paranoids.

In protecting some piece of code from analysis requires that it is
impossible to reach that piece of code from within the context of
application, that is, run that code somewhere else.

The best candidate, as far as I know, is smartcards with crypto
co-processors.

Have the smartcard generate a key pair for you and store the private key
inside itself, never telling it even you. Then, put a piece of code in the
smartcard and give it the access credidentals with only the public key that
the card delivered you. Use a secure communication protocol between the
smartcard and the computer, so that nobody will be able to intercept the data
transmitted.

When your program is running as shareware, it won't require the vital piece
of code that needs to execute in the smartcard. But when it is licensed, you
give your customer the card and the corresponding public key. So, when in
licensed mode, the card executes the vital code, and returns only the
required results meaningful only for that license or context. (The code
inside the smartcard may be dependent on some data or other code in your
application, but your application *must* be dependent on this code piece.)

I used this approach on some projects, and proved well. You can check out
possible cards supported by Windows CSP from Gemplus, Sclumberger and Orga.
The capacity of cards range from 8 to 128 Kbytes, which is sufficient for
many types of applications.

As this is the hardest nut to crack, this is also very hard to code, so you
decide if you want it or not...

Salih
 
M

Michael Giagnocavo [MVP]

It all depends on what the objective is. If it's to understand the working
and architecture of an application, it should be exceedingly hard. If it's
to simply find a single branch instruction, well... perhaps it's much
easier.

--
Michael Giagnocavo
MVP
www.atrevido.net


William Stacey said:
Agreed. When using XenoCode with control flow obfus and IL cracking, I
have
not been able to decomiple a clean enouph version to start really reading.
In some respect I guess, IL and obfuscation may be harder to crack then
native code without obfuscation - assuming one knows how to look at (and
change) both.
 
W

William Stacey [MVP]

True. But it is no harder to branch around this then anything else if your
talking patching (not simple keygens). If keeping secrets, then maybe a
good way to go but seems to have all the draw backs of a dongle which I
would never buy (again).
 
R

Robby

Did you compile for release or debug? Did you move the NGENed assembly to a
different folder or .Net installed computer?

--Robby
 
J

Jon Skeet [C# MVP]

Robby said:
Did you compile for release or debug? Did you move the NGENed assembly to a
different folder or .Net installed computer?

I just compiled with the defaults from the command line.

Note that running NGEN doesn't change the assembly it's run on - it
just adds the native image to the GAC's native images section. I don't
see why moving the assembly itself around either within the same
computer or to a different one would make any difference. (I'd need to
run NGEN again on the other computer, of course.)

However, as you're the one suggesting that NGEN is the way to go, you
should be the one to tell us how we're supposed to get a program
running without the original assembly.
 
R

Robby

Jon Skeet said:
I just compiled with the defaults from the command line.

Note that running NGEN doesn't change the assembly it's run on - it
just adds the native image to the GAC's native images section. I don't
see why moving the assembly itself around either within the same
computer or to a different one would make any difference. (I'd need to
run NGEN again on the other computer, of course.)

However, as you're the one suggesting that NGEN is the way to go, you
should be the one to tell us how we're supposed to get a program
running without the original assembly.


A NGENed assembly has a special non-accessible cache created where the
machine code in stored. When you modify the IL assembly and re-execute it
the .Net Framework stops pointing the the cache and uses the IL cache
instead. This is why you see the changes made to the IL assembly instead of
the cached machine code version.

--Robby
 
J

Jon Skeet [C# MVP]

Robby said:
A NGENed assembly has a special non-accessible cache created where the
machine code in stored.

I don't know why you think it's non-accessible - I found it very
easily.
When you modify the IL assembly and re-execute it
the .Net Framework stops pointing the the cache and uses the IL cache
instead. This is why you see the changes made to the IL assembly instead of
the cached machine code version.

Exactly. The whole point was to demonstrate that. What that means is
that you can't execute the native code without the original assembly,
contrary to your previous assertions.

You still haven't detailed exactly how you think you can use NGEN to
foil people who wish to decompile the assembly. Maybe if you gave step-
by-step instructions as to how you'd go about it, things would be
clearer.
 
M

Massimo

your application *must* be dependent on this code piece.

That's the failure point of your solution. Even in this case, there will be
some point in the application where an IF statement will compare the value
returned from the smart card to something else, and decide if the program is
allowed to run. Find that statement, and you crack the program...

Massimo
 
W

William Stacey [MVP]

That's the failure point of your solution. Even in this case, there will
be
some point in the application where an IF statement will compare the value
returned from the smart card to something else, and decide if the program is
allowed to run. Find that statement, and you crack the program...

Well said.
 
G

Guest

Well,

I think I couldn't point out the case I was talking about. OK, for the sake
of bravity, I'll state these axiomes:

1. Anything locked by a human being can be opened or broken by another human
being.
2. Anything that runs on deterministic fashion (in a way that uses a limited
set of commands like that of a CPU or IL) can be backtracked and reverse
engineered.

We can't do anything about the 1st axiome, as all programmers I know are
human beings, so what we may try is, to make our code for copy protection
less deterministic. With the help of obfuscators, we try to reach this goal.

For further confusion to be put on intruder is, to put *some* other also
deterministic in nature, but indeterministic in vision, a piece of code that
is vital for the protected part of the program. I don't say, just do some
hashing etc. and return the result to the program and compare with something
else and unlock something or not.

What I say is, run some part of the application *outside* the application
context, Windows and CPU that the application is already running. Physically
seperate these two parts of application. For example, using RPC, we do just
this, have some code run on another computer. So that intruder can just trace
the encrypted traffic between these two parts.

Of course it is possible to analyse the main application and find out what
that vital code is doing in that black box and write some other piece of code
or just patch the application, so that it has the same piece of code running
in the same context. But, here is the point: How much will it cost to achieve
this goal?

If I need supercomputers to find out the key pair generated (And don't
forget, my suggestion states that private key is only known by the card
itself. Not even by the programmer or personalizer) and a class 1000 (that is
1000 particles in 1 cubic meters of air) clean room and an electron scanning
microscope to crack a program, well, it's better to buy it...

Of course, if you increase the cost for breaking a system you also increase
the cost for building that system...

That's what I think. I never asserted that the solution I offered was
impenetretable. It is just too expensive to impenetrate...

Salih
 
W

William Stacey [MVP]

Thanks Salih. I think what we are saying is a bit different. You are 100%
correct from the protection stand point. Trying to break a hidden algo on a
card would be too hard. Good protect from that stand point. However, what
we are saying is you can easily find where your program calls your "Card"
method, returns, and does an IF test to see if we can continue. Now you can
patch that and just "JUMP" around it. The hacker does not need to break RSA
or hash or Smart card. All he has to do is set the Test to true and he
totally went around all your protections. This is easier then you may
think. You can't really protect against this kind of hack, but only make it
harder to read and figure out your code, etc. A very good discussion of
these methods are at:
http://www.atrevido.net/blog/CategoryView.aspx?category=Code
 
C

C-Services Holland b.v.

William said:
Thanks Salih. I think what we are saying is a bit different. You are 100%
correct from the protection stand point. Trying to break a hidden algo on a
card would be too hard. Good protect from that stand point. However, what
we are saying is you can easily find where your program calls your "Card"
method, returns, and does an IF test to see if we can continue. Now you can
patch that and just "JUMP" around it. The hacker does not need to break RSA
or hash or Smart card. All he has to do is set the Test to true and he
totally went around all your protections. This is easier then you may
think. You can't really protect against this kind of hack, but only make it
harder to read and figure out your code, etc. A very good discussion of
these methods are at:
http://www.atrevido.net/blog/CategoryView.aspx?category=Code

Not all protection depends on an IF statement. You can use a smartcard
(hardlock) to crypt data, which can only be read by use of this crypto
device. If you make part of your code depend on this crypto process then
it's a very different from just making a bitflip in the exe to bypass an
IF statement. We use Hardlocks to crypt certain DLLs. They have to be
read through the hardlock, otherwise they're useless. There's a whole
lot of wizardry going on to prevent people from getting at the uncrypted
code.

I'm not saying this is uncrackable (anything that can be run can be
cracked), but it's a whole lot more difficult than replacing an IF
statement.
 
W

William Stacey [MVP]

With respect, it does not matter. It eventually has to come down to an if
test somewhere in your main code. Otherwise you could never test if the
hardlock method with valid or not. It does not matter what the "blackbox"
is doing - you still have to test the return of the blackbox somewhere. If
I am still in error, please post some code to review. Don't need the
blackbox code, just the parts where you call the blackbox, return some value
and not test it with an if. Would be interested to see that. tia
 
C

C-Services Holland b.v.

William said:
With respect, it does not matter. It eventually has to come down to an if
test somewhere in your main code. Otherwise you could never test if the
hardlock method with valid or not. It does not matter what the "blackbox"
is doing - you still have to test the return of the blackbox somewhere. If
I am still in error, please post some code to review. Don't need the
blackbox code, just the parts where you call the blackbox, return some value
and not test it with an if. Would be interested to see that. tia

With respect, it does matter. I see you don't understand the method. We
have functional code wrapped up in a DLL. This DLL is then crypted
through a hardlock (www.hardlock.com). You can also crypt the whole .exe
if you want. This DLL can only be used if the hardlock is attached to
the computer. It encrytion 'envelope' decrypts the parts it needs on the
fly using the hardlock. The communication between the hardlock and the
software is also scattered with random stuff to make it very difficult
to catch what's real and what's not.

All interaction with this hardlock is regulated by the encapsulating
encryption. No intervention on my part is nescesary. As such, I don't
need to check anything from a black box, since from my POV (code) there
is no black box, that's the whole beauty of this solution.

Check out the documentation on the site. This protection is very
different from checking if that hardlock is attached, because that would
be easy to circumvent in the way you're describing.
 
W

William Stacey [MVP]

Thanks Rinze. Was not trying to be flippant with response. I assume your
talking license management here. If something else, please expand. To have
context here, lets assume we are talking license check as that is what site
mainly talks about. And your right, we probably can't crack the device or
internal structures. However, I still don't need to. Pretend we call an
IsValid() method in the hardlock. It does and does its thing with checking
keys, decrypting, xyz, etc. That is fine and good. But now, my main code
at some point need to check some reply from the hardlock to see if that was
valid or license failure. So my code my look like this (could be anything)
:

private void MainForm_Load(object sender, System.EventArgs e)
{
bool valid = HardLock.IsValid(); // HardLock goes and does its
magic.
if ( ! valid )
MessageBox.Show("Thank you for using our software. Please
obtain a valid license at xyz.com.");
}

So I can still bypass your HardLock all together with a mod to the code. I
don't need to break the hardlock, I just need to change your code. The
return value my not be a bool but something else. You can still do the same
thing. Now if all your code is in the hardlock, then that is probably a
different issue - but not sure we are talking about that. Truly interested
in this, so please post some other example if I am in error. I did look at
the site. The idea is good, but in the end it is a fancy dongle that people
will not buy sw that requires a dongle/smartcard/smart usb device (at least
a lot of people will not.) A good obfuscator and PKI would probably work as
well to make it very difficult to crack your code without requiring the
dongle. Now if we could load the whole program in the dongle and run it
from there, that may be a little more interesting. Instead of distributing
CDs or exe, you send out USB device with sw on it. Still a dongle however,
and you still have the perception issue. Is your software that great that
people will carry around this dongle with them. What if everyone did this,
I would have 20 dongles sticking out of my machine (If I could even get that
many usb ports.) As a user, chances are a non-dongle SW alternative starts
looking more attractive as the dongle feels like one more thing to keep
track of that I don't need. That said, for some high security applications,
this may be the right choice.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top