25

At my previous employer we used a third party component which basically was just a DLL and a header file. That particular module handled printing in Win32. However, the company that made the component went bankcrupt so I couldn't report a bug I'd found.

So I decided to fix the bug myself and launched the debugger. I was surprised to find anti-debugging code almost everywhere, the usual IsDebuggerPresent, but the thing that caught my attention was this:

    ; some twiddling with xor 
    ; and data, result in eax 
    jmp eax 
    mov eax, 0x310fac09 
    ; rest of code here 

At the first glance I just stepped over the routine which was called twice, then things just went bananas. After a while I realized that the bit twiddling result was always the same, i.e. the jmp eax always jumped right into the mov eax, 0x310fac09 instruction. I dissected the bytes and there it was, 0f31, the rdtsc instruction which was used to measure the time spent between some calls in the DLL.

So my question to SO is: What is your favourite anti-debugging trick?

Jonas Engström
  • 5,015
  • 3
  • 37
  • 36
  • 10
    It's my opinion that I really don't want code running on my system that has had things done to prevent debugging. It shows that the author of the code cannot be trusted. – bruceatk Feb 21 '09 at 16:23
  • 1
    I agree with bruceatk, especially for DLLs and other components I use to build my application. I'm less concerned with full applications I use. I am not surprised the company went bankcrupt :) - they would better spend time producing good code than protecting it. – Michael Entin Feb 21 '09 at 21:05
  • @bruceatk so you don't run Windows? The operating system itself contains some anti-debugger tricks to help hide some of its more interesting protection mechanisms. – mrduclaw Oct 28 '10 at 04:05
  • @mrduclaw. Yes I do, but it doesn't change my statement. The reality is you have to live with things that people do that you don't like. I absolutely do not trust everything that Microsoft does. Especially the time they had a flaw in their Windows Genuine Advantage Notification that flagged all 3 of my HP laptops as not genuine. Their solution re-image them all, I said no. They fixed their problem. I didn't re-image. – bruceatk Nov 03 '10 at 12:35
  • @bruceatk, I was just making a point that anti-debugger tricks are common in software. You can't escape them. There's no reason to hate on software that uses anti-debugger tricks, especially when the most dominant operating system in the world uses them. – mrduclaw Nov 04 '10 at 00:29
  • That kind of stuff was VERY common back in the DOS days as part of various copy-protection algorithms. – Brian Knoblauch Dec 01 '10 at 15:44

10 Answers10

27

My favorite trick is to write a simple instruction emulator for an obscure microprocessor.

The copy protection and some of the core functionality will then compiled for the microprocessor (GCC is a great help here) and linked into the program as a binary blob.

The idea behind this is, that the copy protection does not exist in ordinary x86 code and as such cannot be disassembled. You cannot remove the entire emulator either because this would remove core functionality from the program.

The only chance to hack the program is to reverse engineer what the microprocessor emulator does.

I've used MIPS32 for emulation because it was so easy to emulate (it took just 500 lines of simple C-code). To make things even more obscure I didn't used the raw MIPS32 opcodes. Instead each opcode was xor'ed with it's own address.

The binary of the copy protection looked like garbage-data.

Highly recommended! It took more than 6 month before a crack came out (it was for a game-project).

Nils Pipenbrinck
  • 83,631
  • 31
  • 151
  • 221
  • So basically you went through all that work knowing you would fail eventually? – fow Feb 21 '09 at 16:09
  • Six months is a long time when we're talking about cracking an application. – Irwin Feb 21 '09 at 16:13
  • 3
    I would say it took 6 months before someone tried. It's not worth the effort. I'm sure whatever you did was easily bypassed by something you never thought of. – bruceatk Feb 21 '09 at 16:21
  • 4
    yes, the protection was just bypassed. The cracker "just" made a snapshot of the running executable after the copy-check (freezer-style). Not finding your game on warez-sites for almost six month was a great success though. – Nils Pipenbrinck Feb 21 '09 at 16:45
  • 1
    Wouldn't it be better to sell your software at a reasonable price and provide a mechanism that promotes a community of users to build addon content for your game and for you your self to sell addons for your game. The people that get it at warez sites aren't your customers and never will be. – bruceatk Feb 21 '09 at 19:00
  • bruceatk, that game sold the first month for $19.99, later for $9.99 and was made for PocketPC. That's a *very* reasonable price. – Nils Pipenbrinck Feb 21 '09 at 19:32
  • I have no problem with that price. I just don't believe that the people you are trying to keep from stealing your software are potential customers. Put that time and effort into making your product better and to have a longer life with upgrades if appropriate. – bruceatk Feb 21 '09 at 20:07
  • 2
    Many potential customers can check piratebay before buying, even if they can afford the software and even have a credit card handy. I agree with Nils here. If you can keep the protection unbroken even a month, it's a huge success, and might pay for itself. – John Smith Feb 21 '09 at 20:17
  • I'm not convinced that customers search piratebay before purchasing. Do you know one? I'd like to talk to him/her. – bruceatk Feb 21 '09 at 20:46
  • 1
    The problem is, that on platforms such as PocketPC - where you buy your software online - the torrents and warez-sites are ranked higher than the few sales sites that exist. So potential customers will always first see the warez link. Sad but true. – Nils Pipenbrinck Feb 21 '09 at 20:52
  • 1
    I have owned a Pocket PC since 2003. I hate to even think about how much money I have spent on the software that I have purchased for it. The software is extremely easy to purchase and almost everyone provides a trial. These people are not your customers and you shouldn't waste time on them. – bruceatk Feb 22 '09 at 13:17
  • +1 for a great answer, an instruction emulator is the way to go. – Jonas Engström Feb 22 '09 at 14:17
  • Would you mind sharing that 500 lines of code? After looking at some emulators I'm under the impression that it's more complicated than that. – Tamás Szelei Aug 17 '10 at 22:58
  • 2
    "The copy protection and some of the core functionality will then compiled for the microprocessor (GCC is a great help here) and linked into the program as a binary blob." If only rms knew... – leftaroundabout Feb 28 '12 at 18:48
6

I've been a member of many RCE communities and have had my fair share of hacking & cracking. From my time I've realized that such flimsy tricks are usually volatile and rather futile. Most of the generic anti-debugging tricks are OS specific and not 'portable' at all.

In the aforementioned example, you're presumably using inline assembly and a naked function __declspec, both which are not supported by MSVC when compiling on the x64 architecture. There are of course still ways to implement the aforementioned trick but anybody who has been reversing for long enough will be able to spot and defeat that trick in a matter of minutes.

So generally I'd suggest against using anti-debugging tricks outside of utilizing the IsDebuggerPresent API for detection. Instead, I'd suggest you code a stub and/or a virtual machine. I coded my own virtual machine and have been improving on it for many years now and I can honestly say that it has been by far the best decision I've made in regards to protecting my code so far.

Irwin
  • 499
  • 1
  • 3
  • 12
6

Spin off a child process that attaches to parent as a debugger & modifies key variables. Bonus points for keeping the child process resident and using the debugger memory operations as a kind of IPC for certain key operations.

On my system, you can't attach two debuggers to the same process.

Nice thing about this one is unless they try to tamper w/ things nothing breaks.

Joshua
  • 40,822
  • 8
  • 72
  • 132
4

Reference uninitialized memory! (And other black magic/vodoo...)

This is a very cool read: http://spareclockcycles.org/2012/02/14/stack-necromancy-defeating-debuggers-by-raising-the-dead/

Ed.
  • 1,404
  • 4
  • 17
  • 26
  • I'm sure I can come up with a messier one of that aspect for the jokers to step through that depends on less os-specific stuff. – Joshua Feb 28 '12 at 19:26
3

The most modern obfuscation method seems to be the virtual machine.

You basically take some part of your object code, and convert it to your own bytecode format. Then you add a small virtual machine to run this code. Only way to properly debug this code will be to code an emulator or disassembler for your VM's instruction format. Of course you need to think of performance too. Too much bytecode will make your program run slower than native code.

Most old tricks are useless now:

  • Isdebuggerpresent : very lame and easy to patch
  • Other debugger/breakpoint detections
  • Ring0 stuff : users don't like to install drivers, you might actually break something on their system etc.
  • Other trivial stuff that everybody knows, or that makes your software unstable. remember that even if a crack makes your program unstable but it still works, this unstability will be blamed on you.

If you really want to code the VM solution yourself (there are good programs for sale), don't use just one instruction format. Make it polymorphic, so that you can have different parts of the code have different format. This way all your code can't be broken by writing just one emulator/disassembler. For example MIPS solution some people offered seems to be easily broken because MIPS instruction format is well documented and analysis tools like IDA can already disassemble the code.

List of instruction formats supported by IDA pro disassembler

Community
  • 1
  • 1
John Smith
  • 4,402
  • 4
  • 32
  • 34
3

I would prefer that people write software that is solid, reliable and does what it is advertised to do. That they also sell it for a reasonable price with a reasonable license.

I know that I have wasted way too much time dealing with vendors that have complicated licensing schemes that only cause problems for the customers and the vendors. It is always my recommendation to avoid those vendors. Working at a nuclear power plant we are forced to use certain vendors products and thus are forced to have to deal with their licensing schemes. I wish there was a way to get back the time that I have personally wasted dealing with their failed attempts to give us a working licensed product. It seems like a small thing to ask, but yet it seems to be a difficult thing for people that get too tricky for their own good.

bruceatk
  • 5,118
  • 2
  • 26
  • 36
  • Offensive? I would love whomever decided to label this offensive to contact me and explain what is offensive about it. bruceatk@comcast.net – bruceatk Feb 21 '09 at 20:03
  • +1 To counter-act the "offensive." +1 virtual point for nuclear power concerns. – Bob Cross Feb 21 '09 at 20:54
  • 1
    I didn't flag you as offensive, but I did rate you down as your post is really off topic. – rhinovirus Feb 21 '09 at 23:26
  • @rhinovirus. It is on target. The need to deter debugging is to slow down people breaking your copy protection mechanism. That copy protection mechanism may involve how the license is applied to the software and that is the point that I'm bringing up. – bruceatk Feb 22 '09 at 03:48
  • @rhinovirus. I have no problem with people voting me down, but I would like those people to comment why. – bruceatk Feb 22 '09 at 03:49
  • 1
    Anti-debugging is a common thing in software. Also, your point about licensing seems irrelevant to me. How does the software calling `IsDebuggerPresent()` (or whatever similar trick) have an effect on how that software is licensed? – mrduclaw Oct 28 '10 at 04:17
  • @mrduclaw, my point is that the anti-debugging and intrusive licensing gets in the way of legitimate paying users from using the product. When I have a problem on my system I should be able to look at what is going on without having to deal with tricks and hacks. I only say this because I have dealt with it so much in the 30+ years that I have been supporting systems. – bruceatk Jan 06 '11 at 22:19
  • @bruceatk, I simply disagree. Intrusive licensing might get in the way of legitimate paying users, but I'm not certain anti-debugging tricks do. You're mixing things that don't necessarily mix (that's not to say that anti-debugging tricks cannot be used to help enforce intrusive licensing -- it can). But disregarding all of that since it's my opinion that you're wrong about anti-debugging but will want to argue to wits end over semantics regarding it -- shouldn't a company be allowed to protect its IP? – mrduclaw Jan 08 '11 at 08:01
2

I second the virtual machine suggestion. I implemented a MIPS I simulator that (now) can execute binaries generated with mipsel-elf-gcc. Add to that code/data encryption capabilities (AES or with any other algorithm of your choice), the ability of self-simulation (so you can have nested simulators) and you have a pretty good code obfuscator.

The nice feature of choosing MIPS I is that 1) it's easy to implement, 2) I can write code in C, debug it on my desktop and just cross-compile it for MIPS when it's done. No need to debug custom opcodes or manually write code for a custom VM..

zvrba
  • 24,186
  • 3
  • 55
  • 65
  • Wtf - you use MIPS as well? I thought I was the only one who does it this way. – Nils Pipenbrinck Feb 21 '09 at 15:08
  • Well, I first wanted to design a custom instruction set, but it quickly occurred to me that I'd condemn myself to manually writing and debugging code for it. So I went to look for a simple CPU supported by gcc :-) – zvrba Feb 22 '09 at 06:46
2

My personal favourite was on the Amiga, where there is a coprocessor (the Blitter) doing large data transfers independent from the processor; this chip would be instructed to clear all memory, and reset from a timer IRQ.

When you attached an Action Replay cartridge, stopping the CPU would mean that the Blitter would continue clearing the memory.

Simon Richter
  • 28,572
  • 1
  • 42
  • 64
1

Calculated jumps in the middle of a legitimate looking but really hiding an actual instruction instructions are my favorite. They are pretty easy to detect for humans anyway, but automated tools often mess it up.

Also replacing a return address on the stack makes a good time waster.

artificialidiot
  • 5,309
  • 29
  • 27
0

Using nop to remove assembly via the debugger is a useful trick. Of course, putting the code back is a lot harder!!!

Sean
  • 60,939
  • 11
  • 97
  • 136
  • 1
    Depending on the debugger there should be an 'undo' feature. OllyDbg has one, just select the modified bytes & press ALT+BACKSPACE. – Irwin Feb 21 '09 at 14:37