Heim >Backend-Entwicklung >Golang >Reflektierendes Laden von CGO-generierten DLLs
Ich wollte nur das Laden der reflektierenden DLL ausprobieren, also habe ich ein einfaches Nachrichtenfeld geschrieben:
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() {}
Ich habe mit dem folgenden Befehl eine DLL (nur ein Meldungsfeld mit cgo/golang) generiert go build --buildmode=c-shared main.go
Wenn Sie die DLL mit „loadlibrary()“ laden und die exportierte Funktion „onprocessattach“ ausführen, funktioniert es (das Meldungsfeld wird angezeigt), aber wenn Sie versuchen, das reflektive Laden der DLL durch Auflösen von Verschiebungen und Auflösen von iats zu implementieren, funktioniert es nicht. Es scheint, dass eine grundlegende Verschiebung durchgeführt wird und iat auf einen leeren Abschnitt in .rdata gesetzt wird, der zum Initialisieren der Go-Laufzeit verwendet wird (initialisiert im Einstiegspunkt des NT-Headers). Hier ist der Codeausschnitt, den ich zur Lösung des Importproblems verwendet habe:
// 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++; }
Nachdem ich dies getan habe, habe ich das Problem gelöst, dass eat nach der onprocessattach-Funktion sucht. Das direkte Ausführen funktioniert offensichtlich nicht, da die Go-Laufzeit nicht initialisiert ist. Der Versuch, sie zu initialisieren, führt jedoch wie oben erwähnt zum Absturz des Programms. Es gibt eine Ausnahmebedingung_Zugriffsverletzung, da versucht wird, einen ungültigen Byteblock zu lesen.
Demontage des Einstiegspunkts: mov rax, qdword ptr ds:[adresse] mov dword ptr ds:[rax]
Laut der Adresse im Dump sieht es leer aus 00 00 00 00 00 00 00 00 00 [..]
Obwohl die Original-DLL einen Wert hat 90 2b c5 ea 01 [...]
Ich weiß, dass ich diese Bytes in der .rdata-Datei auf Null setze, aber ich kann nicht herausfinden, warum das passiert, wenn ich eine Verschiebung durchführe. Vielleicht ist die Go-Laufzeitumgebung nicht für das geeignet, was ich tun möchte? Oder etwas anderes?
Lösung Ich habe nur vergessen, die Lösung hier zu posten Der Fehler erscheint in der folgenden Zeile
ReadProcessMemory(GetCurrentProcess(), (LPCVOID)((DWORD_PTR)dllBase, relocationRVA), &addressToPatch, sizeof(DWORD_PTR), NULL);
Es war nur ein Fingerfehler, das Symbol hätte anstelle des Kommas hinzugefügt werden sollen, deshalb wurde die Adresse ungültig.
Das obige ist der detaillierte Inhalt vonReflektierendes Laden von CGO-generierten DLLs. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!