1 Star 0 Fork 1

SesameTechGroup / NearAop

forked from New佳佳 / NearAop 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README

NearAop

简介

自己实现的简单AOP及代码混淆。支持 .NET Framework 4.X , .NET Core 3.0。目前处于测试阶段,请勿在生产环境下使用! 交流群:438789123 ,51492982

Image

安装

Install-Package NearAop
VS菜单: 项目 > 管理 NuGet 程序包 > 输入NearAop
Image

卸载

卸载时需要同时卸载NearAop.Handler,否则编译时出现 AopTask”任务意外失败。

目录

1、 属性变更通知
2 、 属性代理

3 、方法代理

4、接口代理
5、SetProxySourceAttribute特性
6、SetCancelAopAttribute特性
7、AOP调试信息输出

8、代码混淆


1、 属性变更通知

编译时自动实现INotifyPropertyChanged接口。当属性值变更时触发事件来通知处理程序。

类型 用途
AddNotifyPropertyChangedAttribute(特性) 标记要处理的类或者成员属性。
IAopHandlerNotifyPropertyChanged(接口) 用于对外提供触发事件的函数接口。

c#

编译前:
[AddNotifyPropertyChanged]
class NotifyPropertyChangedDemo
{
    public int MyProperty { get; set; }
}

编译后:
[AddNotifyPropertyChanged]
internal class NotifyPropertyChangedDemo : INotifyPropertyChanged, IAopHandlerNotifyPropertyChanged
{
	private int _MyProperty;
	public int MyProperty
	{
		get
		{
			return _MyProperty;
		}
		set
		{
            // 赋值比较可用 AddNotifyPropertyChanged(IsTestEquals = false) 关闭。
			if (_MyProperty != value)
			{                 
				_MyProperty = value;
				IAopHandlerNotifyPropertyChanged.RaiseEvent(this, "MyProperty");
			}
		}
	}
	 //自动添加事件
	public event PropertyChangedEventHandler _nearAop_PropertyChanged;
    //自动添加的RaiseEvent方法。
	void IAopHandlerNotifyPropertyChanged.RaiseEvent(object sender, string propertyName)
	{
		PropertyChanged?.Invoke(sender, new PropertyChangedEventArgs(propertyName));
	}
}

1、由于自动生成了PropertyChanged事件和IAopHandlerNotifyPropertyChanging.RaiseEvent方法,因此在编译前无法使用。如需调用可以自行实现IAopHandlerNotifyPropertyChanging接口,代码实现参考上面的例子,或使用NearAop.AopHelper.RaiseEventPropertyChanged方法。

2、静态成员需要自行添加 PropertyChangedEventHandler静态事件字段。

返回目录

vb.net

编译前:
Imports NearAop
<AddNotifyPropertyChanged>
Public Class NotifyPropertyChangedDemo
    Property MyProperty As Integer
End Class

编译后:
<AddNotifyPropertyChanged>
Public Class NotifyPropertyChangedDemo
    Implements INotifyPropertyChanged, IAopHandlerNotifyPropertyChanged

    Private _MyProperty As Integer
    Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged

    Public Property MyProperty As Integer
        Get
            Return _MyProperty
        End Get
        Set(value As Integer)
                ’赋值比较可用 AddNotifyPropertyChanged(IsTestEquals:=False) 关闭
            If _MyProperty <> value Then
                _MyProperty = value
                [RaiseEvent](Me, "MyProperty")
            End If
        End Set
    End Property

    Sub [RaiseEvent](sender As Object, propertyName As String) Implements IAopHandlerNotifyPropertyChanged.[RaiseEvent]
        RaiseEvent PropertyChanged(sender, New PropertyChangedEventArgs(propertyName))
    End Sub

End Class

返回目录


2、属性代理

编译时自动为属性Get\Set方法植入调用代码。与属性变更通知的差异是可以获取到属性变更前后的值。

特性 对应接口 用途
AddProxyPropertyAttribute IAopHandlerProperty 用于标记要处理的类或属性,等效于同时处理Set\Get方法
AddProxyPropertySetAttribute IAopHandlerPropertySet 用于标记要处理的类或属性,处理Set方法
AddProxyPropertyGetAttribute IAopHandlerPropertyGet 用于标记要处理的类或属性,处理Get方法

返回目录

本地代理

本地代理可以直接实现IAopHandlerPropertyLocal接口,等效下面的代码。

编译前:
[AddProxyProperty]
class ProxyPropertyDemo : IAopHandlerProperty
{
    public int MyProperty { get; set; }

    public void PropertySetHandler<T>(Lazy<AopParamInfo> aopParamInfo, object sender, T value, Func<T> getValue, Action<T> setValue)
    {
        var propName = aopParamInfo.GetMemberName();
        Console.WriteLine($"{sender}.{propName}被修改, 修改前:{getValue()}, 新值:{value}");
        setValue(value);//执行修改
    }

    public T PropertyGetHandler<T>(Lazy<AopParamInfo> aopParamInfo, object sender, Func<T> getValue)
    {
        var propName = aopParamInfo.GetMemberName();
        var result = getValue();
        var msg = $"{sender}.{propName}被读取,值:{result}";
        Console.WriteLine(msg);
        return result;
    }
}

编译后:
[AddProxyProperty]
internal class ProxyPropertyDemo : IAopHandlerProperty, IAopHandlerPropertySet, IAopHandlerPropertyGet
{
	private int _MyPropert;
	private static Lazy<AopParamInfo> _nearAop_Info = AopParamInfo.CreateFactory<ProxyPropertyDemo>(385875971);

	public int MyProperty
	{
		get
		{
			return ((IAopHandlerPropertyGet)this).PropertyGetHandler(_nearAop_Info, this, new _nearAop_get_MyProperty);
		}
		set
		{
            //赋值比较可用 AddProxyProperty(IsTestEquals = false) 关闭
			if (_MyPropert != value)
			{
				((IAopHandlerPropertySet)this).PropertySetHandler(_nearAop_Info, this, value,  _nearAop_get_MyProperty, _nearAop_set_MyProperty));
			}
		}
	}

	public void PropertySetHandler<T>(Lazy<AopParamInfo> aopParamInfo, object sender, T value, Func<T> getValue, Action<T> setValue)
	{
		//---代码同上
	}

	public T PropertyGetHandler<T>(Lazy<AopParamInfo> aopParamInfo, object sender, Func<T> getValue)
	{
		//---代码同上
	}

	private int _nearAop_get_MyProperty() => _MyPropert;

	private void _nearAop_set_MyProperty(int value) => _MyPropert = value;
}

返回目录

外部代理

多个类使用同一个实现了IAopHandlerProperty接口的代理类处理。如果代理类(MyProxy)构造函数中有参数,将不会自动初始化.请自行初始化(参考SetProxySourceAttribute特性).

[AddProxyProperty(typeof(MyProxy))]
class ProxyPropertyDemo1
{
    public int MyProperty { get; set; }
}

[AddProxyProperty(typeof(MyProxy))]
class ProxyPropertyDemo2
{
    public int MyProperty { get; set; }
}

class MyProxy : IAopHandlerProperty
{
    public void PropertySetHandler<T>(Lazy<AopParamInfo> aopParamInfo, object sender, T value, Func<T> getValue, Action<T> setValue)
    {
       //---代码同上
    }

    public T PropertyGetHandler<T>(Lazy<AopParamInfo> aopParamInfo, object sender, Func<T> getValue)
    {
       //---代码同上
    }
}

返回目录


3、方法代理

编译时在原函数中植入代码,在进入函数和退出函数时调用接口实现代码植入。(进入函数时可以修改和读取函数中的参数值)

特性 对应接口 用途
AddProxyMethodAttribute IAopHandlerMethod 用于标记类或成员函数,包含(OnEntry和OnExit)
AddProxyMethodEntryAttribute IAopHandlerMethod 标记进入函数时执行。
AddProxyMethodExitAttribute IAopHandlerMethod 标记退出函数时执行。

基础用法

编译前:

[AddProxyMethod(typeof(Proxy2), IsUpdateValue = true, IsSetValueOnExit = true)]
class ProxyMethodDemo
{
    private int value1;
    private int value2;

    //要植入代码的方法
    public void SetValue(int value1, int value2)
    {
        this.value1 = value1;
        this.value2 = value2;
    }

    //要植入代码的方法
    public string GetValue(int value1, int value2)
    {
        return $"{this.value1} . {this.value2} . {value1} . {value2}";
    }   
}

//代理类,用于处理进入函数和退出函数时的逻辑
class Proxy2 : IAopHandlerMethod
{
	//进入函数时执行
    public void OnEntry(MethodArgs methodArgs)
    {
        //---------------------------获取参数的值
        //通过索引获取指定位置的参数值
        var value1 = methodArgs.TryGetValue<int>(0);
        //通过参数名称获取参数值
        var value2 = methodArgs.TryGetValue<int>("value2");

        //---------------------------修改参数值
        //通过索引修改指定位置的的参数值
        methodArgs.TrySetValue(0, 192);
        //通过参数名称修改参数值
        methodArgs.TrySetValue("value2", 168);

        //获取全部的参数值
        var values = string.Join(",", methodArgs.ParamValues);
        //获取方法名
        var methodName = methodArgs.MethodInfo.Name;            
        Console.WriteLine($"进入[{methodName}]方法时, value1 = {value1} , value2 = {value2}, 全部参数值 = {values}");
    }
    
	//退出函数时执行
    public TResult OnExit<TResult>(MethodArgs methodArgs, TResult result)
    {
        var methodName = methodArgs.MethodInfo.Name;
         return (TResult)(object)$"{methodName}方法返回 : {result}";
    }
}

返回目录

编译后:

[AddProxyMethod(typeof(Proxy2), IsUpdateValue = true, IsSetValueOnExit = true)]
internal class ProxyMethodDemo
{
	private int value1;
	private int value2;
	private static Lazy<AopParamInfo> _nearAop_Info1 = AopParamInfo.CreateFactory<ProxyMethodDemo>(100663328);
	
    //自动添加的代理类型字段。如果代理类构造函数有参数,将不会自动初始化.请自行初始化(参考SetProxySourceAttribute特性)
	private Proxy2 _nearAop_Porxy = new Proxy2();

	public void SetValue(int value1, int value2)
	{        
		var methodArgs = new MethodArgs<int, int>(_nearAop_Info1, this);
        //第一次获取参数
		methodArgs.SetValue(value1, value2);
		var aopHandlerMethod = AopHelper.TestNull<IAopHandlerMethod>("_nearAop_Porxy", _nearAop_Porxy);
        //调用OnEntry方法
		aopHandlerMethod.OnEntry(methodArgs);
        //!!!!!!执行参数值修改(默认关闭,特性 IsUpdateValue = true 时开启)
		methodArgs.OutValue(out value1, out value2);
        //执行原方法代码
		this.value1 = value1;
		this.value2 = value2;
        //!!!!!!第二次获取参数(默认关闭,特性 IsSetValueOnExit = true 时开启)
		methodArgs.SetValue(value1, value2);
        //调用OnExit方法
		aopHandlerMethod.OnExit<object>(methodArgs, null);
	}

	public string GetValue(int value1, int value2)
	{
		//同上
	}
}

执行结果:

var test = new ProxyMethodDemo();
test.SetValue(1, 2);
var result = GetValue(3, 4);
// result ==  "GetValue方法返回 : 192 . 168 . 192 . 168"

返回目录

自定义处理函数

使用特性的HandlerName属性指定处理函数名称。

[AddProxyMethod(typeof(Proxy3), HandlerName = "自定义函数")]
class ProxyMethodDemo
{
    /// <summary>
    /// 实例函数
    /// </summary>
    public void SetValue1(int value) { }

    /// <summary>
    /// 静态函数
    /// </summary>
    public static void SetValue2(int value) { }
}


class Proxy3
{
    //注意:函数签名与IAopHandlerMethod.OnEntry 一致
    public void 自定义函数(MethodArgs methodArgs)
    {
        var info = methodArgs.MethodInfo;
        var staticStr = info.IsStatic ? "静态" : "";
        Console.WriteLine($"进入{staticStr}函数[{info.DeclaringType}.{info.Name}]");
    }

    //注意:函数签名与IAopHandlerMethod.OnExit 一致
    public TResult 自定义函数<TResult>(MethodArgs methodArgs, TResult result)
    {
        var info = methodArgs.MethodInfo;
        var staticStr = info.IsStatic ? "静态" : "";
        Console.WriteLine($"退出{staticStr}函数[{info.DeclaringType}.{info.Name}]");
        return result;
    }
}

返回目录


4、接口代理

由于编译前代理字段可能为自动生成,用于配合代理模式使用。执行时会在类中实现目标接口,并将接口实现指向代理字段。如果代理类构造函数有参数,将不会自动初始化.请自行初始化(参考SetProxySourceAttribute特性)。如果代理类构造函数有参数,将不会自动初始化.请自行初始化(参考SetProxySourceAttribute特性)

特性 参数1 参数2
AddProxyInterface Type:代理类型 Type[]:目标接口

编译前:

[AddProxyInterface(typeof(Proxy4),typeof(IMyInterface1),typeof(IMyInterface2))]
class ProxyInterfaceDemo
{
}   

interface IMyInterface1
{
    void ShowMsg();
}

interface IMyInterface2
{
}

//代理类要求实现目标接口
class Proxy4: IMyInterface
{
    public void ShowMsg()
    {
        Console.WriteLine("接口代理测试成功!");
    }
}

编译后:

[AddProxyInterface(typeof(Proxy4), typeof(IMyInterface))]
internal class ProxyInterfaceDemo : IMyInterface, IMyInterface2
{
	//如果代理类构造函数有参数,将不会自动初始化.请自行初始化(参考SetProxySourceAttribute特性)
	private Proxy4 _nearAop_Porxy = new Proxy4();

	void IMyInterface.ShowMsg()
	{
		AopHelper.TestNull<IMyInterface>("_nearAop_Porxy", _nearAop_Porxy).ShowMsg();
	}
}

返回目录


5、SetProxySourceAttribute特性

用于标记代理类字段,通常情况下代理类字段由AOP自动生成,但在代理类构造函数中有参数的情况下不会自动初始化实例,需用户显式初始化。

!如自动初始化失败,并且用户没有手动初始化,运行时会抛出异常:

_nearAop_Porxy..... is empty,未将对象引用设置到对象的实例.

[AddProxyInterface(typeof(Proxy5), typeof(IMyInterface1))]
[AddProxyInterface(typeof(Proxy6), typeof(IMyInterface2))]
class ProxySourceDemo
{
    //(用户显式初始化)直接使用字段类型
    [SetProxySource]
    readonly Proxy5 proxy5 = new Proxy5("接口1");

    //(用户显式初始化)使用type
    [SetProxySource(typeof(Proxy6))]
    readonly object proxy6 = new Proxy6("接口2");
}


class Proxy5 : IMyInterface1
{
    private readonly string p1;
    public Proxy5(string p1) => this.p1 = p1;
}

class Proxy6 : IMyInterface2
{
    private readonly string p1;
    public Proxy6(string p1) => this.p1 = p1;

}

返回目录


6、SetCancelAopAttribute特性

标记SetCancelAopAttribute特性的成员或类型,AOP将忽略代码植入操作。
返回目录


7、AOP调试信息输出

在项目的输出文件目录obj\Debugobj\Release目录下新建文件NearAop.Debug
返回目录


8、代码混淆

在编译时对输出的(Dll、Exe)文件,进行混淆,不会影响源码。

启用混淆

项目中新建任意名称的Class并继承NearAop.ObfuscatedOption
C#:

class ObfuscatedOption : NearAop.ObfuscatedOption
{
    //没有自定义需求的情况下可忽略构造函数!
    public ObfuscatedOption()
    {
       //短名称文本,启用后成员将被修改为 "O火星文O";
       TargetName = "火星文";
       //混淆符号,启用后会替代O,要求大于16个字符,并且不能相同;
       Key = "АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ";         
       //注:某些字符无法用在成员变量上;
    }
}

编译后:
Image

VB.NET

Public Class ObfuscatedOption
    Inherits NearAop.ObfuscatedOption
    '没有自定义需求的情况下可忽略构造函数!
    Sub New()
       '短名称文本,启用后成员将被修改为 "O火星文O"
       TargetName = "火星文"
       '混淆符号,启用后会替代O,要求大于16个字符,并且不能相同;
       Key = "АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ"      
       '注:某些字符无法用在成员变量上;
    End Sub
End Class

编译后:
Image
返回目录

取消成员混淆

某些情况下需要反射成员,使用SetCancelObfuscatedAttribute特性标记指定的成员,可以取消混淆行为。

//如果没有使用构造函数,将自动判断标记的成员类型

//等同于 [SetCancelObfuscated(MemberType.Type)]
[SetCancelObfuscated]
class Test
{
    //等同于 [SetCancelObfuscated(MemberType.Method)]
    [SetCancelObfuscated]
    public void SetValue() { }

    //同时取消“函数”和“参数”的命名混淆
    [SetCancelObfuscated(MemberType.Method | MemberType.Parameter)]
    public void SetValue2(string param) { }
}

返回目录

混淆覆盖率

如果类型被定义为Public 其中被定义为Public的成员不会被混淆。否则外部引用当前DLL时将无法使用。合理使用访问级别关键字控制混淆覆盖率!

类型被定义为Public 且成员被定义为Public 时,成员及类型不会被混淆。

类型被定义为非Public 时成员会被混淆。例外:定义一个 internal级别的接口,但实现类是public 的情况也会取消成员的混淆。

c# Vb 是否混淆
public Public no
internal Friend yes
protected Protected yes
protected internal Protected Friend yes
private Private yes

空文件

简介

自用简单AOP和代码混淆 展开 收起
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
1
https://gitee.com/sesametechgroup/NearAop.git
git@gitee.com:sesametechgroup/NearAop.git
sesametechgroup
NearAop
NearAop
master

搜索帮助