【文章标题】: 菜鸟死追注册码(详细版,求精华)
【文章作者】: sbright
【作者邮箱】: 51682
【作者主页】: www.qq.com
【作者QQ号】: 51682
【软件名称】: Pic2Ico
【软件大小】: 712KB
【下载地址】: www.exeicon.com
【加壳方式】: ASPack 2.001 -> Alexey Solodovnikov
【保护方式】: 序列号
【编写语言】: Borland C++ 1999
【使用工具】: OD,PEID 0.94,windows 计算器,ASCII码表
【操作平台】: xp1
【软件介绍】: 一款抓取图标的小工具,个人感觉还有点小用
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
        前言,来看雪发贴将近一百啦,学啦很久的脱壳,还是不会什么,决定还是从简单做起,于是就有啦这篇文章。希望在百贴之前能有精华。这篇文章没有任何技术含量,但却包含啦一些对菜鸟而言基本的方法(包过使用od),它花啦我一下午,纯粹是考验我的毅力。 好。我们开始。
       先安装啦程序,实际上这个程序不会复制任何dll,因此主程序可以独立运行。安装好后。我们先运行下程序,弹出个对话框,哈是英文的,大概意思是这个程序能使用7天或使用20次。我们先试探下军情,随便填入个用户名和注册码:sbright,123456.点确定后弹出错误提示:your registration code is invalid.看到这里,我想在现在来看,对这个程序来说,基本有底啦。他不是重起后验证的那种(当然,还是会判断是否已经注册),也应该有注册判断的字符串。应该比较容易找到它判断注册的地方,然后按图索骥,如果算法上不复杂,应该就比较顺利啦。
    虽然是动态的调试,脱掉壳总比较清爽,用peid查壳是aspack 2.001,打开od,点击文件-》打开-》在安装目录下选择:Pic2Ico.exe主程序。这个壳比较容易脱, 直接在第一层找第一个POPAD这句按f4运行到这里。再单步几下,,然后在00613503 RETN这句执行后就到达啦oep,用ollydump插件抓取文件,保存为bbb.exe,便可以直接运行。
         再次用od打开bbb.exe;由于我们开始已经知道如果出现错误,便会有出错提示,因此我们在od主窗口中点击右键,选择查找ascii字符串,上下找一下,我们便会发现your registration code is invalid.我们双击他,来到:
00422C24   .  BA CA275100   MOV EDX,bbb2.005127CA    your registration code is invalid.我们知道,如果我们输入的注册码很用户名不相配,程序就会跳到附近,因此,我们在这附近用鼠标上下点点,看是否有跳转
 跳到附近,因为,如果有,od就会提示一条红色。在他的上一句点一下:
  00422C1E   > \66:C745 B8 80>MOV WORD PTR SS:[EBP-48],80
  00422C24   .  BA CA275100   MOV EDX,bbb2.005127ca    your registration code is invalid.
  我们发现
  004229F9   . /0F84 1F020000 JE bbb2.00422C1E
  也就 004229F9 有可能跳到00422C1E ,然后接着就会出现注册失败===your registration code is invalid。那么知道啦这个,下一步我们应该做些什么呢?急着去分析?我们可以想一下,万一还有别的判断的地方,也就是说还有别的代码不经过这里,而直接跳到注册失败?那岂不是很麻烦?还好,这个程序没有。你也许会问我是如何知道的?因为当我把je改为jne的时候,程序就会注册成功,但因为程序再次启动的时候还是会判断是否注册,所以这样简单的暴力是不行的,,还是让我们来追注册码。我们看004229F9和上面一句:
  004229F2   .  80B9 E4030000>CMP BYTE PTR DS:[ECX+3E4],0
  004229F9   .  0F84 1F020000 JE bbb2.00422C1E
  你不记得汇编代码没有关系,我只知道je是跳转指令,但它的跳转条件我也记不住。我们可以在此期间004229f2处按f2下个断点,然后运行;软件提示我们注册,我们随便输入sbright,123456.中断在004229F2,这时候,我们会发现od中间显示:DS:[00CD308C]=00,也就是说DS:[ECX+3E4]里面的内容为零,如果你稍微懂点汇编,你就知道啦如果DS:[ECX+3E4]等于或小于零,我们就会注册失败。相反,只要DS:[00CD308C]不为零,我们就会成功,因此我们可以不时的看看DS:[00CD308C]=00里面的情况,以便帮助我们了解程序的算法(虽然在这个程序里面,只是最后简单的将DS:[00CD308C]=00给1,但我觉得在其他的一些情况,这种方法很好);
           我们找到啦判断注册的唯一关键,但我们是要追出注册码,找到算法才是最重要的。一般我想,算法应该在004229F2上面,因为程序在判断是否是正确的注册码时算法应该已经执行。现在我们要做的是找个更好的端点,这个断点必须在算法执行前面,以便我们分析算法。看下面这段:
  00422997   > \68 F4010000   PUSH 1F4                                               ; /Timeout = 500. ms
  0042299C   .  E8 B7A40E00   CALL <JMP.&kernel32.Sleep>                             ; \Sleep
  004229A1   .  66:C745 B8 20>MOV WORD PTR SS:[EBP-48],20
  004229A7   .  8D45 F4       LEA EAX,DWORD PTR SS:[EBP-C]
  004229AA   .  E8 CD11FEFF   CALL bbb2.00403B7C
  004229AF   .  8BD0          MOV EDX,EAX
  004229B1   .  FF45 C4       INC DWORD PTR SS:[EBP-3C]
  004229B4   .  8B4D A4       MOV ECX,DWORD PTR SS:[EBP-5C]
  004229B7   .  8B81 04030000 MOV EAX,DWORD PTR DS:[ECX+304]
  004229BD   .  E8 56FE0900   CALL bbb2.004C2818
  004229C2   .  8D55 F4       LEA EDX,DWORD PTR SS:[EBP-C]
  004229C5   .  FF32          PUSH DWORD PTR DS:[EDX]                                ; /Arg1
  004229C7   .  E8 24E7FFFF   CALL bbb2.004210F0                                     ; \bbb2.004210F0
  004229CC   .  59            POP ECX
  004229CD   .  8B0D FCAE5100 MOV ECX,DWORD PTR DS:[51AEFC]                          ;  bbb2._IconConverter
  004229D3   .  8B11          MOV EDX,DWORD PTR DS:[ECX]
  004229D5   .  8882 E4030000 MOV BYTE PTR DS:[EDX+3E4],AL
  004229DB   .  FF4D C4       DEC DWORD PTR SS:[EBP-3C]
  004229DE   .  8D45 F4       LEA EAX,DWORD PTR SS:[EBP-C]
  004229E1   .  BA 02000000   MOV EDX,2
  004229E6   .  E8 890E0D00   CALL bbb2.004F3874
  004229EB   .  A1 FCAE5100   MOV EAX,DWORD PTR DS:[51AEFC]
  004229F0   .  8B08          MOV ECX,DWORD PTR DS:[EAX]
  004229F2   .  80B9 E4030000>CMP BYTE PTR DS:[ECX+3E4],0
  
  这段代码最上面是系统的函数,下面就是:
  
  004229F2   .  80B9 E4030000>CMP BYTE PTR DS:[ECX+3E4],0
  ,算法应该就在之中。
  我们在004229C7   .  E8 24E7FFFF   CALL bbb2.004210F0  下断,部分原因是我看到Arg1,这是不是将我们的伪注册码传进来呢?试试。
  再次点注册,程序断在啦我们想断的地方。按f7跟进看看:
  前面一段是这样的:
  004210F0  /$  55            PUSH EBP
  004210F1  |.  8BEC          MOV EBP,ESP
  004210F3  |.  81C4 74FFFFFF ADD ESP,-8C
  004210F9  |.  56            PUSH ESI
  004210FA  |.  57            PUSH EDI
  004210FB  |.  B8 C0285100   MOV EAX,bbb2.005128C0
  00421100  |.  E8 7B760C00   CALL bbb2.004E8780
  00421105  |.  C745 F8 01000>MOV DWORD PTR SS:[EBP-8],1
  0042110C  |.  8D55 08       LEA EDX,DWORD PTR SS:[EBP+8]
  0042110F  |.  8D45 08       LEA EAX,DWORD PTR SS:[EBP+8]
  00421112  |.  E8 DD260D00   CALL bbb2.004F37F4
  00421117  |.  FF45 F8       INC DWORD PTR SS:[EBP-8]
  0042111A  |.  66:C745 EC 08>MOV WORD PTR SS:[EBP-14],8
  00421120  |.  C645 DB 00    MOV BYTE PTR SS:[EBP-25],0
  00421124  |.  8D45 08       LEA EAX,DWORD PTR SS:[EBP+8]
  00421127  |.  E8 704AFEFF   CALL bbb2.00405B9C
  0042112C  |.  83F8 2C       CMP EAX,2C
  0042112F  |.  0F85 3E020000 JNZ bbb2.00421373
  00421135  |.  BE D6245100   MOV ESI,bbb2.005124D6                          ;  1z1h+2a0n-0g8y*9a1n|
  0042113A  |.  8D7D 88       LEA EDI,DWORD PTR SS:[EBP-78]
  
  这部分你可以粗跟,但我是仔细跟踪每个call啦,因为我菜嘛。有种更好的方式。当你粗跟到:0042112C  |.  83F8 2C       CMP EAX,2C这句时,你会发现eax中的数正好是注册码的位数,那么这是不是比较注册码长度呢?你可以换个注册码试试?看是不是EAX的内容是不是也跟着变化,而且下面这句是不是有点象注册码的格式?
  00421135  |.  BE D6245100   MOV ESI,bbb2.005124D6       1z1h+2a0n-0g8y*9a1n
  你也可以看看00421373处的代码:
  
  00421373  |> \8A45 DB       MOV AL,BYTE PTR SS:[EBP-25]
  00421376  |.  50            PUSH EAX
  00421377  |.  FF4D F8       DEC DWORD PTR SS:[EBP-8]
  0042137A  |.  8D45 08       LEA EAX,DWORD PTR SS:[EBP+8]
  0042137D  |.  BA 02000000   MOV EDX,2
  00421382  |.  E8 ED240D00   CALL bbb2.004F3874
  00421387  |.  58            POP EAX
  00421388  |.  8B55 DC       MOV EDX,DWORD PTR SS:[EBP-24]
  0042138B  |.  64:8915 00000>MOV DWORD PTR FS:[0],EDX
  00421392  |>  5F            POP EDI
  00421393  |.  5E            POP ESI
  00421394  |.  8BE5          MOV ESP,EBP
  00421396  |.  5D            POP EBP
  00421397  \.  C3            RETN
  
  基本上这个跳转等于返回,这相当与提前给你的注册码判死刑,后面几乎没有什么有价值的代码我们当然不能让它跳,索性,我重新运行程序。将用户名改为啦peid,注册码改成12345612345612345612345612345612345612345612 长度为44用16进制转换就 2c,你可以用windows计算器来转换。顺便说一下,对注册码是怎样的格式我并不知道如何能从字符串看出来,
  00421135  |.  BE D6245100   MOV ESI,bbb2.005124D6                          ;  1z1h+2a0n-0g8y*9a1n|
  这具体是做什么的,我还是没有弄明白。接下来是这样一段代码:
  0042113D  |.  B9 05000000   MOV ECX,5
  00421142  |.  F3:A5         REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI]
  00421144  |.  A4            MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI]
  00421145  |.  8D45 08       LEA EAX,DWORD PTR SS:[EBP+8]
  00421148  |.  E8 2B10FEFF   CALL bbb2.00402178
  0042114D  |.  0FBE50 28     MOVSX EDX,BYTE PTR DS:[EAX+28]
  00421151  |.  83FA 50       CMP EDX,50
  00421154  |.  74 23         JE SHORT bbb2.00421179
  00421156  |.  33C0          XOR EAX,EAX
  00421158  |.  50            PUSH EAX
  00421159  |.  FF4D F8       DEC DWORD PTR SS:[EBP-8]
  0042115C  |.  8D45 08       LEA EAX,DWORD PTR SS:[EBP+8]
  0042115F  |.  BA 02000000   MOV EDX,2
  00421164  |.  E8 0B270D00   CALL bbb2.004F3874
  00421169  |.  58            POP EAX
  0042116A  |.  8B55 DC       MOV EDX,DWORD PTR SS:[EBP-24]
  0042116D  |.  64:8915 00000>MOV DWORD PTR FS:[0],EDX
  00421174  |.  E9 19020000   JMP bbb2.00421392
  00421179  |>  8D45 08       LEA EAX,DWORD PTR SS:[EBP+8]
  0042117C  |.  E8 F70FFEFF   CALL bbb2.00402178
  00421181  |.  0FBE50 29     MOVSX EDX,BYTE PTR DS:[EAX+29]
  00421185  |.  83FA 32       CMP EDX,32
  00421188  |.  74 23         JE SHORT bbb2.004211AD
  0042118A  |.  33C0          XOR EAX,EAX
  0042118C  |.  50            PUSH EAX
  0042118D  |.  FF4D F8       DEC DWORD PTR SS:[EBP-8]
  00421190  |.  8D45 08       LEA EAX,DWORD PTR SS:[EBP+8]
  00421193  |.  BA 02000000   MOV EDX,2
  00421198  |.  E8 D7260D00   CALL bbb2.004F3874
  0042119D  |.  58            POP EAX
  0042119E  |.  8B55 DC       MOV EDX,DWORD PTR SS:[EBP-24]
  004211A1  |.  64:8915 00000>MOV DWORD PTR FS:[0],EDX
  004211A8  |.  E9 E5010000   JMP bbb2.00421392
  004211AD  |>  8D45 08       LEA EAX,DWORD PTR SS:[EBP+8]
  004211B0  |.  E8 C30FFEFF   CALL bbb2.00402178
  004211B5  |.  0FBE50 2A     MOVSX EDX,BYTE PTR DS:[EAX+2A]
  004211B9  |.  83FA 49       CMP EDX,49
  004211BC  |.  74 23         JE SHORT bbb2.004211E1
  004211BE  |.  33C0          XOR EAX,EAX
  004211C0  |.  50            PUSH EAX
  004211C1  |.  FF4D F8       DEC DWORD PTR SS:[EBP-8]
  004211C4  |.  8D45 08       LEA EAX,DWORD PTR SS:[EBP+8]
  004211C7  |.  BA 02000000   MOV EDX,2
  004211CC  |.  E8 A3260D00   CALL bbb2.004F3874
  004211D1  |.  58            POP EAX
  004211D2  |.  8B55 DC       MOV EDX,DWORD PTR SS:[EBP-24]
  004211D5  |.  64:8915 00000>MOV DWORD PTR FS:[0],EDX
  004211DC  |.  E9 B1010000   JMP bbb2.00421392
  004211E1  |>  8D45 08       LEA EAX,DWORD PTR SS:[EBP+8]
  004211E4  |.  E8 8F0FFEFF   CALL bbb2.00402178
  004211E9  |.  0FBE50 2B     MOVSX EDX,BYTE PTR DS:[EAX+2B]
  004211ED  |.  83FA 31       CMP EDX,31
  004211F0  |.  74 23         JE SHORT bbb2.00421215
  
  说实话,我对堆和栈现在都还不是很明白,但估计不久就能明白。但我们可以充分利用od的功能来让我们 明白程序在做什么?比如,当你执行到这句的时候,0042114D  |.  0FBE50 28     MOVSX EDX,BYTE PTR DS:[EAX+28]你想知道到底是什么东西被送到啦edx?你可以用 dd EAX+28(注意:这里EAX+28是od在中间显示的具体数值)来查看,你会发现那正是你输入的注册码。你还可以数一下是第几位。如果你明白我刚才所说的,你就会知道上面的代码是在将注册码的倒数第4位,3位,2位,1位的十六进制分别与:50,32,49,31比较,看是否相等。这里50,32,49,31都是灰色显示,说明应该是常量吧。为啦简单起见,你可以在每次比较的时候,修改EDX的值,在od中间那行点右键就可以修改。因为如果不相等,程序就会网注册码错误那个方向走,这样简单的一段代码是我调啦几次才明白的,希望你也能自己调一下。
          继续往下面走,容易来到下一个关键地方,一般来说,在可能的关键地方,如果有循环,就应该要注意啦:
  0042122A  |.  0FBE4D A1     MOVSX ECX,BYTE PTR SS:[EBP-5F]  //这两句比较第二位是否为零。
  0042122E  |.  83F9 30       CMP ECX,30
  00421231  |.  0F85 3C010000 JNZ bbb2.00421373         //注册将失败。
  00421237  |.  C645 A1 23    MOV BYTE PTR SS:[EBP-5F],23       //将第二位放个23,后面计算有用。
  0042123B  |.  C645 DB 01    MOV BYTE PTR SS:[EBP-25],1
  0042123F  |.  C745 D4 02000>MOV DWORD PTR SS:[EBP-2C],2      //估计是循环计数变量,等下要用,
  00421246  |>  8B45 D4       /MOV EAX,DWORD PTR SS:[EBP-2C]         
  00421249  |.  0FBE5405 88   |MOVSX EDX,BYTE PTR SS:[EBP+EAX-78]  这里第一次的值为:1,后面循环分别为:h,+,2,a,0,0,-
  这些值我没有考虑它从哪里来的,经过测试,这个软件不是根据硬件id的,所以有可能根据用户名来,有时间再跟把,跟跟啦这个,注册机也就出来拉,有兴趣的朋友可以试下,基本方法也就是监视:SS:[EBP+EAX-78] 栈的变化罢啦。
  0042124E  |.  8B4D D4       |MOV ECX,DWORD PTR SS:[EBP-2C]        2送EAX;
  00421251  |.  0FBE440D 9F   |MOVSX EAX,BYTE PTR SS:[EBP+ECX-61]   第一次循环时将第注册码第二位送EAX;接着循环将是第3,4,5,6,7,8,9位。
  00421256  |.  03D0          |ADD EDX,EAX                           
  00421258  |.  8B4D D4       |MOV ECX,DWORD PTR SS:[EBP-2C]
  0042125B  |.  0FBE440D A0   |MOVSX EAX,BYTE PTR SS:[EBP+ECX-60]  第一次循环时将第注册码第3位送EAX;接着循环将是第4,5,6,7,8,9,10位。
  00421260  |.  33D0          |XOR EDX,EAX                做异或运算。
  00421262  |.  8B4D D4       |MOV ECX,DWORD PTR SS:[EBP-2C]
  00421265  |.  0FBE440D 88   |MOVSX EAX,BYTE PTR SS:[EBP+ECX-78]
  0042126A  |.  33D0          |XOR EDX,EAX      再将异或运算得到的EDX每次与1,h,+,2,a,0,0,-这些做异或
  0042126C  |.  52            |PUSH EDX                                              ; /Arg1
  0042126D  |.  E8 26010000   |CALL bbb2.00421398             这个call将EDX给EAX;      ; \bbb2.00421398
  00421272  |.  59            |POP ECX
  00421273  |.  B9 1A000000   |MOV ECX,1A
  00421278  |.  99            |CDQ
  00421279  |.  F7F9          |IDIV ECX
  0042127B  |.  83C2 41       |ADD EDX,41                   这一段象个伪随机数的反汇编,因为我在rjjj的crackme里面看到过这个。
  0042127E  |.  8B45 D4       |MOV EAX,DWORD PTR SS:[EBP-2C]
  00421281  |.  0FBE4C05 A9   |MOVSX ECX,BYTE PTR SS:[EBP+EAX-57]第一次循环的时候将得到的值与注册码12位比较,接着分别与13,14,15,16,17,18,19位比较,
  如果不等就注册失败,因此我们得到这几位注册码:第12到19:iRnvRVTR,方便起见,你可以每次修改ECX的值,让他们相等。
  00421286  |.  3BD1          |CMP EDX,ECX
  00421288  |.  74 06         |JE SHORT bbb2.00421290
  0042128A  |.  C645 DB 00    |MOV BYTE PTR SS:[EBP-25],0
  0042128E  |.  EB 09         |JMP SHORT bbb2.00421299
  00421290  |>  FF45 D4       |INC DWORD PTR SS:[EBP-2C]
  00421293  |.  837D D4 0A    |CMP DWORD PTR SS:[EBP-2C],0A  因为从2开始,这里是循环判断条件。
  00421297  |.^ 7C AD         \JL SHORT bbb2.00421246
  
  
  我们接着来到第二个循环:
  004212B6  |> /8B55 D0       /MOV EDX,DWORD PTR SS:[EBP-30]
  004212B9  |. |0FBE4415 89   |MOVSX EAX,BYTE PTR SS:[EBP+EDX-77]
  004212BE  |. |B9 06000000   |MOV ECX,6
  004212C3  |. |99            |CDQ
  004212C4  |. |F7F9          |IDIV ECX
  004212C6  |. |8BCA          |MOV ECX,EDX
  004212C8  |. |8B45 D0       |MOV EAX,DWORD PTR SS:[EBP-30]
  004212CB  |. |0FBE5405 8A   |MOVSX EDX,BYTE PTR SS:[EBP+EAX-76]
  004212D0  |. |D3E2          |SHL EDX,CL
  004212D2  |. |8B45 D0       |MOV EAX,DWORD PTR SS:[EBP-30]
  004212D5  |. |0FBE4C05 8B   |MOVSX ECX,BYTE PTR SS:[EBP+EAX-75]
  004212DA  |. |0BD1          |OR EDX,ECX
  004212DC  |. |52            |PUSH EDX                                              ; /Arg1
  004212DD  |. |E8 B6000000   |CALL bbb2.00421398                                    ; \bbb2.00421398
  004212E2  |. |59            |POP ECX
  004212E3  |. |B9 1A000000   |MOV ECX,1A
  004212E8  |. |99            |CDQ
  004212E9  |. |F7F9          |IDIV ECX
  004212EB  |. |80C2 61       |ADD DL,61
  004212EE  |. |8B45 D0       |MOV EAX,DWORD PTR SS:[EBP-30]
  004212F1  |. |889405 5CFFFF>|MOV BYTE PTR SS:[EBP+EAX-A4],DL
  004212F8  |. |FF45 D0       |INC DWORD PTR SS:[EBP-30]
  004212FB  |. |837D D0 28    |CMP DWORD PTR SS:[EBP-30],28
  004212FF  |.^\7C B5         \JL SHORT bbb2.004212B6
  
  这个循环与上面那个差不多,分析方法也差不多,只不过这里并没有将它得到的值与直接与注册码进行比较
  ,而是通过这句,MOV BYTE PTR SS:[EBP+EAX-A4],DL,将得到的一组值为:ovcjzpsvzaewimsa存到啦0012FA20开始处。
  
  算法的最后一个循环:
  0042131C  |> /8B55 CC       /MOV EDX,DWORD PTR SS:[EBP-34]        18送EDX,这里是常量。
  0042131F  |. |0FBE8415 5CFF>|MOVSX EAX,BYTE PTR SS:[EBP+EDX-A4]   将上个循环取得的值在这里分别取出ovcjzpsvzaewimsa,
  00421327  |. |C1E0 04       |SHL EAX,4
  0042132A  |. |8B55 CC       |MOV EDX,DWORD PTR SS:[EBP-34]
  0042132D  |. |0FBE8C15 5DFF>|MOVSX ECX,BYTE PTR SS:[EBP+EDX-A3]    这里好像依此次都是第2,3,4,5,6。。。位的值,这是因为每个循环SS:[EBP-34] 的值都会加1
  因此EBP+EDX-A4也会每次递增1。
  
  00421335  |. |D1F9          |SAR ECX,1
  00421337  |. |33C1          |XOR EAX,ECX
  00421339  |. |50            |PUSH EAX                                              ; /Arg1
  0042133A  |. |E8 59000000   |CALL bbb2.00421398                                    ; \bbb2.00421398
  0042133F  |. |59            |POP ECX
  00421340  |. |B9 1A000000   |MOV ECX,1A
  00421345  |. |99            |CDQ
  00421346  |. |F7F9          |IDIV ECX
  00421348  |. |83C2 41       |ADD EDX,41                                这又象是个伪随机
  0042134B  |. |8B45 CC       |MOV EAX,DWORD PTR SS:[EBP-34]
  0042134E  |. |0FBE4405 A0   |MOVSX EAX,BYTE PTR SS:[EBP+EAX-60]                       
  00421353  |. |3BD0          |CMP EDX,EAX                           每次循环将得到的EDX与注册码25位后开始的十六进制比较,总共循环16次,因此比较到40位,如果不相等。 则注册不成功。从这里,我们分别得到注册码从25位到40位为:   XBHDUDEQUKFOMBYL  
  00421355  |. |74 06         |JE SHORT bbb2.0042135D
  00421357  |. |C645 DB 00    |MOV BYTE PTR SS:[EBP-25],0
  0042135B  |. |EB 09         |JMP SHORT bbb2.00421366
  0042135D  |> |FF45 CC       |INC DWORD PTR SS:[EBP-34]
  00421360  |. |837D CC 28    |CMP DWORD PTR SS:[EBP-34],28
  00421364  |.^\7C B6         \JL SHORT bbb2.0042131C
  
  
   哈哈,最后一步,
  00421366  |> \0FBE55 AA     MOVSX EDX,BYTE PTR SS:[EBP-56]
  0042136A  |.  83FA 59       CMP EDX,59
  比较第十一位是否为Y;
  
  我们怎么知道这样一来就成功啦呢?我并没有直接试注册码,因为我开始好几位1234都还没有变,这样未免也简单啦一些,
  但当我跟踪到: 将DS:[00CD308C]付值1的时候,我确定自己成功啦。哈哈,这软件是根据机器码的。用来提取程序图标资源还有点用,大家可以试试。最后得出的注册名和注册码是:
  peid
  1034561234YIRNVRVTR23456XBHDUDEQUKFOMBYLP2I1
  顺便再说一下,http://zhidao.baidu.com/question/5608154.html这里有张ascII码表  
                                                   
 补上算法分析:其实,上面已经基本分析完啦,关键是SS:[EBP+EAX-78]处的数据是如何来的,另我郁闷的是居然与用户名无关,那么我们再看看是否与注册码有关,哈哈,麻烦,又要把注册表里面的注册码先删除. 我们先输入sbright,在00421249处下个断.因为前面已经比较啦几位注册码,如果看啦我上面的分析,你可以重新找个伪码,再试下,我这里直接跟踪栈的变化,我们容易知道栈的位置是: 0012fa36设置内存访问断点,我们发现:  00421142  |.  F3:A5         REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI]
这里从005124d6将数据写入,而且正是我们开始看到的那些数据.
我们再重新运行一次,这次我们在三个地方下断点,    00422997,00012fa36这里下内存写入,005124d6  我们目地是看看    005124d6  DS:[ESI[005124D6]=68317A31是从哪里来的.我们发现,程序不是在我们开始认为的算法处初始化的数据,因为第一次断下时,数据已经存在啦,那我们重新载入程序试试.晕,程序刚载入的时候数据就已经有啦,这是否说名是静态变量呢?不明白,但我们现在已经知道与注册名没有关系,因此我们现在可以写注册机啦.
首先,注册码的基本格式是:X0XXXXXXXXYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXP2I1
写注册机的时候,因为这个程序是根据前面的注册码算后面的,我们不妨初始话数组:char a[44]={1023456789YXXXXXXXXXXXXXXXXXXXXXXXXXXXXXP2I1}(逗号省啦)程序判断第二位是否为零后,就将第二为置#,ascii为35,十六进制为23,
因此我们有这句:char a[1]='#';(说明一下,c语言里面数组下标从零开始,
你可以想象:a[i]就是数组第i+1个数的值.)
首先是一个循环,算11位到18位,循环8次.
另外我们开始已经提到程序初始化的时候就给出啦8个初始数据,我们也用数组存起来:
char b[8]={1,h,+,2,a,0,0,-}(可能有误,哈哈)
程序总是利用栈来转换使用寄存器,在高级语言里面,我们定义变量char c,d;

我们写个for(int i=11;i<=18;i++){
//根据  00421256  |.  03D0          |ADD EDX,EAX    
我们有:
c=a[i-9];d=b[i-8];
c=c+d;
//根据  00421260  |.  33D0          |XOR EDX,EAX  
我们有:
d=a[i-8];  
c=c xor d;
//根据这句,我们有0042126A  |.  33D0          |XOR EDX,EAX  
d=b[i-8];
c=c xor d;
//00421278  |.  99            |CDQ
  00421279  |.  F7F9          |IDIV ECX
  0042127B  |.  83C2 41       |ADD EDX,41                   
  0042127E  |.  8B45 D4       |MOV EAX,DWORD PTR SS:[EBP-2C]
根据这句,我们有:(注意a的ascii的十六进制是41)
c=c%(i-9);
c=(c+'a')%256;
a[i]=c;

}
看第二个循环,这个循环我们用来得到一组16位长的字符数组,用来做下面的计

 我们先char e[16]="";
然后for(int i=0;i<=15;i++){
我们就用上面循环的变量,不另外申请空间啦;
int g=6;
//004212B9  |. |0FBE4415 89   |MOVSX EAX,BYTE PTR SS:[EBP+EDX-77]
  004212BE  |. |B9 06000000   |MOV ECX,6
  004212C3  |. |99            |CDQ
  004212C4  |. |F7F9          |IDIV ECX
根据这句,我们得到的代码是:
 c=a[i+1];
c=c%g;
//004212CB  |. |0FBE5405 8A   |MOVSX EDX,BYTE PTR SS:[EBP+EAX-76]
  004212D0  |. |D3E2          |SHL EDX,CL
  004212D2  |. |8B45 D0       |MOV EAX,DWORD PTR SS:[EBP-30]
  004212D5  |. |0FBE4C05 8B   |MOVSX ECX,BYTE PTR SS:[EBP+EAX-75]
  004212DA  |. |0BD1          |OR EDX,ECX
根据上面,有下面的代码.
d=a[i+2];
d=d shr c;
c=a[i+3];
d=d or c;
d=(d%26+97)%256;
e[i]=d;
}        
哈哈,大家有没有觉得,我写的c语言几乎就是汇编?哈哈,谁要我还菜.很多结构]
还不会分析,程序也没有写过几行,姑且叫我上面的为v(伪)c代码吧!!!
下面是最后一个:


for(i=0;i<=15;i++){
//0042131F  |. |0FBE8415 5CFF>|MOVSX EAX,BYTE PTR SS:[EBP+EDX-A4]   将上个循环取得的值在这里分别取出ovcjzpsvzaewimsa,
  00421327  |. |C1E0 04       |SHL EAX,4
  0042132A  |. |8B55 CC       |MOV EDX,DWORD PTR SS:[EBP-34]
  0042132D  |. |0FBE8C15 5DFF>|MOVSX ECX,BYTE PTR SS:[EBP+EDX-A3]
这句代码,我们可以写成
c=e[i] shr 4;
d=a[i+1] shr 1;
c=c or d;
c=(%27+65)256;
a[i+24]=c;
}
最后
a[1]=0;
 这样,我们最后在数组a中得到的就是注册码忘记c里面的左移,右移啦,如果上面数字如果没有弄错,调整下语法,注册机也就出来啦.  我对进制一直不铭感.注册码第2位和后面四位是固定的,第11位到18位由前面11位计算得来,第25位到第40位由第二位到第17位算出来,大概这样啦,如果有错误,请指出.这篇文章我自己读啦下,感觉还是不是很通,哪位大虾有什么建议,多教教我.
如果大家只是想自己得出注册码,可以有下面简单的步奏: 00421353 
00421286 在上面这两个地方下断点,f9运行,用户名随便写,注册码填下面格式:X0XXXXXXXXYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXP2I1
"x"表示随便写.将每次断在00421286的时候的edx的值转换成对应的字符,依次放到注册码的11到19位,将00421353 处得到的edx的值转换成对应的字符依次放到25位到40位,就注册成功

--------------------------------------------------------------------------------
【经验总结】
          总结一下,感觉这个程序的保护比较简单,关键是耐得住寂寞,另外感觉od让我变成啦傻瓜,如果有机会softice破,那么我的技术一定长进啦。是不是国外的软件压跟就没有考虑过保护?写完这篇文章,现在感觉自己可以去看看有加密算法的crackme和壳啦,啦啦啦  。
  
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!

                                                       2006年06月12日 22:46:46