返回首页

{A}
{S0}简介
在我的工作经验,我不得不处理一些用户的错误报告,关于我们公司的产品之一。这些报告包括旨在帮助我们检测错误导致的调用堆栈信息。
我们使用后,我们的生产代码混淆工具,所以调用堆栈错误报告所提供的信息,需要一些Äúhopping左右??一个模糊的地图和手册文本搜索。这Äúhopping??并不总是一件容易的事情做??混淆图是一个巨大的的XML文件的大小超过25 MB,和大多数文本编辑器不欣赏这样的信息量。这类编辑器的偏好是合理的,假设人为一个普通的文件很少超过1 MB边界上运行。
事情变得更糟,当你需要一些语法突出显示,甚至更多??XML树解析/导航。另一个大问题是有数量庞大的XML元素具有相同的混淆名称,以确定其类型,您应该手动分析父XML元素。任务定义
面对这些问题,我决定由名称解析的过程自动化,以帮助我们的支持团队。自动化任务的要求有以下几条:这应该是一个工具,可以找到原始类或类成员名称上的混淆名称。应尽可能简单的UI??我认为简单的任务不应该要求复杂的用户操作。使用LINQ to XML??这是一个方便和简单的方法来处理X​​ML数据。但是,也许,主要因素是,我,终于有机会在实践中使用这一技术。
,AOS的具体步骤。首先,我们定义输入数据。
下面是调用堆栈的内容例如:

Type: System.ArgumentException

Stack:

   at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)

   at System.Collections.Generic.Dictionary.Insert(TKey key, TValue value, Boolean add)

   at ne.c(IError A_0)

   at ne.c(ErrorListEventArgs A_0)

   at ne.c.a()

   at ne.c(Object A_0, EventArgs A_1)

   at System.Windows.Forms.Timer.OnTick(EventArgs e)

   at System.Windows.Forms.Timer.TimerNativeWindow.WndProc(Message& m)

   at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, 

                                                 IntPtr wparam, IntPtr lparam)

本公司使用的工具,其社区版是随Visual Studio中。混淆地图所有混淆器版本相同的格式,所以任何人都可以测试自己的代码名称解析工具。混淆地图是一个XML文件,其结构看起来像这样:{C}
LT; typegt;元素的​​结构如下:
<type>

  <name>type_name</name>            <!--Original type name.-->

  <newname>obfuscated_name</newname>        <!--Obfusctaed type name (Optional).-->

  <methodlist>                    <!--Types method list.-->

    <method>



      <signature>void(object, System.EventArgs)</signature>    <!--Method signature.-->

      <name>method_name</name>         <!--Original method name.-->

      <newname>obfuscated_name</newname>    <!--Obfusctaed method name (Optional).-->

    </method>

    ...

  </methodlist>

  <fieldlist>                     <!--Types filed list.-->

    <field>

      <signature>System.Windows.Forms.Button</signature>    <!--Field signature.-->

      <name>field_name</name>            <!--Original field name.-->

      <newname>obfuscated_name</newname>    <!--Obfuscated field name (Optional).-->

    </field>

    ...

  </fieldlist>

</type>

你会发现,混淆的名字始终是放置在一个可选的LT; newnamegt;元素。如果省略此元素,则该对象使用其原始名称。
接下来,我们应该定义用户的输入。例如,我们需要找到一个类型混淆的名称,AUA??通常情况下,我们搜索LT;吗??newnamegt; ALT / newnamegt ;???/ EM>字符串,这将找到的所有类型,方法和领域有混淆的名称,AOA???有大约数千复杂项目的结果。要实现我们的搜寻目标,我们应该父元素分析和检测,如果它是一个LT; typegt;元素。
因此,用户通常使用两个参数:第一个参数是一个模糊的地图文件的路径,第二个参数是一个混淆的名称。也有一个(隐式)的参数吗??搜索结果类型(类型/方法/领域),但我们会尝试从第二推断此参数。据用户界面简单的要求,我觉得这就够了。键入名称搜索
第一个任务是一个原始类型的名称使用混淆的名称进行搜索。让,AOS做到这一点。首先,我们必须争取从所有类型的映射文件。这是一个简单的:
// Construct the XElement to access map file.

XElement map = XElement.Load("sample.xml");

var types = map.Descendants("type");

这里的主要操作是map.Descendants("; typequot";)调用,它返回所有的LT; typegt从XElement的内容元素。
的descendants()方法返回一个XML元素的后代的纯集合。该集合包含子元素,孙子元素等,所以,如果我们写map.Descendants(),我们会从地图文档中的所有XML元素枚举。这种方法有一个重载,允许指定匹配的元素的名称过滤器过滤输出集合。我用这个重载筛选出的LT以外的所有元素; typegt;
注意:过滤器的名称应该是一个完全合格的名称,这意味着过滤元素,如果有一个命名空间,必须有过滤器的名称也。
注意:请记住,后人使用延后的执行,这意味着实际的访问底层的XML将执行当您第一次访问的后裔,而不是当你调用这个函数的结果。
map.Descendants("; typequot";)将指定元素类型的扫描的整个XML树,它是不是最有效的解决方案,但最简单的一个。使用直接降低了整个XML扫描会更有建设性的导航元素。例如,我们可以使用这样的表达:
var types = map.Elements("mapping").Elements("module").Elements("type");

根据XML内容,这种表达可以给我们十倍的性能提升比后人来。但对于这种应用,我更喜欢简单的后裔功能。
现在我们都在LT; typegt;元素,需要找到与混淆的名称匹配。我实现了这个使用LINQ查询:
string obfuscatedName = "a"; // Define the search criteria.

var found = from type in types

          // Filter type elements by obfuscatedName matching.

          where type.Element("newname").Value == obfuscatedName

          select type;

类型的集合,是相匹配的类型过滤,AOS子元素LT; newnamegt;通过混淆名称的内容。这也可以使用Where扩展方法,lambda表达式:
var found = types.Where(t => t.Element("newname").Value == obfuscatedName);

正如前文所述,LT; newnamegt;元素是可选的,所以返回null元素("newnamequot;)时,该类型是不混乱。为了避免可能的NRE,我,Äôve改变LINQ查询以下:
var found = from type in map.Descendants("type")

// Declare name element variable.

let name = type.Element("newname") ?? type.Element("name")

// Filter type elements by obfuscatedName matching.

where name.Value == obfuscatedName

select type;

这段代码将搜索混淆或原来的名称匹配obfuscatedName类型。
let关键字引入了一个新的变量名,拥有一个LT; newnamegt;元素或LT; namegt;元素的​​情况下没有LT; newnamegt元素存在。这个新变量是一个匿名类型,包含了当前LT; typegt;元素和一个LT; namegt; /公升; newnamegt;元素。类似的东西:
new { Type = type, Name = type.Element("newname") ?? type.Element("name") };

整个查询可代表在C#作为:
IEnumerable<xelement> found = map.Descendants("type").

      Select(type => new { Type = type, Name = type.Element("newname") }).

      Where(tn => tn.Name.Value == obfuscatedName).

      Select(tn => tn.Type);

我们可以看到,有第二个选择函数调用,(结合匿名类型的投影)会给我们带来一些性能损失,所以我重写查询以下:
var found = from type in map.Descendants("type")

// Filter type elements by obfuscatedName matching.

where (type.Element("newname") ?? type.Element("name")).Value == 

    obfuscatedName

select type;

接下来要做的事情是处理复杂类型的名称。在XML中,这些名称是分开的,而不是由?????? ??????例如,ÄúMyClass.MyInternalClass??/ em>的名称是,ÄúMyClass / MyInternalClass??/ em>的字符串值。我们只需要在obfuscatedName变量替换??????上??????允许匹配:
obfuscatedName = obfuscatedName.Replace('.', '/');

最后,我们提供了匿名类型的投影,这将有助于我们处理在C#中的搜索结果:
var types = from type in found

          select new {

            ModuleName = type.Parent.Element("name").Value,

            TypeName = type.Element("name").Value

          };

之后,你可以处理搜索结果如你所愿,例如,输出到控制台:
foreach (var type in types) {

    Console.WriteLine("Module:      {0}", type.ModuleName);

    Console.WriteLine("Type:        {0}", type.TypeName);

    Console.WriteLine();

}
摘要
,AOS。我们已经发现的类型,提供了混淆的名称。在,我会一步到LINQ查询更深提供的字段和方法的名称解决解决方案。
感谢您的时间,并欢迎您发表任何问题或建议。

回答

评论会员:韦斯琼斯 时间:2012/01/25
不Visual Studio的一种已经为我们做这?
在IDE中,去项目 - >属性 - >设置。你添加有什么,你就可以访问,这是一个获取代码生成的类的W / Properties.Settings.Default.MySetting
评论会员:。萨科Dorier 时间:2012/01/25
Visual Studio中使用相同的技术做设置
不过的AppSettings和。设置是不是同样的事情。
的AppSettings创建,使管理员可以轻松地修改您的应用程序的配置,只是通过修改app.config文件,。
设置不是手工设置编辑创建,以便开发人员可以很容易地保存在他的用户首选项的代码。可以是全球性的,或由用户设置
评论会员:。韦斯琼斯 时间:2012/01/25
啊,我看。 ,分享你们的辛勤工作非常出色感谢
评论会员:!OmarGamil 时间:2012/01/25
好工作,有同样的问题太
感谢分享
评论会员:尼克巴特勒 时间:2012/01/25
你们是真正推动了一些令人印象深刻的东西{S2}

感谢分享!

尼克

----------------------------------{ BR}是优秀的相互{S2}
评论会员:萨科Dorier 时间:2012/01/25
感谢这是令人鼓舞的!如果你喜欢这篇文章,你应该明白适用的原则:这篇文章
|萨沙理发
评论会员:游客 时间:2012/01/25
。尼古拉斯,非常漂亮的工作但是你要知道你说"configfile中,文件路径,和语言时,我们通过调用任务的属性。filepath是生成的文件的路径。您可以看到configfile中和FILEPATHITaskItem,和它的工作,如果它只是一个字符串,但,ITaskItem有更多的信息,喜欢的MSBuild的元数据在现实中,我做的不是需要它,和我只是可以使用字符串代替,但觉得一个好的做法,以使用ITaskItem。毕竟,它的接近我的领域类(这是MSBuild的)。"它不是很清楚,我在语言传递。您有以下codeprelang="xml"spanclass="code-keyword"</spanspanclass="code-leadattribute"ClassGeneratorTask/spanspanclass="code-attribute"ConfigFile/spanspanclass="code-keyword"="/spanspanclass="code-keyword"@(AppConfigWithTargetPath)"/spanspanclass="code-attribute"FilePath/spanspanclass="code-keyword"="/spanspanclass="code-keyword"@(SettingsGenerated)"/spanspanclass="code-keyword">/spanspanclass="code-keyword"</spanspanclass="code-keyword"//spanspanclass="code-leadattribute"ClassGeneratorTask/spanspanclass="code-keyword">/span/pre/code那么,语言提供有萨沙理发微软的VisualC#MVP2008/2009CodeprojectMVP2008/2009Your最好的朋友就是你。我是我最好的朋友。我们有着共同的看法,并未落认为我的博客:imgsrc=http://www.orcode.com/img/ico/thumbs_up.gif
萨科Dorier
评论会员:游客 时间:2012/01/25
实际上,它并不清楚我会解决这个问题。语言有一个默认值硬编码为"C#"。,在此,这应该是:codeprespanclass="code-keyword"</spanspanclass="code-leadattribute"ClassGeneratorTask/spanspanclass="code-attribute"Language/spanspanclass="code-keyword"="/spanspanclass="code-keyword"$(Language)"/spanspanclass="code-attribute"ConfigFile/spanspanclass="code-keyword"="/spanspanclass="code-keyword"@(AppConfigWithTargetPath)"/spanspanclass="code-attribute"FilePath/spanspanclass="code-keyword"="/spanspanclass="code-keyword"@(SettingsGenerated)"/spanspanclass="code-keyword">/spanspanclass="code-keyword"</spanspanclass="code-keyword"//spanspanclass="code-leadattribute"ClassGeneratorTask/spanspanclass="code-keyword">/span/pre/code指定的"语言"属性是VB或CSHARP内每csproj或vbproj
。萨沙理发
评论会员:游客 时间:2012/01/25
哦,OK,这使得意义。嘿人在哪里你拿起你的WCF的知识,你做了一些非常先进的WCF的东西,在您的其他物品的人你做了什么学习?萨沙理发微软的VisualC#MVP2008/2009CodeprojectMVP2008/2009Your最好的朋友就是你。我是我最好的朋友。我们有着共同的看法,并未落认为我的博客:imgsrc=http://www.orcode.com/img/ico/thumbs_up.gif
ř ICK C O DE
评论会员:游客 时间:2012/01/25
为什么我会做到这一点?我不明白任何的实际需要......我失去了一些点
?萨科Dorier
评论会员:游客 时间:2012/01/25
想象一下,您删除您设置app.config文件,或重新命名它。你必须手动更新所有在您的代码引用appsetting的关键。而且,如果你忘了一个,你有没有在编译时发现了一个bug。我干了什么,你不能拼错AppSetting关键在你的代码,如果关键的变化,编译器将捕获你的错误。这篇文章的主要观点是,你可以很容易地编译生成的类,在生成过程透明,并获得它的IntelliSense。一个很好的例子是,如果你有一堆xsd文件,并且您希望类编译过程中自动生成每次修​​改一个XSD文件。这样,如果你修改XSD,打破的东西在你的代码,编译器将能够赶上它,而不必担心任何事情。的代码也更容易代码,感谢的IntelliSense。微软的XML队这样做,我觉得他们称之为LINQ到XSD。但现在你能想象从DSL生成这样的类
。twebb72
评论会员:游客 时间:2012/01/25
我觉得这篇文章很有趣,很有创意话虽这么说,我同意该线程的顶部,它并没有成为大多数应用程序有用的目的。如果您需要更改根据环境或数据库连接的设置;,你有问题,因为你需要重新发出另一个构建。最小化的生成数量,通常是发布管理的最佳战略。TFS使得它很容易重新建立一个特定的版本,但它往往只是堵塞的Drop文件夹,使版本号的意义不大。最终,如果你需要你的释放代码的可移植性(这是有应用程序的99%),你需要在运行时设置待定离开,尤伯杯尊重所有文章!我通过阅读他们所有的工作我的方式!感谢。{五}"我说我们起飞和NUKE从轨道,以确保它的唯一方法。"
Natza Mitzi
评论会员:游客 时间:2012/01/25
创建一个设置文件,将它移动到属性文件夹一旦你这样做,所有的设置都充分打字,控制和可以改变使用的设置设计师。代码类是自动创建的,并可以通过属性的名称空间访问。NatzaMitzi
萨科Dorier
评论会员:游客 时间:2012/01/25
的设置是保存在C:\用户\[用户​​名]\应用程序数据\本地和C:\用户\[用户​​名]\应用程序数据\漫游用户机器上,而不是在配置文件。设置用于大多保存用户的偏好,而在配置文件中的appSettings使用轻松配置您的应用程序所使用的一些键/值对。但也许我应该做的,而不是appSettings节的ConnectionString节的文章。(你只需要改变2行代码,这样做的发电机)
丹尼尔沃恩
评论会员:游客 时间:2012/01/25
我真的很喜欢你,Äôre使用MSBuild萨科做。非常酷。我不知道的文章,如果在引进更多的解释可能会从中受益;画一个更清楚地了解你正在努力实现的代码,什么。我认为,额外的清晰度可以让你的代码更加闪耀,它应该是因为它,AOS伟大的工作。我有一个5。欢呼声,丹尼尔丹尼尔沃恩博客:{A7}公司:{A8}