While I was playing with DNLib trying to understand what are its possibilities, at the same point I had to deal with an ‘Agent Tesla’ sample, which used strings obfuscation with AES CBC 256 bits.
The decryption method was easy to find, as can be seen below:
One can just copy paste this method inside a new Visual Studio project, and the job will be done later.
More specifically, first we have to load the assembly binary:
ModuleDefMD module = ModuleDefMD.Load(executable);
Next, we parse the types and all the methods of the binary and search for a String opcode (value 114 in IL), and if the string is forwarded by a Call, this means that the string is a parameter.
foreach (TypeDef type in module.GetTypes())
{
countModule++;
foreach (MethodDef method in type.Methods)
{
//check if the method is not empty and if it not a constructor
if (!method.HasBody || method.IsConstructor)
continue;
countMethod++;
for (int i = 0; i < method.Body.Instructions.Count; i++)
{
if (method.Body.Instructions[i].OpCode.Value == 114) //OpCodes.Ldstr)
{
if (method.Body.Instructions[i + 1].OpCode == OpCodes.Call)
{
Now we can retrieve the encrypted string, and pass it to the DecryptString method. Afterwards, to get a clean output sample, we have to remove the string and the call to the real decryption method inside the loaded assembly:
var cryptedstring = method.Body.Instructions[i].Operand.ToString();
string decryptedstring = DecryptString(cryptedstring);
//For exception max stack value
method.Body.KeepOldMaxStack = true;
method.Body.Instructions[i].OpCode = OpCodes.Ldstr;
method.Body.Instructions[i].Operand = decryptedstring;
method.Body.Instructions.Remove(method.Body.Instructions[i + 1]);
And finally we can save our new clean assembly:
String outputfilename = outputFolderName +" \\" + filename + "_uncrypt.exe";
module.Write(outputfilename);
Now opening the clean Assembly in DNSpy, we can see the clean strings:
Of course, if the algorithm changes, one has to recustomize the source code and rebuild the binary, which can be a bit painful. An evolution of this method could using a type of reflexion by calling the decryption method within the loaded assembly (with is RVA for example). We will explore this another time.
As you can see, it’s really easy to use the basics of DNlib, and we can do even more cool things!
The source code of the decrypter can be found on my github, in case it is useful to anyone.
If you see any bugs or have further ideas to make it great again, don’t hesitate to message us.