/// <summary> /// See base class documentation. /// </summary> /// <param name="anILOpInfo">See base class documentation.</param> /// <param name="aScannerState">See base class documentation.</param> /// <returns>See base class documentation.</returns> public override string Convert(ILOpInfo anILOpInfo, ILScannerState aScannerState) { StringBuilder result = new StringBuilder(); //Push the previous method's ebp result.AppendLine("push dword ebp"); //Set ebp for this method //See calling convention spec - this allows easy access of //args and locals within the method without having to track //temporary values (which would be a nightmare with the //exception handling implmentation that the kernel uses!) result.AppendLine("mov dword ebp, esp"); //Allocate stack space for locals //Only bother if there are any locals if (aScannerState.CurrentILChunk.LocalVariables.Count > 0) { int totalBytes = 0; foreach (StackItem aLocal in aScannerState.CurrentILChunk.LocalVariables) { totalBytes += aLocal.sizeOnStackInBytes; } //We do not use "sub esp, X" (see below) because that leaves //junk memory - we need memory to be "initialised" to 0 //so that local variables are null unless properly initialised. //This prevents errors in the GC. for (int i = 0; i < totalBytes / 4; i++) { result.AppendLine("push dword 0"); } //result.AppendLine(string.Format("sub esp, {0}", totalBytes)); } return result.ToString().Trim(); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="anILOpInfo">See base class documentation.</param> /// <param name="aScannerState">See base class documentation.</param> /// <returns>See base class documentation.</returns> public override string Convert(ILOpInfo anILOpInfo, ILScannerState aScannerState) { StringBuilder result = new StringBuilder(); //Get the ID (i.e. ASM label) of the method to load a pointer to string methodID = aScannerState.GetMethodID(anILOpInfo.MethodToCall); //If we want to load the pointer at a specified IL op number: if(anILOpInfo.LoadAtILOffset != int.MaxValue) { //Append the IL sub-label to the ID methodID += ".IL_" + anILOpInfo.LoadAtILOffset + "_0"; //Note: This is used by try/catch/finally blocks for pushing pointers // to catch/finally handlers and filters } //Push the pointer to the function result.AppendLine(string.Format("push dword {0}", methodID)); aScannerState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isGCManaged = false }); return result.ToString().Trim(); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="anILOpInfo">See base class documentation.</param> /// <param name="aScannerState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown if either or both values to shift left are floating point values or /// if the values are 8 bytes in size. /// </exception> /// <exception cref="System.InvalidOperationException"> /// Thrown if either or both values to multiply are not 4 or 8 bytes /// in size or if the values are of different size. /// </exception> public override string Convert(ILOpInfo anILOpInfo, ILScannerState aScannerState) { StringBuilder result = new StringBuilder(); StackItem theItem = aScannerState.CurrentStackFrame.Stack.Peek(); if (theItem.isFloat) { //SUPPORT - Not op for floats throw new NotSupportedException("Not op not supported for float operands!"); } if (theItem.sizeOnStackInBytes == 4) { result.AppendLine("pop dword eax"); result.AppendLine("not eax"); result.AppendLine("push dword eax"); } else if (theItem.sizeOnStackInBytes == 8) { result.AppendLine("pop dword eax"); result.AppendLine("pop dword ebx"); result.AppendLine("not eax"); result.AppendLine("not ebx"); result.AppendLine("push dword ebx"); result.AppendLine("push dword eax"); } else { throw new NotSupportedException("Not op not supported for operand size!"); } return result.ToString().Trim(); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="anILOpInfo">See base class documentation.</param> /// <param name="aScannerState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown if divide operands are floating point numbers or if attempting to divide 64-bit numbers. /// </exception> /// <exception cref="System.InvalidOperationException"> /// Thrown if either operand is < 4 bytes long. /// </exception> public override string Convert(ILOpInfo anILOpInfo, ILScannerState aScannerState) { StringBuilder result = new StringBuilder(); StackItem testItem = aScannerState.CurrentStackFrame.Stack.Pop(); if (testItem.isFloat) { //TODO - Support floats throw new NotSupportedException("Switch for floats no supported!"); } else if (testItem.sizeOnStackInBytes != 4) { //TODO - Support other sizes throw new NotSupportedException("Switch for non-int32s not supported!"); } result.AppendLine("pop dword eax"); for (int i = 0; i < anILOpInfo.ValueBytes.Length / 4; i++) { int branchPos = anILOpInfo.Position + 4 + Utils.ReadInt32(anILOpInfo.ValueBytes, i * 4); branchPos += anILOpInfo.ValueBytes.Length; branchPos += 1; result.AppendLine("cmp eax, " + i); string jumpToLabel = string.Format("{0}.IL_{1}_0", aScannerState.GetMethodID(aScannerState.CurrentILChunk.Method), branchPos); result.AppendLine("je " + jumpToLabel); } return result.ToString().Trim(); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="anILOpInfo">See base class documentation.</param> /// <param name="aScannerState">See base class documentation.</param> /// <returns>See base class documentation.</returns> public override string Convert(ILOpInfo anILOpInfo, ILScannerState aScannerState) { StringBuilder result = new StringBuilder(); //Load a string literal (- fixed string i.e. one programmed as "a string in code") //Get the string metadata token used to get the string from the assembly int StringMetadataToken = Utils.ReadInt32(anILOpInfo.ValueBytes, 0); //Get the value of the string to load string theString = aScannerState.CurrentILChunk.Method.Module.ResolveString(StringMetadataToken); //Add the string literal and get its ID string theStringID = aScannerState.AddStringLiteral(theString, anILOpInfo); //Push the address of the string (i.e. address of ID - ASM label) result.AppendLine(string.Format("push {0}", theStringID)); aScannerState.CurrentStackFrame.Stack.Push(new StackItem() { sizeOnStackInBytes = 4, isFloat = false, isGCManaged = true }); return result.ToString().Trim(); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="anILOpInfo">See base class documentation.</param> /// <param name="aScannerState">See base class documentation.</param> /// <returns>See base class documentation.</returns> public override string Convert(ILOpInfo anILOpInfo, ILScannerState aScannerState) { StringBuilder result = new StringBuilder(); int dwordsToRotate = anILOpInfo.ValueBytes == null ? 2 : BitConverter.ToInt32(anILOpInfo.ValueBytes, 0); int bytesShift = 0; for (int i = 0; i < dwordsToRotate; i++) { if (i == 0) { GlobalMethods.InsertPageFaultDetection(result, aScannerState, "esp", bytesShift, OpCodes.Unbox); result.AppendLine(string.Format("mov eax, [esp+{0}]", bytesShift)); GlobalMethods.InsertPageFaultDetection(result, aScannerState, "esp", bytesShift + 4, OpCodes.Unbox); result.AppendLine(string.Format("mov dword ebx, [esp+{0}]", bytesShift + 4)); GlobalMethods.InsertPageFaultDetection(result, aScannerState, "esp", bytesShift, OpCodes.Unbox); result.AppendLine(string.Format("mov dword [esp+{0}], ebx", bytesShift)); } else if (i == dwordsToRotate - 1) { GlobalMethods.InsertPageFaultDetection(result, aScannerState, "esp", bytesShift, OpCodes.Unbox); result.AppendLine(string.Format("mov [esp+{0}], eax", bytesShift)); } else { GlobalMethods.InsertPageFaultDetection(result, aScannerState, "esp", bytesShift + 4, OpCodes.Unbox); result.AppendLine(string.Format("mov dword ebx, [esp+{0}]", bytesShift + 4)); GlobalMethods.InsertPageFaultDetection(result, aScannerState, "esp", bytesShift, OpCodes.Unbox); result.AppendLine(string.Format("mov dword [esp+{0}], ebx", bytesShift)); } bytesShift += 4; } return result.ToString().Trim(); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="anILOpInfo">See base class documentation.</param> /// <param name="aScannerState">See base class documentation.</param> /// <returns>See base class documentation.</returns> public override string Convert(ILOpInfo anILOpInfo, ILScannerState aScannerState) { StringBuilder result = new StringBuilder(); result.AppendLine("ret"); return result.ToString().Trim(); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="anILOpInfo">See base class documentation.</param> /// <param name="aScannerState">See base class documentation.</param> /// <returns>See base class documentation.</returns> public override string Convert(ILOpInfo anILOpInfo, ILScannerState aScannerState) { if (anILOpInfo.IsDebugOp) { return "int3"; } else { return "nop"; } }
/// <summary> /// See base class documentation. /// </summary> /// <param name="anILOpInfo">See base class documentation.</param> /// <param name="aScannerState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown if field to load is a floating value or the field to load /// is not of size 4 or 8 bytes. /// </exception> public override string Convert(ILOpInfo anILOpInfo, ILScannerState aScannerState) { StringBuilder result = new StringBuilder(); aScannerState.CurrentStackFrame.Stack.Pop(); DB_Type arrayDBType = DebugDatabase.GetType(aScannerState.GetTypeID(aScannerState.ArrayClass)); int lengthOffset = aScannerState.GetFieldOffset(arrayDBType, "length"); // 1. Check array reference is not null // 1.1. Move array ref into eax // 1.2. Compare eax (array ref) to 0 // 1.3. If not zero, jump to continue execution further down // 1.4. Otherwise, call Exceptions.ThrowNullReferenceException // 2. Load array length string ContinueExecutionLabelBase = string.Format("{0}.IL_{1}_ContinueExecution", aScannerState.GetMethodID(aScannerState.CurrentILChunk.Method), anILOpInfo.Position); string ContinueExecutionLabel1 = ContinueExecutionLabelBase + "1"; // 1.1. Move array ref into eax GlobalMethods.InsertPageFaultDetection(result, aScannerState, "esp", 0, (OpCodes)anILOpInfo.opCode.Value); result.AppendLine("mov eax, [esp]"); // 1.2. Compare eax (array ref) to 0 result.AppendLine("cmp eax, 0"); // 1.3. If not zero, jump to continue execution further down result.AppendLine("jnz " + ContinueExecutionLabel1); // 1.4. Otherwise, call Exceptions.ThrowNullReferenceException result.AppendLine(string.Format("call {0}", aScannerState.GetMethodID(aScannerState.ThrowNullReferenceExceptionMethod))); result.AppendLine(ContinueExecutionLabel1 + ":"); //2. Load array length // - Pop array ref result.AppendLine("pop dword ecx"); // - Load length from array ref GlobalMethods.InsertPageFaultDetection(result, aScannerState, "ecx", lengthOffset, (OpCodes)anILOpInfo.opCode.Value); result.AppendLine(string.Format("mov eax, [ecx+{0}]", lengthOffset)); // - Push array length result.AppendLine("push dword eax"); aScannerState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isGCManaged = false }); return result.ToString().Trim(); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="anILOpInfo">See base class documentation.</param> /// <param name="aScannerState">See base class documentation.</param> /// <returns>See base class documentation.</returns> public override string Convert(ILOpInfo anILOpInfo, ILScannerState aScannerState) { StringBuilder result = new StringBuilder(); //Load null (i.e. 0 as dword) aScannerState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isGCManaged = false }); result.AppendLine("push dword 0"); return result.ToString().Trim(); }
public override string Convert(ILOpInfo anILOpInfo, ILScannerState aScannerState) { StringBuilder result = new StringBuilder(); result.AppendLine("; Method End"); //DEBUG INFO result.AppendLine("pop rbp"); result.AppendLine("mov rsp, rbp"); StackFrame currFrame = aScannerState.StackFrames.Peek(); currFrame.Stack.Pop(); result.AppendLine("ret"); return result.ToString().Trim(); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="anILOpInfo">See base class documentation.</param> /// <param name="aScannerState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// If either value is < 4 bytes in length or /// operands are not of the same size. /// </exception> public override string Convert(ILOpInfo anILOpInfo, ILScannerState aScannerState) { StringBuilder result = new StringBuilder(); //Pop item to duplicate StackItem itemA = aScannerState.CurrentStackFrame.Stack.Pop(); if(itemA.isFloat) { //SUPPORT - floats throw new NotSupportedException("Duplicate float vals not suppported yet!"); } if(itemA.sizeOnStackInBytes == 4) { result.AppendLine("pop dword eax"); result.AppendLine("push dword eax"); result.AppendLine("push dword eax"); } else if (itemA.sizeOnStackInBytes == 8) { result.AppendLine("pop dword eax"); result.AppendLine("pop dword edx"); result.AppendLine("push dword edx"); result.AppendLine("push dword eax"); result.AppendLine("push dword edx"); result.AppendLine("push dword eax"); } else { throw new NotSupportedException("Stack item size not supported by duplicate op!"); } aScannerState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = itemA.isFloat, sizeOnStackInBytes = itemA.sizeOnStackInBytes, isGCManaged = itemA.isGCManaged }); aScannerState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = itemA.isFloat, sizeOnStackInBytes = itemA.sizeOnStackInBytes, isGCManaged = itemA.isGCManaged }); return result.ToString().Trim(); }
public override string Convert(ILOpInfo anILOpInfo, ILScannerState aScannerState) { StringBuilder result = new StringBuilder(); result.AppendLine("; Method Start"); //DEBUG INFO result.AppendLine("push rbp"); result.AppendLine("mov rbp, rsp"); StackFrame currFrame = aScannerState.StackFrames.Peek(); currFrame.Stack.Push(new StackItem() { sizeOnStackInBytes = 8 }); return result.ToString().Trim(); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="anILOpInfo">See base class documentation.</param> /// <param name="aScannerState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown if the value to store is floating point or /// if the value is not 4 or 8 bytes in size. /// </exception> public override string Convert(ILOpInfo anILOpInfo, ILScannerState aScannerState) { StringBuilder result = new StringBuilder(); int metadataToken = Utils.ReadInt32(anILOpInfo.ValueBytes, 0); FieldInfo theField = aScannerState.CurrentILChunk.Method.Module.ResolveField(metadataToken); DB_Type objDBType = DebugDatabase.GetType(aScannerState.GetTypeID(theField.DeclaringType)); int offset = aScannerState.GetFieldOffset(objDBType, theField.Name); int stackSize = Utils.GetNumBytesForType(theField.FieldType); int memSize = theField.FieldType.IsValueType ? Utils.GetSizeForType(theField.FieldType) : stackSize; StackItem value = aScannerState.CurrentStackFrame.Stack.Pop(); StackItem objPointer = aScannerState.CurrentStackFrame.Stack.Pop(); if (value.isFloat) { //SUPPORT - floats throw new NotSupportedException("Storing fields of type float not supported yet!"); } //Get object pointer GlobalMethods.InsertPageFaultDetection(result, aScannerState, "esp", stackSize, (OpCodes)anILOpInfo.opCode.Value); result.AppendLine(string.Format("mov ecx, [esp+{0}]", stackSize)); //Pop and mov value for (int i = 0; i < memSize; i += 2) { if (memSize - i == 1) { result.AppendLine("pop word ax"); GlobalMethods.InsertPageFaultDetection(result, aScannerState, "ecx", offset + i, (OpCodes)anILOpInfo.opCode.Value); result.AppendLine(string.Format("mov byte [ecx+{0}], al", offset + i)); } else { result.AppendLine("pop word ax"); GlobalMethods.InsertPageFaultDetection(result, aScannerState, "ecx", offset + i, (OpCodes)anILOpInfo.opCode.Value); result.AppendLine(string.Format("mov word [ecx+{0}], ax", offset + i)); } } result.AppendLine(string.Format("add esp, {0}", ((stackSize - memSize) / 2) * 2)); //Rounds down result.AppendLine("add esp, 4");//Pop object pointer return result.ToString().Trim(); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="anILOpInfo">See base class documentation.</param> /// <param name="aScannerState">See base class documentation.</param> /// <returns>See base class documentation.</returns> public override string Convert(ILOpInfo anILOpInfo, ILScannerState aScannerState) { StringBuilder result = new StringBuilder(); int metadataToken = Utils.ReadInt32(anILOpInfo.ValueBytes, 0); Type theType = aScannerState.CurrentILChunk.Method.Module.ResolveType(metadataToken); result.AppendLine(string.Format("push dword {0}", Utils.GetNumBytesForType(theType))); aScannerState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isGCManaged = false }); return result.ToString().Trim(); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="anILOpInfo">See base class documentation.</param> /// <param name="aScannerState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown if the value to store is floating point. /// </exception> public override string Convert(ILOpInfo anILOpInfo, ILScannerState aScannerState) { StringBuilder result = new StringBuilder(); int metadataToken = Utils.ReadInt32(anILOpInfo.ValueBytes, 0); FieldInfo theField = aScannerState.CurrentILChunk.Method.Module.ResolveField(metadataToken); string fieldID = aScannerState.GetStaticFieldID(theField); int size = Utils.GetNumBytesForType(theField.FieldType); bool isFloat = Utils.IsFloat(theField.FieldType); StackItem value = aScannerState.CurrentStackFrame.Stack.Pop(); if (isFloat) { //SUPPORT - floats throw new NotSupportedException("Storing static fields of type float not supported yet!"); } if (size == 1) { result.AppendLine("pop dword eax"); result.AppendLine(string.Format("mov byte [{0}], al", fieldID)); } else if (size == 2) { result.AppendLine("pop dword eax"); result.AppendLine(string.Format("mov word [{0}], ax", fieldID)); } else if (size == 4) { result.AppendLine("pop dword eax"); result.AppendLine(string.Format("mov dword [{0}], eax", fieldID)); } else if (size == 8) { result.AppendLine("pop dword eax"); result.AppendLine(string.Format("mov byte [{0}], eax", fieldID)); result.AppendLine("pop dword eax"); result.AppendLine(string.Format("mov byte [{0}+4], eax", fieldID)); } return result.ToString().Trim(); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="anILOpInfo">See base class documentation.</param> /// <param name="aScannerState">See base class documentation.</param> /// <returns>See base class documentation.</returns> public override string Convert(ILOpInfo anILOpInfo, ILScannerState aScannerState) { StringBuilder result = new StringBuilder(); StackItem theItem = aScannerState.CurrentStackFrame.Stack.Pop(); if (theItem.isNewGCObject) { //Decrement ref count //Get the ID of method to call as it will be labelled in the output ASM. string methodID = aScannerState.GetMethodID(aScannerState.DecrementRefCountMethod); //Append the actual call result.AppendLine(string.Format("call {0}", methodID)); } result.AppendLine(string.Format("add esp, {0}", theItem.sizeOnStackInBytes)); return result.ToString().Trim(); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="anILOpInfo">See base class documentation.</param> /// <param name="aScannerState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown when loading a static float field. /// </exception> public override string Convert(ILOpInfo anILOpInfo, ILScannerState aScannerState) { StringBuilder result = new StringBuilder(); //Load static field //Load the metadata token used to get the type info int metadataToken = Utils.ReadInt32(anILOpInfo.ValueBytes, 0); //Get the type info for the object to load Type theType = aScannerState.CurrentILChunk.Method.Module.ResolveType(metadataToken); //Get the object size information int size = Utils.GetNumBytesForType(theType); //Load the object onto the stack result.AppendLine("pop dword ecx"); for (int i = size - 4; i >= 0; i -= 4) { GlobalMethods.InsertPageFaultDetection(result, aScannerState, "ecx", i, (OpCodes)anILOpInfo.opCode.Value); result.AppendLine(string.Format("mov dword eax, [ecx+{0}]", i)); result.AppendLine("push dword eax"); } int extra = size % 4; for (int i = extra - 1; i >= 0; i--) { GlobalMethods.InsertPageFaultDetection(result, aScannerState, "ecx", i, (OpCodes)anILOpInfo.opCode.Value); result.AppendLine(string.Format("mov byte al, [ecx+{0}]", i)); result.AppendLine("push byte al"); } aScannerState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = size, isGCManaged = false }); return result.ToString().Trim(); }
public override string Convert(ILOpInfo anILOpInfo, ILScannerState aScannerState) { StringBuilder result = new StringBuilder(); //Just removes (pops) the top value off our stack //But we must check that our "top value on stack" is actually on the stack and not in a register StackFrame currFrame = aScannerState.StackFrames.Peek(); //We assume there is an item on the stack. If there isn't, we have gotten out of sync with the IL. //If debugging this, you should assume that the IL code is correct and our compiler is wrong. //Microsoft are much more likely to be correct than we are ;) StackItem topItem = currFrame.Stack.Pop(); if (topItem.register == null) { result.AppendLine("pop"); } else { result.AppendLine(string.Format("; top-most stack item in register '{0}'", topItem.register)); //DEBUG INFO } return result.ToString().Trim(); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="anILOpInfo">See base class documentation.</param> /// <param name="aScannerState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown if either or both values to 'or' are floating point values. /// </exception> /// <exception cref="System.InvalidOperationException"> /// Thrown if either or both values to multiply are not 4 or 8 bytes /// in size or if the values are of different size. /// </exception> public override string Convert(ILOpInfo anILOpInfo, ILScannerState aScannerState) { StringBuilder result = new StringBuilder(); //Pop in reverse order to push StackItem itemB = aScannerState.CurrentStackFrame.Stack.Pop(); StackItem itemA = aScannerState.CurrentStackFrame.Stack.Pop(); if (itemB.sizeOnStackInBytes < 4 || itemA.sizeOnStackInBytes < 4) { throw new InvalidOperationException("Invalid stack operand sizes!"); } else if (itemB.isFloat || itemA.isFloat) { //SUPPORT - floats throw new NotSupportedException("Add floats is unsupported!"); } else { if (itemA.sizeOnStackInBytes == 4 && itemB.sizeOnStackInBytes == 4) { //Pop item B result.AppendLine("pop dword ebx"); //Pop item A result.AppendLine("pop dword eax"); result.AppendLine("and eax, ebx"); result.AppendLine("push dword eax"); aScannerState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isGCManaged = false }); } else if ((itemA.sizeOnStackInBytes == 8 && itemB.sizeOnStackInBytes == 4) || (itemA.sizeOnStackInBytes == 4 && itemB.sizeOnStackInBytes == 8)) { throw new InvalidOperationException("Invalid stack operand sizes! They should be the same size."); } else if (itemA.sizeOnStackInBytes == 8 && itemB.sizeOnStackInBytes == 8) { //Pop item B to ecx:ebx result.AppendLine("pop dword ebx"); result.AppendLine("pop dword ecx"); //Pop item A to edx:eax result.AppendLine("pop dword eax"); result.AppendLine("pop dword edx"); //And ecx:ebx with edx:eax result.AppendLine("and eax, ebx"); result.AppendLine("and edx, ecx"); result.AppendLine("push dword edx"); result.AppendLine("push dword eax"); aScannerState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 8, isGCManaged = false }); } } return result.ToString().Trim(); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="anILOpInfo">See base class documentation.</param> /// <param name="aScannerState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown if any argument or the return value is a floating point number. /// </exception> public override string Convert(ILOpInfo anILOpInfo, ILScannerState aScannerState) { StringBuilder result = new StringBuilder(); MethodBase methodToCall = anILOpInfo.MethodToCall; //The method to call is a method base //A method base can be either a method info i.e. a normal method //or a constructor method. The two types are treated separately. if(methodToCall is MethodInfo) { //Need to do callvirt related stuff to load address of method to call // - Check for invoke of a delegate - if so, treat rather differently from normal callvirt string call_Label = string.Format("{0}.IL_{1}_Call", aScannerState.GetMethodID(aScannerState.CurrentILChunk.Method), anILOpInfo.Position); if (typeof(Delegate).IsAssignableFrom(((MethodInfo)methodToCall).DeclaringType)) { //Callvirt to delegate method // - We only support calls to Invoke at the moment if (methodToCall.Name != "Invoke") { throw new NotSupportedException("Callvirt to Delegate method not supported! Method name: " + methodToCall.Name); } int bytesForAllParams = ((MethodInfo)methodToCall).GetParameters().Select(x => Utils.GetNumBytesForType(x.ParameterType)).Sum(); // - Move into eax address of function to call from stack - delegate reference is function pointer //All the parameters for the method that was called List<Type> allParams = ((MethodInfo)methodToCall).GetParameters().Select(x => x.ParameterType).ToList(); int bytesForParams = allParams.Select(x => Utils.GetNumBytesForType(x)).Sum(); GlobalMethods.InsertPageFaultDetection(result, aScannerState, "esp", bytesForParams, (OpCodes)anILOpInfo.opCode.Value); result.AppendLine(string.Format("mov dword eax, [esp+{0}]", bytesForParams)); //Allocate space on the stack for the return value as necessary Type retType = ((MethodInfo)methodToCall).ReturnType; StackItem returnItem = new StackItem() { isFloat = Utils.IsFloat(retType), sizeOnStackInBytes = Utils.GetNumBytesForType(retType), isGCManaged = Utils.IsGCManaged(retType) }; //We do not push the return value onto the stack unless it has size > 0 //We do not push the return value onto our stack at this point - it is pushed after the call is done if (returnItem.sizeOnStackInBytes != 0) { if (returnItem.isFloat) { //SUPPORT - floats throw new NotSupportedException("Cannot handle float return values!"); } else if (returnItem.sizeOnStackInBytes == 4) { result.AppendLine("push dword 0"); } else if (returnItem.sizeOnStackInBytes == 8) { result.AppendLine("push dword 0"); result.AppendLine("push dword 0"); } else { throw new NotSupportedException("Invalid return stack operand size!"); } } //Append the actual call result.AppendLine("call eax"); //After a call, we need to remove the return value and parameters from the stack //This is most easily done by just adding the total number of bytes for params and //return value to the stack pointer (ESP register). //Stores the number of bytes to add // - Initially at least 4 for the delegate (method) ref/pointer int bytesToAdd = 4; //Go through all params that must be removed foreach (Type aParam in allParams) { //Pop the paramter off our stack //(Note: Return value was never pushed onto our stack. See above) aScannerState.CurrentStackFrame.Stack.Pop(); //Add the size of the paramter to the total number of bytes to pop bytesToAdd += Utils.GetNumBytesForType(aParam); } //If there is a return value on the stack if (returnItem.sizeOnStackInBytes != 0) { //We need to store the return value then pop all the params //We now push the return value onto our stack as, //after all is said and done below, it will be the //top item on the stack aScannerState.CurrentStackFrame.Stack.Push(returnItem); //SUPPORT - floats (with above) //Pop the return value into the eax register //We will push it back on after params are skipped over. if (returnItem.sizeOnStackInBytes == 4) { result.AppendLine("pop dword eax"); } else if (returnItem.sizeOnStackInBytes == 8) { result.AppendLine("pop dword eax"); result.AppendLine("pop dword edx"); } } //Skip over the params result.AppendLine(string.Format("add esp, {0}", bytesToAdd)); //If necessary, push the return value onto the stack. if (returnItem.sizeOnStackInBytes != 0) { //SUPPORT - floats (with above) //The return value was stored in eax //So push it back onto the stack if (returnItem.sizeOnStackInBytes == 4) { result.AppendLine("push dword eax"); } else if (returnItem.sizeOnStackInBytes == 8) { result.AppendLine("push dword edx"); result.AppendLine("push dword eax"); } } } else { //Normal callvirt // - Get object ref from loaded args // - Check object ref not null // - Get type table entry from object ref // - Get method table from type table entry // - Scan method table for the method we want // - If found, load method address // - Else, check for parent type method table // - If no parent type method table, throw exception // - Else, scan parent type method table string methodIDValueWanted = aScannerState.GetMethodIDValue((MethodInfo)methodToCall); string loopTableEntries_Label = string.Format("{0}.IL_{1}_LoopMethodTable", aScannerState.GetMethodID(aScannerState.CurrentILChunk.Method), anILOpInfo.Position); string notEqual_Label = string.Format("{0}.IL_{1}_NotEqual", aScannerState.GetMethodID(aScannerState.CurrentILChunk.Method), anILOpInfo.Position); string endOfTable_Label = string.Format("{0}.IL_{1}_EndOfTable", aScannerState.GetMethodID(aScannerState.CurrentILChunk.Method), anILOpInfo.Position); string notFound_Label = string.Format("{0}.IL_{1}_NotFound", aScannerState.GetMethodID(aScannerState.CurrentILChunk.Method), anILOpInfo.Position); string notNull_Label = string.Format("{0}.IL_{1}_NotNullMem", aScannerState.GetMethodID(aScannerState.CurrentILChunk.Method), anILOpInfo.Position); DB_Type declaringDBType = DebugDatabase.GetType(aScannerState.GetTypeID(methodToCall.DeclaringType)); //Get object ref int bytesForAllParams = ((MethodInfo)methodToCall).GetParameters().Select(x => Utils.GetNumBytesForType(x.ParameterType)).Sum(); GlobalMethods.InsertPageFaultDetection(result, aScannerState, "esp", bytesForAllParams, (OpCodes)anILOpInfo.opCode.Value); result.AppendLine(string.Format("mov dword eax, [esp+{0}]", bytesForAllParams)); //Check object ref result.AppendLine("cmp eax, 0"); result.AppendLine(string.Format("jnz {0}", notNull_Label)); result.AppendLine("call GetEIP"); result.AppendLine(string.Format("call {0}", aScannerState.GetMethodID(aScannerState.HaltMethod))); result.AppendLine(notNull_Label + ":"); //Get type ref int typeOffset = aScannerState.GetFieldOffset(declaringDBType, "_Type"); GlobalMethods.InsertPageFaultDetection(result, aScannerState, "eax", typeOffset, (OpCodes)anILOpInfo.opCode.Value); result.AppendLine(string.Format("mov eax, [eax+{0}]", typeOffset)); //Get method table ref int methodTablePtrOffset = aScannerState.GetTypeFieldOffset("MethodTablePtr"); GlobalMethods.InsertPageFaultDetection(result, aScannerState, "eax", methodTablePtrOffset, (OpCodes)anILOpInfo.opCode.Value); result.AppendLine(string.Format("mov eax, [eax+{0}]", methodTablePtrOffset)); //Loop through entries result.AppendLine(loopTableEntries_Label + ":"); //Load ID Val for current entry GlobalMethods.InsertPageFaultDetection(result, aScannerState, "eax", 0, (OpCodes)anILOpInfo.opCode.Value); result.AppendLine("mov ebx, [eax]"); //Compare to wanted ID value result.AppendLine("cmp ebx, " + methodIDValueWanted); //If equal, load method address into eax result.AppendLine("jne " + notEqual_Label); GlobalMethods.InsertPageFaultDetection(result, aScannerState, "eax", 4, (OpCodes)anILOpInfo.opCode.Value); result.AppendLine("mov eax, [eax+4]"); result.AppendLine("jmp " + call_Label); result.AppendLine(notEqual_Label + ":"); //Else, compare to 0 to check for end of table result.AppendLine("cmp ebx, 0"); result.AppendLine("jz " + endOfTable_Label); //Not 0? Move to next entry then loop again result.AppendLine("add eax, 8"); result.AppendLine("jmp " + loopTableEntries_Label); result.AppendLine(endOfTable_Label + ":"); //Compare address value to 0 //If not zero, there is a parent method table to check GlobalMethods.InsertPageFaultDetection(result, aScannerState, "eax", 4, (OpCodes)anILOpInfo.opCode.Value); result.AppendLine("mov ebx, [eax+4]"); result.AppendLine("cmp ebx, 0"); result.AppendLine("jz " + notFound_Label); //Load parent method table and loop result.AppendLine("mov eax, ebx"); result.AppendLine("jmp " + loopTableEntries_Label); result.AppendLine(notFound_Label + ":"); //Throw exception! result.AppendLine(string.Format("call {0}", aScannerState.GetMethodID(aScannerState.ThrowNullReferenceExceptionMethod))); result.AppendLine(call_Label + ":"); //Allocate space on the stack for the return value as necessary Type retType = ((MethodInfo)methodToCall).ReturnType; StackItem returnItem = new StackItem() { isFloat = Utils.IsFloat(retType), sizeOnStackInBytes = Utils.GetNumBytesForType(retType), isGCManaged = Utils.IsGCManaged(retType) }; //We do not push the return value onto the stack unless it has size > 0 //We do not push the return value onto our stack at this point - it is pushed after the call is done if (returnItem.sizeOnStackInBytes != 0) { if (returnItem.isFloat) { //SUPPORT - floats throw new NotSupportedException("Cannot handle float return values!"); } else if (returnItem.sizeOnStackInBytes == 4) { result.AppendLine("push dword 0"); } else if (returnItem.sizeOnStackInBytes == 8) { result.AppendLine("push dword 0"); result.AppendLine("push dword 0"); } else { throw new NotSupportedException("Invalid return stack operand size!"); } } //Append the actual call result.AppendLine("call eax"); //After a call, we need to remove the return value and parameters from the stack //This is most easily done by just adding the total number of bytes for params and //return value to the stack pointer (ESP register). //Stores the number of bytes to add int bytesToAdd = 0; //All the parameters for the method that was called List<Type> allParams = ((MethodInfo)methodToCall).GetParameters().Select(x => x.ParameterType).ToList(); //Go through each one if (!methodToCall.IsStatic) { allParams.Insert(0, methodToCall.DeclaringType); } foreach (Type aParam in allParams) { //Pop the paramter off our stack //(Note: Return value was never pushed onto our stack. See above) aScannerState.CurrentStackFrame.Stack.Pop(); //Add the size of the paramter to the total number of bytes to pop bytesToAdd += Utils.GetNumBytesForType(aParam); } //If the number of bytes to add to skip over params is > 0 if (bytesToAdd > 0) { //If there is a return value on the stack if (returnItem.sizeOnStackInBytes != 0) { //We need to store the return value then pop all the params //We now push the return value onto our stack as, //after all is said and done below, it will be the //top item on the stack aScannerState.CurrentStackFrame.Stack.Push(returnItem); //SUPPORT - floats (with above) //Pop the return value into the eax register //We will push it back on after params are skipped over. if (returnItem.sizeOnStackInBytes == 4) { result.AppendLine("pop dword eax"); } else if (returnItem.sizeOnStackInBytes == 8) { result.AppendLine("pop dword eax"); result.AppendLine("pop dword edx"); } } //Skip over the params result.AppendLine(string.Format("add esp, {0}", bytesToAdd)); //If necessary, push the return value onto the stack. if (returnItem.sizeOnStackInBytes != 0) { //SUPPORT - floats (with above) //The return value was stored in eax //So push it back onto the stack if (returnItem.sizeOnStackInBytes == 4) { result.AppendLine("push dword eax"); } else if (returnItem.sizeOnStackInBytes == 8) { result.AppendLine("push dword edx"); result.AppendLine("push dword eax"); } } } //No params to skip over but we might still need to store return value else if (returnItem.sizeOnStackInBytes != 0) { //The return value will be the top item on the stack. //So all we need to do is push the return item onto our stack. aScannerState.CurrentStackFrame.Stack.Push(returnItem); } } } else if(methodToCall is ConstructorInfo) { throw new NotSupportedException("How the hell are we getting callvirts to constructor methods?!"); } return result.ToString().Trim(); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="anILOpInfo">See base class documentation.</param> /// <param name="aScannerState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown if constant is a floating point number. /// </exception> public override string Convert(ILOpInfo anILOpInfo, ILScannerState aScannerState) { StringBuilder result = new StringBuilder(); Type elementType = null; bool pushValue = true; int sizeToPush = 4; bool signExtend = true; bool isFloat = false; switch ((OpCodes)anILOpInfo.opCode.Value) { case OpCodes.Ldelem: { signExtend = false; //Load the metadata token used to get the type info int metadataToken = Utils.ReadInt32(anILOpInfo.ValueBytes, 0); //Get the type info for the element type elementType = aScannerState.CurrentILChunk.Method.Module.ResolveType(metadataToken); } break; case OpCodes.Ldelema: { signExtend = false; //Load the metadata token used to get the type info int metadataToken = Utils.ReadInt32(anILOpInfo.ValueBytes, 0); //Get the type info for the element type elementType = aScannerState.CurrentILChunk.Method.Module.ResolveType(metadataToken); } break; case OpCodes.Ldelem_R4: case OpCodes.Ldelem_R8: //TODO - Add more LdElem op variants support throw new NotSupportedException("Ldelem op variant not supported yet!"); case OpCodes.Ldelem_I1: sizeToPush = 1; elementType = typeof(sbyte); break; case OpCodes.Ldelem_I2: sizeToPush = 2; elementType = typeof(Int16); break; case OpCodes.Ldelem_U1: sizeToPush = 1; signExtend = false; elementType = typeof(byte); break; case OpCodes.Ldelem_U2: sizeToPush = 2; signExtend = false; elementType = typeof(UInt16); break; case OpCodes.Ldelem_Ref: signExtend = false; elementType = null; break; case OpCodes.Ldelem_U4: signExtend = false; elementType = typeof(UInt32); break; case OpCodes.Ldelem_I4: elementType = typeof(Int32); break; case OpCodes.Ldelem_I8: elementType = typeof(Int64); break; } if (isFloat) { //TODO - Support floats throw new NotSupportedException("LdElem for floats not supported yet!"); } //Get element from array and push the value onto the stack // (or for LdElemA push the address of the value) //This involves: // 1. Check array reference is not null // - If it is, throw NullReferenceException // 2. Check array element type is correct // - If not, throw ArrayTypeMismatchException // 3. Check index to get is > -1 and < array length // - If not, throw IndexOutOfRangeException // 4. Calculate address of element // 5. Push the element onto the stack //Stack setup upon entering this op: (top-most downwards) // 0. Index of element to get as Int32 (dword) // 1. Array object reference as address (dword) string ContinueExecutionLabelBase = string.Format("{0}.IL_{1}_Load_ContinueExecution", aScannerState.GetMethodID(aScannerState.CurrentILChunk.Method), anILOpInfo.Position); DB_Type arrayDBType = DebugDatabase.GetType(aScannerState.GetTypeID(aScannerState.ArrayClass)); // 1. Check array reference is not null // 1.1. Move array ref into eax // 1.2. Compare eax (array ref) to 0 // 1.3. If not zero, jump to continue execution further down // 1.4. Otherwise, call Exceptions.ThrowNullReferenceException string ContinueExecutionLabel1 = ContinueExecutionLabelBase + "1"; // 1.1. Move array ref into eax GlobalMethods.InsertPageFaultDetection(result, aScannerState, "esp", 4, (OpCodes)anILOpInfo.opCode.Value); result.AppendLine("mov eax, [esp+4]"); // 1.2. Compare eax (array ref) to 0 result.AppendLine("cmp eax, 0"); // 1.3. If not zero, jump to continue execution further down result.AppendLine("jnz " + ContinueExecutionLabel1); // 1.4. Otherwise, call Exceptions.ThrowNullReferenceException result.AppendLine(string.Format("call {0}", aScannerState.GetMethodID(aScannerState.ThrowNullReferenceExceptionMethod))); result.AppendLine(ContinueExecutionLabel1 + ":"); // 2. Check array element type is correct // 2.1. Move element type ref into eax // 2.2. Move element type ref from array object into ebx // 2.3. Compare eax to ebx // 2.4. If the same, jump to continue execution further down // 2.5. Otherwise, call Exceptions.ThrowArrayTypeMismatchException //string ContinueExecutionLabel2 = ContinueExecutionLabelBase + "2"; //// 2.1. Move element type ref into eax int elemTypeOffset = aScannerState.GetFieldOffset(arrayDBType, "elemType"); //if (elementType != null) //{ // result.AppendLine(string.Format("mov eax, {0}", aScannerState.GetTypeIdString(aScannerState.GetTypeID(elementType)))); // // 2.2. Move element type ref from array object into ebx // // - Calculate the offset of the field from the start of the array object // // - Move array ref into ebx //GlobalMethods.CheckAddrFromRegister(result, aScannerState, "esp", 4); // result.AppendLine("mov ebx, [esp+4]"); // // - Move elemType ref ([ebx+offset]) into ebx // GlobalMethods.CheckAddrFromRegister(result, aScannerState, "ebx", elemTypeOffset); // result.AppendLine(string.Format("mov ebx, [ebx+{0}]", elemTypeOffset)); // // 2.3. Compare eax to ebx // result.AppendLine("cmp eax, ebx"); // // 2.4. If the same, jump to continue execution further down // result.AppendLine("je " + ContinueExecutionLabel2); // // 2.5. Otherwise, call Exceptions.ThrowArrayTypeMismatchException // result.AppendLine(string.Format("call {0}", aScannerState.GetMethodID(aScannerState.ThrowArrayTypeMismatchExceptionMethod))); // result.AppendLine(ContinueExecutionLabel2 + ":"); //} // 3. Check index to get is > -1 and < array length // 3.1. Move index into eax // 3.2. Move array length into ebx // 3.2. Compare eax to 0 // 3.3. Jump if greater than to next test condition (3.5) // 3.4. Otherwise, call Exceptions.ThrowIndexOutOfRangeException // 3.5. Compare eax to ebx // 3.6. Jump if less than to continue execution further down // 3.7. Otherwise, call Exceptions.ThrowIndexOutOfRangeException string ContinueExecutionLabel3_1 = ContinueExecutionLabelBase + "3_1"; string ContinueExecutionLabel3_2 = ContinueExecutionLabelBase + "3_2"; // 3.1. Move index into eax GlobalMethods.InsertPageFaultDetection(result, aScannerState, "esp", 0, (OpCodes)anILOpInfo.opCode.Value); result.AppendLine("mov eax, [esp]"); // 3.2. Move array length into ecx // - Calculate the offset of the field from the start of the array object int lengthOffset = aScannerState.GetFieldOffset(arrayDBType, "length"); // - Move array ref into ebx GlobalMethods.InsertPageFaultDetection(result, aScannerState, "esp", 4, (OpCodes)anILOpInfo.opCode.Value); result.AppendLine("mov ebx, [esp+4]"); // - Move length value ([ebx+offset]) into ebx GlobalMethods.InsertPageFaultDetection(result, aScannerState, "ebx", lengthOffset, (OpCodes)anILOpInfo.opCode.Value); result.AppendLine(string.Format("mov ebx, [ebx+{0}]", lengthOffset)); // 3.2. Compare eax to 0 result.AppendLine("cmp eax, 0"); // 3.3. Jump if greater than to next test condition (3.5) result.AppendLine("jge " + ContinueExecutionLabel3_1); // 3.4. Otherwise, call Exceptions.ThrowIndexOutOfRangeException result.AppendLine(string.Format("call {0}", aScannerState.GetMethodID(aScannerState.ThrowIndexOutOfRangeExceptionMethod))); result.AppendLine(ContinueExecutionLabel3_1 + ":"); // 3.5. Compare eax to ebx result.AppendLine("cmp eax, ebx"); // 3.6. Jump if less than to continue execution further down result.AppendLine("jl " + ContinueExecutionLabel3_2); // 3.7. Otherwise, call Exceptions.ThrowIndexOutOfRangeException result.AppendLine(string.Format("call {0}", aScannerState.GetMethodID(aScannerState.ThrowIndexOutOfRangeExceptionMethod))); result.AppendLine(ContinueExecutionLabel3_2 + ":"); // 4. Calculate address of element // 4.1. Pop index into ebx // 4.2. Pop array ref into eax // 4.3. Move element type ref (from array ref) into eax // 4.4. Move IsValueType (from element ref type) into ecx // 4.5. If IsValueType, continue to 4.6., else goto 4.8. // 4.6. Move Size (from element type ref) into eax // 4.7. Skip over 4.8. // 4.8. Move StackSize (from element type ref) into eax // 4.9. Mulitply eax by ebx (index by element size) // 4.10. Move array ref into ebx // 4.11. Add enough to go past Kernel.FOS_System.Array fields // 4.12. Add eax and ebx (array ref + fields + (index * element size)) string ContinueExecutionLabel4_1 = ContinueExecutionLabelBase + "4_1"; string ContinueExecutionLabel4_2 = ContinueExecutionLabelBase + "4_2"; // 4.1. Pop index into ebx result.AppendLine("pop ebx"); // 4.2. Move array ref into eax GlobalMethods.InsertPageFaultDetection(result, aScannerState, "esp", 0, (OpCodes)anILOpInfo.opCode.Value); result.AppendLine("mov eax, [esp]"); // 4.3. Move element type ref (from array ref) into eax GlobalMethods.InsertPageFaultDetection(result, aScannerState, "eax", elemTypeOffset, (OpCodes)anILOpInfo.opCode.Value); result.AppendLine(string.Format("mov eax, [eax+{0}]", elemTypeOffset)); // 4.4. Move IsValueType (from element ref type) into ecx int isValueTypeOffset = aScannerState.GetTypeFieldOffset("IsValueType"); result.AppendLine("mov ecx, 0"); GlobalMethods.InsertPageFaultDetection(result, aScannerState, "eax", isValueTypeOffset, (OpCodes)anILOpInfo.opCode.Value); result.AppendLine(string.Format("mov byte cl, [eax+{0}]", isValueTypeOffset)); // 4.5. If IsValueType, continue to 4.6., else goto 4.8. result.AppendLine("cmp ecx, 0"); result.AppendLine("jz " + ContinueExecutionLabel4_1); // 4.6. Move Size (from element type ref) into eax int sizeOffset = aScannerState.GetTypeFieldOffset("Size"); GlobalMethods.InsertPageFaultDetection(result, aScannerState, "eax", sizeOffset, (OpCodes)anILOpInfo.opCode.Value); result.AppendLine(string.Format("mov eax, [eax+{0}]", sizeOffset)); // 4.7. Skip over 4.8. result.AppendLine("jmp " + ContinueExecutionLabel4_2); // 4.8. Move StackSize (from element type ref) into eax result.AppendLine(ContinueExecutionLabel4_1 + ":"); int stackSizeOffset = aScannerState.GetTypeFieldOffset("StackSize"); GlobalMethods.InsertPageFaultDetection(result, aScannerState, "eax", stackSizeOffset, (OpCodes)anILOpInfo.opCode.Value); result.AppendLine(string.Format("mov eax, [eax+{0}]", stackSizeOffset)); // 4.9. Mulitply eax by ebx (index by element size) result.AppendLine(ContinueExecutionLabel4_2 + ":"); result.AppendLine("mul ebx"); // 4.10. Pop array ref into ebx result.AppendLine("pop ebx"); // 4.11. Add enough to go past Kernel.FOS_System.Array fields int allFieldsOffset = 0; #region Offset calculation { //Get the child links of the type (i.e. the fields of the type) List<DB_ComplexTypeLink> allChildLinks = arrayDBType.ChildTypes.ToList(); //Calculate the offset //We use StackBytesSize since fields that are reference types are only stored as a pointer allFieldsOffset = allChildLinks.Sum(x => x.ChildType.IsValueType ? x.ChildType.BytesSize : x.ChildType.StackBytesSize); } #endregion result.AppendLine(string.Format("add ebx, {0}", allFieldsOffset)); // 4.12. Add eax and ebx (array ref + fields + (index * element size)) result.AppendLine("add eax, ebx"); // 5. Push the element onto the stack // 5.1. Push value at [eax] (except for LdElemA op in which case just push address) if (pushValue) { switch (sizeToPush) { case 1: result.AppendLine("mov dword ebx, 0"); GlobalMethods.InsertPageFaultDetection(result, aScannerState, "eax", 0, (OpCodes)anILOpInfo.opCode.Value); result.AppendLine("mov byte bl, [eax]"); if (signExtend) { throw new NotSupportedException("Sign extend byte to 4 bytes in LdElem not supported!"); } break; case 2: result.AppendLine("mov dword ebx, 0"); GlobalMethods.InsertPageFaultDetection(result, aScannerState, "eax", 0, (OpCodes)anILOpInfo.opCode.Value); result.AppendLine("mov word bx, [eax]"); if (signExtend) { result.AppendLine("cwde"); } break; case 4: GlobalMethods.InsertPageFaultDetection(result, aScannerState, "eax", 0, (OpCodes)anILOpInfo.opCode.Value); result.AppendLine("mov dword ebx, [eax]"); break; case 8: GlobalMethods.InsertPageFaultDetection(result, aScannerState, "eax", 0, (OpCodes)anILOpInfo.opCode.Value); result.AppendLine("mov word ebx, [eax]"); GlobalMethods.InsertPageFaultDetection(result, aScannerState, "eax", 4, (OpCodes)anILOpInfo.opCode.Value); result.AppendLine("mov word ecx, [eax+4]"); break; } if (sizeToPush == 8) { result.AppendLine("push ecx"); } result.AppendLine("push ebx"); } else { result.AppendLine("push eax"); } // 5.2. Pop index and array ref from our stack aScannerState.CurrentStackFrame.Stack.Pop(); aScannerState.CurrentStackFrame.Stack.Pop(); // 5.3. Push element onto our stack aScannerState.CurrentStackFrame.Stack.Push(new StackItem() { sizeOnStackInBytes = sizeToPush > 4 ? 8 : 4, isFloat = isFloat, isNewGCObject = false, isGCManaged = pushValue ? Utils.IsGCManaged(elementType) : false }); return result.ToString().Trim(); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="anILOpInfo">See base class documentation.</param> /// <param name="aScannerState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown when loading a static float field. /// </exception> public override string Convert(ILOpInfo anILOpInfo, ILScannerState aScannerState) { StringBuilder result = new StringBuilder(); //Load static field //Load the metadata token used to get the field info int metadataToken = Utils.ReadInt32(anILOpInfo.ValueBytes, 0); //Get the field info for the field to load FieldInfo theField = aScannerState.CurrentILChunk.Method.Module.ResolveField(metadataToken); //Get the ID (i.e. ASM label) of the field to load string fieldID = aScannerState.GetStaticFieldID(theField); //Load the field or field address switch ((OpCodes)anILOpInfo.opCode.Value) { case OpCodes.Ldsfld: { int size = Utils.GetNumBytesForType(theField.FieldType); bool isFloat = Utils.IsFloat(theField.FieldType); if (isFloat) { //SUPPORT - floats throw new NotSupportedException("Loading static fields of type float not supported yet!"); } if(size == 1) { result.AppendLine("xor eax, eax"); result.AppendLine(string.Format("mov byte al, [{0}]", fieldID)); result.AppendLine("push dword eax"); } else if(size == 2) { result.AppendLine("xor eax, eax"); result.AppendLine(string.Format("mov word ax, [{0}]", fieldID)); result.AppendLine("push dword eax"); } else if(size == 4) { result.AppendLine(string.Format("mov dword eax, [{0}]", fieldID)); result.AppendLine("push dword eax"); } else if (size == 8) { result.AppendLine(string.Format("mov dword eax, [{0}+4]", fieldID)); result.AppendLine("push dword eax"); result.AppendLine(string.Format("mov dword eax, [{0}]", fieldID)); result.AppendLine("push dword eax"); } aScannerState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = isFloat, sizeOnStackInBytes = (size == 8 ? 8 : 4), isGCManaged = Utils.IsGCManaged(theField.FieldType) }); } break; case OpCodes.Ldsflda: //Load the address of the field i.e. address of the ASM label result.AppendLine(string.Format("push dword {0}", fieldID)); aScannerState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isGCManaged = false }); break; } return result.ToString().Trim(); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="anILOpInfo">See base class documentation.</param> /// <param name="aScannerState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown if the either of the values to add are floating point. /// </exception> /// <exception cref="System.InvalidOperationException"> /// Thrown if the either of the values to add are less than 4 bytes in size /// or if they are of different sizes. /// </exception> public override string Convert(ILOpInfo anILOpInfo, ILScannerState aScannerState) { StringBuilder result = new StringBuilder(); //Pop the operands from our stack in reverse order //i.e. second operand was pushed last so comes off the //top of the stack first //Pop item B - one of the items to subtract StackItem itemB = aScannerState.CurrentStackFrame.Stack.Pop(); //Pop item A - the other item to subtract StackItem itemA = aScannerState.CurrentStackFrame.Stack.Pop(); //If either item item is < 4 bytes then we have a stack error. if (itemB.sizeOnStackInBytes < 4 || itemA.sizeOnStackInBytes < 4) { throw new InvalidOperationException("Invalid stack operand sizes!"); } //If either item is floating point, we must use floating point conversions //and floating point arithmetic else if (itemB.isFloat || itemA.isFloat) { //SUPPORT - floats // - We need to convert items to float if necessary // - Then use floating point arithmetic // - Then push the result onto the stack and mark it as float // Note: Check but I think floating point arithmetic is done using // XMM registers and their specific ops. throw new NotSupportedException("Add floats is unsupported!"); } else { //If both items are Int32s (or UInt32s - it is irrelevant) //Note: IL handles type conversions using other ops if (itemA.sizeOnStackInBytes == 4 && itemB.sizeOnStackInBytes == 4) { //Pop item B result.AppendLine("pop dword ebx"); //Pop item A result.AppendLine("pop dword eax"); //Subtract the two result.AppendLine("sub eax, ebx"); //Push the result onto the stack result.AppendLine("push dword eax"); //Push the result onto our stack aScannerState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isGCManaged = false }); } //Invalid if the operands are of different sizes. //Note: This usually occurs when a previous IL op failed to process properly. else if ((itemA.sizeOnStackInBytes == 8 && itemB.sizeOnStackInBytes == 4) || (itemA.sizeOnStackInBytes == 4 && itemB.sizeOnStackInBytes == 8)) { throw new InvalidOperationException("Invalid stack operand sizes! They should be the same size."); } else if (itemA.sizeOnStackInBytes == 8 && itemB.sizeOnStackInBytes == 8) { //Pop item B to ecx:ebx //Pop low bits result.AppendLine("pop dword ebx"); //Pop high bits result.AppendLine("pop dword ecx"); //Pop item A to edx:eax //Pop low bits result.AppendLine("pop dword eax"); //Pop high bits result.AppendLine("pop dword edx"); //Sub ecx:ebx from edx:eax //Sub low bits result.AppendLine("sub eax, ebx"); //Sub high bits including any borrow from //when low bits were subtracted result.AppendLine("sbb edx, ecx"); //Push the result //Push high bits result.AppendLine("push dword edx"); //Push low bits result.AppendLine("push dword eax"); //Push the result onto our stack aScannerState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 8, isGCManaged = false }); } } return result.ToString().Trim(); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="anILOpInfo">See base class documentation.</param> /// <param name="aScannerState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown if divide operands are floating point numbers or if attempting to divide 64-bit numbers. /// </exception> /// <exception cref="System.InvalidOperationException"> /// Thrown if either operand is < 4 bytes long. /// </exception> public override string Convert(ILOpInfo anILOpInfo, ILScannerState aScannerState) { StringBuilder result = new StringBuilder(); //Pop in reverse order to push StackItem itemB = aScannerState.CurrentStackFrame.Stack.Pop(); StackItem itemA = aScannerState.CurrentStackFrame.Stack.Pop(); if (itemB.sizeOnStackInBytes < 4 || itemA.sizeOnStackInBytes < 4) { throw new InvalidOperationException("Invalid stack operand sizes!"); } else if (itemB.isFloat || itemA.isFloat) { //SUPPORT - floats throw new NotSupportedException("Divide floats is unsupported!"); } else { if (itemA.sizeOnStackInBytes == 4 && itemB.sizeOnStackInBytes == 4) { //Pop item B result.AppendLine("pop dword ebx"); //Pop item A result.AppendLine("pop dword eax"); if ((OpCodes)anILOpInfo.opCode.Value == OpCodes.Div_Un) { //Unsigned extend A to EAX:EDX result.AppendLine("mov edx, 0"); //Do the division result.AppendLine("div ebx"); } else { //Sign extend A to EAX:EDX result.AppendLine("cdq"); //Do the division result.AppendLine("idiv ebx"); } //Result stored in eax result.AppendLine("push dword eax"); aScannerState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isGCManaged = false }); } else if ((itemA.sizeOnStackInBytes == 8 && itemB.sizeOnStackInBytes == 4) || (itemA.sizeOnStackInBytes == 4 && itemB.sizeOnStackInBytes == 8)) { throw new InvalidOperationException("Invalid stack operand sizes! They should be the 32-32 or 64-64."); } else if (itemA.sizeOnStackInBytes == 8 && itemB.sizeOnStackInBytes == 8) { //SUPPORT - 64-bit division throw new NotSupportedException("64-bit by 64-bit division not supported yet!"); } } return result.ToString().Trim(); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="anILOpInfo">See base class documentation.</param> /// <param name="aScannerState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown if the value to store is floating point. /// </exception> /// <exception cref="System.NotImplementedException"> /// Thrown if the op is 'StIndRef'. /// </exception> public override string Convert(ILOpInfo anILOpInfo, ILScannerState aScannerState) { StringBuilder result = new StringBuilder(); //Pop value //Pop address //Mov [address], value StackItem valueItem = aScannerState.CurrentStackFrame.Stack.Pop(); StackItem addressItem = aScannerState.CurrentStackFrame.Stack.Pop(); int bytesToStore = 0; bool isFloat = false; switch ((OpCodes)anILOpInfo.opCode.Value) { case OpCodes.Stind_I: bytesToStore = 4; break; case OpCodes.Stind_I1: bytesToStore = 1; break; case OpCodes.Stind_I2: bytesToStore = 2; break; case OpCodes.Stind_I4: bytesToStore = 4; break; case OpCodes.Stind_I8: bytesToStore = 8; break; case OpCodes.Stind_R4: bytesToStore = 4; isFloat = true; break; case OpCodes.Stind_R8: bytesToStore = 8; isFloat = true; break; case OpCodes.Stind_Ref: bytesToStore = 4; break; } if(isFloat) { //SUPPORT - floats throw new NotSupportedException("Floats not supported yet!"); } if (bytesToStore == 8) { //Pop value low bits result.AppendLine("pop dword eax"); //Pop value high bits result.AppendLine("pop dword edx"); //Pop address result.AppendLine("pop dword ebx"); //Mov [address], value GlobalMethods.InsertPageFaultDetection(result, aScannerState, "ebx", 4, (OpCodes)anILOpInfo.opCode.Value); result.AppendLine("mov dword [ebx+4], edx"); GlobalMethods.InsertPageFaultDetection(result, aScannerState, "ebx", 0, (OpCodes)anILOpInfo.opCode.Value); result.AppendLine("mov dword [ebx], eax"); } else if (bytesToStore == 4) { //Pop value result.AppendLine("pop dword eax"); //Pop address result.AppendLine("pop dword ebx"); //Mov [address], value GlobalMethods.InsertPageFaultDetection(result, aScannerState, "ebx", 0, (OpCodes)anILOpInfo.opCode.Value); result.AppendLine("mov dword [ebx], eax"); } else if (bytesToStore == 2) { //Pop value result.AppendLine("pop dword eax"); //Pop address result.AppendLine("pop dword ebx"); //Mov [address], value GlobalMethods.InsertPageFaultDetection(result, aScannerState, "ebx", 0, (OpCodes)anILOpInfo.opCode.Value); result.AppendLine("mov word [ebx], ax"); } else if (bytesToStore == 1) { //Pop value result.AppendLine("pop dword eax"); //Pop address result.AppendLine("pop dword ebx"); //Mov [address], value GlobalMethods.InsertPageFaultDetection(result, aScannerState, "ebx", 0, (OpCodes)anILOpInfo.opCode.Value); result.AppendLine("mov byte [ebx], al"); } return result.ToString().Trim(); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="anILOpInfo">See base class documentation.</param> /// <param name="aScannerState">See base class documentation.</param> /// <returns>See base class documentation.</returns> public override string Convert(ILOpInfo anILOpInfo, ILScannerState aScannerState) { StringBuilder result = new StringBuilder(); //Load the metadata token used to get the type info int metadataToken = Utils.ReadInt32(anILOpInfo.ValueBytes, 0); //Get the type info for the element type Type elementType = aScannerState.CurrentILChunk.Method.Module.ResolveType(metadataToken); //New array must: // - Allocate memory on the heap for the object // - If no memory is left, throw a panic attack because we're out of memory... // - Call the specified constructor //The label to jump to if allocated memory isn't null //i.e. not out of memory. string NotNullLabel = string.Format("{0}.IL_{1}_NotNullMem", aScannerState.GetMethodID(aScannerState.CurrentILChunk.Method), anILOpInfo.Position); //Attempt to allocate memory on the heap for the new array //This involves: // - (Number of elements is already on the stack) // - Pushing the element type reference onto the stack // - Calling GC NewArr method // - Check the pointer == 0, if so, out of memory //Push type reference string typeIdStr = aScannerState.GetTypeIdString(aScannerState.GetTypeID(elementType)); result.AppendLine(string.Format("push dword {0}", typeIdStr)); //Push a dword for return value (i.e. new array pointer) result.AppendLine("push dword 0"); //Get the GC.NewArr method ID (i.e. ASM label) string methodLabel = aScannerState.GetMethodID(aScannerState.NewArrMethod); //Call GC.NewArr result.AppendLine(string.Format("call {0}", methodLabel)); //Pop the return value (i.e. new array pointer) result.AppendLine("pop dword eax"); //Remove args from stack result.AppendLine("add esp, 8"); //Check if pointer == 0? result.AppendLine("cmp eax, 0"); //If it isn't 0, not out of memory so continue execution result.AppendLine(string.Format("jnz {0}", NotNullLabel)); //If we are out of memory, we have a massive problem //Because it means we don't have space to create a new exception object //So ultimately we just have to throw a kernel panic //Throw a panic attack... ( :/ ) by calling kernel Halt(uint lastAddress) //result.AppendLine("call GetEIP"); //result.AppendLine("push dword esp"); //result.AppendLine("push dword ebp"); //result.AppendLine("pushad"); //result.AppendLine("mov dword eax, 0xDEADBEEF"); //result.AppendLine("mov dword ebx, 0x2"); //result.AppendLine("mov dword ecx, 1"); //result.AppendLine("mov dword [staticfield_System_Boolean_Kernel_FOS_System_GC_Enabled], 1"); //result.AppendLine("mov dword [staticfield_System_Boolean_Kernel_FOS_System_Heap_PreventAllocation], 0"); //result.AppendLine("jmp method_System_Void_RETEND_Kernel_PreReqs_DECLEND_PageFaultDetection_NAMEEND___Fail"); result.AppendLine("call GetEIP"); result.AppendLine(string.Format("call {0}", aScannerState.GetMethodID(aScannerState.HaltMethod))); //Insert the not null label result.AppendLine(NotNullLabel + ":"); //Push new array pointer result.AppendLine("push dword eax"); aScannerState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isNewGCObject = true, isGCManaged = true }); return result.ToString().Trim(); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="anILOpInfo">See base class documentation.</param> /// <param name="aScannerState">See base class documentation.</param> /// <returns>See base class documentation.</returns> public override string Convert(ILOpInfo anILOpInfo, ILScannerState aScannerState) { StringBuilder result = new StringBuilder(); StackItem itemToConvert = aScannerState.CurrentStackFrame.Stack.Pop(); int numBytesToConvertTo = 0; switch ((OpCodes)anILOpInfo.opCode.Value) { case OpCodes.Conv_I: numBytesToConvertTo = 4; break; case OpCodes.Conv_I1: numBytesToConvertTo = 1; break; case OpCodes.Conv_I2: numBytesToConvertTo = 2; break; case OpCodes.Conv_I4: numBytesToConvertTo = 4; break; case OpCodes.Conv_I8: numBytesToConvertTo = 8; break; } int bytesPopped = 0; bool pushEDX = false; switch(numBytesToConvertTo) { case 1: //Convert to Int8 (byte) //Sign extend to dword result.AppendLine("mov eax, 0"); result.AppendLine("pop byte al"); bytesPopped = 1; break; case 2: //Convert to Int16 (word) //Sign extend to dword result.AppendLine("mov eax, 0"); result.AppendLine("pop word ax"); result.AppendLine("cwde"); bytesPopped = 2; break; case 4: //Convert to Int32 (dword) result.AppendLine("pop dword eax"); bytesPopped = 4; break; case 8: //Convert to Int64 if (itemToConvert.sizeOnStackInBytes == 8) { //Result stored in EAX:EDX result.AppendLine("pop dword eax"); result.AppendLine("pop dword edx"); bytesPopped = 8; } else { //Sign extend dword to qword //Result stored in EAX:EDX result.AppendLine("pop dword eax"); result.AppendLine("cdq"); bytesPopped = 4; } pushEDX = true; break; } int bytesDiff = itemToConvert.sizeOnStackInBytes - bytesPopped; if (bytesDiff > 0) { result.AppendLine(string.Format("add esp, {0}", bytesDiff)); } if (pushEDX) { result.AppendLine("push dword edx"); } result.AppendLine("push dword eax"); aScannerState.CurrentStackFrame.Stack.Push(new StackItem() { sizeOnStackInBytes = (pushEDX ? 8 : 4), isFloat = false, isGCManaged = false }); return result.ToString().Trim(); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="anILOpInfo">See base class documentation.</param> /// <param name="aScannerState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown when the return value is a float or the size on the stack /// in bytes is not 4 or 8 bytes. /// </exception> public override string Convert(ILOpInfo anILOpInfo, ILScannerState aScannerState) { StringBuilder result = new StringBuilder(); //Store the return value //Get the return type Type retType = (aScannerState.CurrentILChunk.Method.IsConstructor || aScannerState.CurrentILChunk.Method is ConstructorInfo ? typeof(void) : ((MethodInfo)aScannerState.CurrentILChunk.Method).ReturnType); //Get the size of the return type on stack int retSize = Utils.GetNumBytesForType(retType); //If the size isn't 0 (i.e. isn't "void" which has no return value) if (retSize != 0) { //Pop the return value off our stack StackItem retItem = aScannerState.CurrentStackFrame.Stack.Pop(); //If it is float, well, we don't support it yet... if (retItem.isFloat) { //SUPPORT - floats throw new NotSupportedException("Floats return type not supported yet!"); } //Otherwise, store the return value at [ebp+8] //[ebp+8] because that is last "argument" // - read the calling convention spec else if (retSize == 4) { result.AppendLine("pop dword eax"); result.AppendLine("mov [ebp+8], eax"); } else if (retSize == 8) { result.AppendLine("pop dword eax"); result.AppendLine("mov [ebp+8], eax"); result.AppendLine("pop dword eax"); result.AppendLine("mov [ebp+12], eax"); } else { throw new NotSupportedException("Return type size not supported / invalid!"); } } //Once return value is off the stack, remove the locals //Deallocate stack space for locals //Only bother if there are any locals if (aScannerState.CurrentILChunk.LocalVariables.Count > 0) { //Get the total size of all locals int totalBytes = 0; foreach (StackItem aLocal in aScannerState.CurrentILChunk.LocalVariables) { totalBytes += aLocal.sizeOnStackInBytes; } //Move esp past the locals result.AppendLine(string.Format("add esp, {0}", totalBytes)); } //Restore ebp to previous method's ebp result.AppendLine("pop dword ebp"); //This pop also takes last value off the stack which //means top item is the return address //So ret command can now be correctly executed. return result.ToString().Trim(); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="anILOpInfo">See base class documentation.</param> /// <param name="aScannerState">See base class documentation.</param> /// <returns>See base class documentation.</returns> public override string Convert(ILOpInfo anILOpInfo, ILScannerState aScannerState) { StringBuilder result = new StringBuilder(); MethodBase constructorMethod = anILOpInfo.MethodToCall; Type objectType = constructorMethod.DeclaringType; //New obj must: // - Ignore for creation of Delegates // - Allocate memory on the heap for the object // - If no memory is left, throw a panic attack because we're out of memory... // - Call the specified constructor if (typeof(Delegate).IsAssignableFrom(objectType)) { result.AppendLine("; Ignore newobj calls for Delegates"); //Still need to: // - Remove the "object" param but preserve the "function pointer" GlobalMethods.InsertPageFaultDetection(result, aScannerState, "esp", 0, (OpCodes)anILOpInfo.opCode.Value); result.AppendLine("mov dword eax, [esp]"); GlobalMethods.InsertPageFaultDetection(result, aScannerState, "esp", 4, (OpCodes)anILOpInfo.opCode.Value); result.AppendLine("mov dword [esp+4], eax"); result.AppendLine("add esp, 4"); return result.ToString().Trim(); } //The label to jump to if allocated memory isn't null //i.e. not out of memory. string NotNullLabel = string.Format("{0}.IL_{1}_NotNullMem", aScannerState.GetMethodID(aScannerState.CurrentILChunk.Method), anILOpInfo.Position); //Attempt to allocate memory on the heap for the new object //This involves: // - Pushing the type reference onto the stack // - Calling GC NewObj method // - Check the pointer == 0, if so, out of memory //Push type reference string typeIdStr = aScannerState.GetTypeIdString(aScannerState.GetTypeID(objectType)); result.AppendLine(string.Format("push dword {0}", typeIdStr)); //Push a dword for return value (i.e. new object pointer) result.AppendLine("push dword 0"); //Get the GC.NewObj method ID (i.e. ASM label) string methodLabel = aScannerState.GetMethodID(aScannerState.NewObjMethod); //Call GC.NewObj result.AppendLine(string.Format("call {0}", methodLabel)); //Pop the return value (i.e. new object pointer) result.AppendLine("pop dword eax"); //Remove arg 0 from stack result.AppendLine("add esp, 4"); //Check if pointer == 0? result.AppendLine("cmp eax, 0"); //If it isn't 0, not out of memory so continue execution result.AppendLine(string.Format("jnz {0}", NotNullLabel)); //If we are out of memory, we have a massive problem //Because it means we don't have space to create a new exception object //So ultimately we just have to throw a kernel panic //Throw a panic attack... ( :/ ) by calling kernel Halt(uint lastAddress) //result.AppendLine("call GetEIP"); //result.AppendLine("push dword esp"); //result.AppendLine("push dword ebp"); //result.AppendLine("pushad"); //result.AppendLine("mov dword eax, 0xDEADBEEF"); //result.AppendLine("mov dword ebx, 0x1"); //result.AppendLine("mov dword ecx, 1"); //result.AppendLine("mov dword [staticfield_System_Boolean_Kernel_FOS_System_GC_Enabled], 1"); //result.AppendLine("mov dword [staticfield_System_Boolean_Kernel_FOS_System_Heap_PreventAllocation], 0"); //result.AppendLine("jmp method_System_Void_RETEND_Kernel_PreReqs_DECLEND_PageFaultDetection_NAMEEND___Fail"); result.AppendLine("call GetEIP"); result.AppendLine(string.Format("call {0}", aScannerState.GetMethodID(aScannerState.HaltMethod))); //Insert the not null label result.AppendLine(NotNullLabel + ":"); //Call the specified constructor //This involves: // - Push empty dword onto stack // - Move all args down by one dword // - Move object reference into dword as first arg // - Call constructor result.AppendLine("push dword 0"); int sizeOfArgs = 0; ParameterInfo[] allParams = constructorMethod.GetParameters(); foreach(ParameterInfo aParam in allParams) { sizeOfArgs += Utils.GetNumBytesForType(aParam.ParameterType); aScannerState.CurrentStackFrame.Stack.Pop(); } result.AppendLine("mov dword ebx, esp"); if (sizeOfArgs > 0) { if (sizeOfArgs % 4 != 0) { throw new InvalidOperationException("sizeOfArgs not exact multiple of 4!"); } result.AppendLine(string.Format("mov dword ecx, {0}", sizeOfArgs / 4)); string ShiftArgsLoopLabel = string.Format("{0}.IL_{1}_ShiftArgsLoop", aScannerState.GetMethodID(aScannerState.CurrentILChunk.Method), anILOpInfo.Position); result.AppendLine(ShiftArgsLoopLabel + ":"); GlobalMethods.InsertPageFaultDetection(result, aScannerState, "ebx", 4, (OpCodes)anILOpInfo.opCode.Value); result.AppendLine("mov dword edx, [ebx+4]"); GlobalMethods.InsertPageFaultDetection(result, aScannerState, "ebx", 0, (OpCodes)anILOpInfo.opCode.Value); result.AppendLine("mov dword [ebx], edx"); result.AppendLine("add ebx, 4"); result.AppendLine(string.Format("loop {0}", ShiftArgsLoopLabel)); } GlobalMethods.InsertPageFaultDetection(result, aScannerState, "ebx", 0, (OpCodes)anILOpInfo.opCode.Value); result.AppendLine("mov dword [ebx], eax"); result.AppendLine(string.Format("call {0}", aScannerState.GetMethodID(constructorMethod))); //Only remove args from stack - we want the object pointer to remain on the stack result.AppendLine(string.Format("add esp, {0}", sizeOfArgs)); aScannerState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isNewGCObject = true, isGCManaged = true }); return result.ToString().Trim(); }