[chenhui530]VB 拷贝SAM文件
最近出差在外,写了几篇文章也没时间发布出来.
前些天看到有朋友提到这方面,我也就留意了下
抽了点时间写了这个程序,其实这个程序也是转换
C的代码,希望对大家有帮助.下面是完整源码
VERSION 5.00
Begin VB.Form frmMain
BorderStyle = 1 'Fixed Single
Caption = "SAM文件复制 "
ClientHeight = 3090
ClientLeft = 45
ClientTop = 435
ClientWidth = 4680
LinkTopic = "Form1 "
MaxButton = 0 'False
MinButton = 0 'False
ScaleHeight = 3090
ScaleWidth = 4680
StartUpPosition = 3 '窗口缺省
Begin VB.TextBox txtPath
Height = 345
Left = 1200
TabIndex = 1
Text = "c:\sam "
Top = 630
Width = 2265
End
Begin VB.CommandButton cmdCopy
Caption = "复制 "
Height = 465
Left = 1470
TabIndex = 0
Top = 1260
Width = 1275
End
End
Attribute VB_Name = "frmMain "
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = False
Private Declare Function DeviceIoControl Lib "kernel32 " (ByVal hDevice As Long, ByVal dwIoControlCode As Long, lpInBuffer As Any, ByVal nInBufferSize As Long, lpOutBuffer As Any, ByVal nOutBufferSize As Long, lpBytesReturned As Long, lpOverlapped As Any) As Long
Private Declare Function CreateFile Lib "kernel32 " Alias "CreateFileA " (ByVal lpFileName As String, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, lpSecurityAttributes As Any, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long
Private Declare Function WriteFile Lib "kernel32 " (ByVal hFile As Long, lpBuffer As Any, ByVal nNumberOfBytesToWrite As Long, lpNumberOfBytesWritten As Long, lpOverlapped As Any) As Long
Private Declare Function SetFilePointer Lib "kernel32 " (ByVal hFile As Long, ByVal lDistanceToMove As Long, lpDistanceToMoveHigh As Long, ByVal dwMoveMethod As Long) As Long
Private Declare Function ReadFile Lib "kernel32 " (ByVal hFile As Long, lpBuffer As Any, ByVal nNumberOfBytesToRead As Long, lpNumberOfBytesRead As Long, lpOverlapped As Any) As Long
Private Declare Function GetSystemDirectory Lib "kernel32 " Alias "GetSystemDirectoryA " (ByVal lpBuffer As String, ByVal nSize As Long) As Long
Private Declare Function GetDiskFreeSpace Lib "kernel32 " Alias "GetDiskFreeSpaceA " (ByVal lpRootPathName As String, lpSectorsPerCluster As Long, lpBytesPerSector As Long, lpNumberOfFreeClusters As Long, lpTotalNumberOfClusters As Long) As Long
Private Declare Function GetFileSize Lib "kernel32 " (ByVal hFile As Long, lpFileSizeHigh As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32 " Alias "RtlMoveMemory " (Destination As Any, Source As Any, ByVal Length As Long)
Private Declare Function CloseHandle Lib "kernel32 " (ByVal hObject As Long) As Long
Private Const GENERIC_READ = &H80000000
Private Const FILE_SHARE_READ = &H1
Private Const FILE_SHARE_WRITE = &H2
Private Const OPEN_EXISTING = 3
Private Const INVALID_HANDLE_VALUE = -1
Private Const GENERIC_WRITE = &H40000000
Private Const OPEN_ALWAYS = 4
Private Const FILE_READ_ATTRIBUTES = (&H80)
Private Const FSCTL_GET_RETRIEVAL_POINTERS = 589939
Private Type RETRIEVAL_POINTERS_BUFFER
dwExtentCount As Long
bytStartingVcn(7) As Byte '这些都可以使用LARGE_INTEGER类型代替
bytNextVcn(7) As Byte '这些都可以使用LARGE_INTEGER类型代替
bytLcn(7) As Byte '这些都可以使用LARGE_INTEGER类型代替
lngTmp As Long
End Type
Private Type LARGE_INTEGER
LowPart As Long
HighPart As Long
End Type
Private Sub cmdCopy_Click()
Dim strSamPath As String
strSamPath = GetSystemPath & "\Config\Sam "
If CopySamFile(strSamPath, txtPath.Text) Then
MsgBox "复制完毕!! ", vbInformation, "提示 "
Else
MsgBox "复制错误!! ", vbCritical, "提示 "
End If
End Sub
'获取系统目录路径
Private Function GetSystemPath() As String
Dim strTmp As String
strTmp = String(260, Chr(0))
GetSystemDirectory strTmp, 260
strTmp = Left(strTmp, InStr(strTmp, Chr(0)) - 1)
GetSystemPath = strTmp
End Function
Private Function GetFileClusters(ByVal strFileName As String, ByVal lngClusterSize As Long, lngClCount As Long, lngFileSize As Long) As Long()
Dim hFile As Long
Dim lngOutSize As Long
Dim lngBytes As Long, lngCls As Long, lngCnCount As Long, r As Long, lngCount As Long, i As Long, j As Long
Dim lngClusters() As Long
Dim bytInBuf(7) As Byte
Dim objOutBuf As RETRIEVAL_POINTERS_BUFFER
hFile = CreateFile(strFileName, FILE_READ_ATTRIBUTES, _
FILE_SHARE_READ Or FILE_SHARE_WRITE Or FILE_SHARE_DELETE, _
ByVal 0&, OPEN_EXISTING, 0, 0)
If hFile <> INVALID_HANDLE_VALUE Then
lngFileSize = GetFileSize(hFile, 0)
lngOutSize = 32 + (lngFileSize / lngClusterSize) * 16
If DeviceIoControl(hFile, FSCTL_GET_RETRIEVAL_POINTERS, bytInBuf(0), 8, objOutBuf, lngOutSize, lngBytes, ByVal 0&) Then
lngClCount = (lngFileSize + lngClusterSize - 1) \ lngClusterSize
CopyMemory lngCount, objOutBuf.bytNextVcn(4), 4
For r = 0 To objOutBuf.dwExtentCount - 1
CopyMemory j, objOutBuf.bytLcn(4), 4
For i = lngCount To 0 Step -1
ReDim Preserve lngClusters(0 To lngCls)
lngClusters(lngCls) = j
j = j + 1
lngCls = lngCls + 1
Next
Next
CloseHandle hFile
GetFileClusters = lngClusters
End If
End If
End Function
Private Function CopySamFile(ByVal strSamPath As String, ByVal strDestPath As String) As Boolean
Dim lngClusterSize As Long
Dim lngClusters() As Long
Dim lngClCount As Long, lngFileSize As Long, lngBytes As Long
Dim hDrive As Long, hFile As Long
Dim lngSecPerCl As Long, lngBtPerSec As Long, r As Long
Dim curTmp As Currency
Dim ligNo As LARGE_INTEGER
Dim bytBuff() As Byte
GetDiskFreeSpace Left(strSamPath, 2), lngSecPerCl, lngBtPerSec, ByVal 0&, ByVal 0&
lngClusterSize = lngSecPerCl * lngBtPerSec
On Error GoTo ErrHandle
lngClusters = GetFileClusters(strSamPath, lngClusterSize, lngClCount, lngFileSize)
hDrive = CreateFile( "\\.\ " & Left(strSamPath, 2), GENERIC_READ, FILE_SHARE_READ Or FILE_SHARE_WRITE, ByVal 0&, OPEN_EXISTING, 0, 0)
If hDrive <> INVALID_HANDLE_VALUE Then
hFile = CreateFile(strDestPath, GENERIC_WRITE, 0, ByVal 0, OPEN_ALWAYS, 0, 0)
If hFile <> INVALID_HANDLE_VALUE Then
For r = 0 To lngClCount - 1
curTmp = Ccur(lngClusterSize) * Ccur(lngClusters(r)) /10000 'lngClusterSize * lngClusters(r)
CopyMemory ligNo, curTmp, Len(ligNo)
Call SetFilePointer(hDrive, ligNo.LowPart, ligNo.HighPart, 0)
If lngFileSize < lngClusterSize Then
ReDim bytBuff(lngFileSize - 1)
Else
ReDim bytBuff(lngClusterSize - 1)
End If
Call ReadFile(hDrive, bytBuff(0), lngClusterSize, lngBytes, ByVal 0&)
lngFileSize = lngFileSize - lngBytes
Call WriteFile(hFile, bytBuff(0), lngClusterSize, lngBytes, ByVal 0&)
Debug.Print ligNo.LowPart; ligNo.HighPart
Next
End If
CloseHandle hFile
End If
CloseHandle hDrive
CopySamFile = True
Exit Function
ErrHandle:
If hDrive <> -1 Then CloseHandle hDrive
If hFile <> -1 Then CloseHandle hFile
End Function
[解决办法]
我来解释一下什么是SAM文件:
SAM最初是跟随第一代NT来到世界的,它在微软总部的特工代号叫做“安全账户管理器”(Security Accounts Manager),可以所sam文件是windows的门卫,在win2k时代这个门卫不太强大,到了NT内核时代,这个家伙的作用就变得强大了。SAM记录的数据很多,包括所有组、账户信息、密码HASH、账户SID等,应该说是一个考虑得比较周全的门卫。
SAM不仅仅是一个文件那么简单,它不但有文件数据,在注册表里面还有一个数据库,位于HKEY_LOCAL_MACHINE\\SAM下,这是一个比较复杂的结构。SAM在系统启动后就处于锁定状态,我们没法擅自更改这个文件内容。
在注册表里我们可以看到一下内容:
1.在HKEY_LOCAL_MACHINE\\SAM\\SAM\\
Domains下就是SAM的内容,其下有两个分支“Account”和“Builtin”。
2.Domains\\Account\\Users下存放的就是各个账号的信息,当然,这里是加密过的二进制数据,每个账号下面有两个子项,F和V。项目V中保存的是账户的基本资料,用户名、所属组、描述、密码、注释、是否可以更改密码、账户启用、密码设置时间等。项目F中保存的是一些登录记录,比如上次登录时间、错误登录次数等。SAM靠这些齐全的备忘录来保存与用户账号相关的各种信息。
3.Domains\\Builtin存放着不同用户分组信息,SAM就是根据这个来划分NT中固有的6个不同的工作组的,它们分别是:管理员(Administrators)、备份操作员(Backup Operators)、客人(Guests)、高权限用户(Power Users)、修复员(Replicator)和普通用户(Users)。
幕后指挥官
在Windows系统中,虽然SAM如此尽力,但是他不听从你的指挥。它只听本地安全认证(Local Security Authority)程序——LSASS.EXE的差遣,就连进门时的审查也是LSASS的指示。如果你把LSASS杀了,你就等着被赶出门吧——当然,对于普通用户来说,如果你试图用普通的进程管理工具或者Windows系统的进程管理杀掉“LSASS.EXE”进程的话,只会得到“该进程为关键系统进程,任务管理器无法结束进程。”的提示,本地安全认证(Local Security Authority)在Windows系统中主要负责以下任务:1.重新找回本地组的SID和用户权限;2.创建用户的访问令牌;3.管理本地安装的服务所使用的服务账号;4. 存储和映射用户权限;5.管理审核的策略和设置;6.管理信任关系。
俗话说,“人无完人”。尽管SAM(萨姆)是这么尽心尽责,可是在这里,我们还是必须用那句话——“萨姆也是人”来形容它。由于一些设计上的失误,在WinNT/2000里,如果你忘记了密码,那么你要做的不是呼天喊地,只需要在非NT环境里把SAM驱逐出硬盘就可以了。但是在XP以后的Windows操作系统里,这个情况得以改善,如果你把萨姆大叔踢了,NT也躲着死活不肯出来了。
特别提醒:不要以为sam文件记录了密码信息你就可以删除该文件使得系统用户密码为空,虽然在早期的win2k时代你可以在dos环境下这样做以求达到置空密码的目的,在xp时代,这样可没有用哦。
[解决办法]
陈辉大哥的代码还有点小问题,就是不能复制C:\windows\system32\config\system文件,我修改了下面几个地方就可以了
1.RETRIEVAL_POINTERS_BUFFER 类型声明的
lngTmp As Long 改成 lngTmp(255) As byte
2.lngOutSize = 32 + (lngFileSize / lngClusterSize) * 16
If DeviceIoControl(hFile, FSCTL_GET_RETRIEVAL_POINTERS, bytInBuf(0), 8, _
objOutBuf, lngOutSize, lngBytes, ByVal 0&) Then
lngClCount = (lngFileSize + lngClusterSize - 1) \ lngClusterSize
改成
lngOutSize = 32 + (lngFileSize \ lngClusterSize) * 16
Dim bytOutBuf() As Byte: ReDim bytOutBuf(lngOutSize - 1)
If DeviceIoControl(hFile, FSCTL_GET_RETRIEVAL_POINTERS, bytInBuf(0), 8, _
bytOutBuf(0), lngOutSize, lngBytes, ByVal 0&) Then
CopyMemory objOutBuf, bytOutBuf(0), lngBytes
lngClCount = (lngFileSize + lngClusterSize - 1) \ lngClusterSize
不过还是很多谢陈辉大哥!以后还有很多地方要想你学习!