internal void CompleteDownload() { if (myMemoryMap == null) { MelonDebug.Msg($"Did not succ any bytes for ptr {OriginalBundleDownload}, just completing"); BundleDownloadMethods.OriginalCompleteDownload(OriginalBundleDownload); return; } MelonDebug.Msg($"Succed {myWriterStream.Position} bytes out of declared {BundleDlInterceptor.GetTotalSize(OriginalBundleDownload)}; waiting for victim process"); var stopwatch = Stopwatch.StartNew(); var exitCode = myVerifierProcess.WaitForExit(TimeSpan.FromSeconds(BundleVerifierMod.TimeLimit.Value)); MelonDebug.Msg($"Process wait done after {stopwatch.ElapsedMilliseconds}ms extra wait"); if (exitCode != 0) { var cleanedUrl = BundleVerifierMod.SanitizeUrl(Url); MelonLogger.Msg($"Verifier process failed with exit code {exitCode} ({VerifierExitCodes.GetExitCodeDescription(exitCode)}) for bundle uid={cleanedUrl.Item1}+{cleanedUrl.Item2}"); BundleVerifierMod.BadBundleCache.Add(Url); MelonDebug.Msg("Reporting completion without data"); // feed some garbage into it, otherwise it dies unsafe { *(long *)(OriginalBundleDownload + 0x40) = 0; var stub = "UnityFS\0"; var bytes = Encoding.UTF8.GetBytes(stub); fixed(byte *bytesPtr = bytes) BundleDownloadMethods.OriginalReceiveBytes(OriginalBundleDownload, (IntPtr)bytesPtr, bytes.Length); } BundleDownloadMethods.OriginalCompleteDownload(OriginalBundleDownload); return; } MelonDebug.Msg("Bundle looks clean, spewing back..."); DoBackSpew(); MelonDebug.Msg("Back-spew done, completing"); BundleDownloadMethods.OriginalCompleteDownload(OriginalBundleDownload); MelonDebug.Msg("Completed!"); }
internal int ProcessBytes(byte[] bytes, int offset, int length) { try { myWriterStream.Write(bytes, offset, length); } catch (IOException ex) { MelonLogger.Error($"Received more bytes than declared for bundle URL {Url} (declared: {BundleDlInterceptor.GetTotalSize(OriginalBundleDownload)})"); MelonLogger.Error(ex.ToString()); DoBackSpew(); unsafe { fixed(byte *bytesPtr = bytes) BundleDownloadMethods.OriginalReceiveBytes(OriginalBundleDownload, (IntPtr)bytesPtr, length); } BundleDlInterceptor.CancelIntercept(this); } return(length); }
internal bool PreProcessBytes() { if (myMemoryMap != null) { return(true); } var declaredSize = BundleDlInterceptor.GetTotalSize(OriginalBundleDownload); if (declaredSize <= 0) { return(false); } try { var memName = "BundleVerifier-" + Guid.NewGuid(); myMemoryMap = MemoryMappedFile.CreateNew(memName, declaredSize + 8, MemoryMappedFileAccess.ReadWrite, MemoryMappedFileOptions.None, HandleInheritability.None); myWriterStream = new MemoryMapWriterStream(myMemoryMap); myWriterStream.SetLength(declaredSize); myVerifierProcess = new BundleVerifierProcessHandle(BundleVerifierMod.BundleVerifierPath, memName, TimeSpan.FromSeconds(BundleVerifierMod.TimeLimit.Value), (ulong)BundleVerifierMod.MemoryLimit.Value * 1024L * 1024L, 20, BundleVerifierMod.ComponentLimit.Value); } catch (Exception ex) { MelonLogger.Error($"Error while initializing verifier internals: {ex}"); return(false); } return(true); }