|
dev
newsgroups
|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
Control flow obfuscation.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_thread/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? 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 Show quote "q23r" <q***@mail.ru> wrote in message news:1144256131.052919.31610@z34g2000cwc.googlegroups.com... > 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_thread/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? > I like Xenocode as well. However, in no way is 5x worth it IMO. I would
just obfuscate and call it a day. -- William Stacey [MVP] 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? 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 q23r wrote: Show quote > 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 wrote:
> What CFO does is to insert extra br instructions to mess up stack How do you know kind of cfo in xenocode?> evaluation. > 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 If I want native code which runs without .net, I should have been using> against reverse engineering by compiling everying into x86 code, and it > runs without .NET Framework, no IL code, no JIT compiling on execution > time. c++ ) 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. q23r wrote: Show quote > Huihong wrote: > > 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++ ) 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... 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 q23r wrote: Show quote > 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... 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. q23r wrote: Show quote > Huihong wrote: > > 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++ ) |
|||||||||||||||||||||||