关于字符串的研究,目前已经有两篇。

原理篇:字符串混淆技术在.NET程序保护中的应用及如何解密被混淆的字符串 

实践篇:字符串反混淆实战 Dotfuscator 4.9 字符串加密技术应对策略

今天来讲第三篇,如何应用上面所学内容,设计一个字符串混淆程序。

先设计一个控制台程序,它是将要被我混淆的程序集文件:

  1. public static void Main()
  2. {
  3. try
  4. {
  5. RunSnippet();
  6. }
  7. catch (Exception e)
  8. {
  9. string error = string.Format("---\nThe following error occurred while executing the snippet:\n{0}\n---", e.ToString());
  10. Console.WriteLine(error);
  11. }
  12. finally
  13. {
  14. Console.Write("Press any key to continue...");
  15. Console.ReadKey();
  16. }
  17. }
  1.  

代码是Snippet Compiler 的标准模板,在控制台上打印一段字符串。这里,有二个字符串常量,是我需要对它进行加密的地方。

不能直接改源代码,而且要以程序的方式来操作程序集。要能修改.net程序集,现在能找到的方法是Mono.Cecil,最新的版本是0.9.5.0。

先设计混淆算法,是个很简单的Base64代码转换,这一步可以深入挖掘,做更复杂的混淆算法。

  1. public static string StringDecode(string text1)
  2. {
  3. return Encoding.UTF8.GetString(Convert.FromBase64String(text1));
  4. }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

要把这段代码转化为IL代码,用Mono.Cecil来注入到制定的程序集中,先来看看翻译成IL之后的代码

  1. .method public hidebysig static string StringDecode(string) cil managed
  2. {
  3. .maxstack 8
  4. L_0000: call class [mscorlib]System.Text.Encoding [mscorlib]System.Text.Encoding::get_UTF8()
  5. L_0005: ldarg.0
  6. L_0006: call uint8[] [mscorlib]System.Convert::FromBase64String(string)
  7. L_000b: callvirt instance string [mscorlib]System.Text.Encoding::GetString(uint8[])
  8. L_0010: ret
  9. }

再对比Mono.Cecil的语法例子,把上面的IL代码,翻译成C#代码

  1. MethodDefinition new_method = new MethodDefinition("StringDecode", attr, asm.MainModule.Import(typeof(string)));
  2. ParameterDefinition para = new ParameterDefinition(asm.MainModule.Import(typeof(string)));
  3. new_method.Parameters.Add(para);
  4. tp.Methods.Add(new_method);
  5.  
  6. new_method.Body.MaxStackSize = 8;
  7. MethodReference mr;
  8. ILProcessor worker = new_method.Body.GetILProcessor ();
  9.  
  10. mr = asm.MainModule.Import(typeof(Encoding).GetMethod("get_UTF8"));
  11. worker.Append(worker.Create(OpCodes.Call, mr));
  12.  
  13. worker.Append(worker.Create(OpCodes.Ldarg_0));
  14.  
  15. mr = asm.MainModule.Import(typeof(Convert).GetMethod("FromBase64String"));
  16. worker.Append(worker.Create(OpCodes.Call, mr));
  17.  
  18. mr = asm.MainModule.Import(typeof(Encoding).GetMethod("GetString", new Type[] { typeof(Byte[]) }));
  19. worker.Append(worker.Create(OpCodes.Callvirt, mr));
  20. worker.Append(worker.Create(OpCodes.Ret));

 

再次,我样要搜索目标程序集中的所有字符串,把它转化成Base64的字符串编码,于是遍历IL指令,进行转化

  1. List<Instruction> actionInsert=new List<Instruction> ();
  2. foreach (Instruction ins in entry_point.Body.Instructions)
  3. {
  4. if (ins.OpCode.Name == "ldstr")
  5. {
  6. Console.WriteLine("Find target instruction, start modify..");
  7. byte[] bytes = System.Text.Encoding.UTF8.GetBytes (Convert.ToString (ins.Operand));
  8. ins.Operand = Convert.ToBase64String (bytes);
  9.  
  10. actionInsert.Add(ins);
  11. }
  1. }
  1.  
  1.  

最后,我们把原来的指令替换成字符串混淆算法调用

  1. for (int i = 0; i < actionInsert.Count; i++)
  2. {
  3. mr = asm.MainModule.Import(new_method);
  4. worker = entry_point.Body.GetILProcessor();
  5. worker.InsertAfter(actionInsert[i], worker.Create(OpCodes.Call, mr));
  6. }
  1.  
  1.  

最后保存程序集,用.net Reflector 载入程序集,如下图所示,字符串常量已经变成了方法调用:

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

这样,增加了代码反编译的难度,字符串的含义完全被替换成一堆无意义的字符串。

Mono.Cecil最新的版本中,API有变化,本篇程序代码中应用到的读取程序集和写入程序集

  1. string path = @"C:\Users\Administrator\Desktop\CPP\Default.exe";
  2. AssemblyDefinition asm = AssemblyDefinition.ReadAssembly(path);
  3. MethodDefinition entry_point = asm.EntryPoint;
  4.  
  5. path = @"C:\Users\Administrator\Desktop\CPP\DefaultSecury.exe";
  6. asm.MainModule.Write(path);

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

关于字符串混淆算法,下面列举几个我找到的混淆算法,加密强度会高一些:

  1. static string stringEncrypt(string string_0)
  2. {
  3. char[] chArray;
  4. char[] chArray1 = chArray = string_0.ToCharArray();
  5. while (true)
  6. {
  7. int num;
  8. int length = chArray1.Length;
  9. if (length <= 0)
  10. {
  11. break;
  12. }
  13. chArray1[num = length + -1] = (char) (chArray[num] - 'ᑩ');
  14. }
  15. return string.Intern(new string(chArray));
  16. }
  1.  

下面是Dotfuscator的混淆算法,还加了盐,强度提升不少。

  1. static string GetString(string source, int salt)
  2. {
  3. int index = 0;
  4. char[] data = source.ToCharArray();
  5. salt += 0xe74d6d7; // This const data generated by dotfuscator
  6. while (index < data.Length)
  7. {
  8. char key = data[index];
  9. byte low = (byte)((key & '\x00ff') ^ salt++);
  10. byte high = (byte)((key >> 8) ^ salt++);
  11. data[index] = (char)((low << 8 | high));
  12. index++;
  13. }
  14. return string.Intern(new string(data));
  15. }
  1.  

经过混淆后的字符串,完全看不出原文的含义。比如下面的代码片段,都有些怀疑它使用的字符集,有点像中东国家的语言

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

再来看一个代码中有中文的例子,这是一段用户登陆代码,它加密后的字符看起来更不可理解。

如果要给字符串混淆加盐,只需要简单的修改上面的代码,添加一个临时变量,再增加到调用的混淆算法中。

全文代码以NUnit测试方法写成,单元测试配合Resharper真是好用,可以节省大量的代码,一个方法即可作为入口程序启动运行。

给开发和测试带多很多方便。

字符串混淆技术应用 设计一个字符串混淆程序 可混淆.NET程序集中的字符串的更多相关文章

  1. 字符串混淆技术在.NET程序保护中的应用及如何解密被混淆的字符串

    Visual Studio提供的Dotfuscator保护程序,可以对用户代码中包含的字符串进行加密.比如下面的例子,为了找到这个程序的注册算法,用.NET Reflector加载程序集后,发现代码中 ...

  2. 字符串反混淆实战 Dotfuscator 4.9 字符串加密技术应对策略

    因为手头需要使用一个第三方类库,网络上又找不到它的可用的版本,于是只好自己动手.这个类库使用了Dotfuscator 加密,用.NET Reflector加载程序集, 看到的字符串是乱码,如下面的代码 ...

  3. 设单链表中存放n个字符,试设计一个算法,使用栈推断该字符串是否中心对称

    转载请注明出处:http://blog.csdn.net/u012860063 问题:设单链表中存放n个字符.试设计一个算法,使用栈推断该字符串是否中心对称,如xyzzyx即为中心对称字符串. 代码例 ...

  4. 设计一个字符串类String(C++练习题)

    要求:设计一个字符串类String,可以求字符串长度,可以连接两个串(如,s1=“计算机”,s2=“软件”,s1与s2连接得到“计算机软件”),并且重载“=”运算符进行字符串赋值,编写主程序实现:s1 ...

  5. 设计一个 Java 程序,自定义异常类,从命令行(键盘)输入一个字符串,如果该字符串值为“XYZ”。。。

    设计一个 Java 程序,自定义异常类,从命令行(键盘)输入一个字符串,如果该字符串值为“XYZ”,则抛出一个异常信息“This is a XYZ”,如果从命令行输入 ABC,则没有抛出异常.(只有 ...

  6. Android安全攻防战,反编译与混淆技术完全解析(下)

    在上一篇文章当中,我们学习了Android程序反编译方面的知识,包括反编译代码.反编译资源.以及重新打包等内容.通过这些内容我们也能看出来,其实我们的程序并没有那么的安全.可能资源被反编译影响还不是很 ...

  7. Android安全攻防战,反编译与混淆技术完全解析(上)

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/49738023 之前一直有犹豫过要不要写这篇文章,毕竟去反编译人家的程序并不是什么值 ...

  8. Android安全攻防战,反编译与混淆技术全然解析(下)

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/50451259 在上一篇文章其中,我们学习了Android程序反编译方面的知识,包括 ...

  9. 字符串 映射相应的 函数 字符串驱动技术—— MethodAddress , MethodName , ObjectInvoke

    http://blog.csdn.net/qustdong/article/details/7267258 字符串驱动技术—— MethodAddress , MethodName , ObjectI ...

随机推荐

  1. Hadoop单机模式安装-(1)安装设置虚拟环境

    网络上关于如何单机模式安装Hadoop的文章很多,按照其步骤走下来多数都失败,按照其操作弯路走过了不少但终究还是把问题都解决了,所以顺便自己详细记录下完整的安装过程. 此篇主要介绍如何在Windows ...

  2. meta 详解,html5 meta 标签日常设置

    <!DOCTYPE html> <!-- 使用 HTML5 doctype,不区分大小写 --> <html lang="zh-cmn-Hans"&g ...

  3. The specified type member 'Date' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties

    出现这个错误提示可以用 DbFunctions.TruncateTime 将Linq中entity的DateTime转化一下再使用,如下所示: var anyCalls = _db.CallLogs. ...

  4. Java基础知识点4:继承

    继承是面向对象编程技术中非常重要的一个基本概念.它背后的基本思想就是:通过已有的类来创建一个新的类,这个新的类可以重用(或继承)已有的类方法:新的类也可以加入新的方法和属性. 在这里我们通过一个实例来 ...

  5. 关于3DSMAX中opensubdiv细分功能的笔记

    说到建模和细分,估计用过3dsmax的同学就会心有余悸,每次添加"涡轮平滑"或者"网格平滑"之前,都会下意识的进行保存,没有为啥,就是因为太容易使软件挂掉了. ...

  6. Mac 不能输入波浪线?

    当你发现你的Mac或者mbp不能输入波浪线 , 输出的都是的时候,检查一下这个选项(如下图所示)有没有选中. 如果没有,就勾上它!

  7. 编译原理-词法分析05-正则表达式到DFA-01

    编译原理-词法分析05-正则表达式到DFA 要经历 正则表达式 --> NFA --> DFA 的过程. 0. 术语 Thompson构造Thompson Construction 利用ε ...

  8. http tcp udp ip 间的关系

    首先,我自己梳理一下,其实除了应对以后的笔试,还有需要应对的是自己在编程中对于api的选择,我在满足需求时采取哪种方案更好. 首先,我需要了解的是tcp/ip是一个协议组,有三大层: ip 对应于网络 ...

  9. Code Complete 笔记—— 第一章

    软件的构建的主要流程: 定义问题 ( Problem Definition) 需求分析 (Requirements Development) 规划构建 (construction planning) ...

  10. T-SQL Recipes之Common Function

    在我们写SQL的时候,经常会用到许多内置方法,简化了我们许多代码,也提高了效率,这篇主要总结一些常用的方法. ISNULL VS COALESCE VS NULLIF 在SQL中,NULL值是比较特殊 ...