Decompiled source of MLVScan v1.6.6

Plugins/MLVScan.MelonLoader.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using MLVScan.Abstractions;
using MLVScan.Adapters;
using MLVScan.MelonLoader;
using MLVScan.Models;
using MLVScan.Models.CrossAssembly;
using MLVScan.Models.Dto;
using MLVScan.Models.Rules;
using MLVScan.Models.Rules.Helpers;
using MLVScan.Models.ThreatIntel;
using MLVScan.Services;
using MLVScan.Services.DeepBehavior;
using MLVScan.Services.Helpers;
using MLVScan.Services.ThreatIntel;
using MelonLoader;
using MelonLoader.Preferences;
using MelonLoader.Utils;
using Microsoft.CodeAnalysis;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Collections.Generic;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: MelonInfo(typeof(MelonLoaderPlugin), "MLVScan", "1.6.6", "Bars", null)]
[assembly: MelonPriority(int.MinValue)]
[assembly: MelonColor(255, 139, 0, 0)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("MLVScan.MelonLoader")]
[assembly: AssemblyConfiguration("MelonLoader")]
[assembly: AssemblyFileVersion("1.6.6")]
[assembly: AssemblyInformationalVersion("1.6.6+0d9b47b6a7535ecb945e6d761817ffe54c11f50b")]
[assembly: AssemblyProduct("MLVScan.MelonLoader")]
[assembly: AssemblyTitle("MLVScan.MelonLoader")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.6.6.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace MLVScan
{
	internal static class MLVScanBuildInfo
	{
		public const string PlatformVersion = "1.6.6";
	}
	public static class PlatformConstants
	{
		public const string PlatformVersion = "1.6.6";

		public const string PlatformName = "MLVScan.MelonLoader";

		public static string GetVersionString()
		{
			return "MLVScan.MelonLoader v1.6.6";
		}

		public static string GetFullVersionInfo()
		{
			return "Engine: " + Constants.GetVersionString() + "\nPlatform: " + GetVersionString();
		}
	}
}
namespace MLVScan.Adapters
{
	public class MelonScanLogger : IScanLogger
	{
		private readonly Instance _logger;

		public MelonScanLogger(Instance logger)
		{
			_logger = logger ?? throw new ArgumentNullException("logger");
		}

		public void Debug(string message)
		{
			_logger.Msg("[DEBUG] " + message);
		}

		public void Info(string message)
		{
			_logger.Msg(message);
		}

		public void Warning(string message)
		{
			_logger.Warning(message);
		}

		public void Error(string message)
		{
			_logger.Error(message);
		}

		public void Error(string message, Exception exception)
		{
			_logger.Error($"{message}: {exception}");
		}
	}
	public class GameAssemblyResolverProvider : IAssemblyResolverProvider
	{
		public IAssemblyResolver CreateResolver()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			DefaultAssemblyResolver val = new DefaultAssemblyResolver();
			try
			{
				string text = Path.Combine(MelonEnvironment.GameRootDirectory, Path.GetFileNameWithoutExtension(MelonEnvironment.GameExecutablePath) + "_Data", "Managed");
				if (Directory.Exists(text))
				{
					((BaseAssemblyResolver)val).AddSearchDirectory(text);
				}
				string text2 = Path.Combine(MelonEnvironment.GameRootDirectory, "MelonLoader", "net35");
				if (Directory.Exists(text2))
				{
					((BaseAssemblyResolver)val).AddSearchDirectory(text2);
				}
				string text3 = Path.Combine(MelonEnvironment.GameRootDirectory, "MelonLoader", "net6");
				if (Directory.Exists(text3))
				{
					((BaseAssemblyResolver)val).AddSearchDirectory(text3);
				}
				string modsDirectory = MelonEnvironment.ModsDirectory;
				if (Directory.Exists(modsDirectory))
				{
					((BaseAssemblyResolver)val).AddSearchDirectory(modsDirectory);
				}
				string pluginsDirectory = MelonEnvironment.PluginsDirectory;
				if (Directory.Exists(pluginsDirectory))
				{
					((BaseAssemblyResolver)val).AddSearchDirectory(pluginsDirectory);
				}
			}
			catch (Exception)
			{
			}
			return (IAssemblyResolver)(object)val;
		}
	}
}
namespace MLVScan.MelonLoader
{
	public class MelonLoaderPlugin : MelonPlugin
	{
		private MelonLoaderServiceFactory _serviceFactory;

		private MelonConfigManager _configManager;

		private MelonPlatformEnvironment _environment;

		private MelonPluginScanner _pluginScanner;

		private MelonPluginDisabler _pluginDisabler;

		private IlDumpService _ilDumpService;

		private DeveloperReportGenerator _developerReportGenerator;

		private ReportUploadService _reportUploadService;

		private bool _initialized = false;

		private bool _showUploadConsentPopup;

		private string _pendingUploadPath = string.Empty;

		private string _pendingUploadModName = string.Empty;

		private List<ScanFinding> _pendingUploadFindings;

		private static readonly string[] DefaultWhitelistedHashes = new string[4] { "3918e1454e05de4dd3ace100d8f4d53936c9b93694dbff5bcc0293d689cb0ab7", "8e6dd1943c80e2d1472a9dc2c6722226d961027a7ec20aab9ad8f1184702d138", "d47eb6eabd3b6e3b742c7d9693651bc3a61a90dcbe838f9a4276953089ee4951", "cfe43c0d285867a5701d96de1edd25cb02725fe2629b88386351dc07b11a08b5" };

		public override void OnEarlyInitializeMelon()
		{
			try
			{
				((MelonBase)this).LoggerInstance.Msg("Pre-scanning for malicious mods...");
				_serviceFactory = new MelonLoaderServiceFactory(((MelonBase)this).LoggerInstance);
				_configManager = _serviceFactory.CreateConfigManager();
				_environment = _serviceFactory.CreateEnvironment();
				InitializeDefaultWhitelist();
				_pluginScanner = _serviceFactory.CreatePluginScanner();
				_pluginDisabler = _serviceFactory.CreatePluginDisabler();
				_ilDumpService = _serviceFactory.CreateIlDumpService();
				_developerReportGenerator = _serviceFactory.CreateDeveloperReportGenerator();
				_reportUploadService = _serviceFactory.CreateReportUploadService();
				_initialized = true;
				ScanAndDisableMods(force: true);
			}
			catch (Exception ex)
			{
				((MelonBase)this).LoggerInstance.Error("Error in pre-mod scan: " + ex.Message);
				((MelonBase)this).LoggerInstance.Error(ex.StackTrace);
			}
		}

		public override void OnInitializeMelon()
		{
			try
			{
				((MelonBase)this).LoggerInstance.Msg("MLVScan initialization complete");
				if (_configManager.Config.WhitelistedHashes.Length != 0)
				{
					((MelonBase)this).LoggerInstance.Msg($"{_configManager.Config.WhitelistedHashes.Length} mod(s) are whitelisted and won't be scanned");
					((MelonBase)this).LoggerInstance.Msg("To manage whitelisted mods, edit MelonPreferences.cfg");
				}
			}
			catch (Exception ex)
			{
				((MelonBase)this).LoggerInstance.Error("Error initializing MLVScan: " + ex.Message);
				((MelonBase)this).LoggerInstance.Error(ex.StackTrace);
			}
		}

		public override void OnGUI()
		{
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			if (_showUploadConsentPopup)
			{
				float num = Math.Min(620f, (float)Screen.width - 40f);
				float num2 = 280f;
				float num3 = ((float)Screen.width - num) / 2f;
				float num4 = ((float)Screen.height - num2) / 2f;
				GUI.Box(new Rect(0f, 0f, (float)Screen.width, (float)Screen.height), string.Empty);
				GUI.Box(new Rect(num3, num4, num, num2), "MLVScan Upload Consent");
				GUI.Label(new Rect(num3 + 20f, num4 + 40f, num - 40f, 140f), "MLVScan flagged " + _pendingUploadModName + " as suspicious and disabled it.\n\nWould you like to upload this file to the MLVScan API for human review?\n\nYes: upload this mod now and enable automatic uploads for future detections.\nNo: do not upload and do not show this prompt again.");
				if (GUI.Button(new Rect(num3 + 20f, num4 + num2 - 60f, (num - 60f) / 2f, 36f), "Yes, upload"))
				{
					HandleUploadConsentDecision(approved: true);
				}
				if (GUI.Button(new Rect(num3 + 40f + (num - 60f) / 2f, num4 + num2 - 60f, (num - 60f) / 2f, 36f), "No thanks"))
				{
					HandleUploadConsentDecision(approved: false);
				}
			}
		}

		private void InitializeDefaultWhitelist()
		{
			if (_configManager != null)
			{
				string[] whitelistedHashes = _configManager.GetWhitelistedHashes();
				if (whitelistedHashes.Length == 0)
				{
					((MelonBase)this).LoggerInstance.Msg("Initializing default whitelist");
					_configManager.SetWhitelistedHashes(DefaultWhitelistedHashes);
				}
			}
		}

		public Dictionary<string, ScannedPluginResult> ScanAndDisableMods(bool force = false)
		{
			try
			{
				if (!_initialized)
				{
					((MelonBase)this).LoggerInstance.Error("Cannot scan mods - MLVScan not properly initialized");
					return new Dictionary<string, ScannedPluginResult>();
				}
				((MelonBase)this).LoggerInstance.Msg("Scanning for suspicious mods...");
				Dictionary<string, ScannedPluginResult> source = _pluginScanner.ScanAllPlugins(force);
				Dictionary<string, ScannedPluginResult> dictionary = source.Where((KeyValuePair<string, ScannedPluginResult> kv) => kv.Value != null && kv.Value.Findings.Count > 0).ToDictionary((KeyValuePair<string, ScannedPluginResult> kv) => kv.Key, (KeyValuePair<string, ScannedPluginResult> kv) => kv.Value);
				if (dictionary.Count > 0)
				{
					List<DisabledPluginInfo> list = _pluginDisabler.DisableSuspiciousPlugins(dictionary, force);
					int count = list.Count;
					((MelonBase)this).LoggerInstance.Msg($"Disabled {count} suspicious mods");
					if (count <= 0)
					{
						return dictionary;
					}
					GenerateDetailedReports(list, dictionary);
					((MelonBase)this).LoggerInstance.Msg("To whitelist any false positives, add their SHA256 hash to the MLVScan → WhitelistedHashes setting in MelonPreferences.cfg");
				}
				else
				{
					((MelonBase)this).LoggerInstance.Msg("No suspicious mods found");
				}
				return dictionary;
			}
			catch (Exception ex)
			{
				((MelonBase)this).LoggerInstance.Error("Error scanning mods: " + ex.Message);
				return new Dictionary<string, ScannedPluginResult>();
			}
		}

		private void GenerateDetailedReports(List<DisabledPluginInfo> disabledMods, Dictionary<string, ScannedPluginResult> scanResults)
		{
			bool valueOrDefault = (_configManager?.Config?.Scan?.DeveloperMode).GetValueOrDefault();
			if (valueOrDefault)
			{
				((MelonBase)this).LoggerInstance.Msg("Developer Mode: Enabled");
			}
			((MelonBase)this).LoggerInstance.Warning("======= DETAILED SCAN REPORT =======");
			((MelonBase)this).LoggerInstance.Msg(PlatformConstants.GetFullVersionInfo());
			foreach (DisabledPluginInfo disabledMod in disabledMods)
			{
				string fileName = Path.GetFileName(disabledMod.OriginalPath);
				string fileHash = disabledMod.FileHash;
				string text = (File.Exists(disabledMod.DisabledPath) ? disabledMod.DisabledPath : disabledMod.OriginalPath);
				((MelonBase)this).LoggerInstance.Warning("BLOCKED MOD: " + fileName);
				((MelonBase)this).LoggerInstance.Msg("SHA256 Hash: " + fileHash);
				((MelonBase)this).LoggerInstance.Msg("-------------------------------");
				if (!scanResults.TryGetValue(disabledMod.OriginalPath, out var value))
				{
					((MelonBase)this).LoggerInstance.Error("Could not find scan results for disabled mod");
					continue;
				}
				List<ScanFinding> list = value?.Findings ?? new List<ScanFinding>();
				ThreatVerdictInfo threatVerdictInfo = disabledMod.ThreatVerdict ?? value?.ThreatVerdict ?? new ThreatVerdictInfo();
				if (list.Count == 0)
				{
					((MelonBase)this).LoggerInstance.Msg("No specific suspicious patterns were identified.");
					continue;
				}
				QueueConsentPromptIfNeeded(text, fileName, list);
				Dictionary<string, List<ScanFinding>> dictionary = (from f in list
					group f by f.Description).ToDictionary((IGrouping<string, ScanFinding> g) => g.Key, (IGrouping<string, ScanFinding> g) => g.ToList());
				((MelonBase)this).LoggerInstance.Warning($"Total suspicious patterns found: {list.Count}");
				((MelonBase)this).LoggerInstance.Warning("Verdict: " + ThreatVerdictTextFormatter.GetVerdictLabel(threatVerdictInfo));
				((MelonBase)this).LoggerInstance.Msg(threatVerdictInfo.Summary);
				string primaryFamilyLabel = ThreatVerdictTextFormatter.GetPrimaryFamilyLabel(threatVerdictInfo);
				if (!string.IsNullOrWhiteSpace(primaryFamilyLabel))
				{
					((MelonBase)this).LoggerInstance.Msg("Family: " + primaryFamilyLabel);
				}
				string confidenceLabel = ThreatVerdictTextFormatter.GetConfidenceLabel(threatVerdictInfo);
				if (!string.IsNullOrWhiteSpace(confidenceLabel))
				{
					((MelonBase)this).LoggerInstance.Msg("Confidence: " + confidenceLabel);
				}
				Dictionary<Severity, int> dictionary2 = (from f in list
					group f by f.Severity into g
					orderby (int)g.Key descending
					select g).ToDictionary((IGrouping<Severity, ScanFinding> g) => g.Key, (IGrouping<Severity, ScanFinding> g) => g.Count());
				((MelonBase)this).LoggerInstance.Warning("Severity breakdown:");
				foreach (KeyValuePair<Severity, int> item in dictionary2)
				{
					string arg = FormatSeverityLabel(item.Key);
					((MelonBase)this).LoggerInstance.Msg($"  {arg}: {item.Value} issue(s)");
				}
				((MelonBase)this).LoggerInstance.Msg("-------------------------------");
				List<string> topFindingSummaries = ThreatVerdictTextFormatter.GetTopFindingSummaries(list);
				if (topFindingSummaries.Count > 0)
				{
					((MelonBase)this).LoggerInstance.Warning("Top signals:");
					foreach (string item2 in topFindingSummaries)
					{
						((MelonBase)this).LoggerInstance.Msg("  - " + item2);
					}
				}
				if (valueOrDefault)
				{
					((MelonBase)this).LoggerInstance.Msg("Developer mode is enabled. Full remediation guidance is included in the report file.");
				}
				((MelonBase)this).LoggerInstance.Msg("Full technical details were written to the saved report file for human review.");
				((MelonBase)this).LoggerInstance.Msg("-------------------------------");
				DisplaySecurityNotice(fileName, threatVerdictInfo);
				try
				{
					string text2 = Path.Combine(MelonEnvironment.UserDataDirectory, "MLVScan", "Reports");
					if (!Directory.Exists(text2))
					{
						Directory.CreateDirectory(text2);
					}
					string text3 = DateTime.Now.ToString("yyyyMMdd_HHmmss");
					string text4 = Path.Combine(text2, fileName + "_" + text3 + ".report.txt");
					string text5 = Path.Combine(text2, "Prompts");
					if (!Directory.Exists(text5))
					{
						Directory.CreateDirectory(text5);
					}
					MelonConfigManager configManager = _configManager;
					if (configManager != null && (configManager.Config?.DumpFullIlReports).GetValueOrDefault() && _ilDumpService != null)
					{
						string path = Path.Combine(text2, "IL");
						string text6 = Path.Combine(path, fileName + "_" + text3 + ".il.txt");
						if (_ilDumpService.TryDumpAssembly(text, text6))
						{
							((MelonBase)this).LoggerInstance.Msg("Full IL dump saved to: " + text6);
						}
						else
						{
							((MelonBase)this).LoggerInstance.Warning("Failed to dump IL for this mod (see logs for details).");
						}
					}
					PromptGeneratorService promptGeneratorService = _serviceFactory.CreatePromptGenerator();
					using (StreamWriter streamWriter = new StreamWriter(text4))
					{
						if (valueOrDefault && _developerReportGenerator != null)
						{
							string value2 = _developerReportGenerator.GenerateFileReport(fileName, fileHash, list, threatVerdictInfo);
							streamWriter.Write(value2);
						}
						else
						{
							streamWriter.WriteLine("MLVScan Security Report");
							streamWriter.WriteLine(PlatformConstants.GetFullVersionInfo());
							streamWriter.WriteLine($"Generated: {DateTime.Now}");
							streamWriter.WriteLine("Mod File: " + fileName);
							streamWriter.WriteLine("SHA256 Hash: " + fileHash);
							streamWriter.WriteLine("Original Path: " + disabledMod.OriginalPath);
							streamWriter.WriteLine("Disabled Path: " + disabledMod.DisabledPath);
							streamWriter.WriteLine("Path Used For Analysis: " + text);
							streamWriter.WriteLine($"Total Suspicious Patterns: {list.Count}");
							streamWriter.WriteLine();
							ThreatVerdictTextFormatter.WriteThreatVerdictSection(streamWriter, threatVerdictInfo);
							streamWriter.WriteLine("\nSeverity Breakdown:");
							foreach (KeyValuePair<Severity, int> item3 in dictionary2)
							{
								streamWriter.WriteLine($"- {item3.Key}: {item3.Value} issue(s)");
							}
							streamWriter.WriteLine("==============================================");
							foreach (KeyValuePair<string, List<ScanFinding>> item4 in dictionary)
							{
								streamWriter.WriteLine("\n== " + item4.Key + " ==");
								streamWriter.WriteLine($"Severity: {item4.Value[0].Severity}");
								streamWriter.WriteLine($"Instances: {item4.Value.Count}");
								streamWriter.WriteLine("\nLocations & Analysis:");
								foreach (ScanFinding item5 in item4.Value)
								{
									streamWriter.WriteLine("- " + item5.Location);
									if (item5.HasCallChain && item5.CallChain != null)
									{
										streamWriter.WriteLine("  Call Chain Analysis:");
										streamWriter.WriteLine("  " + item5.CallChain.Summary);
										streamWriter.WriteLine("  Attack Path:");
										foreach (CallChainNode node in item5.CallChain.Nodes)
										{
											CallChainNodeType nodeType = node.NodeType;
											if (1 == 0)
											{
											}
											string text7 = nodeType switch
											{
												CallChainNodeType.EntryPoint => "[ENTRY]", 
												CallChainNodeType.IntermediateCall => "[CALL]", 
												CallChainNodeType.SuspiciousDeclaration => "[DECL]", 
												_ => "[???]", 
											};
											if (1 == 0)
											{
											}
											string text8 = text7;
											streamWriter.WriteLine("    " + text8 + " " + node.Location);
											if (!string.IsNullOrEmpty(node.Description))
											{
												streamWriter.WriteLine("         " + node.Description);
											}
										}
									}
									if (item5.HasDataFlow && item5.DataFlowChain != null)
									{
										streamWriter.WriteLine("  Data Flow Analysis:");
										streamWriter.WriteLine($"  Pattern: {item5.DataFlowChain.Pattern}");
										streamWriter.WriteLine($"  Confidence: {item5.DataFlowChain.Confidence * 100.0:F0}%");
										streamWriter.WriteLine("  " + item5.DataFlowChain.Summary);
										if (item5.DataFlowChain.IsCrossMethod)
										{
											streamWriter.WriteLine($"  Cross-method flow through {item5.DataFlowChain.InvolvedMethods.Count} methods");
										}
										streamWriter.WriteLine("  Data Flow Chain:");
										foreach (DataFlowNode node2 in item5.DataFlowChain.Nodes)
										{
											DataFlowNodeType nodeType2 = node2.NodeType;
											if (1 == 0)
											{
											}
											string text7 = nodeType2 switch
											{
												DataFlowNodeType.Source => "[SOURCE]", 
												DataFlowNodeType.Transform => "[TRANSFORM]", 
												DataFlowNodeType.Sink => "[SINK]", 
												DataFlowNodeType.Intermediate => "[PASS]", 
												_ => "[???]", 
											};
											if (1 == 0)
											{
											}
											string text9 = text7;
											streamWriter.WriteLine("    " + text9 + " " + node2.Operation + " (" + node2.DataDescription + ") @ " + node2.Location);
										}
									}
									if (!string.IsNullOrEmpty(item5.CodeSnippet))
									{
										streamWriter.WriteLine("  Code Snippet (IL):");
										string[] array = item5.CodeSnippet.Split(new char[2] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
										foreach (string text10 in array)
										{
											streamWriter.WriteLine("    " + text10);
										}
										streamWriter.WriteLine();
									}
								}
							}
							WriteSecurityNoticeToReport(streamWriter);
						}
					}
					if (promptGeneratorService.SavePromptToFile(text, list, text5))
					{
						((MelonBase)this).LoggerInstance.Msg("Detailed report saved to: " + text4);
						((MelonBase)this).LoggerInstance.Msg("LLM analysis prompt saved to: " + Path.Combine(text5, fileName + ".prompt.md"));
						((MelonBase)this).LoggerInstance.Msg("You can copy the contents of the prompt file into ChatGPT to help determine if this is malware or a false positive, although don't trust ChatGPT to be 100% accurate.");
					}
					else
					{
						((MelonBase)this).LoggerInstance.Msg("Detailed report saved to: " + text4);
					}
					MelonConfigManager configManager2 = _configManager;
					if (configManager2 == null || !(configManager2.Config?.EnableReportUpload).GetValueOrDefault() || _reportUploadService == null)
					{
						continue;
					}
					try
					{
						string reportUploadApiBaseUrl = _configManager.GetReportUploadApiBaseUrl();
						if (!string.IsNullOrWhiteSpace(reportUploadApiBaseUrl) && File.Exists(text))
						{
							byte[] assemblyBytes = File.ReadAllBytes(text);
							SubmissionMetadata metadata = BuildSubmissionMetadata(fileName, list);
							_reportUploadService.UploadReportNonBlocking(assemblyBytes, fileName, metadata, reportUploadApiBaseUrl);
						}
					}
					catch (Exception ex)
					{
						((MelonBase)this).LoggerInstance.Warning("Report upload skipped for " + fileName + ": " + ex.Message);
					}
				}
				catch (Exception ex2)
				{
					((MelonBase)this).LoggerInstance.Error("Failed to save detailed report: " + ex2.Message);
				}
			}
			((MelonBase)this).LoggerInstance.Warning("====== END OF SCAN REPORT ======");
		}

		private void QueueConsentPromptIfNeeded(string accessiblePath, string modName, List<ScanFinding> findings)
		{
			if (_configManager != null && !_showUploadConsentPopup)
			{
				MLVScanConfig config = _configManager.Config;
				if (!config.ReportUploadConsentAsked)
				{
					_showUploadConsentPopup = true;
					_pendingUploadPath = accessiblePath;
					_pendingUploadModName = modName;
					_pendingUploadFindings = findings;
					config.ReportUploadConsentPending = true;
					config.PendingReportUploadPath = accessiblePath ?? string.Empty;
					_configManager.SaveConfig(config);
					((MelonBase)this).LoggerInstance.Warning("MLVScan is waiting for your upload consent decision in the in-game popup.");
				}
			}
		}

		private void HandleUploadConsentDecision(bool approved)
		{
			_showUploadConsentPopup = false;
			if (_configManager == null)
			{
				return;
			}
			MLVScanConfig config = _configManager.Config;
			config.ReportUploadConsentAsked = true;
			config.ReportUploadConsentPending = false;
			config.PendingReportUploadPath = string.Empty;
			config.EnableReportUpload = approved;
			_configManager.SaveConfig(config);
			if (!approved)
			{
				((MelonBase)this).LoggerInstance.Msg("MLVScan report upload declined. You will not be prompted again.");
				_pendingUploadPath = string.Empty;
				_pendingUploadModName = string.Empty;
				_pendingUploadFindings = null;
				return;
			}
			((MelonBase)this).LoggerInstance.Msg("MLVScan report upload enabled. Uploading the flagged mod now.");
			try
			{
				if (_reportUploadService != null && !string.IsNullOrWhiteSpace(_pendingUploadPath) && File.Exists(_pendingUploadPath))
				{
					string reportUploadApiBaseUrl = _configManager.GetReportUploadApiBaseUrl();
					if (!string.IsNullOrWhiteSpace(reportUploadApiBaseUrl))
					{
						byte[] assemblyBytes = File.ReadAllBytes(_pendingUploadPath);
						SubmissionMetadata metadata = BuildSubmissionMetadata(_pendingUploadModName, _pendingUploadFindings ?? new List<ScanFinding>());
						_reportUploadService.UploadReportNonBlocking(assemblyBytes, _pendingUploadModName, metadata, reportUploadApiBaseUrl);
					}
				}
			}
			catch (Exception ex)
			{
				((MelonBase)this).LoggerInstance.Warning("Report upload skipped for " + _pendingUploadModName + ": " + ex.Message);
			}
			finally
			{
				_pendingUploadPath = string.Empty;
				_pendingUploadModName = string.Empty;
				_pendingUploadFindings = null;
			}
		}

		private static SubmissionMetadata BuildSubmissionMetadata(string modName, List<ScanFinding> findings)
		{
			List<FindingSummaryItem> findingSummary = (from f in findings.Take(20)
				select new FindingSummaryItem
				{
					RuleId = f.RuleId,
					Description = f.Description,
					Severity = f.Severity.ToString(),
					Location = RedactionHelper.RedactLocation(f.Location)
				}).ToList();
			return new SubmissionMetadata
			{
				LoaderType = "MelonLoader",
				LoaderVersion = null,
				PluginVersion = "1.6.6",
				ModName = RedactionHelper.RedactFilename(modName),
				FindingSummary = findingSummary,
				ConsentVersion = "1",
				ConsentTimestamp = DateTime.UtcNow.ToString("o")
			};
		}

		private static string FormatSeverityLabel(Severity severity)
		{
			if (1 == 0)
			{
			}
			string result = severity switch
			{
				Severity.Critical => "CRITICAL", 
				Severity.High => "HIGH", 
				Severity.Medium => "MEDIUM", 
				Severity.Low => "LOW", 
				_ => severity.ToString().ToUpper(), 
			};
			if (1 == 0)
			{
			}
			return result;
		}

		private void DisplaySecurityNotice(string modName, ThreatVerdictInfo threatVerdict)
		{
			((MelonBase)this).LoggerInstance.Warning("IMPORTANT SECURITY NOTICE");
			((MelonBase)this).LoggerInstance.Msg("MLVScan has detected and disabled " + modName + " before it was loaded.");
			if ((threatVerdict != null && threatVerdict.Kind == ThreatVerdictKind.KnownMaliciousSample) || (threatVerdict != null && threatVerdict.Kind == ThreatVerdictKind.KnownMalwareFamily))
			{
				((MelonBase)this).LoggerInstance.Msg("This block was reinforced by a match to previously analyzed malware.");
				((MelonBase)this).LoggerInstance.Msg("If this is your first time running the game with this mod, your PC is likely safe.");
				((MelonBase)this).LoggerInstance.Msg("However, if you've previously run the game with this mod, your system MAY be infected.");
			}
			else
			{
				((MelonBase)this).LoggerInstance.Msg("This mod was blocked as a precaution based on suspicious behavior patterns.");
				((MelonBase)this).LoggerInstance.Msg("Keep in mind that no detection system is perfect, and this mod may still be falsely flagged.");
			}
			((MelonBase)this).LoggerInstance.Warning("Recommended security steps:");
			((MelonBase)this).LoggerInstance.Msg("1. Check with the modding community first - no detection is perfect");
			((MelonBase)this).LoggerInstance.Msg("   Join the modding Discord at: https://discord.gg/UD4K4chKak");
			((MelonBase)this).LoggerInstance.Msg("   Ask about this mod in the MLVScan thread of #mod-releases to confirm if it's actually malicious");
			((MelonBase)this).LoggerInstance.Msg("2. Run a full system scan with a trusted antivirus like Malwarebytes");
			((MelonBase)this).LoggerInstance.Msg("   Malwarebytes is recommended as a free and effective antivirus solution");
			((MelonBase)this).LoggerInstance.Msg("3. Use Microsoft Safety Scanner for a secondary scan");
			((MelonBase)this).LoggerInstance.Msg("4. Change important passwords if antivirus shows a threat");
			((MelonBase)this).LoggerInstance.Warning("Resources for malware removal:");
			((MelonBase)this).LoggerInstance.Msg("- Malwarebytes: https://www.malwarebytes.com/cybersecurity/basics/how-to-remove-virus-from-computer");
			((MelonBase)this).LoggerInstance.Msg("- Microsoft Safety Scanner: https://learn.microsoft.com/en-us/defender-endpoint/safety-scanner-download");
		}

		private static void WriteSecurityNoticeToReport(StreamWriter writer)
		{
			writer.WriteLine("\n\n============== SECURITY NOTICE ==============\n");
			writer.WriteLine("IMPORTANT: READ THIS SECURITY INFORMATION\n");
			writer.WriteLine("MLVScan has detected and disabled this mod before it was loaded.");
			writer.WriteLine("This mod contains code patterns commonly associated with malware.\n");
			writer.WriteLine("YOUR SYSTEM SECURITY STATUS:");
			writer.WriteLine("- If this is your FIRST TIME starting the game with this mod installed:");
			writer.WriteLine("  Your PC is likely SAFE as MLVScan prevented the mod from loading.");
			writer.WriteLine("\n- If you have PREVIOUSLY PLAYED the game with this mod loaded:");
			writer.WriteLine("  Your system MAY BE INFECTED with malware. Take action immediately.\n");
			writer.WriteLine("RECOMMENDED SECURITY STEPS:");
			writer.WriteLine("1. Check with the modding community first - no detection system is perfect");
			writer.WriteLine("   Join the modding Discord at: https://discord.gg/UD4K4chKak");
			writer.WriteLine("   Ask about this mod in the #MLVScan or #report-mods channels to confirm if it's actually malicious");
			writer.WriteLine("\n2. Run a full system scan with a reputable antivirus program");
			writer.WriteLine("   Free option: Malwarebytes (https://www.malwarebytes.com/)");
			writer.WriteLine("   Malwarebytes is recommended as a free and effective antivirus solution");
			writer.WriteLine("\n3. Run Microsoft Safety Scanner as a secondary check");
			writer.WriteLine("   Download: https://learn.microsoft.com/en-us/defender-endpoint/safety-scanner-download");
			writer.WriteLine("\n4. Update all your software from official sources");
			writer.WriteLine("\n5. Change passwords for important accounts (from a clean device if possible)");
			writer.WriteLine("\n6. Monitor your accounts for any suspicious activity");
			writer.WriteLine("\nDETAILED MALWARE REMOVAL GUIDES:");
			writer.WriteLine("- Malwarebytes Guide: https://www.malwarebytes.com/cybersecurity/basics/how-to-remove-virus-from-computer");
			writer.WriteLine("- Microsoft Safety Scanner: https://learn.microsoft.com/en-us/defender-endpoint/safety-scanner-download");
			writer.WriteLine("- XWorm (Common Modding Malware) Removal Guide: https://www.pcrisk.com/removal-guides/27436-xworm-rat");
			writer.WriteLine("\n=============================================");
		}
	}
	public class MelonLoaderServiceFactory
	{
		private readonly Instance _melonLogger;

		private readonly IScanLogger _scanLogger;

		private readonly IAssemblyResolverProvider _resolverProvider;

		private readonly MelonConfigManager _configManager;

		private readonly MelonPlatformEnvironment _environment;

		private readonly MLVScanConfig _fallbackConfig;

		public MelonLoaderServiceFactory(Instance logger)
		{
			_melonLogger = logger ?? throw new ArgumentNullException("logger");
			_scanLogger = new MelonScanLogger(logger);
			_resolverProvider = new GameAssemblyResolverProvider();
			_environment = new MelonPlatformEnvironment();
			_fallbackConfig = new MLVScanConfig();
			try
			{
				_configManager = new MelonConfigManager(logger);
			}
			catch (Exception ex)
			{
				_melonLogger.Error("Failed to create ConfigManager: " + ex.Message);
				_melonLogger.Msg("Using default configuration values");
			}
		}

		public MelonConfigManager CreateConfigManager()
		{
			if (_configManager == null)
			{
				throw new InvalidOperationException("Configuration manager unavailable: failed to initialize during factory construction.");
			}
			return _configManager;
		}

		public MelonPlatformEnvironment CreateEnvironment()
		{
			return _environment;
		}

		public AssemblyScanner CreateAssemblyScanner()
		{
			MLVScanConfig mLVScanConfig = _configManager?.Config ?? _fallbackConfig;
			IReadOnlyList<IScanRule> rules = RuleFactory.CreateDefaultRules();
			return new AssemblyScanner(rules, mLVScanConfig.Scan, _resolverProvider);
		}

		public MelonPluginScanner CreatePluginScanner()
		{
			MLVScanConfig config = _configManager?.Config ?? _fallbackConfig;
			return new MelonPluginScanner(_scanLogger, _resolverProvider, config, _configManager, _environment);
		}

		public MelonPluginDisabler CreatePluginDisabler()
		{
			MLVScanConfig config = _configManager?.Config ?? _fallbackConfig;
			return new MelonPluginDisabler(_scanLogger, config);
		}

		public PromptGeneratorService CreatePromptGenerator()
		{
			MLVScanConfig mLVScanConfig = _configManager?.Config ?? _fallbackConfig;
			return new PromptGeneratorService(mLVScanConfig.Scan, _scanLogger);
		}

		public IlDumpService CreateIlDumpService()
		{
			return new IlDumpService(_scanLogger, _environment);
		}

		public DeveloperReportGenerator CreateDeveloperReportGenerator()
		{
			return new DeveloperReportGenerator(_scanLogger);
		}

		public ReportUploadService CreateReportUploadService()
		{
			return new ReportUploadService(_configManager, delegate(string msg)
			{
				_melonLogger.Msg(msg);
			}, delegate(string msg)
			{
				_melonLogger.Warning(msg);
			}, delegate(string msg)
			{
				_melonLogger.Error(msg);
			});
		}
	}
	public class MelonConfigManager : IConfigManager
	{
		private readonly Instance _logger;

		private readonly MelonPreferences_Category _category;

		private readonly MelonPreferences_Entry<bool> _enableAutoScan;

		private readonly MelonPreferences_Entry<bool> _enableAutoDisable;

		private readonly MelonPreferences_Entry<string> _minSeverityForDisable;

		private readonly MelonPreferences_Entry<string[]> _scanDirectories;

		private readonly MelonPreferences_Entry<int> _suspiciousThreshold;

		private readonly MelonPreferences_Entry<string[]> _whitelistedHashes;

		private readonly MelonPreferences_Entry<bool> _dumpFullIlReports;

		private readonly MelonPreferences_Entry<bool> _developerMode;

		private readonly MelonPreferences_Entry<bool> _enableReportUpload;

		private readonly MelonPreferences_Entry<bool> _reportUploadConsentAsked;

		private readonly MelonPreferences_Entry<bool> _reportUploadConsentPending;

		private readonly MelonPreferences_Entry<string> _pendingReportUploadPath;

		private readonly MelonPreferences_Entry<string> _reportUploadApiBaseUrl;

		private readonly MelonPreferences_Entry<string[]> _uploadedReportHashes;

		public MLVScanConfig Config { get; private set; }

		public MelonConfigManager(Instance logger)
		{
			_logger = logger ?? throw new ArgumentNullException("logger");
			try
			{
				_category = MelonPreferences.CreateCategory("MLVScan");
				_enableAutoScan = _category.CreateEntry<bool>("EnableAutoScan", true, (string)null, "Whether to scan mods at startup", false, false, (ValueValidator)null, (string)null);
				_enableAutoDisable = _category.CreateEntry<bool>("EnableAutoDisable", true, (string)null, "Whether to disable suspicious mods", false, false, (ValueValidator)null, (string)null);
				_minSeverityForDisable = _category.CreateEntry<string>("MinSeverityForDisable", "Medium", (string)null, "Minimum severity level to trigger disabling (Low, Medium, High, Critical)", false, false, (ValueValidator)null, (string)null);
				_scanDirectories = _category.CreateEntry<string[]>("ScanDirectories", new string[2] { "Mods", "Plugins" }, (string)null, "Directories to scan for mods", false, false, (ValueValidator)null, (string)null);
				_suspiciousThreshold = _category.CreateEntry<int>("SuspiciousThreshold", 1, (string)null, "How many suspicious findings required before disabling a mod", false, false, (ValueValidator)null, (string)null);
				_whitelistedHashes = _category.CreateEntry<string[]>("WhitelistedHashes", Array.Empty<string>(), (string)null, "List of mod SHA256 hashes to skip when scanning", false, false, (ValueValidator)null, (string)null);
				_dumpFullIlReports = _category.CreateEntry<bool>("DumpFullIlReports", false, (string)null, "When enabled, saves full IL dumps for scanned mods next to reports", false, false, (ValueValidator)null, (string)null);
				_developerMode = _category.CreateEntry<bool>("DeveloperMode", false, (string)null, "Developer mode: Shows remediation guidance to help mod developers fix false positives", false, false, (ValueValidator)null, (string)null);
				_enableReportUpload = _category.CreateEntry<bool>("EnableReportUpload", false, (string)null, "When enabled (and consent given), send reports to MLVScan API for false positive analysis", false, false, (ValueValidator)null, (string)null);
				_reportUploadConsentAsked = _category.CreateEntry<bool>("ReportUploadConsentAsked", false, (string)null, "Whether the first-run consent prompt has been shown (internal)", false, false, (ValueValidator)null, (string)null);
				_reportUploadConsentPending = _category.CreateEntry<bool>("ReportUploadConsentPending", false, (string)null, "Whether an upload consent popup is pending (internal)", false, false, (ValueValidator)null, (string)null);
				_pendingReportUploadPath = _category.CreateEntry<string>("PendingReportUploadPath", string.Empty, (string)null, "Suspicious mod path waiting for upload consent (internal)", false, false, (ValueValidator)null, (string)null);
				_reportUploadApiBaseUrl = _category.CreateEntry<string>("ReportUploadApiBaseUrl", "https://api.mlvscan.com", (string)null, "API base URL for report uploads", false, false, (ValueValidator)null, (string)null);
				_uploadedReportHashes = _category.CreateEntry<string[]>("UploadedReportHashes", Array.Empty<string>(), (string)null, "List of assembly SHA256 hashes already uploaded to the MLVScan API (internal)", false, false, (ValueValidator)null, (string)null);
				((MelonEventBase<LemonAction<bool, bool>>)(object)_enableAutoScan.OnEntryValueChanged).Subscribe((LemonAction<bool, bool>)OnConfigChanged, 0, false);
				((MelonEventBase<LemonAction<bool, bool>>)(object)_enableAutoDisable.OnEntryValueChanged).Subscribe((LemonAction<bool, bool>)OnConfigChanged, 0, false);
				((MelonEventBase<LemonAction<string, string>>)(object)_minSeverityForDisable.OnEntryValueChanged).Subscribe((LemonAction<string, string>)OnConfigChanged, 0, false);
				((MelonEventBase<LemonAction<string[], string[]>>)(object)_scanDirectories.OnEntryValueChanged).Subscribe((LemonAction<string[], string[]>)OnConfigChanged, 0, false);
				((MelonEventBase<LemonAction<int, int>>)(object)_suspiciousThreshold.OnEntryValueChanged).Subscribe((LemonAction<int, int>)OnConfigChanged, 0, false);
				((MelonEventBase<LemonAction<string[], string[]>>)(object)_whitelistedHashes.OnEntryValueChanged).Subscribe((LemonAction<string[], string[]>)OnConfigChanged, 0, false);
				((MelonEventBase<LemonAction<bool, bool>>)(object)_dumpFullIlReports.OnEntryValueChanged).Subscribe((LemonAction<bool, bool>)OnConfigChanged, 0, false);
				((MelonEventBase<LemonAction<bool, bool>>)(object)_developerMode.OnEntryValueChanged).Subscribe((LemonAction<bool, bool>)OnConfigChanged, 0, false);
				((MelonEventBase<LemonAction<bool, bool>>)(object)_enableReportUpload.OnEntryValueChanged).Subscribe((LemonAction<bool, bool>)OnConfigChanged, 0, false);
				((MelonEventBase<LemonAction<bool, bool>>)(object)_reportUploadConsentAsked.OnEntryValueChanged).Subscribe((LemonAction<bool, bool>)OnConfigChanged, 0, false);
				((MelonEventBase<LemonAction<bool, bool>>)(object)_reportUploadConsentPending.OnEntryValueChanged).Subscribe((LemonAction<bool, bool>)OnConfigChanged, 0, false);
				((MelonEventBase<LemonAction<string, string>>)(object)_pendingReportUploadPath.OnEntryValueChanged).Subscribe((LemonAction<string, string>)OnConfigChanged, 0, false);
				((MelonEventBase<LemonAction<string, string>>)(object)_reportUploadApiBaseUrl.OnEntryValueChanged).Subscribe((LemonAction<string, string>)OnConfigChanged, 0, false);
				((MelonEventBase<LemonAction<string[], string[]>>)(object)_uploadedReportHashes.OnEntryValueChanged).Subscribe((LemonAction<string[], string[]>)OnConfigChanged, 0, false);
				UpdateConfigFromPreferences();
				_logger.Msg("Configuration loaded successfully");
			}
			catch (Exception ex)
			{
				_logger.Error("Failed to initialize config system: " + ex.Message);
				_logger.Msg("Using fallback in-memory configuration");
				Config = new MLVScanConfig();
			}
		}

		public MLVScanConfig LoadConfig()
		{
			UpdateConfigFromPreferences();
			return Config;
		}

		private void OnConfigChanged<T>(T oldValue, T newValue)
		{
			UpdateConfigFromPreferences();
			_logger.Msg("Configuration updated");
		}

		private void UpdateConfigFromPreferences()
		{
			Config = new MLVScanConfig
			{
				EnableAutoScan = _enableAutoScan.Value,
				EnableAutoDisable = _enableAutoDisable.Value,
				MinSeverityForDisable = ParseSeverity(_minSeverityForDisable.Value),
				ScanDirectories = _scanDirectories.Value,
				SuspiciousThreshold = _suspiciousThreshold.Value,
				WhitelistedHashes = _whitelistedHashes.Value,
				DumpFullIlReports = _dumpFullIlReports.Value,
				Scan = new ScanConfig
				{
					DeveloperMode = _developerMode.Value
				},
				EnableReportUpload = _enableReportUpload.Value,
				ReportUploadConsentAsked = _reportUploadConsentAsked.Value,
				ReportUploadConsentPending = _reportUploadConsentPending.Value,
				PendingReportUploadPath = _pendingReportUploadPath.Value,
				ReportUploadApiBaseUrl = _reportUploadApiBaseUrl.Value,
				UploadedReportHashes = NormalizeHashes(_uploadedReportHashes.Value)
			};
		}

		public void SaveConfig(MLVScanConfig newConfig)
		{
			try
			{
				_enableAutoScan.Value = newConfig.EnableAutoScan;
				_enableAutoDisable.Value = newConfig.EnableAutoDisable;
				_minSeverityForDisable.Value = FormatSeverity(newConfig.MinSeverityForDisable);
				_scanDirectories.Value = newConfig.ScanDirectories;
				_suspiciousThreshold.Value = newConfig.SuspiciousThreshold;
				_whitelistedHashes.Value = newConfig.WhitelistedHashes;
				_dumpFullIlReports.Value = newConfig.DumpFullIlReports;
				_developerMode.Value = newConfig.Scan?.DeveloperMode ?? false;
				_enableReportUpload.Value = newConfig.EnableReportUpload;
				_reportUploadConsentAsked.Value = newConfig.ReportUploadConsentAsked;
				_reportUploadConsentPending.Value = newConfig.ReportUploadConsentPending;
				_pendingReportUploadPath.Value = newConfig.PendingReportUploadPath ?? string.Empty;
				_reportUploadApiBaseUrl.Value = newConfig.ReportUploadApiBaseUrl;
				_uploadedReportHashes.Value = NormalizeHashes(newConfig.UploadedReportHashes);
				MelonPreferences.Save();
				_logger.Msg("Configuration saved successfully");
			}
			catch (Exception ex)
			{
				_logger.Error("Error saving configuration: " + ex.Message);
				Config = newConfig;
			}
		}

		public string[] GetWhitelistedHashes()
		{
			return _whitelistedHashes.Value;
		}

		public void SetWhitelistedHashes(string[] hashes)
		{
			if (hashes != null)
			{
				string[] array = (from h in hashes
					where !string.IsNullOrWhiteSpace(h)
					select h.ToLowerInvariant()).Distinct<string>(StringComparer.OrdinalIgnoreCase).ToArray();
				_whitelistedHashes.Value = array;
				MelonPreferences.Save();
				UpdateConfigFromPreferences();
				_logger.Msg($"Updated whitelist with {array.Length} hash(es)");
			}
		}

		public bool IsHashWhitelisted(string hash)
		{
			if (string.IsNullOrWhiteSpace(hash))
			{
				return false;
			}
			return Config.WhitelistedHashes.Contains<string>(hash.ToLowerInvariant(), StringComparer.OrdinalIgnoreCase);
		}

		public string GetReportUploadApiBaseUrl()
		{
			return _reportUploadApiBaseUrl.Value;
		}

		public bool IsReportHashUploaded(string hash)
		{
			if (string.IsNullOrWhiteSpace(hash))
			{
				return false;
			}
			return NormalizeHashes(_uploadedReportHashes.Value).Contains<string>(hash.ToLowerInvariant(), StringComparer.OrdinalIgnoreCase);
		}

		public void MarkReportHashUploaded(string hash)
		{
			if (HashUtility.IsValidHash(hash))
			{
				string[] array = NormalizeHashes((_uploadedReportHashes.Value ?? Array.Empty<string>()).Append(hash));
				int num = array.Length;
				string[] value = _uploadedReportHashes.Value;
				if (num != ((value != null) ? value.Length : 0) || !IsReportHashUploaded(hash))
				{
					_uploadedReportHashes.Value = array;
					MelonPreferences.Save();
					UpdateConfigFromPreferences();
					_logger.Msg("Recorded uploaded report hash: " + hash);
				}
			}
		}

		private static Severity ParseSeverity(string severity)
		{
			if (string.IsNullOrWhiteSpace(severity))
			{
				return Severity.Medium;
			}
			string text = severity.ToLower();
			if (1 == 0)
			{
			}
			Severity result = text switch
			{
				"critical" => Severity.Critical, 
				"high" => Severity.High, 
				"medium" => Severity.Medium, 
				"low" => Severity.Low, 
				_ => Severity.Medium, 
			};
			if (1 == 0)
			{
			}
			return result;
		}

		private static string FormatSeverity(Severity severity)
		{
			if (1 == 0)
			{
			}
			string result = severity switch
			{
				Severity.Critical => "Critical", 
				Severity.High => "High", 
				Severity.Medium => "Medium", 
				Severity.Low => "Low", 
				_ => "Medium", 
			};
			if (1 == 0)
			{
			}
			return result;
		}

		private static string[] NormalizeHashes(IEnumerable<string> hashes)
		{
			return (from h in hashes ?? Array.Empty<string>()
				where !string.IsNullOrWhiteSpace(h)
				select h.ToLowerInvariant()).Distinct<string>(StringComparer.OrdinalIgnoreCase).ToArray();
		}
	}
	public class MelonPlatformEnvironment : IPlatformEnvironment
	{
		private readonly string _gameRoot;

		private readonly string _dataDir;

		private readonly string _reportsDir;

		public string GameRootDirectory => _gameRoot;

		public string[] PluginDirectories => new string[2]
		{
			Path.Combine(_gameRoot, "Mods"),
			Path.Combine(_gameRoot, "Plugins")
		};

		public string DataDirectory
		{
			get
			{
				if (!Directory.Exists(_dataDir))
				{
					Directory.CreateDirectory(_dataDir);
				}
				return _dataDir;
			}
		}

		public string ReportsDirectory
		{
			get
			{
				if (!Directory.Exists(_reportsDir))
				{
					Directory.CreateDirectory(_reportsDir);
				}
				return _reportsDir;
			}
		}

		public string ManagedDirectory
		{
			get
			{
				try
				{
					string[] directories = Directory.GetDirectories(_gameRoot, "*_Data");
					string[] array = directories;
					foreach (string path in array)
					{
						string text = Path.Combine(path, "Managed");
						if (Directory.Exists(text))
						{
							return text;
						}
					}
				}
				catch
				{
				}
				string text2 = Path.Combine(_gameRoot, "MelonLoader", "Managed");
				if (Directory.Exists(text2))
				{
					return text2;
				}
				return string.Empty;
			}
		}

		public string SelfAssemblyPath
		{
			get
			{
				try
				{
					return typeof(MelonPlatformEnvironment).Assembly.Location;
				}
				catch
				{
					return string.Empty;
				}
			}
		}

		public string PlatformName => "MelonLoader";

		public MelonPlatformEnvironment()
		{
			_gameRoot = MelonEnvironment.GameRootDirectory;
			_dataDir = Path.Combine(_gameRoot, "MLVScan");
			_reportsDir = Path.Combine(_dataDir, "Reports");
		}
	}
	public class MelonPluginScanner : PluginScannerBase
	{
		[CompilerGenerated]
		private sealed class <GetScanDirectories>d__2 : IEnumerable<string>, IEnumerable, IEnumerator<string>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private string <>2__current;

			private int <>l__initialThreadId;

			public MelonPluginScanner <>4__this;

			private string[] <>s__1;

			private int <>s__2;

			private string <scanDir>5__3;

			string IEnumerator<string>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <GetScanDirectories>d__2(int <>1__state)
			{
				this.<>1__state = <>1__state;
				<>l__initialThreadId = Environment.CurrentManagedThreadId;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>s__1 = null;
				<scanDir>5__3 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>s__1 = <>4__this.Config.ScanDirectories;
					<>s__2 = 0;
					break;
				case 1:
					<>1__state = -1;
					<scanDir>5__3 = null;
					<>s__2++;
					break;
				}
				if (<>s__2 < <>s__1.Length)
				{
					<scanDir>5__3 = <>s__1[<>s__2];
					<>2__current = Path.Combine(<>4__this._environment.GameRootDirectory, <scanDir>5__3);
					<>1__state = 1;
					return true;
				}
				<>s__1 = null;
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}

			[DebuggerHidden]
			IEnumerator<string> IEnumerable<string>.GetEnumerator()
			{
				<GetScanDirectories>d__2 result;
				if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
				{
					<>1__state = 0;
					result = this;
				}
				else
				{
					result = new <GetScanDirectories>d__2(0)
					{
						<>4__this = <>4__this
					};
				}
				return result;
			}

			[DebuggerHidden]
			IEnumerator IEnumerable.GetEnumerator()
			{
				return ((IEnumerable<string>)this).GetEnumerator();
			}
		}

		private readonly MelonPlatformEnvironment _environment;

		public MelonPluginScanner(IScanLogger logger, IAssemblyResolverProvider resolverProvider, MLVScanConfig config, IConfigManager configManager, MelonPlatformEnvironment environment)
			: base(logger, resolverProvider, config, configManager)
		{
			_environment = environment ?? throw new ArgumentNullException("environment");
		}

		[IteratorStateMachine(typeof(<GetScanDirectories>d__2))]
		protected override IEnumerable<string> GetScanDirectories()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <GetScanDirectories>d__2(-2)
			{
				<>4__this = this
			};
		}

		protected override bool IsSelfAssembly(string filePath)
		{
			try
			{
				string selfAssemblyPath = _environment.SelfAssemblyPath;
				if (string.IsNullOrEmpty(selfAssemblyPath))
				{
					return false;
				}
				return Path.GetFullPath(filePath).Equals(Path.GetFullPath(selfAssemblyPath), StringComparison.OrdinalIgnoreCase);
			}
			catch
			{
				return false;
			}
		}

		protected override void OnScanComplete(Dictionary<string, ScannedPluginResult> results)
		{
			ScanThunderstoreModManager(results);
		}

		private void ScanThunderstoreModManager(Dictionary<string, ScannedPluginResult> results)
		{
			try
			{
				string folderPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
				string path = Path.Combine(folderPath, "Thunderstore Mod Manager", "DataFolder");
				if (!Directory.Exists(path))
				{
					return;
				}
				string[] directories = Directory.GetDirectories(path);
				foreach (string path2 in directories)
				{
					string path3 = Path.Combine(path2, "profiles");
					if (!Directory.Exists(path3))
					{
						continue;
					}
					string[] directories2 = Directory.GetDirectories(path3);
					foreach (string path4 in directories2)
					{
						string text = Path.Combine(path4, "Mods");
						if (Directory.Exists(text))
						{
							Logger.Info("Scanning Thunderstore profile mods: " + text);
							ScanDirectory(text, results);
						}
						string text2 = Path.Combine(path4, "Plugins");
						if (Directory.Exists(text2))
						{
							Logger.Info("Scanning Thunderstore profile plugins: " + text2);
							ScanDirectory(text2, results);
						}
					}
				}
			}
			catch (Exception ex)
			{
				Logger.Error("Error scanning Thunderstore Mod Manager directories: " + ex.Message);
			}
		}
	}
	public class MelonPluginDisabler : PluginDisablerBase
	{
		private const string DisabledExtension = ".disabled";

		public MelonPluginDisabler(IScanLogger logger, MLVScanConfig config)
			: base(logger, config)
		{
		}

		protected override string GetDisabledExtension()
		{
			return ".disabled";
		}

		protected override string GetDisabledPath(string originalPath)
		{
			return Path.ChangeExtension(originalPath, ".disabled");
		}
	}
}
namespace MLVScan.Services
{
	public abstract class PluginScannerBase
	{
		protected readonly IScanLogger Logger;

		protected readonly IAssemblyResolverProvider ResolverProvider;

		protected readonly MLVScanConfig Config;

		protected readonly IConfigManager ConfigManager;

		protected readonly AssemblyScanner AssemblyScanner;

		protected readonly ThreatVerdictBuilder ThreatVerdictBuilder;

		protected PluginScannerBase(IScanLogger logger, IAssemblyResolverProvider resolverProvider, MLVScanConfig config, IConfigManager configManager)
		{
			Logger = logger ?? throw new ArgumentNullException("logger");
			ResolverProvider = resolverProvider ?? throw new ArgumentNullException("resolverProvider");
			Config = config ?? throw new ArgumentNullException("config");
			ConfigManager = configManager ?? throw new ArgumentNullException("configManager");
			IReadOnlyList<IScanRule> rules = RuleFactory.CreateDefaultRules();
			AssemblyScanner = new AssemblyScanner(rules, Config.Scan, ResolverProvider);
			ThreatVerdictBuilder = new ThreatVerdictBuilder();
		}

		protected abstract IEnumerable<string> GetScanDirectories();

		protected abstract bool IsSelfAssembly(string filePath);

		protected virtual void OnScanComplete(Dictionary<string, ScannedPluginResult> results)
		{
		}

		public Dictionary<string, ScannedPluginResult> ScanAllPlugins(bool forceScanning = false)
		{
			Dictionary<string, ScannedPluginResult> dictionary = new Dictionary<string, ScannedPluginResult>();
			if (!forceScanning && !Config.EnableAutoScan)
			{
				Logger.Info("Automatic scanning is disabled in configuration");
				return dictionary;
			}
			foreach (string scanDirectory in GetScanDirectories())
			{
				if (!Directory.Exists(scanDirectory))
				{
					Logger.Warning("Directory not found: " + scanDirectory);
				}
				else
				{
					ScanDirectory(scanDirectory, dictionary);
				}
			}
			OnScanComplete(dictionary);
			return dictionary;
		}

		protected virtual void ScanDirectory(string directoryPath, Dictionary<string, ScannedPluginResult> results)
		{
			string[] files = Directory.GetFiles(directoryPath, "*.dll", SearchOption.AllDirectories);
			Logger.Info($"Found {files.Length} plugin files in {directoryPath}");
			string[] array = files;
			foreach (string text in array)
			{
				try
				{
					ScanSingleFile(text, results);
				}
				catch (Exception ex)
				{
					Logger.Error("Error scanning " + Path.GetFileName(text) + ": " + ex.Message);
				}
			}
		}

		protected virtual void ScanSingleFile(string filePath, Dictionary<string, ScannedPluginResult> results)
		{
			string fileName = Path.GetFileName(filePath);
			string text = HashUtility.CalculateFileHash(filePath);
			if (IsSelfAssembly(filePath))
			{
				Logger.Debug("Skipping self: " + fileName);
				return;
			}
			if (ConfigManager.IsHashWhitelisted(text))
			{
				Logger.Debug("Skipping whitelisted: " + fileName);
				return;
			}
			List<ScanFinding> source = AssemblyScanner.Scan(filePath).ToList();
			List<ScanFinding> list = source.Where((ScanFinding f) => f.Location != "Assembly scanning").ToList();
			ScannedPluginResult scannedPluginResult = ThreatVerdictBuilder.Build(filePath, text, list);
			if (list.Count < Config.SuspiciousThreshold && !scannedPluginResult.ThreatVerdict.ShouldBypassThreshold)
			{
				return;
			}
			results[filePath] = scannedPluginResult;
			if (scannedPluginResult.ThreatVerdict.Kind == ThreatVerdictKind.KnownMaliciousSample || scannedPluginResult.ThreatVerdict.Kind == ThreatVerdictKind.KnownMalwareFamily)
			{
				string text2 = scannedPluginResult.ThreatVerdict.PrimaryFamily?.DisplayName;
				if (!string.IsNullOrWhiteSpace(text2))
				{
					Logger.Warning($"Found {list.Count} suspicious pattern(s) in {fileName} - {scannedPluginResult.ThreatVerdict.Title}: {text2}");
				}
				else
				{
					Logger.Warning($"Found {list.Count} suspicious pattern(s) in {fileName} - {scannedPluginResult.ThreatVerdict.Title}");
				}
			}
			else
			{
				Logger.Warning($"Found {list.Count} suspicious pattern(s) in {fileName}");
			}
		}
	}
	public class DisabledPluginInfo
	{
		public string OriginalPath { get; }

		public string DisabledPath { get; }

		public string FileHash { get; }

		public ThreatVerdictInfo ThreatVerdict { get; }

		public DisabledPluginInfo(string originalPath, string disabledPath, string fileHash, ThreatVerdictInfo threatVerdict)
		{
			OriginalPath = originalPath;
			DisabledPath = disabledPath;
			FileHash = fileHash;
			ThreatVerdict = threatVerdict ?? new ThreatVerdictInfo();
		}
	}
	public abstract class PluginDisablerBase
	{
		protected readonly IScanLogger Logger;

		protected readonly MLVScanConfig Config;

		protected virtual string GetDisabledExtension()
		{
			return ".disabled";
		}

		protected PluginDisablerBase(IScanLogger logger, MLVScanConfig config)
		{
			Logger = logger ?? throw new ArgumentNullException("logger");
			Config = config ?? throw new ArgumentNullException("config");
		}

		protected virtual string GetDisabledPath(string originalPath)
		{
			return Path.ChangeExtension(originalPath, GetDisabledExtension());
		}

		protected virtual void OnPluginDisabled(string originalPath, string disabledPath, string hash)
		{
		}

		public List<DisabledPluginInfo> DisableSuspiciousPlugins(Dictionary<string, ScannedPluginResult> scanResults, bool forceDisable = false)
		{
			if (!forceDisable && !Config.EnableAutoDisable)
			{
				Logger.Info("Automatic disabling is turned off in configuration");
				return new List<DisabledPluginInfo>();
			}
			List<DisabledPluginInfo> list = new List<DisabledPluginInfo>();
			foreach (KeyValuePair<string, ScannedPluginResult> scanResult in scanResults)
			{
				scanResult.Deconstruct(out var key, out var value);
				string text = key;
				ScannedPluginResult scannedPluginResult = value;
				List<ScanFinding> source = scannedPluginResult?.Findings ?? new List<ScanFinding>();
				List<ScanFinding> list2 = source.Where((ScanFinding f) => f.Severity >= Config.MinSeverityForDisable).ToList();
				bool flag = scannedPluginResult != null && (scannedPluginResult.ThreatVerdict?.ShouldBypassThreshold).GetValueOrDefault();
				if (!flag && list2.Count == 0)
				{
					Logger.Info($"Plugin {Path.GetFileName(text)} has findings but none meet severity threshold ({Config.MinSeverityForDisable})");
					continue;
				}
				if (!forceDisable && !flag && list2.Count < Config.SuspiciousThreshold)
				{
					Logger.Info("Plugin " + Path.GetFileName(text) + " below suspicious threshold");
					continue;
				}
				try
				{
					DisabledPluginInfo disabledPluginInfo = DisablePlugin(text, scannedPluginResult?.ThreatVerdict);
					if (disabledPluginInfo != null)
					{
						list.Add(disabledPluginInfo);
						OnPluginDisabled(disabledPluginInfo.OriginalPath, disabledPluginInfo.DisabledPath, disabledPluginInfo.FileHash);
					}
				}
				catch (Exception ex)
				{
					Logger.Error("Failed to disable " + Path.GetFileName(text) + ": " + ex.Message);
				}
			}
			return list;
		}

		protected virtual DisabledPluginInfo DisablePlugin(string pluginPath, ThreatVerdictInfo threatVerdict)
		{
			string fileHash = HashUtility.CalculateFileHash(pluginPath);
			string disabledPath = GetDisabledPath(pluginPath);
			if (File.Exists(disabledPath))
			{
				File.Delete(disabledPath);
			}
			File.Move(pluginPath, disabledPath);
			Logger.Warning("BLOCKED: " + Path.GetFileName(pluginPath));
			return new DisabledPluginInfo(pluginPath, disabledPath, fileHash, threatVerdict);
		}
	}
	public class DeveloperReportGenerator
	{
		private readonly IScanLogger _logger;

		public DeveloperReportGenerator(IScanLogger logger)
		{
			_logger = logger ?? throw new ArgumentNullException("logger");
		}

		public void GenerateConsoleReport(string modName, List<ScanFinding> findings)
		{
			if (findings == null || findings.Count == 0)
			{
				return;
			}
			_logger.Info("======= DEVELOPER SCAN REPORT =======");
			_logger.Info(PlatformConstants.GetFullVersionInfo());
			_logger.Info("Mod: " + modName);
			_logger.Info("--------------------------------------");
			_logger.Info($"Total findings: {findings.Count}");
			_logger.Info("");
			IOrderedEnumerable<IGrouping<string, ScanFinding>> orderedEnumerable = from f in findings
				where f.RuleId != null
				group f by f.RuleId into g
				orderby g.Max((ScanFinding f) => f.Severity) descending
				select g;
			foreach (IGrouping<string, ScanFinding> item in orderedEnumerable)
			{
				ScanFinding scanFinding = item.First();
				int num = item.Count();
				_logger.Info($"[{scanFinding.Severity}] {scanFinding.Description}");
				_logger.Info("  Rule: " + scanFinding.RuleId);
				_logger.Info($"  Occurrences: {num}");
				if (scanFinding.DeveloperGuidance != null)
				{
					_logger.Info("");
					_logger.Info("  Developer Guidance:");
					_logger.Info("  " + WrapText(scanFinding.DeveloperGuidance.Remediation, 2));
					if (!string.IsNullOrEmpty(scanFinding.DeveloperGuidance.DocumentationUrl))
					{
						_logger.Info("  Documentation: " + scanFinding.DeveloperGuidance.DocumentationUrl);
					}
					if (scanFinding.DeveloperGuidance.AlternativeApis != null && scanFinding.DeveloperGuidance.AlternativeApis.Length != 0)
					{
						_logger.Info("  Suggested APIs: " + string.Join(", ", scanFinding.DeveloperGuidance.AlternativeApis));
					}
					if (!scanFinding.DeveloperGuidance.IsRemediable)
					{
						_logger.Warning("  No safe alternative - this pattern should not be used in mods.");
					}
				}
				else
				{
					_logger.Info("  (No developer guidance available for this rule)");
				}
				_logger.Info("");
				_logger.Info("  Findings:");
				foreach (ScanFinding item2 in from f in item
					orderby f.Severity descending, f.Location
					select f)
				{
					_logger.Info("    - " + item2.Location);
					if (item2.HasCallChain && item2.CallChain != null)
					{
						_logger.Info("      Call Chain:");
						foreach (CallChainNode node in item2.CallChain.Nodes)
						{
							CallChainNodeType nodeType = node.NodeType;
							if (1 == 0)
							{
							}
							string text = nodeType switch
							{
								CallChainNodeType.EntryPoint => "[ENTRY]", 
								CallChainNodeType.IntermediateCall => "[CALL]", 
								CallChainNodeType.SuspiciousDeclaration => "[DECL]", 
								_ => "[???]", 
							};
							if (1 == 0)
							{
							}
							string text2 = text;
							_logger.Info("        " + text2 + " " + node.Location);
							if (!string.IsNullOrWhiteSpace(node.Description))
							{
								_logger.Info("             " + node.Description);
							}
						}
					}
					if (!item2.HasDataFlow || item2.DataFlowChain == null)
					{
						continue;
					}
					_logger.Info($"      Data Flow: {item2.DataFlowChain.Pattern} ({item2.DataFlowChain.Confidence * 100.0:F0}%)");
					if (item2.DataFlowChain.IsCrossMethod)
					{
						_logger.Info($"        Cross-method: {item2.DataFlowChain.InvolvedMethods.Count} methods");
					}
					_logger.Info("      Data Flow Chain:");
					foreach (DataFlowNode node2 in item2.DataFlowChain.Nodes)
					{
						DataFlowNodeType nodeType2 = node2.NodeType;
						if (1 == 0)
						{
						}
						string text = nodeType2 switch
						{
							DataFlowNodeType.Source => "[SOURCE]", 
							DataFlowNodeType.Transform => "[TRANSFORM]", 
							DataFlowNodeType.Sink => "[SINK]", 
							DataFlowNodeType.Intermediate => "[PASS]", 
							_ => "[???]", 
						};
						if (1 == 0)
						{
						}
						string text3 = text;
						_logger.Info("        " + text3 + " " + node2.Operation + " (" + node2.DataDescription + ") @ " + node2.Location);
					}
				}
				_logger.Info("--------------------------------------");
			}
			_logger.Info("");
			_logger.Info("For more information, visit: https://discord.gg/UD4K4chKak");
			_logger.Info("=====================================");
		}

		public string GenerateFileReport(string modName, string hash, List<ScanFinding> findings, ThreatVerdictInfo threatVerdict = null)
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine("======= MLVScan Developer Report =======");
			stringBuilder.AppendLine(PlatformConstants.GetFullVersionInfo());
			stringBuilder.AppendLine("Mod: " + modName);
			stringBuilder.AppendLine("SHA256: " + hash);
			stringBuilder.AppendLine($"Scan Date: {DateTime.Now:yyyy-MM-dd HH:mm:ss}");
			stringBuilder.AppendLine($"Total Findings: {findings.Count}");
			stringBuilder.AppendLine("");
			using (StringWriter writer = new StringWriter(stringBuilder))
			{
				ThreatVerdictTextFormatter.WriteThreatVerdictSection(writer, threatVerdict);
			}
			IOrderedEnumerable<IGrouping<string, ScanFinding>> orderedEnumerable = from f in findings
				where f.RuleId != null
				group f by f.RuleId into g
				orderby g.Max((ScanFinding f) => f.Severity) descending
				select g;
			foreach (IGrouping<string, ScanFinding> item in orderedEnumerable)
			{
				ScanFinding scanFinding = item.First();
				int num = item.Count();
				stringBuilder.AppendLine("=========================================");
				stringBuilder.AppendLine("Rule: " + scanFinding.RuleId);
				stringBuilder.AppendLine($"Severity: {scanFinding.Severity}");
				stringBuilder.AppendLine("Description: " + scanFinding.Description);
				stringBuilder.AppendLine($"Occurrences: {num}");
				stringBuilder.AppendLine("");
				if (scanFinding.DeveloperGuidance != null)
				{
					stringBuilder.AppendLine("--- DEVELOPER GUIDANCE ---");
					stringBuilder.AppendLine("Remediation: " + scanFinding.DeveloperGuidance.Remediation);
					stringBuilder.AppendLine("");
					if (!string.IsNullOrEmpty(scanFinding.DeveloperGuidance.DocumentationUrl))
					{
						stringBuilder.AppendLine("Documentation: " + scanFinding.DeveloperGuidance.DocumentationUrl);
					}
					if (scanFinding.DeveloperGuidance.AlternativeApis != null && scanFinding.DeveloperGuidance.AlternativeApis.Length != 0)
					{
						stringBuilder.AppendLine("Suggested APIs:");
						string[] alternativeApis = scanFinding.DeveloperGuidance.AlternativeApis;
						foreach (string text in alternativeApis)
						{
							stringBuilder.AppendLine("  - " + text);
						}
					}
					if (!scanFinding.DeveloperGuidance.IsRemediable)
					{
						stringBuilder.AppendLine("");
						stringBuilder.AppendLine("WARNING: This pattern has no safe alternative and should not be used in mods.");
					}
					stringBuilder.AppendLine("");
				}
				else
				{
					stringBuilder.AppendLine("(No developer guidance available for this rule)");
					stringBuilder.AppendLine("");
				}
				stringBuilder.AppendLine("--- FINDINGS ---");
				foreach (ScanFinding item2 in item)
				{
					stringBuilder.AppendLine("Location: " + item2.Location);
					if (item2.HasCallChain && item2.CallChain != null)
					{
						stringBuilder.AppendLine();
						stringBuilder.AppendLine("--- CALL CHAIN ANALYSIS ---");
						stringBuilder.AppendLine(item2.CallChain.Summary);
						stringBuilder.AppendLine();
						stringBuilder.AppendLine("Attack Path:");
						foreach (CallChainNode node in item2.CallChain.Nodes)
						{
							CallChainNodeType nodeType = node.NodeType;
							if (1 == 0)
							{
							}
							string text2 = nodeType switch
							{
								CallChainNodeType.EntryPoint => "[ENTRY]", 
								CallChainNodeType.IntermediateCall => "[CALL]", 
								CallChainNodeType.SuspiciousDeclaration => "[DECL]", 
								_ => "[???]", 
							};
							if (1 == 0)
							{
							}
							string text3 = text2;
							stringBuilder.AppendLine("  " + text3 + " " + node.Location);
							if (!string.IsNullOrEmpty(node.Description))
							{
								stringBuilder.AppendLine("         " + node.Description);
							}
						}
					}
					if (item2.HasDataFlow && item2.DataFlowChain != null)
					{
						stringBuilder.AppendLine();
						stringBuilder.AppendLine("--- DATA FLOW ANALYSIS ---");
						stringBuilder.AppendLine($"Pattern: {item2.DataFlowChain.Pattern}");
						stringBuilder.AppendLine($"Confidence: {item2.DataFlowChain.Confidence * 100.0:F0}%");
						stringBuilder.AppendLine(item2.DataFlowChain.Summary);
						if (item2.DataFlowChain.IsCrossMethod)
						{
							stringBuilder.AppendLine();
							stringBuilder.AppendLine("Cross-Method Flow:");
							foreach (string involvedMethod in item2.DataFlowChain.InvolvedMethods)
							{
								stringBuilder.AppendLine("  - " + involvedMethod);
							}
						}
						stringBuilder.AppendLine();
						stringBuilder.AppendLine("Data Flow Path:");
						for (int j = 0; j < item2.DataFlowChain.Nodes.Count; j++)
						{
							DataFlowNode dataFlowNode = item2.DataFlowChain.Nodes[j];
							string text4 = ((j > 0) ? "  -> " : "    ");
							DataFlowNodeType nodeType2 = dataFlowNode.NodeType;
							if (1 == 0)
							{
							}
							string text2 = nodeType2 switch
							{
								DataFlowNodeType.Source => "[SOURCE]", 
								DataFlowNodeType.Transform => "[TRANSFORM]", 
								DataFlowNodeType.Sink => "[SINK]", 
								DataFlowNodeType.Intermediate => "[PASS]", 
								_ => "[???]", 
							};
							if (1 == 0)
							{
							}
							string text5 = text2;
							stringBuilder.AppendLine(text4 + text5 + " " + dataFlowNode.Operation + " (" + dataFlowNode.DataDescription + ")");
							stringBuilder.AppendLine(new string(' ', text4.Length) + "     Location: " + dataFlowNode.Location);
						}
					}
					if (!string.IsNullOrEmpty(item2.CodeSnippet))
					{
						stringBuilder.AppendLine("Code Snippet:");
						stringBuilder.AppendLine(item2.CodeSnippet);
					}
					stringBuilder.AppendLine();
				}
			}
			stringBuilder.AppendLine("=========================================");
			stringBuilder.AppendLine("");
			stringBuilder.AppendLine("Need help? Join the community: https://discord.gg/UD4K4chKak");
			return stringBuilder.ToString();
		}

		private string WrapText(string text, int indent)
		{
			string text2 = new string(' ', indent);
			int num = 80 - indent;
			string[] array = text.Split(' ');
			List<string> list = new List<string>();
			string text3 = "";
			string[] array2 = array;
			foreach (string text4 in array2)
			{
				if (text3.Length + text4.Length + 1 > num)
				{
					if (!string.IsNullOrEmpty(text3))
					{
						list.Add(text3);
					}
					text3 = text4;
				}
				else
				{
					text3 = text3 + ((text3.Length > 0) ? " " : "") + text4;
				}
			}
			if (!string.IsNullOrEmpty(text3))
			{
				list.Add(text3);
			}
			return string.Join("\n  " + text2, list);
		}
	}
	public class IlDumpService
	{
		private readonly IScanLogger _logger;

		private readonly IPlatformEnvironment _environment;

		private readonly DefaultAssemblyResolver _assemblyResolver;

		public IlDumpService(IScanLogger logger, IPlatformEnvironment environment)
		{
			_logger = logger ?? throw new ArgumentNullException("logger");
			_environment = environment ?? throw new ArgumentNullException("environment");
			_assemblyResolver = BuildResolver();
		}

		public bool TryDumpAssembly(string assemblyPath, string outputPath)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Expected O, but got Unknown
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrWhiteSpace(assemblyPath) || string.IsNullOrWhiteSpace(outputPath))
			{
				return false;
			}
			try
			{
				Directory.CreateDirectory(Path.GetDirectoryName(outputPath));
				ReaderParameters val = new ReaderParameters
				{
					ReadWrite = false,
					InMemory = true,
					ReadSymbols = false,
					AssemblyResolver = (IAssemblyResolver)(object)_assemblyResolver
				};
				AssemblyDefinition val2 = AssemblyDefinition.ReadAssembly(assemblyPath, val);
				using StreamWriter streamWriter = new StreamWriter(outputPath);
				streamWriter.WriteLine("; Full IL dump for " + Path.GetFileName(assemblyPath));
				streamWriter.WriteLine($"; Generated: {DateTime.Now}");
				streamWriter.WriteLine("; Platform: " + _environment.PlatformName);
				streamWriter.WriteLine();
				Enumerator<ModuleDefinition> enumerator = val2.Modules.GetEnumerator();
				try
				{
					while (enumerator.MoveNext())
					{
						ModuleDefinition current = enumerator.Current;
						streamWriter.WriteLine(".module " + ((ModuleReference)current).Name);
						streamWriter.WriteLine();
						Enumerator<TypeDefinition> enumerator2 = current.Types.GetEnumerator();
						try
						{
							while (enumerator2.MoveNext())
							{
								TypeDefinition current2 = enumerator2.Current;
								WriteType(current2, streamWriter);
							}
						}
						finally
						{
							((IDisposable)enumerator2).Dispose();
						}
					}
				}
				finally
				{
					((IDisposable)enumerator).Dispose();
				}
				_logger.Info("Saved IL dump to: " + outputPath);
				return true;
			}
			catch (Exception ex)
			{
				_logger.Error("Failed to dump IL for " + Path.GetFileName(assemblyPath) + ": " + ex.Message);
				return false;
			}
		}

		private DefaultAssemblyResolver BuildResolver()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			DefaultAssemblyResolver val = new DefaultAssemblyResolver();
			string gameRootDirectory = _environment.GameRootDirectory;
			if (Directory.Exists(gameRootDirectory))
			{
				((BaseAssemblyResolver)val).AddSearchDirectory(gameRootDirectory);
			}
			string managedDirectory = _environment.ManagedDirectory;
			if (!string.IsNullOrEmpty(managedDirectory) && Directory.Exists(managedDirectory))
			{
				((BaseAssemblyResolver)val).AddSearchDirectory(managedDirectory);
			}
			string[] pluginDirectories = _environment.PluginDirectories;
			foreach (string text in pluginDirectories)
			{
				if (Directory.Exists(text))
				{
					((BaseAssemblyResolver)val).AddSearchDirectory(text);
				}
			}
			return val;
		}

		private static void WriteType(TypeDefinition type, StreamWriter writer)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			writer.WriteLine(".class " + ((MemberReference)type).FullName);
			Enumerator<MethodDefinition> enumerator = type.Methods.GetEnumerator();
			try
			{
				while (enumerator.MoveNext())
				{
					MethodDefinition current = enumerator.Current;
					WriteMethod(current, writer);
				}
			}
			finally
			{
				((IDisposable)enumerator).Dispose();
			}
			Enumerator<TypeDefinition> enumerator2 = type.NestedTypes.GetEnumerator();
			try
			{
				while (enumerator2.MoveNext())
				{
					TypeDefinition current2 = enumerator2.Current;
					WriteType(current2, writer);
				}
			}
			finally
			{
				((IDisposable)enumerator2).Dispose();
			}
		}

		private static void WriteMethod(MethodDefinition method, StreamWriter writer)
		{
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				string text = string.Join(", ", ((IEnumerable<ParameterDefinition>)((MethodReference)method).Parameters).Select((ParameterDefinition p) => ((MemberReference)((ParameterReference)p).ParameterType).FullName + " " + ((ParameterReference)p).Name));
				writer.WriteLine("  .method " + ((MemberReference)((MethodReference)method).ReturnType).FullName + " " + ((MemberReference)method).Name + "(" + text + ")");
				if (!method.HasBody)
				{
					writer.WriteLine("    // No body (abstract / external)");
					writer.WriteLine();
					return;
				}
				writer.WriteLine("  {");
				Enumerator<Instruction> enumerator = method.Body.Instructions.GetEnumerator();
				try
				{
					while (enumerator.MoveNext())
					{
						Instruction current = enumerator.Current;
						string text2 = FormatOperand(current.Operand);
						string text3 = $"    IL_{current.Offset:X4}: {current.OpCode}";
						if (!string.IsNullOrEmpty(text2))
						{
							text3 = text3 + " " + text2;
						}
						writer.WriteLine(text3);
					}
				}
				finally
				{
					((IDisposable)enumerator).Dispose();
				}
				writer.WriteLine("  }");
				writer.WriteLine();
			}
			catch (Exception ex)
			{
				writer.WriteLine("    // Failed to dump method " + ((MemberReference)method).Name + ": " + ex.Message);
				writer.WriteLine();
			}
		}

		private static string FormatOperand(object operand)
		{
			if (1 == 0)
			{
			}
			string result;
			if (operand != null)
			{
				if (!(operand is string text))
				{
					MethodReference val = (MethodReference)((operand is MethodReference) ? operand : null);
					if (val == null)
					{
						FieldReference val2 = (FieldReference)((operand is FieldReference) ? operand : null);
						if (val2 == null)
						{
							TypeReference val3 = (TypeReference)((operand is TypeReference) ? operand : null);
							if (val3 == null)
							{
								Instruction val4 = (Instruction)((operand is Instruction) ? operand : null);
								result = ((val4 != null) ? $"IL_{val4.Offset:X4}" : ((!(operand is Instruction[] source)) ? (operand.ToString() ?? string.Empty) : string.Join(", ", source.Select((Instruction t) => $"IL_{t.Offset:X4}"))));
							}
							else
							{
								result = ((MemberReference)val3).FullName;
							}
						}
						else
						{
							result = ((MemberReference)val2).FullName;
						}
					}
					else
					{
						result = ((MemberReference)val).FullName;
					}
				}
				else
				{
					result = "\"" + text + "\"";
				}
			}
			else
			{
				result = string.Empty;
			}
			if (1 == 0)
			{
			}
			return result;
		}
	}
	public class PromptGeneratorService
	{
		private readonly ScanConfig _config;

		private readonly IScanLogger _logger;

		public PromptGeneratorService(ScanConfig config, IScanLogger logger)
		{
			_config = config ?? throw new ArgumentNullException("config");
			_logger = logger ?? throw new ArgumentNullException("logger");
		}

		public string GeneratePrompt(string modPath, List<ScanFinding> findings)
		{
			if (findings == null || !findings.Any())
			{
				return "No suspicious findings to analyze.";
			}
			string fileName = Path.GetFileName(modPath);
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine("# Mod Security Analysis Request");
			stringBuilder.AppendLine();
			stringBuilder.AppendLine("I need to determine if the following mod is malicious or a false positive. Below is a security scan report generated by MLVScan (a security tool for MelonLoader mods).");
			stringBuilder.AppendLine();
			stringBuilder.AppendLine("## Mod Information");
			stringBuilder.AppendLine("- **Filename**: " + fileName);
			stringBuilder.AppendLine($"- **Scan Date**: {DateTime.Now}");
			stringBuilder.AppendLine($"- **Total Suspicious Patterns**: {findings.Count}");
			stringBuilder.AppendLine();
			Dictionary<Severity, int> dictionary = (from f in findings
				group f by f.Severity into g
				orderby (int)g.Key descending
				select g).ToDictionary((IGrouping<Severity, ScanFinding> g) => g.Key, (IGrouping<Severity, ScanFinding> g) => g.Count());
			stringBuilder.AppendLine("## Severity Breakdown");
			foreach (KeyValuePair<Severity, int> item in dictionary)
			{
				stringBuilder.AppendLine($"- **{FormatSeverityLabel(item.Key)}**: {item.Value} issue(s)");
			}
			stringBuilder.AppendLine();
			stringBuilder.AppendLine("## Detailed Findings");
			Dictionary<string, List<ScanFinding>> dictionary2 = (from f in findings
				group f by f.Description).ToDictionary((IGrouping<string, ScanFinding> g) => g.Key, (IGrouping<string, ScanFinding> g) => g.ToList());
			var (dictionary5, dictionary6) = ExtractCodeBlocks(modPath, findings);
			foreach (KeyValuePair<string, List<ScanFinding>> item2 in dictionary2)
			{
				stringBuilder.AppendLine("### " + item2.Key);
				stringBuilder.AppendLine($"- **Severity**: {item2.Value[0].Severity}");
				stringBuilder.AppendLine($"- **Occurrences**: {item2.Value.Count}");
				stringBuilder.AppendLine("- **Locations & Snippets**:");
				foreach (ScanFinding item3 in item2.Value.Take(5))
				{
					stringBuilder.AppendLine("  - **Location**: " + item3.Location);
					if (!string.IsNullOrEmpty(item3.CodeSnippet))
					{
						stringBuilder.AppendLine("    **IL Snippet (Exact location of suspicious call)**:");
						stringBuilder.AppendLine("    ```");
						string[] array = item3.CodeSnippet.Split(new char[2] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
						foreach (string text in array)
						{
							stringBuilder.AppendLine("    " + text);
						}
						stringBuilder.AppendLine("    ```");
					}
					if (dictionary5.TryGetValue(item3.Location, out var value) && !string.IsNullOrWhiteSpace(value))
					{
						stringBuilder.AppendLine("    **Attempted C# Decompilation (Entire Method Context & Type Info)**:");
						stringBuilder.AppendLine("    ```csharp");
						string[] array2 = value.Split(new char[2] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
						foreach (string text2 in array2)
						{
							stringBuilder.AppendLine("    " + text2);
						}
						stringBuilder.AppendLine("    ```");
					}
					if (dictionary6.TryGetValue(item3.Location, out var value2) && !string.IsNullOrWhiteSpace(value2))
					{
						stringBuilder.AppendLine("    **Surrounding Class Structure (Member Signatures Only)**:");
						stringBuilder.AppendLine("    ```csharp");
						string[] array3 = value2.Split(new char[2] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
						foreach (string text3 in array3)
						{
							stringBuilder.AppendLine("    " + text3);
						}
						stringBuilder.AppendLine("    ```");
					}
					stringBuilder.AppendLine();
				}
				if (item2.Value.Count > 5)
				{
					stringBuilder.AppendLine($"  - *And {item2.Value.Count - 5} more occurrences (details omitted for brevity)*");
				}
				stringBuilder.AppendLine();
			}
			string value3 = ExtractAssemblyMetadata(modPath);
			if (!string.IsNullOrEmpty(value3))
			{
				stringBuilder.AppendLine("## Assembly Metadata");
				stringBuilder.AppendLine(value3);
				stringBuilder.AppendLine();
			}
			stringBuilder.AppendLine("## Request");
			stringBuilder.AppendLine("Based on this scan report and code analysis, please help me determine:");
			stringBuilder.AppendLine("1. Is this mod likely to be malicious or is it a false positive?");
			stringBuilder.AppendLine("2. If potentially malicious, what specific security risks does it pose?");
			stringBuilder.AppendLine("3. What is the intent of the suspicious code? Is there a benign explanation?");
			stringBuilder.AppendLine("4. What further actions should I take? (Whitelist it, delete it, report it, etc.)");
			stringBuilder.AppendLine();
			stringBuilder.AppendLine("Please explain your reasoning with reference to the specific code patterns and provide context about:");
			stringBuilder.AppendLine("- Whether these patterns are common in legitimate mods or game utilities");
			stringBuilder.AppendLine("- Alternative explanations for the suspicious patterns");
			stringBuilder.AppendLine("- Your confidence level in the assessment");
			stringBuilder.AppendLine();
			stringBuilder.AppendLine("Important context: This is a mod for a game using MelonLoader (a mod loading framework). Legitimate mods generally don't need to use system-level APIs like shell execution, registry access, etc.");
			return stringBuilder.ToString();
		}

		private Tuple<Dictionary<string, string>, Dictionary<string, string>> ExtractCodeBlocks(string modPath, List<ScanFinding> findings)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Expected O, but got Unknown
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			Dictionary<string, string> dictionary2 = new Dictionary<string, string>();
			try
			{
				if (!File.Exists(modPath))
				{
					return Tuple.Create(dictionary, dictionary2);
				}
				ReaderParameters val = new ReaderParameters
				{
					ReadWrite = false,
					InMemory = true,
					ReadSymbols = false
				};
				AssemblyDefinition val2 = AssemblyDefinition.ReadAssembly(modPath, val);
				try
				{
					Dictionary<string, List<string>> dictionary3 = new Dictionary<string, List<string>>();
					Enumerator<ModuleDefinition> enumerator = val2.Modules.GetEnumerator();
					try
					{
						while (enumerator.MoveNext())
						{
							ModuleDefinition current = enumerator.Current;
							Enumerator<TypeDefinition> enumerator2 = current.Types.GetEnumerator();
							try
							{
								while (enumerator2.MoveNext())
								{
									TypeDefinition current2 = enumerator2.Current;
									CollectSuspiciousStrings(current2, dictionary3);
								}
							}
							finally
							{
								((IDisposable)enumerator2).Dispose();
							}
						}
					}
					finally
					{
						((IDisposable)enumerator).Dispose();
					}
					if (dictionary3.Any())
					{
						StringBuilder stringBuilder = new StringBuilder();
						stringBuilder.AppendLine("// Notable string literals found in the assembly:");
						stringBuilder.AppendLine();
						foreach (string item in dictionary3.Keys.OrderBy((string k) => k))
						{
							stringBuilder.AppendLine("// Potential " + item + ":");
							foreach (string item2 in dictionary3[item].Take(10))
							{
								stringBuilder.AppendLine("//   \"" + EscapeStringForCode(item2) + "\"");
							}
							if (dictionary3[item].Count > 10)
							{
								stringBuilder.AppendLine($"//   ... and {dictionary3[item].Count - 10} more");
							}
							stringBuilder.AppendLine();
						}
						dictionary["SuspiciousStrings"] = stringBuilder.ToString();
					}
					foreach (ScanFinding finding in findings)
					{
						try
						{
							string location = finding.Location;
							if (location == "Assembly scanning" || !location.Contains("."))
							{
								continue;
							}
							string empty = string.Empty;
							string fullTypeName;
							string methodNameFromFinding;
							if (location.Contains(":"))
							{
								string[] array = location.Split(':');
								string text = array[0];
								empty = array[1];
								int num = text.LastIndexOf('.');
								if (num > 0)
								{
									fullTypeName = text.Substring(0, num);
									methodNameFromFinding = text.Substring(num + 1);
									goto IL_032f;
								}
							}
							else
							{
								int num2 = location.LastIndexOf('.');
								if (num2 > 0)
								{
									fullTypeName = location.Substring(0, num2);
									methodNameFromFinding = location.Substring(num2 + 1);
									goto IL_032f;
								}
							}
							goto end_IL_0244;
							IL_032f:
							TypeDefinition val3 = FindType(val2.MainModule, fullTypeName);
							if (val3 == null)
							{
								continue;
							}
							if (!dictionary2.ContainsKey(finding.Location) || dictionary2[finding.Location] == string.Empty)
							{
								dictionary2[finding.Location] = GenerateClassStructure(val3, methodNameFromFinding);
							}
							MethodDefinition val4 = ((IEnumerable<MethodDefinition>)val3.Methods).FirstOrDefault((Func<MethodDefinition, bool>)((MethodDefinition m) => ((MemberReference)m).Name == methodNameFromFinding));
							if (val4 == null)
							{
								if (!dictionary.ContainsKey(finding.Location))
								{
									dictionary[finding.Location] = "// DllImport or external method: " + finding.Location + ". Primary context is the IL snippet and class structure.";
								}
								continue;
							}
							if (!val4.HasBody && !val4.IsAbstract)
							{
								if (!dictionary.ContainsKey(finding.Location))
								{
									dictionary[finding.Location] = "// Method " + methodNameFromFinding + " has no body or is abstract.";
								}
								continue;
							}
							string text2 = DecompileMethod(val4);
							if (string.IsNullOrEmpty(text2))
							{
								continue;
							}
							StringBuilder stringBuilder2 = new StringBuilder();
							stringBuilder2.AppendLine("// Context: Method is part of " + ((MemberReference)val3).FullName);
							if (val3.HasCustomAttributes)
							{
								stringBuilder2.AppendLine("// Type attributes:");
								foreach (CustomAttribute item3 in ((IEnumerable<CustomAttribute>)val3.CustomAttributes).Take(5))
								{
									stringBuilder2.AppendLine("// - " + ((MemberReference)item3.AttributeType).Name);
								}
								if (val3.CustomAttributes.Count > 5)
								{
									stringBuilder2.AppendLine($"// - ...and {val3.CustomAttributes.Count - 5} more");
								}
							}
							if (val3.BaseType != null && ((MemberReference)val3.BaseType).FullName != "System.Object")
							{
								stringBuilder2.AppendLine("// Inherits from: " + ((MemberReference)val3.BaseType).FullName);
							}
							List<MethodDefinition> list = FindRelatedSuspiciousMethods(val3, val4);
							if (list.Any())
							{
								stringBuilder2.AppendLine("// Other suspicious methods in this class (names only):");
								foreach (MethodDefinition item4 in list.Take(3))
								{
									stringBuilder2.AppendLine("// - " + ((MemberReference)item4).Name);
								}
								if (list.Count > 3)
								{
									stringBuilder2.AppendLine($"// - ...and {list.Count - 3} more");
								}
							}
							stringBuilder2.AppendLine();
							stringBuilder2.AppendLine("// Finding Description: " + finding.Description);
							stringBuilder2.AppendLine($"// Severity: {finding.Severity}");
							stringBuilder2.AppendLine();
							dictionary[finding.Location] = stringBuilder2.ToString() + text2;
							end_IL_0244:;
						}
						catch (Exception ex)
						{
							_logger.Error("Failed to extract code for " + finding.Location + ": " + ex.Message);
							dictionary[finding.Location] = "// Error extracting detailed code for " + finding.Location + ": " + ex.Message;
						}
					}
					if (((IEnumerable<Resource>)val2.MainModule.Resources).Any())
					{
						StringBuilder stringBuilder3 = new StringBuilder();
						stringBuilder3.AppendLine("// Assembly Resources (could contain hidden payloads):");
						foreach (Resource item5 in ((IEnumerable<Resource>)val2.MainModule.Resources).Take(20))
						{
							stringBuilder3.AppendLine("//   " + item5.Name + " - " + GetResourceTypeName(item5));
						}
						if (val2.MainModule.Resources.Count > 20)
						{
							stringBuilder3.AppendLine($"//   ...and {val2.MainModule.Resources.Count - 20} more resources");
						}
						dictionary["Assembly.Resources"] = stringBuilder3.ToString();
					}
				}
				finally
				{
					((IDisposable)val2)?.Dispose();
				}
			}
			catch (Exception ex2)
			{
				_logger.Error("Failed to extract code blocks from " + modPath + ": " + ex2.Message);
			}
			return Tuple.Create(dictionary, dictionary2);
		}

		private void CollectSuspiciousStrings(TypeDefinition type, Dictionary<string, List<string>> suspiciousStrings)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			Enumerator<MethodDefinition> enumerator = type.Methods.GetEnumerator();
			try
			{
				while (enumerator.MoveNext())
				{
					MethodDefinition current = enumerator.Current;
					if (!current.HasBody)
					{
						continue;
					}
					Enumerator<Instruction> enumerator2 = current.Body.Instructions.GetEnumerator();
					try
					{
						while (enumerator2.MoveNext())
						{
							Instruction current2 = enumerator2.Current;
							OpCode opCode = current2.OpCode;
							if (((OpCode)(ref opCode)).Name == "ldstr" && current2.Operand is string text && IsSuspiciousString(text, out var category))
							{
								if (!suspiciousStrings.ContainsKey(category))
								{
									suspiciousStrings[category] = new List<string>();
								}
								if (!suspiciousStrings[category].Contains(text))
								{
									suspiciousStrings[category].Add(text);
								}
							}
						}
					}
					finally
					{
						((IDisposable)enumerator2).Dispose();
					}
				}
			}
			finally
			{
				((IDisposable)enumerator).Dispose();
			}
			Enumerator<TypeDefinition> enumerator3 = type.NestedTypes.GetEnumerator();
			try
			{
				while (enumerator3.MoveNext())
				{
					TypeDefinition current3 = enumerator3.Current;
					CollectSuspiciousStrings(current3, suspiciousStrings);
				}
			}
			finally
			{
				((IDisposable)enumerator3).Dispose();
			}
		}

		private bool IsSuspiciousString(string value, out string category)
		{
			if (string.IsNullOrEmpty(value))
			{
				category = string.Empty;
				return false;
			}
			if (value.Length > 20 && IsLikelyBase64(value))
			{
				category = "Base64 encoded data";
				return true;
			}
			if (value.StartsWith("http://") || value.StartsWith("https://") || value.StartsWith("ftp://") || value.StartsWith("ws://"))
			{
				category = "URL";
				return true;
			}
			if (value.Contains(".exe") || value.Contains(".dll") || value.Contains(".bat") || value.Contains(".cmd") || value.Contains(".ps1") || value.Contains(".vbs"))
			{
				category = "executable file reference";
				return true;
			}
			if (IsLikelyIPAddress(value))
			{
				category = "IP address";
				return true;
			}
			if (value.StartsWith("HKEY_") || value.Contains("\\Software\\") || value.Contains("\\Microsoft\\") || value.Contains("\\System\\"))
			{
				category = "registry path";
				return true;
			}
			if (value.StartsWith("cmd ") || value.StartsWith("powershell ") || value.Contains(" /c ") || value.Contains(" /k "))
			{
				category = "command line";
				return true;
			}
			if (value.Contains("encrypt") || value.Contains("decrypt") || value.Contains("aes") || value.Contains("rsa") || value.Contains("md5") || value.Contains("sha") || value.Contains("hash"))
			{
				category = "cryptographic reference";
				return true;
			}
			if ((value.Contains(".") && !value.Contains(" ") && !value.Contains("\\") && !value.EndsWith(".cs") && !value.EndsWith(".txt") && value.Length > 5) || value.Contains("pastebin") || value.Contains("discord") || value.Contains("webhook"))
			{
				category = "domain or web service";
				return true;
			}
			category = string.Empty;
			return false;
		}

		private bool IsLikelyBase64(string value)
		{
			if (value.Length % 4 != 0)
			{
				return false;
			}
			foreach (char c2 in value)
			{
				if ((c2 < 'A' || c2 > 'Z') && (c2 < 'a' || c2 > 'z') && (c2 < '0' || c2 > '9') && c2 != '+' && c2 != '/' && c2 != '=')
				{
					return false;
				}
			}
			return value.Length > 20 && value.Any((char c) => c >= 'A' && c <= 'Z') && value.Any((char c) => c >= 'a' && c <= 'z') && value.Any((char c) => c >= '0' && c <= '9');
		}

		private bool IsLikelyIPAddress(string value)
		{
			string pattern = "^\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}";
			string pattern2 = "^[0-9a-fA-F:]+";
			return Regex.IsMatch(value, pattern) || Regex.IsMatch(value, pattern2);
		}

		private string GetResourceTypeName(Resource resource)
		{
			//IL_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
			EmbeddedResource val = (EmbeddedResource)(object)((resource is EmbeddedResource) ? resource : null);
			if (val != null)
			{
				using (Stream stream = val.GetResourceStream())
				{
					if (stream.Length > 0)
					{
						byte[] array = new byte[Math.Min(stream.Length, 16L)];
						stream.Read(array, 0, array.Length);
						if (array.Length >= 2 && array[0] == 77 && array[1] == 90)
						{
							return "PE File/DLL (MZ header)";
						}
						if (array.Length >= 4 && array[0] == 127 && array[1] == 69 && array[2] == 76 && array[3] == 70)
						{
							return "ELF Binary";
						}
						if (array.Length >= 4 && array[0] == 80 && array[1] == 75 && array[2] == 3 && array[3] == 4)
						{
							return "ZIP Archive";
						}
						if (array.Length >= 2 && array[0] == byte.MaxValue && array[1] == 216)
						{
							return "JPEG Image";
						}
						if (array.Length >= 3 && array[0] == 71 && array[1] == 73 && array[2] == 70)
						{
							return "GIF Image";
						}
						if (array.Length >= 4 && ((array[0] == 137 && array[1] == 80 && array[2] == 78 && array[3] == 71) || (array[0] == 66 && array[1] == 77)))
						{
							return "PNG or BMP Image";
						}
						return $"Binary data ({stream.Length} bytes)";
					}
					return "Empty resource";
				}
			}
			ResourceType resourceType = resource.ResourceType;
			return ((object)(ResourceType)(ref resourceType)).ToString();
		}

		private List<MethodDefinition> FindRelatedSuspiciousMethods(TypeDefinition type, MethodDefinition currentMethod)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			List<MethodDefinition> list = new List<MethodDefinition>();
			Enumerator<MethodDefinition> enumerator = type.Methods.GetEnumerator();
			try
			{
				while (enumerator.MoveNext())
				{
					MethodDefinition current = enumerator.Current;
					if (current == currentMethod || !current.HasBody)
					{
						continue;
					}
					Enumerator<Instruction> enumerator2 = current.Body.Instructions.GetEnumerator();
					try
					{
						while (enumerator2.MoveNext())
						{
							Instruction current2 = enumerator2.Current;
							OpCode opCode = current2.OpCode;
							if (!(((OpCode)(ref opCode)).Name == "call"))
							{
								opCode = current2.OpCode;
								if (!(((OpCode)(ref opCode)).Name == "callvirt"))
								{
									opCode = current2.OpCode;
									if (!(((OpCode)(ref opCode)).Name == "newobj"))
									{
										continue;
									}
								}
							}
							object operand = current2.Operand;
							MethodReference val = (MethodReference)((operand is MethodReference) ? operand : null);
							if (val != null && IsSuspiciousMethodCall(val))
							{
								list.Add(current);
								break;
							}
						}
					}
					finally
					{
						((IDisposable)enumerator2).Dispose();
					}
				}
			}
			finally
			{
				((IDisposable)enumerator).Dispose();
			}
			return list;
		}

		private TypeDefinition FindType(ModuleDefinition module, string fullTypeName)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			Enumerator<TypeDefinition> enumerator = module.Types.GetEnumerator();
			try
			{
				while (enumerator.MoveNext())
				{
					TypeDefinition current = enumerator.Current;
					if (((MemberReference)current).FullName == fullTypeName)
					{