修改C#编译的exe中的Emdeded字符串

发布于 2024-08-30 11:12:25 字数 311 浏览 8 评论 0原文

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

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

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

如果是的话怎么办?如果没有你有什么想法吗?我已经挠头好几天了,由于我需要工作的边界而受到限制。

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

谢谢。

I have an issue where I need to be able to have a compiled exe ( .net 3.5 c# ) that I will make copies of to distribute that will need to change a key for example before the exe is sent out.

I cannot compile each time a new exe is needed. This is a thin client that will be used as part of a registration process.

Is it possible to add a entry to a resource file with a blank value then when a request comes in have another application grab the blank default thin client, copy it, populate the blank value with the data needed.

If yes how? If no do you have any ideas? I have been scratching my head for a few days now and the limitation as due to the boundaries I am required to work in.

The other idea I has was to inject the value into a method, which I have no idea how I would even attempt that.

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

妥活 2024-09-06 11:12:25

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

Convert the assembly to IL, do a textual search and replace, recompile the IL to an assembly again. Use the standard tools from the .NET SDK.

梦冥 2024-09-06 11:12:25

不要将密钥嵌入到程序集中,而是将其放入 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;
   }
}

Instead of embedding the key in the assembly, put it in the app.config file (or another file delivered with the application) and prevent your application from running if the key is not present and valid. To protect it against modification by users, also add an RSA signature the config file.

This code could be used to generate XML containing your key.

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();
}

Example output from this code:

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

Then you can use code like this to verify it. You never have to distribute the private key:

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;
   }
}
述情 2024-09-06 11:12:25

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

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

From within the capability of the .NET code itself, I'm not sure if this is doable. But it is possible to dynamically generate a .NET DLL which contains some key that can be referred from the main application. That is, if you wouldn't mind a second file in the distribution.

Or if you don't mind to use Ildasm to disassemble the .exe, change the key, then use Ilasm to reassemble, then you can do something to automate that.

围归者 2024-09-06 11:12:25

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

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

由于我不良的源代码版本控制习惯,我最近面临类似的问题。简而言之,我有一个可执行文件,它应该通过引用它的 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"

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

我希望这有帮助。

I don't think You can get away without recompiling Your .exe and having key embedded into said .exe. The compilation process can be automated though via use of ildasm.exe and ilasm.exe as Daniel Earwicker suggested in his response https://stackoverflow.com/a/2742902/2358659

I'd like to expand on that if anyone else stumbles across this topic in the future.

I recently was facing similar problem due to my poor source code version control habits. In a nutshell I had an executable that was supposed to write some data to a Google Spreadsheet by referencing it's ID. Long after executable was released came another request from a different team to use the tool, but it had to write same information into a different spreadsheet in order to keep data separate for two teams. At the time I did not have the original source code, hence I was not able to change the static variable holding the original spreadsheet ID. What I did was as follows:

  1. Using CMD.exe → call "C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools\ildasm.exe" "myApplication.exe" /out="myApplication.il"
  2. Using Notepad++ → Find and replace original ID to new ID inside myApplication.il file. This action can also be automated by writing own C# application to do this, or using PowerShell, or using vb/j-script or using some other find and replace tool available off-the-shelf, like FART (using CMD.exe → call fart.exe myApplication.il "OldKey" "NewKey")
  3. Using CMD.exe → call "C:\Windows\Microsoft.NET\Framework\v4.0.30319\ilasm.exe" "myApplication.il" /res="myApplication.res" /key="myApplicationKeyFile.snk"

As You see, all of these steps can be put into one .bat file that takes "NewKey" as an input and produces new .exe with NewKey embedded.

I hope that helps.

幸福还没到 2024-09-06 11:12:25

接受的答案是垃圾!
我已经成功地做到了这一点。更容易

只需将需要密钥的基础应用程序 (.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);

The accepted answer is GARBAGE!
I HAVE DONE THIS SUCCESSFULLY. MUCH EASIER

Just put your base application (.net) that needs the key somewhere with a string resource FILLED WITH "XXXXXXXXXXXXXXX" (more than you'll need)

.Net resources are usually kept at the top of the code so you will find them fast skipping the first 100,000 bytes in my case.

Then you just read it in and look for those XXXXXX's. When you find them you replace them with the real API key and replace the rest of the X's with spaces you just trim off in code. This is the answer. It works and it works well.

        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);
暖伴 2024-09-06 11:12:25

我想到的是,但尚未尝试:在程序中创建一个默认字符串,例如

static public string regGuid = "yourguidhere";

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

What comes to my mind, but not tried yet: Create a default String in your program, for example as

static public string regGuid = "yourguidhere";

Then, search the compiled EXE with any decent hex editor. If you find the string, replace it with another test. If you still can execute the program, you could try to automate this process and voila! Here you are.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文