private IEnumerable <ProgramState> ProcessCall(VMFunction function, ILInstruction instruction, ProgramState next)
        {
            var symbolicAddress = next.Stack.Pop();

            instruction.Dependencies.AddOrMerge(0, symbolicAddress);

            uint address = (uint)symbolicAddress.InferStackValue().U8;

            if (address >= KoiStream.Contents.GetPhysicalSize())
            {
                Logger.Warning(Tag,
                               $"Call instruction at IL_{instruction.Offset:X4} "
                               + $"transfers control to a function outside of the KoiVM stream (IL_{address:X4}.");
            }

            var callee = _disassembler.GetOrCreateFunctionInfo(address, next.Key);

            callee.References.Add(new FunctionReference(function, instruction.Offset, FunctionReferenceType.Call, callee));
            instruction.Annotation = new CallAnnotation
            {
                Function          = callee,
                InferredPopCount  = 1,
                InferredPushCount = 1,
            };

            if (!callee.ExitKey.HasValue)
            {
                // Exit key of called function is not known yet.
                // We cannot continue disassembly yet because of the encryption used in KoiVM.
                function.UnresolvedOffsets.Add(instruction.Offset);
                Logger.Debug(Tag,
                             $"Stopped at call instruction at IL_{instruction.Offset:X4} "
                             + $"as exit key of function_{address:X4} is not known yet.");
                return(Enumerable.Empty <ProgramState>());
            }
            else
            {
                // Exit key is known, we can continue disassembly!
                function.UnresolvedOffsets.Remove(instruction.Offset);
                next.Key = callee.ExitKey.Value;

                return(new[] { next });
            }
        }
示例#2
0
        private void ProcessLdftn(VMFunction currentFunction, ILInstruction instruction, ProgramState next)
        {
            var symbolicMethod = next.Stack.Pop();
            var symbolicObject = next.Stack.Pop();

            instruction.Dependencies.AddOrMerge(1, symbolicMethod);
            instruction.Dependencies.AddOrMerge(2, symbolicObject);

            var methodSlot = symbolicMethod.InferStackValue();

            if (symbolicObject.Type == VMType.Object)
            {
                // This is a virtual dispatched ldftn.

                var method = (IMethodDescriptor)KoiStream.ResolveReference(Logger, instruction.Offset, methodSlot.U4,
                                                                           TableIndex.Method,
                                                                           TableIndex.MemberRef,
                                                                           TableIndex.MethodSpec);

                instruction.Annotation = new LdftnAnnotation(method, true);
            }
            else
            {
                // This is a static ldftn.

                var obj = symbolicObject.InferStackValue();
                if (obj.U8 != 0)
                {
                    // We are dealing with intra-linked methods.

                    // Pop entry key.
                    var symbolicEntryKey = next.Stack.Pop();
                    instruction.Dependencies.AddOrMerge(3, symbolicEntryKey);
                    uint entryKey = symbolicEntryKey.InferStackValue().U4;

                    // Obtain export containing signature.
                    uint exportId   = obj.U4;
                    var  exportInfo = KoiStream.Exports[exportId];

                    // Get the function at the pushed address and register reference.
                    uint codeAddress = (uint)methodSlot.U8;
                    var  function    = _disassembler.GetOrCreateFunctionInfo(codeAddress, entryKey);
                    function.References.Add(new FunctionReference(
                                                currentFunction,
                                                instruction.Offset,
                                                FunctionReferenceType.Ldftn,
                                                function));

                    instruction.Annotation = new LdftnAnnotation(function, exportInfo.Signature);
                }
                else
                {
                    // Resolve method.
                    var method = (IMethodDescriptor)KoiStream.ResolveReference(Logger, instruction.Offset, methodSlot.U4,
                                                                               TableIndex.Method,
                                                                               TableIndex.MemberRef,
                                                                               TableIndex.MethodSpec);

                    instruction.Annotation = new LdftnAnnotation(method, false);
                }
            }

            next.Stack.Push(new SymbolicValue(instruction, VMType.Pointer));

            instruction.Annotation.InferredPopCount  = instruction.Dependencies.Count;
            instruction.Annotation.InferredPushCount = 1;
        }
示例#3
0
        private void ProcessLdftn(VMFunction currentFunction, ILInstruction instruction, ProgramState next)
        {
            var symbolicMethod = next.Stack.Pop();
            var symbolicObject = next.Stack.Pop();

            instruction.Dependencies.AddOrMerge(1, symbolicMethod);
            instruction.Dependencies.AddOrMerge(2, symbolicObject);

            var methodSlot = symbolicMethod.InferStackValue();

            if (symbolicObject.Type == VMType.Object)
            {
                // TODO: get base method.
                throw new DisassemblyException(
                          $"Failed to process the LDFTN instruction at offset IL_{instruction.Offset:X4}.",
                          new NotSupportedException("LDFTN instructions based on objects is not supported yet."));
            }
            else
            {
                var obj = symbolicObject.InferStackValue();
                if (obj.U8 != 0)
                {
                    // We are dealing with intra-linked methods.

                    // Pop entry key.
                    var symbolicEntryKey = next.Stack.Pop();
                    instruction.Dependencies.AddOrMerge(3, symbolicEntryKey);
                    uint entryKey = symbolicEntryKey.InferStackValue().U4;

                    // Obtain export containing signature.
                    uint exportId   = obj.U4;
                    var  exportInfo = KoiStream.Exports[exportId];

                    // Get the function at the pushed address and register reference.
                    uint codeAddress = (uint)methodSlot.U8;
                    var  function    = _disassembler.GetOrCreateFunctionInfo(codeAddress, entryKey);
                    function.References.Add(new FunctionReference(
                                                currentFunction,
                                                instruction.Offset,
                                                FunctionReferenceType.Ldftn,
                                                function));

                    instruction.Annotation = new LdftnAnnotation(function, exportInfo.Signature);
                }
                else
                {
                    // Resolve method.
                    var method = (ICallableMemberReference)KoiStream.ResolveReference(Logger, instruction.Offset, methodSlot.U4,
                                                                                      MetadataTokenType.Method,
                                                                                      MetadataTokenType.MemberRef,
                                                                                      MetadataTokenType.MethodSpec);

                    instruction.Annotation = new LdftnAnnotation(method);
                }
            }

            next.Stack.Push(new SymbolicValue(instruction, VMType.Pointer));

            instruction.Annotation.InferredPopCount  = instruction.Dependencies.Count;
            instruction.Annotation.InferredPushCount = 1;
        }