你好,这里是 Dotnet 工具箱,定期分享 Dotnet 有趣,实用的工具和组件,希望对您有用!

JIEJIE.NET - 强大的 .NET 代码混淆工具

JIEJIE.NET

JIEJIE.NET 是一个使用 C# 开发的开源 .NET 代码加密工具。

很多 .NET 开发人员担心他们的软件被破解,版权受到侵犯,所以他们使用一些工具来混淆 IL 代码。比如 PreEmptive dotfuscator, 但有些场景的需求,是这些工具不能满足的。

所以作者写了 JieJie.NET,它可以深度加密.NET程序集,帮助大家保护版权。重要的是,这个工具是开源的。

界面预览

功能特性

1.类型和成员重命名

旧代码:

public abstract class XTextDocumentContentElement : XTextContentElement
{
public override void AfterLoad(ElementLoadEventArgs args);
public override void Clear();
[Obfuscation(Exclude = true, ApplyToMembers = true)]
public override XTextElement Clone(bool Deeply);
[Obfuscation(Exclude = true, ApplyToMembers = true)]
public override XTextDocument CreateContentDocument(bool includeThis);
public XTextSelection CreateSelection(int startIndex, int length);
public override void Dispose();
public override void DrawContent(InnerDocumentPaintEventArgs args);
[Obfuscation(Exclude = true, ApplyToMembers = true)]
public override void EditorRefreshViewExt(bool fastMode);
public float FixPageLinePosition(int pos);
public override void Focus();
[Obfuscation(Exclude = true, ApplyToMembers = true)]
public XTextLineList GetAllLines();
[Obfuscation(Exclude = true, ApplyToMembers = true)]
public virtual XTextRange GetRange(int StartIndex, int EndIndex);
public void InnerGetSelectionBorderElement(ref XTextElement startElement, ref XTextElement endElement);
public void InvalidateSpecifyLayoutElements();
[Obfuscation(Exclude = true, ApplyToMembers = true)]
public virtual bool IsSelected(XTextElement element);
public void RefreshParagraphListState(bool checkFlag, bool updateListIndex);
public XTextParagraphFlagElement RootParagraphFlag();
[Obfuscation(Exclude = true, ApplyToMembers = true)]
public bool SetSelection(int startIndex, int length);
[Obfuscation(Exclude = true, ApplyToMembers = true)]
public bool SetSelectionRange(int firstIndex, int lastIndex);
}

加密后:

public abstract class XTextDocumentContentElement : XTextContentElement
{
public override void Clear();
public override XTextElement Clone(bool Deeply);
public override XTextDocument CreateContentDocument(bool includeThis);
public override void Dispose();
public override void EditorRefreshViewExt(bool fastMode);
public override void Focus();
public XTextLineList GetAllLines();
public virtual XTextRange GetRange(int StartIndex, int EndIndex);
public virtual bool IsSelected(XTextElement element);
public bool SetSelection(int startIndex, int length);
public bool SetSelectionRange(int firstIndex, int lastIndex);
public XTextParagraphFlagElement z0ZzZzbmm1mO001();
public XTextSelection z0ZzZzbmm1mO011(int startIndex, int length);
public void z0ZzZzbmm1mO01O();
public float z0ZzZzbmm1mOOm1(int pos);
public void z0ZzZzbmm1mOOmn(ref XTextElement startElement, ref XTextElement endElement);
public void z0ZzZzbmm1mOOmO(bool checkFlag, bool updateListIndex);
public override void z0ZzZzbmmOO11nn(z0ZzZzbm0mmlm1O args);
public override void z0ZzZzbmmOOl0nO(ElementLoadEventArgs args);
}

可以看到,一些 API 的名称被混淆了。

2. 混淆代码流程

JieJie.NET 可以分析 IL 代码,并且在不丢失任何特性的情况下随机混淆代码流程。它可以破坏 foreach/lock/using, 让代码很难阅读,有时候还会导致破解工具错误。

旧代码:

public int RemoveByControl(object control)
{
if (control == null)
{
throw new ArgumentNullException("control");
}
if (CheckOwner() == false)
{
return -1;
}
int result = 0;
lock (this)
{
for (int iCount = _Tasks.Count - 1; iCount >= 0; iCount--)
{
if (_Tasks[iCount].Control == control)
{
_Tasks.RemoveAt(iCount);
result++;
}
}
if (_CurrentTask != null && _CurrentTask.Control == control)
{
_CurrentTask = null;
}
}
return result;
}

使用 JieJie.NET 后,在 ILSpy 中显示的代码如下:

public int RemoveByControl(object control)
{
//Discarded unreachable code: IL_000b, IL_0073
//IL_000b: Incompatible stack heights: 1 vs 0
//IL_0073: Incompatible stack heights: 1 vs 0
int num = z0ZzZzgw.z0kh;
bool flag = default(bool);
int num4 = default(int);
int result = default(int);
while (true)
{
switch (num)
{
default:
{
if (control == null)
{
throw new ArgumentNullException(z0ZzZzow.z0rj);
}
if (!z0rk())
{
goto IL_0049;
}
int num2 = 0;
z0ZzZzjw.z0uk(this);
try
{
int num3 = z0ZzZzgw.z0ah;
while (true)
{
switch (num3)
{
default:
num2++;
goto IL_0097;
case 3:
if (flag)
{
z0ik = null;
}
break;
case 4:
case 5:
{
num4 = z0bk.Count - 1;
goto IL_009e;
}
IL_009e:
if (num4 < 0)
{
flag = z0ik != null && z0ik.Control == control;
num3 = z0ZzZzgw.z0wj;
continue;
}
if (z0bk[num4].Control == control)
{
z0bk.RemoveAt(num4);
num3 = z0ZzZzgw.z0sh;
continue;
}
goto IL_0097;
IL_0097:
num4--;
goto IL_009e;
}
break;
}
}
finally
{
Monitor.Exit(this);
}
result = num2;
break;
}
case 0:
case 1:
case 3:
break;
}
break;
IL_0049:
result = -1;
num = z0ZzZzgw.z0wj;
}
return result;
}

现在代码流程已经被破坏了。

3. 加密所有字符串值

JieJie.NET 可以收集程序集中定义的所有字符串值,然后把它们转换为新类中的静态只读字段,并对它们的值进行加密。

旧代码:

private string GetLicenseMessage()
{ return "这是一个密钥 :" + Environment.UserName;
}

加密后:

private string GetLicenseMessage()
{
string text = _0._6 + Environment.UserName;
return text;
}
// also create a new class, contains all string value in assembly in random order.
internal static class _0
{
public static readonly string _0;
public static readonly string _1;
public static readonly string _2;
public static readonly string _3;
public static readonly string _4;
public static readonly string _5;
public static readonly string _6;
public static readonly string _7;
public static readonly string _8;
public static readonly string _9;
public static readonly string _10;
public static readonly string _11;
public static readonly string _12;
public static readonly string _13;
public static readonly string _14;
public static readonly string _15;
public static readonly string _16;
public static readonly string _17;
public static readonly string _18;
public static readonly string _19;
public static readonly string _20;
public static readonly string _21; static _0()
{
byte[] datas = _BytesContainer__._0();
_11 = GetStringByLong(datas, 151732605047602L);
_20 = GetStringByLong(datas, 450799767951810L);
_7 = GetStringByLong(datas, 101155071172227L);
_4 = GetStringByLong(datas, 47279000500949L);
_15 = GetStringByLong(datas, 415615395474299L);
_5 = GetStringByLong(datas, 54975582493063L);
_2 = GetStringByLong(datas, 17592187197342L);
_14 = GetStringByLong(datas, 206708198516324L);
_8 = GetStringByLong(datas, 124244814685054L);
_21 = GetStringByLong(datas, 459595860893446L);
_6 = GetStringByLong(datas, 72567769190975L);
_13 = GetStringByLong(datas, 182518931688172L);
_18 = GetStringByLong(datas, 433207581847376L);
_16 = GetStringByLong(datas, 417814419099513L);
_3 = GetStringByLong(datas, 36283884381871L);
_1 = GetStringByLong(datas, 9895605165436L);
_9 = GetStringByLong(datas, 136339442622330L);
_19 = GetStringByLong(datas, 440904163377248L);
_17 = GetStringByLong(datas, 426610511995160L);
_0 = GetStringByLong(datas, 598562L);
_10 = GetStringByLong(datas, 148434069970387L);
_12 = GetStringByLong(datas, 158329675868829L);
}
private static string GetStringByLong(byte[] datas, long key)
{
int num = (int)(key & 0xFFFF) ^ 0xEF83;
key >>= 16;
int num2 = (int)(key & 0xFFFFF);
key >>= 24;
int num3 = (int)key;
char[] array = new char[num2];
int num4 = 0;
while (num4 < num2)
{
int num5 = num4 + num3 << 1;
array[num4] = (char)(((datas[num5] << 8) + datas[num5 + 1]) ^ num);
num4++;
num++;
}
return new string(array);
}
}

项目地址: https://github.com/dcsoft-yyf/JIEJIE.NET

Dots - 更友好的 .NET SDK 管理器

什么是 Dots?

Dots 是一个用于管理 .NET SDK 的 GUI 工具,它使用 .NET MAUI 开发的,可用于 Windows 和 macOS(对不住了,Linux 用户)。

为什么会开发 Dots?

总所周知, .NET 的小版本更新很快,而我经常会试用 SDK 的最新预览版。甚至尝试自定义构建。我在我的机器上安装了几个不同版本的 SDK,只是方便能够在它们之间进行切换。通常我会尝试保留当前的稳定版本、最新的预览版和 LTS 版本。除此之外,我可能需要特定项目的特定 SDK 版本。

当然有 dotnet cli 允许我检查安装的版本,dotnet --list-sdks 可以输出安装的版本信息。

但我想更好地了解所有已安装版本的一些细节,并能够快速卸载它们。

于是,Dots - 更友好的 .NET SDK 管理器来了!欢迎大家尝试使用!

项目地址: https://github.com/nor0x/Dots

【DotNetCorePlugins- 动态加载和卸载 .NET 程序插件】

DotNetCorePlugins 是一个 .NET 的开源插件项目,它提供了能够动态加载程序集的 API,然后把它们作为 .NET 主程序的扩展程序执行。

这个库主要用到了 AssemblyLoadContext 技术, System.Runtime.Loader.AssemblyLoadContext,又名 ALC,提供了一些用于定义动态程序集加载行为的基本 API。这是 .NET Core 中我最喜欢但鲜为人知的 API 之一。

如何使用?

安装 McMaster.NETCore.Plugins NuGet 包。

dotnet add package McMaster.NETCore.Plugins

主要使用的 API 是 PluginLoader.CreateFromAssemblyFile, 它允许从文件中读取并加载程序集。

PluginLoader.CreateFromAssemblyFile(
assemblyFile: "./plugins/MyPlugin/MyPlugin1.dll",
sharedTypes: new [] { typeof(IPlugin), typeof(IServiceCollection), typeof(ILogger) },
isUnloadable: true)
  • assemblyFile = 插件 .dll 的文件路径
  • sharedTypes = 加载程序的统一的类型列表
  • isUnloadable = 允许这个插件在将来的某个时候从内存中卸载。

定义接口

这是一个示例,我们定义了一个接口,里面包含了 GetName, 如下

public interface IPlugin
{
string GetName();
}

对于插件,我们直接使用这个接口并进行实现,如下

internal class MyPlugin1 : IPlugin
{
public string GetName() => "My plugin v1";
}

对于主程序,我们可以使用 PluginLoader API 来加载插件,程序需要使用查找磁盘中的插件程序集。一种方式是基于约定的,比如

plugins/
$PluginName1/
$PluginName1.dll
(additional plugin files)
$PluginName2/
$PluginName2.dll

每个插件都发布到一个单独的目录中,这样可以避免插件之间的争用和重复的依赖问题。

以通过运行下面的命令,输出插件到文件夹中。

dotnet publish MyPlugin1.csproj --output plugins/MyPlugin1/

接下来,我们可以通过反射获取所有的插件,并进行加载, 代码如下

using McMaster.NETCore.Plugins;

var loaders = new List<PluginLoader>();

// create plugin loaders
var pluginsDir = Path.Combine(AppContext.BaseDirectory, "plugins");
foreach (var dir in Directory.GetDirectories(pluginsDir))
{
var dirName = Path.GetFileName(dir);
var pluginDll = Path.Combine(dir, dirName + ".dll");
if (File.Exists(pluginDll))
{
var loader = PluginLoader.CreateFromAssemblyFile(
pluginDll,
sharedTypes: new [] { typeof(IPlugin) });
loaders.Add(loader);
}
} // Create an instance of plugin types
foreach (var loader in loaders)
{
foreach (var pluginType in loader
.LoadDefaultAssembly()
.GetTypes()
.Where(t => typeof(IPlugin).IsAssignableFrom(t) && !t.IsAbstract))
{
IPlugin plugin = (IPlugin)Activator.CreateInstance(pluginType); Console.WriteLine($"Created plugin instance '{plugin.GetName()}'.");
}
}

支持 MVC 和 Razor

另外插件还支持加载 MVC 的 Controller 和 Razor Pages。通过安装下面的 Nuget 包。

dotnet add package McMaster.NETCore.Plugins.Mvc

加载程序集的方法如下:

public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
var pluginFile = Path.Combine(AppContext.BaseDirectory, "plugins/MyRazorPlugin/MyRazorPlugin.dll");
services
.AddMvc()
.AddPluginFromAssemblyFile(pluginFile);
}
}

更多插件的使用方法,作者提供了一些示例项目,可以进行参考。

项目地址:https://github.com/natemcmaster/DotNetCorePlugins

【Dotnet 工具箱】JIEJIE.NET - 强大的 .NET 代码混淆工具的更多相关文章

  1. Java代码混淆工具ProGuard

    目录 Java代码混淆工具ProGuard 简介 描述 作用的环境 功能 工作原理 下载 使用时注意事项 版本问题 JDK位数问题 Java的字节码验证问题 关于使用类似于Hibernate的对象关系 ...

  2. .NET代码混淆工具NET Reactor - 初学者系列-学习者系列文章

    这几天无事,除了看书,然后就倒腾原来的代码.想起.NET的代码混淆工具软件,所以今天就讲讲这个.NET代码混淆工具. .NET代码混淆工具软件,以前有了解和找过,但是当时需求不大,所以找了下就搁置了. ...

  3. 代码混淆工具——Virbox Protector Standalone

    VirboxProtector Standalone 加壳工具可对代码加密的技术有:代码混淆.代码虚拟化.代码加密. 代码混淆:利用花指令和代码非等价变形等技术,将程序的代码,转换成一种功能上等价,但 ...

  4. ChaosTool,iOS添加垃圾代码工具,代码混淆工具,代码生成器,史上最好用的垃圾代码添加工具,自己开发的小工具

    最近在H5游戏项目中需要添加垃圾代码作混淆,提高过审机率.手动添加太费时费力,在网上并没有找到合适的比较好的工具,就自己动手写了一个垃圾代码添加工具,命名为ChaosTool. 扣扣交流群:81171 ...

  5. 升级:DNAtools for Excel工具箱,2.x英文版- VBA代码破解工具

    原始出处:www.cnblogs.com/Charltsing/p/DnaTools.html QQ:564955427 DNA工具箱全部功能一览:    单元格焦点指示(支持Excel 2007~2 ...

  6. 一个强大的VS代码搜索工具

    最近一直在寻找一款VS代码搜索插件,终于找到了一个不错的,仅支持vs2012以上. https://marketplace.visualstudio.com/items?itemName=mario- ...

  7. CodeMixerPro工具,完美替代ChaosTool,iOS添加垃圾代码工具,代码混淆工具,代码生成器,史上最好用的垃圾代码添加工具,自己开发的小工具

    新工具 ProjectTool 已上线 这是一款快速写白包工具,秒级别写H5游戏壳包,可视化操作,极易使用,支持Swift.Objecive-C双语言 扣扣交流群:811715780 进入 Proje ...

  8. CodeMixer工具,完美替代ChaosTool,iOS添加垃圾代码工具,代码混淆工具,代码生成器,史上最好用的垃圾代码添加工具,自己开发的小工具

    新工具 ProjectTool 已上线 这是一款快速写白包工具,秒级别写H5游戏壳包,可视化操作,极易使用,支持Swift.Objecive-C双语言 扣扣交流群:811715780 进入 Proje ...

  9. Dotfuscator代码混淆工具的使用

    关于Dotfuscator,VS自带了一个社区版的源代码保护工具,不过它只有基本的混淆命名的功能.专业版功能很多,可以混淆流程,密字符串,加入水印,程序签名等. 工具/原料   Dotfuscator ...

  10. python 代码混淆工具汇总

    pyminifier Pyminifier is a Python code minifier, obfuscator, and compressor. Note For the latest, co ...

随机推荐

  1. C# 图片 等 文件 读取操作 的一点提示

    源于:在读取图片时,总喜欢首先采用:Image img=Image.FromFile("");操作,这种方式由于 调用图片的程序与图片文件是通过 绝对地址关联的,会造成 当前进程或 ...

  2. 004Java的一些基本概念

    004Java的一些基本概念 1.Java特性和优势 Java至少具有以下特性: 简单性(没有头文件.没有指针运算.也没有分配内存等操作) 面向对象(万物皆对象) 可移植性(一次编写,到处运行 Wri ...

  3. Java集合框架个人总结

    Java集合框架个人总结 集合主要分为两大类:①单列集合Collection ②双列集合Map 集合存储的都是引用类型,不可是基础类型,如果保存基础类型需要用包装类. 1.Collection接口 ​ ...

  4. 用echarts做兼容ie8的三测单(体温单) 代码全

    $.fn.extend({ /** * * @param { * UrineOutputData: 尿量数据 * OutputData: 出量数据 * InputData: 入量数据 * shitDa ...

  5. Docker 容器的备份和迁移

    Docker的Save和Export的区别 Docker的镜像和容器有两种方式导出 Docker Save镜像方法,会保存该镜像的所有历史记录,包括数据 1.创建快照 使用 docker commit ...

  6. 上位机-串口通信详解(以RS232为例))

    1.什么是串口通信? 写这个的时候我在想应该怎么解释串口通信,因为串口通信很多朋友不了解的原因是涉及到硬件的知识,对于没有相关专业知识的朋友很难理解串口通信.所以我这里只做部分的解释,需要了解更多硬件 ...

  7. windows下创建虚拟环境

    创建虚拟环境依赖以下两个模块 virtualenv  和virtualenvwrapper-win 1.下载 2.修改环境变量,增加一条 WORKON_HOME:路径 3.  同步配置 去向Pytho ...

  8. opengauss集群安装报错

    DB_VERSION:opengauss 3.0.3 1.[GAUSS-51632] [GAUSS-51632] : Failed to do gs_sshexkey.Error: Please en ...

  9. WinUI(WASDK)使用ChatGPT和摄像头手势识别结合TTS让机器人更智能

    前言 之前写过一篇基于ML.NET的手部关键点分类的博客,可以根据图片进行手部的提取分类,于是我就将手势分类和摄像头数据结合,集成到了我开发的电子脑壳软件里. 电子脑壳是一个为稚晖君开源的桌面机器人E ...

  10. something to SSSSay

    可能记录写博客的初衷,现在的状态,一些目标.想法. 首先让我拟定几个关键词: 半吊子程序员 咸鱼 欲求不满 终生学习 自律 <差不多程序员> 长得差不多(175)高,看着差不多(普通)帅, ...