先开计算机的先河了-----我的ASM CrackMe分析(PEDIY200帖留念)
noname剑人2008/07/23软件综合 IP:北京
呵呵,在UNPACKCN和PEDIY上发过,路过的朋友别打我...

我的ASM CrackMe分析(PEDIY200帖留念) [分析+源码](详解!新手看)
【文章标题】: 我的ASM CrackMe分析(200帖留念) [分析+源码](超详解!新手必看)
【文章作者】: NONAME剑人
【作者邮箱】: wangjunyi2008@XXXXXXXX
【作者主页】: ....Have No....
【作者QQ号】: 464252600(验证:你目前的论坛名(看雪或Unpackcn))
【下载地址】: 自己搜索下载
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
  呵呵,好久没写破文了,最近也颓废了一下,终于决心把我自己做的CrackMe的流程给说说了……
  (别砸我,我写破文的时候没看源码)
  
  这个CrackMe难度好象不太高,难道是没人品吗:)HEHE
  (我还是别开玩笑了,发现越是大大的大牛,越没幽默感,到时候太过于幽默了没法混了就不好了:) )
  
  ……,我将在破文的过程中用反汇编,最后给大家汇编代码,可以参考一下,再最后给大家VB的注册机。。。
  (我这性格就是古怪,各位看管别介意:) )
  
  好,废话少说,PEiD加载,ACProtect V1.4X -> risco *。HEHE,那是因为我伪装了文件头,用了一个花
  
  00401000 > $  60            PUSHAD
  00401001   .  E8 01000000   CALL CrackMe1.00401007                   //跳到4010007
  00401006      7C            DB 7C                                      CHAR '|'
  00401007   .  830424 06     ADD DWORD PTR SS:[ESP],6                 //改变堆栈,使返回时到下一条指令
  0040100B   .  C3            RETN
  
  如果你喜欢F8的话,中招了……
  
  (不过这个花指令会“吃”掉一条堆栈中的数据……)
  
  由于是汇编,比较好看,往下拉就能看到领空了。
  
  0040111D   .  68 00020000   PUSH 200                                 ; /Count = 200 (512.)
  00401122   .  68 B4304000   PUSH CrackMe1.004030B4                   ; |Buffer = CrackMe1.004030B4
  00401127   .  68 B80B0000   PUSH 0BB8                                 |ControlID = BB8 (3000.)
  0040112C   .  FF75 08       PUSH DWORD PTR SS:[EBP+8]                 |hWnd
  0040112F   .  E8 24050000   CALL <JMP.&XXXXXXXXXtDlgItemTextA>       ; \GetDlgItemTextA
  00401134   .  50            PUSH EAX                                 //用户名堆2次
  00401135   .  50            PUSH EAX
  00401136   .  68 00020000   PUSH 200                                 ; /Count = 200 (512.)
  0040113B   .  68 B4324000   PUSH CrackMe1.004032B4                   ; |Buffer = CrackMe1.004032B4
  00401140   .  6A 03         PUSH 3                                   ; |ControlID = 3
  00401142   .  FF75 08       PUSH DWORD PTR SS:[EBP+8]                 |hWnd
  00401145   .  E8 0E050000   CALL <JMP.&XXXXXXXXXtDlgItemTextA>       ; \GetDlgItemTextA
  0040114A   .  50            PUSH EAX                                 //密码堆两次
  0040114B   .  50            PUSH EAX
  
  好象没什么太大的动作,继续!
  
  0040114C   .  6A 00         PUSH 0                                   ; /pModule = NULL
  0040114E   .  E8 2F050000   CALL <JMP.&XXXXXXXXXXXtModuleHandleA>     \GetModuleHandleA
  
  怎么到这用GETMODULE?下看
  
  00401153   .  05 00100000   ADD EAX,1000                             //原来是得到OEP(401000)
  00401158   .  50            PUSH EAX                                 //PUSH OEP*2
  00401159   .  50            PUSH EAX
  0040115A   .  54            PUSH ESP                                 ; /pOldProtect
  0040115B   .  6A 40         PUSH 40                                   |NewProtect = PAGE_EXECUTE_READWRITE
  0040115D   .  68 00100000   PUSH 1000                                 |Size = 1000 (4096.)
  00401162   .  50            PUSH EAX                                 ; |Address
  00401163   .  E8 26050000   CALL <JMP.&XXXXXXXXXXXrtualProtect>       \VirtualProtect
  
  利用虚拟内存API改变内存页属性,使该段代码可读
  至此,你的堆栈应该是这样了
  ===========================
  0013FB90   00000020  VirtualProtect私M一个……
  0013FB94   00401000  CrackMe1.<模块入口点>
  0013FB98   00000003  密码长
  0013FB9C   00000003  密码长
  0013FBA0   00000003  用户名长
  0013FBA4   00000003  用户名产
  ===========================
  
  00401168   .  EB 5B         JMP SHORT CrackMe1.004011C5
  
  走!
  
  004011C5   > \B8 6A114000   MOV EAX,CrackMe1.0040116A
  004011CA   .  B9 C4114000   MOV ECX,CrackMe1.004011C4
  004011CF   .  2BC8          SUB ECX,EAX
  004011D1   .  8BD1          MOV EDX,ECX
  004011D3   >  B8 6A114000   MOV EAX,CrackMe1.0040116A
  004011D8   .  03C2          ADD EAX,EDX
  004011DA   .  2BC1          SUB EAX,ECX
  004011DC   .  8BF0          MOV ESI,EAX
  004011DE   .  8B06          MOV EAX,DWORD PTR DS:[ESI]
  004011E0   .  40            INC EAX
  004011E1   .  8906          MOV DWORD PTR DS:[ESI],EAX
  004011E3   .^ E2 EE         LOOPD SHORT CrackMe1.004011D3
  
  看到这段,你想到了什么?
  
  我们先来看看40116a是什么......
  
  0040116A   .  AF            SCAS DWORD PTR ES:[EDI]
  0040116B   .  C3            RETN
  0040116C   .  BD B6B6D3C0   MOV EBP,C0D3B6B6
  00401171   .  BA AE9FB5C1   MOV EDX,C1B59FAE
  00401176   .  BC D3BDB6C0   MOV ESP,C0B6BDD3
  0040117B   .  F600 05       TEST BYTE PTR DS:[EAX],5
  0040117E   .  AF            SCAS DWORD PTR ES:[EDI]
  0040117F   .  C3            RETN
  00401180   .  C3            RETN
  00401181      B6            DB B6
  00401182      C1            DB C1
  
  再看看4011c4呢……
  004011BD   .  A5            MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ES>
  004011BE   .  AC            LODS BYTE PTR DS:[ESI]
  004011BF   .  A5            MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ES>
  004011C0   .  C2 C4B0       RETN 0B0C4
  004011C3      AE            DB AE
  004011C4      00            DB 00
  
  毫无规律,继续往下看
  
  004011C5   > \B8 6A114000   MOV EAX,CrackMe1.0040116A
  004011CA   .  B9 C4114000   MOV ECX,CrackMe1.004011C4
  
  004011CF   .  2BC8          SUB ECX,EAX                    
  这是什么?毫无疑问,应该是40116A-->(4011C4-1)之间的个数
  
  004011D1   .  8BD1          MOV EDX,ECX
  我们暂时不知道EDX以后干什么,目前只知道他是个数-1
  
  该这个循环了
  004011D3   > /B8 6A114000   MOV EAX,CrackMe1.0040116A
  004011D8   . |03C2          ADD EAX,EDX
  004011DA   . |2BC1          SUB EAX,ECX
  004011DC   . |8BF0          MOV ESI,EAX
  004011DE   . |8B06          MOV EAX,DWORD PTR DS:[ESI]
  004011E0   . |40            INC EAX
  004011E1   . |8906          MOV DWORD PTR DS:[ESI],EAX
  004011E3   .^\E2 EE         LOOPD SHORT CrackMe1.004011D3
  
  咱们一点一点看
  
  004011D3   > /B8 6A114000   MOV EAX,CrackMe1.0040116A
  为什么把40116A递到EAX里呢?
  他也不能执行……
  
  004011D8   .  03C2          ADD EAX,EDX
  EAX=EAX+位数-1
  
  这个位数-1不大好理解,其实就是40116a到4011c3的个数
  (因为EDX=ECX=4011C4-1,简称个数-1,这里的“个数”是指跳过的字节数)
  
  004011DA   .  2BC1          SUB EAX,ECX
  EAX=EAX-循环指针
  
  看到这里你应该能猜到了——这是个SMC
  为什么呢?
  因为到目前为止,EAX=基地址(40116A)+总个数-1(EDX)-循环指针(ECX)
  
  怎么说呢,理解理解吧:)
  
  下面就好办了
  
  004011DC   .  8BF0          MOV ESI,EAX
  
  因为EAX没法直接框起来,要不编译器会报错,所以就存到ESI了
  
  004011DE   .  8B06          MOV EAX,DWORD PTR DS:[ESI]
  
  把ESI(即EAX)里的地址取出来,存入EAX
  
  004011E0   .  40            INC EAX
  
  EAX=EAX+1
  这里就是SMC的一个解密
  
  004011E1   .  8906          MOV DWORD PTR DS:[ESI],EAX
  
  不用说了吧,存回去
  
  004011E3   .^\E2 EE         LOOPD SHORT CrackMe1.004011D3
  
  注意这里:ECX是默认-1的!
  
  到此,一个SMC就已经解完了
  注意!解完了以后OD有个BUG,就是鼠标不听使唤,这是CTRL+A就可以了
  
  很好,但是上面的命令还是很古怪,有两种可能
  第1种是 多层SMC
  第2种是 数据
  
  第1种暂时无法判断,看第2种吧:)
  
  下命令 D 40116A
  
  0040116A  B0 C4 BE B7 B7 D4 C1 BB AF A0 B6 C2 BD D4 BE B7  澳痉吩粱癄堵皆痉
  0040117A  C1 F7 01 06 B0 C4 C4 B7 C2 D2 D8 B9 AF A0 B6 C2  流澳姆乱毓癄堵
  0040118A  BD D4 DC F7 C6 C8 01 06 B1 FD C4 D9 DA DA DA DA  皆荀迫饼馁谮谮
  0040119A  AF A0 C7 CA C7 A2 C2 D2 B6 D7 01 06 B1 FD C3 AA  癄鞘洽乱蹲饼锚
  004011AA  CF FB C3 AA AF A0 B2 F1 DE DD C8 BC CE BB 01 06  消锚癄柴掭燃位
  004011BA  2C 2C AD A6 AD A6 C3 C5 B1 AF 00                 ,,??门悲.竕@.
  
  什么玩意?八成是2层的smc……
  
  不管,咱们继续
  004011E5   .  B8 6A114000   MOV EAX,CrackMe1.0040116A
  004011EA   .  B9 C4114000   MOV ECX,CrackMe1.004011C4
  004011EF   .  2BC8          SUB ECX,EAX
  004011F1   .  8BD1          MOV EDX,ECX
  004011F3   >  B8 6A114000   MOV EAX,CrackMe1.0040116A
  004011F8   .  03C2          ADD EAX,EDX
  004011FA   .  2BC1          SUB EAX,ECX
  004011FC   .  8BF0          MOV ESI,EAX
  004011FE   .  8B06          MOV EAX,DWORD PTR DS:[ESI]
  00401200   .  83F0 0C       XOR EAX,0C                         //***************
  00401203   .  8906          MOV DWORD PTR DS:[ESI],EAX
  00401205   .^ E2 EC         LOOPD SHORT CrackMe1.004011F3
  
  果然说曹操,曹操到。感觉到很熟悉没?这里我就不多说了,唯一要注意的是这个SMC的算法是XOR EAX,0C
  而刚才的是INC EAX
  
  不再多说,F4到401207,下断点D 40116A
  0040116A  BC C8 B2 BB BB D8 CD B7 A3 AC BA CE B1 D8 B2 BB  既不回头,何必不
  0040117A  CD FB 0D 0A BC C8 C8 BB CE DE D4 B5 A3 AC BA CE  望..既然无缘,何
  0040118A  B1 D8 D0 FB CA C4 0D 0A BD F1 C8 D5 D6 D6 D6 D6  必宣誓..今日种种
  0040119A  A3 AC CB C6 CB AE CE DE BA DB 0D 0A BD F1 CF A6  ,似水无痕..今夕
  004011AA  C3 F7 CF A6 A3 AC BE FD D2 D1 C4 B0 C2 B7 0D 0A  明夕,君已陌路..
  004011BA  20 20 A1 AA A1 AA CF C9 BD A3 00                   ——仙剑.竕@.
  
  很好,很标准的字符串
  
  但是不知道大家发现没有,为什么之前要位数-1呢?
  
  你可以重新回过头来看,2次SMC中始终不会对最后一位4011C4的00进行操作
  这是因为LOOPD的特性,相当于高级语言中的FOR,只不过像UNTIL一样放在了尾段,所以当ECX=0时
  就不再执行了
  
  另外你应该明白前面为什么要VIRTUALPROTECT了吧:)
  
  向下看
  00401207   .  68 9C304000   PUSH CrackMe1.0040309C                   ; /pLocaltime = CrackMe1.0040309C
  0040120C   .  E8 6B040000   CALL <JMP.&XXXXXXXXXXXtLocalTime>         \GetLocalTime
  
  40309C指向的应该是一个时间结构,不管。但为什么注册程序中会出现时间的东西呢?
  时间有随机性,你总不能让用户把什么时间注册告诉你吧……
  呵呵,所以只可能是ANTI了
  
  我们不管他,以后会碰上,咱们继续……
  
  查查M$的API大全就知道,这是读秒……
  
  0040121A   .  50            PUSH EAX
  0040121B   .  8BF8          MOV EDI,EAX                                CrackMe1.004001E4
  0040121D   .  58            POP EAX
  
  混淆视线,在逆向中一定要有毅力:)
  不过第2句很蹊跷,咱先记住EDI是第一次的秒数……
  
  0040121E   .  58            POP EAX
  0040121F   .  5E            POP ESI
  
  清除GetLocalTime产生的堆栈垃圾:)
  
  来看看这个
  
  0040122A   > /51            PUSH ECX
  0040122B   . |68 9C304000   PUSH CrackMe1.0040309C                   ; /pLocaltime = CrackMe1.0040309C
  00401230   . |E8 47040000   CALL <JMP.&XXXXXXXXXXXtLocalTime>         \GetLocalTime
  00401235   . |8BD1          MOV EDX,ECX
  00401237   . |59            POP ECX
  00401238   . |BE 9C304000   MOV ESI,CrackMe1.0040309C
  0040123D   . |66:8B46 0E    MOV AX,WORD PTR DS:[ESI+E]
  00401241   . |50            PUSH EAX
  00401242   . |58            POP EAX
  00401243   . |BE 04104000   MOV ESI,CrackMe1.00401004
  00401248   . |890E          MOV DWORD PTR DS:[ESI],ECX
  0040124A   .^\E2 DE         LOOPD SHORT CrackMe1.0040122A
  
  呵呵,实际上只有最后一层的循环管用。第2次读取时间……
  
  如果你很仔细的话,应该能发现……
  0040123D   .  66:8B46 0E    MOV AX,WORD PTR DS:[ESI+E]
  
  最后一次秒数根本没动,一直保存在AX中
  
  0040124C   .  3BF8          CMP EDI,EAX                                CrackMe1.0040035B
  
  比较两次的时间……正常肯定是1秒,非正常那就没准了
  
  0040124E   . /74 05         JE SHORT CrackMe1.00401255
  00401250   . |BF 01000000   MOV EDI,1
  00401255   > \3BF8          CMP EDI,EAX
  
  这里如果EDI=1你就=死吧,咱们走这条路,看看怎么死的
  
  00401257   . /75 05         JNZ SHORT CrackMe1.0040125E
  00401259   . |BF 02000000   MOV EDI,2
  0040125E   > \B8 18104000   MOV EAX,CrackMe1.00401018
  
  很显然,如果两次的秒数是一样的,EDI=2,你可以继续!
  
  这里有个防止爆破的地方,就是如果你只改第一次的MOV EDI,1的JE的话,
  你的EDI会既不是1也不是2,这样你还是得死:)
  
  00401263   .  B9 0E104000   MOV ECX,CrackMe1.0040100E
  00401268   .  83E9 01       SUB ECX,1
  0040126B   .  33DB          XOR EBX,EBX
  0040126D   >  41            INC ECX
  0040126E   .  8BF1          MOV ESI,ECX
  00401270   .  8B06          MOV EAX,DWORD PTR DS:[ESI]
  00401272   .  3BC8          CMP ECX,EAX
  00401274   .^ 72 F7         JB SHORT CrackMe1.0040126D
  
  呵呵,这里怎么那么像上面的SMC啊?
  别着急,咱们仔细看
  
  00401263   .  B9 0E104000   MOV ECX,CrackMe1.0040100E
  怎么SMC到执行语句上了?
  咱么CTRL+G看看40100E
  
  0040100C   . /EB 0A         JMP SHORT CrackMe1.00401018
  0040100E     |90            NOP
  0040100F     |90            NOP
  00401010     |90            NOP
  00401011     |90            NOP
  00401012     |90            NOP
  00401013     |90            NOP
  00401014     |90            NOP
  00401015     |90            NOP
  00401016     |90            NOP
  00401017     |90            NOP
  00401018   > \6A 00         PUSH 0                                   ; /pModule = NULL
  0040101A   .  E8 63060000   CALL <JMP.&XXXXXXXXXXXtModuleHandleA>     \GetModuleHandleA
  0040101F   .  A3 AC304000   MOV DWORD PTR DS:[4030AC],EAX
  00401024   .  6A 00         PUSH 0                                   ; /lParam = NULL
  00401026   .  68 43104000   PUSH CrackMe1.00401043                   ; |DlgProc = CrackMe1.00401043
  0040102B   .  6A 00         PUSH 0                                   ; |hOwner = NULL
  0040102D   .  68 00304000   PUSH CrackMe1.00403000                   ; |pTemplate = "IsDebugPresent"
  00401032   .  FF35 AC304000 PUSH DWORD PTR DS:[4030AC]               ; |hInst = 00400000
  00401038   .  E8 09060000   CALL <JMP.&user32.DialogBoxParamA>       ; \DialogBoxParamA
  0040103D   .  50            PUSH EAX                                 ; /ExitCode
  0040103E   .  E8 33060000   CALL <JMP.&kernel32.ExitProcess>         ; \ExitProcess
  
  
  
  恩……
  
  00401268   .  83E9 01       SUB ECX,1
  
  ECX=ECX-1,就是40100E的前一项
  
  XOR EBX,EBX 混淆视线……
  
  看看这个循环
  
  0040126D   > /41            INC ECX
  0040126E   . |8BF1          MOV ESI,ECX
  00401270   . |8B06          MOV EAX,DWORD PTR DS:[ESI]
  00401272   . |3BC8          CMP ECX,EAX
  00401274   .^\72 F7         JB SHORT CrackMe1.0040126D
  
  呵呵,第一次运行的时候ECX又回来了。因为这次没用LOOPD,所以手工得INC ECX
  
  看这个
  
  00401272   . |3BC8          CMP ECX,EAX
  
  当EAX<ECX的时候停止?这个结束条件貌似很古怪,为什么呢?
  我们知道,EAX读取的时候因为有一串NOP,而又是DWORD的读取方式,所以EAX总是等于90909090
  而当ECX一出过909090区域,就自己报警了……
  
  00401276   .  83FF 02       CMP EDI,2
  00401279   .  75 2D         JNZ SHORT CrackMe1.004012A8
  
  这里没跳是很好的,咱们分析分析他发现DEBUG后要干什么……
  
  004012A8   > \B8 24104000   MOV EAX,CrackMe1.00401024
  004012AD   .  B9 3D104000   MOV ECX,CrackMe1.0040103D
  004012B2   .  83E9 03       SUB ECX,3
  004012B5   .  2BC8          SUB ECX,EAX
  004012B7   .  8BD1          MOV EDX,ECX
  004012B9   .  BB 90909090   MOV EBX,90909090
  004012BE   >  8BF0          MOV ESI,EAX
  004012C0   .  03F2          ADD ESI,EDX
  004012C2   .  2BF1          SUB ESI,ECX
  004012C4   .  891E          MOV DWORD PTR DS:[ESI],EBX
  004012C6   .^ E2 F6         LOOPD SHORT CrackMe1.004012BE
  
  熟悉吗?太熟悉了!又是SMC……不过是SMC的另一种形式,不断用NOP(90)覆盖401024-40103D的区域,咱们看看是什么
  
  00401024   .  6A 00         PUSH 0                                   ; /lParam = NULL
  00401026   .  68 43104000   PUSH CrackMe1.00401043                   ; |DlgProc = CrackMe1.00401043
  0040102B   .  6A 00         PUSH 0                                   ; |hOwner = NULL
  0040102D   .  68 00304000   PUSH CrackMe1.00403000                   ; |pTemplate = "IsDebugPresent"
  00401032   .  FF35 AC304000 PUSH DWORD PTR DS:[4030AC]               ; |hInst = 00400000
  00401038   .  E8 09060000   CALL <JMP.&user32.DialogBoxParamA>       ; \DialogBoxParamA
  0040103D   .  50            PUSH EAX                                 ; /ExitCode
  
  呵呵,这段一覆盖成NOP...
  
  这里F4
  004012C8   .  68 00004000   PUSH CrackMe1.00400000
  
  004012C8   .  68 00004000   PUSH CrackMe1.00400000
  004012CD   .  810424 001000>ADD DWORD PTR SS:[ESP],1000
  
  很阴险,先PUSH一个400000,再改变堆栈,最终是401000,RETN,看看:)
  
  00401000 >/$  60            PUSHAD
  00401001  |.  E8 01000100   CALL 00411007
  00401006  |.  0000          ADD BYTE PTR DS:[EAX],AL
  00401008  |.  002406        ADD BYTE PTR DS:[ESI+EAX],AH
  0040100B  \.  C3            RETN
  
  还是别忘了跳(F7)花……
  
  到401000
  
  00401000 >/$  60            PUSHAD
  00401001  |.  E8 01000100   CALL 00411007
  00401006  |.  0000          ADD BYTE PTR DS:[EAX],AL
  00401008  |.  002406        ADD BYTE PTR DS:[ESI+EAX],AH
  0040100B  \.  C3            RETN
  
  这里很抱歉大家,我可能哪个地方出错了,没做得很完美,这里会因为一个异常退出,而我
  原来的意思是让他继续执行下去,一直到ExitProcess……不过也没关系,目的达到了……
  
  好,咱们这条路走完了,走正确的那条路
  
  直接F4到咱们刚才分析的
  0040127B   .  BF 24104000   MOV EDI,CrackMe1.00401024
  
  0040127B   .  BF 24104000   MOV EDI,CrackMe1.00401024  //edi=401024
  00401280   .  B9 C3000000   MOV ECX,0C3                //ecx=c3
  00401285   .  890F          MOV DWORD PTR DS:[EDI],ECX // [401024]=c3
  00401287   .  83EF 02       SUB EDI,2                  //edi=401022
  0040128A   .  83C7 03       ADD EDI,3                  //edi=401025 (混淆视线)
  0040128D   .  B9 12000000   MOV ECX,12                
  00401292   .  890F          MOV DWORD PTR DS:[EDI],ECX //[401025]=12
  00401294   .  83C7 01       ADD EDI,1                  //edi=401026
  00401297   .  B9 CC000000   MOV ECX,0CC
  0040129C   .  890F          MOV DWORD PTR DS:[EDI],ECX //[401026]=cc
  0040129E   .  47            INC EDI                    //edi=401027
  0040129F   .  B9 12000000   MOV ECX,12
  004012A4   .  890F          MOV DWORD PTR DS:[EDI],ECX //[401027]=12
  
  这段,仔细分析一下,就不单独解释了,主要看注释,大致的意思是把401024-401027的段给重写一下……
  
  变成了
  00401024   .  C3            RETN
  00401025      12            DB 12
  00401026      CC            INT3
  00401027      12            DB 12
  
  继续走……
  
  004012D5   >  BE 10134000   MOV ESI,CrackMe1.00401310
  004012DA   . |B9 E8909090   MOV ECX,909090E8
  004012DF   . |890E          MOV DWORD PTR DS:[ESI],ECX
  004012E1   . |46            INC ESI
  004012E2   . |B9 F9909090   MOV ECX,909090F9
  004012E7   . |890E          MOV DWORD PTR DS:[ESI],ECX
  004012E9   . |B9 FC909090   MOV ECX,909090FC
  004012EE   . |46            INC ESI
  004012EF   . |890E          MOV DWORD PTR DS:[ESI],ECX
  004012F1   . |B9 FF909090   MOV ECX,909090FF
  004012F6   . |46            INC ESI
  004012F7   . |890E          MOV DWORD PTR DS:[ESI],ECX
  004012F9   . |B9 FF909090   MOV ECX,909090FF
  004012FE   . |46            INC ESI
  004012FF   . |890E          MOV DWORD PTR DS:[ESI],ECX
  00401301   . |B9 90909090   MOV ECX,90909090
  00401306   . |46            INC ESI
  00401307   . |890E          MOV DWORD PTR DS:[ESI],ECX
  00401309   . |3D 34120000   CMP EAX,1234
  0040130E   .^\74 C5         JE SHORT CrackMe1.004012D5
  
  呵呵,401310不就在底下吗?扯到眼皮子底下了:)
  不分析了吧,这段太简单了。实在不幸就F8观察一下
  (最后那个JE是迷惑你的:))
  
  好,这段运行完了,401310出来一个
  00401310   .  E8 F9FCFFFF   CALL CrackMe1.0040100E
  
  跟进看看:)
  
  0040100E      90            NOP
  0040100F      90            NOP
  00401010      90            NOP
  00401011      90            NOP
  00401012      90            NOP
  00401013      90            NOP
  00401014      90            NOP
  00401015      90            NOP
  00401016      90            NOP
  00401017      90            NOP
  00401018   >  6A 00         PUSH 0                                   ; /pModule = NULL
  0040101A   .  E8 63060000   CALL <JMP.&XXXXXXXXXXXtModuleHandleA>     \GetModuleHandleA
  0040101F   .  A3 AC304000   MOV DWORD PTR DS:[4030AC],EAX
  00401024   .  C3            RETN
  
  真无聊,回去吧
  
  00401319   .  BE 10134000   MOV ESI,CrackMe1.00401310    //ESI是什么?
  0040131E   .  E8 35000000   CALL CrackMe1.00401358
  00401323   .  EB 1A         JMP SHORT CrackMe1.0040133F  //走到这里就完了!各位记住401323是GAMEOVER!
  
  00401325   >  66:3D BA0B    CMP AX,0BBA                  //走到这里也就完了!各位记住401325是GAMEOVER!
  00401329   .  75 14         JNZ SHORT CrackMe1.0040133F
  
  我们还不知道401310要干什么,所以先不管他……
  跟进CALL...
  
  00401358  /$  5F            POP EDI                                    CrackMe1.00401323
  00401359  |.  58            POP EAX
  0040135A  |.  58            POP EAX
  0040135B  |.  5B            POP EBX
  0040135C  |.  5B            POP EBX
  0040135D  |.  50            PUSH EAX
  0040135E  |.  53            PUSH EBX
  0040135F  |.  68 DC134000   PUSH CrackMe1.004013DC
  00401364  |.  6A 01         PUSH 1
  00401366  |.  B8 41164000   MOV EAX,CrackMe1.00401641                  ASCII "%8 @"
  0040136B  |.  83C0 FF       ADD EAX,-1
  0040136E  |.  8BF8          MOV EDI,EAX
  00401370  |.  B9 60184000   MOV ECX,CrackMe1.00401860
  00401375  |.  8B38          MOV EDI,DWORD PTR DS:[EAX]
  00401377  |.  8939          MOV DWORD PTR DS:[ECX],EDI
  00401379  |.  BF 40000000   MOV EDI,40
  0040137E  |.  83C1 04       ADD ECX,4
  00401381  |.  8939          MOV DWORD PTR DS:[ECX],EDI
  00401383  |.  83E9 04       SUB ECX,4
  00401386  |.  FFD1          CALL ECX
  00401388  \.  C3            RETN
  
  什么玩意?这就是算法?别着急,我们慢慢看……
  
  首先是前面关于栈的操作
  
  00401358  /$  5F            POP EDI                                    CrackMe1.00401323
  00401359  |.  58            POP EAX
  0040135A  |.  58            POP EAX
  0040135B  |.  5B            POP EBX
  0040135C  |.  5B            POP EBX
  0040135D  |.  50            PUSH EAX
  0040135E  |.  53            PUSH EBX
  
  很好理解,去EDI是把CALL当成跳转用
  4个POP,2个PUSH是把位数变为一个(还记得以前是PUSH了2次吗?)
  0040135F  |.  68 DC134000   PUSH CrackMe1.004013DC
  00401364  |.  6A 01         PUSH 1
  
  这2个PUSH咱们走着瞧:)
  
  00401366  |.  B8 41164000   MOV EAX,CrackMe1.00401641                  ASCII "%8 @"
  0040136B  |.  83C0 FF       ADD EAX,-1
  0040136E  |.  8BF8          MOV EDI,EAX
  
  EDI=eax=401640
  
  00401370  |.  B9 60184000   MOV ECX,CrackMe1.00401860
  
  ECX=401860
  
  00401375  |.  8B38          MOV EDI,DWORD PTR DS:[EAX]
  00401377  |.  8939          MOV DWORD PTR DS:[ECX],EDI
  
  呵呵,看到没?把DWORD PTR DS:[EAX]覆盖到DWORD PTR DS:[ECX]
  
  偷窥一下EAX是什么
  
  00401640   >-\FF25 38204000 JMP DWORD PTR DS:[<&user32.BlockInput>]    user32.BlockInput
  
  覆盖到ECx又怎么样呢?慢慢看
  
  00401379  |.  BF 40000000   MOV EDI,40
  0040137E  |.  83C1 04       ADD ECX,4
  00401381  |.  8939          MOV DWORD PTR DS:[ECX],EDI
  
  呵呵,结合上面的EAX内容FF 25 38 20 40 00
  而复制由于是Dword,所以只复制了 FF 25 38 20
  你应该能看见,40没复制过来,所以……
  
  到401381结束时,ECX是401864,而
  00401383  |.  83E9 04       SUB ECX,4
  要他返回来,干吗?
  
  00401386  |.  FFD1          CALL ECX
  
  HIHI~CALL啊!
  当你运行到401386时,你可以看见
  00401386  |.  FFD1          CALL ECX                                 ;  <JMP.&user32.BlockInput>
  
  怎么样?!这就是我这个CM用的独特技术——让OD混淆你的API,
  至于前面这个
  00401366  |.  B8 41164000   MOV EAX,CrackMe1.00401641                  ASCII "%8 @"
  0040136B  |.  83C0 FF       ADD EAX,-1
  
  是可以改的,比如改成
  mov eax,401642
  sub eax,2等等
  有的时候,OD还会把你的API认成别的API那我们可乐了(我就碰到过,不过后来又改回来了)
  这个时候,你知道前面PUSH 1是什么意思了吧?他是API BlockInput的参数....
  不过我们可不想让他运行:)还是NOP掉的好
  
  不过在NOP API前请特别注意!!!一定要把堆栈里API的参数也给POP掉,否则……
  
  这样一来,前面的PUSH 4013DC也说得通了,因为有个
  00401388  \.  C3            RETN
  呵呵,F8走!
  
  004013DC   .  57            PUSH EDI
  
  把EDI给PUSH进去,不管,向下看……
  
  004013DD   .  B9 48000000   MOV ECX,48
  004013E2   .  890E          MOV DWORD PTR DS:[ESI],ECX
  004013E4   .  46            INC ESI
  004013E5   .  B9 65000000   MOV ECX,65
  004013EA   .  890E          MOV DWORD PTR DS:[ESI],ECX
  004013EC   .  46            INC ESI
  004013ED   .  B9 6C000000   MOV ECX,6C
  004013F2   .  890E          MOV DWORD PTR DS:[ESI],ECX
  004013F4   .  46            INC ESI
  004013F5   .  890E          MOV DWORD PTR DS:[ESI],ECX
  004013F7   .  46            INC ESI
  004013F8   .  B9 6F000000   MOV ECX,6F
  004013FD   .  890E          MOV DWORD PTR DS:[ESI],ECX
  
  明显,在往401310到401315写入代码(当运行到4013DD时,ESI为401310)
  看看401310
  
  00401310   .  48            DEC EAX
  00401311   .  65:6C         INS BYTE PTR ES:[EDI],DX
  00401313   .  6C            INS BYTE PTR ES:[EDI],DX
  00401314   .  6F            OUTS DX,DWORD PTR ES:[EDI]
  00401315   .  0000          ADD BYTE PTR DS:[EAX],AL
  00401317   .  0090 BE101340 ADD BYTE PTR DS:[EAX+401310BE],DL
  
  什么东西?看数据窗
  00401310  48 65 6C 6C 6F 00 00 00                          Hello...
  
  晕死……
  
  004013FF   .  B8 89134000   MOV EAX,CrackMe1.00401389
  00401404   .  BB DB134000   MOV EBX,CrackMe1.004013DB
  00401409   .  83EB 01       SUB EBX,1
  0040140C   .  2BD8          SUB EBX,EAX
  0040140E   .  8BCB          MOV ECX,EBX
  00401410   >  B8 89134000   MOV EAX,CrackMe1.00401389
  00401415   .  03C3          ADD EAX,EBX
  00401417   .  2BC1          SUB EAX,ECX
  00401419   .  8BF0          MOV ESI,EAX
  0040141B   .  8B16          MOV EDX,DWORD PTR DS:[ESI]
  0040141D   .  83F2 14       XOR EDX,14
  00401420   .  8916          MOV DWORD PTR DS:[ESI],EDX
  00401422   .^ E2 EC         LOOPD SHORT CrackMe1.00401410
  
  不说了,SMC,操作是XOR EDX,14,直接在
  00401424   .  68 3D144000   PUSH CrackMe1.0040143D
  下断
  
  忽然发现
  晕死……
  
  0040142A   .  6A 00         PUSH 0                                   ; /Style = MB_OK|MB_APPLMODAL
  0040142C   .  68 89134000   PUSH CrackMe1.00401389                   ; |Title = "很不错了,能找到这里。不过前方的路还很长,希望你有心理准备.前面都是ANTI,现在开始..:"
  00401431   .  68 89134000   PUSH CrackMe1.00401389                   ; |Text = "很不错了,能找到这里。不过前方的路还很长,希望你有心理准备.前面都是ANTI,现在开始..:"
  00401436   .  6A 00         PUSH 0                                   ; |hOwner = NULL
  00401438   .  E8 21020000   CALL <JMP.&user32.MessageBoxA>           ; \MessageBoxA
  
  00401424   .  68 3D144000   PUSH CrackMe1.0040143D
  00401429   .  C3            RETN
  转到40143d
  
  0040143D   .  68 52144000   PUSH CrackMe1.00401452
  00401442   .  33FF          XOR EDI,EDI
  00401444   .  C3            RETN
  转到401452
  
  00401452   ?  BB 40184000   MOV EBX,CrackMe1.00401840
  00401457   .  8B03          MOV EAX,DWORD PTR DS:[EBX]
  00401459   .  3D D2040000   CMP EAX,4D2
  0040145E   .  75 08         JNZ SHORT CrackMe1.00401468
  00401460   .  68 8C144000   PUSH CrackMe1.0040148C
  00401465   .  C3            RETN
  00401466   .  EB 00         JMP SHORT CrackMe1.00401468
  00401468   >  BE 46144000   MOV ESI,CrackMe1.00401446
  0040146D   .  B9 0C000000   MOV ECX,0C
  00401472   >  8B06          MOV EAX,DWORD PTR DS:[ESI]
  00401474   .  48            DEC EAX
  00401475   .  8906          MOV DWORD PTR DS:[ESI],EAX
  00401477   .  46            INC ESI
  00401478   .^ E2 F8         LOOPD SHORT CrackMe1.00401472
  0040147A   .  BB 40184000   MOV EBX,CrackMe1.00401840
  0040147F   .  B9 D2040000   MOV ECX,4D2
  00401484   .  890B          MOV DWORD PTR DS:[EBX],ECX
  00401486   .  68 46144000   PUSH CrackMe1.00401446
  0040148B   .  C3            RETN
  
  恩……有点晕了,(看看表:23:16了!明天还上学呢……不管,继续吧)
  (唉~没熬出头的学生啊……)
  
  慢慢来,首先咱们第一次运行时401840还没值呢,所以这个也不可能成立了
  
  00401452   ?  BB 40184000   MOV EBX,CrackMe1.00401840
  00401457   .  8B03          MOV EAX,DWORD PTR DS:[EBX]
  00401459   .  3D D2040000   CMP EAX,4D2
  0040145E   . /75 08         JNZ SHORT CrackMe1.00401468  走
  
  吐血,又是SMC,我被我自己写的SMC给玩死了……(这个CM我是编了几个星期才完成的)
  
  分析:
    00401468   > \BE 46144000   MOV ESI,CrackMe1.00401446
    基地址:401446
    0040146D   .  B9 0C000000   MOV ECX,0C
    ECX:0C 循环13次
  
  00401472   > /8B06          MOV EAX,DWORD PTR DS:[ESI]    
  00401474   . |48            DEC EAX
  00401475   . |8906          MOV DWORD PTR DS:[ESI],EAX   //SMC(算法:DEC EAX)
  00401477   . |46            INC ESI                      //指针+1
  00401478   .^\E2 F8         LOOPD SHORT CrackMe1.00401472
  
  看看401446是何方神圣现在
  
  00401446   .  60            PUSHAD
  00401447   .  E8 01000000   CALL CrackMe1.0040144D
  0040144C      7C            DB 7C                                      CHAR '|'
  0040144D   .  830424 06     ADD DWORD PTR SS:[ESP],6
  00401451   .  C3            RETN
  
  这……这不是传说中的......AC花指令(就是文件头那个)
  唉……继续吧
  
  0040147A   .  BB 40184000   MOV EBX,CrackMe1.00401840
  0040147F   .  B9 D2040000   MOV ECX,4D2
  00401484   .  890B          MOV DWORD PTR DS:[EBX],ECX
  
  呵呵,401840终于变成了4D2,还记得刚才提到的吗?
  00401486   .  68 46144000   PUSH CrackMe1.00401446
  0040148B   .  C3            RETN
  走了
  
  00401446   .  60            PUSHAD
  00401447   .  E8 01000000   CALL CrackMe1.0040144D
  0040144C      7C            DB 7C                                      CHAR '|'
  0040144D   .  830424 06     ADD DWORD PTR SS:[ESP],6
  00401451   .  C3            RETN
  
  老办法,F7……
  你会发现,又回到……
  00401452   .  BB 40184000   MOV EBX,CrackMe1.00401840
  00401457   .  8B03          MOV EAX,DWORD PTR DS:[EBX]
  00401459   .  3D D2040000   CMP EAX,4D2
  0040145E   .  75 08         JNZ SHORT CrackMe1.00401468
  
  这回的JNZ我们可不会放过了……
  00401460   .  68 8C144000   PUSH CrackMe1.0040148C
  00401465   .  C3            RETN
  
  跳到40148c
  那么不讲面子:)
  0040148C   . /EB 05         JMP SHORT CrackMe1.00401493
  0040148E   . |25 73257390   AND EAX,90732573
  
  00401493   > \B8 92144000   MOV EAX,CrackMe1.00401492
  00401498   .  8BF0          MOV ESI,EAX
  
  
  上来就一个JMP
  别管,继续
  目前ESI=EAX=401492
  
  0040149A   .  33FF          XOR EDI,EDI
  0040149C   .  BF 00000000   MOV EDI,0
  004014A1   .  B2 00         MOV DL,0
  
  占用硬盘空间……(-_-)
  004014A3   .  8816          MOV BYTE PTR DS:[ESI],DL
  这还是比较关键的
  
  改了这句话……
  0040148E   .  25 73257300   AND EAX,732573
  
  见鬼了,干吗改这句呢?
  
  004014A5   .  68 8E144000   PUSH CrackMe1.0040148E
  004014AA   .  B8 89164000   MOV EAX,CrackMe1.00401689
  004014AF   .  83C0 FF       ADD EAX,-1
  004014B2   .  8BF8          MOV EDI,EAX
  004014B4   .  B9 70184000   MOV ECX,CrackMe1.00401870
  004014B9   .  8B38          MOV EDI,DWORD PTR DS:[EAX]
  004014BB   .  8939          MOV DWORD PTR DS:[ECX],EDI
  004014BD   .  BF 40000000   MOV EDI,40
  004014C2   .  83C1 04       ADD ECX,4
  004014C5   .  8939          MOV DWORD PTR DS:[ECX],EDI
  004014C7   .  83E9 04       SUB ECX,4
  004014CA   .  FFD1          CALL ECX
  
  好熟悉啊啊啊啊啊啊啊,这不是我的原创大法吗(笑~)
  
  那为什么要PUSH 40148E呢?难道这是个字串吗?
  CTRL+A一下,原形毕露
  0040148E   .  25 73 25 73 0>ASCII "%s%s",0
  
  呵呵,%s%s....
  直接在CALL ECX下F4,NOP并POP掉
  
  吐发黑色的血(中毒?),又来了
  004014CC   .  B8 B4304000   MOV EAX,CrackMe1.004030B4
  004014D1   .  33FF          XOR EDI,EDI
  004014D3   .  BB 00000000   MOV EBX,0
  004014D8   >  83C3 01       ADD EBX,1
  004014DB   .  83C0 01       ADD EAX,1
  004014DE   .  8BF0          MOV ESI,EAX
  004014E0   .  8B0E          MOV ECX,DWORD PTR DS:[ESI]
  004014E2   .  0BC9          OR ECX,ECX
  004014E4   .  75 05         JNZ SHORT CrackMe1.004014EB
  004014E6   .  BF 01000000   MOV EDI,1
  004014EB   >  83FF 01       CMP EDI,1
  004014EE   .^ 75 E8         JNZ SHORT CrackMe1.004014D8
  
  NND,还一点一点来吧
  
  如果你记忆力不错的话,你会猜到这是什么:)用户名
  004014CC   .  B8 B4304000   MOV EAX,CrackMe1.004030B4                  ASCII "abcdefghijklmn"
  我实在不想说了,这段实在太简单了(观众:偷懒!),判断位数……保存到EBX里
  有一点我要强调一下
  
  004014E2   .  0BC9          OR ECX,ECX
  004014E4   .  75 05         JNZ SHORT CrackMe1.004014EB
  004014E6   .  BF 01000000   MOV EDI,1
  
  这个永远不会执行,所以你也别期望"快点出去"。。。
  
  004014F5   .  6A 00         PUSH 0
  004014F7   .  B8 42164000   MOV EAX,CrackMe1.00401642
  004014FC   .  83C0 FE       ADD EAX,-2
  004014FF   .  8BF8          MOV EDI,EAX
  00401501   .  B9 70184000   MOV ECX,<JMP.&kernel32.OutputDebugString>
  00401506   .  8B38          MOV EDI,DWORD PTR DS:[EAX]
  00401508   .  8939          MOV DWORD PTR DS:[ECX],EDI
  0040150A   .  BF 40000000   MOV EDI,40
  0040150F   .  83C1 04       ADD ECX,4
  00401512   .  8939          MOV DWORD PTR DS:[ECX],EDI
  00401514   .  83E9 04       SUB ECX,4
  00401517   .  FFD1          CALL ECX
  
  恢复BLOCKINPUT,看见没?OD已经把ECX给搞晕了……
  
  00401519   .  68 23134000   PUSH CrackMe1.00401323  //GAMEOVER
  0040151E   .  C3            RETN
  
  同理可证,
  0040151F   > \B8 B4324000   MOV EAX,CrackMe1.004032B4                  ASCII "1234567890123"
  00401524   .  33FF          XOR EDI,EDI
  00401526   .  BB 00000000   MOV EBX,0
  0040152B   >  83C3 01       ADD EBX,1
  0040152E   .  83C0 01       ADD EAX,1
  00401531   .  8BF0          MOV ESI,EAX
  00401533   .  8B0E          MOV ECX,DWORD PTR DS:[ESI]
  00401535   .  0BC9          OR ECX,ECX
  00401537   .  75 05         JNZ SHORT CrackMe1.0040153E
  00401539   .  BF 01000000   MOV EDI,1
  0040153E   >  83FF 01       CMP EDI,1
  00401541   .^ 75 E8         JNZ SHORT CrackMe1.0040152B
  00401543   .  83FB 0A       CMP EBX,0A
  00401546   .  77 2A         JA SHORT CrackMe1.00401572
  00401548   .  6A 00         PUSH 0
  0040154A   .  B8 42164000   MOV EAX,CrackMe1.00401642
  0040154F   .  83C0 FE       ADD EAX,-2
  00401552   .  8BF8          MOV EDI,EAX
  00401554   .  B9 70184000   MOV ECX,<JMP.&kernel32.OutputDebugString>
  00401559   .  8B38          MOV EDI,DWORD PTR DS:[EAX]
  0040155B   .  8939          MOV DWORD PTR DS:[ECX],EDI
  0040155D   .  BF 40000000   MOV EDI,40
  00401562   .  83C1 04       ADD ECX,4
  00401565   .  8939          MOV DWORD PTR DS:[ECX],EDI
  00401567   .  83E9 04       SUB ECX,4
  0040156A   .  FFD1          CALL ECX
  0040156C   .  68 23134000   PUSH CrackMe1.00401323
  00401571   .  C3            RETN
  
  是判断密码长度的(已经被搞晕了……我写的CM怎么自己还……已经23:41了,坚持!)
  
  ………………………………
  
  00401572   > \33DB          XOR EBX,EBX
  00401574   .  33D2          XOR EDX,EDX
  00401576   .  33C9          XOR ECX,ECX
  00401578   .  BE B4304000   MOV ESI,CrackMe1.004030B4                  ASCII "abcdefghijklmn"
  0040157D   .  BF B4324000   MOV EDI,CrackMe1.004032B4                  ASCII "1234567890123"
  
  终于到了,终于到了.........
  
  00401572   > \33DB          XOR EBX,EBX                               //下面三句是做初始化
  00401574   .  33D2          XOR EDX,EDX
  00401576   .  33C9          XOR ECX,ECX
  00401578   .  BE B4304000   MOV ESI,CrackMe1.004030B4                  ASCII "abcdefghijklmn"
  0040157D   .  BF B4324000   MOV EDI,CrackMe1.004032B4                  ASCII "1234567890123"
  00401582   .  83C6 01       ADD ESI,1                                 //esi==>用户名第2位
  00401585   .  8B1E          MOV EBX,DWORD PTR DS:[ESI]                //ebx==>逆向用户名第2-5位,结合!
  (比如bcde就是65646362)
  00401587   .  83C7 01       ADD EDI,1
  0040158A   .  030F          ADD ECX,DWORD PTR DS:[EDI]                //ecx==>逆向密码2-5位
  0040158C   .  83C6 01       ADD ESI,1
  0040158F   .  031E          ADD EBX,DWORD PTR DS:[ESI]                //ebx=ebx+逆向用户名3-6位
  
  (打个岔:今天就到这,明天继续,都23:48了,睡觉睡觉……顺便膜拜一下风间仁这个牲口)
  (回来了。。。)
  00401591   .  83C7 04       ADD EDI,4
  00401594   .  030F          ADD ECX,DWORD PTR DS:[EDI]                //ecx=ecx+逆向密码6-9位
  00401596   .  83C6 04       ADD ESI,4
  00401599   .  031E          ADD EBX,DWORD PTR DS:[ESI]                //ebx=ebx+逆向用户名7-10位
  0040159B   .  83C7 01       ADD EDI,1
  0040159E   .  030F          ADD ECX,DWORD PTR DS:[EDI]                //ecx=ecx+逆向密码7-10位
  004015A0   .  83EE 03       SUB ESI,3
  004015A3   .  031E          ADD EBX,DWORD PTR DS:[ESI]                //ebx=ebx+逆向用户名4-7位
  004015A5   .  83EF 02       SUB EDI,2
  004015A8   .  030F          ADD ECX,DWORD PTR DS:[EDI]                //ecx=ecx+逆向密码5-8位
  
  晕了,继续
  
  004015AA   .  B8 00104000   MOV EAX,CrackMe1.<模块入口点>
  004015AF   .  03C8          ADD ECX,EAX                        
  004015B1   .  83C1 01       ADD ECX,1                                 //ecx=ecx+400001h
  004015B4   .  B8 46144000   MOV EAX,CrackMe1.00401446
  004015B9   .  83C0 01       ADD EAX,1
  004015BC   .  03D8          ADD EBX,EAX                               //ebx=ebx+401447h
  004015BE   .  B8 89134000   MOV EAX,CrackMe1.00401389
  004015C3   .  83C0 03       ADD EAX,3
  004015C6   .  03C8          ADD ECX,EAX                               //ecx=ecx+40138ch
  004015C8   .  B8 6A114000   MOV EAX,CrackMe1.0040116A
  004015CD   .  83C0 30       ADD EAX,30
  004015D0   .  03D8          ADD EBX,EAX                               //ebx=ebx+40119ah
  004015D2   .  33C0          XOR EAX,EAX
  
  004015D4   .  0BC0          OR EAX,EAX
  004015D6   .  75 39         JNZ SHORT CrackMe1.00401611
  永远不会跳转……
  
  004015D8   .  3BD9          CMP EBX,ECX
  004015DA   .  75 3A         JNZ SHORT CrackMe1.00401616
  如果OK了不跳,否则去死
  
  去死路线:
  
  00401616   ?  6A 00         PUSH 0
  00401618   ?  B8 41164000   MOV EAX,CrackMe1.00401641                  ASCII "%8 @"
  0040161D   .  83C0 FF       ADD EAX,-1
  00401620   .  8BF8          MOV EDI,EAX
  00401622   .  B9 50184000   MOV ECX,CrackMe1.00401850
  00401627   .  8B38          MOV EDI,DWORD PTR DS:[EAX]
  00401629   .  8939          MOV DWORD PTR DS:[ECX],EDI
  0040162B   .  BF 40000000   MOV EDI,40
  00401630   .  83C1 04       ADD ECX,4
  00401633   .  8939          MOV DWORD PTR DS:[ECX],EDI
  00401635   .  83E9 04       SUB ECX,4
  00401638   .  FFD1          CALL ECX
  
  又是一个API变形,恢复BlockInput
  
  0040163A   .  68 23134000   PUSH CrackMe1.00401323
  0040163F   .  C3            RETN
  
  去死了……
  
  OK路线:
  
  004015DF   > \6A 40         PUSH 40
  004015E1   .  68 DE154000   PUSH CrackMe1.004015DE
  004015E6   .  68 6A114000   PUSH CrackMe1.0040116A
  004015EB   .  6A 00         PUSH 0
  004015ED   .  B8 5F164000   MOV EAX,CrackMe1.0040165F
  004015F2   .  83C0 FF       ADD EAX,-1
  004015F5   .  8BF8          MOV EDI,EAX
  004015F7   .  B9 00194000   MOV ECX,<JMP.&user32.MessageBoxA>
  004015FC   .  8B38          MOV EDI,DWORD PTR DS:[EAX]
  004015FE   .  8939          MOV DWORD PTR DS:[ECX],EDI
  00401600   .  BF 40000000   MOV EDI,40
  00401605   .  83C1 04       ADD ECX,4
  00401608   .  8939          MOV DWORD PTR DS:[ECX],EDI
  0040160A   .  83E9 04       SUB ECX,4
  0040160D   .  FFD1          CALL ECX
  
  API变形,MessageboxA
  
  0040160F   . /EB 05         JMP SHORT CrackMe1.00401616
  见去死路线……
  
  不知大家发现没有,这里有个严重的BUG
  
  就是你必须第一次注册就成功,要不然以后解“既不回头”就会出现双重解码
  其他的SMC肯定也有这个问题,但反过头来想一想,有一个指令的SMC,为什么没出错呢?
  
  00401459   .  3D D2040000   CMP EAX,4D2                      //关键就在这里了!!!
  0040145E   .  75 08         JNZ SHORT CrackMe1.00401468
  00401460   .  68 8C144000   PUSH CrackMe1.0040148C
  00401465   .  C3            RETN
  00401466   .  EB 00         JMP SHORT CrackMe1.00401468
  00401468   >  BE 46144000   MOV ESI,CrackMe1.00401446
  0040146D   .  B9 0C000000   MOV ECX,0C
  00401472   >  8B06          MOV EAX,DWORD PTR DS:[ESI]
  00401474   .  48            DEC EAX
  00401475   .  8906          MOV DWORD PTR DS:[ESI],EAX
  00401477   .  46            INC ESI
  00401478   .^ E2 F8         LOOPD SHORT CrackMe1.00401472
  0040147A   .  BB 40184000   MOV EBX,CrackMe1.00401840
  0040147F   .  B9 D2040000   MOV ECX,4D2
  00401484   .  890B          MOV DWORD PTR DS:[EBX],ECX
  00401486   .  68 46144000   PUSH CrackMe1.00401446
  0040148B   .  C3            RETN
  
  为什么说关键在401459呢?因为第一次运行的时候会在内存某处有个标记,标记被SMC过,所以没死……
  看来以后用SMC得小心点了:)
  
  注册机就不发了,留给大家:)
  
--------------------------------------------------------------------------------
【经验总结】
  第2部分:反思
  
  反思这个CM,其实并不怎么困难为什么只有一个人出KEY……(也许是我的人品有问题^_^)
  呵呵,不是抬高自己的意思。这个CM主要看着眼晕(实际上自己也写晕了……),眼花缭乱:)
  
  不过这个CM给大家一个教训,那就是SMC解码时一定要想着第2次……………………
  
  第3部分:后记
  随便吧……写注册机去了
  
--------------------------------------------------------------------------------
                                                       2007年12月05日 下午 11:33:28
来自:计算机科学 / 软件综合
11
已屏蔽 原因:{{ notice.reason }}已屏蔽
{{notice.noticeContent}}
~~空空如也
noname剑人 作者
16年6个月前 IP:未同步
34314
老外给这个CRACKME写的破文

1. Main()

Firing up the executable in OllyDbg (OEP - 0x00401000) raises a couple of eyebrows. A PUSHAD/CALL to a function that increases the stack pointer and rets into a JMP over a bunch of NOPs. It looks like the author had a lot of fun writing this program.

The next thing we see is a dialog box being created through the user32.DialogBoxParamA function with the template name set as "IsDebugPresent" (hmmmm).

The window event processing loop follows.

1.5. Entering in your Name/Key

Enter in any values you want here. Press the RegMe button and place a breakpoint on one of the two addresses listed in the next section.

2. EventProcessing()

None of the information in this function actually matters except for the part where the values from the YourName/YourID are copied into memory.

On lines 0x0040112F and 0x00401145 we see two sequential XXXXXXXXXtDlgItemTextA's. These corresponding to the copying of the name and key into memory.

Following our previous copies is an all too familiar call to XXXXXXXXXXXrtualProtect making the .text section writable. And so begins the morphing code.

3. Anti-Debugging and Morphing Code

The next sections of code, beginning at 0x004011C5 were created to transform sections of the code which appear to be data into actual executable code. I will not discuss every section in detail as most are just simple XORs or additions of hardcoded constants. Instead, I will try to explain the general program flow on a higher level.

0x004011E3 and 0x00401205 are both LOOPD-based loop statements that transform some of the .text section into more meaningful statements.

Past these two loops we will see two calls to XXXXXXXXXXXtLocalTime (0x0040120C & 0x00401230).

At 0x0040124C the milliseconds of the local times are compared. If they are not equal, which implies that we must have been single-step debugging through the section, then the program halts.

Since there is absolutely no reason to single step this section (as it simply and trivially converts more sections of code) then place a breakpoint at 0x0040124C where the compare occurs.

The compare will succeed. A new call will be generated on the spot in the following loop, the program will return to EventProcessing() and then do a modified return into code at 0x00401358.

Put a breakpoint on Call ECX at 0x00401386.

ECX is a call to a far call containing user32.BlockInput which does a "int 2e" to disrupt debugging.

To circumvent this check, trace into Call ECX, trace into the far call, and NOP out the call at line 0x77D9C648 (Windows XP SP2) inside user32. This will force nothing to happen and the code to return from the call like everything went fine.

Returning from our BlockInput call, we will find data translating. Place a breakpoint at 0x00401429 to skip past all this nonsense.

4. Last Tricks

We are now in the final code section.

Ignore the weird compares and the always weird code translations.

We see another Call ECX at the bottom. This was a dangerous part of the code last time, and its a dangerous part of the code this time. Place a breakpoint at this address (0x004014CA) and see what it finally translates to.

OutputDebugStringA(%s%s) the classic OllyDbg 1.10 crash bug. Just NOP out this entire call and continue on your merry way.


5. Name/Key initial checks

After a modified inline strlen() equivalent function, the name and key are both checked for length.

The name length check is at 0x004014F0
The key length check is at 0x00401543

If the name is greater than or equal to 10, it passes.
If the key is greater than or equal to 11, it passes.

Failure of either check causes another call to OutputDebugStringA(%s%s).

6. Final Verification

The final verification appears at 0x00401572. In a high level view you take a 4 DWORDS at different location from the username and add them together into a single DWORD. The same process is performed with the key but from different locations.

The resulting DWORD values, or hashes, are then summed with 2 different constants (which are actually locations in the code). If the 2 hashes match, then you entered a valid combination and a message box is pop'd up.


0x004015DB is the final compare.


Here is the equation that needs to be solved to generate keys for names.


n_1 + (2^8*n_2) + (2^16*n_3) + (2^24*n_4) +
n_2 + (2^8*n_3) + (2^16*n_4) + (2^24*n_5) +
n_6 + (2^8*n_7) + (2^16*n_8) + (2^24*n_9) +
n_3 + (2^8*n_4) + (2^16*n_5) + (2^24*n_6) + c_n

=

k_1 + (2^8*k_2) + (2^16*k_3) + (2^24*k_4) +
k_5 + (2^8*k_6) + (2^16*k_7) + (2^24*k_8) +
k_6 + (2^8*k_7) + (2^16*k_8) + (2^24*k_9) +
k_4 + (2^8*k_5) + (2^16*k_6) + (2^24*k_7) + c_k


Where
    - n_i is the ith character in the name
    - c_n is the name's constant
    - k_i is the ith character in the key
    - c_k is the key's constant

All of the n_i's are given by the user entered in his name. Which leaves the k_i's to be solved for. Since there are 9 variables and 1 equation, there is no simple solution for this problem.

Instead one should set the values of all of the key's characters (k_i) to set numbers and solve for the last k_i. Unfortunately, since characters can only express 2^8 different values, we can't simply set all characters to 0, and k_1 to the difference between the name hash and the key hash.

Also note that general equations have many solutions. So the user 'RedStripeBeer' will have many multiples of valid keys associated with it.


7. Algorithm Realizations

By looking at the key equation above, you will first notice that although the key needs to be 11 characters in length, k_0 and k_10 are not used for the calculation. Set these values to whatever you want.

The next thing you should notice is that each character affects a different portion of the hash based upon the position they are pointed inside the DWORD.

For instance, k_1 (since it only appears once and in the lowest byte) can only affect the hash by +255 bits. k_9, on the exact opposite of the spectrum, is being multiplied by 2^24 since it appears only once in the highest byte. This means that k_9 can affect the overall hash by (2^24 * 255).

Also you should see that some characters, such as k_7 appear affect the total hash by (2^24+2^16+2^8 * 255) which is very powerful.

8. My Solution


    a. Start with the key X000000000X.
    b. Compute the hash of the key and the name.
    c. Calculate the difference (name_hash - key_hash).
         i. If the difference is negative, we need to make it positive. The way to do this is key adding large values until the DWORD overflows into positive.
    d. When the difference becomes positive, divide the difference by the strength of the character.
    e. Increase the character by this multiple.
    f. Repeat (a) with the new key.

9. Notes/Curiosities/Anger

This program was coded for an Asian language set. This presented many challenges in finding valid characters to use for generating the key. One method I used was to alternate between powerful characters to spread the changes across the key. This prevented single characters from reaching the 254 value and ruining the algorithm.

Also, the MessageBox that pops up in the end appears to look like garbage. Are these poorly translated Asian characters? I have no way of telling.

10. See the README.txt for the solution keygen.

Have fun,

TCM
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
noname剑人作者
16年6个月前 IP:未同步
34316
如果各位感兴趣的话,可以去XXXXXXXXXXXXXXXXXXXXXX/users/nonameswordman/nonames_first_keygenme_in_asm/
下载这个CRACKME

呵呵.原创的啊
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
noname剑人作者
16年6个月前 IP:未同步
34317
另:UNPACKCN原帖
XXXXXXXXXXXXXXXXXXXX/XXXXXXXXXXXXXp?tid=19965&highlight=%2BNONAME%BD%A3%C8%CB
各位可以在那里发个短信与我联系
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
noname剑人作者
16年6个月前 IP:未同步
34885
呵呵.....楼上很生猛啊..
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
noname剑人作者
16年6个月前 IP:未同步
34886
唉,可惜这里好多人都不会这个,所以....
贼郁闷
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
noname剑人作者
16年6个月前 IP:未同步
34987
呵呵。是啊,就是精华很难得。混了很久才……唉,郁闷
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
noname剑人作者
16年6个月前 IP:未同步
34988
不过现在貌似UNPACKCN比PEDIY人气要高
================
另:金刚石是已知材料中硬度最高的吗?填 不是

那是什么?
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论

想参与大家的讨论?现在就 登录 或者 注册

所属专业
所属分类
上级专业
同级专业
noname剑人
学者 笔友
文章
48
回复
430
学术分
3
2008/07/22注册,6年11个月前活动
暂无简介
主体类型:个人
所属领域:无
认证方式:邮箱
IP归属地:未同步
文件下载
加载中...
{{errorInfo}}
{{downloadWarning}}
你在 {{downloadTime}} 下载过当前文件。
文件名称:{{resource.defaultFile.name}}
下载次数:{{resource.hits}}
上传用户:{{uploader.username}}
所需积分:{{costScores}},{{holdScores}}下载当前附件免费{{description}}
积分不足,去充值
文件已丢失

当前账号的附件下载数量限制如下:
时段 个数
{{f.startingTime}}点 - {{f.endTime}}点 {{f.fileCount}}
视频暂不能访问,请登录试试
仅供内部学术交流或培训使用,请先保存到本地。本内容不代表科创观点,未经原作者同意,请勿转载。
音频暂不能访问,请登录试试
支持的图片格式:jpg, jpeg, png
插入公式
评论控制
加载中...
文号:{{pid}}
投诉或举报
加载中...
{{tip}}
请选择违规类型:
{{reason.type}}

空空如也

加载中...
详情
详情
推送到专栏从专栏移除
设为匿名取消匿名
查看作者
回复
只看作者
加入收藏取消收藏
收藏
取消收藏
折叠回复
置顶取消置顶
评学术分
鼓励
设为精选取消精选
管理提醒
编辑
通过审核
评论控制
退修或删除
历史版本
违规记录
投诉或举报
加入黑名单移除黑名单
查看IP
{{format('YYYY/MM/DD HH:mm:ss', toc)}}