public LdftnAnnotation(VMFunction function, VMFunctionSignature signature) : base(VMCalls.LDFTN, VMType.Pointer) { Function = function; Signature = signature; Method = null; }
public FunctionReference(VMFunction caller, int offset, FunctionReferenceType referenceType, VMFunction callee) { Caller = caller; Offset = offset; Callee = callee; ReferenceType = referenceType; }
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); }
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); }
public VirtualisedMethod(VMFunction function, uint exportId, VMExportInfo exportInfo) { Function = function; ExportId = exportId; ExportInfo = exportInfo; }
public VirtualisedMethod(VMFunction function) { Function = function; }
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); }
public static void Run(VMFunction mainFunc) { // todo... }
public Call(VMFunction function) { }
public Call(VMValue x, VMFunction function) { }