How to get hash value in user.config path?

情到浓时终转凉″ 提交于 2021-02-18 11:12:07

问题


I have installed .NET application. Its config location is

%AppData%\[CompanyName]\[ExeName]_Url_[hash]\[version]\user.config.

I need to get [hash] value from another application.

According with MSDN, user.config path template is

[c:\Documents and Settings]\[username]\[Local Settings]\Application Data\[companyname]\[appdomainname]_[eid]_[hash]\[version]

where [hash] is SHA1 hash of evidence (in my case eid=Url).

I noticed the following things:

  • [hash] changes with application installation path changes.
  • [hash] is always 32 characters long, so it is not hex representation of SHA1 which is 40 characters long. It seems that [hash]=base32(sha1([install path]))

I have tried different values for [install path]

c:\Program Files...
file:///c:\Program Files....
file:///c:\Program%20Files..., etc

but [hash] is always wrong.


回答1:


After going through the same problem of trying to calculate a program's user.config (local) path, i decided to complement @Gerard Sexton 's answer with a code snippet. The following method was done with the assumptions that the [eid] equals "Url" and [appdomainname] is the executable file name.

public string GetExeLocalAppDataUserConfigPath(string fullExePath)
{
    //E.g.: fullExePath = @"C:\Program Files (x86)\MyExeFolder\MyProgram.exe"
    var localAppDataPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);

    var versionInfo = FileVersionInfo.GetVersionInfo(fullExePath);
    var companyName = versionInfo.CompanyName;
    var exeName = versionInfo.OriginalFilename;// or 'AppDomain.CurrentDomain.FriendlyName'

    var assemblyName = AssemblyName.GetAssemblyName(fullExePath);
    var version = assemblyName.Version.ToString();

    var uri = "file:///" + fullExePath; //or 'assemblyName.CodeBase' if vshost (you can check the 'FriendlyName')
    uri = uri.ToUpperInvariant();

    var ms = new MemoryStream();
    var bSer = new BinaryFormatter();
    bSer.Serialize(ms, uri);
    ms.Position = 0;
    var sha1 = new SHA1CryptoServiceProvider();
    var hash = sha1.ComputeHash(ms);
    var hashstring = ToBase32StringSuitableForDirName(hash);

    //<AppData Local User Path> + <Company Name> + <[ExeName]_[eid]_[Hash]> + <Version> + user.config
    var userConfigLocalAppDataPath = Path.Combine(localAppDataPath, companyName, exeName+"_Url_"+hashstring, version, "user.config");

    return userConfigLocalAppDataPath;
}

And here is the ToBase32StringSuitableForDirName implementation found in Gerard's link!

static Char[] s_Base32Char = {
            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 
            'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
            'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 
            'y', 'z', '0', '1', '2', '3', '4', '5'};

private static string ToBase32StringSuitableForDirName(byte[] buff)
{
    StringBuilder sb = new StringBuilder();
    byte b0, b1, b2, b3, b4;
    int l, i;

    l = buff.Length;
    i = 0;

    // Create l chars using the last 5 bits of each byte.  
    // Consume 3 MSB bits 5 bytes at a time.

    do
    {
        b0 = (i < l) ? buff[i++] : (byte)0;
        b1 = (i < l) ? buff[i++] : (byte)0;
        b2 = (i < l) ? buff[i++] : (byte)0;
        b3 = (i < l) ? buff[i++] : (byte)0;
        b4 = (i < l) ? buff[i++] : (byte)0;

        // Consume the 5 Least significant bits of each byte
        sb.Append(s_Base32Char[b0 & 0x1F]);
        sb.Append(s_Base32Char[b1 & 0x1F]);
        sb.Append(s_Base32Char[b2 & 0x1F]);
        sb.Append(s_Base32Char[b3 & 0x1F]);
        sb.Append(s_Base32Char[b4 & 0x1F]);

        // Consume 3 MSB of b0, b1, MSB bits 6, 7 of b3, b4
        sb.Append(s_Base32Char[(
            ((b0 & 0xE0) >> 5) |
            ((b3 & 0x60) >> 2))]);

        sb.Append(s_Base32Char[(
            ((b1 & 0xE0) >> 5) |
            ((b4 & 0x60) >> 2))]);

        // Consume 3 MSB bits of b2, 1 MSB bit of b3, b4

        b2 >>= 5;

        if ((b3 & 0x80) != 0)
            b2 |= 0x08;
        if ((b4 & 0x80) != 0)
            b2 |= 0x10;

        sb.Append(s_Base32Char[b2]);

    } while (i < l);

    return sb.ToString();
}



回答2:


The advice for writing to a custom location is to provide your own SettingsProvider. The default settings provider is LocalFileSettingsProvider. So starting in LocalFileSettingsProvider, then following the code to ConfigurationManagerInternalFactory then ConfigurationManagerInternal then finally in ClientConfigPaths. In ClientConfigPaths:412 you can see how the hash is determined from the current AppDomain's evidence.

Basically, for Uri type, it takes the Uri in the form

file:///c:\app\app.exe

This uri is then converted to upper case (invariant), then SHA-1 hashed, then the hash is encoded in base32. I don't know if the base32 used in the referenced source is a standard base32 implementation or not (if one exists).



来源:https://stackoverflow.com/questions/24660121/how-to-get-hash-value-in-user-config-path

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!