A forum for reverse engineering, OS internals and malware analysis 

Forum for discussion about user-mode development.
 #26915  by kerpow1
 Sun Oct 11, 2015 10:50 am
InLoadOrderModuleList
InMemoryOrderModuleList
InInitializationOrderModuleList
LdrpHashTable
Code: Select all
//===========================================================================
typedef struct _PEB_LDR_DATA
{
	ULONG			Length;
	BOOLEAN			Initialized;
	PVOID			SsHandle;
	LIST_ENTRY		InLoadOrderModuleList;
	LIST_ENTRY		InMemoryOrderModuleList;
	LIST_ENTRY		InInitializationOrderModuleList;
} PEB_LDR_DATA, *PPEB_LDR_DATA;
//===========================================================================
typedef struct _LDR_MODULE
{
	LIST_ENTRY		InLoadOrderModuleList;
	LIST_ENTRY		InMemoryOrderModuleList;
	LIST_ENTRY		InInitializationOrderModuleList;
	PVOID			BaseAddress;
	PVOID			EntryPoint;
	ULONG			SizeOfImage;
	UNICODE_STRING	FullDllName;
	UNICODE_STRING	BaseDllName;
	ULONG			Flags;
	SHORT			LoadCount;
	SHORT			TlsIndex;
	LIST_ENTRY		HashTableEntry;
	ULONG			TimeDateStamp;
} LDR_MODULE, *PLDR_MODULE;
//===========================================================================
void UnlinkModule(char *szModule)
{
	DWORD dwPEB = 0, dwOffset = 0;
	PLIST_ENTRY pUserModuleHead, pUserModule;
	PPEB_LDR_DATA pLdrData;
	PLDR_MODULE pLdrModule = NULL;
	PUNICODE_STRING lpModule = NULL;
	char szModuleName[512];
	int i = 0, n = 0;

	_asm
	{
		pushad
		mov eax, fs: [48]
		mov dwPEB, eax
		popad
	}

	pLdrData=(PPEB_LDR_DATA)(PDWORD)(*(PDWORD)(dwPEB + 12));

	for(; i < 3; i++)
	{
		switch(i)
		{
		case 0:
			pUserModuleHead = pUserModule =(PLIST_ENTRY)(&(pLdrData->InLoadOrderModuleList));
			dwOffset = 0;
			break;

		case 1:
			pUserModuleHead = pUserModule =(PLIST_ENTRY)(&(pLdrData->InMemoryOrderModuleList));
			dwOffset = 8;
			break;
		case 2:
			pUserModuleHead = pUserModule =(PLIST_ENTRY)(&(pLdrData->InInitializationOrderModuleList));
			dwOffset = 16;
			break;
		}

		while(pUserModule->Flink != pUserModuleHead)
		{
			pUserModule = pUserModule->Flink;
			lpModule =(PUNICODE_STRING)(((DWORD)(pUserModule)) +(36-dwOffset));
			
			for(n = 0; n <(lpModule->Length)/2 && n < 512; n++)
				szModuleName[n] =(CHAR)(*((lpModule->Buffer)+(n)));
			
			szModuleName[n] = '\0';
			if(strstr(szModuleName, szModule))
			{
				if (!pLdrModule)
					pLdrModule = (PLDR_MODULE)(((DWORD)(pUserModule)) - dwOffset);
				pUserModule->Blink->Flink = pUserModule->Flink;
				pUserModule->Flink->Blink = pUserModule->Blink;
			}
		}
	}
	
	// Unlink from LdrpHashTable
	if (pLdrModule)
	{
		pLdrModule->HashTableEntry.Blink->Flink = pLdrModule->HashTableEntry.Flink;
		pLdrModule->HashTableEntry.Flink->Blink = pLdrModule->HashTableEntry.Blink;
	}
}
Done a million times before but may be useful.
 #26924  by Microwave89
 Sun Oct 11, 2015 3:45 pm
In addition to posting x86 code where x86 systems are continuing decrease why don't you solely push eax if you don't destroy the other registers contents?
Even if the instruction length is the same for "push eax" and "pushad" it will still take a longer time. (Although that isn't too important nowadays and in that type of application.)

Better include <intrin.h> header and use following code:
dwPEB = __readfsdword(0x30);

Best Regards - Microwave89
 #26927  by EP_X0FF
 Mon Oct 12, 2015 3:15 am
Code: Select all
lpModule =(PUNICODE_STRING)(((DWORD)(pUserModule)) +(36-dwOffset));
....
Code: Select all
	RtlEnterCriticalSection( (PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);

	Head = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
	Next = Head->Flink;
	bFound = FALSE;

	while ( Next != Head ) {

		Entry = CONTAINING_RECORD(Next, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);

		if ( Entry->DllBase == DllHandle ) {

			bFound = TRUE;
			RemoveEntryList(&Entry->InLoadOrderLinks);
			RemoveEntryList(&Entry->InInitializationOrderLinks);
			RemoveEntryList(&Entry->HashLinks);

			switch ( dwFlags ) {

			case DLL_RENAME_MEMORYORDERENTRY:

				RandomizeDllName(Entry);
				break;

			default:
				RemoveEntryList(&Entry->InMemoryOrderLinks);
				break;
			}
		
		}
		Next = Next->Flink;
	}

	RtlLeaveCriticalSection( (PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
 #26930  by Brock
 Mon Oct 12, 2015 12:37 pm
As EP_X0FF pointed out, you need to engage the loader lock so the module list doesn't change during enumeration of loaded modules. Also, in case you're unaware Kerpow1, modules hidden through PEB hiding can still be identified/discovered from usermode with PSAPI!GetMappedFileNameA/W or by calling NtQueryVirtualMemory directly with the MemorySectionName information class. So, this PEB unlinking doesn't defeat lower-level methods of virtual memory enumeration and name querying
 #26932  by kerpow1
 Mon Oct 12, 2015 4:58 pm
Yeh I see that HookShark uses ZwQueryVirtualMemory or something similar to have a view of the entire PEB for its analysis tool.

This ofc isn't strong and is limited, I am looking into VAD currently as I see this is the ideal approach.
 #26935  by Brock
 Tue Oct 13, 2015 6:31 am
Yeah, that's where ZwQueryVirtualMemory(MemorySectionName) gets its info from, the VAD tree for the specified process
 #26946  by kerpow1
 Wed Oct 14, 2015 5:53 pm
I am trying approach of removing vad currently, BlackBone method seems like it doesn't work, Darkthon himself posting some issues he was having but never submitted a revision.

Do you know of any other documentation on hiding a dll from VAD that may be useful? Thanks
 #26957  by kerpow1
 Thu Oct 15, 2015 7:13 am
Sorry for bump, so i have got vad working and checking against;

pchunter, powertools, gmer, hookshark (32 and 64) my module that i inject into spawned svchost is hidden, i cannot locate it anywhere.

now when i test with process hacker x64 (driver disabled) and check strings then mapped, private i can clearly see the memory of my dll and the name but searching for handle/dll in process hacker returns no result. question is am i missing something here?

thanks
 #26965  by Brock
 Thu Oct 15, 2015 3:39 pm
VMMAP will probably list the regions too then. Sounds like your code is incorrect but most importantly why "hide" a DLL to begin with? Sounds a bit sketchy tbh since it's mostly used to evade game cheat detection software.
 #26967  by kerpow1
 Thu Oct 15, 2015 4:31 pm
Yes whether it is to do with evasion or protection, same principle. My code is correct but I guess there is a way to still review the modules code/text section which tools like phacker use. Maybe someone is familiar with the methods phacker uses.