- UID
- 75402
注册时间2014-5-2
阅读权限30
最后登录1970-1-1
龙战于野
TA的每日心情 | 开心 2015-8-2 16:07 |
---|
签到天数: 2 天 [LV.1]初来乍到
|
本帖最后由 F8LEFT 于 2014-11-24 11:15 编辑
2014PYG10周年庆典,Nisy校长发了个异常强大的cm,我是菜鸟一个,不过在机缘巧合之下还是弄出来了,发一下分析,来加深印象。这个cm的想法还是挺不错的。
简单的东西就不多提了。我直接用一组key来进行讲解:
Name:F8LEFT
Pass : NS-oZQe7Eru-8EE8
切入算法流程可以直接使用GetWindowTextW断点,直接在命令行进行bpx GetWindowTextW就可以同时在两个验证段断下了。然后单步跟踪。
进入第一步验证,除去基础长度判断后,会来到下面一个小buff
- 0040E43E |. 50 PUSH EAX ; Push Pass
- 0040E43F |. 8D85 D0FBFFFF LEA EAX, [LOCAL.268]
- 0040E445 |. 50 PUSH EAX ; Push Name
- 0040E446 |. 8D45 FC LEA EAX, [LOCAL.1]
- 0040E449 |. 8038 00 CMP BYTE PTR DS:[EAX], 0x0 ; [eax] = 0
- 0040E44C |. 75 05 JNZ SHORT NsCrackM.0040E453
- 0040E44E |. 8B00 MOV EAX, DWORD PTR DS:[EAX] ; Err1
- 0040E450 |. C600 CC MOV BYTE PTR DS:[EAX], 0xCC ; Err2
- 0040E453 |> FF10 CALL NEAR DWORD PTR DS:[EAX] ; --> Func (In SEH)
复制代码 这里入栈了 Pass 与 Name ,没啥的,关键是下面:
CMP BYTE PTR DS:[EAX], 0x0 ; [eax] = 0
JNZ SHORT NsCrackM.0040E453
MOV EAX, DWORD PTR DS:[EAX] ; Err1
MOV BYTE PTR DS:[EAX], 0xCC ; Err2
---------------------------->--------------------------->--------------------------->
cmp [eax],0 => jnz XXXXXXXX, 这里保证了[eax]里面的值是0,也即 BYTE: [eax] = 0
MOV EAX, DWORD :[EAX], 这里取了[EAX],于是,EAX = 0
那么问题就来了,下一句
MOV BYTE PTR DS:[EAX], 0xCC , 此时EAX = 0,这就相当于 MOV DS:[0], 0xCC,显然是无法进行的。因此,程序到了这里,便会产生异常。
既然有异常,那么就自然可以想到异常处理函数,直接查看OD的SEH链窗体,可以看到以下几个异常处理函数:
只要一个函数是属于程序段的,这个便是处理函数了,可以在这个函数上面下个断点,接着F9,便会停在004127C0处,此时便可以进行下一步的跟踪了(不过,暂时用不上)。这时候可以再一次F9,因为前面下了GetWindowTextW断点,此时会停留在第二段验证处。0040DAB0
跟踪下去就是第一段比较了:
- 0040DB7A . 50 PUSH EAX ; Push Name
- 0040DB7B . 8D4D E4 LEA ECX, DWORD PTR SS:[EBP-0x1C]
- 0040DB7E . E8 BD6FFFFF CALL <NsCrackM.N_Strcpy>
- 0040DB83 . 8D8D D0FDFFFF LEA ECX, DWORD PTR SS:[EBP-0x230]
- 0040DB89 . 51 PUSH ECX ; Push Pass
- 0040DB8A . 8D8D C8FDFFFF LEA ECX, DWORD PTR SS:[EBP-0x238]
- 0040DB90 . E8 AB6FFFFF CALL <NsCrackM.N_Strcpy>
- 0040DB95 . C745 FC 01000>MOV DWORD PTR SS:[EBP-0x4], 0x1
- 0040DB9C . BA 4E000000 MOV EDX, 0x4E ; N
- 0040DBA1 . 66:8995 B0FBF>MOV WORD PTR SS:[EBP-0x450], DX
- 0040DBA8 . B8 53000000 MOV EAX, 0x53
- 0040DBAD . 66:8985 B2FBF>MOV WORD PTR SS:[EBP-0x44E], AX ; S
- 0040DBB4 . 33C9 XOR ECX, ECX
- 0040DBB6 . 66:898D B4FBF>MOV WORD PTR SS:[EBP-0x44C], CX ; 创建字符串 NS
- 0040DBBD . 8D8D C8FDFFFF LEA ECX, DWORD PTR SS:[EBP-0x238] ; Pass
- 0040DBC3 . E8 F893FFFF CALL <NsCrackM.N_Strlen> ; 求密码长度
- 0040DBC8 . 83F8 03 CMP EAX, 0x3 ; 长度>=3
- 0040DBCB . 7C 39 JL SHORT NsCrackM.0040DC06
- 0040DBCD . 8D95 B0FBFFFF LEA EDX, DWORD PTR SS:[EBP-0x450]
- 0040DBD3 . 52 PUSH EDX
- 0040DBD4 . 6A 02 PUSH 0x2 ; 长度为2
- 0040DBD6 . 8D85 94FBFFFF LEA EAX, DWORD PTR SS:[EBP-0x46C]
- 0040DBDC . 50 PUSH EAX
- 0040DBDD . 8D8D C8FDFFFF LEA ECX, DWORD PTR SS:[EBP-0x238]
- 0040DBE3 . E8 380A0000 CALL <NsCrackM.N_StrSub> ; 取Pass的子窜,这里是取头两个字符
- 0040DBE8 . 838D 80FBFFFF>OR DWORD PTR SS:[EBP-0x480], 0x1
- 0040DBEF . 8BC8 MOV ECX, EAX
- 0040DBF1 . E8 6A090000 CALL <NsCrackM.N_Strcmp?> ; 与前面创建的字符串NS比较
复制代码 这里可以知道密码的前2个字符为NS。再继续跟踪。
- 0040DC44 . 8B0D 90664200 MOV ECX, DWORD PTR DS:[0x426690] ; [426690] = 0
- 0040DC4A . C701 01000000 MOV DWORD PTR DS:[ECX], 0x1 ; SEH => 2
复制代码 喜闻乐见+丧心病狂,这里又一次触发了SEH异常,函数函数哪一个,下好断点,然后F9吧。
断在异常处理函数后F8跟踪,注意大致的浏览一下每一个字call,此时可以定位到一个非常可疑的Call中:
- 00412927 |. E8 A5030000 CALL NsCrackM.00412CD1 ; In (函数分派) ECX = 跳转目标地址
复制代码 这个Call的里面是这样的。:
- 00412CD1 nbsp; 8BEA MOV EBP, EDX
- 00412CD3 . 8BF1 MOV ESI, ECX ; 复制跳转地址
- 00412CD5 . 8BC1 MOV EAX, ECX ; 取跳转地址
- 00412CD7 . 6A 01 PUSH 0x1
- 00412CD9 . E8 B74A0000 CALL NsCrackM.00417795
- 00412CDE . 33C0 XOR EAX, EAX ; NsCrackM.0040DC62
- 00412CE0 . 33DB XOR EBX, EBX
- 00412CE2 . 33C9 XOR ECX, ECX
- 00412CE4 . 33D2 XOR EDX, EDX
- 00412CE6 . 33FF XOR EDI, EDI
- 00412CE8 . FFE6 JMP NEAR ESI ; jmp Func
复制代码 清空了一下寄存器的内容,紧接着就直接跳走了,这个显然是人为用汇编代码写上去的,非常的可疑。实际上这里是非常重要的函数分配段,后面还有一次验证会用到这里,下好断点了,然后jmp ESI,跳到相应的处理段中。来到第3段验证:0040DC62
- 0040DC62 . 8B65 E8 MOV ESP, DWORD PTR SS:[EBP-0x18] ; 3
- 0040DC65 . 8D95 D0FDFFFF LEA EDX, DWORD PTR SS:[EBP-0x230]
- 0040DC6B . 52 PUSH EDX
- 0040DC6C . 8D8D ACFBFFFF LEA ECX, DWORD PTR SS:[EBP-0x454]
- 0040DC72 . E8 C96CFFFF CALL <NsCrackM.N_Strcpy> ; 复制Pass
- 0040DC77 . 8D8D A8FBFFFF LEA ECX, DWORD PTR SS:[EBP-0x458]
- 0040DC7D . E8 CE92FFFF CALL NsCrackM.00406F50
- 0040DC82 . 8D8D ACFBFFFF LEA ECX, DWORD PTR SS:[EBP-0x454] ; Pass
- 0040DC88 . E8 3393FFFF CALL <NsCrackM.N_Strlen> ; PassLen
- 0040DC8D . 83F8 03 CMP EAX, 0x3
- 0040DC90 . 0F8E 2D010000 JLE NsCrackM.0040DDC3
- 0040DC96 . 6A 2D PUSH 0x2D ; 0x2D = "-"
- 0040DC98 . 8D8D ACFBFFFF LEA ECX, DWORD PTR SS:[EBP-0x454] ; Pass
- 0040DC9E . E8 6D0A0000 CALL <NsCrackM.N_StrIndex> ; 取-在Pass中的第一个位置
- 0040DCA3 . 8985 A0FBFFFF MOV DWORD PTR SS:[EBP-0x460], EAX
- 0040DCA9 . 8B85 A0FBFFFF MOV EAX, DWORD PTR SS:[EBP-0x460]
- 0040DCAF . 83C0 01 ADD EAX, 0x1
- 0040DCB2 . 50 PUSH EAX
- 0040DCB3 . 6A 2D PUSH 0x2D
- 0040DCB5 . 8D8D ACFBFFFF LEA ECX, DWORD PTR SS:[EBP-0x454]
- 0040DCBB . E8 C00A0000 CALL <NsCrackM.IndexOfStr> ; 取第二个-在Pass的位置
- 0040DCC0 . 8985 A4FBFFFF MOV DWORD PTR SS:[EBP-0x45C], EAX
- 0040DCC6 . 8B8D A4FBFFFF MOV ECX, DWORD PTR SS:[EBP-0x45C] ; Len
- 0040DCCC . 2B8D A0FBFFFF SUB ECX, DWORD PTR SS:[EBP-0x460] ; -2
- 0040DCD2 . 83E9 01 SUB ECX, 0x1 ; -1(-3)
- 0040DCD5 . 51 PUSH ECX ; 第二个-位置
- 0040DCD6 . 8B95 A0FBFFFF MOV EDX, DWORD PTR SS:[EBP-0x460]
- 0040DCDC . 83C2 01 ADD EDX, 0x1
- 0040DCDF . 52 PUSH EDX ; 第一个-位置
- 0040DCE0 . 8D85 90FBFFFF LEA EAX, DWORD PTR SS:[EBP-0x470]
- 0040DCE6 . 50 PUSH EAX
- 0040DCE7 . 8D8D ACFBFFFF LEA ECX, DWORD PTR SS:[EBP-0x454]
- 0040DCED . E8 8E080000 CALL <NsCrackM.N_SubStr> ; Pass取两个-中间的字符串
- 0040DCF2 . 8B08 MOV ECX, DWORD PTR DS:[EAX]
- 0040DCF4 . 51 PUSH ECX
- 0040DCF5 . 8B95 A4FBFFFF MOV EDX, DWORD PTR SS:[EBP-0x45C]
- 0040DCFB . 52 PUSH EDX
- 0040DCFC . 8B85 A0FBFFFF MOV EAX, DWORD PTR SS:[EBP-0x460]
- 0040DD02 . 50 PUSH EAX
- 0040DD03 . 68 9C0C4200 PUSH NsCrackM.00420C9C ; %d %d %s
- 0040DD08 . 8D8D A8FBFFFF LEA ECX, DWORD PTR SS:[EBP-0x458]
- 0040DD0E . 51 PUSH ECX
- 0040DD0F . E8 DC0A0000 CALL NsCrackM.0040E7F0 ; (格式化字符串)第一个-位置 第二个-位置 两个-中间的字符串
- 0040DD14 . 83C4 14 ADD ESP, 0x14
- 0040DD17 . 8D8D 90FBFFFF LEA ECX, DWORD PTR SS:[EBP-0x470]
- 0040DD1D . E8 7E70FFFF CALL <NsCrackM.ToString>
- 0040DD22 . 8B95 A4FBFFFF MOV EDX, DWORD PTR SS:[EBP-0x45C]
- 0040DD28 . 3B95 A0FBFFFF CMP EDX, DWORD PTR SS:[EBP-0x460]
- 0040DD2E 0F8E 8F000000 JLE NsCrackM.0040DDC3
- 0040DD34 . 8B85 A4FBFFFF MOV EAX, DWORD PTR SS:[EBP-0x45C] ; 同上
- 0040DD3A . 2B85 A0FBFFFF SUB EAX, DWORD PTR SS:[EBP-0x460]
- 0040DD40 . 83E8 01 SUB EAX, 0x1
- 0040DD43 . 50 PUSH EAX
- 0040DD44 . 8B8D A0FBFFFF MOV ECX, DWORD PTR SS:[EBP-0x460]
- 0040DD4A . 83C1 01 ADD ECX, 0x1
- 0040DD4D . 51 PUSH ECX
- 0040DD4E . 8D95 8CFBFFFF LEA EDX, DWORD PTR SS:[EBP-0x474]
- 0040DD54 . 52 PUSH EDX
- 0040DD55 . 8D8D ACFBFFFF LEA ECX, DWORD PTR SS:[EBP-0x454]
- 0040DD5B . E8 20080000 CALL <NsCrackM.N_SubStr> ; 继续取两个-中间的字符串
- 0040DD60 . 50 PUSH EAX
- 0040DD61 . 8D8D A8FBFFFF LEA ECX, DWORD PTR SS:[EBP-0x458]
- 0040DD67 . E8 44B4FFFF CALL NsCrackM.004091B0
- 0040DD6C . 8D8D 8CFBFFFF LEA ECX, DWORD PTR SS:[EBP-0x474] ; 取中间的字符串
- 0040DD72 . E8 2970FFFF CALL <NsCrackM.ToString>
- 0040DD77 . 8D85 A8FBFFFF LEA EAX, DWORD PTR SS:[EBP-0x458]
- 0040DD7D . 50 PUSH EAX ; str2
- 0040DD7E . 8D8D 88FBFFFF LEA ECX, DWORD PTR SS:[EBP-0x478]
- 0040DD84 . 51 PUSH ECX ; str2
- 0040DD85 . E8 A689FFFF CALL NsCrackM.00406730 ; 进行某种变换
- 0040DD8A . 83C4 08 ADD ESP, 0x8
- 0040DD8D . 50 PUSH EAX
- 0040DD8E . 8D8D A8FBFFFF LEA ECX, DWORD PTR SS:[EBP-0x458]
- 0040DD94 . E8 17B4FFFF CALL NsCrackM.004091B0
- 0040DD99 . 8D8D 88FBFFFF LEA ECX, DWORD PTR SS:[EBP-0x478]
- 0040DD9F . E8 FC6FFFFF CALL <NsCrackM.ToString>
- 0040DDA4 . 8D95 B8FBFFFF LEA EDX, DWORD PTR SS:[EBP-0x448]
- 0040DDAA . 52 PUSH EDX ; Push Name
- 0040DDAB . 8D8D A8FBFFFF LEA ECX, DWORD PTR SS:[EBP-0x458]
- 0040DDB1 . E8 AA070000 CALL <NsCrackM.N_Strcmp?> ; 与用户名比较
复制代码 代码虽然比较长,但实际上就做了几件事。首先,用-分割Pass为3段,然后取中间的那一段,进行某种变换,并把变换结果与用户名比较。所以,我们得知Pass的大致结构如下:
NS-Code(Name)-Str3
这里先不管加密方式,继续跟踪下去:
下面几步F8后,达到一个call
- 0040DDE7 . E8 05000000 CALL NsCrackM.0040DDF1 ; OneCheck F7进去
复制代码 F7跟踪进去:
- 0040DDF1 /nbsp; 6A 02 PUSH 0x2
- 0040DDF3 |. 8D8D C8FDFFFF LEA ECX, [LOCAL.142]
- 0040DDF9 |. E8 E2060000 CALL NsCrackM.0040E4E0 ; 取Pass[2]
- 0040DDFE |. 0FB7C0 MOVZX EAX, AX
- 0040DE01 |. 83F8 2D CMP EAX, 0x2D ; Pass[2] = 0x2D('-')
- 0040DE04 75 77 JNZ SHORT NsCrackM.0040DE7D
- 0040DE06 |. 83BD CCFDFFFF>CMP [LOCAL.141], 0x1 ; bool
- 0040DE0D |. 75 6E JNZ SHORT NsCrackM.0040DE7D
- 0040DE0F |. 8D4D E4 LEA ECX, [LOCAL.7]
- 0040DE12 |. 51 PUSH ECX
- 0040DE13 |. 8D8D 9CFBFFFF LEA ECX, [LOCAL.281]
- 0040DE19 |. E8 5291FFFF CALL NsCrackM.00406F70 ; Name
- 0040DE1E |. 68 B00C4200 PUSH NsCrackM.00420CB0 ; -
- 0040DE23 |. 8D8D 9CFBFFFF LEA ECX, [LOCAL.281]
- 0040DE29 |. E8 02070000 CALL NsCrackM.0040E530
- 0040DE2E |. 8D95 C8FDFFFF LEA EDX, [LOCAL.142]
- 0040DE34 |. 52 PUSH EDX
- 0040DE35 |. 8D8D 9CFBFFFF LEA ECX, [LOCAL.281] ; Pass
- 0040DE3B |. E8 C0060000 CALL NsCrackM.0040E500
- 0040DE40 |. 8D8D 9CFBFFFF LEA ECX, [LOCAL.281]
- 0040DE46 |. E8 E573FFFF CALL <NsCrackM.*p> ; 用 - 链接Name与Pass
- 0040DE4B |. 50 PUSH EAX
- 0040DE4C |. 68 04010000 PUSH 0x104
- 0040DE51 |. 68 A0664200 PUSH NsCrackM.004266A0
- 0040DE56 |. E8 35060000 CALL NsCrackM.0040E490
- 0040DE5B |. 6A 00 PUSH 0x0 ; /lParam = 0x0
- 0040DE5D |. 6A 00 PUSH 0x0 ; |wParam = 0x0
- 0040DE5F |. A1 AC684200 MOV EAX, DWORD PTR DS:[0x4268AC] ; |
- 0040DE64 |. 50 PUSH EAX ; |Message => MSG(0xC1A3)
- 0040DE65 |. 8B0D B0684200 MOV ECX, DWORD PTR DS:[0x4268B0] ; |
- 0040DE6B |. 51 PUSH ECX ; |hWnd => 0xB02A6
- 0040DE6C |. FF15 B0014200 CALL NEAR DWORD PTR DS:[<&USER32.PostMessage>; \PostMessageW
- 0040DE72 |. 8D8D 9CFBFFFF LEA ECX, [LOCAL.281]
- 0040DE78 |. E8 236FFFFF CALL <NsCrackM.ToString>
- 0040DE7D \> C3 RETN
复制代码 这里发送了一个我们不知道的消息,显然这个消息是Nisy校长自己定义的。跟踪之下,会发现是发给主窗体的,于是,需要在主窗体相应的Msg处理的地方下一个断点,才能继续跟踪。
在0040DE5F处,右键,查找参考,地址常量,找到一处 CMP EDX, DWORD PTR DS:[0x4268AC], (00407441) 可以快速的到底处理的地方,在 CMP...JNZ...的下面下个int3断点,F9运行,便会断下来。到底第4处验证(真多。。。。)
这里用F7跟踪,进入一个CALL后,便会看到希望了。
紧接着马上对这个字符串进行某种变换得到: 恭喜,注册成功!@>--- (Nice!!!!)
然后继续初始化另外一个字符串: EOo&xA^W
变换后得到:恭喜!
Good Job!!于是,这里就成功了吗?不是的,必须得再留心一下,前面的Pass还有第三段没有进行验证呢!肯定还有下一个验证点!慢慢跟踪下去,会发现一个非常典型的跳转:
- 004079DD |. E8 CE660000 CALL NsCrackM.0040E0B0 ; 4
- 004079E2 |. 85C0 TEST EAX, EAX
- 004079E4 74 27 JE SHORT NsCrackM.00407A0D
复制代码 这个CALL便是最后一段验证,下面的JE Nop掉就直接成功了,当然,我们继续跟进这个call,看一下它做了什么。
这个call便是处理Pass第三段的验证段。- 0040E0B0 $ 55 PUSH EBP
- 0040E0B1 . 8BEC MOV EBP, ESP
- 0040E0B3 . 6A FE PUSH -0x2
- 0040E0B5 . 68 48354200 PUSH NsCrackM.00423548
- 0040E0BA . 68 C0274100 PUSH NsCrackM.004127C0
- 0040E0BF . 64:A1 0000000>MOV EAX, DWORD PTR FS:[0]
- 0040E0C5 . 50 PUSH EAX
- 0040E0C6 . 83C4 C0 ADD ESP, -0x40
- 0040E0C9 . 53 PUSH EBX
- 0040E0CA . 56 PUSH ESI
- 0040E0CB . 57 PUSH EDI
- 0040E0CC . A1 74534200 MOV EAX, DWORD PTR DS:[0x425374]
- 0040E0D1 . 3145 F8 XOR DWORD PTR SS:[EBP-0x8], EAX
- 0040E0D4 . 33C5 XOR EAX, EBP
- 0040E0D6 . 50 PUSH EAX
- 0040E0D7 . 8D45 F0 LEA EAX, DWORD PTR SS:[EBP-0x10]
- 0040E0DA . 64:A3 0000000>MOV DWORD PTR FS:[0], EAX
- 0040E0E0 . 8965 E8 MOV DWORD PTR SS:[EBP-0x18], ESP
- 0040E0E3 . C745 DC 00000>MOV DWORD PTR SS:[EBP-0x24], 0x0
- 0040E0EA . C745 D4 00000>MOV DWORD PTR SS:[EBP-0x2C], 0x0
- 0040E0F1 . C745 E0 00000>MOV DWORD PTR SS:[EBP-0x20], 0x0 ; 取前面链接的 Name-Pass
- 0040E0F8 . 68 A0664200 PUSH NsCrackM.004266A0 ; F8LEFT-NS-oZQe7Eru-8EE8
- 0040E0FD . 8D4D E4 LEA ECX, DWORD PTR SS:[EBP-0x1C]
- 0040E100 . E8 3B68FFFF CALL <NsCrackM.N_Strcpy>
- 0040E105 . 8D4D D8 LEA ECX, DWORD PTR SS:[EBP-0x28]
- 0040E108 . E8 438EFFFF CALL NsCrackM.00406F50
- 0040E10D . C745 FC 00000>MOV DWORD PTR SS:[EBP-0x4], 0x0
- 0040E114 . C745 FC 01000>MOV DWORD PTR SS:[EBP-0x4], 0x1
- 0040E11B . 8D4D E4 LEA ECX, DWORD PTR SS:[EBP-0x1C]
- 0040E11E . E8 9D8EFFFF CALL <NsCrackM.N_Strlen> ; buffLen
- 0040E123 . 85C0 TEST EAX, EAX ; 判断长度是否为0
- 0040E125 . 75 05 JNZ SHORT NsCrackM.0040E12C
- 0040E127 . E9 AB000000 JMP NsCrackM.0040E1D7
- 0040E12C > 68 08020000 PUSH 0x208
- 0040E131 . 6A 00 PUSH 0x0
- 0040E133 . 68 A0664200 PUSH NsCrackM.004266A0
- 0040E138 . E8 23400000 CALL <NsCrackM.memset?> ; 清除空间
- 0040E13D . 83C4 0C ADD ESP, 0xC
- 0040E140 . 6A 2D PUSH 0x2D ; '-'
- 0040E142 . 8D4D E4 LEA ECX, DWORD PTR SS:[EBP-0x1C] ; Name-Pass链接
- 0040E145 . E8 E6050000 CALL <NsCrackM.StrLastIndex> ; 取最后一个-的位置
- 0040E14A . 8945 D0 MOV DWORD PTR SS:[EBP-0x30], EAX
- 0040E14D . 8B45 D0 MOV EAX, DWORD PTR SS:[EBP-0x30]
- 0040E150 . 50 PUSH EAX
- 0040E151 . 8D4D CC LEA ECX, DWORD PTR SS:[EBP-0x34]
- 0040E154 . 51 PUSH ECX
- 0040E155 . 8D4D E4 LEA ECX, DWORD PTR SS:[EBP-0x1C]
- 0040E158 . E8 C3040000 CALL <NsCrackM.N_StrSub> ; 取最后一个-前面的所有数据
- 0040E15D . 51 PUSH ECX ; F8LEFT-NS-oZQe7Eru
- 0040E15E . 8BCC MOV ECX, ESP
- 0040E160 . 8D55 CC LEA EDX, DWORD PTR SS:[EBP-0x34]
- 0040E163 . 52 PUSH EDX
- 0040E164 . E8 078EFFFF CALL NsCrackM.00406F70 ; 利用上面取出的字符串
- 0040E169 . E8 8287FFFF CALL NsCrackM.004068F0 ; 计算出加密key (DWORD)
- 0040E16E . 83C4 04 ADD ESP, 0x4
- 0040E171 . 8945 E0 MOV DWORD PTR SS:[EBP-0x20], EAX ; 保存DWORD
- 0040E174 . 8D4D E4 LEA ECX, DWORD PTR SS:[EBP-0x1C]
- 0040E177 . E8 448EFFFF CALL <NsCrackM.N_Strlen>
- 0040E17C . 2B45 D0 SUB EAX, DWORD PTR SS:[EBP-0x30]
- 0040E17F . 83E8 01 SUB EAX, 0x1
- 0040E182 . 50 PUSH EAX
- 0040E183 . 8D45 C0 LEA EAX, DWORD PTR SS:[EBP-0x40]
- 0040E186 . 50 PUSH EAX
- 0040E187 . 8D4D E4 LEA ECX, DWORD PTR SS:[EBP-0x1C]
- 0040E18A . E8 01050000 CALL NsCrackM.0040E690 ; 取Pass的最后的一个buff
- 0040E18F . 50 PUSH EAX
- 0040E190 . 8D4D D8 LEA ECX, DWORD PTR SS:[EBP-0x28]
- 0040E193 . E8 18B0FFFF CALL NsCrackM.004091B0
- 0040E198 . 8D4D C0 LEA ECX, DWORD PTR SS:[EBP-0x40]
- 0040E19B . E8 006CFFFF CALL <NsCrackM.ToString>
- 0040E1A0 . 8D4D D8 LEA ECX, DWORD PTR SS:[EBP-0x28]
- 0040E1A3 . E8 188EFFFF CALL <NsCrackM.N_Strlen> ; 取长度,与4比较
- 0040E1A8 . 83F8 04 CMP EAX, 0x4
- 0040E1AB . 74 02 JE SHORT NsCrackM.0040E1AF
- 0040E1AD . EB 28 JMP SHORT NsCrackM.0040E1D7
- 0040E1AF > 8D4D D8 LEA ECX, DWORD PTR SS:[EBP-0x28]
- 0040E1B2 . E8 098EFFFF CALL <NsCrackM.N_Strlen>
- 0040E1B7 . 83F8 04 CMP EAX, 0x4
- 0040E1BA . 75 13 JNZ SHORT NsCrackM.0040E1CF
- 0040E1BC . C745 D4 01000>MOV DWORD PTR SS:[EBP-0x2C], 0x1 ; bool Continue = 1
- 0040E1C3 . 8B0D 90664200 MOV ECX, DWORD PTR DS:[0x426690] ; ECX = 0
- 0040E1C9 . C701 01000000 MOV DWORD PTR DS:[ECX], 0x1 ; Err3 (To SEH)
复制代码 处理了一下用户名与密码,计算出一个加密key,判断Pass的最后一段长度是否为4,是的话就触发新的异常。异常处理函数还是哪一个,就连分配的地点也是一样的。这下知道了我前面下分配函数的那个断点的作用了吧。慢慢跟踪下去,来到最后一段验证: 0040E1E9
- 0040E1E9 . 8B65 E8 MOV ESP, DWORD PTR SS:[EBP-0x18]
- 0040E1EC . 837D D4 00 CMP DWORD PTR SS:[EBP-0x2C], 0x0 ; if bool = 0?
- 0040E1F0 . 74 74 JE SHORT NsCrackM.0040E266
- 0040E1F2 . 51 PUSH ECX
- 0040E1F3 . 8BCC MOV ECX, ESP
- 0040E1F5 . 8D55 D8 LEA EDX, DWORD PTR SS:[EBP-0x28]
- 0040E1F8 . 52 PUSH EDX
- 0040E1F9 . E8 728DFFFF CALL NsCrackM.00406F70 ; 取Pass最后一段
- 0040E1FE . E8 1D88FFFF CALL <NsCrackM.atoi> ; Str 转换 为 DWORD = Temp
- 0040E203 . 83C4 04 ADD ESP, 0x4
- 0040E206 . 8945 C8 MOV DWORD PTR SS:[EBP-0x38], EAX
- 0040E209 . 8B45 E0 MOV EAX, DWORD PTR SS:[EBP-0x20] ; 取出刚才算出的key
- 0040E20C . 25 0000FFFF AND EAX, 0xFFFF0000
- 0040E211 C1E8 10 SHR EAX, 0x10 ; a = (key & 0xFFFF0000) >> 10
- 0040E214 . 8B4D E0 MOV ECX, DWORD PTR SS:[EBP-0x20]
- 0040E217 . 81E1 FFFF0000 AND ECX, 0xFFFF ; b = key & 0x0000FFFF
- 0040E21D . 33C1 XOR EAX, ECX ; c = a ^ b, 也就是key高地位异或
- 0040E21F . 8945 E0 MOV DWORD PTR SS:[EBP-0x20], EAX
- 0040E222 . 8B55 C8 MOV EDX, DWORD PTR SS:[EBP-0x38]
- 0040E225 . 0355 E0 ADD EDX, DWORD PTR SS:[EBP-0x20] ; d = Temp + c
- 0040E228 . 33C0 XOR EAX, EAX
- 0040E22A . 81FA 00000100 CMP EDX, 0x10000 ; cmp d, 0x10000
- 0040E230 . 0F94C0 SETE AL ; Set Flag
复制代码 这下终于弄完大致的流程了,终结一下,程序现在有两段加密的算法没有弄出来,记为Encode1, Encode2.那么加密的数据为
Pass1 = NS
Name = Encode1(Pass2)
Pass3 = Encode2(Name-Pass1-Pass2)
最后就剩下Encode1与Encode2要判断了。先来看Encode2,只是一个简单的查表变换,很简单的。
- 00406890 /$ 55 PUSH EBP
- 00406891 |. 8BEC MOV EBP, ESP
- 00406893 |. 83EC 08 SUB ESP, 0x8
- 00406896 |. 8B45 08 MOV EAX, [ARG.1]
- 00406899 |. 83F0 FF XOR EAX, 0xFFFFFFFF
- 0040689C |. 8945 FC MOV [LOCAL.1], EAX ; sum = -1
- 0040689F |. C745 F8 00000>MOV [LOCAL.2], 0x0
- 004068A6 |. EB 09 JMP SHORT NsCrackM.004068B1
- 004068A8 |> 8B4D F8 /MOV ECX, [LOCAL.2]
- 004068AB |. 83C1 01 |ADD ECX, 0x1
- 004068AE |. 894D F8 |MOV [LOCAL.2], ECX
- 004068B1 |> 8B55 F8 MOV EDX, [LOCAL.2]
- 004068B4 |. 3B55 10 |CMP EDX, [ARG.3] ; while(i < iPasslen)
- 004068B7 |. 73 24 |JNB SHORT NsCrackM.004068DD
- 004068B9 |. 8B45 0C |MOV EAX, [ARG.2]
- 004068BC |. 0345 F8 |ADD EAX, [LOCAL.2]
- 004068BF |. 0FBE08 |MOVSX ECX, BYTE PTR DS:[EAX] ; UCHAR a = Str[i]
- 004068C2 |. 334D FC |XOR ECX, [LOCAL.1] ; a ^= sum
- 004068C5 |. 81E1 FF000000 |AND ECX, 0xFF
- 004068CB |. 8B55 FC |MOV EDX, [LOCAL.1]
- 004068CE |. C1EA 08 |SHR EDX, 0x8 ; sum >>= 8
- 004068D1 |. 33148D C80342>|XOR EDX, DWORD PTR DS:[ECX*4+0x4203>; sum ^= CheckTable[a] (查表变换)
- 004068D8 |. 8955 FC |MOV [LOCAL.1], EDX
- 004068DB |.^ EB CB \JMP SHORT NsCrackM.004068A8
- 004068DD |> 8B45 FC MOV EAX, [LOCAL.1]
- 004068E0 |. 83F0 FF XOR EAX, 0xFFFFFFFF ; sum ^= -1
- 004068E3 |. 8BE5 MOV ESP, EBP
- 004068E5 |. 5D POP EBP
- 004068E6 \. C3 RETN
复制代码 接着来看Encode1,直接说结论,这是一个变形Base64解密的代码,变换表变了,数据组合方式也有一点改变。
假设原始数据为 A,B,C 分组后的数据为 a,b,c,d。 其中A,B,C都是8bit的数据,a,b,c,d 都是6bit的数据。那么他们的组合为
d | c | b | a
111111 111111 111111 111111
C | B | A
与标准的组合算法恰好相反。注意一下就可以了。另外,解密的DecodeTable为:
- base64: |Start Y为结束标记,解密表为 0012E4B5 ~ 0012E535 长0x80 * 2
- 0012E4B3 59 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Y...............
- 0012E4C3 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
- 0012E4D3 00 00 00 00 02 37 00 3A 00 00 00 00 0F 00 00 00 ....7.:.......
- 0012E4E3 3E 30 11 10 28 17 24 00 05 25 0A 00 00 36 3D 00 >0($.%...6=.
- 0012E4F3 00 1A 00 00 1F 07 19 1E 09 1C 2F 0C 31 29 38 00 . 32.../.1)8.
- 0012E503 00 2A 03 27 0B 00 33 12 32 00 00 21 00 2B 1B 16 .*'.32..!.+
- 0012E513 08 00 22 2D 01 34 13 18 35 00 26 14 1D 00 2C 39 ."-45.&.,9
- 0012E523 06 00 2E 04 0D 20 15 23 3C 0E 3F 3B 00 00 00 00 ... #<?;....
- 0012E533 00 00
复制代码 变换一下:
- unsigned char CodeTable[0x40] = {0};
- int i;
- for(i = 0; i < 0x80; i++) {
- CodeTable[DeCodeTable[i]] = i;
- }
复制代码 得到原始的加密表为:
- char table[] = {
- 0x36, 0x63, 0x23, 0x51, 0x72, 0x37, 0x6F, 0x44, 0x5F, 0x47, 0x39, 0x53, 0x4A, 0x73, 0x78, 0x2B,
- 0x32, 0x31, 0x56, 0x65, 0x6A, 0x75, 0x5E, 0x34, 0x66, 0x45, 0x40, 0x5D, 0x48, 0x6B, 0x46, 0x43,
- 0x74, 0x5A, 0x61, 0x76, 0x35, 0x38, 0x69, 0x52, 0x33, 0x4C, 0x50, 0x5C, 0x6D, 0x62, 0x71, 0x49,
- 0x30, 0x4B, 0x57, 0x55, 0x64, 0x67, 0x3C, 0x24, 0x4D, 0x6E, 0x26, 0x7A, 0x77, 0x3D, 0x2F, 0x79
- };
复制代码 到此,这个算法也就得到了,CM中相应的分析就不发了,因为我本身也没有做多少,知道是Base64后就直接弄出结果来了。。。
KeyGen源码见附件,相信也是不难的。要爆破的话就把上面相应的点给修改一下足以。这里在说一下程序的自校验(暗桩)。
程序在点击注册的时候会验证代码是否被修改(KMP),如果改了的话就直接退出程序。首先异常的地方在上面说过PostMessage处,哪里变成这样了。
- 0040DE5B |. 6A 00 PUSH 0x0 ; /lParam = 0x0
- 0040DE5D |. 6A 00 PUSH 0x0 ; |wParam = 0x0
- 0040DE5F |. A1 AC684200 MOV EAX, DWORD PTR DS:[0x4268AC] ; |
- 0040DE64 |. 50 PUSH EAX ; |Message => WM_CLOSE
- 0040DE65 |. 8B0D B0684200 MOV ECX, DWORD PTR DS:[0x4268B0] ; |
- 0040DE6B |. 51 PUSH ECX ; |hWnd => 0x130204
- 0040DE6C |. FF15 B0014200 CALL NEAR DWORD PTR DS:[<&USER32.Post>; \PostMessageW
复制代码 这次变成了发送WM_CLOSE消息了。。。继续的查找地址常量参考,来到赋值处
- 00401853 |. E8 E8F9FFFF CALL Crack.00401240 ; 自校验
- 00401858 |. 85C0 TEST EAX, EAX
- 0040185A 75 0A JNZ SHORT Crack.00401866
- 0040185C |. C705 AC684200>MOV DWORD PTR DS:[0x4268AC], 0x10 ; WM_CLOSE
复制代码 该怎么搞就怎么搞,call里面是使用KMP算法来验证程序段某些部分是否被修改掉了。
keygen附上,大家来指点一下吧。
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?加入我们
x
评分
-
查看全部评分
|