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

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

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

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

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

public static void Main()
{
try
{
RunSnippet();
}
catch (Exception e)
{
string error = string.Format("---\nThe following error occurred while executing the snippet:\n{0}\n---", e.ToString());
Console.WriteLine(error);
}
finally
{
Console.Write("Press any key to continue...");
Console.ReadKey();
}
}
 

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

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

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

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

.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之后的代码

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

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

MethodDefinition new_method = new MethodDefinition("StringDecode", attr, asm.MainModule.Import(typeof(string)));
ParameterDefinition para = new ParameterDefinition(asm.MainModule.Import(typeof(string)));
new_method.Parameters.Add(para);
tp.Methods.Add(new_method); new_method.Body.MaxStackSize = 8;
MethodReference mr;
ILProcessor worker = new_method.Body.GetILProcessor (); mr = asm.MainModule.Import(typeof(Encoding).GetMethod("get_UTF8"));
worker.Append(worker.Create(OpCodes.Call, mr)); worker.Append(worker.Create(OpCodes.Ldarg_0)); mr = asm.MainModule.Import(typeof(Convert).GetMethod("FromBase64String"));
worker.Append(worker.Create(OpCodes.Call, mr)); mr = asm.MainModule.Import(typeof(Encoding).GetMethod("GetString", new Type[] { typeof(Byte[]) }));
worker.Append(worker.Create(OpCodes.Callvirt, mr));
worker.Append(worker.Create(OpCodes.Ret));

 

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

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

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

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

最后保存程序集,用.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有变化,本篇程序代码中应用到的读取程序集和写入程序集

string path = @"C:\Users\Administrator\Desktop\CPP\Default.exe";
AssemblyDefinition asm = AssemblyDefinition.ReadAssembly(path);
MethodDefinition entry_point = asm.EntryPoint; path = @"C:\Users\Administrator\Desktop\CPP\DefaultSecury.exe";
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; }

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

static string stringEncrypt(string string_0)
{
char[] chArray;
char[] chArray1 = chArray = string_0.ToCharArray();
while (true)
{
int num;
int length = chArray1.Length;
if (length <= 0)
{
break;
}
chArray1[num = length + -1] = (char) (chArray[num] - 'ᑩ');
}
return string.Intern(new string(chArray));
}
 

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

static string GetString(string source, int salt)
{
int index = 0;
char[] data = source.ToCharArray();
salt += 0xe74d6d7; // This const data generated by dotfuscator
while (index < data.Length)
{
char key = data[index];
byte low = (byte)((key & '\x00ff') ^ salt++);
byte high = (byte)((key >> 8) ^ salt++);
data[index] = (char)((low << 8 | high));
index++;
}
return string.Intern(new string(data));
}
 

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

 

.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. kettle系列-5.kettle实现二进制文件迁移

    本文就是分享下二进制文件(图片.txt文件等)在oracle和文件系统间的传输的转换示例. 转换示例如下图: 示例本身较简单,但很多人应该还是不太清楚怎么做,很多时候都是上网搜索,网上有关的就是通过j ...

  2. Linux内核--内核数据类型

    转自:http://www.linuxidc.com/Linux/2013-12/93637.htm 将Linux 移植到新的体系结构时,开发者遇到的若干问题都与不正确的数据类型有关.坚持使用严格的数 ...

  3. Oracle 11g RAC 环境打PSU补丁的详细步骤

    首先重要的事情说三遍:操作之前还是自己先看文档!操作之前还是自己先看文档!!操作之前还是自己先看文档!!! 把11.2.0.4 RAC 环境打PSU补丁的步骤详细记录一下,方便参考. 环境:11.2. ...

  4. winform快速开发平台 -> 快速绑定ComboBox数据控件

    通常我们在处理编辑窗体时.往往会遇到数据绑定.例如combobox控件绑定数据字典可能是我们经常用到的.然而在我的winform快速开发平台中我是如何处理这个频繁的操作呢? 首先,我们要绑定combo ...

  5. DataGridView控件行标题显示序号

    Rectangle rectangle = new Rectangle(e.RowBounds.Location.X, e.RowBounds.Location.Y, dataGridViewX1.R ...

  6. IMEI串号

    IMEI串号就是国际移动设备身份码,是电子设备的唯一身份证,由于它的唯一性,它可以用来查询电子设备的保修期还有产地,可以说用处直逼人民的身份证啊! 在拨号键盘页面  输入[*#06#]五个字符

  7. dir命令只显示文件名

    dir /b 就是ls -f的效果 1057 -- FILE MAPPING_web_archive.7z 2007 多校模拟 - Google Search_web_archive.7z 2083 ...

  8. Nginx配置文件nginx.conf中文详解

    #定义Nginx运行的用户和用户组user www www; #nginx进程数,建议设置为等于CPU总核心数.worker_processes 8; #全局错误日志定义类型,[ debug | in ...

  9. 从外部浏览开启app

    先描述一下需求:从浏览器中点击某个按钮,如果手机上装有相应的app,则直接开启app,并且到相对的页面.如果没有装该app,则会到相应的下载app的界面. 我这里主要用的是第三方的东西,就是魔窗中的m ...

  10. mac下安装mysql教程

    由于更换了mac电脑,需要装一个mysql,经过各种资料的翻阅,各种踩坑,终于装完了,记录一下,方便大家参照: 1.下载最新的mysql安装包,下载地址:http://dev.mysql.com/do ...