2011-08-03 4 views
9

동적으로 Windows API를 호출하고 있습니다. 이렇게 할 수있는 온라인 코드를 몇 개 발견했는데, 많은 관심을 보였습니다. 아이디어 그 자체는 가장 적게 말하기에 훌륭합니다. 그러나, 나는 내 코드에 대해 작동하도록 할 수 없습니다. 동적 호출의 매개 변수는 string, stringint[] 유형이며, GetThreadContext 매개 변수는 pInfo.hThredref ctx (아래 참조)과 함께 사용하고 싶습니다.C# IntPtr을 int로 변환합니다.

위의 코드는 (내 프로젝트에 선언 주어진)를 GetThreadContext API 호출을 만들 것입니다

GetThreadContext(pInfo.hThread, ref ctx); 

API 호출 - 그리고 완벽하게 잘 작동합니다. 그러나 동적 호출의 장점은 선언이 필요 없다는 것입니다. 따라서, 동적 호출에 내 시도 :

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

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

여기서 문제는 내가이 구조체는 사실 주어진 int 형으로 매개 변수 CTX을 전달할 수있는 방법에 대한 단서를하지 않은 것입니다.

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

통화 API 동적 클래스

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

관리되지 않는 쪽에서 myVoid에서 기대하는 REAL 매개 변수를 제공 할 수 있습니까? 그것은 정말로 손잡이이자 문맥입니까? 그렇다면 이것을위한 관리되지 않는 메모리를 할당해야합니다. 그 안에 CONTEXT 인스턴스를 복사하십시오. 대신 http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal.structuretoptr.aspx를 참조하십시오. PROCESS_INFORMATION *이 필요한 핸들의 경우이 매개 변수에 대해 동일한 작업을 수행해야합니다. –

+0

@VirtualBlackFox 업데이트 ... –

+0

주의 사항 64 비트 – SLaks

답변

6

당신이 IntPtr.ToInt32 방법을 사용할 수있는 추가 코드는 아래를 참조하십시오? 그것은 첫 번째 매개 변수에 대해 작동해야합니다. 구조체 변환에 대해서는 확실하지 않습니다.

구조체를 정수로 변환하는 방법에 대한 아이디어는 this post을 참조하십시오.

UPDATE :

가 C#에서 아래 문장의 직접적인 C 번호에 해당이 없지만, 나는 그것이 무엇을하고 있는지에 대한 설명과 함께 here을 (참조 매뉴얼을 찾았어요 ... 아래 문장의 설명에서와 비슷한 소리 this post). 이것은 코드의 발췌 부분입니다. 그것은 당신을 위해 유용 할 수 있습니다 :

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

참고 :이 post에 언급 된이 기능에 약간의 잠재력 결함이있다.

+0

아마도 첫 번째 객체가 전달되었지만 Context 객체에서는 작동하지 않습니다. –

+0

@ 에반 (Evan) : 구조 변환을 위해 올바른 방향으로 시작할 수있는 게시물에 대한 링크를 추가했습니다. –

+0

@ 에반 : 어쩌면 나는 아침에 더 많은 도움이 될지도 모른다. .. 매우 피곤했다. –

관련 문제