Appel de pointeur de fonctions - api sans les declarer

Soyez le premier à donner votre avis sur cette source.

Vue 4 932 fois - Téléchargée 570 fois

Description

Bonjour,

Oui, ca existe déjà sur le site

EBArtSoft nous avait pondu :
http://www.vbfrance.com/codes/APPELER-FONCTION-DEPUIS-SON-ADRESSE_39481.aspx

Mais bon, j'aime bien implémenter les choses moi même, donc ^^
J'ai juste repiqué ses exemples.

Implémenter soi même, ok, mais quelles sont les différences proposées ?

j'utilises un ParamArray pour transmettre les paramètres aux APIs
Plus simple à utiliser, donc, puisqu'on n'a pas a créer le prototype, mais il faut du coup faire deux fois plus attention au nombre d'arguments passés et à leur taille.

Source / Exemple :


'# BruNews, s'il te vient l'idée de lire ce code ASM,
'# rappelle toi que je suis pas spécialiste, hein ^^
Private Sub Class_Initialize()
Dim pFirstVTEntry As Long
Dim pCode As Long
Dim i As Long
    GetMem4 ObjPtr(Me), pFirstVTEntry
    mpCode = VirtualAlloc(ByVal 0&, 512, MEM_COMMIT, PAGE_EXECUTE_READWRITE)
    
    '# Invoke et InvokeArr
    pCode = mpCode
    For i = 0 To 1
        PutMem4 pFirstVTEntry + &H1C& + i * 4, pCode
        PutMem4 pCode, &H56EC8B55: pCode = pCode + 4  'push ebp
                                                      'mov ebp, esp
                                                      'push esi
        PutMem4 pCode, &H9010758B: pCode = pCode + 4  'mov esi, [ebp+10h]
        If i Then '# InvokeArr
            PutMem4 pCode, &H9008768D: pCode = pCode + 4  'lea esi, [esi+8h] => Permet de sauter l'entete du Variant (type+2 reserved words)
        End If
        PutMem4 pCode, &H488B068B: pCode = pCode + 4  'mov eax, [esi]
                                                      'mov ecx, [eax+10h]
        PutMem4 pCode, &H14483B10: pCode = pCode + 4  'cmp ecx, [eax+14h]

        PutMem4 pCode, &H9090267E: pCode = pCode + 4  'jle LBL_CALL  (36+2)
        PutMem4 pCode, &HEA83D18B: pCode = pCode + 4  'mov edx, ecx
        PutMem4 pCode, &H4E2C101: pCode = pCode + 4   'sub edx, 1
                                                      'shl edx, 4
        'LBL_NEXT_ARG
        PutMem4 pCode, &H30C408B: pCode = pCode + 4   'mov eax, [eax+0Ch]
        PutMem4 pCode, &H8C083C2: pCode = pCode + 4   'add eax, edx
        PutMem4 pCode, &H68B30FF: pCode = pCode + 4   'push [eax]
        PutMem4 pCode, &H9001E983: pCode = pCode + 4  'mov eax, [esi]
                                                      'sub ecx, 1
        PutMem4 pCode, &H3B10EA83: pCode = pCode + 4  'sub edx, 10h
        PutMem4 pCode, &H90901448: pCode = pCode + 4  'cmp ecx, [eax+14h]
        PutMem4 pCode, &H9090E67F: pCode = pCode + 4  'jg LBL_NEXT_ARG (-24-2)
        'LBL_CALL
        PutMem4 pCode, &H8B0C55FF: pCode = pCode + 4  'call [ebp+0Ch]
        PutMem4 pCode, &H2891455: pCode = pCode + 4   'mov edx, [ebp+14h]
                                                      'mov [edx], eax
        PutMem4 pCode, &H5D5EC033: pCode = pCode + 4  'xor eax, eax
                                                      'pop esi
                                                      'pop ebp
        PutMem1 pCode, &HC3: pCode = pCode + 4        'ret
    Next
    
    '# Invoke 0-4
    For i = 0 To 4
        PutMem4 pFirstVTEntry + &H24& + 4 * i, pCode

        PutMem4 pCode, &H90EC8B55: pCode = pCode + 4          'push ebp
                                                              'mov ebp, esp
        If i = 4 Then
            PutMem4 pCode, &H901C458B: pCode = pCode + 4      'mov eax, [ebp+1Ch]
            PutMem4 pCode, &H9018558B: pCode = pCode + 4      'mov edx, [ebp+18h]
            PutMem4 pCode, &H90144D8B: pCode = pCode + 4      'mov ecx, [ebp+14h]
            PutMem4 pCode, &H90515250: pCode = pCode + 4      'push eax
                                                              'push edx
                                                              'push ecx
            PutMem4 pCode, &H5010458B: pCode = pCode + 4      'mov eax, [ebp+10h]
        ElseIf i Then
            If i >= 3 Then
                PutMem4 pCode, &H9018558B: pCode = pCode + 4  'mov edx, [ebp+18h]
            End If
            If i >= 2 Then
                PutMem4 pCode, &H90144D8B: pCode = pCode + 4  'mov ecx, [ebp+14h]
            End If
            PutMem4 pCode, &H9010458B: pCode = pCode + 4      'mov eax, [ebp+10h]
            If i >= 3 Then
                PutMem1 pCode, &H52: pCode = pCode + 1        'push edx
            End If
            If i >= 2 Then
                PutMem1 pCode, &H51: pCode = pCode + 1        'push ecx
            End If
            PutMem1 pCode, &H50: pCode = pCode + 1            'push eax
            Do While (pCode Mod 4)
                PutMem1 pCode, &H90: pCode = pCode + 1
            Loop
        End If
        
        PutMem4 pCode, &H900C4D8B: pCode = pCode + 4  'mov ecx, [ebp+0C]
        PutMem4 pCode, &HD1FF9090: pCode = pCode + 4  'call ecx
        
        PutMem4 pCode, &H9000558B + &H10000 * (&H10 + i * 4): pCode = pCode + 4 'mov edx, [ebp+XX]
        
        PutMem4 pCode, &H2899090:  pCode = pCode + 4  'mov [edx], eax
        PutMem4 pCode, &HC35DC033: pCode = pCode + 4  'xor eax, eax
                                                      'pop ebp
                                                      'ret
    Next
End Sub

Conclusion :


Bon, ben amusez-vous ^^

J'ai pris du plaisir a coder cela, comme quoi, un debugger (IDA), c'est pas fait que pour cracker, mais bien pour débugger :p

Codes Sources

A voir également

Ajouter un commentaire

Commentaires

Messages postés
406
Date d'inscription
lundi 9 juin 2003
Statut
Membre
Dernière intervention
4 septembre 2013
1
Bonjour Renfield,

J'ai besoin de changer le nom de la DLL dynamiquement
Apparement pas possible a faire avec VB6, du fait que DECLARE ne le permet pas :-(

Donc ce code pourrait etre une alternative a mon probleme
Peut on appeller une DLL standard perso, lui envoyer une structure et recevoir un pointeur de structure en retour ??
Messages postés
51
Date d'inscription
samedi 21 octobre 2000
Statut
Membre
Dernière intervention
10 octobre 2011

Bravo, j'en étais resté au code d'Ebart.
Un idée de perfectionnement, plutôt qu'Invoke0-4
il serait intéressant d'avoir des fonctions retournant des types autre que long
(Currency , String etc.) 8)
Messages postés
17286
Date d'inscription
mercredi 2 janvier 2002
Statut
Modérateur
Dernière intervention
23 décembre 2019
66
En fait, on va se servir d'un objet ActiveX pour faire exécuter du code assembleur.
Pour cela, on réserve une plage mémoire de 512 octets qui a l'autorisation de stocker et exécuter du code ; pour éviter que le DEP ne se manifeste.

Quand on considère un objet ActiveX, le pointeur renvoyant vers celui-ci (ObjPtr) est en fait l'adresse vers la VTable de cet objet.
La VTable est un simple tableau de Long. Il s'agit de l'adresse des différentes méthodes de l'objet, dans l'ordre de déclaration de celles-ci ; en prenant en compte IUnknown et IDispatch (qui cumulent 7 méthodes à elles deux).
7 * 4 => 0x1C

La première méthode de notre classe est Invoke.
L'adresse de cette fonction se trouve donc a l'offset 0x1C de la VTable.

Ici:
GetMem4 ObjPtr(Me), pFirstVTEntry

On récupère le début de la VTable.

Et ici:
PutMem4 pFirstVTEntry + &H1C& + i * 4, pCode

On remplace l'adresse correspondante a Invoke puis InvokeArr dans la VTable par l'adresse mémoire voulue ; où on stocke les opCode assembleurs de notre choix.

De façon identique, pour Invoke0-4 :
PutMem4 pFirstVTEntry + &H24& + 4 * i, pCode

Désormais, la VTable de notre objet est hackée. Lorsque nous appellerons nos méthodes, c'est le code assembleur qui sera exécuté.

VB utilise StdCall comme convention d'appel. Dans le cadre de la technologie COM, nous avons droit à quelques subtilités supplémentaires.

Lors de l'appel, on trouve sur la pile :
- L'adresse de l'instruction à exécuter à la sortie de la procédure +0x4
- Le pointeur vers l'objet en cours (Me), automatiquement ajouté par VB +0x8
- Le premier paramètre +0xC
- Le second paramètre
- ...
- Un pointeur vers la variable qui recevra la valeur de retour s'il y a lieu.

Normalement, avec StdCall, le code retour des procédures est transmis via eax. Ici, eax sert à renvoyer le HRESULT. S_OK (0) si tout c'est bien passé, par exemple.

Decryptons un peu l'assembleur. Si on prend le cas de Invoke0 :

push ebp => Sauvegarde de ebp
mov ebp, esp => ebp permettra de 'figer' le pointeur de pile esp
mov ecx, [ebp+0Ch] => ecx contient le 1er param: l'adresse du code à lancer
call ecx => exécution du code assembleur indiqué par l’user
mov edx, [ebp+10h] => edx pointe l’adresse de la valeur de retour
mov [edx], eax => stocke la valeur retournée par la function dans [edx]
xor eax, eax => mise à 0 de eax : HRESULT = S_OK
pop ebp => restauration de ebp
ret => on quitte la procédure

Finalement assez simple, compte tenu de la pile que nous avons pour Invoke0

Si on corse un peu la chose, pour Invoke1 :

push ebp => Sauvegarde de ebp
mov ebp, esp => ebp permettra de 'figer' le pointeur de pile esp
mov eax, [ebp+10h] => eax est 2nd param de Invoke1 : 1er param du code perso
push eax => on place ce parametre sur la pile
mov ecx, [ebp+0Ch] => ecx contient le 1er param: l'adresse du code à lancer
call ecx => exécution du code assembleur indiqué par l’user
mov edx, [ebp+14h] => edx pointe l’adresse de la valeur de retour
mov [edx], eax => stocke la valeur retournée par la function dans [edx]
xor eax, eax => mise à 0 de eax : HRESULT = S_OK
pop ebp => restauration de ebp
ret => on quitte la procédure

Assez peu de changement au final.

Pour Invoke2-4, on reprend les même et on recommence. Gaffe au fait que l’on empile les paramètres du dernier au premier.

Invoke et InvokeArr sont assez similaire (une seule instruction les différencie). Au début de l’appel, leur pile ressemble à cela :
- L'adresse de l'instruction à exécuter à la sortie de la procédure +0x4
- Le pointeur vers l'objet en cours (Me), automatiquement ajouté par VB +0x8

- L’adresse du SafeArray qui stocke nos paramètres dans le cas de Invoke
- L’adresse d’un VARIANT contenant un SafeArray qui stocke nos paramètres dans le cas de InvokeArr

- Un pointeur vers la variable qui recevra la valeur de retour s'il y a lieu.

Assez proches, donc.

push ebp => Sauvegarde de ebp
mov ebp, esp => ebp permettra de 'figer' le pointeur de pile esp
push esi => Sauvegarde esi

mov esi, [ebp+10h] => 1er paramètre du code a lancer
mov eax, [esi] => eax pointe vers mon SafeArray (tableau VB6)
mov ecx, [eax+10h] => ecx est le nombre d’éléments (voir type SAFEARRAY)
cmp ecx, [eax+14h] => comparaison ecx avec l’indice min du tableau
jle LBL_CALL (+38) => pas de paramètre, on saute les 38 octets suivants

mov edx, ecx => edx va etre un offset mémoire pour les paramètres
sub edx, 1 => -1 car on pars de 0
shl edx, 4 => on viens de faire: edx = (ecx-1) * 16

LBL_NEXT_ARG :
mov eax, [eax+0Ch] => eax va pointer vers les données du SafeArray
add eax, edx => on ajoute notre offset, eax pointe le dernier param
push [eax] => on place la valeur sur la pile, pour l’appel

mov eax, [esi] => on replace eax en tête du SafeArray
sub ecx, 1 => on vient de traiter ce paramètre
sub edx, 10h => on décale l’offset pour pointer sur le param précédent
cmp ecx, [eax+14h] => comparaison ecx avec l’indice min du tableau
jg LBL_NEXT_ARG => on boucle tant qu’il reste des paramètres a traiter

LBL_CALL:
call [ebp+0Ch] => on appelle le code perso
mov edx, [ebp+14h] => edx pointe l’adresse de la valeur de retour
mov [edx], eax => stocke la valeur retournée par la function dans [edx]
xor eax, eax => mise à 0 de eax : HRESULT = S_OK
pop ebp => restauration de ebp
ret => on quitte la procédure

pop esi => restauration de esi
pop ebp => restauration de ebp
ret => on quitte la procédure

La seule différence pour InvokeArr se situe dans la récupération de l’adresse du SafeArray (esi).
Pour Invoke, le second parametre est directement notre SafeArray :
mov esi, [ebp+10h]

Pour InvokeArr, nous avons là l’adresse d’un VARIANT de type Tableau de Variant (0x200C). Un variant se décompose ainsi :
- Type (4 octets)
- Donnée réservée 1 (2 octets)
- Donnée réservée 2 (2 octets)
- Donnée du Variant (notre SafeArray)

Du coup, une fois que nous avons en esi l’adresse du variant, un simple :
lea esi, [esi+8h]
Permet de placer en esi l’adresse pointée par esi+8h... notre SafeArray.

Ainsi, la suite du code exploite bien via esi notre SafeArray

Voilà, j’espère que cela vous aidera à bien comprendre ce code, les conventions d’appel et l’assembleur dans une moindre mesure.
Messages postés
9
Date d'inscription
jeudi 18 octobre 2007
Statut
Membre
Dernière intervention
2 juillet 2010

Bon, ben Renfield, c'est vrai qu'au départ je trouvais que le code manquait de commentaires.
C'est vrai que depuis, y'a pas eu trop de rajout de commentaires.
N'empêche je mets quand même 10 parce que tu t'impliques dans les posts de tes lecteurs à un point qu'aucun commentaire ne saura jamais atteindre !

Merci beaucoup pour tout !
(on se recoisera sans doute... je poursuite ma quête: conquérir l'assembleur ! :-) )
Messages postés
17286
Date d'inscription
mercredi 2 janvier 2002
Statut
Modérateur
Dernière intervention
23 décembre 2019
66
[mis a jour]
le Variant de InvokeArr est maintenant en tant que ByRef. J'ai corrigé le code assembleur de InvokeArr, ca va mieux, pas de crash et code retour bien récupéré...
Afficher les 33 commentaires

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.