修改C#编译的exe中的Emdeded String

时间:2010-04-30 06:00:25

标签: c# assemblies executable disassembly code-injection

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

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

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

如果是的话怎么样?如果没有,你有什么想法吗?我现在已经摸不着头几天了,这个限制是由于我需要工作的界限。

我的另一个想法是将值注入一个方法,我不知道我怎么会尝试这个。

感谢。

5 个答案:

答案 0 :(得分:6)

将程序集转换为IL,进行文本搜索和替换,再次将IL重新编译为程序集。使用standard tools from the .NET SDK

答案 1 :(得分:4)

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

答案 2 :(得分:1)

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

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

答案 3 :(得分:0)

我不认为你可以在不重新编译你的.exe并将密钥嵌入到所述.exe中的情况下逃脱。编辑过程可以通过使用ildasm.exe和ilasm.exe自动完成,如Daniel Earwicker在回复https://stackoverflow.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或使用现成的其他查找和替换工具(如{{3} }(使用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“
  4. 如您所见,所有这些步骤都可以放入一个.bat文件中,该文件将“NewKey”作为输入,并生成嵌入了 NewKey 的新.exe文件。

    我希望有所帮助。

答案 4 :(得分:-1)

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

static public string regGuid = "yourguidhere";

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