I generated a dll (just a messagebox with cgo/golang), using the following command
When loading the dll with LoadLibrary() and running the exported function OnProcessAttach it works (pops the message box), but when trying to achieve DLL reflective loading, by resolving the relocations and resolving the IAT it just don't work.
Seems like performing the base relocations and the IAT sets to null sections on .rdata that are used for initializing the go runtime (which initializes in the entrypoint from NT headers)
This is the piece of code I'm using for resolving the imports:
After doing so I resolve the EAT looking for the OnProcessAttach function, running it directly doesn't work obviously because the go runtime isn't initialized, but trying to initialize it crashes the program because the above stated. It gives a EXCEPTION_ACCESS_VIOLATION because tries to read a chunk of bytes that gets nullified.
While in the original DLL it has
To be honest, i'm trying to figure out if it's worth trying to do this, or if go runtime just doesn't fit for loading it reflectively because others internal details.
Код:
go build --buildmode=c-shared main.go
Код:
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() {}
When loading the dll with LoadLibrary() and running the exported function OnProcessAttach it works (pops the message box), but when trying to achieve DLL reflective loading, by resolving the relocations and resolving the IAT it just don't work.
Seems like performing the base relocations and the IAT sets to null sections on .rdata that are used for initializing the go runtime (which initializes in the entrypoint from NT headers)
This is the piece of code I'm using for resolving the imports:
C:
// 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++;
}
After doing so I resolve the EAT looking for the OnProcessAttach function, running it directly doesn't work obviously because the go runtime isn't initialized, but trying to initialize it crashes the program because the above stated. It gives a EXCEPTION_ACCESS_VIOLATION because tries to read a chunk of bytes that gets nullified.
While in the original DLL it has
To be honest, i'm trying to figure out if it's worth trying to do this, or if go runtime just doesn't fit for loading it reflectively because others internal details.