ILSpy中baml转化为xaml的改进(四)

周一上班接着补充。

这些天状态的确低迷。上午对着电脑发了好一会呆。但活还是要干的。

上午的改进完了以后,面对一些小问题。

1。如何自动在反编译后的工程中,加入引用路径。

2。 在资源文件中,如果用到了模板类,则编不过。


  • 如何自动在反编译后的工程中,加入引用路径。

这个走了一点弯路。原以来为这个信息在.csproj文件,原来不是这样,而是在.csproj.user中。

有些吃惊,一直以为那个文件没有用。

先说一下为什么要有这样的需求:

因为正在看的程序,内容很多,但所感兴趣的东西,只是冰山一角,虽然这个一角也不小,所以,只需要看几个DLL就OK了。

但这些DLL是引用了其它的DLL的,所以,加引用路径是最简单的事情。当然,可以事先把一些可以注册的库用:gacutil /i
注册一下,也是个办法。

这里选择用引用路径。


发现引用路径在.csproj.user中,就好办了,只要找到一个地方,加一段代码就OK了:

在:ILSpy\TextView\DecompilerTextView.cs

中改进一下如下的代码就OK了。

Task<AvalonEditTextOutput> SaveToDiskAsync(DecompilationContext context, string fileName)
		{
			TaskCompletionSource<AvalonEditTextOutput> tcs = new TaskCompletionSource<AvalonEditTextOutput>();
			Thread thread = new Thread(new ThreadStart(
				delegate {
					try {
						Stopwatch stopwatch = new Stopwatch();
						stopwatch.Start();

                        //haoyujie 写入工程文件
						using (StreamWriter w = new StreamWriter(fileName)) {
							try {
								DecompileNodes(context, new PlainTextOutput(w));
							} catch (OperationCanceledException) {
								w.WriteLine();
								w.WriteLine("Decompiled was cancelled.");
								throw;
							}
						}
                        //把user设置拷到指定位置

                        //最后,把引用路径模板拷过去,因为需要引用许多其它的库,引用路径在这个文件中指定
                        string strUserTmppath = Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory + "hayujie_usertmp.usertmp");
                        string strDescUserpath = fileName + ".user";
                        FileInfo fi = new FileInfo(strUserTmppath);
                        if (File.Exists(strDescUserpath))
                        {
                            File.Delete(strDescUserpath);
                        }
                        fi.CopyTo(strDescUserpath);

						stopwatch.Stop();
						AvalonEditTextOutput output = new AvalonEditTextOutput();
						output.WriteLine("Decompilation complete in " + stopwatch.Elapsed.TotalSeconds.ToString("F1") + " seconds.");
						output.WriteLine();
						output.AddButton(null, "Open Explorer", delegate { Process.Start("explorer", "/select,\"" + fileName + "\""); });
						output.WriteLine();
						tcs.SetResult(output);
					} catch (OperationCanceledException) {
						tcs.SetCanceled();
						#if DEBUG
					} catch (AggregateException ex) {
						tcs.SetException(ex);
						#else
					} catch (Exception ex) {
						tcs.SetException(ex);
						#endif
					}
				}));
			thread.Start();
			return tcs.Task;
		}
至于里面提到的模板文件hayujie_usertmp.usertmp,可以自己想名字,内容也可以自己写,给出一个例子:


<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <ReferencePath>E:\work\lib\</ReferencePath>
  </PropertyGroup>
</Project>

提不起精神,感觉代码写得对不起观众。


  • 在资源文件中,如果用到了模板类,则编不过。

在反编译过程中,发现有一个resource.baml反编译不成功。

仔细分析后一天多,才明白,这里面用到了模板类,不了解在C#中叫什么,在C++里要模板,

也就是说,在一个核心库中定义了一个模板类,然后这个模板类的实现(c#是不是叫装箱),相当于一个类,在使用者的库中才被编译器实现,也就是说,实际上它在两个地方,当然在C++只会存在于一个地方,因为C++的模板,是预编译阶段完成的。

但好象C#的实现,有点象容器(所以模板在C#中好象就叫容器类),两边的库都要用到,这也容易理解,C#是解释性语言。

各有各的好外,总得来说,还是装箱这种方式,简单得多。

而这个类,恰好被resource.baml里面引用到了。而ILSPY就是错了。

具体出错的内容

模板类名`[[实现类的命名空间,类名,版本号,KEY]]
注意,那个`,是最奇怪的,不清楚是怎么出来的,60H,就是键盘上esc 下面的那个键。见鬼啊。

而正常的类名,只有一个模板类名。然后ILSpy ,以大无畏的猜测的精视,猜出前面是命名空间,后面是类名,当然,大多数时候,它都是对的。

对微软的统一语言进行时的二进制码不熟,所以,一步步逆推到这,就停下了,因为再整,就对不起老板给开的工资了,毕竟还有工作要做。

如果有哥们对二进制码非常熟的,请告知。


从内存中,看到ILSPY对于模板类的反编译,并不正确之后,决定稍稍修剪一下代码,虽然结果不完全正确,也总比什么都不出来强。

后来,真的可用了。


这里,把改完的代码放在这里:

ILSpy.BamlDecompiler\Ricciolo.StylesExplorer.MarkupReflection\XmlBamlReader.cs

		void ReadTypeInfo()
		{
			short typeId = reader.ReadInt16();
			short assemblyId = reader.ReadInt16();
			string fullName = reader.ReadString();
			assemblyId = (short)(assemblyId & 0xfff);
			TypeDeclaration declaration;

            int indexpp = fullName.IndexOf("[[");    //说明这个类是模板类


            if (indexpp >= 0)
            {

                int indexppend = fullName.IndexOf("]]");    //说明这个类是模板类
                fullName=fullName.Substring(indexpp+2,indexppend-indexpp-2);
     
            }


                if (fullName.IndexOf(',')>=0)
                {
                    int douhao = fullName.IndexOf(',');
                    fullName = fullName.Substring(0,douhao);
                }

                int length = fullName.LastIndexOf('.');

                if (length != -1)
                {
                    string name = fullName.Substring(length + 1);
                    string namespaceName = fullName.Substring(0, length);

                    declaration = new TypeDeclaration(this, this.Resolver, name, namespaceName, assemblyId);

                }
                else
                {
                    declaration = new TypeDeclaration(this, this.Resolver, fullName, string.Empty, assemblyId);
                }
   
			this.typeTable.Add(typeId, declaration);
		}

这段代码,对原有的代码进行了修改,最后可以工作,但结果应该是不正确的,但也不耽误用了。


另外,这里,把在逆推的过程中,用到的代码,也贴出来,减少大家逆推的时间。

因为逆推有几个难题:

1。 出错的时候,读入错误信息的地方,早就过去了。

2。文件流stream,是顺序的,不是随机的,这样,就不能再读一次。

所以,加了这段代码分析内存:


ILSpy.BamlDecompiler\Ricciolo.StylesExplorer.MarkupReflection\BamlBinaryReader.cs


public override string ReadString()
        {
            //haoyujie,为调试资源错误,因为现在在资源中,如果出现模板类,就会出错。
            string strInner = base.ReadString();

            if (strInner.StartsWith("出错的那个模板的类的名称"))  //这句是重点,加入拦截
            {
                int ll = 500;
                Stream basestream = base.BaseStream;
                byte[] buffer = new byte[ll];
                if (basestream.CanSeek)
                {
                    basestream.Seek(-ll, SeekOrigin.Current);
                }
                buffer = base.ReadBytes(ll);

            }
            return strInner;
        }

就这么多吧。

这个系列,也就基本上结束了。


你可能感兴趣的:(反编译,XAML,ilspy,BAML,WFP)