From e9d0b7329650b23b66e97e1f892cd701a5130c10 Mon Sep 17 00:00:00 2001 From: Sardelka Date: Sat, 9 Jul 2022 09:55:12 +0800 Subject: [PATCH] Add managed and loaded assembly check --- RageCoop.Server/Scripting/ServerResource.cs | 63 ++++++++++++++++++++- 1 file changed, 61 insertions(+), 2 deletions(-) diff --git a/RageCoop.Server/Scripting/ServerResource.cs b/RageCoop.Server/Scripting/ServerResource.cs index 12007d4..e05a81c 100644 --- a/RageCoop.Server/Scripting/ServerResource.cs +++ b/RageCoop.Server/Scripting/ServerResource.cs @@ -64,9 +64,20 @@ namespace RageCoop.Server.Scripting IsDirectory=false, Name=relativeName }; - if (file.EndsWith(".dll")) + if (file.EndsWith(".dll") && IsManagedAssembly(file)) { - r.LoadScriptsFromAssembly(rfile, r.LoadAssemblyFromPath(Path.GetFullPath(file))); + try + { + r.LoadScriptsFromAssembly(rfile, r.LoadAssemblyFromPath(Path.GetFullPath(file))); + } + catch(FileLoadException ex) + { + if(!ex.Message.EndsWith("Assembly with same name is already loaded")) + { + logger?.Warning("Failed to load assembly: "+Path.GetFileName(file)); + logger?.Trace(ex.Message); + } + } } r.Files.Add(relativeName, rfile); } @@ -150,6 +161,54 @@ namespace RageCoop.Server.Scripting { base.Dispose(); } + private static bool IsManagedAssembly(string filename) + { + try + { + using (Stream file = new FileStream(filename, FileMode.Open, FileAccess.Read)) + { + if (file.Length < 64) + return false; + using (BinaryReader bin = new BinaryReader(file)) + { + // PE header starts at offset 0x3C (60). Its a 4 byte header. + file.Position = 0x3C; + uint offset = bin.ReadUInt32(); + if (offset == 0) + offset = 0x80; + + // Ensure there is at least enough room for the following structures: + // 24 byte PE Signature & Header + // 28 byte Standard Fields (24 bytes for PE32+) + // 68 byte NT Fields (88 bytes for PE32+) + // >= 128 byte Data Dictionary Table + if (offset > file.Length - 256) + return false; + + // Check the PE signature. Should equal 'PE\0\0'. + file.Position = offset; + if (bin.ReadUInt32() != 0x00004550) + return false; + + // Read PE magic number from Standard Fields to determine format. + file.Position += 20; + var peFormat = bin.ReadUInt16(); + if (peFormat != 0x10b /* PE32 */ && peFormat != 0x20b /* PE32Plus */) + return false; + + // Read the 15th Data Dictionary RVA field which contains the CLI header RVA. + // When this is non-zero then the file contains CLI data otherwise not. + file.Position = offset + (peFormat == 0x10b ? 232 : 248); + return bin.ReadUInt32() != 0; + } + } + } + catch + { + // This is likely not a valid assembly if any IO exceptions occur during reading + return false; + } + } } }