首页
社区
课程
招聘
[原创]蜘蛛纸牌 DIY 秒杀功能
2011-2-22 11:43 10264

[原创]蜘蛛纸牌 DIY 秒杀功能

2011-2-22 11:43
10264
看了第六期精华中的 xdkui  <<蜘蛛纸牌分析与简单DIY>>  
及hearmecryle 写的<<蜘蛛纸牌底牌数据结构图及辅助代码利用>>
(链 接: http://bbs.pediy.com/showthread.php?t=129478)
对蜘蛛纸牌进行了一次DIY实践。

通过分析,程序一开始就保存了一个内存的基址:
0100FE5F   .  B9 08200101   mov ecx,01012008    ;  设置基址的地方
0100FE64   .  E8 6D58FFFF   call 010056D6
0100FE69   .  68 7AFE0001   push 0100FE7A
0100FE6E   .  E8 9B94FFFF   call 0100930E
0100FE73   .  59            pop ecx
0100FE74   .  C3            retn

01012008是一个基址
里面保存的是游戏窗口的句柄,很多地方要使用的。
+4的地方保存一个地址,指向难度值。
+8的地方保存一个地址,指向一个有10个元素的数组,每个元素代表每一列的一个双向链表的指针地址,指针中保存的是链表的第一张牌的位置。
+14h 与+18h这两个地方保存的是两列牌之间的空隙的宽度值,在sendmessage时,计算坐标要用到的。

+58h 的地方保存发牌的次数



[01012008+4]+0Ch  指向每张牌的信息



以一次游戏过程中的第三列数据为例:



每张牌的信息:



利用本程序消息循环的特征指令,可以在程序中定位到处理菜单消息的地方:
movzx eax,word ptr ss:[ebp+10]  ; Case 111 (WM_COMMAND) of switch 01007BF5

利用reshack增加一个菜单:
101 MENU
LANGUAGE LANG_CHINESE, 0x2
{
POPUP "游戏(&G)"
{
  MENUITEM "开局(&N)\tF2",  40005
  MENUITEM "重新开局(&R)",  40006,  GRAYED
  MENUITEM SEPARATOR
  MENUITEM "撤销(&U)\tCtrl+Z",  40010,  GRAYED
  MENUITEM "新一轮发牌(&D)\tD",  40007,  GRAYED
  MENUITEM "显示可行的操作(&M)\tM",  40013,  GRAYED
  MENUITEM SEPARATOR
  MENUITEM "难易级别(&I)...\tF3",  40017
  MENUITEM "战况(&T)...\tF4",  40014
  MENUITEM "选项(&P)...\tF5",  40015
  MENUITEM SEPARATOR
  MENUITEM "保存本次游戏(&S)\tCtrl+S",  40011,  GRAYED
  MENUITEM "打开上次保存的游戏(&O)\tCtrl+O",  40012
  MENUITEM SEPARATOR
  MENUITEM "退出(&X)",  40004
}
MENUITEM "发牌(&D)",  40016,  GRAYED
POPUP "帮助(&H)"
{
  MENUITEM "目录(&C)\tF1",  40003
  MENUITEM SEPARATOR
  MENUITEM "关于蜘蛛(&A)...",  40002
}
MENUITEM "秒杀",  40020
}

原程序中移动牌的地方:
01004C98   |> \FF75 FC                     PUSH [LOCAL.1]        ;目的列的第几张
01004C9B   |.  8B4E 08                     MOV ECX,DWORD PTR DS:[ESI+8];指向listarray
01004C9E   |.  FF75 10                     PUSH [ARG.3]                ;目的列
01004CA1   |.  FF75 0C                     PUSH [ARG.2]
01004CA4   |.  57                          PUSH EDI              ;  
01004CA5   |.  E8 50320000                 CALL 01007EFA         ;  移动牌的函数

考虑到代码要多次修改,并且增加的比较多,因此采用了增加一个DLL导入函数的方法对程序进行补丁,利用loadPE增加,并记下其RVA地址。

原来的程序,主窗口菜单消息过程,判断是什么菜单
01006C3F  |.  0FB745 10     movzx eax,word ptr ss:[ebp+10]
01006C43  |.  05 BE63FFFF   add eax,FFFF63BE                        ;  Switch (cases 9C42..9C51)
01006C48  |.  83F8 0F       cmp eax,0F

对原程序进行修改:

01006C43     /E9 08A00000       jmp 01010C50

并在后面的空白处写入新加菜单的处理代码:
01010C50      60            pushad
01010C51      3D 549C0000   cmp eax,9C54
01010C56      75 06         jnz short 01010C5E
01010C58      FF15 1D700801 call dword ptr ds:[108701D]  ; 调用新加的功能函数
01010C5E      61            popad
01010C5F      05 BE63FFFF   add eax,FFFF63BE
01010C64      E9 DF5FFFFF   jmp 01006C48

新加函数的主要功能:
1.调用发牌函数,把所有的牌全部发完;
2.把后面两列的牌调整到前面8列,使每列均为13张;
3.修改每列的双向链表中的牌的序号;
4.修改保存每张牌详细的数组,使每列牌按K--A的顺序排列;
5.修改每列没有翻开的张数;
6.发送鼠标消息,完成自动移牌。

完工的蜘蛛纸牌如下:



dll代码如下:

.386
.model flat, stdcall      ; 32 bit memory model
option casemap :none      ; case sensitive

include windows.inc
include masm32.inc
include user32.inc

includelib masm32.lib
includelib user32.lib

DllEntry    proto hInstance:DWORD, dwFunction:DWORD, lpReserve:DWORD
crackspider   proto

.data?
dwEasyLevel                        dd        ?        ;保存难度等级,初级为1,中级为2,高级为4,数值正好为牌的花色数量
dwListArray                        dd        ?        ;保存每列链表的指针数组的起始地址
dwCardArray                        dd        ?        ;保存牌的信息数组的起始地址
dwCardNumArray                dd        ?        ;保存每列牌的张数的数组地址
dwUnShowNumArray        dd        ?        ;保存每列没有翻开的张数的数组地址

;//////////////////////////////////////////////////////////////////

.const
lpMoveCard                equ                01007EFAh        ;移动牌的函数入口
lpSendCard                equ                010069B2h        ;发牌的函数入口
dwBaseMemAdd        equ                01012008h        ;内存基址,并在这里保存了主窗口的句柄
       
;//////////////////////////////////////////////////////////////////

.code
align 4

DllEntry proc hInstance:DWORD, dwFunction:DWORD, lpReserve:DWORD

xor eax, eax
inc eax
ret

DllEntry endp
;//////////////////////////////////////////////////////////////////

AdjustTen2Eight proc dwOut,dwIn1,dwIn2,dwIn3,dwIn4        ;把dwOut列分到后面的4个列中,前两个分两个元素,后两个分三个元素
       
        mov ecx,dwListArray
        mov ebx,lpMoveCard
        push 0ah                ;目的列的现有张数
        push dwIn1                ;目的列,列是从0计算的
        push 8                        ;源列的第几张牌开始移动,从0计算的
        push dwOut                ;源列,列是从0计算的
        call ebx

        mov ecx,dwListArray
        mov ebx,lpMoveCard
        push 0ah                ;目的列的现有张数
        push dwIn2                ;目的列,列是从0计算的
        push 6                        ;源列的第几张牌开始移动,从0计算的
        push dwOut                ;源列,列是从0计算的
        call ebx

        mov ecx,dwListArray
        mov ebx,lpMoveCard
        push 9                        ;目的列的现有张数
        push dwIn3                ;目的列,列是从0计算的
        push 3                        ;源列的第几张牌开始移动,从0计算的
        push dwOut                ;源列,列是从0计算的
        call ebx

        mov ecx,dwListArray
        mov ebx,lpMoveCard
        push 9                        ;目的列的现有张数
        push dwIn4                ;目的列,列是从0计算的
        push 0                        ;源列的第几张牌开始移动,从0计算的
        push dwOut                ;源列,列是从0计算的
        call ebx

        ret
AdjustTen2Eight endp

MoveCardCol proc dwCol
        LOCAL @hWnd
        LOCAL @width
       
        ;取得游戏的窗口句柄,其值是保存在dwBaseMemAdd中
    mov eax,dword ptr ds:[dwBaseMemAdd]
        mov @hWnd,eax

        ;取得列与列之间的间隙宽度
        mov eax,dword ptr ds:[dwBaseMemAdd+14h]
        mov @width,eax
       
       
        mov eax,47h
        add eax,@width
        mov ecx,dwCol
        imul eax,ecx
        add eax,@width
        add eax,23h
       
        mov ebx,1bh
        shl        ebx,16
        add eax,ebx

        invoke PostMessage,@hWnd,WM_LBUTTONDOWN,1,eax
       
        mov eax,47h
        add eax,@width
        mov ecx,8
        imul ecx
        add eax,@width
        mov ecx,eax
        mov eax,1bh
        shl eax,16
        add eax,ecx
        push eax
        invoke PostMessage,@hWnd,WM_MOUSEMOVE,1,eax
        pop eax
        invoke PostMessage,@hWnd,WM_LBUTTONUP,0,eax

        ret
MoveCardCol endp

crackspider proc
    LOCAL @index
    LOCAL @dwNum
    LOCAL @dwTemp
        LOCAL @dwCardValue
       
        ;取得每列牌的链表指针数组地址
        mov edx,dword ptr ds:[dwBaseMemAdd+8]
        mov dwListArray,edx
               
        ;取得每列没有翻开的牌的张数的数组地址
        add edx,28h
        mov dwCardNumArray,edx
        add edx,28h
        mov dwUnShowNumArray,edx
       
        ;取得保存张牌信息的数组地址及难度级别
    mov edx,dword ptr ds:[dwBaseMemAdd+4]
    mov esi,[edx]
    mov dwEasyLevel,esi
    add edx,0Ch
    mov esi,[edx]
        mov dwCardArray,esi
       
    ;;;;;;;;;;;发完所有的牌;;;;;;
    mov eax,dword ptr ds:[dwBaseMemAdd+58h]        ;该地址保存已发牌的次数
    mov @index,eax
   
    .while @index<5
            mov ecx,dwBaseMemAdd        ;过程需要此参数
            mov eax,lpSendCard        ;发牌的过程入口
            call eax
            inc @index
    .endw
    ;;;;;;;;;;;;;;;;;;;;;
        .if eax
                ;发牌出错时,中止后面的工作
                ret
        .endif
       
    ;;设置每张牌为翻开的状态
    mov @index,0
    mov esi,dwCardArray
    .while @index<68h
            mov eax,@index
            mov ebx,0Ch
                imul eax,ebx
                mov dword ptr ds:[esi+eax+8],1
            
            inc @index
        .endw
       
        ;;设置每列没有翻开的牌的张数为0
        ;;游戏中是以这个没有翻开的张数来设置每张牌露在外面的高度
        mov @index,0
        mov esi,dwUnShowNumArray
        .while @index<0Ah
                mov dword ptr ds:[esi],0
            add esi,4
            
            inc @index
        .endw
       
        ;;;只保留8列在窗口中,
        ;把最后两列分到前面几列中,使每列有13张牌
        invoke AdjustTen2Eight,8,0,1,4,5
        invoke AdjustTen2Eight,9,2,3,6,7
       
        ;;;修改每一列牌的顺序
        mov @index,0
        mov @dwNum,0
        .while @index<8
                mov esi,dwListArray
                mov eax,@index
                mov ebx,4
                imul eax,ebx
                mov esi,dword ptr ds:[esi+eax]
                mov eax,dword ptr ds:[esi]                ;eax指向第一张牌了

                .while eax
                        mov ebx,@dwNum
                        mov dword ptr ds:[eax],ebx
                        mov eax,dword ptr ds:[eax+8]
                        inc @dwNum
                .endw
               
                inc @index
        .endw

        ;;;对牌的数组进行重写,从K到A,在内存中重写
        push dwEasyLevel
        pop @index                ;牌的花色
       
        xor edx,edx
        mov eax,104
        mov ecx,13
        div ecx
        xor edx,edx
        mov ecx,@index
        div ecx
        mov edi,eax
       
        mov esi,dwCardArray
        .while @index>0
                mov edx,4
                sub edx,@index        ;牌的花色
               
                mov @dwNum,edi
                .while @dwNum>0
                        mov @dwCardValue,0Ch        ;牌的点数
                        mov @dwTemp,0
                        .while @dwTemp<13
                                mov dword ptr ds:[esi],edx                ;牌的花色
                                mov ecx,@dwCardValue
                                mov dword ptr ds:[esi+4],ecx        ;牌的点数
                                add esi,12
                                inc @dwTemp
                                dec @dwCardValue
                        .endw
                        dec @dwNum
                .endw
                dec @index
        .endw
       
        ;取得游戏的窗口句柄,其值是保存在dwBaseMemAdd中
    mov eax,dword ptr ds:[dwBaseMemAdd]
        ;重绘窗口内容
        invoke InvalidateRect,eax,NULL,TRUE
       
        ;移动第1-8列到第9列
        mov @dwNum,0
        .while @dwNum<8
                invoke MoveCardCol,@dwNum
                inc @dwNum
        .endw
       
    ret
   
crackspider endp

;///////////////////////////////////////////////////////////////////
end DllEntry

补丁及DLL如下:

patch_dll.rar


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
点赞6
打赏
分享
最新回复 (8)
雪    币: 435
活跃值: (110)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
tornodo 1 2011-2-22 12:06
2
0
看下子。
雪    币: 155
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
yaofande 2011-2-22 14:28
3
0
由于编程水平有限,代码写的很烂,就不贴源码了,各位见谅了!!  你还不如不发这篇文章呢 还浪费你的时间
雪    币: 2264
活跃值: (302)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
cdanlover 2 2011-2-23 14:59
4
0
谢谢,代码经修改,已贴出来!!
雪    币: 284
活跃值: (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
jerrynpc 2011-2-24 08:51
5
0
秒杀蜘蛛,好可怜的蜘蛛。 顺路膜拜楼主
雪    币: 206
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
backboy 2011-2-24 18:23
6
0
详细的代码,谢谢分享
雪    币: 100
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
yangcock 2011-2-24 19:43
7
0
学习了。。。。
雪    币: 210
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
lmhmylsq 2011-2-24 22:16
8
0
学习,多谢楼主!
雪    币: 201
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
brun 2011-8-21 20:16
9
0
只是想知道有没有比系统自带的蜘蛛纸牌更好玩的蜘蛛纸牌
游客
登录 | 注册 方可回帖
返回