private void HookAndUpdate(MethodInfoRestoration m) { MethodInfo targetMethod = m.OriginalMethod; MethodInfo replaceMethod = m.ReplacedMethod; byte[] ilCodes = new byte[5]; ilCodes[0] = (byte)OpCodes.Jmp.Value; ilCodes[1] = (byte)(replaceMethod.MetadataToken & 0xFF); ilCodes[2] = (byte)(replaceMethod.MetadataToken >> 8 & 0xFF); ilCodes[3] = (byte)(replaceMethod.MetadataToken >> 16 & 0xFF); ilCodes[4] = (byte)(replaceMethod.MetadataToken >> 24 & 0xFF); InjectionHelper.UpdateILCodes(targetMethod, ilCodes); }
//private string GetExecutablePath(int ProcessId) //{ // var buffer = new StringBuilder(1024); // IntPtr hprocess = OpenProcess(ProcessAccessFlags.QueryLimitedInformation, // false, ProcessId); // if (hprocess != IntPtr.Zero) // { // try // { // int size = buffer.Capacity; // if (QueryFullProcessImageName(hprocess, 0, buffer, out size)) // { // return buffer.ToString(); // } // } // finally // { // CloseHandle(hprocess); // } // } // return string.Empty; //} private void SlamClassInternal(Type sourceType, Type replacementType) { var methodReplacements = new List <MethodInfoRestoration>(); BindingFlags bf = BindingFlags.FlattenHierarchy | BindingFlags.IgnoreReturn | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.SuppressChangeType; MethodInfo methodFromSource = null; foreach (MethodInfo methodFromReplacement in replacementType.GetMethods(bf)) { // premptive strike that needs to be replaced with better determiners if ((methodFromReplacement.Name == "ToString") || (methodFromReplacement.Name == "Dispose") || (methodFromReplacement.Name == "GetHashCode") || (methodFromReplacement.Name == "Equals") || (methodFromReplacement.Name == "ReferenceEquals") || (methodFromReplacement.Name == "GetType") || (methodFromReplacement.Name == "Finalize") || (methodFromReplacement.Name == "MemberwiseClone")) { continue; } // check for SlamIngore attribute if (methodFromReplacement.GetCustomAttributes().Where(a => a.TypeId.ToString() == "Slam.DynamicInjection.SlamIgnore").Count > 0) { continue; } methodFromSource = null; // make sure its one we actually can replace TODO: Add logging to those that cannot be if ( methodFromReplacement.GetMethodImplementationFlags() == MethodImplAttributes.IL || methodFromReplacement.GetMethodImplementationFlags() == MethodImplAttributes.NoInlining ) { bool isOverLoaded = false; var replacementMethodParameterInfo = methodFromReplacement.GetParameters(); try { methodFromSource = sourceType.GetMethod(methodFromReplacement.Name.Replace("_Slam", ""), bf); } catch (System.Reflection.AmbiguousMatchException ambigous) { isOverLoaded = true; } if (isOverLoaded) { // this means that we have an overloaded method now we have to look more closely var methods = sourceType.GetMethods(bf).Where(m => m.Name == methodFromReplacement.Name); foreach (var method in methods) { var sourceMethodParameterInfo = method.GetParameters(); if (sourceMethodParameterInfo.Length == replacementMethodParameterInfo.Length) { bool found = true; methodFromSource = null; if (replacementMethodParameterInfo.Length == 0) { methodFromSource = method; // doing it below already break; } for (var i = 0; i < sourceMethodParameterInfo.Length; i++) { if (sourceMethodParameterInfo[i].ParameterType != replacementMethodParameterInfo[i].ParameterType) { found = false; } } if (found) { methodFromSource = method; break; } } } } // let's store this stuff MethodInfoRestoration methodInfoRestoration = new MethodInfoRestoration() { OriginalMethod = methodFromSource, ReplacedMethod = methodFromReplacement, OriginalMethodDetails = methodFromSource.GetMethodBody().GetILAsByteArray(), ReplacedMethodDetails = methodFromReplacement.GetMethodBody().GetILAsByteArray(), }; methodReplacements.Add(methodInfoRestoration); // could move this out of the look if we preserve sourceType. if (!ClassInfoRestoration.ContainsKey(sourceType.Name)) { ClassInfoRestoration.Add(sourceType.Name, new List <MethodInfoRestoration>()); } ClassInfoRestoration[sourceType.Name].Add(methodInfoRestoration); } } byte[] byteArrayOfNewFunction; // do IL work (for now doing it seperately foreach (var m in methodReplacements) { // check for slam vs. squirt if ( m.OriginalMethod.GetCustomAttributes() .Where(a => a.TypeId.ToString() == "Slam.DynamicInjection.SlamSquirtee") .Count > 0) { int indexOfSquirtHere = m.ReplacedMethod.GetCustomAttribute <SlamSquirter>().InjectionIndex; if (indexOfSquirtHere < 0 || indexOfSquirtHere > m.OriginalMethodDetails.Length) { throw new Exception("Index out of bounds"); } byteArrayOfNewFunction = new byte[m.OriginalMethodDetails.Length + m.ReplacedMethodDetails.Length]; Array.Copy(m.OriginalMethodDetails, 0, byteArrayOfNewFunction, 0, indexOfSquirtHere); Array.Copy(m.ReplacedMethodDetails, 0, byteArrayOfNewFunction, indexOfSquirtHere, m.ReplacedMethodDetails.Length); Array.Copy(m.ReplacedMethodDetails, indexOfSquirtHere, byteArrayOfNewFunction, indexOfSquirtHere - 1 + m.ReplacedMethodDetails.Length, m.ReplacedMethodDetails.Length - indexOfSquirtHere); //// then commit to the IL which is now in originalmethod details InjectionHelper.UpdateILCodes(m.OriginalMethod, byteArrayOfNewFunction); // output bytes // squirtee OutputIL(sourceType.Name, m.OriginalMethod.Name + " (Squirtee)", m.OriginalMethodDetails); // squirter OutputIL(sourceType.Name, m.OriginalMethod.Name + " (Squirter)", m.ReplacedMethodDetails); // squirter OutputIL(sourceType.Name, m.OriginalMethod.Name + " (New Squirtee)", byteArrayOfNewFunction); } else { // if (m.OriginalMethod.IsStatic) // OK to slam statics InjectionHelper.UpdateILCodes(m.OriginalMethod, m.ReplacedMethodDetails); // else // { // HookAndUpdate(m); // } } } }