邪恶八进制信息安全团队技术讨论组's Archiver

炉子 2008-1-31 22:36

[原创]发段Hive格式解析的VB代码

信息来源:邪恶八进制信息安全团队([url]www.eviloctal.com[/url])
文章作者:炉子

[language=vb]
Attribute VB_Name = "mHiveControl"

'By 炉子[0GiNr]
'http://hi.baidu.com/breakinglove_
'http://0ginr.com

Option Explicit

Public Declare Function RegRestoreKey Lib "advapi32.dll" Alias "RegRestoreKeyA" ( _
     ByVal hKey As Long, _
     ByVal lpFile As String, _
     ByVal dwFlags As RegRestoreFlags) As Long
Public Declare Function RegSaveKeyEx Lib "advapi32.dll" Alias "RegSaveKeyExA" ( _
     ByVal hKey As Long, _
     ByVal lpFile As String, _
     ByVal lpSecurityAttributes As Long, _
     ByVal dwFlags As RegSaveExFlags) As Long
Public Enum RegKeys
    HKEY_CLASSES_ROOT = &H80000000
    HKEY_CURRENT_USER = &H80000001
    HKEY_LOCAL_MACHINE = &H80000002
    HKEY_USERS = &H80000003
    HKEY_CURRENT_CONFIG = &H80000005
End Enum
Public Enum RegRestoreFlags
    REG_FORCE_RESTORE = &H8
    REG_WHOLE_HIVE_VOLATILE = &H1
End Enum
Public Enum RegSaveExFlags
    REG_STANDARD_FORMAT = &H1
    REG_LATEST_FORMAT = &H2
    REG_NO_COMPRESSION = &H4
End Enum
Public Type LARGE_INTEGER
    LowPart As Long
    HighPart As Long
End Type
Public Type RegfBlock
    dwSignature As Long '字符串 - "regf" = 0x66676572
    dwUnknown1 As Long '未知
    dwUnknown2 As Long '总是为 0x00000004
    liLastEdit As LARGE_INTEGER 'NT 时间格式
    dwNumber1 As Long '恒为1
    dwNumber2 As Long '恒为3
    dwNumber3 As Long '恒为0
    dwNumber4 As Long '恒为1 - 或许这个1301是版本1.3.0.1?
    dwOffsetOfFirstKeyRecord As Long '第一个键纪录的偏移
    dwBlockSize As Long '数据块大小(文件大小-4kb)
    dwNumber5 As Long '恒为1
    bytUnknownData(1 To &H1CC) As Byte '无需分析
    dwSum As Long '从 0x00000000 至 0x000001FB 的所有DWORD的数据总和
End Type

Public Type UnkownDataAfterRegfBlock '紧随 RegfBlock 之后
    bytReserved(1 To &HE00) As Byte '未知
End Type

Public Type HBinHeader
    dwSignature As Long '字符串 - "hbin" = 0x6E696268
    dwOffsetFromFirstHBinRecord As Long '第一个 Hbin 记录的偏移
    dwOffsetFromNextHBinRecord As Long '下一个 Hbin 记录的偏移
    dwUnknownData(1 To &H10) As Byte
    dwBlockSize As Long 'Hbin 记录长度
End Type

Public Type HBinData '如果这个段是一个负值(第 31 位被置1),则这个块是空的,并且长度被置为负的块大小
    dwDataBlockSize As Long
    szData() As Byte '长度取决于 dwDataBlockSize
End Type

Public Type NkRecord 'NameKey
    wSignature As Integer '字符串 - "nk" = 0x6B6E
    wKeyType As Integer '根键为 0x2C,否则为0x20
    liLastEdit As LARGE_INTEGER 'NT 时间格式
    bytUnknowData(1 To &H4) As Byte
    dwOffsetOfParentKey As Long '父键的偏移
    dwSubKeyNumber As Long '子键数目
    bytUnknowData2(1 To &H4) As Byte
    dwOffsetOfSubKeyLfRecords As Long '子键的 Lf 记录的偏移
    bytUnknowData3(1 To &H4) As Byte
    dwValuesNumber As Long '项的数目
    dwOffsetOfValueList As Long 'NkRecordValueList 的偏移
    dwOffsetOfSkRecord As Long 'Sk 记录的偏移
    dwOffsetOfClassName As Long '类名的偏移(???)
    bytUnused(1 To &H10) As Byte
    dwUnused As Long '无用数据
    wNameLength As Integer '项名长度
    wClassNameLength As Integer '类名的长度(???)
    szKeyName(1 To 1) As Byte '长度取决于 dwNameLength
End Type

Public Type NkRecordValueList
    dwValueOffset(1) As Long '数组数量取决于 dwValuesNumber
End Type

Public Type VkRecord 'ValueKey
    wSignature As Integer '字符串 - "vk" = 0x6B76
    wNameLength As Integer '项名长度
    dwDataLength As Long '数据长度 - 如果 dwDataLength <=4 那么这个值的数据就是该项的数据 (DWORD);如果为 0 那么这个项无数据
    dwDataOffset As Long '数据偏移
    dwValueType As Long '数据类别 - 数据类别见 DataTypes
    wFlags As Integer '如果第 0 位被置1,那么这条数据是有名称的,否则意味着这条数据是无名称的(“默认”)
    wUnused As Integer '无用数据
    szName(1 To 1) As Byte
End Type

Public Enum DataTypes
    REG_SZ = &H1 '字符串 UNICODE
    REG_EXPEND_SZ = &H2 '可展开的字符串(使用环境变量,例如 "%SystemRoot%\system32") UNICODE
    REG_BINARY = &H3 '二进制数据
    REG_DWORD = &H4 'DWORD
    REG_MULTI_SZ = &H7 '多个字符串,使用 vbNullChar 分隔 UNICODE
    REG_UNKNOWN = &HFFFFFFFF
End Enum

Public Type HashRecord 'Lf 记录的哈希记录
    dwRecordOffset As Long '所属的 Lf 记录的偏移
    szKeyName(1 To 4) As Byte '键名的前4字节 如果修改了键名,这个也需要修改
End Type

Public Type LfRecord
    wSignature As Integer '字符串 - "lf" = 0x666C
    wKeyNumber As Integer '键的数目
    dwHashRecord(1 To 1) As HashRecord
End Type

Public Type SkRecord 'SecurityKey
    wSignature As Integer '字符串 - "sk" = 0x6B73
    wUnused As Integer
    dwPreviousSkRecordOffset As Long '前一个Sk记录的偏移
    dwNextSkRecordOffset As Long '后一个Sk记录的偏移
    dwUsageCounter As Long '使用计数 (???)
    dwRecordSize As Long 'Sk记录的字节数
    '剩余部分为权限设置数据
End Type

Public Declare Function SafeCopyMemory _
        Lib "NTDLL.DLL" Alias "ZwWriteVirtualMemory" _
                (ByVal ProcessHandle As Long, _
                ByVal pDest As Long, _
                ByVal pSrc As Long, _
                ByVal NumberOfBytesToCopy As Long, _
                ByRef NumberOfBytesCopied As Long) As Long
Public Const ZwGetCurrentProcess As Long = -1 '//0xFFFFFFFF
Dim m_pHive As Long
Dim m_RegfBlock As RegfBlock, m_HBinHeader As HBinHeader, m_RootNkRecord As NkRecord
Dim m_RaisedErr As Boolean
Dim m_pRootNk As Long
Private Const GlobalOffset As Long = &H1004
Private Const RegDefault As String = "(Default)"

Public Sub dbg()
    Dim a As NkRecord
    Debug.Print Hex(LenB(a))
End Sub

'hHive should be the base of the hive file in memory
Public Function PreProcessHive(ByVal hHive As Long) As Boolean
    Dim st As Long
    Dim hBase As Long
    Dim unKnownData As UnkownDataAfterRegfBlock
   
    'save hive pointer
    m_pHive = hHive
   
    hBase = hHive
   
    'read regf block
    st = CopyMemory(VarPtr(m_RegfBlock), hBase, LenB(m_RegfBlock))
    If (Not st) Then GoTo InitFaild_
   
    'read hbin header
    hBase = hBase + LenB(m_RegfBlock) + LenB(unKnownData)
    st = CopyMemory(VarPtr(m_HBinHeader), hBase, LenB(m_HBinHeader))
    If (Not st) Then GoTo InitFaild_
   
    'read root nk header
    Dim HbData As HBinData
    st = CopyMemory(VarPtr(HbData), hBase + LenB(m_HBinHeader), LenB(HbData))
    If (Not st) Then GoTo InitFaild_
    hBase = hBase + GetHBinSize(HbData)
    st = CopyMemory(VarPtr(m_RootNkRecord), hBase, LenB(m_RootNkRecord))
    m_pRootNk = hBase
    If (Not st) Then GoTo InitFaild_
   
    'return
    PreProcessHive = True
    Exit Function
InitFaild_:
    PreProcessHive = False
End Function

'这两段是测试用的。
Public Sub NOP()
    NOP1 (m_pRootNk)
   
    DoEvents
End Sub

Public Sub NOP1(ByVal lpNk As Long)
    'MsgBox GetKeyNameByPointer(m_pRootNk)
    Dim szReturn As String
    Dim I As Long, J As Long
    Dim nks() As Long
    Dim lfs() As Long
    lfs = GetSubKeyListNkPointers(lpNk)
    For I = LBound(lfs) To UBound(lfs)
        Dim vks() As Long
        vks = GetValueListVkPointers(lfs(I))
        szReturn = szReturn & "KeyName:" & GetKeyNameByPointer(lfs(I)) & vbCrLf
        If (Not m_RaisedErr) Then
            For J = LBound(vks) To UBound(vks)
                If (vks(J)) = 0 Then Exit For
                Dim dt As DataTypes
                dt = GetValueTypeByPointer(vks(J))
                Dim ret() As Byte
                ret = GetValueDataByPointer(vks(J), dt)
                If dt = REG_DWORD Then
                    Dim K As Long
                    Call CopyMemory(VarPtr(K), VarPtr(ret(1)), 4)
                    szReturn = szReturn & vbTab & GetValueNameByPointer(vks(J)) & vbTab & K & vbCrLf
                ElseIf dt = REG_SZ Then
                    Dim szValue As String: szValue = ret
                    szReturn = szReturn & vbTab & GetValueNameByPointer(vks(J)) & vbTab & szValue & vbCrLf
                Else
                    szReturn = szReturn & vbTab & GetValueNameByPointer(vks(J)) & vbTab & "(Unsupportted value type = " & dt & ")" & vbCrLf
                End If
                DoEvents
            Next

        Else
            ClearError
        End If
    Next
    DoEvents
    WriteFile App.Path & "\Output.txt", StrConv(szReturn, vbFromUnicode)
End Sub

'get the size of the HBIN block
Private Function GetHBinSize(ByRef pHBinInfo As HBinData) As Long
    Dim HBHdrInfo As HBinHeader
    If (pHBinInfo.dwDataBlockSize And &H80000000) Then
        'the 31bit of 0x80000000 is 1, others are 0
        GetHBinSize = LenB(HBHdrInfo) + LenB(pHBinInfo.dwDataBlockSize)
        Exit Function
    Else
        GetHBinSize = LenB(HBHdrInfo) + LenB(pHBinInfo.dwDataBlockSize) + pHBinInfo.dwDataBlockSize
    End If
End Function

'get key name from NK record
Public Function GetKeyNameByPointer(ByVal pNkRecord As Long) As String
    Dim retByt() As Byte
    Dim szRetKeyName As String
    Dim Offset As Long
    Dim NkRec As NkRecord
    Dim st As Boolean
    ReDim pVkRec(1 To 1)
    st = CopyMemory(VarPtr(NkRec), pNkRecord, LenB(NkRec))
    If (Not st) Then GoTo ExitFunc_
    With NkRec
        If (.wNameLength = 0) Then GoTo ExitFunc_
        ReDim retByt(.wNameLength)
        Offset = VarPtr(.szKeyName(1)) - VarPtr(NkRec) + pNkRecord ' - m_pHive
        st = CopyMemory(VarPtr(retByt(LBound(retByt))), Offset, .wNameLength)
        If (Not st) Then GoTo ExitFunc_
        szRetKeyName = StrConv(retByt, vbUnicode)
        If (InStr(szRetKeyName, vbNullChar)) Then szRetKeyName = Left(szRetKeyName, InStr(szRetKeyName, vbNullChar) - 1)
    End With
FinishFunc_:
    Erase retByt
    GetKeyNameByPointer = szRetKeyName
    Exit Function
ExitFunc_:
    m_RaisedErr = True
    'Resume FinishFunc_
End Function

'get key name from NK record
Public Function GetValueNameByPointer(ByVal pVkRecord As Long) As String
    Dim retByt() As Byte
    Dim szRetName As String
    Dim Offset As Long
    Dim VkRec As VkRecord
    Dim st As Boolean
    ReDim pVkRec(1 To 1)
    st = CopyMemory(VarPtr(VkRec), pVkRecord, LenB(VkRec))
    If (Not st) Then GoTo ExitFunc_
    With VkRec
        If (.wNameLength = 0) Then szRetName = RegDefault: GoTo FinishFunc_
        ReDim retByt(.wNameLength)
        Offset = VarPtr(.szName(1)) - VarPtr(VkRec) + pVkRecord ' - m_pHive
        st = CopyMemory(VarPtr(retByt(LBound(retByt))), Offset, .wNameLength)
        If (Not st) Then GoTo ExitFunc_
        szRetName = StrConv(retByt, vbUnicode)
        If (InStr(szRetName, vbNullChar)) Then szRetName = Left(szRetName, InStr(szRetName, vbNullChar) - 1)
    End With
FinishFunc_:
    Erase retByt
    GetValueNameByPointer = szRetName
    Exit Function
ExitFunc_:
    m_RaisedErr = True
    'Resume FinishFunc_
End Function

'get value list, pNkRecord should be the NK record to list, return val is a array pointer to VK record
Public Function GetValueListVkPointers(ByVal pNkRecord As Long) As Long()
    Dim pVkRec() As Long
    Dim NkRec As NkRecord
    Dim dwNumber As Long
    Dim lOffset As Long
    Dim st As Boolean
    ReDim pVkRec(1 To 1)
    st = CopyMemory(VarPtr(NkRec), pNkRecord, LenB(NkRec))
    If (Not st) Then GoTo ExitFunc_
    With NkRec
        dwNumber = .dwValuesNumber
        If (dwNumber = 0) Then GoTo ExitFunc_
        ReDim pVkRec(1 To dwNumber)
        st = CopyMemory(VarPtr(lOffset), VarPtr(.dwOffsetOfValueList) - VarPtr(NkRec) + pNkRecord, LenB(lOffset))
        If (Not st) Then GoTo ExitFunc_
        lOffset = lOffset + m_pHive + GlobalOffset
        st = CopyMemory(VarPtr(pVkRec(LBound(pVkRec))), lOffset, dwNumber * LenB(pVkRec(LBound(pVkRec))))
        If (Not st) Then GoTo ExitFunc_
    End With
   
    'add offset to them :)
    Dim I As Long
    For I = LBound(pVkRec) To UBound(pVkRec)
        pVkRec(I) = pVkRec(I) + GlobalOffset + m_pHive
    Next
FinishFunc_:
    GetValueListVkPointers = pVkRec
    Exit Function
ExitFunc_:
    m_RaisedErr = True
    'Resume FinishFunc_
End Function

'get sub-key list, pNkRecord should be the NK record to list, return val is a array pointer to HASH record
Public Function GetSubKeyListNkPointers(ByVal pNkRecord As Long) As Long()
    Dim pNkRec() As Long
    Dim NkRec As NkRecord
    Dim LfRec As LfRecord
    Dim HashRec() As HashRecord
    Dim st As Boolean
    ReDim pNkRec(1 To 1)
    st = CopyMemory(VarPtr(NkRec), pNkRecord, LenB(NkRec))
    If (Not st) Then GoTo ExitFunc_
    With NkRec
        Dim dwNumber As Long
        Dim dwPosi As Long
        dwNumber = .dwSubKeyNumber
        If (dwNumber = 0) Then GoTo ExitFunc_
        ReDim HashRec(1 To dwNumber)
        st = CopyMemory(VarPtr(dwPosi), VarPtr(.dwOffsetOfSubKeyLfRecords) - VarPtr(NkRec) + pNkRecord, LenB(dwPosi))
        If (Not st) Then GoTo ExitFunc_
        dwPosi = dwPosi + GlobalOffset + m_pHive
        st = CopyMemory(VarPtr(LfRec), dwPosi, LenB(LfRec))
        If (Not st) Then GoTo ExitFunc_
        dwPosi = dwPosi + VarPtr(LfRec.dwHashRecord(1)) - VarPtr(LfRec)
        st = CopyMemory(VarPtr(HashRec(LBound(HashRec))), dwPosi, dwNumber * LenB(HashRec(LBound(HashRec))))
        If (Not st) Then GoTo ExitFunc_
    End With
   
    'calc NK record address
    Dim I As Long
    ReDim pNkRec(1 To dwNumber)
    For I = LBound(pNkRec) To UBound(pNkRec)
        pNkRec(I) = HashRec(I).dwRecordOffset + GlobalOffset + m_pHive
    Next
FinishFunc_:
    GetSubKeyListNkPointers = pNkRec
    Exit Function
ExitFunc_:
    m_RaisedErr = True
    'Resume FinishFunc_
End Function

'get NK record pointer by HASH record
Public Function GetKeyNkRecordPointer(ByVal pHashRecord As Long) As Long
    Dim ret As Long
    Dim HashRec As HashRecord
    Dim st As Boolean
    st = CopyMemory(VarPtr(HashRec), pHashRecord, LenB(HashRec))
    If (Not st) Then GoTo ExitFunc_
    With HashRec
        ret = .dwRecordOffset + GlobalOffset + m_pHive
    End With
FinishFunc_:
    GetKeyNkRecordPointer = ret
    Exit Function
ExitFunc_:
    m_RaisedErr = True
    'Resume FinishFunc_
End Function

'get key value by VK record
Public Function GetValueDataByPointer(ByVal pVkRecord As Long, ByVal dwValueType As DataTypes) As Byte()
    Dim ret() As Byte
    Dim VkRec As VkRecord
    Dim lOffset As Long
    Dim st As Boolean
    ReDim ret(1 To 1)
    st = CopyMemory(VarPtr(VkRec), pVkRecord, LenB(VkRec))
    If (Not st) Then ReDim ret(1 To 1): GoTo ExitFunc_
    With VkRec
        lOffset = .dwDataOffset + GlobalOffset + m_pHive
        Select Case dwValueType
            Case REG_DWORD
                ReDim ret(1 To LenB(.dwDataOffset))
                    st = CopyMemory(VarPtr(ret(LBound(ret))), VarPtr(.dwDataOffset), UBound(ret) - LBound(ret) + 1)
            Case REG_SZ
                If (.dwDataOffset = 0) Then GoTo ExitFunc_
                ReDim ret(1 To .dwDataLength)
                    st = CopyMemory(VarPtr(ret(LBound(ret))), lOffset, UBound(ret) - LBound(ret) + 1)
            Case Else
                'unsupportted.
                If (.dwDataOffset = 0) Then GoTo ExitFunc_
                ReDim ret(1 To .dwDataLength)
                    st = CopyMemory(VarPtr(ret(LBound(ret))), lOffset, UBound(ret) - LBound(ret) + 1)

        End Select
               
        'If (.dwDataOffset < 5) Then GoTo ExitFunc_
        'lOffset = .dwDataOffset + GlobalOffset + m_pHive
        'ReDim ret(1 To .dwDataLength)
        'st = CopyMemory(VarPtr(ret(LBound(ret))), lOffset, .dwDataLength)
        'If (Not st) Then ReDim ret(1 To 1): GoTo ExitFunc_
    End With
FinishFunc_:
    GetValueDataByPointer = ret
    Exit Function
ExitFunc_:
    m_RaisedErr = True
    'Resume FinishFunc_
End Function

'get key value by VK record
Public Function GetValueTypeByPointer(ByVal pVkRecord As Long) As DataTypes
    Dim VkRec As VkRecord
    Dim st As Boolean
    Dim ret As DataTypes
    ret = REG_UNKNOWN
    st = CopyMemory(VarPtr(VkRec), pVkRecord, LenB(VkRec))
    If (Not st) Then GoTo ExitFunc_
    With VkRec
        ret = .dwValueType
    End With
FinishFunc_:
    GetValueTypeByPointer = ret
    Exit Function
ExitFunc_:
    m_RaisedErr = True
    'Resume FinishFunc_
End Function

Public Sub ClearError()
    m_RaisedErr = False
End Sub

'return TRUE if the operation is successful
Public Function NT_SUCCESS(ByVal Status As Long) As Boolean
    NT_SUCCESS = (Status >= 0)
End Function

'copy data
Public Function CopyMemory(ByVal pDst As Long, ByVal pSrc As Long, ByVal nLength As Long) As Boolean
    Dim st As Long
    st = SafeCopyMemory(ZwGetCurrentProcess, pDst, pSrc, nLength, ByVal 0)
    CopyMemory = NT_SUCCESS(st)
End Function[/language]

页: [1]
© 1999-2008 EvilOctal Security Team