也谈.Net中间语言——破解Delphi2CS行数和时间限制

  其实我一直在研究将Delphi版的传奇2源代码使用C#实现,不过由于我并没有学习过Delphi。就只能说先试着用一些工具转换代码。

  后来我在网上找到了一款软件:Delphi2CS。这款软件比较强大,虽然不支持条件编译,但竟然能对窗体控件达到非常高的转换效率!且直接生成vs.net的项目,令我十分高兴,这意味着我们只需要修复很少的部分。

  不过真正尝试转换的时候发现有一个限制:源文件不得超过500行。

  如下,图片为准换完成后的报告,代码为转换完成后的cs文件:

 1 using System;
 2 using System.IO;
 3 using DCPconst;
 4 using Base64;
 5 using Sha1;
 6 
 7 namespace DCPcrypt
 8 {
 9  // Delphi2CS trial converts the .PAS file that is less than 500 lines. 
10  // DCPcrypt.pas is 1029 lines. 
11  // Please purchse the final version to avoid the limitation.
12 }

  这令我十分困扰。

  后来在网上发现博客园的liufei同学解决了这个问题,他说明了方法并提供了可用程序。

  使用他的程序确实可以达到效果,但是另一个问题却出现了:

    

  大概意思是说过期了。我是从官网上下载了文件进行安装,然后将liufei同学的破解文件放到程序目录下执行的(如果是直接使用liu同学的程序是可行的)。不过出现了上图的情况。

  虽然不知道原因,不过貌似现在只能自己来破解了。

  先打开IL,载入程序

  

  

  然后依次点击“文件”=>“转储”,使用默认设置就行了

  

  然后打开il文件开始找,不过没什么挑战性,一下就找到了

  

  上述代码可用.NET Reflector还原

  1 public void F()
  2 {
  3     if (!this.TB)
  4     {
  5         try
  6         {
  7             DC.Q = this;
  8             StringBuilder builder = new StringBuilder();
  9             bool flag = false;
 10             StringBuilder builder2 = new StringBuilder();
 11             bool flag2 = false;
 12             StringBuilder builder3 = new StringBuilder();
 13             StringBuilder b = null;
 14             if (this.R != null)
 15             {
 16                 AB ab = null;
 17                 foreach (string str in this.R)
 18                 {
 19                     ab = this.NB.BB(str);
 20                     if (ab != null)
 21                     {
 22                         this.U(this.LD(ab.O()), null);
 23                     }
 24                 }
 25             }
 26             if (this.OB != null)
 27             {
 28                 foreach (string str2 in this.OB)
 29                 {
 30                     if (!str2.Equals(this.O()))
 31                     {
 32                         builder.Append("using ").Append(str2).Append(";").Append("\r\n");
 33                     }
 34                 }
 35             }
 36             string str3 = SB.U();
 37             if ((str3 != null) && (str3 != ""))
 38             {
 39                 builder.Append(str3);
 40             }
 41             if (this.EB != null)
 42             {
 43                 builder.Append(this.EB.Replace("U_K_N_O_W_N ", " "));
 44             }
 45             if (QB.B != 100)
 46             {
 47                 this.ED("Delphi2CS has expired.");
 48                 builder3.Append("// Delphi2CS has expired, please purchase the final version. \r\n");
 49                 flag = true;
 50             }
 51             else if (this.GB.A > 0x1f4)
 52             {
 53                 this.ED("Delphi2CS trial converts the .pas file that is less than 500 lines.");
 54                 builder3.Append(" // Delphi2CS trial converts the .PAS file that is less than 500 lines. \r\n");
 55                 string fileName = Path.GetFileName(this.O);
 56                 builder3.Append(string.Concat(new object[] { " // ", fileName, " is ", this.GB.A, " lines. \r\n" }));
 57                 builder3.Append(" // Please purchse the final version to avoid the limitation.\r\n");
 58                 flag = true;
 59             }
 60             if (!flag)
 61             {
 62                 if ((this.MB != null) && (this.MB.Count > 0))
 63                 {
 64                     foreach (YB yb in this.MB.ToArray())
 65                     {
 66                         if (yb.L() == null)
 67                         {
 68                             continue;
 69                         }
 70                         if (SB.J())
 71                         {
 72                             if (b == null)
 73                             {
 74                                 b = new StringBuilder();
 75                             }
 76                             b.Append("namespace " + this.O() + "\r\n{").Append("\r\n");
 77                             b.Append("  partial class ").Append(yb.B.A).Append("\r\n");
 78                             b.Append("    {\r\n");
 79                             b.Append(yb.L().U());
 80                             b.Append("    }\r\n");
 81                             b.Append("}\r\n");
 82                         }
 83                         builder3.Append(yb.HB());
 84                         this.MB.Remove(yb);
 85                     }
 86                 }
 87                 if ((this.MB != null) && (this.MB.Count > 0))
 88                 {
 89                     foreach (YB yb2 in this.MB)
 90                     {
 91                         builder3.Append(yb2.HB());
 92                     }
 93                 }
 94                 if (this.U.K.W != null)
 95                 {
 96                     flag2 = true;
 97                     StringBuilder builder5 = new StringBuilder();
 98                     builder5.Append(this.U.K.W.FB());
 99                     if (builder5.Length > 0)
100                     {
101                         builder2.Append("namespace ").Append(this.O()).Append(".Units\r\n");
102                         builder2.Append("{\r\n");
103                         builder2.Append(builder5.ToString());
104                         builder2.Append("}\r\n");
105                         builder2.Append("\r\n");
106                         string str5 = this.HB();
107                         if (str5 != null)
108                         {
109                             str5 = str5.Replace("U_K_N_O_W_N ", "");
110                             builder2.Append(str5);
111                         }
112                     }
113                 }
114             }
115             string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(this.O);
116             string a = fileNameWithoutExtension + ".Designer.cs";
117             if (this.RB)
118             {
119                 string str8 = this.NB.LB(this.O);
120                 fileNameWithoutExtension = fileNameWithoutExtension + str8;
121             }
122             else
123             {
124                 fileNameWithoutExtension = fileNameWithoutExtension + ".cs";
125             }
126             string str9 = this.O.ToLower().Replace(this.NB.K, this.NB.J);
127             if (!str9.StartsWith(this.NB.J))
128             {
129                 str9 = this.NB.J(str9, this.NB.J);
130             }
131             if (!str9.StartsWith(this.NB.J))
132             {
133                 str9 = this.NB.K(str9, this.NB.J);
134             }
135             str9 = Path.Combine(Path.GetDirectoryName(str9), fileNameWithoutExtension);
136             FileInfo info = new FileInfo(str9);
137             if (info.Exists)
138             {
139                 info.Delete();
140             }
141             else
142             {
143                 info.Directory.Create();
144             }
145             this.PC();
146             FileStream stream = info.Open(FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read);
147             StreamWriter writer = new StreamWriter(stream, Encoding.Default);
148             writer.Write(builder.ToString());
149             if (builder3.Length > 0)
150             {
151                 writer.WriteLine("namespace " + this.O() + "\r\n{");
152                 writer.Write(builder3.ToString());
153                 writer.WriteLine("}\r\n");
154             }
155             if (flag2)
156             {
157                 writer.Write(builder2.ToString());
158             }
159             writer.Close();
160             stream.Close();
161             writer = null;
162             stream = null;
163             if ((b != null) && (b.Length > 0))
164             {
165                 this.VC(a, b);
166             }
167             builder2 = null;
168             builder3 = null;
169             builder = null;
170             this.P = str9.Replace(this.NB.J, "");
171             if (this.P.StartsWith(Path.DirectorySeparatorChar.ToString()))
172             {
173                 this.P = this.P.Substring(1);
174             }
175             this.NB.T.Add(this.P);
176             if (this.KB != null)
177             {
178                 string key = this.KB.Replace(this.NB.J, "");
179                 this.JC("Creating " + Path.GetFileName(this.KB));
180                 try
181                 {
182                     this.LB.Close();
183                     this.NB.U.Add(key, this.P);
184                 }
185                 catch
186                 {
187                 }
188             }
189         }
190         catch (Exception exception)
191         {
192             this.NB.W(exception.ToString());
193             this.ED(exception.Message);
194         }
195     }
196 }

  上面的语句其实是一个条件判断,判断读取到的行数是否小于500,在第51行处。我们可以改到500000。

  行数限制似乎破解了,那么时间限制呢?文章第一副图片所示大概是说我们使用的是Delphi2CS评估版,而现在它过期了。

  破解过期时间很简单,我们在il文件中找到过期判断语句

 1 .method private hidebysig instance void 
 2           H(object A,
 3             class [mscorlib]System.EventArgs B) cil managed
 4   {
 5     // 代码大小       435 (0x1b3)
 6     .maxstack  4
 7     .locals init (string V_0,
 8              string V_1,
 9              class [mscorlib]System.Threading.ThreadStart V_2,
10              class [mscorlib]System.Threading.Thread V_3)
11     IL_0000:  ldsfld     int32 QB::B
12     IL_0005:  ldc.i4.s   100
13     IL_0007:  beq.s      IL_001d
14 
15     IL_0009:  ldstr      "Delphi2CS Evaluation Version has expired, please p"
16     + "urchase the final version."
17     IL_000e:  ldstr      "Error"
18     IL_0013:  ldc.i4.0
19     IL_0014:  ldc.i4.s   16

  搜索“Delphi2CS Evaluation”即可找到,上面代码第11行即判断了QB.B和100是否相等,我们通过.NET Reflector来查看可得下面的代码:

 1 private void H(object A, EventArgs B)
 2 {
 3     if (QB.B != 100)
 4     {
 5         MessageBox.Show("Delphi2CS Evaluation Version has expired, please purchase the final version.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Hand);
 6     }
 7     else
 8     {
 9         this.UB = this.O.Text;
10         if ((this.UB.Trim().Length == 0) || (this.UB == null))
11         {
12             MessageBox.Show("You must input an existed Delphi Project filename", "Error", MessageBoxButtons.OK, MessageBoxIcon.Hand);
13         }
14         else if (!File.Exists(this.UB))
15         {
16             MessageBox.Show("You must input an existed Delphi Project filename:\n '" + this.UB + "'", "Error", MessageBoxButtons.OK, MessageBoxIcon.Hand);
17         }
18         else
19         {
20             this.VB = this.J.Text;
21             if (this.VB.Trim().Length == 0)
22             {
23                 MessageBox.Show("Please specify an output path for the generated C# files", "Error", MessageBoxButtons.OK, MessageBoxIcon.Hand);
24             }
25             else
26             {
27                 if (!Directory.Exists(this.VB))
28                 {
29                     Directory.CreateDirectory(this.VB);
30                 }
31                 this.VB = Path.GetFullPath(this.VB);
32                 if (!this.VB.EndsWith(new string(Path.DirectorySeparatorChar, 1)))
33                 {
34                     this.VB = this.VB + Path.DirectorySeparatorChar;
35                 }
36                 string str = Path.GetDirectoryName(this.UB).ToLower();
37                 string str2 = Path.GetDirectoryName(this.VB).ToLower();
38                 if (str.StartsWith(str2))
39                 {
40                     MessageBox.Show("Please make sure the Output path is different from the project path.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Hand);
41                 }
42                 else
43                 {
44                     this.WB = new LD(this);
45                     ThreadStart start = new ThreadStart(this.I);
46                     Thread thread = new Thread(start);
47                     thread.Start();
48                     this.WB.ShowDialog(this);
49                     try
50                     {
51                         if (thread != null)
52                         {
53                             thread.Abort();
54                         }
55                         else
56                         {
57                             thread = null;
58                         }
59                     }
60                     catch
61                     {
62                     }
63                     this.WB = null;
64                     base.Activate();
65                 }
66             }
67         }
68     }
69 }

  其实能够猜到:这个方法是点击浏览按钮选择了文件后的事件处理方法。第一步就判断了QB.B是否等于100,如果不等的话就会终端执行。我们只需把if的条件设为永远不等即可,如下面这样

 1 .method private hidebysig instance void 
 2           H(object A,
 3             class [mscorlib]System.EventArgs B) cil managed
 4   {
 5     // 代码大小       435 (0x1b3)
 6     .maxstack  4
 7     .locals init (string V_0,
 8              string V_1,
 9              class [mscorlib]System.Threading.ThreadStart V_2,
10              class [mscorlib]System.Threading.Thread V_3)
11     IL_0000:  ldc.i4.s   100
12     IL_0005:  ldc.i4.s   100
13     IL_0007:  beq.s      IL_001d
14 
15     IL_0009:  ldstr      "Delphi2CS Evaluation Version has expired, please p"
16     + "urchase the final version."
17     IL_000e:  ldstr      "Error"
18     IL_0013:  ldc.i4.0
19     IL_0014:  ldc.i4.s   16

  在IL_0000里我把二元判断表达式左边的值从QB.B直接换成了100,这样的话就不存在过期了,因为if(100 != 100)永远为false!

  其实现在要做的就很简单了,把上面的0x1f4(即500)改大和把这个使用了QB.B判断并终止程序执行的地方修正(其实重要的地方有两个,上述的KD.H方法中和BB.F中,后者的if判断正在500行判断前)。我更改过后后进入vs.net的命令行生成可执行文件。

  

  

  按照liu同学的说法,delphi2cs程序需要.net framework3.5,所以vs2005的cmd无法编译,不过我没有尝试。按照上图的方法就能生成exe文件了,使用生成的文件替换掉安装目录下文件即可。

  我把破解了的文件上传上来,大家可以看看。

 

 欢迎您移步我们的交流群,无聊的时候大家一起打发时间:Programmer Union

 或者通过QQ与我联系:点击这里给我发消息

 (最后编辑时间2013-08-17 01:05:38)

 

posted @ 2013-08-17 01:01  云中双月  阅读(2193)  评论(2编辑  收藏  举报