Archive

Posts Tagged ‘ntdll’

LdrpLoadedDllHandleCache

May 6th, 2009

LdrpLoadedDllHandleCache is the name of the cached module handle that NTDLL holds which was covered briefly in my previous post.

Just as a confirmation that it does infact exist and is still present, here is the entire body of LdrpUnloadDll from Vista x86 SP1 Untouched. (Generated by IDA v5.4 and HexRays)

int __stdcall LdrpUnloadDll(int a1, int a2)
{
int v2; // [email protected]
int v4; // [email protected]
int v5; // [email protected]
int v6; // [email protected]
int v7; // [email protected]
int v8; // [email protected]
int v9; // [email protected]
int v10; // [email protected]
int v11; // [email protected]
int v12; // [email protected]
int v13; // [email protected]
int v14; // [email protected]
int v15; // [email protected]
int v16; // [email protected]
int v17; // [email protected]
int v18; // [email protected]
int v19; // [email protected]
int v20; // [email protected]
int v21; // [email protected]
int v22; // [email protected]
int v23; // [email protected]
int v24; // [email protected]
char v25; // [email protected]
int v26; // [email protected]
int v27; // [email protected]
int v28; // [email protected]
char v29; // [email protected]
int (__stdcall *v30)(_DWORD); // [email protected]
int v31; // [email protected]
int v32; // [email protected]
int v33; // [email protected]
int v34; // [email protected]
int v35; // [email protected]
int v36; // [email protected]
int v37; // [email protected]
int v38; // [email protected]
int v39; // [email protected]
int v40; // [email protected]
int v41; // [email protected]
int v42; // [sp+70h] [bp-28h]@1
int v43; // [sp+68h] [bp-30h]@1
int v44; // [sp+6Ch] [bp-2Ch]@1
int v45; // [sp+94h] [bp-4h]@1
int v46; // [sp+7Ch] [bp-1Ch]@2
int v47; // [sp+74h] [bp-24h]@7
int *v48; // [sp+78h] [bp-20h]@7
int *v49; // [sp+5Ch] [bp-3Ch]@10
int *v50; // [sp+58h] [bp-40h]@10
int v51; // [sp+64h] [bp-34h]@10
int v52; // [sp+10h] [bp-88h]@13
int v53; // [sp+14h] [bp-84h]@13
char v54; // [sp+18h] [bp-80h]@13
char v55; // [sp+60h] [bp-38h]@19
int v56; // [sp+34h] [bp-64h]@28
int v57; // [sp+38h] [bp-60h]@28
char v58; // [sp+3Ch] [bp-5Ch]@28

v42 = *(_DWORD *)a2;
v16 = *(_DWORD *)(*MK_FP(__FS__, 24) + 48);
v43 = *(_DWORD *)(*MK_FP(__FS__, 24) + 48);
v2 = 0;
v44 = 0;
v45 = 0;
++LdrpActiveUnloadCount;
if ( !*(_BYTE *)(*(_DWORD *)(v16 + 12) + 40) )
{
if ( (unsigned __int8)LdrpCheckForLoadedDllHandle(a1, &v46) )
{
if ( *(_WORD *)(v46 + 56) != -1 )
{
-*(_WORD *)(v46 + 56);
LdrpUpdateServiceTagCount(v46, 2);
LdrpCheckForwardedEntries(v46);
if ( *(_BYTE *)(v46 + 52) & 4 )
{
v56 = 36;
v57 = 1;
memset(&v58, 0, 0×1Cu);
RtlActivateActivationContextUnsafeFast();
v45 = 1;
LdrpUpdateLoadCount2(v46, 2);
v45 = 0;
sub_77F0982B();
}
if ( LdrpActiveUnloadCount == 1 )
{
dword_77F991A4 = (int)&LdrpUnloadHead;
LdrpUnloadHead = (int)&LdrpUnloadHead;
}
v13 = dword_77F94CE0;
v48 = (int *)dword_77F94CE0;
while ( v13 != (_DWORD)&dword_77F94CDC )
{
v31 = v13 - 16;
v46 = v13 - 16;
v13 = *(_DWORD *)(v13 + 4);
v48 = (int *)v13;
*(_DWORD *)(v31 + 52) &= 0xFFFFDFFFu;
if ( !*(_WORD *)(v46 + 56) )
{
LdrpModuleCacheUnloadNotification(v46);
v14 = v46;
if ( !*(_WORD *)(v46 + 56) )
{
v47 = v46;
if ( g_ShimsEnabled )
{
v30 = (int (__stdcall *)(_DWORD))RtlDecodeSystemPointer(g_pfnSE_DllUnloaded);
v30(v14);
}
v32 = *(_DWORD *)(v14 + 16);
v33 = *(_DWORD *)(v14 + 20);
*(_DWORD *)v33 = v32;
*(_DWORD *)(v32 + 4) = v33;
v34 = *(_DWORD *)(v14 + 8);
v35 = *(_DWORD *)(v14 + 12);
*(_DWORD *)v35 = v34;
*(_DWORD *)(v34 + 4) = v35;
v15 = v14 + 60;
v36 = *(_DWORD *)(v14 + 60);
v37 = *(_DWORD *)(v14 + 64);
*(_DWORD *)v37 = v36;
*(_DWORD *)(v36 + 4) = v37;
if ( (unsigned __int8)LdrpActiveUnloadCount > 1u )
{
LdrpLoadedDllHandleCache = 0;
*(_DWORD *)(v14 + = 0;
}
v38 = dword_77F991A4;
*(_DWORD *)v15 = &LdrpUnloadHead;
*(_DWORD *)(v14 + 64) = v38;
*(_DWORD *)v38 = v15;
dword_77F991A4 = v14 + 60;
}
}
}
if ( (unsigned __int8)LdrpActiveUnloadCount <= 1u )
{
v49 = (int *)&v50;
v50 = (int *)&v50;
v5 = 0;
v47 = 0;
v4 = LdrpUnloadHead;
v48 = (int *)LdrpUnloadHead;
while ( v4 != (_DWORD)&LdrpUnloadHead )
{
if ( v5 == v2 )
{
v6 = (int)v48;
}
else
{
RtlRemoveInvertedFunctionTable(&LdrpInvertedFunctionTable, *(_DWORD *)(v5 + 24));
v39 = *(_DWORD *)v5;
v40 = *(_DWORD *)(v5 + 4);
*(_DWORD *)v40 = v39;
*(_DWORD *)(v39 + 4) = v40;
v47 = v2;
v6 = LdrpUnloadHead;
v48 = (int *)LdrpUnloadHead;
if ( LdrpUnloadHead == (_DWORD)&LdrpUnloadHead )
break;
}
v19 = v6 - 60;
v46 = v19;
LdrpRecordUnloadEvent(v19);
v8 = v46;
v47 = v46;
LdrpLoadedDllHandleCache = v2;
*(_DWORD *)(v46 + = v2;
v20 = v46 + 60;
v21 = *(_DWORD *)(v46 + 60);
v22 = *(_DWORD *)(v46 + 64);
*(_DWORD *)v22 = v21;
*(_DWORD *)(v21 + 4) = v22;
v23 = (int)v49;
*(_DWORD *)v20 = &v50;
*(_DWORD *)(v20 + 4) = v23;
*(_DWORD *)v23 = v20;
v49 = (int *)v20;
v7 = *(_DWORD *)(v46 + 28);
v51 = *(_DWORD *)(v46 + 28);
if ( !v7 || (v24 = *(_DWORD *)(v46 + 52), v24 &= 0×80000u, v25 = v24 == 0, v25) )
{
RtlRemoveInvertedFunctionTable(&LdrpInvertedFunctionTable, *(_DWORD *)(v8 + 24));
v17 = *(_DWORD *)v8;
v18 = *(_DWORD *)(v8 + 4);
*(_DWORD *)v18 = v17;
*(_DWORD *)(v17 + 4) = v18;
v5 = 0;
v47 = 0;
v4 = LdrpUnloadHead;
v48 = (int *)LdrpUnloadHead;
}
else
{
v45 = 2;
JUMPOUT((dword_77F143C8 | 1) & ShowSnaps, *(unsigned int *)sub_77F41A51);
if ( ShowSnaps & dword_77F143CC )
DbgBreakPoint();
v52 = 36;
v53 = 1;
memset(&v54, 0, 0×1Cu);
RtlActivateActivationContextUnsafeFast();
v45 = 3;
v9 = v46;
if ( *(_WORD *)(v46 + 58) )
{
LdrpCallTlsInitializers(0, v46);
v9 = v46;
}
LdrpCallInitRoutine(v7, *(_DWORD *)(v9 + 24), 0, 0);
v45 = 2;
sub_77F0904D();
RtlRemoveInvertedFunctionTable(&LdrpInvertedFunctionTable, *(_DWORD *)(v8 + 24));
v26 = *(_DWORD *)v8;
v27 = *(_DWORD *)(v8 + 4);
*(_DWORD *)v27 = v26;
*(_DWORD *)(v26 + 4) = v27;
v5 = 0;
v47 = 0;
v4 = LdrpUnloadHead;
v48 = (int *)LdrpUnloadHead;
v45 = 0;
}
v2 = 0;
}
v11 = (int)v50;
v48 = v50;
while ( v11 != (_DWORD)&v50 )
{
v10 = v11 - 60;
v46 = v11 - 60;
v11 = *(_DWORD *)v11;
v48 = (int *)v11;
v12 = v10;
v47 = v10;
if ( *(_WORD *)(v43 + 104) & 0×100 )
{
AVrfDllUnloadNotification(v10);
LOBYTE(v10) = v46;
}
if ( (dword_77F143C8 | 1) & ShowSnaps )
LdrpLogDbgPrint(
“d:\\rtm\\base\\ntdll\\ldrapi.c”,
1468,
“LdrpUnloadDll”,
2,
“Unmapping DLL \”%wZ\”\n”,
v10 + 36);
if ( ShowSnaps & dword_77F143CC )
DbgBreakPoint();
LdrUnloadAlternateResourceModule(*(_DWORD *)(v12 + 24));
if ( RtlImageDirectoryEntryToData(*(_DWORD *)(v12 + 24), 1, 14, &v55) != v2 )
LdrpCorUnloadImage(*(_DWORD *)(v12 + 24));
v28 = *(_DWORD *)(v12 + 52);
v28 &= 0×800000u;
v29 = v28 == 0;
if ( v29 )
v44 = NtUnmapViewOfSection(-1, *(_DWORD *)(v12 + 24));
LdrpSendDllNotifications(v12, 2, *(_BYTE *)(*(_DWORD *)(v43 + 12) + 40) != 0);
while ( *(_DWORD *)(v12 + 76) != v2 )
{
v41 = *(_DWORD *)(v12 + 76);
*(_DWORD *)(v12 + 76) = *(_DWORD *)(v41 + 12);
*(_DWORD *)(v41 + 12) = v42;
v42 = v41;
}
LdrpCheckForwardedEntries(v12);
LdrpFinalizeAndDeallocateDataTableEntry(v12);
if ( v12 == LdrpGetModuleHandleCache )
LdrpGetModuleHandleCache = v2;
}
LdrpModuleReferenceFreeCallback();
}
}
}
else
{
v44 = -1073741515;
}
}
v45 = -2;
sub_77F0E99C();
*(_DWORD *)a2 = v42;
return v44;
}

You can see referenced there LdrpLoadedDllHandleCache. Just wanted to point that out for anyone who had their doubts about its existence.

Erasing the Cached Module Pointer in NTDLL

May 5th, 2009

Darawk first documented this insecurity in his CloakDLL project but never fixed it, Shynd then fixed it in his HideModule class.

Here it is again, but upgraded for x64 and to work with my Cloaker class:

// TODO: Scan more than just the image. Scan the heap.
void Cloaker::Module::EraseCachedPointer()
{
// Exception handling
try
{
// SEH proxy
SehGuard Guard;

// Get handle to NTDLL
HMODULE Handle = GetModuleHandle(_T(”ntdll.dll”));

// Check handle is valid
if (!Handle)
throw std::runtime_error(”Cloaker::Module::EraseCachedPointer: Handle to ntdll.dll is invalid.”);

// Check DOS header is valid
PIMAGE_DOS_HEADER pDosHeader = reinterpret_cast<PIMAGE_DOS_HEADER>(Handle);
if (!pDosHeader || pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
throw std::runtime_error(”Cloaker::Module::EraseCachedPointer: DOS PE header is invalid.”);

// Check NT header is valid
PIMAGE_NT_HEADERS pNtHeader = reinterpret_cast<PIMAGE_NT_HEADERS>
((PCHAR)Handle + pDosHeader->e_lfanew);
if (pNtHeader->Signature != IMAGE_NT_SIGNATURE)
throw std::runtime_error(”Cloaker::Module::EraseCachedPointer: NT PE header is invalid.”);

// Get beginning and end of search region (entire region)
// TODO: Scan heap too
DWORD_PTR* Begin = reinterpret_cast<DWORD_PTR*>(pNtHeader->OptionalHeader.ImageBase);
DWORD_PTR* End = reinterpret_cast<DWORD_PTR*>(pNtHeader->OptionalHeader.ImageBase + pNtHeader->OptionalHeader.SizeOfImage);

// Search for cached pointers
DWORD_PTR* Searcher = NULL;
for (Searcher = Begin; Searcher < End; Searcher++)
{
// Check for cached pointer
if (*Searcher != reinterpret_cast<DWORD_PTR>(m_Handle))
continue;

// Get information for page of memory
MEMORY_BASIC_INFORMATION mbi = { 0 };
if (!VirtualQuery(Searcher, &mbi, sizeof(mbi)))
continue;

// Check page flags to verify we can write to it
if ((mbi.Protect & PAGE_READWRITE) == PAGE_READWRITE ||
(mbi.Protect & PAGE_EXECUTE_READWRITE) == PAGE_EXECUTE_READWRITE)
*Searcher = 0;
}
}
// Catch access violations
catch (const SehException& e)
{
e;
TDBGOUT(_T(”SEH Error in Cloaker::EraseCachedPointer: “) << e << std::endl);
}
}

Credits to Darawk for documenting it, and Shynd for his HideModule class which I ripped the base of this function from.