Beispiel #1
0
 public LdftnAnnotation(VMFunction function, VMFunctionSignature signature)
     : base(VMCalls.LDFTN, VMType.Pointer)
 {
     Function  = function;
     Signature = signature;
     Method    = null;
 }
Beispiel #2
0
 public FunctionReference(VMFunction caller, int offset, FunctionReferenceType referenceType, VMFunction callee)
 {
     Caller        = caller;
     Offset        = offset;
     Callee        = callee;
     ReferenceType = referenceType;
 }
Beispiel #3
0
        public ControlFlowGraph BuildGraph(VMFunction function)
        {
            var graph = new ControlFlowGraph();

            CollectBlocks(graph, function.Instructions.Values, function.BlockHeaders);
            graph.Entrypoint = GetNode(graph, function.EntrypointAddress);
            ConnectNodes(graph);

            try
            {
                CreateEHClusters(graph);
                AddAbnormalEdges(graph);
            }
            catch (Exception ex) when(SalvageOnError)
            {
                Logger.Error(Tag,
                             $"Failed to create EH clusters in CFG of function_{function.EntrypointAddress:X4}. {ex.Message}");
            }

            return(graph);
        }
Beispiel #4
0
        public IFrameLayout DetectFrameLayout(VMConstants constants, MetadataImage image,
                                              VMFunction function)
        {
            if (function.References.Count == 0)
            {
                throw new ArgumentException("Can only infer frame layout of a function that is at least referenced once.");
            }

            var exceptions = new List <Exception>();

            // Order the references by reference type, as LDFTN references are more reliable.
            foreach (var reference in function.References.OrderBy(r => r.ReferenceType))
            {
                try
                {
                    switch (reference.ReferenceType)
                    {
                    case FunctionReferenceType.Call:
                        return(InferLayoutFromCallReference(image, reference));

                    case FunctionReferenceType.Ldftn:
                        return(InferLayoutFromLdftnReference(constants, image, reference));

                    default:
                        throw new ArgumentOutOfRangeException();
                    }
                }
                catch (Exception ex)
                {
                    exceptions.Add(ex);
                }
            }

            throw new AggregateException(
                      $"Failed to infer the stack frame layout of function_{function.EntrypointAddress:X4}.", exceptions);
        }
Beispiel #5
0
 public VirtualisedMethod(VMFunction function, uint exportId, VMExportInfo exportInfo)
 {
     Function   = function;
     ExportId   = exportId;
     ExportInfo = exportInfo;
 }
Beispiel #6
0
 public VirtualisedMethod(VMFunction function)
 {
     Function = function;
 }
Beispiel #7
0
        public uint?ResolveExitKey(ILogger logger, KoiStream koiStream, VMConstants constants, VMFunction function)
        {
            // Strategy:
            //
            // Find CALL references to the function, and try every possible key in the key space that
            // decrypts the next instruction to either a PUSHR_xxxx R0 or a PUSHR_DWORD SP, as they
            // appear in the post-call to either store the return value, or adjust SP to clean up
            // the stack.

            // Since the actual decryption of the opcode only uses the 8 least significant bits, we can
            // make an optimisation that shaves off around 8 bits of the key space. By attempting to
            // decrypt the first byte using just the first 8 bits, and verifying whether this output
            // results to one of the instructions mentioned in the above, we can quickly rule out many
            // potential keys.

            var callReferences = function.References.Where(r => r.ReferenceType == FunctionReferenceType.Call).ToArray();

            if (callReferences.Length == 0)
            {
                logger.Warning(Tag, $"Cannot brute-force the exit key of function_{function.EntrypointAddress:X4} as it has no recorded call references.");
                return(null);
            }

            var data = koiStream.Data;

            // Find any call reference.
            foreach (var callReference in callReferences)
            {
                var  call         = callReference.Caller.Instructions[callReference.Offset];
                long targetOffset = call.Offset + call.Size;

                // Go over all possible LSBs.
                for (uint lsb = 0; lsb < byte.MaxValue; lsb++)
                {
                    // Check whether the LSB decodes to a PUSHR_xxxx.
                    if (IsPotentialLSB(constants, data[targetOffset], lsb))
                    {
                        // Go over all remaining 24 bits.
                        for (uint i = 0; i < 0x00FFFFFF; i++)
                        {
                            uint currentKey = (i << 8) | lsb;

                            // Try new key.
                            if (IsValidKey(constants, data, targetOffset, currentKey))
                            {
                                // We have found a key!
                                return(currentKey);
                            }
                        } // for all other 24 bits.
                    }     // if potential LSB
                }         // foreach LSB
            }             // foreach call reference

            return(null);
        }
        public uint?ResolveExitKey(ILogger logger, KoiStream koiStream, VMConstants constants, VMFunction function)
        {
            // Strategy:
            //
            // Find CALL references to the function, and try every possible key in the key space that
            // decrypts the next instruction to either a PUSHR_xxxx R0 or a PUSHR_DWORD SP, as they
            // appear in the post-call to either store the return value, or adjust SP to clean up
            // the stack.

            // Since the actual decryption of the opcode only uses the 8 least significant bits, we can
            // make an optimisation that shaves off around 8 bits of the key space. By attempting to
            // decrypt the first byte using just the first 8 bits, and verifying whether this output
            // results to one of the instructions mentioned in the above, we can quickly rule out many
            // potential keys.

            var callReferences = function.References
                                 .Where(r => r.ReferenceType == FunctionReferenceType.Call)
                                 .ToArray();

            if (callReferences.Length == 0)
            {
                logger.Warning(Tag, $"Cannot brute-force the exit key of function_{function.EntrypointAddress:X4} as it has no recorded call references.");
                return(null);
            }

            var reader = koiStream.Contents.CreateReader();

            byte[] encryptedOpCodes = new byte[3];
            var    watch            = new Stopwatch();

            // Find any call reference.
            for (int i = 0; i < callReferences.Length; i++)
            {
                var callReference = callReferences[i];
                logger.Debug(Tag, $"Started bruteforcing key for call reference {i.ToString()} ({callReference.ToString()}).");
                watch.Restart();

                var  call         = callReference.Caller.Instructions[callReference.Offset];
                long targetOffset = call.Offset + call.Size;

                reader.FileOffset = (uint)targetOffset;
                reader.ReadBytes(encryptedOpCodes, 0, encryptedOpCodes.Length);

                // Go over all possible LSBs.
                for (uint lsb = 0; lsb < byte.MaxValue; lsb++)
                {
                    // Check whether the LSB decodes to a PUSHR_xxxx.
                    if (IsPotentialLSB(constants, encryptedOpCodes[0], lsb))
                    {
                        // Go over all remaining 24 bits.
                        for (uint j = 0; j < 0x00FFFFFF; j++)
                        {
                            uint currentKey = (j << 8) | lsb;

                            // Try new key.
                            if (IsValidKey(constants, encryptedOpCodes, currentKey))
                            {
                                // We have found a key!
                                watch.Stop();
                                logger.Debug(Tag, $"Found key after {watch.Elapsed.TotalSeconds:0.00}s.");

                                return(currentKey);
                            }
                        } // for all other 24 bits.
                    }     // if potential LSB
                }         // foreach LSB

                watch.Stop();
                logger.Debug(Tag, $"Exhausted key space after {watch.Elapsed.TotalSeconds:0.00}s without finding key.");
            }

            return(null);
        }
Beispiel #9
0
 public static void Run(VMFunction mainFunc)
 {
     // todo...
 }
Beispiel #10
0
 public Call(VMFunction function)
 {
 }
Beispiel #11
0
 public Call(VMValue x, VMFunction function)
 {
 }