【文章标题】: 玲珑3D几何作图工具 V2.06的注册流程全面分析
【文章作者】: zouzhiyong
【作者邮箱】: zzydog@foxmail.com
【软件名称】: 玲珑3D几何作图工具 V2.06
【软件大小】: 763KB
【下载地址】: http://www.linglong3d.net/download/Linglong3dV2.06.rar
【加壳方式】: 没有加壳
【保护方式】: 序列号,实际上是KeyFile
【编写语言】: Microsoft Visual C++ 6.0
【使用工具】: od+peid+windows记事本+破解辅助计算器
【操作平台】: 虚拟机windows XP
【软件介绍】: 简单灵活的立体几何作图软件
【作者声明】: 这是自己首次详细的算法分析,文章可能有很多不当之处。还请大家来指正。
之前一直在找CrackMe来练习,感觉上有点脱离现实软件的注册算法,因此特意找一个共享软件来练习一下,总体感觉上难度不是不大,只是注册方式有点怪。至于怎么个怪法,下面开始分析。之前发过的算法分析可能是过于草率了吧,未能得到邀请码。
这次是从最简单的爆破开始逐步深入到算法分析,然后到写注册机,最后到探究注册算法的本质。分析尽量详细,比较通俗易懂。希望这次能得到大家的回复和支持,得到一个邀请码。
【分析过程】:
开始就用PEID查了一下,没有加壳的,是用Microsoft Visual C++ 6.0编写的程序,用OD载入进去,一看到那些乱七八糟的函数名就知道是MFC写的程序。小弟菜鸟一个,第一次分析MFC程序,MFC的程序真的是非常的头疼,要在一大堆封装代码上找出关键算法,幸好,软件的注册提示信息还是比较全的。
爆破追踪:
跟踪 入手点1-------输入错误信息跟踪:
废话说多了,切入正题。首先要说一下软件比较怪的注册流程。
软件运行后,窗口标题会显示软件没有注册,如果是超过了使用次数会显示已经超过了使用次数,并且弹出窗口要你输入解密锁密文。如图所示:
实际上这个输入框根本就没有任何意义,这仅仅是显示一个输入框而已,并没有任何功能(除了相应WM_CLOSE这个消息外),不管你输入的注册码正确与否,都不会作出反应,只能关掉。可能你会说只有正确的注册码才会有反应,但是下面就证明你是错的。
究竟是怎样看的出来的呢。我是通过这样发现的:开始想从这里入手跟踪注册流程的,下断bp GetDlgItemTextW,没有断下,消息断点没有断下,既然是MFC的话就更不用下GetWindowTextW了。此时想到如果获取了密文后一定会存放于某个buffer缓冲区的,因此,可以通过搜索内存来定位数据,然后对数据下断即可。
在随便输入字符串,点击确定后,我用winhex 搜索软件的全部内存,只找到一处,就是MFC资源框所在的buffer。正常情况下,如果有获取到内容到缓冲区的话,就肯定不止一处的,除非是根本没有获取内容。为了验证,我又做了两次对比,在点击确定的前和后搜索内存,结果是一样的,同样的地址。
其后又做一个次验证,就是在该地址下内存访问断点(硬件访问都试过了),然后按确定,没有被断下。
根本没有对密文框数据访问,到这里就证明了这个对话框根本就是废的,只是显示你没有注册而已。就是说,注册不能通过输入的形式来实现。这就是我在前面所说的怪异支出。
跟踪入手点2-------经典的查找字符串方式:
如果一开始就看字符串的话就不用走这么多弯路了,但是一开始就找字符串的话也不会发现作者的注册手段了~~,那个“虚伪”的对话框。
好,查找字符串,发现了一个关键的东西,就是窗口标题。这个很明显是切入点了。
随便跟入一个,就来到了所在的函数,下面代码:
00402380 . 6A FF PUSH -1 00402382 . 68 96DC4000 PUSH Geometry.0040DC96 ; SE 处理程序安装 00402387 . 64:A1 0000000>MOV EAX,DWORD PTR FS:[0] 0040238D . 50 PUSH EAX 0040238E . 64:8925 00000>MOV DWORD PTR FS:[0],ESP 00402395 . 81EC C0000000 SUB ESP,0C0 0040239B . 53 PUSH EBX 0040239C . 55 PUSH EBP 0040239D . 56 PUSH ESI 0040239E . 57 PUSH EDI 0040239F . 8BF1 MOV ESI,ECX 004023A1 . 6A 00 PUSH 0 004023A3 . E8 8CAF0000 CALL <JMP.&MFC42.#1134_?AfxEnableControlContainer@@YAXPAVCO> 004023A8 . 83C4 04 ADD ESP,4 004023AB . 8D4C24 1C LEA ECX,DWORD PTR SS:[ESP+1C] 004023AF . E8 1C880000 CALL Geometry.0040ABD0 004023B4 . 8D4C24 14 LEA ECX,DWORD PTR SS:[ESP+14] 004023B8 . C78424 D80000>MOV DWORD PTR SS:[ESP+D8],0 004023C3 . E8 38ECFFFF CALL Geometry.00401000 004023C8 . 8D4C24 14 LEA ECX,DWORD PTR SS:[ESP+14] 004023CC . C68424 D80000>MOV BYTE PTR SS:[ESP+D8],1 004023D4 . E8 67ECFFFF CALL Geometry.00401040 004023D9 . 8D4C24 14 LEA ECX,DWORD PTR SS:[ESP+14] 004023DD . E8 EEEEFFFF CALL Geometry.004012D0 004023E2 . 8D4C24 14 LEA ECX,DWORD PTR SS:[ESP+14] 004023E6 . E8 75EDFFFF CALL Geometry.00401160 004023EB . 8D4C24 14 LEA ECX,DWORD PTR SS:[ESP+14] 004023EF . E8 0CEEFFFF CALL Geometry.00401200 004023F4 . 8D4C24 1C LEA ECX,DWORD PTR SS:[ESP+1C] 004023F8 . 8BF8 MOV EDI,EAX 004023FA . E8 61880000 CALL Geometry.0040AC60 ; //这里就是关键CALL了,需要跟入 004023FF . 8BCE MOV ECX,ESI 00402401 . 8BE8 MOV EBP,EAX ; //ebp=上面的CALL返回值,返回值必须为2 00402403 . E8 26AF0000 CALL <JMP.&MFC42.#2621_?Enable3dControls@CWinApp@@IAEHXZ> 00402408 . 68 5C624100 PUSH Geometry.0041625C ; Local AppWizard-Generated Applications 0040240D . 8BCE MOV ECX,ESI 0040240F . E8 14AF0000 CALL <JMP.&MFC42.#6117_?SetRegistryKey@CWinApp@@IAEXPBD@Z> 00402414 . BB 04000000 MOV EBX,4 00402419 . 8BCE MOV ECX,ESI 0040241B . 53 PUSH EBX 0040241C . E8 01AF0000 CALL <JMP.&MFC42.#4159_?LoadStdProfileSettings@CWinApp@@IAE> 00402421 . 6A 6C PUSH 6C 00402423 . E8 F4AE0000 CALL <JMP.&MFC42.#823_??2@YAPAXI@Z> 00402428 . 83C4 04 ADD ESP,4 0040242B . 894424 18 MOV DWORD PTR SS:[ESP+18],EAX 0040242F . 85C0 TEST EAX,EAX 00402431 . C68424 D80000>MOV BYTE PTR SS:[ESP+D8],2 00402439 . 74 1D JE SHORT Geometry.00402458 0040243B . 68 48054100 PUSH Geometry.00410548 ; CGeometryView 00402440 . 68 08174100 PUSH Geometry.00411708 ; CMainFrame 00402445 . 68 50044100 PUSH Geometry.00410450 ; CGeometryDoc 0040244A . 68 80000000 PUSH 80 0040244F . 8BC8 MOV ECX,EAX 00402451 . E8 C0AE0000 CALL <JMP.&MFC42.#520_??0CSingleDocTemplate@@QAE@IPAUCRunti> 00402456 . EB 02 JMP SHORT Geometry.0040245A 00402458 > 33C0 XOR EAX,EAX 0040245A > 50 PUSH EAX 0040245B . 8BCE MOV ECX,ESI 0040245D . C68424 DC0000>MOV BYTE PTR SS:[ESP+DC],1 00402465 . E8 A6AE0000 CALL <JMP.&MFC42.#986_?AddDocTemplate@CWinApp@@QAEXPAVCDocT> 0040246A . 8D4C24 34 LEA ECX,DWORD PTR SS:[ESP+34] 0040246E . E8 97AE0000 CALL <JMP.&MFC42.#296_??0CCommandLineInfo@@QAE@XZ> 00402473 . 8D4424 34 LEA EAX,DWORD PTR SS:[ESP+34] 00402477 . 8BCE MOV ECX,ESI 00402479 . 50 PUSH EAX 0040247A . C68424 DC0000>MOV BYTE PTR SS:[ESP+DC],3 00402482 . E8 7DAE0000 CALL <JMP.&MFC42.#5214_?ParseCommandLine@CWinApp@@QAEXAAVCC> 00402487 . 8D4C24 34 LEA ECX,DWORD PTR SS:[ESP+34] 0040248B . 51 PUSH ECX 0040248C . 8BCE MOV ECX,ESI 0040248E . E8 6BAE0000 CALL <JMP.&MFC42.#5301_?ProcessShellCommand@CWinApp@@QAEHAA> 00402493 . 85C0 TEST EAX,EAX 00402495 . 75 3D JNZ SHORT Geometry.004024D4 00402497 . 8D4C24 34 LEA ECX,DWORD PTR SS:[ESP+34] 0040249B . C68424 D80000>MOV BYTE PTR SS:[ESP+D8],1 004024A3 . E8 50AE0000 CALL <JMP.&MFC42.#617_??1CCommandLineInfo@@UAE@XZ> 004024A8 . 8D4C24 14 LEA ECX,DWORD PTR SS:[ESP+14] 004024AC . C68424 D80000>MOV BYTE PTR SS:[ESP+D8],0 004024B4 . E8 77EBFFFF CALL Geometry.00401030 004024B9 . 8D4C24 1C LEA ECX,DWORD PTR SS:[ESP+1C] 004024BD . C78424 D80000>MOV DWORD PTR SS:[ESP+D8],-1 004024C8 . E8 43870000 CALL Geometry.0040AC10 004024CD . 33C0 XOR EAX,EAX 004024CF . E9 AA020000 JMP Geometry.0040277E 004024D4 > 8B4E 20 MOV ECX,DWORD PTR DS:[ESI+20] 004024D7 . 6A 03 PUSH 3 004024D9 . E8 14AE0000 CALL <JMP.&MFC42.#6215_?ShowWindow@CWnd@@QAEHH@Z> 004024DE . 8B46 20 MOV EAX,DWORD PTR DS:[ESI+20] 004024E1 . 8B50 20 MOV EDX,DWORD PTR DS:[EAX+20] 004024E4 . 52 PUSH EDX ; /hWnd 004024E5 . FF15 C8F54000 CALL DWORD PTR DS:[<&USER32.UpdateWindow>] ; \UpdateWindow 004024EB . 8D4C24 1C LEA ECX,DWORD PTR SS:[ESP+1C] 004024EF . E8 2C8C0000 CALL Geometry.0040B120 004024F4 . 3BC7 CMP EAX,EDI 004024F6 . 7D 0B JGE SHORT Geometry.00402503 004024F8 . 8D4C24 1C LEA ECX,DWORD PTR SS:[ESP+1C] 004024FC . E8 1F8C0000 CALL Geometry.0040B120 00402501 . EB 02 JMP SHORT Geometry.00402505 00402503 > 8BC7 MOV EAX,EDI 00402505 > 83FD 02 CMP EBP,2 ; //EBP是关键值,一定要为2 00402508 . 75 26 JNZ SHORT Geometry.00402530 ; //这个是关键跳,爆破点 0040250A . 8B4E 20 MOV ECX,DWORD PTR DS:[ESI+20] 0040250D . 68 40624100 PUSH Geometry.00416240 ; 玲珑3D几何作图软件2.06版 //这个是注册成功显示的标题 00402512 . E8 D5AD0000 CALL <JMP.&MFC42.#6199_?SetWindowTextA@CWnd@@QAEXPBD@Z> 00402517 . E8 CAAD0000 CALL <JMP.&MFC42.#1175_?AfxGetThread@@YGPAVCWinThread@@XZ> 0040251C . 85C0 TEST EAX,EAX 0040251E . 0F84 EA010000 JE Geometry.0040270E 00402524 . 8B10 MOV EDX,DWORD PTR DS:[EAX] 00402526 . 8BC8 MOV ECX,EAX 00402528 . FF52 7C CALL DWORD PTR DS:[EDX+7C]
总体上就分析到这里,将爆破点NOP掉即可完成爆破。
*******************************************************************************************************************
下面是算法分析:
跟入前面得到的算法CALL,可以得到如下代码(可能有点复杂):
0040AC60 /$ 64:A1 0000000>MOV EAX,DWORD PTR FS:[0] 0040AC66 |. 6A FF PUSH -1 0040AC68 |. 68 7EE54000 PUSH Geometry.0040E57E 0040AC6D |. 50 PUSH EAX 0040AC6E |. 64:8925 00000>MOV DWORD PTR FS:[0],ESP 0040AC75 |. 81EC 34010000 SUB ESP,134 0040AC7B |. 53 PUSH EBX 0040AC7C |. 55 PUSH EBP 0040AC7D |. 56 PUSH ESI 0040AC7E |. 57 PUSH EDI 0040AC7F |. 68 60644100 PUSH Geometry.00416460 ; /r+b 0040AC84 |. 8BD9 MOV EBX,ECX ; | 0040AC86 |. 68 58644100 PUSH Geometry.00416458 ; |gzf.gg 0040AC8B |. FF15 14F54000 CALL DWORD PTR DS:[<&MSVCRT.fopen>] ; \//打开当前目录下的gzf.gg文件,就是keyfile了,使用C语言函数fopen打开 0040AC91 |. 8BF0 MOV ESI,EAX 0040AC93 |. 83C4 08 ADD ESP,8 0040AC96 |. 85F6 TEST ESI,ESI 0040AC98 |. 0F84 5A040000 JE Geometry.0040B0F8 ; //打开失败就返回 0040AC9E |. 8A4424 17 MOV AL,BYTE PTR SS:[ESP+17] 0040ACA2 |. 6A 00 PUSH 0 0040ACA4 |. 8D4C24 30 LEA ECX,DWORD PTR SS:[ESP+30] 0040ACA8 |. 884424 30 MOV BYTE PTR SS:[ESP+30],AL 0040ACAC |. FF15 B0F44000 CALL DWORD PTR DS:[<&MSVCP60.?_Tidy@?$basic_stri>; MSVCP60.?_Tidy@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@AAEX_N@Z 0040ACB2 |. BF A8644100 MOV EDI,Geometry.004164A8 0040ACB7 |. 83C9 FF OR ECX,FFFFFFFF 0040ACBA |. 33C0 XOR EAX,EAX 0040ACBC |. F2:AE REPNE SCAS BYTE PTR ES:[EDI] 0040ACBE |. F7D1 NOT ECX 0040ACC0 |. 49 DEC ECX 0040ACC1 |. 51 PUSH ECX 0040ACC2 |. 68 A8644100 PUSH Geometry.004164A8 0040ACC7 |. 8D4C24 34 LEA ECX,DWORD PTR SS:[ESP+34] 0040ACCB |. FF15 C8F44000 CALL DWORD PTR DS:[<&MSVCP60.?assign@?$basic_str>; MSVCP60.?assign@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAEAAV12@PBDI@Z 0040ACD1 |. 8A4C24 17 MOV CL,BYTE PTR SS:[ESP+17] 0040ACD5 |. 6A 00 PUSH 0 0040ACD7 |. 884C24 20 MOV BYTE PTR SS:[ESP+20],CL 0040ACDB |. 8D4C24 20 LEA ECX,DWORD PTR SS:[ESP+20] 0040ACDF |. C78424 500100>MOV DWORD PTR SS:[ESP+150],0 0040ACEA |. FF15 B0F44000 CALL DWORD PTR DS:[<&MSVCP60.?_Tidy@?$basic_stri>; MSVCP60.?_Tidy@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@AAEX_N@Z 0040ACF0 |. BF A8644100 MOV EDI,Geometry.004164A8 0040ACF5 |. 83C9 FF OR ECX,FFFFFFFF 0040ACF8 |. 33C0 XOR EAX,EAX 0040ACFA |. F2:AE REPNE SCAS BYTE PTR ES:[EDI] 0040ACFC |. F7D1 NOT ECX 0040ACFE |. 49 DEC ECX 0040ACFF |. 51 PUSH ECX 0040AD00 |. 68 A8644100 PUSH Geometry.004164A8 0040AD05 |. 8D4C24 24 LEA ECX,DWORD PTR SS:[ESP+24] 0040AD09 |. FF15 C8F44000 CALL DWORD PTR DS:[<&MSVCP60.?assign@?$basic_str>; MSVCP60.?assign@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAEAAV12@PBDI@Z 0040AD0F |. 8B2D 10F54000 MOV EBP,DWORD PTR DS:[<&MSVCRT.fread>] ; msvcrt.fread 0040AD15 |. 56 PUSH ESI ; /stream 0040AD16 |. 6A 01 PUSH 1 ; |n = 1 0040AD18 |. 8D5424 18 LEA EDX,DWORD PTR SS:[ESP+18] ; | 0040AD1C |. 6A 04 PUSH 4 ; |size = 4 0040AD1E |. 52 PUSH EDX ; |ptr 0040AD1F |. C68424 5C0100>MOV BYTE PTR SS:[ESP+15C],1 ; | 0040AD27 |. FFD5 CALL EBP ; \//读取一个DWORD型的数据nCount1 0040AD29 |. 8B4424 20 MOV EAX,DWORD PTR SS:[ESP+20] 0040AD2D |. 83C4 10 ADD ESP,10 0040AD30 |. 85C0 TEST EAX,EAX ; //nCount要大于0,比0小则返回 0040AD32 |. 7E 35 JLE SHORT Geometry.0040AD69 0040AD34 |. 56 PUSH ESI 0040AD35 |. 50 PUSH EAX 0040AD36 |. 8D4424 4C LEA EAX,DWORD PTR SS:[ESP+4C] 0040AD3A |. 6A 01 PUSH 1 0040AD3C |. 50 PUSH EAX 0040AD3D |. FFD5 CALL EBP ; //接着读取nCount1个字节到缓冲区,记为hex1 0040AD3F |. 8B4C24 20 MOV ECX,DWORD PTR SS:[ESP+20] 0040AD43 |. 8D7C24 54 LEA EDI,DWORD PTR SS:[ESP+54] 0040AD47 |. 33C0 XOR EAX,EAX 0040AD49 |. 83C4 10 ADD ESP,10 0040AD4C |. C6440C 44 00 MOV BYTE PTR SS:[ESP+ECX+44],0 0040AD51 |. 83C9 FF OR ECX,FFFFFFFF 0040AD54 |. F2:AE REPNE SCAS BYTE PTR ES:[EDI] 0040AD56 |. F7D1 NOT ECX 0040AD58 |. 49 DEC ECX 0040AD59 |. 8D5424 44 LEA EDX,DWORD PTR SS:[ESP+44] 0040AD5D |. 51 PUSH ECX 0040AD5E |. 52 PUSH EDX 0040AD5F |. 8D4C24 34 LEA ECX,DWORD PTR SS:[ESP+34] 0040AD63 |. FF15 C8F44000 CALL DWORD PTR DS:[<&MSVCP60.?assign@?$basic_str>; MSVCP60.?assign@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAEAAV12@PBDI@Z 0040AD69 |> 56 PUSH ESI 0040AD6A |. 6A 01 PUSH 1 0040AD6C |. 8D4424 18 LEA EAX,DWORD PTR SS:[ESP+18] 0040AD70 |. 6A 04 PUSH 4 0040AD72 |. 50 PUSH EAX 0040AD73 |. FFD5 CALL EBP ; //读取一个DWORD型数据nCount2 0040AD75 |. 8B4424 20 MOV EAX,DWORD PTR SS:[ESP+20] 0040AD79 |. 83C4 10 ADD ESP,10 0040AD7C |. 85C0 TEST EAX,EAX ; //nCount2要大于0 0040AD7E |. 7E 35 JLE SHORT Geometry.0040ADB5 0040AD80 |. 56 PUSH ESI 0040AD81 |. 50 PUSH EAX 0040AD82 |. 8D4C24 4C LEA ECX,DWORD PTR SS:[ESP+4C] 0040AD86 |. 6A 01 PUSH 1 0040AD88 |. 51 PUSH ECX 0040AD89 |. FFD5 CALL EBP ; //接着读取nCount2个字节数据到缓冲区,记为hex2 0040AD8B |. 8B5424 20 MOV EDX,DWORD PTR SS:[ESP+20] 0040AD8F |. 8D7C24 54 LEA EDI,DWORD PTR SS:[ESP+54] 0040AD93 |. 83C9 FF OR ECX,FFFFFFFF 0040AD96 |. 33C0 XOR EAX,EAX 0040AD98 |. 83C4 10 ADD ESP,10 0040AD9B |. C64414 44 00 MOV BYTE PTR SS:[ESP+EDX+44],0 0040ADA0 |. F2:AE REPNE SCAS BYTE PTR ES:[EDI] 0040ADA2 |. F7D1 NOT ECX 0040ADA4 |. 49 DEC ECX 0040ADA5 |. 8D4424 44 LEA EAX,DWORD PTR SS:[ESP+44] 0040ADA9 |. 51 PUSH ECX 0040ADAA |. 50 PUSH EAX 0040ADAB |. 8D4C24 24 LEA ECX,DWORD PTR SS:[ESP+24] 0040ADAF |. FF15 C8F44000 CALL DWORD PTR DS:[<&MSVCP60.?assign@?$basic_str>; MSVCP60.?assign@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAEAAV12@PBDI@Z 0040ADB5 |> 56 PUSH ESI 0040ADB6 |. 6A 01 PUSH 1 0040ADB8 |. 8D4C24 18 LEA ECX,DWORD PTR SS:[ESP+18] 0040ADBC |. 6A 04 PUSH 4 0040ADBE |. 51 PUSH ECX 0040ADBF |. FFD5 CALL EBP ; //这个再读取一个DWORD型的数据,记为nRemainTime,为加密后的剩余谁用次数 0040ADC1 |. 8B4424 20 MOV EAX,DWORD PTR SS:[ESP+20] 0040ADC5 |. 8B2D 0CF54000 MOV EBP,DWORD PTR DS:[<&MSVCRT.fclose>] ; msvcrt.fclose 0040ADCB |. 35 51629471 XOR EAX,71946251 ; //nRemainTime = nRemainTime xor 71946251,这里是剩余使用次数 0040ADD0 |. 56 PUSH ESI ; /stream 0040ADD1 |. 894424 24 MOV DWORD PTR SS:[ESP+24],EAX ; | 0040ADD5 |. 8943 04 MOV DWORD PTR DS:[EBX+4],EAX ; | 0040ADD8 |. FFD5 CALL EBP ; \//关闭文件 0040ADDA |. 8B43 04 MOV EAX,DWORD PTR DS:[EBX+4] 0040ADDD |. 83C4 14 ADD ESP,14 0040ADE0 |. 83F8 1E CMP EAX,1E ; //记录的使用次数不能超过30次,可能是防止胡乱修改吧 0040ADE3 |. 0F8F D8020000 JG Geometry.0040B0C1 ; //这里不能跳 0040ADE9 |. 85C0 TEST EAX,EAX ; //使用次数是否已经为0 0040ADEB |. 0F8C D0020000 JL Geometry.0040B0C1 ; //这里也不能跳 0040ADF1 |. 68 54644100 PUSH Geometry.00416454 ; /w+b 0040ADF6 |. 68 58644100 PUSH Geometry.00416458 ; |gzf.gg 0040ADFB |. FF15 14F54000 CALL DWORD PTR DS:[<&MSVCRT.fopen>] ; \//用可写入的方式打开文件 0040AE01 |. 8BF0 MOV ESI,EAX 0040AE03 |. 83C4 08 ADD ESP,8 0040AE06 |. 85F6 TEST ESI,ESI 0040AE08 |. 75 31 JNZ SHORT Geometry.0040AE3B 0040AE0A |. 6A 01 PUSH 1 0040AE0C |. 8D4C24 20 LEA ECX,DWORD PTR SS:[ESP+20] 0040AE10 |. 888424 500100>MOV BYTE PTR SS:[ESP+150],AL 0040AE17 |. FF15 B0F44000 CALL DWORD PTR DS:[<&MSVCP60.?_Tidy@?$basic_stri>; MSVCP60.?_Tidy@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@AAEX_N@Z 0040AE1D |. 6A 01 PUSH 1 0040AE1F |. 8D4C24 30 LEA ECX,DWORD PTR SS:[ESP+30] 0040AE23 |. C78424 500100>MOV DWORD PTR SS:[ESP+150],-1 0040AE2E |. FF15 B0F44000 CALL DWORD PTR DS:[<&MSVCP60.?_Tidy@?$basic_stri>; MSVCP60.?_Tidy@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@AAEX_N@Z 0040AE34 |. 33C0 XOR EAX,EAX 0040AE36 |. E9 BD020000 JMP Geometry.0040B0F8 0040AE3B |> 8B5424 34 MOV EDX,DWORD PTR SS:[ESP+34] 0040AE3F |. 8B3D 08F54000 MOV EDI,DWORD PTR DS:[<&MSVCRT.fwrite>] ; msvcrt.fwrite 0040AE45 |. 56 PUSH ESI ; /stream 0040AE46 |. 6A 01 PUSH 1 ; |n = 1 0040AE48 |. 8D4424 18 LEA EAX,DWORD PTR SS:[ESP+18] ; | 0040AE4C |. 6A 04 PUSH 4 ; |size = 4 0040AE4E |. 50 PUSH EAX ; |ptr 0040AE4F |. 895424 20 MOV DWORD PTR SS:[ESP+20],EDX ; | 0040AE53 |. FFD7 CALL EDI ; \//将nCount1写回到文件中 0040AE55 |. 8B4424 20 MOV EAX,DWORD PTR SS:[ESP+20] 0040AE59 |. 83C4 10 ADD ESP,10 0040AE5C |. 85C0 TEST EAX,EAX 0040AE5E |. 7E 18 JLE SHORT Geometry.0040AE78 0040AE60 |. 8B4C24 30 MOV ECX,DWORD PTR SS:[ESP+30] 0040AE64 |. 85C9 TEST ECX,ECX 0040AE66 |. 75 06 JNZ SHORT Geometry.0040AE6E 0040AE68 |. 8B0D A8F44000 MOV ECX,DWORD PTR DS:[<&MSVCP60.?_C@?1??_Nullstr>; MSVCP60.?_C@?1??_Nullstr@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@CAPBDXZ@4DB 0040AE6E |> 56 PUSH ESI 0040AE6F |. 50 PUSH EAX 0040AE70 |. 6A 01 PUSH 1 0040AE72 |. 51 PUSH ECX 0040AE73 |. FFD7 CALL EDI ; //将hex1写回到文件中 0040AE75 |. 83C4 10 ADD ESP,10 0040AE78 |> 8B4C24 24 MOV ECX,DWORD PTR SS:[ESP+24] 0040AE7C |. 56 PUSH ESI 0040AE7D |. 6A 01 PUSH 1 0040AE7F |. 8D5424 18 LEA EDX,DWORD PTR SS:[ESP+18] 0040AE83 |. 6A 04 PUSH 4 0040AE85 |. 52 PUSH EDX 0040AE86 |. 894C24 20 MOV DWORD PTR SS:[ESP+20],ECX 0040AE8A |. FFD7 CALL EDI ; //将nCount2写回到文件中 0040AE8C |. 8B4424 20 MOV EAX,DWORD PTR SS:[ESP+20] 0040AE90 |. 83C4 10 ADD ESP,10 0040AE93 |. 85C0 TEST EAX,EAX 0040AE95 |. 7E 18 JLE SHORT Geometry.0040AEAF 0040AE97 |. 8B4C24 20 MOV ECX,DWORD PTR SS:[ESP+20] 0040AE9B |. 85C9 TEST ECX,ECX 0040AE9D |. 75 06 JNZ SHORT Geometry.0040AEA5 0040AE9F |. 8B0D A8F44000 MOV ECX,DWORD PTR DS:[<&MSVCP60.?_C@?1??_Nullstr>; MSVCP60.?_C@?1??_Nullstr@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@CAPBDXZ@4DB 0040AEA5 |> 56 PUSH ESI 0040AEA6 |. 50 PUSH EAX 0040AEA7 |. 6A 01 PUSH 1 0040AEA9 |. 51 PUSH ECX 0040AEAA |. FFD7 CALL EDI ; //将hex2写回到文件中去 0040AEAC |. 83C4 10 ADD ESP,10 0040AEAF |> 8B43 04 MOV EAX,DWORD PTR DS:[EBX+4] 0040AEB2 |. 85C0 TEST EAX,EAX 0040AEB4 |. 7E 04 JLE SHORT Geometry.0040AEBA 0040AEB6 |. 48 DEC EAX 0040AEB7 |. 8943 04 MOV DWORD PTR DS:[EBX+4],EAX 0040AEBA |> 8B43 04 MOV EAX,DWORD PTR DS:[EBX+4] 0040AEBD |. 56 PUSH ESI 0040AEBE |. 6A 01 PUSH 1 0040AEC0 |. 8D4C24 18 LEA ECX,DWORD PTR SS:[ESP+18] 0040AEC4 |. 35 51629471 XOR EAX,71946251 ; //剩余使用次数nRemainTime做xor加密 0040AEC9 |. 6A 04 PUSH 4 0040AECB |. 51 PUSH ECX 0040AECC |. 894424 20 MOV DWORD PTR SS:[ESP+20],EAX 0040AED0 |. FFD7 CALL EDI ; //将加密后的nRemainTime写回到文件中去 0040AED2 |. 56 PUSH ESI 0040AED3 |. FFD5 CALL EBP 0040AED5 |. 8B4424 48 MOV EAX,DWORD PTR SS:[ESP+48] 0040AED9 |. 83C4 14 ADD ESP,14 0040AEDC |. 85C0 TEST EAX,EAX ; //判断nCount1是否为0 0040AEDE |. 0F84 E4010000 JE Geometry.0040B0C8 ; //不能跳 0040AEE4 |. 8B4424 24 MOV EAX,DWORD PTR SS:[ESP+24] 0040AEE8 |. 85C0 TEST EAX,EAX ; //判断nCount2是否为0 0040AEEA |. 0F84 D8010000 JE Geometry.0040B0C8 ; //不能跳 0040AEF0 |. 6A 0A PUSH 0A ; /pFileSystemNameSize = 0000000A 0040AEF2 |. 6A 00 PUSH 0 ; |pFileSystemNameBuffer = NULL 0040AEF4 |. 6A 00 PUSH 0 ; |pFileSystemFlags = NULL 0040AEF6 |. 8D5424 48 LEA EDX,DWORD PTR SS:[ESP+48] ; | 0040AEFA |. 6A 00 PUSH 0 ; |pMaxFilenameLength = NULL 0040AEFC |. 52 PUSH EDX ; |pVolumeSerialNumber 0040AEFD |. 6A 0C PUSH 0C ; |MaxVolumeNameSize = C (12.) 0040AEFF |. 6A 00 PUSH 0 ; |VolumeNameBuffer = NULL 0040AF01 |. 68 50644100 PUSH Geometry.00416450 ; |c:\ 0040AF06 |. FF15 84F04000 CALL DWORD PTR DS:[<&KERNEL32.GetVolumeInformati>; \//获取c盘信息,获取Serial 0040AF0C |. 8B5424 3C MOV EDX,DWORD PTR SS:[ESP+3C] 0040AF10 |. 8D4C24 18 LEA ECX,DWORD PTR SS:[ESP+18] 0040AF14 |. 81F2 24827351 XOR EDX,51738224 ; //对serial运算,serial xor 51738224H 0040AF1A |. 895424 3C MOV DWORD PTR SS:[ESP+3C],EDX 0040AF1E |. E8 59210000 CALL <JMP.&MFC42.#540_??0CString@@QAE@XZ> ; //copy数据 0040AF23 |. 8B4424 3C MOV EAX,DWORD PTR SS:[ESP+3C] 0040AF27 |. 8D4C24 18 LEA ECX,DWORD PTR SS:[ESP+18] 0040AF2B |. 50 PUSH EAX 0040AF2C |. 68 4C644100 PUSH Geometry.0041644C ; %x 0040AF31 |. 51 PUSH ECX 0040AF32 |. C68424 580100>MOV BYTE PTR SS:[ESP+158],2 0040AF3A |. E8 9B230000 CALL <JMP.&MFC42.#2818_?Format@CString@@QAAXPBDZ>; //将上面serial数据从hex转换成字符串形式,记为string 0040AF3F |. 8B5424 24 MOV EDX,DWORD PTR SS:[ESP+24] 0040AF43 |. 83C4 0C ADD ESP,0C 0040AF46 |. 8BCB MOV ECX,EBX 0040AF48 |. 52 PUSH EDX ; /Arg1 0040AF49 |. E8 32040000 CALL Geometry.0040B380 ; \//这里对string进行运算,生成hex3,8个字节,是机器码的算法call 0040AF4E |. 50 PUSH EAX 0040AF4F |. 8D4C24 44 LEA ECX,DWORD PTR SS:[ESP+44] 0040AF53 |. E8 E0220000 CALL <JMP.&MFC42.#537_??0CString@@QAE@PBD@Z> ; //Copy数据 0040AF58 |. 8B7C24 40 MOV EDI,DWORD PTR SS:[ESP+40] ; //EDI是Copy后数据的地址 0040AF5C |. 83C9 FF OR ECX,FFFFFFFF 0040AF5F |. 33C0 XOR EAX,EAX 0040AF61 |. 8BF7 MOV ESI,EDI 0040AF63 |. F2:AE REPNE SCAS BYTE PTR ES:[EDI] 0040AF65 |. F7D1 NOT ECX 0040AF67 |. 49 DEC ECX ; //计算数据hex3的字节数(长度) 0040AF68 |. 6A 01 PUSH 1 0040AF6A |. 8BE9 MOV EBP,ECX 0040AF6C |. 8D4C24 30 LEA ECX,DWORD PTR SS:[ESP+30] 0040AF70 |. 55 PUSH EBP 0040AF71 |. C68424 540100>MOV BYTE PTR SS:[ESP+154],3 0040AF79 |. FF15 ACF44000 CALL DWORD PTR DS:[<&MSVCP60.?_Grow@?$basic_stri>; MSVCP60.?_Grow@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@AAE_NI_N@Z 0040AF7F |. 84C0 TEST AL,AL 0040AF81 |. 74 20 JE SHORT Geometry.0040AFA3 0040AF83 |. 8B7C24 30 MOV EDI,DWORD PTR SS:[ESP+30] ; //读取hex1的地址 0040AF87 |. 8BCD MOV ECX,EBP 0040AF89 |. 8BC1 MOV EAX,ECX 0040AF8B |. C1E9 02 SHR ECX,2 0040AF8E |. F3:A5 REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI] ; //对齐4个字节,进行每次dword数据复制(这里是覆盖hex1) 0040AF90 |. 8BC8 MOV ECX,EAX 0040AF92 |. 83E1 03 AND ECX,3 0040AF95 |. F3:A4 REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI] ; //上面复制剩余的按照字节再进行复制 0040AF97 |. 8B4C24 30 MOV ECX,DWORD PTR SS:[ESP+30] 0040AF9B |. 896C24 34 MOV DWORD PTR SS:[ESP+34],EBP 0040AF9F |. C60429 00 MOV BYTE PTR DS:[ECX+EBP],0 ; //写入结束标记 0040AFA3 |> 8B4C24 20 MOV ECX,DWORD PTR SS:[ESP+20] ; //读取hex2地址 0040AFA7 |. 8B15 A8F44000 MOV EDX,DWORD PTR DS:[<&MSVCP60.?_C@?1??_Nullstr>; MSVCP60.?_C@?1??_Nullstr@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@CAPBDXZ@4DB 0040AFAD |. 33F6 XOR ESI,ESI 0040AFAF |. 3BCE CMP ECX,ESI ; //hex2是否存在(hex2是否为空) 0040AFB1 |. 75 02 JNZ SHORT Geometry.0040AFB5 0040AFB3 |. 8BCA MOV ECX,EDX 0040AFB5 |> 8B4424 30 MOV EAX,DWORD PTR SS:[ESP+30] ; //取hex3的地址 0040AFB9 |. 3BC6 CMP EAX,ESI ; //hex3是否为空 0040AFBB |. 75 02 JNZ SHORT Geometry.0040AFBF 0040AFBD |. 8BC2 MOV EAX,EDX 0040AFBF |> 51 PUSH ECX ; /Arg2 0040AFC0 |. 50 PUSH EAX ; |Arg1 0040AFC1 |. 8BCB MOV ECX,EBX ; | 0040AFC3 |. E8 68010000 CALL Geometry.0040B130 ; \//将hex2和hex3压栈进行运算,这个就是注册码的比较 0040AFC8 |. 83F8 63 CMP EAX,63 ; //上面的CALL返回值一定要为63H 0040AFCB |. C68424 4C0100>MOV BYTE PTR SS:[ESP+14C],2 ; //写入注册成功的标记 0040AFD3 |. 8D4C24 40 LEA ECX,DWORD PTR SS:[ESP+40] 0040AFD7 |. 75 7C JNZ SHORT Geometry.0040B055 0040AFD9 |. E8 92200000 CALL <JMP.&MFC42.#800_??1CString@@QAE@XZ> 0040AFDE |. 8D4C24 18 LEA ECX,DWORD PTR SS:[ESP+18] 0040AFE2 |. C68424 4C0100>MOV BYTE PTR SS:[ESP+14C],1 0040AFEA |. E8 81200000 CALL <JMP.&MFC42.#800_??1CString@@QAE@XZ> 0040AFEF |. 8B4C24 20 MOV ECX,DWORD PTR SS:[ESP+20] 0040AFF3 |. 3BCE CMP ECX,ESI 0040AFF5 |. 74 1C JE SHORT Geometry.0040B013 0040AFF7 |. 8A41 FF MOV AL,BYTE PTR DS:[ECX-1] 0040AFFA |. 84C0 TEST AL,AL 0040AFFC |. 74 0B JE SHORT Geometry.0040B009 0040AFFE |. 3C FF CMP AL,0FF 0040B000 |. 74 07 JE SHORT Geometry.0040B009 0040B002 |. FEC8 DEC AL 0040B004 |. 8841 FF MOV BYTE PTR DS:[ECX-1],AL 0040B007 |. EB 0A JMP SHORT Geometry.0040B013 0040B009 |> 49 DEC ECX 0040B00A |. 51 PUSH ECX ; /block 0040B00B |. E8 5A200000 CALL <JMP.&MFC42.#825_??3@YAXPAX@Z> ; \free 0040B010 |. 83C4 04 ADD ESP,4 0040B013 |> 8B4C24 30 MOV ECX,DWORD PTR SS:[ESP+30] 0040B017 |. 897424 20 MOV DWORD PTR SS:[ESP+20],ESI 0040B01B |. 3BCE CMP ECX,ESI 0040B01D |. 897424 24 MOV DWORD PTR SS:[ESP+24],ESI 0040B021 |. 897424 28 MOV DWORD PTR SS:[ESP+28],ESI 0040B025 |. 74 24 JE SHORT Geometry.0040B04B 0040B027 |. 8A41 FF MOV AL,BYTE PTR DS:[ECX-1] 0040B02A |. 84C0 TEST AL,AL 0040B02C |. 74 13 JE SHORT Geometry.0040B041 0040B02E |. 3C FF CMP AL,0FF 0040B030 |. 74 0F JE SHORT Geometry.0040B041 0040B032 |. FEC8 DEC AL 0040B034 |. 8841 FF MOV BYTE PTR DS:[ECX-1],AL 0040B037 |. B8 02000000 MOV EAX,2 0040B03C |. E9 B7000000 JMP Geometry.0040B0F8 0040B041 |> 49 DEC ECX 0040B042 |. 51 PUSH ECX ; /block 0040B043 |. E8 22200000 CALL <JMP.&MFC42.#825_??3@YAXPAX@Z> ; \free 0040B048 |. 83C4 04 ADD ESP,4 0040B04B |> B8 02000000 MOV EAX,2 0040B050 |. E9 A3000000 JMP Geometry.0040B0F8 0040B055 |> E8 16200000 CALL <JMP.&MFC42.#800_??1CString@@QAE@XZ> 0040B05A |. 8D4C24 18 LEA ECX,DWORD PTR SS:[ESP+18] 0040B05E |. C68424 4C0100>MOV BYTE PTR SS:[ESP+14C],1 0040B066 |. E8 05200000 CALL <JMP.&MFC42.#800_??1CString@@QAE@XZ> 0040B06B |. 8B4C24 20 MOV ECX,DWORD PTR SS:[ESP+20] 0040B06F |. 3BCE CMP ECX,ESI 0040B071 |. 74 1C JE SHORT Geometry.0040B08F 0040B073 |. 8A41 FF MOV AL,BYTE PTR DS:[ECX-1] 0040B076 |. 84C0 TEST AL,AL 0040B078 |. 74 0B JE SHORT Geometry.0040B085 0040B07A |. 3C FF CMP AL,0FF 0040B07C |. 74 07 JE SHORT Geometry.0040B085 0040B07E |. FEC8 DEC AL 0040B080 |. 8841 FF MOV BYTE PTR DS:[ECX-1],AL 0040B083 |. EB 0A JMP SHORT Geometry.0040B08F 0040B085 |> 49 DEC ECX 0040B086 |. 51 PUSH ECX ; /block 0040B087 |. E8 DE1F0000 CALL <JMP.&MFC42.#825_??3@YAXPAX@Z> ; \free 0040B08C |. 83C4 04 ADD ESP,4 0040B08F |> 8B4C24 30 MOV ECX,DWORD PTR SS:[ESP+30] 0040B093 |. 897424 20 MOV DWORD PTR SS:[ESP+20],ESI 0040B097 |. 3BCE CMP ECX,ESI 0040B099 |. 897424 24 MOV DWORD PTR SS:[ESP+24],ESI 0040B09D |. 897424 28 MOV DWORD PTR SS:[ESP+28],ESI 0040B0A1 |. 74 50 JE SHORT Geometry.0040B0F3 0040B0A3 |. 8A41 FF MOV AL,BYTE PTR DS:[ECX-1] 0040B0A6 |. 84C0 TEST AL,AL 0040B0A8 |. 74 0B JE SHORT Geometry.0040B0B5 0040B0AA |. 3C FF CMP AL,0FF 0040B0AC |. 74 07 JE SHORT Geometry.0040B0B5 0040B0AE |. FEC8 DEC AL 0040B0B0 |. 8841 FF MOV BYTE PTR DS:[ECX-1],AL 0040B0B3 |. EB 3E JMP SHORT Geometry.0040B0F3 0040B0B5 |> 49 DEC ECX 0040B0B6 |. 51 PUSH ECX ; /block 0040B0B7 |. E8 AE1F0000 CALL <JMP.&MFC42.#825_??3@YAXPAX@Z> ; \free 0040B0BC |. 83C4 04 ADD ESP,4 0040B0BF |. EB 32 JMP SHORT Geometry.0040B0F3 0040B0C1 |> C743 04 00000>MOV DWORD PTR DS:[EBX+4],0 0040B0C8 |> 6A 01 PUSH 1 0040B0CA |. 8D4C24 20 LEA ECX,DWORD PTR SS:[ESP+20] 0040B0CE |. C68424 500100>MOV BYTE PTR SS:[ESP+150],0 0040B0D6 |. FF15 B0F44000 CALL DWORD PTR DS:[<&MSVCP60.?_Tidy@?$basic_stri>; MSVCP60.?_Tidy@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@AAEX_N@Z 0040B0DC |. 6A 01 PUSH 1 0040B0DE |. 8D4C24 30 LEA ECX,DWORD PTR SS:[ESP+30] 0040B0E2 |. C78424 500100>MOV DWORD PTR SS:[ESP+150],-1 0040B0ED |. FF15 B0F44000 CALL DWORD PTR DS:[<&MSVCP60.?_Tidy@?$basic_stri>; MSVCP60.?_Tidy@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@AAEX_N@Z 0040B0F3 |> B8 01000000 MOV EAX,1 0040B0F8 |> 8B8C24 440100>MOV ECX,DWORD PTR SS:[ESP+144] 0040B0FF |. 5F POP EDI 0040B100 |. 5E POP ESI 0040B101 |. 5D POP EBP 0040B102 |. 5B POP EBX 0040B103 |. 64:890D 00000>MOV DWORD PTR FS:[0],ECX 0040B10A |. 81C4 40010000 ADD ESP,140 0040B110 \. C3 RETN
1、从它读取的数据来看,keyfile 文件总共分成5个部分(我在代码注解那里标明了一些变量名了),在文件中的顺序为:
nCount1,hex1,nCount2,hex2,nRemainTime
nCount1记录了hex1的长度,nCount2记录了hex2 的长度,nRemainTime则为加密后的剩余使用次数。
2、这段代码中有两个是这个注册中的关键算法,分别是:
地址0040af49的指令 CALL 0040B380,这里是生成最终的机器码hex3的
地址0040afc3的指令 CALL 0040B130,这里是注册成功与否的比较,即是hex2和hex3比较
3、机器码hex3的形成过程:首先调用GetVolumeInformation获取VolumeSerialNumber这个成员的值,然后转化成字符串的形式,记string,然后调用CALL 0040B380这个子函数生成最后的hex3
4、要注意的是,上面两个CALL 都没有对hex1进行处理或运算,现在再往上看看地址为0040af8e的指令REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI]和地址0040af95的指令REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI],这两条指令其实实现的功能就是将hex3的数据覆盖到hex1的buffer中。因此hex1从来都没有参与过运算,但是hex1却不能为空。所以在最后构造keyfile的时候我们可以随意构造的
*******************************************************************************************************************
跟入0040af49 CALL 0040B380:
好,现在跟入0040af49 CALL 0040B380,分析机器码从string到hex3的生成过程,跟入会得到如下代码:
0040B380 /$ 81EC 08020000 SUB ESP,208 0040B386 |. 8D8424 080100>LEA EAX,DWORD PTR SS:[ESP+108] 0040B38D |. 53 PUSH EBX 0040B38E |. 55 PUSH EBP 0040B38F |. 56 PUSH ESI 0040B390 |. 57 PUSH EDI 0040B391 |. 8BBC24 1C0200>MOV EDI,DWORD PTR SS:[ESP+21C] 0040B398 |. 8BD9 MOV EBX,ECX 0040B39A |. 57 PUSH EDI ; /<%s> 0040B39B |. 68 64644100 PUSH Geometry.00416464 ; |%s 0040B3A0 |. 50 PUSH EAX ; |s 0040B3A1 |. FF15 7CF54000 CALL DWORD PTR DS:[<&USER32.wsprintfA>] ; \//格式化字符串string 0040B3A7 |. 83C9 FF OR ECX,FFFFFFFF 0040B3AA |. 33C0 XOR EAX,EAX 0040B3AC |. 83C4 0C ADD ESP,0C 0040B3AF |. 33F6 XOR ESI,ESI 0040B3B1 |. F2:AE REPNE SCAS BYTE PTR ES:[EDI] 0040B3B3 |. F7D1 NOT ECX 0040B3B5 |. 49 DEC ECX ; //计算字符串长度 0040B3B6 |. 8BF9 MOV EDI,ECX 0040B3B8 |. 85FF TEST EDI,EDI ; //判断string是否为空 0040B3BA |. 7E 35 JLE SHORT Geometry.0040B3F1 0040B3BC |. 8B2D 18F54000 MOV EBP,DWORD PTR DS:[<&MSVCRT.div>] ; msvcrt.ldiv 0040B3C2 |> 0FBE8C34 1801>/MOVSX ECX,BYTE PTR SS:[ESP+ESI+118] ; //取string[i], 0040B3CA |. 68 C3000000 |PUSH 0C3 ; ///除数 0040B3CF |. 6A 65 |PUSH 65 ; |//循环次数 0040B3D1 |. 51 |PUSH ECX ; |//被除数 0040B3D2 |. 8BCB |MOV ECX,EBX ; | 0040B3D4 |. E8 D7000000 |CALL Geometry.0040B4B0 ; \//计算一个商值quot 0040B3D9 |. 68 C3000000 |PUSH 0C3 0040B3DE |. 50 |PUSH EAX 0040B3DF |. FFD5 |CALL EBP 0040B3E1 |. 83C4 08 |ADD ESP,8 0040B3E4 |. 885434 18 |MOV BYTE PTR SS:[ESP+ESI+18],DL ; //设remainder = quot % 0c3h,保存到buffer里 0040B3E8 |. 46 |INC ESI ; //i++ 0040B3E9 |. 894424 10 |MOV DWORD PTR SS:[ESP+10],EAX 0040B3ED |. 3BF7 |CMP ESI,EDI 0040B3EF |.^ 7C D1 \JL SHORT Geometry.0040B3C2 0040B3F1 |> C6443C 18 00 MOV BYTE PTR SS:[ESP+EDI+18],0 ; //写入结束标记 0040B3F6 |. 8D7C24 18 LEA EDI,DWORD PTR SS:[ESP+18] 0040B3FA |. 83C9 FF OR ECX,FFFFFFFF 0040B3FD |. 33C0 XOR EAX,EAX 0040B3FF |. 83C3 08 ADD EBX,8 0040B402 |. F2:AE REPNE SCAS BYTE PTR ES:[EDI] 0040B404 |. F7D1 NOT ECX 0040B406 |. 49 DEC ECX ; //计算buffer长度 0040B407 |. 8BE9 MOV EBP,ECX
这里还有一个算法CALL是需要分析的,就是地址0040b3d4 CALL 0040B4B0。
现在就跟入这个算法CALL,可以得到如下代码:
0040B4B0 /$ 83EC 08 SUB ESP,8 0040B4B3 |. 53 PUSH EBX 0040B4B4 |. 8B1D 18F54000 MOV EBX,DWORD PTR DS:[<&MSVCRT.div>] ; msvcrt.ldiv 0040B4BA |. 56 PUSH ESI 0040B4BB |. 8B7424 1C MOV ESI,DWORD PTR SS:[ESP+1C] 0040B4BF |. 57 PUSH EDI 0040B4C0 |. 8B7C24 18 MOV EDI,DWORD PTR SS:[ESP+18] 0040B4C4 |. 56 PUSH ESI ; ///传入参数C3 0040B4C5 |. 57 PUSH EDI ; |//传入参数c1 0040B4C6 |. FFD3 CALL EBX ; \//c1 / c3 0040B4C8 |. 8B4C24 24 MOV ECX,DWORD PTR SS:[ESP+24] ; //传入参数c2是循环计数变量 0040B4CC |. 83C4 08 ADD ESP,8 0040B4CF |. 894424 0C MOV DWORD PTR SS:[ESP+C],EAX ; //保存上上面除法的商到局部变量 0040B4D3 |. 83F9 01 CMP ECX,1 ; //传入的参数c2 <= 1? 0040B4D6 |. 8BC2 MOV EAX,EDX 0040B4D8 |. 7E 18 JLE SHORT Geometry.0040B4F2 0040B4DA |. 55 PUSH EBP 0040B4DB |. 8D69 FF LEA EBP,DWORD PTR DS:[ECX-1] ; // c2-- 0040B4DE |> 0FAFC7 /IMUL EAX,EDI ; //var1=除法的余数值 x 传入参数c1 0040B4E1 |. 56 |PUSH ESI 0040B4E2 |. 50 |PUSH EAX 0040B4E3 |. FFD3 |CALL EBX ; //var2 = var1 / 传入参数c3 0040B4E5 |. 83C4 08 |ADD ESP,8 0040B4E8 |. 894424 10 |MOV DWORD PTR SS:[ESP+10],EAX ; //保存商到局部变量 0040B4EC |. 4D |DEC EBP ; // c2-- 0040B4ED |. 8BC2 |MOV EAX,EDX ; //循环结束后,余数作为返回值 0040B4EF |.^ 75 ED \JNZ SHORT Geometry.0040B4DE 0040B4F1 |. 5D POP EBP 0040B4F2 |> 5F POP EDI 0040B4F3 |. 5E POP ESI 0040B4F4 |. 5B POP EBX 0040B4F5 |. 83C4 08 ADD ESP,8 0040B4F8 \. C2 0C00 RETN 0C
到这里机器码hex3的生成算法已经分析完了,下面要分析的是比较的那个算法CALL
*******************************************************************************************************************
跟入0040afc3 CALL 0040B130:
前面说到了有两个关键的算法CALL,一个是生成机器码hex3的算法CALL,在上面已经分析完了,另一个是注册信息的比较算法,这个是判断你注册能否成功的算法,现在就看看它是怎样比较的。
跟入这个算法call可以得到下面代码:
0040B130 /$ 83EC 10 SUB ESP,10 0040B133 |. 8B4424 18 MOV EAX,DWORD PTR SS:[ESP+18] 0040B137 |. 55 PUSH EBP 0040B138 |. 56 PUSH ESI 0040B139 |. 57 PUSH EDI 0040B13A |. 50 PUSH EAX ; /Arg1 0040B13B |. E8 10010000 CALL Geometry.0040B250 ; \//在比较前对hex2进行运算,还是用hex2来表示处理后的hex2 0040B140 |. 8A4C24 24 MOV CL,BYTE PTR SS:[ESP+24] 0040B144 |. 8BF0 MOV ESI,EAX 0040B146 |. 884C24 0C MOV BYTE PTR SS:[ESP+C],CL 0040B14A |. 8BFE MOV EDI,ESI 0040B14C |. 83C9 FF OR ECX,FFFFFFFF 0040B14F |. 33C0 XOR EAX,EAX 0040B151 |. C74424 10 000>MOV DWORD PTR SS:[ESP+10],0 0040B159 |. C74424 14 000>MOV DWORD PTR SS:[ESP+14],0 0040B161 |. C74424 18 000>MOV DWORD PTR SS:[ESP+18],0 0040B169 |. 6A 01 PUSH 1 0040B16B |. F2:AE REPNE SCAS BYTE PTR ES:[EDI] 0040B16D |. F7D1 NOT ECX 0040B16F |. 49 DEC ECX ; //计算hex2长度 0040B170 |. 8BE9 MOV EBP,ECX 0040B172 |. 8D4C24 10 LEA ECX,DWORD PTR SS:[ESP+10] 0040B176 |. 55 PUSH EBP 0040B177 |. FF15 ACF44000 CALL DWORD PTR DS:[<&MSVCP60.?_Grow@?$basic_string@D>; MSVCP60.?_Grow@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@AAE_NI_N@Z 0040B17D |. 84C0 TEST AL,AL 0040B17F |. 74 1F JE SHORT Geometry.0040B1A0 0040B181 |. 8B7C24 10 MOV EDI,DWORD PTR SS:[ESP+10] 0040B185 |. 8BCD MOV ECX,EBP 0040B187 |. 8BD1 MOV EDX,ECX 0040B189 |. 55 PUSH EBP 0040B18A |. C1E9 02 SHR ECX,2 0040B18D |. F3:A5 REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI] 0040B18F |. 8BCA MOV ECX,EDX 0040B191 |. 83E1 03 AND ECX,3 0040B194 |. F3:A4 REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI] 0040B196 |. 8D4C24 10 LEA ECX,DWORD PTR SS:[ESP+10] 0040B19A |. FF15 C4F44000 CALL DWORD PTR DS:[<&MSVCP60.?_Eos@?$basic_string@DU>; MSVCP60.?_Eos@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@AAEXI@Z 0040B1A0 |> 8B7C24 10 MOV EDI,DWORD PTR SS:[ESP+10] 0040B1A4 |. 8B35 A8F44000 MOV ESI,DWORD PTR DS:[<&MSVCP60.?_C@?1??_Nullstr@?$b>; MSVCP60.?_C@?1??_Nullstr@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@CAPBDXZ@4DB 0040B1AA |. 85FF TEST EDI,EDI 0040B1AC |. 74 02 JE SHORT Geometry.0040B1B0 0040B1AE |. 8BF7 MOV ESI,EDI 0040B1B0 |> 8B4424 20 MOV EAX,DWORD PTR SS:[ESP+20] 0040B1B4 |> 8A10 /MOV DL,BYTE PTR DS:[EAX] ; //取hex3[i] 0040B1B6 |. 8ACA |MOV CL,DL 0040B1B8 |. 3A16 |CMP DL,BYTE PTR DS:[ESI] ; //hex3[i] == hex2[j] ? 0040B1BA |. 75 1C |JNZ SHORT Geometry.0040B1D8 0040B1BC |. 84C9 |TEST CL,CL 0040B1BE |. 74 14 |JE SHORT Geometry.0040B1D4 0040B1C0 |. 8A50 01 |MOV DL,BYTE PTR DS:[EAX+1] ; //取hex3[i+1] 0040B1C3 |. 8ACA |MOV CL,DL 0040B1C5 |. 3A56 01 |CMP DL,BYTE PTR DS:[ESI+1] ; //hex3[i+1] == hex2[j+1] ? 0040B1C8 |. 75 0E |JNZ SHORT Geometry.0040B1D8 0040B1CA |. 83C0 02 |ADD EAX,2 ; //i+=2 0040B1CD |. 83C6 02 |ADD ESI,2 ; //i+=2 0040B1D0 |. 84C9 |TEST CL,CL 0040B1D2 |.^ 75 E0 \JNZ SHORT Geometry.0040B1B4
0040B250 /$ 8B5424 04 MOV EDX,DWORD PTR SS:[ESP+4] 0040B254 |. 81EC 08020000 SUB ESP,208 0040B25A |. 33C0 XOR EAX,EAX 0040B25C |. 53 PUSH EBX 0040B25D |. 55 PUSH EBP 0040B25E |. 56 PUSH ESI 0040B25F |. 8BD9 MOV EBX,ECX 0040B261 |. 57 PUSH EDI 0040B262 |. 8BFA MOV EDI,EDX 0040B264 |. 83C9 FF OR ECX,FFFFFFFF 0040B267 |. 52 PUSH EDX ; /<%s> 0040B268 |. F2:AE REPNE SCAS BYTE PTR ES:[EDI] ; | 0040B26A |. F7D1 NOT ECX ; | 0040B26C |. 8D8424 1C0100>LEA EAX,DWORD PTR SS:[ESP+11C] ; | 0040B273 |. 49 DEC ECX ; | 0040B274 |. 68 64644100 PUSH Geometry.00416464 ; |%s 0040B279 |. 50 PUSH EAX ; |s 0040B27A |. 8BF9 MOV EDI,ECX ; | 0040B27C |. FF15 7CF54000 CALL DWORD PTR DS:[<&USER32.wsprintfA>] ; \wsprintfA 0040B282 |. 83C4 0C ADD ESP,0C 0040B285 |. 33F6 XOR ESI,ESI 0040B287 |. 85FF TEST EDI,EDI 0040B289 |. 7E 35 JLE SHORT Geometry.0040B2C0 0040B28B |. 8B2D 18F54000 MOV EBP,DWORD PTR DS:[<&MSVCRT.div>] ; msvcrt.ldiv 0040B291 |> 0FBE8C34 1801>/MOVSX ECX,BYTE PTR SS:[ESP+ESI+118] 0040B299 |. 68 C3000000 |PUSH 0C3 ; /Arg3 = 000000C3 0040B29E |. 6A 05 |PUSH 5 ; |Arg2 = 00000005 0040B2A0 |. 51 |PUSH ECX ; |Arg1 0040B2A1 |. 8BCB |MOV ECX,EBX ; | 0040B2A3 |. E8 08020000 |CALL Geometry.0040B4B0 ; \Geometry.0040B4B0 0040B2A8 |. 68 C3000000 |PUSH 0C3 0040B2AD |. 50 |PUSH EAX 0040B2AE |. FFD5 |CALL EBP 0040B2B0 |. 83C4 08 |ADD ESP,8 0040B2B3 |. 885434 18 |MOV BYTE PTR SS:[ESP+ESI+18],DL 0040B2B7 |. 46 |INC ESI 0040B2B8 |. 894424 10 |MOV DWORD PTR SS:[ESP+10],EAX 0040B2BC |. 3BF7 |CMP ESI,EDI 0040B2BE |.^ 7C D1 \JL SHORT Geometry.0040B291
好,整个注册过程的算法分析就到此为止了,整个算法就是让我们来求hex2的数据,好,下面开始写注册机。
注册机编写:
因为小弟喜欢WIN32 的汇编编程,因此,再此我提供的是asm版的注册机。代码结合上面的分析应该是挺好理解的,汗~
首先是确定需要的函数:
1、机器码hex3的生成函数EncryptSerial。
2、上面说道了在注册信息比较前会对hex2进行运算处理,而这个算法跟hex3 的生成算法发很类似,出了那个参数,因此定义一个通用的加密函数MainEncrypt。
3、地址为0040B4B0的里循环除法求余数的函数CycleDiv。
EncryptSerial调用MainEncrypt,MainEncrypt调用CycleDiv
现在要做的是hex3=MainEncrypt(string,65) = MainEncrpyt(hex2,5),如果是输入的参数都是65或5的话,两个加密过程就是等价的,因此hex2=string即可,现在是不等,其实是不能够否定他们现在是不等价的(在后面会说到其实他们是等价的)。
现在提供的是一个非常笨的方法:
4、现在就假设不等价,既然能够让每台机都能够注册,那么肯定存在某些字节值经过运算后能与string的每个字节数据经过加密的数据对应相同(即同hex3某对应的字节的值相等),一个字节的范围1----0ffh,通过循环查找即可,所以需要一个循环查找函数,生成原始的hex2数据的,GenerateSerial
这真的是比较笨的方法,用循环对每个值运算一次找相同的。幸好加密的数据是字节为单位,范围是1---0ffh,很快就能够找到的。
注册机源代码已经作为附件贴上
注册算法的本质:
上面是直观的角度去写注册算法,比较繁琐,下面来通过试验来探讨注册加密过程的本质。
其实当时看到hex2和string的处理函数非常相似的时候(不同之处在前面已经讲过了),就怀疑他们是否等价的,如果全值等价(或者在string每个字节所在的范围等价),那么hex2的数据就非常简单了,hex2=string即可。
首先在前面的分析中我们就知道,string是通过调用GetVolumeInformation获取VolumeSerialNumber这是一个dword型数据,做了xor运算后还是dword型数据,因此它包括00000000------ffffffff,因此通过”%x”的格式转化为字符串的话,string每个字符范围是以下字符串:“1234567890abcdef”中的一个,并且string的长度已经确定,为8这个字符。
现在就来验证它们的过程是否等价,如果等价的相同,也很简单,对记stemp=”1234567890abcdef”使用两种加密过程对其进行加密,如果得到的数据相同,就表明在这些字符中,两个加密过程是等价的,也就hex2=string。在前面已经写了一个hex3 的生成函数MainEncrypt,然后做如下调用:MainEncrypt(string,65)和 MainEncrpyt(hex2,5)。
最后,你会发现实际上,加密后的数据是一样的,也就表明了它们是等价的。
也就是说整个注册的算法的本质只是需要得到string,而string的获取仅仅是调用一个API函数,异或了一下
到这里才发现自己在上面写的注册机里,根本没必要对string进行加密运算,真的是给软件的作者甩了一圈,汗~,在此也不对注册机做优化了,这就留给大家了吧
【遗留问题】: 在上面虽然通过试验验证它们是等价的,但是并没有从逻辑或者是数学的角度去证明,希望有朋友证明出来后能告诉小弟,好让我学习学习~