.NET Forum / .NET Framework / New Users / April 2006
Control flow obfuscation.
|
|
Thread rating:  |
q23r - 05 Apr 2006 17:55 GMT Have you seen real control flow obfuscation(CFO)? I mean not in advertising material but in work?
I suppose there are three main obfuscators, which supports CFO. 1. Xenocode 2. Dotfuscator 3. Demeanor
1. When you choose max CFO, produces a lot of trash classes, but don't change flow of your code. 2. Trial version. All settings are default. I can't see any CFO effect. 3. Trial version doesn't support CFO. All I have is the code sample from here: http://groups.google.com/group/microsoft.public.dotnet.languages.csharp/browse_t hread/thread/53dcada5c3cdf7e3/d24076125868738a?lnk=st&q=control+flow+obfuscation &rnum=1#d24076125868738a
Please, correct me, if I'm wrong. And tell me may be there are another ones, which supports CFO?
Ben Callister - 05 Apr 2006 21:33 GMT i use Xenocode and it works pretty good. once CFO has been applied, if you load your assembly into a reflection tool (i use Reflector), and you look at your various function bodies, you will see that they have indeed been replaced with alot more simple-instructions and labels that make it very difficult to reverse engineer. one thing that i have complained to them already about is that there is currently no GUI for applying CFO to *particular* function bodies. rather, it just defaults to all function bodies within your assembly. you can do this, but you have to drop down into the project file yourself which is a pain.
fyi... i typically use their 'conservative' filter so that i can keep my public interfaces in tact since i share my components.
one thing to note is that your assembly size will grow substantially, which is an indicator that CFO has indeed been apllied. i have been seeing about a 5x increase in size after CFO has been applied - which sucks, but i guess thats what you get for buying into this managed world if you want to protect yourself somewhat.
unfortunately, i cant speak for the other obfuscator utilities as i have not used them.
hope this helps somewhat. ben
> Have you seen real control flow obfuscation(CFO)? > I mean not in advertising material but in work? [quoted text clipped - 14 lines] > Please, correct me, if I'm wrong. > And tell me may be there are another ones, which supports CFO? William Stacey [MVP] - 05 Apr 2006 21:43 GMT I like Xenocode as well. However, in no way is 5x worth it IMO. I would just obfuscate and call it a day.
 Signature William Stacey [MVP]
q23r - 06 Apr 2006 17:28 GMT Example of xenocode work(trial version 3.1.6 build 2012): CFO is max.
before obfuscation:
[STAThread] static void Main(string[] args) { System.Console.WriteLine("Please, enter number."); int number = Convert.ToInt32(System.Console.ReadLine()); System.Console.WriteLine(String.Format("Factorial of {0} is {1}", number, Calculate(number))); System.Console.WriteLine(String.Format("Squared {0} is {1}", number, GetSquared(number))); double d = 53.0; System.Console.WriteLine(String.Format("Squared {0} is {1}", d, GetSquared(d))); System.Console.WriteLine(String.Format("Square root of {0} is {1}", d, GetSquareRoot(d))); }
private static int Calculate(int number) { if (number == 1) return 1; return number * Calculate(number - 1); }
private static int GetSquared(int x) { return x*x; }
private static double GetSquared(double x) { return x*x; }
private static double GetSquareRoot(double x) { return Math.Sqrt(x); } }
after(decompiled by Salamander, RemoteSoft said that main method is obfuscated):
[STAThreadAttribute()] private static void xc447809891322395(string[] xce8d8c7e3c2c2426) { int i;
double d;
Console.WriteLine("Please, enter number."); i = Convert.ToInt32(Console.ReadLine()); ConstantExp: "Factorial of {0} is {1}" VariableExp: i ConstantExp: "Square root of {0} is {1}" VariableExp: d IL_0054: box [mscorlib]System.Int32 BoxingExp: xb1de1ba20faeeff8(i) IL_0064: call string [mscorlib]System.String::Format(string, object, object) IL_0069: call void [mscorlib]System.Console::WriteLine(string) Console.WriteLine(String.Format("Squared {0} is {1}", i, x68479d4d6a6e9138(i))); d = 53.0; Console.WriteLine(String.Format("Squared {0} is {1}", d, x68479d4d6a6e9138(d))); IL_008b: box [mscorlib]System.Double BoxingExp: x51c832559b7f7cb7(d) IL_009b: call string [mscorlib]System.String::Format(string, object, object) IL_00a0: call void [mscorlib]System.Console::WriteLine(string) }
private static int xb1de1ba20faeeff8(int x78b0a0bc28459535) { if (x78b0a0bc28459535 == 1) { return 1; } else { return x78b0a0bc28459535 * xb1de1ba20faeeff8(x78b0a0bc28459535 - 1); } }
private static int x68479d4d6a6e9138(int x08db3aeabb253cb1) { return x08db3aeabb253cb1 * x08db3aeabb253cb1; }
private static double x68479d4d6a6e9138(double x08db3aeabb253cb1) { return x08db3aeabb253cb1 * x08db3aeabb253cb1; }
private static double x51c832559b7f7cb7(double x08db3aeabb253cb1) { return Math.Sqrt(x08db3aeabb253cb1); } }
Is there any CFO? I think no. The trash in the main method appears because of xenocode damaged some metadata.
May be it is also restriction of trial version? If so why settings of CFO is available?
Huihong - 06 Apr 2006 20:46 GMT This kind of control flow obfuscation is not difficult to defeat. I just didn't bother to add the support into our salamander decompiler. Internally, I have a version that can easily remove those extra jump instructions injected by obfuscators, and yield high quality source code.
What CFO does is to insert extra br instructions to mess up stack evaluation. Usually, decompiler assumes that a stack starts with empty, and becomes empty during a straight excution path, e.g., path immediately follow an if...else.. node. CFO uses jump instruction to make this simple stack evaluation a bit more difficult, but still easy to remove. I may release a version that defeats this kind of obfuscation.
Be aware, extra jumps introduce more branches, and thus will slow down the performance.
I still think if you use obfuscators, renaming is the key feature. Otherwise, try our native compiler, it provides THE best protection against reverse engineering by compiling everying into x86 code, and it runs without .NET Framework, no IL code, no JIT compiling on execution time.
Huihong Remotesoft, Inc. http://www.remotesoft.com
> Example of xenocode work(trial version 3.1.6 build 2012): > CFO is max. [quoted text clipped - 112 lines] > May be it is also restriction of trial version? If so why settings of > CFO is available? q23r - 07 Apr 2006 16:21 GMT > What CFO does is to insert extra br instructions to mess up stack > evaluation. How do you know kind of cfo in xenocode?
> I still think if you use obfuscators, renaming is the key feature. I think know. But it's easy to implement.
I want obfuscator which results can't be compiled code after cycle of obfuscation, decompilation. Is it possible to change some methadata(or smth else) so, that binaries are correct to execute, but when decompiled, can't be compiled again without human interference?
> Otherwise, try our native compiler, it provides THE best protection > against reverse engineering by compiling everying into x86 code, and it > runs without .NET Framework, no IL code, no JIT compiling on execution > time. If I want native code which runs without .net, I should have been using c++ )
Huihong - 07 Apr 2006 16:57 GMT No, we don't check whether the code is CFO-ed, rather than, perform some optimization before stack evaluation for the decompiler. In your case, the Main() method is failed to decompile, because some nodes with branches are inserted, which can be completely removed. In other words, CFO-enabled obfuscators make a straight execution path to become a conditional path, I'll give you an example,
Before:
int sum = 0; sum = x + y;
After CFO: (for illustration only, not exact, should use IL instructions to accurate description)
int sum = 0 ; push sum if (sum ! = 0) goto L1; <=== extra node with branched pop x; <== this exectution path's stack does not start with empty L1: sum = x + y;
Pretty much, this is the techniques CFO uses. It relies on branches to mess up the decompilers, but as you can see, a bit more advanced stack evaluation will undo the work.
As for native compilation vs programming with native C++, I think it's totally different concept. Native compilation means you still use .NET programming languages, such as C# and VB.NET, so you still can take advantage of the productivity of these wonderful languages, and only if you are really serious about reverse engineering, you have an option to compile into native code. Garbage collection is still in place.
On the other hand, if you program in C++, you don't gain productivity, so it's totally different stories.
> > What CFO does is to insert extra br instructions to mess up stack > > evaluation. [quoted text clipped - 16 lines] > If I want native code which runs without .net, I should have been using > c++ ) q23r - 08 Apr 2006 13:04 GMT I assume it is just very simple example of CFO or most obfuscators really use the same technics?
Do you know obfuscators which use more complex CFO strategy? You know there are plenty of theory about it, but i didn't see it in practice...
Huihong - 09 Apr 2006 00:20 GMT What I can say is that decompiler always wins in these kinds of battles. There are some variations of CFO, but the principle is same, trying to mess up decompiler's control analysis by inserting extra nodes with in/out edges.
What protection measure to take really depends on your comfort level. If you think "well, I better do something", then obfuscators are fine. If you think "God, I really need to protect my code", then try native compilation. I wrote my salamander decompiler in java languages, before release, I tried obfuscation, but didn't meet my goals, so I converted java source code to C++ (for this I developed our java to C++ Octopus translator), and recompiled it to native executables. Today, I still develop in Java for the decompiler, but generate native code for release.
This will be true for C#, with our native compiler:
http://ww.remotesoft.com/linker
Huihong
> I assume it is just very simple example of CFO or most obfuscators > really use the same technics? > > Do you know obfuscators which use more complex CFO strategy? You know > there are plenty of theory about it, but i didn't see it in practice... Huihong - 07 Apr 2006 16:57 GMT No, we don't check whether the code is CFO-ed, rather than, perform some optimization before stack evaluation for the decompiler. In your case, the Main() method is failed to decompile, because some nodes with branches are inserted, which can be completely removed. In other words, CFO-enabled obfuscators make a straight execution path to become a conditional path, I'll give you an example,
Before:
int sum = 0; sum = x + y;
After CFO: (for illustration only, not exact, should use IL instructions to accurate description)
int sum = 0 ; push sum if (sum ! = 0) goto L1; <=== extra node with branched pop x; <== this exectution path's stack does not start with empty L1: sum = x + y;
Pretty much, this is the techniques CFO uses. It relies on branches to mess up the decompilers, but as you can see, a bit more advanced stack evaluation will undo the work.
As for native compilation vs programming with native C++, I think it's totally different concept. Native compilation means you still use .NET programming languages, such as C# and VB.NET, so you still can take advantage of the productivity of these wonderful languages, and only if you are really serious about reverse engineering, you have an option to compile into native code. Garbage collection is still in place.
On the other hand, if you program in C++, you don't gain productivity, so it's totally different stories.
> > What CFO does is to insert extra br instructions to mess up stack > > evaluation. [quoted text clipped - 16 lines] > If I want native code which runs without .net, I should have been using > c++ )
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|