Dailydave mailing list archives

Re: Mutating to avoid structural analysis


From: Halvar Flake <halvar () gmx de>
Date: Wed, 19 Dec 2007 01:05:26 +0100

Hey Dave, all,

I am kinda busy at the moment, so replies will be late / brief.

1. Obfuscation on the callgraph alone will break _some_ part of the
diffing, without rendering it useless -- you still have a ton of
structure on the flowgraphs.
2. Breaking structural comparison is possible, but requires more than
inserting 4 lines of C code into your existing codebase (which is
sufficient for breaking behavioral classification).
3. Even for a 'modest' obfuscation such as the one proposed, one needs
to go through some binary rewriting or at least major preprocessing voodoo.
4. You should make your dispatcher NP-hard to analyze. And quick to
dispatch. Constant table lookups are likely to be optimized away.

So I guess what I am saying is: I think that in order to break
structural classification, you have to do some 'real' work -- rewrite
your binary, build an obfuscating compiler back-end or something along
the lines. Which is more than for most other approahces.

Cheers,
Halvar

So flying home from JFK I was wondering this...

Given that avoiding "behavioral signatures" is a matter of calling
random NOP-like API calls (i.e. CreateFile + CloseHandle == 1 NOP),
Halvar's program classification techniques involve a structural
differencing engine. This has advantages (see his talk for details) in
that program structure closely reflects the semantic meaning of a
program, as interpreted by a compiler.

So the obvious way, from what I can tell, to defeat a structural
differencing algorithm would be to do a static or dynamic analysis of
your target program, and for each CALL opcode, change the destination
to a dispatcher function. This dispatcher function can then be built
to do a O(1) table lookup to find the true destination of the call.

So now all your functions call one function D. Your call graph is
meaningless without reverse engineering the dispatcher function and
reconstructing it, or doing dynamic analysis of the whole program
(assuming you can get decent code coverage).

For bonus points you could mutate your dispatcher function by putting
it as a never-used basic block in lots of other functions. You'd
probably also want to do some other easy obfuscation.

So my question is this: is defeating a structural based fingerprint of
a program more difficult to do than defeating behavioral based
fingerprints.

-dave

_______________________________________________
Dailydave mailing list
Dailydave () lists immunitysec com
http://lists.immunitysec.com/mailman/listinfo/dailydave

_______________________________________________
Dailydave mailing list
Dailydave () lists immunitysec com
http://lists.immunitysec.com/mailman/listinfo/dailydave


Current thread: