Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get hash value in user.config path?

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.

like image 661
user3821449 Avatar asked Jul 09 '14 17:07

user3821449


2 Answers

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();
}
like image 192
F. ALA Avatar answered Oct 04 '22 10:10

F. ALA


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).

like image 20
Gerard Sexton Avatar answered Oct 04 '22 11:10

Gerard Sexton