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.
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?