也谈.Net中间语言——破解Delphi2CS行数和时间限制
其实我一直在研究将Delphi版的传奇2源代码使用C#实现,不过由于我并没有学习过Delphi。就只能说先试着用一些工具转换代码。
后来我在网上找到了一款软件:Delphi2CS。这款软件比较强大,虽然不支持条件编译,但竟然能对窗体控件达到非常高的转换效率!且直接生成vs.net的项目,令我十分高兴,这意味着我们只需要修复很少的部分。
不过真正尝试转换的时候发现有一个限制:源文件不得超过500行。
如下,图片为准换完成后的报告,代码为转换完成后的cs文件:

using System;
using System.IO;
using DCPconst;
using Base64;
using Sha1; namespace DCPcrypt
{
// Delphi2CS trial converts the .PAS file that is less than 500 lines.
// DCPcrypt.pas is 1029 lines.
// Please purchse the final version to avoid the limitation.
}
这令我十分困扰。
后来在网上发现博客园的liufei同学解决了这个问题,他说明了方法并提供了可用程序。
使用他的程序确实可以达到效果,但是另一个问题却出现了:

大概意思是说过期了。我是从官网上下载了文件进行安装,然后将liufei同学的破解文件放到程序目录下执行的(如果是直接使用liu同学的程序是可行的)。不过出现了上图的情况。
虽然不知道原因,不过貌似现在只能自己来破解了。
先打开IL,载入程序


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

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

上述代码可用.NET Reflector还原
public void F()
{
if (!this.TB)
{
try
{
DC.Q = this;
StringBuilder builder = new StringBuilder();
bool flag = false;
StringBuilder builder2 = new StringBuilder();
bool flag2 = false;
StringBuilder builder3 = new StringBuilder();
StringBuilder b = null;
if (this.R != null)
{
AB ab = null;
foreach (string str in this.R)
{
ab = this.NB.BB(str);
if (ab != null)
{
this.U(this.LD(ab.O()), null);
}
}
}
if (this.OB != null)
{
foreach (string str2 in this.OB)
{
if (!str2.Equals(this.O()))
{
builder.Append("using ").Append(str2).Append(";").Append("\r\n");
}
}
}
string str3 = SB.U();
if ((str3 != null) && (str3 != ""))
{
builder.Append(str3);
}
if (this.EB != null)
{
builder.Append(this.EB.Replace("U_K_N_O_W_N ", " "));
}
if (QB.B != )
{
this.ED("Delphi2CS has expired.");
builder3.Append("// Delphi2CS has expired, please purchase the final version. \r\n");
flag = true;
}
else if (this.GB.A > 0x1f4)
{
this.ED("Delphi2CS trial converts the .pas file that is less than 500 lines.");
builder3.Append(" // Delphi2CS trial converts the .PAS file that is less than 500 lines. \r\n");
string fileName = Path.GetFileName(this.O);
builder3.Append(string.Concat(new object[] { " // ", fileName, " is ", this.GB.A, " lines. \r\n" }));
builder3.Append(" // Please purchse the final version to avoid the limitation.\r\n");
flag = true;
}
if (!flag)
{
if ((this.MB != null) && (this.MB.Count > ))
{
foreach (YB yb in this.MB.ToArray())
{
if (yb.L() == null)
{
continue;
}
if (SB.J())
{
if (b == null)
{
b = new StringBuilder();
}
b.Append("namespace " + this.O() + "\r\n{").Append("\r\n");
b.Append(" partial class ").Append(yb.B.A).Append("\r\n");
b.Append(" {\r\n");
b.Append(yb.L().U());
b.Append(" }\r\n");
b.Append("}\r\n");
}
builder3.Append(yb.HB());
this.MB.Remove(yb);
}
}
if ((this.MB != null) && (this.MB.Count > ))
{
foreach (YB yb2 in this.MB)
{
builder3.Append(yb2.HB());
}
}
if (this.U.K.W != null)
{
flag2 = true;
StringBuilder builder5 = new StringBuilder();
builder5.Append(this.U.K.W.FB());
if (builder5.Length > )
{
builder2.Append("namespace ").Append(this.O()).Append(".Units\r\n");
builder2.Append("{\r\n");
builder2.Append(builder5.ToString());
builder2.Append("}\r\n");
builder2.Append("\r\n");
string str5 = this.HB();
if (str5 != null)
{
str5 = str5.Replace("U_K_N_O_W_N ", "");
builder2.Append(str5);
}
}
}
}
string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(this.O);
string a = fileNameWithoutExtension + ".Designer.cs";
if (this.RB)
{
string str8 = this.NB.LB(this.O);
fileNameWithoutExtension = fileNameWithoutExtension + str8;
}
else
{
fileNameWithoutExtension = fileNameWithoutExtension + ".cs";
}
string str9 = this.O.ToLower().Replace(this.NB.K, this.NB.J);
if (!str9.StartsWith(this.NB.J))
{
str9 = this.NB.J(str9, this.NB.J);
}
if (!str9.StartsWith(this.NB.J))
{
str9 = this.NB.K(str9, this.NB.J);
}
str9 = Path.Combine(Path.GetDirectoryName(str9), fileNameWithoutExtension);
FileInfo info = new FileInfo(str9);
if (info.Exists)
{
info.Delete();
}
else
{
info.Directory.Create();
}
this.PC();
FileStream stream = info.Open(FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read);
StreamWriter writer = new StreamWriter(stream, Encoding.Default);
writer.Write(builder.ToString());
if (builder3.Length > )
{
writer.WriteLine("namespace " + this.O() + "\r\n{");
writer.Write(builder3.ToString());
writer.WriteLine("}\r\n");
}
if (flag2)
{
writer.Write(builder2.ToString());
}
writer.Close();
stream.Close();
writer = null;
stream = null;
if ((b != null) && (b.Length > ))
{
this.VC(a, b);
}
builder2 = null;
builder3 = null;
builder = null;
this.P = str9.Replace(this.NB.J, "");
if (this.P.StartsWith(Path.DirectorySeparatorChar.ToString()))
{
this.P = this.P.Substring();
}
this.NB.T.Add(this.P);
if (this.KB != null)
{
string key = this.KB.Replace(this.NB.J, "");
this.JC("Creating " + Path.GetFileName(this.KB));
try
{
this.LB.Close();
this.NB.U.Add(key, this.P);
}
catch
{
}
}
}
catch (Exception exception)
{
this.NB.W(exception.ToString());
this.ED(exception.Message);
}
}
}
上面的语句其实是一个条件判断,判断读取到的行数是否小于500,在第51行处。我们可以改到500000。
行数限制似乎破解了,那么时间限制呢?文章第一副图片所示大概是说我们使用的是Delphi2CS评估版,而现在它过期了。
破解过期时间很简单,我们在il文件中找到过期判断语句
.method private hidebysig instance void
H(object A,
class [mscorlib]System.EventArgs B) cil managed
{
// 代码大小 (0x1b3)
.maxstack
.locals init (string V_0,
string V_1,
class [mscorlib]System.Threading.ThreadStart V_2,
class [mscorlib]System.Threading.Thread V_3)
IL_0000: ldsfld int32 QB::B
IL_0005: ldc.i4.s
IL_0007: beq.s IL_001d IL_0009: ldstr "Delphi2CS Evaluation Version has expired, please p"
+ "urchase the final version."
IL_000e: ldstr "Error"
IL_0013: ldc.i4.
IL_0014: ldc.i4.s
搜索“Delphi2CS Evaluation”即可找到,上面代码第11行即判断了QB.B和100是否相等,我们通过.NET Reflector来查看可得下面的代码:
private void H(object A, EventArgs B)
{
if (QB.B != )
{
MessageBox.Show("Delphi2CS Evaluation Version has expired, please purchase the final version.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Hand);
}
else
{
this.UB = this.O.Text;
if ((this.UB.Trim().Length == ) || (this.UB == null))
{
MessageBox.Show("You must input an existed Delphi Project filename", "Error", MessageBoxButtons.OK, MessageBoxIcon.Hand);
}
else if (!File.Exists(this.UB))
{
MessageBox.Show("You must input an existed Delphi Project filename:\n '" + this.UB + "'", "Error", MessageBoxButtons.OK, MessageBoxIcon.Hand);
}
else
{
this.VB = this.J.Text;
if (this.VB.Trim().Length == )
{
MessageBox.Show("Please specify an output path for the generated C# files", "Error", MessageBoxButtons.OK, MessageBoxIcon.Hand);
}
else
{
if (!Directory.Exists(this.VB))
{
Directory.CreateDirectory(this.VB);
}
this.VB = Path.GetFullPath(this.VB);
if (!this.VB.EndsWith(new string(Path.DirectorySeparatorChar, )))
{
this.VB = this.VB + Path.DirectorySeparatorChar;
}
string str = Path.GetDirectoryName(this.UB).ToLower();
string str2 = Path.GetDirectoryName(this.VB).ToLower();
if (str.StartsWith(str2))
{
MessageBox.Show("Please make sure the Output path is different from the project path.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Hand);
}
else
{
this.WB = new LD(this);
ThreadStart start = new ThreadStart(this.I);
Thread thread = new Thread(start);
thread.Start();
this.WB.ShowDialog(this);
try
{
if (thread != null)
{
thread.Abort();
}
else
{
thread = null;
}
}
catch
{
}
this.WB = null;
base.Activate();
}
}
}
}
}
其实能够猜到:这个方法是点击浏览按钮选择了文件后的事件处理方法。第一步就判断了QB.B是否等于100,如果不等的话就会终端执行。我们只需把if的条件设为永远不等即可,如下面这样
.method private hidebysig instance void
H(object A,
class [mscorlib]System.EventArgs B) cil managed
{
// 代码大小 (0x1b3)
.maxstack
.locals init (string V_0,
string V_1,
class [mscorlib]System.Threading.ThreadStart V_2,
class [mscorlib]System.Threading.Thread V_3)
IL_0000: ldc.i4.s
IL_0005: ldc.i4.s
IL_0007: beq.s IL_001d IL_0009: ldstr "Delphi2CS Evaluation Version has expired, please p"
+ "urchase the final version."
IL_000e: ldstr "Error"
IL_0013: ldc.i4.
IL_0014: ldc.i4.s
在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文件了,使用生成的文件替换掉安装目录下文件即可。
我把破解了的文件上传上来,大家可以看看。
欢迎您移步我们的交流群,无聊的时候大家一起打发时间:
或者通过QQ与我联系:
(最后编辑时间2013-08-17 01:05:38)
也谈.Net中间语言——破解Delphi2CS行数和时间限制的更多相关文章
- Android日志打印类LogUtils,能够定位到类名,方法名以及出现错误的行数并保存日志文件
Android日志打印类LogUtils,能够定位到类名,方法名以及出现错误的行数并保存日志文件 在开发中,我们常常用打印log的方式来调试我们的应用.在Java中我们常常使用方法System.out ...
- replace into 影响行数
replace into 影响行数,谈起影响行数,先理解replace into 原理:其是先到表里通过一定规则(单主键或复合主键或唯一索引)找到记录,并且删除,然后在insert into 记录,即 ...
- 统计iOS项目的总代码行数的方法
打开终端, 用cd命令 定位到工程所在的目录,然后调用以下命名即可把每个源代码文件行数及总数统计出来: find . "(" -name "*.m" -or - ...
- jquery获取table的行数、列数
$("#grd").find("tr").length; //行数 $("#grd").find("tr").find( ...
- SQL 从指定表筛选指定行信息 获取表行数
1.获取指定表的行数 --获取表中数据行数 --select max([列名]) from 表名 2.筛选指定表的指定行数据(数据表分页获取) http://www.cnblogs.com/morni ...
- 使用java读取文件夹中文件的行数
使用java统计某文件夹下所有文件的行数 经理突然交代一个任务:要求统计某个文件夹下所有文件的行数.在网上查了一个多小时没有解决.后来心里不爽就决定自己写一个java类用来统计文件的行数,于是花了两个 ...
- 图文介绍如何在Eclipse统计代码行数(转)
使用Eclipse可以方便的统计工程或文件的代码行数,方法如下: 1.点击要统计的项目或许文件夹,在菜单栏点击Search,然后点击File... 2.选中正则表达式(Regular expressi ...
- 如何获取ResultSet的行数和列数
当我们执行数据库查询返回一个ResultSet的时候,很多情况下我们需要知道这个ResultSet的大小,即它的行数和列数.我们知道它的列数可以通过resultSet.getMetaData().ge ...
- 软件工程-构建之法 WordCount小程序 统计文件中字符串个数,单词个数,词频,行数
一.前言 在之前写过一个词频统计的C语言课设,别人说你一个大三的怎么写C语言课程,我只想说我是先学习VB,VB是我编程语言的开始,然后接触到C语言及C++:再后来我是学习C++,然后反过来学习C语言, ...
随机推荐
- 学员会诊之02:SVN协作以及Page类的设计
三层架构的学生管理系统是我们第一个稍微大型的项目:分层.一个解决方案多个Project,所以值得我们停下来好好审查审查. 1.测试SVN服务器地址 我们的作业要求学员创建自己的SVN服务器,并且将代码 ...
- 奇怪吸引子---LuChen
奇怪吸引子是混沌学的重要组成理论,用于演化过程的终极状态,具有如下特征:终极性.稳定性.吸引性.吸引子是一个数学概念,描写运动的收敛类型.它是指这样的一个集合,当时间趋于无穷大时,在任何一个有界集上出 ...
- (转) Java RandomAccessFile与MappedByteBuffer
RandomAccessFile RandomAccessFile是用来访问那些保存数据记录的文件的,你就可以用seek( )方法来访问记录,并进行读写了.这些记录的大小不必相同:但是其大小和位置必须 ...
- org.hibernate.PropertyAccessException: Null value was assigned to a property of primitive type setter of com.*.Paper.totalTime
at org.hibernate.property.BasicPropertyAccessor$BasicSetter.set(BasicPropertyAccessor.java:109) at o ...
- Windows视频桌面壁纸实现(libvlc)(类似于wall paper engine效果)
简介 这个项目是很久之前的事情了,当时一个朋友正在研究一个国外的软件(wall paper engine ),可以在桌面壁纸层播放视频,也就差不多是动态壁纸的意思. 后来我也动手来实现这个功能,因为手 ...
- List or delete hidden files from command prompt(CMD)
In Windows, files/folders have a special attribute called hidden attribute. By setting this attribut ...
- Java中apache下面FtpClient主动模式和被动模式
最近在做ftp文件上传的时候,开发测试环境上传都没有问题,但是在开发环境缺无法上传,但是也没有报错,纠结了老久.最后看到网上有说FtpClient有主动模式和被动模式之分,然后就解决了. FTPCli ...
- Windows 8系统默认开启的.Net Framework版本是4.0,而部分用户可能需要使用到3.5或以下版本,简单添加方法
从网络途径下载的.Net Framework3.5是无法直接在Windows 8系统上安装的,我们可以通过Windows 8的添加功能来实现 1.打开控制面板,点击”启用或关闭Windows 功能“ ...
- Vue(八):监听属性watch
Vue.js 可以通过 watch 来响应数据的变化. 以下实例模拟购物车里商品数量增加,对应价格也增加 <!--模拟购物车商品数量增加,价格也随之增加--> <div id = & ...
- JS中的PadLeft、PadRight,位数不足,自动补位,String扩展方法
类似C#中的 PadLeft.PadRight方法 //方法一 function FillZero(p) { return new Array(3 - (p + '').length + 1).joi ...