2010-12-31 2 views
2

Comment puis-je analyser par programme une DLL native pour lire ses importations?Comment faire pour lire par programmation les importations DLL natives en C#?


[EDIT: ma question originale ressemblait à ceci, avec un énorme morceau de code défectueux. Veuillez voir les réponses ci-dessous pour plus de code correct.]

Le code C# situé à this link est destiné à imprimer les importations d'une DLL native.

Je trouve que lorsque j'exécute l'exemple de code avec la cible de l'exemple original, MSCOREE.DLL, il imprime toutes les importations correctement. Mais quand j'utilise d'autres DLLs comme GDI32.DLL ou WSOCK32.DLL, les imports ne sont pas imprimés. Qu'est-ce qui manque à ce code qui laisserait imprimer toutes les importations comme, par exemple, DUMPBIN.EXE?

+2

Vous devez être une blague. Utilisez Dumpbin.exe/exports –

+0

@Hans - le code va éventuellement être utilisé dans un outil d'analyse de dépendance. La version de console ici est juste un échauffement. J'ai en fait une version de travail de l'application réelle qui invoque "DUMPBIN/imports", puis analyse la sortie, mais je préférerais ne pas le faire. – Eric

+0

+1 Hans. Mais si vous avez besoin de faire cela par programme, n'est pas ce que dbghelp.dll est pour? –

Répondre

4

Il y a un très gros problème dans le code (à savoir la définition de THUNK_DATA) et divers autres petits problèmes concernant principalement en fin de table détection (en utilisant IsBadReadPtr au lieu de vérifications NULL, sans ajouter d'adresse de base si nécessaire).

est ici une version fixe qui produit la même sortie que dumpbin au moins pour wsock32:

using System; 
using System.Runtime.InteropServices; 
using System.Security; 

namespace PETest2 
{ 
    [StructLayout(LayoutKind.Explicit)] 
    public unsafe struct IMAGE_IMPORT_BY_NAME 
    { 
     [FieldOffset(0)] 
     public ushort Hint; 
     [FieldOffset(2)] 
     public fixed char Name[1]; 
    } 

    [StructLayout(LayoutKind.Explicit)] 
    public struct IMAGE_IMPORT_DESCRIPTOR 
    { 
     #region union 
     /// <summary> 
     /// CSharp doesnt really support unions, but they can be emulated by a field offset 0 
     /// </summary> 

     [FieldOffset(0)] 
     public uint Characteristics;   // 0 for terminating null import descriptor 
     [FieldOffset(0)] 
     public uint OriginalFirstThunk;   // RVA to original unbound IAT (PIMAGE_THUNK_DATA) 
     #endregion 

     [FieldOffset(4)] 
     public uint TimeDateStamp; 
     [FieldOffset(8)] 
     public uint ForwarderChain; 
     [FieldOffset(12)] 
     public uint Name; 
     [FieldOffset(16)] 
     public uint FirstThunk; 
    } 

    [StructLayout(LayoutKind.Explicit)] 
    public struct THUNK_DATA 
    { 
     [FieldOffset(0)] 
     public uint ForwarderString;  // PBYTE 
     [FieldOffset(0)] 
     public uint Function;    // PDWORD 
     [FieldOffset(0)] 
     public uint Ordinal; 
     [FieldOffset(0)] 
     public uint AddressOfData;  // PIMAGE_IMPORT_BY_NAME 
    } 

    public unsafe class Interop 
    { 
     #region Public Constants 
     public static readonly ushort IMAGE_DIRECTORY_ENTRY_IMPORT = 1; 
     #endregion 
     #region Private Constants 
     #region CallingConvention CALLING_CONVENTION 
     /// <summary> 
     ///  Specifies the calling convention. 
     /// </summary> 
     /// <remarks> 
     ///  Specifies <see cref="CallingConvention.Winapi" /> for Windows to 
     ///  indicate that the default should be used. 
     /// </remarks> 
     private const CallingConvention CALLING_CONVENTION = CallingConvention.Winapi; 
     #endregion CallingConvention CALLING_CONVENTION 
     #region IMPORT DLL FUNCTIONS 
     private const string KERNEL_DLL = "kernel32"; 
     private const string DBGHELP_DLL = "Dbghelp"; 
     #endregion 
     #endregion Private Constants 

     [DllImport(KERNEL_DLL, CallingConvention = CALLING_CONVENTION, EntryPoint = "GetModuleHandleA"), SuppressUnmanagedCodeSecurity] 
     public static extern void* GetModuleHandleA(/*IN*/ char* lpModuleName); 

     [DllImport(KERNEL_DLL, CallingConvention = CALLING_CONVENTION, EntryPoint = "GetModuleHandleW"), SuppressUnmanagedCodeSecurity] 
     public static extern void* GetModuleHandleW(/*IN*/ char* lpModuleName); 

     [DllImport(KERNEL_DLL, CallingConvention = CALLING_CONVENTION, EntryPoint = "IsBadReadPtr"), SuppressUnmanagedCodeSecurity] 
     public static extern bool IsBadReadPtr(void* lpBase, uint ucb); 

     [DllImport(DBGHELP_DLL, CallingConvention = CALLING_CONVENTION, EntryPoint = "ImageDirectoryEntryToData"), SuppressUnmanagedCodeSecurity] 
     public static extern void* ImageDirectoryEntryToData(void* Base, bool MappedAsImage, ushort DirectoryEntry, out uint Size); 


    } 


    static class Foo 
    { 
     // From winbase.h in the Win32 platform SDK. 
     // 
     const uint DONT_RESOLVE_DLL_REFERENCES = 0x00000001; 
     const uint LOAD_IGNORE_CODE_AUTHZ_LEVEL = 0x00000010; 

     [DllImport("kernel32.dll"), SuppressUnmanagedCodeSecurity] 
     static extern uint LoadLibraryEx(string fileName, uint notUsedMustBeZero, uint flags); 

     public static void Main() 
     { 
      //var path = @"c:\windows\system32\mscoree.dll"; 
      //var path = @"c:\windows\system32\gdi32.dll"; 
      var path = @"c:\windows\system32\wsock32.dll"; 
      var hLib = LoadLibraryEx(path, 0, 
            DONT_RESOLVE_DLL_REFERENCES | LOAD_IGNORE_CODE_AUTHZ_LEVEL); 
      TestImports(hLib, true); 

     } 


     // using mscoree.dll as an example as it doesnt export any thing 
     // so nothing shows up if you use your own module. 
     // and the only none delayload in mscoree.dll is the Kernel32.dll 
     private static void TestImports(uint hLib, bool mappedAsImage) 
     { 
      unsafe 
      { 
       //fixed (char* pszModule = "mscoree.dll") 
       { 
        //void* hMod = Interop.GetModuleHandleW(pszModule); 
        void* hMod = (void*)hLib; 

        uint size = 0; 
        uint BaseAddress = (uint)hMod; 

        if (hMod != null) 
        { 
         Console.WriteLine("Got handle"); 

         IMAGE_IMPORT_DESCRIPTOR* pIID = (IMAGE_IMPORT_DESCRIPTOR*)Interop.ImageDirectoryEntryToData((void*)hMod, mappedAsImage, Interop.IMAGE_DIRECTORY_ENTRY_IMPORT, out size); 
         if (pIID != null) 
         { 
          Console.WriteLine("Got Image Import Descriptor"); 
          while (pIID->OriginalFirstThunk != 0) 
          { 
           try 
           { 
            char* szName = (char*)(BaseAddress + pIID->Name); 
            string name = Marshal.PtrToStringAnsi((IntPtr)szName); 
            Console.WriteLine("pIID->Name = {0} BaseAddress - {1}", name, (uint)BaseAddress); 

            THUNK_DATA* pThunkOrg = (THUNK_DATA*)(BaseAddress + pIID->OriginalFirstThunk); 

            while (pThunkOrg->AddressOfData != 0) 
            { 
             char* szImportName; 
             uint Ord; 

             if ((pThunkOrg->Ordinal & 0x80000000) > 0) 
             { 
              Ord = pThunkOrg->Ordinal & 0xffff; 
              Console.WriteLine("imports ({0}).Ordinal{1} - Address: {2}", name, Ord, pThunkOrg->Function); 
             } 
             else 
             { 
              IMAGE_IMPORT_BY_NAME* pIBN = (IMAGE_IMPORT_BY_NAME*)(BaseAddress + pThunkOrg->AddressOfData); 

              if (!Interop.IsBadReadPtr((void*)pIBN, (uint)sizeof(IMAGE_IMPORT_BY_NAME))) 
              { 
               Ord = pIBN->Hint; 
               szImportName = (char*)pIBN->Name; 
               string sImportName = Marshal.PtrToStringAnsi((IntPtr)szImportName); // yes i know i am a lazy ass 
               Console.WriteLine("imports ({0}).{1}@{2} - Address: {3}", name, sImportName, Ord, pThunkOrg->Function); 
              } 
              else 
              { 
               Console.WriteLine("Bad ReadPtr Detected or EOF on Imports"); 
               break; 
              } 
             } 

             pThunkOrg++; 
            } 
           } 
           catch (AccessViolationException e) 
           { 
            Console.WriteLine("An Access violation occured\n" + 
                 "this seems to suggest the end of the imports section\n"); 
            Console.WriteLine(e); 
           } 

           pIID++; 
          } 

         } 

        } 
       } 
      } 

      Console.WriteLine("Press Any Key To Continue......"); 
      Console.ReadKey(); 
     } 
    } 
} 
+0

merci beaucoup! – Eric

+0

Les pointeurs C++ à l'intérieur des structures doivent devenir .NET 'IntPtr', pas UInt32 (C#' uint'). –

1

à partir du débogueur, vous pouvez voir que cette boucle while est jamais entré (pour gdi32.dll & wsock32.dll):

while (!Interop.IsBadReadPtr((void*)pIID->OriginalFirstThunk, (uint)size)) 

Il est fortement conseillé de ne pas utiliser IsBadReadPtr puisque vous ne pouvez pas toujours compter sur elle est valeur de retour. voir: http://msdn.microsoft.com/en-us/library/aa366713.aspx ou http://blogs.msdn.com/b/oldnewthing/archive/2006/09/27/773741.aspx

Une approche différente pour gérer la validité d'un pointeur consiste à utiliser une gestion d'exception structurée. Essayez d'accéder à l'adresse mémoire, gérer les exceptions de violation d'accès.

Que ce soit une bonne pratique ou non, est une discussion différente.

pourrait être utile:

http://www.codeproject.com/Messages/2626152/Replacement-for-IsBadReadPtr-in-Windows-Vista.aspx

http://www.softwareverify.com/software-verify-blog/?p=319

2

bâtiment sur les corrections Jester à l'échantillon d'origine, voici une classe qui lit les importations et les Exportations. Je l'ai utilisé avec succès sur les DLL 32 bits, je ne sais pas encore sur 64 bits cependant.

using System; 
using System.Collections.Generic; 
using System.Runtime.InteropServices; 
using System.Security; 

/* 
Inspirations: 
* http://www.bearcanyon.com/dotnet/#AssemblyParser (Mike Woodring's "Parsing PE File Headers to Determine if a DLL or EXE is an Assembly") 
* http://stackoverflow.com/questions/1563134/how-do-i-read-the-pe-header-of-a-module-loaded-in-memory ("How do I read the PE header of a module loaded in memory?") 
* http://stackoverflow.com/questions/2975639/resolving-rvas-for-import-and-export-tables-within-a-pe-file ("Resolving RVA's for Import and Export tables within a PE file.") 
* http://www.lenholgate.com/blog/2006/04/i-love-it-when-a-plan-comes-together.html 
* http://www.gamedev.net/community/forums/topic.asp?topic_id=409936 
* http://stackoverflow.com/questions/4571088/how-to-programatically-read-native-dll-imports-in-c 
*/ 

namespace PE 
{  
    public unsafe class PortableExecutableParser 
    { 
     public delegate void DLog(string fmt, params object[] args); 
     private readonly DLog _fnLog; 
     private void Log(string fmt, params object[] args) 
     { 
      if (_fnLog != null) 
       _fnLog(fmt, args); 
     } 

     private readonly List<string> _exports = new List<string>(); 
     public IEnumerable<string> Exports { get { return _exports; } } 

     private readonly List<Tuple<string, List<string>>> _imports = new List<Tuple<string, List<string>>>(); 
     public IEnumerable<Tuple<string, List<string>>> Imports { get { return _imports; } } 


     public PortableExecutableParser(string path, DLog fnLog=null) 
     { 
      _fnLog = fnLog; 
      LOADED_IMAGE loadedImage; 

      if (MapAndLoad(path, null, out loadedImage, true, true)) 
      { 
       LoadExports(loadedImage); 
       LoadImports(loadedImage); 
      } 
     } 

     private void LoadExports(LOADED_IMAGE loadedImage) 
     { 
      var hMod = (void*)loadedImage.MappedAddress; 

      if (hMod != null) 
      { 
       Log("Got handle"); 

       uint size; 
       var pExportDir = (IMAGE_EXPORT_DIRECTORY*)ImageDirectoryEntryToData(
        (void*)loadedImage.MappedAddress, 
        false, 
        IMAGE_DIRECTORY_ENTRY_EXPORT, 
        out size); 

       if (pExportDir != null) 
       { 
        Log("Got Image Export Descriptor"); 

        var pFuncNames = (uint*)RvaToVa(loadedImage, pExportDir->AddressOfNames); 

        for (uint i = 0; i < pExportDir->NumberOfNames; i++) 
        { 
         uint funcNameRva = pFuncNames[i]; 
         if (funcNameRva != 0) 
         { 
          var funcName = 
           (char*)RvaToVa(loadedImage, funcNameRva); 
          var name = Marshal.PtrToStringAnsi((IntPtr)funcName); 
          Log(" funcName: {0}", name); 
          _exports.Add(name); 
         } 

        } 

       } 

      } 

     } 

     private static IntPtr RvaToVa(LOADED_IMAGE loadedImage, uint rva) 
     { 
      return ImageRvaToVa(loadedImage.FileHeader, loadedImage.MappedAddress, rva, IntPtr.Zero); 
     } 
     private static IntPtr RvaToVa(LOADED_IMAGE loadedImage, IntPtr rva) 
     { 
      return RvaToVa(loadedImage, (uint)(rva.ToInt32())); 
     } 



     private void LoadImports(LOADED_IMAGE loadedImage) 
     { 
      var hMod = (void*)loadedImage.MappedAddress; 

      if (hMod != null) 
      { 
       Console.WriteLine("Got handle"); 

       uint size; 
       var pImportDir = 
        (IMAGE_IMPORT_DESCRIPTOR*) 
        ImageDirectoryEntryToData(hMod, false, 
                 IMAGE_DIRECTORY_ENTRY_IMPORT, out size); 
       if (pImportDir != null) 
       { 
        Log("Got Image Import Descriptor"); 
        while (pImportDir->OriginalFirstThunk != 0) 
        { 
         try 
         { 
          var szName = (char*) RvaToVa(loadedImage, pImportDir->Name); 
          string name = Marshal.PtrToStringAnsi((IntPtr) szName); 

          var pr = new Tuple<string, List<string>>(name, new List<string>()); 
          _imports.Add(pr); 


          var pThunkOrg = (THUNK_DATA*)RvaToVa(loadedImage, pImportDir->OriginalFirstThunk); 

          while (pThunkOrg->AddressOfData != IntPtr.Zero) 
          { 
           uint ord; 

           if ((pThunkOrg->Ordinal & 0x80000000) > 0) 
           { 
            ord = pThunkOrg->Ordinal & 0xffff; 
            Log("imports ({0}).Ordinal{1} - Address: {2}", name, ord, 
                 pThunkOrg->Function); 
           } 
           else 
           { 
            var pImageByName = 
             (IMAGE_IMPORT_BY_NAME*) RvaToVa(loadedImage, pThunkOrg->AddressOfData); 

            if (
             !IsBadReadPtr(pImageByName, (uint) sizeof (IMAGE_IMPORT_BY_NAME))) 
            { 
             ord = pImageByName->Hint; 
             var szImportName = pImageByName->Name; 
             string sImportName = Marshal.PtrToStringAnsi((IntPtr) szImportName); 
             Log("imports ({0}).{1}@{2} - Address: {3}", name, 
                  sImportName, ord, pThunkOrg->Function); 

             pr.Item2.Add(sImportName); 
            } 
            else 
            { 
             Log("Bad ReadPtr Detected or EOF on Imports"); 
             break; 
            } 
           } 

           pThunkOrg++; 
          } 
         } 
         catch (AccessViolationException e) 
         { 
          Log("An Access violation occured\n" + 
               "this seems to suggest the end of the imports section\n"); 
          Log(e.ToString()); 
         } 

         pImportDir++; 
        } 

       } 

      } 
     } 


// ReSharper disable InconsistentNaming 
     private const ushort IMAGE_DIRECTORY_ENTRY_IMPORT = 1; 
     private const ushort IMAGE_DIRECTORY_ENTRY_EXPORT = 0; 

     private const CallingConvention WINAPI = CallingConvention.Winapi; 

     private const string KERNEL_DLL = "kernel32"; 
     private const string DBGHELP_DLL = "Dbghelp"; 
     private const string IMAGEHLP_DLL = "ImageHlp"; 
// ReSharper restore InconsistentNaming 

     [DllImport(KERNEL_DLL, CallingConvention = WINAPI, EntryPoint = "GetModuleHandleA"), SuppressUnmanagedCodeSecurity] 
     public static extern void* GetModuleHandleA(/*IN*/ char* lpModuleName); 

     [DllImport(KERNEL_DLL, CallingConvention = WINAPI, EntryPoint = "GetModuleHandleW"), SuppressUnmanagedCodeSecurity] 
     public static extern void* GetModuleHandleW(/*IN*/ char* lpModuleName); 

     [DllImport(KERNEL_DLL, CallingConvention = WINAPI, EntryPoint = "IsBadReadPtr"), SuppressUnmanagedCodeSecurity] 
     public static extern bool IsBadReadPtr(void* lpBase, uint ucb); 

     [DllImport(DBGHELP_DLL, CallingConvention = WINAPI, EntryPoint = "ImageDirectoryEntryToData"), SuppressUnmanagedCodeSecurity] 
     public static extern void* ImageDirectoryEntryToData(void* pBase, bool mappedAsImage, ushort directoryEntry, out uint size); 

     [DllImport(DBGHELP_DLL, CallingConvention = WINAPI), SuppressUnmanagedCodeSecurity] 
     public static extern IntPtr ImageRvaToVa(
      IntPtr pNtHeaders, 
      IntPtr pBase, 
      uint rva, 
      IntPtr pLastRvaSection); 

     [DllImport(DBGHELP_DLL, CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurity] 
     public static extern IntPtr ImageNtHeader(IntPtr pImageBase); 

     [DllImport(IMAGEHLP_DLL, CallingConvention = CallingConvention.Winapi), SuppressUnmanagedCodeSecurity] 
     public static extern bool MapAndLoad(string imageName, string dllPath, out LOADED_IMAGE loadedImage, bool dotDll, bool readOnly); 

    } 


// ReSharper disable InconsistentNaming 
    [StructLayout(LayoutKind.Sequential)] 
    public struct LOADED_IMAGE 
    { 
     public IntPtr moduleName; 
     public IntPtr hFile; 
     public IntPtr MappedAddress; 
     public IntPtr FileHeader; 
     public IntPtr lastRvaSection; 
     public UInt32 numbOfSections; 
     public IntPtr firstRvaSection; 
     public UInt32 charachteristics; 
     public ushort systemImage; 
     public ushort dosImage; 
     public ushort readOnly; 
     public ushort version; 
     public IntPtr links_1; // these two comprise the LIST_ENTRY 
     public IntPtr links_2; 
     public UInt32 sizeOfImage; 
    } 



    [StructLayout(LayoutKind.Explicit)] 
    public unsafe struct IMAGE_IMPORT_BY_NAME 
    { 
     [FieldOffset(0)] 
     public ushort Hint; 
     [FieldOffset(2)] 
     public fixed char Name[1]; 
    } 

    [StructLayout(LayoutKind.Explicit)] 
    public struct IMAGE_IMPORT_DESCRIPTOR 
    { 
     #region union 
     /// <summary> 
     /// CSharp doesnt really support unions, but they can be emulated by a field offset 0 
     /// </summary> 

     [FieldOffset(0)] 
     public uint Characteristics;   // 0 for terminating null import descriptor 
     [FieldOffset(0)] 
     public uint OriginalFirstThunk;   // RVA to original unbound IAT (PIMAGE_THUNK_DATA) 
     #endregion 

     [FieldOffset(4)] 
     public uint TimeDateStamp; 
     [FieldOffset(8)] 
     public uint ForwarderChain; 
     [FieldOffset(12)] 
     public uint Name; 
     [FieldOffset(16)] 
     public uint FirstThunk; 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    public struct IMAGE_EXPORT_DIRECTORY 
    { 
     public UInt32 Characteristics; 
     public UInt32 TimeDateStamp; 
     public UInt16 MajorVersion; 
     public UInt16 MinorVersion; 
     public UInt32 Name; 
     public UInt32 Base; 
     public UInt32 NumberOfFunctions; 
     public UInt32 NumberOfNames; 
     public IntPtr AddressOfFunctions;  // RVA from base of image 
     public IntPtr AddressOfNames;  // RVA from base of image 
     public IntPtr AddressOfNameOrdinals; // RVA from base of image 
    } 

    [StructLayout(LayoutKind.Explicit)] 
    public struct THUNK_DATA 
    { 
     [FieldOffset(0)] 
     public uint ForwarderString;  // PBYTE 
     [FieldOffset(0)] 
     public uint Function;    // PDWORD 
     [FieldOffset(0)] 
     public uint Ordinal; 
     [FieldOffset(0)] 
     public IntPtr AddressOfData;  // PIMAGE_IMPORT_BY_NAME 
    } 
// ReSharper restore InconsistentNaming 
} 
+1

Ne fonctionne pas sur x64. – Maxence

+2

S'il vous plaît voir la réponse de @PiranhA - il contient des modifications nécessaires pour faire fonctionner ce code – Alexander

2

Pour Eric's answer travail sur x64 vous avez changer le type de données des adresses RVA (AddressOfFunctions, AddressOfNames et AddressOfNameOrdinals) dans IMAGE_EXPORT_DIRECTORY. Ceux-ci sont toujours longs de 32 bits (UInt32). IntPtr est 32 bits sur x86 et 64 bits sur x64.

Voir http://pinvoke.net/default.aspx/Structures/IMAGE_EXPORT_DIRECTORY.html

[StructLayout(LayoutKind.Sequential)] 
public struct IMAGE_EXPORT_DIRECTORY 
{ 
    public UInt32 Characteristics; 
    public UInt32 TimeDateStamp; 
    public UInt16 MajorVersion; 
    public UInt16 MinorVersion; 
    public UInt32 Name; 
    public UInt32 Base; 
    public UInt32 NumberOfFunctions; 
    public UInt32 NumberOfNames; 
    public UInt32 AddressOfFunctions;  // RVA from base of image 
    public UInt32 AddressOfNames;  // RVA from base of image 
    public UInt32 AddressOfNameOrdinals; // RVA from base of image 
} 
0

expansion sur Eric's answer (et merci à tous ceux qui ont contribué le code ici) ... Cette classe, lors de la fusion avec les correctifs x64, semble fonctionner correctement si les objectifs du projet d'accueil .NET x86.Il lit les exécutables 32 et 64 bits avec succès. Toutefois, deux problèmes se produisent si le projet hôte est défini sur x64 cible.

  1. se bloque RvaToVA sur certains fichiers (par exemple, le cas de test du lecteur Adobe mentionné ci-dessous), sur la ligne

    retour RvaToVa (loadedImage, (uint) (rva.ToInt32());

    Avec un débordement, la modification en .ToInt64 résout le débordement, mais

  2. Il semble produire une liste incomplète d'importations lorsqu'il est testé par rapport à la base de référence Acrobat Reader 10 MUI (acrord32.exe version 10.0.0.396). Exécutable 32 bits

    Dumpbin rapporte les 9 importations suivantes pour Shell32.dll

    SHGetFolderPathW, 
    ShellExecuteExW, 
    CommandLineToArgvW, 
    ShellExecuteW, 
    SHCreateDirectoryExW, 
    SHGetFileInfoW, 
    SHGetPathFromIDListW, 
    FindExecutableW 
    SHBrowseForFolderW 
    

    Cependant le code lorsqu'il est exécuté en mode 64 bits ne trouve que 4 de ces

    SHGetFolderPathW, 
    ShellExecuteW, 
    SHGetFileInfoW, 
    FindExecutableW 
    

    Et à ce moment pThunk-> ordinaux de retour 0, causant la fin de la boucle

Je n'ai pas encore eu l'occasion de faire du débogage pour essayer et fi Découvrez ce qui se passe, même si la taille de quelque chose change en x64. En attendant, sachez que cela semble fonctionner tant que l'hôte cible x86 (ce qui est assez bon pour mes besoins). Si je trouve la raison sous-jacente, je vous le ferai savoir.

0

Utilisez le PeNet Library. Il peut analyser l'en-tête PE et est écrit en C#. Vous pouvez l'utiliser facilement en installant le paquet NuGet. (Disclaimer: Je suis, l'auteur de la bibliothèque)

Questions connexes