/// <summary> /// Certain games distribute modified assemblies which disable /// reflection and impede modding. /// </summary> private void EnableReflection(string strDataPath) { string strMscorlib = Path.Combine(strDataPath, Constants.MSCORLIB); FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(strMscorlib); string version = fvi.FileVersion; string strLib = LIB_REPLACEMENTS .Where(replacement => replacement.Substring(Constants.MSCORLIB.Length + 1, 1) == version.Substring(0, 1)) .SingleOrDefault(); if (null != strLib) { try { WebClient wc = new WebClient(); Uri uri = new Uri(Constants.GITHUB_LINK + strLib); wc.DownloadDataAsync(uri, Path.Combine(strDataPath, strLib)); wc.DownloadDataCompleted += (sender, e) => { string strFileName = e.UserState.ToString(); File.WriteAllBytes(strFileName, e.Result); Util.ReplaceFile(strMscorlib, strFileName); m_eInjectorState = Enums.EInjectorState.FINISHED; }; } catch (Exception exc) { m_eInjectorState = Enums.EInjectorState.FINISHED; string strMessage = "Unhandled mscorlib version."; Enums.EErrorCode err = Enums.EErrorCode.MISSING_FILE; string strResponse = JSONResponse.CreateSerializedResponse(strMessage, err, exc); Console.Error.WriteLine(strResponse); Environment.Exit((int)(err)); } } else { m_eInjectorState = Enums.EInjectorState.FINISHED; string strMessage = "Unhandled mscorlib version."; Enums.EErrorCode err = Enums.EErrorCode.UNHANDLED_FILE_VERSION; string strResponse = JSONResponse.CreateSerializedResponse(strMessage, err); Console.Error.WriteLine(strResponse); Environment.Exit((int)(err)); } }
public void Inject() { m_eInjectorState = Enums.EInjectorState.RUNNING; string strTempFile = null; AssemblyDefinition unityAssembly = null; try { // Ensure we have reflection enabled - there's no point // in continuing if reflection is disabled. if (!Util.IsReflectionEnabled(m_strDataPath)) { EnableReflection(m_strDataPath); } else { m_eInjectorState = Enums.EInjectorState.FINISHED; } // Deploy patcher related files. DeployFiles(); // Start the patching process. string[] patcherPoints = Constants.VORTEX_PATCH_METHOD.Split(new string[] { "::" }, StringSplitOptions.None); string[] entryPoint = m_strEntryPoint.Split(new string[] { "::" }, StringSplitOptions.None); strTempFile = Util.GetTempFile(m_strGameAssemblyPath); using (unityAssembly = AssemblyDefinition.ReadAssembly(strTempFile, new ReaderParameters { ReadWrite = true, AssemblyResolver = m_resolver })) { if (IsInjected(unityAssembly, entryPoint)) { unityAssembly.Dispose(); Util.DeleteTemp(strTempFile); return; } // Back up the game assembly before we do anything. Util.BackupFile(m_strGameAssemblyPath); AssemblyDefinition vrtxPatcher = AssemblyDefinition.ReadAssembly(Path.Combine(m_strDataPath, Constants.VORTEX_LIB)); MethodDefinition patcherMethod = vrtxPatcher.MainModule.GetType(patcherPoints[0]).Methods.First(x => x.Name == patcherPoints[1]); TypeDefinition type = unityAssembly.MainModule.GetType(entryPoint[0]); if ((type == null) || !type.IsClass) { throw new EntryPointNotFoundException("Invalid entry point"); } MethodDefinition methodDefinition = type.Methods.FirstOrDefault(meth => meth.Name == entryPoint[1]); if ((methodDefinition == null) || !methodDefinition.HasBody) { throw new EntryPointNotFoundException("Invalid entry point"); } methodDefinition.Body.GetILProcessor().InsertBefore(methodDefinition.Body.Instructions[0], Instruction.Create(OpCodes.Call, methodDefinition.Module.ImportReference(patcherMethod))); unityAssembly.Write(m_strGameAssemblyPath); unityAssembly.Dispose(); Util.DeleteTemp(strTempFile); } } catch (Exception exc) { Enums.EErrorCode errorCode = Enums.EErrorCode.UNKNOWN; if (unityAssembly != null) { unityAssembly.Dispose(); } if (strTempFile != null) { Util.DeleteTemp(strTempFile); } Util.RestoreBackup(m_strGameAssemblyPath); if (exc is FileNotFoundException) { errorCode = Enums.EErrorCode.MISSING_FILE; } else if (exc is EntryPointNotFoundException) { errorCode = Enums.EErrorCode.INVALID_ENTRYPOINT; } string strMessage = "Failed to inject patcher."; string strResponse = JSONResponse.CreateSerializedResponse(strMessage, errorCode, exc); Console.Error.WriteLine(strResponse); Environment.Exit((int)(errorCode)); } while (InjectorState != Enums.EInjectorState.FINISHED) { // Do nothing. } }