Maison  >  Article  >  développement back-end  >  Chargement réfléchissant des DLL générées par CGO

Chargement réfléchissant des DLL générées par CGO

王林
王林avant
2024-02-08 21:00:13450parcourir

反射加载 CGO 生成的 DLL

Contenu de la question

Je voulais juste essayer le chargement de DLL par réflexion, j'ai donc écrit une simple boîte de message :

package main
import "c"
import (
    "unsafe"
    "syscall"
)

//export onprocessattach
func onprocessattach() {
    const (
        null  = 0
        mb_ok = 0
    )
    caption := "hola"
    title := "desdegoo"
    ret, _, _ := syscall.newlazydll("user32.dll").newproc("messageboxw").call(
        uintptr(null),
        uintptr(unsafe.pointer(syscall.stringtoutf16ptr(caption))),
        uintptr(unsafe.pointer(syscall.stringtoutf16ptr(title))),
        uintptr(mb_ok))

    if ret != 1 {
        return
    }
    return
}

func main() {}

J'ai généré une DLL (juste une boîte de message avec cgo/golang) en utilisant la commande suivante allez build --buildmode=c-shared main.go

Lors du chargement de la DLL à l'aide de loadlibrary() et de l'exécution de la fonction exportée onprocessattach, cela fonctionne (une boîte de message apparaît), mais lorsque vous essayez d'implémenter le chargement réfléchissant de la DLL, en résolvant les relocalisations et en résolvant iats, cela ne fonctionne pas. Il semble qu'une relocalisation de base soit effectuée et iat est défini sur une section vide sur .rdata qui est utilisée pour initialiser le runtime go (initialisé dans le point d'entrée de l'en-tête nt) Voici l'extrait de code que j'ai utilisé pour résoudre le problème d'importation :

// resolve base relocations
    IMAGE_DATA_DIRECTORY relocations = ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
    DWORD_PTR relocationTable = relocations.VirtualAddress + (DWORD_PTR)dllBase;
    DWORD relocationsProcessed = 0;


    while (relocationsProcessed < relocations.Size)
    {
        PBASE_RELOCATION_BLOCK relocationBlock = (PBASE_RELOCATION_BLOCK)(relocationTable + relocationsProcessed);
        relocationsProcessed += sizeof(BASE_RELOCATION_BLOCK);
        DWORD relocationsCount = (relocationBlock->BlockSize - sizeof(BASE_RELOCATION_BLOCK)) / sizeof(BASE_RELOCATION_ENTRY);
        PBASE_RELOCATION_ENTRY relocationEntries = (PBASE_RELOCATION_ENTRY)(relocationTable + relocationsProcessed);
        for (DWORD i = 0; i < relocationsCount; i++)
        {
            relocationsProcessed += sizeof(BASE_RELOCATION_ENTRY);
            if (relocationEntries[i].Type == 0)
            {
                continue;
            }


            DWORD_PTR relocationRVA = relocationBlock->PageAddress + relocationEntries[i].Offset;
            DWORD_PTR addressToPatch = 0;
            ReadProcessMemory(GetCurrentProcess(), (LPCVOID)((DWORD_PTR)dllBase, relocationRVA), &addressToPatch, sizeof(DWORD_PTR), NULL);
            addressToPatch += deltaImageBase;
            memcpy((PVOID)((DWORD_PTR)dllBase + relocationRVA), &addressToPatch, sizeof(DWORD_PTR));
        }
    }
    
    // resolve IAT
    PIMAGE_IMPORT_DESCRIPTOR importDescriptor = NULL;
    IMAGE_DATA_DIRECTORY importsDirectory = ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
    importDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)(importsDirectory.VirtualAddress + (DWORD_PTR)dllBase);
    LPCSTR libraryName = "";
    HMODULE library = NULL;


    while (importDescriptor->Name != NULL)
    {
        libraryName = (LPCSTR)importDescriptor->Name + (DWORD_PTR)dllBase;
        library = LoadLibraryA(libraryName);
        if (library)
        {
            PIMAGE_THUNK_DATA thunk = NULL;
            thunk = (PIMAGE_THUNK_DATA)((DWORD_PTR)dllBase + importDescriptor->FirstThunk);
            while (thunk->u1.AddressOfData != NULL)
            {
                if (IMAGE_SNAP_BY_ORDINAL(thunk->u1.Ordinal))
                {
                    LPCSTR functionOrdinal = (LPCSTR)IMAGE_ORDINAL(thunk->u1.Ordinal);
                    thunk->u1.Function = (DWORD_PTR)GetProcAddress(library, functionOrdinal);
                }
                else {
                    PIMAGE_IMPORT_BY_NAME functionName = (PIMAGE_IMPORT_BY_NAME)((DWORD_PTR)dllBase + thunk->u1.AddressOfData);
                    DWORD_PTR functionAddress = (DWORD_PTR)GetProcAddress(library, functionName->Name);
                    thunk->u1.Function = functionAddress;
                }
                ++thunk;
            }
        }
        importDescriptor++;
    }

Après avoir fait cela, j'ai résolu le problème de manger en recherchant la fonction onprocessattach, l'exécuter directement ne fonctionne évidemment pas car le runtime go n'est pas initialisé, mais essayer de l'initialiser provoque le crash du programme, comme mentionné ci-dessus. Il donne exception_access_violation car un bloc d'octets non valide est tenté d'être lu.

Démontage du point d'entrée : mov rax, qdword ptr ds :[adresse] mov dword ptr ds :[rax]

Selon l'adresse dans la décharge, elle semble vide 00 00 00 00 00 00 00 00 00 [..]

Bien que la DLL d'origine ait de la valeur 90 2b c5 ch 01 [...]

Je sais que je définis ces octets sur le .rdata sur null, mais je n'arrive pas à comprendre pourquoi cela se produit lors d'une relocalisation, peut-être que le runtime go n'est pas adapté à ce que j'essaie de faire ? Ou autre chose?


Réponse correcte


Solution J'ai juste oublié de poster la solution ici L'erreur apparaît sur la ligne suivante

ReadProcessMemory(GetCurrentProcess(), (LPCVOID)((DWORD_PTR)dllBase, relocationRVA), &addressToPatch, sizeof(DWORD_PTR), NULL);

C'était juste une erreur de doigt, le symbole aurait dû être ajouté à la place de la virgule, c'est pour cela que cela invalidait l'adresse.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer