- UID
- 12472
注册时间2006-5-7
阅读权限20
最后登录1970-1-1
以武会友
TA的每日心情 | 开心 2016-6-17 14:50 |
---|
签到天数: 2 天 [LV.1]初来乍到
|
选自逍遥风算法精华集第2篇,自己没能力分析出来,照搬学习也是一种途径呀,就怕眼高手低。
自我安慰,呵呵!
前几天天下了逍遥兄的算法分析,把这篇跟了几次,还是有点看不明白。好不容易等到周五,终于有空了,于是有了下面的学习笔记。
OD载入后,断点非常容易找到,超级字符串查找到'GOOD JOB,MAN!'在以下处F2下断。
0040116E |. 68 FF000000 PUSH 0FF ; /Count = FF (255.)
00401173 |. 68 8C344000 PUSH CrackMe_.0040348C ; |Buffer = CrackMe_.0040348C
00401178 |. 68 EC030000 PUSH 3EC ; |ControlID = 3EC (1004.)
0040117D |. FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |hWnd
00401180 |. E8 6D020000 CALL <JMP.&user32.GetDlgItemTextA> ; \GetDlgItemTextA
00401185 |. 83F8 04 CMP EAX,4
00401188 |. 73 05 JNB SHORT CrackMe_.0040118F
0040118A |. E9 11020000 JMP CrackMe_.004013A0
0040118F |> A3 8F354000 MOV DWORD PTR DS:[40358F],EAX
00401194 |. 68 FF000000 PUSH 0FF ; /Count = FF (255.)
00401199 |. 68 93354000 PUSH CrackMe_.00403593 ; |Buffer = CrackMe_.00403593
0040119E |. 68 ED030000 PUSH 3ED ; |ControlID = 3ED (1005.)
004011A3 |. FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |hWnd
004011A6 |. E8 47020000 CALL <JMP.&user32.GetDlgItemTextA> ; \GetDlgItemTextA
004011AB |. BA 1B344000 MOV EDX,CrackMe_.0040341B ; 上面这两个CALL是取字符串长度的,结果放在EAX里
004011B0 |. 8902 MOV DWORD PTR DS:[EDX],EAX
004011B2 |. E8 49FEFFFF CALL CrackMe_.00401000 ; 初始化CRC32数据表
004011B7 |. 8D1D 1B344000 LEA EBX,DWORD PTR DS:[40341B] ; 储存注册码的位数准备进行CRC32计算
004011BD |. E8 78FEFFFF CALL CrackMe_.0040103A ; 开始对注册码的位数进行CRC32计算
004011C2 |. 3D F716602F CMP EAX,2F6016F7
004011C7 |. 0F85 D3010000 JNZ CrackMe_.004013A0
004011CD |. 6A 08 PUSH 8 ; /Length = 8
004011CF |. 68 7F344000 PUSH CrackMe_.0040347F ; |Destination = CrackMe_.0040347F
004011D4 |. E8 FB010000 CALL <JMP.&kernel32.RtlZeroMemory> ; \RtlZeroMemory
004011D9 |. 8D05 93354000 LEA EAX,DWORD PTR DS:[403593] ; 试练码存放地址403593放在[EAX]
004011DF |. 83C0 08 ADD EAX,8 ; 指向试练码第9位
004011E2 |. 8A18 MOV BL,BYTE PTR DS:[EAX] ; 使BL等于试练码的第9位
004011E4 |. 8D15 7F344000 LEA EDX,DWORD PTR DS:[40347F]
004011EA |. 881A MOV BYTE PTR DS:[EDX],BL
004011EC |. 42 INC EDX
004011ED |. 83C0 09 ADD EAX,9 ; 指向试练码的第18位,EAX原值为9
004011F0 |. 8A18 MOV BL,BYTE PTR DS:[EAX]
004011F2 |. 881A MOV BYTE PTR DS:[EDX],BL
004011F4 |. E8 07FEFFFF CALL CrackMe_.00401000
004011F9 |. 8D1D 7F344000 LEA EBX,DWORD PTR DS:[40347F] ; 注册码第9位与第18位合并在一起储存在EDX中
004011FF |. E8 36FEFFFF CALL CrackMe_.0040103A ; 注册码的第9位与第18位连接为一个整体,对整体做CRC32计算。
00401204 |. 3D 65142C24 CMP EAX,242C1465 ; 这里就知道第9和18位为什么是'-'了,呵呵
00401209 |. 0F85 91010000 JNZ CrackMe_.004013A0 ; 计算的结果等于0x242C1465?不等跳完
0040120F |. 6A 0A PUSH 0A ; /Length = A (10.)
00401211 |. 8D45 EA LEA EAX,DWORD PTR SS:[EBP-16] ; |
00401214 |. 50 PUSH EAX ; |Destination
00401215 |. E8 BA010000 CALL <JMP.&kernel32.RtlZeroMemory> ; \RtlZeroMemory
0040121A |. 6A 0A PUSH 0A ; /Length = A (10.)
0040121C |. 8D45 E0 LEA EAX,DWORD PTR SS:[EBP-20] ; |
0040121F |. 50 PUSH EAX ; |Destination
00401220 |. E8 AF010000 CALL <JMP.&kernel32.RtlZeroMemory> ; \RtlZeroMemory
00401225 |. 33C9 XOR ECX,ECX
00401227 |. 8D05 93354000 LEA EAX,DWORD PTR DS:[403593] ; 试练码
0040122D |> 8A1401 /MOV DL,BYTE PTR DS:[ECX+EAX] ; 逐位取试练码ASCII码放在EAX低位
00401230 |. 80FA 39 |CMP DL,39 ; 与0x39(对应字符9的ASCII)比较
00401233 |. 76 05 |JBE SHORT CrackMe_.0040123A ; 小于等于就跳下来,我的是第一次是0x31('1'),所以跳
00401235 |. 80FA 41 |CMP DL,41
00401238 |. 72 0A |JB SHORT CrackMe_.00401244
0040123A |> 80FA 30 |CMP DL,30 ; 与0x30(对应字符0的ASCII)比较,
0040123D |. 72 05 |JB SHORT CrackMe_.00401244 ; 小于就跳,我的第一次是'1',就不跳了
0040123F |. 80FA 46 |CMP DL,46 ; 与0x46(对应字符F的ASCII)比较
00401242 |. 76 05 |JBE SHORT CrackMe_.00401249 ; 小于等于就跳下来,我的是第一次是0x31('1'),所以跳
00401244 |> E9 57010000 |JMP CrackMe_.004013A0
00401249 |> 41 |INC ECX ; ECX计数器+1
0040124A |. 83F9 08 |CMP ECX,8 ; 取注册码的前8位(注册码第一部分)
0040124D |.^ 75 DE \JNZ SHORT CrackMe_.0040122D ; 上面两句实现了只对试练码的前8位比较
0040124F |. 33C9 XOR ECX,ECX
00401251 |. 33DB XOR EBX,EBX
00401253 |. 8D75 EA LEA ESI,DWORD PTR SS:[EBP-16]
00401256 |> C1E3 04 /SHL EBX,4 ; 左移4位,相当于乘10
00401259 |. 8A1401 |MOV DL,BYTE PTR DS:[ECX+EAX] ; 逐位取注册码第一部分(即前8位)
0040125C |. 8816 |MOV BYTE PTR DS:[ESI],DL
0040125E |. 80FA 41 |CMP DL,41 ; 与0x41(对应字符A的ASCII)比较,
00401261 |. 72 0A |JB SHORT CrackMe_.0040126D ; 小于就跳,我的第一位是0x31,就跳了
00401263 |. 80FA 46 |CMP DL,46
00401266 |. 77 05 |JA SHORT CrackMe_.0040126D
00401268 |. 80EA 37 |SUB DL,37
0040126B |. EB 03 |JMP SHORT CrackMe_.00401270
0040126D |> 80EA 30 |SUB DL,30
00401270 |> 80E2 0F |AND DL,0F
00401273 |. 0ADA |OR BL,DL
00401275 |. 46 |INC ESI
00401276 |. 41 |INC ECX
00401277 |. 83F9 08 |CMP ECX,8 ; 这两句好眼熟,与前一循环作用相同,呵呵
0040127A |. 895D FC |MOV DWORD PTR SS:[EBP-4],EBX
0040127D |.^ 75 D7 \JNZ SHORT CrackMe_.00401256 ; 将注册码的第一部分转换成对应的16进制
0040127F |. E8 7CFDFFFF CALL CrackMe_.00401000 ; 运行到这里时可以看到EBX是转为16进制的前8位试练码
00401284 |. 8D1D 8C344000 LEA EBX,DWORD PTR DS:[40348C] ; 用户名的存放地址[40348C]放在EBX
0040128A |. E8 ABFDFFFF CALL CrackMe_.0040103A ; 开始对用户名作CRC32计算
0040128F |. 3945 FC CMP DWORD PTR SS:[EBP-4],EAX ; 对用户名CRC32计算的结果与试练码的前8位比较,不等就跳完
00401292 0F85 08010000 JNZ CrackMe_.004013A0 ; 真码第一部分就是CRC32(用户名)。我的用户名是agang,CRC32后是A53C759F
00401298 |. 33C9 XOR ECX,ECX
0040129A |. 8D05 93354000 LEA EAX,DWORD PTR DS:[403593] ; 试练码又呼出来,准备第二部分的计算了
004012A0 |. 83C0 09 ADD EAX,9
004012A3 |> 8A1401 /MOV DL,BYTE PTR DS:[ECX+EAX] ; 从这里开始。。。
004012A6 |. 80FA 39 |CMP DL,39
004012A9 |. 76 05 |JBE SHORT CrackMe_.004012B0
004012AB |. 80FA 41 |CMP DL,41
004012AE |. 72 0A |JB SHORT CrackMe_.004012BA
004012B0 |> 80FA 30 |CMP DL,30
004012B3 |. 72 05 |JB SHORT CrackMe_.004012BA
004012B5 |. 80FA 46 |CMP DL,46
004012B8 |. 76 05 |JBE SHORT CrackMe_.004012BF
004012BA |> E9 E1000000 |JMP CrackMe_.004013A0
004012BF |> 41 |INC ECX
004012C0 |. 83F9 08 |CMP ECX,8
004012C3 |.^ 75 DE \JNZ SHORT CrackMe_.004012A3
004012C5 |. 33C9 XOR ECX,ECX ; 逍遥兄称上述循环为'格式检验',说得够精练的,我等菜菜要慢慢分析才能看出来
004012C7 |. 33DB XOR EBX,EBX
004012C9 |. 8D75 E0 LEA ESI,DWORD PTR SS:[EBP-20]
004012CC |> C1E3 04 /SHL EBX,4
004012CF |. 8A1401 |MOV DL,BYTE PTR DS:[ECX+EAX]
004012D2 |. 8816 |MOV BYTE PTR DS:[ESI],DL
004012D4 |. 8810 |MOV BYTE PTR DS:[EAX],DL
004012D6 |. 80FA 41 |CMP DL,41
004012D9 |. 72 0A |JB SHORT CrackMe_.004012E5
004012DB |. 80FA 46 |CMP DL,46
004012DE |. 77 05 |JA SHORT CrackMe_.004012E5
004012E0 |. 80EA 37 |SUB DL,37
004012E3 |. EB 03 |JMP SHORT CrackMe_.004012E8
004012E5 |> 80EA 30 |SUB DL,30
004012E8 |> 80E2 0F |AND DL,0F
004012EB |. 0ADA |OR BL,DL
004012ED |. 46 |INC ESI
004012EE |. 41 |INC ECX
004012EF |. 83F9 08 |CMP ECX,8
004012F2 |. 895D F8 |MOV DWORD PTR SS:[EBP-8],EBX
004012F5 |.^ 75 D5 \JNZ SHORT CrackMe_.004012CC ; 以上循环将试练第二部分转为16进制,记为S1吧
004012F7 |. E8 04FDFFFF CALL CrackMe_.00401000 ; 初始化CRC32数据表
004012FC |. 8D5D EA LEA EBX,DWORD PTR SS:[EBP-16] ; 取出试练码前8位
004012FF |. E8 36FDFFFF CALL CrackMe_.0040103A ; 对注册码的前8位进行CRC32计算
00401304 |. 3945 F8 CMP DWORD PTR SS:[EBP-8],EAX ; S1与CRC32(CRC32(agang))[也就是真码第一部分的CRC32结果]比较,
00401307 |. 0F85 93000000 JNZ CrackMe_.004013A0 ; 注册码的第一部分CRC32计算后的值即为注册码的第2部分
0040130D |. E8 EEFCFFFF CALL CrackMe_.00401000 ; 又是初始化CRC32数据表
00401312 |. 8D5D E0 LEA EBX,DWORD PTR SS:[EBP-20] ; 取真码的第二部分,就是刚刚算出来那个。我的是39944E09
00401315 |. E8 20FDFFFF CALL CrackMe_.0040103A ; 对其再进行CRC32计算,我这里的结果是AD14BD73
0040131A |. 8945 F8 MOV DWORD PTR SS:[EBP-8],EAX
0040131D |. 33C9 XOR ECX,ECX
0040131F |. 8D05 93354000 LEA EAX,DWORD PTR DS:[403593]
00401325 |. 83C0 12 ADD EAX,12 ; 从试练码的第19位开始取值(取注册码的第3部分)
00401328 |> 8A1401 /MOV DL,BYTE PTR DS:[ECX+EAX]
0040132B |. 80FA 39 |CMP DL,39
0040132E |. 76 05 |JBE SHORT CrackMe_.00401335
00401330 |. 80FA 41 |CMP DL,41
00401333 |. 72 0A |JB SHORT CrackMe_.0040133F
00401335 |> 80FA 30 |CMP DL,30
00401338 |. 72 05 |JB SHORT CrackMe_.0040133F
0040133A |. 80FA 46 |CMP DL,46
0040133D |. 76 02 |JBE SHORT CrackMe_.00401341
0040133F |> EB 5F |JMP SHORT CrackMe_.004013A0
00401341 |> 41 |INC ECX
00401342 |. 83F9 08 |CMP ECX,8
00401345 |.^ 75 E1 \JNZ SHORT CrackMe_.00401328 ; 格式验证,再多说也没意义了,呵呵
00401347 |. 33C9 XOR ECX,ECX
00401349 |. 33DB XOR EBX,EBX
0040134B |> C1E3 04 /SHL EBX,4
0040134E |. 8A1401 |MOV DL,BYTE PTR DS:[ECX+EAX]
00401351 |. 8810 |MOV BYTE PTR DS:[EAX],DL
00401353 |. 80FA 41 |CMP DL,41
00401356 |. 72 0A |JB SHORT CrackMe_.00401362
00401358 |. 80FA 46 |CMP DL,46
0040135B |. 77 05 |JA SHORT CrackMe_.00401362
0040135D |. 80EA 37 |SUB DL,37
00401360 |. EB 03 |JMP SHORT CrackMe_.00401365
00401362 |> 80EA 30 |SUB DL,30
00401365 |> 80E2 0F |AND DL,0F
00401368 |. 0ADA |OR BL,DL
0040136A |. 41 |INC ECX
0040136B |. 83F9 08 |CMP ECX,8
0040136E |. 895D F4 |MOV DWORD PTR SS:[EBP-C],EBX
00401371 |.^ 75 D8 \JNZ SHORT CrackMe_.0040134B ; 转为16进制
00401373 |. 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4] ; [EBP-4]里是A53C759F
00401376 |. 3345 F8 XOR EAX,DWORD PTR SS:[EBP-8] ; [EBP-8]是真码第二部分再作CRC32计算的结果,与A53C759F异或
00401379 |. 3B45 F4 CMP EAX,DWORD PTR SS:[EBP-C] ; 我这里的结果是0828C8EC,[EBP-C]存的是试练码第三部分,两者比较
0040137C 75 22 JNZ SHORT CrackMe_.004013A0
0040137E |. 68 D2204000 PUSH CrackMe_.004020D2 ; /good job, man!
00401383 |. FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |hWnd
00401386 |. E8 8B000000 CALL <JMP.&user32.SetWindowTextA> ; \SetWindowTextA
0040138B |. 68 EE030000 PUSH 3EE ; /ControlID = 3EE (1006.)
00401390 |. FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |hWnd
00401393 |. E8 54000000 CALL <JMP.&user32.GetDlgItem> ; \GetDlgItem
00401398 |. 6A 00 PUSH 0 ; /Enable = FALSE
0040139A |. 50 PUSH EAX ; |hWnd
0040139B |. E8 40000000 CALL <JMP.&user32.EnableWindow> ; \EnableWindow
004013A0 |> 33C0 XOR EAX,EAX
--------------------逍遥兄的算法总结-------------------
1)注册码必须为26位,第9位与第18位必须是:-
注册码的形式为12345678-01234567-90123456
2)将注册名进行CRC32计算,将注册码的第1部分转换成对应的16进制。两个值必须相等
3)将注册码的第1部分进行CRC32计算(设为A),将注册码的第2部分转换成对应的16进制。两个值必须相等
4)将注册码的第2部分进行CRC32计算(设为B)。
5)将A,B做XOR运算,将注册码的第3部分转换成对应的16进制。两个值必须相等
即。注册码
第一部分:CRC(注册名)
第二部分:CRC(注册码第一部分)
第三部分:XOR [ 第一部分,CRC(第二部分)]
------------------------------------------------------------
我的试练信息说明
用户名:agang
试练码:12345678-abcdefgh-98765432
真 码:A53C759F-39944E09-0828C8EC
此CRACKME分三部分对注册码检验,建议采用逐步替换的方式进行调试。
即:用户名:agang,
注册码这样逐步替换:
第一次:12345678-abcdefgh-98765432;
第二次:A53C759F-abcdefgh-98765432
第三次:A53C759F-39944E09-98765432
第四次:A53C759F-39944E09-0828C8EC
这样可以清晰的看到逍遥兄算法分析的结果,
第一部分:CRC(注册名)------------------------我的是CRC32(agang),结果是A53C759F(真码的第一部分)
第二部分:CRC(注册码第一部分)-----------------我的是CRC32(A53C759F),结果是39944E09(真码的第二部分)
第三部分:XOR [ 第一部分,CRC(第二部分)]----我的是XOR(A53C759F,CRC32(39944E09)),结果是0828C8EC(真码的第三部分)
最后有两个地方想说一下:
1、连接符'-'的穷举法问题。
此crackme的第9位和第18位均要求是'-',其中在
004011F9 |. 8D1D 7F344000 LEA EBX,DWORD PTR DS:[40347F];处,
把注册码第9位与第18位作为一个整体,也就是'--',再对它进行CRC32计算。
这里我在想,当我们只有CRC32结果,要对其逆推并穷举出原字符串是多大的工程啊?
逍遥兄是不是应用了社会工程学原理呀?
要不就是爆CRC32原码的专用工具(像MD5爆破一样)?如果是,请兄弟们不要金屋藏娇了,拿出来大家共享下吧,在下先谢过了。。。
2、提示成功窗口的问题。
我按照逍遥兄的分析,得出自己的正确注册码并载入OD。当第三部分验证结束后,我以为会弹出提示成功的窗口信息,所以一直F8,就等着听响[XP的系统声音],过了好久,仍不见动静,反而又跳到不知道是什么地方。我以为是我的注册码不对,遂关掉OD,直接运行软件注册。
这才明白了,原来我们在OD中超级字符串找到的'GOOD JOB, MAN!'并不是提示窗口,而是标题栏的信息。也就是说注册成功后,软件会把标题栏原来的信息'Coded by [HappyTown]'改成为'GOOD JOB ,MAN!',并且设置Check按钮不可用。
这里我想说的是,Crackme作者HappyTown兄弟的思路,非常适合应用到实际。防止我等菜鸟上来就是窗口拦截断点打到入手处。如果字符再加密,恐怕我等菜辈下断都成问题了。必竟我等菜菜还是占多数嘛!呵呵
agang好啰嗦,谢谢兄弟能坚持看这里。 |
|