Ferramentas de Usuário

Ferramentas de Site


dev_net:vb.net:nativedllcalls

Chamadas API Dinamicamente

Introdução: Este conceito não é muito complicado.. mas em grandes projectos com muitas API's pode ficar um pouco "HardCode".. Porque alguns executáveis utilizam este método? Bem a resposta é simples, são utilizados por os Runtime Crypters, Packers mais sofisticados, isto porque a maioria dos AV's lêem o Source do executável e com alguns algoritmos conseguem detectar se o executável faz chamadas API utilizadas por este tipo de softwares.. Este método também é muito útil para o desenvolvimento de aplicações que suportem Plugins ou Scripts.. assim podemos criar e carregar dll's dinamicamente sem as declarar no Core da aplicação!

Apenas necessita de três chamadas declaradas:

  • -LoadLibrary
  • -SetLastError
  • -GetProcAddress
'========================================
'       Codificado por Carlos.DF
'           fLaSh - 2010-03
'         c4rl0s.pt@gmail.com
'========================================
Imports System.Security.Permissions
Imports Microsoft.Win32.SafeHandles
Imports System.Runtime.InteropServices
Imports System.Runtime.ConstrainedExecution
Public Class NativeDllCalls
    ''' <summary>
    ''' Executa um API dinamicamente
    ''' </summary>
    ''' <param name="sLib">O nome ou directoria da DLL</param>
    ''' <param name="sMethod">O nome do metodo a executar</param>
    ''' <param name="oType">O tipo de delegate</param>
    ''' <returns>O delegate associado a chamada API</returns>
    ''' <remarks></remarks>
    Public Function DynamicCall _
            ( _
                ByVal sLib As String, _
                ByVal sMethod As String, _
                ByVal oType As System.Type _
            ) As [Delegate]
        ' Carrega a DLL
        Dim oLibrary As SafeLibraryHandle = Methods.LoadLibrary(sLib)
        Dim dRet As [Delegate] = Nothing
        ' Verifica se foi bem carregada..
        If Not oLibrary.IsInvalid AndAlso Not oLibrary.IsClosed Then
            ' Obtem o enderesso do processo para a função prentendida..
            Dim iProcess As IntPtr = Methods.GetProcAddress(oLibrary, sMethod)
            If Not iProcess = 0 Then
                ' Obtem o ponto do delegate..
                dRet = Marshal.GetDelegateForFunctionPointer(iProcess, oType)
            End If
            ' Fecha o objecto..
            oLibrary.Close()
        End If
        ' Retorna o delegate..
        Return dRet
    End Function
 
    ''' <summary>
    ''' Classe utilizada por os novos mecanismos do .NET
    ''' para carregar as DLL's com segurança..
    ''' </summary>
    ''' <remarks></remarks>
    <SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode:=True)> _
    Public NotInheritable Class SafeLibraryHandle
        Inherits SafeHandleZeroOrMinusOneIsInvalid
        Private Sub New()
            MyBase.New(True)
        End Sub
        Protected Overloads Overrides Function ReleaseHandle() As Boolean
            Return Methods.FreeLibrary(handle)
        End Function
    End Class
 
    ''' <summary>
    ''' Classe para o metodos Nativos (API)
    ''' </summary>
    ''' <remarks></remarks>
    Public NotInheritable Class Methods
        Private Const KERNEL32 As String = "kernel32"
 
        <DllImport(KERNEL32, CharSet:=CharSet.Auto, BestFitMapping:=False, SetLastError:=True)> _
        Public Shared Function LoadLibrary _
                    (ByVal fileName As String) As SafeLibraryHandle
        End Function
 
        <ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)> _
        <DllImport(KERNEL32, SetLastError:=True)> _
        Public Shared Function FreeLibrary _
                    (ByVal hModule As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean
        End Function
 
        <DllImport(KERNEL32)> _
        Public Shared Function GetProcAddress _
                    (ByVal hModule As SafeLibraryHandle, _
                     ByVal procname As String) As IntPtr
        End Function
    End Class
 
End Class

Um exemplo prático: crie um novo projecto e no Form1 adicione este código..

Public  Class Form1
 
    ''' <summary>
    ''' Numerador do tipo de Beep's
    ''' usado neste teste..
    ''' </summary>
    ''' <remarks></remarks>
    Public Enum BeepType
        SimpleBeep = -1
        OK = &H0
        Question = &H20
        Exclamation = &H30
        Asterisk = &H40
    End Enum
 
    ' ATENÇÃO, em ves da chamda API, criamos um delegate com os mesmo parametros!
    '<DllImport("User32.dll", ExactSpelling:=True)> _
    'Private Shared Function MessageBeep(ByVal type As UInteger) As Boolean
    'End Function
    Private Delegate Function MessageBeep(ByVal type As UInteger) As Boolean
 
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ' Cria a instancia do objecto..
        Dim oNativeDllCalls As New NativeDllCalls
        ' Associa o delegate ao ponto da função da DLL..
        Dim oMessageBeep As MessageBeep = _
                oNativeDllCalls.DynamicCall("User32", "MessageBeep", GetType(MessageBeep))
        ' Invoca a chamda
        oMessageBeep.Invoke(BeepType.Asterisk)
    End Sub
 
End Class

Outro exemplo de melhor utilização: podemos herdar a classe NativeDllCalls.vb, assim o código ficara mais estruturado caso utilizemos muitas chamadas diferente em varias classes..

' Nova classe que não pode ser herdada, mas por sua vez herda a classe NativeDllCalls
Public NotInheritable Class NativeBeep : Inherits NativeDllCalls
 
    Friend Enum BeepType
        SimpleBeep = -1
        OK = &H0
        Question = &H20
        Exclamation = &H30
        Asterisk = &H40
    End Enum
 
    Private Delegate Function MessageBeep(ByVal type As UInteger) As Boolean
 
    Friend Function Beep(ByVal type As BeepType) As Boolean
        ' Associa o delegate ao ponto da função da DLL..
        Dim oMessageBeep As MessageBeep = _
                MyBase.DynamicCall("User32", "MessageBeep", GetType(MessageBeep))
        ' Invoca a chamda
        Return oMessageBeep.Invoke(BeepType.Asterisk)
    End Function
 
End Class

Exemplo prático: crie um novo projecto e no Form1 adicione este código..

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim oBeep As New NativeBeep
        oBeep.Beep(NativeBeep.BeepType.Asterisk)
    End Sub
dev_net/vb.net/nativedllcalls.txt · Última modificação em: 2018/05/14 21:37 (edição externa)