游侠无极限 发表于 2003-11-2 18:09:00

[转帖]2000/xp下读硬盘序列号[汇编]

我可没这个水平
.686p
.model flat, stdcall
option casemap :none   ; case sensitive
; #########################################################################
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\advapi32.inc
      
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\advapi32.lib
DEBUG = TRUE

HMODULE typedef dword
NTSTATUS typedef dword
PACL typedef dword
PSECURITY_DESCRIPTOR typedef dword

OBJ_INHERIT=2
OBJ_PERMANENT=10h
OBJ_EXCLUSIVE=20h
OBJ_CASE_INSENSITIVE=40h
OBJ_OPENIF=80h
OBJ_OPENLINK =100h
OBJ_KERNEL_HANDLE=200
OBJ_VALID_ATTRIBUTES=3F2h

SE_KERNEL_OBJECT = 6
GRANT_ACCESS =1
NO_INHERITANCE =0
TRUSTEE_IS_NAME=1
TRUSTEE_IS_USER=1
STATUS_SUCCESS =0
STATUS_ACCESS_DENIED =0C0000022h

STATUS_ACCESS_VIOLATION equ 0C0000005h
STATUS_INFO_LENGTH_MISMATCH equ 0C0000004h
SystemModuleInformation               equ 11
PVOIDTYPEDEF DWORD
UNLONG TYPEDEF DWORD
CHAR   TYPEDEF BYTE

UNICODE_STRING struct
   nLength word ?
   MaximumLength word ?
   Buffer dword ?
UNICODE_STRING ends

OBJECT_ATTRIBUTES struct
   nLength dword ?
   RootDirectory HANDLE ?
   ObjectName dword ?;PUNICODE_STRING
   Attributes dword ?;
   SecurityDescriptor dword ?; PVOID // Points to type SECURITY_DESCRIPTOR
   SecurityQualityOfService dword ?;PVOID// Points to type SECURITY_QUALITY_OF_SERVICE
OBJECT_ATTRIBUTES ends


TRUSTEE struct
    pMultipleTrustee dword ?;PTRUSTEE                  
    MultipleTrusteeOperation dword ?; MULTIPLE_TRUSTEE_OPERATION
    TrusteeForm dword ?;TRUSTEE_FORM
    TrusteeType dword ?;TRUSTEE_TYPE               
    ptstrName dword ?;LPTSTR                     
TRUSTEE ends


EXPLICIT_ACCESSstruct
    grfAccessPermissions DWORD   ?   
    grfAccessModedword ? ;ACCESS_MODE
    grfInheritance DWORD ?       ;
    Trustee TRUSTEE<>    ;
EXPLICIT_ACCESS ends

MyGATE   struct    ;门结构类型定义
    OFFSETLWORD      ?;32位偏移的低16位
    SELECTOR WORd      ?;选择子
    DCOUNT   BYTE      ?;双字计数字段
    GTYPE    BYTE      ?;类型
    OFFSETHWORD   ?;32位偏移的高16位
MyGATE   ends

IDEINFOstruct
wGenConfig   dw ?
wNumCyls   dw ?;拄面数
wReserved   dw ?
wNumHeads   dw ?;磁头数
wBytesPerTrack   dw ?;每道字节数
wBytesPerSector   dw ?;每扇区字节数
wSectorsPerTrackdw ?;每道山区数
wVendorUnique   dw 3 dup (?)
sSerialNumber   db 20 dup (?);硬盘序列号
wBufferType   dw ?;
wBufferSize   dw ?; ;n * 512
wECCSize   dw ?
sFirmwareRev   db 8 dup (?);
sModelNumber   db 40 dup (?)
wMoreVendorUniquedw ?
wDoubleWordIO   dw ?
wCapabilities   dw ?
wReserved1   dw ?
wPIOTiming   dw ?;
wDMATiming   dw ?;
wBS    dw ?
wNumCurrentCyls   dw ?;
wNumCurrentHeadsdw ?;
wNumCurrentSectorsPerTrack dw ?;
dwCurrentSectorCapacitydd ?;
wMultSectorStuffdw ?;
dwTotalAddressableSectors dd ?;
wSingleWordDMA   dw ?;
wMultiWordDMA   dw ?;
bReserved   db 128 dup (?)
IDEINFOends


SetPhyscialMemorySectionCanBeWrited proto :dword
MiniMmGetPhysicalAddress proto :dword

ENTERRING0 macro
pushad
pushfd
cli
mov eax,cr0   ;get rid off readonly protect
and eax,0fffeffffh
mov cr0,eax
endm

LEAVERING0 macro
mov eax,cr0 ;restore readonly protect
or eax,10000h
mov cr0,eax
sti
popfd
popad
retf
endm


UNICODE_STR macro str
irpc _c,<str>
db '&_c'
db 0
endm
endm

.data?
GdtLimit dw ?
GdtAddr dd ?

mapAddr dd ?
OldEsp dd ?

readeddw ?
buffer db 512 dup(?)
ShowText db 512*3 dup (?)

szBuffer db 1024 dup (?)
szModelNumber db 41 dup (?)
szSerialNumber db 21 dup (?)
szFirmwareRev db 9 dup (?)

stIDEINFO IDEINFO <?>

.data
align 4
objname dw objnamestr_size,objnamestr_size+2
objnameptr dd 0
objnamestr equ this byte
UNICODE_STR <\Device\PhysicalMemory>
objnamestr_size equ $-objnamestr

szTitledb 'IDE 硬盘信息',0
szErrInfo db '无法读取硬盘信息',0
szIDEInfo db '柱面数   : %d',0dh,0ah
db '磁头数   : %d',0dh,0ah
db '每道扇区数 : %d',0dh,0ah
db '缓冲大小   : %d 扇区',0dh,0ah
db '硬盘型号   : %40s',0dh,0ah
db '序列号   : %20s',0dh,0ah
db '版本号   : %8s',0

align 4
ObjAttr db 24 dup (0)

Callgt dq 0      ;call gate's sel:off
Captiondb 'Windows XP绝对磁盘读写',0
Digitdb '0123456789ABCDEF',0
.code
_ShowBuffer proc    ;显示所读出的信息
;把数据转换成16进制的形式
mov,512
movesi,offset buffer;数据
movedi,offset ShowText;转换后的数据
movebx,offset Digit
xorecx,ecx
xoreax,eax
computeAgain:
cmp,0
jz   endCompute
dec
lodsb
push eax
shreax,4   ;高4位
xlatb
stosb
popeax
andeax,0fH   ;低4位
xlatb
stosb
movbyte ptr[edi],' ';空格
incedi
incecx
cmpecx,16
jnzcomputeAgain
xorecx,ecx
movbyte ptr[edi-1],13;回车
jmpcomputeAgain
endCompute:
;显示
invokeMessageBoxA,NULL,offset ShowText,offset Caption,MB_OK
ret
_ShowBuffer endp

SetPhyscialMemorySectionCanBeWrited proc uses ebx esi edi hSection:HANDLE
local pDacl: PACL
local pNewDacl:PACL
local pSD :PSECURITY_DESCRIPTOR
local dwRes:DWORD ;
local ea:EXPLICIT_ACCESS ;
invoke GetSecurityInfo,hSection,SE_KERNEL_OBJECT,DACL_SECURITY_INFORMATION,                  NULL,NULL, addr pDacl,NULL, addr pSD
cmp eax,ERROR_SUCCESS
jz @f
jmp OutSet
@@:
mov dwRes,eax
mov ea.grfAccessPermissions ,SECTION_MAP_WRITE;2
mov ea.grfAccessMode ,GRANT_ACCESS;1
mov ea.grfInheritance,NO_INHERITANCE;0
mov ea.Trustee.pMultipleTrustee,0
mov ea.Trustee.MultipleTrusteeOperation,0
mov ea.Trustee.TrusteeForm,TRUSTEE_IS_NAME;1
mov ea.Trustee.TrusteeType,TRUSTEE_IS_USER;1
call @f
db "CURRENT_USER",0
@@:
pop edx
mov ea.Trustee.ptstrName,edx
invoke SetEntriesInAcl,1,addr ea,pDacl,addr pNewDacl
cmp eax,ERROR_SUCCESS
jz @f
jmp OutSet
@@:
invoke SetSecurityInfo,hSection,SE_KERNEL_OBJECT,DACL_SECURITY_INFORMATION,                  NULL,NULL,pNewDacl,NULL
OutSet:
cmp pSD,0
jz @f
invoke LocalFree,pSD
@@:
cmp pNewDacl,0
jz @f
invoke LocalFree,pNewDacl
@@:
ret
SetPhyscialMemorySectionCanBeWrited endp

MiniMmGetPhysicalAddress proc virtualaddress:dword
mov eax,virtualaddress
cmp eax,80000000h
jb @f
cmp eax,0a0000000h
jae @f
and eax,1FFFF000h
ret
@@:
mov eax,0
ret
MiniMmGetPhysicalAddress endp

ExecRing0Proc proc
local tmpSel:dword
local setcg:dword
local BaseAddress:dword
local NtdllMod :dword
local hSection:HANDLE
local status:NTSTATUS
local objectAttributes:OBJECT_ATTRIBUTES
local objName:UNICODE_STRING
mov status,STATUS_SUCCESS;
sgdt GdtLimit
invoke MiniMmGetPhysicalAddress,GdtAddr
mov mapAddr,eax
test eax,eax
jz Exit1
call @f
db "Ntdll.dll",0
@@:
call LoadLibraryA
mov NtdllMod,eax

lea edx,objnamestr
mov objnameptr,edx
lea edi,ObjAttr
and di,0fffch ;align to 4 bytes,or ZwOpenSection will fail
push edi   ;edi->ObjAttr
push 24    ;length of <\Device\PhysicalMemory>
pop ecx
push ecx
xor eax,eax
rep stosb   ;put ObjAttr with 0
pop ecx
pop edi
mov esi,edi
stosd
mov dword ptr[esi],ecx
stosd
lea eax,[edx-8] ;eax->objname
stosd      ;ObjAddr(18h,00,00,00,00,00,00,00,offset objname,40,02,00,00,dd 2 dup(0)
mov dword ptr [edi],240h

call @f
db "ZwOpenSection",0
@@:
push NtdllMod
call GetProcAddress
mov ebx,eax ;ebx=ZwOpenSection

push esi ;esi->ObjAttr
push SECTION_MAP_READ or SECTION_MAP_WRITE
lea edi,hSection
push edi ;edi->hSection
call eax ;ZwOpenSection(&hSection,SECTION_MAP_READ or SECTION_MAP_WRITE,ObjAttr)

mov status,eax
cmp status,STATUS_ACCESS_DENIED
jnz AccessPermit
mov eax,ebx

push esi
push READ_CONTROL or WRITE_DAC
push edi
call eax

mov status,eax
invoke SetPhyscialMemorySectionCanBeWrited,hSection

call @f
db "ZwClose",0
@@:
push NtdllMod
call GetProcAddress

push hSection
call eax;zwClose hSection

mov eax,ebx

push esi
push SECTION_MAP_READ or SECTION_MAP_WRITE
lea edi,hSection
push edi
call eax
mov status ,eax
;status =ZwOpenSection(&hSection,SECTION_MAP_WRITE|SECTION_MAP_WRITE,&objectAttributes);
AccessPermit:
cmp status ,STATUS_SUCCESS
jz @f
;printf("Error Open PhysicalMemory Section Object,Status:%08X\n",status);
;return 0;
mov eax,0
ret
@@:
movzx eax,word ptr
inc eax
invoke MapViewOfFile,hSection, FILE_MAP_READ or FILE_MAP_WRITE, 0, mapAddr,                      eax
mov BaseAddress,eax
cmp BaseAddress,0
jnz @f
;printf("Error MapViewOffile:");
;PrintWin32Error(GetLastError()); return 0;
mov eax,0
ret
@@:
mov    esi,eax ;esi->gdt base
mov ecx,3e0h
mov eax,GdtAddr
.if dword ptr [esi+ecx+2]!=0ec0003e8h
mov byte ptr [esi],0c3h

mov word ptr [esi+ecx],ax
shr eax,16
mov word ptr [esi+ecx+6],ax
mov dword ptr [esi+ecx+2],0ec0003e8h

mov dword ptr [esi+ecx+8],0000ffffh
mov dword ptr [esi+ecx+12],00cf9a00h
.endif

mov setcg,TRUE
cmp setcg,0
jnz ChangeOK
call @f
db "ZwClose",0
@@:
push NtdllMod
call GetProcAddress
push hSection
call eax
xor eax,eax
ret
ChangeOK:
and    dword ptr Callgt,0
xor eax,eax
mov    ax,3e0h
or   al,3h
mov    wordptr ,ax
;farcall=((short)((ULONG)cg-(ULONG)BaseAddress))|3; //Ring 3 callgate;
lea eax,_Ring0Proc
;invoke VirtualLock,eax,seglen
test eax,eax
jnz @f
xor eax,eax
ret
@@:
invoke GetCurrentThread
invoke SetThreadPriority,eax,THREAD_PRIORITY_TIME_CRITICAL

invoke Sleep,0
call    fword ptr             ;use callgate to Ring0!
;_asm call fword ptr
_Ring0Proc:   ; Ring0 code here..
mov eax,esp   ;save ring0 esp
mov esp,[esp+4];->ring3 esp
push eax
mov ebx,offset stIDEINFO
      assume ebx:ptr IDEINFO
;********************************************************************
; 等待硬盘就绪
;********************************************************************
      mov ecx,10000h
      mov dx,01f7h
   @@:
      in al,dx
      cmp al,50h
      jz @F
      loop @B
      jmp _II_TimeOut
   @@:
;********************************************************************
; 发送命令
; 如果向主控制发送命令,则端口为 1f0h-1f7h
; 如果向副控制发送命令,则端口为 170h-177h
; 1f6h 如果要检测的设备为该IDE接口的主(MASTER)设备,
; 那么发送 a0,如果为从那么发送 b0
; 1f7h 如果要检测的设备为 ATA 设备那么发送 ec
; 如果为 ATAPI 设备那么发送 a1
;********************************************************************
      mov al,0a0h;Drive 0,Head 0
      mov dx,01f6h ;Drive and head port
      out dx,al

      mov al,0ech
      inc dx       ;Command port
      out dx,al
;********************************************************************
; 等待硬盘就绪
;********************************************************************
      mov ecx,10000h
@@:
      in al,dx;1f7 (r-status register)
      cmp al,58h;(driver is ready ,and seek complete)
      jz @F
      loop @B
      jmp _II_TimeOut
@@:
;********************************************************************
; 将返回信息读回
; 注意一定要读满 100h 个字长
;********************************************************************
      cld
      mov edx,01f0h;data port - data comes in and out here
      mov edi,ebx
      mov ecx,0100h
      rep insw
;********************************************************************
; 返回的信息中,型号、序列号、版本号为字形式
; 需要整理到字符串的形式
;********************************************************************
      lea esi,[ebx].sSerialNumber
      mov edi,esi
      mov ecx,10
   @@:
      lodsw
      xchg ah,al
      stosw
      loop @B

      lea esi,[ebx].sFirmwareRev
      mov edi,esi
      mov ecx,24
   @@:
      lodsw
      xchg ah,al
      stosw
      loop @B
_II_TimeOut:
assume ebx:nothing
      
pop esp   ;restore ring0 esp
push offset Ring3
retf
Ring0CodeLen=$-_Ring0Proc

Ring3:
invoke GetCurrentThread
invoke SetThreadPriority,eax,THREAD_PRIORITY_NORMAL

;invoke VirtualUnlock,Entry,seglen

call @f
db "ZwClose",0
@@:
push NtdllMod
call GetProcAddress
push hSection
call eax
mov eax,TRUE
ret
ExecRing0Proc endp

main:
assume fs:nothing
push offset MySEH
push fs:
mov fs:,esp
mov OldEsp,esp
mov ax,ds ;if Win9x?
test ax,4
jnz Exit1
invoke ExecRing0Proc

.if stIDEINFO.wNumCyls
   lea esi,stIDEINFO.sModelNumber
   mov edi,offset szModelNumber
   mov ecx,sizeof stIDEINFO.sModelNumber
   rep movsb

   lea esi,stIDEINFO.sSerialNumber
   mov edi,offset szSerialNumber
   mov ecx,sizeof stIDEINFO.sSerialNumber
   rep movsb

   lea esi,stIDEINFO.sFirmwareRev
   mov edi,offset szFirmwareRev
   mov ecx,sizeof stIDEINFO.sFirmwareRev
   rep movsb

movzx eax,stIDEINFO.wNumCyls
movzx ebx,stIDEINFO.wNumHeads
movzx ecx,stIDEINFO.wSectorsPerTrack
movzx edx,stIDEINFO.wBufferSize
invokewsprintf,addr szBuffer,addr szIDEInfo,   eax,ebx,ecx,edx,   addr szModelNumber,   addr szSerialNumber,   addr szFirmwareRev
mov eax,offset szBuffer
.else
mov eax,offset szErrInfo
.endif
@@:
invoke MessageBox,NULL,eax,addr szTitle,MB_ICONINFORMATION or MB_OK
Exit1:
pop fs:
add esp,4
invoke ExitProcess,0

MySEH :
mov esp,OldEsp
pop fs:
add esp,4
invoke ExitProcess,-1
end main

[此贴子已经被作者于2003-11-2 18:14:02编辑过]

bigfoot 发表于 2003-11-3 16:22:00

呵呵,ExecRing0Proc 这段程序甚妙,先得到gdt,然后构造一个调用门call gate's ,使程序从用户模式(ring 3)进入内核模式(ring 0)。进入内核模式之后,就可以没有限制地对系统干任何勾当。这段程序确实为高手所为,在下佩服得紧。
至于读硬盘序列号之类,只不过是在内核模式下的一个I/O应用罢了。
其实在NT/2000下读取硬盘序列号只要打开\\.\PhysicalDriveX(X:设备号0~26)设备,然后用DeviceIoControl()就可以读取了,不需要绕ring0这么一个大圈子

这个程序也可以C语言实现,不过中间必须嵌入几条汇编的指令,如sgdt GdtLimit
但还是用c来写更方便,例如:
call @f
db "ZwOpenSection",0
@@:
push NtdllMod
call GetProcAddress
mov ebx,eax ;ebx=ZwOpenSection
push esi ;esi->ObjAttr
push SECTION_MAP_READ or SECTION_MAP_WRITE
lea edi,hSection
push edi ;edi->hSection
call eax ;

用c的话只要一句就可以了
ZwOpenSection(&hSection,SECTION_MAP_READ or SECTION_MAP_WRITE,ObjAttr);
因此懂汇编,然后用C/C++编程,是成为高手的捷径

[此贴子已经被作者于2003-11-3 16:46:50编辑过]

firelinux 发表于 2003-11-19 00:12:00

win32位汇编,真的很不错,业余的时间,全都投进去了

唐明 发表于 2003-11-26 19:36:00

要能有台机器试一下多好,学汇编还从没想过去ring0,也感觉没哪个必要。
现在闲着真相试试。这片文章我在家保存了有快一年了。不用感觉可惜了。一直停着不用,我都快忘了那些曾经那些依稀的记忆了。水能给我一台电脑,我力马高喊:有你这么富的吗?

fyer 发表于 2003-12-3 03:31:00

很久以前的一段代码

游侠无极限 发表于 2003-12-3 15:33:00

很久以前?
不是吧,这个是 轻描淡写 编程论坛的斑竹写的

fyer 发表于 2003-12-24 19:21:00

看到过的。
页: [1]
查看完整版本: [转帖]2000/xp下读硬盘序列号[汇编]