稻草屋
疯行天下
关于.net程序破解思路

NET程序的破解(一)
-------------静态分析


NET程序已经红红火火的兴起,就象LINUX一样势不可挡的涌来。作为一名Cracker,你会选择躲避吗?嘿嘿,对俺而言,挑战更富有趣味。

破解好几个.NET的程序了,一直想写出来,只是时间问题,所以拖到现在,怕再不写,就忘的一干二净了;)…….

一、兵器

   公欲善其事,必先励其器。在静态下反编译NET程序我选择Reflector,Xenocode Fox 2006 Evaluation。他们的下载地址分别如下:

Reflector:   http://www.aisto.com/roeder/dotnet/

Xenocode:http://www.xenocode.com/Products/Fox/Community.aspx

二、破解目标:Xenocode Fox 2006 Evaluation   14天使用限制

二、破解流程

     很多人都介绍过静态分析破解.NET的程序,所以如果你已经是老手或者下面的部分刚好是你所不屑一看的部分,请退出J。

之因为破解这个程序,是在论坛里henryouly曾“【推荐】两个.NET IL的相关工具”,试用了一下Xenocode Fox 2006 Evaluation,效果确实很不错,程序有点类似Reflector,只是多了一点我认为比较好的功能:直接显示代码在程序体中的位置。Reflector是完全免费的,但Xenocode Fox 2006 Evaluation却有14天的限制,过了14天想使用就需要调整计算机的日期了,而且老版本的Reflector还无法反编译Xenocode Fox 2006 Evaluation。以己之矛,克己之盾,唉,军中大忌呀。

启动Xenocode Fox 2006 Evaluation的主程序FOX.EXE,在没过期的时候很容易就启动了;把时间向后调整1个月,FOX.EXE启动就提示14天的测试期到了,然后就退出了。

用新版本的.NET Reflector, Version 4.2.36.0打开Xenocode Fox 2006 Evaluation主程序,发现程序代码已经被混淆过,看不出什么名堂了,就是有一点的有名函数,对我们来说也没什么太大作用了;搜索关键字串14-day,也找不到。过期如下



在Reflector里用鼠标右键点程序FOX的名字,在出现的菜单里有一个选项“Go To Entry Point”,嘿嘿,看到了吗?



在这个菜单上点一下,我们被动局面立刻就被扭转了:我们直接来到了程序的入口代码处!按我们的推测,程序启动就判断了时间,验证是是不是过期了,没过期就启动,否则就出现过期的提示框,然后退出。那么在入口代码处,我们一段段代码的过,一定可以找到时间比较过程等。入口处函数代码如下图:



在xc447809891322395函数上双击,出现函数代码一如下(C#)显示:[STAThread]
private static void xc447809891322395()
{
      if (!x867eb3246b182488._c7c43f12e732db09())        ;行1
      {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new x3e4e23fadc83a77e());
      }
}
看到上面的入口代码,你不觉得行1可疑吗?进入程序就调用了一个函数,然后判断的结果影响后面的所有代码的执行,嘿嘿,我们点击上面的_c7c43f12e732db09()进入,看到代码段二如下:

public static bool _c7c43f12e732db09()
{
      if (x71a0073930f50f3f.xb30f5e1eb4806151("XFTRL" + x77fa6322561797a0.x9c1ceef9a932f141, new TimeSpan(x867eb3246b182488.x7ee7e0aa39016337, 0, 0, 0, 0)))
      {
            MessageBox.Show(MessageTable.TrialExpired, x77fa6322561797a0.x6886d5a1867d55cb);
            return false;
      }
      return false;
}

看到什么了?如果你学的外语是英语,一定可以看出来在.IF语句里的TimeSpan、TrialExpired 是什么意思了,而且还带着MessageBox,哎,是不是来的有点太容易了,J。上面语句中进入就用那些参数进行了时间比较,然后不过期的话,返回FALSE;过期返回TRUE。

看来修改返回的TRUE和FALSE测试一下,就知道我们上面的判断的正确与否了,就是让返回的都是FALSE,程序不就认为是在使用期限内吗?如何修改?有很多前辈高人讲了很多办法,比如直接用ILDASM反汇编出来,然后修改语句,再用ILASM编译回去等等。我对他们的方法一直操作的不好,所以我用懒人的办法。你想知道吗?呵呵,let us go!

把上面代码段二切换为IL格式,如下代码段三:

.method public hidebysig static bool _c7c43f12e732db09() cil managed
{
      .maxstack 8
      L_0000: ldstr "XFTRL"
      L_0005: call string Xenocode.Fox.Gui.x77fa6322561797a0::get_x9c1ceef9a932f141()
      L_000a: call string string::Concat(string, string)
      L_000f: ldsfld int32 Xenocode.Fox.Gui.x867eb3246b182488::x7ee7e0aa39016337
      L_0014: ldc.i4.0
      L_0015: ldc.i4.0
      L_0016: ldc.i4.0
      L_0017: ldc.i4.0
      L_0018: newobj instance void [mscorlib]System.TimeSpan::.ctor(int32, int32, int32, int32, int32)
      L_001d: call bool Xenocode.Fox.Gui.x71a0073930f50f3f::xb30f5e1eb4806151(string, [mscorlib]System.TimeSpan)
      L_0022: brfalse.s L_0036
      L_0024: call string Xenocode.Fox.Gui.Common.MessageTable::get_TrialExpired()
      L_0029: call string Xenocode.Fox.Gui.x77fa6322561797a0::get_x6886d5a1867d55cb()
      L_002e: call [System.Windows.Forms]System.Windows.Forms.DialogResult [System.Windows.Forms]System.Windows.Forms.MessageBox::Show(string, string)
      L_0033: pop
      L_0034: ldc.i4.1
      L_0035: ret
      L_0036: ldc.i4.0
      L_0037: ret
}
在Reflector中,当你把鼠标放在指令上停留的时候,指令的机器码和对应的指令意思立刻会显示出来,真的很感谢Reflector的作者,简直让我崇拜 J。比如上面的指令
L_0033: pop
      L_0034: ldc.i4.1
      L_0035: ret
      L_0036: ldc.i4.0
      L_0037: ret
所对应的机器码就是26 17 2A 16 2A ,而我们想修改上面的L_0034: ldc.i4.1变成L_0034: ldc.i4.0 就可以了。我用HEXWORKSHOP打开FOX.EXE,然后查找上面的HEX代码,找到后,修改17为16,就可以了。这里会有个问题:如果在程序中查找出来好几个地方都一样,你如何修改?这就是我看中Xenocode Fox 2006 Evaluation的地方,它可以直接告诉你函数的入口在BODY中的地址,而且告诉你这个函数一共占有多少个字节。如下图:

  

用HexWorkShop打开FOX.EXE,然后直接定位到文件的111D88处,然后向下看我们的26 17 2A 16 2A,或者找111D88处的偏移,111D88+34=111DBC,怎么样?修改吧,还等什么,记得修改完后保存。


启动FOX看看效果,嘿嘿,已经在过期的情况也使用了,只是过期提示还存在,让人觉得难受。去掉提示框:①修改代码L_0022: brfalse.s L_0036 这里,改为直接跳转到L_0036②或者把Messagebox函数屏蔽掉,都可以去掉过期提示。我开始用方法1修改,发现程序运行就出错,原来是牵扯到OPCODE语句执行后有堆栈平衡的问题,看来不熟悉也不行。我最终选择使用方法2修改,启动Hexworkshop,把L_0024~ L_0033间的语句全替换为NOP,在IL语言中就是00,然后保存退出。
再启动,世界清净了,嘿嘿,里面的EVALUTE 就修改成PRO好了,嘿嘿,顺手牵牛…….。

 

软件简介:数独(SUDUKU):一种数字逻辑游戏,其概念源自[拉丁方块],由18世纪瑞士数学家发明。是国际上流行的一种用来锻炼逻辑思维及策略的工具。目前正在以前所未有的速度在中国大地流传。最近几天稍关注了一下相关软件,发现目前适合国人的有以下三款:完美数独、数独博士、数独终结者。三者各有千秋,本文简要介绍数独终结者2.2Build2633版的限制解除方法。

加密特点:该软件基于.net环境编制,有七天的无限制使用。程序启动时会弹出试用版的提示。超过七天则不能进入主界面。

破解手记:.net环境下的反编译工具主要有Reflector和Xenocode Fox款,两者都很强大,能比较完美的反编译出各类语言的源代码,比较而言,Reflector是免费软件,执行速度较快,而且支持pascal语言的反编译显示。Xenocode Fox 的强项在于其可以显示函数在二进制文件中的偏移量,这点很重要,两者可以结合使用。用Reflector载入isudoku.exe,定位到函数入口处(这是Reflector很实用的功能之一),能看到以下代码:

 bool flag;
        Preferences.RegistrationStatus = RegistrationStatus.TrialExpired;
        string str = "";
        string userName = str;
        string serialNumber = str;
        if (RegistryHelper.ReadRegInfo(ref userName, ref serialNumber))
        {
            if (RegistrationHelper.VerifyRegistrationCode(serialNumber, userName))
            {
                goto Label_00D3;
            }
            flag = false;
        }
        else
        {
            flag = false;
        }

可见程序启动之后首先就校验注册码,Label_00D3为赋已注册标记处,由于我们需要暴破它,因此我们要让其直接跳转到Label_00D3处,在Reflector中将代码显示IL格式,可以看出上面的代码编译成托管代码如下:


    L_000b: ldc.i4.2
    L_000c: call void Luckybird.iSudoku.Preferences::set_RegistrationStatus(valuetype Luckybird.iSudoku.RegistrationStatus)
    L_0011: ldstr ""
    L_0016: stloc.s str
    L_0018: ldloc.s str
    L_001a: stloc.s str3
    L_001c: ldloc.s str
    L_001e: stloc.s str2
    L_0020: ldloca.s str3
    L_0022: ldloca.s str2
    L_0024: call bool Luckybird.iSudoku.Utilities.RegistryHelper::ReadRegInfo(string&, string&)
    L_0029: stloc.0
    L_002a: ldloc.0
    L_002b: brfalse.s L_003f
    L_002d: ldloc.s str2
    L_002f: ldloc.s str3
    L_0031: call bool Luckybird.iSudoku.Utilities.RegistrationHelper::VerifyRegistrationCode(string, string)
    L_0036: brtrue L_00d3
    L_003b: ldc.i4.0
    L_003c: stloc.0
    L_003d: br.s L_0041
    L_003f: ldc.i4.0
    L_0040: stloc.0

由于我们没有注册码,则 L_002b: brfalse.s L_003f处肯定会跳过去(相当于执行最外层的else语句),我们的目标就是要让其直接跳至L_00d3处,则可以通过Xenocode Fox 找到该函数所在的位置,用UE定位到该处,将其修改为无条件长转移指令(需注意修改位置,ReadRegInfo语句后的两句为堆栈平衡语句不可覆盖),修改后的代码如下:

    L_000b: ldc.i4.2
    L_000c: call void Luckybird.iSudoku.Preferences::set_RegistrationStatus(valuetype Luckybird.iSudoku.RegistrationStatus)
    L_0011: ldstr ""
    L_0016: stloc.s str
    L_0018: ldloc.s str
    L_001a: stloc.s str3
    L_001c: ldloc.s str
    L_001e: stloc.s str2
    L_0020: ldloca.s str3
    L_0022: ldloca.s str2
    L_0024: call bool Luckybird.iSudoku.Utilities.RegistryHelper::ReadRegInfo(string&, string&)
    L_0029: stloc.0
    L_002a: ldloc.0
    L_002b: br L_00d3
    L_0030: stloc.0
    L_0031: call bool Luckybird.iSudoku.Utilities.RegistrationHelper::VerifyRegistrationCode(string, string)
    L_0036: brtrue L_00d3
    L_003b: ldc.i4.0
    L_003c: stloc.0
    L_003d: br.s L_0041
    L_003f: ldc.i4.0
    L_0040: stloc.0
保存退出,发现程序直接提示过期,看来没这么简单。

分析RegistrationStatus可知其为一属性,它指向一枚举类型:

internal enum RegistrationStatus
{
    Registered,
    Trial,
    TrialExpired,
    InvalidLicense
}

其读写函数如下:

public static RegistrationStatus RegistrationStatus
{
    get
    {
        return _registrationStatus;
    }
    set
    {
        _registrationStatus = value;
    }
}

该属性的赋值过程被多次调用,因此比较好的办法就是将其改为如下形式:

public static RegistrationStatus RegistrationStatus
{
    get
    {
        return RegistrationStatus.Registered;
    }
    set
    {
        _registrationStatus = RegistrationStatus.Registered;
    }
}
保存退出后运行程序没有发现异常。

补充:关于枚举类型的默认值修改可通过分析枚举类型、值的大小,结合枚举名称进行定位修改(本例改后没有效果,仅记录下来供参考),比如枚举中包含int32 abcd=1,则可以先通过搜索abcd定位一次,然后搜索04 01结合其它枚举值进行精确定位(32位整数形赋1是04 01,64位整数开型赋1是08 01)。

 

软件及破解补丁下载地址:http://oriface.ys168.com/


 

posted on 2009-07-23 10:22  子谦  阅读(729)  评论(0编辑  收藏  举报