Search code examples
stringwindowsgohexregistry

Reverse function or library for os.Getenv()


I have a list of hexadecimal strings of REG_EXPAND_SZ type. Sample: reg,[HKEY_LOCAL_MACHINE\SOFTWAR\WOW6432Node], "Pathethic"=hex(2):43,00,3a,00,5c,00,57,00,49,00,4e,00,44,00,4f,00,57,00,53,00,\00,00 //Ignore the parsing and formatting part.

I need to convert it to the original string.

Expected output: %systemroot%

Actual output: C:\Windows

The problem is that when user initially run the command terminal expands it: reg add HKEY_LOCAL_MACHINE\SOFTWAR\WOW6432Node /v Pathetic /t REG_EXPAND_SZ /d "%systemroot%". Later the actual expanded string is used. For example: initial %systemroot% = actual C:\Windows. When I convert hex string to the regular one I get C:\Windows.

That is why I wonder if there any library or tool to get the key by providing value, meaning reverse. C:\Window :=os.Getenv(???).

package main

import (
    "encoding/hex"
    "fmt"
    "log"
    "os"
)

func CToGoString(b []byte) string {
    var buf []byte
    for _, c := range b {
        if c != 0 {
            buf = append(buf, c)
        }
    }
    return string(buf)
}

func main() {

    str := "43003a005c00570049004e0044004f00570053000000" //%systemroot%
    bs, err := hex.DecodeString(str)
    if err != nil {
        panic(err)
    }
    //s := CToGoString(bs)
    result := CToGoString(bs)
    fmt.Println(result)

    f, err := os.OpenFile("rollback.bat", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755)
    if err != nil {
        log.Fatal(err)
    }

    f.WriteString(result + "\n")

}

I have tried doing it manually but there are more expanded strings than I expected. Therefore, my program is limited. Please advise any solutions for this problem. `

func reverseEnvVar(value string) string {
    // Use os.ExpandEnv() to expand environment variables in the input string
    expanded := os.ExpandEnv(value)

    // Check if the expanded string matches a known environment variable value
    switch expanded {
    case os.Getenv("SystemRoot"):
        return "%systemroot%"
    case os.Getenv("ProgramFiles"):
        return "%programfiles%"
    case os.Getenv("ProgramFiles(x86)"):
        return "%programfiles(x86)%"
    case os.Getenv("AppData"):
        return "%appdata%"
    case os.Getenv("LocalAppData"):
        return "%localappdata%"
    case os.Getenv("UserProfile"):
        return "%userprofile%"
    case os.Getenv("TEMP"):
        return "%temp%"
    case os.Getenv("TMP"):
        return "%tmp%"
    default:
        // If the expanded string doesn't match a known environment variable value,
        // return the original input value
        return value
    }
}

Solution

  • I didn't find a library that takes C:\WINDOWS and gives %systemroot% but it can easily be implemented using os.Environ().

    Imports:

    import (
        "errors"
        "fmt"
        "os"
        "strings"
    )
    

    Hashmap for value -> array of keys:

    func createEnvHashMap() map[string][]string {
        envMap := make(map[string][]string)
    
        for _, env := range os.Environ() {
            pair := strings.SplitN(env, "=", 2)
            if len(pair) == 2 {
                key := fmt.Sprintf("%%%s%%", strings.ToLower(pair[0]))
                value := pair[1]
                envMap[value] = append(envMap[value], key)
            }
        }
    
        return envMap
    }
    

    Function to return the list of keys given the value:

    func getEnvKeysByValue(envMap map[string][]string, value string) ([]string, error) {
        keys, found := envMap[value]
        if !found {
            return nil, errors.New("no environment variable keys found for the value")
        }
        return keys, nil
    }
    

    Now you can use the getEnvKeysByValue() function in you main function:

    func main() {
    
        // Create a map of environment variables and their keys
        envMap := createEnvHashMap()
    
        // This value can be replaced with the result variable in your main() function
        value := "C:\\WINDOWS"
    
        // Get environment variable keys by value
        keys, err := getEnvKeysByValue(envMap, value)
        if err != nil {
            fmt.Println("Error:", err)
            return
        }
    
        fmt.Println("Environment variable keys:")
        for _, key := range keys {
            fmt.Println(key)
        }
    }
    

    Output:

    Environment variable keys:
    %systemroot%
    %windir%
    

    This way there won't be a need to write switch case statements manually.
    Make sure to call createEnvHashMap() only once and then call getEnvKeysByValue(envMap, value) as many times to get list of keys in O(1) time.