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 }); } }
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; }
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; }