【文章标题】: 菜鸟死追注册码(详细版,求精华)
【文章作者】: 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
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课