本次反编译用的是IL Spy工具,反编译的是winform程序,反编译后需要修改的代码主要有以下几种情况:
1、复杂lamda表达式反编译后会被拆解成多个部分,比较乱,如下例,出现这种情况的基本都是:
//反编译后代码
private sealed class <>c
{
public static readonly ControlUtil。<>c <>9 = new ControlUtil.<>c();
public static CancelEventHandler <>9__54_0;
public static CancelEventHandler <>9__55_0;
internal void <SetEditorString4Name>b__54_0(object s, CancelEventArgs e)
{
ControlUtil.txtEditor_EditValueChanging_4StringCommonName(s, new ChangingEventArgs(string.Empty, (s as TextEdit).Text));
}
}
//调用处
Control arg_4D_0 = txtEditor;
CancelEventHandler arg_4D_1;
if ((arg_4D_1 = DevControlUtil.<>c.<>9__54_0) == null)
{
arg_4D_1 = (ControlUtil.<>c.<>9__54_0 = new CancelEventHandler(ControlUtil.<>c.<>9.<SetEditorString4Name>b__54_0));
}
arg_4D_0.Validating += arg_4D_1;
改成正常代码后应该是
public void SetEditorString4Name(TextEdit txtEditor)
{
txtEditor.Validating += (sender, e) =>
{
ControlUtil.txtEditor_EditValueChanging_4StringCommonName(sender, new ChangingEventArgs(string.Empty, (sender as TextEdit).Text));
};
}
出现以上情况的基本都是lamda表达式,只要熟悉c#语法,理解逻辑,然后转换成正常写法就可以了。
2、部分switch语句中,如果是switch后的表达式是字符型,反编译后也会出现乱码,如下所示:
//switch部分代码 完整代码太长了
uint num = <PrivateImplementationDetails>.ComputeStringHash(skinName);
if (num <= 1961623285u)
{
if (num <= 1360554982u)
{
if (num != 721696580u)
{
if (num != 940092246u)
{
if (num != 1360554982u)
{
return;
}
if (!(skinName == "iMaginary"))
{
return;
}
this.iMaginary.Checked = true;
return;
}
else
{
if (!(skinName == "Lilian"))
{
return;
}
this.iLilian.Checked = true;
return;
}
}
else
{
if (!(skinName == "Black"))
{
return;
}
this.iBlack.Checked = true;
return;
}
}
}
修改后的代码为:
switch(skinName)
{
case "iMaginary":
this.iMaginary.Checked = true;
break;
case "Lilian":
this.iLilian.Checked = true;
break;
case "Black":
this.iBlack.Checked = true;
break;
case "London Liquid Sky.DevExpressEx":
this.iLondoLiquidSky.Checked = true;
break;
case "Glass Oceans":
this.iGlassOcean.Checked = true;
break;
case "Office 2007 Silver":
this.iOffice2007Silver.Checked = true;
break;
}
3、窗体文件还原
这块一开始我是参照正常窗体需要的文件格式去挨个还原的,即一个窗体有一个.cs文件,一个.Designer.cs文件,一个.resx文件。反编译后的文件是将前两个合到一个文件里了,资源文件是一个.resources文件,即一个.cs文件,一个.resources文件,而这个资源文件vs是不识别的。还原过程如下:
1)、参照其他人的提供的方法,用vs自带的开发人工具命令行通过resgen命令将.resources转为.resx。但是如果窗体中有引用到本身电脑系统中没有的库,会转换不成功,一般都是第三方库。因为我这反编译的窗体有用到devexpress,我电脑装的devexpress版本和原代码用的不一致,有些.resources就没有转换成功,但似乎不影响结果。
2)、.Designer.cs文件的还原:将反编译后的 .cs文件复制一份,文件名改为.Designer.cs结尾,类名前都要加上partial关键字。 在.Designer.cs中只保留控件声明和初始化方法InitializeComponent()和Dispose()方法,其余都删掉。而将原来的.cs文件里的这些都删掉。
里面有些属性会被以get_ 和set_显示,需将这些还原,
即get_properties()=>properties,
set_properties(val)=>properties=val
事件改写方式如下:
//例如
this.barBtnGoBack.add_ItemClick(new ItemClickEventHandler(this.barBtnGoBack_ItemClick));
//改写后
this.barBtnGoBack.ItemClick+=(new ItemClickEventHandler(this.barBtnGoBack_ItemClick));
在正常的.Designer.cs文件中,是没有引用命名空间的,所以就需要把一些类或属性前带上命名空间,然后将最前面的引用都删掉,就这样改完就好了
3)、.cs文件中也会出现get、set式调用属性,改法与上面相同。
4)、最后将.Designer.cs、.resx以添加文件的方式添加到vs解决方案中来,会自动识别到同名的.cs 文件夹下。
5)、将原来.resources从项目中排除,否则编译会报错。
6)、重新编译,界面正常显示就好了。
以上还原过程若没有资源文件缺失,基本上是完整还原的,但过程是有些麻烦。如果窗体多且复杂,工作量会非常大,也会非常费时间。
后来我发现,有些窗体反编译后不用改动也可以正常打开并显示,所以以上步骤其实可以简化的。2、3步中,可以不用分两个文件,就放一个文件中,将那些以get、set调用属性的错误代码改掉就好了,界面显示那块没有错误了,也不用转换.resources文件,编译后会自动生成.resx文件
4、因资源缺失界面不能正常显示
这种通常都是缺图标和图片资源导致,界面上会提示找不到资源,解决方发就是将代码中这部分代码先注释掉,让界面正常展示,要是有资源可以再手动加上就可以了。代码类似下图,通常是第一行那会报错。
5、还有一种事件委托型的,反编译后代码如下
public event DoubleControlNumberValue OnDoubleControlValue
{
[CompilerGenerated]
add
{
DoubleControlNumberValue doubleControlNumberValue = this.OnDoubleControlValue;
DoubleControlNumberValue doubleControlNumberValue2;
do
{
doubleControlNumberValue2 = doubleControlNumberValue;
DoubleControlNumberValue value2 = (DoubleControlNumberValue)Delegate.Combine(doubleControlNumberValue2, value);
doubleControlNumberValue = Interlocked.CompareExchange<DoubleControlNumberValue>(ref this.OnDoubleControlValue, value2, doubleControlNumberValue2);
}
while (doubleControlNumberValue != doubleControlNumberValue2);
}
[CompilerGenerated]
remove
{
DoubleControlNumberValue doubleControlNumberValue = this.OnDoubleControlValue;
DoubleControlNumberValue doubleControlNumberValue2;
do
{
doubleControlNumberValue2 = doubleControlNumberValue;
DoubleControlNumberValue value2 = (DoubleControlNumberValue)Delegate.Remove(doubleControlNumberValue2, value);
doubleControlNumberValue = Interlocked.CompareExchange<DoubleControlNumberValue>(ref this.OnDoubleControlValue, value2, doubleControlNumberValue2);
}
while (doubleControlNumberValue != doubleControlNumberValue2);
}
}
改写就是把花括号内的内容全部去掉,结果如下
public event DoubleControlNumberValue OnDoubleControlValue;