습작 및 R&D

닷넷 opcode 실행 예제.

empty1234 2025. 6. 24. 22:14

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Security.Permissions;
using System.Text;
using Systehttp://m.Threading.Tasks;
using dnlib.DotNet;
using dnlib.DotNet.Emit;

namespace dnLib
{
    internal class Program
    {
        public static void test()
        {
            var sb = new StringBuilder();

            sb.AppendLine("test1");
            sb.AppendLine("test2");
            sb.AppendLine("test3");

            if (sb.ToString().Length > 10)
            {
                sb.AppendLine("10>");
            }
            var sbResult = sb.ToString();

            Console.WriteLine(sbResult);

            var strMsg = string.Empty;
            strMsg = " TEST MSG";
            strMsg += " MSG3";
            strMsg += " MSG4";

            Console.WriteLine(strMsg);

            strMsg = " NO TEST MSG";
            strMsg += " MSG2";
            strMsg += " MSG3";

            Console.WriteLine(strMsg);
            
        }

        static void Main(string[] args)
        {

            string path = @"dnlib - 복사본.exe"; // 분석할 DLL 또는 EXE
            var module = ModuleDefMD.Load(path);

            foreach (TypeDef type in module.Types)
            {
                foreach (MethodDef method in type.Methods)
                {
                    if (!method.HasBody) continue;
                    Console.WriteLine(">> Method: " + method.FullName);
                    Simulate(method);
                }
            }





        }


        public static void Simulate(MethodDef method)
        {
            Stack<object> stack = new Stack<object>();
            Dictionary<string, object> locals = new Dictionary<string, object>();

            IList<Instruction> instructions = method.Body.Instructions;

            for (int i = 0; i < instructions.Count; i++)
            {
                Instruction instr = instructions[i];
                OpCode opcode = instr.OpCode;
                object operand = instr.Operand;

                // --- PUSH (ldstr)
                if (opcode == OpCodes.Ldstr)
                {
                    string str = operand as string;
                    stack.Push(str);
                    Console.WriteLine("[PUSH] \"" + str + "\"");
                }
                else if (opcode == OpCodes.Newobj && operand is IMethod ctor)
                {
                    string fullTypeName = ctor.DeclaringType.FullName.Replace("/", "+");
                    Type type = Type.GetType(fullTypeName);

                    if (type != null)
                    {
                        try
                        {
                            object instance = Activator.CreateInstance(type);
                            stack.Push(instance);
                            Console.WriteLine("[NEWOBJ] 생성자 호출 → 인스턴스 push: " + fullTypeName);
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine("[!] 생성자 실행 실패: " + ex.Message);
                        }
                    }
                    else
                    {
                        Console.WriteLine("[!] newobj: 타입 못 찾음 → " + fullTypeName);
                    }
                }
                else if (opcode == OpCodes.Ldsfld)
                {
                    if (operand is IField field)
                    {
                        string fullFieldName = field.FullName;

                        // 특수 처리: System.String::Empty
                        if (fullFieldName == "System.String System.String::Empty")
                        {
                            stack.Push(string.Empty);
                            Console.WriteLine("[LDSFLD] System.String::Empty → \"\"");
                        }
                        else
                        {
                            Console.WriteLine("[LDSFLD] 지원되지 않는 정적 필드: " + fullFieldName);
                            stack.Push(null); // 기본 처리
                        }
                    }
                }
                // --- PUSH (ldloc)
                else if (opcode.Code.ToString().StartsWith("Ldloc"))
                {
                    int index = GetLocalIndex(opcode.Code, operand, method);
                    string varName = "V_" + index;
                    object value = locals.ContainsKey(varName) ? locals[varName] : null;
                    stack.Push(value);
                    Console.WriteLine("[PUSH] " + varName + " → \"" + value + "\"");
                }
                // --- POP + STLOC
                else if (opcode.Code.ToString().StartsWith("Stloc"))
                {
                    int index = GetLocalIndex(opcode.Code, operand, method);
                    string varName = "V_" + index;
                    object value = stack.Pop();
                    locals[varName] = value;
                    //stack.Push(value);  // 선택적
                    Console.WriteLine("[STLOC] " + varName + " = \"" + value + "\"");
                }
                else if (opcode == OpCodes.Ldc_I4_S || opcode == OpCodes.Ldc_I4)
                {
                    int intValue = Convert.ToInt32(operand);
                    stack.Push(intValue);
                    Console.WriteLine("[PUSH] int32 " + intValue);
                }
                else if (opcode == OpCodes.Cgt)
                {
                    object right = stack.Pop();  // value2
                    object left = stack.Pop();   // value1

                    int a = Convert.ToInt32(left);
                    int b = Convert.ToInt32(right);
                    int result = (a > b) ? 1 : 0;

                    stack.Push(result);
                    Console.WriteLine("[CGT] " + a + " > " + b + " → " + result);
                }
                else if (opcode == OpCodes.Brfalse_S || opcode == OpCodes.Brfalse)
                {
                    if (stack.Count > 0)
                    {
                        object val = stack.Pop();
                        bool condition = Convert.ToInt32(val) == 0;

                        Instruction target = operand as Instruction;
                        int targetIndex = instructions.IndexOf(target);

                        Console.WriteLine("[BRFALSE] 조건값: " + val + " → " + (condition ? "분기함" : "계속 진행"));

                        if (condition)
                        {
                            i = targetIndex - 1; // for 루프 내에서 자동 증가되므로 -1
                        }
                    }
                    else
                    {
                        Console.WriteLine("[!] BRFALSE 조건 스택에 값 없음");
                    }
                }
                // --- POP
                else if (opcode == OpCodes.Pop)
                {
                    if (stack.Count > 0)
                    {
                        object discarded = stack.Pop();
                        Console.WriteLine("[POP] Discarded \"" + discarded + "\"");
                    }
                }
                // --- CALL (e.g., String.Concat)
                else if (opcode == OpCodes.Call && operand is IMethod methodRefCall)
                {
                   
                   InvokeCallvirtWithStack(methodRefCall, stack);
                   
                }
                // --- CALLVIRT (인스턴스 메서드 호출)
                else if (opcode == OpCodes.Callvirt && operand is IMethod methodRefVirt)
                {
                    InvokeCallvirtWithStack(methodRefVirt, stack);
                }


            }
            foreach (var item in method.Body.Variables)
            {
                Console.WriteLine(item);

            }
            Console.WriteLine(  );
        }

        // 도우미: 로컬 변수 인덱스 계산
        private static int GetLocalIndex(Code code, object operand, MethodDef method)
        {
            if (code == Code.Stloc_0 || code == Code.Ldloc_0) return 0;
            if (code == Code.Stloc_1 || code == Code.Ldloc_1) return 1;
            if (code == Code.Stloc_2 || code == Code.Ldloc_2) return 2;
            if (code == Code.Stloc_3 || code == Code.Ldloc_3) return 3;

            Local local = operand as Local;
            if (local != null)
                return method.Body.Variables.IndexOf(local);

            return -1;
        }

        // 핵심: callvirt 명령 실행
        public static void InvokeCallvirtWithStack(IMethod methodRef, Stack<object> ilStack)
        {
            string fullTypeName = methodRef.DeclaringType.FullName.Replace("/", "+");
            string methodName = methodRef.Name;

            Type type = Type.GetType(fullTypeName);
            if (type == null)
            {
                Console.WriteLine("[!] 타입을 찾을 수 없습니다: " + fullTypeName);
                return;
            }

           
            int paramCount = methodRef.MethodSig.Params.Count;
            List<object> argsList = new List<object>();

            for (int i = 0; i < paramCount; i++)
            {
                if (ilStack.Count > 0)
                {
                    object arg = ilStack.Pop();
                    argsList.Add(arg);
                    Console.WriteLine("[STACK POP] arg[" + i + "] = \"" + arg + "\"");
                }
                else
                {
                    argsList.Add(null);
                    Console.WriteLine("[STACK MISS] arg[" + i + "] = null");
                }
            }

            argsList.Reverse();
            object[] paramValues = argsList.ToArray();

            Type[] paramTypes = new Type[paramCount];
            for (int i = 0; i < paramCount; i++)
            {
                paramTypes[i] = typeof(string); // 간단화: 모두 string 처리
            }

            MethodInfo methodInfo = type.GetMethod(methodName, paramTypes);
            if (methodInfo == null)
            {
                Console.WriteLine("[!] 메서드 못 찾음: " + methodName);
                return;
            }


            object instance;
            if (ilStack.Count > 0) instance = ilStack.Pop();
            else
            {
                try
                {
                    instance = methodInfo.IsStatic ? null : Activator.CreateInstance(type);
                    //instance = Activator.CreateInstance(type);
                    Console.WriteLine("[✓] 인스턴스 생성: " + fullTypeName);
                }
                catch (Exception ex)
                {
                    Console.WriteLine("[!] 인스턴스 생성 실패: " + ex.Message);
                    return;
                }

            }

            try
            {
                object result = methodInfo.Invoke(instance, paramValues);
                Console.WriteLine("[✓] callvirt 실행 완료 → 반환값: " + (result ?? "(void)"));
                if (result != null)
                {
                    ilStack.Push(result);
                    Console.WriteLine("[PUSH] 반환값 \"" + result + "\"");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("[!] 호출 오류: " + ex.Message);
            }
        }


    }
}