2011-08-03 22 views
9

Windows API'yi dinamik olarak arıyorum. Bunu yapabileceğimiz bazı kodlar buldum ve buna çok ilgi gösterdim. Fikrin kendisi en azından söylemek zekice. Ancak, kodum için çalışmasını sağlayamıyorum. Dinamik çağrının parametreleri string, stringint[] türlerinden ve GetThreadContext API'sini pInfo.hThred ve ref ctx (aşağıda gösterilen) parametreleriyle kullanmak istiyorum.C# IntPtr'i int dönüştüre

yukarıdaki kodu (benim projede bildirilmiş olduğu göz önüne alındığında) GetThreadContext API çağrısı yapacak

GetThreadContext(pInfo.hThread, ref ctx); 

API Çağrı - ve mükemmel çalışıyor. Bununla birlikte, dinamik çağrının güzelliği, herhangi bir deklarasyonun gerekmemesidir. Yani, dinamik çağrı benim girişimi:

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

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

burada mesele ben bir yapı olduğunu göz önüne alındığında int tipte parametre ctx geçebilir nasıl bir ipucu değil olması.

[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; 
    } 

Çağrı API Dinamik Sınıf

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

Yönetilmeyen tarafımda myVoid tarafından beklenen GERÇEK parametreleri sağlayabilir misiniz? gerçekten bir HANDLE ve bir CONTEXT * mi? Eğer evet ise bunun için bir yönetilmeyen bellek ayırmanız gerekir ki bunun içinde bir CONTEXT örneği var, bunun yerine http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal.structuretoptr.aspx adresine bakın. Bir tanıtıcıya ihtiyacınız olan bir PROCESS_INFORMATION * bu parametrenin aynısını yapmanız gerekir. –

+0

@VirtualBlackFox Güncelleniyor ... –

+0

64 bit – SLaks

cevap

6

Eğer IntPtr.ToInt32 yöntemini kullanabilir ek kod için lütfen aşağıya bakın? Bu ilk parametre için çalışmalıdır. Yapısal dönüşüm hakkında emin değilim.

Yapıyı tamsayıya dönüştürme hakkında fikir edinmek için this post'a bakın.

GÜNCELLEME:

Orada C# VarPtr doğrudan hiçbir C# eşdeğerdir, ama ne yaptığına dair bir açıklama ile birlikte here (başvurulan bir kılavuz buldunuz ... VarPtr açıklamasında benzer sesler this post). Bu kodun bir alıntıdır. Bu sizin için yararlı olabilir:

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

NOT: Bu post belirtildiği gibi bu işlev için bazı potansiyeller kusurları vardır.

+0

Belki de iletilen ilk nesne için, ancak Bağlam nesnesinde çalışmayacaktır. –

+0

@Evan: Doğru yönde başlamanıza neden olabilecek bir gönderiye bağlantı ekledim (struct conversion için). –

+0

@Evan: Belki sabahları daha fazla yardım edebilirim ... çok yorgunum. –

İlgili konular