[Bug 10273] satisfy SafeDisc 2.x heuristic API analyzer by "adjusting" API exports/entry statistics of wine builtins

wine-bugs at winehq.org wine-bugs at winehq.org
Mon Nov 5 15:46:22 CST 2007


http://bugs.winehq.org/show_bug.cgi?id=10273





--- Comment #18 from Anastasius Focht <focht at gmx.net>  2007-11-05 15:46:21 ---
Hello,

--- quote ---
I don't think we can drop -fPIC, some distros don't allow text relocations, and
we can't guarantee that the specified load address will always be free.
--- quote ---

Pity .. so we have to think about other solutions.

--- quote ---
And changing the location produces even worse c2 results for
gdi32.
--- quote ---

Thats something I wondered about too. I disassembled and compared the entry
code of the first checked exports - it did not change at all: same stack frame,
same location of __i686.get_pc_thunk.bx().
Usually within 8 instruction range, which makes it "bad guy".
So c2 must include additional information from somewhere.

--- quote ---
 So it seems it is the fact that there is a call at all in these first 8
instructions that safedisc considers "bad".
--- quote ---

True, any instruction which transfers execution flow within that range seems to
be considered bad by analyzer (jmp, jcond, call ...) - regardless of the
destination (within own .text section other outside).
Though "outside" destinations seem to have "modifier" effect on c3.

They probably analyzed windows API entry code and made up some statistics how
many instructions are needed to safely detect any "hostile" execution flow
transfer (jump trampolines) without having too much false positives.
Besides there are other ways to trace/hook system calls without the need to
overwrite opcodes on entry code ;-)

I did some more testing with my custom "backdoor" dll and presented the
analyzer some lengthy code sequences (which do just nothing but waste
instructions + cpu cycles).

"t_x" = testcase x
"exp" = exports

t_1: 10 exp, seq len: 20 instr, standard stack frame (ebp), register math
t_2: 9 exp, seq len: 20 instr, standard stack frame (ebp)
     1 exp, seq len: 6 instr, standard stack frame (ebp)
t_3: 5 exp, seq len: 20 instr, standard stack frame (ebp)
     5 exp, seq len: 6 instr, standard stack frame (ebp)
t_4: 10 exp, seq len: 10 instr, standard stack frame (ebp), 9 x nop + 1 x ret

     t1     t2     t3     t4     condition (cx < th)
--------------------------------------------------------------------
c1:  0x00   0x0A   0x32   0x00   0x5F
c2:  0x00   0x01   0x19   0x00   0x3C
c3:  0x00   0x00   0x00   0x00   0x5A

The instruction classes used seem to have no influence. The disassembler only
treats any control transfer instructions special (including ret).

So if we pad the entry code at least 8-9 instructions long with NOP or other
padding opcodes we should get around these idiotic checks.

For testing I abused the wine tools and wine's relay thunk feature.
Seemed to me quickest solution for testing, sorry for that ;-)

--- snip ---

diff --git a/tools/winebuild/spec32.c b/tools/winebuild/spec32.c
index 8df5b85..9164827 100644
--- a/tools/winebuild/spec32.c
+++ b/tools/winebuild/spec32.c
@@ -124,7 +124,16 @@ static void output_relay_debug( DLLSPEC *spec )

         output( "\t.align %d\n", get_alignment(4) );
         output( ".L__wine_spec_relay_entry_point_%d:\n", i );
-
+
+        output( "\tnop\n" );
+        output( "\tnop\n" );
+        output( "\tnop\n" );
+        output( "\tnop\n" );
+        output( "\tnop\n" );
+        output( "\tnop\n" );
+        output( "\tnop\n" );
+        output( "\tnop\n" );
+
         if (odp->flags & FLAG_REGISTER)
             output( "\tpushl %%eax\n" );
         else
--- snip ---

(rebuild)

The results seem very positive to the current state of affair.
With the "hacked" relay thunk (first 8 bytes in thunk are NOP) the following
stats are generated:

*** Note: you have to run the target with +relay to let this test work ***

    kernel32   user32      gdi32       condition (cx < threshold)
--------------------------------------------------------------------
c1:  0x12       0x04        0x14        0x5F
c2:  0x02       0x00        0x04        0x3C
c3:  0x00       0x00        0x00        0x5A

So if wine could make default thunks/entry code with just enough no-op opcode
padding before jumping to real thing we can keep -fPIC.
This "feature" should be tested thoroughly, maybe some other brain damaged PE
protectors/virii might find this entry code somewhat suspicious.

Though this kind of entry code is not uncommon, Micro$oft has such kind of API
entry padding too to support "hot patching" technique (their infamous "mov edi,
edi").

Regards


-- 
Configure bugmail: http://bugs.winehq.org/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are watching all bug changes.



More information about the wine-bugs mailing list