Logo




Subscribe:
RSS 2.0 | Atom 1.0
Categories:

Sign In


[Giagnocavo]Michael::Write()

 Sunday, November 28, 2004
Cracking Code 4: Replacing a strong name

In my last article, someone commented that editing an assembly would create a problem if the assembly is strong named. They are correct. If an assembly has a strong name and is tampered with, you'll get a System.IO.FileLoadException: Strong name validation failed for assembly <foo>.

Strong names are to identify an assembly. They are "strong" because the identification is provided with cryptographic means, rather than just the name of the file. The system is designed to ensure the assembly is what it claims to be, and public key cryptography proves it. Against malicious people, it can ensure someone can't drop an assembly signed with one of your trusted publisher's keys and get you to trust their assembly more than you should. It's NOT meant to be a way to stop people from editing and running assemblies on their own machine.

I was hoping there was a simple way to replace the strong name on an assembly, but I don't believe there is. Then again, there's a LOT of stuff that ships with .NET, so perhaps I just overlooked it. If so, let me know. At any rate, I wrote a tiny program to replace the strong name on an assembly. Let me explain it.

Somewhere in the assembly, a public key is provided (otherwise the runtime wouldn't know what to verify against!). Then, there is a hash of the assembly, and the hash is signed with the private key. When the assembly is modified, the hash will change, the signature will no longer match and the runtime will refuse to load the assembly. A cracker usually won't have access to the private key, and thus can't resign. However, one can simply replace the public key in the assembly with our own public key, and resign using our own private key. Problem solved.

A quick word to those who are thinking "Can't I just use SN -Vu to skip verification checking?". No, this doesn't work. Verification skipping only applies to partially (delay signed) assemblies, not to fully signed assemblies. If you somehow manage to get verification skipping working on fully signed assemblies, I'd love to know.

My program is a very simple tool with nothing amazing in it (except for a very slow search algorithm). All it does is take an assembly and a keyfile, replace the public key, and call SN -R <assembly> <keyfile> to resign. Here's how you'd use it:

1. Take Some.exe, a strongly named assembly. Modify it.
2. Note that attempting to load Some.exe will fail.
3. Create a new keyfile by running "SN -k mykey.snk". (SN is the StrongName utility that ships with the .NET Framework SDK).
4. Ensure you have the .NET Framework SDK (bin) in your path.
5. Change the public key and resign via "SNReplace Some.exe mykey.snk".

That's all. You can run "SN -Tp Some.exe" before and after to see that the public key has indeed changed. "SN -v Some.exe" will verify things are in order.

Download: SNReplace.exe (16 KB) Source: SNReplace.cs.txt (2.72 KB)
Code | Security
Sunday, November 28, 2004 7:20:21 AM UTC  #    Comments [12]  |  Trackback

 Friday, November 26, 2004
Flaime bait: A new exception in Whidbey for VB devs
http://weblogs.asp.net/wallym/archive/2004/11/25/270521.aspx

The coolest thing about this new Whidbey exception model is that the IDE actually throws exceptions *about your code* at design-time instead of runtime.

Humour
Friday, November 26, 2004 8:58:05 PM UTC  #    Comments [1]  |  Trackback

Telgua ADSL: Turbonett -- really sucks

Isn't this fun? I ordered ADSL from Telgua (Turbonett -- their marketing people are morons, yes) at a price of $229 a month for 512k. Ridiculous. Even more crazy is that now, 2 months later, they haven't installed the service. Also, since Telgua moves your phone line over to the Turbonett people, now my phone line doesn't work either. Every call to them, including talking to manager ends with some silly statement about how the technical people don't have phones, so you can't call them. I asked the guy if I should just cancel my phone and switch companies and he said “yea, you're right.” I'm supposedly getting some cable Internet today, so we'll see how that works out.

Personal
Friday, November 26, 2004 8:49:42 PM UTC  #    Comments [2]  |  Trackback

Cracking code 3: Cracking an obfuscated .NET assembly

Intro
It's been a while since I wrote anything that interesting, so I figured for Thanksgiving, I'd go ahead and do so. Merry Thanksgiving. The first article in this “series“ is here.

Cracking .NET programs can be just like cracking any other program. In this article, I'm going to use the same approach as I did last time. I threw together a quick little program called CrackMe2. CrackMe2 has a really cool feature called “Reverse Text”, however, it's only available to registered users. What's a poor boy to do?

Target
First, we try registering. Since we don't have a valid code (we don't even know what one looks like), we get an “Invalid serial.“ MessageBox. OK, so now we know that the program does something when we click a button, and if the serial is wrong, we get a MessageBox.


Darn, 123 didn't work.

Well, the first step in cracking is defining our target and it's location. Our target is the code that's deciding to say “Invalid serial.” instead of “You're registered!”. Where's the “bad code“ that needs to be fixed? Well, with a .NET assembly, our first information is gained by taking a look with IL DASM.


View of the obfuscated CrackMe2 assembly

Oh no! It's obfuscated (thanks to Ivan Medvedev's Mangler). Let's assume this is a big application and that we'll never find what we're looking for just by going through the IL. Just by glancing at the hierarchy, we don't know that much more than when we started: There's a form with code.

Seeing past the names
Now certainly, we can do static analysis and try to find out where the bad code is. One way would be by getting the strings (Ctrl+M in IL DASM, scroll to the bottom), and then grep the IL for ldstr , and work from there. In fact, that's a pretty quick and easy way to locate certain parts. However, lets pretend the strings are encrypted/dynamically generated, and that's not viable. So, let's start debugging.

[Michael@MAO C:\]$ cordbg CrackMe2.exe
Microsoft (R) Common Language Runtime Test Debugger Shell Version 1.1.4322.573
Copyright (C) Microsoft Corporation 1998-2002. All rights reserved.

(cordbg) run CrackMe2.exe
Process 4488/0x1188 created.
Warning: couldn't load symbols for c:\windows\microsoft.net\framework\v1.1.4322\mscorlib.dll
[thread 0x1510] Thread created.
Warning: couldn't load symbols for C:\CrackMe2.exe
Warning: couldn't load symbols for c:\windows\assembly\gac\system.windows.forms\1.0.5000.0__b77a5c561934e089\system.windows.forms.dll
Warning: couldn't load symbols for c:\windows\assembly\gac\system\1.0.5000.0__b77a5c561934e089\system.dll

[0004] mov         ecx,98543Ch
(cordbg)


cordbg is a command line debugger that ships with the .NET Framework SDK, and it's just loaded the CrackMe2.exe and related assemblies. Just like before, we're going to go ahead and set a breakpoint and find out where we are in the program, and work from there. So, let's breakpoint the MessageBox.Show function. We use IL-similar syntax to specify the function name: NameSpace.ClassName::Method.

(cordbg) b System.Windows.Forms.MessageBox::Show
Breakpoint #1 has bound to c:\windows\assembly\gac\system.windows.forms\1.0.5000.0__b77a5c561934e089\system.windows.forms.dll.
#1      c:\windows\assembly\gac\system.windows.forms\1.0.5000.0__b77a5c561934e089\system.windows.forms.dll!System.Windows.Forms.MessageBox::Show:0      Show+0x0(native) [active]
(cordbg)

Then, we tell cordbg to go until it breaks by typing go. The form comes up, and we enter a serial number: 123.

(cordbg) go
Warning: couldn't load symbols for c:\windows\assembly\gac\system.drawing\1.0.5000.0__b03f5f7f11d50a3a\system.drawing.dll
break at #1     c:\windows\assembly\gac\system.windows.forms\1.0.5000.0__b77a5c561934e089\system.windows.forms.dll!System.Windows.Forms.MessageBox::Show:0      Show+0x0(native) [active]
Source not available when in the prolog of a function(offset 0x0)

[0000] push        edi
(cordbg)

Bingo, we're stopped at a MessageBox. We want to know who called this function, since most likely, that will lead us to the critical code section we need to fix. So, we ask cordbg where are we?

(cordbg) where
Thread 0x1510 Current State:Normal
0)* system.windows.forms!System.Windows.Forms.MessageBox::Show +0000 [no source information available]
                owner=(0x00ac36b0)
                text=(0x00ad5854) "Invalid serial."
1)  CrackMe2!CrackMe2.Form1::AAAAAAAAAAAAAAAAAAAA +0070 [no source information available]
                AAAAAA=(0x00ac8400)
                A=(0x00aca86c)
2)  system.windows.forms!System.Windows.Forms.Control::OnClick +005e [no source information available]
                e=(0x00aca86c)

9)  system.windows.forms!ControlNativeWindow::OnMessage +0013 [no source information available]
                m=(0x0012ef04)
--- Managed transition ---

We see what's expected. Somewhere in Win32 code, a message was sent, and we see the OnMessage called and bubbling up all the way to the Control::OnClick, and then user code. We can look at all the arguments along the way, and that's useful for more complex scenarios (say, when a registration function calls another passing the serial number or validation code).

At any rate, we've got something to go on: The name of the function that calls the MessageBox: CrackMe2.Form1::AAAAAAAAAAAAAAAAAAAA (20 A's). We're done with cordbg (quit). Our next stop is to read the bad code.

Looking at the bad code
Using IL DASM (see above), I navigate to the CrackMe2.Form1::AAAAAAAAAAAAAAAAAAAA method. Inside is relatively straighforward code. First, there's a try/catch that has an Int32::Parse call in it. The result is stored in local 0. So we now know the code is numeric. Immediately after the catch handler, we have this snippet:
  IL_0022:  ldloc.0
  IL_0023:  ldc.i4.1
  IL_0024:  and
  IL_0025:  ldc.i4.1
  IL_0026:  bne.un.s   IL_0035
  IL_0028:  ldarg.0
  IL_0029:  ldstr      "Invalid serial."
  IL_002e:  call       valuetype [System.Windows.Forms]System.Windows.Forms.DialogResult [System.Windows.Forms]System.Windows.Forms.MessageBox::Show(class [System.Windows.Forms]System.Windows.Forms.IWin32Window, string)

Load the local (the number entered), then load the number 1, and AND them. Then, load one, and if they are not equal, jump to IL_0035. If they are equal, execute the following instructions, which quite obviously say “Invalid serial.”. AND'ing a number with 1 and comparing to 1 is a check to see if the number is odd. So, at this point, we can write a keygenerator that produces... even numbers. A keygenerator is always preferred to a patch, however, generally speaking, finding the algorithm might be a bit harder. Then, there's always the possibility that the check actually does something hard to fake (i.e., uses RSA or talks to a hardware dongle/web service). So, let's go on and patch this code.

At IL_0035 (the target of the branch if the number is even), we have some code that does activation work and then proceeds to say “Thank you...”. Simple sample. Now, let's make the fix.

Simple Patching
With IL DASM and IL ASM, we have a really easy way to make patches. Simply run ildasm /out=CrackMe2.il CrackMe2.exe, and IL DASM will dump all the IL required for that assembly to a nicely formatted file. All we have to do is goto the bad method and fix up the IL. I think the most unintrusive fix would be to add “br IL_0035” to the top of the method. That would branch immediately to the good code, and the product would activate on any serial number entered.

However, some obfuscators try to stop IL DASM round tripping, and that might stop some posers in their tracks. The IL obfuscator I'm going to give away for free will do this, for example. (Actually, my free obfuscator would make this tutorial a bit harder because of how it handles names -- we'd have to actually get a token instead.)

Assuming we can't use IL DASM/ASM, what can we do? Use a hex editor.

Binary Patching
When we can't reassemble an entire program, we can patch certain opcodes instead. Tools like OllyDbg have a built-in assembler so we can easily make patches to the x86 code. For IL, I'm not aware of any such tool. Another issue with binary patching IL is that we have to ensure the resulting IL is fully correct and is able to be JIT'd to native code. If our patch ends up screwing with the IL in a way that makes it incorrect, we'll get a runtime exception from the execution engine. Let's try to create a binary patch that jumps from the beginning of the method right to the good code, at IL offset 0x0035.

First, in IL DASM, turn on “Show bytes”, under the View menu. This allows us to see the actual bytes that make up the opcodes. Now, lets look at the beginning of the critical function:

  // Method begins at RVA 0x2434
  // Code size       78 (0x4e)
  .maxstack  2
  .locals init (int32 V_0)
  .try
  {
    IL_0000:  /* 02   |                  */ ldarg.0
    IL_0001:  /* 7B   | (04)000002       */ ldfld      class [System.Windows.Forms]System.Windows.Forms.TextBox CrackMe2.Form1::AAAAAAAAAAAA
    IL_0006:  /* 6F   | (0A)000026       */ callvirt   instance string [System.Windows.Forms]System.Windows.Forms.Control::get_Text()
    IL_000b:  /* 28   | (0A)000027       */ call       int32 [mscorlib]System.Int32::Parse(string)
    IL_0010:  /* 0A   |                  */ stloc.0
    IL_0011:  /* DE   | 0F               */ leave.s    IL_0022
  }  // end .try

This code is protected in a try block. We could go and remove the try block, but that's modifying more code. Generally speaking, we should aim to patch as little code as possible to ensure we don't accidentally screw something up. So, we're going to deal with the try block and fix it from within. The ECMA specifications for .NET will come in handy here. Specifically, Partition III, CIL. This can be found in the .NET Framework SDK folder, under “Tool Developers Guide\docs”. It's also available from MSDN, here.

The first instinct is to say, hey, let's change IL_0000 to a br to IL_0035, and NOP out the remainder of the try block. However, that'd create illegal code, since you can't branch out from a try block, you must use the leave opcode instead. So, let's rewrite the method to simply leave to IL_0035. Here's the description of the leave opcode:

The leave instruction unconditionally transfers control to target. Target is represented as a signed offset (4 bytes for leave, 1 byte for leave.s) from the beginning of the instruction following the current instruction.

The formats (in hex) are DD <4 bytes> for leave and DE <1 byte> (as shown above), for leave.s. We'll use leave.s, just to be efficient :). Since the total size for leave.s is 2 bytes, we calculate the offset to 0x35 from 0x02 (since our leave instruction is at 0x00). Subtraction tells us we must have an offset of 0x33. Hence, our leave instruction in hex looks like: DE 33. Since that'd leave the IL in an incorrect state, we must nop out the rest of the try block. The hex for nop is 00.

Open the assembly in your favorite hex editor, and let's find the method. IL DASM gives us the RVA, but for now we'll just search for a specific byte sequence. The IL DASM Show bytes allows us to easily find our place. Do note that the way tokens are displayed ((04)000002, for example), is reverse from how they are stored. Depending on the size of the app, you might need to search on quite a large number of bytes, since IL sequences are most likely repeated. For this case, we're going to search on the last bit: “0A DE 0F”. No other matches found, so this is the one.

As when programming, in cracking we have many ways to solve a problem. Many of them can be considered “right”. We could make a simple one-byte patch by allowing any number as a valid serial. This has the merit of ensuring the local int is assigned, and well, being only a one-byte edit. The leave.s opcode is at offset 0x11, so add 2 to that amount and we get 0x13. 0x35 - 0x13 = 0x22. So by changing “0F” to “22”, we'd have our crack. However, let's stick to the original plan and jump right to the good bits from the beginning.

In the hex editor, we back up a bit until we find the 02 7B 02 00 00 04 part (ldarg.0, then load the textbox field). At the 02, we drop our leave.s IL_0035 payload, which is DE 33. Then, we nop out (00) everything until the end of the 0A DE 0F part. The resulting hex for the try block is thus: DE 33 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00. Save the file as CrackMe2.cracked.exe.

Satisfaction
Run the program. Type in anything for the serial. “Thank you for registering.” The second textbox activates. We've won access to the coveted “Reverse Text” function. Write up an .NFO, ensuring to remind people to purchase software to support the authors. Then kick back and play a game of KSpaceDuel.

Download the program itself (Right click and save as, since it's a .NET assembly and IEExec will try to run it otherwise): CrackMe2.exe (24 KB). Or, download the source: CrackMe2.cs.txt (4.81 KB).

Was this post interesting, helpful, stupid, or lame? Leave a comment and help me improve.

Code | IL | Security
Friday, November 26, 2004 5:22:20 AM UTC  #    Comments [11]  |  Trackback

 Thursday, November 25, 2004
Overzealous defenders - or - people who don't understand why they're being insulted

Mr. F. Morales left an interesting [read: lame] comment on my post about MPAA/security stupidity down here in Guatemala (at the Miraflores / Cinepolis mall). The mall *banned* all cameras and recording equipment, and actually goes around enforcing this. (Although, this isn't any different than Disney does these days in the states.) Basically, he swears at me and tells me to put up with stupidity or get out of the country. I replied to him already, so we'll leave that alone.

What he did remind me of was a time I met another overzealous "Defender of the Republic". I was once driving home, only to find that some people had decided to park all over the road, completely blocking it off. They were all inside some little party; they weren't even thinking of moving their cars. We waited a few minutes.

Then I got out and found whoever was around there and asked them why they were such morons by parking their vehicles there, and if I should move them or if they were going to take care of it. I got a long flaming response about how I shouldn't insult people just cause they're from another country and things aren't as good as they are in the USA.

I started choking from laughter. I nicely explained to the person that being an idiot is a trans-gender, trans-racial, and international designation. I don't care if this guy is from Guatemala, Canada, Zimbabwe or Manchuria. If you park your car in the road blocking me from getting home without any reason besides laziness, I'll yell at you. Some people are so insecure or sensitive about their <whatever> (be it their OS, database engine (MySQL anyone? :)), religion, or country). Sometimes, just *sometimes*, it helps to think a bit before you get annoyed about a particular bit of criticism.

Guatemala | Misc
Thursday, November 25, 2004 3:43:08 AM UTC  #    Comments [1]  |  Trackback

 Wednesday, November 24, 2004
ast_mono - First class compiles!

I chose to expose cli.h, since it's very simple :). My code generator is now debugged enough to generate all the things required for the ManagedAsterisk and ast_mono runtime to compile and allow access to a specific .h. Even the simple cli.h, which is only 92 lines long, requires about 500 lines of output (C and C#) to be fully wiredup (of course, this counts spacing and open/close braces).  

Anyways, a bit of tweaking the generated code (and applying the fixes to the generator), it now compiles just fine without any warnings or errors. Yey.

ast_mono
Wednesday, November 24, 2004 7:18:18 AM UTC  #    Comments [0]  |  Trackback

 Sunday, November 21, 2004
ast_mono - Phase 02 - Classes and Libraries

As mentioned before, one of the challenges of ast_mono is creating a “.NET-like” library, when the underlying code is all C. Since there's no real grouping in the C API other than which functions are in a certain header file, I don't have much to go on. Here's a sample of the current thinking for the managed API:

ManagedAsterisk.Core.Cli
  Contains the cli.h constants implemented as public static readonly fields. The value is loaded in the .cctor via an internalcall that returns the constant. This was done so that if a C constant is changed later on, recompiling the ast_mono runtime will provide the new value to managed code, without any changes.
  Also contains “static” functions, such as ast_cli_command, however, renamed to Command (ManagedAsterisk.Core.Cli.Command).

ManagedAsterisk.Core.Cli.Native
  This contains all the internalcall declarations to call the runtime wrapper methods. For now, access is public to all the functions, such as ast_cli_command, ast_cli_register and so on. Field accessors (see next) and constant accessors are not accessible and must be accessed thru the respective classes. I'm not completely sure on making this public, and might mark it internal instead (unless there's a good reason that it needs to be public).

ManagedAsterisk.Core.CliEntry
  This class is the managed version of struct ast_cli_entry. All the data is kept in unmanaged memory, and only a pointer is kept in managed memory, using internalcalls to access fields. It's constructed via new (heap allocated), or it's constructed by passing a pointer. It has a manual free (IDisposable) method, but it's *not* finalizable. This is because it's quite possible that the managed reference will go out of scope while on the unmanaged side it might be still in use. Automatic finalization (And hence a free) of it could easily cause Asterisk to segfault. Do note that improper usage could lead to a memory leak, although in most cases.

  The fields, (char* usage, struct ast_cli_entry *next;, int inuse) are all available as standard class properties. They are renamed to reflect that (public string Usage{ get; set; }, etc.). Methods that take a struct ast_cli_entry* will take a CliEntry class instead.

ManagedAsterisk.Core.CliEntry.Native
  Private implementation details to get/set the data (something like ast_mono_wrapper_ast_cli_entry_set_usage). Internalcalls set/get values, as well as enforce data limits (such as array bounds -- no need to worry about buffer overflows). No plans to make publically exposed.

---
For files like channel.h, where there is a lot of both static and “instance” methods, things will be put into one class, Core.Channel. There won't be a separate Core.ChannelMethods or Core.ChannelClass. The cli.h just happened to lend itself to this format.

Currently, the ast_mono code generator is in the final stage of taking the SWiG-generated XML and producing the various declarations and wireup code required to make everything work. This generated code will be heavily hand-edited before becoming part of the ast_mono/ManagedAsterisk platform.

ast_mono
Sunday, November 21, 2004 6:05:12 AM UTC  #    Comments [0]  |  Trackback

 Saturday, November 20, 2004
Avalon's on XP

http://msdn.microsoft.com/Longhorn/understanding/pillars/avalon/avnov04ctp/default.aspx

Downloading from MSDN right now...

Code | Misc. Technology
Saturday, November 20, 2004 5:22:29 AM UTC  #    Comments [0]  |  Trackback

 Tuesday, November 16, 2004
MySQL is the Visual Basic of the DB world

Today I was having a fun discussion about MySQL. A number of people were pointing how how bad MySQL is (one Anti-MS person said “It's worse than anything MS has made.”). One of the big problems with MySQL is how it handles datatypes. It doesn't. Pass it invalid data, and it silently “fixes” it (read corrupts) so that it works in whatever column you specified. This allows people to pass whatever they want as a date, for instance.

Now, those reading who've done any real work with DBs and applications are probably saying “uh oh” right now. If I declare something as int NOT NULL, I mean it. Don't take NULL and magically conver it into 0 or empty string. Don't turn my varchar into a DateTime of 0000-0-0. If I do a query that has invalid data, *something is wrong*. Throw an error. Let the developer know.

This went back and forth for a while, until someone responded angrily and said “You: I want errors. Me: F* you, I want it to work.” This is exactly like some VB developers are thinking when they do “On Error Resume Next”. What do you think? Should a DB work like VB and “On Error Resume Next”?

I say, lets take this one step further! Why should the filesystem give us errors? “rm -rf something”? Something isn't found? Well, just use the next item found, alphabetical order. That way, we can “just work” instead of giving back nasty error messages. Sigh.

Humour | Misc. Technology
Tuesday, November 16, 2004 6:43:52 PM UTC  #    Comments [2]  |  Trackback

Annoying anti-pirating software implementors: please stop!

Quick summary for those looking for problems playing games or using software:

If you get this error, it does NOT mean you have a debugger installed or running. It doesn't mean you have SoftIce installed. It is the SafeDisc (or perhaps other) copyright protection software in action. This software often messes up, and incorrectly decides to deny you access to the programs you paid for.

Two ways to solve the problem:
 1. Complain to the game publisher. It's their stupidity that causes this kind of copyright protection to be included in the first place. Tell them you're going to return the game to the store where you bought it because of this silly protection system. Perhaps they will send you a non-protected version.
 2. Install a crack. Cracks disable the SafeDisc (and other) protection mechanisms, allowing you to play without the CD or error messages. Yes, I know it's stupid to have to do this, since you paid for the game. However, with some companies, that's the only solution. I'd also recommend avoiding purchases from them in the future (and let them know why too!). I'd highly recommend GameCopyWorld.

If you're trying to create a crack for the game, go learn more. If you have to sit around using google to figure out how to crack a game, chances are you won't succeed. Go look for some cracking tutorials first.

------- Original Article -------

Quite some years ago (8 or 9?), I played a game called One Must Fall, a cool robot melee fighter game. Now they released a new version with cool effects, Internet play, and so on: One Must Fall:Battlegrounds. I just recently learned it was shipping (they did good job of press before it shipped, but I never heard about it after it shipped). My copy finally arrived in the mail today. I start it up, check it out, and after winning a level, the game quits with this message box:
---------------------------
Protection Error
---------------------------
Debugger detected  - please close it down and restart! Windows NT users: Please note that having the WinIce/SoftIce service installed means that you are running a debugger!
---------------------------
OK  
---------------------------
This is wrong. I work from home, as well as play games from home. I've got a few debuggers installed (not SoftICE though). At the time, I had Visual Studio closed, and hadn't been running the debugger since my machine started. But what's worse is that apparently they thought this perfectly acceptable! Note that this doesn't stop piracy *AT ALL*. Experienced crackers are going to crack the game, and serious “pirates” are going to apply patches. Having a CD check stops “casual piracy”. Having a debugger check stops wannabe crackers from cracking. That's it!

I've emailed support with my current plan of action: Try a pirated version and if that doesn't work, return it for a refund (something publishers don't like). Sigh.

Update: Well, I reluctlantly installed a crack from a game backup site. And guess what? It works just fine. No more debugger complaints (and I get to take the CD out too).

Last update: Got in touch with one of the developers. At first, they thought it was a problem with DirectX, or the video card or likewise, since their code doesn't do any checking. However, they were using SafeDisc (which is less safe than rolling your own, since there are a few tools that instantly remove SafeDisc). However, after I told them that a pirate crack makes the game run, he said he'd get me an unprotected version. Hey, at least their support is good!

Misc. Technology
Tuesday, November 16, 2004 3:05:31 AM UTC  #    Comments [5]  |  Trackback

Great customer service: pirates

I was feeling nostalgic for a game I bought a long time ago, but wasn't able to find the CDs. I decided to give the local pirates a whirl. Let me go over the experience with them, then compare it with the experience of buying some software legitimately.

1. Finding the store. Simple: Just get a newspaper and scan the classifieds for computer software. One had a rather large advert that must have cost a pretty penny. Also, a lot of them have websites, making return purchases easier.

2. Finding the game. I was looking for a game that's not well played down here, so it took a few tries. However, the pirates have one thing done way better than the retail vendors: Their entire inventory is online. I haven't seen this from any retail store down here so far.

3. Placing the order. Dial the cell phone listed. Ask for game. Get *immediate* response (no wait at all), with pricing with and without warranty. Select the game + warranty (The game is 5CDs, total cost with warranty: $12). Give name and address for delivery. Since my house is hard to find, suggest meeting at the local Burger King. They say they'll be there in 2.5 hours. I tell them I'm in a dirty black Jeep.

4. Bring cash to Burger King, arriving a few minutes early. Within 30 seconds, a motorcycle pulls up beside me and offers me some CDs. Cash changed for CDs *with a receipt*!

That's it. The warranty covers the CDs from physical damage, as well as provides installation support (useful for people who buy those expensive art programs that require all sorts of network licensing managers to work).

Now, lets see how this compares to buying retail software. First, there's no website with all the inventory. So that's out. Second, calling may or may not get me correct information. Then, delivery? *Maybe*, but highly doubtful for a small order. Pricing? Hmm, games go for around $70. That's a lot, especially down here where $70 is equal to about 20% of an average salary. Sorta ridiculous actually.

Warranty? Installation support? Ha. Try to trade in something you buy at a retail store -- you'll get a flat NO. Support? Maybe. You'll probably have to make a long distance call. And then, depending on the company, support sucks (this goes for every lame game publisher, such as Eidos, Activision, etc.).

Buying a larger amount of software (say, equipping a company with 500 machines with Windows and Office)? The experience is even suckier. Big “software partners“ down here are 100% clueless. They love to waste your time asking tons of questions on the phone, not getting back to you, saying they don't sell Enterprise Licenses, trying to insist non-Guatemalan-sold versions of MS software is illegal, and sometimes, charging a ton more. I see Office on retail shelves for $800. WTF are they thinking?

Does this justify piracy? Well, no. But, it certainly is embarrassing that the customer experience is WORSE for legit customers than for pirate customers. BTW, the same goes for movies and music. If I'm tempted to buy a DVD, I'll phone the same place up. They've got a special: Any 4 DVDs for $12. Not bad, considering they do the work of getting rid of region zoning and CSS for me.

What's the lesson? Do better than the pirates. It can't be that hard not to completely suck. After all, the pirates aren't doing anything amazing. They're just providing a service like I'd expect it to be provided. Even if they had charged me $30, I'd have still paid. Didn't mean to rant on, it just annoys me when companies do a worse job, then complain when people go around them.

Misc. Technology
Tuesday, November 16, 2004 3:01:27 AM UTC  #    Comments [3]  |  Trackback

Why DRM for purchases is stupid and pointless

Digital Rights Management has been and will continue to be a hot topic for a while. On the one end we have the MPAA and the RIAA who are stuck in the early 1900s, and intelligent consumers. In the middle, we have people like Microsoft, who have to try to satisfy both ends of the scale. Then, there's some lesser companies that make DRM (like MacroVision) who even beyond the MPAA and RIAA, in the sense that they try to propogate the need for their useless technology.

Why is DRM bad? Because it hurts the customer. It takes the flexibility and usefulness of a technology away. It's anti-innovation. No one wakes up in the morning and says “Hmm, I'd like to pay money to do less than I can do for free.” That's exactly what DRM does for consumers.

Some people defend DRM, saying that if there was no DRM, then people would copy things left and right and collapse their industry. Apparently these people have never heard of eMule or Kazaa. Crackers and pirates are going to bypass whatever system you have installed anyways. Except for simple protections (say, an easy-to-use activation system that doesn't require an Internet connection), putting extra runtime checks in that interefere with operation makes things worse for your customers.

This doesn't mean you shouldn't encrypt your binaries or run them through an obfuscator. It means you shouldn't have software that polls in the background for debuggers that might be running, or secret checks on the CD to ensure it is legitimate.

For instance, take my post about stupid copy protection like SafeDisc: Here, a legit customer is suffering from the stupidity imposed by the corporation: You MUST SafeDisc all releases. In fact, me, a legitimate customer, had to turn to getting a pirate crack to be able to use the software I purchased. Had I pirated it to begin with, I'd have never run into trouble. In fact, check that link out, and look at all the search referrals. A LOT of people are having the same problems. The solution? Don't pay, just get a crack. Again, DRM messing things up.

Same thing for some of those dongle-based protection systems. If the software is worth it, it'll get cracked. However, legit customers don't get a crack. So, when their dongle fails, they get rather annoyed. Ask some Autodesk/discreet customers about that, and I'm sure you'll hear some great stories. Nothing like shelling out $$$$$ to get a top-of-the-line system, only to have your software say “Hey, you don't have a dongle. Theif! Call and buy our software!” a day before deadlines.

So, besides pissing customers off, does it hurt companies? Well, yes, and quite directly. An average user, say, someone with an Autodesk product, might not go into cracks, thinking every crack download has a virus and whatnot. They might not want to/care to/be able to install them. However, when the company FORCES the customer to figure it out (i.e., to meet your deadline, or to copy some music in time for a party, or to just bloody use the software you paid for), that customer now KNOWS how to work the pirate scene. The customer sees that well, no, cracks down erase your hard disk and delete your work while infecting every machine on the network with a virus. In fact, in some cases, things might work even better (like a SafeDisc game that pauses the game every few minutes to search for the CD).

Now what? Well, you've taken an innocent customer, and forced him into piracy once. Next time he needs 1 more license, he's got one less reason to purchase it. Next time there's a choice between running down and buying a DVD, or downloading a rip from the net (and avoiding region issues), there's less incentive to buy. “Average Joe” customers who would never have used a crack before (even if they wanted to), now might go ahead and do that. And recommend/show to their “Average Jane” friends.

And unlike earlier MacroVision stuff that protected analog tapes (ever try to copy a rental to VHS?) that required small $10 hardware cleaners to fix, things in the digital domain and on the Internet don't require any special hardware. Installing a crack can be as easy as 3 clicks. Deprotecting content can be done with a single click. Hell, Windows even asks me to decrypt DVDs when inserted in the drive -- no clicks required if I so desired!

I wonder how long it'll take people holding IP to realise that working WITH their customers instead of treating everyone like the devil will help them. It seems pretty obvious to me and everyone I've talked to. I wonder why it's so hard for them?

Misc | Security
Tuesday, November 16, 2004 2:30:31 AM UTC  #    Comments [0]  |  Trackback

 Sunday, November 14, 2004
ast_mono: printf functions

I was working on ast_mono tonight, and had to make some decisions on how the ManagedAsterisk API would handle formatted (printf style) functions.

First, there's technical issues. printf functions use varargs. I'm not exactly sure on how to forward and prototype these methods. I know IL supports varargs, but I don't think that C# does. So, I'd end up doing a “params object[] args” parameter. The issue is that my unmanaged runtime is then massed a set of pointers, and would have to figure out what each item is to be able to format it correctly. Still, it's possible.

Then the real issue comes into play. .NET APIs don't use printf style functions. To many .NET programmers this style would seem foreign, and clash with other APIs. Since one of the goals of ast_mono is to present an API that's consistent and feels like any other .NET library, this is unacceptable. So, instead, I'm doing to use string.Format to handle the formatting for these functions (such as ast_log). Yes, the functionality is somewhat different, but overall it should provide a much better development experience to ast_mono users.

ast_mono
Sunday, November 14, 2004 4:45:08 AM UTC  #    Comments [0]  |  Trackback

 Thursday, November 11, 2004
ASP.NET 2: Compatability on the rise

When I got ASP.NET 2 Alpha, the first thing I did was drop it on my webserver and see if all my real sites worked. Some did. Some didn't. dasBlog refused to run. Lots of strange little problems. So, regretfully, I rolled back to 1.1.

Well, I just moved to a new server. I forgot to roll all the sites back to 1.1. Interestingly enough, I didn't notice. Everything worked just great. (I've since rolled them back anyways.) Way to go ASP.NET team! This makes me feel much better, as earlier (Alpha) it seemed as if caring about their existing customers wasn't a priority.

Misc. Technology
Thursday, November 11, 2004 12:01:05 AM UTC  #    Comments [0]  |  Trackback

 Wednesday, November 10, 2004
Some open source people say sending patches by email is OK (bad security ahead...)

BroadVoice released a patch for Asterisk that fixes some issues with SIP registration. They hired people and made a commercial patch. Way to go.

Then, they decided to *email* it to customers. Yes. In 2004. A company emailing patches to customers. Apparently they didn't think this was dumb. No link to their web site, no secure download from their website, nothing. In fact, the email was signed “The BroadVoice Team”, which is the signature I remember seeing on a few virus emails.

So, I responded to the Asterisk-users mailing list about this patch, saying how it was utterly ridiculous to do this, as it teaches customers to not be secure and go blindly installing stuff. Here are some of the comments I got back (and they aren't sarcastic either!):

“the patch is pure c code. it took me 5 mins to read & understand it. is very simple (but useful).
Simply that patch (apart from adding some logs, comments and little code formatting) simply caches auth data AND let * manage 403 responses from the server, and this last one perhaps is the issue that was overloading BV .
so, just read it (or let someone do for it) and understand that's not a problem :)“

“I don't see a security issue with his method. If you (a) read the entire patch and (b) comprehend fully everything that it does, then there's nothing to worry about. Fear comes from the unknown, and if you know everything in the patch, there's nothing to fear. “

“To claim that someone opens a security hole by accepting a verified patch via email, is the same as claiming that you never have a security hole just because you download from "trusted" sites. Webservers can be hacked, you know. And not every buffer-overflow will lead to a security issue -- many just crash the system. “

So, I think this goes some way towards showing that all is not well as far as security mentality in open-source land. I pointed out to them that “even Microsoft does it right” :). Didn't seem to make me popular.

Thinking that you can just read the code and be set is equivalent to saying there should never be any security holes in any code because people will just read and know. Add to the fact that what you're combating is a possible *malicious* security hole, not just an accident, and I think most devs would pass things right over.

Code | Security
Wednesday, November 10, 2004 11:57:11 PM UTC  #    Comments [0]  |  Trackback