首页
社区
课程
招聘
[原创]一款游戏光碟校验的破解及类外挂的编写
发表于: 2007-3-19 12:59 11545

[原创]一款游戏光碟校验的破解及类外挂的编写

2007-3-19 12:59
11545

【破解作者】 王仁军
【作者邮箱】 [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下调试通过,收工!


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 7
支持
分享
最新回复 (14)
雪    币: 263
活跃值: (10)
能力值: ( LV9,RANK:250 )
在线值:
发帖
回帖
粉丝
2
好,顶一下
2007-3-19 13:11
0
雪    币: 209
活跃值: (40)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
3
这个要学习一下
2007-3-19 15:25
0
雪    币: 440
活跃值: (737)
能力值: ( LV9,RANK:690 )
在线值:
发帖
回帖
粉丝
4
这个地址是个全局变量?静态变量?

为什么不搞成动态的啊
2007-3-19 15:39
0
雪    币: 461
活跃值: (93)
能力值: ( LV9,RANK:1170 )
在线值:
发帖
回帖
粉丝
5
好东西,支持一下!
2007-3-19 19:26
0
雪    币: 231
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
byc
6
看得不是很懂...
得好好学一下汇编了
2007-3-20 02:37
0
雪    币: 297
活跃值: (21)
能力值: ( LV9,RANK:330 )
在线值:
发帖
回帖
粉丝
7
强,好好学习一下
2007-3-21 13:53
0
雪    币: 146
活跃值: (72)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
8
好久没见到LZ了,原来在修练内功啊...呵呵,支持一下!
2007-3-21 15:58
0
雪    币: 190
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
我想求助下!
2007-3-21 17:38
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
:eek看不明白呀????????
2007-3-21 18:41
0
雪    币: 325
活跃值: (97)
能力值: ( LV13,RANK:530 )
在线值:
发帖
回帖
粉丝
11
其实嘛~~~~~拦截DirectX函数 重定向MP3播放地址是个不错的办法~
2007-3-21 22:29
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
钱用光了怎么办?
2007-3-22 23:20
0
雪    币: 405
活跃值: (10)
能力值: ( LV9,RANK:1130 )
在线值:
发帖
回帖
粉丝
13
这些东西是修改游戏的好材料,非常感谢共享。
2007-3-23 18:12
0
雪    币: 314
活跃值: (15)
能力值: ( LV12,RANK:410 )
在线值:
发帖
回帖
粉丝
14
最初由 石中剑 发布
钱用光了怎么办?


你再按“Home”键4秒就又8888了
2007-3-26 13:26
0
雪    币: 4441
活跃值: (805)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
15
看不懂,不过支持一下
2007-3-26 20:16
0
游客
登录 | 注册 方可回帖
返回
//