学习逍遥风对HappyTown兄弟的crackme_13(CRC32)的算法分析,超菜级笔记
选自逍遥风算法精华集第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: ; |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:,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: ; |hWnd
004011A6|.E8 47020000 CALL <JMP.&user32.GetDlgItemTextA> ; \GetDlgItemTextA
004011AB|.BA 1B344000 MOV EDX,CrackMe_.0040341B ;上面这两个CALL是取字符串长度的,结果放在EAX里
004011B0|.8902 MOV DWORD PTR DS:,EAX
004011B2|.E8 49FEFFFF CALL CrackMe_.00401000 ;初始化CRC32数据表
004011B7|.8D1D 1B344000 LEA EBX,DWORD PTR DS: ;储存注册码的位数准备进行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放在
004011DF|.83C0 08 ADD EAX,8 ;指向试练码第9位
004011E2|.8A18 MOV BL,BYTE PTR DS: ;使BL等于试练码的第9位
004011E4|.8D15 7F344000 LEA EDX,DWORD PTR DS:
004011EA|.881A MOV BYTE PTR DS:,BL
004011EC|.42 INC EDX
004011ED|.83C0 09 ADD EAX,9 ;指向试练码的第18位,EAX原值为9
004011F0|.8A18 MOV BL,BYTE PTR DS:
004011F2|.881A MOV BYTE PTR DS:,BL
004011F4|.E8 07FEFFFF CALL CrackMe_.00401000
004011F9|.8D1D 7F344000 LEA EBX,DWORD PTR DS: ;注册码第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: ; |
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: ; |
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: ;试练码
0040122D|>8A1401 /MOV DL,BYTE PTR DS: ;逐位取试练码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:
00401256|>C1E3 04 /SHL EBX,4 ;左移4位,相当于乘10
00401259|.8A1401 |MOV DL,BYTE PTR DS: ;逐位取注册码第一部分(即前8位)
0040125C|.8816 |MOV BYTE PTR DS:,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:,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: ;用户名的存放地址放在EBX
0040128A|.E8 ABFDFFFF CALL CrackMe_.0040103A ;开始对用户名作CRC32计算
0040128F|.3945 FC CMP DWORD PTR SS:,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: ;试练码又呼出来,准备第二部分的计算了
004012A0|.83C0 09 ADD EAX,9
004012A3|>8A1401 /MOV DL,BYTE PTR DS: ;从这里开始。。。
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:
004012CC|>C1E3 04 /SHL EBX,4
004012CF|.8A1401 |MOV DL,BYTE PTR DS:
004012D2|.8816 |MOV BYTE PTR DS:,DL
004012D4|.8810 |MOV BYTE PTR DS:,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:,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: ;取出试练码前8位
004012FF|.E8 36FDFFFF CALL CrackMe_.0040103A ;对注册码的前8位进行CRC32计算
00401304|.3945 F8 CMP DWORD PTR SS:,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: ;取真码的第二部分,就是刚刚算出来那个。我的是39944E09
00401315|.E8 20FDFFFF CALL CrackMe_.0040103A ;对其再进行CRC32计算,我这里的结果是AD14BD73
0040131A|.8945 F8 MOV DWORD PTR SS:,EAX
0040131D|.33C9 XOR ECX,ECX
0040131F|.8D05 93354000 LEA EAX,DWORD PTR DS:
00401325|.83C0 12 ADD EAX,12 ;从试练码的第19位开始取值(取注册码的第3部分)
00401328|>8A1401 /MOV DL,BYTE PTR DS:
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:
00401351|.8810 |MOV BYTE PTR DS:,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:,EBX
00401371|.^ 75 D8 \JNZ SHORT CrackMe_.0040134B ;转为16进制
00401373|.8B45 FC MOV EAX,DWORD PTR SS: ;里是A53C759F
00401376|.3345 F8 XOR EAX,DWORD PTR SS: ;是真码第二部分再作CRC32计算的结果,与A53C759F异或
00401379|.3B45 F4 CMP EAX,DWORD PTR SS: ;我这里的结果是0828C8EC,存的是试练码第三部分,两者比较
0040137C 75 22 JNZ SHORT CrackMe_.004013A0
0040137E|.68 D2204000 PUSH CrackMe_.004020D2 ; /good job, man!
00401383|.FF75 08 PUSH DWORD PTR SS: ; |hWnd
00401386|.E8 8B000000 CALL <JMP.&user32.SetWindowTextA> ; \SetWindowTextA
0040138B|.68 EE030000 PUSH 3EE ; /ControlID = 3EE (1006.)
00401390|.FF75 08 PUSH DWORD PTR SS: ; |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:;处,
把注册码第9位与第18位作为一个整体,也就是'--',再对它进行CRC32计算。
这里我在想,当我们只有CRC32结果,要对其逆推并穷举出原字符串是多大的工程啊?
逍遥兄是不是应用了社会工程学原理呀?
要不就是爆CRC32原码的专用工具(像MD5爆破一样)?如果是,请兄弟们不要金屋藏娇了,拿出来大家共享下吧,在下先谢过了。。。
2、提示成功窗口的问题。
我按照逍遥兄的分析,得出自己的正确注册码并载入OD。当第三部分验证结束后,我以为会弹出提示成功的窗口信息,所以一直F8,就等着听响,过了好久,仍不见动静,反而又跳到不知道是什么地方。我以为是我的注册码不对,遂关掉OD,直接运行软件注册。
这才明白了,原来我们在OD中超级字符串找到的'GOOD JOB, MAN!'并不是提示窗口,而是标题栏的信息。也就是说注册成功后,软件会把标题栏原来的信息'Coded by '改成为'GOOD JOB ,MAN!',并且设置Check按钮不可用。
这里我想说的是,Crackme作者HappyTown兄弟的思路,非常适合应用到实际。防止我等菜鸟上来就是窗口拦截断点打到入手处。如果字符再加密,恐怕我等菜辈下断都成问题了。必竟我等菜菜还是占多数嘛!呵呵
agang好啰嗦,谢谢兄弟能坚持看这里。 好文,学习了/:D!!! 兄弟所讲的凭经验,道上也叫社会工程学,呵呵
作者都说了是CRC32,其结果是8位,共分三组比较,再加两个连接符,这也是经验吧, /:D 学习,社会工程学,呵呵~~穷举可是个工程了 agang好像是黑道高手!:lol: :lol:
无意中见过! 看的不是很懂,,,,我不会算法的哦,,,呵呵。。。。努力中 加密算法
........ 好呀,很详细! 学习一下,共同进步:handshake 属于自己的时间越来越少了,每天睁眼忙到现在才有空触网,急得要死.
TO书生兄弟:你在PYG讲话很有影响力的,在PYG我是密界菜菜,其余的暂且不谈.哈哈
页:
[1]
2