.NET Reactor代码混淆注意事项
C#开发的一个dll,在使用.NET Reactor进行代码混淆后,调用混淆后的dll发生异常,记录一下踩过的坑(自己给自己挖的,与.NET Reactor无关)
一、对象转换遇到NULL
现象
我的代码中存在要将DataTable转换为对象Object的操作,对象转换代码如下:
根据对象属性的名字进行值的转换
internal class Tools
{
public static T ConvertObject<T>(DataRow dr) where T : new()
{
var v = typeof(T).GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
List<string> _ArryColumnNames = new List<string>();
foreach (DataColumn col in dr.Table.Columns)
{
_ArryColumnNames.Add(col.ColumnName);
}
T t = new T();
foreach (var s in v)
{
var ColName = _ArryColumnNames.Where(w => String.Equals(w, s.Name, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
if (!String.IsNullOrEmpty(ColName))
{
if (object.Equals(dr[ColName], DBNull.Value)) continue;
{
s.SetValue(t, dr[ColName]);
}
}
}
return t;
}
}
代码中对象定义如下:
internal class SNDetail
{
public string doccode { get; set; }
public string seed { get; set; }
public long maxid { get; set; }
public int turns { get; set; }
}
现在如果我们用 .NET Reactor 混淆代码,那么最后得到的dll中,SNDetail 这个对象的属性会被更改名称
代码混淆原则之一,非开放public的属性更改一个名字使代码反编译后难以阅读
此时就会发现一个问题,属性被重命名了,这个时候用 Tools.ConvertObject<SNDetail>(datasn.Rows[0]) 方法转换对象就会出现问题了,
混淆后的SNDetail类代码
解决办法
1、完善Tools.ConvertObject方法,增加一个特性,然后取特性的值,类属性中给需要转换的字段设置这个特性
2、把类设置为public,这样就不会被混淆了
public混淆后的SNDetail代码
二、对象属性无法赋值
.NET Reactor 代码混淆时 勾选了 NecroBit
类库代码中有一个基类:
public abstract class ModelDocNo
{
/// <summary>
/// 单据标识,系统自动生成切不可重复
/// </summary>
public string DocCode { get; set; }
private string _seed;
/// <summary>
/// 单据种子,如果为空,取DocCode
/// </summary>
public string seed
{
get
{
if (String.IsNullOrEmpty(_seed))
return DocCode;
else
return _seed;
}
set
{
_seed = value;
}
}
/// <summary>
/// 单据名称
/// </summary>
public string DocName { get; set; }
/// <summary>
/// 单据头
/// </summary>
public string DocHeader { get; set; }
/// <summary>
/// 单据头间隔符号
/// </summary>
public string Separate { get; set; }
private GenerateDocSNRule _DocType = GenerateDocSNRule.Up;
/// <summary>
/// 单据生成规则
/// </summary>
public GenerateDocSNRule DocType { get { return _DocType; } set { _DocType = value; } }
/// <summary>
/// 自定义生成标记
/// </summary>
public string CustomerSeed { get; set; }
public string DocRule
{
get
{
string RuleType = "";
switch (DocType)
{
case GenerateDocSNRule.Up:
RuleType = "Up"; break;
case GenerateDocSNRule.Year:
RuleType = "Year"; break;
case GenerateDocSNRule.Year_Month:
RuleType = "Year-Month"; break;
case GenerateDocSNRule.Year_Month_Day:
RuleType = "Year-Month-dd"; break;
case GenerateDocSNRule.Custom:
RuleType = "Customer"; break;
}
return RuleType;
}
}
private int _Length = 5;
/// <summary>
/// 单据长度
/// </summary>
public int Length { get { return _Length; } set { _Length = value; } }
//bool isInit = false;
//public void Init(DbContext dbContext)
//{
// if (isInit == true) return;
// SqlParameter[] para = new SqlParameter[] {
// new SqlParameter("@DocCode", this.DocCode)
// };
// string sql = "SELECT * FROM sys_DataSN WHERE DocCode=@DocCode";
// DataTable dt = dbContext.Database.SqlQueryDataTable(sql, para);
// if (dt.Rows.Count > 0)
// {
// DocHeader = ConvertLib.ToString(dt.Rows[0]["docHeader"]);
// DocType = (GenerateDocSNRule)Enum.Parse(typeof(GenerateDocSNRule), ConvertLib.ToString(dt.Rows[0]["docType"]));
// Separate = ConvertLib.ToString(dt.Rows[0]["separate"]);
// Length = ConvertLib.ToInt(dt.Rows[0]["length"]);
// }
// else
// {
// string sqlInsert = "INSERT INTO sys_DataSN(docCode,docName,docHeader,separate,docType,[length]) VALUES(@DocCode,@DocName,@DocHeader,@Separate,@DocType,@Length)";
// SqlParameter[] pInsert = new SqlParameter[] {
// new SqlParameter("@DocCode",SqlDbType.VarChar,50){ Value=this.DocCode},
// new SqlParameter("@DocName",SqlDbType.NVarChar,50){ Value=this.DocName},
// new SqlParameter("@DocHeader",SqlDbType.VarChar,10){ Value=this.DocHeader??""},
// new SqlParameter("@Separate", SqlDbType.VarChar,2){ Value=this.Separate??""},
// new SqlParameter("@DocType", SqlDbType.VarChar,20){ Value=this.DocType.ToString()},
// new SqlParameter("@Length", SqlDbType.Int){ Value=this.Length},
// };
// dbContext.Database.ExecuteSqlCommand(sqlInsert, pInsert);
// }
// isInit = true;
//}
}
在使用.NET Reactor进行类库代码混淆后,我们在项目中创建一个类,集成该基类
public class SNAPPRouterAuthorize : ModelDocNo
{
public SNAPPRouterAuthorize()
{
base.DocCode = "MicroAPPRouterAuthorize";
base.DocName = "微应用编号";
base.DocHeader = "APP";
base.Length = 4;
base.DocType = GenerateDocSNRule.Custom;
}
}
调试项目,我们会发现,不管怎么样,就是无法给基类的属性赋值
看看基类混淆后的代码:
通过代码我们可以发现端倪, .NET Reactor 混淆后,基类属性被直接返回null了
解惑
这里不要疑惑,先来看下 NecroBit 的解释,
NecroBit 是一种强大的保护技术,通过将方法中的 CIL 代码替换为加密代码,为您的敏感知识产权提供全面保护。 这样就不可能对您的方法源代码进行反编译/逆向工程。
再回到项目中调试,这时候,如果直接查看对象,的确看到的属性都是null,但是我们再直接查看属性值呢?a.DocCode 就能正确的显示出属性,具体原因自己体会吧,所以这个不影响项目正常运行,但是肯定会对性能有所影响的吧