Jump to content
  • Revista PROGRAMAR: Já está disponível a edição #60 da revista programar. Faz já o download aqui!

fLaSh_PT

Chamadas API Dinamicamente [transferido para wiki]

Recommended Posts

fLaSh_PT

Ora viva;

Vou mostrar como fazer chamadas API sem as declarar..

Apenas necessita de três chamadas:

LoadLibrary

SetLastError

GetProcAddress

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!

'========================================
'       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

Simple teste .. crie 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

Compr.


Making the impossible possible and pwing the world on db at a time.

Share this post


Link to post
Share on other sites
ribeiro55

Excelente contribuição, aliás, como sempre ;)

Wikas tu ou wikos eu?


Sérgio Ribeiro


"Great coders aren't born. They're compiled and released"
"Expert coders do not need a keyboard. They just throw magnets at the RAM chips"

Share this post


Link to post
Share on other sites
BrunoMaestro

Parabéns pelo artigo, e gostaria de saber se com esse código consigo acessar dlls de outros compiladores tipo Delphi, C++, etc...

Share this post


Link to post
Share on other sites
fLaSh_PT

Parabéns pelo artigo, e gostaria de saber se com esse código consigo acessar dlls de outros compiladores tipo Delphi, C++, etc...

Sim consegues, utilizar qualquer DLL codificado em qualquer linguagem desde que seja DLL Standard..

delegate_usado = DynamicCall("directoria_da_dll", "nome_da_funcao", GetType(delegate_usado))

PS: se a DLL estiver na Dir do sistema (System32) ou na mesma Dir do executável.. basta o nome da DLL.. caso contrario tens de indicar o caminho completo da DLL..

Compr.


Making the impossible possible and pwing the world on db at a time.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.