├── VERSION ├── .gitmodules ├── KoiVM ├── AST │ ├── ASTNode.cs │ ├── IL │ │ ├── IILOperand.cs │ │ ├── IHasOffset.cs │ │ ├── ILImmediate.cs │ │ ├── ILBlock.cs │ │ ├── ILInstrList.cs │ │ ├── ILDataTarget.cs │ │ ├── ILJumpTarget.cs │ │ ├── ILJumpTable.cs │ │ ├── ILMethodTarget.cs │ │ ├── ILRelReference.cs │ │ ├── ILInstruction.cs │ │ └── ILRegister.cs │ ├── ILAST │ │ ├── IILASTStatement.cs │ │ ├── IILASTNode.cs │ │ ├── ILASTVariableType.cs │ │ ├── ILASTVariable.cs │ │ ├── ILASTAssignment.cs │ │ ├── ILASTPhi.cs │ │ ├── ILASTTree.cs │ │ └── ILASTExpression.cs │ ├── IR │ │ ├── IIROperand.cs │ │ ├── IRVariableType.cs │ │ ├── IRVariable.cs │ │ ├── IRInstrList.cs │ │ ├── IRBlockTarget.cs │ │ ├── IRDataTarget.cs │ │ ├── IRJumpTable.cs │ │ ├── IRMetaTarget.cs │ │ ├── IRPointer.cs │ │ ├── IRConstant.cs │ │ ├── IRRegister.cs │ │ └── IRInstruction.cs │ ├── ASTExpression.cs │ ├── ASTVariable.cs │ ├── ASTType.cs │ ├── InstrAnnotation.cs │ ├── ASTConstant.cs │ └── TypeInference.cs ├── CFG │ ├── ScopeType.cs │ ├── BlockFlags.cs │ ├── CILInstrList.cs │ ├── IBasicBlock.cs │ └── BasicBlock.cs ├── VisitFunc.cs ├── Properties │ └── AssemblyInfo.cs ├── VMIL │ ├── ITransform.cs │ ├── IPostTransform.cs │ ├── ITranslationHandler.cs │ ├── Transforms │ │ ├── EntryExitTransform.cs │ │ ├── SaveInfoTransform.cs │ │ ├── FixMethodRefTransform.cs │ │ ├── ReferenceOffsetTransform.cs │ │ └── SaveRegistersTransform.cs │ ├── Translation │ │ ├── InvocationHandlers.cs │ │ ├── MiscHandlers.cs │ │ ├── EHHandlers.cs │ │ ├── MemoryHandlers.cs │ │ └── PseudoHandlers.cs │ ├── ILPostTransformer.cs │ ├── ILTransformer.cs │ ├── ILOpCode.cs │ └── ILTranslator.cs ├── VMIR │ ├── ITransform.cs │ ├── ITranslationHandler.cs │ ├── Transforms │ │ ├── RegisterAllocationTransform.cs │ │ ├── LeaTransform.cs │ │ ├── GetSetFlagTransform.cs │ │ ├── MarkReturnRegTransform.cs │ │ ├── MetadataTransform.cs │ │ ├── StackFrameTransform.cs │ │ ├── InitLocalTransform.cs │ │ ├── LogicTransform.cs │ │ └── GuardBlockTransform.cs │ ├── Compiler │ │ ├── IRCompilerAssemblyFinder.cs │ │ └── IRConstants.cs │ ├── TranslationHelpers.cs │ ├── RegAlloc │ │ └── BlockLiveness.cs │ ├── IROpCode.cs │ ├── Translation │ │ ├── CastHandlers.cs │ │ ├── LocalHandlers.cs │ │ ├── ParameterHandlers.cs │ │ ├── MiscHandlers.cs │ │ ├── ConstantHandlers.cs │ │ ├── FnPtrHandlers.cs │ │ └── BranchHandlers.cs │ └── IRTransformer.cs ├── RT │ ├── IKoiChunk.cs │ ├── KoiHeap.cs │ ├── BinaryChunk.cs │ ├── JumpTableChunk.cs │ ├── Mutation │ │ ├── RuntimePatcher.cs │ │ └── Renamer.cs │ └── DbgWriter.cs ├── ILAST │ ├── ITransformationHandler.cs │ ├── Transformation │ │ ├── NullTransform.cs │ │ ├── StringTransform.cs │ │ └── BranchTransform.cs │ └── ILASTTransformer.cs ├── IVMSettings.cs ├── VM │ ├── VMFlags.cs │ ├── Descriptors │ │ ├── RegisterDescriptor.cs │ │ ├── OpCodeDescriptor.cs │ │ ├── ArchDescriptor.cs │ │ ├── RuntimeDescriptor.cs │ │ ├── VCallOpsDescriptor.cs │ │ ├── VMDescriptor.cs │ │ ├── RTFlagDescriptor.cs │ │ ├── FlagDescriptor.cs │ │ └── VMCallDescriptor.cs │ ├── VMRegisters.cs │ ├── VMCalls.cs │ ├── VMMethodInfo.cs │ └── FuncSig.cs ├── Obfuscation.cs ├── Watermark.cs ├── Protections │ └── SMC │ │ └── SMCBlock.cs ├── MethodVirtualizer.cs └── Scanner.cs ├── KoiVM.Runtime ├── Properties │ └── AssemblyInfo.cs ├── Execution │ ├── ExecutionState.cs │ ├── PointerType.cs │ ├── EHFrame.cs │ ├── TypedRefPtr.cs │ ├── IReference.cs │ ├── EHState.cs │ ├── VMContext.cs │ ├── Internal │ │ ├── Unverifier.cs │ │ ├── SizeOfHelper.cs │ │ ├── ValueTypeBox.cs │ │ └── ArrayStoreHelpers.cs │ ├── PointerRef.cs │ ├── StackRef.cs │ ├── FieldRef.cs │ └── TypedRef.cs ├── VCalls │ ├── IVCall.cs │ ├── Exit.cs │ ├── Throw.cs │ ├── Localloc.cs │ ├── Ckoverflow.cs │ ├── Sizeof.cs │ ├── Rangechk.cs │ ├── Ckfinite.cs │ ├── Box.cs │ ├── Token.cs │ ├── Cast.cs │ ├── Initobj.cs │ ├── Unbox.cs │ ├── Ldfld.cs │ ├── Stfld.cs │ └── Ldftn.cs ├── OpCodes │ ├── IOpCode.cs │ ├── Nop.cs │ ├── Call.cs │ ├── Ret.cs │ ├── Vcall.cs │ ├── Pop.cs │ ├── Leave.cs │ ├── Try.cs │ ├── Sx.cs │ ├── Nor.cs │ ├── Shl.cs │ ├── IConv.cs │ ├── Sub.cs │ ├── FConv.cs │ ├── Shr.cs │ └── Jmp.cs ├── Platform.cs ├── Data │ ├── VMExportInfo.cs │ ├── VCallMap.cs │ ├── OpCodeMap.cs │ ├── VMFuncSig.cs │ └── VMData.cs ├── VMEntry.cs └── Utils.cs ├── KoiVM.Confuser ├── Properties │ └── AssemblyInfo.cs ├── Program.cs ├── Internal │ ├── Fish.cs │ └── FinalizePhase.cs ├── Obfuscation.cs ├── KoiSettings.cs ├── RC4.cs ├── KoiProtection.cs ├── LoginPrompt.cs ├── UpdatePrompt.cs ├── KoiSystem.cs └── SimpleSettings.cs ├── README.md ├── .gitignore ├── GlobalAssemblyInfo.Template.cs └── libs ├── UpdateVersion.csproj └── UpdateVersion.cs /VERSION: -------------------------------------------------------------------------------- 1 | 0.2.0 -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "dnlib"] 2 | path = dnlib 3 | url = https://github.com/yck1509/dnlib.git 4 | -------------------------------------------------------------------------------- /KoiVM/AST/ASTNode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KoiVM.AST { 4 | public abstract class ASTNode { 5 | } 6 | } -------------------------------------------------------------------------------- /KoiVM/AST/IL/IILOperand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KoiVM.AST.IL { 4 | public interface IILOperand { 5 | } 6 | } -------------------------------------------------------------------------------- /KoiVM/AST/ILAST/IILASTStatement.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KoiVM.AST.ILAST { 4 | public interface IILASTStatement { 5 | } 6 | } -------------------------------------------------------------------------------- /KoiVM/AST/IL/IHasOffset.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KoiVM.AST.IL { 4 | public interface IHasOffset { 5 | uint Offset { get; } 6 | } 7 | } -------------------------------------------------------------------------------- /KoiVM/AST/IR/IIROperand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KoiVM.AST.IR { 4 | public interface IIROperand { 5 | ASTType Type { get; } 6 | } 7 | } -------------------------------------------------------------------------------- /KoiVM/AST/ILAST/IILASTNode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KoiVM.AST.ILAST { 4 | public interface IILASTNode { 5 | ASTType? Type { get; } 6 | } 7 | } -------------------------------------------------------------------------------- /KoiVM/CFG/ScopeType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KoiVM.CFG { 4 | public enum ScopeType { 5 | None, 6 | Try, 7 | Filter, 8 | Handler 9 | } 10 | } -------------------------------------------------------------------------------- /KoiVM/AST/ASTExpression.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KoiVM.AST { 4 | public abstract class ASTExpression : ASTNode { 5 | public ASTType? Type { get; set; } 6 | } 7 | } -------------------------------------------------------------------------------- /KoiVM/VisitFunc.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KoiVM { 4 | public delegate void VisitFunc(TList list, TInstr instr, ref int index, TState state); 5 | } -------------------------------------------------------------------------------- /KoiVM/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | 4 | [assembly: AssemblyTitle("KoiVM virtualizer")] 5 | [assembly: AssemblyDescription("KoiVM virtualizer")] -------------------------------------------------------------------------------- /KoiVM.Runtime/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | 4 | [assembly: AssemblyTitle("KoiVM Runtime")] 5 | [assembly: AssemblyDescription("KoiVM runtime library")] -------------------------------------------------------------------------------- /KoiVM.Confuser/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | 4 | [assembly: AssemblyTitle("KoiVM Confuser")] 5 | [assembly: AssemblyDescription("KoiVM Confuser Interface")] -------------------------------------------------------------------------------- /KoiVM/CFG/BlockFlags.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KoiVM.CFG { 4 | [Flags] 5 | public enum BlockFlags { 6 | Normal = 0, 7 | ExitEHLeave = 1, 8 | ExitEHReturn = 2 9 | } 10 | } -------------------------------------------------------------------------------- /KoiVM/VMIL/ITransform.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KoiVM.VMIL { 4 | public interface ITransform { 5 | void Initialize(ILTransformer tr); 6 | void Transform(ILTransformer tr); 7 | } 8 | } -------------------------------------------------------------------------------- /KoiVM/VMIR/ITransform.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KoiVM.VMIR { 4 | public interface ITransform { 5 | void Initialize(IRTransformer tr); 6 | void Transform(IRTransformer tr); 7 | } 8 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | KoiVM 2 | ===== 3 | 4 | This is open source release of KoiVM. No support will be provided. 5 | 6 | Please do not use it for illegal purpose. Thanks. 7 | 8 | License 9 | ------- 10 | CC0 11 | -------------------------------------------------------------------------------- /KoiVM.Runtime/Execution/ExecutionState.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KoiVM.Runtime.Execution { 4 | internal enum ExecutionState { 5 | Next, 6 | Exit, 7 | Throw, 8 | Rethrow 9 | } 10 | } -------------------------------------------------------------------------------- /KoiVM/AST/IR/IRVariableType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KoiVM.AST.IR { 4 | public enum IRVariableType { 5 | VirtualRegister, 6 | Local, 7 | Argument, 8 | ExceptionObj 9 | } 10 | } -------------------------------------------------------------------------------- /KoiVM/AST/ILAST/ILASTVariableType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KoiVM.AST.ILAST { 4 | public enum ILASTVariableType { 5 | StackVar, 6 | ExceptionVar, 7 | FilterVar, 8 | PhiVar 9 | } 10 | } -------------------------------------------------------------------------------- /KoiVM/VMIL/IPostTransform.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KoiVM.VMIL { 4 | public interface IPostTransform { 5 | void Initialize(ILPostTransformer tr); 6 | void Transform(ILPostTransformer tr); 7 | } 8 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/Execution/PointerType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KoiVM.Runtime.Execution { 4 | internal enum PointerType { 5 | BYTE, 6 | WORD, 7 | DWORD, 8 | QWORD, 9 | OBJECT 10 | } 11 | } -------------------------------------------------------------------------------- /KoiVM/RT/IKoiChunk.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KoiVM.RT { 4 | public interface IKoiChunk { 5 | uint Length { get; } 6 | 7 | void OnOffsetComputed(uint offset); 8 | byte[] GetData(); 9 | } 10 | } -------------------------------------------------------------------------------- /KoiVM/ILAST/ITransformationHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KoiVM.ILAST { 4 | public interface ITransformationHandler { 5 | void Initialize(ILASTTransformer tr); 6 | void Transform(ILASTTransformer tr); 7 | } 8 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/VCalls/IVCall.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.Runtime.Execution; 3 | 4 | namespace KoiVM.Runtime.VCalls { 5 | internal interface IVCall { 6 | byte Code { get; } 7 | void Run(VMContext ctx, out ExecutionState state); 8 | } 9 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/OpCodes/IOpCode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.Runtime.Execution; 3 | 4 | namespace KoiVM.Runtime.OpCodes { 5 | internal interface IOpCode { 6 | byte Code { get; } 7 | void Run(VMContext ctx, out ExecutionState state); 8 | } 9 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/Platform.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KoiVM.Runtime { 4 | internal static class Platform { 5 | public static readonly bool x64 = (IntPtr.Size == 8); 6 | public static readonly bool LittleEndian = BitConverter.IsLittleEndian; 7 | } 8 | } -------------------------------------------------------------------------------- /KoiVM/AST/ASTVariable.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KoiVM.AST { 4 | public class ASTVariable { 5 | public ASTType Type { get; set; } 6 | public string Name { get; set; } 7 | 8 | public override string ToString() { 9 | return Name; 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /KoiVM/VMIL/ITranslationHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.AST.IR; 3 | using KoiVM.VMIR; 4 | 5 | namespace KoiVM.VMIL { 6 | public interface ITranslationHandler { 7 | IROpCode IRCode { get; } 8 | void Translate(IRInstruction instr, ILTranslator tr); 9 | } 10 | } -------------------------------------------------------------------------------- /KoiVM/CFG/CILInstrList.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using dnlib.DotNet.Emit; 4 | 5 | namespace KoiVM.CFG { 6 | public class CILInstrList : List { 7 | public override string ToString() { 8 | return string.Join(Environment.NewLine, this); 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/Execution/EHFrame.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KoiVM.Runtime.Execution { 4 | internal struct EHFrame { 5 | public byte EHType; 6 | public ulong FilterAddr; 7 | public ulong HandlerAddr; 8 | public Type CatchType; 9 | 10 | public VMSlot BP; 11 | public VMSlot SP; 12 | } 13 | } -------------------------------------------------------------------------------- /KoiVM/AST/ASTType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | 4 | namespace KoiVM.AST { 5 | [Obfuscation(Exclude = false, ApplyToMembers = false, Feature = "+rename(forceRen=true);")] 6 | public enum ASTType { 7 | I4, 8 | I8, 9 | R4, 10 | R8, 11 | O, 12 | Ptr, 13 | ByRef 14 | } 15 | } -------------------------------------------------------------------------------- /KoiVM/AST/IL/ILImmediate.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KoiVM.AST.IL { 4 | public class ILImmediate : ASTConstant, IILOperand { 5 | public static ILImmediate Create(object value, ASTType type) { 6 | return new ILImmediate { 7 | Value = value, 8 | Type = type 9 | }; 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /KoiVM/VMIR/ITranslationHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using dnlib.DotNet.Emit; 3 | using KoiVM.AST.ILAST; 4 | using KoiVM.AST.IR; 5 | 6 | namespace KoiVM.VMIR { 7 | public interface ITranslationHandler { 8 | Code ILCode { get; } 9 | IIROperand Translate(ILASTExpression expr, IRTranslator tr); 10 | } 11 | } -------------------------------------------------------------------------------- /KoiVM/AST/ILAST/ILASTVariable.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KoiVM.AST.ILAST { 4 | public class ILASTVariable : ASTVariable, IILASTNode { 5 | ASTType? IILASTNode.Type { 6 | get { return base.Type; } 7 | } 8 | 9 | public ILASTVariableType VariableType { get; set; } 10 | public object Annotation { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /KoiVM/CFG/IBasicBlock.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace KoiVM.CFG { 5 | public interface IBasicBlock { 6 | int Id { get; } 7 | object Content { get; } 8 | BlockFlags Flags { get; set; } 9 | IEnumerable Sources { get; } 10 | IEnumerable Targets { get; } 11 | } 12 | } -------------------------------------------------------------------------------- /KoiVM/IVMSettings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using dnlib.DotNet; 3 | 4 | namespace KoiVM { 5 | public interface IVMSettings { 6 | int Seed { get; } 7 | bool IsDebug { get; } 8 | bool ExportDbgInfo { get; } 9 | bool DoStackWalk { get; } 10 | bool IsVirtualized(MethodDef method); 11 | bool IsExported(MethodDef method); 12 | } 13 | } -------------------------------------------------------------------------------- /KoiVM/AST/ILAST/ILASTAssignment.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KoiVM.AST.ILAST { 4 | public class ILASTAssignment : ASTNode, IILASTStatement { 5 | public ILASTVariable Variable { get; set; } 6 | public ILASTExpression Value { get; set; } 7 | 8 | public override string ToString() { 9 | return string.Format("{0} = {1}", Variable, Value); 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /KoiVM.Confuser/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; 3 | 4 | namespace KoiVM.Confuser { 5 | internal class Program { 6 | [STAThread] 7 | static void Main(string[] args) { 8 | KoiInfo.Init(); 9 | 10 | Application.EnableVisualStyles(); 11 | Application.SetCompatibleTextRenderingDefault(false); 12 | Application.Run(new ConfigWindow()); 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/OpCodes/Nop.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.Runtime.Dynamic; 3 | using KoiVM.Runtime.Execution; 4 | 5 | namespace KoiVM.Runtime.OpCodes { 6 | internal class Nop : IOpCode { 7 | public byte Code { 8 | get { return Constants.OP_NOP; } 9 | } 10 | 11 | public void Run(VMContext ctx, out ExecutionState state) { 12 | state = ExecutionState.Next; 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/VCalls/Exit.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.Runtime.Dynamic; 3 | using KoiVM.Runtime.Execution; 4 | 5 | namespace KoiVM.Runtime.VCalls { 6 | internal class Exit : IVCall { 7 | public byte Code { 8 | get { return Constants.VCALL_EXIT; } 9 | } 10 | 11 | public void Run(VMContext ctx, out ExecutionState state) { 12 | state = ExecutionState.Exit; 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /KoiVM/VM/VMFlags.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | 4 | namespace KoiVM.VM { 5 | [Obfuscation(Exclude = false, ApplyToMembers = false, Feature = "+rename(forceRen=true);")] 6 | public enum VMFlags { 7 | OVERFLOW = 0, 8 | CARRY = 1, 9 | ZERO = 2, 10 | SIGN = 3, 11 | UNSIGNED = 4, 12 | BEHAV1 = 5, 13 | BEHAV2 = 6, 14 | BEHAV3 = 7, 15 | 16 | Max 17 | } 18 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/Execution/TypedRefPtr.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KoiVM.Runtime.Execution { 4 | internal unsafe struct TypedRefPtr { 5 | public void* ptr; 6 | 7 | public static implicit operator TypedRefPtr(void* ptr) { 8 | return new TypedRefPtr { ptr = ptr }; 9 | } 10 | 11 | public static implicit operator void*(TypedRefPtr ptr) { 12 | return ptr.ptr; 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/Execution/IReference.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KoiVM.Runtime.Execution { 4 | internal interface IReference { 5 | VMSlot GetValue(VMContext ctx, PointerType type); 6 | void SetValue(VMContext ctx, VMSlot slot, PointerType type); 7 | IReference Add(uint value); 8 | IReference Add(ulong value); 9 | 10 | void ToTypedReference(VMContext ctx, TypedRefPtr typedRef, Type type); 11 | } 12 | } -------------------------------------------------------------------------------- /KoiVM/AST/IL/ILBlock.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using dnlib.DotNet; 3 | using KoiVM.CFG; 4 | using KoiVM.RT; 5 | 6 | namespace KoiVM.AST.IL { 7 | public class ILBlock : BasicBlock { 8 | public ILBlock(int id, ILInstrList content) 9 | : base(id, content) { 10 | } 11 | 12 | public virtual IKoiChunk CreateChunk(VMRuntime rt, MethodDef method) { 13 | return new BasicBlockChunk(rt, method, this); 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /KoiVM/AST/IR/IRVariable.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using dnlib.DotNet; 3 | 4 | namespace KoiVM.AST.IR { 5 | public class IRVariable : ASTVariable, IIROperand { 6 | public IRVariableType VariableType { get; set; } 7 | public TypeSig RawType { get; set; } 8 | public int Id { get; set; } 9 | public object Annotation { get; set; } 10 | 11 | public override string ToString() { 12 | return string.Format("{0}:{1}", Name, Type); 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /KoiVM/VM/Descriptors/RegisterDescriptor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | 4 | namespace KoiVM.VM { 5 | public class RegisterDescriptor { 6 | byte[] regOrder = Enumerable.Range(0, (int)VMRegisters.Max).Select(x => (byte)x).ToArray(); 7 | 8 | public RegisterDescriptor(Random random) { 9 | random.Shuffle(regOrder); 10 | } 11 | 12 | public byte this[VMRegisters reg] { 13 | get { return regOrder[(int)reg]; } 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /KoiVM/VM/Descriptors/OpCodeDescriptor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using KoiVM.VMIL; 4 | 5 | namespace KoiVM.VM { 6 | public class OpCodeDescriptor { 7 | byte[] opCodeOrder = Enumerable.Range(0, 256).Select(x => (byte)x).ToArray(); 8 | 9 | public OpCodeDescriptor(Random random) { 10 | random.Shuffle(opCodeOrder); 11 | } 12 | 13 | public byte this[ILOpCode opCode] { 14 | get { return opCodeOrder[(int)opCode]; } 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /KoiVM/AST/IL/ILInstrList.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace KoiVM.AST.IL { 5 | public class ILInstrList : List { 6 | public override string ToString() { 7 | return string.Join(Environment.NewLine, this); 8 | } 9 | 10 | public void VisitInstrs(VisitFunc visitFunc, T arg) { 11 | for (int i = 0; i < Count; i++) 12 | visitFunc(this, this[i], ref i, arg); 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /KoiVM/AST/IR/IRInstrList.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace KoiVM.AST.IR { 5 | public class IRInstrList : List { 6 | public override string ToString() { 7 | return string.Join(Environment.NewLine, this); 8 | } 9 | 10 | public void VisitInstrs(VisitFunc visitFunc, T arg) { 11 | for (int i = 0; i < Count; i++) 12 | visitFunc(this, this[i], ref i, arg); 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | #ignore thumbnails created by windows 3 | Thumbs.db 4 | #Ignore files build by Visual Studio 5 | *.obj 6 | *.exe 7 | *.pdb 8 | *.user 9 | *.aps 10 | *.pch 11 | *.vspscc 12 | *_i.c 13 | *_p.c 14 | *.ncb 15 | *.suo 16 | *.tlb 17 | *.tlh 18 | *.bak 19 | *.cache 20 | *.ilk 21 | *.log 22 | [Bb]in 23 | [Dd]ebug*/ 24 | *.lib 25 | *.sbr 26 | obj/ 27 | [Rr]elease*/ 28 | _ReSharper*/ 29 | [Tt]est[Rr]esult* 30 | 31 | users*.lst 32 | GlobalAssemblyInfo.cs 33 | Temp/ -------------------------------------------------------------------------------- /KoiVM/AST/IR/IRBlockTarget.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.CFG; 3 | 4 | namespace KoiVM.AST.IR { 5 | public class IRBlockTarget : IIROperand { 6 | public IRBlockTarget(IBasicBlock target) { 7 | Target = target; 8 | } 9 | 10 | public IBasicBlock Target { get; set; } 11 | 12 | public ASTType Type { 13 | get { return ASTType.Ptr; } 14 | } 15 | 16 | public override string ToString() { 17 | return string.Format("Block_{0:x2}", Target.Id); 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /KoiVM/AST/IR/IRDataTarget.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.RT; 3 | 4 | namespace KoiVM.AST.IR { 5 | public class IRDataTarget : IIROperand { 6 | public IRDataTarget(BinaryChunk target) { 7 | Target = target; 8 | } 9 | 10 | public BinaryChunk Target { get; set; } 11 | public string Name { get; set; } 12 | 13 | public ASTType Type { 14 | get { return ASTType.Ptr; } 15 | } 16 | 17 | public override string ToString() { 18 | return Name; 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /KoiVM/AST/IR/IRJumpTable.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.CFG; 3 | 4 | namespace KoiVM.AST.IR { 5 | public class IRJumpTable : IIROperand { 6 | public IRJumpTable(IBasicBlock[] targets) { 7 | Targets = targets; 8 | } 9 | 10 | public IBasicBlock[] Targets { get; set; } 11 | 12 | public ASTType Type { 13 | get { return ASTType.Ptr; } 14 | } 15 | 16 | public override string ToString() { 17 | return string.Format("[..{0}..]", Targets.Length); 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /KoiVM/AST/IR/IRMetaTarget.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KoiVM.AST.IR { 4 | public class IRMetaTarget : IIROperand { 5 | public IRMetaTarget(object mdItem) { 6 | MetadataItem = mdItem; 7 | } 8 | 9 | public object MetadataItem { get; set; } 10 | public bool LateResolve { get; set; } 11 | 12 | public ASTType Type { 13 | get { return ASTType.Ptr; } 14 | } 15 | 16 | public override string ToString() { 17 | return MetadataItem.ToString(); 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/Execution/EHState.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KoiVM.Runtime.Execution { 4 | internal class EHState { 5 | public enum EHProcess { 6 | Searching, // Search for handler, filter are executed 7 | Unwinding // Unwind the stack, fault/finally are executed 8 | } 9 | 10 | public EHProcess CurrentProcess; 11 | public object ExceptionObj; 12 | public VMSlot OldBP; 13 | public VMSlot OldSP; 14 | public int? CurrentFrame; 15 | public int? HandlerFrame; 16 | } 17 | } -------------------------------------------------------------------------------- /KoiVM/AST/IL/ILDataTarget.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.RT; 3 | 4 | namespace KoiVM.AST.IL { 5 | public class ILDataTarget : IILOperand, IHasOffset { 6 | public ILDataTarget(BinaryChunk target) { 7 | Target = target; 8 | } 9 | 10 | public BinaryChunk Target { get; set; } 11 | public string Name { get; set; } 12 | 13 | public uint Offset { 14 | get { return Target.Offset; } 15 | } 16 | 17 | public override string ToString() { 18 | return Name; 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /KoiVM/VM/Descriptors/ArchDescriptor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KoiVM.VM { 4 | public class ArchDescriptor { 5 | public ArchDescriptor(Random random) { 6 | OpCodes = new OpCodeDescriptor(random); 7 | Flags = new FlagDescriptor(random); 8 | Registers = new RegisterDescriptor(random); 9 | } 10 | 11 | public OpCodeDescriptor OpCodes { get; private set; } 12 | public FlagDescriptor Flags { get; private set; } 13 | public RegisterDescriptor Registers { get; private set; } 14 | } 15 | } -------------------------------------------------------------------------------- /KoiVM/VM/VMRegisters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | 4 | namespace KoiVM.VM { 5 | [Obfuscation(Exclude = false, ApplyToMembers = false, Feature = "+rename(forceRen=true);")] 6 | public enum VMRegisters { 7 | R0 = 0, 8 | R1 = 1, 9 | R2 = 2, 10 | R3 = 3, 11 | R4 = 4, 12 | R5 = 5, 13 | R6 = 6, 14 | R7 = 7, 15 | 16 | BP = 8, 17 | SP = 9, 18 | IP = 10, 19 | FL = 11, 20 | K1 = 12, 21 | K2 = 13, 22 | M1 = 14, 23 | M2 = 15, 24 | 25 | Max 26 | } 27 | } -------------------------------------------------------------------------------- /KoiVM/AST/IL/ILJumpTarget.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.CFG; 3 | 4 | namespace KoiVM.AST.IL { 5 | public class ILBlockTarget : IILOperand, IHasOffset { 6 | public ILBlockTarget(IBasicBlock target) { 7 | Target = target; 8 | } 9 | 10 | public IBasicBlock Target { get; set; } 11 | 12 | public uint Offset { 13 | get { return ((ILBlock)Target).Content[0].Offset; } 14 | } 15 | 16 | public override string ToString() { 17 | return string.Format("Block_{0:x2}", Target.Id); 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /KoiVM/VM/Descriptors/RuntimeDescriptor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KoiVM.VM { 4 | public class RuntimeDescriptor { 5 | public RuntimeDescriptor(Random random) { 6 | VMCall = new VMCallDescriptor(random); 7 | VCallOps = new VCallOpsDescriptor(random); 8 | RTFlags = new RTFlagDescriptor(random); 9 | } 10 | 11 | public VMCallDescriptor VMCall { get; private set; } 12 | public VCallOpsDescriptor VCallOps { get; private set; } 13 | public RTFlagDescriptor RTFlags { get; private set; } 14 | } 15 | } -------------------------------------------------------------------------------- /GlobalAssemblyInfo.Template.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | [assembly: AssemblyProduct("KoiVM")] 4 | [assembly: AssemblyCompany("Ki")] 5 | [assembly: AssemblyCopyright("Copyright (C) Ki 2014")] 6 | 7 | #if DEBUG 8 | 9 | [assembly: AssemblyConfiguration("Debug")] 10 | #elif __TRACE 11 | 12 | [assembly: AssemblyConfiguration("Trace")] 13 | #else 14 | 15 | [assembly: AssemblyConfiguration("Release")] 16 | #endif 17 | 18 | [assembly: AssemblyVersion("{{VER}}")] 19 | [assembly: AssemblyFileVersion("{{VER}}")] 20 | [assembly: AssemblyInformationalVersion("{{TAG}}")] -------------------------------------------------------------------------------- /KoiVM/Obfuscation.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | 4 | [assembly: Obfuscation(Exclude = false, Feature = "koi(dbgInfo=true,rtName=kiRT)", ApplyToMembers = false)] 5 | 6 | [assembly: Obfuscation(Exclude = false, Feature = 7 | "preset(aggressive);+constants(mode=dynamic,decoderCount=10,cfg=true);" + 8 | "+ctrl flow(predicate=expression,intensity=100);+rename(renPublic=true,mode=sequential);" + 9 | "+ref proxy(mode=strong,encoding=expression,typeErasure=true);" + 10 | "+resources(mode=dynamic);" 11 | #if DEBUG 12 | + "-anti debug;-rename;" 13 | #endif 14 | )] -------------------------------------------------------------------------------- /KoiVM/VM/VMCalls.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | 4 | namespace KoiVM.VM { 5 | [Obfuscation(Exclude = false, ApplyToMembers = false, Feature = "+rename(forceRen=true);")] 6 | public enum VMCalls { 7 | EXIT = 0, 8 | BREAK = 1, 9 | ECALL = 2, 10 | CAST = 3, 11 | CKFINITE = 4, 12 | CKOVERFLOW = 5, 13 | RANGECHK = 6, 14 | INITOBJ = 7, 15 | LDFLD = 8, 16 | LDFTN = 9, 17 | TOKEN = 10, 18 | THROW = 11, 19 | SIZEOF = 12, 20 | STFLD = 13, 21 | BOX = 14, 22 | UNBOX = 15, 23 | LOCALLOC = 16, 24 | 25 | Max 26 | } 27 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/OpCodes/Call.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.Runtime.Dynamic; 3 | using KoiVM.Runtime.Execution; 4 | 5 | namespace KoiVM.Runtime.OpCodes { 6 | internal class Call : IOpCode { 7 | public byte Code { 8 | get { return Constants.OP_CALL; } 9 | } 10 | 11 | public void Run(VMContext ctx, out ExecutionState state) { 12 | var sp = ctx.Registers[Constants.REG_SP].U4; 13 | var slot = ctx.Stack[sp]; 14 | ctx.Stack[sp] = ctx.Registers[Constants.REG_IP]; 15 | ctx.Registers[Constants.REG_IP].U8 = slot.U8; 16 | state = ExecutionState.Next; 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /KoiVM.Confuser/Internal/Fish.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | 4 | namespace KoiVM.Confuser.Internal { 5 | [Obfuscation(Exclude = false, Feature = "+koi;")] 6 | public static class Fish { 7 | public static readonly string UserName = "{USERNAME}"; 8 | public static readonly string SubscriptionEnd = "{SUBSCRIPTION}"; 9 | public static readonly string Id = "00000000"; 10 | 11 | public static readonly object VirtualizerKey = new object(); 12 | public static readonly object MergeKey = new object(); 13 | public static readonly object ExportKey = new object(); 14 | } 15 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/Data/VMExportInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | 4 | namespace KoiVM.Runtime.Data { 5 | internal struct VMExportInfo { 6 | public unsafe VMExportInfo(ref byte* ptr, Module module) { 7 | CodeOffset = *(uint*)ptr; 8 | ptr += 4; 9 | if (CodeOffset != 0) { 10 | EntryKey = *(uint*)ptr; 11 | ptr += 4; 12 | } 13 | else 14 | EntryKey = 0; 15 | Signature = new VMFuncSig(ref ptr, module); 16 | } 17 | 18 | public readonly uint CodeOffset; 19 | public readonly uint EntryKey; 20 | public readonly VMFuncSig Signature; 21 | } 22 | } -------------------------------------------------------------------------------- /KoiVM/ILAST/Transformation/NullTransform.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using dnlib.DotNet.Emit; 3 | using KoiVM.AST.ILAST; 4 | 5 | namespace KoiVM.ILAST.Transformation { 6 | public class NullTransform : ITransformationHandler { 7 | public void Initialize(ILASTTransformer tr) { 8 | } 9 | 10 | public void Transform(ILASTTransformer tr) { 11 | tr.Tree.TraverseTree(Transform, tr); 12 | } 13 | 14 | static void Transform(ILASTExpression expr, ILASTTransformer tr) { 15 | if (expr.ILCode != Code.Ldnull) 16 | return; 17 | 18 | expr.ILCode = Code.Ldc_I4; 19 | expr.Operand = 0; 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/VCalls/Throw.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.Runtime.Dynamic; 3 | using KoiVM.Runtime.Execution; 4 | 5 | namespace KoiVM.Runtime.VCalls { 6 | internal class Throw : IVCall { 7 | public byte Code { 8 | get { return Constants.VCALL_THROW; } 9 | } 10 | 11 | public void Run(VMContext ctx, out ExecutionState state) { 12 | var sp = ctx.Registers[Constants.REG_SP].U4; 13 | var type = ctx.Stack[sp--].U4; 14 | ctx.Registers[Constants.REG_SP].U4 = sp; 15 | if (type == 1) 16 | state = ExecutionState.Rethrow; 17 | else 18 | state = ExecutionState.Throw; 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /KoiVM/VMIR/Transforms/RegisterAllocationTransform.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.VMIR.RegAlloc; 3 | 4 | namespace KoiVM.VMIR.Transforms { 5 | public class RegisterAllocationTransform : ITransform { 6 | RegisterAllocator allocator; 7 | 8 | public static readonly object RegAllocatorKey = new object(); 9 | 10 | public void Initialize(IRTransformer tr) { 11 | allocator = new RegisterAllocator(tr); 12 | allocator.Initialize(); 13 | tr.Annotations[RegAllocatorKey] = allocator; 14 | } 15 | 16 | public void Transform(IRTransformer tr) { 17 | allocator.Allocate(tr.Block); 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/OpCodes/Ret.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.Runtime.Dynamic; 3 | using KoiVM.Runtime.Execution; 4 | 5 | namespace KoiVM.Runtime.OpCodes { 6 | internal class Ret : IOpCode { 7 | public byte Code { 8 | get { return Constants.OP_RET; } 9 | } 10 | 11 | public void Run(VMContext ctx, out ExecutionState state) { 12 | var sp = ctx.Registers[Constants.REG_SP].U4; 13 | var slot = ctx.Stack[sp]; 14 | ctx.Stack.SetTopPosition(--sp); 15 | ctx.Registers[Constants.REG_SP].U4 = sp; 16 | 17 | ctx.Registers[Constants.REG_IP].U8 = slot.U8; 18 | state = ExecutionState.Next; 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /KoiVM/AST/ILAST/ILASTPhi.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | 4 | namespace KoiVM.AST.ILAST { 5 | public class ILASTPhi : ASTNode, IILASTStatement { 6 | public ILASTVariable Variable { get; set; } 7 | public ILASTVariable[] SourceVariables { get; set; } 8 | 9 | public override string ToString() { 10 | var ret = new StringBuilder(); 11 | ret.AppendFormat("{0} = [", Variable); 12 | for (int i = 0; i < SourceVariables.Length; i++) { 13 | if (i != 0) 14 | ret.Append(", "); 15 | ret.Append(SourceVariables[i]); 16 | } 17 | ret.Append("]"); 18 | return ret.ToString(); 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /KoiVM/VM/Descriptors/VCallOpsDescriptor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KoiVM.VM { 4 | public class VCallOpsDescriptor { 5 | uint[] ecallOrder = { 0, 1, 2, 3 }; 6 | 7 | public VCallOpsDescriptor(Random random) { 8 | random.Shuffle(ecallOrder); 9 | } 10 | 11 | public uint ECALL_CALL { 12 | get { return ecallOrder[0]; } 13 | } 14 | 15 | public uint ECALL_CALLVIRT { 16 | get { return ecallOrder[1]; } 17 | } 18 | 19 | public uint ECALL_NEWOBJ { 20 | get { return ecallOrder[2]; } 21 | } 22 | 23 | public uint ECALL_CALLVIRT_CONSTRAINED { 24 | get { return ecallOrder[3]; } 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/OpCodes/Vcall.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.Runtime.Data; 3 | using KoiVM.Runtime.Dynamic; 4 | using KoiVM.Runtime.Execution; 5 | 6 | namespace KoiVM.Runtime.OpCodes { 7 | internal class Vcall : IOpCode { 8 | public byte Code { 9 | get { return Constants.OP_VCALL; } 10 | } 11 | 12 | public void Run(VMContext ctx, out ExecutionState state) { 13 | var sp = ctx.Registers[Constants.REG_SP].U4; 14 | var slot = ctx.Stack[sp]; 15 | ctx.Stack.SetTopPosition(--sp); 16 | ctx.Registers[Constants.REG_SP].U4 = sp; 17 | 18 | var vCall = VCallMap.Lookup(slot.U1); 19 | vCall.Run(ctx, out state); 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/VCalls/Localloc.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.Runtime.Dynamic; 3 | using KoiVM.Runtime.Execution; 4 | 5 | namespace KoiVM.Runtime.VCalls { 6 | internal class Localloc : IVCall { 7 | public byte Code { 8 | get { return Constants.VCALL_LOCALLOC; } 9 | } 10 | 11 | public void Run(VMContext ctx, out ExecutionState state) { 12 | var sp = ctx.Registers[Constants.REG_SP].U4; 13 | var bp = ctx.Registers[Constants.REG_BP].U4; 14 | var size = ctx.Stack[sp].U4; 15 | ctx.Stack[sp] = new VMSlot { 16 | U8 = (ulong)ctx.Stack.Localloc(bp, size) 17 | }; 18 | 19 | state = ExecutionState.Next; 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /KoiVM/VM/VMMethodInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using KoiVM.CFG; 4 | 5 | namespace KoiVM.VM { 6 | public class VMMethodInfo { 7 | public VMMethodInfo() { 8 | BlockKeys = new Dictionary(); 9 | UsedRegister = new HashSet(); 10 | } 11 | 12 | public ScopeBlock RootScope; 13 | public readonly Dictionary BlockKeys; 14 | public readonly HashSet UsedRegister; 15 | public byte EntryKey; 16 | public byte ExitKey; 17 | } 18 | 19 | public struct VMBlockKey { 20 | public byte EntryKey; 21 | public byte ExitKey; 22 | } 23 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/VCalls/Ckoverflow.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.Runtime.Dynamic; 3 | using KoiVM.Runtime.Execution; 4 | 5 | namespace KoiVM.Runtime.VCalls { 6 | internal class Ckoverflow : IVCall { 7 | public byte Code { 8 | get { return Constants.VCALL_CKOVERFLOW; } 9 | } 10 | 11 | public unsafe void Run(VMContext ctx, out ExecutionState state) { 12 | var sp = ctx.Registers[Constants.REG_SP].U4; 13 | var fSlot = ctx.Stack[sp--]; 14 | 15 | if (fSlot.U4 != 0) 16 | throw new OverflowException(); 17 | 18 | ctx.Stack.SetTopPosition(sp); 19 | ctx.Registers[Constants.REG_SP].U4 = sp; 20 | state = ExecutionState.Next; 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /KoiVM/AST/IL/ILJumpTable.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.CFG; 3 | using KoiVM.RT; 4 | 5 | namespace KoiVM.AST.IL { 6 | public class ILJumpTable : IILOperand, IHasOffset { 7 | public ILJumpTable(IBasicBlock[] targets) { 8 | Targets = targets; 9 | Chunk = new JumpTableChunk(this); 10 | } 11 | 12 | public JumpTableChunk Chunk { get; private set; } 13 | public ILInstruction RelativeBase { get; set; } 14 | public IBasicBlock[] Targets { get; set; } 15 | 16 | public uint Offset { 17 | get { return Chunk.Offset; } 18 | } 19 | 20 | public override string ToString() { 21 | return string.Format("[..{0}..]", Targets.Length); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /KoiVM/AST/IR/IRPointer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KoiVM.AST.IR { 4 | public class IRPointer : IIROperand { 5 | public IRRegister Register { get; set; } 6 | public int Offset { get; set; } 7 | 8 | public IRVariable SourceVariable { get; set; } 9 | public ASTType Type { get; set; } 10 | 11 | public override string ToString() { 12 | string prefix = Type.ToString(); 13 | string offsetStr = ""; 14 | if (Offset > 0) 15 | offsetStr = string.Format(" + {0:x}h", Offset); 16 | else if (Offset < 0) 17 | offsetStr = string.Format(" - {0:x}h", -Offset); 18 | return string.Format("{0}:[{1}{2}]", prefix, Register, offsetStr); 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /KoiVM.Confuser/Obfuscation.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | 4 | [assembly: Obfuscation(Exclude = false, Feature = 5 | "name('KoiVM.Confuser.exe'):+anti debug(mode=antinet)" 6 | )] 7 | 8 | [assembly: Obfuscation(Exclude = false, Feature = 9 | "preset(aggressive);+constants(mode=dynamic,decoderCount=10,cfg=true);" + 10 | "+ctrl flow(predicate=expression,intensity=100);+rename(renPublic=false,mode=sequential);" + 11 | "+resources(mode=dynamic);+ref proxy(typeErasure=true,internal=true);" 12 | #if DEBUG 13 | + "-anti debug;-rename;" 14 | #endif 15 | )] 16 | 17 | [assembly: Obfuscation(Exclude = false, Feature = 18 | "module('KoiVM.Confuser.Internal.dll'):-ref proxy" 19 | )] -------------------------------------------------------------------------------- /KoiVM/AST/IL/ILMethodTarget.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using dnlib.DotNet; 3 | using KoiVM.RT; 4 | 5 | namespace KoiVM.AST.IL { 6 | public class ILMethodTarget : IILOperand, IHasOffset { 7 | ILBlock methodEntry; 8 | 9 | public ILMethodTarget(MethodDef target) { 10 | Target = target; 11 | } 12 | 13 | public MethodDef Target { get; set; } 14 | 15 | public void Resolve(VMRuntime runtime) { 16 | runtime.LookupMethod(Target, out methodEntry); 17 | } 18 | 19 | public uint Offset { 20 | get { return methodEntry == null ? 0 : methodEntry.Content[0].Offset; } 21 | } 22 | 23 | public override string ToString() { 24 | return Target.ToString(); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/Data/VCallMap.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using KoiVM.Runtime.VCalls; 4 | 5 | namespace KoiVM.Runtime.Data { 6 | internal static class VCallMap { 7 | static readonly Dictionary vCalls; 8 | 9 | static VCallMap() { 10 | vCalls = new Dictionary(); 11 | foreach (var type in typeof(VCallMap).Assembly.GetTypes()) { 12 | if (typeof(IVCall).IsAssignableFrom(type) && !type.IsAbstract) { 13 | var vCall = (IVCall)Activator.CreateInstance(type); 14 | vCalls[vCall.Code] = vCall; 15 | } 16 | } 17 | } 18 | 19 | public static IVCall Lookup(byte code) { 20 | return vCalls[code]; 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /KoiVM/VMIR/Compiler/IRCompilerAssemblyFinder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using dnlib.DotNet; 3 | 4 | namespace KoiVM.VMIR.Compiler { 5 | public class IRCompilerAssemblyFinder : IAssemblyRefFinder { 6 | readonly ModuleDef module; 7 | readonly AssemblyDef corlib; 8 | 9 | public IRCompilerAssemblyFinder(ModuleDef module) { 10 | this.module = module; 11 | corlib = module.Context.AssemblyResolver.Resolve(module.CorLibTypes.AssemblyRef, module); 12 | } 13 | 14 | public AssemblyRef FindAssemblyRef(TypeRef nonNestedTypeRef) { 15 | if (corlib.Find(nonNestedTypeRef) != null) { 16 | return module.CorLibTypes.AssemblyRef; 17 | } 18 | return AssemblyRef.CurrentAssembly; 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /KoiVM/VMIR/TranslationHelpers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using KoiVM.AST; 4 | using KoiVM.AST.IR; 5 | 6 | namespace KoiVM.VMIR { 7 | public static class TranslationHelpers { 8 | public static void EmitCompareEq(IRTranslator tr, ASTType type, IIROperand a, IIROperand b) { 9 | if (type == ASTType.O || type == ASTType.ByRef || 10 | type == ASTType.R4 || type == ASTType.R8) { 11 | tr.Instructions.Add(new IRInstruction(IROpCode.CMP, a, b)); 12 | } 13 | else { 14 | // I4/I8/Ptr 15 | Debug.Assert(type == ASTType.I4 || type == ASTType.I8 || type == ASTType.Ptr); 16 | tr.Instructions.Add(new IRInstruction(IROpCode.CMP, a, b)); 17 | } 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /KoiVM/VMIL/Transforms/EntryExitTransform.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.AST.IL; 3 | 4 | namespace KoiVM.VMIL.Transforms { 5 | public class EntryExitTransform : ITransform { 6 | public void Initialize(ILTransformer tr) { 7 | } 8 | 9 | public void Transform(ILTransformer tr) { 10 | tr.Instructions.VisitInstrs(VisitInstr, tr); 11 | } 12 | 13 | void VisitInstr(ILInstrList instrs, ILInstruction instr, ref int index, ILTransformer tr) { 14 | if (instr.OpCode == ILOpCode.__ENTRY) { 15 | instrs.RemoveAt(index); 16 | index--; 17 | } 18 | else if (instr.OpCode == ILOpCode.__EXIT) { 19 | instrs[index] = new ILInstruction(ILOpCode.RET, null, instr); 20 | } 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/Data/OpCodeMap.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using KoiVM.Runtime.OpCodes; 4 | 5 | namespace KoiVM.Runtime.Data { 6 | internal static class OpCodeMap { 7 | static readonly Dictionary opCodes; 8 | 9 | static OpCodeMap() { 10 | opCodes = new Dictionary(); 11 | foreach (var type in typeof(OpCodeMap).Assembly.GetTypes()) { 12 | if (typeof(IOpCode).IsAssignableFrom(type) && !type.IsAbstract) { 13 | var opCode = (IOpCode)Activator.CreateInstance(type); 14 | opCodes[opCode.Code] = opCode; 15 | } 16 | } 17 | } 18 | 19 | public static IOpCode Lookup(byte code) { 20 | return opCodes[code]; 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/VCalls/Sizeof.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.Runtime.Dynamic; 3 | using KoiVM.Runtime.Execution; 4 | using KoiVM.Runtime.Execution.Internal; 5 | 6 | namespace KoiVM.Runtime.VCalls { 7 | internal class Sizeof : IVCall { 8 | public byte Code { 9 | get { return Constants.VCALL_SIZEOF; } 10 | } 11 | 12 | public void Run(VMContext ctx, out ExecutionState state) { 13 | var sp = ctx.Registers[Constants.REG_SP].U4; 14 | var bp = ctx.Registers[Constants.REG_BP].U4; 15 | var type = (Type)ctx.Instance.Data.LookupReference(ctx.Stack[sp].U4); 16 | ctx.Stack[sp] = new VMSlot { 17 | U4 = (uint)SizeOfHelper.SizeOf(type) 18 | }; 19 | 20 | state = ExecutionState.Next; 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /KoiVM/AST/IL/ILRelReference.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.RT; 3 | 4 | namespace KoiVM.AST.IL { 5 | public class ILRelReference : IILOperand { 6 | public ILRelReference(IHasOffset target, IHasOffset relBase) { 7 | Target = target; 8 | Base = relBase; 9 | } 10 | 11 | public IHasOffset Target { get; set; } 12 | public IHasOffset Base { get; set; } 13 | 14 | public virtual uint Resolve(VMRuntime runtime) { 15 | var relBase = Base.Offset; 16 | if (Base is ILInstruction) 17 | relBase += runtime.serializer.ComputeLength((ILInstruction)Base); 18 | return Target.Offset - relBase; 19 | } 20 | 21 | public override string ToString() { 22 | return string.Format("[{0:x8}:{1:x8}]", Base.Offset, Target.Offset); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /KoiVM/VM/Descriptors/VMDescriptor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KoiVM.VM { 4 | public class VMDescriptor { 5 | public VMDescriptor(IVMSettings settings) { 6 | Random = new Random(settings.Seed); 7 | Settings = settings; 8 | Architecture = new ArchDescriptor(Random); 9 | Runtime = new RuntimeDescriptor(Random); 10 | Data = new DataDescriptor(Random); 11 | } 12 | 13 | public Random Random { get; private set; } 14 | public IVMSettings Settings { get; private set; } 15 | public ArchDescriptor Architecture { get; private set; } 16 | public RuntimeDescriptor Runtime { get; private set; } 17 | public DataDescriptor Data { get; private set; } 18 | 19 | public void ResetData() { 20 | Data = new DataDescriptor(Random); 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /KoiVM/RT/KoiHeap.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using dnlib.DotNet.Writer; 5 | 6 | namespace KoiVM.RT { 7 | internal class KoiHeap : HeapBase { 8 | List chunks = new List(); 9 | uint currentLen; 10 | 11 | public uint AddChunk(byte[] chunk) { 12 | uint offset = currentLen; 13 | chunks.Add(chunk); 14 | currentLen += (uint)chunk.Length; 15 | return offset; 16 | } 17 | 18 | public override string Name { 19 | get { return "#Koi"; } 20 | } 21 | 22 | public override uint GetRawLength() { 23 | return currentLen; 24 | } 25 | 26 | protected override void WriteToImpl(BinaryWriter writer) { 27 | foreach (var chunk in chunks) 28 | writer.Write(chunk); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /KoiVM.Confuser/Internal/FinalizePhase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using Confuser.Core; 4 | 5 | namespace KoiVM.Confuser.Internal { 6 | [Obfuscation(Exclude = false, Feature = "+koi;")] 7 | public class FinalizePhase : ProtectionPhase { 8 | public FinalizePhase(Protection parent) 9 | : base(parent) { 10 | } 11 | 12 | public override ProtectionTargets Targets { 13 | get { return ProtectionTargets.Modules; } 14 | } 15 | 16 | public override string Name { 17 | get { return "Finalize virtualization data"; } 18 | } 19 | 20 | protected override void Execute(ConfuserContext context, ProtectionParameters parameters) { 21 | //var vr = context.Annotations.Get(context, Fish.VirtualizerKey); 22 | //vr.CommitRuntime(); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /KoiVM/VMIL/Translation/InvocationHandlers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.AST.IL; 3 | using KoiVM.AST.IR; 4 | using KoiVM.VMIR; 5 | 6 | namespace KoiVM.VMIL.Translation { 7 | public class CallHandler : ITranslationHandler { 8 | public IROpCode IRCode { 9 | get { return IROpCode.CALL; } 10 | } 11 | 12 | public void Translate(IRInstruction instr, ILTranslator tr) { 13 | tr.PushOperand(instr.Operand1); 14 | tr.Instructions.Add(new ILInstruction(ILOpCode.CALL) { Annotation = instr.Annotation }); 15 | } 16 | } 17 | 18 | public class RetHandler : ITranslationHandler { 19 | public IROpCode IRCode { 20 | get { return IROpCode.RET; } 21 | } 22 | 23 | public void Translate(IRInstruction instr, ILTranslator tr) { 24 | tr.Instructions.Add(new ILInstruction(ILOpCode.RET)); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/OpCodes/Pop.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.Runtime.Dynamic; 3 | using KoiVM.Runtime.Execution; 4 | 5 | namespace KoiVM.Runtime.OpCodes { 6 | internal class Pop : IOpCode { 7 | public byte Code { 8 | get { return Constants.OP_POP; } 9 | } 10 | 11 | public void Run(VMContext ctx, out ExecutionState state) { 12 | var sp = ctx.Registers[Constants.REG_SP].U4; 13 | var slot = ctx.Stack[sp]; 14 | ctx.Stack.SetTopPosition(--sp); 15 | ctx.Registers[Constants.REG_SP].U4 = sp; 16 | 17 | var regId = ctx.ReadByte(); 18 | if ((regId == Constants.REG_SP || regId == Constants.REG_BP) && slot.O is StackRef) 19 | ctx.Registers[regId] = new VMSlot { U4 = ((StackRef)slot.O).StackPos }; 20 | else 21 | ctx.Registers[regId] = slot; 22 | state = ExecutionState.Next; 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/VCalls/Rangechk.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.Runtime.Dynamic; 3 | using KoiVM.Runtime.Execution; 4 | 5 | namespace KoiVM.Runtime.VCalls { 6 | internal class Rangechk : IVCall { 7 | public byte Code { 8 | get { return Constants.VCALL_RANGECHK; } 9 | } 10 | 11 | public unsafe void Run(VMContext ctx, out ExecutionState state) { 12 | var sp = ctx.Registers[Constants.REG_SP].U4; 13 | var valueSlot = ctx.Stack[sp--]; 14 | var maxSlot = ctx.Stack[sp--]; 15 | var minSlot = ctx.Stack[sp]; 16 | 17 | valueSlot.U8 = ((long)valueSlot.U8 > (long)maxSlot.U8 || (long)valueSlot.U8 < (long)minSlot.U8) ? 1u : 0; 18 | 19 | ctx.Stack[sp] = valueSlot; 20 | 21 | ctx.Stack.SetTopPosition(sp); 22 | ctx.Registers[Constants.REG_SP].U4 = sp; 23 | state = ExecutionState.Next; 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /KoiVM/VM/Descriptors/RTFlagDescriptor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | 4 | namespace KoiVM.VM { 5 | public class RTFlagDescriptor { 6 | byte[] flagOrder = Enumerable.Range(1, 7).Select(x => (byte)x).ToArray(); 7 | byte[] ehOrder = Enumerable.Range(0, 4).Select(x => (byte)x).ToArray(); 8 | 9 | public RTFlagDescriptor(Random random) { 10 | random.Shuffle(flagOrder); 11 | random.Shuffle(ehOrder); 12 | } 13 | 14 | public byte INSTANCE { 15 | get { return flagOrder[0]; } 16 | } 17 | 18 | public byte EH_CATCH { 19 | get { return ehOrder[0]; } 20 | } 21 | 22 | public byte EH_FILTER { 23 | get { return ehOrder[1]; } 24 | } 25 | 26 | public byte EH_FAULT { 27 | get { return ehOrder[2]; } 28 | } 29 | 30 | public byte EH_FINALLY { 31 | get { return ehOrder[3]; } 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /KoiVM/VMIL/Transforms/SaveInfoTransform.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.AST.IL; 3 | using KoiVM.VM; 4 | 5 | namespace KoiVM.VMIL.Transforms { 6 | public class SaveInfoTransform : ITransform { 7 | VMMethodInfo methodInfo; 8 | 9 | public void Initialize(ILTransformer tr) { 10 | methodInfo = tr.VM.Data.LookupInfo(tr.Method); 11 | methodInfo.RootScope = tr.RootScope; 12 | tr.VM.Data.SetInfo(tr.Method, methodInfo); 13 | } 14 | 15 | public void Transform(ILTransformer tr) { 16 | tr.Instructions.VisitInstrs(VisitInstr, tr); 17 | } 18 | 19 | void VisitInstr(ILInstrList instrs, ILInstruction instr, ref int index, ILTransformer tr) { 20 | if (instr.Operand is ILRegister) { 21 | var reg = ((ILRegister)instr.Operand).Register; 22 | if (reg.IsGPR()) 23 | methodInfo.UsedRegister.Add(reg); 24 | } 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /KoiVM/VMIL/Translation/MiscHandlers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.AST.IL; 3 | using KoiVM.AST.IR; 4 | using KoiVM.VMIR; 5 | 6 | namespace KoiVM.VMIL.Translation { 7 | public class VcallHandler : ITranslationHandler { 8 | public IROpCode IRCode { 9 | get { return IROpCode.VCALL; } 10 | } 11 | 12 | public void Translate(IRInstruction instr, ILTranslator tr) { 13 | if (instr.Operand2 != null) 14 | tr.PushOperand(instr.Operand2); 15 | tr.PushOperand(instr.Operand1); 16 | tr.Instructions.Add(new ILInstruction(ILOpCode.VCALL)); 17 | } 18 | } 19 | 20 | public class NopHandler : ITranslationHandler { 21 | public IROpCode IRCode { 22 | get { return IROpCode.NOP; } 23 | } 24 | 25 | public void Translate(IRInstruction instr, ILTranslator tr) { 26 | tr.Instructions.Add(new ILInstruction(ILOpCode.NOP)); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /KoiVM/VMIR/Transforms/LeaTransform.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using KoiVM.AST.IR; 4 | 5 | namespace KoiVM.VMIR.Transforms { 6 | public class LeaTransform : ITransform { 7 | public void Initialize(IRTransformer tr) { 8 | } 9 | 10 | public void Transform(IRTransformer tr) { 11 | tr.Instructions.VisitInstrs(VisitInstr, tr); 12 | } 13 | 14 | void VisitInstr(IRInstrList instrs, IRInstruction instr, ref int index, IRTransformer tr) { 15 | if (instr.OpCode == IROpCode.__LEA) { 16 | var source = (IRPointer)instr.Operand2; 17 | var target = instr.Operand1; 18 | Debug.Assert(source.Register == IRRegister.BP); 19 | instrs.Replace(index, new[] { 20 | new IRInstruction(IROpCode.MOV, target, IRRegister.BP, instr), 21 | new IRInstruction(IROpCode.ADD, target, IRConstant.FromI4(source.Offset), instr) 22 | }); 23 | } 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/Execution/VMContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using KoiVM.Runtime.Dynamic; 4 | 5 | namespace KoiVM.Runtime.Execution { 6 | internal class VMContext { 7 | const int NumRegisters = 16; 8 | 9 | public readonly VMSlot[] Registers = new VMSlot[16]; 10 | public readonly VMStack Stack = new VMStack(); 11 | public readonly VMInstance Instance; 12 | public readonly List EHStack = new List(); 13 | public readonly List EHStates = new List(); 14 | 15 | public VMContext(VMInstance inst) { 16 | Instance = inst; 17 | } 18 | 19 | public unsafe byte ReadByte() { 20 | var key = Registers[Constants.REG_K1].U4; 21 | var ip = (byte*)Registers[Constants.REG_IP].U8++; 22 | byte b = (byte)(*ip ^ key); 23 | key = key * 7 + b; 24 | Registers[Constants.REG_K1].U4 = key; 25 | return b; 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /KoiVM/VMIL/Transforms/FixMethodRefTransform.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using KoiVM.AST.IL; 4 | using KoiVM.VM; 5 | 6 | namespace KoiVM.VMIL.Transforms { 7 | public class FixMethodRefTransform : IPostTransform { 8 | HashSet saveRegs; 9 | 10 | public void Initialize(ILPostTransformer tr) { 11 | saveRegs = tr.Runtime.Descriptor.Data.LookupInfo(tr.Method).UsedRegister; 12 | } 13 | 14 | public void Transform(ILPostTransformer tr) { 15 | tr.Instructions.VisitInstrs(VisitInstr, tr); 16 | } 17 | 18 | void VisitInstr(ILInstrList instrs, ILInstruction instr, ref int index, ILPostTransformer tr) { 19 | var rel = instr.Operand as ILRelReference; 20 | if (rel == null) 21 | return; 22 | 23 | var methodRef = rel.Target as ILMethodTarget; 24 | if (methodRef == null) 25 | return; 26 | 27 | methodRef.Resolve(tr.Runtime); 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/Execution/Internal/Unverifier.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using System.Reflection.Emit; 4 | using System.Security.Permissions; 5 | 6 | namespace KoiVM.Runtime.Execution.Internal { 7 | internal static class Unverifier { 8 | public static readonly Module Module; 9 | 10 | static Unverifier() { 11 | var asm = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("Fish"), AssemblyBuilderAccess.Run); 12 | var mod = asm.DefineDynamicModule("Fish"); 13 | CustomAttributeBuilder att = 14 | new CustomAttributeBuilder(typeof(SecurityPermissionAttribute).GetConstructor(new[] { typeof(SecurityAction) }), 15 | new object[] { SecurityAction.Assert }, 16 | new[] { typeof(SecurityPermissionAttribute).GetProperty("SkipVerification") }, 17 | new object[] { true }); 18 | mod.SetCustomAttribute(att); 19 | Module = mod.DefineType(" ").CreateType().Module; 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /KoiVM/RT/BinaryChunk.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KoiVM.RT { 4 | public class BinaryChunk : IKoiChunk { 5 | public BinaryChunk(byte[] data) { 6 | Data = data; 7 | } 8 | 9 | public byte[] Data { get; private set; } 10 | public uint Offset { get; private set; } 11 | 12 | public EventHandler OffsetComputed; 13 | 14 | uint IKoiChunk.Length { 15 | get { return (uint)Data.Length; } 16 | } 17 | 18 | void IKoiChunk.OnOffsetComputed(uint offset) { 19 | if (OffsetComputed != null) 20 | OffsetComputed(this, new OffsetComputeEventArgs(offset)); 21 | Offset = offset; 22 | } 23 | 24 | byte[] IKoiChunk.GetData() { 25 | return Data; 26 | } 27 | } 28 | 29 | public class OffsetComputeEventArgs : EventArgs { 30 | internal OffsetComputeEventArgs(uint offset) { 31 | Offset = offset; 32 | } 33 | 34 | public uint Offset { get; private set; } 35 | } 36 | } -------------------------------------------------------------------------------- /KoiVM/VMIR/RegAlloc/BlockLiveness.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using KoiVM.AST.IR; 4 | 5 | namespace KoiVM.VMIR.RegAlloc { 6 | public class BlockLiveness { 7 | BlockLiveness(HashSet inLive, HashSet outLive) { 8 | InLive = inLive; 9 | OutLive = outLive; 10 | } 11 | 12 | public HashSet InLive { get; private set; } 13 | public HashSet OutLive { get; private set; } 14 | 15 | internal static BlockLiveness Empty() { 16 | return new BlockLiveness(new HashSet(), new HashSet()); 17 | } 18 | 19 | internal BlockLiveness Clone() { 20 | return new BlockLiveness(new HashSet(InLive), new HashSet(OutLive)); 21 | } 22 | 23 | public override string ToString() { 24 | return string.Format("In=[{0}], Out=[{1}]", string.Join(", ", InLive), string.Join(", ", OutLive)); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /KoiVM/VMIR/Transforms/GetSetFlagTransform.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.AST.IR; 3 | 4 | namespace KoiVM.VMIR.Transforms { 5 | public class GetSetFlagTransform : ITransform { 6 | public void Initialize(IRTransformer tr) { 7 | } 8 | 9 | public void Transform(IRTransformer tr) { 10 | tr.Instructions.VisitInstrs(VisitInstr, tr); 11 | } 12 | 13 | void VisitInstr(IRInstrList instrs, IRInstruction instr, ref int index, IRTransformer tr) { 14 | if (instr.OpCode == IROpCode.__GETF) { 15 | instrs.Replace(index, new[] { 16 | new IRInstruction(IROpCode.MOV, instr.Operand1, IRRegister.FL, instr), 17 | new IRInstruction(IROpCode.__AND, instr.Operand1, instr.Operand2, instr) 18 | }); 19 | } 20 | else if (instr.OpCode == IROpCode.__SETF) { 21 | instrs.Replace(index, new[] { 22 | new IRInstruction(IROpCode.__OR, IRRegister.FL, instr.Operand1, instr) 23 | }); 24 | } 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /KoiVM/VMIL/Transforms/ReferenceOffsetTransform.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.AST.IL; 3 | 4 | namespace KoiVM.VMIL.Transforms { 5 | public class ReferenceOffsetTransform : ITransform { 6 | public void Initialize(ILTransformer tr) { 7 | } 8 | 9 | public void Transform(ILTransformer tr) { 10 | tr.Instructions.VisitInstrs(VisitInstr, tr); 11 | } 12 | 13 | void VisitInstr(ILInstrList instrs, ILInstruction instr, ref int index, ILTransformer tr) { 14 | if (instr.OpCode == ILOpCode.PUSHI_DWORD && instr.Operand is IHasOffset) { 15 | var relBase = new ILInstruction(ILOpCode.PUSHR_QWORD, ILRegister.IP, instr); 16 | instr.OpCode = ILOpCode.PUSHI_DWORD; 17 | instr.Operand = new ILRelReference((IHasOffset)instr.Operand, relBase); 18 | 19 | instrs.Replace(index, new[] { 20 | relBase, 21 | instr, 22 | new ILInstruction(ILOpCode.ADD_QWORD, null, instr) 23 | }); 24 | } 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /KoiVM/ILAST/Transformation/StringTransform.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using dnlib.DotNet; 3 | using dnlib.DotNet.Emit; 4 | using KoiVM.AST.ILAST; 5 | 6 | namespace KoiVM.ILAST.Transformation { 7 | public class StringTransform : ITransformationHandler { 8 | public void Initialize(ILASTTransformer tr) { 9 | } 10 | 11 | public void Transform(ILASTTransformer tr) { 12 | tr.Tree.TraverseTree(Transform, tr); 13 | } 14 | 15 | static void Transform(ILASTExpression expr, ILASTTransformer tr) { 16 | if (expr.ILCode != Code.Ldstr) 17 | return; 18 | 19 | var operand = (string)expr.Operand; 20 | expr.ILCode = Code.Box; 21 | expr.Operand = tr.Method.Module.CorLibTypes.String.ToTypeDefOrRef(); 22 | expr.Arguments = new IILASTNode[] { 23 | new ILASTExpression { 24 | ILCode = Code.Ldc_I4, 25 | Operand = (int)tr.VM.Data.GetId(operand), 26 | Arguments = new IILASTNode[0] 27 | } 28 | }; 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/Execution/Internal/SizeOfHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Reflection.Emit; 4 | 5 | namespace KoiVM.Runtime.Execution.Internal { 6 | internal class SizeOfHelper { 7 | static Hashtable sizes = new Hashtable(); 8 | 9 | public static int SizeOf(Type type) { 10 | var size = sizes[type]; 11 | if (size == null) { 12 | lock (sizes) { 13 | size = sizes[type]; 14 | if (size == null) { 15 | size = GetSize(type); 16 | sizes[type] = size; 17 | } 18 | } 19 | } 20 | return (int)size; 21 | } 22 | 23 | static int GetSize(Type type) { 24 | var dm = new DynamicMethod("", typeof(int), Type.EmptyTypes, Unverifier.Module, true); 25 | var gen = dm.GetILGenerator(); 26 | 27 | gen.Emit(System.Reflection.Emit.OpCodes.Sizeof, type); 28 | gen.Emit(System.Reflection.Emit.OpCodes.Ret); 29 | 30 | return (int)dm.Invoke(null, null); 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/Execution/PointerRef.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.Runtime.Execution.Internal; 3 | 4 | namespace KoiVM.Runtime.Execution { 5 | internal unsafe class PointerRef : IReference { 6 | // Only for typed reference use 7 | 8 | void* ptr; 9 | 10 | public PointerRef(void* ptr) { 11 | this.ptr = ptr; 12 | } 13 | 14 | public VMSlot GetValue(VMContext ctx, PointerType type) { 15 | throw new NotSupportedException(); 16 | } 17 | 18 | public void SetValue(VMContext ctx, VMSlot slot, PointerType type) { 19 | throw new NotSupportedException(); 20 | } 21 | 22 | public IReference Add(uint value) { 23 | throw new NotSupportedException(); 24 | } 25 | 26 | public IReference Add(ulong value) { 27 | throw new NotSupportedException(); 28 | } 29 | 30 | public void ToTypedReference(VMContext ctx, TypedRefPtr typedRef, Type type) { 31 | TypedReferenceHelpers.MakeTypedRef(ptr, typedRef, type); 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /KoiVM/VMIL/Translation/EHHandlers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.AST.IL; 3 | using KoiVM.AST.IR; 4 | using KoiVM.VMIR; 5 | 6 | namespace KoiVM.VMIL.Translation { 7 | public class TryHandler : ITranslationHandler { 8 | public IROpCode IRCode { 9 | get { return IROpCode.TRY; } 10 | } 11 | 12 | public void Translate(IRInstruction instr, ILTranslator tr) { 13 | if (instr.Operand2 != null) 14 | tr.PushOperand(instr.Operand2); 15 | tr.PushOperand(instr.Operand1); 16 | tr.Instructions.Add(new ILInstruction(ILOpCode.TRY) { Annotation = instr.Annotation }); 17 | } 18 | } 19 | 20 | public class LeaveHandler : ITranslationHandler { 21 | public IROpCode IRCode { 22 | get { return IROpCode.LEAVE; } 23 | } 24 | 25 | public void Translate(IRInstruction instr, ILTranslator tr) { 26 | tr.PushOperand(instr.Operand1); 27 | tr.Instructions.Add(new ILInstruction(ILOpCode.LEAVE) { Annotation = instr.Annotation }); 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /KoiVM/VMIL/Translation/MemoryHandlers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.AST.IR; 3 | using KoiVM.VMIR; 4 | 5 | namespace KoiVM.VMIL.Translation { 6 | public class PushHandler : ITranslationHandler { 7 | public IROpCode IRCode { 8 | get { return IROpCode.PUSH; } 9 | } 10 | 11 | public void Translate(IRInstruction instr, ILTranslator tr) { 12 | tr.PushOperand(instr.Operand1); 13 | } 14 | } 15 | 16 | public class PopHandler : ITranslationHandler { 17 | public IROpCode IRCode { 18 | get { return IROpCode.POP; } 19 | } 20 | 21 | public void Translate(IRInstruction instr, ILTranslator tr) { 22 | tr.PopOperand(instr.Operand1); 23 | } 24 | } 25 | 26 | public class MovHandler : ITranslationHandler { 27 | public IROpCode IRCode { 28 | get { return IROpCode.MOV; } 29 | } 30 | 31 | public void Translate(IRInstruction instr, ILTranslator tr) { 32 | tr.PushOperand(instr.Operand2); 33 | tr.PopOperand(instr.Operand1); 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/VCalls/Ckfinite.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.Runtime.Dynamic; 3 | using KoiVM.Runtime.Execution; 4 | 5 | namespace KoiVM.Runtime.VCalls { 6 | internal class Ckfinite : IVCall { 7 | public byte Code { 8 | get { return Constants.VCALL_CKFINITE; } 9 | } 10 | 11 | public unsafe void Run(VMContext ctx, out ExecutionState state) { 12 | var sp = ctx.Registers[Constants.REG_SP].U4; 13 | var valueSlot = ctx.Stack[sp--]; 14 | 15 | var fl = ctx.Registers[Constants.REG_FL].U1; 16 | if ((fl & Constants.FL_UNSIGNED) != 0) { 17 | float v = valueSlot.R4; 18 | if (float.IsNaN(v) || float.IsInfinity(v)) 19 | throw new ArithmeticException(); 20 | } 21 | else { 22 | double v = valueSlot.R8; 23 | if (double.IsNaN(v) || double.IsInfinity(v)) 24 | throw new ArithmeticException(); 25 | } 26 | 27 | ctx.Stack.SetTopPosition(sp); 28 | ctx.Registers[Constants.REG_SP].U4 = sp; 29 | state = ExecutionState.Next; 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/VMEntry.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KoiVM.Runtime { 4 | public class VMEntry { 5 | public static object Run(RuntimeTypeHandle type, uint id, object[] args) { 6 | var module = Type.GetTypeFromHandle(type).Module; 7 | return VMInstance.Instance(module).Run(id, args); 8 | } 9 | 10 | public static unsafe void Run(RuntimeTypeHandle type, uint id, void*[] typedRefs, void* retTypedRef) { 11 | var module = Type.GetTypeFromHandle(type).Module; 12 | VMInstance.Instance(module).Run(id, typedRefs, retTypedRef); 13 | } 14 | 15 | internal static object RunInternal(int moduleId, ulong codeAddr, uint key, uint sigId, object[] args) { 16 | return VMInstance.Instance(moduleId).Run(codeAddr, key, sigId, args); 17 | } 18 | 19 | internal static unsafe void RunInternal(int moduleId, ulong codeAddr, uint key, uint sigId, void*[] typedRefs, 20 | void* retTypedRef) { 21 | VMInstance.Instance(moduleId).Run(codeAddr, key, sigId, typedRefs, retTypedRef); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /KoiVM/VMIR/Transforms/MarkReturnRegTransform.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.AST; 3 | using KoiVM.AST.IR; 4 | 5 | namespace KoiVM.VMIR.Transforms { 6 | public class MarkReturnRegTransform : ITransform { 7 | public void Initialize(IRTransformer tr) { 8 | } 9 | 10 | public void Transform(IRTransformer tr) { 11 | tr.Instructions.VisitInstrs(VisitInstr, tr); 12 | } 13 | 14 | void VisitInstr(IRInstrList instrs, IRInstruction instr, ref int index, IRTransformer tr) { 15 | var callInfo = instr.Annotation as InstrCallInfo; 16 | if (callInfo == null || callInfo.ReturnValue == null) 17 | return; 18 | 19 | if (instr.Operand1 is IRRegister && ((IRRegister)instr.Operand1).SourceVariable == callInfo.ReturnValue) { 20 | callInfo.ReturnRegister = (IRRegister)instr.Operand1; 21 | } 22 | else if (instr.Operand1 is IRPointer && ((IRPointer)instr.Operand1).SourceVariable == callInfo.ReturnValue) { 23 | callInfo.ReturnSlot = (IRPointer)instr.Operand1; 24 | } 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/VCalls/Box.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using KoiVM.Runtime.Dynamic; 4 | using KoiVM.Runtime.Execution; 5 | 6 | namespace KoiVM.Runtime.VCalls { 7 | internal class Box : IVCall { 8 | public byte Code { 9 | get { return Constants.VCALL_BOX; } 10 | } 11 | 12 | public void Run(VMContext ctx, out ExecutionState state) { 13 | var sp = ctx.Registers[Constants.REG_SP].U4; 14 | var typeSlot = ctx.Stack[sp--]; 15 | var valSlot = ctx.Stack[sp]; 16 | 17 | var valType = (Type)ctx.Instance.Data.LookupReference(typeSlot.U4); 18 | if (Type.GetTypeCode(valType) == TypeCode.String && valSlot.O == null) 19 | valSlot.O = ctx.Instance.Data.LookupString(valSlot.U4); 20 | else { 21 | Debug.Assert(valType.IsValueType); 22 | valSlot.O = valSlot.ToObject(valType); 23 | } 24 | ctx.Stack[sp] = valSlot; 25 | 26 | ctx.Stack.SetTopPosition(sp); 27 | ctx.Registers[Constants.REG_SP].U4 = sp; 28 | state = ExecutionState.Next; 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /KoiVM/VMIR/Transforms/MetadataTransform.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using dnlib.DotNet; 3 | using KoiVM.AST.IR; 4 | 5 | namespace KoiVM.VMIR.Transforms { 6 | public class MetadataTransform : ITransform { 7 | public void Initialize(IRTransformer tr) { 8 | } 9 | 10 | public void Transform(IRTransformer tr) { 11 | tr.Instructions.VisitInstrs(VisitInstr, tr); 12 | } 13 | 14 | void VisitInstr(IRInstrList instrs, IRInstruction instr, ref int index, IRTransformer tr) { 15 | instr.Operand1 = TransformMD(instr.Operand1, tr); 16 | instr.Operand2 = TransformMD(instr.Operand2, tr); 17 | } 18 | 19 | IIROperand TransformMD(IIROperand operand, IRTransformer tr) { 20 | if (operand is IRMetaTarget) { 21 | var target = (IRMetaTarget)operand; 22 | if (!target.LateResolve) { 23 | if (!(target.MetadataItem is IMemberRef)) 24 | throw new NotSupportedException(); 25 | return IRConstant.FromI4((int)tr.VM.Data.GetId((IMemberRef)target.MetadataItem)); 26 | } 27 | } 28 | return operand; 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /KoiVM/VM/Descriptors/FlagDescriptor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | 4 | namespace KoiVM.VM { 5 | public class FlagDescriptor { 6 | int[] flagOrder = Enumerable.Range(0, (int)VMFlags.Max).ToArray(); 7 | 8 | public FlagDescriptor(Random random) { 9 | random.Shuffle(flagOrder); 10 | } 11 | 12 | public int this[VMFlags flag] { 13 | get { return flagOrder[(int)flag]; } 14 | } 15 | 16 | public int OVERFLOW { 17 | get { return flagOrder[0]; } 18 | } 19 | 20 | public int CARRY { 21 | get { return flagOrder[1]; } 22 | } 23 | 24 | public int ZERO { 25 | get { return flagOrder[2]; } 26 | } 27 | 28 | public int SIGN { 29 | get { return flagOrder[3]; } 30 | } 31 | 32 | public int UNSIGNED { 33 | get { return flagOrder[4]; } 34 | } 35 | 36 | public int BEHAV1 { 37 | get { return flagOrder[5]; } 38 | } 39 | 40 | public int BEHAV2 { 41 | get { return flagOrder[6]; } 42 | } 43 | 44 | public int BEHAV3 { 45 | get { return flagOrder[7]; } 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/OpCodes/Leave.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.Runtime.Dynamic; 3 | using KoiVM.Runtime.Execution; 4 | 5 | namespace KoiVM.Runtime.OpCodes { 6 | internal class Leave : IOpCode { 7 | public byte Code { 8 | get { return Constants.OP_LEAVE; } 9 | } 10 | 11 | public void Run(VMContext ctx, out ExecutionState state) { 12 | var sp = ctx.Registers[Constants.REG_SP].U4; 13 | var handler = ctx.Stack[sp--].U8; 14 | 15 | var frameIndex = ctx.EHStack.Count - 1; 16 | var frame = ctx.EHStack[frameIndex]; 17 | 18 | if (frame.HandlerAddr != handler) 19 | throw new InvalidProgramException(); 20 | ctx.EHStack.RemoveAt(frameIndex); 21 | 22 | if (frame.EHType == Constants.EH_FINALLY) { 23 | ctx.Stack[++sp] = ctx.Registers[Constants.REG_IP]; 24 | ctx.Registers[Constants.REG_K1].U1 = 0; 25 | ctx.Registers[Constants.REG_IP].U8 = frame.HandlerAddr; 26 | } 27 | 28 | ctx.Stack.SetTopPosition(sp); 29 | ctx.Registers[Constants.REG_SP].U4 = sp; 30 | 31 | state = ExecutionState.Next; 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /KoiVM/VMIR/IROpCode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | 4 | namespace KoiVM.VMIR { 5 | [Obfuscation(Exclude = false, ApplyToMembers = false, Feature = "+rename(forceRen=true);")] 6 | public enum IROpCode { 7 | NOP, 8 | 9 | MOV, 10 | POP, 11 | PUSH, 12 | CALL, 13 | RET, 14 | 15 | NOR, 16 | 17 | CMP, 18 | JZ, 19 | JNZ, 20 | JMP, 21 | SWT, 22 | 23 | ADD, 24 | SUB, // Only for floats 25 | MUL, 26 | DIV, 27 | REM, 28 | SHR, 29 | SHL, 30 | 31 | FCONV, 32 | ICONV, 33 | SX, 34 | 35 | VCALL, 36 | 37 | TRY, 38 | LEAVE, 39 | 40 | Max, 41 | 42 | // Pseudo-Opcodes, will be eliminate by transforms 43 | __NOT, 44 | __AND, 45 | __OR, 46 | __XOR, 47 | 48 | __GETF, 49 | __SETF, 50 | 51 | __CALL, 52 | __CALLVIRT, 53 | __NEWOBJ, 54 | __BEGINCALL, 55 | __ENDCALL, 56 | 57 | __ENTRY, 58 | __EXIT, 59 | 60 | __LEAVE, 61 | __EHRET, 62 | 63 | __LDOBJ, 64 | __STOBJ, 65 | 66 | __GEN, 67 | __KILL, 68 | 69 | __LEA 70 | } 71 | } -------------------------------------------------------------------------------- /KoiVM/VM/FuncSig.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using dnlib.DotNet; 3 | 4 | namespace KoiVM.VM { 5 | public class FuncSig { 6 | public byte Flags; 7 | public ITypeDefOrRef[] ParamSigs; 8 | public ITypeDefOrRef RetType; 9 | 10 | public override int GetHashCode() { 11 | var comparer = new SigComparer(); 12 | int hashCode = Flags; 13 | foreach (var param in ParamSigs) 14 | hashCode = (hashCode * 7) + comparer.GetHashCode(param); 15 | return (hashCode * 7) + comparer.GetHashCode(RetType); 16 | } 17 | 18 | public override bool Equals(object obj) { 19 | var other = obj as FuncSig; 20 | if (other == null || other.Flags != Flags) 21 | return false; 22 | 23 | if (other.ParamSigs.Length != ParamSigs.Length) 24 | return false; 25 | var comparer = new SigComparer(); 26 | for (int i = 0; i < ParamSigs.Length; i++) { 27 | if (!comparer.Equals(ParamSigs[i], other.ParamSigs[i])) 28 | return false; 29 | } 30 | if (!comparer.Equals(RetType, other.RetType)) 31 | return false; 32 | return true; 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/OpCodes/Try.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.Runtime.Dynamic; 3 | using KoiVM.Runtime.Execution; 4 | 5 | namespace KoiVM.Runtime.OpCodes { 6 | internal class Try : IOpCode { 7 | public byte Code { 8 | get { return Constants.OP_TRY; } 9 | } 10 | 11 | public void Run(VMContext ctx, out ExecutionState state) { 12 | var sp = ctx.Registers[Constants.REG_SP].U4; 13 | var type = ctx.Stack[sp--].U1; 14 | 15 | var frame = new EHFrame(); 16 | frame.EHType = type; 17 | if (type == Constants.EH_CATCH) { 18 | frame.CatchType = (Type)ctx.Instance.Data.LookupReference(ctx.Stack[sp--].U4); 19 | } 20 | else if (type == Constants.EH_FILTER) { 21 | frame.FilterAddr = ctx.Stack[sp--].U8; 22 | } 23 | frame.HandlerAddr = ctx.Stack[sp--].U8; 24 | 25 | ctx.Stack.SetTopPosition(sp); 26 | ctx.Registers[Constants.REG_SP].U4 = sp; 27 | 28 | frame.BP = ctx.Registers[Constants.REG_BP]; 29 | frame.SP = ctx.Registers[Constants.REG_SP]; 30 | ctx.EHStack.Add(frame); 31 | 32 | state = ExecutionState.Next; 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/VCalls/Token.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using KoiVM.Runtime.Dynamic; 4 | using KoiVM.Runtime.Execution; 5 | using KoiVM.Runtime.Execution.Internal; 6 | 7 | namespace KoiVM.Runtime.VCalls { 8 | internal class Token : IVCall { 9 | public byte Code { 10 | get { return Constants.VCALL_TOKEN; } 11 | } 12 | 13 | public void Run(VMContext ctx, out ExecutionState state) { 14 | var sp = ctx.Registers[Constants.REG_SP].U4; 15 | var typeSlot = ctx.Stack[sp]; 16 | 17 | var reference = ctx.Instance.Data.LookupReference(typeSlot.U4); 18 | if (reference is Type) 19 | typeSlot.O = ValueTypeBox.Box(((Type)reference).TypeHandle, typeof(RuntimeTypeHandle)); 20 | else if (reference is MethodBase) 21 | typeSlot.O = ValueTypeBox.Box(((MethodBase)reference).MethodHandle, typeof(RuntimeMethodHandle)); 22 | else if (reference is FieldInfo) 23 | typeSlot.O = ValueTypeBox.Box(((FieldInfo)reference).FieldHandle, typeof(RuntimeFieldHandle)); 24 | ctx.Stack[sp] = typeSlot; 25 | 26 | state = ExecutionState.Next; 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /libs/UpdateVersion.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Release 5 | AnyCPU 6 | {1e74b523-aa86-42a0-8116-fff7cebfcba7} 7 | Exe 8 | UpdateVersion 9 | UpdateVersion 10 | v2.0 11 | 12 | 13 | false 14 | None 15 | true 16 | .\ 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /KoiVM.Runtime/VCalls/Cast.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.Runtime.Dynamic; 3 | using KoiVM.Runtime.Execution; 4 | 5 | namespace KoiVM.Runtime.VCalls { 6 | internal class Cast : IVCall { 7 | public byte Code { 8 | get { return Constants.VCALL_CAST; } 9 | } 10 | 11 | public void Run(VMContext ctx, out ExecutionState state) { 12 | var sp = ctx.Registers[Constants.REG_SP].U4; 13 | var typeSlot = ctx.Stack[sp--]; 14 | var valSlot = ctx.Stack[sp]; 15 | 16 | bool castclass = (typeSlot.U4 & 0x80000000) != 0; 17 | var castType = (Type)ctx.Instance.Data.LookupReference(typeSlot.U4 & ~0x80000000); 18 | if (Type.GetTypeCode(castType) == TypeCode.String && valSlot.O == null) 19 | valSlot.O = ctx.Instance.Data.LookupString(valSlot.U4); 20 | else if (valSlot.O == null) 21 | valSlot.O = null; 22 | else if (!castType.IsInstanceOfType(valSlot.O)) { 23 | valSlot.O = null; 24 | if (castclass) 25 | throw new InvalidCastException(); 26 | } 27 | ctx.Stack[sp] = valSlot; 28 | 29 | ctx.Stack.SetTopPosition(sp); 30 | ctx.Registers[Constants.REG_SP].U4 = sp; 31 | state = ExecutionState.Next; 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /KoiVM.Confuser/KoiSettings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KoiVM.Confuser { 4 | internal class KoiSettings : SimpleSettings { 5 | public bool NoUI { 6 | get { 7 | bool value; 8 | if (bool.TryParse(GetValue("noUI", "false"), out value)) 9 | return value; 10 | SetValue("noUI", "false"); 11 | return false; 12 | } 13 | set { SetValue("noUI", value.ToString().ToLowerInvariant()); } 14 | } 15 | 16 | public bool NoCheck { 17 | get { 18 | bool value; 19 | if (bool.TryParse(GetValue("noCheck", "false"), out value)) 20 | return value; 21 | SetValue("noCheck", "false"); 22 | return false; 23 | } 24 | set { SetValue("noCheck", value.ToString().ToLowerInvariant()); } 25 | } 26 | 27 | public string Version { 28 | get { 29 | string value = GetValue("ver", ""); 30 | return string.IsNullOrEmpty(value) ? null : value; 31 | } 32 | set { SetValue("ver", value); } 33 | } 34 | 35 | public string KoiID { 36 | get { 37 | string value = GetValue("id", ""); 38 | return string.IsNullOrEmpty(value) ? null : value; 39 | } 40 | set { SetValue("id", value); } 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /KoiVM/AST/IR/IRConstant.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KoiVM.AST.IR { 4 | public class IRConstant : ASTConstant, IIROperand { 5 | ASTType IIROperand.Type { 6 | get { return base.Type.Value; } 7 | } 8 | 9 | public static IRConstant FromI4(int value) { 10 | return new IRConstant { 11 | Value = value, 12 | Type = ASTType.I4 13 | }; 14 | } 15 | 16 | public static IRConstant FromI8(long value) { 17 | return new IRConstant { 18 | Value = value, 19 | Type = ASTType.I8 20 | }; 21 | } 22 | 23 | public static IRConstant FromR4(float value) { 24 | return new IRConstant { 25 | Value = value, 26 | Type = ASTType.R4 27 | }; 28 | } 29 | 30 | public static IRConstant FromR8(double value) { 31 | return new IRConstant { 32 | Value = value, 33 | Type = ASTType.R8 34 | }; 35 | } 36 | 37 | public static IRConstant FromString(string value) { 38 | return new IRConstant { 39 | Value = value, 40 | Type = ASTType.O 41 | }; 42 | } 43 | 44 | public static IRConstant Null() { 45 | return new IRConstant { 46 | Value = null, 47 | Type = ASTType.O 48 | }; 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/Data/VMFuncSig.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | 4 | namespace KoiVM.Runtime.Data { 5 | internal class VMFuncSig { 6 | public unsafe VMFuncSig(ref byte* ptr, Module module) { 7 | this.module = module; 8 | 9 | Flags = *ptr++; 10 | paramToks = new int[Utils.ReadCompressedUInt(ref ptr)]; 11 | for (int i = 0; i < paramToks.Length; i++) { 12 | paramToks[i] = (int)Utils.FromCodedToken(Utils.ReadCompressedUInt(ref ptr)); 13 | } 14 | retTok = (int)Utils.FromCodedToken(Utils.ReadCompressedUInt(ref ptr)); 15 | } 16 | 17 | Module module; 18 | readonly int[] paramToks; 19 | readonly int retTok; 20 | Type[] paramTypes; 21 | Type retType; 22 | 23 | public byte Flags; 24 | 25 | public Type[] ParamTypes { 26 | get { 27 | if (paramTypes != null) 28 | return paramTypes; 29 | 30 | var p = new Type[paramToks.Length]; 31 | for (int i = 0; i < p.Length; i++) { 32 | p[i] = module.ResolveType(paramToks[i]); 33 | } 34 | paramTypes = p; 35 | return p; 36 | } 37 | } 38 | 39 | public Type RetType { 40 | get { return retType ?? (retType = module.ResolveType(retTok)); } 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /KoiVM/CFG/BasicBlock.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace KoiVM.CFG { 5 | public class BasicBlock : IBasicBlock { 6 | public BasicBlock(int id, TContent content) { 7 | Id = id; 8 | Content = content; 9 | Sources = new List>(); 10 | Targets = new List>(); 11 | } 12 | 13 | public int Id { get; set; } 14 | public TContent Content { get; set; } 15 | public BlockFlags Flags { get; set; } 16 | public IList> Sources { get; private set; } 17 | public IList> Targets { get; private set; } 18 | 19 | object IBasicBlock.Content { 20 | get { return Content; } 21 | } 22 | 23 | IEnumerable IBasicBlock.Sources { 24 | get { return Sources; } 25 | } 26 | 27 | IEnumerable IBasicBlock.Targets { 28 | get { return Targets; } 29 | } 30 | 31 | public void LinkTo(BasicBlock target) { 32 | Targets.Add(target); 33 | target.Sources.Add(this); 34 | } 35 | 36 | public override string ToString() { 37 | return string.Format("Block_{0:x2}:{1}{2}", Id, Environment.NewLine, Content); 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /KoiVM/Watermark.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | 4 | namespace KoiVM { 5 | [Obfuscation(Exclude = false, Feature = "+koi;-ref proxy")] 6 | internal static class Watermark { 7 | internal static byte[] GenerateWatermark(uint rand) { 8 | uint id = 0x10000; 9 | uint a = id * 0x94952c99; // 0x71b467a9 10 | uint b = id * 0xbaaa9827; // 0x1edd5797 11 | uint c = id * 0x6f3592e3; // 0x4fa242cb 12 | uint d = a + b + c; 13 | 14 | byte[] watermark = new byte[0x10]; 15 | watermark[0x0] = (byte)(a >> 24); 16 | watermark[0x1] = (byte)(a >> 16); 17 | watermark[0x2] = (byte)(a >> 8); 18 | watermark[0x3] = (byte)(a >> 0); 19 | 20 | watermark[0x4] = (byte)(b >> 24); 21 | watermark[0x5] = (byte)(b >> 16); 22 | watermark[0x6] = (byte)(b >> 8); 23 | watermark[0x7] = (byte)(b >> 0); 24 | 25 | watermark[0x8] = (byte)(c >> 24); 26 | watermark[0x9] = (byte)(c >> 16); 27 | watermark[0xA] = (byte)(c >> 8); 28 | watermark[0xB] = (byte)(c >> 0); 29 | 30 | watermark[0xC] = (byte)(d >> 24); 31 | watermark[0xD] = (byte)(d >> 16); 32 | watermark[0xE] = (byte)(d >> 8); 33 | watermark[0xF] = (byte)(d >> 0); 34 | 35 | return watermark; 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/Execution/Internal/ValueTypeBox.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | 4 | namespace KoiVM.Runtime.Execution.Internal { 5 | // Unboxed VT is stored in these boxes, boxed VT is stored as raw object. 6 | 7 | internal interface IValueTypeBox { 8 | object GetValue(); 9 | Type GetValueType(); 10 | IValueTypeBox Clone(); 11 | } 12 | 13 | internal struct ValueTypeBox : IValueTypeBox { 14 | public ValueTypeBox(T value) { 15 | this.value = value; 16 | } 17 | 18 | T value; 19 | 20 | public object GetValue() { 21 | return value; 22 | } 23 | 24 | public Type GetValueType() { 25 | return typeof(T); 26 | } 27 | 28 | public IValueTypeBox Clone() { 29 | return new ValueTypeBox(value); 30 | } 31 | } 32 | 33 | internal static class ValueTypeBox { 34 | public static IValueTypeBox Box(object vt, Type vtType) { 35 | Debug.Assert(vtType.IsValueType); 36 | var boxType = typeof(ValueTypeBox<>).MakeGenericType(vtType); 37 | return (IValueTypeBox)Activator.CreateInstance(boxType, vt); 38 | } 39 | 40 | public static object Unbox(object box) { 41 | if (box is IValueTypeBox) 42 | return ((IValueTypeBox)box).GetValue(); 43 | return box; 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /KoiVM/AST/IR/IRRegister.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.VM; 3 | 4 | namespace KoiVM.AST.IR { 5 | public class IRRegister : IIROperand { 6 | public IRRegister(VMRegisters reg) { 7 | Register = reg; 8 | Type = ASTType.Ptr; 9 | } 10 | 11 | public IRRegister(VMRegisters reg, ASTType type) { 12 | Register = reg; 13 | Type = type; 14 | } 15 | 16 | public VMRegisters Register { get; set; } 17 | public IRVariable SourceVariable { get; set; } 18 | public ASTType Type { get; set; } 19 | 20 | public override string ToString() { 21 | return Register.ToString(); 22 | } 23 | 24 | public static readonly IRRegister BP = new IRRegister(VMRegisters.BP, ASTType.I4); 25 | public static readonly IRRegister SP = new IRRegister(VMRegisters.SP, ASTType.I4); 26 | public static readonly IRRegister IP = new IRRegister(VMRegisters.IP); 27 | public static readonly IRRegister FL = new IRRegister(VMRegisters.FL, ASTType.I4); 28 | public static readonly IRRegister K1 = new IRRegister(VMRegisters.K1, ASTType.I4); 29 | public static readonly IRRegister K2 = new IRRegister(VMRegisters.K2, ASTType.I4); 30 | public static readonly IRRegister M1 = new IRRegister(VMRegisters.M1, ASTType.I4); 31 | public static readonly IRRegister M2 = new IRRegister(VMRegisters.M2, ASTType.I4); 32 | } 33 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/VCalls/Initobj.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.Serialization; 3 | using KoiVM.Runtime.Dynamic; 4 | using KoiVM.Runtime.Execution; 5 | using KoiVM.Runtime.Execution.Internal; 6 | 7 | namespace KoiVM.Runtime.VCalls { 8 | internal class Initobj : IVCall { 9 | public byte Code { 10 | get { return Constants.VCALL_INITOBJ; } 11 | } 12 | 13 | public void Run(VMContext ctx, out ExecutionState state) { 14 | var sp = ctx.Registers[Constants.REG_SP].U4; 15 | var typeSlot = ctx.Stack[sp--]; 16 | var addrSlot = ctx.Stack[sp--]; 17 | 18 | var type = (Type)ctx.Instance.Data.LookupReference(typeSlot.U4); 19 | if (addrSlot.O is IReference) { 20 | var reference = (IReference)addrSlot.O; 21 | var slot = new VMSlot(); 22 | if (type.IsValueType) { 23 | object def = null; 24 | if (Nullable.GetUnderlyingType(type) == null) 25 | def = FormatterServices.GetUninitializedObject(type); 26 | slot.O = ValueTypeBox.Box(def, type); 27 | } 28 | else 29 | slot.O = null; 30 | reference.SetValue(ctx, slot, PointerType.OBJECT); 31 | } 32 | else { 33 | throw new NotSupportedException(); 34 | } 35 | 36 | ctx.Stack.SetTopPosition(sp); 37 | ctx.Registers[Constants.REG_SP].U4 = sp; 38 | state = ExecutionState.Next; 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/VCalls/Unbox.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.Runtime.Dynamic; 3 | using KoiVM.Runtime.Execution; 4 | using KoiVM.Runtime.Execution.Internal; 5 | 6 | namespace KoiVM.Runtime.VCalls { 7 | internal class Unbox : IVCall { 8 | public byte Code { 9 | get { return Constants.VCALL_UNBOX; } 10 | } 11 | 12 | public void Run(VMContext ctx, out ExecutionState state) { 13 | var sp = ctx.Registers[Constants.REG_SP].U4; 14 | var typeSlot = ctx.Stack[sp--]; 15 | var valSlot = ctx.Stack[sp]; 16 | 17 | bool unboxPtr = (typeSlot.U4 & 0x80000000) != 0; 18 | var valType = (Type)ctx.Instance.Data.LookupReference(typeSlot.U4 & ~0x80000000); 19 | if (unboxPtr) { 20 | unsafe { 21 | TypedReference typedRef; 22 | TypedReferenceHelpers.UnboxTypedRef(valSlot.O, &typedRef); 23 | var reference = new TypedRef(typedRef); 24 | valSlot = VMSlot.FromObject(valSlot.O, valType); 25 | ctx.Stack[sp] = valSlot; 26 | } 27 | } 28 | else { 29 | if (valType == typeof(object) && valSlot.O != null) 30 | valType = valSlot.O.GetType(); 31 | valSlot = VMSlot.FromObject(valSlot.O, valType); 32 | ctx.Stack[sp] = valSlot; 33 | } 34 | 35 | ctx.Stack.SetTopPosition(sp); 36 | ctx.Registers[Constants.REG_SP].U4 = sp; 37 | state = ExecutionState.Next; 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /KoiVM/VMIR/Transforms/StackFrameTransform.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.AST.IR; 3 | using KoiVM.VMIR.RegAlloc; 4 | 5 | namespace KoiVM.VMIR.Transforms { 6 | public class StackFrameTransform : ITransform { 7 | RegisterAllocator allocator; 8 | bool doneEntry, doneExit; 9 | 10 | public void Initialize(IRTransformer tr) { 11 | allocator = (RegisterAllocator)tr.Annotations[RegisterAllocationTransform.RegAllocatorKey]; 12 | } 13 | 14 | public void Transform(IRTransformer tr) { 15 | tr.Instructions.VisitInstrs(VisitInstr, tr); 16 | } 17 | 18 | void VisitInstr(IRInstrList instrs, IRInstruction instr, ref int index, IRTransformer tr) { 19 | if (instr.OpCode == IROpCode.__ENTRY && !doneEntry) { 20 | instrs.Replace(index, new[] { 21 | instr, 22 | new IRInstruction(IROpCode.PUSH, IRRegister.BP), 23 | new IRInstruction(IROpCode.MOV, IRRegister.BP, IRRegister.SP), 24 | new IRInstruction(IROpCode.ADD, IRRegister.SP, IRConstant.FromI4(allocator.LocalSize)) 25 | }); 26 | doneEntry = true; 27 | } 28 | else if (instr.OpCode == IROpCode.__EXIT && !doneExit) { 29 | instrs.Replace(index, new[] { 30 | new IRInstruction(IROpCode.MOV, IRRegister.SP, IRRegister.BP), 31 | new IRInstruction(IROpCode.POP, IRRegister.BP), 32 | instr 33 | }); 34 | doneExit = true; 35 | } 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /KoiVM/AST/ILAST/ILASTTree.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace KoiVM.AST.ILAST { 6 | public class ILASTTree : List { 7 | public ILASTVariable[] StackRemains { get; set; } 8 | 9 | public override string ToString() { 10 | var ret = new StringBuilder(); 11 | foreach (var st in this) 12 | ret.AppendLine(st.ToString()); 13 | ret.AppendLine(); 14 | ret.Append("["); 15 | for (int i = 0; i < StackRemains.Length; i++) { 16 | if (i != 0) 17 | ret.Append(", "); 18 | ret.Append(StackRemains[i]); 19 | } 20 | ret.AppendLine("]"); 21 | return ret.ToString(); 22 | } 23 | 24 | public void TraverseTree(Action visitFunc, T state) { 25 | foreach (var st in this) { 26 | if (st is ILASTExpression) 27 | TraverseTreeInternal((ILASTExpression)st, visitFunc, state); 28 | else if (st is ILASTAssignment) 29 | TraverseTreeInternal(((ILASTAssignment)st).Value, visitFunc, state); 30 | } 31 | } 32 | 33 | void TraverseTreeInternal(ILASTExpression expr, Action visitFunc, T state) { 34 | foreach (var arg in expr.Arguments) { 35 | if (arg is ILASTExpression) 36 | TraverseTreeInternal((ILASTExpression)arg, visitFunc, state); 37 | } 38 | visitFunc(expr, state); 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/VCalls/Ldfld.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using KoiVM.Runtime.Dynamic; 4 | using KoiVM.Runtime.Execution; 5 | 6 | namespace KoiVM.Runtime.VCalls { 7 | internal class Ldfld : IVCall { 8 | public byte Code { 9 | get { return Constants.VCALL_LDFLD; } 10 | } 11 | 12 | public void Run(VMContext ctx, out ExecutionState state) { 13 | var sp = ctx.Registers[Constants.REG_SP].U4; 14 | var fieldSlot = ctx.Stack[sp--]; 15 | var objSlot = ctx.Stack[sp]; 16 | 17 | bool addr = (fieldSlot.U4 & 0x80000000) != 0; 18 | var field = (FieldInfo)ctx.Instance.Data.LookupReference(fieldSlot.U4 & 0x7fffffff); 19 | if (!field.IsStatic && objSlot.O == null) 20 | throw new NullReferenceException(); 21 | 22 | if (addr) 23 | ctx.Stack[sp] = new VMSlot { O = new FieldRef(objSlot.O, field) }; 24 | else { 25 | object instance; 26 | if (field.DeclaringType.IsValueType && objSlot.O is IReference) 27 | instance = ((IReference)objSlot.O).GetValue(ctx, PointerType.OBJECT).ToObject(field.DeclaringType); 28 | else 29 | instance = objSlot.ToObject(field.DeclaringType); 30 | ctx.Stack[sp] = VMSlot.FromObject(field.GetValue(instance), field.FieldType); 31 | } 32 | 33 | ctx.Stack.SetTopPosition(sp); 34 | ctx.Registers[Constants.REG_SP].U4 = sp; 35 | state = ExecutionState.Next; 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /KoiVM/AST/IL/ILInstruction.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using KoiVM.AST.IR; 4 | using KoiVM.VMIL; 5 | 6 | namespace KoiVM.AST.IL { 7 | public class ILInstruction : ASTNode, IHasOffset { 8 | public ILInstruction(ILOpCode opCode) { 9 | OpCode = opCode; 10 | } 11 | 12 | public ILInstruction(ILOpCode opCode, IILOperand operand) { 13 | OpCode = opCode; 14 | Operand = operand; 15 | } 16 | 17 | public ILInstruction(ILOpCode opCode, IILOperand operand, object annotation) { 18 | OpCode = opCode; 19 | Operand = operand; 20 | Annotation = annotation; 21 | } 22 | 23 | public ILInstruction(ILOpCode opCode, IILOperand operand, ILInstruction origin) { 24 | OpCode = opCode; 25 | Operand = operand; 26 | Annotation = origin.Annotation; 27 | IR = origin.IR; 28 | } 29 | 30 | public uint Offset { get; set; } 31 | public IRInstruction IR { get; set; } 32 | public ILOpCode OpCode { get; set; } 33 | public IILOperand Operand { get; set; } 34 | public object Annotation { get; set; } 35 | 36 | public override string ToString() { 37 | var ret = new StringBuilder(); 38 | ret.AppendFormat("{0}", OpCode.ToString().PadLeft(16)); 39 | if (Operand != null) { 40 | ret.AppendFormat(" {0}", Operand); 41 | } 42 | if (Annotation != null) 43 | ret.AppendFormat(" ; {0}", Annotation); 44 | return ret.ToString(); 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /KoiVM/RT/JumpTableChunk.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.AST.IL; 3 | 4 | namespace KoiVM.RT { 5 | public class JumpTableChunk : IKoiChunk { 6 | internal VMRuntime runtime; 7 | 8 | public JumpTableChunk(ILJumpTable table) { 9 | Table = table; 10 | if (table.Targets.Length > ushort.MaxValue) 11 | throw new NotSupportedException("Jump table too large."); 12 | } 13 | 14 | public ILJumpTable Table { get; private set; } 15 | public uint Offset { get; private set; } 16 | 17 | uint IKoiChunk.Length { 18 | get { return (uint)Table.Targets.Length * 4 + 2; } 19 | } 20 | 21 | void IKoiChunk.OnOffsetComputed(uint offset) { 22 | Offset = offset + 2; 23 | } 24 | 25 | byte[] IKoiChunk.GetData() { 26 | byte[] data = new byte[Table.Targets.Length * 4 + 2]; 27 | ushort len = (ushort)Table.Targets.Length; 28 | int ptr = 0; 29 | data[ptr++] = (byte)Table.Targets.Length; 30 | data[ptr++] = (byte)(Table.Targets.Length >> 8); 31 | 32 | var relBase = Table.RelativeBase.Offset; 33 | relBase += runtime.serializer.ComputeLength(Table.RelativeBase); 34 | for (int i = 0; i < Table.Targets.Length; i++) { 35 | var offset = ((ILBlock)Table.Targets[i]).Content[0].Offset; 36 | offset -= relBase; 37 | data[ptr++] = (byte)(offset >> 0); 38 | data[ptr++] = (byte)(offset >> 8); 39 | data[ptr++] = (byte)(offset >> 16); 40 | data[ptr++] = (byte)(offset >> 24); 41 | } 42 | return data; 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /KoiVM/VMIR/Transforms/InitLocalTransform.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using dnlib.DotNet; 4 | using KoiVM.AST; 5 | using KoiVM.AST.IR; 6 | 7 | namespace KoiVM.VMIR.Transforms { 8 | public class InitLocalTransform : ITransform { 9 | bool done; 10 | 11 | public void Initialize(IRTransformer tr) { 12 | } 13 | 14 | public void Transform(IRTransformer tr) { 15 | if (!tr.Context.Method.Body.InitLocals) 16 | return; 17 | tr.Instructions.VisitInstrs(VisitInstr, tr); 18 | } 19 | 20 | void VisitInstr(IRInstrList instrs, IRInstruction instr, ref int index, IRTransformer tr) { 21 | if (instr.OpCode == IROpCode.__ENTRY && !done) { 22 | var init = new List(); 23 | init.Add(instr); 24 | foreach (var local in tr.Context.Method.Body.Variables) { 25 | if (local.Type.IsValueType && !local.Type.IsPrimitive) { 26 | var adr = tr.Context.AllocateVRegister(ASTType.ByRef); 27 | init.Add(new IRInstruction(IROpCode.__LEA, adr, tr.Context.ResolveLocal(local))); 28 | 29 | var typeId = (int)tr.VM.Data.GetId(local.Type.RemovePinnedAndModifiers().ToTypeDefOrRef()); 30 | var ecallId = tr.VM.Runtime.VMCall.INITOBJ; 31 | init.Add(new IRInstruction(IROpCode.PUSH, adr)); 32 | init.Add(new IRInstruction(IROpCode.VCALL, IRConstant.FromI4(ecallId), IRConstant.FromI4(typeId))); 33 | } 34 | } 35 | instrs.Replace(index, init); 36 | done = true; 37 | } 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /KoiVM.Confuser/RC4.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KoiVM.Confuser { 4 | internal class RC4 { 5 | // Adopted from BouncyCastle 6 | 7 | static readonly int STATE_LENGTH = 256; 8 | 9 | byte[] engineState; 10 | int x; 11 | int y; 12 | byte[] workingKey; 13 | 14 | public RC4(byte[] key) { 15 | workingKey = (byte[])key.Clone(); 16 | 17 | x = 0; 18 | y = 0; 19 | 20 | if (engineState == null) { 21 | engineState = new byte[STATE_LENGTH]; 22 | } 23 | 24 | // reset the state of the engine 25 | for (int i = 0; i < STATE_LENGTH; i++) { 26 | engineState[i] = (byte)i; 27 | } 28 | 29 | int i1 = 0; 30 | int i2 = 0; 31 | 32 | for (int i = 0; i < STATE_LENGTH; i++) { 33 | i2 = ((key[i1] & 0xff) + engineState[i] + i2) & 0xff; 34 | // do the byte-swap inline 35 | byte tmp = engineState[i]; 36 | engineState[i] = engineState[i2]; 37 | engineState[i2] = tmp; 38 | i1 = (i1 + 1) % key.Length; 39 | } 40 | } 41 | 42 | public void Crypt(byte[] buf, int offset, int len) { 43 | for (int i = 0; i < len; i++) { 44 | x = (x + 1) & 0xff; 45 | y = (engineState[x] + y) & 0xff; 46 | 47 | // swap 48 | byte tmp = engineState[x]; 49 | engineState[x] = engineState[y]; 50 | engineState[y] = tmp; 51 | 52 | // xor 53 | buf[i + offset] = (byte)(buf[i + offset] 54 | ^ engineState[(engineState[x] + engineState[y]) & 0xff]); 55 | } 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/Execution/StackRef.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.Runtime.Execution.Internal; 3 | 4 | namespace KoiVM.Runtime.Execution { 5 | internal class StackRef : IReference { 6 | public StackRef(uint pos) { 7 | StackPos = pos; 8 | } 9 | 10 | public uint StackPos { get; set; } 11 | 12 | public VMSlot GetValue(VMContext ctx, PointerType type) { 13 | var slot = ctx.Stack[StackPos]; 14 | if (type == PointerType.BYTE) 15 | slot.U8 = slot.U1; 16 | else if (type == PointerType.WORD) 17 | slot.U8 = slot.U2; 18 | else if (type == PointerType.DWORD) 19 | slot.U8 = slot.U4; 20 | else if (slot.O is IValueTypeBox) { 21 | // Value types have value-copying semantics. 22 | slot.O = ((IValueTypeBox)slot.O).Clone(); 23 | } 24 | return slot; 25 | } 26 | 27 | public void SetValue(VMContext ctx, VMSlot slot, PointerType type) { 28 | if (type == PointerType.BYTE) 29 | slot.U8 = slot.U1; 30 | else if (type == PointerType.WORD) 31 | slot.U8 = slot.U2; 32 | else if (type == PointerType.DWORD) 33 | slot.U8 = slot.U4; 34 | ctx.Stack[StackPos] = slot; 35 | } 36 | 37 | public IReference Add(uint value) { 38 | return new StackRef(StackPos + value); 39 | } 40 | 41 | public IReference Add(ulong value) { 42 | return new StackRef(StackPos + (uint)(long)value); 43 | } 44 | 45 | public void ToTypedReference(VMContext ctx, TypedRefPtr typedRef, Type type) { 46 | ctx.Stack.ToTypedReference(StackPos, typedRef, type); 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/Execution/FieldRef.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using KoiVM.Runtime.Execution.Internal; 4 | 5 | namespace KoiVM.Runtime.Execution { 6 | internal class FieldRef : IReference { 7 | object instance; 8 | FieldInfo field; 9 | 10 | public FieldRef(object instance, FieldInfo field) { 11 | this.instance = instance; 12 | this.field = field; 13 | } 14 | 15 | public VMSlot GetValue(VMContext ctx, PointerType type) { 16 | var inst = instance; 17 | if (field.DeclaringType.IsValueType && instance is IReference) 18 | inst = ((IReference)instance).GetValue(ctx, PointerType.OBJECT).ToObject(field.DeclaringType); 19 | return VMSlot.FromObject(field.GetValue(inst), field.FieldType); 20 | } 21 | 22 | public unsafe void SetValue(VMContext ctx, VMSlot slot, PointerType type) { 23 | if (field.DeclaringType.IsValueType && instance is IReference) { 24 | TypedReference typedRef; 25 | ((IReference)instance).ToTypedReference(ctx, &typedRef, field.DeclaringType); 26 | field.SetValueDirect(typedRef, slot.ToObject(field.FieldType)); 27 | } 28 | else 29 | field.SetValue(instance, slot.ToObject(field.FieldType)); 30 | } 31 | 32 | public IReference Add(uint value) { 33 | return this; 34 | } 35 | 36 | public IReference Add(ulong value) { 37 | return this; 38 | } 39 | 40 | public void ToTypedReference(VMContext ctx, TypedRefPtr typedRef, Type type) { 41 | TypedReferenceHelpers.GetFieldAddr(ctx, instance, field, typedRef); 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/OpCodes/Sx.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.Runtime.Dynamic; 3 | using KoiVM.Runtime.Execution; 4 | 5 | namespace KoiVM.Runtime.OpCodes { 6 | internal class SxDword : IOpCode { 7 | public byte Code { 8 | get { return Constants.OP_SX_DWORD; } 9 | } 10 | 11 | public void Run(VMContext ctx, out ExecutionState state) { 12 | var sp = ctx.Registers[Constants.REG_SP].U4; 13 | var operand = ctx.Stack[sp]; 14 | if ((operand.U4 & 0x80000000) != 0) 15 | operand.U8 = 0xffffffff00000000 | operand.U4; 16 | ctx.Stack[sp] = operand; 17 | 18 | state = ExecutionState.Next; 19 | } 20 | } 21 | 22 | internal class SxWord : IOpCode { 23 | public byte Code { 24 | get { return Constants.OP_SX_WORD; } 25 | } 26 | 27 | public void Run(VMContext ctx, out ExecutionState state) { 28 | var sp = ctx.Registers[Constants.REG_SP].U4; 29 | var operand = ctx.Stack[sp]; 30 | if ((operand.U2 & 0x8000) != 0) 31 | operand.U4 = operand.U2 | 0xffff0000; 32 | ctx.Stack[sp] = operand; 33 | 34 | state = ExecutionState.Next; 35 | } 36 | } 37 | 38 | internal class SxByte : IOpCode { 39 | public byte Code { 40 | get { return Constants.OP_SX_BYTE; } 41 | } 42 | 43 | public void Run(VMContext ctx, out ExecutionState state) { 44 | var sp = ctx.Registers[Constants.REG_SP].U4; 45 | var operand = ctx.Stack[sp]; 46 | if ((operand.U1 & 0x80) != 0) 47 | operand.U4 = operand.U1 | 0xffffff00; 48 | ctx.Stack[sp] = operand; 49 | 50 | state = ExecutionState.Next; 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /KoiVM.Confuser/KoiProtection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using Confuser.Core; 4 | using KoiVM.Confuser.Internal; 5 | 6 | namespace KoiVM.Confuser { 7 | [Obfuscation(Exclude = false, Feature = "-rename", ApplyToMembers = false)] 8 | [BeforeProtection("Ki.ControlFlow", "Ki.AntiTamper"), AfterProtection("Ki.Constants")] 9 | public class KoiProtection : Protection { 10 | public const string _Id = "koi"; 11 | public const string _FullId = "Ki.Koi"; 12 | 13 | public override string Name { 14 | get { return "Koi Virtualizer"; } 15 | } 16 | 17 | public override string Description { 18 | get { return "A majestic Koi fish (or Magikarp, if you prefer) will virtualize your code!"; } 19 | } 20 | 21 | public override string Id { 22 | get { return _Id; } 23 | } 24 | 25 | public override string FullId { 26 | get { return _FullId; } 27 | } 28 | 29 | public override ProtectionPreset Preset { 30 | get { return ProtectionPreset.Maximum; } 31 | } 32 | 33 | protected override void Initialize(ConfuserContext context) { 34 | KoiInfo.Init(context); 35 | } 36 | 37 | protected override void PopulatePipeline(ProtectionPipeline pipeline) { 38 | pipeline.InsertPostStage(PipelineStage.Inspection, 39 | new InitializePhase(this, KoiInfo.KoiDirectory)); 40 | pipeline.InsertPreStage(PipelineStage.EndModule, new MarkPhase(this)); 41 | pipeline.InsertPreStage(PipelineStage.Debug, new FinalizePhase(this)); 42 | pipeline.InsertPreStage(PipelineStage.Pack, new SavePhase(this)); 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/VCalls/Stfld.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using KoiVM.Runtime.Dynamic; 4 | using KoiVM.Runtime.Execution; 5 | using KoiVM.Runtime.Execution.Internal; 6 | 7 | namespace KoiVM.Runtime.VCalls { 8 | internal class Stfld : IVCall { 9 | public byte Code { 10 | get { return Constants.VCALL_STFLD; } 11 | } 12 | 13 | public unsafe void Run(VMContext ctx, out ExecutionState state) { 14 | var sp = ctx.Registers[Constants.REG_SP].U4; 15 | var fieldSlot = ctx.Stack[sp--]; 16 | var valSlot = ctx.Stack[sp--]; 17 | var objSlot = ctx.Stack[sp--]; 18 | 19 | var field = (FieldInfo)ctx.Instance.Data.LookupReference(fieldSlot.U4); 20 | if (!field.IsStatic && objSlot.O == null) 21 | throw new NullReferenceException(); 22 | 23 | object value; 24 | if (Type.GetTypeCode(field.FieldType) == TypeCode.String && valSlot.O == null) 25 | value = ctx.Instance.Data.LookupString(valSlot.U4); 26 | else 27 | value = valSlot.ToObject(field.FieldType); 28 | 29 | if (field.DeclaringType.IsValueType && objSlot.O is IReference) { 30 | TypedReference typedRef; 31 | ((IReference)objSlot.O).ToTypedReference(ctx, &typedRef, field.DeclaringType); 32 | TypedReferenceHelpers.CastTypedRef(&typedRef, field.DeclaringType); 33 | field.SetValueDirect(typedRef, value); 34 | } 35 | else 36 | field.SetValue(objSlot.ToObject(field.DeclaringType), value); 37 | 38 | ctx.Stack.SetTopPosition(sp); 39 | ctx.Registers[Constants.REG_SP].U4 = sp; 40 | state = ExecutionState.Next; 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /KoiVM/AST/ILAST/ILASTExpression.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Text; 4 | using dnlib.DotNet.Emit; 5 | using KoiVM.CFG; 6 | 7 | namespace KoiVM.AST.ILAST { 8 | public class ILASTExpression : ASTExpression, IILASTNode, IILASTStatement { 9 | public Code ILCode { get; set; } 10 | public Instruction CILInstr { get; set; } 11 | public object Operand { get; set; } 12 | public IILASTNode[] Arguments { get; set; } 13 | public Instruction[] Prefixes { get; set; } 14 | 15 | public override string ToString() { 16 | var ret = new StringBuilder(); 17 | ret.AppendFormat("{0}{1}(", ILCode.ToOpCode().Name, Type == null ? "" : ":" + Type.Value); 18 | if (Operand != null) { 19 | if (Operand is string) 20 | ASTConstant.EscapeString(ret, (string)Operand, true); 21 | else if (Operand is IBasicBlock) 22 | ret.AppendFormat("Block_{0:x2}", ((IBasicBlock)Operand).Id); 23 | else if (Operand is IBasicBlock[]) { 24 | var targets = ((IBasicBlock[])Operand).Select(block => string.Format("Block_{0:x2}", block.Id)); 25 | ret.AppendFormat("[{0}]", string.Join(", ", targets)); 26 | } 27 | else 28 | ret.Append(Operand); 29 | if (Arguments.Length > 0) 30 | ret.Append(";"); 31 | } 32 | for (int i = 0; i < Arguments.Length; i++) { 33 | if (i != 0) 34 | ret.Append(","); 35 | ret.Append(Arguments[i]); 36 | } 37 | ret.Append(")"); 38 | return ret.ToString(); 39 | } 40 | 41 | public ILASTExpression Clone() { 42 | return (ILASTExpression)MemberwiseClone(); 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /KoiVM/AST/InstrAnnotation.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using dnlib.DotNet; 3 | using dnlib.DotNet.Emit; 4 | using KoiVM.AST.IR; 5 | 6 | namespace KoiVM.AST { 7 | public class InstrAnnotation { 8 | public InstrAnnotation(string name) { 9 | Name = name; 10 | } 11 | 12 | public string Name { get; private set; } 13 | 14 | public override string ToString() { 15 | return Name; 16 | } 17 | 18 | public static readonly InstrAnnotation JUMP = new InstrAnnotation("JUMP"); 19 | } 20 | 21 | public class InstrCallInfo : InstrAnnotation { 22 | public InstrCallInfo(string name) 23 | : base(name) { 24 | } 25 | 26 | public ITypeDefOrRef ConstrainType { get; set; } 27 | public IMethod Method { get; set; } 28 | public IIROperand[] Arguments { get; set; } 29 | public IIROperand ReturnValue { get; set; } 30 | public IRRegister ReturnRegister { get; set; } 31 | public IRPointer ReturnSlot { get; set; } 32 | public bool IsECall { get; set; } 33 | 34 | public override string ToString() { 35 | return base.ToString() + " " + Method; 36 | } 37 | } 38 | 39 | public class PointerInfo : InstrAnnotation { 40 | public PointerInfo(string name, ITypeDefOrRef ptrType) 41 | : base(name) { 42 | PointerType = ptrType; 43 | } 44 | 45 | public ITypeDefOrRef PointerType { get; set; } 46 | } 47 | 48 | public class EHInfo : InstrAnnotation { 49 | public EHInfo(ExceptionHandler eh) 50 | : base("EH_" + eh.GetHashCode()) { 51 | ExceptionHandler = eh; 52 | } 53 | 54 | public ExceptionHandler ExceptionHandler { get; set; } 55 | } 56 | } -------------------------------------------------------------------------------- /KoiVM/VMIL/ILPostTransformer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using dnlib.DotNet; 4 | using KoiVM.AST.IL; 5 | using KoiVM.CFG; 6 | using KoiVM.RT; 7 | using KoiVM.VMIL.Transforms; 8 | 9 | namespace KoiVM.VMIL { 10 | public class ILPostTransformer { 11 | IPostTransform[] pipeline; 12 | 13 | public ILPostTransformer(MethodDef method, ScopeBlock rootScope, VMRuntime runtime) { 14 | RootScope = rootScope; 15 | Method = method; 16 | Runtime = runtime; 17 | 18 | Annotations = new Dictionary(); 19 | pipeline = InitPipeline(); 20 | } 21 | 22 | IPostTransform[] InitPipeline() { 23 | return new IPostTransform[] { 24 | new SaveRegistersTransform(), 25 | new FixMethodRefTransform(), 26 | new BlockKeyTransform() 27 | }; 28 | } 29 | 30 | public VMRuntime Runtime { get; private set; } 31 | public MethodDef Method { get; private set; } 32 | public ScopeBlock RootScope { get; private set; } 33 | 34 | internal Dictionary Annotations { get; private set; } 35 | internal ILBlock Block { get; private set; } 36 | 37 | internal ILInstrList Instructions { 38 | get { return Block.Content; } 39 | } 40 | 41 | public void Transform() { 42 | if (pipeline == null) 43 | throw new InvalidOperationException("Transformer already used."); 44 | 45 | foreach (var handler in pipeline) { 46 | handler.Initialize(this); 47 | 48 | RootScope.ProcessBasicBlocks(block => { 49 | Block = (ILBlock)block; 50 | handler.Transform(this); 51 | }); 52 | } 53 | 54 | pipeline = null; 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /KoiVM/AST/ASTConstant.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | 4 | namespace KoiVM.AST { 5 | public class ASTConstant : ASTExpression { 6 | public object Value { get; set; } 7 | 8 | public static void EscapeString(StringBuilder sb, string s, bool addQuotes) { 9 | if (s == null) { 10 | sb.Append("null"); 11 | return; 12 | } 13 | 14 | if (addQuotes) 15 | sb.Append('"'); 16 | 17 | foreach (var c in s) { 18 | if (c < 0x20) { 19 | switch (c) { 20 | case '\a': 21 | sb.Append(@"\a"); 22 | break; 23 | case '\b': 24 | sb.Append(@"\b"); 25 | break; 26 | case '\f': 27 | sb.Append(@"\f"); 28 | break; 29 | case '\n': 30 | sb.Append(@"\n"); 31 | break; 32 | case '\r': 33 | sb.Append(@"\r"); 34 | break; 35 | case '\t': 36 | sb.Append(@"\t"); 37 | break; 38 | case '\v': 39 | sb.Append(@"\v"); 40 | break; 41 | default: 42 | sb.Append(string.Format(@"\u{0:X4}", (int)c)); 43 | break; 44 | } 45 | } 46 | else if (c == '\\' || c == '"') { 47 | sb.Append('\\'); 48 | sb.Append(c); 49 | } 50 | else 51 | sb.Append(c); 52 | } 53 | 54 | if (addQuotes) 55 | sb.Append('"'); 56 | } 57 | 58 | public override string ToString() { 59 | var ret = new StringBuilder(); 60 | if (Value == null) 61 | ret.Append("<<>>"); 62 | else if (Value is string) 63 | EscapeString(ret, (string)Value, true); 64 | else 65 | ret.Append(Value); 66 | return ret.ToString(); 67 | } 68 | } 69 | } -------------------------------------------------------------------------------- /KoiVM/AST/IR/IRInstruction.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using KoiVM.AST.ILAST; 4 | using KoiVM.VMIR; 5 | 6 | namespace KoiVM.AST.IR { 7 | public class IRInstruction : ASTNode { 8 | public IRInstruction(IROpCode opCode) { 9 | OpCode = opCode; 10 | } 11 | 12 | public IRInstruction(IROpCode opCode, IIROperand op1) { 13 | OpCode = opCode; 14 | Operand1 = op1; 15 | } 16 | 17 | public IRInstruction(IROpCode opCode, IIROperand op1, IIROperand op2) { 18 | OpCode = opCode; 19 | Operand1 = op1; 20 | Operand2 = op2; 21 | } 22 | 23 | public IRInstruction(IROpCode opCode, IIROperand op1, IIROperand op2, object annotation) { 24 | OpCode = opCode; 25 | Operand1 = op1; 26 | Operand2 = op2; 27 | Annotation = annotation; 28 | } 29 | 30 | public IRInstruction(IROpCode opCode, IIROperand op1, IIROperand op2, IRInstruction origin) { 31 | OpCode = opCode; 32 | Operand1 = op1; 33 | Operand2 = op2; 34 | Annotation = origin.Annotation; 35 | ILAST = origin.ILAST; 36 | } 37 | 38 | public IROpCode OpCode { get; set; } 39 | public IILASTStatement ILAST { get; set; } 40 | public IIROperand Operand1 { get; set; } 41 | public IIROperand Operand2 { get; set; } 42 | public object Annotation { get; set; } 43 | 44 | public override string ToString() { 45 | var ret = new StringBuilder(); 46 | ret.AppendFormat("{0}", OpCode.ToString().PadLeft(16)); 47 | if (Operand1 != null) { 48 | ret.AppendFormat(" {0}", Operand1); 49 | if (Operand2 != null) 50 | ret.AppendFormat(", {0}", Operand2); 51 | } 52 | if (Annotation != null) 53 | ret.AppendFormat(" ; {0}", Annotation); 54 | return ret.ToString(); 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /libs/UpdateVersion.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.IO; 4 | 5 | public static class Program { 6 | public static int Main(string[] args) { 7 | if (args.Length != 1) { 8 | Console.WriteLine("invalid argument length."); 9 | return -1; 10 | } 11 | 12 | string dir = args[0]; 13 | string ver = File.ReadAllText(Path.Combine(dir, "VERSION")); 14 | string tag = null; 15 | 16 | string gitDir = Path.Combine(dir, ".git"); 17 | if (!Directory.Exists(gitDir)) { 18 | Console.WriteLine("git repository not found."); 19 | } 20 | else { 21 | try { 22 | var info = new ProcessStartInfo("git", "describe"); 23 | info.RedirectStandardOutput = true; 24 | info.UseShellExecute = false; 25 | using (Process ps = Process.Start(info)) { 26 | tag = ps.StandardOutput.ReadLine(); 27 | string[] infos = tag.Split('-'); 28 | if (infos.Length >= 3) 29 | ver = ver + "." + infos[infos.Length - 2]; 30 | else 31 | ver = infos[0].Substring(1); 32 | ps.WaitForExit(); 33 | if (ps.ExitCode != 0) { 34 | Console.WriteLine("error when executing git describe: " + ps.ExitCode); 35 | } 36 | } 37 | } 38 | catch { 39 | Console.WriteLine("error when executing git describe."); 40 | } 41 | } 42 | tag = tag ?? "v" + ver + "-custom"; 43 | 44 | string template = Path.Combine(dir, "GlobalAssemblyInfo.Template.cs"); 45 | string output = Path.Combine(dir, "GlobalAssemblyInfo.cs"); 46 | 47 | string verInfo = File.ReadAllText(template); 48 | verInfo = verInfo.Replace("{{VER}}", ver); 49 | verInfo = verInfo.Replace("{{TAG}}", tag); 50 | File.WriteAllText(output, verInfo); 51 | Console.WriteLine("Version updated."); 52 | return 0; 53 | } 54 | } -------------------------------------------------------------------------------- /KoiVM/VMIL/ILTransformer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using dnlib.DotNet; 4 | using KoiVM.AST.IL; 5 | using KoiVM.CFG; 6 | using KoiVM.RT; 7 | using KoiVM.VM; 8 | using KoiVM.VMIL.Transforms; 9 | 10 | namespace KoiVM.VMIL { 11 | public class ILTransformer { 12 | ITransform[] pipeline; 13 | 14 | public ILTransformer(MethodDef method, ScopeBlock rootScope, VMRuntime runtime) { 15 | RootScope = rootScope; 16 | Method = method; 17 | Runtime = runtime; 18 | 19 | Annotations = new Dictionary(); 20 | pipeline = InitPipeline(); 21 | } 22 | 23 | ITransform[] InitPipeline() { 24 | return new ITransform[] { 25 | // new SMCILTransform(), 26 | new ReferenceOffsetTransform(), 27 | new EntryExitTransform(), 28 | new SaveInfoTransform() 29 | }; 30 | } 31 | 32 | public VMRuntime Runtime { get; private set; } 33 | public MethodDef Method { get; private set; } 34 | public ScopeBlock RootScope { get; private set; } 35 | 36 | public VMDescriptor VM { 37 | get { return Runtime.Descriptor; } 38 | } 39 | 40 | internal Dictionary Annotations { get; private set; } 41 | internal ILBlock Block { get; private set; } 42 | 43 | internal ILInstrList Instructions { 44 | get { return Block.Content; } 45 | } 46 | 47 | public void Transform() { 48 | if (pipeline == null) 49 | throw new InvalidOperationException("Transformer already used."); 50 | 51 | foreach (var handler in pipeline) { 52 | handler.Initialize(this); 53 | 54 | RootScope.ProcessBasicBlocks(block => { 55 | Block = (ILBlock)block; 56 | handler.Transform(this); 57 | }); 58 | } 59 | 60 | pipeline = null; 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /KoiVM/VM/Descriptors/VMCallDescriptor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | 4 | namespace KoiVM.VM { 5 | public class VMCallDescriptor { 6 | int[] callOrder = Enumerable.Range(0, 256).ToArray(); 7 | 8 | public VMCallDescriptor(Random random) { 9 | random.Shuffle(callOrder); 10 | } 11 | 12 | public int this[VMCalls call] { 13 | get { return callOrder[(int)call]; } 14 | } 15 | 16 | public int EXIT { 17 | get { return callOrder[0]; } 18 | } 19 | 20 | public int BREAK { 21 | get { return callOrder[1]; } 22 | } 23 | 24 | public int ECALL { 25 | get { return callOrder[2]; } 26 | } 27 | 28 | public int CAST { 29 | get { return callOrder[3]; } 30 | } 31 | 32 | public int CKFINITE { 33 | get { return callOrder[4]; } 34 | } 35 | 36 | public int CKOVERFLOW { 37 | get { return callOrder[5]; } 38 | } 39 | 40 | public int RANGECHK { 41 | get { return callOrder[6]; } 42 | } 43 | 44 | public int INITOBJ { 45 | get { return callOrder[7]; } 46 | } 47 | 48 | public int LDFLD { 49 | get { return callOrder[8]; } 50 | } 51 | 52 | public int LDFTN { 53 | get { return callOrder[9]; } 54 | } 55 | 56 | public int TOKEN { 57 | get { return callOrder[10]; } 58 | } 59 | 60 | public int THROW { 61 | get { return callOrder[11]; } 62 | } 63 | 64 | public int SIZEOF { 65 | get { return callOrder[12]; } 66 | } 67 | 68 | public int STFLD { 69 | get { return callOrder[13]; } 70 | } 71 | 72 | public int BOX { 73 | get { return callOrder[14]; } 74 | } 75 | 76 | public int UNBOX { 77 | get { return callOrder[15]; } 78 | } 79 | 80 | public int LOCALLOC { 81 | get { return callOrder[16]; } 82 | } 83 | } 84 | } -------------------------------------------------------------------------------- /KoiVM/VMIL/ILOpCode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | 4 | namespace KoiVM.VMIL { 5 | [Obfuscation(Exclude = false, ApplyToMembers = false, Feature = "+rename(forceRen=true);")] 6 | public enum ILOpCode { 7 | NOP, 8 | 9 | LIND_PTR, 10 | LIND_OBJECT, 11 | LIND_BYTE, 12 | LIND_WORD, 13 | LIND_DWORD, 14 | LIND_QWORD, 15 | 16 | SIND_PTR, 17 | SIND_OBJECT, 18 | SIND_BYTE, 19 | SIND_WORD, 20 | SIND_DWORD, 21 | SIND_QWORD, 22 | 23 | POP, 24 | 25 | PUSHR_OBJECT, 26 | PUSHR_BYTE, 27 | PUSHR_WORD, 28 | PUSHR_DWORD, 29 | PUSHR_QWORD, 30 | 31 | PUSHI_DWORD, 32 | PUSHI_QWORD, 33 | 34 | SX_BYTE, 35 | SX_WORD, 36 | SX_DWORD, 37 | 38 | CALL, 39 | RET, 40 | 41 | NOR_DWORD, 42 | NOR_QWORD, 43 | 44 | CMP, 45 | CMP_DWORD, 46 | CMP_QWORD, 47 | CMP_R32, 48 | CMP_R64, 49 | 50 | JZ, 51 | JNZ, 52 | JMP, 53 | SWT, 54 | 55 | ADD_DWORD, 56 | ADD_QWORD, 57 | ADD_R32, 58 | ADD_R64, 59 | 60 | SUB_R32, 61 | SUB_R64, 62 | 63 | MUL_DWORD, 64 | MUL_QWORD, 65 | MUL_R32, 66 | MUL_R64, 67 | 68 | DIV_DWORD, 69 | DIV_QWORD, 70 | DIV_R32, 71 | DIV_R64, 72 | 73 | REM_DWORD, 74 | REM_QWORD, 75 | REM_R32, 76 | REM_R64, 77 | 78 | SHR_DWORD, 79 | SHR_QWORD, 80 | SHL_DWORD, 81 | SHL_QWORD, 82 | 83 | FCONV_R32_R64, 84 | FCONV_R64_R32, 85 | FCONV_R32, 86 | FCONV_R64, 87 | ICONV_PTR, 88 | ICONV_R64, 89 | 90 | VCALL, 91 | 92 | TRY, 93 | LEAVE, 94 | 95 | Max, 96 | 97 | // Pseudo-Opcodes, will be eliminate by transforms 98 | __ENTRY, 99 | __EXIT, 100 | 101 | __BEGINCALL, 102 | __ENDCALL 103 | } 104 | } -------------------------------------------------------------------------------- /KoiVM.Confuser/LoginPrompt.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Windows.Forms; 4 | 5 | namespace KoiVM.Confuser { 6 | internal partial class LoginPrompt : Form { 7 | public LoginPrompt() { 8 | InitializeComponent(); 9 | txtId.Text = KoiInfo.settings.KoiID ?? ""; 10 | } 11 | 12 | void btnLogin_Click(object sender, EventArgs e) { 13 | btnLogin.Enabled = false; 14 | txtId.Enabled = false; 15 | KoiInfo.settings.KoiID = txtId.Text; 16 | KoiInfo.settings.Save(); 17 | 18 | var sys = new KoiSystem(); 19 | var ver = sys.GetVersion(KoiInfo.settings.KoiID); 20 | sys.Progress += value => BeginInvoke(new Action(() => { 21 | if (value == 0) { 22 | progress.Value = 0; 23 | progress.Style = ProgressBarStyle.Marquee; 24 | } 25 | else { 26 | progress.Style = ProgressBarStyle.Continuous; 27 | progress.Value = (int)(value * 1000); 28 | } 29 | })); 30 | sys.Finish += success => { 31 | BeginInvoke(new Action(() => { 32 | btnLogin.Enabled = true; 33 | txtId.Enabled = true; 34 | if (success) { 35 | KoiInfo.settings.Version = ver; 36 | KoiInfo.settings.Save(); 37 | DialogResult = DialogResult.OK; 38 | } 39 | else { 40 | KoiInfo.settings.Version = ""; 41 | KoiInfo.settings.Save(); 42 | MessageBox.Show("Login failed.", "Koi System", MessageBoxButtons.OK, MessageBoxIcon.Error); 43 | } 44 | })); 45 | }; 46 | sys.Login(txtId.Text); 47 | } 48 | 49 | protected override void OnShown(EventArgs e) { 50 | base.OnShown(e); 51 | BringToFront(); 52 | } 53 | 54 | protected override void OnClosing(CancelEventArgs e) { 55 | if (!btnLogin.Enabled) 56 | e.Cancel = true; 57 | base.OnClosing(e); 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/Execution/Internal/ArrayStoreHelpers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Diagnostics; 5 | using System.Reflection.Emit; 6 | 7 | namespace KoiVM.Runtime.Execution.Internal { 8 | internal class ArrayStoreHelpers { 9 | static Hashtable storeHelpers = new Hashtable(); 10 | 11 | delegate void _SetValue(Array array, int index, object value); 12 | 13 | public static void SetValue(Array array, int index, object value, Type valueType, Type elemType) { 14 | Debug.Assert(value == null || value.GetType() == valueType); 15 | 16 | var key = new KeyValuePair(valueType, elemType); 17 | var helper = storeHelpers[key]; 18 | if (helper == null) { 19 | lock (storeHelpers) { 20 | helper = storeHelpers[key]; 21 | if (helper == null) { 22 | helper = BuildStoreHelper(valueType, elemType); 23 | storeHelpers[key] = helper; 24 | } 25 | } 26 | } 27 | ((_SetValue)helper)(array, index, value); 28 | } 29 | 30 | static _SetValue BuildStoreHelper(Type valueType, Type elemType) { 31 | var paramTypes = new[] { typeof(Array), typeof(int), typeof(object) }; 32 | var dm = new DynamicMethod("", typeof(void), paramTypes, Unverifier.Module, true); 33 | var gen = dm.GetILGenerator(); 34 | 35 | gen.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); 36 | gen.Emit(System.Reflection.Emit.OpCodes.Ldarg_1); 37 | gen.Emit(System.Reflection.Emit.OpCodes.Ldarg_2); 38 | if (elemType.IsValueType) 39 | gen.Emit(System.Reflection.Emit.OpCodes.Unbox_Any, valueType); 40 | gen.Emit(System.Reflection.Emit.OpCodes.Stelem, elemType); 41 | gen.Emit(System.Reflection.Emit.OpCodes.Ret); 42 | 43 | return (_SetValue)dm.CreateDelegate(typeof(_SetValue)); 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/Execution/TypedRef.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | using KoiVM.Runtime.Execution.Internal; 4 | 5 | namespace KoiVM.Runtime.Execution { 6 | internal unsafe class TypedRef : IReference { 7 | // TODO: compat with mono? 8 | [StructLayout(LayoutKind.Sequential)] 9 | struct PseudoTypedRef { 10 | public IntPtr Type; 11 | public IntPtr Value; 12 | } 13 | 14 | TypedRefPtr? _ptr; 15 | PseudoTypedRef _typedRef; 16 | 17 | public TypedRef(TypedRefPtr ptr) { 18 | _ptr = ptr; 19 | } 20 | 21 | public TypedRef(TypedReference typedRef) { 22 | _ptr = null; 23 | _typedRef = *(PseudoTypedRef*)&typedRef; 24 | } 25 | 26 | public VMSlot GetValue(VMContext ctx, PointerType type) { 27 | TypedReference typedRef; 28 | if (_ptr != null) 29 | *&typedRef = *(TypedReference*)_ptr.Value; 30 | else 31 | *(PseudoTypedRef*)&typedRef = _typedRef; 32 | return VMSlot.FromObject(TypedReference.ToObject(typedRef), __reftype(typedRef)); 33 | } 34 | 35 | public void SetValue(VMContext ctx, VMSlot slot, PointerType type) { 36 | TypedReference typedRef; 37 | if (_ptr != null) 38 | *&typedRef = *(TypedReference*)_ptr.Value; 39 | else 40 | *(PseudoTypedRef*)&typedRef = _typedRef; 41 | 42 | var refType = __reftype(typedRef); 43 | var value = slot.ToObject(refType); 44 | TypedReferenceHelpers.SetTypedRef(value, &typedRef); 45 | } 46 | 47 | public IReference Add(uint value) { 48 | return this; 49 | } 50 | 51 | public IReference Add(ulong value) { 52 | return this; 53 | } 54 | 55 | public void ToTypedReference(VMContext ctx, TypedRefPtr typedRef, Type type) { 56 | if (_ptr != null) 57 | *(TypedReference*)typedRef = *(TypedReference*)_ptr.Value; 58 | else 59 | *(PseudoTypedRef*)typedRef = _typedRef; 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/OpCodes/Nor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.Runtime.Dynamic; 3 | using KoiVM.Runtime.Execution; 4 | 5 | namespace KoiVM.Runtime.OpCodes { 6 | internal class NorDword : IOpCode { 7 | public byte Code { 8 | get { return Constants.OP_NOR_DWORD; } 9 | } 10 | 11 | public void Run(VMContext ctx, out ExecutionState state) { 12 | var sp = ctx.Registers[Constants.REG_SP].U4; 13 | var op1Slot = ctx.Stack[sp - 1]; 14 | var op2Slot = ctx.Stack[sp]; 15 | sp -= 1; 16 | ctx.Stack.SetTopPosition(sp); 17 | ctx.Registers[Constants.REG_SP].U4 = sp; 18 | 19 | var slot = new VMSlot(); 20 | slot.U4 = ~(op1Slot.U4 | op2Slot.U4); 21 | ctx.Stack[sp] = slot; 22 | 23 | byte mask = (byte)(Constants.FL_ZERO | Constants.FL_SIGN); 24 | var fl = ctx.Registers[Constants.REG_FL].U1; 25 | Utils.UpdateFL(op1Slot.U4, op2Slot.U4, slot.U4, slot.U4, ref fl, mask); 26 | ctx.Registers[Constants.REG_FL].U1 = fl; 27 | 28 | state = ExecutionState.Next; 29 | } 30 | } 31 | 32 | internal class NorQword : IOpCode { 33 | public byte Code { 34 | get { return Constants.OP_NOR_QWORD; } 35 | } 36 | 37 | public void Run(VMContext ctx, out ExecutionState state) { 38 | var sp = ctx.Registers[Constants.REG_SP].U4; 39 | var op1Slot = ctx.Stack[sp - 1]; 40 | var op2Slot = ctx.Stack[sp]; 41 | sp -= 1; 42 | ctx.Stack.SetTopPosition(sp); 43 | ctx.Registers[Constants.REG_SP].U4 = sp; 44 | 45 | var slot = new VMSlot(); 46 | slot.U8 = ~(op1Slot.U8 | op2Slot.U8); 47 | ctx.Stack[sp] = slot; 48 | 49 | byte mask = (byte)(Constants.FL_ZERO | Constants.FL_SIGN); 50 | var fl = ctx.Registers[Constants.REG_FL].U1; 51 | Utils.UpdateFL(op1Slot.U8, op2Slot.U8, slot.U8, slot.U8, ref fl, mask); 52 | ctx.Registers[Constants.REG_FL].U1 = fl; 53 | 54 | state = ExecutionState.Next; 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /KoiVM/VMIR/Translation/CastHandlers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using dnlib.DotNet; 4 | using dnlib.DotNet.Emit; 5 | using KoiVM.AST.ILAST; 6 | using KoiVM.AST.IR; 7 | 8 | namespace KoiVM.VMIR.Translation { 9 | public class IsinstHandler : ITranslationHandler { 10 | public Code ILCode { 11 | get { return Code.Isinst; } 12 | } 13 | 14 | public IIROperand Translate(ILASTExpression expr, IRTranslator tr) { 15 | Debug.Assert(expr.Arguments.Length == 1); 16 | var value = tr.Translate(expr.Arguments[0]); 17 | 18 | var retVar = tr.Context.AllocateVRegister(expr.Type.Value); 19 | var typeId = (int)tr.VM.Data.GetId((ITypeDefOrRef)expr.Operand); 20 | var ecallId = tr.VM.Runtime.VMCall.CAST; 21 | tr.Instructions.Add(new IRInstruction(IROpCode.PUSH, value)); 22 | tr.Instructions.Add(new IRInstruction(IROpCode.VCALL, IRConstant.FromI4(ecallId), IRConstant.FromI4(typeId))); 23 | tr.Instructions.Add(new IRInstruction(IROpCode.POP, retVar)); 24 | 25 | return retVar; 26 | } 27 | } 28 | 29 | public class CastclassHandler : ITranslationHandler { 30 | public Code ILCode { 31 | get { return Code.Castclass; } 32 | } 33 | 34 | public IIROperand Translate(ILASTExpression expr, IRTranslator tr) { 35 | Debug.Assert(expr.Arguments.Length == 1); 36 | var value = tr.Translate(expr.Arguments[0]); 37 | 38 | var retVar = tr.Context.AllocateVRegister(expr.Type.Value); 39 | var typeId = (int)(tr.VM.Data.GetId((ITypeDefOrRef)expr.Operand) | 0x80000000); 40 | var ecallId = tr.VM.Runtime.VMCall.CAST; 41 | tr.Instructions.Add(new IRInstruction(IROpCode.PUSH, value)); 42 | tr.Instructions.Add(new IRInstruction(IROpCode.VCALL, IRConstant.FromI4(ecallId), IRConstant.FromI4(typeId))); 43 | tr.Instructions.Add(new IRInstruction(IROpCode.POP, retVar)); 44 | 45 | return retVar; 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/OpCodes/Shl.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.Runtime.Dynamic; 3 | using KoiVM.Runtime.Execution; 4 | 5 | namespace KoiVM.Runtime.OpCodes { 6 | internal class ShlDword : IOpCode { 7 | public byte Code { 8 | get { return Constants.OP_SHL_DWORD; } 9 | } 10 | 11 | public void Run(VMContext ctx, out ExecutionState state) { 12 | var sp = ctx.Registers[Constants.REG_SP].U4; 13 | var op1Slot = ctx.Stack[sp - 1]; 14 | var op2Slot = ctx.Stack[sp]; 15 | sp -= 1; 16 | ctx.Stack.SetTopPosition(sp); 17 | ctx.Registers[Constants.REG_SP].U4 = sp; 18 | 19 | var slot = new VMSlot(); 20 | slot.U4 = op1Slot.U4 << (int)op2Slot.U4; 21 | ctx.Stack[sp] = slot; 22 | 23 | byte mask = (byte)(Constants.FL_ZERO | Constants.FL_SIGN); 24 | var fl = ctx.Registers[Constants.REG_FL].U1; 25 | Utils.UpdateFL(op1Slot.U4, op2Slot.U4, slot.U4, slot.U4, ref fl, mask); 26 | ctx.Registers[Constants.REG_FL].U1 = fl; 27 | 28 | state = ExecutionState.Next; 29 | } 30 | } 31 | 32 | internal class ShlQword : IOpCode { 33 | public byte Code { 34 | get { return Constants.OP_SHL_QWORD; } 35 | } 36 | 37 | public void Run(VMContext ctx, out ExecutionState state) { 38 | var sp = ctx.Registers[Constants.REG_SP].U4; 39 | var op1Slot = ctx.Stack[sp - 1]; 40 | var op2Slot = ctx.Stack[sp]; 41 | sp -= 1; 42 | ctx.Stack.SetTopPosition(sp); 43 | ctx.Registers[Constants.REG_SP].U4 = sp; 44 | 45 | var slot = new VMSlot(); 46 | slot.U8 = op1Slot.U8 << (int)op2Slot.U4; 47 | ctx.Stack[sp] = slot; 48 | 49 | byte mask = (byte)(Constants.FL_ZERO | Constants.FL_SIGN); 50 | var fl = ctx.Registers[Constants.REG_FL].U1; 51 | Utils.UpdateFL(op1Slot.U8, op2Slot.U8, slot.U8, slot.U8, ref fl, mask); 52 | ctx.Registers[Constants.REG_FL].U1 = fl; 53 | 54 | state = ExecutionState.Next; 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /KoiVM/ILAST/ILASTTransformer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using dnlib.DotNet; 4 | using KoiVM.AST.ILAST; 5 | using KoiVM.CFG; 6 | using KoiVM.ILAST.Transformation; 7 | using KoiVM.RT; 8 | using KoiVM.VM; 9 | 10 | namespace KoiVM.ILAST { 11 | public class ILASTTransformer { 12 | ITransformationHandler[] pipeline; 13 | 14 | public ILASTTransformer(MethodDef method, ScopeBlock rootScope, VMRuntime runtime) { 15 | RootScope = rootScope; 16 | Method = method; 17 | Runtime = runtime; 18 | 19 | Annotations = new Dictionary(); 20 | InitPipeline(); 21 | } 22 | 23 | void InitPipeline() { 24 | pipeline = new ITransformationHandler[] { 25 | new VariableInlining(), 26 | new StringTransform(), 27 | new ArrayTransform(), 28 | new IndirectTransform(), 29 | new ILASTTypeInference(), 30 | new NullTransform(), 31 | new BranchTransform() 32 | }; 33 | } 34 | 35 | public MethodDef Method { get; private set; } 36 | public ScopeBlock RootScope { get; private set; } 37 | public VMRuntime Runtime { get; private set; } 38 | 39 | public VMDescriptor VM { 40 | get { return Runtime.Descriptor; } 41 | } 42 | 43 | internal Dictionary Annotations { get; private set; } 44 | internal BasicBlock Block { get; private set; } 45 | 46 | internal ILASTTree Tree { 47 | get { return Block.Content; } 48 | } 49 | 50 | public void Transform() { 51 | if (pipeline == null) 52 | throw new InvalidOperationException("Transformer already used."); 53 | 54 | foreach (var handler in pipeline) { 55 | handler.Initialize(this); 56 | 57 | RootScope.ProcessBasicBlocks(block => { 58 | Block = block; 59 | handler.Transform(this); 60 | }); 61 | } 62 | 63 | pipeline = null; 64 | } 65 | } 66 | } -------------------------------------------------------------------------------- /KoiVM/AST/IL/ILRegister.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using KoiVM.VM; 4 | 5 | namespace KoiVM.AST.IL { 6 | public class ILRegister : IILOperand { 7 | static readonly Dictionary regMap = new Dictionary(); 8 | 9 | ILRegister(VMRegisters reg) { 10 | Register = reg; 11 | regMap.Add(reg, this); 12 | } 13 | 14 | public VMRegisters Register { get; set; } 15 | 16 | public override string ToString() { 17 | return Register.ToString(); 18 | } 19 | 20 | public static readonly ILRegister R0 = new ILRegister(VMRegisters.R0); 21 | public static readonly ILRegister R1 = new ILRegister(VMRegisters.R1); 22 | public static readonly ILRegister R2 = new ILRegister(VMRegisters.R2); 23 | public static readonly ILRegister R3 = new ILRegister(VMRegisters.R3); 24 | public static readonly ILRegister R4 = new ILRegister(VMRegisters.R4); 25 | public static readonly ILRegister R5 = new ILRegister(VMRegisters.R5); 26 | public static readonly ILRegister R6 = new ILRegister(VMRegisters.R6); 27 | public static readonly ILRegister R7 = new ILRegister(VMRegisters.R7); 28 | 29 | public static readonly ILRegister BP = new ILRegister(VMRegisters.BP); 30 | public static readonly ILRegister SP = new ILRegister(VMRegisters.SP); 31 | public static readonly ILRegister IP = new ILRegister(VMRegisters.IP); 32 | public static readonly ILRegister FL = new ILRegister(VMRegisters.FL); 33 | public static readonly ILRegister K1 = new ILRegister(VMRegisters.K1); 34 | public static readonly ILRegister K2 = new ILRegister(VMRegisters.K2); 35 | public static readonly ILRegister M1 = new ILRegister(VMRegisters.M1); 36 | public static readonly ILRegister M2 = new ILRegister(VMRegisters.M2); 37 | 38 | public static ILRegister LookupRegister(VMRegisters reg) { 39 | return regMap[reg]; 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /KoiVM.Confuser/UpdatePrompt.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Windows.Forms; 4 | 5 | namespace KoiVM.Confuser { 6 | internal partial class UpdatePrompt : Form { 7 | string newVersion; 8 | 9 | public UpdatePrompt(string newVersion) { 10 | InitializeComponent(); 11 | 12 | this.newVersion = newVersion; 13 | verCurrent.Text = KoiInfo.settings.Version ?? "<< None >>"; 14 | verServer.Text = newVersion; 15 | } 16 | 17 | bool failed = false; 18 | 19 | void btnLogin_Click(object sender, EventArgs e) { 20 | btnUpdate.Enabled = false; 21 | 22 | var sys = new KoiSystem(); 23 | sys.Progress += value => BeginInvoke(new Action(() => { 24 | if (value == 0) { 25 | progress.Value = 0; 26 | progress.Style = ProgressBarStyle.Marquee; 27 | } 28 | else { 29 | progress.Style = ProgressBarStyle.Continuous; 30 | progress.Value = (int)(value * 1000); 31 | } 32 | })); 33 | sys.Finish += success => { 34 | BeginInvoke(new Action(() => { 35 | btnUpdate.Enabled = true; 36 | 37 | if (success) { 38 | KoiInfo.settings.Version = newVersion; 39 | KoiInfo.settings.Save(); 40 | DialogResult = DialogResult.OK; 41 | } 42 | else { 43 | failed = true; 44 | KoiInfo.settings.Version = ""; 45 | KoiInfo.settings.Save(); 46 | MessageBox.Show("Login failed.", "Koi System", MessageBoxButtons.OK, MessageBoxIcon.Error); 47 | } 48 | })); 49 | }; 50 | sys.Login(KoiInfo.settings.KoiID); 51 | } 52 | 53 | protected override void OnShown(EventArgs e) { 54 | base.OnShown(e); 55 | BringToFront(); 56 | } 57 | 58 | protected override void OnClosing(CancelEventArgs e) { 59 | if (!btnUpdate.Enabled) 60 | e.Cancel = true; 61 | if (!failed) 62 | DialogResult = DialogResult.OK; 63 | base.OnClosing(e); 64 | } 65 | } 66 | } -------------------------------------------------------------------------------- /KoiVM/VMIR/Compiler/IRConstants.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * IRConstants.cs 3 | * 4 | * THIS FILE HAS BEEN GENERATED AUTOMATICALLY. DO NOT EDIT! 5 | */ 6 | 7 | namespace KoiVM.VMIR.Compiler { 8 | 9 | /** 10 | * An enumeration with token and production node 11 | * constants. 12 | */ 13 | internal enum IRConstants { 14 | STR = 1001, 15 | NUM = 1002, 16 | REG = 1003, 17 | ASTTYPE = 1004, 18 | ID = 1005, 19 | WHITESPACE = 1006, 20 | NEWLINE = 1007, 21 | COMMENT = 1008, 22 | DATA_DECL = 1009, 23 | TYPE_DECL = 1010, 24 | METHOD_DECL = 1011, 25 | INSTANCE = 1012, 26 | CODE_HEADER = 1013, 27 | CODE_FOOTER = 1014, 28 | LEFT_ANG = 1015, 29 | RIGHT_ANG = 1016, 30 | LEFT_PAREN = 1017, 31 | RIGHT_PAREN = 1018, 32 | LEFT_BRACE = 1019, 33 | RIGHT_BRACE = 1020, 34 | LEFT_BRACKET = 1021, 35 | RIGHT_BRACKET = 1022, 36 | EQUALS = 1023, 37 | COMMA = 1024, 38 | COLON = 1025, 39 | PLUS = 1026, 40 | MINUS = 1027, 41 | DOT = 1028, 42 | DELIM = 1029, 43 | PROGRAM = 2001, 44 | BLOCK = 2002, 45 | DATA = 2003, 46 | DATA_SIZE = 2004, 47 | DATA_CONTENT = 2005, 48 | DATA_STRING = 2006, 49 | DATA_BUFFER = 2007, 50 | CODE = 2008, 51 | INSTR = 2009, 52 | OP_CODE = 2010, 53 | OPERAND = 2011, 54 | NUMBER = 2012, 55 | REGISTER = 2013, 56 | POINTER = 2014, 57 | POINTER_OFFSET = 2015, 58 | REFERENCE = 2016, 59 | TYPE = 2017, 60 | RAW_TYPE = 2018, 61 | TYPE_REF_DECL = 2019, 62 | METHOD_REF_DECL = 2020, 63 | TYPE_REF = 2021, 64 | METHOD_REF = 2022, 65 | METHOD_RET_TYPE = 2023, 66 | METHOD_PARAMS = 2024 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /KoiVM/VMIR/Translation/LocalHandlers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using dnlib.DotNet; 4 | using dnlib.DotNet.Emit; 5 | using KoiVM.AST; 6 | using KoiVM.AST.ILAST; 7 | using KoiVM.AST.IR; 8 | 9 | namespace KoiVM.VMIR.Translation { 10 | public class LdlocHandler : ITranslationHandler { 11 | public Code ILCode { 12 | get { return Code.Ldloc; } 13 | } 14 | 15 | public IIROperand Translate(ILASTExpression expr, IRTranslator tr) { 16 | var local = tr.Context.ResolveLocal((Local)expr.Operand); 17 | var ret = tr.Context.AllocateVRegister(local.Type); 18 | tr.Instructions.Add(new IRInstruction(IROpCode.MOV, ret, local)); 19 | 20 | if (local.RawType.ElementType == ElementType.I1 || 21 | local.RawType.ElementType == ElementType.I2) { 22 | ret.RawType = local.RawType; 23 | var r = tr.Context.AllocateVRegister(local.Type); 24 | tr.Instructions.Add(new IRInstruction(IROpCode.SX, r, ret)); 25 | ret = r; 26 | } 27 | return ret; 28 | } 29 | } 30 | 31 | public class StlocHandler : ITranslationHandler { 32 | public Code ILCode { 33 | get { return Code.Stloc; } 34 | } 35 | 36 | public IIROperand Translate(ILASTExpression expr, IRTranslator tr) { 37 | Debug.Assert(expr.Arguments.Length == 1); 38 | tr.Instructions.Add(new IRInstruction(IROpCode.MOV) { 39 | Operand1 = tr.Context.ResolveLocal((Local)expr.Operand), 40 | Operand2 = tr.Translate(expr.Arguments[0]) 41 | }); 42 | return null; 43 | } 44 | } 45 | 46 | public class LdlocaHandler : ITranslationHandler { 47 | public Code ILCode { 48 | get { return Code.Ldloca; } 49 | } 50 | 51 | public IIROperand Translate(ILASTExpression expr, IRTranslator tr) { 52 | var local = tr.Context.ResolveLocal((Local)expr.Operand); 53 | var ret = tr.Context.AllocateVRegister(ASTType.ByRef); 54 | tr.Instructions.Add(new IRInstruction(IROpCode.__LEA, ret, local)); 55 | return ret; 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /KoiVM/VMIR/Translation/ParameterHandlers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using dnlib.DotNet; 4 | using dnlib.DotNet.Emit; 5 | using KoiVM.AST; 6 | using KoiVM.AST.ILAST; 7 | using KoiVM.AST.IR; 8 | 9 | namespace KoiVM.VMIR.Translation { 10 | public class LdargHandler : ITranslationHandler { 11 | public Code ILCode { 12 | get { return Code.Ldarg; } 13 | } 14 | 15 | public IIROperand Translate(ILASTExpression expr, IRTranslator tr) { 16 | var param = tr.Context.ResolveParameter((Parameter)expr.Operand); 17 | var ret = tr.Context.AllocateVRegister(param.Type); 18 | tr.Instructions.Add(new IRInstruction(IROpCode.MOV, ret, param)); 19 | 20 | if (param.RawType.ElementType == ElementType.I1 || 21 | param.RawType.ElementType == ElementType.I2) { 22 | ret.RawType = param.RawType; 23 | var r = tr.Context.AllocateVRegister(param.Type); 24 | tr.Instructions.Add(new IRInstruction(IROpCode.SX, r, ret)); 25 | ret = r; 26 | } 27 | return ret; 28 | } 29 | } 30 | 31 | public class StargHandler : ITranslationHandler { 32 | public Code ILCode { 33 | get { return Code.Starg; } 34 | } 35 | 36 | public IIROperand Translate(ILASTExpression expr, IRTranslator tr) { 37 | Debug.Assert(expr.Arguments.Length == 1); 38 | tr.Instructions.Add(new IRInstruction(IROpCode.MOV) { 39 | Operand1 = tr.Context.ResolveParameter((Parameter)expr.Operand), 40 | Operand2 = tr.Translate(expr.Arguments[0]) 41 | }); 42 | return null; 43 | } 44 | } 45 | 46 | public class LdargaHandler : ITranslationHandler { 47 | public Code ILCode { 48 | get { return Code.Ldarga; } 49 | } 50 | 51 | public IIROperand Translate(ILASTExpression expr, IRTranslator tr) { 52 | var param = tr.Context.ResolveParameter((Parameter)expr.Operand); 53 | var ret = tr.Context.AllocateVRegister(ASTType.ByRef); 54 | tr.Instructions.Add(new IRInstruction(IROpCode.__LEA, ret, param)); 55 | return ret; 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/OpCodes/IConv.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.Runtime.Dynamic; 3 | using KoiVM.Runtime.Execution; 4 | 5 | namespace KoiVM.Runtime.OpCodes { 6 | internal class IConvPtr : IOpCode { 7 | public byte Code { 8 | get { return Constants.OP_ICONV_PTR; } 9 | } 10 | 11 | public void Run(VMContext ctx, out ExecutionState state) { 12 | var sp = ctx.Registers[Constants.REG_SP].U4; 13 | var valueSlot = ctx.Stack[sp]; 14 | 15 | byte fl = (byte)(ctx.Registers[Constants.REG_FL].U1 & ~Constants.FL_OVERFLOW); 16 | if (!Platform.x64 && (valueSlot.U8 >> 32) != 0) 17 | fl |= Constants.FL_OVERFLOW; 18 | ctx.Registers[Constants.REG_FL].U1 = fl; 19 | 20 | ctx.Stack[sp] = valueSlot; 21 | 22 | state = ExecutionState.Next; 23 | } 24 | } 25 | 26 | internal class IConvR64 : IOpCode { 27 | public byte Code { 28 | get { return Constants.OP_ICONV_R64; } 29 | } 30 | 31 | public void Run(VMContext ctx, out ExecutionState state) { 32 | // coreclr/src/vm/jithelpers.cpp JIT_Dbl2ULngOvf & JIT_Dbl2LngOvf 33 | 34 | var sp = ctx.Registers[Constants.REG_SP].U4; 35 | var valueSlot = ctx.Stack[sp]; 36 | 37 | const double two63 = 2147483648.0 * 4294967296.0; 38 | const double two64 = 4294967296.0 * 4294967296.0; 39 | 40 | double value = valueSlot.R8; 41 | valueSlot.U8 = (ulong)(long)value; 42 | byte fl = (byte)(ctx.Registers[Constants.REG_FL].U1 & ~Constants.FL_OVERFLOW); 43 | 44 | if ((fl & Constants.FL_UNSIGNED) != 0) { 45 | if (!(value > -1.0 && value < two64)) 46 | fl |= Constants.FL_OVERFLOW; 47 | 48 | if (!(value < two63)) 49 | valueSlot.U8 = (ulong)((long)value - two63) + 0x8000000000000000UL; 50 | } 51 | else { 52 | if (!(value > -two63 - 0x402 && value < two63)) 53 | fl |= Constants.FL_OVERFLOW; 54 | } 55 | 56 | ctx.Registers[Constants.REG_FL].U1 = (byte)(fl & ~Constants.FL_UNSIGNED); 57 | 58 | ctx.Stack[sp] = valueSlot; 59 | 60 | state = ExecutionState.Next; 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/OpCodes/Sub.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.Runtime.Dynamic; 3 | using KoiVM.Runtime.Execution; 4 | 5 | namespace KoiVM.Runtime.OpCodes { 6 | internal class SubR32 : IOpCode { 7 | public byte Code { 8 | get { return Constants.OP_SUB_R32; } 9 | } 10 | 11 | public void Run(VMContext ctx, out ExecutionState state) { 12 | var sp = ctx.Registers[Constants.REG_SP].U4; 13 | var op1Slot = ctx.Stack[sp - 1]; 14 | var op2Slot = ctx.Stack[sp]; 15 | sp -= 1; 16 | ctx.Stack.SetTopPosition(sp); 17 | ctx.Registers[Constants.REG_SP].U4 = sp; 18 | 19 | var slot = new VMSlot(); 20 | slot.R4 = op1Slot.R4 - op2Slot.R4; 21 | ctx.Stack[sp] = slot; 22 | 23 | byte mask = (byte)(Constants.FL_ZERO | Constants.FL_SIGN | Constants.FL_OVERFLOW | Constants.FL_CARRY); 24 | var fl = (byte)(ctx.Registers[Constants.REG_FL].U1 & ~mask); 25 | if (slot.R4 == 0) 26 | fl |= Constants.FL_ZERO; 27 | else if (slot.R4 < 0) 28 | fl |= Constants.FL_SIGN; 29 | ctx.Registers[Constants.REG_FL].U1 = fl; 30 | 31 | state = ExecutionState.Next; 32 | } 33 | } 34 | 35 | internal class SubR64 : IOpCode { 36 | public byte Code { 37 | get { return Constants.OP_SUB_R64; } 38 | } 39 | 40 | public void Run(VMContext ctx, out ExecutionState state) { 41 | var sp = ctx.Registers[Constants.REG_SP].U4; 42 | var op1Slot = ctx.Stack[sp - 1]; 43 | var op2Slot = ctx.Stack[sp]; 44 | sp -= 1; 45 | ctx.Stack.SetTopPosition(sp); 46 | ctx.Registers[Constants.REG_SP].U4 = sp; 47 | 48 | var slot = new VMSlot(); 49 | slot.R8 = op1Slot.R8 - op2Slot.R8; 50 | ctx.Stack[sp] = slot; 51 | 52 | byte mask = (byte)(Constants.FL_ZERO | Constants.FL_SIGN | Constants.FL_OVERFLOW | Constants.FL_CARRY); 53 | var fl = (byte)(ctx.Registers[Constants.REG_FL].U1 & ~mask); 54 | if (slot.R8 == 0) 55 | fl |= Constants.FL_ZERO; 56 | else if (slot.R8 < 0) 57 | fl |= Constants.FL_SIGN; 58 | ctx.Registers[Constants.REG_FL].U1 = fl; 59 | 60 | state = ExecutionState.Next; 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /KoiVM/Protections/SMC/SMCBlock.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using dnlib.DotNet; 3 | using KoiVM.AST; 4 | using KoiVM.AST.IL; 5 | using KoiVM.RT; 6 | 7 | namespace KoiVM.Protections.SMC { 8 | internal class SMCBlock : ILBlock { 9 | public SMCBlock(int id, ILInstrList content) 10 | : base(id, content) { 11 | } 12 | 13 | internal static readonly InstrAnnotation CounterInit = new InstrAnnotation("SMC_COUNTER"); 14 | internal static readonly InstrAnnotation EncryptionKey = new InstrAnnotation("SMC_KEY"); 15 | internal static readonly InstrAnnotation AddressPart1 = new InstrAnnotation("SMC_PART1"); 16 | internal static readonly InstrAnnotation AddressPart2 = new InstrAnnotation("SMC_PART2"); 17 | 18 | public byte Key { get; set; } 19 | public ILImmediate CounterOperand { get; set; } 20 | 21 | public override IKoiChunk CreateChunk(VMRuntime rt, MethodDef method) { 22 | return new SMCBlockChunk(rt, method, this); 23 | } 24 | } 25 | 26 | internal class SMCBlockChunk : BasicBlockChunk, IKoiChunk { 27 | public SMCBlockChunk(VMRuntime rt, MethodDef method, SMCBlock block) 28 | : base(rt, method, block) { 29 | block.CounterOperand.Value = Length + 1; 30 | } 31 | 32 | uint IKoiChunk.Length { 33 | get { return base.Length + 1; } 34 | } 35 | 36 | void IKoiChunk.OnOffsetComputed(uint offset) { 37 | base.OnOffsetComputed(offset + 1); 38 | } 39 | 40 | byte[] IKoiChunk.GetData() { 41 | byte[] data = GetData(); 42 | byte[] newData = new byte[data.Length + 1]; 43 | byte key = ((SMCBlock)Block).Key; 44 | 45 | for (int i = 0; i < data.Length; i++) 46 | newData[i + 1] = (byte)(data[i] ^ key); 47 | newData[0] = key; 48 | return newData; 49 | } 50 | } 51 | 52 | internal class SMCBlockRef : ILRelReference { 53 | public SMCBlockRef(IHasOffset target, IHasOffset relBase, uint key) 54 | : base(target, relBase) { 55 | Key = key; 56 | } 57 | 58 | public uint Key { get; set; } 59 | 60 | public override uint Resolve(VMRuntime runtime) { 61 | return base.Resolve(runtime) ^ Key; 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /KoiVM/VMIR/Transforms/LogicTransform.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.AST.IR; 3 | 4 | namespace KoiVM.VMIR.Transforms { 5 | public class LogicTransform : ITransform { 6 | public void Initialize(IRTransformer tr) { 7 | } 8 | 9 | public void Transform(IRTransformer tr) { 10 | tr.Instructions.VisitInstrs(VisitInstr, tr); 11 | } 12 | 13 | void VisitInstr(IRInstrList instrs, IRInstruction instr, ref int index, IRTransformer tr) { 14 | if (instr.OpCode == IROpCode.__NOT) { 15 | instrs.Replace(index, new[] { 16 | new IRInstruction(IROpCode.NOR, instr.Operand1, instr.Operand1, instr) 17 | }); 18 | } 19 | else if (instr.OpCode == IROpCode.__AND) { 20 | var tmp = tr.Context.AllocateVRegister(instr.Operand2.Type); 21 | instrs.Replace(index, new[] { 22 | new IRInstruction(IROpCode.MOV, tmp, instr.Operand2, instr), 23 | new IRInstruction(IROpCode.NOR, instr.Operand1, instr.Operand1, instr), 24 | new IRInstruction(IROpCode.NOR, tmp, tmp, instr), 25 | new IRInstruction(IROpCode.NOR, instr.Operand1, tmp, instr) 26 | }); 27 | } 28 | else if (instr.OpCode == IROpCode.__OR) { 29 | instrs.Replace(index, new[] { 30 | new IRInstruction(IROpCode.NOR, instr.Operand1, instr.Operand2, instr), 31 | new IRInstruction(IROpCode.NOR, instr.Operand1, instr.Operand1, instr) 32 | }); 33 | } 34 | else if (instr.OpCode == IROpCode.__XOR) { 35 | var tmp1 = tr.Context.AllocateVRegister(instr.Operand2.Type); 36 | var tmp2 = tr.Context.AllocateVRegister(instr.Operand2.Type); 37 | instrs.Replace(index, new[] { 38 | new IRInstruction(IROpCode.MOV, tmp1, instr.Operand1, instr), 39 | new IRInstruction(IROpCode.NOR, tmp1, instr.Operand2, instr), 40 | new IRInstruction(IROpCode.MOV, tmp2, instr.Operand2, instr), 41 | new IRInstruction(IROpCode.NOR, instr.Operand1, instr.Operand1, instr), 42 | new IRInstruction(IROpCode.NOR, tmp2, tmp2, instr), 43 | new IRInstruction(IROpCode.NOR, instr.Operand1, tmp2, instr), 44 | new IRInstruction(IROpCode.NOR, instr.Operand1, tmp1, instr) 45 | }); 46 | } 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /KoiVM/VMIL/Transforms/SaveRegistersTransform.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using KoiVM.AST; 6 | using KoiVM.AST.IL; 7 | using KoiVM.AST.IR; 8 | using KoiVM.VM; 9 | 10 | namespace KoiVM.VMIL.Transforms { 11 | public class SaveRegistersTransform : IPostTransform { 12 | HashSet saveRegs; 13 | 14 | public void Initialize(ILPostTransformer tr) { 15 | saveRegs = tr.Runtime.Descriptor.Data.LookupInfo(tr.Method).UsedRegister; 16 | } 17 | 18 | public void Transform(ILPostTransformer tr) { 19 | tr.Instructions.VisitInstrs(VisitInstr, tr); 20 | } 21 | 22 | void VisitInstr(ILInstrList instrs, ILInstruction instr, ref int index, ILPostTransformer tr) { 23 | if (instr.OpCode != ILOpCode.__BEGINCALL && instr.OpCode != ILOpCode.__ENDCALL) 24 | return; 25 | 26 | var callInfo = (InstrCallInfo)instr.Annotation; 27 | if (callInfo.IsECall) { 28 | instrs.RemoveAt(index); 29 | index--; 30 | return; 31 | } 32 | 33 | var saving = new HashSet(saveRegs); 34 | var retVar = (IRVariable)callInfo.ReturnValue; 35 | // R0 = return register, need to save if retVar register is not R0 36 | Debug.Assert(!(retVar == null ^ (callInfo.ReturnRegister == null ^ callInfo.ReturnSlot == null))); 37 | if (retVar != null) { 38 | if (callInfo.ReturnSlot == null) { 39 | var retReg = callInfo.ReturnRegister.Register; 40 | saving.Remove(retReg); 41 | if (retReg != VMRegisters.R0) 42 | saving.Add(VMRegisters.R0); 43 | } 44 | else 45 | saving.Add(VMRegisters.R0); 46 | } 47 | else 48 | saving.Add(VMRegisters.R0); 49 | 50 | if (instr.OpCode == ILOpCode.__BEGINCALL) { 51 | instrs.Replace(index, saving 52 | .Select(reg => new ILInstruction(ILOpCode.PUSHR_OBJECT, ILRegister.LookupRegister(reg), instr))); 53 | } 54 | else { 55 | instrs.Replace(index, saving 56 | .Select(reg => new ILInstruction(ILOpCode.POP, ILRegister.LookupRegister(reg), instr)) 57 | .Reverse()); 58 | } 59 | index--; 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /KoiVM/RT/Mutation/RuntimePatcher.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using dnlib.DotNet; 4 | using dnlib.DotNet.Emit; 5 | 6 | namespace KoiVM.RT.Mutation { 7 | [Obfuscation(Exclude = false, Feature = "+koi;-ref proxy")] 8 | internal static class RuntimePatcher { 9 | public static void Patch(ModuleDef runtime, bool debug, bool stackwalk) { 10 | PatchDispatcher(runtime, debug, stackwalk); 11 | } 12 | 13 | static void PatchDispatcher(ModuleDef runtime, bool debug, bool stackwalk) { 14 | var dispatcher = runtime.Find(RTMap.VMDispatcher, true); 15 | var dispatcherRun = dispatcher.FindMethod(RTMap.VMRun); 16 | foreach (var eh in dispatcherRun.Body.ExceptionHandlers) { 17 | if (eh.HandlerType == ExceptionHandlerType.Catch) 18 | eh.CatchType = runtime.CorLibTypes.Object.ToTypeDefOrRef(); 19 | } 20 | PatchDoThrow(dispatcher.FindMethod(RTMap.VMDispatcherDothrow).Body, debug, stackwalk); 21 | dispatcher.Methods.Remove(dispatcher.FindMethod(RTMap.VMDispatcherThrow)); 22 | } 23 | 24 | static void PatchDoThrow(CilBody body, bool debug, bool stackwalk) { 25 | for (int i = 0; i < body.Instructions.Count; i++) { 26 | var method = body.Instructions[i].Operand as IMethod; 27 | if (method != null && method.Name == RTMap.VMDispatcherThrow) { 28 | body.Instructions.RemoveAt(i); 29 | } 30 | else if (method != null && method.Name == RTMap.VMDispatcherGetIP) { 31 | if (!debug) { 32 | body.Instructions.RemoveAt(i); 33 | body.Instructions[i - 1].OpCode = OpCodes.Ldnull; 34 | var def = method.ResolveMethodDefThrow(); 35 | def.DeclaringType.Methods.Remove(def); 36 | } 37 | else if (stackwalk) { 38 | var def = method.ResolveMethodDefThrow(); 39 | body.Instructions[i].Operand = def.DeclaringType.FindMethod(RTMap.VMDispatcherStackwalk); 40 | def.DeclaringType.Methods.Remove(def); 41 | } 42 | else { 43 | var def = method.ResolveMethodDefThrow(); 44 | def = def.DeclaringType.FindMethod(RTMap.VMDispatcherStackwalk); 45 | def.DeclaringType.Methods.Remove(def); 46 | } 47 | } 48 | } 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/OpCodes/FConv.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.Runtime.Dynamic; 3 | using KoiVM.Runtime.Execution; 4 | 5 | namespace KoiVM.Runtime.OpCodes { 6 | internal class FConvR32 : IOpCode { 7 | public byte Code { 8 | get { return Constants.OP_FCONV_R32; } 9 | } 10 | 11 | public void Run(VMContext ctx, out ExecutionState state) { 12 | var sp = ctx.Registers[Constants.REG_SP].U4; 13 | var valueSlot = ctx.Stack[sp]; 14 | 15 | valueSlot.R4 = (long)valueSlot.U8; 16 | 17 | ctx.Stack[sp] = valueSlot; 18 | 19 | state = ExecutionState.Next; 20 | } 21 | } 22 | 23 | internal class FConvR64 : IOpCode { 24 | public byte Code { 25 | get { return Constants.OP_FCONV_R64; } 26 | } 27 | 28 | public void Run(VMContext ctx, out ExecutionState state) { 29 | var sp = ctx.Registers[Constants.REG_SP].U4; 30 | var valueSlot = ctx.Stack[sp]; 31 | 32 | byte fl = ctx.Registers[Constants.REG_FL].U1; 33 | if ((fl & Constants.FL_UNSIGNED) != 0) { 34 | valueSlot.R8 = valueSlot.U8; 35 | } 36 | else { 37 | valueSlot.R8 = (long)valueSlot.U8; 38 | } 39 | ctx.Registers[Constants.REG_FL].U1 = (byte)(fl & ~Constants.FL_UNSIGNED); 40 | 41 | ctx.Stack[sp] = valueSlot; 42 | 43 | state = ExecutionState.Next; 44 | } 45 | } 46 | 47 | internal class FConvR32R64 : IOpCode { 48 | public byte Code { 49 | get { return Constants.OP_FCONV_R32_R64; } 50 | } 51 | 52 | public void Run(VMContext ctx, out ExecutionState state) { 53 | var sp = ctx.Registers[Constants.REG_SP].U4; 54 | var valueSlot = ctx.Stack[sp]; 55 | valueSlot.R8 = valueSlot.R4; 56 | ctx.Stack[sp] = valueSlot; 57 | 58 | state = ExecutionState.Next; 59 | } 60 | } 61 | 62 | internal class FConvR64R32 : IOpCode { 63 | public byte Code { 64 | get { return Constants.OP_FCONV_R64_R32; } 65 | } 66 | 67 | public void Run(VMContext ctx, out ExecutionState state) { 68 | var sp = ctx.Registers[Constants.REG_SP].U4; 69 | var valueSlot = ctx.Stack[sp]; 70 | valueSlot.R4 = (float)valueSlot.R8; 71 | ctx.Stack[sp] = valueSlot; 72 | 73 | state = ExecutionState.Next; 74 | } 75 | } 76 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/OpCodes/Shr.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.Runtime.Dynamic; 3 | using KoiVM.Runtime.Execution; 4 | 5 | namespace KoiVM.Runtime.OpCodes { 6 | internal class ShrDword : IOpCode { 7 | public byte Code { 8 | get { return Constants.OP_SHR_DWORD; } 9 | } 10 | 11 | public void Run(VMContext ctx, out ExecutionState state) { 12 | var sp = ctx.Registers[Constants.REG_SP].U4; 13 | var op1Slot = ctx.Stack[sp - 1]; 14 | var op2Slot = ctx.Stack[sp]; 15 | sp -= 1; 16 | ctx.Stack.SetTopPosition(sp); 17 | ctx.Registers[Constants.REG_SP].U4 = sp; 18 | 19 | var fl = ctx.Registers[Constants.REG_FL].U1; 20 | var slot = new VMSlot(); 21 | if ((fl & Constants.FL_UNSIGNED) != 0) 22 | slot.U4 = op1Slot.U4 >> (int)op2Slot.U4; 23 | else 24 | slot.U4 = (uint)((int)op1Slot.U4 >> (int)op2Slot.U4); 25 | ctx.Stack[sp] = slot; 26 | 27 | byte mask = (byte)(Constants.FL_ZERO | Constants.FL_SIGN | Constants.FL_UNSIGNED); 28 | Utils.UpdateFL(op1Slot.U4, op2Slot.U4, slot.U4, slot.U4, ref fl, mask); 29 | ctx.Registers[Constants.REG_FL].U1 = fl; 30 | 31 | state = ExecutionState.Next; 32 | } 33 | } 34 | 35 | internal class ShrQword : IOpCode { 36 | public byte Code { 37 | get { return Constants.OP_SHR_QWORD; } 38 | } 39 | 40 | public void Run(VMContext ctx, out ExecutionState state) { 41 | var sp = ctx.Registers[Constants.REG_SP].U4; 42 | var op1Slot = ctx.Stack[sp - 1]; 43 | var op2Slot = ctx.Stack[sp]; 44 | sp -= 1; 45 | ctx.Stack.SetTopPosition(sp); 46 | ctx.Registers[Constants.REG_SP].U4 = sp; 47 | 48 | var fl = ctx.Registers[Constants.REG_FL].U1; 49 | var slot = new VMSlot(); 50 | if ((fl & Constants.FL_UNSIGNED) != 0) 51 | slot.U8 = op1Slot.U8 >> (int)op2Slot.U4; 52 | else 53 | slot.U8 = (ulong)((long)op1Slot.U8 >> (int)op2Slot.U4); 54 | ctx.Stack[sp] = slot; 55 | 56 | byte mask = (byte)(Constants.FL_ZERO | Constants.FL_SIGN | Constants.FL_UNSIGNED); 57 | Utils.UpdateFL(op1Slot.U8, op2Slot.U8, slot.U8, slot.U8, ref fl, mask); 58 | ctx.Registers[Constants.REG_FL].U1 = fl; 59 | 60 | state = ExecutionState.Next; 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/VCalls/Ldftn.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Reflection; 4 | using KoiVM.Runtime.Dynamic; 5 | using KoiVM.Runtime.Execution; 6 | using KoiVM.Runtime.Execution.Internal; 7 | 8 | namespace KoiVM.Runtime.VCalls { 9 | internal class Ldftn : IVCall { 10 | public byte Code { 11 | get { return Constants.VCALL_LDFTN; } 12 | } 13 | 14 | public void Run(VMContext ctx, out ExecutionState state) { 15 | var sp = ctx.Registers[Constants.REG_SP].U4; 16 | var methodSlot = ctx.Stack[sp--]; 17 | var objectSlot = ctx.Stack[sp]; 18 | 19 | if (objectSlot.O != null) { 20 | var method = (MethodInfo)ctx.Instance.Data.LookupReference(methodSlot.U4); 21 | var type = objectSlot.O.GetType(); 22 | 23 | var baseTypes = new List(); 24 | do { 25 | baseTypes.Add(type); 26 | type = type.BaseType; 27 | } while (type != null && type != method.DeclaringType); 28 | baseTypes.Reverse(); 29 | 30 | MethodInfo found = method; 31 | const BindingFlags fl = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance; 32 | foreach (var baseType in baseTypes) { 33 | foreach (var m in baseType.GetMethods(fl)) 34 | if (m.GetBaseDefinition() == found) { 35 | found = m; 36 | break; 37 | } 38 | } 39 | 40 | ctx.Stack[sp] = new VMSlot { U8 = (ulong)found.MethodHandle.GetFunctionPointer() }; 41 | } 42 | if (objectSlot.U8 != 0) { 43 | // intra linking 44 | var entryKey = ctx.Stack[--sp].U4; 45 | var codeAdr = methodSlot.U8; 46 | var sig = ctx.Instance.Data.LookupExport(objectSlot.U4).Signature; 47 | var ptr = VMTrampoline.CreateTrampoline(ctx.Instance.Data.Module, codeAdr, entryKey, sig, objectSlot.U4); 48 | ctx.Stack[sp] = new VMSlot { U8 = (ulong)ptr }; 49 | } 50 | else { 51 | var method = (MethodBase)ctx.Instance.Data.LookupReference(methodSlot.U4); 52 | ctx.Stack[sp] = new VMSlot { U8 = (ulong)method.MethodHandle.GetFunctionPointer() }; 53 | } 54 | 55 | ctx.Stack.SetTopPosition(sp); 56 | ctx.Registers[Constants.REG_SP].U4 = sp; 57 | state = ExecutionState.Next; 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/Utils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.Runtime.Dynamic; 3 | 4 | namespace KoiVM.Runtime { 5 | internal static unsafe class Utils { 6 | public static uint ReadCompressedUInt(ref byte* ptr) { 7 | uint num = 0; 8 | int shift = 0; 9 | do { 10 | num |= (*ptr & 0x7fu) << shift; 11 | shift += 7; 12 | } while ((*ptr++ & 0x80) != 0); 13 | return num; 14 | } 15 | 16 | public static uint FromCodedToken(uint codedToken) { 17 | uint rid = codedToken >> 3; 18 | switch (codedToken & 7) { 19 | case 1: 20 | return rid | 0x02000000; 21 | case 2: 22 | return rid | 0x01000000; 23 | case 3: 24 | return rid | 0x1b000000; 25 | case 4: 26 | return rid | 0x0a000000; 27 | case 5: 28 | return rid | 0x06000000; 29 | case 6: 30 | return rid | 0x04000000; 31 | case 7: 32 | return rid | 0x2b000000; 33 | } 34 | return rid; 35 | } 36 | 37 | // https://github.com/copy/v86/blob/master/src/misc_instr.macro.js 38 | public static void UpdateFL(uint op1, uint op2, uint flResult, uint result, ref byte fl, byte mask) { 39 | const ulong SignMask = (1U << 31); 40 | byte flag = 0; 41 | if (result == 0) 42 | flag |= Constants.FL_ZERO; 43 | if ((result & SignMask) != 0) 44 | flag |= Constants.FL_SIGN; 45 | if (((op1 ^ flResult) & (op2 ^ flResult) & SignMask) != 0) 46 | flag |= Constants.FL_OVERFLOW; 47 | if (((op1 ^ (op1 ^ op2) & (op2 ^ flResult)) & SignMask) != 0) 48 | flag |= Constants.FL_CARRY; 49 | fl = (byte)((fl & ~mask) | (flag & mask)); 50 | } 51 | 52 | public static void UpdateFL(ulong op1, ulong op2, ulong flResult, ulong result, ref byte fl, byte mask) { 53 | const ulong SignMask = (1U << 63); 54 | byte flag = 0; 55 | if (result == 0) 56 | flag |= Constants.FL_ZERO; 57 | if ((result & SignMask) != 0) 58 | flag |= Constants.FL_SIGN; 59 | if (((op1 ^ flResult) & (op2 ^ flResult) & SignMask) != 0) 60 | flag |= Constants.FL_OVERFLOW; 61 | if (((op1 ^ (op1 ^ op2) & (op2 ^ flResult)) & SignMask) != 0) 62 | flag |= Constants.FL_CARRY; 63 | fl = (byte)((fl & ~mask) | (flag & mask)); 64 | } 65 | } 66 | } -------------------------------------------------------------------------------- /KoiVM/VMIR/IRTransformer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using KoiVM.AST.IR; 4 | using KoiVM.CFG; 5 | using KoiVM.RT; 6 | using KoiVM.VM; 7 | using KoiVM.VMIR.Transforms; 8 | 9 | namespace KoiVM.VMIR { 10 | public class IRTransformer { 11 | ITransform[] pipeline; 12 | 13 | public IRTransformer(ScopeBlock rootScope, IRContext ctx, VMRuntime runtime) { 14 | RootScope = rootScope; 15 | Context = ctx; 16 | Runtime = runtime; 17 | 18 | Annotations = new Dictionary(); 19 | InitPipeline(); 20 | } 21 | 22 | void InitPipeline() { 23 | pipeline = new ITransform[] { 24 | // new SMCIRTransform(), 25 | Context.IsRuntime ? null : new GuardBlockTransform(), 26 | Context.IsRuntime ? null : new EHTransform(), 27 | new InitLocalTransform(), 28 | new ConstantTypePromotionTransform(), 29 | new GetSetFlagTransform(), 30 | new LogicTransform(), 31 | new InvokeTransform(), 32 | new MetadataTransform(), 33 | Context.IsRuntime ? null : new RegisterAllocationTransform(), 34 | Context.IsRuntime ? null : new StackFrameTransform(), 35 | new LeaTransform(), 36 | Context.IsRuntime ? null : new MarkReturnRegTransform() 37 | }; 38 | } 39 | 40 | public IRContext Context { get; private set; } 41 | public VMRuntime Runtime { get; private set; } 42 | 43 | public VMDescriptor VM { 44 | get { return Runtime.Descriptor; } 45 | } 46 | 47 | public ScopeBlock RootScope { get; private set; } 48 | 49 | internal Dictionary Annotations { get; private set; } 50 | internal BasicBlock Block { get; private set; } 51 | 52 | internal IRInstrList Instructions { 53 | get { return Block.Content; } 54 | } 55 | 56 | public void Transform() { 57 | if (pipeline == null) 58 | throw new InvalidOperationException("Transformer already used."); 59 | 60 | foreach (var handler in pipeline) { 61 | if (handler == null) 62 | continue; 63 | handler.Initialize(this); 64 | 65 | RootScope.ProcessBasicBlocks(block => { 66 | Block = block; 67 | handler.Transform(this); 68 | }); 69 | } 70 | 71 | pipeline = null; 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /KoiVM.Confuser/KoiSystem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Net; 4 | using System.Text; 5 | 6 | namespace KoiVM.Confuser { 7 | internal class KoiSystem { 8 | public event Action Finish; 9 | public event Action Progress; 10 | 11 | uint Hash(string value) { 12 | uint hash = 0; 13 | for (int i = 0; i < value.Length; i++) 14 | hash = (uint)value[i] ^ (hash * 33); 15 | return hash; 16 | } 17 | 18 | public string GetVersion(string koiId) { 19 | try { 20 | #if DEBUG || __TRACE 21 | const string VER_URI = @"http://ki.no-ip.info/koi/{0}/VERSION"; 22 | #else 23 | const string VER_URI = @"https://ki-host.appspot.com/KoiVM/koi/{0}/VERSION"; 24 | #endif 25 | var verUri = new Uri(string.Format(VER_URI, koiId)); 26 | WebClient client = new WebClient(); 27 | var data = client.DownloadData(verUri); 28 | 29 | var rc4 = new RC4(Encoding.UTF8.GetBytes(koiId)); 30 | rc4.Crypt(data, 0, data.Length); 31 | var ver = Encoding.UTF8.GetString(data); 32 | 33 | if (Hash(ver) == 0x4c3e88e4) // REVOKED 34 | File.Delete(Path.Combine(KoiInfo.KoiDirectory, "koi.pack")); 35 | 36 | return ver; 37 | } 38 | catch { 39 | return null; 40 | } 41 | } 42 | 43 | public void Login(string koiId) { 44 | try { 45 | #if DEBUG || __TRACE 46 | const string PACK_URI = @"http://ki.no-ip.info/koi/{0}/koi.pack"; 47 | #else 48 | const string PACK_URI = @"https://ki-host.appspot.com/KoiVM/koi/{0}/koi.pack"; 49 | #endif 50 | var pack = new Uri(string.Format(PACK_URI, koiId)); 51 | WebClient client = new WebClient(); 52 | var file = Path.Combine(KoiInfo.KoiDirectory, "koi.pack"); 53 | 54 | client.DownloadProgressChanged += (sender, e) => { 55 | double progressValue = (double)e.BytesReceived / e.TotalBytesToReceive; 56 | if (e.TotalBytesToReceive == -1) 57 | progressValue = 0; 58 | Progress(progressValue); 59 | }; 60 | 61 | client.DownloadFileCompleted += (sender, e) => { 62 | if (e.Error != null) { 63 | if (File.Exists(file)) 64 | File.Delete(file); 65 | } 66 | Finish(e.Error == null); 67 | }; 68 | 69 | if (File.Exists(file)) 70 | File.Delete(file); 71 | client.DownloadFileAsync(pack, file); 72 | } 73 | catch { 74 | Finish(false); 75 | } 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/OpCodes/Jmp.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.Runtime.Dynamic; 3 | using KoiVM.Runtime.Execution; 4 | 5 | namespace KoiVM.Runtime.OpCodes { 6 | internal class Jmp : IOpCode { 7 | public byte Code { 8 | get { return Constants.OP_JMP; } 9 | } 10 | 11 | public void Run(VMContext ctx, out ExecutionState state) { 12 | var sp = ctx.Registers[Constants.REG_SP].U4; 13 | var slot = ctx.Stack[sp]; 14 | ctx.Stack.SetTopPosition(--sp); 15 | ctx.Registers[Constants.REG_SP].U4 = sp; 16 | 17 | ctx.Registers[Constants.REG_IP].U8 = slot.U8; 18 | state = ExecutionState.Next; 19 | } 20 | } 21 | 22 | internal class Jz : IOpCode { 23 | public byte Code { 24 | get { return Constants.OP_JZ; } 25 | } 26 | 27 | public void Run(VMContext ctx, out ExecutionState state) { 28 | var sp = ctx.Registers[Constants.REG_SP].U4; 29 | var adrSlot = ctx.Stack[sp]; 30 | var valSlot = ctx.Stack[sp - 1]; 31 | sp -= 2; 32 | ctx.Stack.SetTopPosition(sp); 33 | ctx.Registers[Constants.REG_SP].U4 = sp; 34 | 35 | if (valSlot.U8 == 0) 36 | ctx.Registers[Constants.REG_IP].U8 = adrSlot.U8; 37 | state = ExecutionState.Next; 38 | } 39 | } 40 | 41 | internal class Jnz : IOpCode { 42 | public byte Code { 43 | get { return Constants.OP_JNZ; } 44 | } 45 | 46 | public void Run(VMContext ctx, out ExecutionState state) { 47 | var sp = ctx.Registers[Constants.REG_SP].U4; 48 | var adrSlot = ctx.Stack[sp]; 49 | var valSlot = ctx.Stack[sp - 1]; 50 | sp -= 2; 51 | ctx.Stack.SetTopPosition(sp); 52 | ctx.Registers[Constants.REG_SP].U4 = sp; 53 | 54 | if (valSlot.U8 != 0) 55 | ctx.Registers[Constants.REG_IP].U8 = adrSlot.U8; 56 | state = ExecutionState.Next; 57 | } 58 | } 59 | 60 | internal class Swt : IOpCode { 61 | public byte Code { 62 | get { return Constants.OP_SWT; } 63 | } 64 | 65 | public unsafe void Run(VMContext ctx, out ExecutionState state) { 66 | var sp = ctx.Registers[Constants.REG_SP].U4; 67 | var tblSlot = ctx.Stack[sp]; 68 | var valSlot = ctx.Stack[sp - 1]; 69 | sp -= 2; 70 | ctx.Stack.SetTopPosition(sp); 71 | ctx.Registers[Constants.REG_SP].U4 = sp; 72 | 73 | uint index = valSlot.U4; 74 | ushort len = *(ushort*)(tblSlot.U8 - 2); 75 | if (index < len) 76 | ctx.Registers[Constants.REG_IP].U8 += (ulong)(int)((uint*)tblSlot.U8)[index]; 77 | state = ExecutionState.Next; 78 | } 79 | } 80 | } -------------------------------------------------------------------------------- /KoiVM.Confuser/SimpleSettings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | 5 | namespace KoiVM.Confuser { 6 | internal class SimpleSettings { 7 | readonly SortedDictionary values; 8 | bool changed; 9 | 10 | public SimpleSettings() { 11 | values = new SortedDictionary(StringComparer.InvariantCultureIgnoreCase); 12 | string cfgFile = Path.Combine(KoiInfo.KoiDirectory, "koi.cfg"); 13 | if (File.Exists(cfgFile)) 14 | using (var rdr = new StreamReader(File.OpenRead(cfgFile))) { 15 | string line; 16 | int lineNum = 1; 17 | while ((line = rdr.ReadLine()) != null) { 18 | if (string.IsNullOrEmpty(line)) 19 | continue; 20 | int i = line.IndexOf(":"); 21 | if (i == -1) { 22 | throw new ArgumentException("Invalid settings."); 23 | } 24 | string val = line.Substring(i + 1); 25 | 26 | values.Add(line.Substring(0, i), 27 | val.Equals("null", StringComparison.InvariantCultureIgnoreCase) ? null : val); 28 | lineNum++; 29 | } 30 | } 31 | } 32 | 33 | public string GetValue(string key, string def) { 34 | string ret; 35 | if (!values.TryGetValue(key, out ret)) { 36 | if (def == null) { 37 | throw new ArgumentException(string.Format("'{0}' does not exist in settings.", key)); 38 | } 39 | ret = values[key] = def; 40 | changed = true; 41 | } 42 | return ret; 43 | } 44 | 45 | public T GetValue(string key, string def) { 46 | string ret; 47 | if (!values.TryGetValue(key, out ret)) { 48 | if (def == null) { 49 | throw new ArgumentException(string.Format("'{0}' does not exist in settings.", key)); 50 | } 51 | ret = values[key] = def; 52 | changed = true; 53 | } 54 | return (T)Convert.ChangeType(ret, typeof(T)); 55 | } 56 | 57 | public void SetValue(string key, string val) { 58 | if (!values.ContainsKey(key) || values[key] != val) { 59 | values[key] = val; 60 | changed = true; 61 | } 62 | } 63 | 64 | public void Save() { 65 | if (!changed) return; 66 | string cfgFile = Path.Combine(KoiInfo.KoiDirectory, "koi.cfg"); 67 | using (var writer = new StreamWriter(File.Open(cfgFile, FileMode.Create, FileAccess.Write))) { 68 | foreach (var entry in values) 69 | writer.WriteLine("{0}:{1}", entry.Key, entry.Value ?? "null"); 70 | writer.Flush(); 71 | } 72 | changed = false; 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /KoiVM/VMIR/Translation/MiscHandlers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using dnlib.DotNet.Emit; 4 | using KoiVM.AST; 5 | using KoiVM.AST.ILAST; 6 | using KoiVM.AST.IR; 7 | 8 | namespace KoiVM.VMIR.Translation { 9 | public class DupHandler : ITranslationHandler { 10 | public Code ILCode { 11 | get { return Code.Dup; } 12 | } 13 | 14 | public IIROperand Translate(ILASTExpression expr, IRTranslator tr) { 15 | Debug.Assert(expr.Arguments.Length == 1); 16 | var ret = tr.Context.AllocateVRegister(expr.Type.Value); 17 | tr.Instructions.Add(new IRInstruction(IROpCode.MOV) { 18 | Operand1 = ret, 19 | Operand2 = tr.Translate(expr.Arguments[0]) 20 | }); 21 | return ret; 22 | } 23 | } 24 | 25 | public class NopHandler : ITranslationHandler { 26 | public Code ILCode { 27 | get { return Code.Nop; } 28 | } 29 | 30 | public IIROperand Translate(ILASTExpression expr, IRTranslator tr) { 31 | tr.Instructions.Add(new IRInstruction(IROpCode.NOP)); 32 | return null; 33 | } 34 | } 35 | 36 | public class BreakHandler : ITranslationHandler { 37 | public Code ILCode { 38 | get { return Code.Break; } 39 | } 40 | 41 | public IIROperand Translate(ILASTExpression expr, IRTranslator tr) { 42 | var ecallId = tr.VM.Runtime.VMCall.BREAK; 43 | tr.Instructions.Add(new IRInstruction(IROpCode.VCALL, IRConstant.FromI4(ecallId))); 44 | return null; 45 | } 46 | } 47 | 48 | public class CkfiniteHandler : ITranslationHandler { 49 | public Code ILCode { 50 | get { return Code.Ckfinite; } 51 | } 52 | 53 | public IIROperand Translate(ILASTExpression expr, IRTranslator tr) { 54 | Debug.Assert(expr.Arguments.Length == 1); 55 | var value = tr.Translate(expr.Arguments[0]); 56 | var ecallId = tr.VM.Runtime.VMCall.CKFINITE; 57 | if (value.Type == ASTType.R4) { 58 | tr.Instructions.Add(new IRInstruction(IROpCode.__SETF) { 59 | Operand1 = IRConstant.FromI4(1 << tr.Arch.Flags.UNSIGNED) 60 | }); 61 | } 62 | tr.Instructions.Add(new IRInstruction(IROpCode.VCALL, IRConstant.FromI4(ecallId), value)); 63 | return value; 64 | } 65 | } 66 | 67 | public class PopHandler : ITranslationHandler { 68 | public Code ILCode { 69 | get { return Code.Pop; } 70 | } 71 | 72 | public IIROperand Translate(ILASTExpression expr, IRTranslator tr) { 73 | Debug.Assert(expr.Arguments.Length == 1); 74 | tr.Translate(expr.Arguments[0]); 75 | return null; 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /KoiVM/VMIR/Translation/ConstantHandlers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using dnlib.DotNet; 3 | using dnlib.DotNet.Emit; 4 | using KoiVM.AST.ILAST; 5 | using KoiVM.AST.IR; 6 | 7 | namespace KoiVM.VMIR.Translation { 8 | public class LdcI4Handler : ITranslationHandler { 9 | public Code ILCode { 10 | get { return Code.Ldc_I4; } 11 | } 12 | 13 | public IIROperand Translate(ILASTExpression expr, IRTranslator tr) { 14 | return IRConstant.FromI4((int)expr.Operand); 15 | } 16 | } 17 | 18 | public class LdcI8Handler : ITranslationHandler { 19 | public Code ILCode { 20 | get { return Code.Ldc_I8; } 21 | } 22 | 23 | public IIROperand Translate(ILASTExpression expr, IRTranslator tr) { 24 | return IRConstant.FromI8((long)expr.Operand); 25 | } 26 | } 27 | 28 | public class LdcR4Handler : ITranslationHandler { 29 | public Code ILCode { 30 | get { return Code.Ldc_R4; } 31 | } 32 | 33 | public IIROperand Translate(ILASTExpression expr, IRTranslator tr) { 34 | return IRConstant.FromR4((float)expr.Operand); 35 | } 36 | } 37 | 38 | public class LdcR8Handler : ITranslationHandler { 39 | public Code ILCode { 40 | get { return Code.Ldc_R8; } 41 | } 42 | 43 | public IIROperand Translate(ILASTExpression expr, IRTranslator tr) { 44 | return IRConstant.FromR8((double)expr.Operand); 45 | } 46 | } 47 | 48 | public class LdnullHandler : ITranslationHandler { 49 | public Code ILCode { 50 | get { return Code.Ldnull; } 51 | } 52 | 53 | public IIROperand Translate(ILASTExpression expr, IRTranslator tr) { 54 | return IRConstant.Null(); 55 | } 56 | } 57 | 58 | public class LdstrHandler : ITranslationHandler { 59 | public Code ILCode { 60 | get { return Code.Ldstr; } 61 | } 62 | 63 | public IIROperand Translate(ILASTExpression expr, IRTranslator tr) { 64 | return IRConstant.FromString((string)expr.Operand); 65 | } 66 | } 67 | 68 | public class LdtokenHandler : ITranslationHandler { 69 | public Code ILCode { 70 | get { return Code.Ldtoken; } 71 | } 72 | 73 | public IIROperand Translate(ILASTExpression expr, IRTranslator tr) { 74 | var retVar = tr.Context.AllocateVRegister(expr.Type.Value); 75 | var refId = (int)tr.VM.Data.GetId((IMemberRef)expr.Operand); 76 | var ecallId = tr.VM.Runtime.VMCall.TOKEN; 77 | tr.Instructions.Add(new IRInstruction(IROpCode.VCALL, IRConstant.FromI4(ecallId), IRConstant.FromI4(refId))); 78 | tr.Instructions.Add(new IRInstruction(IROpCode.POP, retVar)); 79 | 80 | return retVar; 81 | } 82 | } 83 | } -------------------------------------------------------------------------------- /KoiVM/VMIR/Transforms/GuardBlockTransform.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KoiVM.AST.IR; 3 | using KoiVM.CFG; 4 | 5 | namespace KoiVM.VMIR.Transforms { 6 | public class GuardBlockTransform : ITransform { 7 | BasicBlock prolog; 8 | BasicBlock epilog; 9 | 10 | public void Initialize(IRTransformer tr) { 11 | int maxId = 0; 12 | BasicBlock entry = null; 13 | tr.RootScope.ProcessBasicBlocks(block => { 14 | block.Id++; 15 | if (block.Id > maxId) 16 | maxId = block.Id; 17 | if (entry == null) 18 | entry = block; 19 | }); 20 | 21 | prolog = new BasicBlock(0, new IRInstrList { 22 | new IRInstruction(IROpCode.__ENTRY), 23 | new IRInstruction(IROpCode.JMP, new IRBlockTarget(entry)) 24 | }); 25 | prolog.Targets.Add(entry); 26 | entry.Sources.Add(prolog); 27 | 28 | epilog = new BasicBlock(maxId + 1, new IRInstrList { 29 | new IRInstruction(IROpCode.__EXIT) 30 | }); 31 | InsertProlog(tr.RootScope); 32 | InsertEpilog(tr.RootScope); 33 | } 34 | 35 | void InsertProlog(ScopeBlock block) { 36 | if (block.Children.Count > 0) { 37 | if (block.Children[0].Type == ScopeType.None) 38 | InsertProlog(block.Children[0]); 39 | else { 40 | var prologScope = new ScopeBlock(); 41 | prologScope.Content.Add(prolog); 42 | block.Children.Insert(0, prologScope); 43 | } 44 | } 45 | else { 46 | block.Content.Insert(0, prolog); 47 | } 48 | } 49 | 50 | void InsertEpilog(ScopeBlock block) { 51 | if (block.Children.Count > 0) { 52 | if (block.Children[block.Children.Count - 1].Type == ScopeType.None) 53 | InsertEpilog(block.Children[block.Children.Count - 1]); 54 | else { 55 | var epilogScope = new ScopeBlock(); 56 | epilogScope.Content.Add(epilog); 57 | block.Children.Insert(block.Children.Count, epilogScope); 58 | } 59 | } 60 | else { 61 | block.Content.Insert(block.Content.Count, epilog); 62 | } 63 | } 64 | 65 | public void Transform(IRTransformer tr) { 66 | tr.Instructions.VisitInstrs(VisitInstr, tr); 67 | } 68 | 69 | void VisitInstr(IRInstrList instrs, IRInstruction instr, ref int index, IRTransformer tr) { 70 | if (instr.OpCode == IROpCode.RET) { 71 | instrs.Replace(index, new[] { 72 | new IRInstruction(IROpCode.JMP, new IRBlockTarget(epilog)) 73 | }); 74 | if (!tr.Block.Targets.Contains(epilog)) { 75 | tr.Block.Targets.Add(epilog); 76 | epilog.Sources.Add(tr.Block); 77 | } 78 | } 79 | } 80 | } 81 | } -------------------------------------------------------------------------------- /KoiVM/VMIR/Translation/FnPtrHandlers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using dnlib.DotNet; 4 | using dnlib.DotNet.Emit; 5 | using KoiVM.AST.ILAST; 6 | using KoiVM.AST.IR; 7 | 8 | namespace KoiVM.VMIR.Translation { 9 | public class LdftnHandler : ITranslationHandler { 10 | public Code ILCode { 11 | get { return Code.Ldftn; } 12 | } 13 | 14 | public IIROperand Translate(ILASTExpression expr, IRTranslator tr) { 15 | var retVar = tr.Context.AllocateVRegister(expr.Type.Value); 16 | 17 | var method = ((IMethod)expr.Operand).ResolveMethodDef(); 18 | 19 | bool intraLinking = method != null && tr.VM.Settings.IsVirtualized(method); 20 | var ecallId = tr.VM.Runtime.VMCall.LDFTN; 21 | if (intraLinking) { 22 | var sigId = (int)tr.VM.Data.GetId(method.DeclaringType, method.MethodSig); 23 | uint entryKey = tr.VM.Data.LookupInfo(method).EntryKey; 24 | entryKey = ((uint)tr.VM.Random.Next() & 0xffffff00) | entryKey; 25 | tr.Instructions.Add(new IRInstruction(IROpCode.PUSH, IRConstant.FromI4((int)entryKey))); 26 | tr.Instructions.Add(new IRInstruction(IROpCode.PUSH, IRConstant.FromI4(sigId))); 27 | tr.Instructions.Add(new IRInstruction(IROpCode.PUSH, new IRMetaTarget(method) { LateResolve = true })); 28 | tr.Instructions.Add(new IRInstruction(IROpCode.VCALL, IRConstant.FromI4(ecallId))); 29 | } 30 | else { 31 | var methodId = (int)tr.VM.Data.GetId((IMethod)expr.Operand); 32 | tr.Instructions.Add(new IRInstruction(IROpCode.PUSH, IRConstant.FromI4(0))); 33 | tr.Instructions.Add(new IRInstruction(IROpCode.VCALL, IRConstant.FromI4(ecallId), IRConstant.FromI4(methodId))); 34 | } 35 | tr.Instructions.Add(new IRInstruction(IROpCode.POP, retVar)); 36 | return retVar; 37 | } 38 | } 39 | 40 | public class LdvirtftnHandler : ITranslationHandler { 41 | public Code ILCode { 42 | get { return Code.Ldvirtftn; } 43 | } 44 | 45 | public IIROperand Translate(ILASTExpression expr, IRTranslator tr) { 46 | Debug.Assert(expr.Arguments.Length == 1); 47 | var retVar = tr.Context.AllocateVRegister(expr.Type.Value); 48 | var obj = tr.Translate(expr.Arguments[0]); 49 | 50 | var method = (IMethod)expr.Operand; 51 | var methodId = (int)tr.VM.Data.GetId(method); 52 | 53 | var ecallId = tr.VM.Runtime.VMCall.LDFTN; 54 | tr.Instructions.Add(new IRInstruction(IROpCode.PUSH, obj)); 55 | tr.Instructions.Add(new IRInstruction(IROpCode.VCALL, IRConstant.FromI4(ecallId), IRConstant.FromI4(methodId))); 56 | tr.Instructions.Add(new IRInstruction(IROpCode.POP, retVar)); 57 | return retVar; 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /KoiVM/RT/Mutation/Renamer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using dnlib.DotNet; 4 | 5 | namespace KoiVM.RT.Mutation { 6 | public class Renamer { 7 | public Renamer(int seed) { 8 | next = seed; 9 | } 10 | 11 | Dictionary nameMap = new Dictionary(); 12 | int next; 13 | 14 | string ToString(int id) { 15 | return id.ToString("x"); 16 | } 17 | 18 | string NewName(string name) { 19 | string newName; 20 | if (!nameMap.TryGetValue(name, out newName)) { 21 | nameMap[name] = newName = ToString(next); 22 | next = next * 0x19660D + 0x3C6EF35F; 23 | } 24 | return newName; 25 | } 26 | 27 | public void Process(ModuleDef module) { 28 | foreach (var type in module.GetTypes()) { 29 | if (!type.IsPublic) { 30 | type.Namespace = ""; 31 | type.Name = NewName(type.FullName); 32 | } 33 | foreach (var genParam in type.GenericParameters) 34 | genParam.Name = ""; 35 | 36 | bool isDelegate = type.BaseType != null && 37 | (type.BaseType.FullName == "System.Delegate" || 38 | type.BaseType.FullName == "System.MulticastDelegate"); 39 | 40 | foreach (var method in type.Methods) { 41 | if (method.HasBody) { 42 | foreach (var instr in method.Body.Instructions) { 43 | var memberRef = instr.Operand as MemberRef; 44 | if (memberRef != null) { 45 | var typeDef = memberRef.DeclaringType.ResolveTypeDef(); 46 | 47 | if (memberRef.IsMethodRef && typeDef != null) { 48 | var target = typeDef.ResolveMethod(memberRef); 49 | if (target != null && target.IsRuntimeSpecialName) 50 | typeDef = null; 51 | } 52 | 53 | if (typeDef != null && typeDef.Module == module) 54 | memberRef.Name = NewName(memberRef.Name); 55 | } 56 | } 57 | } 58 | 59 | foreach (var arg in method.Parameters) 60 | arg.Name = ""; 61 | if (method.IsRuntimeSpecialName || isDelegate || type.IsPublic) 62 | continue; 63 | method.Name = NewName(method.Name); 64 | method.CustomAttributes.Clear(); 65 | } 66 | for (int i = 0; i < type.Fields.Count; i++) { 67 | var field = type.Fields[i]; 68 | if (field.IsLiteral) { 69 | type.Fields.RemoveAt(i--); 70 | continue; 71 | } 72 | if (field.IsRuntimeSpecialName) 73 | continue; 74 | field.Name = NewName(field.Name); 75 | } 76 | type.Properties.Clear(); 77 | type.Events.Clear(); 78 | type.CustomAttributes.Clear(); 79 | } 80 | } 81 | } 82 | } -------------------------------------------------------------------------------- /KoiVM/MethodVirtualizer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using dnlib.DotNet; 4 | using KoiVM.CFG; 5 | using KoiVM.ILAST; 6 | using KoiVM.RT; 7 | using KoiVM.VMIL; 8 | using KoiVM.VMIR; 9 | 10 | namespace KoiVM { 11 | [Obfuscation(Exclude = false, Feature = "+koi;-ref proxy")] 12 | public class MethodVirtualizer { 13 | public MethodVirtualizer(VMRuntime runtime) { 14 | Runtime = runtime; 15 | } 16 | 17 | protected VMRuntime Runtime { get; private set; } 18 | protected MethodDef Method { get; private set; } 19 | protected ScopeBlock RootScope { get; private set; } 20 | protected IRContext IRContext { get; private set; } 21 | protected bool IsExport { get; private set; } 22 | 23 | public ScopeBlock Run(MethodDef method, bool isExport) { 24 | try { 25 | Method = method; 26 | IsExport = isExport; 27 | 28 | Init(); 29 | BuildILAST(); 30 | TransformILAST(); 31 | BuildVMIR(); 32 | TransformVMIR(); 33 | BuildVMIL(); 34 | TransformVMIL(); 35 | Deinitialize(); 36 | 37 | var scope = RootScope; 38 | RootScope = null; 39 | Method = null; 40 | return scope; 41 | } 42 | catch (Exception ex) { 43 | throw new Exception(string.Format("Failed to translate method {0}.", method), ex); 44 | } 45 | } 46 | 47 | protected virtual void Init() { 48 | RootScope = BlockParser.Parse(Method, Method.Body); 49 | IRContext = new IRContext(Method, Method.Body); 50 | } 51 | 52 | protected virtual void BuildILAST() { 53 | ILASTBuilder.BuildAST(Method, Method.Body, RootScope); 54 | } 55 | 56 | protected virtual void TransformILAST() { 57 | var transformer = new ILASTTransformer(Method, RootScope, Runtime); 58 | transformer.Transform(); 59 | } 60 | 61 | protected virtual void BuildVMIR() { 62 | var translator = new IRTranslator(IRContext, Runtime); 63 | translator.Translate(RootScope); 64 | } 65 | 66 | protected virtual void TransformVMIR() { 67 | var transformer = new IRTransformer(RootScope, IRContext, Runtime); 68 | transformer.Transform(); 69 | } 70 | 71 | protected virtual void BuildVMIL() { 72 | var translator = new ILTranslator(Runtime); 73 | translator.Translate(RootScope); 74 | } 75 | 76 | protected virtual void TransformVMIL() { 77 | var transformer = new ILTransformer(Method, RootScope, Runtime); 78 | transformer.Transform(); 79 | } 80 | 81 | protected virtual void Deinitialize() { 82 | IRContext = null; 83 | Runtime.AddMethod(Method, RootScope); 84 | if (IsExport) 85 | Runtime.ExportMethod(Method); 86 | } 87 | } 88 | } -------------------------------------------------------------------------------- /KoiVM/VMIL/ILTranslator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using KoiVM.AST.IL; 4 | using KoiVM.AST.IR; 5 | using KoiVM.CFG; 6 | using KoiVM.RT; 7 | using KoiVM.VM; 8 | using KoiVM.VMIR; 9 | 10 | namespace KoiVM.VMIL { 11 | public class ILTranslator { 12 | static ILTranslator() { 13 | handlers = new Dictionary(); 14 | foreach (var type in typeof(ILTranslator).Assembly.GetExportedTypes()) { 15 | if (typeof(ITranslationHandler).IsAssignableFrom(type) && !type.IsAbstract) { 16 | var handler = (ITranslationHandler)Activator.CreateInstance(type); 17 | handlers.Add(handler.IRCode, handler); 18 | } 19 | } 20 | } 21 | 22 | static readonly Dictionary handlers; 23 | 24 | public ILTranslator(VMRuntime runtime) { 25 | Runtime = runtime; 26 | } 27 | 28 | public VMRuntime Runtime { get; private set; } 29 | 30 | public VMDescriptor VM { 31 | get { return Runtime.Descriptor; } 32 | } 33 | 34 | internal ILInstrList Instructions { get; private set; } 35 | 36 | public ILInstrList Translate(IRInstrList instrs) { 37 | Instructions = new ILInstrList(); 38 | 39 | int i = 0; 40 | foreach (var instr in instrs) { 41 | ITranslationHandler handler; 42 | if (!handlers.TryGetValue(instr.OpCode, out handler)) 43 | throw new NotSupportedException(instr.OpCode.ToString()); 44 | try { 45 | handler.Translate(instr, this); 46 | } 47 | catch (Exception ex) { 48 | throw new Exception(string.Format("Failed to translate ir {0}.", instr.ILAST), ex); 49 | } 50 | while (i < Instructions.Count) { 51 | Instructions[i].IR = instr; 52 | i++; 53 | } 54 | } 55 | 56 | var ret = Instructions; 57 | Instructions = null; 58 | return ret; 59 | } 60 | 61 | public void Translate(ScopeBlock rootScope) { 62 | var blockMap = rootScope.UpdateBasicBlocks( 63 | block => { return Translate(block.Content); }, 64 | (id, content) => new ILBlock(id, content)); 65 | 66 | rootScope.ProcessBasicBlocks(block => { 67 | foreach (var instr in block.Content) { 68 | if (instr.Operand is ILBlockTarget) { 69 | var op = (ILBlockTarget)instr.Operand; 70 | op.Target = blockMap[(BasicBlock)op.Target]; 71 | } 72 | else if (instr.Operand is ILJumpTable) { 73 | var op = (ILJumpTable)instr.Operand; 74 | for (int i = 0; i < op.Targets.Length; i++) 75 | op.Targets[i] = blockMap[(BasicBlock)op.Targets[i]]; 76 | } 77 | } 78 | }); 79 | } 80 | } 81 | } -------------------------------------------------------------------------------- /KoiVM/Scanner.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using dnlib.DotNet; 4 | using dnlib.DotNet.Emit; 5 | 6 | namespace KoiVM { 7 | public class Scanner { 8 | ModuleDef module; 9 | HashSet methods; 10 | HashSet exclude = new HashSet(); 11 | HashSet export = new HashSet(); 12 | List> results = new List>(); 13 | 14 | public Scanner(ModuleDef module) 15 | : this(module, null) { 16 | } 17 | 18 | public Scanner(ModuleDef module, HashSet methods) { 19 | this.module = module; 20 | this.methods = methods; 21 | } 22 | 23 | public IEnumerable> Scan() { 24 | ScanMethods(FindExclusion); 25 | ScanMethods(ScanExport); 26 | ScanMethods(PopulateResult); 27 | return results; 28 | } 29 | 30 | void ScanMethods(Action scanFunc) { 31 | foreach (var type in module.GetTypes()) { 32 | foreach (var method in type.Methods) 33 | scanFunc(method); 34 | } 35 | } 36 | 37 | void FindExclusion(MethodDef method) { 38 | if (!method.HasBody || (methods != null && !methods.Contains(method))) 39 | exclude.Add(method); 40 | else if (method.HasGenericParameters) { 41 | foreach (var instr in method.Body.Instructions) { 42 | var target = instr.Operand as IMethod; 43 | if (target != null && target.IsMethod && 44 | (target = target.ResolveMethodDef()) != null && 45 | (methods == null || methods.Contains((MethodDef)target))) 46 | export.Add((MethodDef)target); 47 | } 48 | } 49 | } 50 | 51 | void ScanExport(MethodDef method) { 52 | if (!method.HasBody) 53 | return; 54 | 55 | bool shouldExport = false; 56 | shouldExport |= method.IsPublic; 57 | shouldExport |= method.SemanticsAttributes != 0; 58 | shouldExport |= method.IsConstructor; 59 | shouldExport |= method.IsVirtual; 60 | shouldExport |= (method.Module.EntryPoint == method); 61 | if (shouldExport) 62 | export.Add(method); 63 | 64 | bool excluded = exclude.Contains(method) || method.DeclaringType.HasGenericParameters; 65 | foreach (var instr in method.Body.Instructions) { 66 | if (instr.OpCode == OpCodes.Callvirt || 67 | (instr.Operand is IMethod && excluded)) { 68 | var target = ((IMethod)instr.Operand).ResolveMethodDef(); 69 | if (target != null && (methods == null || methods.Contains((MethodDef)target))) 70 | export.Add(target); 71 | } 72 | } 73 | } 74 | 75 | void PopulateResult(MethodDef method) { 76 | if (exclude.Contains(method) || method.DeclaringType.HasGenericParameters) 77 | return; 78 | results.Add(Tuple.Create(method, export.Contains(method))); 79 | } 80 | } 81 | } -------------------------------------------------------------------------------- /KoiVM/ILAST/Transformation/BranchTransform.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using dnlib.DotNet; 6 | using dnlib.DotNet.Emit; 7 | using KoiVM.AST; 8 | using KoiVM.AST.ILAST; 9 | 10 | namespace KoiVM.ILAST.Transformation { 11 | public class BranchTransform : ITransformationHandler { 12 | public void Initialize(ILASTTransformer tr) { 13 | } 14 | 15 | public void Transform(ILASTTransformer tr) { 16 | tr.Tree.TraverseTree(Transform, tr.Method.Module); 17 | } 18 | 19 | /* 20 | * Transform according to spec, identical effects 21 | * beq -> ceq; brtrue 22 | * bne.un -> ceq; brfalse 23 | * bge -> clt/clt.un; brfalse 24 | * bge.un -> clt.un/clt; brfalse (spec does not say?) 25 | * bgt -> cgt; brtrue 26 | * bgt.un -> cgt.un; brtrue 27 | * ble -> cgt/cgt.un; brfalse 28 | * ble.un -> cgt.un/cgt; brfalse 29 | * blt -> clt; brtrue 30 | * blt.un -> clt.un; brtrue 31 | */ 32 | 33 | static readonly Dictionary> transformMap = 34 | new Dictionary> { 35 | { Code.Beq, Tuple.Create(Code.Ceq, Code.Ceq, Code.Brtrue) }, 36 | { Code.Bne_Un, Tuple.Create(Code.Ceq, Code.Ceq, Code.Brfalse) }, 37 | { Code.Bge, Tuple.Create(Code.Clt, Code.Clt_Un, Code.Brfalse) }, 38 | { Code.Bge_Un, Tuple.Create(Code.Clt_Un, Code.Clt, Code.Brfalse) }, 39 | { Code.Ble, Tuple.Create(Code.Cgt, Code.Cgt_Un, Code.Brfalse) }, 40 | { Code.Ble_Un, Tuple.Create(Code.Cgt_Un, Code.Cgt, Code.Brfalse) }, 41 | { Code.Bgt, Tuple.Create(Code.Cgt, Code.Cgt, Code.Brtrue) }, 42 | { Code.Bgt_Un, Tuple.Create(Code.Cgt_Un, Code.Cgt_Un, Code.Brtrue) }, 43 | { Code.Blt, Tuple.Create(Code.Clt, Code.Clt, Code.Brtrue) }, 44 | { Code.Blt_Un, Tuple.Create(Code.Clt_Un, Code.Clt_Un, Code.Brtrue) } 45 | }; 46 | 47 | static void Transform(ILASTExpression expr, ModuleDef module) { 48 | switch (expr.ILCode) { 49 | case Code.Beq: 50 | case Code.Bne_Un: 51 | case Code.Bge: 52 | case Code.Bge_Un: 53 | case Code.Bgt: 54 | case Code.Bgt_Un: 55 | case Code.Ble: 56 | case Code.Ble_Un: 57 | case Code.Blt: 58 | case Code.Blt_Un: 59 | break; 60 | default: 61 | return; 62 | } 63 | Debug.Assert(expr.Arguments.Length == 2); 64 | var mapInfo = transformMap[expr.ILCode]; 65 | var isFloat = expr.Arguments.Any(arg => arg.Type.Value == ASTType.R4 || arg.Type.Value == ASTType.R8); 66 | var compCode = isFloat ? mapInfo.Item2 : mapInfo.Item1; 67 | 68 | expr.ILCode = mapInfo.Item3; 69 | expr.Arguments = new IILASTNode[] { 70 | new ILASTExpression { 71 | ILCode = compCode, 72 | Arguments = expr.Arguments, 73 | Type = ASTType.I4 74 | } 75 | }; 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /KoiVM/VMIR/Translation/BranchHandlers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using dnlib.DotNet.Emit; 4 | using KoiVM.AST; 5 | using KoiVM.AST.ILAST; 6 | using KoiVM.AST.IR; 7 | using KoiVM.CFG; 8 | 9 | namespace KoiVM.VMIR.Translation { 10 | public class BrHandler : ITranslationHandler { 11 | public Code ILCode { 12 | get { return Code.Br; } 13 | } 14 | 15 | public IIROperand Translate(ILASTExpression expr, IRTranslator tr) { 16 | tr.Instructions.Add(new IRInstruction(IROpCode.JMP) { 17 | Operand1 = new IRBlockTarget((IBasicBlock)expr.Operand) 18 | }); 19 | return null; 20 | } 21 | } 22 | 23 | public class BrtrueHandler : ITranslationHandler { 24 | public Code ILCode { 25 | get { return Code.Brtrue; } 26 | } 27 | 28 | public IIROperand Translate(ILASTExpression expr, IRTranslator tr) { 29 | Debug.Assert(expr.Arguments.Length == 1); 30 | 31 | var val = tr.Translate(expr.Arguments[0]); 32 | TranslationHelpers.EmitCompareEq(tr, expr.Arguments[0].Type.Value, val, IRConstant.FromI4(0)); 33 | var tmp = tr.Context.AllocateVRegister(ASTType.I4); 34 | tr.Instructions.Add(new IRInstruction(IROpCode.__GETF) { 35 | Operand1 = tmp, 36 | Operand2 = IRConstant.FromI4(1 << tr.Arch.Flags.ZERO) 37 | }); 38 | tr.Instructions.Add(new IRInstruction(IROpCode.JZ) { 39 | Operand1 = new IRBlockTarget((IBasicBlock)expr.Operand), 40 | Operand2 = tmp 41 | }); 42 | return null; 43 | } 44 | } 45 | 46 | public class BrfalseHandler : ITranslationHandler { 47 | public Code ILCode { 48 | get { return Code.Brfalse; } 49 | } 50 | 51 | public IIROperand Translate(ILASTExpression expr, IRTranslator tr) { 52 | Debug.Assert(expr.Arguments.Length == 1); 53 | 54 | var val = tr.Translate(expr.Arguments[0]); 55 | TranslationHelpers.EmitCompareEq(tr, expr.Arguments[0].Type.Value, val, IRConstant.FromI4(0)); 56 | var tmp = tr.Context.AllocateVRegister(ASTType.I4); 57 | tr.Instructions.Add(new IRInstruction(IROpCode.__GETF) { 58 | Operand1 = tmp, 59 | Operand2 = IRConstant.FromI4(1 << tr.Arch.Flags.ZERO) 60 | }); 61 | tr.Instructions.Add(new IRInstruction(IROpCode.JNZ) { 62 | Operand1 = new IRBlockTarget((IBasicBlock)expr.Operand), 63 | Operand2 = tmp 64 | }); 65 | return null; 66 | } 67 | } 68 | 69 | public class SwitchHandler : ITranslationHandler { 70 | public Code ILCode { 71 | get { return Code.Switch; } 72 | } 73 | 74 | public IIROperand Translate(ILASTExpression expr, IRTranslator tr) { 75 | Debug.Assert(expr.Arguments.Length == 1); 76 | 77 | var val = tr.Translate(expr.Arguments[0]); 78 | tr.Instructions.Add(new IRInstruction(IROpCode.SWT) { 79 | Operand1 = new IRJumpTable((IBasicBlock[])expr.Operand), 80 | Operand2 = val 81 | }); 82 | return null; 83 | } 84 | } 85 | } -------------------------------------------------------------------------------- /KoiVM.Runtime/Data/VMData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Reflection; 4 | using System.Runtime.InteropServices; 5 | 6 | namespace KoiVM.Runtime.Data { 7 | internal unsafe class VMData { 8 | [StructLayout(LayoutKind.Sequential)] 9 | struct VMDAT_HEADER { 10 | public uint MAGIC; 11 | public uint MD_COUNT; 12 | public uint STR_COUNT; 13 | public uint EXP_COUNT; 14 | } 15 | 16 | class RefInfo { 17 | public Module module; 18 | public int token; 19 | public MemberInfo resolved; 20 | 21 | public MemberInfo Member { 22 | get { return resolved ?? (resolved = module.ResolveMember(token)); } 23 | } 24 | } 25 | 26 | Dictionary references; 27 | Dictionary strings; 28 | Dictionary exports; 29 | 30 | static Dictionary moduleVMData = new Dictionary(); 31 | 32 | public Module Module { get; private set; } 33 | 34 | public VMData(Module module, void* data) { 35 | var header = (VMDAT_HEADER*)data; 36 | if (header->MAGIC != 0x68736966) 37 | throw new InvalidProgramException(); 38 | 39 | references = new Dictionary(); 40 | strings = new Dictionary(); 41 | exports = new Dictionary(); 42 | 43 | var ptr = (byte*)(header + 1); 44 | for (int i = 0; i < header->MD_COUNT; i++) { 45 | var id = Utils.ReadCompressedUInt(ref ptr); 46 | var token = (int)Utils.FromCodedToken(Utils.ReadCompressedUInt(ref ptr)); 47 | references[id] = new RefInfo { 48 | module = module, 49 | token = token 50 | }; 51 | } 52 | for (int i = 0; i < header->STR_COUNT; i++) { 53 | var id = Utils.ReadCompressedUInt(ref ptr); 54 | var len = Utils.ReadCompressedUInt(ref ptr); 55 | strings[id] = new string((char*)ptr, 0, (int)len); 56 | ptr += len << 1; 57 | } 58 | for (int i = 0; i < header->EXP_COUNT; i++) { 59 | exports[Utils.ReadCompressedUInt(ref ptr)] = new VMExportInfo(ref ptr, module); 60 | } 61 | 62 | KoiSection = (byte*)data; 63 | 64 | Module = module; 65 | moduleVMData[module] = this; 66 | } 67 | 68 | public static VMData Instance(Module module) { 69 | VMData data; 70 | lock (moduleVMData) { 71 | if (!moduleVMData.TryGetValue(module, out data)) 72 | data = moduleVMData[module] = VMDataInitializer.GetData(module); 73 | } 74 | return data; 75 | } 76 | 77 | public byte* KoiSection { get; set; } 78 | 79 | public MemberInfo LookupReference(uint id) { 80 | return references[id].Member; 81 | } 82 | 83 | public string LookupString(uint id) { 84 | if (id == 0) 85 | return null; 86 | return strings[id]; 87 | } 88 | 89 | public VMExportInfo LookupExport(uint id) { 90 | return exports[id]; 91 | } 92 | } 93 | } -------------------------------------------------------------------------------- /KoiVM/AST/TypeInference.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using dnlib.DotNet; 3 | 4 | namespace KoiVM.AST { 5 | public static class TypeInference { 6 | public static ASTType ToASTType(TypeSig type) { 7 | switch (type.ElementType) { 8 | case ElementType.I1: 9 | case ElementType.I2: 10 | case ElementType.I4: 11 | case ElementType.U1: 12 | case ElementType.U2: 13 | case ElementType.U4: 14 | case ElementType.Boolean: 15 | case ElementType.Char: 16 | return ASTType.I4; 17 | 18 | case ElementType.I8: 19 | case ElementType.U8: 20 | return ASTType.I8; 21 | 22 | case ElementType.R4: 23 | return ASTType.R4; 24 | 25 | case ElementType.R8: 26 | return ASTType.R8; 27 | 28 | case ElementType.I: 29 | case ElementType.U: 30 | case ElementType.FnPtr: 31 | case ElementType.Ptr: 32 | return ASTType.Ptr; 33 | 34 | case ElementType.ByRef: 35 | return ASTType.ByRef; 36 | 37 | case ElementType.ValueType: 38 | var typeDef = type.ScopeType.ResolveTypeDef(); 39 | if (typeDef != null && typeDef.IsEnum) 40 | return ToASTType(typeDef.GetEnumUnderlyingType()); 41 | return ASTType.O; 42 | 43 | default: 44 | return ASTType.O; 45 | } 46 | } 47 | 48 | public static ASTType InferBinaryOp(ASTType a, ASTType b) { 49 | if (a == b && (a == ASTType.I4 || a == ASTType.I8 || a == ASTType.R4 || a == ASTType.R8)) 50 | return a; 51 | // Here we sometimes uses I8 for Ptr 52 | if ((a == ASTType.Ptr && (b == ASTType.I4 || b == ASTType.I8 || b == ASTType.Ptr)) || 53 | (b == ASTType.Ptr && (a == ASTType.I4 || b == ASTType.I4 || a == ASTType.Ptr))) 54 | return ASTType.Ptr; 55 | if ((a == ASTType.ByRef && (b == ASTType.I4 || b == ASTType.Ptr)) || 56 | (b == ASTType.ByRef && (a == ASTType.I4 || a == ASTType.Ptr))) 57 | return ASTType.ByRef; 58 | if (a == ASTType.ByRef && b == ASTType.ByRef) 59 | return ASTType.Ptr; 60 | throw new ArgumentException("Invalid Binary Op Operand Types."); 61 | } 62 | 63 | public static ASTType InferIntegerOp(ASTType a, ASTType b) { 64 | if (a == b && (a == ASTType.I4 || a == ASTType.I8 || a == ASTType.R4 || a == ASTType.R8)) 65 | return a; 66 | // Here we sometimes uses I8 for Ptr 67 | if ((a == ASTType.Ptr && (b == ASTType.I4 || b == ASTType.I8 || b == ASTType.Ptr)) || 68 | (b == ASTType.Ptr && (a == ASTType.I4 || b == ASTType.I8 || a == ASTType.Ptr))) 69 | return ASTType.Ptr; 70 | throw new ArgumentException("Invalid Integer Op Operand Types."); 71 | } 72 | 73 | public static ASTType InferShiftOp(ASTType a, ASTType b) { 74 | if ((b == ASTType.Ptr || b == ASTType.I4) && 75 | (a == ASTType.I4 || b == ASTType.I4 || a == ASTType.Ptr)) 76 | return a; 77 | throw new ArgumentException("Invalid Shift Op Operand Types."); 78 | } 79 | } 80 | } -------------------------------------------------------------------------------- /KoiVM/VMIL/Translation/PseudoHandlers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using dnlib.DotNet; 3 | using KoiVM.AST; 4 | using KoiVM.AST.IL; 5 | using KoiVM.AST.IR; 6 | using KoiVM.VMIR; 7 | 8 | namespace KoiVM.VMIL.Translation { 9 | public class EntryHandler : ITranslationHandler { 10 | public IROpCode IRCode { 11 | get { return IROpCode.__ENTRY; } 12 | } 13 | 14 | public void Translate(IRInstruction instr, ILTranslator tr) { 15 | tr.Instructions.Add(new ILInstruction(ILOpCode.__ENTRY)); 16 | } 17 | } 18 | 19 | public class ExitHandler : ITranslationHandler { 20 | public IROpCode IRCode { 21 | get { return IROpCode.__EXIT; } 22 | } 23 | 24 | public void Translate(IRInstruction instr, ILTranslator tr) { 25 | tr.Instructions.Add(new ILInstruction(ILOpCode.__EXIT)); 26 | } 27 | } 28 | 29 | public class BeginCallHandler : ITranslationHandler { 30 | public IROpCode IRCode { 31 | get { return IROpCode.__BEGINCALL; } 32 | } 33 | 34 | public void Translate(IRInstruction instr, ILTranslator tr) { 35 | tr.Instructions.Add(new ILInstruction(ILOpCode.__BEGINCALL) { Annotation = instr.Annotation }); 36 | } 37 | } 38 | 39 | public class EndCallHandler : ITranslationHandler { 40 | public IROpCode IRCode { 41 | get { return IROpCode.__ENDCALL; } 42 | } 43 | 44 | public void Translate(IRInstruction instr, ILTranslator tr) { 45 | tr.Instructions.Add(new ILInstruction(ILOpCode.__ENDCALL) { Annotation = instr.Annotation }); 46 | } 47 | } 48 | 49 | public class EHRetHandler : ITranslationHandler { 50 | public IROpCode IRCode { 51 | get { return IROpCode.__EHRET; } 52 | } 53 | 54 | public void Translate(IRInstruction instr, ILTranslator tr) { 55 | if (instr.Operand1 != null) { 56 | tr.PushOperand(instr.Operand1); 57 | tr.Instructions.Add(new ILInstruction(ILOpCode.POP, ILRegister.R0)); 58 | } 59 | tr.Instructions.Add(new ILInstruction(ILOpCode.RET)); 60 | } 61 | } 62 | 63 | public class LdobjHandler : ITranslationHandler { 64 | public IROpCode IRCode { 65 | get { return IROpCode.__LDOBJ; } 66 | } 67 | 68 | public void Translate(IRInstruction instr, ILTranslator tr) { 69 | tr.PushOperand(instr.Operand1); 70 | var rawType = ((PointerInfo)instr.Annotation).PointerType.ToTypeSig(); 71 | tr.Instructions.Add(new ILInstruction(TranslationHelpers.GetLIND(instr.Operand2.Type, rawType))); 72 | tr.PopOperand(instr.Operand2); 73 | } 74 | } 75 | 76 | public class StobjHandler : ITranslationHandler { 77 | public IROpCode IRCode { 78 | get { return IROpCode.__STOBJ; } 79 | } 80 | 81 | public void Translate(IRInstruction instr, ILTranslator tr) { 82 | tr.PushOperand(instr.Operand2); 83 | tr.PushOperand(instr.Operand1); 84 | var rawType = ((PointerInfo)instr.Annotation).PointerType.ToTypeSig(); 85 | tr.Instructions.Add(new ILInstruction(TranslationHelpers.GetSIND(instr.Operand2.Type, rawType))); 86 | } 87 | } 88 | } -------------------------------------------------------------------------------- /KoiVM/RT/DbgWriter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.IO.Compression; 5 | using System.Reflection; 6 | using System.Security.Cryptography; 7 | using KoiVM.AST.IL; 8 | 9 | namespace KoiVM.RT { 10 | [Obfuscation(Exclude = false, Feature = "+koi;-ref proxy")] 11 | internal class DbgWriter { 12 | struct DbgEntry { 13 | public uint offset; 14 | public uint len; 15 | 16 | public string document; 17 | public uint lineNum; 18 | } 19 | 20 | Dictionary> entries = new Dictionary>(); 21 | HashSet documents = new HashSet(); 22 | byte[] dbgInfo; 23 | 24 | public void AddSequencePoint(ILBlock block, uint offset, uint len, string document, uint lineNum) { 25 | List entryList; 26 | if (!entries.TryGetValue(block, out entryList)) 27 | entryList = entries[block] = new List(); 28 | 29 | entryList.Add(new DbgEntry { 30 | offset = offset, 31 | len = len, 32 | document = document, 33 | lineNum = lineNum 34 | }); 35 | documents.Add(document); 36 | } 37 | 38 | public DbgSerializer GetSerializer() { 39 | return new DbgSerializer(this); 40 | } 41 | 42 | public byte[] GetDbgInfo() { 43 | return dbgInfo; 44 | } 45 | 46 | internal class DbgSerializer : IDisposable { 47 | DbgWriter dbg; 48 | BinaryWriter writer; 49 | MemoryStream stream; 50 | Dictionary docMap; 51 | 52 | internal DbgSerializer(DbgWriter dbg) { 53 | this.dbg = dbg; 54 | stream = new MemoryStream(); 55 | var aes = new AesManaged(); 56 | aes.IV = aes.Key = Convert.FromBase64String("UkVwAyrARLAy4GmQLL860w=="); 57 | writer = new BinaryWriter( 58 | new DeflateStream( 59 | new CryptoStream(stream, aes.CreateEncryptor(), CryptoStreamMode.Write), 60 | CompressionMode.Compress 61 | ) 62 | ); 63 | 64 | InitStream(); 65 | } 66 | 67 | void InitStream() { 68 | docMap = new Dictionary(); 69 | writer.Write(dbg.documents.Count); 70 | uint docId = 0; 71 | foreach (var doc in dbg.documents) { 72 | writer.Write(doc); 73 | docMap[doc] = docId++; 74 | } 75 | } 76 | 77 | public void WriteBlock(BasicBlockChunk chunk) { 78 | List entryList; 79 | if (chunk == null || !dbg.entries.TryGetValue(chunk.Block, out entryList) || 80 | chunk.Block.Content.Count == 0) 81 | return; 82 | 83 | var offset = chunk.Block.Content[0].Offset; 84 | foreach (var entry in entryList) { 85 | writer.Write(entry.offset + chunk.Block.Content[0].Offset); 86 | writer.Write(entry.len); 87 | writer.Write(docMap[entry.document]); 88 | writer.Write(entry.lineNum); 89 | } 90 | } 91 | 92 | public void Dispose() { 93 | writer.Dispose(); 94 | dbg.dbgInfo = stream.ToArray(); 95 | } 96 | } 97 | } 98 | } --------------------------------------------------------------------------------