Results 1 to 5 of 5

Thread: C# Scar plugin function lister

  1. #1
    Join Date
    Feb 2009
    Location
    Nebraska
    Posts
    68
    Mentioned
    0 Post(s)
    Quoted
    0 Post(s)

    Post C# Scar plugin function lister

    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();
            }
        }
    }
    Last edited by Grippy; 03-31-2009 at 04:20 AM.
    Grippy has approximately 30,000 hours of Delphi coding experience. srsly.

  2. #2
    Join Date
    Sep 2009
    Posts
    66
    Mentioned
    0 Post(s)
    Quoted
    0 Post(s)

    Default

    Code is quite clean. Comments are good enough for straightforward program like this except missing XML comments on some classes and properties.

  3. #3
    Join Date
    Apr 2007
    Location
    The Netherlands
    Posts
    5,553
    Mentioned
    0 Post(s)
    Quoted
    0 Post(s)

    Default

    You're back!

    Interesting.
    ~Hermen

  4. #4
    Join Date
    Feb 2006
    Location
    Amsterdam
    Posts
    13,692
    Mentioned
    146 Post(s)
    Quoted
    130 Post(s)

    Default

    Quote Originally Posted by Hermen View Post
    You're back!

    Interesting.
    Back...? Seems the post was made quite a while ago?



    The best way to contact me is by email, which you can find on my website: http://wizzup.org
    I also get email notifications of private messages, though.

    Simba (on Twitter | Group on Villavu | Website | Stable/Unstable releases
    Documentation | Source | Simba Bug Tracker on Github and Villavu )


    My (Blog | Website)

  5. #5
    Join Date
    Apr 2007
    Location
    The Netherlands
    Posts
    5,553
    Mentioned
    0 Post(s)
    Quoted
    0 Post(s)

    Default

    Quote Originally Posted by Wizzup? View Post
    Back...? Seems the post was made quite a while ago?
    Ow, I see now he gravedigged it. Sorry =(
    ~Hermen

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •