问题描述
我正在动态调用Windows API。我在网上找到了一些可以做到这一点的代码,我对此感兴趣。这个想法本身是至关重要的。然而,我似乎无法使我的代码工作。动态调用的参数是类型 string
, string
int []
,我想使用API GetThreadContext
与参数 pInfo.hThred
和 ref ctx
(如下所示) API调用
GetThreadContext(pInfo.hThread,ref ctx);
上面的代码将调用GetThreadContext API(假定它在我的项目中声明) - 并且完美的工作。然而,动态调用的优点是不需要声明。所以,我尝试动态调用:
ctx = new CONTEXT {ContextFlags = 0x10007};
PROCESS_INFORMATION pInfo;
CInvokeAPI.Invoke(kernel32,GetThreadContext,pInfo.hThread,ctx);
这里的问题是我不知道如何将参数ctx作为类型传递int,因为它是一个结构。
请参阅下面的附加代码
[StructLayout(LayoutKind.Sequential)]
struct CONTEXT
{
public uint ContextFlags;
不安全固定字节未使用[160];
public uint Ebx;
public uint Edx;
public uint Ecx;
public uint Eax;
不安全固定字节unused2 [24];
}
[StructLayout(LayoutKind.Sequential)]
struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public int dwProcessId;
public int dwThreadId;
}
呼叫API动态类
using System;
使用System.Runtime.InteropServices;
使用System.Text;
/ *
*标题:CInvokeAPI.cs
*说明:通过名称实现在纯管理的C#中调用API(这里不存在不安全)。
*
*开发人:affixiate
*评论:如果你使用这段代码,我需要你给我积分。
* /
public static class CInvokeAPI
{
///< summary>
///在内存中生成一个新的非垃圾回收字符串。使用UnicodeWAPI。
///< / summary>
///< param name =theString>一个Unicode字符串< / param>
///< returns>内存中新分配的字符串的地址。请记住在使用后释放它。< / returns>
public static int StringToPtrW(string theString)
{
返回StringToPtr(Encoding.Unicode.GetBytes(theString));
}
///< summary>
///在内存中生成一个新的非垃圾回收字符串。使用ANSIAAPI。
///< / summary>
///< param name =theString> ANSII字符串< / param>
///< returns>内存中新分配的字符串的地址。请记住在使用后释放它。< / returns>
public static String StringToPtrA(string theString)
{
返回StringToPtr(Encoding.ASCII.GetBytes(theString));
}
///< summary>
///用于分配内存的内部方法。
///< / summary>
///< param name =buf>一个字节缓冲区< / param>
///< returns>新分配的内存的地址。请记住在使用后释放它。< / returns>
private static int StringToPtr(byte [] buf)
{
return(int)GCHandle.Alloc(buf,GCHandleType.Pinned).AddrOfPinnedObject();
}
///< summary>
///调用指定的Windows API。
///< / summary>
///< param name =libraryName>库的名称< / param>
///< param name =functionName>函数名称< / param>
///< param name =args>参数< / param>
///< returns> True如果函数成功,否则为false。< / returns>
public static bool Invoke(string libraryName,string functionName,params int [] args)
{
/ *完整性检查。 * /
IntPtr hLoadLibrary = LoadLibrary(libraryName);
if(hLoadLibrary == IntPtr.Zero)return false;
IntPtr hGetProcAddress = GetProcAddress(hLoadLibrary,functionName);
if(hGetProcAddress == IntPtr.Zero)return false;
//为stdcall分配足够的内存和WinAPI函数的参数
IntPtr hMemory = VirtualAlloc(IntPtr.Zero,1024 * 1024,MEM_COMMIT | MEM_RESERVE,MEM_EXECUTE_READWRITE);
if(hMemory == IntPtr.Zero)
return false;
IntPtr hMemoryItr = hMemory;
//预置stdcall标题签名
Marshal.Copy(新字节[] {0x55,0x89,0xE5},0,hMemoryItr,0x3);
hMemoryItr =(IntPtr)((int)hMemoryItr + 0x3);
//循环遍历参数,并以相反的顺序将它们放在堆栈上
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);
//清理堆栈
Marshal.Copy(new byte [] {0x5D,0xC2,0x4,0x0 / *< =我做了一个LOL * /},0, hMemoryItr,0x4);
//如果在这里添加更多ASM代码,请不要忘记增加:hMemoryItr =(IntPtr)((int)hMemoryItr + 0x4);
try
{
var executeAsm =(RunAsm)Marshal.GetDelegateForFunctionPointer(hMemory,typeof(RunAsm));
executeAsm();
}
catch {return false;
//清理我们分配的内存来执行脏工作
VirtualFree(hMemory,0,MEM_RELEASE);
返回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
//我自己的性感代理:
[UnmanagedFunctionPointer(CallingConvention.StdCall,SetLastError = true)]
private delegate void RunAsm() ;
//使用WinAPI:
[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);
}
你可以使用方法?这应该适用于第一个参数。不了解结构体转换。
也许看一下,了解如何将结构转换为整数。
更新:
C#中没有直接的C#相当于VarPtr,但是我确实发现了一个手册引用(以及它在做什么的解释...听起来类似于)。这是代码的摘录。这可能对你有用:
public static int VarPtr(object e)
{
GCHandle GC = GCHandle.Alloc(e,GCHandleType.Pinned);
int gc = GC.AddrOfPinnedObject()。ToInt32();
GC.Free();
return gc;
}
注意:这个功能有一些潜在的缺陷,如上所述在此。
I am dynamically calling Windows API. I found some code online that can do this, and I took a whole lot of interest to it. The idea itself is brilliant to say the least. However, I can't seem to make it work for my code. The parameters for the dynamic call are as of type string
, string
int[]
, and I would like to use the API GetThreadContext
with the parameters of pInfo.hThred
and ref ctx
(shown below).
API Call
GetThreadContext(pInfo.hThread, ref ctx);
The above code will make a call to the GetThreadContext API (given that it is declared in my project) - and works perfectly fine. The beauty of the dynamic call, however, is that no declaration is needed. So, my attempt at the dynamic call:
ctx = new CONTEXT {ContextFlags = 0x10007};
PROCESS_INFORMATION pInfo;
CInvokeAPI.Invoke("kernel32","GetThreadContext",pInfo.hThread, ctx);
The issue here is that I haven't a clue as to how I can pass parameter ctx as type int given the fact that it is a struct.
Please see below for additional code
[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;
}
Call API Dynamically Class
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);
}
Can you use the IntPtr.ToInt32 method? That should work for the first parameter. Not sure about the struct conversion though.
Maybe take a look at this post for ideas on how to convert the struct to an integer.
UPDATE:
There is no direct C# equivalent of VarPtr in C#, but I did find a manual referenced here (along with an explanation of what it is doing... sounds similar to the explanation of VarPtr in this post). This is an excerpt of the code. It may be useful for you:
public static int VarPtr(object e)
{
GCHandle GC = GCHandle.Alloc(e, GCHandleType.Pinned);
int gc = GC.AddrOfPinnedObject().ToInt32();
GC.Free();
return gc;
}
NOTE: There are some potentials flaws to this function, as mentioned in this post.
这篇关于C#将IntPtr转换成int的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!