Re: Writing spaghetti code for obfuscation/encryption
- From: "Jim Leonard" <spamtrap@xxxxxxxxxx>
- Date: Wed, 31 Aug 2005 00:19:29 +0000 (UTC)
spamtrap@xxxxxxxxxx wrote:
> I would like for it to be similar to the copy protection schemes of
> old, that make tracing difficult and unpredictable.
>
> Can anyone offer any suggestions on how this might be done, besides
> undocumented opcodes and simple encryption?
As someone who used to be a rabid software pirate, as I imagine all
computer-obsessed teenagers once were, I have much experience in
cracking copy-protection. First off, I'd like to tell you that
anything you can come up with, someone else can undo. That's not
boasting, it's just a simple fact of life. If the only hardware
involved is the computer and the program, all obfuscation/protection
can do is deter, not prevent. My immediate advice is to not bother
trying to do this yourself, but rather license a third-party package to
do the protection and distribution (I'll justify this later, keep
reading).
That being said, copy-protection on the IBM PC in the 1980s was a
mixture of several things (sometimes all at once):
- Odd diskette formats that the '765 controller could read but NOT
write (these were created using special duplication equipment)
- Encrypted program code
- Self-modifying code
One of the hardest programs one of my colleages unprotected was the
original 1985 bootable version of King's Quest 2 for IBM PC by Sierra
Online; since you used the phrase "schemes of old", I'll use it as an
example. Here's how the scheme worked: A section of program code
(core game engine) was stored encrypted on the disk. The encryption
key used to decrypt the game code was embedded into a
specially-formatted track that the 765 controller could not duplicate
(it could read the data out of the track but could not write that track
to a new diskette due to the goofy formatting that exploited flaws of
the controller). This key was used to decrypt the main program code.
The bootloader that loaded/decrypted the main code itself had sections
of self-modifying code.
So here's the scheme in action: Put disk in, turn on computer. The
bootstrap (first 512 bytes of diskette) is loaded and runs, and the
self-modifying code transforms itself into the "real" bootloader, which
loads the encryption key from the malformed track, using it to decrypt
the game code, then jumps to the code's entry point. Why was this
difficult to crack? Several reasons:
- Being a bootable program, you couldn't run DEBUG or anything to see
what the code was doing, so you had to dump the boot sector and try to
figure out what was going on.
- Once you dumped the boot sector, you loaded it into DEBUG and saw
code that, in sections, simply didn't make any damn sense because it
was obfuscated with self-modification tricks. Figuring out the code
was very tedious, as any INT 3 breakpoints you set were most likely
turned into something else as the self-mod code was run -- which not
only FAILED to interrupt program execution, but also hung the computer
in most cases and had to reboot and start over. (The litmus test of
any good cracker is when you realize that going over a 512-byte hex
dump on paper is going to be faster than using DEBUG -- and then you
proceed to do it.)
- Once you realized what was going on, you then had to extract the
encryption key from disk, further disassemble to try to figure out the
decryption method, then decrypt the code and write it back to disk
unencrypted, then patch and relocate everything so that it would work.
This was harder than it sounds because all of the things you would
search for, like INT 13 disk accesses, were also obfuscated with
self-modifying code so you couldn't just search for the opcode sequence
"CD 13" to find them. And here's the best part: Even after it was
decrypted, you still couldn't just trace the code normally with
breakpoints because, being a bootable disk with no need for an
operating system, the code was designed to load in certain specific
places -- usually overlaying itself right on top of DOS and/or your
debugger.
This was, pardon my language, a royal fucking pain in the ass. Most
"search for INT 13 disk accesses and replace them with JMP/NOP" simple
crackers would give up in 2 minutes; for someone who is truly
dedicated, like my friend, it took a little over two weeks. Of course,
for someone who is truly dedicated, it is fun and not tedious :-) so by
protecting something so heavily you are actually issuing a challenge to
people to crack it.
(Note: I never saw undocumented x86 behavior used in copy-protection
because there simply wasn't any benefit in doing so. Undocumented x86
behavior falls along the lines of "instructions doing more/different
than intended" rather than something applicable to copy-protection such
as "instructions taking longer/shorter than intended".)
So, what should you do? If you *truly* want to protect your program,
you're going to have to use a hardware dongle. Hardware dongles are
extremely simple: Your program code is encrypted with a key chosen at
random, then that key is stored inside the hardware dongle. When the
end-user wants to run the program, the dongle must be attached to the
computer or else the proper encryption key can't be retrieved to
decrypt the program. Since each distribution of your program comes
with its own dongle and its own different key, no two keys can be used
with the same program (and vice versa). Note that this can still be
cracked -- as the program loads, dump decrypted code segments to disk
-- but it requires physical access to the hardware dongle to get the
decryption key so simply copying the data to another computer will not
give the cracker anything useful.
I hope this helps. Just curious, what are you developing that is
important enough to you to protect?
.
- Follow-Ups:
- References:
- Writing spaghetti code for obfuscation/encryption
- From: spamtrap
- Writing spaghetti code for obfuscation/encryption
- Prev by Date: Re: Writing spaghetti code for obfuscation/encryption
- Next by Date: Re: Writing spaghetti code for obfuscation/encryption
- Previous by thread: Re: Writing spaghetti code for obfuscation/encryption
- Next by thread: Re: Writing spaghetti code for obfuscation/encryption
- Index(es):