【破解作者】 王仁军
【作者邮箱】 [email]xgzxwrj001@163.com[/email]
【使用工具】 olldbg vc++6.0
【破解平台】 WinXP SP2
【软件名称】 游戏“XX三国”之“sanguo.exe”
【软件简介】 较早的一款游戏,每次进入游戏都要光碟,没有则退出。
【破解声明】 只是为了个人使用方便,与新手交流一下而已,高手就不必看了。
--------------------------------------------------------------------------------
【破解内容】我的小弟们受易老头的影响,拿着“XX三国”光碟去网络教室,想对杀一番,那知网络教室里的机子是没有光驱的,无法玩,
就找到了我。我也是个新手,但是想到它是几年前的东西,能难到哪里去?就斗胆一试。
一、光碟校验的破解
对光碟进行校验,一般就是找上面的文件,而这些文件有可能是游戏运行所必需的,我们可以动态跟踪程序,看看它需要哪些文件,对于
必需的文件,复制到游戏文件夹里,然后把程序动态生成的文件绝对路径改为相对路径就可以了。另外,程序中必定有检测驱动器类型的函数
GetDriveType,我们就从这个GetDriveType开始:
用OD载入,程序停在入口处,Ctrl+A分析代码后,右键菜单:查找――>所有模块间的调用,会打开“找到的模块间的调用”窗口,在其中找到下面这行:
0048663B
call dword ptr [<&KERNEL32.GetDriveTypeA>]
双击这行反汇编代码来到CPU窗口,找到了整个校验
call:
00486610 /$ 81EC 10020000
sub esp, 210
;校验call入口
00486616 |. 53
push ebx
00486617 |. 55
push ebp
00486618 |. 8B2D C0216100
mov ebp,
dword ptr [<&KERNEL32.GetPrivat>
; kernel32.GetPrivateProfileStringA
0048661E |. 56
push esi
0048661F |. 57
push edi
00486620 |. 8BD9
mov ebx,
ecx
00486622 |. C64424 14 00
mov byte ptr [
esp+14], 0
00486627 |. C64424 11 3A
mov byte ptr [
esp+11], 3A
;":"
0048662C |. C64424 12 00
mov byte ptr [
esp+12], 0
00486631 |. C64424 10 41
mov byte ptr [
esp+10], 41
;'A'=0x41,表示A盘,把它直接改成C盘:0x43
00486636 |> 8D4424 10 /
lea eax,
dword ptr [
esp+10]
0048663A |. 50 |
push eax ; /RootPathName,盘符为参数
0048663B |. FF15 24226100 |
call dword ptr [<&KERNEL32.GetDriveTypeA>
; \GetDriveTypeA,取EAX中驱动器类型
00486641 |. 83F8 05 |
cmp eax, 5
;返回值与5比较,5为光盘,3为硬盘,直接改成3就成硬盘版的了^_^
现在右键菜单:复制到可执行文件――>所有修改,保存文件,覆盖原文件?谁怕谁呀!如果重新载入就不用再改了。在下一行F2设断,F9运行后断在下面,先用F7一路跟下去:
00486644 |. 0F85 0C020000 |
jnz 00486856
;前面的修改使跳转未发生,后面还会提到此行的修改问题
0048664A |. 8A4424 14 |
mov al,
byte ptr [
esp+14]
;[esp+14]中为一标志??
0048664E |. 84C0 |
test al,
al ;al==0
00486650 |. 75 25 |
jnz short 00486677
;未跳
00486652 |. 8D7C24 10 |
lea edi,
dword ptr [
esp+10]
;[esp+10]中为盘符C
00486656 |. 83C9 FF |
or ecx, FFFFFFFF
;ECX=-1
00486659 |. 33C0 |
xor eax,
eax ;EAX=0
0048665B |. 8D5424 14 |
lea edx,
dword ptr [
esp+14]
0048665F |. F2:AE |
repne scas byte ptr es:[
edi]
00486661 |. F7D1 |
not ecx
00486663 |. 2BF9 |
sub edi,
ecx
00486665 |. 8BC1 |
mov eax,
ecx
00486667 |. 8BF7 |
mov esi,
edi
00486669 |. 8BFA |
mov edi,
edx
0048666B |. C1E9 02 |
shr ecx, 2
0048666E |. F3:A5 |
rep movs dword ptr es:[
edi],
dword ptr [
esi]
00486670 |. 8BC8 |
mov ecx,
eax
00486672 |. 83E1 03 |
and ecx, 3
00486675 |. F3:A4 |
rep movs byte ptr es:[
edi],
byte ptr [
esi]
00486677 |> 8D7C24 10 |
lea edi,
dword ptr [
esp+10]
0048667B |. 83C9 FF |
or ecx, FFFFFFFF
0048667E |. 33C0 |
xor eax,
eax
00486680 |. 8D5424 18 |
lea edx,
dword ptr [
esp+18]
00486684 |. F2:AE |
repne scas byte ptr es:[
edi]
00486686 |. F7D1 |
not ecx
00486688 |. 2BF9 |
sub edi,
ecx
0048668A |. 8BC1 |
mov eax,
ecx
0048668C |. 8BF7 |
mov esi,
edi
0048668E |. 8BFA |
mov edi,
edx
00486690 |. 8D5424 18 |
lea edx,
dword ptr [
esp+18]
00486694 |. C1E9 02 |
shr ecx, 2
00486697 |. F3:A5 |
rep movs dword ptr es:[
edi],
dword ptr [
esi]
00486699 |. 8BC8 |
mov ecx,
eax
0048669B |. 33C0 |
xor eax,
eax
0048669D |. 83E1 03 |
and ecx, 3
004866A0 |. F3:A4 |
rep movs byte ptr es:[
edi],
byte ptr [
esi]
;以上把“C:”复制了两份
004866A2 |. BF 28F86300 |
mov edi, 0063F828
;ASCII "\autorun.inf"
请注意,目标出现,要autorun.inf做什么呢?继续跟吧F7.
004866A7 |. 83C9 FF |
or ecx, FFFFFFFF
004866AA |. F2:AE |
repne scas byte ptr es:[
edi]
004866AC |. F7D1 |
not ecx ;计算出了"\autorun.inf"的长度
004866AE |. 2BF9 |
sub edi,
ecx ;让EDI仍指向ASCII "\autorun.inf"
004866B0 |. 8BF7 |
mov esi,
edi
004866B2 |. 8BFA |
mov edi,
edx ;EDX中为"C:"
004866B4 |. 8BD1 |
mov edx,
ecx ;"\autorun.inf"的长度暂存在EDX中
004866B6 |. 83C9 FF |
or ecx, FFFFFFFF
004866B9 |. F2:AE |
repne scas byte ptr es:[
edi]
004866BB |. 8BCA |
mov ecx,
edx ;"\autorun.inf"的长度恢复到ECX中
004866BD |. 4F |
dec edi ;EDI指向保存"C:"的下一位置
004866BE |. C1E9 02 |
shr ecx, 2
004866C1 |. F3:A5 |
rep movs dword ptr es:[
edi],
dword ptr [
esi]
;连接成"C:\autorun.inf"
004866C3 |. 8BCA |
mov ecx,
edx ;"\autorun.inf"的长度恢复到ECX中
004866C5 |. 8D4424 18 |
lea eax,
dword ptr [
esp+18]
;[esp+18]指向"C:\autorun.inf"
004866C9 |. 83E1 03 |
and ecx, 3
004866CC |. 50 |
push eax ;文件名"C:\autorun.inf"入栈
004866CD |. F3:A4 |
rep movs byte ptr es:[
edi],
byte ptr [
esi]
004866CF |. 8D8C24 2001000>|
lea ecx,
dword ptr [
esp+120]
004866D6 |. 68 04010000 |
push 104
; size 入栈
004866DB |. 51 |
push ecx ; buf 入栈
004866DC |. 68 20F86300 |
push 0063F820
; ASCII "NODISK" 默认值 入栈
004866E1 |. 68 14F86300 |
push 0063F814
; ASCII "ObjectKey" 键名 入栈
004866E6 |. 68 10F86300 |
push 0063F810
; ASCII "UI" 段名 入栈
004866EB |. FFD5 |
call ebp ; kernel32.GetPrivateProfileStringA 读入字串,F8过之
到此,结合下一句知:程序找到合适的磁盘(前面的修改使它为C:盘)后,读根目录下的文件
"autorun.inf",如果文件存在格式也对则会得到字串
"SOFTWARE\Object Software (Beijng) Co.,Ltd.",否则为
"NODISK",无碟?!
004866ED |. BE E4F76300 |
mov esi, 0063F7E4
; ASCII "SOFTWARE\Object Software (Beijng) Co.,Ltd."
004866F2 |. 8D8424 1C01000>|
lea eax,
dword ptr [
esp+11C]
;[esp+11C]为从文件读到的字串
004866F9 |> 8A10 |/
mov dl,
byte ptr [
eax]
;真正的校验开始了^_^,第一个地方
004866FB |. 8ACA ||
mov cl,
dl ;字符送入cl保存,作用见下面
004866FD |. 3A16 ||
cmp dl,
byte ptr [
esi]
;逐个比较
004866FF |. 75 1C ||
jnz short 0048671D
;不等则完蛋,你说改不改它呢?
00486701 |. 84C9 ||
test cl,
cl ;相等后再检查是否比较完了
00486703 |. 74 14 ||
je short 00486719
;比较成功的话去进行下一项检验
00486705 |. 8A50 01 ||
mov dl,
byte ptr [
eax+1]
;下一字符
00486708 |. 8ACA ||
mov cl,
dl ;字符送入cl保存,
0048670A |. 3A56 01 ||
cmp dl,
byte ptr [
esi+1]
;比较下一字符
0048670D |. 75 0E ||
jnz short 0048671D
;不等则完蛋
0048670F |. 83C0 02 ||
add eax, 2
;字串地址加2,指向下一WORD
00486712 |. 83C6 02 ||
add esi, 2
;字串地址加2,指向下一WORD
00486715 |. 84C9 ||
test cl,
cl ;再检查是否比较完了
00486717 |.^ 75 E0 |\
jnz short 004866F9
;没完接着比较
00486719 |> 33C0 |
xor eax,
eax ;第一项校验成功,让标志EAX=0
0048671B |. EB 05 |
jmp short 00486722
;去检测第二个地方
0048671D |> 1BC0 |
sbb eax,
eax ;检测失败了
0048671F |. 83D8 FF |
sbb eax, -1
00486722 |> 85C0 |
test eax,
eax ;EAX当然不为0
00486724 |. 0F85 2C010000 |
jnz 00486856
;去检查下一驱动器吧
第一处检测成功就会进行下面第二处检测,大同小异,不多说了
0048672A |. 8D4424 18 |
lea eax,
dword ptr [
esp+18]
;第二处检测开始了
0048672E |. 8D8C24 1C01000>|
lea ecx,
dword ptr [
esp+11C]
00486735 |. 50 |
push eax
00486736 |. 68 04010000 |
push 104
0048673B |. 51 |
push ecx
0048673C |. 68 20F86300 |
push 0063F820
; ASCII "NODISK"
00486741 |. 68 DCF76300 |
push 0063F7DC
; ASCII "BtnNum"
00486746 |. 68 10F86300 |
push 0063F810
; ASCII "UI"
0048674B |. FFD5 |
call ebp
0048674D |. BE D8F76300 |
mov esi, 0063F7D8
; ASCII "11"
00486752 |. 8D8424 1C01000>|
lea eax,
dword ptr [
esp+11C]
00486759 |> 8A10 |/
mov dl,
byte ptr [
eax]
0048675B |. 8ACA ||
mov cl,
dl
0048675D |. 3A16 ||
cmp dl,
byte ptr [
esi]
0048675F |. 75 1C ||
jnz short 0048677D
00486761 |. 84C9 ||
test cl,
cl
00486763 |. 74 14 ||
je short 00486779
00486765 |. 8A50 01 ||
mov dl,
byte ptr [
eax+1]
00486768 |. 8ACA ||
mov cl,
dl
0048676A |. 3A56 01 ||
cmp dl,
byte ptr [
esi+1]
0048676D |. 75 0E ||
jnz short 0048677D
0048676F |. 83C0 02 ||
add eax, 2
00486772 |. 83C6 02 ||
add esi, 2
00486775 |. 84C9 ||
test cl,
cl
00486777 |.^ 75 E0 |\
jnz short 00486759
00486779 |> 33C0 |
xor eax,
eax ;第二处检测完毕而且成功来到这里,EAX=0
0048677B |. EB 05 |
jmp short 00486782
;去第三处检测点
0048677D |> 1BC0 |
sbb eax,
eax
0048677F |. 83D8 FF |
sbb eax, -1
00486782 |> 85C0 |
test eax,
eax
00486784 |. 0F85 CC000000 |
jnz 00486856
;不成功则去检查下一驱动器吧
修改004866FF
jnz short 0048671D 为
004866FF
jmp short 00486779 就跳过前面两处检测,无
"C:\autorun.inf"也可以了。
去下面看看,都干了些什么。
0048678A |. 83C9 FF |
or ecx, FFFFFFFF
;第三处检测开始
0048678D |. 8D7C24 10 |
lea edi,
dword ptr [
esp+10]
;还记得吗?里面是盘符"C:"
00486791 |. F2:AE |
repne scas byte ptr es:[
edi]
;找EAX中的值,此时应为0
00486793 |. F7D1 |
not ecx
00486795 |. 2BF9 |
sub edi,
ecx
00486797 |. 8D5424 18 |
lea edx,
dword ptr [
esp+18]
;堆栈中为 (ASCII "C:\autorun.inf")
0048679B |. 8BC1 |
mov eax,
ecx
0048679D |. 8BF7 |
mov esi,
edi
0048679F |. C1E9 02 |
shr ecx, 2
004867A2 |. 8BFA |
mov edi,
edx
004867A4 |. 8D5424 18 |
lea edx,
dword ptr [
esp+18]
004867A8 |. F3:A5 |
rep movs dword ptr es:[
edi],
dword ptr [
esi]
004867AA |. 8BC8 |
mov ecx,
eax
004867AC |. 33C0 |
xor eax,
eax
004867AE |. 83E1 03 |
and ecx, 3
004867B1 |. 68 78F46300 |
push 0063F478
; ASCII "rb" 参数入栈
又要打开什么文件了,瞧这个
"rb",要读入二进制文件???
004867B6 |. F3:A4 |
rep movs byte ptr es:[
edi],
byte ptr [
esi]
004867B8 |. 83C9 FF |
or ecx, FFFFFFFF
004867BB |. BF D4F76300 |
mov edi, 0063F7D4
004867C0 |. F2:AE |
repne scas byte ptr es:[
edi]
004867C2 |. F7D1 |
not ecx
004867C4 |. 2BF9 |
sub edi,
ecx
004867C6 |. 8BF7 |
mov esi,
edi
004867C8 |. 8BFA |
mov edi,
edx
004867CA |. 8BD1 |
mov edx,
ecx
004867CC |. 83C9 FF |
or ecx, FFFFFFFF
004867CF |. F2:AE |
repne scas byte ptr es:[
edi]
004867D1 |. 8BCA |
mov ecx,
edx
004867D3 |. 4F |
dec edi
004867D4 |. C1E9 02 |
shr ecx, 2
004867D7 |. F3:A5 |
rep movs dword ptr es:[
edi],
dword ptr [
esi]
004867D9 |. 8BCA |
mov ecx,
edx
004867DB |. A1 84358800 |
mov eax,
dword ptr [883584]
004867E0 |. 83E1 03 |
and ecx, 3
004867E3 |. 8D5424 1C |
lea edx,
dword ptr [
esp+1C]
004867E7 |. F3:A4 |
rep movs byte ptr es:[
edi],
byte ptr [
esi]
004867E9 |. 8B3C85 E015640>|
mov edi,
dword ptr [
eax*4+6415E0]
;ASCII"CHINESEPRC"
004867F0 |. 83C9 FF |
or ecx, FFFFFFFF
004867F3 |. 33C0 |
xor eax,
eax
004867F5 |. F2:AE |
repne scas byte ptr es:[
edi]
004867F7 |. F7D1 |
not ecx ;求出"CHINESEPRC"的总长度为11
004867F9 |. 2BF9 |
sub edi,
ecx
004867FB |. 8BF7 |
mov esi,
edi
004867FD |. 8BFA |
mov edi,
edx
004867FF |. 8BD1 |
mov edx,
ecx
00486801 |. 83C9 FF |
or ecx, FFFFFFFF
00486804 |. F2:AE |
repne scas byte ptr es:[
edi]
00486806 |. 8BCA |
mov ecx,
edx
00486808 |. 4F |
dec edi
00486809 |. C1E9 02 |
shr ecx, 2
0048680C |. F3:A5 |
rep movs dword ptr es:[
edi],
dword ptr [
esi]
0048680E |. 8BCA |
mov ecx,
edx
00486810 |. 8D5424 1C |
lea edx,
dword ptr [
esp+1C]
00486814 |. 83E1 03 |
and ecx, 3
00486817 |. F3:A4 |
rep movs byte ptr es:[
edi],
byte ptr [
esi]
00486819 |. BF C8F76300 |
mov edi, 0063F7C8
;ASCII "\readme.txt" 值得关注
0048681E |. 83C9 FF |
or ecx, FFFFFFFF
00486821 |. F2:AE |
repne scas byte ptr es:[
edi]
00486823 |. F7D1 |
not ecx
00486825 |. 2BF9 |
sub edi,
ecx
00486827 |. 8BF7 |
mov esi,
edi
00486829 |. 8BFA |
mov edi,
edx
0048682B |. 8BD1 |
mov edx,
ecx
0048682D |. 83C9 FF |
or ecx, FFFFFFFF
00486830 |. F2:AE |
repne scas byte ptr es:[
edi]
00486832 |. 8BCA |
mov ecx,
edx
00486834 |. 4F |
dec edi
00486835 |. C1E9 02 |
shr ecx, 2
00486838 |. F3:A5 |
rep movs dword ptr es:[
edi],
dword ptr [
esi]
;"C:\CHINESEPRC\readme.txt"
程序的效率也太低了吧???上面一大段只是为了得到这么一个字串
"C:\CHINESEPRC\readme.txt"。嗯!下一目标出现^_^
0048683A |. 8BCA |
mov ecx,
edx
0048683C |. 8D4424 1C |
lea eax,
dword ptr [
esp+1C]
00486840 |. 83E1 03 |
and ecx, 3
00486843 |. 50 |
push eax ;文件名"C:\CHINESEPRC\readme.txt"入栈
00486844 |. F3:A4 |
rep movs byte ptr es:[
edi],
byte ptr [
esi]
00486846 |. E8 22901600 |
call 005EF86D
;应该象是 FILE *fp=fopen(filename,"rb")这样的函数调用吧?!
"C:\CHINESEPRC\readme.txt"本应在光盘上(C:是改来的),但是游戏文件夹里已经有这个
"\readme.txt"了,这就好办了,只要把绝对路径改为相对路径就搞定这第三处校验,道理不用我多说了吧?。由
00486819
mov edi, 0063F7C8
;ASCII "\readme.txt" 这一行知:从0063F7C9开始就是"readme.txt",所以改法如下:
00486819
push 0063F7C9
;ASCII "readme.txt"
0048681E
jmp short 00486846
;后面生成绝对路径的代码就免了吧^_^,直接跳走就成相对路径了。 至此已经解决了三处,还有没有呢?用F8向下跑:
0048684B |. 83C4 08 |
add esp, 8
0048684E |. 85C0 |
test eax,
eax ;那么EAX就是文件指针了
00486850 |. 0F85 88000000 |
jnz 004868DE
;打开文件是否成功,成功就去校验文件的真假??
00486856 |> 8A4424 10 |
mov al,
byte ptr [
esp+10]
;准备检查下一个驱动器
0048685A |. FEC0 |
inc al
0048685C |. 3C 5A |
cmp al, 5A
;"Z"=0x5A
0048685E |. 884424 10 |
mov byte ptr [
esp+10],
al
00486862 |.^ 0F8E CEFDFFFF \
jle 00486636
;AL如果小于Z,检查下一个驱动器
校验失败现在不属于我,我不管了。
00486868 |. 8B83 C40A0000
mov eax,
dword ptr [
ebx+AC4]
;开始校验失败后的处理工作
0048686E |. 85C0
test eax,
eax
00486870 |. 0F85 05010000
jnz 0048697B
00486876 |. 8A4424 14
mov al,
byte ptr [
esp+14]
0048687A |. 84C0
test al,
al
0048687C |. 0F84 D0000000
je 00486952
00486882 |. 8D7C24 14
lea edi,
dword ptr [
esp+14]
00486886 |. 83C9 FF
or ecx, FFFFFFFF
00486889 |. 33C0
xor eax,
eax
0048688B |. 8D93 C4090000
lea edx,
dword ptr [
ebx+9C4]
00486891 |. F2:AE
repne scas byte ptr es:[
edi]
00486893 |. F7D1
not ecx
00486895 |. 2BF9
sub edi,
ecx
00486897 |. 8BC1
mov eax,
ecx
00486899 |. 8BF7
mov esi,
edi
0048689B |. 8BFA
mov edi,
edx
0048689D |. C1E9 02
shr ecx, 2
004868A0 |. F3:A5
rep movs dword ptr es:[
edi],
dword ptr [
esi]
004868A2 |. 8BC8
mov ecx,
eax
004868A4 |. 33C0
xor eax,
eax
004868A6 |. 83E1 03
and ecx, 3
004868A9 |. F3:A4
rep movs byte ptr es:[
edi],
byte ptr [
esi]
004868AB |. BF D4F76300
mov edi, 0063F7D4
004868B0 |. 83C9 FF
or ecx, FFFFFFFF
004868B3 |. F2:AE
repne scas byte ptr es:[
edi]
004868B5 |. F7D1
not ecx
004868B7 |. 2BF9
sub edi,
ecx
004868B9 |. 8BF7
mov esi,
edi
004868BB |. 8BD9
mov ebx,
ecx
004868BD |. 8BFA
mov edi,
edx
004868BF |. 83C9 FF
or ecx, FFFFFFFF
004868C2 |. F2:AE
repne scas byte ptr es:[
edi]
004868C4 |. 8BCB
mov ecx,
ebx
004868C6 |. 4F
dec edi
004868C7 |. C1E9 02
shr ecx, 2
004868CA |. F3:A5
rep movs dword ptr es:[
edi],
dword ptr [
esi]
004868CC |. 8BCB
mov ecx,
ebx
004868CE |. 83E1 03
and ecx, 3
004868D1 |. F3:A4
rep movs byte ptr es:[
edi],
byte ptr [
esi]
004868D3 |. 5F
pop edi
004868D4 |. 5E
pop esi
004868D5 |. 5D
pop ebp
004868D6 |. 5B
pop ebx
004868D7 |. 81C4 10020000
add esp, 210
004868DD |. C3
retn ;无光碟则失败,返回。
004868DE |> 50
push eax ;文件指针入栈
004868DF |. E8 A28D1600
call 005EF686
;此call是干什么的已经不重要了,我有那个"readme.txt"文件了啊
004868E4 |. 8B83 C40A0000
mov eax,
dword ptr [
ebx+AC4]
;取出“校验是否为真”的标志??
004868EA |. 83C4 04
add esp, 4
004868ED |. 85C0
test eax,
eax ;检查标志
004868EF |. 75 51
jnz short 00486942
;跳走了,去光明大道^_^
只要你有
"readme.txt"文件,内容不限,那怕它是空的,都会跳走,不会执行到下面的代码
004868F1 |. 8D7C24 10
lea edi,
dword ptr [
esp+10]
;好象在清除什么内容??
004868F5 |. 83C9 FF
or ecx, FFFFFFFF
004868F8 |. 33C0
xor eax,
eax
004868FA |. 8D93 C4090000
lea edx,
dword ptr [
ebx+9C4]
00486900 |. F2:AE
repne scas byte ptr es:[
edi]
00486902 |. F7D1
not ecx
00486904 |. 2BF9
sub edi,
ecx
00486906 |. 8BC1
mov eax,
ecx
00486908 |. 8BF7
mov esi,
edi
0048690A |. 8BFA
mov edi,
edx
0048690C |. C1E9 02
shr ecx, 2
0048690F |. F3:A5
rep movs dword ptr es:[
edi],
dword ptr [
esi]
00486911 |. 8BC8
mov ecx,
eax
00486913 |. 33C0
xor eax,
eax
00486915 |. 83E1 03
and ecx, 3
00486918 |. F3:A4
rep movs byte ptr es:[
edi],
byte ptr [
esi]
0048691A |. BF D4F76300
mov edi, 0063F7D4
0048691F |. 83C9 FF
or ecx, FFFFFFFF
00486922 |. F2:AE
repne scas byte ptr es:[
edi]
00486924 |. F7D1
not ecx
00486926 |. 2BF9
sub edi,
ecx
00486928 |. 8BF7
mov esi,
edi
0048692A |. 8BD9
mov ebx,
ecx
0048692C |. 8BFA
mov edi,
edx
0048692E |. 83C9 FF
or ecx, FFFFFFFF
00486931 |. F2:AE
repne scas byte ptr es:[
edi]
00486933 |. 8BCB
mov ecx,
ebx
00486935 |. 4F
dec edi
00486936 |. C1E9 02
shr ecx, 2
00486939 |. F3:A5
rep movs dword ptr es:[
edi],
dword ptr [
esi]
0048693B |. 8BCB
mov ecx,
ebx
0048693D |. 83E1 03
and ecx, 3
00486940 |. F3:A4
rep movs byte ptr es:[
edi],
byte ptr [
esi]
00486942 |> 5F
pop edi ;准备退出,通向光明的大门^_^,直接从前面跳到这里岂不快哉?
00486943 |. 5E
pop esi
00486944 |. 5D
pop ebp
00486945 |. B8 01000000
mov eax, 1
;让EAX=1,返回结果为 true
0048694A |. 5B
pop ebx
0048694B |. 81C4 10020000
add esp, 210
00486951 |. C3
retn ;找到光盘的退出点
00486952 |> 8DBB C4020000
lea edi,
dword ptr [
ebx+2C4]
00486958 |. 83C9 FF
or ecx, FFFFFFFF
0048695B |. 33C0
xor eax,
eax
0048695D |. 8D93 C4090000
lea edx,
dword ptr [
ebx+9C4]
00486963 |. F2:AE
repne scas byte ptr es:[
edi]
00486965 |. F7D1
not ecx
00486967 |. 2BF9
sub edi,
ecx
00486969 |. 8BC1
mov eax,
ecx
0048696B |. 8BF7
mov esi,
edi
0048696D |. 8BFA
mov edi,
edx
0048696F |. C1E9 02
shr ecx, 2
00486972 |. F3:A5
rep movs dword ptr es:[
edi],
dword ptr [
esi]
00486974 |. 8BC8
mov ecx,
eax
00486976 |. 83E1 03
and ecx, 3
00486979 |. F3:A4
rep movs byte ptr es:[
edi],
byte ptr [
esi]
0048697B |> 5F
pop edi ;准备退出
0048697C |. 5E
pop esi
0048697D |. 5D
pop ebp
0048697E |. 33C0
xor eax,
eax ;让EAX=0,返回结果为 false
00486980 |. 5B
pop ebx
00486981 |. 81C4 10020000
add esp, 210
00486987 \. C3
retn ;未找到光盘的退出点
就这三处校验,涉及两个文件,而且不是游戏必需的文件,
"readme.txt"文件为空也可以,所以后来我干脆把
00486644
jnz 00486856 一行改为
00486644
jmp 00486942 保存修改,删掉那个
"readme.txt"也照样可以进入游戏了,除了没有背景音乐外,其他一切正常。
二、实现背景音乐功能和作弊键功能
其实,没有背景音乐是因为背景音乐是以CD音轨的形式记录在光碟上的。未放入光碟,当然就没有背景音乐了。这通常有两种办法可以解决:跟踪、修改程序中播放音乐的相关代码,我晕倒;还有就是自己写个游戏外挂。我请出了VC6,很快稿定了音乐问题,还加了个作弊键。
先用Nero中的插件把那段CD音轨录制成
"sanguo.mp3"备用。然后自己编写一段代码循环播放这个mp3就可以了,但是还要考虑一个问题:音乐最好是在玩者正式进入游戏后再播放,如果人家正在看那段动画,你的音乐响起,岂不坏人胃口!怎么办呢?嗯,想起来了,有钱好办事嘛^_^:正式进入游戏时玩家有一定数量的金钱,那么,没有正式进入游戏时玩家有金钱数吗?这个数在什么内存地址保存着?这个地址是变化的还是固定的?
进入游戏,用金山游侠搜寻一下金钱,找到了保存金钱数的内存地址,多次退出、进入游戏,都搜寻到同样的一个地址。而且,未正式进入游戏时此地址内一直为0,正式进入后则不为0。太好了,这个地址是固定的。下面就看我的代码吧:
// XX三国.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include<mmsystem.h>
#pragma comment(lib,
"winmm.lib")
/////////////////////////////////////////////////////////////////////////////
DWORD WINAPI getinfo(DWORD item,DWORD count)
{ MCI_STATUS_PARMS mcistatusparms;
mcistatusparms.dwCallback=NULL;
//(DWORD)GetSafeHwnd();
mcistatusparms.dwItem=item;
mcistatusparms.dwReturn=0;
mciSendCommand(count,MCI_STATUS,MCI_STATUS_ITEM,(DWORD)&mcistatusparms);
return mcistatusparms.dwReturn;
}
int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,
int nCmdShow)
{ PROCESS_INFORMATION PI={0};
DWORD Isrun=0,M=0;
MCI_OPEN_PARMS mciopenparms;
MCI_PLAY_PARMS mciplayparms;
STARTUPINFO
SI={0};
DWORD buf=0,size=0,adrr=0x1017d42;
//存放金钱的地址
SI.cb=
sizeof(STARTUPINFO);
SI.dwFlags=STARTF_USESHOWWINDOW;
SI.wShowWindow=SW_SHOWNORMAL;
CreateProcess(NULL,
"sanguo.exe",NULL,NULL,
false,0,NULL,NULL,&
SI,&PI);
//启动游戏程序
Sleep(20000);
//等等吧,启动游戏需要时间
VirtualAllocEx(PI.hProcess,(LPVOID)adrr,
sizeof(DWORD), MEM_COMMIT, PAGE_READWRITE) ;
do
{ ::GetExitCodeProcess(PI.hProcess,&Isrun);
if(Isrun!=STILL_ACTIVE)
//游戏还在运行吗?
return 0;
::ReadProcessMemory(PI.hProcess,(LPCVOID)adrr,&buf,
sizeof(buf),&size);
Sleep(100);
}
while(!buf);
//金钱数为0?
mciopenparms.lpstrElementName=
"sanguo.mp3";
mciopenparms.lpstrDeviceType=NULL;
mciopenparms.dwCallback=NULL;
mciSendCommand(0,MCI_OPEN,MCI_DEVTYPE_WAVEFORM_AUDIO,(DWORD)(LPVOID)&mciopenparms);
mciplayparms.dwCallback= NULL;
//(DWORD)GetSafeHwnd();
mciplayparms.dwFrom=0;
mciplayparms.dwTo=getinfo(MCI_STATUS_LENGTH,mciopenparms.wDeviceID);
do //每秒检查一次mp3播放进度和游戏活动情况
{ DWORD pos=getinfo(MCI_STATUS_POSITION,mciopenparms.wDeviceID);
if(::GetAsyncKeyState(VK_HOME)<0)
//按键否?
{ buf=8888;
if(++M==3)
//按键时间长度因数之一
::WriteProcessMemory(PI.hProcess,(LPVOID)adrr,&buf,
sizeof(buf),&size);
}
else M=0;
if(pos==mciplayparms.dwTo||pos==0)
//循环播放mp3
mciSendCommand(mciopenparms.wDeviceID,MCI_PLAY,MCI_TO|MCI_FROM,(DWORD)(LPVOID)&mciplayparms);
Sleep(1000);
//减轻CPU的负担;按键时间长度因数之二
::GetExitCodeProcess(PI.hProcess,&Isrun);
}
while(Isrun==STILL_ACTIVE);
//若游戏已经退出则结束本程序
::CloseHandle(PI.hProcess);
return 0;
}
用VC6编译后生成
"XX三国.exe",把它与
"sanguo.exe"、
"sanguo.mp3"放在同一文件夹内,运行
"XX三国.exe",游戏被启动,正式进入游戏后音乐响起,按住编辑区的
"Home"键4秒,你就发发发发了。至此,所有问题全部解决,在WinXP/SP2下调试通过,收工!
[课程]Linux pwn 探索篇!