2011-08-03 23 views
9

Llamo dinámicamente a la API de Windows. Encontré un código en línea que puede hacer esto, y me interesó mucho. La idea en sí es brillante por decir lo menos. Sin embargo, parece que no puedo hacer que funcione para mi código. Los parámetros para la llamada dinámica son del tipo string, stringint[], y me gustaría utilizar la API GetThreadContext con los parámetros pInfo.hThred y ref ctx (mostrados a continuación).C# Convertir IntPtr en int

llamada de API

GetThreadContext(pInfo.hThread, ref ctx); 

El código anterior hará una llamada a la API GetThreadContext (dado que se declara en mi proyecto) - y funciona perfectamente bien. La belleza de la llamada dinámica, sin embargo, es que no se necesita ninguna declaración. Por lo tanto, mi intento de la llamada dinámica:

ctx = new CONTEXT {ContextFlags = 0x10007}; 
PROCESS_INFORMATION pInfo; 

CInvokeAPI.Invoke("kernel32","GetThreadContext",pInfo.hThread, ctx); 

El problema aquí es que no tengo la menor idea de cómo me puede pasar el parámetro ctx como tipo int dado el hecho de que se trata de una estructura.

favor ver más abajo para código adicional

[StructLayout(LayoutKind.Sequential)] 
    struct CONTEXT 
    { 
     public uint ContextFlags; 
     unsafe fixed byte unused[160]; 
     public uint Ebx; 
     public uint Edx; 
     public uint Ecx; 
     public uint Eax; 
     unsafe fixed byte unused2[24]; 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    struct PROCESS_INFORMATION 
    { 
     public IntPtr hProcess; 
     public IntPtr hThread; 
     public int dwProcessId; 
     public int dwThreadId; 
    } 

llamada de API dinámicamente Clase

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 
* Comments: If you use this code, I require you to give me credits. 
*/ 

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); 
} 
+0

¿Podría proporcionar los parámetros REALES esperados por myVoid en el lado no administrado? ¿es realmente una MANIJA y un CONTEXTO *? En caso afirmativo, deberá asignar alguna memoria no administrada para esto y copiar una instancia CONTEXT dentro de ella, ver http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal.structuretoptr.aspx si en su lugar de un controlador necesita un PROCESS_INFORMATION * necesita hacer lo mismo para este parámetro. –

+0

@VirtualBlackFox Actualizado ... –

+0

Tenga cuidado con 64-bit – SLaks

Respuesta

6

¿Se puede utilizar el método IntPtr.ToInt32? Eso debería funcionar para el primer parámetro. No estoy seguro acerca de la conversión de estructura sin embargo.

Tal vez eche un vistazo a this post para obtener ideas sobre cómo convertir la estructura a un número entero.

ACTUALIZACIÓN:

No hay directa equivalente C# de VarPtr en C#, pero encontré un manual de referencia here (junto con una explicación de lo que está haciendo ... suena similar a la explicación de VarPtr en this post). Este es un extracto del código. Puede ser útil para Usted:

public static int VarPtr(object e) 
{ 
    GCHandle GC = GCHandle.Alloc(e, GCHandleType.Pinned); 
    int gc = GC.AddrOfPinnedObject().ToInt32(); 
    GC.Free(); 
    return gc; 
} 

NOTA: Hay algunos defectos potenciales a esta función, como se ha mencionado en este post.

+0

Quizás para el primer objeto que se pasa, pero no funcionará para el objeto Contexto. –

+0

@Evan: agregué un enlace a una publicación que podría ayudarlo a comenzar en la dirección correcta (para la conversión de estructuras). –

+0

@Evan: Tal vez también pueda ser más útil por la mañana ... muy cansado. –