Sign in to follow this  
Followers 0
sulfurious

REG_BINARY, Little Endian octet string

1 post in this topic

Hi.

I am working on a little thing, and ran into a large problem. When implementing ipSec on XP Pro SP2 or SP3, the mmc snap-in is not that great to work with. One can use the command line tool ipseccmd.exe to make static or dynamic rules. In interest of making my own interface to ipSec, I am reading the registry to see what rules are in place. Unfortunately, ipseccmd implemented filters/rules carry a description of text2pol{ GUID }, nothing that I can find changes that. So let's start with a reg edit to get rid of any default values. The default values can be replaced easily from the snap-in

Windows Registry Editor Version 5.00

[-HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\IPSec\Policy\Local]

[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\IPSec\Policy\Local]

Now we use ipseccmd.exe to simply make a couple static rules

:: Make a simple policy to block everything
ipseccmd -w REG -p "Block All" -r "Block All" -f *:*:*+*:*:* -n BLOCK

:: Make a simple policy to allow ONLY LAN activity
ipseccmd -w REG -p "LAN Only" -r "Block All" -f *:*:*+*:*:* -n BLOCK
ipseccmd -w REG -p "LAN Only" -r "Allow LAN" -f 0:*:*+192.168.1.*:*:* -n PASS

and the link to the resource kit that contains ipseccmd

resource kit

Of course the ipsec service must be running.

Now, if you assign one of the two simple rules, you can type in command prompt ipseccmd.exe show filters. The results will show the text2pol{ GUID } and the parameters for the rules, such as address:port:protocol etc. This is the only place short of the snap-in that you can view this data to my knowledge. Well, almost. Seems the snap-in gets it from some ipsecpol database file. I don't know how to get that, whether through wmi or else. But I can get the binary registry key for the ipsecFilter{} value in question, which does contain the text2pol{ GUID } value. So in a sort, I can look at the output from ipseccmd show filters results, and then reference the registry to find which 'rule' this text2pol{} applies to.

However, on closer examination at MSDN, the ipsecData reg value contains all the data I need. However, it is a complicated value. Stated as being implicitly Little Endian. The document shows every segment and byte value etc. I have enough knowledge to understand the BOM on a document, and that Little Endian is transposed.

So what I don't completely understand in how to strip apart this REG_BINARY value. You can use _HexToString on it, and you get the text2pol{value}, but not the underlying data such as address:port:protocol which lies within it. Also I don't get how to read exactly a byte string like this as far as transposing Endian. If a segment exists as this B1 B2 B3 B4, depending on the byte length you would read it as B2 B1 B4 B3 or B4 B3 B2 B1.

Here is sample code that retrieves the byte array from wmi StdRegProv. A vbs example shows to take the resulting array and concatenate the dec values together. The function "GetBinaryValue" returns an array converted to dec evidentily. I handled the concatenation to make the single value 0 or double 32 become 000 or 032 to keep the order correct. I also returned the hex value that RegRead() returns.

#include <array.au3>
#include <file.au3>
Const $HKEY_CLASSES_ROOT = 0x80000000
Const $HKEY_CURRENT_USER = 0x80000001
Const $HKEY_LOCAL_MACHINE = 0x80000002
Const $HKEY_USERS = 0x80000003
Const $HKEY_PERFORMANCE_DATA = 0x80000004
Const $HKEY_CURRENT_CONFIG = 0x80000005
Const $HKEY_DYN_DATA = 0x80000006
Global $FileOut = FileOpen(@DesktopDir & '\byteArray.txt',1)
Global $oReg = ObjGet("winmgmts:{impersonationLevel=impersonate}!\\" & @ComputerName & "\root\default:StdRegProv")
Global $regParent = 'SOFTWARE\Policies\Microsoft\Windows\IPSec\Policy\Local'

_getIpsecData()
FileClose($FileOut)
Func _getIpsecData()
; get the ipsecFilter subkeys into array
    Local $a_subkeys = _RegEnumKeys('.','HKLM',$regParent), $x, $y, $a_keys
    If Not @error Then
        _ArrayDisplay($a_subkeys,'The list of parent keys')
        
        For $x = 0 To UBound($a_subkeys) - 1
;~          ipsecData : REG_BINARY strictly Little Endian
;~              http://msdn.microsoft.com/en-us/library/cc232443(PROT.10).aspx
            If StringInStr($a_subkeys[$x],'ipsecFilter{') Then; get only ipsecFilter key values
                FileWriteLine($FileOut,$a_subkeys[$x]); write the ipsecFilter{ GUID }
                $iData = _RegReadBinary($a_subkeys[$x],'ipsecData'); read the REG_BINARY key into array
                FileWriteLine($FileOut,RegRead('HKLM\' & $regParent & '\' & $a_subkeys[$x],'ipsecData')); write the hex value of the key
                FileWriteLine($FileOut,'')
            EndIf
            
            _ArrayDisplay($iData,'reg binary values')
        Next
    EndIf
EndFunc

#Region
;===============================================================================
;
; Description:    _RegEnumValues
; Parameter(s):  computer name  - string of remote computer or "." for current computer
;                    registry tree  - contains the sSubKeyName path
;                    sub key name   - A path that contains the named values to be enumerated
; Requirement:    None
; Return Value(s):  Returns a multi-dimensional array ([0] = key name, [1] = key value, [2] = key type)
;                    If an error occurs @error is set and 0 is returned
; User CallTip:  _RegEnumValues(computer name, registry tree, sub key name) Enumerates the values of the given subkey
; Author(s):            Gary Frost (custompcs at charter dot net)
; Note(s):      A registry tree can be one of:
;                       "HKEY_LOCAL_MACHINE" ("HKLM")
;                       "HKEY_USERS" ("HKU")
;                       "HKEY_CURRENT_USER" ("HKCU")
;                       "HKEY_CLASSES_ROOT" ("HKCR")
;                       "HKEY_CURRENT_CONFIG" ("HKCC")
;
;===============================================================================
Func _RegEnumValues($strComputer, $s_hDefKey, $strKeyPath)
    Local $hDefKey, $x
;~   Enum $HKEY_CLASSES_ROOT = 0x80000000, $HKEY_CURRENT_USER, $HKEY_LOCAL_MACHINE, $HKEY_USERS, $HKEY_CURRENT_CONFIG = 0x80000005
    If $strComputer = "." Then $strComputer = @ComputerName
    Switch StringUpper($s_hDefKey)
        Case "HKEY_LOCAL_MACHINE", "HKLM"
            $hDefKey = $HKEY_LOCAL_MACHINE
        Case "HKEY_USERS", "HKU"
            $hDefKey = $HKEY_USERS
        Case "HKEY_CURRENT_USER", "HKCU"
            $hDefKey = $HKEY_CURRENT_USER
        Case "HKEY_CLASSES_ROOT", "HKCR"
            $hDefKey = $HKEY_CLASSES_ROOT
        Case "HKEY_CURRENT_CONFIG", "HKCC"
            $hDefKey = $HKEY_CURRENT_CONFIG
        Case Else
            Return SetError(1, 1, 0)
    EndSwitch
   
    Local $a_Type[8] = [7, "REG_SZ", "REG_EXPAND_SZ", "REG_BINARY", "REG_DWORD", "", "", "REG_MULTI_SZ"]
    Local $arrValueNames, $arrValueTypes
;~   Local $oReg = ObjGet("winmgmts:{impersonationLevel=impersonate}!\\" & $strComputer & "\root\default:StdRegProv")
    $oReg.EnumValues ($hDefKey, $strKeyPath, $arrValueNames, $arrValueTypes)
    If Not IsArray($arrValueNames) Then Return SetError(2, 2, 0)
    Local $a_ret[UBound($arrValueNames) ][3]
    For $x = 0 To UBound($arrValueNames) - 1
        $a_ret[$x][0] = $arrValueNames[$x]
        $a_ret[$x][1] = RegRead($s_hDefKey & "\" & $strKeyPath, $arrValueNames[$x])
        $a_ret[$x][2] = $a_Type[$arrValueTypes[$x]]
    Next
    Return $a_ret
EndFunc  ;==>_RegEnumValues

; Fixed registry keys

;===============================================================================
;
; Description:    _RegEnumKeys
; Parameter(s):  computer name  - string of remote computer or "." for current computer
;                    registry tree  - contains the sSubKeyName path
;                    sub key name   - A path that contains the named values to be enumerated
; Requirement:    None
; Return Value(s):  Returns An array of subkey strings
;                    If an error occurs @error is set and 0 is returned
; User CallTip:  _RegEnumKeys(computer name, registry tree, sub key name) Enumerates the subkeys for a path
; Author(s):            Gary Frost (custompcs at charter dot net)
; Note(s):      A registry tree can be one of:
;                       "HKEY_LOCAL_MACHINE" ("HKLM")
;                       "HKEY_USERS" ("HKU")
;                       "HKEY_CURRENT_USER" ("HKCU")
;                       "HKEY_CLASSES_ROOT" ("HKCR")
;                       "HKEY_CURRENT_CONFIG" ("HKCC")
;
;===============================================================================
Func _RegEnumKeys($strComputer, $s_hDefKey, $strKeyPath)
    Local $hDefKey, $x
;~   Enum $HKEY_CLASSES_ROOT = 0x80000000, $HKEY_CURRENT_USER, $HKEY_LOCAL_MACHINE, $HKEY_USERS, $HKEY_CURRENT_CONFIG = 0x80000005
    If $strComputer = "." Then $strComputer = @ComputerName
    Switch StringUpper($s_hDefKey)
        Case "HKEY_LOCAL_MACHINE", "HKLM"
            $hDefKey = $HKEY_LOCAL_MACHINE
        Case "HKEY_USERS", "HKU"
            $hDefKey = $HKEY_USERS
        Case "HKEY_CURRENT_USER", "HKCU"
            $hDefKey = $HKEY_CURRENT_USER
        Case "HKEY_CLASSES_ROOT", "HKCR"
            $hDefKey = $HKEY_CLASSES_ROOT
        Case "HKEY_CURRENT_CONFIG", "HKCC"
            $hDefKey = $HKEY_CURRENT_CONFIG
        Case Else
            Return SetError(1, 1, 0)
    EndSwitch
   
    Local $arrValueNames
;~  Local $oReg = ObjGet("winmgmts:{impersonationLevel=impersonate}!\\" & $strComputer & "\root\default:StdRegProv")
    $oReg.EnumKey ($hDefKey, $strKeyPath, $arrValueNames)
    If Not IsArray($arrValueNames) Then Return SetError(2, 2, 0)
    Return $arrValueNames
EndFunc  ;==>_RegEnumKeys

Func _RegReadBinary($vKeyPath,$vKeyName)
;~   If $strComputer = "." Then $strComputer = @ComputerName
;~   Switch StringUpper($s_hDefKey)
;~       Case "HKEY_LOCAL_MACHINE", "HKLM"
;~           $hDefKey = $HKEY_LOCAL_MACHINE
;~       Case "HKEY_USERS", "HKU"
;~           $hDefKey = $HKEY_USERS
;~       Case "HKEY_CURRENT_USER", "HKCU"
;~           $hDefKey = $HKEY_CURRENT_USER
;~       Case "HKEY_CLASSES_ROOT", "HKCR"
;~           $hDefKey = $HKEY_CLASSES_ROOT
;~       Case "HKEY_CURRENT_CONFIG", "HKCC"
;~           $hDefKey = $HKEY_CURRENT_CONFIG
;~       Case Else
;~           Return SetError(1, 1, 0)
;~   EndSwitch
    Local $sValue, $sResult, $max
    Local $max, $red = '',$cnt = 0,$crr
    $max = $oReg.GetBinaryValue ($HKEY_LOCAL_MACHINE,$regParent & '\' & $vKeyPath,$vKeyName,$sValue)
;~  http://msdn.microsoft.com/en-us/library/aa390440(VS.85).aspx

;~  MsgBox(0,'max',$max); return value 0 is OK.
    _ArrayDisplay($sValue,'byte array for binary reg key')
    For $i = 0 To UBound($sValue) - 1
        If StringLen($sValue[$i]) = 1 Then; pad values to be 3 chars total length each
            $sValue[$i] = '00' & $sValue[$i]
        ElseIf StringLen($sValue[$i]) = 2 Then
            $sValue[$i] = '0' & $sValue[$i]
        EndIf
        FileWriteLine($FileOut,$i & ' ___  ' & $sValue[$i]); write out the array 
        $sResult&= $sValue[$i]
    Next
    FileWriteLine($FileOut,$sResult); write out the concatenated array

EndFunc; ->> end RegReadBinary

Func _DebugPrint($s_text)
    $s_text = StringReplace($s_text, @LF, @LF & "-->")
    ConsoleWrite("!===========================================================" & @LF & _
            "!===========================================================" & @LF & _
            "-->" & $s_text & @LF & _
            "!===========================================================" & @LF)
EndFunc  ;==>_DebugPrint
 #EndRegion

Notice in the script there are links to the MSDN pages regarding the REG_BINARY key to ipsecData{} and for the GetBinaryValue of the StdRegProv class.

Is there anyone here who can help me understand that tech sheet for the ipsecData value? It is a bit cryptic. I understand I will be converting different segments of the binary key value, and I think that depending on the byte lenght will be doing some funky stuff shifting because of it being Little Endian. But I don't completely understand how to do it all.

To make matters even worse, if you use ipseccmd to make static rules, as I have above, most references state that you add a common rule, such as 'Block All' to EACH static rule. So that if you looked at the policies in the snap-in, you would see a block all for each policy. This seems to be clutter to me, so I have made one rule 'name' and then any policy also includes that rule name for creation, leaving a much cleaner 'look' to the snap-in when you look at it.

However, this appears to create some kind of anomaly wtihin the ipsecData keys. The simple policies like I have above don't show it, but say you had 4 policies being created with ipseccmd. Allow All, Block All, Lan Only and Firewall. Each of these had a rule called 'Block All' (and each needs this rule to perform properly), you would see some ipsecData values contain more than one text2pola{GUID} value.

The goal here is to create an interface using AutoIt to the ipsec policies. Quicker and less cluttered than the snap-in. It is possible already to assign/unassign each policy with ipseccmd. It is also easy to set a flag value in another regkey to 'check/ucheck' each rule on a polciy, so you can basically enable or disable the 'rules' with each policy. However, without the interface to the addres:port:protocol, I am afraid it will be pretty crippled. I already piped the output of 'show filters' and parsed it, but still, converting the binary value will show it to contain more info that the parsed output.

Does anyone care to help here?

Thanks.

Sul.

Share this post


Link to post
Share on other sites



Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0