QFT:
Originally Posted by 0x1337.org
First and foremost they introduced heavy obfuscation to "protect" their binaries (battle-net.dll). Obfuscation is (imho) a waste of money. It decreases performance and stability of the product, and offers nothing in return.
I concur. WoW now uses an officially undocumented x86 opcode to detect debuggers, the "Ice Breakpoint", opcode 0xF1.
From Symantec's Windows Anti-Debug Reference:
The so-called "Ice breakpoint" is one of Intel's undocumented instruction, opcode 0xF1. It is used to detect tracing programs.
Executing this instruction will generate a SINGLE_STEP exception. Therefore, if the program is already traced, the debugger will think it is the normal exception generated by executing the instruction with the SingleStep bit set in the Flags registers. The associated exception handler won't be executed, and execution will not continue as expected.
I stumbled upon it when WoW 3.3.5 crashed in WINE, something I haven't seen for many WoW versions before. The problem has been initially reported in the WINE bugtracker, where it was discovered that the current Linux kernel doesn't handle the "Ice Breakpoint" properly which lead to a kernel bug report. It only affects Win32 applications running below WINE. A kernel developer presented a patch against Linux-2.6.34 within only 12 hours! Yay. The fix will most likely find its way into the upcoming kernel 2.6.35.
TL;DR: Use the following patch against kernel 2.6.34 to run WoW-3.3.5 with WINE:
Code:
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index 142d70c..725ef4d 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -526,6 +526,7 @@ asmlinkage __kprobes struct pt_regs *sync_regs(struct pt_regs *eregs)
dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
{
struct task_struct *tsk = current;
+ int user_icebp = 0;
unsigned long dr6;
int si_code;
@@ -534,6 +535,14 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
/* Filter out all the reserved bits which are preset to 1 */
dr6 &= ~DR6_RESERVED;
+ /*
+ * If dr6 has no reason to give us about the origin of this trap,
+ * then it's very likely the result of an icebp/int01 trap.
+ * User wants a sigtrap for that.
+ */
+ if (!dr6 && user_mode(regs))
+ user_icebp = 1;
+
/* Catch kmemcheck conditions first of all! */
if ((dr6 & DR_STEP) && kmemcheck_trap(regs))
return;
@@ -575,7 +584,7 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
regs->flags &= ~X86_EFLAGS_TF;
}
si_code = get_si_code(tsk->thread.debugreg6);
- if (tsk->thread.debugreg6 & (DR_STEP | DR_TRAP_BITS))
+ if (tsk->thread.debugreg6 & (DR_STEP | DR_TRAP_BITS) || user_icebp)
send_sigtrap(tsk, regs, error_code, si_code);
preempt_conditional_cli(regs);