新手对07年某强删工具sys的逆向学习
[前置说明] 纯新手的动手过程,事无巨细,大牛飘过
[使用工具] IDA,WinDbg,wsyscheck
[系统环境] windows xp sp3
打开该程序后,用wsyscheck观察驱动模块,发现它平时并不加载驱动。于是自己写一个hook_NtLoadDriver的sys,发
现只有点击程序界面的“删除文件”后,才会加载驱动,并且删除完成后会删掉该驱动。于是在hook_NtLoadDriver里
加入copyfile,顺利复制到该驱动。附件中包含hook_NtLoadDriver,早期代码,没有考虑hook时多核安全性。
将该sys拖入IDA,到入口点,

观察到以下字样,
INIT:0001268A mov eax, dword_12604
INIT:0001268F test eax, eax
INIT:00012691 mov ecx, 0BB40h
......
INIT:0001269C mov edx, ds:KeTickCount
INIT:000126A2 mov eax, offset dword_12604
此段可google "/gs Cookie" 得到一些解释,推荐阅读:
794K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8X3q4V1N6X3c8T1k6#2)9J5k6h3!0J5k6#2)9J5c8X3u0D9L8$3N6K6i4K6u0r3j5h3c8$3k6r3u0Y4i4K6g2X3M7%4W2K6N6r3g2E0i4K6u0r3j5i4u0@1K9h3y4D9k6i4y4Q4x3V1j5@1x3K6u0Q4x3X3g2S2M7%4m8^5
该驱动主要功能如下:首先是对FSD的hook的处理,
一、RemoveAttachedDevice:
void __stdcall RemoveAttachedDevice(PCWSTR pwStr) // L"\\FileSystem\\Ntfs" & L"\\FileSystem\\Fastfat"
{
UNICODE_STRING DestinationString;
PDRIVER_OBJECT pDrvObj;
RtlInitUnicodeString(&DestinationString, pwStr);
if (ObReferenceObjectByName(&DestinationString,
OBJ_CASE_INSENSITIVE,
0,
0,
*IoDriverObjectType,
KernelMode,
0,
&pDrvObj))
{
return;
}
if (pDrvObj)
{
PDEVICE_OBJECT pDevObj = NULL;
KIRQL Irql;
Irql = KfAcquireSpinLock(&SpinLock);
__asm
{
mov eax, cr0
and eax, not 10000h
mov cr0, eax
cli
}
for ( pDevObj = pDrvObj->DeviceObject; pDevObj; pDevObj = pDevObj->NextDevice )
pDevObj->AttachedDevice = NULL;
ObfDereferenceObject(pDrvObj);
__asm
{
sti
mov eax, cr0
or eax, 10000h
mov cr0, eax
}
KfReleaseSpinLock(&SpinLock, Irql);
}
}
注意IDA5.5附带的Hex-Rays Decompiler plugin,貌似是1.1版,会忽略cli与sti指令。
二、RestoreFSDDispatchRoutine
分别获取当前内存中FSD的DispatchRoutine地址,和根据实际文件中(Fastfat.sys & Ntfs.sys)计算得到的DispatchRoutine,比较之,不同则恢复。
其中,从文件中获取DispatchRoutine的方法是,先根据PE结构查到进入点,然后匹配opcode来查找DispatchRoutine地址,就是所谓的硬编码。
PE结构参考“新手入门文章 by 野男孩.CHM”,还有从网上找的一张PE图,附件提供该图。
弄清PE相关偏移时有用的windbg命令:
1. dt STRUCT (显示某结构)
dt STRUCT -r
dt STRUCT -r1(或-r2 -r3。。。)
2. ??sizeof(STRUCT) (计算某结构大小)
opcode参考“6eeK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6%4N6#2)9J5k6h3I4#2L8$3y4G2L8X3N6Q4x3X3g2U0L8$3#2Q4x3V1k6D9k6h3q4J5L8X3W2F1k6$3!0H3j5$3!0V1k6g2)9J5c8X3W2F1k6r3g2^5i4K6u0W2K9s2c8E0i4@1f1J5i4K6R3H3i4K6W2p5i4@1g2r3i4@1u0o6i4K6S2o6
比如: if ( *((UCHAR *)pBuf + x) == 0xC7 // opcode C7 mov
&& *((UCHAR *)pBuf + x + 2) == v36
&& *((UCHAR *)pBuf + x + 7) == 0xC7
&& (*((UCHAR *)pBuf + x + 1) == 0x46 || *((UCHAR *)pBuf + x + 1) == 0x43)
)
上面参考资料的教程不全,看完后仍然没有解释C7是什么,那这里自己来找。其实在IDA里面双击这个驱动的DriverEntry,切到IDA View窗口,点击设置分发函数的那些mov,然后切到Hex View窗口,可见有的mov是B8,有的mov是89,有的mov是C7,肉眼观测C7的mov指令长度为7字节,后4字节是一个32位地址,也就是说C7是把一个32位立即数弄到XXX里去的mov指令,那个上面的代码里pBuf + x + 7就是下一条指令了,它也是个mov。
HANDLE __stdcall ItsOpenFile(PCWSTR SourceString, ACCESS_MASK DesiredAccess, ULONG ShareAccess) // done!
{
NTSTATUS status;
//
UNICODE_STRING DestinationString;
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE FileHandle;
IO_STATUS_BLOCK IoStatusBlock;
if ( KeGetCurrentIrql() )
return 0;
RtlInitUnicodeString(&DestinationString, SourceString);
ObjectAttributes.RootDirectory = 0;
ObjectAttributes.SecurityDescriptor = 0;
ObjectAttributes.SecurityQualityOfService = 0;
ObjectAttributes.Length = 24;
ObjectAttributes.Attributes = 576;
ObjectAttributes.ObjectName = &DestinationString;
status = IoCreateFile(
&FileHandle,
DesiredAccess,
&ObjectAttributes,
&IoStatusBlock,
0,
0x80u,
ShareAccess,
1u,
0,
0,
0,
0,
0,
0x100u);
if ( status )
{
return 0;
}
return FileHandle;
}
PULONG __stdcall SetFileAttributeNormal(HANDLE handle) // done!
{
NTSTATUS status;
//
PFILE_OBJECT pFileObject;
PDEVICE_OBJECT pDevObj;
IO_STATUS_BLOCK IoStatusBlock = {0};
FILE_BASIC_INFORMATION FileInformation = {0};
KEVENT Event;
PIRP pIrp;
PIO_STACK_LOCATION pIrpSp;
status = ObReferenceObjectByHandle(
handle,
DELETE,
*IoFileObjectType,
0,
(PVOID*)&pFileObject,
0);
if ( status )
{
return 0;
}
pDevObj = IoGetRelatedDeviceObject(pFileObject);
pIrp = IoAllocateIrp(pDevObj->StackSize, TRUE);
if ( pIrp )
{
KeInitializeEvent(&Event, SynchronizationEvent, 0);
pIrp->AssociatedIrp.SystemBuffer = &FileInformation;
pIrp->UserEvent = &Event;
pIrp->UserIosb = &IoStatusBlock;
pIrp->Tail.Overlay.OriginalFileObject = pFileObject;
pIrp->Tail.Overlay.Thread = (PETHREAD)KeGetCurrentThread();
pIrp->RequestorMode = 0;
FileInformation.FileAttributes = FILE_ATTRIBUTE_NORMAL;
pIrpSp = ((char *)pIrp->Tail.Overlay.CurrentStackLocation - 36);
pIrpSp->MajorFunction = IRP_MJ_SET_INFORMATION;
pIrpSp->DeviceObject = pDevObj;
pIrpSp->FileObject = pFileObject;
pIrpSp->Parameters.SetFile.Length = sizeof(FILE_BASIC_INFORMATION);
pIrpSp->Parameters.SetFile.FileInformationClass = FileBasicInformation;
pIrpSp->Parameters.SetFile.FileObject = pFileObject;
pIrpSp->CompletionRoutine = SetFileAttributeCompletion;
pIrpSp->Context = 0;
pIrpSp->Control = 0xE0;
IofCallDriver(pDevObj, pIrp);
KeWaitForSingleObject(&Event, 0, 0, 1u, 0);
}
ObfDereferenceObject(pFileObject);
return IoStatusBlock.Status;
}
PULONG __stdcall SetFileAttributeDelete(HANDLE handle) // done!
{
PFILE_OBJECT pFileObject;
PDEVICE_OBJECT pDevObj;
IO_STATUS_BLOCK IoStatusBlock = {0};
FILE_DISPOSITION_INFORMATION FileInformation;
PIRP pIrp;
KEVENT Event;
PIO_STACK_LOCATION pIrpSp;
if ( ObReferenceObjectByHandle(
handle,
DELETE,
*IoFileObjectType,
0,
(PVOID*)&pFileObject,
0) )
{
return 0;
}
pDevObj = IoGetRelatedDeviceObject(pFileObject);
pIrp = IoAllocateIrp(pDevObj->StackSize, TRUE);
if ( pIrp )
{
KeInitializeEvent(&Event, SynchronizationEvent, 0);
pIrp->AssociatedIrp.SystemBuffer = &FileInformation;
pIrp->UserEvent = &Event;
pIrp->UserIosb = &IoStatusBlock;
pIrp->Tail.Overlay.OriginalFileObject = pFileObject;
pIrp->Tail.Overlay.Thread = (PETHREAD)KeGetCurrentThread();
pIrp->RequestorMode = 0;
FileInformation.DeleteFile = TRUE;
pIrpSp = ((char *)pIrp->Tail.Overlay.CurrentStackLocation - 36);
pIrpSp->MajorFunction = IRP_MJ_SET_INFORMATION;
pIrpSp->DeviceObject = pDevObj;
pIrpSp->FileObject = pFileObject;
pIrpSp->Parameters.SetFile.Length = sizeof(FILE_DISPOSITION_INFORMATION);
pIrpSp->Parameters.SetFile.FileInformationClass = FileDispositionInformation;
pIrpSp->Parameters.SetFile.FileObject = pFileObject;
pIrpSp->CompletionRoutine = SetFileAttributeCompletion;
pIrpSp->Context = 0;
pIrpSp->Control = 0xE0;
IofCallDriver(pDevObj, pIrp);
KeWaitForSingleObject(&Event, 0, 0, 1u, 0);
}
ObfDereferenceObject(pFileObject);
return IoStatusBlock.Status;
}
[培训]科锐逆向工程师培训第53期2025年7月8日开班!