欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

编写扫雷游戏插件

编写扫雷游戏插件

先说一下:本人菜鸟,做这个完全当是写作业(~~~~)
闲来无聊,下了个郁金香的外挂教程,看了第一章,想学习一下,就用扫雷开始练下手。
先上OD,检测下数据:

用PEID检测下,是c程序。由于每次布雷都不一样,猜测应该用了随机函数rand来布点;
下断点如下:

运行程序,点击扫雷笑脸图标;
断下来了:

反汇编中跟随,查找函数的调用:
rand:随机函数(记住地址 1003940)

继续查找上一步调用:
0100367A  /$  A1 AC560001   MOV EAX,DWORD PTR DS:[10056AC]//宽度
0100367F  |.  8B0D A8560001 MOV ECX,DWORD PTR DS:[10056A8]//高度
01003685  |.  53            PUSH EBX
01003686  |.  56            PUSH ESI
01003687  |.  57            PUSH EDI
01003688  |.  33FF          XOR EDI,EDI
0100368A  |.  3B05 34530001 CMP EAX,DWORD PTR DS:[1005334]//比较1005334与10056ac地址是否一致
01003690  |.  893D 64510001 MOV DWORD PTR DS:[1005164],EDI
01003696  |.  75 0C         JNZ SHORT winmine.010036A4
01003698  |.  3B0D 38530001 CMP ECX,DWORD PTR DS:[1005338]//比较1005338与10056a8地址是否一致
0100369E  |.  75 04         JNZ SHORT winmine.010036A4
010036A0  |.  6A 04         PUSH 4
010036A2  |.  EB 02         JMP SHORT winmine.010036A6
010036A4  |>  6A 06         PUSH 6
010036A6  |>  5B            POP EBX
010036A7  |.  A3 34530001   MOV DWORD PTR DS:[1005334],EAX//宽度
010036AC  |.  890D 38530001 MOV DWORD PTR DS:[1005338],ECX//高度
010036B2  |.  E8 1EF8FFFF   CALL winmine.01002ED5   //分配并编写雷区的内存数据
010036B7  |.  A1 A4560001   MOV EAX,DWORD PTR DS:[10056A4]//雷数
010036BC  |.  893D 60510001 MOV DWORD PTR DS:[1005160],EDI//5160处赋0
010036C2  |.  A3 30530001   MOV DWORD PTR DS:[1005330],EAX//雷数
010036C7  |>  FF35 34530001 PUSH DWORD PTR DS:[1005334]
010036CD  |.  E8 6E020000   CALL winmine.01003940//横坐标随机化
010036D2  |.  FF35 38530001 PUSH DWORD PTR DS:[1005338]
010036D8  |.  8BF0          MOV ESI,EAX   //将结果赋给ESI
010036DA  |.  46            INC ESI             //ESI加一
010036DB  |.  E8 60020000   CALL winmine.01003940//纵坐标随机化
010036E0  |.  40            INC EAX           //纵坐标随机结果加一;
010036E1  |.  8BC8          MOV ECX,EAX
010036E3  |.  C1E1 05       SHL ECX,5    //纵坐标结果乘以(OX20)
010036E6  |.  F68431 405300>TEST BYTE PTR DS:[ECX+ESI+1005340],80 //检测随机处的内存数是否为80
010036EE  |.^ 75 D7         JNZ SHORT winmine.010036C7      //如果为80则重新随机
010036F0  |.  C1E0 05       SHL EAX,5                                    //纵坐标结果乘以(OX20)
010036F3  |.  8D8430 405300>LEA EAX,DWORD PTR DS:[EAX+ESI+1005340] //取有效地址赋给EAX;
010036FA  |.  8008 80       OR BYTE PTR DS:[EAX],80           //将随机处内存数据与80向或;
010036FD  |.  FF0D 30530001 DEC DWORD PTR DS:[1005330]   //雷数减一
01003703  |.^ 75 C2         JNZ SHORT winmine.010036C7  //雷数为0则不调转,否则继续布雷
01003705  |.  8B0D 38530001 MOV ECX,DWORD PTR DS:[1005338]
0100370B  |.  0FAF0D 345300>IMUL ECX,DWORD PTR DS:[1005334]
01003712  |.  A1 A4560001   MOV EAX,DWORD PTR DS:[10056A4]
01003717  |.  2BC8          SUB ECX,EAX
01003719  |.  57            PUSH EDI
0100371A  |.  893D 9C570001 MOV DWORD PTR DS:[100579C],EDI
01003720  |.  A3 30530001   MOV DWORD PTR DS:[1005330],EAX
01003725  |.  A3 94510001   MOV DWORD PTR DS:[1005194],EAX
0100372A  |.  893D A4570001 MOV DWORD PTR DS:[10057A4],EDI
01003730  |.  890D A0570001 MOV DWORD PTR DS:[10057A0],ECX
01003736  |.  C705 00500001>MOV DWORD PTR DS:[1005000],1
01003740  |.  E8 25FDFFFF   CALL winmine.0100346A
01003745  |.  53            PUSH EBX                                 ; /Arg1
01003746  |.  E8 05E2FFFF   CALL winmine.01001950                    ; \winmine.01001950
0100374B  |.  5F            POP EDI
0100374C  |.  5E            POP ESI
0100374D  |.  5B            POP EBX
0100374E  \.  C3            RETN
OD中输入:db 10056ac
检测下传递至EAX,ECX中的内容,测试知10056ac中数据为宽度,10056a8为高度。
在扫雷游戏里,标记一个地雷,发现该处的内存数为8E
进入010036B2  |.  E8 1EF8FFFF   CALL winmine.01002ED5
查看布雷详情:
01002ED5  /$  B8 60030000   MOV EAX,360                        //开辟0X360个内存单元
01002EDA  |>  48            /DEC EAX
01002EDB  |.  C680 40530001>|MOV BYTE PTR DS:[EAX+1005340],0F//将内存单元的数值设为0F
01002EE2  |.^ 75 F6         \JNZ SHORT winmine.01002EDA
01002EE4  |.  8B0D 34530001 MOV ECX,DWORD PTR DS:[1005334]  //横坐标赋值给ECX
01002EEA  |.  8B15 38530001 MOV EDX,DWORD PTR DS:[1005338] //~~~~~~~~~
01002EF0  |.  8D41 02       LEA EAX,DWORD PTR DS:[ECX+2]
01002EF3  |.  85C0          TEST EAX,EAX
01002EF5  |.  56            PUSH ESI
01002EF6  |.  74 19         JE SHORT winmine.01002F11
01002EF8  |.  8BF2          MOV ESI,EDX
01002EFA  |.  C1E6 05       SHL ESI,5
01002EFD  |.  8DB6 60530001 LEA ESI,DWORD PTR DS:[ESI+1005360]
01002F03  |>  48            /DEC EAX
01002F04  |.  C680 40530001>|MOV BYTE PTR DS:[EAX+1005340],10
01002F0B  |.  C60406 10     |MOV BYTE PTR DS:[ESI+EAX],10
01002F0F  |.^ 75 F2         \JNZ SHORT winmine.01002F03
01002F11  |>  8D72 02       LEA ESI,DWORD PTR DS:[EDX+2]
01002F14  |.  85F6          TEST ESI,ESI
01002F16  |.  74 21         JE SHORT winmine.01002F39
01002F18  |.  8BC6          MOV EAX,ESI
01002F1A  |.  C1E0 05       SHL EAX,5
01002F1D  |.  8D90 40530001 LEA EDX,DWORD PTR DS:[EAX+1005340]
01002F23  |.  8D8408 415300>LEA EAX,DWORD PTR DS:[EAX+ECX+1005341]
01002F2A  |>  83EA 20       /SUB EDX,20
01002F2D  |.  83E8 20       |SUB EAX,20
01002F30  |.  4E            |DEC ESI
01002F31  |.  C602 10       |MOV BYTE PTR DS:[EDX],10
01002F34  |.  C600 10       |MOV BYTE PTR DS:[EAX],10
01002F37  |.^ 75 F1         \JNZ SHORT winmine.01002F2A
01002F39  |>  5E            POP ESI
01002F3A  \.  C3            RETN

从这个里面可以看到和80或的是0F,相或结果为8F
在随机化布雷时,纵坐标数值始终是以纵坐标数乘以32进行增长(16进制为20),所以对于横纵坐标数值应为:
32高+宽;
用SPY++检测雷区坐标位置如下:



第一格和第二格:(这个和图片有点对不齐,因为图是后来截的。呵呵)
横坐标:17,纵坐标:59;
横坐标:32,纵坐标:75;
横坐标相差16,纵坐标相差16.
以横坐标为16纵坐标为60做为第一点,依次类推;
编写开雷的函数如下:

用C++编写代码如下:
void CSaoleiDlg::scanfun(int dire, BOOL biaolei, BOOL kailei, BOOL step)
{
  const lt=0;(左上方)
  const lb=1;(左下方)
  const rt=2;(右上方)
  const rb=3;(右下方)
//第三位为顺序位:横向为1;纵向为0;
  DWORD x = 0x10056A8;
  DWORD lparam=0x003C0010;
  DWORD y = 0x10056AC;
  DWORD addr = 0x1005361;
  HWND hwnd = ::FindWindow(NULL, "扫雷");
  DWORD hProcessId;
  GetWindowThreadProcessId(hwnd, &hProcessId);
  HANDLE Process =OpenProcess(PROCESS_ALL_ACCESS, FALSE, hProcessId);
  int b=0,s =0,nx =0,ny =0,ti=0,tj=0;
  BOOL contr=TRUE;
  ReadProcessMemory(Process, (LPCVOID)x, &nx, 1, NULL); //X为高度
  ReadProcessMemory(Process, (LPCVOID)y, &ny, 1, NULL); //Y为宽度。
if((dire&4)==4)
{
    for(int i = 0; (i < nx)&&contr ; i++)
    {
  {
    if((dire&2)==2)
      ti=nx-i-1;
    else
      ti=i;
  }
  for(int j = 0; (j < ny)&&contr; j++)
  {
    {
      if((dire&1)==1)
        tj=ny-j-1;
      else
        tj=j;
    }
    ::ReadProcessMemory(Process, (LPCVOID)(addr + 32*ti+tj), &b, 1, NULL);
  if (b == 0x8F&&biaolei==TRUE) //判断是否有雷
    {
    s = 0x8E; //如果有雷就画上小红旗
    ::WriteProcessMemory(Process, (LPVOID)(addr + 32*ti+tj), &s, 1, NULL);
    if(step==TRUE)
        { 
        contr=FALSE;
//        break;
        }
    }
  else if(b==0x0F&&kailei==TRUE)
    {  
      lparam=(0x003C0010+0x10000*(16*ti)+16*tj);
      ::SendMessage(hwnd,WM_LBUTTONDOWN,0,lparam);
      ::SendMessage(hwnd,WM_LBUTTONUP,0,lparam);
      if(step==TRUE)
        { 
        contr=FALSE;
//        break;
        }
    }
    
  }
    }
}
else
  for(int j = 0; (j < ny)&&contr; j++)
{
  {
      if((dire&1)==1)
        tj=ny-j-1;
      else
        tj=j;    
  }
  for(int i = 0; (i < nx)&&contr ; i++)
  {
    {
      if((dire&2)==2)
        ti=nx-i-1;
      else
        ti=i;      
    }
    ::ReadProcessMemory(Process, (LPCVOID)(addr + 32*ti+tj), &b, 1, NULL);
  if (b == 0x8F&&biaolei==TRUE) //判断是否有雷
    {
    s = 0x8E; //如果有雷就画上小红旗
    ::WriteProcessMemory(Process, (LPVOID)(addr + 32*ti+tj), &s, 1, NULL);
    if(step==TRUE)
        { 
        contr=FALSE;
//        break;
        }
    }
  else if(b==0x0F&&kailei==TRUE)
    {  
      lparam=(0x003C0010+0x10000*(16*ti)+16*tj);
      ::SendMessage(hwnd,WM_LBUTTONDOWN,0,lparam);
      ::SendMessage(hwnd,WM_LBUTTONUP,0,lparam);
      if(step==TRUE)
        { 
        contr=FALSE;
//        break;
        }
    }
    
  }
}
  ::InvalidateRect(hwnd, NULL, TRUE);
  ::CloseHandle(Process);
}
例如:
  scanfun(4,TRUE,FALSE,TRUE);
则表明从左上方横向单补表雷;

由于本人菜鸟,写这个完全是学习,只是把他当作业~~-~~

上传的附件 扫雷辅助.rar

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途。
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功