11

我有一个问题,我需要能够拥有一个已编译的 exe ( .net 3.5 c# ),我将复制它以分发,例如在发送 exe 之前需要更改密钥。

每次需要新的 exe 时我都无法编译。这是一个瘦客户端,将用作注册过程的一部分。

是否可以使用空白值向资源文件添加一个条目,然后当请求进入时,让另一个应用程序获取空白的默认瘦客户端,复制它,用所需的数据填充空白值。

如果是怎么办?如果没有,你有什么想法吗?几天来,我一直在摸不着头脑,并且由于我需要工作的界限而受到限制。

我的另一个想法是将值注入一个方法,我什至不知道我会如何尝试。

谢谢。

4

6 回答 6

6

将程序集转换为 IL,进行文本搜索和替换,再次将 IL 重新编译为程序集。使用.NET SDK 中的标准工具

于 2010-04-30T07:21:01.907 回答
5

不要将密钥嵌入程序集中,而是将其放入 app.config 文件(或应用程序随附的其他文件)中,如果密钥不存在且无效,则阻止您的应用程序运行。为了保护它不被用户修改,还要在配置文件中添加一个 RSA 签名。

此代码可用于生成包含您的密钥的 XML。

public static void Main()
{
   Console.WriteLine(GenerateKey());
}

public static Byte[] Transform(Byte[] bytes, ICryptoTransform xform)
{
   using (System.IO.MemoryStream stream = new System.IO.MemoryStream())
   {
      using (CryptoStream cstream = new CryptoStream(stream, xform, CryptoStreamMode.Write))
      {
         cstream.Write(bytes, 0, bytes.Length);
         cstream.Close();
         stream.Close();
         return stream.ToArray();
      }
   }
}

public static string GenerateKey()
{
   RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
   // This is the private key and should never be shared.
   // Generate your own with RSA.Create().ToXmlString(true).
   String rsaPrivateKey = "<RSAKeyValue><Modulus>uPCow37yEzlKQXgbqO9E3enSOXY1MCQB4TMbOZyk9eXmc7kuiCMhJRbrwild0LGO8KE3zci9ETBWVVSJEqUqwtZyfUjvWOLHrf5EmzribtSU2e2hlsNoB2Mu11M0SaGd3qZfYcs2gnEnljfvkDAbCyJhUlxmHeI+35w/nqSCjCk=</Modulus><Exponent>AQAB</Exponent><P>4SMSdNcOP0qAIoT2qzODgyl5yu9RubpIU3sSqky+85ZqJHXLUDjlgqAZvT71ROexJ4tMfMOgSWezHQwKWpz3sw==</P><Q>0krr7cmorhWgwCDG8jmzLMo2jafAy6tQout+1hU0bBKAQaPTGGogPB3hTnFIr84kHcRalCksI6jk4Xx/hiw+sw==</Q><DP>DtR9mb60zIx+xkdV7E8XYaNwx2JeUsqniwA3aYpmpasJ0N8FhoJI9ALRzzp/c4uDiuRNJIbKXyt6i/ZIFFH0qw==</DP><DQ>mGCxlBwLnhkN4ind/qbQriPYY8yqZuo8A9Ggln/G/IhrZyTOUWKU+Pqtx6lOghVdFjSxbapn0W8QalNMFGz7AQ==</DQ><InverseQ>WDYfqefukDvMhPHqS8EBFJFpls/pB1gKsEmTwbJu9fBxN4fZfUFPuTnCIJsrEsnyRfeNTAUFYl3hhlRYZo5GiQ==</InverseQ><D>qB8WvAmWFMW67EM8mdlReI7L7jK4bVf+YXOtJzVwfJ2PXtoUI+wTgH0Su0IRp9sR/0v/x9HZlluj0BR2O33snQCxYI8LIo5NoWhfhkVSv0QFQiDcG5Wnbizz7w2U6pcxEC2xfcoKG4yxFkAmHCIkgs/B9T86PUPSW4ZTXcwDmqU=</D></RSAKeyValue>";

   rsa.FromXmlString(rsaPrivateKey);
   String signedData = "<SignedData><Key>Insert your key here</Key></SignedData>";
   Byte[] licenseData = System.Text.Encoding.UTF8.GetBytes(signedData);
   Byte[] sigBytes = rsa.SignData(licenseData, new SHA1CryptoServiceProvider());
   String sigText = System.Text.Encoding.UTF8.GetString(Transform(sigBytes, new ToBase64Transform()));
   System.Text.StringBuilder sb = new StringBuilder();
   using (System.Xml.XmlWriter xw = System.Xml.XmlTextWriter.Create(sb))
   {
      xw.WriteStartElement("License");
      xw.WriteRaw(signedData);
      xw.WriteElementString("Signature", sigText);
      xw.WriteEndElement();
   }
   return sb.ToString();
}

此代码的示例输出:

<?xml version="1.0" encoding="utf-16"?>
<License>
  <SignedData>
    <Key>Insert your key here</Key>
  </SignedData>
  <Signature>cgpmyqaDlHFetCZbm/zo14NEcBFZWaQpyHXViuDa3d99AQ5Dw5Ya8C9WCHbTiGfRvaP4nVGyI+ezAAKj287dhHi7l5fQAggUmh9xTfDZ0slRtvYD/wISCcHfYkEhofXUFQKFNItkM9PnOTExZvo75pYPORkvKBF2UpOIIFvEIU=</Signature>
</License>

然后你可以使用这样的代码来验证它。您永远不必分发私钥:

public static Boolean CheckLicenseSignature(String licXml)
{
   try
   {
      System.Xml.XmlDocument xd = new System.Xml.XmlDocument();
      xd.LoadXml(licXml);
      String licSig = xd.SelectSingleNode("/License/Signature").InnerText;
      RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
      String rsaPublicKey = "<RSAKeyValue><Modulus>uPCow37yEzlKQXgbqO9E3enSOXY1MCQB4TMbOZyk9eXmc7kuiCMhJRbrwild0LGO8KE3zci9ETBWVVSJEqUqwtZyfUjvWOLHrf5EmzribtSU2e2hlsNoB2Mu11M0SaGd3qZfYcs2gnEnljfvkDAbCyJhUlxmHeI+35w/nqSCjCk=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";
      rsa.FromXmlString(rsaPublicKey);
      Byte[] licenseData = System.Text.Encoding.UTF8.GetBytes(xd.SelectSingleNode("/License/SignedData").OuterXml);
      return rsa.VerifyData(licenseData, new SHA1CryptoServiceProvider(), Transform(System.Text.Encoding.UTF8.GetBytes(licSig), new FromBase64Transform()));
   }
   catch (System.Xml.XmlException ex)
   {
      return false;
   }
   catch (InvalidOperationException ex)
   {
      return false;
   }
}
于 2010-04-30T13:45:15.683 回答
1

从 .NET 代码本身的能力来看,我不确定这是否可行。但是可以动态生成一个 .NET DLL,其中包含一些可以从主应用程序引用的密钥。也就是说,如果您不介意分发中的第二个文件。

或者,如果您不介意使用 Ildasm 反汇编 .exe,更改密钥,然后使用 Ilasm 重新组装,那么您可以做一些事情来自动化。

于 2010-04-30T07:19:08.763 回答
0

我认为如果不重新编译您的 .exe 并将密钥嵌入到所述 .exe 中,您将无法逃脱。正如 Daniel Earwicker 在他的回复https://stackoverflow.com/a/2742902/2358659中建议的那样,编译过程可以通过使用 ildasm.exe 和 ilasm.exe 实现自动化

如果将来有其他人偶然发现该主题,我想对此进行扩展。

由于我糟糕的源代码版本控制习惯,我最近遇到了类似的问题。简而言之,我有一个可执行文件,它应该通过引用它的 ID 将一些数据写入 Google 电子表格。可执行文件发布很久之后,来自不同团队的另一个请求使用该工具,但它必须将相同的信息写入不同的电子表格,以保持两个团队的数据分开。当时我没有原始源代码,因此我无法更改保存原始电子表格 ID 的静态变量。我所做的如下:

  1. 使用 CMD.exe →调用 "C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools\ildasm.exe" "myApplication.exe" /out="myApplication.il"
  2. 使用 Notepad++ → 在myApplication.il文件中查找原始 ID 并将其替换为新 ID 。也可以通过编写自己的 C# 应用程序来自动执行此操作,或使用PowerShell,或使用 vb/j-script 或使用其他一些现成的查找和替换工具,如FART(使用 CMD.exe →调用fart.exe myApplication.il "OldKey" "NewKey" )
  3. 使用 CMD.exe →调用 "C:\Windows\Microsoft.NET\Framework\v4.0.30319\ilasm.exe" "myApplication.il" /res="myApplication.res" /key="myApplicationKeyFile.snk"

如您所见,所有这些步骤都可以放入一个 .bat 文件中,该文件将“NewKey”作为输入并生成嵌入了NewKey的新 .exe 。

我希望这会有所帮助。

于 2017-03-17T15:26:48.247 回答
0

公认的答案是垃圾! 我已经成功地做到了。更容易

只需将需要密钥的基本应用程序(.net)放在带有“XXXXXXXXXXXXXXX”的字符串资源的地方(超出您的需要)

.Net 资源通常保留在代码的顶部,因此在我的例子中,您会发现它们快速跳过前 100,000 个字节。

然后,您只需阅读并查找那些 XXXXXX。当您找到它们时,您将它们替换为真正的 API 密钥,并将其余的 X 替换为您刚刚在代码中修剪掉的空格。这就是答案。它有效并且运作良好。

        ApiToken at = new ApiToken(UserId, SelectedCID);
        at.MakeToken();

        byte[] app = System.IO.File.ReadAllBytes(Path.Combine(AppDomain.CurrentDomain.GetData("DataDirectory").ToString(), "notkeyedapp.exe"));

        for (int i = 100000; i < app.Length; i++)
        {
            if (app[i] == 0x58 && app[i + 1] == 0x58 && app[i + 2] == 0x58)
            {
                for (int j = 0; j < 128; j++)
                {
                    if (at.Token.Length >= j + 1)
                        app[i + j] = System.Text.Encoding.ASCII.GetBytes(at.Token[j].ToString())[0];
                    else
                        app[i + j] = 0x20;

                }
                break;
            }
        }
        string filename = "SoftwareProduct for - " + BaseModel.CompanyName.Replace(".", "") + ".exe";
        return File(app, System.Net.Mime.MediaTypeNames.Application.Octet, filename);
于 2021-11-05T00:01:07.843 回答
-1

我想到了什么,但还没有尝试过:在你的程序中创建一个默认字符串,例如

static public string regGuid = "yourguidhere";

然后,使用任何像样的十六进制编辑器搜索已编译的 EXE。如果找到该字符串,请将其替换为另一个测试。如果你仍然可以执行程序,你可以尝试自动化这个过程,瞧!这个给你。

于 2010-04-30T06:10:40.270 回答