Just for fun I wrote a simple little C# plugin function lister. It loads a scar plugin and dumps the functions provided.
It has minimal error checking, but does try to protect itself from library load failure and non-plugin libraries.
Code:/* * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You may review the terms of the GNU GPL at <http://www.gnu.org/licenses/>. * * gryphook@live.com */ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; using System.Runtime.InteropServices; using System.Threading; namespace Grippy.ScarPluginInfo { /// <summary> /// Very simple container for Kernel32 library imports /// </summary> public static class Kernel32 { [DllImport("kernel32.dll")] public static extern IntPtr LoadLibrary(string lpLibFileName); [DllImport("kernel32.dll")] public static extern int FreeLibrary(IntPtr hLibModule); [DllImport("kernel32.dll")] public static extern IntPtr GetProcAddress(IntPtr hwnd, string procedureName); } /// <summary> /// ScarPlugin is a simple utility class to load a plugin that implements /// the Scar-style plugin interface. It dynamically loads the library and /// imports the two plugin functions, GetFunctionCount and GetFunctionInfo. /// It's only function provides a list of all of the plugin functions that /// the library publishes. /// ToDo: scrape the PE format to extract the mangled names and match the /// addresses to the plugin addresses, then generate the code to statically /// link the library. /// </summary> public class ScarPlugin { // handle to the library, which will be required in the destructor to unload the library. private IntPtr lib; // Name of the library private string libName; // simple container for plugin function information. public class PluginFunction { public string name; public IntPtr address; } // delegate types for the plugin functions public delegate int getFunctionCount(); public delegate int getFunctionInfo(int x, out IntPtr ProcAddr, ref StringBuilder ProcDef); // variables through which the functions will be called public getFunctionCount GetFunctionCount; public getFunctionInfo GetFunctionInfo; /// <summary> /// Constructor, attempts to load the specified file and import the plugin functions. /// Does not error check, so if the library is not a scar plugin, it probably will /// fail badly. /// </summary> /// <param name="plugin"></param> public ScarPlugin(string plugin) { libName = plugin; // Load the library lib = Kernel32.LoadLibrary(plugin); // The Kernel32 function could be wrapped up neatly to do this error // checking inside the Kernel32 function, but we'll just keep it simple. if (lib == IntPtr.Zero) throw new Exception(string.Format("Unable to load the specified library: \"{0}\", is it a dll?", libName)); // import the functions var gfc = Kernel32.GetProcAddress(lib, "GetFunctionCount"); var gfi = Kernel32.GetProcAddress(lib, "GetFunctionInfo"); // More error checking if ((gfc == IntPtr.Zero) || (gfi == IntPtr.Zero)) throw new Exception(string.Format("The specified file, \"{0}\", does not appear to be a Scar plugin", libName)); // Set up the delegates for the functions GetFunctionCount = (getFunctionCount)Marshal.GetDelegateForFunctionPointer(gfc, typeof(getFunctionCount)); GetFunctionInfo = (getFunctionInfo)Marshal.GetDelegateForFunctionPointer(gfi, typeof(getFunctionInfo)); } ~ScarPlugin() { Kernel32.FreeLibrary(lib); } /// <summary> /// Return a list all of the functions provided by this plugin. /// </summary> /// <returns></returns> public List<PluginFunction> GetFunctions() { try { var functions = new List<PluginFunction>(); IntPtr addr; for (int i = 0; i < GetFunctionCount(); i++) { // StringBuilder is mutable, so it can be used like a pchar. // Reusing the same one seems to cause problems, so create a // new one for each iteration. StringBuilder name = new StringBuilder(300); GetFunctionInfo(i, out addr, ref name); functions.Add(new PluginFunction() { name = name.ToString(), address = addr }); } return functions; } catch (Exception e) { throw new Exception("There was an error while listing the plugin functions.", e); } } } class ScarPluginInfo { static void Main(string[] args) { Console.WriteLine("* This is free software provided under the terms of the GNU GPL."); Console.WriteLine("* You may review the terms of the GNU GPL at <http://www.gnu.org/licenses/>."); Thread.Sleep(500); if (args.Count() != 1) { Console.Error.WriteLine("Error, provide a single parameter, the name of the plugin to examine"); return; } if (!File.Exists(args[0])) { Console.Error.WriteLine("Error, specified file not found: {0}", args[0]); return; } try { // Create a ScarPlugin instance to load the library var plugin = new ScarPlugin(args[0]); // Get a list of all the functions in this library var functions = plugin.GetFunctions(); // Iterate through the list of functions and print the name foreach (ScarPlugin.PluginFunction func in functions) Console.WriteLine(func.name); } catch( Exception e ) { Console.Error.WriteLine("Error: {0}", e.Message); } Console.ReadLine(); } } }




Reply With Quote










