C# Convertir IntPtr en int
Je suis dynamiquement l'appel de l'API Windows. J'ai trouvé un peu de code en ligne qui peut faire cela, et j'ai pris beaucoup d'intérêt pour elle. L'idée elle-même est génial pour dire le moins. Cependant, je n'arrive pas à faire fonctionner mon code. Les paramètres de la dynamique de l'appel sont de type string
, string
int[]
, et je voudrais utiliser l'API GetThreadContext
avec les paramètres de pInfo.hThred
et ref ctx
(voir ci-dessous).
Appel d'API
GetThreadContext(pInfo.hThread, ref ctx);
Le code ci-dessus va faire un appel à la GetThreadContext API (étant donné qu'il est déclaré dans mon projet) et fonctionne parfaitement bien. La beauté de la dynamique de l'appel, cependant, est qu'aucune déclaration n'est nécessaire. Donc, ma tentative de la dynamique de l'appel:
ctx = new CONTEXT {ContextFlags = 0x10007};
PROCESS_INFORMATION pInfo;
CInvokeAPI.Invoke("kernel32","GetThreadContext",pInfo.hThread, ctx);
Ici, le problème est que je n'ai pas la moindre idée de comment je peux passer le paramètre ctx comme étant de type int, étant donné le fait que c'est une struct.
Veuillez voir ci-dessous pour plus de 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;
}
Appel de l'API Dynamiquement Classe
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);
}
Mis à jour ...
Méfiez-vous des 64-bit
En utilisant 32 bits de la machine. Je vous remercie bien.
OriginalL'auteur | 2011-08-03
Vous devez vous connecter pour publier un commentaire.
Pouvez-vous utiliser le IntPtr.ToInt32 méthode? Cela devrait fonctionner pour le premier paramètre. Pas sûr au sujet de la structure de conversion.
Peut-être jeter un oeil à ce post pour des idées sur la façon de convertir la structure d'un entier.
Mise à JOUR:
Il n'y a pas de direct C# équivalent de VarPtr en C#, mais j'ai trouvé un manuel référencé ici (avec une explication de ce qu'il est en train de faire... des sons semblables à l'explication de VarPtr dans ce post). Ceci est un extrait de code. Il peut être utile pour vous:
REMARQUE: Il existe des potentiels de défauts à cette fonction, comme mentionné dans ce post.
J'ai ajouté un lien vers un post qui pourrait vous aider à démarrer dans la bonne direction (pour la structure de conversion).
Peut-être que je peux aussi être plus d'aide dans le matin... très fatigué.
Malheureusement, il n'existe pas de remplacement direct pour VarPtr en C#. J'ai mis à jour ma réponse avec une fonction qui peut être assez près pour que vous avez besoin, ainsi que quelques liens pour expliquer les choses plus loin.
J'ai utilisé pour Convertir les.ToInt32() sur le premier paramètre, et VarPtr sur le deuxième paramètre (Ctx), mais toujours pas de chance. Vous peut-être quelque chose de bien..
OriginalL'auteur Jason Down