;#########################
;是男人就上120层破解记录
;2004-02-01
;ohko.com@163.com
;http://www.ohko.com
;如果转载请不要删除此信息
;#########################
今天在网上逛,看到一篇关于这个游戏的文章,突然想起,自己的这个程序还没注册.哎呀,就动手来试试吧.这个游戏早就出来了,
相信大家都玩过了,也可能已经注册了.如果不是自己的注册码就看下去,搞个自己的注册码来注册吧.
;#########################
;程序:是男人就上120层
;工具:Ollydbg (如果没有,网上到处都有,很小的,下载吧.)
;时间:不会超过0.5小时的
;#########################
打开Ollydbg,载用"是男人就上120层"这个程序.好,载入出,自动停在了程序的入口点上了.
不要急,现在我们要先下断点.按"CTRL+N".找到"GetDlgItemTextA",按"回车",会弹出窗口的,在每一项上按"F2",每一个都断点.
好,现在断点好了,按"F9"运行程序.游戏运行后,点注册.
用户名: ohko
注册码: 1234567
确定.怎么样,断点对了,拦截在00402FC6处.
就是下面的代码了.
下面就一下一下的按"F8"
00402FC6 > 68 00010000 PUSH 100 ; /Count = 100 (256.)
00402FCB . 8D85 FCFDFFFF LEA EAX, DWORD PTR SS:[EBP-204] ; |
00402FD1 . 50 PUSH EAX ; |Buffer
00402FD2 . 68 EB030000 PUSH 3EB ; |ControlID = 3EB (1003.)
00402FD7 . 8B45 08 MOV EAX, DWORD PTR SS:[EBP+8] ; |
00402FDA . 50 PUSH EAX ; |hWnd
00402FDB . FF15 78F34000 CALL DWORD PTR DS:[<&USER32.GetDlg>; GetDlgItemTextA 取得用户输入的注册码
00402FE1 . 8D85 FCFDFFFF LEA EAX, DWORD PTR SS:[EBP-204]
00402FE7 . 50 PUSH EAX ; [注册码]
;注意这里了00402FE8,下面就是验证注册码的了,要跟进去,按"F7"进入.
00402FE8 . E8 C0010000 CALL 是男人就.004031AD ;!!!这里就是验证注册码了就.004031AD!!!
00402FED . 83C4 04 ADD ESP, 4
00402FF0 . 85C0 TEST EAX, EAX ; 测试EAX,就是说注册码是否是正确的
00402FF2 . 0F85 37000000 JNZ 是男人就.0040302F ; 是对的就跳,不对不完了,失败框框302F
00402FF8 . 68 00010000 PUSH 100 ; /Count = 100 (256.)
00402FFD . 8D85 FCFEFFFF LEA EAX, DWORD PTR SS:[EBP-104] ; |
00403003 . 50 PUSH EAX ; |Buffer
00403004 . 6A 04 PUSH 4 ; |RsrcID = STRING "注册码不煌炅?失?"
00403006 . A1 98D24000 MOV EAX, DWORD PTR DS:[40D298] ; |
0040300B . 50 PUSH EAX ; |hInst => 00400000
0040300C . FF15 BCF34000 CALL DWORD PTR DS:[<&USER32.LoadSt>; LoadStringA
00403012 . 6A 10 PUSH 10 ; /Style = MB_OK|MB_ICONHAND|MB_APPLMODAL
00403014 . 68 6CC24000 PUSH 是男人就.0040C26CNHAN ; |Title = "NS-TOWER"
00403019 . 8D85 FCFEFFFF LEA EAX, DWORD PTR SS:[EBP-104] ; |
0040301F . 50 PUSH EAX ; |Text
00403020 . 8B45 08 MOV EAX, DWORD PTR SS:[EBP+8] ; |
00403023 . 50 PUSH EAX ; |hOwner
00403024 . FF15 B8F34000 CALL DWORD PTR DS:[<&USER32.Messag>; MessageBoxA
0040302A . E9 41000000 JMP 是男人就.00403070[<&U
0040302F > 68 00010000 PUSH 100 ; /Count = 100 (256.)
00403034 . 8B45 FC MOV EAX, DWORD PTR SS:[EBP-4] ; |
00403037 . 83C0 10 ADD EAX, 10 ; |
0040303A . 50 PUSH EAX ; |Buffer
0040303B . 68 EA030000 PUSH 3EA ; |ControlID = 3EA (1002.)
00403040 . 8B45 08 MOV EAX, DWORD PTR SS:[EBP+8] ; |
00403043 . 50 PUSH EAX ; |hWnd
00403044 . FF15 78F34000 CALL DWORD PTR DS:[<&USER32.GetDlg>; GetDlgItemTextA
0040304A . 6A 08 PUSH 8 ; /Count = 8
0040304C . 8B45 FC MOV EAX, DWORD PTR SS:[EBP-4] ; |
0040304F . 05 10010000 ADD EAX, 110 ; |
00403054 . 50 PUSH EAX ; |Buffer
00403055 . 68 EB030000 PUSH 3EB ; |ControlID = 3EB (1003.)
0040305A . 8B45 08 MOV EAX, DWORD PTR SS:[EBP+8] ; |
0040305D . 50 PUSH EAX ; |hWnd
0040305E . FF15 78F34000 CALL DWORD PTR DS:[<&USER32.GetDlg>; GetDlgItemTextA
00403064 . 6A 00 PUSH 0 ; /Result = 0
00403066 . 8B45 08 MOV EAX, DWORD PTR SS:[EBP+8] ; |
00403069 . 50 PUSH EAX ; |hWnd
0040306A . FF15 7CF34000 CALL DWORD PTR DS:[<&USER32.EndDia>; EndDialog
004031AD $ 55 PUSH EBP
004031AE . 8BEC MOV EBP, ESP
004031B0 . 83EC 04 SUB ESP, 4
004031B3 . 53 PUSH EBX
004031B4 . 56 PUSH ESI
004031B5 . 57 PUSH EDI
004031B6 . 8B45 08 MOV EAX, DWORD PTR SS:[EBP+8] ; 注册码给[EAX]
004031B9 . 33C9 XOR ECX, ECX ; 清空ECX
004031BB . 8A48 07 MOV CL, BYTE PTR DS:[EAX+7] ; 把注册码的第8个注册码给CL,下面要用于判断的
004031BE . 85C9 TEST ECX, ECX ; 测试ECX是否是空
004031C0 . 0F84 07000000 JE 是男人就.004031CD ; 如果是空就跳,不是空就继续.也就是说,注册码必须小于8位.
004031C6 . 33C0 XOR EAX, EAX ; 清空EAX
004031C8 . E9 45010000 JMP 是男人就.00403312 ; 弹出[注册失败的框框]
004031CD > C745 FC 0000000>MOV DWORD PTR SS:[EBP-4], 0 ; 这个地址放的数据是循环用的,从0到7
004031D4 . E9 03000000 JMP 是男人就.004031DC ; 跳
004031D9 > FF45 FC INC DWORD PTR SS:[EBP-4] ; 循环数++
004031DC > 837D FC 07 CMP DWORD PTR SS:[EBP-4], 7 ; 循环数与7比较
004031E0 . 0F8D 2B000000 JGE 是男人就.00403211 ; 循环数>=7就跳
004031E6 . 8B45 FC MOV EAX, DWORD PTR SS:[EBP-4] ; 循环数给EAX
004031E9 . 8B4D 08 MOV ECX, DWORD PTR SS:[EBP+8] ; 注册码地址给ECX
004031EC . 8A0408 MOV AL, BYTE PTR DS:[EAX+ECX] ; 循环数+注册码地址里的数据给AL
004031EF . 50 PUSH EAX ; EAX进栈
004031F0 . E8 22010000 CALL 是男人就.00403317 ; 调用子程序,如果是数字就转换成16进制数(31h->1h),如果是字母,就转换成大写.不能是符号
004031F5 . 83C4 04 ADD ESP, 4
004031F8 . 33C9 XOR ECX, ECX ; ECX清空
004031FA . 8AC8 MOV CL, AL ; AL给CL
004031FC . 83F9 24 CMP ECX, 24 ; 把用一位注册码算出的数据与24"$"比较
004031FF . 0F8E 07000000 JLE 是男人就.0040320C ; 这里说明注册码只能是数字或字母,不然就给你注册失败的框框
00403205 . 33C0 XOR EAX, EAX ; 清空EAX
00403207 . E9 06010000 JMP 是男人就.00403312 ; 弹出[注册失败的框框]
0040320C > E9 C8FFFFFF JMP 是男人就.004031D9
00403211 > 8B45 08 MOV EAX, DWORD PTR SS:[EBP+8] ; 注册码地址给EAX
00403214 . 8A40 05 MOV AL, BYTE PTR DS:[EAX+5] ; 把注册码的第6位给AL
00403217 . 50 PUSH EAX ; EAX进栈
00403218 . E8 FA000000 CALL 是男人就.00403317 ; 这个子程序不是很清楚是做什么的,我想是用注册码的第6位来算出个密钥吧,可后面还调用了它,再看看吧.
0040321D . 83C4 04 ADD ESP, 4
00403220 . 33DB XOR EBX, EBX
00403222 . 8AD8 MOV BL, AL ; 调用子程序换算出的东东给BL
00403224 . 8B45 08 MOV EAX, DWORD PTR SS:[EBP+8] ; 注册码地址给EAX
00403227 . 8A40 02 MOV AL, BYTE PTR DS:[EAX+2] ; 注册码第3位给AL
0040322A . 50 PUSH EAX ; EAX进栈
0040322B . E8 E7000000 CALL 是男人就.00403317 ; 上面以调用过此子程序了,又来了.就不用跟进去了
00403230 . 83C4 04 ADD ESP, 4
00403233 . 33C9 XOR ECX, ECX
00403235 . 8AC8 MOV CL, AL ; 调用子程序换算出的东东给CL
00403237 . BE 24000000 MOV ESI, 24 ; ESI=24
0040323C . 8D4459 1C LEA EAX, DWORD PTR DS:[ECX+EBX*2+1C] ; 哦,这里把换算回的两个数字加起来了,把[ECX+EBX*2+1C]算出的值给EAX
00403240 . 99 CDQ ; 清空EDX,下面要做除法了
00403241 . F7FE IDIV ESI ; EAX/ESI(24h),商给EAX,余于给EDX
00403243 . 8BDA MOV EBX, EDX ; 余数给EBX
00403245 . 8B45 08 MOV EAX, DWORD PTR SS:[EBP+8] ; 注册码地址给EAX
00403248 . 8A00 MOV AL, BYTE PTR DS:[EAX] ; 注册码第1位给AL
0040324A . 50 PUSH EAX ; EAX进栈
0040324B . E8 C7000000 CALL 是男人就.00403317 ; 这个子程序又调用了,不用跟了
00403250 . 83C4 04 ADD ESP, 4
00403253 . 33C9 XOR ECX, ECX
00403255 . 8AC8 MOV CL, AL ; 转回的东东给CL
00403257 . 3BD9 CMP EBX, ECX ; 上面数出来的余数和注册码第一位算出的数比较
00403259 . 0F85 AC000000 JNZ 是男人就.0040330B ; 哎呀,不得了,如果不相等就跳,跳出失败框框哦
0040325F . 8B45 08 MOV EAX, DWORD PTR SS:[EBP+8] ; 注册码地址再次给了EAX
00403262 . 8A40 04 MOV AL, BYTE PTR DS:[EAX+4] ; 把注册码第5位给AL
00403265 . 50 PUSH EAX ; EAX进栈
00403266 . E8 AC000000 CALL 是男人就.00403317 ; 看,是不是,这个子程序又调用了,哈哈,不用跟了
0040326B . 83C4 04 ADD ESP, 4
0040326E . 33DB XOR EBX, EBX
00403270 . 8AD8 MOV BL, AL ; 哎呀,累不累,下面这一段不用看也知道是,和上面一样的嘛,一看就知道
00403272 . 8B45 08 MOV EAX, DWORD PTR SS:[EBP+8] ; 这下面就简单说说了
00403275 . 8A40 01 MOV AL, BYTE PTR DS:[EAX+1] ; 注册码第2位
00403278 . 50 PUSH EAX
00403279 . E8 99000000 CALL 是男人就.00403317
0040327E . 83C4 04 ADD ESP, 4
00403281 . 33C9 XOR ECX, ECX
00403283 . 8AC8 MOV CL, AL
00403285 . BE 24000000 MOV ESI, 24
0040328A . 8D4459 1C LEA EAX, DWORD PTR DS:[ECX+EBX*2+1C] ; 做算术(ECX+EBX*2+1C)
0040328E . 99 CDQ
0040328F . F7FE IDIV ESI ; 做除法(EAX/ESI)
00403291 . 8BDA MOV EBX, EDX
00403293 . 8B45 08 MOV EAX, DWORD PTR SS:[EBP+8]
00403296 . 8A40 06 MOV AL, BYTE PTR DS:[EAX+6] ; 注册码第7位给AL
00403299 . 50 PUSH EAX
0040329A . E8 78000000 CALL 是男人就.00403317 ; 又调用了这个子程序,不跟
0040329F . 83C4 04 ADD ESP, 4
004032A2 . 33C9 XOR ECX, ECX
004032A4 . 8AC8 MOV CL, AL
004032A6 . 3BD9 CMP EBX, ECX ; 和上面一样,比来个比较,上次上第6位和第3位算出的数据与第1位算出的比较,这次就是第5位和第2位算出的数据和第7位算出的数据比较
004032A8 . 0F85 5D000000 JNZ 是男人就.0040330B ; 不等就跳,跳到失败框
004032AE . 8B45 08 MOV EAX, DWORD PTR SS:[EBP+8] ; 下面又是一样的
004032B1 . 8A40 06 MOV AL, BYTE PTR DS:[EAX+6] ; 这是第7位给AL
004032B4 . 50 PUSH EAX
004032B5 . E8 5D000000 CALL 是男人就.00403317 ; 调
004032BA . 83C4 04 ADD ESP, 4
004032BD . 33DB XOR EBX, EBX
004032BF . 8AD8 MOV BL, AL
004032C1 . 8B45 08 MOV EAX, DWORD PTR SS:[EBP+8]
004032C4 . 8A00 MOV AL, BYTE PTR DS:[EAX] ; 这是第1位给AL
004032C6 . 50 PUSH EAX
004032C7 . E8 4B000000 CALL 是男人就.00403317 ; 调
004032CC . 83C4 04 ADD ESP, 4
004032CF . 33C9 XOR ECX, ECX
004032D1 . 8AC8 MOV CL, AL
004032D3 . BE 24000000 MOV ESI, 24
004032D8 . 8D4459 1C LEA EAX, DWORD PTR DS:[ECX+EBX*2+1C] ; 再做一次算数
004032DC . 99 CDQ
004032DD . F7FE IDIV ESI ; 再做一次除法
004032DF . 8BDA MOV EBX, EDX
004032E1 . 8B45 08 MOV EAX, DWORD PTR SS:[EBP+8]
004032E4 . 8A40 03 MOV AL, BYTE PTR DS:[EAX+3] ; 第4位给AL,下面去调子程序算
004032E7 . 50 PUSH EAX
004032E8 . E8 2A000000 CALL 是男人就.00403317 ; 又调
004032ED . 83C4 04 ADD ESP, 4
004032F0 . 33C9 XOR ECX, ECX
004032F2 . 8AC8 MOV CL, AL
004032F4 . 3BD9 CMP EBX, ECX
004032F6 . 0F85 0F000000 JNZ 是男人就.0040330B ; 不等就给你失败框
004032FC . B8 01000000 MOV EAX, 1 ; EAX=1,就是说注册码验证成功
00403301 . E9 0C000000 JMP 是男人就.00403312 ; 好了注册码看来是验证完了,准备跳出这个子程序了,回到主程序
00403306 . E9 07000000 JMP 是男人就.00403312
0040330B > 33C0 XOR EAX, EAX
0040330D . E9 00000000 JMP 是男人就.00403312
00403312 > 5F POP EDI
00403313 . 5E POP ESI
00403314 . 5B POP EBX
00403315 . C9 LEAVE
00403316 . C3 RETN
00403317 /$ 55 PUSH EBP
00403318 |. 8BEC MOV EBP, ESP
0040331A |. 53 PUSH EBX
0040331B |. 56 PUSH ESI
0040331C |. 57 PUSH EDI
0040331D |. 33C0 XOR EAX, EAX
0040331F |. 8A45 08 MOV AL, BYTE PTR SS:[EBP+8] ; 调用此子程序时传来的东东给AL,这里是注册码的第6位
00403322 |. 83F8 61 CMP EAX, 61 ; EAX与61"a"比较
00403325 |. 0F8C 0B000000 JL 是男人就.00403336 ; 小于就跳
0040332B |. 33C0 XOR EAX, EAX ; 清空EAX
0040332D |. 8A45 08 MOV AL, BYTE PTR SS:[EBP+8] ; 转来的东东给AL
00403330 |. 83E8 20 SUB EAX, 20 ; EAX-20h
00403333 |. 8845 08 MOV BYTE PTR SS:[EBP+8], AL ; 还回去
00403336 |> 33C0 XOR EAX, EAX ; 清空EAX
00403338 |. 8A45 08 MOV AL, BYTE PTR SS:[EBP+8] ; 传来的东东再次给AL
0040333B |. 83F8 41 CMP EAX, 41 ; EAX与41"A"比较
0040333E |. 0F8C 0B000000 JL 是男人就.0040334F ; 小于就跳
00403344 |. 33C0 XOR EAX, EAX ; 清空EAX
00403346 |. 8A45 08 MOV AL, BYTE PTR SS:[EBP+8] ; 把转来的西西给AL
00403349 |. 83E8 07 SUB EAX, 7 ; EAX-7
0040334C |. 8845 08 MOV BYTE PTR SS:[EBP+8], AL ; 还给转来的东东
0040334F |> 33C0 XOR EAX, EAX ; 再清空EAX
00403351 |. 8A45 08 MOV AL, BYTE PTR SS:[EBP+8] ; 还是那个传来的东西给AL
00403354 |. 83E8 30 SUB EAX, 30 ; EAX-30"0",也就是把ASCII数字转换成十六进制了.上面已经判断出不是字母,那就一定是数字了
00403357 |. E9 00000000 JMP 是男人就.0040335C ; 没什么用,多于的跳转命令,不如删除了
0040335C |> 5F POP EDI
0040335D |. 5E POP ESI
0040335E |. 5B POP EBX
0040335F |. C9 LEAVE
00403360 . C3 RETN
好了,结束了,算法出来了,就是这样了
([3]+[6]*2+1C) % 24 与 [1]
([2]+[5]*2+1C) % 24 与 [7]
([1]+[7]*2+1C) % 24 与 [4]
if [?]<"a" then jl _NEXT
else [?]-20h
if [?]<"A" then jl _NEXT
else [?]-7h
_NEXT [?]-30h