Jump to content
Nytro

[C#] Call an API by name

Recommended Posts

Posted

[h=2][C#] Call an API by name[/h]

Author: affixiate

The subject of this post pretty much explains what this class does.

You simply pass in the parameters of a WinAPI function and you will be able to call it in memory without having to use "DllImport".

The code, CInvokeAPI.cs:

using System;
using System.Runtime.InteropServices;
using System.Text;

/*
* Title: CInvokeAPI.cs
* Description: Call API by name implementation in purely managed C# (no 'unsafe' mess here).
*
* Developed by: affixiate
* Release date: December 10, 2010
* Released on: http://opensc.ws
*
* Comments: If you use this code, I require you to give me credits. Don't be a ripper! ;]
*/

public static class CInvokeAPI
{
/// <summary>
/// Generates a new, non-garbage collectable string in memory. Use this with Unicode "W" API.
/// </summary>
/// <param name="theString">A Unicode string.</param>
/// <returns>Address of newly allocated string in memory. Remember to free it after use.</returns>
public static int StringToPtrW(string theString)
{
return StringToPtr(Encoding.Unicode.GetBytes(theString));
}

/// <summary>
/// Generates a new, non-garbage collectable string in memory. Use this with ANSI "A" API.
/// </summary>
/// <param name="theString">An ANSII string.</param>
/// <returns>Address of newly allocated string in memory. Remember to free it after use.</returns>
public static int StringToPtrA(string theString)
{
return StringToPtr(Encoding.ASCII.GetBytes(theString));
}

/// <summary>
/// Internal method used to allocate memory.
/// </summary>
/// <param name="buf">A byte buffer.</param>
/// <returns>Address of newly allocated memory. Remember to free it after use.</returns>
private static int StringToPtr(byte[] buf)
{
return (int)GCHandle.Alloc(buf, GCHandleType.Pinned).AddrOfPinnedObject();
}

/// <summary>
/// Invokes the specified Windows API.
/// </summary>
/// <param name="libraryName">Name of the library.</param>
/// <param name="functionName">Name of the function.</param>
/// <param name="args">The arguments.</param>
/// <returns>True if function succeeds, otherwise false.</returns>
public static bool Invoke(string libraryName, string functionName, params int[] args)
{
/* Sanity checks. */
IntPtr hLoadLibrary = LoadLibrary(libraryName);
if (hLoadLibrary == IntPtr.Zero) return false;

IntPtr hGetProcAddress = GetProcAddress(hLoadLibrary, functionName);
if (hGetProcAddress == IntPtr.Zero) return false;

// Allocates more than enough memory for an stdcall and the parameters of a WinAPI function
IntPtr hMemory = VirtualAlloc(IntPtr.Zero, 1024 * 1024, MEM_COMMIT | MEM_RESERVE, MEM_EXECUTE_READWRITE);
if (hMemory == IntPtr.Zero)
return false;

IntPtr hMemoryItr = hMemory;

// Prepends the stdcall header signature
Marshal.Copy(new byte[] {0x55, 0x89, 0xE5}, 0, hMemoryItr, 0x3);
hMemoryItr = (IntPtr)((int)hMemoryItr + 0x3);

// Loop through the passed in arguments and place them on the stack in reverse order
for (int i = (args.Length - 1); i >= 0; i--)
{
Marshal.Copy(new byte[] {0x68}, 0, hMemoryItr, 0x1);
hMemoryItr = (IntPtr)((int)hMemoryItr + 0x1);
Marshal.Copy(BitConverter.GetBytes(args[i]), 0, hMemoryItr, 0x4);
hMemoryItr = (IntPtr)((int)hMemoryItr + 0x4);
}

Marshal.Copy(new byte[] {0xE8}, 0, hMemoryItr, 0x1);
hMemoryItr = (IntPtr)((int)hMemoryItr + 0x1);
Marshal.Copy(BitConverter.GetBytes((int)hGetProcAddress - (int)hMemoryItr - 0x4), 0, hMemoryItr, 0x4);
hMemoryItr = (IntPtr)((int)hMemoryItr + 0x4);

// Cleaning up the stack
Marshal.Copy(new byte[] {0x5D, 0xC2, 0x4, 0x0 /* <= I made a LOL. */}, 0, hMemoryItr, 0x4);
// Don't forget to increment if you are adding more ASM code here: hMemoryItr = (IntPtr)((int)hMemoryItr + 0x4);

try
{
var executeAsm = (RunAsm) Marshal.GetDelegateForFunctionPointer(hMemory, typeof (RunAsm));
executeAsm();
}
catch { return false; }

// Clean up the memory we allocated to do the dirty work
VirtualFree(hMemory, 0, MEM_RELEASE);
return true;
}

// ReSharper disable InconsistentNaming
private const uint MEM_RELEASE = 0x8000;
private const uint MEM_COMMIT = 0x1000;
private const uint MEM_RESERVE = 0x2000;
private const uint MEM_EXECUTE_READWRITE = 0x40;
// ReSharper restore InconsistentNaming

// My own sexy delegate:
[UnmanagedFunctionPointer(CallingConvention.StdCall, SetLastError = true)]
private delegate void RunAsm();

// WinAPI used:
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool VirtualFree(IntPtr lpAddress, UInt32 dwSize, uint dwFreeType);

[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr VirtualAlloc(IntPtr lpAddress, UInt32 dwSize, uint flAllocationType, uint flProtect);

[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr LoadLibrary(string lpFileName);

[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Ansi)]
private static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
}

Sample usage:

CInvokeAPI.Invoke("user32", "MessageBoxW", 0, CInvokeAPI.StringToPtrW("Greetings from affixiate."), CInvokeAPI.StringToPtrW("Hello world."), 1);

Remember: when using my StringToPtr(W/A) methods, it's your responsibility to free the string (the garbage collector is told to not worry about it). You wouldn't want memory leaks now, eh?

If you use this code, it would be most excellent if you could maintain the credits. I'm not asking for cash or beer. This is the least you can do for such high quality work, no? wink.png

Don't be a ripper.

/affixiate

P.S. All constructive criticism as well as questions and general comments are welcome.

Sursa: [sRC] [C#] Call an API by name (my own method)

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...