Skip to content

Instantly share code, notes, and snippets.

@sunnamed434
Last active October 19, 2022 15:39
Show Gist options
  • Save sunnamed434/f1a0fe2af304ee3c26b25b1d98b12d81 to your computer and use it in GitHub Desktop.
Save sunnamed434/f1a0fe2af304ee3c26b25b1d98b12d81 to your computer and use it in GitHub Desktop.
TypeLoadException after obfuscation

The problem

Getting exception after obfuscation when running obfuscated app.

Unhandled Exception: System.TypeLoadException: Could not load type 'ManagedHook' from assembly 'NETFrameConsoleApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' because the parent does not exist. at NETFrameConsoleApp.Program.Main(String[] args)

app.cs - program which was obfuscated by obfuscation.cs

What does obfuscation do after error occurs?

Hides method calling by calling another method

Example of obfuscation result in C#

internal class Program
{
    private static void Main(string[] args)
    {
        ManagedHook.Redirect(
            from: typeof(Program).GetMethod(nameof(SayHello)).MethodHandle, 
            to: typeof(Program).GetMethod(nameof(SayHelloMagic)).MethodHandle);

        // Should output in console: "Hello!", but, will output in console: "Hello Magic!" (this is intentional by obfuscation)
        SayHello();
        Console.ReadLine();
    }


    public static void SayHello()
    {
        Console.WriteLine("Hello!");
    }
    public static void SayHelloMagic()
    {
        Console.WriteLine("Hello Magic!");
    }

    internal static class ManagedHook
    {
        internal static void Redirect(RuntimeMethodHandle from, RuntimeMethodHandle to)
        {
            RuntimeHelpers.PrepareMethod(from);
            RuntimeHelpers.PrepareMethod(to);

            var _fromPtr = from.GetFunctionPointer();
            var _toPtr = to.GetFunctionPointer();

            VirtualProtect(_fromPtr, (IntPtr)5, 0x40, out uint x);

            if (IntPtr.Size == 8)
            {
                Marshal.WriteByte(_fromPtr, 0, 0x49);
                Marshal.WriteByte(_fromPtr, 1, 0xbb);

                Marshal.WriteInt64(_fromPtr, 2, _toPtr.ToInt64());

                Marshal.WriteByte(_fromPtr, 10, 0x41);
                Marshal.WriteByte(_fromPtr, 11, 0xff);
                Marshal.WriteByte(_fromPtr, 12, 0xe3);
            }
            else if (IntPtr.Size == 4)
            {
                Marshal.WriteByte(_fromPtr, 0, 0xe9);
                Marshal.WriteInt32(_fromPtr, 1, _toPtr.ToInt32() - _fromPtr.ToInt32() - 5);
                Marshal.WriteByte(_fromPtr, 5, 0xc3);
            }

            VirtualProtect(_fromPtr, (IntPtr)5, x, out _);
        }


        [DllImport("kernel32.dll")]
        internal static extern bool VirtualProtect(IntPtr lpAddress, IntPtr dwSize, uint flNewProtect, out uint lpflOldProtect);
    }
}
// Code of executable program where exception occurs
// -- NB! This is already obfuscated app! --
internal static class ManagedHook
{
[DllImport("kernel32.dll", CallingConvention = CallingConvention.Cdecl)]
internal static extern bool VirtualProtect(IntPtr, IntPtr, uint, [Out] uint);
internal static void Redirect(RuntimeMethodHandle A_0, RuntimeMethodHandle A_1)
{
RuntimeHelpers.PrepareMethod(A_0);
RuntimeHelpers.PrepareMethod(A_1);
IntPtr functionPointer = A_0.GetFunctionPointer();
IntPtr functionPointer2 = A_1.GetFunctionPointer();
uint num;
ManagedHook.VirtualProtect(functionPointer, (IntPtr)5, 0U, out num);
if (IntPtr.Size == 8)
{
Marshal.WriteByte(functionPointer, 0, 0);
Marshal.WriteByte(functionPointer, 1, 187);
Marshal.WriteInt64(functionPointer, 2, functionPointer2.ToInt64());
Marshal.WriteByte(functionPointer, 0, 0);
Marshal.WriteByte(functionPointer, 0, byte.MaxValue);
Marshal.WriteByte(functionPointer, 0, 227);
}
else if (IntPtr.Size == 4)
{
Marshal.WriteByte(functionPointer, 0, 233);
Marshal.WriteInt32(functionPointer, 1, functionPointer2.ToInt32() - functionPointer.ToInt32() - 5);
Marshal.WriteByte(functionPointer, 5, 195);
}
uint num2;
ManagedHook.VirtualProtect(functionPointer, (IntPtr)5, num, out num2);
}
}
internal class Program
{
private static void Main(string[] args)
{
ManagedHook.Redirect(typeof(Program).GetMethod("Dummy").MethodHandle, typeof(Program).TypeHandle.GetMethod("SayHello").MethodHandle);
Program.Dummy();
Console.ReadLine();
}
public static void SayHello()
{
Console.WriteLine("Hello!");
}
public Program()
{
}
public static void Dummy()
{
Console.WriteLine("hello!");
}
}
var importer = new Importer(context.ModuleDefMD);
var runtimeMethodHandle = importer.ImportAsTypeSig(typeof(RuntimeMethodHandle));
var managedHookTypeDef = new TypeDefUser("ManagedHook");
managedHookTypeDef.Attributes = TypeAttributes.Abstract | TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit;
var redirectMethodDef = new MethodDefUser("Redirect", MethodSig.CreateStatic(context.ModuleDefMD.CorLibTypes.Void, new TypeSig[]
{
runtimeMethodHandle, runtimeMethodHandle
}), MethodAttributes.Assembly | MethodAttributes.Static);
redirectMethodDef.Body = new CilBody();
var fromPtrLocal = redirectMethodDef.Body.Variables.Add(new Local(context.ModuleDefMD.CorLibTypes.IntPtr, "_fromPtr"));
var toPtrLocal = redirectMethodDef.Body.Variables.Add(new Local(context.ModuleDefMD.CorLibTypes.IntPtr, "_toPtr"));
var xLocal = redirectMethodDef.Body.Variables.Add(new Local(context.ModuleDefMD.CorLibTypes.UInt32, "x"));
var undefinedLocal = redirectMethodDef.Body.Variables.Add(new Local(context.ModuleDefMD.CorLibTypes.UInt32));
var virtualProtectNativeMethodAttributes = MethodAttributes.PinvokeImpl | MethodAttributes.Assembly | MethodAttributes.Static;
var virtualProtectNativeMethodImplementationAttributes = MethodImplAttributes.PreserveSig;
var dllReference = new ModuleRefUser(context.ModuleDefMD, "kernel32.dll");
var implementationMap = new ImplMapUser(dllReference, string.Empty, PInvokeAttributes.CallConvCdecl);
var virtualProtectNativeMethod = new MethodDefUser("VirtualProtect",
MethodSig.CreateStatic(context.ModuleDefMD.CorLibTypes.Boolean, context.ModuleDefMD.CorLibTypes.IntPtr, context.ModuleDefMD.CorLibTypes.IntPtr, context.ModuleDefMD.CorLibTypes.UInt32, context.ModuleDefMD.CorLibTypes.UInt32),
virtualProtectNativeMethodImplementationAttributes, virtualProtectNativeMethodAttributes);
virtualProtectNativeMethod.ImplMap = implementationMap;
virtualProtectNativeMethod.ParamDefs.Add(new ParamDefUser(string.Empty, 1));
virtualProtectNativeMethod.ParamDefs.Add(new ParamDefUser(string.Empty, 2));
virtualProtectNativeMethod.ParamDefs.Add(new ParamDefUser(string.Empty, 3));
virtualProtectNativeMethod.ParamDefs.Add(new ParamDefUser(string.Empty, 4, ParamAttributes.Out));
managedHookTypeDef.Methods.Add(virtualProtectNativeMethod);
managedHookTypeDef.Methods.Add(redirectMethodDef);
context.ModuleDefMD.Types.Add(managedHookTypeDef);
var prepareMethodMethod = importer.Import(typeof(RuntimeHelpers).GetMethod(nameof(RuntimeHelpers.PrepareMethod), new Type[]
{
typeof(RuntimeMethodHandle)
}));
var getFunctionPointerMethod = importer.Import(typeof(RuntimeMethodHandle).GetMethod(nameof(RuntimeMethodHandle.GetFunctionPointer)));
var intPtrExplicitMethod = importer.Import(typeof(IntPtr).GetMethod("op_Explicit", new Type[]
{
typeof(int)
}));
var intPtrGetSizeMethod = importer.Import(typeof(IntPtr).GetMethod("get_Size"));
var writeByteMethod = importer.Import(typeof(Marshal).GetMethod(nameof(Marshal.WriteByte), new Type[]
{
typeof(IntPtr), typeof(int), typeof(byte)
}));
var intPtrToInt64Method = importer.Import(typeof(IntPtr).GetMethod(nameof(IntPtr.ToInt64)));
var marshalWriteInt64Method = importer.Import(typeof(Marshal).GetMethod(nameof(Marshal.WriteInt64), new Type[]
{
typeof(IntPtr), typeof(int), typeof(long)
}));
var intPtrToInt32Method = importer.Import(typeof(IntPtr).GetMethod(nameof(IntPtr.ToInt32)));
var marshalWriteInt32Method = importer.Import(typeof(Marshal).GetMethod(nameof(Marshal.WriteInt32), new Type[]
{
typeof(IntPtr), typeof(int), typeof(int)
}));
var from = redirectMethodDef.Parameters[0];
var to = redirectMethodDef.Parameters[1];
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldarg_0));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Call, prepareMethodMethod));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldarg_1));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Call, prepareMethodMethod));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldarga_S, from));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Call, getFunctionPointerMethod));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Stloc_0));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldarga_S, to));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Call, getFunctionPointerMethod));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Stloc_1));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldloc_0));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldc_I4_5));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Call, intPtrExplicitMethod));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldc_I4_S, 0x40));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldloca_S, xLocal));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Call, virtualProtectNativeMethod));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Pop));
var callIntPtrGetSizeInstruction = new Instruction(OpCodes.Call, intPtrGetSizeMethod);
redirectMethodDef.Body.Instructions.Add(callIntPtrGetSizeInstruction);
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldc_I4_8));
var jumpFromInstruction1 = new Instruction(OpCodes.Bne_Un_S);
redirectMethodDef.Body.Instructions.Add(jumpFromInstruction1);
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldloc_0));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldc_I4_0));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldc_I4_S, 0x49));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Call, writeByteMethod));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldloc_0));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldc_I4_1));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldc_I4, 0xBB));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Call, writeByteMethod));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldloc_0));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldc_I4_2));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldloca_S, toPtrLocal));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Call, intPtrToInt64Method));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Call, marshalWriteInt64Method));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldloc_0));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldc_I4_S, 10));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldc_I4_S, 0x41));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Call, writeByteMethod));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldloc_0));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldc_I4_S, 11));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldc_I4, 0xFF));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Call, writeByteMethod));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldloc_0));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldc_I4_S, 12));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldc_I4, 0xE3));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Call, writeByteMethod));
var jumpFromInstruction2 = new Instruction(OpCodes.Br_S);
redirectMethodDef.Body.Instructions.Add(jumpFromInstruction2);
var jumpToInstruction1 = new Instruction(OpCodes.Call, intPtrGetSizeMethod);
redirectMethodDef.Body.Instructions.Add(jumpToInstruction1);
jumpFromInstruction1.Operand = jumpToInstruction1;
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldc_I4_4));
var jumpFromInstruction3 = new Instruction(OpCodes.Bne_Un_S);
redirectMethodDef.Body.Instructions.Add(jumpFromInstruction3);
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldloc_0));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldc_I4_0));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldc_I4, 0xE9));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Call, writeByteMethod));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldloc_0));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldc_I4_1));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldloca_S, toPtrLocal));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Call, intPtrToInt32Method));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldloca_S, fromPtrLocal));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Call, intPtrToInt32Method));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Sub));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldc_I4_5));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Sub));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Call, marshalWriteInt32Method));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldloc_0));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldc_I4_5));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldc_I4, 0xC3));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Call, writeByteMethod));
var jumpToInstruction2 = new Instruction(OpCodes.Ldloc_0);
redirectMethodDef.Body.Instructions.Add(jumpToInstruction2);
jumpFromInstruction2.Operand = jumpToInstruction2;
jumpFromInstruction3.Operand = jumpToInstruction2;
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldc_I4_5));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Call, intPtrExplicitMethod));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldloc_2));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ldloca_S, undefinedLocal));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Call, virtualProtectNativeMethod));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Pop));
redirectMethodDef.Body.Instructions.Add(new Instruction(OpCodes.Ret));
var getTypeFromHandleMethod = importer.Import(typeof(Type).GetMethod(nameof(Type.GetTypeFromHandle)));
var typeGetMethodMethod = importer.Import(typeof(Type).GetMethod(nameof(Type.GetMethod), new Type[]
{
typeof(string)
}));
var methodBaseGetMethodHandle = importer.Import(typeof(MethodBase).GetMethod("get_MethodHandle"));
foreach (var typeDef in context.ModuleDefMD.GetTypes().ToArray())
{
foreach (var methodDef in typeDef.Methods.ToArray())
{
if (methodDef.HasBody)
{
for (int i = 0; i < methodDef.Body.Instructions.Count; i++)
{
if (methodDef.Body.Instructions[i].OpCode == OpCodes.Call
&& methodDef.Body.Instructions[i].Operand is MethodDef callingMethodDef
&& callingMethodDef.DeclaredInSameAssemblyAs(context.Assembly)
&& callingMethodDef.Name.Equals("Dummy") == false)
{
m_Logger.Information("name: {0}, declaring type: {1}", callingMethodDef.Name, callingMethodDef.DeclaringType.Name);
var dummyMethod = new MethodDefUser("Dummy", callingMethodDef.MethodSig, callingMethodDef.ImplAttributes, callingMethodDef.Attributes);
dummyMethod.ReturnType = callingMethodDef.ReturnType;
dummyMethod.Body = new CilBody();
var writeLineMethod = importer.Import(typeof(Console).GetMethod(nameof(Console.WriteLine), new Type[]
{
typeof(string)
}));
dummyMethod.Body.Instructions.Add(new Instruction(OpCodes.Ldstr, "hello!"));
dummyMethod.Body.Instructions.Add(new Instruction(OpCodes.Call, writeLineMethod));
dummyMethod.Body.Instructions.Add(new Instruction(OpCodes.Ret));
typeDef.Methods.Add(dummyMethod);
methodDef.Body.Instructions[i].Operand = dummyMethod;
var index = i;
methodDef.Body.Instructions.Insert(index++, new Instruction(OpCodes.Ldtoken, dummyMethod.DeclaringType));
methodDef.Body.Instructions.Insert(index++, new Instruction(OpCodes.Call, getTypeFromHandleMethod));
methodDef.Body.Instructions.Insert(index++, new Instruction(OpCodes.Ldstr, dummyMethod.Name.ToString()));
methodDef.Body.Instructions.Insert(index++, new Instruction(OpCodes.Call, typeGetMethodMethod));
methodDef.Body.Instructions.Insert(index++, new Instruction(OpCodes.Callvirt, methodBaseGetMethodHandle));
methodDef.Body.Instructions.Insert(index++, new Instruction(OpCodes.Ldtoken, dummyMethod.DeclaringType));
methodDef.Body.Instructions.Insert(index++, new Instruction(OpCodes.Ldstr, callingMethodDef.Name.ToString()));
methodDef.Body.Instructions.Insert(index++, new Instruction(OpCodes.Call, typeGetMethodMethod));
methodDef.Body.Instructions.Insert(index++, new Instruction(OpCodes.Call, methodBaseGetMethodHandle));
methodDef.Body.Instructions.Insert(index++, new Instruction(OpCodes.Call, redirectMethodDef));
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment