DLL-Injection und eigene GetProcAddress implementierung



  • Durch ceplusplus' frage nach dll-injection habe ich selbst lust bekommen soetwas zu probieren. Nur da ich vista benutze, und das nun ein mal ASLR hat, kann ich nicht einfach die Addresse von GetProcAddress an das injizierte program übergeben.

    Daher habe ich folgende lösung gefunden:

    Der zu injizierende code ist in einem extra code segment namens .inject gespeichert.

    struct INJECTSTRUCT
    {
    	HMODULE BaseAddress; // Die Addresse von Kernel32.dll mittels
                             // Module32First/Next im zielprozess gefunden
    	fpLoadLibrary lpfnLoadLibrary;
    	fpGetProcAddress lpfnGetProcAddress;
    	fpDllThreadEntry lpfnDllThreadEntry;
    	LPVOID Parameter;
    	TCHAR Path[MAX_PATH];
    	struct
    	{
    		CHAR szTarget[255];
    		CHAR szLoadLibrary[16];
    		CHAR szGetProcAddress[16];
    	} FunctionNames;
    };
    
    // Wird mittels CreateRemoteThread aufgerufen
    DWORD CALLBACK ThreadStart(LPVOID lpParameter)
    {
    	__asm int 3; // Debug!
    	INJECTSTRUCT* pIs = (INJECTSTRUCT*)lpParameter;
    
    	pIs->lpfnGetProcAddress = (fpGetProcAddress)GetExportAddress(pIs->BaseAddress, pIs->FunctionNames.szGetProcAddress);
    	pIs->lpfnLoadLibrary = (fpLoadLibrary)GetExportAddress(pIs->BaseAddress, pIs->FunctionNames.szLoadLibrary);
    
    	HINSTANCE hDll = pIs->lpfnLoadLibrary(pIs->Path);
    	pIs->lpfnDllThreadEntry = (fpDllThreadEntry)pIs->lpfnGetProcAddress(hDll, pIs->FunctionNames.szTarget);
    	return pIs->lpfnDllThreadEntry(pIs->Parameter);
    }
    

    Und nun die wichtige, aber leider fehlerhafte funktion GetExportAddress

    LPVOID CALLBACK GetExportAddress(HMODULE hModule, LPCSTR lpFuncName)
    {
    	// Get the base values
    	IMAGE_DOS_HEADER* pDh = (IMAGE_DOS_HEADER*)hModule;
    	IMAGE_NT_HEADERS* pNt = (IMAGE_NT_HEADERS*)((BYTE*)pDh + pDh->e_lfanew);
    	DWORD vaExport = pNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
    	DWORD expSize = pNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
    
    	IMAGE_EXPORT_DIRECTORY* pEd = (IMAGE_EXPORT_DIRECTORY*)((BYTE*)pDh + vaExport);
    	DWORD* lpNames = (DWORD*)((BYTE*)pDh + pEd->AddressOfNames);
    	LPVOID lpFuncs = (LPVOID)((BYTE*)pDh + pEd->AddressOfFunctions);
    
    	// Iterate over the exported names
    	for(DWORD i = 0; i < pEd->NumberOfNames; i++)
    	{
    		LPCSTR pName = (LPCSTR)((BYTE*)pDh + lpNames[i]);
    		if(StringEqual(lpFuncName, pName))
    		{
                // Die ordinale sind immer 2-3 vom richtigen entfernt!!!
    			WORD* lpOrdinals = (WORD*)((BYTE*)pDh + pEd->AddressOfNameOrdinals);
    			DWORD rvaEntry = *((DWORD*)lpFuncs + (lpOrdinals[i] - pEd->Base));
    			if(rvaEntry < vaExport || rvaEntry >= vaExport + expSize)
    				return (LPVOID)((BYTE*)pDh + rvaEntry);
    			else // Forwarder
    			{
    				LPCSTR lpFwd = (LPCSTR)((BYTE*)pDh + rvaEntry);
    				CHAR dllName[255] = {0};
    				int j = 0;
    				while(lpFwd[j] != '.')
    					dllName[j] = lpFwd[j++];
    				BOOL isOrdinal = FALSE;
    				if(lpFwd[j + 1] == '#')
    					isOrdinal = TRUE;
    				LPCSTR lpFunc = lpFwd + j + (isOrdinal ? 2 : 1);
    				return GetImportAddress(hModule, dllName, lpFunc, isOrdinal);
    			}
    		}
    	}
    	return NULL;
    }
    

    GetImportAddress habe ich jetzt mal nicht gepostet, weil ich noch keinem geforwardetem eintrag begegnet bin. StringEqual ist meine implementation von strcmp(keine festen adressen benutzen!).

    Nun jetzt möchte ich wissen wo der Fehler bei meiner GetProcAddress implementierung ist.

    Vielen Dank im voRaus!



  • ich hab einfach folgendes gemacht:

    DWORD rvaEntry = *((DWORD*)lpFuncs + (lpOrdinals[i] - pEd->Base + 1));
    

    Dann ist aber section 6.3.4 von der PE spezifikation eindeutig falsch:

    Thus, when the export name pointer table is searched and a matching string is found at position i, the algorithm for finding the symbol’s address is:
    i = Search_ExportNamePointerTable (ExportName);
    ordinal = ExportOrdinalTable [i];
    SymbolRVA = ExportAddressTable [ordinal - OrdinalBase];



  • fggffg schrieb:

    Dann ist aber section 6.3.4 von der PE spezifikation eindeutig falsch

    Ist richtig, daß es falsch ist. 😋

    Auch wenn das Array "AddressOfNameOrdinals" heißt, enthält es keine "Ordinals", also Ordnungszahlen.

    Dieses Array enthält die "echten" Indizes für das "AddressOfFunctions" - Array.


Anmelden zum Antworten