2023-07-15 14:29:14 +02:00
|
|
|
|
using System.Reflection;
|
|
|
|
|
using System.Runtime.InteropServices;
|
|
|
|
|
using System.Runtime.Loader;
|
|
|
|
|
|
|
|
|
|
namespace ImHex
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
public class EntryPoint
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
public static int ExecuteScript(IntPtr arg, int argLength)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
2024-03-10 22:05:26 +01:00
|
|
|
|
return ExecuteScript(Marshal.PtrToStringUTF8(arg, argLength));
|
2023-07-15 14:29:14 +02:00
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
2023-07-16 20:13:50 +02:00
|
|
|
|
Console.WriteLine("[.NET Script] Exception in AssemblyLoader: " + e.ToString());
|
2023-07-15 14:29:14 +02:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-10 22:05:26 +01:00
|
|
|
|
private static List<string> loadedPlugins = new();
|
|
|
|
|
private static int ExecuteScript(string args)
|
2023-07-15 14:29:14 +02:00
|
|
|
|
{
|
2024-03-10 22:05:26 +01:00
|
|
|
|
// Parse input in the form of "execType||path"
|
|
|
|
|
var splitArgs = args.Split("||");
|
|
|
|
|
var type = splitArgs[0];
|
|
|
|
|
var methodName = splitArgs[1];
|
|
|
|
|
var path = splitArgs[2];
|
|
|
|
|
|
|
|
|
|
// Get the parent folder of the passed path
|
2023-07-16 20:13:50 +02:00
|
|
|
|
string? basePath = Path.GetDirectoryName(path);
|
|
|
|
|
if (basePath == null)
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine("[.NET Script] Failed to get base path");
|
2024-03-10 22:05:26 +01:00
|
|
|
|
return 1;
|
2023-07-16 20:13:50 +02:00
|
|
|
|
}
|
|
|
|
|
|
2024-03-10 22:05:26 +01:00
|
|
|
|
// Create a new assembly context
|
2023-07-16 20:13:50 +02:00
|
|
|
|
AssemblyLoadContext? context = new("ScriptDomain_" + basePath, true);
|
2023-07-15 14:29:14 +02:00
|
|
|
|
|
2024-03-10 22:05:26 +01:00
|
|
|
|
int result = 0;
|
2023-07-15 14:29:14 +02:00
|
|
|
|
try
|
|
|
|
|
{
|
2024-03-10 22:05:26 +01:00
|
|
|
|
if (type is "LOAD")
|
|
|
|
|
{
|
2024-03-13 19:49:48 +01:00
|
|
|
|
// If the script has been loaded already, don't do it again
|
2024-03-10 22:05:26 +01:00
|
|
|
|
if (loadedPlugins.Contains(path))
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check if the plugin is already loaded
|
|
|
|
|
loadedPlugins.Add(path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Load all assemblies in the parent folder
|
2023-07-16 20:13:50 +02:00
|
|
|
|
foreach (var file in Directory.GetFiles(basePath, "*.dll"))
|
|
|
|
|
{
|
2024-03-10 22:05:26 +01:00
|
|
|
|
// Skip main Assembly
|
|
|
|
|
if (file.EndsWith("Main.dll"))
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2024-03-11 21:09:45 +01:00
|
|
|
|
|
2024-03-13 19:49:48 +01:00
|
|
|
|
// Load the Assembly
|
2024-03-11 21:09:45 +01:00
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
context.LoadFromStream(new MemoryStream(File.ReadAllBytes(file)));
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
2024-03-13 19:49:48 +01:00
|
|
|
|
Console.WriteLine("[.NET Script] Failed to load assembly: " + file + " - " + e);
|
2024-03-11 21:09:45 +01:00
|
|
|
|
}
|
2023-07-16 20:13:50 +02:00
|
|
|
|
}
|
|
|
|
|
|
2024-03-10 22:05:26 +01:00
|
|
|
|
// Load the script assembly
|
2023-07-15 14:29:14 +02:00
|
|
|
|
var assembly = context.LoadFromStream(new MemoryStream(File.ReadAllBytes(path)));
|
|
|
|
|
|
2024-03-13 19:49:48 +01:00
|
|
|
|
// Find ImHexLibrary module
|
|
|
|
|
var libraryModule = Array.Find(context.Assemblies.ToArray(), module => module.GetName().Name == "ImHexLibrary");
|
|
|
|
|
if (libraryModule == null)
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine("[.NET Script] Refusing to load non-ImHex script");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Load Library type
|
|
|
|
|
var libraryType = libraryModule.GetType("Library");
|
|
|
|
|
if (libraryType == null)
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine("[.NET Script] Failed to find Library type in ImHexLibrary");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Load Initialize function in the Library type
|
|
|
|
|
var initMethod = libraryType.GetMethod("Initialize", BindingFlags.Static | BindingFlags.Public);
|
|
|
|
|
if (initMethod == null)
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine("[.NET Script] Failed to find Initialize method");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Execute it
|
|
|
|
|
initMethod.Invoke(null, null);
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-10 22:05:26 +01:00
|
|
|
|
// Find a class named "Script"
|
2023-07-15 14:29:14 +02:00
|
|
|
|
var entryPointType = assembly.GetType("Script");
|
|
|
|
|
if (entryPointType == null)
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine("[.NET Script] Failed to find Script type");
|
2024-03-10 22:05:26 +01:00
|
|
|
|
return 1;
|
2023-07-15 14:29:14 +02:00
|
|
|
|
}
|
|
|
|
|
|
2024-03-10 22:05:26 +01:00
|
|
|
|
if (type is "EXEC" or "LOAD")
|
2023-07-15 14:29:14 +02:00
|
|
|
|
{
|
2024-03-10 22:05:26 +01:00
|
|
|
|
// Load the function
|
|
|
|
|
var method = entryPointType.GetMethod(methodName, BindingFlags.Static | BindingFlags.Public);
|
|
|
|
|
if (method == null)
|
|
|
|
|
{
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
2023-07-15 14:29:14 +02:00
|
|
|
|
|
2024-03-10 22:05:26 +01:00
|
|
|
|
// Execute it
|
2024-03-13 19:49:48 +01:00
|
|
|
|
method.Invoke(null, null);
|
2024-03-10 22:05:26 +01:00
|
|
|
|
}
|
|
|
|
|
else if (type == "CHECK")
|
|
|
|
|
{
|
2024-03-13 19:49:48 +01:00
|
|
|
|
// Check if the method exists
|
2024-03-10 22:05:26 +01:00
|
|
|
|
return entryPointType.GetMethod(methodName, BindingFlags.Static | BindingFlags.Public) != null ? 0 : 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2023-07-15 14:29:14 +02:00
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
2024-03-13 19:49:48 +01:00
|
|
|
|
Console.WriteLine("[.NET Script] Exception in AssemblyLoader: " + e);
|
2024-03-10 22:05:26 +01:00
|
|
|
|
return 3;
|
2023-07-15 14:29:14 +02:00
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
2024-03-10 22:05:26 +01:00
|
|
|
|
if (type != "LOAD")
|
2023-07-15 14:29:14 +02:00
|
|
|
|
{
|
2024-03-10 22:05:26 +01:00
|
|
|
|
// Unload all assemblies associated with this script
|
|
|
|
|
context.Unload();
|
|
|
|
|
context = null;
|
|
|
|
|
|
|
|
|
|
// Run the garbage collector multiple times to make sure that the
|
|
|
|
|
// assemblies are unloaded for sure
|
|
|
|
|
for (int i = 0; i < 10; i++)
|
|
|
|
|
{
|
|
|
|
|
GC.Collect();
|
|
|
|
|
GC.WaitForPendingFinalizers();
|
|
|
|
|
}
|
2023-07-15 14:29:14 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-10 22:05:26 +01:00
|
|
|
|
return result;
|
2023-07-15 14:29:14 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|