返回首页

简介
欢迎到我的写作。NET程序集反编译的旅程。首先,我将尝试开发一个理论来反编译的MSIL。我只是做我做任何MSIL指令要求。但我牢记,我反编译的MSIL。因此,当问我推了一个变量的值,我把该变量在栈上的名称。简单的案例
理解代码,它是必需的,你知道每个MSIL指令实际上没有什么参考。下面是一个示例程序来测试,如果我们的概念作品:

namespace DisasmIL

{

    class Math

    {

        public int add(int x, int y)

        {

            return x + y;

        }

    }

    class Program

    {

        static void Main(string[] args)

        {

            Math m;

            int a, b;

            m = new Math();

            a = 20;

            b = 50;

            int p = m.add(a, b);

        }

    }

}

我们只检查方法之一。主要方法。的主要方法是编译时,它的形式如下。{C}
我们解析一行行:
.method private hidebysig static void Main(string[] args) cil managed

这是一个具有默认的起始大括号的方法声明。输出码:
static void Main(string[] args)

{

堆栈:[空]
.entrypoint

// Code size 23 (0x17)

.maxstack 3

.locals init (

[0] class DisasmIL.Math m,

[1] int32 a,

[2] int32 b,

[3] int32 p

)

这里是无需解释。他们言自明。声明变量。输出码:
DisasmIL.Math m;

int a;

int b;

int p;

堆栈:[空]
IL_0000: nop:

无关(NOP)
输出代码:[无]
堆栈:[空]
IL_0001: newobj instance void DisasmIL.Math::.ctor()

我们的堆栈上创建一个新的DisasmIL.Math例如,使用一个默认的构造函数,所以我们把"新DisasmIL.Math()quot;
,输出的代码:
没有堆栈:新DisasmIL.Math(。 )
IL_0006: stloc.0

所以我们弹出堆栈的顶部和分配到一个局部变量0。输出码:
m = new DisasmIL.Math();

堆栈:[空]
IL_0007: ldc.i4.s 20

我们做的是在堆栈上推恒定20
输出代码:[无]
堆栈:20
IL_0009: stloc.1

所以我们弹出的最高价值和它分配给局部变量1。输出码:
堆栈:[空]
IL_000a: ldc.i4.s 50

我们在栈上推恒定50
输出代码:[无]
堆栈:50
IL_000c: stloc.2

弹出顶部的价值,并将其分配到一个局部变量2
输出代码。
b = 50;

堆栈:[空]
推局部变量0,tstack
输出代码1和2:无
堆栈:M,A,B
IL_0010: callvirt instance int32 DisasmIL.Math::'add'(int32,int32)

IL_0015: stloc.3

我们调用add - 1,堆栈的顶部,例如顶级2值的方法。对于任何方法调用,如果它返回一个值,它是返回堆栈上。因此,检查的下一条指令。如果它是一个stloc,那么我们指定返回值。我们的返回值分配给局部变量3

输出代码。
p=m.add(a,b);

堆栈:[空]
IL_0016: ret

返回void。所以除了右大括号中的代码。输出码:
}

堆栈:[空]
现在,如果你添加的输出码在一起,你会发现原来的C#代码生成。这简单的情况下。我们需要测试它是否为复杂的情况下。让我们现在做一些更有趣的事情。if结构
让我们来看看最基本和最有用的if - then结构。编译器会生成一个条件分支。我们创建了一个结构的指示块。块是分隔的分支指令(像brtrue)和分支标签(如IL_0019 - 其中的代码跳转)。我们的条件是在栈上。如果我们找到一个真正的条件分支,我们否定它,并把它作为一个if语句的条件。块是最初的MSIL块,我们将转换后的C#代码(我们可能需要递归这里吗?)。请注意,标签不存储在MSIL。它只是在一个方法的MSIL偏移字节。

我们举一个简单的方法来测试我们的理论与if结构。
public int IfStructure(int a, int b)

{

    if (a < b)

    {

        System.Console.Write("Condition is true");



    }

    return b;

}

这里是由Visual Studio 2005编译器生成的MSIL代码。
.method public hidebysig instance int32 IfStructure(int32 a, int32 b) cil managed

{

    // Code size 31 (0x1f)

    .maxstack 2

    .locals init ([0] int32 CS$1$0000,

    [1] bool CS$4$0001)

    IL_0000: nop

    IL_0001: ldarg.1

    IL_0002: ldarg.2

    IL_0003: clt

    IL_0005: ldc.i4.0

    IL_0006: ceq

    IL_0008: stloc.1

    IL_0009: ldloc.1

    IL_000a: brtrue.s IL_0019

    IL_000c: nop

    IL_000d: ldstr "Condition is true"

    IL_0012: call void [mscorlib]System.Console::Write(string)

    IL_0017: nop

    IL_0018: nop

    IL_0019: ldarg.2

    IL_001a: stloc.0

    IL_001b: br.s IL_001d

    IL_001d: ldloc.0

    IL_001e: ret

} // end of method ControlStructures::IfStructure

我们现在开始解析:
.method public hidebysig instance int32 IfStructure(int32 a, int32 b) cil managed

{

// Code size 31 (0x1f)

.maxstack 2

.locals init ([0] int32 CS$1$0000,

[1] bool CS$4$0001)

这些行生成的输出,我们没有做任何处理的MSIL。有一个方法定义和局部变量。我们改变局部变量名到C#目前的名称,而不会发生冲突。为了简单起见,这里我们只需更换'$'用'_'。评估MSIL指令的一件事,我们必须保持一个局部变量与变量数的地图。在这个例子中,政务司司长$ 1 $ 0000是本地的int类型的变量0。为了清楚起见,我们不显示位置图。一个简单的STL地图应工作

输出。
public int IfStructure(int a, int b)

{

int32 CS_1_0000;

bool CS_4_0001;

堆栈:[空]
IL_0000: nop

IL_0001: ldarg.1

IL_0002: ldarg.2

因此,我们推堆栈方法的参数1和2:

输出:[无]

堆栈:A,B
IL_0003: clt

这教导我们,如果堆栈的顶部是小于堆栈的顶部。这两个元素从堆栈中弹出,结果到堆栈。当然没有输出

输出:[无]

堆栈:
ALT,B
IL_0005: ldc.i4.0

负载(指推)值为0的整数常量堆栈

输出:[无]
堆栈:ALT,B,0。
IL_0006: ceq

检查堆栈顶部1等于堆栈的顶部。结果到堆栈
输出:[无]
堆栈:LT; B == 0
IL_0008: stloc.1

IL_0009: ldloc.1

还有什么呢?存储在局部变量堆栈的顶部,并再次加载跟踪。我们决定以前,当我们在一个局部变量存储一定的价值,我们使用分配给该变量和输出代码。为了清楚起见,我添加了括号:

输出:
CS_4_0001 = (a < b == 0)

堆栈:CS_4_0001
IL_000a: brtrue.s IL_0019

我们有一个条件分支。我们创建了一个块的开始从这里到IL_0019。并把他们在大括号。我们的条件是在栈上。我们找到一个真正的条件分支,所以我们否定它,并把它作为一个结构如果我在开始时说

输出。
if(!CS_4_0001)

{

IL_000c: nop

IL_000d: ldstr "Condition is true"

IL_0012: call void [mscorlib]System.Console::Write(string)



IL_0017: nop

IL_0018: nop

}

堆栈:[空]
IL_0019: ldarg.2

IL_001a: stloc.0

IL_001b: br.s IL_001d

IL_001d: ldloc.0

IL_001e: ret

我们不分析它们在这里。他们是很简单的了解和使用我们在简单的例子中看到的方法,我们可以分析它们。
确定,我们现在可以稍微复杂一些的代码工作。这也将产生quot产生的代码; structurequot,但一个有趣的方式。如果我们添加多一点智力产生quot; gotoquot;输出的特殊分支,我们不能用,如果处理的代码,我们得到以下结果

这样的代码... ...。
for(int i=0;i<10;i++)

{

...

}

...

...将被转换为:
int i;

i=0;

label_1:



if(i<10)

{

---

i++;

goto label_1;

}

...

OK,但没有问题。稍后我们来看看循环。现在,你可能会发现,我们的理论产生一个有趣的代码块,如:
CS$4$0001=((a<b)==0);



if(!CS$4$0001)

{



---



}

这里的优化场景。但是,我们现在跳过它。循环
我想,作为一个反编译器作家,就没有循环。程序员使用数以千计的goto语句与if语句。但因为它是没有的情况下,我必须了解如何解析MSIL循环生成的指令。

最常见的循环的三种类型(同时,同时)while循环的基础之一。从任何类型的这些循环产生的块通常有一个条件跳转(通常是一个brtrue.slt; labelgt;)作为最后一个指令块。从如果差分结构的指令跳转的偏移量小于当前指令的偏移量。 for和while循环有一个无条件分支(br.slt; labelgt;)偏移块的开始和结束之间。跳转的目标通常是在开始条件检查的指示。 DO - while循环缺乏的原因这个分支 - 块结束之前,它不会测试条件。

所以,我们得到类似下面的MSIL块的指令块:LT / labelgt; LT / labelgt;
IL_0010: br.s IL_005a ;do-while loop does not have this line

IL_0012: nop



[any type and number of instructions]



IL_0059: nop



[condition check instruction- results boolean value on stack]



IL_0060: brtrue.s IL_0012

一边看着,如果结构,我们已经看到如何创建一个布尔条件,如果结构。东西都是类似的循环。按照说明 - 堆栈顶元素时,发现条件跳转 - 反向(添加只是一个!)brtrue.s跳,并把它作为循环语句条件语句。请注意,条件跳转的目标只是在或块的起始指令后的指令。

在这里,我们发现,我们不能有一个单一的通过反编译。我们必须确定在迭代前的最后一次迭代的代码块。到目前为止,我们可以识别的if块,同时,做结构,而通过使用条件跳转指令和他们的目的地。如果有目的地后偏置电流和其他目的地之前,当前偏移的偏移。并不能区分得很清楚,但做而没有跳的开头。当然,可以从嵌套循环生成的嵌套块

有一些复杂的循环变化 - 无限循环一样,foreach循环等,他们都没有太大的不同。但现在,让我保持未完成的,等待你的回应,修正错误,并继续再进一步。发表评论,投票支持它,并显示我的失误。工具
我已经使用Visual Studio 2005和MSIL反汇编程序自带的。NET平台的安装。历史2007年9月24日:战后初期

回答

评论会员:麦克Hankey 时间:2011/12/15
不要在WPF上游荡,很多时候,但就是这样一个控制
。感谢
一个女孩给我打电话说,'你过来。有没有人在家。"我走过去。没有人的家!罗德尼Dangerfield
评论会员:会员4770292 时间:2011/12/15
好文章 - 非常有用的代码位
评论会员:会员4734187 时间:2011/12/15
这是很大的控制。只用了很短的时间转换为Visual Studio 2010和集成在一个测试项目中的SplitButton。
多谢了!
最好的问候安德斯
评论会员:会员4734187 时间:2011/12/15
。真的很容易使用和实施是伟大的
评论会员:Espiritu 时间:2011/12/15
您好:

与此对照的东西奇怪。演示作品描述的那样,但是当我在其他项目中使用以下的指示,按钮显示仅在设计模式中的空白矩形和运行不显示在所有。我用的是VS 2010中,该项目迁移到框架4.0。

奇怪的是,我插在我的新项目的示范项目,并有splitbutton正确显示
评论会员:。Roeni 时间:2011/12/15
听起来像一个XAML文件的样式问题,确保您有插入到您的项目corretly?
我还使用VS2010与Net4,在所有
没有问题
评论会员:。kairu7 时间:2011/12/15
您好,
我发现我只能添加VistaSplitButtonStyle作为风格,

如何回合的,因为我需要它来搭配我其他正常的按钮
感谢
评论会员:stg609 时间:2011/12/15
优秀文章
评论会员:马丁Pozor 时间:2011/12/15
我有2到绑定相关的修复:

如果菜单项是数据绑定(如]),一个问题是,上下文菜单中的位置的属性是不适用(因为EnsureContextMenuIsValid方法的一部分创建的ContextMenu实例)

修改EnsureContextMenuIsValid方法WHIS修复:

private void EnsureContextMenuIsValid()

{

    if (this.ContextMenu == null)

    {

        this.ContextMenu = new ContextMenu();

    }

 

    this.ContextMenu.PlacementTarget = this;

    this.ContextMenu.Placement = Placement;

 

    this.ContextMenu.Opened -= ((sender, routedEventArgs) => IsContextMenuOpen = true);

    this.ContextMenu.Closed -= ((sender, routedEventArgs) => IsContextMenuOpen = false); 

    this.ContextMenu.Opened += ((sender, routedEventArgs) => IsContextMenuOpen = true);

    this.ContextMenu.Closed += ((sender, routedEventArgs) => IsContextMenuOpen = false);            

}
第二个问题是发生也与数据绑定。如果(!ContextMenu.HasItems)在OnDropDown方法检查评估为false时,项目的约束(但只在某些情况下)和菜单没有显示的数据。所以我已经删除了这check.Martin Pozor(婆子)
评论会员:马丁Pozor 时间:2011/12/15
出色的控制,谢谢

然而,有一个问题。 ButtonChrome应该渲染不仅打开上下文菜单时按下,而且当鼠标按下按钮(像普通按钮)。目前,点击按钮(在斯普利特和按钮模式),没有提供视觉反馈给用户。

下面的XAML片段插入ControlTemplate.Triggers部分修复的问题:

除了经典和Vista的所有主题:

<Trigger Property="IsPressed" Value="true" >

    <Setter Property="RenderPressed" Value="true" TargetName="buttonChrome" />

</Trigger>

经典主题:

<Trigger Property="IsPressed" Value="true">

    <Setter Property="BorderStyle" TargetName="buttonChrome" Value="RaisedPressed"/>

</Trigger>

Vista主题:

<Trigger Property="IsPressed" Value="True">

    <Setter Property="Style" TargetName="outerBorder1" Value="{StaticResource outerBorderPressed}"/>

    <Setter Property="Style" TargetName="innerBorder1" Value="{StaticResource innerBorderPressed}"/>

    <Setter Property="Style" TargetName="outerBorder2" Value="{StaticResource outerBorderPressed}"/>

    <Setter Property="Style" TargetName="innerBorder2" Value="{StaticResource innerBorderPressed}"/>

</Trigger>
马丁Pozor(婆子)
上周三,2月24日,2010下午03:47
修改
评论会员:chukky4 时间:2011/12/15
基本修复这个伟大的控制。感谢
评论会员:!FreQi 时间:2011/12/15
感谢你这真是太好了控制!我已经使用了示例代码使用一个StackPanel设置在我SplitButton的形象,但我并不清楚如何使用Icon属性的MenuItems。我试着设置图标="资源\ icon.png",这是相同的文件,我用我​​StackPanel的形象,但它呈现的文字而不是图像。

我使用Blend 3中,想确认这是所有在XAML
评论会员:FreQi 时间:2011/12/15
我想通了一点点帮助,从这篇文章
{A}
LT; Wpf_Controls:SplitButton.Contentgt;

LT; StackPanel的方向="水平"GT;
LT图像的X:名称="img_Name"来源="资源\ Image.png"宽度="17"的高度="18"/ GT;
LT; TextBlock的Text ="键名"保证金="3,0,0,0"/ GT; LT / StackPanelgt;
LT; / Wpf_Controls:SplitButton.Contentgt;

LT; MENUITEM头="菜单项1"点击="btnsName_Menuitem1_Click"GT; LT; MenuItem.Icongt;

LT图片来源="资源\ Image1.png"宽度="17"的高度="18"/ GT; LT / MenuItem.Icongt;
LT / MenuItemgt;

; MENUITEM头="菜单项2"点击="btnsName_Menuitem2_Click"GT; LT; MenuItem.Icongt;
&# 160;
LT图片来源="资源\ Image2.png"宽度="17"的高度="18"/ GT; LT / MenuItem.Icongt;
LT / MenuItemgt;
评论会员:west188:不支持 时间:2011/12/15
会员4770292
评论会员:游客 时间:2011/12/15
支持你,这不是他的工作。很高兴,他作出了贡献一个非常有用的文章,源代码的控制和容易理解的演示应用程序。如果你不能图从那里出来-你真的不应该编程
west188
评论会员:游客 时间:2011/12/15
您好所选的项目不显示在按钮。:(
大卫Veeneman
评论会员:游客 时间:2011/12/15
。这种控制的很好的工作-我真的很喜欢它我有一个使用工具栏上的控制问题。盒外的WPF按钮采取放置在工具栏控件时工具栏上的按钮造型。然而,此按钮保留其默认样式-没有工具栏按钮的造型。我缺少的属性设置此按钮,以显示工具栏的造型吗?我添加一个按钮的用户希望清单的要求,自动工具栏上的按钮造型,放置在一个工具栏时,再次,很好的工作,并感谢。大卫Veenemanwww.veeneman.com
MrPMorris
评论会员:游客 时间:2011/12/15
!恭喜你,这是非常好的我真的需要降下来的数据绑定的物品。你是否有机会加入的ItemsSource和ItemTemplate中?好!皮特
mraviator
评论会员:游客 时间:2011/12/15
我想在运行时使用代码添加额外的子菜单项,而不是在XAML中的前期。例如,child1和child2段将添加在基于一个给定的事件的运行时XAML中定义的结构:主-Sub1的----Child1----Child2-Sub2的-SUB3这是可能的
?acm_hk
评论会员:游客 时间:2011/12/15
我太满足了同样的问题而我SplitButton类添加以下新​​的方法来解决它。公共无效UpdateContextMenu(MenuItem的项目1){EnsureContextMenuIsValid();this.ContextMenu.Items.Add(项目1);}在你的程序中,SplitButtonbtn1=新SplitButton()MenuItem的M1=新的MenuItem()m1.Header="SUB1";MenuItem的m1_1=新的MenuItem()m1_1.Header="sub1_1";m1.Items.Add(m1_1);MenuItem的M2=新的MenuItem()m2.Header="SUB2";btn1.UpdateContextMenu(M1);btn1.UpdateContextMenu(M2);
DavideMar
评论会员:游客 时间:2011/12/15
有可能使用这个控制在Silverlight2?添加的引用是不可能的beacauseWPF调试。我寻找一种解决方法,在Silverlight中使用的splitbutton..,为Silverlight创建的任何想法或有人知道这种控制
?超级劳埃德
评论会员:游客 时间:2011/12/15
!男子{S0}火车站列车进站。一个公共汽车站,巴士站。我的办公桌上,我有一个工作站...._________________________________________________________{BR}我的程序永远不会有错误,他们只是随机特征
。ssing
评论会员:游客 时间:2011/12/15
发布本文感谢。我真的很喜欢它。我使用VS2008SP1和我很有一对夫妇的问题。1。SplitButton项目有一个参考Microsoft.Windows.Design.Markup这不是我的系统上发现的,但它似乎并没有阻止我运行演示。2。我试图改变Dropdowm模式(见下文)从默认的分割,当我按一下按钮上的任何地方,没有什么下降。codeprespanclass="code-keyword"</spanspanclass="code-leadattribute"m:SplitButton/spanspanclass="code-attribute"Mode/spanspanclass="code-keyword"="/spanspanclass="code-keyword"Dropdown"/spanspanclass="code-attribute"Margin/spanspanclass="code-keyword"="/spanspanclass="code-keyword"0,1,0,1"/spanspanclass="code-attribute"Padding/spanspanclass="code-keyword"="/spanspanclass="code-keyword"5,0,5,0"/spanspanclass="code-attribute"Placement/spanspanclass="code-keyword"="/spanspanclass="code-keyword"Bottom"/spanspanclass="code-attribute"HorizontalAlignment/spanspanclass="code-keyword"="/spanspanclass="code-keyword"Center"/spanspanclass="code-attribute"VerticalAlignment/spanspanclass="code-keyword"="/spanspanclass="code-keyword"Center"/spanspanclass="code-attribute"Height/spanspanclass="code-keyword"="/spanspanclass="code-keyword"24"/spanspanclass="code-attribute"Click/spanspanclass="code-keyword"="/spanspanclass="code-keyword"SplitButton_Click"/span spanclass="code-attribute"Style/spanspanclass="code-keyword"="/spanspanclass="code-keyword"{DynamicResource{x:Staticm:SplitButtonResources.VistaSplitButtonStyleKey}}"/spanspanclass="code-keyword">/spanspanclass="code-keyword"</spanspanclass="code-leadattribute"m:SplitButton.Content/spanspanclass="code-keyword">/spanspanclass="code-keyword"</spanspanclass="code-leadattribute"StackPanel/spanspanclass="code-attribute"Orientation/spanspanclass="code-keyword"="/spanspanclass="code-keyword"Horizontal"/spanspanclass="code-keyword">/spanspanclass="code-keyword"</spanspanclass="code-leadattribute"Image/spanspanclass="code-attribute"Source/spanspanclass="code-keyword"="/spanspanclass="code-keyword"Icons\mail.ico"/spanspanclass="code-attribute"Width/spanspanclass="code-keyword"="/spanspanclass="code-keyword"16"/spanspanclass="code-attribute"Height/spanspanclass="code-keyword"="/spanspanclass="code-keyword"16"/spanspanclass="code-keyword"//spanspanclass="code-keyword">/spanspanclass="code-keyword"</spanspanclass="code-leadattribute"TextBlock/spanspanclass="code-attribute"Text/spanspanclass="code-keyword"="/spanspanclass="code-keyword"Send/Receive"/spanspanclass="code-attribute"Margin/spanspanclass="code-keyword"="/spanspanclass="code-keyword"3,0,0,0"/spanspanclass="code-keyword"//spanspanclass="code-keyword">/spanspanclass="code-keyword"</spanspanclass="code-keyword"//spanspanclass="code-leadattribute"StackPanel/spanspanclass="code-keyword">/spanspanclass="code-keyword"</spanspanclass="code-keyword"//spanspanclass="code-leadattribute"m:SplitButton.Content/spanspanclass="code-keyword">/spanspanclass="code-keyword"</spanspanclass="code-leadattribute"MenuItem/spanspanclass="code-attribute"Header/spanspanclass="code-keyword"="/spanspanclass="code-keyword"Sendandreceive_all"/spanspanclass="code-keyword"//spanspanclass="code-keyword">/spanspanclass="code-keyword"</spanspanclass="code-leadattribute"MenuItem/spanspanclass="code-attribute"Header/spanspanclass="code-keyword"="/spanspanclass="code-keyword"ReceiveAll"/spanspanclass="code-keyword"//spanspanclass="code-keyword">/spanspanclass="code-keyword"</spanspanclass="code-leadattribute"MenuItem/spanspanclass="code-attribute"Header/spanspanclass="code-keyword"="/spanspanclass="code-keyword"SendAll"/spanspanclass="code-keyword"//spanspanclass="code-keyword">/spanspanclass="code-keyword"</spanspanclass="code-leadattribute"Separator/spanspanclass="code-keyword"//spanspanclass="code-keyword">/spanspanclass="code-keyword"</spanspanclass="code-leadattribute"MenuItem/spanspanclass="code-attribute"Header/spanspanclass="code-keyword"="/spanspanclass="code-keyword"Hotmail(Default)"/spanspanclass="code-keyword"//spanspanclass="code-keyword">/spanspanclass="code-keyword"</spanspanclass="code-leadattribute"MenuItem/spanspanclass="code-attribute"Header/spanspanclass="code-keyword"="/spanspanclass="code-keyword"Gmail"/spanspanclass="code-keyword"//spanspanclass="code-keyword">/spanspanclass="code-keyword"</spanspanclass="code-keyword"//spanspanclass="code-leadattribute"m:SplitButton/spanspanclass="code-keyword">/span/pre/code
ssing
评论会员:游客 时间:2011/12/15
我想通了,使其真正作为一个左击下拉行为的一种方式。只需要修改你的应用程序如下按钮的单击处理程序:私人无效SplitButton_Click(对象发件人,发送RoutedEventArgs) { (((SplitButton)发件人)模式==SplitButtonMode.Dropdown) {((SplitButton)发件人)ContextMenu.PlacementTarget=(SplitButton)发件人; ((SplitButton)发件人)ContextMenu.IsOpen=TRUE; e.Handled=真; 返回}
alrh
评论会员:游客 时间:2011/12/15
喜ssing感谢指出错误,我不能看着这一段时间,没有其他人发现的错误,我很惊讶,可能没有人使用它在下拉模式,反正我上传一个修复CodeProject上。再次感谢。艾伦...