hdsn32.asm 是 2000 年編寫的 Win9x 專用小工具,功能為讀取硬碟 (IDE/ATA) 序號並寫入檔案。核心技術為修改 IDT (Interrupt Descriptor Table) 暫存器,將 INT 3 (中斷向量 3) 的描述符替換為自訂的 Ring 0 程式碼選擇子,再觸發 INT 3 進入核心模式,直接操作 IDE 控制器埠 (1F0h~1F7h) 發送 IDENTIFY DEVICE 命令 (ECh) 讀取 256 字組資料,從中解析序號。此法仿照 CIH 病毒核心技術,僅適用於 Windows 9x (VxD 架構),Windows 2000/XP 及後續 NT 核心系統因保護機制不同無法執行。
; 建立自訂 Gate Descriptor (OurGate)
mov eax, offset Ring0Proc
mov [OurGate], ax ; Offset Low
shr eax, 16
mov [OurGate+6], ax ; Offset High
; OurGate 結構:Offset Low | Selector(0x28) | Attr(0xEE00) | Offset High
; Selector 0x28 = GDT 索引 5, TI=0, RPL=0 → Kernel Code Segment
; Attr 0xEE00 = Present(1) DPL=3 Type=1110 (32-bit Interrupt Gate)
; 讀取 IDTR 基址
sidt fword ptr IDTR
mov ebx, dword ptr [IDTR+2] ; IDT Base Address
add ebx, 8*3 ; INT 3 描述符位置 (每個描述符 8 位元組)
; 保存原描述符、寫入新描述符
mov edi, ebx
mov esi, offset OurGate
movsd
movsd
; 觸發 INT 3 進入 Ring0Proc
int 3h
; 還原原描述符
mov edi, ebx
mov esi, offset SavedGate
movsd
movsd
關鍵點:
SIDT 只能在特權級 0 執行,但 Win9x 允許 Ring 3 讀取 IDTR (不檢查 CPL),這是安全漏洞被利用的基礎。0x28 對應 Win9x VMM 建立的核心代碼段描述符,DPL=0,但 Gate DPL=3 允許 Ring 3 呼叫 INT 3 進入。0xEE00 = 1110 1110 0000 0000b:P=1, DPL=3, Type=0xE (32-bit Interrupt Gate)。Ring0Proc PROC
start_1:
mov edx, 1F7h
in al, dx
cmp al, 50h
jnz start_1 ; 等待 BSY=0, DRDY=1 (Status 0x50)
dec dx ; dx = 1F6h (Device/Head)
mov al, 0A0h ; LBA=0, Device 0 (Master)
out dx, al
mov dx, 1F7h
mov al, 0ECh ; IDENTIFY DEVICE 命令
out dx, al
mov dx, 1F7h
st_1:
in al, dx
cmp al, 58h
jnz st_1 ; 等待 DRQ=1 (Status 0x58)
mov dx, 1F0h ; Data Port
mov edi, offset BUFF1
mov ecx, 256
st_2:
in ax, dx ; 讀取一字組 (16-bit)
xchg ah, al ; 大小端轉換 (IDE 回傳 Little Endian)
stosw ; 存入緩衝區
loop st_2
sti
; 複製序號區塊 (Offset 20h~33h, 20 字節) 至 hdsn_2
push offset BUFF1[20]
pop esi
push offset hdsn_2
pop edi
mov ecx, 20
rep movsb
iretd
Ring0Proc ENDP
流程說明:
ECh (IDENTIFY DEVICE)。1F0h 連續讀取 256 字組 (512 位元組)。IRETD 返回 Ring 3 繼續執行。
invoke MessageBox, NULL, addr hdsn_1, addr szCaption, MB_OK
invoke CreateFile, ADDR name_buffer, GENERIC_READ or GENERIC_WRITE, \
FILE_SHARE_READ or FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, \
FILE_ATTRIBUTE_ARCHIVE, NULL
mov hFile, eax
push offset hdsn_2
pop esi
push offset hdsn_3
pop edi
mov ecx, 20
jm_1:
lodsb
xor al, 36h ; 簡易 XOR 混淆
stosb
loop jm_1
invoke WriteFile, hFile, ADDR hdsn_3, 20, ADDR SizeReadWrite, NULL
invoke CloseHandle, hFile
invoke ExitProcess, eax
.386
.model flat, stdcall
option casemap :none
include \masm32\include\windows.inc
include \MASM32\INCLUDE\shell32.inc
include \MASM32\INCLUDE\masm32.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
includelib \MASM32\LIB\shell32.lib
includelib \MASM32\LIB\masm32.lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
.data
IDTR df 0
SavedGate dq 0
OurGate dw 0
dw 028h
dw 0EE00h
dw 0
BUFF1 DW 256 DUP(20H)
hdsn_1 db '硬盤C序列號:',0DH,0AH
hdsn_2 db 256 dup(0)
hdsn_3 db 20 dup(0)
szCaption db 'hdsn32 v1.0 for win9x 山東海化集團 盛玉增 編制 2000.12.21',0
name_buffer db 'hdsn.bin',0
.data?
hFile HANDLE ?
SizeReadWrite DWORD ?
.code
Start:
mov eax, offset Ring0Proc
mov [OurGate], ax
shr eax, 16
mov [OurGate+6], ax
sidt fword ptr IDTR
mov ebx, dword ptr [IDTR+2]
add ebx, 8*3
mov edi, offset SavedGate
mov esi, ebx
movsd
movsd
mov edi, ebx
mov esi, offset OurGate
movsd
movsd
int 3h
mov edi, ebx
mov esi, offset SavedGate
movsd
movsd
invoke MessageBox,NULL,addr hdsn_1,addr szCaption,MB_OK
invoke CreateFile,ADDR name_buffer,\
GENERIC_READ or GENERIC_WRITE,\
FILE_SHARE_READ or FILE_SHARE_WRITE,\
NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_ARCHIVE,\
NULL
mov hFile,eax
push offset hdsn_2
pop esi
push offset hdsn_3
pop edi
mov ecx,20
jm_1:
lodsb
xor al,36h
stosb
loop jm_1
invoke WriteFile,hFile,ADDR hdsn_3,20,\
ADDR SizeReadWrite,NULL
invoke CloseHandle,hFile
invoke ExitProcess,eax
Ring0Proc PROC
start_1:
mov edx,1F7h
in al,dx
cmp al,50h
jnz start_1
dec dx
mov al,0A0h
out dx,al
mov dx,1F7h
mov al,0ECh
out dx,al
mov dx,1F7h
st_1:
in al,dx
cmp al,58h
jnz st_1
mov dx,1F0h
mov edi,offset BUFF1
mov ecx,0
mov cx,256
st_2:
in ax,dx
xchg ah,al
stosw
loop st_2
sti
push offset BUFF1[20]
pop esi
push offset hdsn_2
pop edi
mov ecx,20
rep movsb
iretd
Ring0Proc ENDP
end Start
DeviceIoControl + IOCTL_STORAGE_QUERY_PROPERTY / SMART_RCV_DRIVE_DATA。Win32_DiskDrive.SerialNumber。libata (Linux)、IOKit (macOS)。此程式展示了 90 年代末期 Windows 9x 架構下,應用程式如何突破 Ring 3 限制直接存取硬體——透過 IDT Gate 描述符竄改實現 Ring 0 代碼執行。這是理解舊版 Windows 核心架構、VxD 驅動模型、以及早期病毒 (CIH、Chernobyl) 感染機制的重要教學案例。雖技術已過時,但「描述符表操作、特權級轉換、硬體埠編程」等核心觀念在作業系統開發、虛擬化、安全研究領域仍具參考價值。