首页
社区
课程
招聘
[原创] 算法分析入门教程实战篇及应用篇---NBA2005新春大奉送
发表于: 2008-2-12 00:21 71329

[原创] 算法分析入门教程实战篇及应用篇---NBA2005新春大奉送

2008-2-12 00:21
71329

【文章标题】: 算法分析入门教程实战篇及应用篇
【文章作者】: NBA2005
【作者邮箱】: NBA2008PE@126.com
【作者QQ号】: 382309369
【软件名称】: CRACK ME 2007之Splish
【软件大小】: 232KB
【下载地址】: PEDIY CRACK ME 2007 序列号 爱在天涯之Splish
【加壳方式】: 无
【保护方式】: 无
【编写语言】: MASM32 / TASM32
【使用工具】: OD
【操作平台】: WINXP
【软件介绍】: 供我写算法教程的好例子
【作者声明】: 围绕算法分析的相关知识点进行介绍,浅薄之处望海涵!!
--------------------------------------------------------------------------------
【详细过程】
       要上网,踏新浪
       找资料,上百度
       当黑客,乘黑鹰
       学破解,来看雪
      
  
       算法分析是道坎
       破解知识都沾边
       要想一直打此过
       文武全才是方向
  
    曾经夸下海口,要写一篇关于算法分析入门教程的文章。新春佳节之际,祝各位破友心情愉快,破解顺利,破解技术节节高。顺便在看雪论坛上又浏览了一圈,发现算法分析的文章确实都很好,但似乎没有一位对算法分析进行系统、全面的阐述的,对初学算法分析的人的实战困惑解答很少。倒是发现了一位好同志laomms的好文章自效验,读来思路清晰,简洁易懂,内容前卫却又深入浅出,同时作者还细心地配了附件供练习、体会。(这样的好同志居然没有看雪勋章,令人叫屈)。看雪论坛之藏龙卧虎是破解界公认的。CRACK ME的难度也是业内公认的。感谢好同志laomms,你的好文激发了我的创作热情。但真正开始写破文时,又觉得困难重重,自己的能力有限啊。
  
    PEDIY CRACK ME 2007出来了,这凝聚着看雪论坛上诸多默默无闻的高手的心血结晶。但,你会用它吗?我的理解是CRACK ME是给你自己独立做的,不是用来欣赏的。要学好破解的最好方法就是不断地自己独立地破解而不是在论坛上焦急地等待别人的关照。只有不断地实践,才能体会破解书中散落的种种技术细节问题。很多菜鸟也懂这个道理,但心里有一种急功近利和畏难心理在做怪,总是迫不急待地看破文答案。这不是一个好习惯。其实开始学破解时,好几天没有进展是很平常的。这是好事。百分之九十的人都会这样。为什么呢?每位破解高手都有他的强项和弱项。多数人遇到的障碍,往往是他的弱项。你想提高自己,弥补弱项,就以它为目标钻研下去。很简单的道理,强项都不是天生的。要想既快又扎实地学好破解,必须养成一个好习惯。
  
    什么,这不是算法分析吗?你怎么竟扯好习惯?没错。要学好算法分析,必须要有一个好习惯。否则事倍功半。
  
    学破解的好习惯(也是做CRACK ME 的好习惯):
  1.坚持独立完成破解(CRACK ME)。贵在坚持。开始时很吃力,成果也不明显。没关系。万事开头难,坚持。
  2.独立地查找相关资料并研读,弥补自己的弱项。案头常备基础破解教材查询是绝大多数破解高手的好习惯。很奇怪,竟没有一个高手强调这一点,尽管他就是这么做的。我的案头放的是段钢著的《家蜜和街蜜II》--看雪老大的风流韵事。绝大多数破解的基础问题,在上面都能找到答案。不需要在网上无头的苍蝇般乱搜索。建议先看一遍段钢著的《加密和解密II》*,再来做CRACK ME。因为CRACK ME是综合考试,不过是开卷考试啊。
  3.打开记事本,记录破解过程。这也是许多高手的好习惯,有助于整理破解的思路。
  4.破解成功后,对照相应的破文,印证和加深对破解的理解。
  5.复习相关的破解知识,总结心得和收获。
  6.如果三天以上还做不出来,可以看看前辈的破文,对照段钢著的《加密和解密II》复习相关的破解知识点。并就书中和CRACK ME中的难点请教高手指点。
  7.坚持、坚持、再坚持。
  8.没有相应的破文,无人回答的CRACK ME问题,不妨暂时放入破解悬案库中。以后等功力提高了再看看。或者借鉴同类型的破文,寻找破解的思路、灵感。
  
    *PUSH 001:段钢著的《加密和解密II》。玩笑一下,才能更好地集中注意力欣赏。呵呵,希望老大不要象Petnt大侠那样放在心上。
  
    好了,我先进行一下测试,你有没有达到学算法分析的水平。这是残酷的淘汰赛,加油。2008年NBA2005算法分析实战淘汰赛正式开张,看以下程序段代码:
  
    00404444:CALL对这个CRACK ME Splish你会爆破吗?
    00404466:CMP EAX,0
    00404468:JE  00404666                      CALL不会
    00404486:CALL 继续下文
    ......
    CALL 不会:
    00404666:CALL 你数学成绩好吗?
    00404688:CMP EAX,0
    00404848:JE  00409999                      CALL放弃破解梦 寻找能发挥你才华的领域
    00404868:CALL 复习爆破知识再来
  
    .......
    CALL对这个CRACK ME Splish你会爆破吗?
    地球人都知道,要学算法分析,先会爆破。为什么?许多高手遇到这些菜鸟的问题还真蒙了,书上
  说的啊。这个结论的理论基础是什么?为什么数学好的人学破解有天分?许多破解书上都没有答案。
  我个人的答案:破解是以程序为目标的。而程序的关键就是程序的流程。相对应的,破解的最最基础
  就是对程序流程的理解是否透彻。通常情况下,会爆破意味着对程序流程的理解比较透彻,而算法分
  析的基石就是程序流程。有数学天分的人,往往逻辑性强。程序流程的要求就是强调逻辑性。只有自
  己独立地做CRACK ME,才会对这些基本的问题进行思考,才会学到许多实用的知识。
   
    好,算法分析入门教程第二个测试来了,这回不是淘汰赛了。你会用各种破解工具吗?破解工具的
  熟练使用,有助于我们集中精神算法分析。不会不要紧,可以边看边学。建议你先看看相关的工具使
  用教程。
  
  
     算法分析入门教程实战篇第一课:断点篇
     
     看过了段钢著的《加密和解密II》和CCDEBUGER及其他高手的OLLYDBG入门系列,我们总结一下断点的常用手段:
     1.根据注册成功与否的提示字符串查找字符串。这是最普通和最常用的。OD是右键选查找,有
       OD自带和插件两种字符串的查找方法。破解老手都知道,现在大多数软件的字符串查找后的内容是动态的。
       Ultra String Reference
  Address    Disassembly                               Text String
  00401000   push    0                                 (initial cpu selection)
  004010B5   mov     dword ptr [ebp-8], 00403000       ourwindow
  0040110B   push    0040300A                          splish, splash
  00401110   push    00403000                          ourwindow
  004011B1   push    00403086                          hard coded:
  004011B6   push    00403060                          static
  004011DC   push    00403092                          name:
  004011E1   push    00403060                          static
  00401207   push    00403098                          serial:
  0040120C   push    00403060                          static
  00401237   push    0040305B                          edit
  0040126A   push    0040305B                          edit
  0040129D   push    0040305B                          edit
  004012D9   push    00403020                          check hardcoded
  004012DE   push    00403019                          button
  0040130F   push    00403030                          name/serial check
  00401314   push    00403019                          button
  004013BF   push    0040300A                          splish, splash
  004013C4   push    0040138E                          congratulations, you got the hard coded serial
  004013D4   push    0040300A                          splish, splash
  004013D9   push    00403067                          sorry, please try again.
  00401433   push    0040300A                          splish, splash
  00401438   push    004030D9                          your mission is to disable the splash screen, find the hardcoded serial\n\nand to keygen the name/serial part.  this level is to make sure you understand\n\nhow to use your tools and what is going on in the program.  these are three very\n\nbasic and e ...
  004014DD   mov     dword ptr [ebp-8], 0040147F       splash_class
  00401528   push    0040300A                          splish, splash
  0040152D   push    0040147F                          splash_class
  00401680   push    0040300A                          splish, splash
  00401685   push    004030A0                          please enter your name.
  00401695   push    0040300A                          splish, splash
  0040169A   push    004030B8                          please enter your serial number.
  004016CF   push    0040300A                          splish, splash
  004016D4   push    00403042                          good job, now keygen it.
  004016E4   push    0040300A                          splish, splash
  004016E9   push    00403067                          sorry, please try again.
  
     在下面认为有价值的字符串分别设断,有经验了就可选其中最有把握的设断。
       check hardcoded
       Splish splash
       congratulations, you got the hard coded serial
       good job, now keygen it.
       Sorry try again.
  
     2.根据函数设断。CTRL+N列出该软件的函数表。
  名称位于 Splish
  地址       区段       类型    (  名称                                    注释
  00402070   .rdata     输入    (    USER32.BeginPaint
  00402004   .rdata     输入    (    GDI32.CreatePatternBrush
  00402060   .rdata     输入    (    USER32.CreateWindowExA
  00402068   .rdata     输入    (    USER32.DefWindowProcA
  00402064   .rdata     输入    (    USER32.DispatchMessageA
  0040203C   .rdata     输入    (    USER32.EndPaint
  00402018   .rdata     输入    (    KERNEL32.ExitProcess
  0040205C   .rdata     输入    (    USER32.GetClientRect
  00402014   .rdata     输入    (    KERNEL32.GetCommandLineA
  00402058   .rdata     输入    (    USER32.GetMessageA
  00402010   .rdata     输入    (    KERNEL32.GetModuleHandleA
  00402034   .rdata     输入    (    USER32.GetSystemMetrics
  0040200C   .rdata     输入    (    KERNEL32.GetTickCount
  00402024   .rdata     输入    (    USER32.GetWindowTextA
  00402020   .rdata     输入    (    USER32.LoadBitmapA
  00402038   .rdata     输入    (    USER32.LoadCursorA
  00402028   .rdata     输入    (    USER32.LoadIconA
  0040202C   .rdata     输入    (    USER32.LoadMenuA
  00402030   .rdata     输入    (    USER32.MessageBoxA
  0040206C   .rdata     输入    (    USER32.PostQuitMessage
  00402074   .rdata     输入    (    USER32.RegisterClassExA
  00402040   .rdata     输入    (    USER32.SendMessageA
  00402000   .rdata     输入    (    GDI32.SetBkMode
  00402044   .rdata     输入    (    USER32.SetFocus
  00402048   .rdata     输入    (    USER32.SetMenu
  0040204C   .rdata     输入    (    USER32.ShowWindow
  00402050   .rdata     输入    (    USER32.TranslateMessage
  00402054   .rdata     输入    (    USER32.UpdateWindow
  00401000   .text      输出         <模块入口点>                                 (initial cpu selection)
  我认为通常破解软件重要的有:
  00402018   .rdata     输入    (    KERNEL32.ExitProcess
  00402058   .rdata     输入    (    USER32.GetMessageA
  0040200C   .rdata     输入    (    KERNEL32.GetTickCount
  00402024   .rdata     输入    (    USER32.GetWindowTextA
  00402030   .rdata     输入    (    USER32.MessageBoxA
  
  爱在天涯的断点下在 GetWindowTextA ( bp GetWindowTextA ) 。我对CRACK ME的理解是给我们做破解的练习题。既然是练习就应该多种方法尝试。
  
     3.内存和硬件断点,是算法分析的好伙伴。后面我将会进一步的阐述。
     4.无提示的断点法。这是许多初学者的难点,一般的教材上也没有详细的论述。许多
       破解高手只是反复地实验,很少总结回顾。这不是好习惯。我自己的总结经验就是
       断点的设定应根据程序的相应事件进行着手,这是设断总的思路原则。具体类型有:
  
       A.Windows的窗口消息,见第一卷 OllyDBG 入门系列 第五篇 消息断点及 RUN 跟踪
       B.相应的事件。如我遇到的一价值三千多的教育软件光盘,不是光盘就无声退出,没有
         任何提示。在设断的效率问题上,我自己总不满意,成了我心中的悬案。看了laomms
         (常见自校检分析实例),忽然有所启发:退出本身就是一个事件,设断退出函数,
         然后逆向追踪。试验几个破解的悬案,果然效率大大地高。他山之玉,可以攻石。特取
         laomms(常见自校检分析实例)中的例子说明,在此感谢laomms的好文赐我灵感。啥?
         侵权?你知道不,laomms是个女的,身材超赞的。还不懂?情人节快到了,明白了吗?
         我俩分啥彼此。
  
         下例子取自laomms(常见自校检分析实例):http://bbs.pediy.com/showthread.php?threadid=28298
         我们就是要从退出函数入手。软件退出一般都是调用ExitProcess、PostQuitMessage之类的,我们用OD载入sample2-change.EXE,从输入表中我们可以看出软件是调用ExitProcess退出的。于是在OD中下断BP ExitProcess,F9运行,断下后看堆栈信息:
  0012FEB8   004015B5  /CALL 到 ExitProcess 来自 sample2-.004015AF     //从这里我们可以看出ExitProcess的调用地方是在004015AF
  0012FEBC   00000000  \ExitCode = 0
  0012FEC0   20DFA6E6
  在OD中CTRL+G,输入004015AF:
  004015AF  |.  FF15 AC514200 CALL DWORD PTR DS:[<&KERNEL32.ExitProces>; \就在这里,向上找这个子CALL的首部
  004015B5  |>  8BE5          MOV ESP,EBP
  004015B7  |.  5D            POP EBP
  004015B8  \.  C3            RETN
  =======================================
  004014E0  /$  55            PUSH EBP                                 ;  找到这里,注意信息栏的内容
  004014E1  |.  8BEC          MOV EBP,ESP
  004014E3  |.  51            PUSH ECX
  004014E4  |.  833D F8354200>CMP DWORD PTR DS:[4235F8],1
  004014EB  |.  75 11         JNZ SHORT sample2-.004014FE
  信息栏的内容:
  Local Calls from 0040146B, 0040148B, 004014A9, 004014C9
  也就是说有四个地方调用ExitProcess退出,因为程序的退出按钮和关闭的叉号也是调用ExitProcess函数的,一般都会在前面几个,我们在内容上右击,“前往CALL来自0040146B”
  0040146B  |.  E8 70000000   CALL sample2-.004014E0                   ; \到这里,同样查找首部
  00401470  |.  83C4 0C       ADD ESP,0C
  00401473  |.  5D            POP EBP
  00401474  \.  C3            RETN
  ============
  00401460  /$  55            PUSH EBP                                 ;  在这里,信息栏提示:Local Calls from 00401072, <ModuleEntryPoint>+11A
  00401461  |.  8BEC          MOV EBP,ESP
  00401463  |.  6A 00         PUSH 0                                   ; /Arg3 = 00000000
  00401465  |.  6A 00         PUSH 0                                   ; |Arg2 = 00000000
  在Local Calls from 00401072上右击,前往CALL来自00401072:
  00401048  |.  E8 BDFFFFFF   CALL sample2-.0040100A
  0040104D  |.  85C0          TEST EAX,EAX
  0040104F  |.  74 1F         JE SHORT sample2-.00401070               ;  是从这里跳过去的,NOP掉
  00401051  |.  8BF4          MOV ESI,ESP
  00401053  |.  6A 30         PUSH 30                                  ; /Style = MB_OK|MB_ICONEXCLAMATION|MB_APPLMODAL
  00401055  |.  68 28004200   PUSH sample2-.00420028                   ; |Title = "提示"
  0040105A  |.  68 1C004200   PUSH sample2-.0042001C                   ; |Text = "正常运行!"
  0040105F  |.  6A 00         PUSH 0                                   ; |hOwner = NULL
  00401061  |.  FF15 B4524200 CALL DWORD PTR DS:[<&USER32.MessageBoxA>>; \MessageBoxA
  00401067  |.  3BF4          CMP ESI,ESP
  00401069  |.  E8 82050000   CALL sample2-.004015F0
  0040106E  |.  EB 07         JMP SHORT sample2-.00401077
  00401070  |>  6A 00         PUSH 0
  00401072  |.  E8 E9030000   CALL sample2-.00401460                   ;  就是这里了,最终会调用ExitProcess,向上看是从哪里跳过来
  00401077  |>  33C0          XOR EAX,EAX
  
  可以看出,00401072处的CALL最终呼叫ExitProcess退出,所以只要使0040104F处的跳转失效即可,将0040104F的跳转NOP掉后保存,测试运行正常。
  
  
       C.EXEscope等资源修改软件查看相应资源和ID号,进行设断。
       D.动态调试下,在相应的子程序里查找字符串。我上面提过:现在大多数软件的字符串查找后的内容是动态的。
       E.万能断点法bpx hmemcpy。效率差了些,将就吧。
     
      
       要成名,先断背
       学算法,先学断
      
       韩红和管彤的断背之说,闹的是沸沸扬扬。为了感谢laomms,我这整了个小花边。无他,想
  让laomms出名,只好让他当了会女的。废话,不当女的,我不就和他断背了吗?呵呵,搞点小花絮
  轻松一下。哎呀,我这断点论是越说话越多。算法分析啊,注意重点。哥们我偏说断。设断时还要
  考虑编程语言的特点。我就取易语言说说自己的心得,其他语言以后大家破解时注意积累:
  
  易语言的下断方法常用的有如下几种:
  1.有注册失败提示的,CTRL+N断MessageBoxA函数。
  2.无注册失败提示的,易语言的万能断点GetWindowTextA试试。
  3.还不行,用通用万用断点。命令:“bpx hmemcpy“。
  4.算法分析中,常用的断点法:Alt+M打开内存镜像,找到易语言的标志物“.ecode”段,F2断了它。
    动态调试中查看字符串。

无提示的断法详细示范:
《阳小子的第一个易语言编写的EM,希望新手可以找回自信!高手飘!》此论坛上找最新的帖子。
建议自己先尝试能否断下来,找到关键,不会断的再看下文。会断的就挥挥手,不耽误你新年的
娱乐。

************不会断的再看下文************

ALT+M打开内存镜象,于易语言的标志.ecode段F2设断,运行程序,断下。右键查找字符串:

Ultra String Reference
Address    Disassembly                               Text String
0041A861   push    0040C0EC                          !
0041A903   push    0040C0EE                          m
0041A999   push    0040C0F0                          y
0041AA3B   push    0040C0F2                          x
0041AADD   push    0040C0F4                          c
0041AB7F   push    0040C0EE                          m
0041AC21   push    0040C0F6                          e
0041AC92   push    0040C0F8                          believed oneself you are best!\n\n         cracker by:
0041ACBE   push    0040C12D                          恭喜
0041AD07   push    0040C132                          已注册
0041AF45   push    0040F4BD                          handle
0041B07F   mov     ebp, esp                          (initial cpu selection)

哈哈,找到了:
0041ACBE   push    0040C12D                          恭喜
0041AD07   push    0040C132                          已注册
练练逆向追踪吧!

这就是动态调试的原理来查找字符串,结合了内存资源段断点法
和字符串查找两种方法。大家可细细领略体会高手阳小子的浪漫
情怀。
  
       算法分析是道坎
       破解知识都沾边
       要想一直打此过
       文武全才是方向
  
       算法分析入门教程实战篇第二课:追出注册码。
     这一课很简单,因为重点和难点都在第一课断点上了,而且看雪论坛上的文章是好的不的了。我就不和人家的石头上碰了,哥们我天生就是孬种。为什么老说哥们?怕大家怀疑我是女的呀。这里我再强调一下程序流程,
      
      循环渐多迷人眼,
      程序流程指方向,
      分清主次破四方,
      程序流程念心中。
  
      附算法分析入门教程实战篇基础知识之一:程序流程。
  
      判断明码注册码的一般程序流程:
      段1:赋值注册码。
      段2:检测注册码的对错,即控制程序流程的语句。特征是条件判断语句。
      段3:分道扬镳。对和错两个子程序。
  
附业余版本的查找注册码:
      1.确定提示信息的位置。多数是错误的信息。设断方法文中已经详细叙述了。

      2.向上查找关键的跳转。粗粗过一遍程序的大体结构,把握程序的流程和大体结构。

      3.再向上寻找关键的CALL 、内存地址或堆栈窗口,结合与你输入的假用户名和假码相关的程序流  程、汇编语言知识的理解综合研判。对大多数程序而言,注册码(特别是明码)往往在关键的跳转不远处的内存地址或堆栈窗口、寄存器窗口中。暗码分析要看懂大致的算法。

      哎呀,太抽象了。我们不是学画画的。我也不是。说练就练,WHO怕WHO。就拿CRACK ME 2007之Splish来剖析吧。OD载入,试运行。了解CM作者的题目要求是做CRACK ME的基本常识。点HELP---ABOUT,作者有三个要求:
     1.禁止Splash。
     2.找到硬件序列号。
     3.对Name/Serial部分做出注册机。
  
     第一题是考处理NAG窗口的知识点。如果你不知道如何下手,拿起《加密和解密II》看看,复习基本的相关知识。
  字符串查找,发现Splish Splash字符都指向同样的语句:
  00401680  |.  68 0A304000   push    0040300A       ; |splish, splash
  很简单,将这些push    0040300A统统NOP掉。对是对了,还不能拿满分。没说禁止Splish啊。
  
  0040300A里的字符splish, splash是啥时有的?固定的还是动态的?试验一下,重来CTRL+F2,停在:
  00401000 >/$  6A 00         push    0                                ; /(initial cpu selection)
  00401002  |.  E8 83070000   call    <jmp.&KERNEL32.GetModuleHandleA> ; \GetModuleHandleA
  
  右击内存窗口,转到0040300A,一看,是固定值。分别在0040300A内存处设内存读、写断点和
  硬件读、写断点,各自运行,都没断下来。看来,是程序初始化时的赋值。只好运行Winhex,查找文本Splish, Splash
  在100A-1017地址处。将2C 53 70 6C 61 73 68,Splash全部赋值为20 20 20 20 20 20 20。为啥不赋值为零?
  你试试看,显示......。另存为TEMPSplish.EXE。试运行,哈哈,“, Splash”没了。(*002)记住字符的ASCII值是算法分析的基础。
  
    *PUSH002:对字符的ASCII值一定要熟悉,深入分析非密码学算法的关键。很多算法是在字符的ASCII值上做文章的。连字符在序列号中经常用到,应熟记。空  格--> 20在NAG窗口中常用,应背熟熟。
  
附算法分析入门教程实战篇基础知识之二:常用ASCII表

  数 字类:
数    字  0  1  2  3  4  5  6  7  8  9  
十六进制  30 31 32 33 34 35 36 37 38 39
十  进制  48 49 50 51 52 53 54 55 56 57

  大写字母:
字    母  A  B  C  D  E  F  G  H  I  J  K  L  M  N  O  P  Q  R  S  T  U  V  W  X  Y  Z  
十六进制  41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 51 52 53 54 55 56 57 58 59 5A
十  进制  65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90

  小写字母:
小写字母  a  b  c  d  e  f  g  h  i  j  k  l  m  n  o  p  q  r  s  t  u  v  w  x  y  z
十六进制  61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A
十  进制  97 98 99 100101102103104105106107108109110111112113114115116117118119120121122

  特殊字符:
字    符     !  "  #  $  %  &  '  (  )  *  +  ,  -  .  /  :  ;  <  =  >  ?  @  [  \  ]  ^  _  `  {  |  }  ~
十六进制  20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 3A 3B 3C 3D 3E 3F 40 5B 5C 5D 5E 5F 60 7B 7C 7D 7E
十  进制  32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 58 59 60 61 62 63 64 91 92 93 94 95 96123124125126

使用频率高的:
数    字:'0'~'9' --> 30~39
大写字母:'A'~'Z' --> 41~5A
小写字母:'a'~'z' --> 61~7A

特别字符:空  格' '--> 20
             连字符'-'--> 2D  
  哇塞,这么多,记不住啊。我也不全记得,常用的记住了。再不行,在OD的命令行里用?指令啊:? 61,ASCII a。多方便啊。试试? 空格。ASCII后面怎么是空的。看来不太常用的少见的字符还是要记?NO,NO,NO,我连放了三个洋屁:段钢著的《加密和解密II》开头就是ASCII表,经常查阅吧。现在你开始体会我为什么床头放这书了吧。
  
      我说过,CRACK ME是给你练习各种破解技术的。哥们我就自己给找个乐,能不能将Splish, Splash换成别的字符?说干就干,就换成WWW.PEDIY.COM吧。运行Winhex,替换文本Splish, Splash为WWW.PEDIY.COM,等等,提示说少一个字符。小CASE,输入WWW.PEDIY.COMM,替换完成后,将1017处4D改为20,另存为TEMPSplish.EXE。试运行,哈哈,WWW.PEDIY.COM。
  
     说这么多有什么用?一是强调常用ASCII表的重要性。二是现身说法,不要为了做CRACK ME而做。记住,我们是为了提高自己的破解技术来做CRACK ME 的。
  
     第二题是找到硬件序列号。这是一个明码比较的题目。很简单,利用出错字符串提示找到关键设断。这许多朋友都会。我这就整点新招,我们是练破解技术的,不是比谁快。双击TEMPSplish.EXE,检测硬件序列号。有错误提示。不许动,打开OD,附加TEMPSplish.EXE,F12暂停,然后CTAL+F9,直到错误提示的确定之类的按钮有效,点它,继续回到ODCTAL+F9。
  许多朋友对找不到字符串的软件很头痛,比如许多的NAG窗口。F12暂停,然后CTAL+F9是个好的组合。直到回到主程序领空:
  004013E5  |> \61            popad
  004013E6  |.  EB 73         jmp     short 0040145B
  004013E8  |>  66:83F8 02    cmp     ax, 2
  004013EC  |.  75 1B         jnz     short 00401409
  
  向上看:
  004013BD  |> \6A 00         push    0                                ; /Style = MB_OK|MB_APPLMODAL
  004013BF      68 0A304000   push    0040300A                         ;  www.pediy.com
  004013C4  |.  68 8E134000   push    0040138E                         ; |congratulations, you got the hard coded serial
  004013C9  |.  6A 00         push    0                                ; |hOwner = NULL
  004013CB  |.  E8 78030000   call    <jmp.&USER32.MessageBoxA>        ; \MessageBoxA
  004013D0  |.  EB 13         jmp     short 004013E5
  004013D2  |>  6A 00         push    0                                ; /Style = MB_OK|MB_APPLMODAL
  004013D4  |.  68 0A304000   push    0040300A                         ; |www.pediy.com
  004013D9  |.  68 67304000   push    00403067                         ; |sorry, please try again.
  004013DE  |.  6A 00         push    0                                ; |hOwner = NULL
  004013E0  |.  E8 63030000   call    <jmp.&USER32.MessageBoxA>        ; \MessageBoxA
  004013E5  |>  61            popad
  004013E6  |.  EB 73         jmp     short 0040145B
  004013E8  |>  66:83F8 02    cmp     ax, 2
  
  许多新手不是不会算法分析,而是常常困在77******之类的地址里,只能空叹英雄无妞可泡啊。这死地方哪来的MM泡啊。如何返回程序领空,是许多新手学算法分析时常常困惑的盲点。偏偏很少有高手强调这个知识点。一分钱能憋死英雄汉。相信许多人都有这样的感慨。CRACK ME论坛上有一篇“关于Hackgbeta.exe ”,其实就是这个知识点。我就将当时的回答复制如下:http://bbs.pediy.com/showthread.php?t=59077。我懒啊,懒人懒办法。
  Quote:
  Originally Posted by sexyhuli  
  我说NBA2005兄,你的那个MessageBox怎么是在主程序里?
  我的是在krnln.fnr模块里啊...
  
  我的也是在krnln.fnr模块里啊
  
  77E133B3 >  55              push    ebp
  77E133B4    8BEC            mov     ebp, esp
  77E133B6    51              push    ecx
  77E133B7    833D 583BE477 0>cmp     dword ptr [77E43B58], 0
  77E133BE    74 29           je      short 77E133E9
  77E133C0    64:A1 18000000  mov     eax, dword ptr fs:[18]
  77E133C6    8B40 24         mov     eax, dword ptr [eax+24]
  77E133C9    8945 FC         mov     dword ptr [ebp-4], eax
  77E133CC    B8 00000000     mov     eax, 0
  77E133D1    B9 2835E477     mov     ecx, 77E43528
  
  EAX 00002010
  ECX 0040C1CB 001Hackg.0040C1CB
  EDX 0040C1C4 001Hackg.0040C1C4
  EBX 100E357C krnln.100E357C
  ESP 0012F8B4
  EBP 0012F97C
  ESI 00001000
  EDI 80000004
  
  CTRL+F9:,出现P.S提示后,断下:
  10062176    5F              pop     edi                              ; 018B0240
  10062177    83F8 03         cmp     eax, 3
  1006217A    5E              pop     esi
  1006217B    75 0F           jnz     short 1006218C
  1006217D    8B4C24 68       mov     ecx, dword ptr [esp+68]
  10062181    B8 02000000     mov     eax, 2
  10062186    8901            mov     dword ptr [ecx], eax
  10062188    83C4 64         add     esp, 64
  1006218B    C3              retn
  
  CTRL+F9反复,直到:
  004A797C    83C4 28         add     esp, 28
  004A797F    68 04000080     push    80000004
  004A7984    6A 00           push    0
  004A7986    68 E9C14000     push    0040C1E9                         ; ASCII "P.S..."
  004A798B    68 01030080     push    80000301
  004A7990    6A 00           push    0
  004A7992    68 00000000     push    0
  
  返回程序领空是基本的技能,即如何返回程序主干。
   
  
  结论:F12暂停,然后CTAL+F9是个好的组合,回到主程序领空不成问题。原来这么简单。
  
  返回主程序领空的一般方法:
  1.CTAL+F9。
  2.ALT+F9。
  3.内存代码段设断法。
  我示范一下,双击TEMPSplish.EXE,检测硬件序列号。有错误提示。不许动,打开OD,附加TEMPSplish.EXE,ALT+M打开内存窗口,右击代码段,F2设断,点窗口选CPU,F9运行。点错误提示的确定之类的按钮,怎么样?断在同样的地方。
  
  许多新手看高手的算法分析,往往有看编程的感觉。我们是逆向工程师啊?看雪祭坛,锻成钢。怎么琢磨都象走错门了。怎么逆向追踪?同样是CRACK ME论坛上的一篇“关于Hackgbeta.exe ”,我回答“messageboxa 设断,往上追踪源头:”就有人不乐意。废话,我就是不知道如何追踪源头才问你呢。算法分析的文章我都能倒背如流,就是不会逆向追踪。
  这是什么论坛啊?别牢骚了,没看见论坛坛主的名字吗?
  
  我自逍遥又风流,
  气你气你就气你。
  情人节时忙买花,
  送花莫要写错名。
  
  天,你这哪是算法分析,整个一看雪论坛名人整盅游戏。轻松一下,休息休息。
  
  其实,我上面特意选了偶像laomms(常见自校检分析实例)中的退出事件的逆向追踪,很经典,希望新手
  仔细琢磨钻研。我这就这简单的CRACE ME再演示一遍,对照阅读理解。
  
  现在的软件很少有对和错的提示是邻居的了。好,我就看错误提示信息逆向追踪:
  004013D2  |>  6A 00         push    0                                ; /Style = MB_OK|MB_APPLMODAL
  004013D4  |.  68 0A304000   push    0040300A                         ; |www.pediy.com
  004013D9  |.  68 67304000   push    00403067                         ; |sorry, please try again.
  004013DE  |.  6A 00         push    0                                ; |hOwner = NULL
  004013E0  |.  E8 63030000   call    <jmp.&USER32.MessageBoxA>        ; \MessageBoxA
  004013E5  |>  61            popad
  004013E6  |.  EB 73         jmp     short 0040145B
  
  
  点此程序段开头  004013D2  |>  6A 00         push    0   
  信息窗口提示:
  跳转来自 00401386
  
  有一条红线来自00401386  |. /75 4A         |jnz     short 004013D2
  
  是控制程序流程的语句,这可是注册码的重要特征啊。你说是就是啊?我还说偶像laomms是个武林高手呢。
  如何确定这是关键的控制程序流程的语句?
  实验爆破啊。JNZ改为JZ。运行。哈哈,正确的提示。回顾上面我的程序流程的知识:
  
  判断明码注册码的一般程序流程:
  
      段1:赋值注册码。
      段2:检测注册码的对错,即控制程序流程的语句。特征是条件判断语句。
      段3:分道扬镳。对和错两个子程序。
  
  段2和段3都全了。向上找段1:
  
  0040136F  |.  8D05 53134000 lea     eax, dword ptr [401353]
  00401375  |.  8D1D 15324000 lea     ebx, dword ptr [403215]
  0040137B  |>  8038 00       /cmp     byte ptr [eax], 0
  0040137E  |.  74 0C         |je      short 0040138C
  00401380  |.  8A08          |mov     cl, byte ptr [eax]
  00401382  |.  8A13          |mov     dl, byte ptr [ebx]
  00401384  |.  38D1          |cmp     cl, dl
  00401386  |.  75 4A         |jnz     short 004013D2
  
  经典的赋值语句EAX和EBX。设断
  0040136F  |.  8D05 53134000 lea     eax, dword ptr [401353]
  重新运行。断下,信息窗口提示:
  地址=00401353, (ASCII "HardCoded")
  eax=00000000
  
  我们什么也没有输入,猜HardCoded就是注册码。F8单步,
  寄存器窗口变化:
  EAX 00401353 ASCII "HardCoded"
  ECX 0012FF34
  EDX B6BEF9D8
  EBX 005A2A10
  ESP 0012FCD4
  EBP 0012FCF4
  ESI 00000111
  EDI 005F01F0
  EIP 00401375 TEMPSpli.00401375
  其中EAX一行变红,ASCII HardCoded分外醒目。
  
  再F8后,信息窗口:
  ds:[00401353]=48 ('H')
  跳转来自 0040138A
  
  寄存器窗口变化:
  EAX 00401353 ASCII "HardCoded"
  ECX 0012FF34
  EDX B6BEF9D8
  EBX 00403215 TEMPSpli.00403215
  ESP 0012FCD4
  EBP 0012FCF4
  ESI 00000111
  EDI 005F01F0
  EIP 0040137B TEMPSpli.0040137B
  其中EBX变红,403215是地址。
  向上看:
  0040135F  |.  68 153240>push    00403215                   ; |Buffer = TEMPSpli.00403215
  00401364  |.  FF35 9034>push    dword ptr [403490]         ; |hWnd = 001E026A (class='Edit',parent=001F0200)
  0040136A  |.  E8 BB0300>call    <jmp.&USER32.GetWindowText>; \GetWindowTextA
  
  00403215是获取对话框内的信息。应该是假机器码。设断0040135F  |.  68 153240>push    00403215,重运行。
  输入5201314,我爱你一生一世。断下,右键点内存窗口,转到00403215,还全是零啊。别急,F8过CALL,再看,我爱你一生一世。看寄存器:
  EAX 00000007
  ECX 0012FF34
  EDX B6A329D8
  EBX 0059B6F8
  ESP 0012FCD4
  EBP 0012FCF4
  ESI 00000111
  EDI 005C7720
  EIP 0040136F TEMPSpli.0040136F
  这个CALL什么用途?EAX=7,正好是我们输入假码的位数。这个CALL将我们输入的假码写入内存403215处,并统计出它的位数赋值给EAX。你怀疑?不会是巧合吧?我的爱天下唯一,不信我证明给你看。破解算法分析最常用的方法就是对比法。
  我再输入334420,生生世世爱你,六位。还不信,我可要割腕了。
  
  我再输入1234567890,
  每个数字都刻你的名字,
  天天破解敲着你,
  证明我有多想你。
  
  许多朋友对CALL的含义不知道如何快速地理解它的用途。这可是算法分析的关键。还有许多朋友不知道如何看寄存器窗口和内存窗口、信息窗口,这里唠叨了一大堆帮助他们理解。会的朋友请黑眼睛飘过去。其中多次运用了相应的断点法,加深理解。
  其实看这几个窗口的核心就是我们输入的假用户名和假码,结合程序流程的关键控制流程语句细细研读,不放心的可以变换用户名和注册假码多用用对比法。
  
  注册码在哪?EAX里啊。
  假码在哪?EBX里啊。
  
  输入注册码HardCoded,成功了。等等,还有注册机呢。
  
  我不会写注册机啊。天,我有恐高症。
  没关系,利用程序自身写注册机。国外在这方面研究很多的。这是算法分析啊。我问你,我们为什么研究算法分析?
  注册码找到了,研究算法分析有什么用?
  
     算法分析入门教程第三课应用篇:算法分析的作用
  1.象杀毒软件样方便、高效。现在的注册码许多都对应机器码,一机一码。下面我就不举例了,大家都是比我聪明的高智商,只有我这傻瓜在这象蜗牛样爬格子。论坛上讲得太多了,小孩子都能倒背。
  2.发现软件的BUG,尽量调试弥补。
  3.也可以打补丁。
  4.利用软件自身做注册机。这是一个方向,终点是调试、完善软件。许多人可能认为不如注册机自己编写方便。但我说过,这是一个方向,终点是调试、完善软件,不是单单的注册码。我们还在摸索中,通过
    利用软件自身做注册机的练习,我们初步体会简单的完善软件的感觉。就象我刚学破解,很长时间没有进展。因为我没经验,走了不少弯路。我自己在这方面摸索了一阵,所以看了laomms文章如获至宝,许多的悬案都有了眉目和方向。真心地再次感谢laomms。自己英文不好,理解上不如laomms深刻。这方面laomms在看雪论坛上写了许多相关的文章,大家有兴趣的可以在看雪论坛输入laomms查询,下载laomms文中的附件练习。
  http://www.google.cn/search?q=laomms&btnG=%BC%EC%CB%F7&client=pub-1585618761901261&ie=GB2312&oe
  =GB2312&hl=zh-CN&domains=http%3A%2F%2Fwww.pediy.com&sitesearch=http%3A%2F%2Fwww.pediy.com
  
    CRACK ME的练习并不在数量的多少,而在于质量,在于不断的练习、总结和积累经验。
  
    首先,我们来整理下程序流程,你可以当作文章的段落大意更好理解:
    段1:读取假码,获得位数。
    段2:真码和假码分别赋值EAX和EBX,再在CL和DL中分别取单字符比较。这个比较的循环以假码位数为
         循环结束的判断条件。这是控制程序流程的关键段落。
    段3:正确的提示。
    段4:错误的提示。
  
    我们要动手的就是对错误的提示段4进行整改,将它改头换面成注册机。
  004013D4  |.  68 0A3040>push    0040300A                   ; |www.pediy.com
  004013D9  |.  68 673040>push    00403067                   ; |sorry, please try again.
  
  将错误提示换成真的注册码,将标题www.pediy.com换成
  004013C4  |.  68 8E1340>push    0040138E                   ; |congratulations, you got the hard coded serial
  
  你如果觉得注册码的表达不准确,也可改成自己的句子。方法同上:将标题splish, splash改成www.pediy.com。
  不输入任何假码,结果如下:
  004013D2  |> \6A 00         push    0                                ; /Style = MB_OK|MB_APPLMODAL
  004013D4  |.  68 8E134000   push    0040138E                         ; |Title = "Congratulations, you got the hard coded serial"
  004013D9  |.  50            push    eax                              ; |Text
  004013DA  |.  90            nop                                      ; |
  004013DB  |.  90            nop                                      ; |
  004013DC  |.  90            nop                                      ; |
  004013DD  |.  90            nop                                      ; |
  004013DE  |.  6A 00         push    0                                ; |hOwner = NULL
  
  成功了吗?没有,这里有个BUG,EAX里的值是动态的。你可以分别输入两位、三位、四位....假码,关公的脸啊,真是
  个大BUG。没关系,回顾一下,关键是EAX,将EAX换成00401353:
  004013D2  |> \6A 00         push    0                                ; /Style = MB_OK|MB_APPLMODAL
  004013D4  |.  68 8E134000   push    0040138E                         ; |Title = "Congratulations, you got the hard coded serial"
  004013D9      68 53134000   push    00401353                         ;  ASCII "HardCoded"
  004013DE  |.  6A 00         push    0                                ; |hOwner = NULL
  004013E0  |.  E8 63030000   call    <jmp.&USER32.MessageBoxA>        ; \MessageBoxA
  
  记得这句:0040136F  |.  8D05 53134000 lea     eax, dword ptr [401353]
  将右键复制到可执行文件,选全部修改,关掉新出的窗口,选Y,另存为001TEMPSplish.EXE。原来这么简单。
  等等,还有个小BUG,你输入错的机器码才会出现修改过的注册机。那万一买彩票中了大奖,输入的是正确的机器码呢?不是看不到你辛苦做的注册机了吗?
  
  哈哈哈,既然你运气这么好,还要看我的注册机干什么?我的注册机作用是啥?给你看的?你脑袋里灌水了?破解就是这么有趣。在这唠叨一句,破解很容易走火入魔。编程的高手里,水平越高,行为举止在一般人眼里都觉得怪异。破解也很类似。
  围棋高手钱宇平就是典型的用脑过度,在决赛前住进精神病院,将世界冠军从指间溜过。思来令人扼腕,惋惜连连。奉劝爱好破解的朋友注意心理健康的调节,有自己的业余爱好,不要做破解呆子。所幸许多朋友象我一样,喜欢打游戏和体育运动。我认识一位水平比我高的不得了的高手,说天才丝毫不为过,可惜他在精神病院做标本。让人一声叹息,往事堪回首。
  
    再来练练如何补丁。这太EASY了。对照着段钢著的《加密和解密II》书照做吧。我就不做看不起朋友智慧的事了。
   
    算法分析入门教程第四课实战及应用篇:汇编语言和BUG的研判。
  
  论坛上经常有朋友问下面类似的问题:
  
  算法分析需要懂汇编语言吗?
  写文章需要认识字吗?
  
  高手是不是都很牛,一看汇编语句就明明白白我的心?
  看小说是不是所有的字都认识?研究生英语考试的阅读理解生词多不多,是不是全能看懂?
  
  呵呵,外交家的标准格式,我也会太极推手啊。
  我又不是周星弛,需要懂汇编语言吗、不需要吗的唠叨个没完。
  我想我的意思表达还是满准确的。
  
  写了上面的这么多内容,我都累了。我就简单地讲下算法分析的思路:
  1.首先我再次强调算法分析的程序流程,这是基础啊:
  
      判断暗码注册码算法分析的一般程序流程:
      段1:赋值假用户名和假码。
      段2:用户名和注册码算法段
      段3:检测注册码的对错,即控制程序流程的语句。特征是条件判断语句。
      段4:分道扬镳。对和错两个子程序。

     在算法分析中,程序流程的理解能力的高低,决定了算法分析的效率和精确度。可以毫不夸张地说,算法分析的水平差距就在程序流程的把握能力上。这是我再三强调的原因。而写注册机,则更让我们加深对程序流程的理解。许多高手也知道这道理,但怕吓跑了新手。

  2.你可以将要破解的程序理解成你要做的阅读理解题目。议论文和叙述文的文体不同,文章结构也不同。考试既考你的综合理解能力,也考你根据文章中心思想和段落大意、上下文猜测生词和冷僻词汇的能力。我们进行算法分析,首先要了解他的程序流程,即段落大意和文章布局。干啥呀,确定算法分析的坐标。同样地,我们先逆向追踪到关键处,粗粗地跟一遍附近的主程序大段落,不要在CALL猜的对不对的问题上浪费时间(初学算法分析可以跟进去研究),这样便于从主程序大段落的全局角度来把握这部分的程序流程,目标是迅速确定确定算法分析的大致范围甚至具体的方位。做阅读理解不就是这样的嘛。
  
  3.对于汇编语言的理解问题,我的理解是提问题的朋友是以W32dasm静态汇编的角度来理解汇编语言的。其实猜测生词和冷僻词汇也一样,我们很难在没有上下文的情况下猜出词意。但这不代表我连上下文也看不懂,更不代表没有学单词的必要。
    学汇编语言是算法分析的基础。但不意味着我们只有完全掌握了汇编语言后才能来搞算法分析。学于算法分析,用于算法分析,这是可行的。符合西方实用的教育原则:发现问题,解决问题。
  
    *PUSH003:我国的教育原则是解决问题,发现问题则几乎被忽略。体现在破解上,就是绝大多数人从书上照搬,从不多问几个为什么,对菜鸟的一针见血的问题以一句书上说的敷衍了之。破解的目的就是为了注册码,其它的也懒得去管。体现在市场中,我们的研究多数停留在象牙塔,而很少象国外同仁迅速转化成生产力。这有沉重的历史性原因。可喜的是,目前的国家领导人已经开始着手处理这方面的问题。看雪老大也已经行动起来了。在现代社会中,发现问题的人才比解决问题的人才重要得多。体现在破解中,发现程序BUG的人才太少了。CRACK ME论坛上的一篇“关于Hackgbeta.exe ”中的CRACK ME软件“crackmegame游戏一下”也有一个小BUG,你看出来了吗?我是很长时间才发现。刚想上网吹吹牛,发现阳小子一眼就看出来了。
     
     一山还比一山高,
     不是菜鸟我是谁?
     望尽破解路遥遥,
     我不勤奋待何日?
  
     横批:不服不行。
  
  4.怎样象猜冷僻词样猜不太理解的汇编语言?要点如下:
    A.熟悉算法分析大段落的文章结构模板。
    B.充分利用动态调试的特点。对吃不准的CALL,宁愿更换用户名和注册码试验,采用对比法鉴定自己的猜想。
      在算法分析里,现在的软件子循环象子公司一样多,子循环内套着子循环。晕死你。
    C.在关键的地址处可以采用内存断点法或硬件断点法跟踪算法流程。
    D.经常对堆栈窗口、寄存器窗口和信息窗口、内存窗口进行查看,特别留意与假用户名和假注册码相关的汇编语言。
  
  5.如何正确地理解算法分析?个人的体会是,一边看汇编和各结果显示的窗口的红色变化,根据自己的理解一边计算器模拟。
    在程序的结果显示窗口中相互验证。开始时,很吃力是正常的。除非你是计算机专业出身的。边破解,边学汇编。我经常破解完一个软件,就回头对汇编语言进行恶补。万事开头难。
  
  6.算法分析大段落的文章结构模板:
  
    A.读取假用户名和假码。
    B.获取位数。判断是否为空。以前经常看到有CRACK ME的作者出洋相,什么都不输入,直接点注册,居然成功。所以这往
      往是我们确定算法分析的开始的依据。为什么直接点注册,居然成功?要善于发现问题。
    C.对用户名和注册码的限制条件判断。
    D.对用户名和(或)注册码的处理段,可以是逻辑运算和(或)各种字符的转换。这里可分几个小段分别处理。
    E.对处理过的用户名和(或)注册码进行保藏,地址可以是内存、堆栈、注册表或文件。
    F.调用处理过的用户名和(或)注册码,进行比较。
    G.消除比较后的用户名和(或)注册码进行安全处理,你可以理解为毁尸灭迹。
  
   上述的结构前后顺序可能不完全一样,许多语句或段落也不一定全具备。你心中有了这个模板,猜CALL的含义会轻松很多。
  结合这个CRACK ME分段如下:
  
     B段:
  004015E7  |.  >push    20                               ; /Count = 20 (32.)
  004015E9  |.  >push    00403242                         ; |Buffer = 001TEMPS.00403242
  004015EE  |.  >push    dword ptr [ebp+C]                ; |hWnd
  004015F1  |.  >call    <jmp.&USER32.GetWindowTextA>     ; \GetWindowTextA
  004015F6  |.  >test    eax, eax
  004015F8  |.  >je      00401693
  004015FE  |.  >mov     dword ptr [403467], eax
  00401603  |.  >push    0B                               ; /Count = B (11.)
  00401605  |.  >push    00403236                         ; |Buffer = 001TEMPS.00403236
  0040160A  |.  >push    dword ptr [ebp+8]                ; |hWnd
  0040160D  |.  >call    <jmp.&USER32.GetWindowTextA>     ; \GetWindowTextA
  00401612  |.  >test    eax, eax
  00401614  |.  >je      short 0040167E
  00401616  |.  >mov     dword ptr [403463], eax
  
  用户名A段,寄存器初始化:
  0040161B  |.  >xor     ecx, ecx
  0040161D  |.  >xor     ebx, ebx
  0040161F  |.  >xor     edx, edx
  00401621  |.  >lea     esi, dword ptr [403236]
  00401627  |.  >lea     edi, dword ptr [403258]
  0040162D  |.  >mov     ecx, 0A
  
  用户名D段,算法分析核心循环段:
  00401632  |> />/movsx   eax, byte ptr [esi+ebx]
  00401636  |. |>|cdq
  00401637  |. |>|idiv    ecx
  00401639  |. |>|xor     edx, ebx
  0040163B  |. |>|add     edx, 2
  0040163E  |. |>|cmp     dl, 0A
  00401641  |. |>|jl      short 00401646
  00401643  |. |>|sub     dl, 0A
  00401646  |> |>|mov     byte ptr [edi+ebx], dl
  00401649  |. |>|inc     ebx
  0040164A  |. |>|cmp     ebx, dword ptr [403463]
  00401650  |.^\>\jnz     short 00401632
  
  假码A段,寄存器初始化:
  00401652  |.  >xor     ecx, ecx
  00401654  |.  >xor     ebx, ebx
  00401656  |.  >xor     edx, edx
  00401658  |.  >lea     esi, dword ptr [403242]
  0040165E  |.  >lea     edi, dword ptr [40324D]
  00401664  |.  >mov     ecx, 0A
  
  F段:
  00401658  |.  >lea     esi, dword ptr [403242]
  0040165E  |.  >lea     edi, dword ptr [40324D]
  00401664  |.  >mov     ecx, 0A
  00401669  |>  >/movsx   eax, byte ptr [esi+ebx]
  0040166D  |.  >|cdq
  0040166E  |.  >|idiv    ecx
  00401670  |.  >|mov     byte ptr [edi+ebx], dl
  00401673  |.  >|inc     ebx
  00401674  |.  >|cmp     ebx, dword ptr [403467]
  0040167A  |.^ >\jnz     short 00401669
  0040167C  |.  >jmp     short 004016A8
  
  
  其中E段表现为:
  00401646  |> \>|mov     byte ptr [edi+ebx], dl
  存储地址是内存 00403258。初学者可在算法分析前设内存断点研究。
  00401670  |.  >|mov     byte ptr [edi+ebx], dl
  存储地址是内存 0040324D。初学者可在算法分析前设内存断点研究。
  
  不错,少了C段和G段。这可是个BUG啊。
  C段.对用户名和注册码的限制条件判断。
  加上注册码的取余数判断,造成了注册码的多样性、简单化。只要是除以0A的余数与用户名处理后的对应字符相同就可以,
  答案就不是唯一的。而注册码的安全性是以它的超低猜中几率为表现的。
  
  我举个例子:
  用户名:1
  注册码:尝试数字0123456789,3是正确的注册码。
          尝试小写字母,e、o和y是正确的注册码。
         
          查看ASCII,十进制个位是1的特殊符号有=和[。大写字母G和Q是正确的注册码。
  
    呵呵,学破解搞算法分析的,这么累,原来这样也行。具体的算法公式你应该会写出来了吧?
  
  最后,写几个常见的汇编语句组合:
  1.大写和小写的相互转换:你呀的穿上小皮袄我就认不出你是乌龟了。
    大写 -> 小写: 加20H
    小写 -> 大写: 减20H
  2.数值的十进制和16进制转化、字符直接变数字和数字直接变字符。你就是脱了小皮袄我照样认出你是小乌龟。
  3.NEC往往和OR一起结合,完成对字符串长度的取值。
  4.左移->乘
  SHL  EAX,2
  等价于EAX = EAX * (2^2)
  
  右移->除
  SHR  EAX,3
  等价于EAX = EAX / (2^3)
  5。奇偶测试
  test EAX,80000001
  je/jne xxxxxxxx
  6.对标志位值进行测试
  
  test EAX,EAX
  je/jne xxxxxxxx
  
  7.对某位进行测试
  test EAX,4
  je/jne xxxxxxxx
  
  8.根据姓名个字符依次循环取值。
  
  9.用户名或注册码的限制条件举例子:
   0040137E MOV ESI,[ESP+04] <--输入的名字
  :00401382 PUSH ESI <-- 进栈
  :00401383 MOV AL,[ESI] <-- AL = 姓名的第1个字母
  :00401385 TEST AL,AL <-- 判断是否等于0.
  :00401387 JZ 0040139C <-- 等于0就跳
  :00401389 CMP AL,41 <-- 将它与41 或 'A'进行比较
  :0040138B JB 004013AC <-- 小于'A'就跳
  :0040138D CMP AL,5A <-- 将它与5A 或 'Z'进行比较.
  :0040138F JNB 00401394 <-- 不小于'Z'就跳.
  :00401391 INC ESI <-- 姓名的计数器.
  :00401392 JMP 00401383 <-- 重复测试
  :00401394 CALL 004013D2 <-- 大于 'Z'跳到这里.
  :00401399 INC ESI <-- 姓名的计数器
  :0040139A JMP 00401383 <-- 重复测试.
  上面这段代码检查输入姓名中的字母是否介于A和Z之间,如果是小写字母就执行00401394处的CALL,
  它包含经典的 SUB AL,20大写化程式。到这里我们的名字完全成了大写。
      
  具体的例子大家自己在不断练习中逐渐总结吧。我累了。

  本来还想写注册机的体会,但有《算法注册机编写扫盲BY我要[DFCG]》,看雪论坛上有laomms的六篇系列注册机教程,我这个菜鸟最后还是删去了浅薄空乏的注册机体会和SMC技术的探讨、与算法分析关系不大的汉化技术。
  
  既生NBA2005,何生laomms?
  
  附算法分析入门教程实战篇基础知识之三:汇编语言集合 BY转自PYG官方论坛飘云阁 初学者乐园。
  
  汇编语言的准备知识--给初次接触汇编者
  汇编语言和CPU以及内存,端口等硬件知识是连在一起的. 这也是为什么汇编语言没有通用性的原因. 下面简单讲讲基本知识(针对INTEL x86及其兼容机)
    ============================
    x86汇编语言的指令,其操作对象是CPU上的寄存器,系统内存,或者立即数. 有些指令表面上没有操作数, 或者看上去缺少操作数, 其实该指令有内定的操作对象, 比如push指令, 一定是对SS:ESP指定的内存操作, 而cdq的操作对象一定是eax / edx.
  
    在汇编语言中,寄存器用名字来访问. CPU 寄存器有好几类, 分别有不同的用处:
  
    1. 通用寄存器:
    EAX,EBX,ECX,EDX,ESI,EDI,EBP,ESP(这个虽然通用,但很少被用做除了堆栈指针外的用途)
    
    这些32位可以被用作多种用途,但每一个都有"专长". EAX 是"累加器"(accumulator), 它是很多加法乘法指令的缺省寄存器. EBX 是"基地址"(base)寄存器, 在内存寻址时存放基地址. ECX 是计数器(counter), 是重复(REP)前缀指令和LOOP指令的内定计数器. EDX是...(忘了..哈哈)但它总是被用来放整数除法产生的余数. 这4个寄存器的低16位可以被单独访问,分别用AX,BX,CX和DX. AX又可以单独访问低8位(AL)和高8位(AH), BX,CX,DX也类似. 函数的返回值经常被放在EAX中.
    
    ESI/EDI分别叫做"源/目标索引寄存器"(source/destination index),因为在很多字符串操作指令中, DS:ESI指向源串,而ES:EDI指向目标串.
  
    EBP是"基址指针"(BASE POINTER), 它最经常被用作高级语言函数调用的"框架指针"(frame pointer). 在破解的时候,经常可以看见一个标准的函数起始代码:
    
    push ebp ;保存当前ebp
    mov ebp,esp ;EBP设为当前堆栈指针
    sub esp, xxx ;预留xxx字节给函数临时变量.
    ...
    
    这样一来,EBP 构成了该函数的一个框架, 在EBP上方分别是原来的EBP, 返回地址和参数. EBP下方则是临时变量. 函数返回时作 mov esp,ebp/pop ebp/ret 即可.
    
    ESP 专门用作堆栈指针.
    
    2. 段寄存器:
    CS(Code Segment,代码段) 指定当前执行的代码段. EIP (Instruction pointer, 指令指针)则指向该段中一个具体的指令. CS:EIP指向哪个指令, CPU 就执行它. 一般只能用jmp, ret, jnz, call 等指令来改变程序流程,而不能直接对它们赋值.
    DS(DATA SEGMENT, 数据段) 指定一个数据段. 注意:在当前的计算机系统中, 代码和数据没有本质差别, 都是一串二进制数, 区别只在于你如何用它. 例如, CS 制定的段总是被用作代码, 一般不能通过CS指定的地址去修改该段. 然而,你可以为同一个段申请一个数据段描述符"别名"而通过DS来访问/修改. 自修改代码的程序常如此做.
    ES,FS,GS 是辅助的段寄存器, 指定附加的数据段.
    SS(STACK SEGMENT)指定当前堆栈段. ESP 则指出该段中当前的堆栈顶. 所有push/pop 系列指令都只对SS:ESP指出的地址进行操作.
    
    3. 标志寄存器(EFLAGS):
  
    该寄存器有32位,组合了各个系统标志. EFLAGS一般不作为整体访问, 而只对单一的标志位感兴趣. 常用的标志有:
    
    进位标志C(CARRY), 在加法产生进位或减法有借位时置1, 否则为0.
    零标志Z(ZERO), 若运算结果为0则置1, 否则为0
    符号位S(SIGN), 若运算结果的最高位置1, 则该位也置1.
    溢出标志O(OVERFLOW), 若(带符号)运算结果超出可表示范围, 则置1.
    
    JXX 系列指令就是根据这些标志来决定是否要跳转, 从而实现条件分枝. 要注意,很多JXX 指令是等价的, 对应相同的机器码. 例如, JE 和JZ 是一样的,都是当Z=1是跳转. 只有JMP 是无条件跳转. JXX 指令分为两组, 分别用于无符号操作和带符号操作. JXX 后面的"XX" 有如下字母:
    
    无符号操作: 带符号操作:
    A = "ABOVE", 表示"高于" G = "GREATER", 表示"大于"
    B = "BELOW", 表示"低于" L = "LESS", 表示"小于"
    C = "CARRY", 表示"进位"或"借位" O = "OVERFLOW", 表示"溢出"
    S = "SIGN", 表示"负"
    通用符号:
    E = "EQUAL" 表示"等于", 等价于Z (ZERO)
    N = "NOT" 表示"非", 即标志没有置位. 如JNZ "如果Z没有置位则跳转"
    Z = "ZERO", 与E同.
    
    如果仔细想一想,就会发现 JA = JNBE, JAE = JNB, JBE = JNA, JG = JNLE, JGE= JNL, JL= JNGE, ....
    
    4. 端口
  
    端口是直接和外部设备通讯的地方。外设接入系统后,系统就会把外设的数据接口映射到特定的端口地址空间,这样,从该端口读入数据就是从外设读入数据,而向外设写入数据就是向端口写入数据。当然这一切都必须遵循外设的工作方式。端口的地址空间与内存地址空间无关,系统总共提供对64K个8位端口的访问,编号0-65535. 相邻的8位端口可以组成成一个16位端口,相邻的16位端口可以组成一个32位端口。端口输入输出由指令IN,OUT,INS和OUTS实现,具体可参考汇编语言书籍。
  tianxj 2008-1-30 21:41
  汇编指令的操作数可以是内存中的数据, 如何让程序从内存中正确取得所需要的数据就是对内存的寻址.
  
  INTEL 的CPU 可以工作在两种寻址模式:实模式和保护模式. 前者已经过时,就不讲了, WINDOWS 现在是32位保护模式的系统, PE 文件就基本是运行在一个32位线性地址空间, 所以这里就只介绍32位线性空间的寻址方式.
  
  其实线性地址的概念是很直观的, 就想象一系列字节排成一长队,第一个字节编号为0, 第二个编号位1, .... 一直到4294967295(十六进制FFFFFFFF,这是32位二进制数所能表达的最大值了). 这已经有4GB的容量! 足够容纳一个程序所有的代码和数据. 当然, 这并不表示你的机器有那么多内存. 物理内存的管理和分配是很复杂的内容, 初学者不必在意, 总之, 从程序本身的角度看, 就好象是在那么大的内存中.
  
  在INTEL系统中, 内存地址总是由"段选择符:有效地址"的方式给出.段选择符(SELECTOR)存放在某一个段寄存器中, 有效地址则可由不同的方式给出. 段选择符通过检索段描述符确定段的起始地址, 长度(又称段限制), 粒度, 存取权限, 访问性质等. 先不用深究这些, 只要知道段选择符可以确定段的性质就行了. 一旦由选择符确定了段, 有效地址相对于段的基地址开始算. 比如由选择符1A7选择的数据段, 其基地址是400000, 把1A7 装入DS中, 就确定使用该数据段. DS:0 就指向线性地址400000. DS:1F5278 就指向线性地址5E5278. 我们在一般情况下, 看不到也不需要看到段的起始地址, 只需要关心在该段中的有效地址就行了. 在32位系统中, 有效地址也是由32位数字表示, 就是说, 只要有一个段就足以涵盖4GB线性地址空间, 为什么还要有不同的段选择符呢? 正如前面所说的, 这是为了对数据进行不同性质的访问. 非法的访问将产生异常中断, 而这正是保护模式的核心内容, 是构造优先级和多任务系统的基础. 这里有涉及到很多深层的东西, 初学者先可不必理会.
  
  有效地址的计算方式是: 基址+间址*比例因子+偏移量. 这些量都是指段内的相对于段起始地址的量度, 和段的起始地址没有关系. 比如, 基址=100000, 间址=400, 比例因子=4, 偏移量=20000, 则有效地址为:
  
  100000+400*4+20000=100000+1000+20000=121000. 对应的线性地址是400000+121000=521000. (注意, 都是十六进制数).
  
  基址可以放在任何32位通用寄存器中, 间址也可以放在除ESP外的任何一个通用寄存器中. 比例因子可以是1, 2, 4 或8. 偏移量是立即数. 如: [EBP+EDX*8+200]就是一个有效的有效地址表达式. 当然, 多数情况下用不着这么复杂, 间址,比例因子和偏移量不一定要出现.
  
  内存的基本单位是字节(BYTE). 每个字节是8个二进制位, 所以每个字节能表示的最大的数是11111111, 即十进制的255. 一般来说, 用十六进制比较方便, 因为每4个二进制位刚好等于1个十六进制位, 11111111b = 0xFF. 内存中的字节是连续存放的, 两个字节构成一个字(WORD), 两个字构成一个双字(DWORD). 在INTEL架构中, 采用small endian格式, 即在内存中,高位字节在低位字节后面. 举例说明:十六进制数803E7D0C, 每两位是一个字节, 在内存中的形式是: 0C 7D 3E 80. 在32位寄存器中则是正常形式,如在EAX就是803E7D0C. 当我们的形式地址指向这个数的时候,实际上是指向第一个字节,即0C. 我们可以指定访问长度是字节, 字或者双字. 假设DS:[EDX]指向第一个字节0C:
  
  mov AL, byte ptr DS:[EDX] ;把字节0C存入AL
  mov AX, word ptr DS:[EDX] ;把字7D0C存入AX
  mov EAX, dword ptr DS:[EDX] ;把双字803E7D0C存入EAX
  
  在段的属性中,有一个就是缺省访问宽度.如果缺省访问宽度为双字(在32位系统中经常如此),那么要进行字节或字的访问,就必须用byte/word ptr显式地指明.
  
  缺省段选择:如果指令中只有作为段内偏移的有效地址,而没有指明在哪一个段里的时候,有如下规则:
  
  如果用ebp和esp作为基址或间址,则认为是在SS确定的段中;
  其他情况,都认为是在DS确定的段中。
  
  如果想打破这个规则,就必须使用段超越前缀。举例如下:
  
  mov eax, dword ptr [edx] ;缺省使用DS,把DS:[EDX]指向的双字送入eax
  mov ebx, dword ptr ES:[EDX] ;使用ES:段超越前缀,把ES:[EDX]指向的双字送入ebx
  
  堆栈:
  
  堆栈是一种数据结构,严格地应该叫做“栈”。“堆”是另一种类似但不同的结构。SS 和 ESP 是INTEL对栈这种数据结构的硬件支持。push/pop指令是专门针对栈结构的特定操作。SS指定一个段为栈段,ESP则指出当前的栈顶。push xxx 指令作如下操作:
  
  把ESP的值减去4;
  把xxx存入SS:[ESP]指向的内存单元。
  
  这样,esp的值减小了4,并且SS:[ESP]指向新压入的xxx. 所以栈是“倒着长”的,从高地址向低地址方向扩展。pop yyy 指令做相反的操作,把SS:[ESP]指向的双字送到yyy指定的寄存器或内存单元,然后把esp的值加上4。这时,认为该值已被弹出,不再在栈上了,因为它虽然还暂时存在在原来的栈顶位置,但下一个push操作就会把它覆盖。因此,在栈段中地址低于esp的内存单元中的数据均被认为是未定义的。
  
  最后,有一个要注意的事实是,汇编语言是面向机器的,指令和机器码基本上是一一对应的,所以它们的实现取决于硬件.有些看似合理的指令实际上是不存在的,比如:
  
  mov DS:[edx], ds:[ecx] ;内存单元之间不能直接传送
  mov DS, 1A7 ;段寄存器不能直接由立即数赋值
  mov EIP, 3D4E7 ;不能对指令指针直接操作.
  tianxj 2008-1-30 21:42
  “汇编语言”作为一门语言,对应于高级语言的编译器,我们需要一个“汇编器”来把汇编语言原文件汇编成机器可执行的代码。高级的汇编器如MASM, TASM等等为我们写汇编程序提供了很多类似于高级语言的特征,比如结构化、抽象等。在这样的环境中编写的汇编程序,有很大一部分是面向汇编器的伪指令,已经类同于高级语言。现在的汇编环境已经如此高级,即使全部用汇编语言来编写windows的应用程序也是可行的,但这不是汇编语言的长处。汇编语言的长处在于编写高效且需要对机器硬件精确控制的程序。而且我想这里的人学习汇编的目的多半是为了在破解时看懂反汇编代码,很少有人真的要拿汇编语言编程序吧?(汗......)
  
  好了,言归正传。大多数汇编语言书都是面向汇编语言编程的,我的帖是面向机器和反汇编的,希望能起到相辅相成的作用。有了前面两篇的基础,汇编语言书上对大多数指令的介绍应该能够看懂、理解了。这里再讲一讲一些常见而操作比较复杂的指令。我这里讲的都是机器的硬指令,不针对任何汇编器。
  
  无条件转移指令jmp:
  
  这种跳转指令有三种方式:短(short),近(near)和远(far)。短是指要跳至的目标地址与当前地址前后相差不超过128字节。近是指跳转的目标地址与当前地址在用一个段内,即CS的值不变,只改变EIP的值。远指跳到另一个代码段去执行,CS/EIP都要改变。短和近在编码上有所不同,在汇编指令中一般很少显式指定,只要写 jmp 目标地址,几乎任何汇编器都会根据目标地址的距离采用适当的编码。远转移在32位系统中很少见到,原因前面已经讲过,由于有足够的线性空间,一个程序很少需要两个代码段,就连用到的系统模块也被映射到同一个地址空间。
  
  jmp的操作数自然是目标地址,这个指令支持直接寻址和间接寻址。间接寻址又可分为寄存器间接寻址和内存间接寻址。举例如下(32位系统):
  
  jmp 8E347D60 ;直接寻址段内跳转
  jmp EBX ;寄存器间接寻址:只能段内跳转
  jmp dword ptr [EBX] ;内存间接寻址,段内跳转
  jmp dword ptr [00903DEC] ;同上
  jmp fward ptr [00903DF0] ;内存间接寻址,段间跳转
  
  解释:
  在32位系统中,完整目标地址由16位段选择子和32位偏移量组成。因为寄存器的宽度是32位,因此寄存器间接寻址只能给出32位偏移量,所以只能是段内近转移。在内存间接寻址时,指令后面是方括号内的有效地址,在这个地址上存放跳转的目标地址。比如,在[00903DEC]处有如下数据:7C 82 59 00 A7 01 85 65 9F 01
  
  内存字节是连续存放的,如何确定取多少作为目标地址呢?dword ptr 指明该有效地址指明的是双字,所以取
  0059827C作段内跳转。反之,fward ptr 指明后面的有效地址是指向48位完全地址,所以取19F:658501A7 做远跳转。
  
  注意:在保护模式下,如果段间转移涉及优先级的变化,则有一系列复杂的保护检查,现在可不加理会。将来等各位功力提升以后可以自己去学习。
  
  条件转移指令jxx:只能作段内转移,且只支持直接寻址。
  
  =========================================
  调用指令CALL:
  
  Call的寻址方式与jmp基本相同,但为了从子程序返回,该指令在跳转以前会把紧接着它的下一条指令的地址压进堆栈。如果是段内调用(目标地址是32位偏移量),则压入的也只是一个偏移量。如果是段间调用(目标地址是48位全地址),则也压入下一条指令的完全地址。同样,如果段间转移涉及优先级的变化,则有一系列复杂的保护检查。
  
  与之对应retn/retf指令则从子程序返回。它从堆栈上取得返回地址(是call指令压进去的)并跳到该地址执行。retn取32位偏移量作段内返回,retf取48位全地址作段间返回。retn/f 还可以跟一个立即数作为操作数,该数实际上是从堆栈上传给子程序的参数的个数(以字计)返回后自动把堆栈指针esp加上指定的数*2,从而丢弃堆栈中的参数。这里具体的细节留待下一篇讲述。
  
  虽然call和ret设计为一起工作,但它们之间没有必然的联系。就是说,如果你直接用push指令向堆栈中压入一个数,然后执行ret,他同样会把你压入的数作为返回地址,而跳到那里去执行。这种非正常的流程转移可以被用作反跟踪手段。
  
  ==========================================
  中断指令INT n
  
  在保护模式下,这个指令必定会被操作系统截获。在一般的PE程序中,这个指令已经不太见到了,而在DOS时代,中断是调用操作系统和BIOS的重要途径。现在的程序可以文质彬彬地用名字来调用windows功能,如 call user32!getwindowtexta。从程序角度看,INT指令把当前的标志寄存器先压入堆栈,然后把下一条指令的完全地址也压入堆栈,最后根据操作数n来检索“中断描述符表”,试图转移到相应的中断服务程序去执行。通常,中断服务程序都是操作系统的核心代码,必然会涉及到优先级转换和保护性检查、堆栈切换等等,细节可以看一些高级的教程。
  
  与之相应的中断返回指令IRET做相反的操作。它从堆栈上取得返回地址,并用来设置CS:EIP,然后从堆栈中弹出标志寄存器。注意,堆栈上的标志寄存器值可能已经被中断服务程序所改变,通常是进位标志C, 用来表示功能是否正常完成。同样的,IRET也不一定非要和INT指令对应,你可以自己在堆栈上压入标志和地址,然后执行IRET来实现流程转移。实际上,多任务操作系统常用此伎俩来实现任务转换。
  
  广义的中断是一个很大的话题,有兴趣可以去查阅系统设计的书籍。
  
  ============================================
  装入全指针指令LDS,LES,LFS,LGS,LSS
  
  这些指令有两个操作数。第一个是一个通用寄存器,第二个操作数是一个有效地址。指令从该地址取得48位全指针,将选择符装入相应的段寄存器,而将32位偏移量装入指定的通用寄存器。注意在内存中,指针的存放形式总是32位偏移量在前面,16位选择符在后面。装入指针以后,就可以用DS:[ESI]这样的形式来访问指针指向的数据了。
  
  ============================================
  字符串操作指令
  
  这里包括CMPS,SCAS,LODS,STOS,MOVS,INS和OUTS等。这些指令有一个共同的特点,就是没有显式的操作数,而由硬件规定使用DS:[ESI]指向源字符串,用ES:[EDI]指向目的字符串,用AL/AX/EAX做暂存。这是硬件规定的,所以在使用这些指令之前一定要设好相应的指针。
  这里每一个指令都有3种宽度形式,如CMPSB(字节比较)、CMPSW(字比较)、CMPSD(双字比较)等。
  CMPSB:比较源字符串和目标字符串的第一个字符。若相等则Z标志置1。若不等则Z标志置0。指令执行完后,ESI 和EDI都自动加1,指向源/目标串的下一个字符。如果用CMPSW,则比较一个字,ESI/EDI自动加2以指向下一个字。
  如果用CMPSD,则比较一个双字,ESI/EDI自动加4以指向下一个双字。(在这一点上这些指令都一样,不再赘述)
  SCAB/W/D 把AL/AX/EAX中的数值与目标串中的一个字符/字/双字比较。
  LODSB/W/D 把源字符串中的一个字符/字/双字送入AL/AX/EAX
  STOSB/W/D 把AL/AX/EAX中的直送入目标字符串中
  MOVSB/W/D 把源字符串中的字符/字/双字复制到目标字符串
  INSB/W/D 从指定的端口读入字符/字/双字到目标字符串中,端口号码由DX寄存器指定。
  OUTSB/W/D 把源字符串中的字符/字/双字送到指定的端口,端口号码由DX寄存器指定。
  
  串操作指令经常和重复前缀REP和循环指令LOOP结合使用以完成对整个字符串的操作。而REP前缀和LOOP指令都有硬件规定用ECX做循环计数器。举例:
  
  LDS ESI,SRC_STR_PTR
  LES EDI,DST_STR_PTR
  MOV ECX,200
  REP MOVSD
  
  上面的代码从SRC_STR拷贝200个双字到DST_STR. 细节是:REP前缀先检查ECX是否为0,若否则执行一次MOVSD,ECX自动减1,然后执行第二轮检查、执行......直到发现ECX=0便不再执行MOVSD,结束重复而执行下面的指令。
  
  
  LDS ESI,SRC_STR_PTR
  MOV ECX,100
  LOOP1:
  LODSW
  .... (deal with value in AX)
  
  LOOP LOOP1
  .....
  
  从SRC_STR处理100个字。同样,LOOP指令先判断ECX是否为零,来决定是否循环。每循环一轮ECX自动减1。
  
  REP和LOOP 都可以加上条件,变成REPZ/REPNZ 和 LOOPZ/LOOPNZ. 这是除了ECX外,还用检查零标志Z. REPZ 和LOOPZ在Z为1时继续循环,否则退出循环,即使ECX不为0。REPNZ/LOOPNZ则相反。
  tianxj 2008-1-30 21:42
  高级语言程序的汇编解析
  
  在高级语言中,如C和PASCAL等等,我们不再直接对硬件资源进行操作,而是面向于问题的解决,这主要体现在数据抽象化和程序的结构化。例如我们用变量名来存取数据,而不再关心这个数据究竟在内存的什么地方。这样,对硬件资源的使用方式完全交给了编译器去处理。不过,一些基本的规则还是存在的,而且大多数编译器都遵循一些规范,这使得我们在阅读反汇编代码的时候日子好过一点。这里主要讲讲汇编代码中一些和高级语言对应的地方。
  
  1. 普通变量。通常声明的变量是存放在内存中的。编译器把变量名和一个内存地址联系起来(这里要注意的是,所谓的“确定的地址”是对编译器而言在编译阶段算出的一个临时的地址。在连接成可执行文件并加载到内存中执行的时候要进行重定位等一系列调整,才生成一个实时的内存地址,不过这并不影响程序的逻辑,所以先不必太在意这些细节,只要知道所有的函数名字和变量名字都对应一个内存的地址就行了),所以变量名在汇编代码中就表现为一个有效地址,就是放在方括号中的操作数。例如,在C文件中声明:
  
  int my_age;
  
  这个整型的变量就存在一个特定的内存位置。语句 my_age= 32; 在反汇编代码中可能表现为:
  
  mov word ptr [007E85DA], 20
  
  所以在方括号中的有效地址对应的是变量名。又如:
  
  char my_name[11] = "lianzi2000";
  
  这样的说明也确定了一个地址,对应于my_name. 假设地址是007E85DC,则内存中[007E85DC]='l',[007E85DD]='i', etc. 对my_name的访问也就是对这地址处的数据访问。
  
  指针变量其本身也同样对应一个地址,因为它本身也是一个变量。如:
  
  char *your_name;
  
  这时也确定变量"your_name"对应一个内存地址,假设为007E85F0. 语句your_name=my_name;很可能表现为:
  
  mov [007E85F0], 007E85DC ;your_name的内容是my_name的地址。
  
  2. 寄存器变量
  
  在C和C++中允许说明寄存器变量。register int i; 指明i是寄存器存放的整型变量。通常,编译器都把寄存器变量放在esi和edi中。寄存器是在cpu内部的结构,对它的访问要比内存快得多,所以把频繁使用的变量放在寄存器中可以提高程序执行速度。
  
  3. 数组
  
  不管是多少维的数组,在内存中总是把所有的元素都连续存放,所以在内存中总是一维的。例如,int i_array[2][3]; 在内存确定了一个地址,从该地址开始的12个字节用来存贮该数组的元素。所以变量名i_array对应着该数组的起始地址,也即是指向数组的第一个元素。存放的顺序一般是i_array[0][0],[0][1],[0][2],[1][0],[1][1],[1][2] 即最右边的下标变化最快。当需要访问某个元素时,程序就会从多维索引值换算成一维索引,如访问i_array[1][1],换算成内存中的一维索引值就是1*3+1=4.这种换算可能在编译的时候就可以确定,也可能要到运行时才可以确定。无论如何,如果我们把i_array对应的地址装入一个通用寄存器作为基址,则对数组元素的访问就是一个计算有效地址的问题:
  
  ; i_array[1][1]=0x16
  
  lea ebx,xxxxxxxx ;i_array 对应的地址装入ebx
  mov edx,04 ;访问i_array[1][1],编译时就已经确定
  mov word ptr [ebx+edx*2], 16 ;
  
  当然,取决于不同的编译器和程序上下文,具体实现可能不同,但这种基本的形式是确定的。从这里也可以看到比例因子的作用(还记得比例因子的取值为1,2,4或8吗?),因为在目前的系统中简单变量总是占据1,2,4或者8个字节的长度,所以比例因子的存在为在内存中的查表操作提供了极大方便。
  
  4. 结构和对象
  
  结构和对象的成员在内存中也都连续存放,但有时为了在字边界或双字边界对齐,可能有些微调整,所以要确定对象的大小应该用sizeof操作符而不应该把成员的大小相加来计算。当我们声明一个结构变量或初始化一个对象时,这个结构变量和对象的名字也对应一个内存地址。举例说明:
  
  struct tag_info_struct
  {
  int age;
  int sex;
  float height;
  float weight;
  } marry;
  
  变量marry就对应一个内存地址。在这个地址开始,有足够多的字节(sizeof(marry))容纳所有的成员。每一个成员则对应一个相对于这个地址的偏移量。这里假设此结构中所有的成员都连续存放,则age的相对地址为0,sex为2, height 为4,weight为8。
  
  ; marry.sex=0;
  
  lea ebx,xxxxxxxx ;marry 对应的内存地址
  mov word ptr [ebx+2], 0
  ......
  
  对象的情况基本相同。注意成员函数具体的实现在代码段中,在对象中存放的是一个指向该函数的指针。
  
  
  5. 函数调用
  
  一个函数在被定义时,也确定一个内存地址对应于函数名字。如:
  
  long comb(int m, int n)
  {
  long temp;
  .....
  
  return temp;
  }
  
  这样,函数comb就对应一个内存地址。对它的调用表现为:
  
  CALL xxxxxxxx ;comb对应的地址。这个函数需要两个整型参数,就通过堆栈来传递:
  
  ;lresult=comb(2,3);
  
  push 3
  push 2
  call xxxxxxxx
  mov dword ptr [yyyyyyyy], eax ;yyyyyyyy是长整型变量lresult的地址
  
  这里请注意两点。第一,在C语言中,参数的压栈顺序是和参数顺序相反的,即后面的参数先压栈,所以先执行push 3. 第二,在我们讨论的32位系统中,如果不指明参数类型,缺省的情况就是压入32位双字。因此,两个push指令总共压入了两个双字,即8个字节的数据。然后执行call指令。call 指令又把返回地址,即下一条指令(mov dword ptr....)的32位地址压入,然后跳转到xxxxxxxx去执行。
  
  在comb子程序入口处(xxxxxxxx),堆栈的状态是这样的:
  
  03000000 (请回忆small endian 格式)
  02000000
  yyyyyyyy <--ESP 指向返回地址
  
  前面讲过,子程序的标准起始代码是这样的:
  
  push ebp ;保存原先的ebp
  mov ebp, esp;建立框架指针
  sub esp, XXX;给临时变量预留空间
  .....
  
  执行push ebp之后,堆栈如下:
  
  03000000
  02000000
  yyyyyyyy
  old ebp <---- esp 指向原来的ebp
  
  执行mov ebp,esp之后,ebp 和esp 都指向原来的ebp. 然后sub esp, xxx 给临时变量留空间。这里,只有一个临时变量temp,是一个长整数,需要4个字节,所以xxx=4。这样就建立了这个子程序的框架:
  
  03000000
  02000000
  yyyyyyyy
  old ebp <---- 当前ebp指向这里
  temp
  
  所以子程序可以用[ebp+8]取得第一参数(m),用[ebp+C]来取得第二参数(n),以此类推。临时变量则都在ebp下面,如这里的temp就对应于[ebp-4].
  
  子程序执行到最后,要返回temp的值:
  
  mov eax,[ebp-04]
  然后执行相反的操作以撤销框架:
  
  mov esp,ebp ;这时esp 和ebp都指向old ebp,临时变量已经被撤销
  pop ebp ;撤销框架指针,恢复原ebp.
  
  这是esp指向返回地址。紧接的retn指令返回主程序:
  
  retn 4
  
  该指令从堆栈弹出返回地址装入EIP,从而返回到主程序去执行call后面的指令。同时调整esp(esp=esp+4*2),从而撤销参数,使堆栈恢复到调用子程序以前的状态,这就是堆栈的平衡。调用子程序前后总是应该维持堆栈的平衡。从这里也可以看到,临时变量temp已经随着子程序的返回而消失,所以试图返回一个指向临时变量的指针是非法的。
  
  为了更好地支持高级语言,INTEL还提供了指令Enter 和Leave 来自动完成框架的建立和撤销。Enter 接受两个操作数,第一个指明给临时变量预留的字节数,第二个是子程序嵌套调用层数,一般都为0。enter xxx,0 相当于:
  
  push ebp
  mov ebp,esp
  sub esp,xxx
  
  leave 则相当于:
  
  mov esp,ebp
  pop ebp
  
  =============================================================
  
  Saver 2005-2-17 20:49
  8088 汇编速查手册
  一、数据传输指令
  ───────────────────────────────────────
      它们在存贮器和寄存器、寄存器和输入输出端口之间传送数据.
      1. 通用数据传送指令.
          MOV    传送字或字节.
          MOVSX  先符号扩展,再传送.
          MOVZX  先零扩展,再传送.
          PUSH    把字压入堆栈.
          POP    把字弹出堆栈.
          PUSHA  把AX,CX,DX,BX,SP,BP,SI,DI依次压入堆栈.
          POPA    把DI,SI,BP,SP,BX,DX,CX,AX依次弹出堆栈.
          PUSHAD  把EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI依次压入堆栈.
          POPAD  把EDI,ESI,EBP,ESP,EBX,EDX,ECX,EAX依次弹出堆栈.
          BSWAP  交换32位寄存器里字节的顺序
          XCHG    交换字或字节.( 至少有一个操作数为寄存器,段寄存器不可作为操作数)
          CMPXCHG 比较并交换操作数.( 第二个操作数必须为累加器AL/AX/EAX )
          XADD    先交换再累加.( 结果在第一个操作数里 )
          XLAT    字节查表转换.
                  ── BX 指向一张 256 字节的表的起点, AL 为表的索引值 (0-255,即
                  0-FFH); 返回 AL 为查表结果. ( [BX+AL]->AL )
      2. 输入输出端口传送指令.
          IN      I/O端口输入. ( 语法: IN 累加器, {端口号│DX} )
          OUT    I/O端口输出. ( 语法: OUT {端口号│DX},累加器 )
            输入输出端口由立即方式指定时, 其范围是 0-255; 由寄存器 DX 指定时,
            其范围是 0-65535.
      3. 目的地址传送指令.
          LEA    装入有效地址.
            例: LEA DX,string  ;把偏移地址存到DX.
          LDS    传送目标指针,把指针内容装入DS.
            例: LDS SI,string  ;把段地址:偏移地址存到DS:SI.
          LES    传送目标指针,把指针内容装入ES.
            例: LES DI,string  ;把段地址:偏移地址存到ES:DI.
          LFS    传送目标指针,把指针内容装入FS.
            例: LFS DI,string  ;把段地址:偏移地址存到FS:DI.
          LGS    传送目标指针,把指针内容装入GS.
            例: LGS DI,string  ;把段地址:偏移地址存到GS:DI.
          LSS    传送目标指针,把指针内容装入SS.
            例: LSS DI,string  ;把段地址:偏移地址存到SS:DI.
      4. 标志传送指令.
          LAHF    标志寄存器传送,把标志装入AH.
          SAHF    标志寄存器传送,把AH内容装入标志寄存器.
          PUSHF  标志入栈.
          POPF    标志出栈.
          PUSHD  32位标志入栈.
          POPD    32位标志出栈.
  
  二、算术运算指令
  ───────────────────────────────────────
            ADD    加法.
          ADC    带进位加法.
          INC    加 1.
          AAA    加法的ASCII码调整.
          DAA    加法的十进制调整.
          SUB    减法.
          SBB    带借位减法.
          DEC    减 1.
          NEC    求反(以 0 减之).
          CMP    比较.(两操作数作减法,仅修改标志位,不回送结果).
          AAS    减法的ASCII码调整.
          DAS    减法的十进制调整.
          MUL    无符号乘法.
          IMUL    整数乘法.
            以上两条,结果回送AH和AL(字节运算),或DX和AX(字运算),
          AAM    乘法的ASCII码调整.
          DIV    无符号除法.
          IDIV    整数除法.
            以上两条,结果回送:
                商回送AL,余数回送AH, (字节运算);
            或  商回送AX,余数回送DX, (字运算).
          AAD    除法的ASCII码调整.
          CBW    字节转换为字. (把AL中字节的符号扩展到AH中去)
          CWD    字转换为双字. (把AX中的字的符号扩展到DX中去)
          CWDE    字转换为双字. (把AX中的字符号扩展到EAX中去)
          CDQ    双字扩展.    (把EAX中的字的符号扩展到EDX中去)
  
  三、逻辑运算指令
  ───────────────────────────────────────
            AND    与运算.
          OR      或运算.
          XOR    异或运算.
          NOT    取反.
          TEST    测试.(两操作数作与运算,仅修改标志位,不回送结果).
          SHL    逻辑左移.
          SAL    算术左移.(=SHL)
          SHR    逻辑右移.
          SAR    算术右移.(=SHR)
          ROL    循环左移.
          ROR    循环右移.
          RCL    通过进位的循环左移.
          RCR    通过进位的循环右移.
            以上八种移位指令,其移位次数可达255次.
                移位一次时, 可直接用操作码.  如 SHL AX,1.
                移位>1次时, 则由寄存器CL给出移位次数.
                  如  MOV CL,04
                      SHL AX,CL
  
  四、串指令
  ───────────────────────────────────────
               DS:SI  源串段寄存器  :源串变址.
              ES:DI  目标串段寄存器:目标串变址.
              CX      重复次数计数器.
              AL/AX  扫描值.
              D标志  0表示重复操作中SI和DI应自动增量; 1表示应自动减量.
              Z标志  用来控制扫描或比较操作的结束.
          MOVS    串传送.
              ( MOVSB  传送字符.    MOVSW  传送字.    MOVSD  传送双字. )
          CMPS    串比较.
              ( CMPSB  比较字符.    CMPSW  比较字. )
          SCAS    串扫描.
              把AL或AX的内容与目标串作比较,比较结果反映在标志位.
          LODS    装入串.
              把源串中的元素(字或字节)逐一装入AL或AX中.
              ( LODSB  传送字符.    LODSW  传送字.    LODSD  传送双字. )
          STOS    保存串.
              是LODS的逆过程.
          REP            当CX/ECX<>0时重复.
          REPE/REPZ      当ZF=1或比较结果相等,且CX/ECX<>0时重复.
          REPNE/REPNZ    当ZF=0或比较结果不相等,且CX/ECX<>0时重复.
          REPC          当CF=1且CX/ECX<>0时重复.
          REPNC          当CF=0且CX/ECX<>0时重复.
  
  五、程序转移指令
  ───────────────────────────────────────
       1>无条件转移指令 (长转移)
          JMP    无条件转移指令
          CALL    过程调用
          RET/RETF过程返回.
      2>条件转移指令 (短转移,-128到+127的距离内)
          ( 当且仅当(SF XOR OF)=1时,OP1<OP2 )
          JA/JNBE 不小于或不等于时转移.
          JAE/JNB 大于或等于转移.
          JB/JNAE 小于转移.
          JBE/JNA 小于或等于转移.
            以上四条,测试无符号整数运算的结果(标志C和Z).
          JG/JNLE 大于转移.
          JGE/JNL 大于或等于转移.
          JL/JNGE 小于转移.
          JLE/JNG 小于或等于转移.
            以上四条,测试带符号整数运算的结果(标志S,O和Z).
          JE/JZ  等于转移.
          JNE/JNZ 不等于时转移.
          JC      有进位时转移.
          JNC    无进位时转移.
          JNO    不溢出时转移.
          JNP/JPO 奇偶性为奇数时转移.
          JNS    符号位为 "0" 时转移.
          JO      溢出转移.
          JP/JPE  奇偶性为偶数时转移.
          JS      符号位为 "1" 时转移.
      3>循环控制指令(短转移)
          LOOP            CX不为零时循环.
          LOOPE/LOOPZ    CX不为零且标志Z=1时循环.
          LOOPNE/LOOPNZ  CX不为零且标志Z=0时循环.
          JCXZ            CX为零时转移.
          JECXZ          ECX为零时转移.
      4>中断指令
          INT    中断指令
          INTO    溢出中断
          IRET    中断返回
      5>处理器控制指令
          HLT    处理器暂停, 直到出现中断或复位信号才继续.
          WAIT    当芯片引线TEST为高电平时使CPU进入等待状态.
          ESC    转换到外处理器.
          LOCK    封锁总线.
          NOP    空操作.
          STC    置进位标志位.
          CLC    清进位标志位.
          CMC    进位标志取反.
          STD    置方向标志位.
          CLD    清方向标志位.
          STI    置中断允许位.
          CLI    清中断允许位.
  
  六、伪指令
  ───────────────────────────────────────
            DW      定义字(2字节).
          PROC    定义过程.
          ENDP    过程结束.
          SEGMENT 定义段.
          ASSUME  建立段寄存器寻址.
          ENDS    段结束.
          END    程序结束.
  
  汇编常用命令、指令一览 (应该对新手有点用处)
  汇编常用命令、指令一览
  (作者:wutoyou)
  --------------------------------------------------------------------------------
  
  MOV(MOVe)    传送指令P28
  PUSH      入栈指令P32
  POP      出栈指令P33
  XCHG(eXCHanG)   交换指令P34
  XLAT(TRANSLATE)   换码指令P34
  LEA  (Load  Effective  Address)  有效地址送寄存器指令P35
  LDS(Load  DS  with  pointer)  指针送寄存器和DS指令P35
  LES(Load  ES  with  pointer)  指针送寄存器和ES指令P35
  LAHF(Load  AH  with  Flags)  标志位送AH指令P36
  SAHF(Store  AH  into  Flgs)  AH送标志寄存器指令P36
  PUSHF(PUSH  the Flags)   标志进栈指令P36
  POPF(POP  the Flags)   标志出栈指令P37
  ADD      加法指令P38
  ADC      带进位加法指令P39
  INC      加1指令P39
  SUB(SUBtract)    不带借位的减法指令P40
  SBB(SuVtrach  with  borrow)  带借位的减法指令P40
  DEC(DECrement)    减1指领P41
  NEG(NEGate)    求补指令P41
  CMP(CoMPare)    比较指令P42
  MUL(unsinged  MULtiple)  无符号数乘法指令P46
  IMUL(sIgned  MUL  tiple)  有符号数乘法指令P46
  DIV(unsigned  DIVide)   无符号数除法指令P48
  IDIV(sIgned  DIVide)   有符号数除法指令P48
  CBW(Count  Byte  to  Word)  字节转换为字指令P50
  CWD(Count  Word  to  Doble  word) 字转换为双字指令P50
  DAA     压缩的BCD码加法十进制调整指令P53
  DAS     压缩的BCD码减法十进制调整指令P53
  AAA     非压缩的BCD码加法十进制调整指令P54
  AAS     非压缩的BCD码加法十进制调整指令P54
  AND      逻辑与指令P54
  OR      逻辑或指令P55
  XOR      逻辑异或指令P56
  NOT      逻辑非指令P56
  TEST      测试指令P57
  SHL(SHift  logical  Letf)   逻辑左移指令P57
  SHR(SHift  logical  Right)   逻辑右移指令P57
  ROL(Rotate  Left  )   循环左移指令P58
  ROR(Rotate  Right)   循环右移指令P58
  RCL(Rotate  Left  through  Carry) 带进位循环左移P58
  RCR(Rotate  Right  through  Carry) 带进位循环左移P58
  MOVS(MOVe  String)   串传送指令P58
  STOS(STOre  into  String)  存入串指令P60
  LODS(LOad  from  string)  从串取指令P60
  REP(REPeat)    重复操作前缀P61
  CLD(CLear  Direction  flag)  清除方向标志指令P61
  STD(SeT  Direction  flag)   设置方向标志指令P61
  CMPS(CoMPare  String)   串比较指令P62
  SCAS(SCAn  String)   串扫描指令P63
  REPE/REPZ(REPeat  while  Equal/Zero)相等/为零时重复操作前缀P63
  REPNE/REPNZ(REPeat  while  Not  Equal/Zero)不相等/不为零进重复前缀
  IN(INput)     输入指令P65
  OUT(OUTput)    输出指令P65
  JMP(JuMP)    无条件转移指令P66
  JZ,JNZ,JS,JNS,JO,JNO,JP,JNP,JB,JNB,JBE,JNBE,JL,JNL,JLE,JNLE,JCXZ    条件转移指令P67
  LOOP      循环指令P70
  LOOPZ/LOOPE    为零/相等时循环指令P70
  LOOPNZ/LOOPNE    不为零/不相等时循环指令P70
  CALL      子程序调用指令P71
  RET(RETun)    子程序返回指令P72
  CLC(CLear  Carry)   进位位置0指令P77
  CMC(CoMplement  Carry)  进位位求反指令P77
  SRC(SeT  Carry)    进位位置1指令P77
  NOP(No  OPeretion)   无操作指令P77
  HLT(HaLT)    停机指令P77
  OFFSET     返回偏移地址P85
  SEG      返回段地址P85
  EQU(=)     等值语句P90
  PURGE     解除语句P91
  DUP      操作数字段用复制操作符P93
  SEGMENT,ENDS    段定义指令P95
  ASSUME     段地址分配指令P95
  ORG      起始偏移地址设置指令P96
  $      地址计数器的当前值P97
  PROC,ENDP    过程定义语句P97
  NAME,TITLE,END   程序开始结束语句P98
  MACRO,ENDM    宏定义指令P99
  
  --------------------------------------------------------------------------------
  
  段内直接短跳转 JMP SHORT OPR
  段内直接近转移 JMP NEAR PTR OPR
  段内间接转移 JMP WORD PTR OPR
  段间直接转移 JMP FAR PTR OPR
  段间间接转移 JMP DWORD PTR OPR
  
  JZ    OPR  //结果为零转移
  JNZ    OPR  //结果不为零转移
  JS    OPR  //结果为负转移
  JNS    OPR  //结果为正转移
  JO   OPR  //溢出转移
  JNO   OPR  //不溢出转移
  JP    OPR  //结果为偶转移
  JNP    OPR  //结果为奇转移
  JC    OPR  //有进位转移
  JNC    OPR  //无进位转移
  
  
       要上网,踏新浪
       找资料,上百度
       当黑客,乘黑鹰
       学破解,来看雪
      
  
       算法分析是道坎
       破解知识都沾边
       要想一直打此过
       文武全才是方向
  
--------------------------------------------------------------------------------
【经验总结】
       要上网,踏新浪
       找资料,上百度
       当黑客,乘黑鹰
       学破解,来看雪
  
       算法分析是道坎
       破解知识都沾边
       要想一直打此过
       文武全才是方向
  
  学破解的好习惯(也是做CRACK ME 的好习惯):
  坚持独立完成破解(CRACK ME)。贵在坚持。
  案头常备基础破解教材查询。
  记事本,记录破解过程。
  了解CM作者的题目要求是做CRACK ME的基本常识。
  不要为了做CRACK ME而做。记住,我们是为了提高自己的破解技术来做CRACK ME 的。
  CRACK ME的练习并不在数量的多少,而在于质量,在于不断的练习、总结和积累经验。
  要学好破解的最好方法就是不断地自己独立地破解而不
  是在论坛上焦急地等待别人的关照。只有不断地实践,才能体会破解书中散落的种种技术细节问题。很多菜鸟也懂这个道理,但心里有一种急功近利和畏难心理在做怪,总是迫不急待地看破文答案。这不是一个好习惯。其实开始学破解时,好几天没有进展是很平常的。这是好事。百分之九十的人都会这样。为什么呢?每位破解高手都有他的强项和弱项。多数人遇到的障碍,往往是他的弱项。你想提高自己,弥补弱项,就以它为目标钻研下去。
  很简单的道理,强项都不是天生的。
  
  有没有达到学算法分析水平的测试。
  
  我自己的总结经验就是
       断点的设定应根据程序的相应事件进行着手,这是设断总的思路原则。
  对许多无提示的软件,在动态调试中查看字符串是常用手段。
  设断时还要考虑编程语言的特点。
  易语言的下断常用方法。
  
  破解的最最基础:
  就是对程序流程的理解是否透彻。通常情况下,会爆破意味着对程序流程的理解比较透彻,而算法分
  析的基石就是程序流程。有数学天分的人,往往逻辑性强。
      循环渐多迷人眼,
      程序流程指方向,
      分清主次破四方,
      程序流程念心中。
  
  判断明码注册码的一般程序流程:
      段1:赋值注册码。
      段2:检测注册码的对错,即控制程序流程的语句。特征是条件判断语句。
      段3:分道扬镳。对和错两个子程序。
  
  判断暗码注册码算法分析的一般程序流程:
      段1:赋值假用户名和假码。
      段2:用户名和注册码算法段
      段3:检测注册码的对错,即控制程序流程的语句。特征是条件判断语句。
      段4:分道扬镳。对和错两个子程序。
  
  目的是迅速确定算法分析的大致范围甚至具体的方位。
  
附算法分析入门教程实战篇基础知识之一:程序流程。
  算法分析入门教程实战篇基础知识之二:常用ASCII表。在OD的命令行里用?指令助记忆。
                                      汇编资料书查询少见字符串。
  算法分析入门教程实战篇基础知识之三:汇编语言集合 转自PYG官方论坛飘云阁 初学者乐园。
  
  新手常见的调试问题处理方法有------
  
  --返回主程序领空的一般方法:
  1.CTAL+F9。
  2.ALT+F9。
  3.内存代码段设断法。
  
  --逆向追踪的两个例子,体会逆向工程的大意。
  
  --许多朋友对CALL的含义不知道如何快速地理解它的用途。这可是算法分析的关键。示范了 如何看寄存器窗口和内存窗口、信息窗口,唠叨了一大堆帮助他们理解,其中多次运用了相应的断点法,加深理解。其实看这几个窗口的核心就是我们输入的假用户名和假码两内奸,结合程序流程的关键控制流程语句细细研读,不放心的可以变换用户名和注册假码多用用对比法。
  
  ---许多的NAG窗口。F12暂停,然后CTAL+F9是个好的组合。
  
  算法分析应用价值具体例子:利用程序自身写注册机具体过程和思路。
  推荐laomms的许多相关的系列文章。这方面laomms在看雪论坛上写了许多相关的文章,
  大家有兴趣的可以在看雪论坛输入laomms查询,下载laomms文中的附件练习。
  
  算法分析的作用
  1.象杀毒软件样方便、高效。现在的注册码许多都对应机器码,一机一码。下面我就不举例了,大家都是比我聪明的
    高智商,只有我这傻瓜在这象蜗牛样爬格子。论坛上讲得太多了,小孩子都能倒背。
  2.发现软件的BUG,尽量调试弥补。
  3.也可以打补丁。
  4.利用软件自身做注册机。这是一个方向,终点是调试、完善软件。
  
  在这唠叨一句,破解很容易走火入魔。奉劝爱
  好破解的朋友注意心理健康的调节,有自己的业余爱好,不要做破解呆子。
  
  算法分析需要懂汇编语言吗?
  写文章需要认识字吗?
  
  高手是不是都很牛,一看汇编语句就明明白白我的心?
  看小说是不是所有的字都认识?研究生英语考试的阅读理解生词多不多,是不是全能看懂?
  
    其实猜测生词和冷僻
    词汇也一样,我们很难在没有上下文的情况下猜出词意。但这不代表我连上下文也看不懂,更不代表没有学单词的必要。
    学汇编语言是算法分析的基础。但不意味着我们只有完全掌握了汇编语言后才能来搞算法分析。学于算法分析,用于算法
    分析,这是可行的。
  
  怎样象猜冷僻词样猜不太理解的汇编语言?要点如下:
    A.熟悉算法分析大段落的文章结构模板。
    B.充分利用动态调试的特点。对吃不准的CALL,宁愿更换用户名和注册码试验,采用对比法鉴定自己的猜想。
      在算法分析里,现在的软件子循环象子公司一样多,子循环内套着子循环。晕死你。
    C.在关键的地址处可以采用内存断点法或硬件断点法跟踪算法流程。
    D.经常对堆栈窗口、寄存器窗口和信息窗口、内存窗口进行查看,特别留意与假用户名和假注册码相关的汇编语言。
  
  算法分析大段落的文章结构模板:
  
    A.读取假用户名和假码。
    B.获取位数。判断是否为空。以前经常看到有CRACK ME的作者出洋相,什么都不输入,直接点注册,居然成功。所以这往
      往是我们确定算法分析的开始的依据。为什么直接点注册,居然成功?要善于发现问题。
    C.对用户名和注册码的限制条件判断。
    D.对用户名和(或)注册码的处理段,可以是逻辑运算和(或)各种字符的转换。这里可分几个小段分别处理。
    E.对处理过的用户名和(或)注册码进行保藏,地址可以是内存、堆栈、注册表或文件。
    F.调用处理过的用户名和(或)注册码,进行比较。
    G.消除比较后的用户名和(或)注册码进行安全处理,你可以理解为毁尸灭迹。
  
  上述的结构前后顺序可能不完全一样,许多语句或段落也不一定全具备。你心中有了这个模板,猜CALL的含义会轻松很多。
  
  几个常见的汇编语句组合。
    *PUSH002:对字符的ASCII值一定要熟悉,深入分析非密码学算法的关键。很多算法是在字符的ASCII值
  上做文章的。连字符在序列号中经常用到,应熟记。空  格--> 20在NAG窗口中常用,应背熟。
  
  BUG和修改字符串的简单探讨。
  
  《算法注册机编写扫盲BY我要[DFCG]》,看雪论坛上有laomms的六篇系列注册机教程、CCDEBUGER及
  其他高手的OLLYDBG入门系列。
  
  看雪论坛名人整盅游戏系列,穿插调节文章的节奏--
  
  --看雪论坛之藏龙卧虎是破解界公认的。CRACK ME的难度也是业内公认的。
  --我的案头放的是段钢著的《家蜜和街蜜II》--看雪老大的风流韵事。
  --在此感谢laomms的好文赐我灵感。啥?
         侵权?你知道不,laomms是个女的,身材超赞的。还不懂?情人节快到了,明白了吗?
         我俩分啥彼此。
     要成名,先断背
     学算法,先学断  
       韩红和管彤的断背之说,闹的是沸沸扬扬。为了感谢laomms,我这整了个小花边。无他,想
  让laomms出名,只好让他当了会女的。废话,不当女的,我不就和他断背了吗?呵呵,搞点小花絮
  轻松一下。
       哥们我天生就是孬种。为什么老说哥们?怕大家怀疑我是女的呀。

  ---这是什么论坛啊?别牢骚了,没看见论坛坛主的名字吗?
  
  我自逍遥又风流,
  气你气你就气你。
  情人节时忙买花,
  送花莫要写错名。
  
  天,你这哪是算法分析,整个一看雪论坛名人整盅游戏。轻松一下,休息休息。
  ---是控制程序流程的语句,这可是注册码的重要特征啊。你说是就是啊?我还说偶像laomms是个武林高手呢。
  ---大家都是比我聪明的高智商,只有我这傻瓜在这象蜗牛样爬格子。论坛上讲得太多了,
     小孩子都能倒背。
  ---等等,还有个小BUG,你输入错的机器码才会出现修改过的注册机。那万一买彩票中了大奖,
     输入的是正确的机器码呢?
    不是看不到你辛苦做的注册机了吗?
  ---“crackmegame游戏一下”也有一个小BUG,你看出来了吗?我是很长时间才发现。刚想上网吹吹牛,发现阳小子一眼就看出来了。
     
     一山还比一山高,
     不是菜鸟我是谁?
     望尽破解路遥遥,
     我不勤奋待何日?
  
     横批:不服不行。
  ---大写和小写的相互转换:你呀的穿上小皮袄我就认不出你是乌龟了。
  ---数值的十进制和16进制转化、字符直接变数字和数字直接变字符。你就是脱了小皮袄我照样认出你是小乌龟。
  
  
       要上网,踏新浪
       找资料,上百度
       当黑客,乘黑鹰
       学破解,来看雪
      
  
       算法分析是道坎
       破解知识都沾边
       要想一直打此过
       文武全才是方向
  
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛和NBA2005, 转载请注明作者并保持文章的完整, 谢谢!

                                                       2008年02月12日 上午 12:15:15常用,应背熟。


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 7
支持
分享
最新回复 (96)
雪    币: 423
活跃值: (11)
能力值: ( LV9,RANK:230 )
在线值:
发帖
回帖
粉丝
2
套用周星驰--武状元苏乞儿的经典对白:
降龙十七式使用完毕,第十八式就靠你自己的悟性和汗水了。

天才=百分之一的灵感+百分之九十九的汗水。

看雪论坛之藏龙卧虎是破解界公认的。CRACK ME的难度也是业内公认的。
所以,开始做不出来很正常。别灰心。坚持,坚持,再坚持。

好累啊。以后就要忙考试了。我会想念大家的!我会常来玩的。

汇集其他人写的此CRACK ME 的破文:
{
【原创】题目为“Splish,Splash”的crackme的算法分析(菜鸟第一次)      

--------------------------------------------------------------------------------
标 题: 【原创】题目为“Splish,Splash”的crackme的算法分析(菜鸟第一次)
作 者: WILDBUG
时 间: 2006-06-17,16:18
链 接: http://bbs.pediy.com/showthread.php?t=27566

【破解作者】 wildbug
【作者邮箱】 :)
【作者主页】 :)
【使用工具】 OD, PEiD,ASCII码转换,windows计算器
【破解平台】 Win98
【软件名称】 题目为“Splish,Splash”的crackme
【下载地址】 看雪论坛精华5-序列号-splish
【软件简介】 一个crackme,有3个输入框,第一个为Hard Coded,输入,下面有Check HardCoded按钮,第二、三是输入Name和

Serial的,下面有Name/Serial Check按钮。
【软件大小】 232KB
【加壳方式】 无
【破解声明】 献给和我一样看到无明码就想爆破的兄弟:)
}

{
一个2合1的CRACKME算法分析      

--------------------------------------------------------------------------------
标 题: 一个2合1的CRACKME算法分析
作 者: 逍遥风
时 间: 2006-02-15,13:31
链 接: http://bbs.pediy.com/showthread.php?t=21346

}
2008-2-12 00:32
0
雪    币: 423
活跃值: (11)
能力值: ( LV9,RANK:230 )
在线值:
发帖
回帖
粉丝
3
怪了,排序老改不过来:

附算法分析入门教程实战篇基础知识之二:常用ASCII表

  数 字类:
数    字  0  1  2  3  4  5  6  7  8  9  
十六进制  30 31 32 33 34 35 36 37 38 39
十  进制  48 49 50 51 52 53 54 55 56 57

  大写字母:
字    母  A  B  C  D  E  F  G  H  I  J  K  L  M  N  O  P  Q  R  S  T  U  V  W  X  Y  Z  
十六进制  41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 51 52 53 54 55 56 57 58 59 5A
十  进制  65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90

  小写字母:
小写字母  a  b  c  d  e  f  g  h  i  j  k  l  m  n  o  p  q  r  s  t  u  v  w  x  y  z
十六进制  61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A
十  进制  97 98 99 100101102103104105106107108109110111112113114115116117118119120121122

  特殊字符:
字    符  
   !  "  #  $  %  &  '  (  )  *  +  ,  -  .  /  :  ;  <  =  >  ?  @  [  \  ]  ^  _  `  {  |  }  ~
十六进制  
20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 3A 3B 3C 3D 3E 3F 40 5B 5C 5D 5E 5F 60 7B 7C 7D 7E
十  进制  
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 58 59 60 61 62 63 64 91 92 93 94 95 96123124125126

使用频率高的:
数    字:'0'~'9' --> 30~39
大写字母:'A'~'Z' --> 41~5A
小写字母:'a'~'z' --> 61~7A

特别字符:空  格' '--> 20
         连字符'-'--> 2D
2008-2-12 01:17
0
雪    币: 485
活跃值: (12)
能力值: ( LV9,RANK:490 )
在线值:
发帖
回帖
粉丝
4
很长,很暴力。
严重支持。。。
2008-2-12 07:56
0
雪    币: 141
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
支持。注册码方面看哪些资料会比较好呢?谢谢!
脱了壳,卡在注册码。
http://rapidshare.com/files/91091789/bee.rar.html
2008-2-12 12:40
0
雪    币: 134
活跃值: (84)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
6
要上网,踏雅虎
找资料,上谷歌
当黑客,戴黑帽
学破解,来看雪
2008-2-12 13:09
0
雪    币: 443
活跃值: (200)
能力值: ( LV9,RANK:1140 )
在线值:
发帖
回帖
粉丝
7
看完你这篇,我都不用看其他的啦!!!!很暴力!
2008-2-12 15:31
0
雪    币: 204
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
这么经典,汗
2008-2-12 18:36
0
雪    币: 203
活跃值: (21)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
一看就知道楼主是个严重会学习的人,善于思考,赞一个!!!
俺缺的就是静下心来细细总结的耐心,向你学习!!!
2008-2-13 13:46
0
雪    币: 248
活跃值: (10)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
10
家里没电脑,呵呵。复制下来打印归一回家看喽~~~~谢谢NBA2005,果然NBA。呵呵
2008-2-13 16:54
0
雪    币: 423
活跃值: (11)
能力值: ( LV9,RANK:230 )
在线值:
发帖
回帖
粉丝
11
抱歉。春节前筹备构思了半个月,节日里连续奋斗了两天两夜一气呵成(为了保证写作思路的严谨和前后的呼应和谐)。很累。睡了一天,锻练了两三天,见了写作就怵。写过了才知道,为什么前辈都挑简单的程序做教材的示范例子。当时挺满意的。

其实我的文中已经详细的回答了。今天认真看了自己的辛苦大作,发现过于专业化了。因为本文的重点是对算法分析努力进行系统的理论阐述,核心是程序流程。个人的理解是:将研究重心放在算法分析的人多数具备对注册码的查找实战了。因此没有过多地着墨于此。

附业余版本的查找注册码:
1.确定提示信息的位置。多数是错误的信息。设断方法文中已经详细叙述了。

2.向上查找关键的跳转。粗粗过一遍程序的大体结构,把握程序的流程和大体结构。

3.再向上寻找关键的CALL 、内存地址或堆栈窗口,结合与你输入的假用户名和假码相关的程序流程、汇编语言知识的理解综合研判。对大多数程序而言,注册码(特别是明码)往往在关键的跳转不远处的内存地址或堆栈窗口、寄存器窗口中。暗码分析要看懂大致的算法。

写作随笔点滴:
    有许多的联想和瞬间飘过的灵感并没有体现在文中,都是为了体现算法分析的大核心而忍痛放弃。现就回忆记录如下:

    元旦时,MM拿这个简单的CRACK ME向我求教。忽然感慨:这么有名的看雪论坛,在算法分析的教学上,居然都是单一的记叙文。好些的文章里,偶尔会飘出一两句经典的经验体会。但就系统性来说,远远不能满足新兵的强烈求知欲。难道就不能多些议论文、多些专题论文?难道真是我的水平比他们好、文才比他们优美?我还没有无知到这个地步。gzgzlxg的API 绝密档案系列的精彩,大家有目共睹。看雪论坛上,研究利用程序注册机的人很多,水平高的人也不少,但象laomms那样无私地将自己系统的理论、经验毫无保留地奉献、公开,恐怕曲指可数。如果看雪论坛有声望排行榜的,我相信laomms一定榜上有名。正是laomms的无私,才有了我的这篇拙著。无提示的例子,也是最后才决定加入的。

    现代的破解人,需要有远大的眼光和清醒的政治头脑。现代的战争里,虚拟战场已经成为关系国家安全的最核心的战场。当人们在讨论金融战争时,又有多少人意识到外国金融这两年对中国金融的巨大冲击。房产、期货、黄金、外汇和股市、债券......几乎所有的金融品种全部随国外相关品种创出历史新高。在高昂的牛头下,又有多少人意识到未来两年多金融市场的惨烈。人无远虑,必有近忧。在遍地黄金的赚钱效应下,又有多少人在纸上富贵的梦里沉迷。慢涨巨跌的规律,同样造就了绝大多数人亏损的铁律。又有多少人会想到,中国金融市场两三年后的绝处逢春呢?大众很少有人意识到:外国的金融已经做好了对中国金融侵略的战略部署。箭在弦上!!!1997年,泰国的经济毁于外国金融的侵略,一点不为过。

    金融如是,破解又何尝不是如此?经常上看雪的人都知道,看雪老是受到有心人有组织有技术含量的攻击。看雪不公开破国内的软件,同时及时通报软件作者有关的BUG,经常调试、检测许多的国内著名软件。很显然,攻击的利益团体来自国内的可能性很小。

    似乎虚拟战争离我们很远。但黑客圈的人都知道,近几年中外黑客进行了多次的较量。很可惜,在我的菜鸟裁判的眼中,中国的劣势很明显。与老百姓关系最密切的就是大众软件和游戏软件的破解,这实质就是经济发展的相互破坏。银行、金融、信息、通讯、交通......,哪一项离得开电脑?哪一项离得开程序?一个非洲国家的大选工具竟被亲美派做了手脚,其意义和启示是深远的。最显著的例子就是中国的股市,人为控制的痕迹相当明显,政治意图逼迫人民币升值,缓解某大国的巨大财政赤字。

   扯远了?NO!黑客、破解和软件开发,这三者对未来国家安全的重要性日益明显。为什么多家软件公司给熊猫烧香的作者许诺未来?为什么CRACK ME将“软件漏洞分析入门”置顶?为什么现在的研究重点放在了密码学上?为什么欧洲和其他国家抵制有后门机关的WIN视窗和浏览器?

   2004年8月17日的美国加州圣巴巴拉,正在召开的国际密码学会议(Crypto’2004)安排了三场关于杂凑函数的特别报告。在国际著名密码学家Eli Biham和Antoine Joux相继做了对SHA-1的分析与给出SHA-0的一个碰撞之后,来自山东大学的王小云教授做了破译MD5、HAVAL-128、 MD4和RIPEMD算法的报告。因为她的研究成果作为密码学领域的重大发现宣告了固若金汤的世界通行密码标准MD5的堡垒轰然倒塌,引发了密码学界的轩然大波。会议总结报告这样写道:“我们该怎么办?MD5被重创了;它即将从应用中淘汰。SHA-1仍然活着,但也见到了它的末日。

   破解是相当有前途的一门新兴学科,必将会受到国家政策的大力扶持。在这方面,有着政府背景传闻的看雪论坛,做出了巨大的努力,并已经着手开始行动具体化。美国、台湾、欧洲和中国的劲敌印度,都大力扶持破解、软件开发和网络安全的发展。许多有着政府背景传闻的实力软件公司,也在四处寻找货真价实的相关人才。我期待着,破解和网络攻防的知识能早日出现在计算机专业大学的科目中。这是加强我国防安全的必然发展趋势。

   在你迈向上述三大领域前,算法分析是道坎,而不是查找注册码。

   在算法分析中,程序流程的理解能力的高低,决定了算法分析的效率和精确度。可以毫不夸张地说,算法分析的水平差距就在程序流程的把握能力上。这是我再三强调的原因。而写注册机,则更让我们加深对程序流程的理解。许多高手也知道这道理,但怕吓跑了新手。

   汇编知识随着经验的积累和多次练习,很快就能掌握。但对程序流程的把握能力,却是需要天分的,与是不是学计算机专业没有关系。这能回答为什么许多业余的破解手能超越学计算机专业的。2008年NBA2005算法分析实战淘汰赛是你学习破解和有没有发展潜力的理论依据。

    突破了算法分析,就要面临发展方向的选择了。人的精力是有限的,只能发挥人的特长,才会人尽其用。你的优势就是你的发展方向。
脱壳?
软件调试和完善?
密码学?
翻译?
教学?
文秘?
汉化?

   几点建议:
1.脱壳也是破解的重要技术。建议脱壳CRACK ME 专栏。
2.每年评选十大优秀破文。
3.开辟破解技术的专题教学,如算法分析或密码学、程序BUG、利用程序自身做注册机等等。

呵呵,象写网络小说了。
签上特征:

没有远虑
必有近忧
没有看雪
必有雪灾

破友们
大家起来
为看雪的兴旺
众人拾柴火焰高。
2008-2-16 23:40
0
雪    币: 485
活跃值: (12)
能力值: ( LV9,RANK:490 )
在线值:
发帖
回帖
粉丝
12
再次对nba2005顶帖支持.
2008-2-17 08:13
0
雪    币: 479
活跃值: (25)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
13
我觉得NBA2005的这句话“ 在算法分析中,程序流程的理解能力的高低,决定了算法分析的效率和精确度。”深有同感。
支持!
2008-2-17 12:16
0
雪    币: 69
活跃值: (342)
能力值: ( LV9,RANK:550 )
在线值:
发帖
回帖
粉丝
14
哥们,是文科出身阿
2008-2-17 14:17
0
雪    币: 2256
活跃值: (941)
能力值: (RANK:2210 )
在线值:
发帖
回帖
粉丝
15
谁说文科的就不能搞这个呀。。。
2008-2-17 15:38
0
雪    币: 224
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
laomms粉丝!!
2008-2-18 03:57
0
雪    币: 423
活跃值: (11)
能力值: ( LV9,RANK:230 )
在线值:
发帖
回帖
粉丝
17
附业余版本的查找注册码:
1.确定提示信息的位置。多数是错误的信息。设断方法文中已经详细叙述了。

2.向上查找关键的跳转。粗粗过一遍程序的大体结构,把握程序的流程和大体结构。

3.再向上寻找关键的CALL 、内存地址或堆栈窗口,结合与你输入的假用户名和假码相关的程序流程、汇编语言知识的理解综合研判。对大多数程序而言,注册码(特别是明码)往往在关键的跳转不远处的内存地址或堆栈窗口、寄存器窗口中。暗码分析要看懂大致的算法。

程序流程的理解能力的高低,决定了算法分析的效率和精确度。可以毫不夸张地说,算法分析的水平差距就在程序流程的把握能力上。这是我再三强调的原因。

具体举例如下:
阳小子的第一个易语言编写的EM,希望新手可以找回自信!高手飘!

mingligli 已经做出了答案,我就可以简单分析如下,按照逆向追踪的顺序记录:

1.设断。上文已经详述。
2.向上查看关键跳转语句,粗粗过一遍,了解整个注册码处理大段的程序大致流程。
  发现关键跳转语句都对应下面一排共十个JMP。
Breakpoints
地址       模块       激活                       反汇编                                注释
0041A6F1   阳小子EM      始终                         push    ebp                           (initial cpu selection)
0041A745   阳小子EM      始终                         je      0041AD71
0041A7A1   阳小子EM      始终                         jge     0041AD6C
0041A7FD   阳小子EM      始终                         jnz     0041AD67
0041A893   阳小子EM      始终                         je      0041AD62
0041A935   阳小子EM      始终                         je      0041AD5D
0041A9CB   阳小子EM      始终                         je      0041AD58
0041AA6D   阳小子EM      始终                         je      0041AD53
0041AB0F   阳小子EM      始终                         je      0041AD4E
0041ABB1   阳小子EM      始终                         je      0041AD49
0041AC53   阳小子EM      始终                         je      0041AD44

正确的提示段

0041AD3F   /E9 00000000     jmp     0041AD44
0041AD44   \E9 00000000     jmp     0041AD49
0041AD49    E9 00000000     jmp     0041AD4E
0041AD4E    E9 00000000     jmp     0041AD53
0041AD53    E9 00000000     jmp     0041AD58
0041AD58    E9 00000000     jmp     0041AD5D
0041AD5D    E9 00000000     jmp     0041AD62
0041AD62    E9 00000000     jmp     0041AD67
0041AD67    E9 00000000     jmp     0041AD6C
0041AD6C    E9 00000000     jmp     0041AD71
0041AD71    8BE5            mov     esp, ebp

估计要经过十次考验,只要一次不通过就绕过正确的提示。有了大致的程序流程的框架,
破解的目标就很明确了。

3.再向上一直到整个注册码处理大段的段首,设断0041A6F1    55      push    ebp:
0041A6EF    5D              pop     ebp
0041A6F0    C3              retn
0041A6F1    55              push    ebp
0041A6F2    8BEC            mov     ebp, esp
0041A6F4    81EC 0C000000   sub     esp, 0C
0041A6FA    6A FF           push    -1
0041A6FC    6A 08           push    8
0041A6FE    68 72000116     push    16010072
0041A703    68 01000152     push    52010001
0041A708    E8 610A0000     call    0041B16E
0041A70D    83C4 10         add     esp, 10

第一个判断是注册码不能为空。
第二个判断是判断注册码位数小于0A。
0041A79D    837D F8 0A      cmp     dword ptr [ebp-8], 0A
0041A7A1    0F8D C5050000   jge     0041AD6C
第三个判断是判断注册码位数为07。
0041A7F9    837D F8 07      cmp     dword ptr [ebp-8], 7
0041A7FD    0F85 64050000   jnz     0041AD67
前三个判断是对注册码的限制条件。其中第二个判断是干扰,不重要。

4.程序流程概念清晰的人立刻想到剩下的七个判断就是分别逐位地判断。

后面七个判断的关键对比:
0041A9C7    837D F4 00      cmp     dword ptr [ebp-C], 0
关键对比前的关键CALL:
call    0041A58D
查找所有命令:call    0041A58D

找到的命令有八个:
找到的命令
地址       反汇编                      注释
0041A71B   call    0041A58D        判断注册码不能为空。

0041A869   call    0041A58D
0041A90B   call    0041A58D
0041A9A1   call    0041A58D
0041AA43   call    0041A58D
0041AAE5   call    0041A58D
0041AB87   call    0041A58D
0041AC29   call    0041A58D
看来要处理比较七次。

全部设断(除外注册码不能为空的判断),进入此        CALL:
0041A58D    8B5424 04       mov     edx, dword ptr [esp+4]          假注册码
0041A591    8B4C24 08       mov     ecx, dword ptr [esp+8]          内存地址0040C0EC处的字符串
0041A595    85D2            test    edx, edx
0041A597    75 0D           jnz     short 0041A5A6
0041A599    33C0            xor     eax, eax
0041A59B    85C9            test    ecx, ecx
0041A59D    74 06           je      short 0041A5A5
0041A59F    8039 00         cmp     byte ptr [ecx], 0
0041A5A2    74 01           je      short 0041A5A5
0041A5A4    48              dec     eax
0041A5A5    C3              retn

0041A5A6    85C9            test    ecx, ecx
0041A5A8    75 09           jnz     short 0041A5B3
0041A5AA    33C0            xor     eax, eax
0041A5AC    803A 00         cmp     byte ptr [edx], 0
0041A5AF    74 01           je      short 0041A5B2
0041A5B1    40              inc     eax
0041A5B2    C3              retn

0041A5B3    F7C2 03000000   test    edx, 3
0041A5B9    75 37           jnz     short 0041A5F2
0041A5BB    8B02            mov     eax, dword ptr [edx]
0041A5BD    3A01            cmp     al, byte ptr [ecx]
0041A5BF    75 2B           jnz     short 0041A5EC
0041A5C1    0AC0            or      al, al
0041A5C3    74 24           je      short 0041A5E9
0041A5C5    3A61 01         cmp     ah, byte ptr [ecx+1]
0041A5C8    75 22           jnz     short 0041A5EC
0041A5CA    0AE4            or      ah, ah
0041A5CC    74 1B           je      short 0041A5E9
0041A5CE    C1E8 10         shr     eax, 10
0041A5D1    3A41 02         cmp     al, byte ptr [ecx+2]
0041A5D4    75 16           jnz     short 0041A5EC
0041A5D6    0AC0            or      al, al
0041A5D8    74 0F           je      short 0041A5E9
0041A5DA    3A61 03         cmp     ah, byte ptr [ecx+3]
0041A5DD    75 0D           jnz     short 0041A5EC
0041A5DF    83C1 04         add     ecx, 4
0041A5E2    83C2 04         add     edx, 4
0041A5E5    0AE4            or      ah, ah
0041A5E7  ^ 75 D2           jnz     short 0041A5BB
0041A5E9    33C0            xor     eax, eax
0041A5EB    C3              retn

0041A5EC    1BC0            sbb     eax, eax
0041A5EE    D1E0            shl     eax, 1
0041A5F0    40              inc     eax
0041A5F1    C3              retn

关键的内存地址:
内存0040C0EC

其中经典的关键比较处:
0041A5BB    8B02            mov     eax, dword ptr [edx]
0041A5BD    3A01            cmp     al, byte ptr [ecx]
0041A5BF    75 2B           jnz     short 0041A5EC

关键比较处设断:
0041A5BD    3A01            cmp     al, byte ptr [ecx]
注意信息窗口的对比字符。要记住你自己输入的假码的ASCII值。
假码为1234567,较容易确定具体位数的字符。

按程序比较顺序整理如下:
字符判断1:第七位为!
字符判断2:第六位为m
字符判断3:第一位为y
字符判断4:第二位为x
字符判断5:第五位为c
字符判断6:第六位为m
字符判断7:第四位为e
第三位无要求。

内存地址0040C0EC处的字符!myxce共六个分别取值比较,可在此内存地址设访问断点。
正确注册码出来了:(yx*ecm!),第三位任意字符。

与用户名无关,这也是小BUG吧。不输入用户名没关系,只要注册码对就行。
唉,用户名成了聋子的耳朵---摆设!
其实是阳小子故意的,减少了可跟踪判断的信息。但同时也减轻了新手的破解工作量啊。

注册成功后:注册按钮变成了灰化的已注册。
如果你输入用户名,会显示Cracker by 用户名。

这个CRACK ME的难点有:
1:无提示。考易语言的特殊断点法。
2:循环多。考对程序流程的把握能力。猜CALL应该从属于程序流程的判断。
3:逐字乱序比较。考汇编语言的理解能力。

核心是程序流程的把握能力。

好记性不如烂笔头,将自己破解成功的CRACK ME写下来,能促进你对破解的理解。同时也能帮助别人共同进步。何乐而不为呢?

会否会否?
击皱一池春水
知否知否?
扬萧自在看雪

破否破否?
击皱一池春水
懂否懂否?
阳小子在看雪
2008-2-19 08:17
0
雪    币: 423
活跃值: (11)
能力值: ( LV9,RANK:230 )
在线值:
发帖
回帖
粉丝
18
关键CALL里没有详细注释,是故意的。

看看你对程序流程把握好的情况下,考汇编语言的理解能力。

不要偷懒啊!!!
2008-2-19 08:37
0
雪    币: 423
活跃值: (11)
能力值: ( LV9,RANK:230 )
在线值:
发帖
回帖
粉丝
19
英雄不论出身。
王侯将相,
宁有种乎?
望眼破解
科班多乎?

呵呵,泡MM练出来的。歪门邪道,不值一提。想学吗?加入我圣教吧。
2008-2-19 08:42
0
雪    币: 557
活跃值: (10)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
20
NB的长篇大论
2008-2-19 19:23
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
很详细哈!!
2008-2-24 09:41
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
好文章!兄弟厉害,兄弟是个人才
2008-2-25 21:04
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
nba2005 写的真好!谢谢!
2008-3-18 11:14
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
24

这篇文章是我等菜鸟之幸啊
2008-3-24 11:59
0
雪    币: 423
活跃值: (11)
能力值: ( LV9,RANK:230 )
在线值:
发帖
回帖
粉丝
25
我没有想到,自己的这篇长篇之作受到这么多朋友捧场,感动......!!!

是我以一个业余的角度写的缘故?
还是从实战的角度夹叙夹议的原因?

破解是我的爱好,而我的爱好很多:下棋,冰峰王座,溜冰,文学,跳舞,电脑,NBA系列游戏等,泡妞。样样半掉子。所以我始终能够抽出时间以一个陌生的角度面对破解。我是求变的人,不喜欢墨守成规。最近破解了一些实用软件,但都是国产的,所以也不好拿出手。而且最近工作上很忙,没有时间静下心来写作。许多人不愿写破文,因为写的时间远比破的时间长太多。四月初我争取连休,到时找个好的例子感谢大家的厚爱。

到时是另列题目还是接着这个系列呢?

希望欣赏我文章的朋友可以给我添加声望,也希望给你喜欢的破文作者添加声望。就是右上角的红五星。我百忙中写了这么多,只混了一个精,想想都冤。网上老是看到有人暗恋Petnt,就是没有人通过添加声望表白。

其实我很菜,
其实我很忙,
其实我很懒,
其实我业余。
2008-3-25 17:28
0
游客
登录 | 注册 方可回帖
返回
//