如何在Delphi EXE中隐藏或隐藏字符串?

时间:2011-07-23 12:23:34

标签: string delphi obfuscation

我目前正在Delphi中开发一个应用程序,我必须在源代码中隐藏(混淆)一个字符串,如str := 'Example String'
为什么?因为如果我在文本编辑器中打开EXE并搜索Example String,我会在第二个中找到该字符串......

我尝试使用像#$65#$78#$61#$6d#$70#$6c#$65这样的基本HEX转录,但在编译时它会被清楚地重新转录。
我找了包装工,但这不是最好的解决方案(PECompact可以被检测为误报恶意软件,UPX太容易de-UPX,......)。我希望在我的内部代码中有一个想法...

有人会让我走上正确的路。

2 个答案:

答案 0 :(得分:20)

一种非常简单的方法是存储由ROT13方法模糊的字符串。

procedure ROT13(var Str: string);
const
  OrdBigA = Ord('A');
  OrdBigZ = Ord('Z');
  OrdSmlA = Ord('a');
  OrdSmlZ = Ord('z');
var
  i, o: integer;
begin
  for i := 1 to length(Str) do
  begin
    o := Ord(Str[i]);
    if InRange(o, OrdBigA, OrdBigZ) then
      Str[i] := Chr(OrdBigA + (o - OrdBigA + 13) mod 26)
    else if InRange(o, OrdSmlA, OrdSmlZ) then
      Str[i] := Chr(OrdSmlA + (o - OrdSmlA + 13) mod 26);
  end;
end;

function ROT13fun(const Str: string): string;
begin
  result := Str;
  ROT13(result);
end;

const
  ObfuscatedString = 'Guvf vf n frperg zrffntr.';

procedure TForm4.FormCreate(Sender: TObject);
begin
  ShowMessage(ROT13fun(ObfuscatedString));
end;

采用Caesar切片机或Vigenère切片机稍微复杂一点。

要获取要在源代码中使用的模糊字符串,您可以使用像我自己的Rejbrand Text EditorWolfram|Alpha这样不错的文本编辑器。

<强>更新

ROT13非常容易破译,但它可能对您的情况来说已经足够了,具体取决于它的外观!至少在二进制文件中识别字符串会变得非常困难。获取字符串需要花费一些精力。 (毕竟,日常用户甚至不会在十六进制编辑器/文本编辑器中查看二进制文件!)Caesar密码是ROT13密码的一个非常简单的概括,并且也很容易被破译。实际上,只有25种不同的“密码”。 Vigenère密码更加棘手,并且需要一些非常认真的努力来破解(尤其是,因为你不知道在字符串的二进制文件中 )。

作为一个例子,下面我给出了一个使用Vigenèrecihper进行混淆的字符串:

  

Xlc tsrgcdk sj'vrivem'ww cei sd kli acirivqhfriw cw qsbsir tfmjmgw,rrh biimrk hyi pygk gilhlvc mf ws,wk leq rpws pvgsqc fj agrvwtvcou mrrsiiwx we izcfp-hew cmji,rpxlmixl ml r piqg xigfbzgep zrrkyyuv。 Mlrvih,hyi qmrvvr qctmixw vbtpmwkw ilsikc qclvgiq ks wsqy er soxirr klex hyi ilhzvi cbmmvslavrx mt xli Srvxl wj irboekivcr。先生hymw qstxmsl,ai uwcp mljvwxmeoki xfs tlcqwtep zojmw mt xli seivkw tsrgcdk。

当然可以扩展密码以处理数字和特殊字符,包括空格。它也可以混合大写字母和小写字母。那么解密会非常困难(虽然可能)。如果密码是已知单词,则可能更容易解密,这可以在字典中找到。如果一个单词,它会更安全。

上面的文字使用您可以在足够大的词典中找到的单词进行模糊处理。使用无意义的字符串作为密码对下面的文本进行模糊处理:

  

Miwzvjfy m vjsy-tombox zguol ap ahqovz d uwk sbze w conz pe biusvth pagh h njsx。 Io puvyeq,fl cjsx xic vmovdq zappzjvz,vnjnatl frcb vy dtmd vhxkt fto babtf davf。 Uuxlhqb,khk aa dbn eumsuzq,auk saed vlpnbuuo ywlemz ue pnyl ttmxv。 Pa ghof,fl cjsx kmbbzk atmd wv sfjtmxcl rtfysk cb yuta md jsy。 Sqf nql njsx ly vs ilusrn o gok uxwupagupaz u。

最后,下面的文本以相同的方式进行模糊处理,但是 - 此外 - 所有空格和特殊字符都已从字符串中删除:

  

cishkclruervutzgnyarkgzjsaqgsrzvmmrzweolpcnvbkxrvdnqrlurhpmhfaxsuoqncxgzqegnqmngaryfbgozpcgrkgzrrybybmouyzbbkoucbnrnsxkmcbywpllxhkoobmzoydrfvrkhpvsavmzocwjflouboymlotjcnqrirgucdrftllladcwtmnkqehjpmnafoobyvkvdaancbzeokdnsotkkawvanjkryculluyaoklpnojfnqrlatypznpalzocjunuxzdbnzntpqulplekxhrshpttjqyculkkjyxhxgxdozruwlbtkyrsuumkgslbyunabbkryfupvnafobhuoyyvqjlzgzpomc

我挑战你破译这三个文本。如果有人能成功破译最后一个,我保证给这个人100瑞典克朗(100瑞典克朗)!

但是,Warren P仍然是对的:如果你真的要求高安全性,即使是专家也无法破译,那么你应该去找一些真正的加密。

<强>更新

根据Warren P的要求,我使用以下代码加密/解密Vigenère:

const
  OrdBigA = Ord('A');
  OrdBigZ = Ord('Z');
  OrdSmlA = Ord('a');
  OrdSmlZ = Ord('z');

function imod(const x: integer; const y: integer): integer;
begin
  if x >= 0 then
    imod := x - floor(x/y) * y
  else
    imod := x + ceil(-x/y) * y;
end;

procedure Vigenère(var Str: string; const Key: string);
var
  n, i, o: integer;
  KeyChrs: TBytes;
begin

  n := length(Key);
  SetLength(KeyChrs, n);
  for i := 1 to n do
    if InRange(ord(Key[i]), OrdBigA, OrdBigZ) then
      KeyChrs[i - 1] := Ord(Key[i]) - OrdBigA
    else
      raise Exception.Create('Invalid character in Vigenère key.');

  for i := 1 to length(Str) do
  begin
    o := Ord(Str[i]);
    if InRange(o, OrdBigA, OrdBigZ) then
      Str[i] := Chr(OrdBigA + imod((o - OrdBigA + KeyChrs[(i-1) mod n]), 26))
    else if InRange(o, OrdSmlA, OrdSmlZ) then
      Str[i] := Chr(OrdSmlA + imod((o - OrdSmlA + KeyChrs[(i-1) mod n]), 26));
  end;

end;

function Vigenèref(const Str: string; const Key: string): string;
begin
  result := Str;
  Vigenère(result, Key);
end;

procedure VigenèreD(var Str: string; const Key: string);
var
  n, i, o: integer;
  KeyChrs: TBytes;
begin

  n := length(Key);
  SetLength(KeyChrs, n);
  for i := 1 to n do
    if InRange(ord(Key[i]), OrdBigA, OrdBigZ) then
      KeyChrs[i - 1] := Ord(Key[i]) - OrdBigA
    else
      raise Exception.Create('Invalid character in Vigenère key.');

  for i := 1 to length(Str) do
  begin
    o := Ord(Str[i]);
    if InRange(o, OrdBigA, OrdBigZ) then
      Str[i] := Chr(OrdBigA + imod((o - OrdBigA - KeyChrs[(i-1) mod n]), 26))
    else if InRange(o, OrdSmlA, OrdSmlZ) then
      Str[i] := Chr(OrdSmlA + imod((o - OrdSmlA - KeyChrs[(i-1) mod n]), 26));
  end;

end;

function VigenèreDf(const Str: string; const Key: string): string;
begin
  result := Str;
  VigenèreD(result, Key);
end;

答案 1 :(得分:0)

您可以使用this question中的真实加密库。一个小的外部实用程序可以将您的原始字符串转换为静态字节数组,这些数组将被编译到您的应用程序中,并作为字符串在内存中解密和恢复。这将带来额外的好处,它不会看起来像ascii(范围32..127),并且对于使用十六进制编辑器的临时检查员来说不会那么明显。

此外,真正的加密(甚至3DES或Blowfish)也不会轻易删除,甚至不需要查看源代码或反向工程二进制文件,如ROT13或单级凯撒密码,但是,如果你的密钥(用于解密/加密)本身不受保护,它也不像你希望的那样安全。我很容易将调试器附加到您的代码,甚至发布版本,并在运行时恢复和记录字符串堆中的所有字符串,即使您使用真正的库,也无需破解加密以上。我同意Andreas的看法,Vigenere对你的目的似乎是一种合理的保护和努力,我认为ROT13和单级凯撒密码本身就是可笑的。更新:安德烈亚斯发布的内容很精彩,但在我看来,我更喜欢它是一个很棒的外部库。

对于你在文本文件中存储内容的特定情况,我会编写一个小实用程序,可以将您的秘密加密和编码到源代码中,并至少将密钥存储在其他地方。这就像把你的弹药放在一个锁箱里,并把钥匙放在其他地方。即使这并不完美,但它可能比ROT13更好,ROT13是所有玩具加密风格中最“玩具”的。