//   GetHDSerial.cpp:   implementation   of   the   CGetHDSerial   class.
//
//////////////////////////////////////////////////////////////////////
#include   "stdafx.h"
#include   "GetHDSerial.h"


char     m_buffer[256];
WORD     m_serial[256];


DWORD   m_OldInterruptAddress;
DWORDLONG   m_IDTR;

//   等待硬盘空闲
static   unsigned   int   WaitHardDiskIdle()  
{  
BYTE   byTemp;

Waiting:
_asm
{
mov   dx,   0x1f7
in   al,   dx
cmp   al,   0x80
jb   Endwaiting
jmp   Waiting
}
Endwaiting:
_asm
{
mov   byTemp,   al
}
return   byTemp;  
}  

//中断服务程序
void     _declspec(   naked   )InterruptProcess(void)
{
  int       byTemp;
          int       i;
  WORD   temp;
  //保存寄存器值
          _asm
          {
                  push   eax
                  push   ebx
                  push   ecx
                  push   edx
                  push   esi
          }
           
          WaitHardDiskIdle();//等待硬盘空闲状态
          _asm
  {
          mov   dx,   0x1f6
  mov   al,   0xa0
  out   dx,   al
  }
  byTemp   =   WaitHardDiskIdle();   //若直接在Ring3级执行等待命令,会进入死循环
  if   ((byTemp&0x50)!=0x50)  
  {
_asm     //   恢复中断现场并退出中断服务程序
{
                        pop   esi
                        pop   edx
pop   ecx
pop   ebx
pop   eax
iretd
}
  }

  _asm
  {
  mov   dx,   0x1f6   //命令端口1f6,选择驱动器0
  mov   al,   0xa0
    out   dx,   al
  inc   dx
  mov   al,   0xec
  out   dx,   al   //发送读驱动器参数命令
  }
  byTemp   =   WaitHardDiskIdle();  
  if   ((byTemp&0x58)!=0x58)  
          {
_asm     //   恢复中断现场并退出中断服务程序
{
  pop   esi
  pop   edx
  pop   ecx
  pop   ebx
  pop   eax
  iretd
}
  }
          //读取硬盘控制器的全部信息
  for   (i=0;i<256;i++)  
  {
  _asm
  {
  mov   dx,   0x1f0
  in   ax,   dx
    mov   temp,   ax
  }
  m_serial[i]   =   temp;  
  }                                                                
    _asm
  {
                  pop   esi
          pop   edx
                  pop   ecx
                  pop   ebx
                  pop   eax
  iretd
          }
}
//////////////////////////////////////////////////////////////////////
//   Construction/Destruction
//////////////////////////////////////////////////////////////////////

CGetHDSerial::CGetHDSerial()
{

}

CGetHDSerial::~CGetHDSerial()
{

}
//   读取硬盘序列号函数
char*   CGetHDSerial::GetHDSerial()
{
    m_buffer[0]='\n';
    //   得到当前操作系统版本
    OSVERSIONINFO   OSVersionInfo;
    OSVersionInfo.dwOSVersionInfoSize   =   sizeof(OSVERSIONINFO);
    GetVersionEx(   &OSVersionInfo);
    if   (OSVersionInfo.dwPlatformId   !=   VER_PLATFORM_WIN32_NT)
    {      
    //   Windows   9x/ME下读取硬盘序列号
    WORD   m_wWin9xHDSerial[256];
    Win9xReadHDSerial(m_wWin9xHDSerial);    
            strcpy   (m_buffer,   WORDToChar   (m_wWin9xHDSerial,   10,   19));
    }
    else
    {
            //   Windows   NT/2000/XP下读取硬盘序列号
    DWORD   m_wWinNTHDSerial[256];    
    //   判断是否有SCSI硬盘
            if   (   !   WinNTReadIDEHDSerial(m_wWinNTHDSerial))  
              WinNTReadSCSIHDSerial(m_wWinNTHDSerial);    
            strcpy   (m_buffer,   DWORDToChar   (m_wWinNTHDSerial,   10,   19));
    }
    return   m_buffer;
}

//   Windows9X/ME系统下读取硬盘序列号
void   _stdcall   CGetHDSerial::Win9xReadHDSerial(WORD   *   buffer)
{
int   i;
for(i=0;i<256;i++)  
buffer[i]=0;
        _asm
        {
            push   eax                
                //获取修改的中断的中断描述符(中断门)地址
                sidt   m_IDTR
                mov   eax,dword   ptr   [m_IDTR+02h]                
                add   eax,3*08h+04h
                cli
                //保存原先的中断入口地址
                push   ecx
                mov   ecx,dword   ptr   [eax]
                mov   cx,word   ptr   [eax-04h]
                mov   dword   ptr   m_OldInterruptAddress,ecx
                pop   ecx
                //设置修改的中断入口地址为新的中断处理程序入口地址
                push   ebx
                lea   ebx,InterruptProcess
                mov   word   ptr   [eax-04h],bx
                shr   ebx,10h
                mov   word   ptr   [eax+02h],bx
                pop   ebx
                //执行中断,转到Ring   0(类似CIH病毒原理)
int   3h
                //恢复原先的中断入口地址
                push   ecx
                mov   ecx,dword   ptr   m_OldInterruptAddress
                mov   word   ptr   [eax-04h],cx
                shr   ecx,10h
                mov   word   ptr   [eax+02h],cx
                pop   ecx
                sti
                pop   eax
        }  
for(i=0;i<256;i++)
buffer[i]=m_serial[i];
}
//   Windows   9x/ME系统下,将字类型(WORD)的硬盘信息转换为字符类型(char)
char   *   CGetHDSerial::WORDToChar   (WORD   diskdata   [256],   int   firstIndex,   int   lastIndex)
{
      static   char   string   [1024];
      int   index   =   0;
      int   position   =   0;

      //   按照高字节在前,低字节在后的顺序将字数组diskdata   中内容存入到字符串string中  
      for   (index   =   firstIndex;   index   <=   lastIndex;   index++)
      {
            //   存入字中的高字节
            string   [position]   =   (char)   (diskdata   [index]   /   256);
            position++;
            //   存入字中的低字节
            string   [position]   =   (char)   (diskdata   [index]   %   256);
            position++;
      }
      //     添加字符串结束标志
      string   [position]   =   '\0';

      //     删除字符串中空格
      for   (index   =   position   -   1;   index   >   0   &&   '   '   ==   string   [index];   index--)
            string   [index]   =   '\0';

      return   string;
}

//   Windows   NT/2000/XP系统下,将双字类型(DWORD)的硬盘信息转换为字符类型(char)
char*   CGetHDSerial::DWORDToChar   (DWORD   diskdata   [256],   int   firstIndex,   int   lastIndex)
{
      static   char   string   [1024];
      int   index   =   0;
      int   position   =   0;

      //   按照高字节在前,低字节在后的顺序将双字中的低字存入到字符串string中  
      for   (index   =   firstIndex;   index   <=   lastIndex;   index++)
      {
            //   存入低字中的高字节
            string   [position]   =   (char)   (diskdata   [index]   /   256);
            position++;
            //   存入低字中的低字节
            string   [position]   =   (char)   (diskdata   [index]   %   256);
            position++;
      }
      //     添加字符串结束标志
      string   [position]   =   '\0';

      //     删除字符串中空格
      for   (index   =   position   -   1;   index   >   0   &&   '   '   ==   string   [index];   index--)
            string   [index]   =   '\0';

      return   string;
}

//   Windows   NT/2000/XP下读取IDE硬盘序列号
BOOL   CGetHDSerial::WinNTReadIDEHDSerial(DWORD   *   buffer)
{
      BYTE   IdOutCmd   [sizeof   (SENDCMDOUTPARAMS)   +   IDENTIFY_BUFFER_SIZE   -   1];
      BOOL   bFlag   =   FALSE;
      int     drive   =   0;
      char   driveName   [256];
      HANDLE   hPhysicalDriveIOCTL   =   0;        
           
      sprintf   (driveName,   "\\\\.\\PhysicalDrive%d",   drive);
      //     Windows   NT/2000/XP下创建文件需要管理员权限
      hPhysicalDriveIOCTL   =   CreateFile   (driveName,
                                                        GENERIC_READ   |   GENERIC_WRITE,  
                                                        FILE_SHARE_READ   |   FILE_SHARE_WRITE,   NULL,
                                                        OPEN_EXISTING,   0,   NULL);

      if   (hPhysicalDriveIOCTL   !=   INVALID_HANDLE_VALUE)
      {
              GETVERSIONOUTPARAMS   VersionParams;
              DWORD                               cbBytesReturned   =   0;

              //   得到驱动器的IO控制器版本
              memset   ((void*)   &VersionParams,   0,   sizeof(VersionParams));
              if(DeviceIoControl   (hPhysicalDriveIOCTL,   IOCTL_GET_VERSION,
                                                              NULL,   0,   &VersionParams,
                                                              sizeof(VersionParams),
                                                              &cbBytesReturned,   NULL)   )
      {                
                    if   (VersionParams.bIDEDeviceMap   >   0)
    {
                            BYTE                           bIDCmd   =   0;       //   IDE或者ATAPI识别命令
                            SENDCMDINPARAMS     scip;
 
                            //   如果驱动器是光驱,采用命令IDE_ATAPI_IDENTIFY,   command,
                            //   否则采用命令IDE_ATA_IDENTIFY读取驱动器信息
                            bIDCmd   =   (VersionParams.bIDEDeviceMap   >>   drive   &   0x10)?
                                            IDE_ATAPI_IDENTIFY   :   IDE_ATA_IDENTIFY;

                            memset   (&scip,   0,   sizeof(scip));
                            memset   (IdOutCmd,   0,   sizeof(IdOutCmd));
                            //   获取驱动器信息
                            if   (WinNTGetIDEHDInfo   (hPhysicalDriveIOCTL,  
                                                                            &scip,  
                                                                            (PSENDCMDOUTPARAMS)&IdOutCmd,  
                                                                            (BYTE)   bIDCmd,
                                                                            (BYTE)   drive,
                                                                            &cbBytesReturned))
    {
                                    int   m   =   0;
                                    USHORT   *pIdSector   =   (USHORT   *)
                                                          ((PSENDCMDOUTPARAMS)   IdOutCmd)   ->   bBuffer;

                                    for   (m   =   0;   m   <   256;   m++)
                                              buffer[m]   =   pIdSector   [m];
                                    bFlag   =   TRUE;     //   读取硬盘信息成功
    }
    }
      }
              CloseHandle   (hPhysicalDriveIOCTL);     //   关闭句柄
      }
      return   bFlag;
}

  • 分类: 学习心得