воскресенье, 15 ноября 2009 г.

Сокрытие строк в коде .NET

Код, создаваемый компилятором языка c# сохраняет строки в "чистом" виде.
Например вот такой код
static void Main()
{
  String str = "123 abc TEST";
  Console.WriteLine(str);
}

* This source code was highlighted with Source Code Highlighter.
после компиляции и последующей декомпиляции выглядит следующим образом:

.method private hidebysig static void Main() cil managed
{
.entrypoint
.maxstack 1
.locals init (
[0] string str)
L_0000: nop
L_0001: ldstr "123 abc TEST"
L_0006: stloc.0
L_0007: ldloc.0
L_0008: call void [mscorlib]System.Console::WriteLine(string)
L_000d: nop
L_000e: ret
}

Провести декомпиляцию можно очень легко, для этого существуют как утилиты от корпорации MS - ildasm.exe, так и независимые от MS решения. Самый известный среди них будет, пожалуй, ".NET Reflector" от Рёдера.

Так вот, учитывая то, что код и его логика может быть в принципе легко восстановлена, даже несмотря на применение программ для сокрытия логики приложения и усложняющих декомпиляцию (так называемых обфускаторов), иногда все же необходимо скрыть прямое распознавание некоторых строк, вшитых в код. В своей программе для этой цели я создал следующие методы "шифрования" и "расшифрования". Логика проста, надеюсь все ясно.

public static String Decode(string str)
{
  // validate param
  if (String.IsNullOrEmpty(str))
    throw new ArgumentException();

  // number generator
  Random rnd = new Random();

  // declare result
  StringBuilder result = new StringBuilder();

  // decode string : [decoded char1][keychar1][decoded char2][keychar2]...[decoded charN][keycharN]
  for (int i = 0; i < str.Length; i++)
  {
    int rndInt = 0;
    int intChar = 0;

    while (!(intChar >= 32)) // exclude special characters
    {
      rndInt = rnd.Next(32, 127); // exclude special characters in keychars and limit from above
      intChar = str[i] ^ rndInt;
    }

    result.Append((char)intChar);
    result.Append((char)rndInt);
  }

  // result
  return result.ToString();
}

public static String Encode(string str)
{
  // validate param
  if (String.IsNullOrEmpty(str))
    throw new ArgumentException();
  if (str.Length % 2 != 0)
    throw new ArgumentException();

  // declare result
  StringBuilder result = new StringBuilder();

  // encode string: [encoded char] = [decoded char] XOR [key char]
  for (int i = 0; i < str.Length; i += 2)
  {
    char char1 = (char)(str[i] ^ str [i+1]);
    result.Append(char1);
  }

  // result
  return result.ToString();
}


* This source code was highlighted with Source Code Highlighter.

Теперь метод и IL выглядят следующим образом:
static void Main()
{
  String str = Decode("~OEwVeqQH)Y;&EvV%q⌂:c08l");
  Console.WriteLine(str);
}


* This source code was highlighted with Source Code Highlighter.

.method private hidebysig static void Main() cil managed
{
.entrypoint
.maxstack 1
.locals init (
[0] string str)
L_0000: nop
L_0001: ldstr "~OEwVeqQH)Y;&EvV%q\u2302:c08l"
L_0006: call string HideCodestring.Program::Decode(string)
L_000b: stloc.0
L_000c: ldloc.0
L_000d: call void [mscorlib]System.Console::WriteLine(string)
L_0012: nop
L_0013: ret
}


PS: В процессе написания поста обнаружил, что некоторые обфускаторы делают нечто подобное, т.е. "шифруют" (если это вообще можно шифрованием назвать) строки каким нибудь несложным, но быстрым алгоритмом. Но мой незарегистрированный Dotfuscator, идущий с VS не поддерживает эту возможность.

воскресенье, 8 ноября 2009 г.

Исходные коды .NET Framework Libraries

Собственно сама ссылка

На момент создания поста доступные исходники:
.NET v8.0
FX1434 v1.0
dotnetfx35SP1_3053 v1.3
FXUpdate3074 v1.1
ASP.NET_MVC v1.0
WCF v3.5SP1
Dotnetfx_4016_VistaSP2 v1.1
Dotnetfx_35.1_Win7 v1.1