●黑石(BlackStone)
连珠(五子棋)对弈/辅助计算软件。BlackStone本意为棋子中的黑子,在国内通译为黑石。
黑石由俄罗斯人Victor Barykin开发,最早的版本发布于1997年。黑石被公认为目前已公开发布的连珠/五子棋对弈软件中综合棋力最强的,曾获得第二、三届世界计算机连珠程序锦标赛(Renju Computer World Championship)竞赛组冠军。黑石采用的对弈规则为三手交换,五手两打,有禁手,可调节难度(剪枝方法、计算深度和时间),4.0以后的版本可调节棋盘线数。黑石的局部计算能力强大,被普遍用于局面研究拆解和网络五子棋对弈。2000年传入中国后,对连珠/五子棋开局理论的研究起到了前所未有的巨大推进作用,并成为网络连珠/五子棋对弈中最常用的辅助计算软件。在黑石传入中国后的短短几年中,依靠黑石发展、修正、建立起的连珠/五子棋开局理论,超过了过去一百多年全世界连珠/五子棋开局理论总和的数百甚至上千倍之多;目前高水平的网络五子棋对弈、比赛,参赛选手绝大多选用黑石作为辅助计算工具。
软件明码比较,压缩壳,我们带壳调试,使用a_p大哥修改的野猪OD.
////////////
00517000 > 53 PUSH EBX ; OD载入后来到这里
00517001 55 PUSH EBP
00517002 89C5 MOV EBP,EAX
00517004 33DB XOR EBX,EBX
00517006 EB 60 JMP SHORT Wrenju.00517068 ; F8单步一次
////////////
00517068 E8 00000000 CALL Wrenju.0051706D ; JMP后来到这里
0051706D 58 POP EAX
0051706E 2D 6D000000 SUB EAX,6D
00517073 50 PUSH EAX
00517074 60 PUSHAD ; 我们看到这里有PUSHAD
00517075 33C9 XOR ECX,ECX ; 所以我们向下找一下POPAD
……
……
……
00517282 61 POPAD ; 在这里看到了POPAD
00517283 58 POP EAX
00517284 8BE8 MOV EBP,EAX
00517286 2E:0385 9502000>ADD EAX,DWORD PTR CS:[EBP+295]
0051728D 05 99020000 ADD EAX,299
00517292 5D POP EBP
00517293 5B POP EBX
00517294 ^ E9 17B0F6FF JMP Wrenju.004822B0 ; JMP到OEP // 我们在该行左键单击 然后F4来到这里
////////////
004822B0 55 PUSH EBP ; 来到OEP
004822B1 8BEC MOV EBP,ESP
004822B3 83C4 F4 ADD ESP,-0C
004822B6 53 PUSH EBX
////////////
F9运行,我们用OD的插件下万能断点来拦截注册部分:
77D3353D F3:A5 REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS>; 断到这里,ESI中显示我们输入的假码
77D3353F 8BC8 MOV ECX,EAX
77D33541 83E1 03 AND ECX,3
77D33544 F3:A4 REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[>
77D33546 E8 E3FBFFFF CALL user32.77D3312E
77D3354B 5F POP EDI
77D3354C 5E POP ESI
77D3354D 8BC3 MOV EAX,EBX
77D3354F 5B POP EBX
77D33550 5D POP EBP
77D33551 C2 1000 RETN 10 ; 我们Ctrl+F9一路返回到程序领空
00469084 55 PUSH EBP
00469085 8BEC MOV EBP,ESP
00469087 83C4 E4 ADD ESP,-1C
0046908A 53 PUSH EBX
0046908B 56 PUSH ESI
0046908C 57 PUSH EDI
0046908D 33C9 XOR ECX,ECX
0046908F 894D E4 MOV DWORD PTR SS:[EBP-1C],ECX
00469092 894D E8 MOV DWORD PTR SS:[EBP-18],ECX
00469095 8BD8 MOV EBX,EAX
00469097 33C0 XOR EAX,EAX
00469099 55 PUSH EBP
0046909A 68 F2924600 PUSH Wrenju.004692F2
0046909F 64:FF30 PUSH DWORD PTR FS:[EAX]
004690A2 64:8920 MOV DWORD PTR FS:[EAX],ESP
004690A5 8D55 E8 LEA EDX,DWORD PTR SS:[EBP-18]
004690A8 8B83 FC010000 MOV EAX,DWORD PTR DS:[EBX+1FC]
004690AE E8 E95DFBFF CALL Wrenju.0041EE9C ; 该CALL取假码
004690B3 8B45 E8 MOV EAX,DWORD PTR SS:[EBP-18] ; 我们返回到这里
004690B6 8D55 FC LEA EDX,DWORD PTR SS:[EBP-4]
004690B9 E8 769BF9FF CALL Wrenju.00402C34
004690BE 8BF8 MOV EDI,EAX
004690C0 A1 E8424800 MOV EAX,DWORD PTR DS:[4842E8]
004690C5 8B00 MOV EAX,DWORD PTR DS:[EAX]
004690C7 8BCF MOV ECX,EDI
004690C9 BA 08000000 MOV EDX,8
004690CE E8 1D2CFFFF CALL Wrenju.0045BCF0
004690D3 8D55 E8 LEA EDX,DWORD PTR SS:[EBP-18]
004690D6 8B83 00020000 MOV EAX,DWORD PTR DS:[EBX+200]
004690DC E8 BB5DFBFF CALL Wrenju.0041EE9C
004690E1 8B45 E8 MOV EAX,DWORD PTR SS:[EBP-18] ; 该CALL取得Serial Number数值
004690E4 E8 5FE2F9FF CALL Wrenju.00407348
004690E9 8BF0 MOV ESI,EAX ; 将Serial Number数值转化为16进制后保存到ESI
004690EB 81C6 6B030000 ADD ESI,36B ; Serial Number数值+36BH
004690F1 A1 E8424800 MOV EAX,DWORD PTR DS:[4842E8]
004690F6 8B00 MOV EAX,DWORD PTR DS:[EAX]
004690F8 8BCE MOV ECX,ESI
004690FA BA 09000000 MOV EDX,9
004690FF E8 EC2BFFFF CALL Wrenju.0045BCF0
00469104 A1 E8424800 MOV EAX,DWORD PTR DS:[4842E8]
00469109 8B00 MOV EAX,DWORD PTR DS:[EAX]
0046910B 8B0D 70274A00 MOV ECX,DWORD PTR DS:[4A2770]
00469111 BA 07000000 MOV EDX,7
00469116 E8 D52BFFFF CALL Wrenju.0045BCF0
0046911B 56 PUSH ESI
0046911C 8B0D 74274A00 MOV ECX,DWORD PTR DS:[4A2774] ; Computer Number数值放ECX
00469122 8B15 70274A00 MOV EDX,DWORD PTR DS:[4A2770] ; Serial Number 数值放EDX
00469128 8BC7 MOV EAX,EDI
0046912A E8 3932FFFF CALL Wrenju.0045C368 ; 算法CALL 我们跟进
0046912F 8B15 28434800 MOV EDX,DWORD PTR DS:[484328] ; Wrenju.004A272D
00469135 C602 00 MOV BYTE PTR DS:[EDX],0
00469138 48 DEC EAX
00469139 0F84 8E010000 JE Wrenju.004692CD
0046913F 48 DEC EAX
00469140 74 64 JE SHORT Wrenju.004691A6
00469142 48 DEC EAX
00469143 74 0C JE SHORT Wrenju.00469151 ; 这里跳向注册成功 若想实现这里跳转算法CALL返回时EAX数值应为3
00469145 48 DEC EAX
00469146 0F84 9B000000 JE Wrenju.004691E7 ; 这里跳向注册成功 若想实现这里跳转算法CALL返回时EAX数值应为4
0046914C E9 CD000000 JMP Wrenju.0046921E
00469151 8B0D 78444800 MOV ECX,DWORD PTR DS:[484478] ; Wrenju.004A2784
00469157 8B09 MOV ECX,DWORD PTR DS:[ECX]
00469159 A1 E8424800 MOV EAX,DWORD PTR DS:[4842E8]
0046915E 8B00 MOV EAX,DWORD PTR DS:[EAX]
00469160 BA 01000000 MOV EDX,1
00469165 E8 4A2DFFFF CALL Wrenju.0045BEB4
0046916A 83F8 01 CMP EAX,1
0046916D 74 05 JE SHORT Wrenju.00469174
0046916F 83F8 16 CMP EAX,16
00469172 75 15 JNZ SHORT Wrenju.00469189
00469174 6A 00 PUSH 0
00469176 68 00934600 PUSH Wrenju.00469300 ; ASCII "Success"
0046917B 68 08934600 PUSH Wrenju.00469308 ; ASCII "Application authorization complete"
00469180 6A 00 PUSH 0
00469182 E8 F9CFF9FF CALL <JMP.&user32.MessageBoxA>
00469187 EB 0B JMP SHORT Wrenju.00469194
00469189 BA 2C934600 MOV EDX,Wrenju.0046932C ; ASCII "Application Violation - Error #"
0046918E 92 XCHG EAX,EDX
0046918F E8 28080000 CALL Wrenju.004699BC
00469194 E8 8FFCFFFF CALL Wrenju.00468E28
00469199 A1 28434800 MOV EAX,DWORD PTR DS:[484328]
0046919E C600 01 MOV BYTE PTR DS:[EAX],1
004691A1 E9 27010000 JMP Wrenju.004692CD
004691A6 8B15 78444800 MOV EDX,DWORD PTR DS:[484478] ; Wrenju.004A2784
004691AC 8B12 MOV EDX,DWORD PTR DS:[EDX]
004691AE A1 E8424800 MOV EAX,DWORD PTR DS:[4842E8]
004691B3 8B00 MOV EAX,DWORD PTR DS:[EAX]
004691B5 E8 EE2DFFFF CALL Wrenju.0045BFA8
004691BA 83F8 01 CMP EAX,1
004691BD 74 10 JE SHORT Wrenju.004691CF
004691BF BA 4C934600 MOV EDX,Wrenju.0046934C ; ASCII "De-authorization failed - Error #"
004691C4 92 XCHG EAX,EDX
004691C5 E8 F2070000 CALL Wrenju.004699BC
004691CA E9 FE000000 JMP Wrenju.004692CD
004691CF 6A 00 PUSH 0
004691D1 68 00934600 PUSH Wrenju.00469300 ; ASCII "Success"
004691D6 68 70934600 PUSH Wrenju.00469370 ; ASCII "Application de-authorization complete"
004691DB 6A 00 PUSH 0
004691DD E8 9ECFF9FF CALL <JMP.&user32.MessageBoxA>
004691E2 E9 E6000000 JMP Wrenju.004692CD
004691E7 8B0D 78444800 MOV ECX,DWORD PTR DS:[484478] ; 当退出算法CALL时,EAX=4时跳到这里
004691ED 8B09 MOV ECX,DWORD PTR DS:[ECX]
004691EF A1 E8424800 MOV EAX,DWORD PTR DS:[4842E8]
004691F4 8B00 MOV EAX,DWORD PTR DS:[EAX]
004691F6 BA 01000000 MOV EDX,1
004691FB E8 B42CFFFF CALL Wrenju.0045BEB4
00469200 E8 4F080000 CALL Wrenju.00469A54 ; 弹出注册成功对话框 我们跟进看看
00469205 33C0 XOR EAX,EAX
00469207 E8 3C090000 CALL Wrenju.00469B48
0046920C E8 17FCFFFF CALL Wrenju.00468E28
00469211 A1 28434800 MOV EAX,DWORD PTR DS:[484328]
00469216 C600 01 MOV BYTE PTR DS:[EAX],1
00469219 E9 AF000000 JMP Wrenju.004692CD
0046921E 6A 00 PUSH 0
00469220 68 98934600 PUSH Wrenju.00469398 ; ASCII "Invalid Code"
00469225 68 A8934600 PUSH Wrenju.004693A8 ; ASCII "Invalid Code Entered!"
0046922A 6A 00 PUSH 0
0046922C E8 4FCFF9FF CALL <JMP.&user32.MessageBoxA>
我们跟进算法CALL 0045BEB4
0045C368 55 push ebp ; EAX=假码
0045C369 8BEC mov ebp, esp ; ECX=(Computer Number)
0045C36B 53 push ebx ; EDX=(Code Entry)
0045C36C 56 push esi
0045C36D 57 push edi
0045C36E 8345 08 34 add dword ptr [ebp+8], 34 ; [ebp+8]存放的是数值=Serial Number +36BH
0045C372 83F9 01 cmp ecx, 1
0045C375 7D 05 jge short 0045C37C ; 我们要注意这一个跳转,如果Computer Number为字母时,ECX和EDX均为0
0045C377 B9 01000000 mov ecx, 1 ; 若ECX为0,则这里向ECX赋值为1
0045C37C 8BDA mov ebx, edx
0045C37E 81E3 00E00700 and ebx, 7E000 ; EDX AND 7E000
0045C384 C1EB 0D shr ebx, 0D ; 逻辑右移 D
0045C387 81C3 BC070000 add ebx, 7BC ; EBX+=7BC
0045C38D 6BDB 44 imul ebx, ebx, 44 ; *44
0045C390 8BF2 mov esi, edx ; EDX放到ESI
0045C392 81E6 00007800 and esi, 780000 ; ESI AND 7E000
0045C398 C1EE 13 shr esi, 13 ; 逻辑右移 13
0045C39B 69F6 08010000 imul esi, esi, 108 ; *108
0045C3A1 03DE add ebx, esi ; EBX+=ESI
0045C3A3 8BF2 mov esi, edx ; EDX放到ESI
0045C3A5 81E6 001F0000 and esi, 1F00
0045C3AB C1EE 08 shr esi, 8
0045C3AE 69F6 F3000000 imul esi, esi, 0F3
0045C3B4 03DE add ebx, esi ; 再相加
0045C3B6 8BF2 mov esi, edx ; 再放ESI
0045C3B8 81E6 0000807F and esi, 7F800000
0045C3BE C1EE 0F shr esi, 0F
0045C3C1 81E2 FF000000 and edx, 0FF ; EDX AND FF
0045C3C7 03F2 add esi, edx ; ESI+=EDX
0045C3C9 8D1476 lea edx, dword ptr [esi+esi*2] ; ESI*3 送EDX
0045C3CC 03C9 add ecx, ecx ; ECX*2
0045C3CE 03D1 add edx, ecx ; EDX+=ECX
0045C3D0 8BCA mov ecx, edx ; EDX放ECX
0045C3D2 8BD3 mov edx, ebx ; EBX =》ECX
0045C3D4 C1E2 05 shl edx, 5 ; 逻辑左移5
0045C3D7 2BD3 sub edx, ebx ; 减法
0045C3D9 8B75 08 mov esi, dword ptr [ebp+8] ; [ebp+8]存放的是数值=Serial Number +36BH +34H
0045C3DC 8BFE mov edi, esi
0045C3DE C1E6 03 shl esi, 3
0045C3E1 2BF7 sub esi, edi ; -
0045C3E3 03CE add ecx, esi ; +
0045C3E5 03CA add ecx, edx
0045C3E7 8BF3 mov esi, ebx
0045C3E9 03F6 add esi, esi
0045C3EB BA 01000000 mov edx, 1 ; EDX做计数器
0045C3F0 8BD9 mov ebx, ecx ; ECX送EBX
0045C3F2 81E3 FFFFFF7F and ebx, 7FFFFFFF ; 与运算
0045C3F8 3BC3 cmp eax, ebx ; EAX的十进制即为我们输入的假码
0045C3FA 75 04 jnz short 0045C400
0045C3FC 8BC2 mov eax, edx ; EDX将循环结果放EAX中
0045C3FE EB 0A jmp short 0045C40A
0045C400 03CE add ecx, esi
0045C402 42 inc edx ; 循环到3或4时 EBX出现的便是真码//为何要循环三次或四次呢,我们看下文
0045C403 83FA 33 cmp edx, 33
0045C406 ^ 75 E8 jnz short 0045C3F0
0045C408 33C0 xor eax, eax
0045C40A 5F pop edi
0045C40B 5E pop esi
0045C40C 5B pop ebx
0045C40D 5D pop ebp
0045C40E C2 0400 retn 4
这里EAX=?EBX中即为真值是通过返回算法CALL后,是通过EDC EAX 下放这句JE==>注册成功来推断出来的。通过观察明显可看到当EAX=3时注册成功,当EAX=其他值时,我们也来看一下。当EAX=4时,退出算法CALL后来到这里:
004691E7 8B0D 78444800 MOV ECX,DWORD PTR DS:[484478] ; 当退出算法CALL时,EAX=4时跳到这里
004691ED 8B09 MOV ECX,DWORD PTR DS:[ECX]
004691EF A1 E8424800 MOV EAX,DWORD PTR DS:[4842E8]
004691F4 8B00 MOV EAX,DWORD PTR DS:[EAX]
004691F6 BA 01000000 MOV EDX,1
004691FB E8 B42CFFFF CALL Wrenju.0045BEB4
00469200 E8 4F080000 CALL Wrenju.00469A54 ; 弹出注册成功对话框 我们跟进看看
跟进CALL 00469A54:
00469A54 83C4 E8 ADD ESP,-18
00469A57 A1 E8424800 MOV EAX,DWORD PTR DS:[4842E8]
00469A5C 8B00 MOV EAX,DWORD PTR DS:[EAX]
00469A5E B9 F09A4600 MOV ECX,Wrenju.00469AF0
00469A63 BA 09000000 MOV EDX,9
00469A68 E8 E722FFFF CALL Wrenju.0045BD54
00469A6D 8D4424 08 LEA EAX,DWORD PTR SS:[ESP+8]
00469A71 50 PUSH EAX
00469A72 E8 11C0F9FF CALL <JMP.&kernel32.GetLocalTime>
00469A77 8D4424 08 LEA EAX,DWORD PTR SS:[ESP+8]
00469A7B E8 24ECF9FF CALL Wrenju.004086A4
00469A80 D805 F49A4600 FADD DWORD PTR DS:[469AF4]
00469A86 DD1C24 FSTP QWORD PTR SS:[ESP]
00469A89 9B WAIT
00469A8A FF7424 04 PUSH DWORD PTR SS:[ESP+4]
00469A8E FF7424 04 PUSH DWORD PTR SS:[ESP+4]
00469A92 8D4424 10 LEA EAX,DWORD PTR SS:[ESP+10]
00469A96 E8 D1EBF9FF CALL Wrenju.0040866C
00469A9B 66:8B4424 0A MOV AX,WORD PTR SS:[ESP+A]
00469AA0 50 PUSH EAX
00469AA1 66:8B4424 0C MOV AX,WORD PTR SS:[ESP+C]
00469AA6 50 PUSH EAX
00469AA7 A1 E8424800 MOV EAX,DWORD PTR DS:[4842E8]
00469AAC 8B00 MOV EAX,DWORD PTR DS:[EAX]
00469AAE 66:8B4C24 16 MOV CX,WORD PTR SS:[ESP+16]
00469AB3 BA 02000000 MOV EDX,2
00469AB8 E8 5723FFFF CALL Wrenju.0045BE14
00469ABD 83F8 01 CMP EAX,1
00469AC0 75 15 JNZ SHORT Wrenju.00469AD7
00469AC2 6A 00 PUSH 0
00469AC4 68 F89A4600 PUSH Wrenju.00469AF8 ; ASCII "Success!"
00469AC9 68 049B4600 PUSH Wrenju.00469B04 ; ASCII "Application authorization complete"
00469ACE 6A 00 PUSH 0
00469AD0 E8 ABC6F9FF CALL <JMP.&user32.MessageBoxA>
00469AD5 EB 0B JMP SHORT Wrenju.00469AE2
综上所述,退出算法CALL时EAX数值为3或4时,EBX保存的为真码。但我用KeyMake做了内存KG,取截取不到注册码,不知为何,KeyMake设置如下:
这款软件还有一种注册情况,就是Code Entry和Computer Number这里出现的并非数字,而是字母,此时只要将算法部分的变量A和B重新赋值即可。
我们看一下应该赋值为多少,我们看算法CALL中这个关键语句:
0045C372 83F9 01 cmp ecx, 1
0045C375 7D 05 jge short 0045C37C ; 我们要注意这一个跳转,如果Computer Number为字母时,ECX和EDX均为0
0045C377 B9 01000000 mov ecx, 1 ; 若ECX为0,则这里向ECX赋值为1
由此可见,将A赋值为0,B赋值为1即可。
算法总结:
情况1:
当Code Entry和Computer Number为数字时:
Code Entry 设为 A
Computer Number 设为 B
Serial Number 设为 C
D=[shr d(A and 7E000)+7BC]*44H +[shr 13(A and 780000)]*108H +[shr d(A)and 1F00]*0F3
F=(((shr f(A and 7F800000))+( A and FF))*3)+B*2 +(shl 3 (C+36BH+34H))-(C+36BH+34H)+(shl 5 D)-D
The Code =(循环三次){(F and 7FFFFFFF)+2*D }
或者
The Code =(循环四次){(F and 7FFFFFFF)+2*D}
情况2:
当Code Entry和Computer Number为字母时:
Code Entry 设为 A=0
Computer Number 设为 B=1
Serial Number 设为 C
算法同上。
软件将注册码保存到Bl&wh.dat这个文件中,算法部分研究完毕,再来搞一下暴破吧。
我们这里说的暴破呢,有这样几种情况是可以实现完美暴破的:
1.修改软件的功能部分和注册部分的标志位达到暴破。(多用与算法CALL唯一的情况)
2.修改关键跳转,使软件跳转到注册后实现的功能部分的地址。(强制暴破,多用于软件标志处出现“未注册”字样)
3.将真码保存到系统。(多用于真假码比较的软件)
4.将关键值保存到系统。(软件用检测是否保存关键值来判断软件是否已注册,关键值多保存在注册表后某文件中)
我们这款软件是真假码比较,所以采用第三中方式暴破,我们先看一下真假码比较部分:
0045C3EB BA 01000000 mov edx, 1 ; EDX做计数器
0045C3F0 8BD9 mov ebx, ecx ; ECX送EBX
0045C3F2 81E3 FFFFFF7F and ebx, 7FFFFFFF ; 与运算
0045C3F8 3BC3 cmp eax, ebx ; EAX的十进制即为我们输入的假码
0045C3FA 75 04 jnz short 0045C400
0045C3FC 8BC2 mov eax, edx
0045C3FE EB 0A jmp short 0045C40A
0045C400 03CE add ecx, esi ; 我们在这里JMP出来写暴破数据 JMP 0048238A
0045C402 42 inc edx
0045C403 83FA 33 cmp edx, 33
0045C406 ^ 75 E8 jnz short 0045C3F0
0045C408 33C0 xor eax, eax
0045C40A 5F pop edi
0045C40B 5E pop esi
0045C40C 5B pop ebx
0045C40D 5D pop ebp
0045C40E C2 0400 retn 4
0048238A 83FA 03 CMP EDX,3
0048238D 74 08 JZ SHORT dump.00482397
0048238F 03CE ADD ECX,ESI
00482391 42 INC EDX
00482392 ^ E9 59A0FDFF JMP dump.0045C3F0
00482397 8BC3 MOV EAX,EBX
00482399 ^ E9 5AA0FDFF JMP dump.0045C3F8
这段Patch写入后,软件注册成功后是无法正常运行的,至于是软件是哪里出的问题,我偷个懒留给读者吧,这里给出的就当是一种思路吧。
[注意]APP应用上架合规检测服务,协助应用顺利上架!