Parsing Registry.pol (Local Group Policy) / Get numeric ASCII values of characters in a string?

I’m reading a file (specifically a Registry.pol file), which is a UNICODE file containing both strings and numeric data.

Where I’m having trouble, is converting some of the numeric data back into an integer. For instance, I have a portion of the file that contains the bytes 0x0F27. When I output this as a string value in BigFix, I get

%0f'

The 0F byte shows up as it’s percent-encoded value, while the 27 byte is displayed as a single quote. What I want to find is the “ASCII values” of the characters in the string, as I want to check in Relevance for the given integer value in a registry key. In other languages I could use something like Cint() or Ascii(), for instance the character “A” has an ASCII value of 65.

I can convert the %0f to an integer via hexadecimal integer (following text of first “%25” of it) for the “%0f” portion, but haven’t found a way to handle the byte value for 0x27 that Relevance is translating as the single quote character.

I’ve done a fair bit of digging but I can’t find a property or cast for a string or character to return the corresponding ASCII integer value. Can anyone help with that?

As an update, I’ve found something potentially related:

https://www.ibm.com/developerworks/community/forums/html/topic?id=77777777-0000-0000-0000-000014753096&ps=100000

concatenation of characters ( bytes (( 72 + (it * 2) ) of ( positions  whose (it < ((

byte (

byte 20 of it) of files 
"<filename>.JOB" of folder 
"tasks" of windows folder)) - 1 ) of ( 
"..............................................................." & 
"................................................................" & 
"................................................................" & 
"................................................................" ) ) ) of files 
"<filename>.JOB" of folder 
"tasks" of windows folder)

I’m not yet sure how I’ll use this to split up a Registry.pol file into its individual registry keys and values, but I feel like that’s on the right track and might nudge someone’s memory.

I also think we can create the string of “.” dynamically to create a string of arbitrary size to use as an index of positions:

q: concatenation of "." of integers in (0, 255)
A: ................................................................................................................................................................................................................................................................



q:  concatenation  of "." of (integers in (0, size of it)) of file "c:\temp\hi.txt"
A: .................................................
T: 0.160 ms
I: singular string

And there’s a reference on the Registry.pol file format at https://msdn.microsoft.com/en-us/library/windows/desktop/aa374407(v=vs.85).aspx

Unfortunately there doesn’t seem to be a good way to delimit the file. My earlier attempts were to concatenate substrings separated by “%00” of the file lines…but “%00” is also used as a valid value frequently within the file. We also can’t assume that the “;” character is always a delimiter between [key;value;type;size;data], because if the value is one of the “**DelValues” or “**DeleteKeys” directives, a semicolon-delimited list of key/value names follows. And I’m not sure how safe it is to use “[” and “]” to separate directives, I’m not sure how a square-bracket would be escaped if it’s part of the data.

Some progress on parsing Registry.pol. As a reminder, this is UNICODE text (2-byte characters) with embedded binary values.
Explanation:

  1. Gets the lines out of Registry.pol and concatenates them together.
    1a) The file should “really” be one line. But BigFix splits it up into lines at 2,048 characters each, so those have to be concatenated back together. BigFix also splits if one of those binary values happens to be decimal 10, i.e. 0x0a, which is also the Newline character. So if one the line length is 2048 and was arbitrarily split by the “lines of file” inspector, just put it back together; but if the length is less than 2048, the inspector found a “%0a” which was removed and needs to be put back. ** Note - I don’t have a good way to handle cases where %0d%0a were both present and both were stripped out, but I haven’t encountered that in practice and I will ignore it for now.

  2. Split into substrings bounded by %00[ and %00], the two-byte characters for “[” and “]”. These are each Registry setting found in reg.pol, equivalent to each “line”

  3. Split each “line” into items, splitting at semicolons ( “%00;” ) - where item 0 is the Key Name, item 1 is the Value Name, item 2 is the Type, and item 3 is the Data. Note that I skip the third field - which corresponds to “size of data field”, because I can’t find an interesting use for that.

  4. Items 0 and 1 are String, so take out the UNICODE Nulls with "concatenation of substrings separated by “%00”.

  5. Item 3 may be a string, depending on the Data Type. So if the Data type corresponds to “REG_SZ” or “REG_EXPAND_SZ”, then also remove the NULLs from item 3. If the Data type corresponds to “REG_MULTI_SZ”, then split the data on double-nulls (which are the delimiter between the multiple String values), remove the NULLs from the individual strings, then put them back together again with a NULL separator.
    5a) Otherwise, Item 3 is some kind of a binary value, so just keep it as-is.

    (concatenation of substrings separated by “%00” of item 0 of it & “;” & concatenation of substrings separated by “%00” of item 1 of it & “;” & item 2 of it & “;” & (if (it = “%00%01%00%00” or it="%00%02%00%00") of item 2 of it then concatenation of substrings separated by “%00” of item 3 of it else item 3 of it)) of (preceding text of first “%00%00%00;” of it, preceding text of first “%00%00%00;” of following text of first “%00%00%00;” of it, preceding text of first “%00;” of following text of first “%00%00%00;” of following text of first “%00%00%00;” of it , following text of first “%00;” of following text of first “%00;” of following text of first “%00%00%00;” of following text of first “%00%00%00;” of it) of ( substrings separated by “%00[” of substrings separated by “%00]” of concatenation of (if length of it = 2048 then it else it & “%0a”) of lines of files “Registry.pol” of folders “GroupPolicy\Machine” of native system folder) whose (it as trimmed string contains “;”)

    A: Software\Microsoft\Windows\CurrentVersion\Policies\CredUI;EnumerateAdministrators;%00%04%00%00;%00%00%00%00
    A: Software\Microsoft\Windows\CurrentVersion\Policies\Explorer;NoPublishingWizard;%00%04%00%00;%00%01%00%00
    A: Software\Microsoft\Windows\CurrentVersion\Policies\Explorer;NoDriveTypeAutoRun;%00%04%00%00;%00%ff%00%00
    A: Software\Microsoft\Windows\CurrentVersion\Policies\Explorer;NoWebServices;%00%04%00%00;%00%01%00%00
    A: Software\Microsoft\Windows\CurrentVersion\Policies\Explorer;UseDefaultTile;%00%04%00%00;%00%01%00%00
    A: Software\Microsoft\Windows\CurrentVersion\Policies\Ext;**del.NoFirsttimeprompt;%00%01%00%00;
    A: Software\Microsoft\Windows\CurrentVersion\Policies\System;DisableStartupSound;%00%04%00%00;%00%01%00%00

      A: Software\Policies\Google\Chrome;AuthServerWhitelist;%00%01%00%00;*.mycompany.com
    

    …
    T: 41.384 ms
    I: plural string

This lends itself to checking multiple Registry.pol entries in Fixlet Relevance; here, check that Local Group Policy is configured to turn on Windows Firewall and set the DefaultInboundAction to Drop:

q: (size of (set of ("Software\Policies\Microsoft\WindowsFirewall\PublicProfile;EnableFirewall;%00%04%00%00;%00%01%00%00";"Software\Policies\Microsoft\WindowsFirewall\PublicProfile;DefaultInboundAction;%00%04%00%00;%00%01%00%00") - it) = 0) of set of (concatenation of substrings separated by "%00" of item 0 of it & ";" & concatenation of substrings separated by "%00" of item 1 of it & ";" & item 2 of it & ";" & (if (it = "%00%01%00%00" or it="%00%02%00%00") of item 2 of it then concatenation of substrings separated by "%00" of item 3 of it else item 3 of it))  of (preceding text of first "%00%00%00;" of it, preceding text of first "%00%00%00;" of following text of first "%00%00%00;" of it, preceding text of first "%00;" of following text of first "%00%00%00;" of following text of first "%00%00%00;" of it , following text of first "%00;" of following text of first "%00;" of following text of first "%00%00%00;" of following text of first "%00%00%00;" of it) of ( substrings separated by "%00[" of substrings separated by "%00]" of concatenation of (if length of it = 2048 then it else it & "%0a") of lines of files "Registry.pol" of folders "GroupPolicy\Machine" of native system folder) whose (it as trimmed string contains ";")
A: True
T: 24.532 ms
I: singular boolean

Hi Jason,

Recently a colleague of mine informed me there is a new GPO tool that was released just this year. It has a really cool feature where it can read registry.pol files and spit out a plain text file (among other things). Check it out, it may save you some pain! :smile:

LGPO.exe v1.00 - Local Group Policy Object utility

LGPO.exe has four modes:

  • Import and apply policy settings;
  • Export local policy to a GPO backup;
  • Parse a registry.pol file to “LGPO text” format;
  • Build a registry.pol file from “LGPO text”.

To apply policy settings:

LGPO.exe command [...]

where "command" is one or more of the following (each of which can be repeated):

/g path               import settings from one or more GPO backups under "path"
/m path\registry.pol  import settings from registry.pol into machine config
/u path\registry.pol  import settings from registry.pol into user config
/s path\GptTmpl.inf   apply security template
/a[c] path\Audit.csv  apply advanced auditing settings; /ac to clear policy first
/t path\lgpo.txt      apply registry commands from LGPO text
/e <name>|<guid>      enable GP extension for local policy processing; specify a
                      GUID, or one of these names:
                      * "zone" for IE zone mapping extension
                      * "mitigation" for mitigation options, including font blocking
                      * "audit" for advanced audit policy configuration
/boot                 reboot after applying policies
/v                    verbose output
/q                    quiet output (no headers)

To create a GPO backup from local policy:

LGPO.exe /b path [/n GPO-name]

/b path               Create GPO backup in "path"
/n GPO-name           Optional GPO display name (use quotes if it contains spaces)

To parse a Registry.pol file to LGPO text (stdout):

LGPO.exe /parse [/q] {/m|/u} path\registry.pol

/m path\registry.pol  parse registry.pol as machine config commands
/u path\registry.pol  parse registry.pol as user config commands
/q                    quiet output (no headers)

To build a Registry.pol file from LGPO text:

LGPO.exe /r path\lgpo.txt /w path\registry.pol [/v]

/r path\lgpo.txt      Read input from LGPO text file
/w path\registry.pol  Write new registry.pol file
1 Like

Lol and now I’m reading the comments on that page and see some from you…

1 Like

Agreed, it’s a great tool, and it’s what I’m using to apply settings to the system now (I’m still migrating out of the older ImportRegPol and Apply_LGPO_Delta utilities).

The part I’ve been trying to solve on this thread is the relevance to check whether I need to run LGPO to update Local Group Policy, which is complicated by the mix of UNICODE text and binary data.

I think my post from earlier today is working, so I wanted to update my progress in case anyone finds this in a search; or in case someone can point me in a better direction.

1 Like

I do have some examples using the older tool that @JasonWalker mentions on bigfix.me : https://bigfix.me/fixlet/details/3747

I like this idea @JasonWalker … particularly for per-user items. I usually detect if a per-machine item is needed just by looking for the effect of it.

Prefetch for the new tool:

prefetch LGPO.zip sha1:4335992dfb3f6592eb37d39e521d0e9459112cb3 size:626964 http://blogs.technet.com/cfs-filesystemfile.ashx/__key/telligent-evolution-components-attachments/01-4062-00-00-03-65-94-11/LGPO.zip  sha256:c7623ad8b2d6b50f030d63b87c9864b1ec5221e2c0a4c2aac87e91426f294d97

Related:

So, I was happy with this Relevance until a few days ago. The Relevance works as expected, but tying up the Registry.pol file for read is a Bad Thing.

Now that I have a few hundred fixlets parsing data out of Registry.pol, I’m finding

  • BES clients report more slowly and spend more time reading Registry.pol. Increased number of fixlets and increased size of the registry.pol file are making it worse.
  • GPEDIT.MSC sometimes fails to appply changes; registry.pol could not be written while BigFix is reading it.
  • Group Policy Updates sometimes fail to apply because registry.pol is locked

I’m going to go in a different direction, have a task that uses LGPO to dump registry.pol to text, and then import that text to an alternate registry path that I can use to check fixlet relevance.

1 Like

If anyone’s still following this, I’ve just posted a Task at https://bigfix.me/fixlet/details/22387. Some caveats:

  1. It’s really better to look at the results of Group Policy settings in most cases, for instance by checking HKLM\Software\Policies for the output registry values.
  2. I wrote this to handle some particular cases - such as checking on Per-User Local GPO settings, and to check that Per-Machine Local GPO settings have been configured such that the right values stay in place after I remove Domain GPO
  3. This is a quite hackish way of handling it, so much so that I was hesitant to post it
  4. It uses LGPO v1. LGPO and ImportRegPol cannot handle REG_QWORD data types.
  5. A prerelease version of LGPO v2 is available, that should handle REG_QWORD and MLGPO settings better.
  6. The task has a manual download/caching required.
1 Like

This will filter out non-ascii chars:

Q: (concatenations of characters whose( exists (hexadecimal integer (it as hexadecimal) ) whose(it >= 32 AND it <= 126) of it ) of it) of ("abc%00";"%00123")
A: abc
A: 123
T: 0.266 ms

Related: Tip: Comparing really long REG_BINARY value (Sysmon Ruleset) - #2 by jgstew

Wow, really digging up some history here @jgstew :slight_smile:

In case anyone is seeing this thread, there is a later version that uses LGPO.exe v2, which handles the REG_QWORD type, as well as adding support for MLGPO and for removing values from the configuration.

1 Like

:slight_smile: I was searching around for related things and found this and the other.

Link?

…and here’s my example of using it https://bigfix.me/fixlet/details/24619

2 Likes