扫雷群规则资讯

微信红包群扫雷外挂编写红包榜

发布人:147小编 来源:微信抢红包群,支付宝红包群,红包群,红包扫雷群发布时间:2022-08-11 21:07:36 热度:

一、外挂效果

①、标注炸弹位置。(Crack菜单为外挂设置的)

可以与对比上图

②、冻结时间。

二、简要过程

一、首先用CE找到一些重要的数据位置。

1、不断改变棋盘的宽度和长度, 宽度,高度最大为24(0x18)*30(0x1e),最小9*9。其中宽度地址为:0x010056AC,高度地址为0x010056A8。均为全局变量,如下图:

2、程序会记录翻开的格子数,该变量同样为全局变量,位于0x010057A4,未开局时格式数为0。3、同理,也可以找到炸弹数等变量的位置,在此略过。

二、找到棋盘格的数据。

1、用IDA查看程序符号表。发现用到了SetTimer,KillTimer函数。猜测程序用Timer计时,查看SetTimer的引用位置,发现:

可见uElapse即间隔为0x3E8H,也即1000,意味着1000ms触发一次WM_TIMER消息。2、程序中炸弹是随机生成的,而通过IDA查看符号表时发现了rand函数。也就是说,可以假设,如果要产生炸弹,就会用到rand函数。于是找到引用rand函数的位置:

将此过程称为rand_number,然后再次查看它的引用,发现有两处,均为同一过程。

可见程序调用的两次rand_number,在此设为r1,r2。有:esi = r1+1,ecx = (r2+1)*32;。发现这两条指令

.text:010036F3 lea eax, dword_1005340[eax+esi] .text:010036FA or byte ptr [eax], 80h

联想到二维数组的存取,也就是说,这两条指令非常类似于产生两个随机的x,y坐标将其设为炸弹。要记着上面的随机数均加了1。下面来验证,设此数组为target ,并记下地址0x01005340,边在扫雷上点击,边用CE去查看target的情况。

在第一个格子处插旗子,0x01005361处的原来的值-1,插问号-2,在点击右键此值还原。第二个格子在0x01005362处,同样的现象。并且观察到0x01005361 = 0x01005340 + 32 +1。正好与上面的两个随机数都加了1情况相符。找到了游戏放置棋盘格子的数组,下面逐渐找规律,不断点击,尝试,过程略过,结果如下:

未翻开无炸弹:0x0F,翻开无数字0x40,翻开有数字=0x40+数字,如显示1就为0x41,未翻开有炸弹:0x8F,踩到0xcc此外,在任意格子上插旗-1,插问号-2并且网格二维数组宽度为固定大小 32,其中每行开头一个0x10,结尾一个0x10,标识该行数据的结束,其后的数据无效数组宽度 32 -2 = 30 ,恰好是可设置的最大宽度

三、因为要在扫雷程序上标注,还要找到一格的像素大小和位置。

程序用到了Bitblt,CreateCompatibleDC,CreateCompatibleBitmap函数。推测棋盘是用BitBlt画出来的。

查看BitBlt的引用。共两处。第一处:

在BitBlt函数上设下断点,命中并执行一次后:

第二处:

设下断点,发现此过程是在点击某个网格时调用的。查看BitBlt函数的具体参数,cx,cy为大小;x,y为位置。通过点击不同网格,可以得到:(0,0对应第一个网格)0,0(0xC,0x37)0,1(0x1C,0x37)1,0(0x0C,0x47)1,1(0x1C,0x47)网格大小为16 * 16第一个网格位置(相对于客户区)为0xC,0x37。**

三、编写外挂

因为要在扫雷上画图,采用HOOK注入DLL+窗口子类化。主程序代码:

//主程序代码:includeincludeincludeinclude"..\crackDll\crackDll.h"includeifdef _UNICODEusingtstring=std::wstring;elseusingtstring=std::string;endiftstringg_strCurrentDir;intWINAPI_tWinMain(HINSTANCEhInstExe,HINSTANCE,PTSTRpszCmdLine,intnCmdShow){TCHARszPath[MAX_PATH];GetModuleFileName(NULL,szPath,_countof(szPath));g_strCurrentDir=szPath;g_strCurrentDir=g_strCurrentDir.substr(0,g_strCurrentDir.find_last_of(_T(\\))+1);tstringstr=g_strCurrentDir+_T("winmine.exe");//启动扫雷STARTUPINFOinfoStartUp={sizeof(infoStartUp)};PROCESS_INFORMATIONinfoProcess;BOOLret=CreateProcess(str.c_str(),NULL,NULL,NULL,FALSE,NULL,NULL,NULL,&infoStartUp,&infoProcess);if(ret==0){MessageBox(NULL,_T("Startup Error"),_T("Error"),MB_ICONERROR);exit(0);}ret=Crack(infoProcess.dwThreadId);if(!ret){MessageBox(NULL,_T("Crack fail..."),_T("Error"),MB_ICONERROR);}WaitForSingleObject(infoProcess.hProcess,INFINITE);CloseHandle(infoProcess.hProcess);CloseHandle(infoProcess.hThread);return0;}//需将扫雷与外挂放在同一目录下。//crackDll.h为DLL的导出函数头文件,在这里就只有一个Crack导出函数

下面是DLL的代码:

Crack函数:

//外挂调用CRACKDLL_APIBOOLCrack(DWORDdwThreadId){while((g_hMainWnd=FindWindow(NULL,_T("扫雷")))==NULL)//等窗口出现再HOOKSleep(300);g_hHook=SetWindowsHookEx(WH_GETMESSAGE,HookMessageProc,g_hDllModule,dwThreadId);returng_hHook!=NULL;}

Hook过程函数,在这里子类化扫雷的窗口,设置自己的窗口过程函数,并设置自己的菜单:

LRESULTCALLBACKHookMessageProc(_In_intcode,_In_WPARAMwParam,_In_LPARAMlParam){staticboolbFrist=true;if(bFrist){bFrist=false;g_oldWndProc=(WNDPROC)SetWindowLongPtr(g_hMainWnd,GWLP_WNDPROC,(LONG)CrackWndProc);HMENUhMenu=GetMenu(g_hMainWnd);HMENUhNewMenu=LoadMenu(g_hDllModule,MAKEINTRESOURCE(IDR_CRACK));AppendMenu(hMenu,MF_POPUP,(UINT_PTR)GetSubMenu(hNewMenu,0),_T("Crack"));SetMenu(g_hMainWnd,hMenu);InvalidateRect(g_hMainWnd,NULL,TRUE);}returnCallNextHookEx(g_hHook,code,wParam,lParam);}

新窗口过程:

LRESULTWINAPICrackWndProc(HWNDhwnd,UINTmsg,WPARAMwParam,LPARAMlParam){boolbUnplayed;switch(msg){caseWM_PAINT:CallWindowProc(g_oldWndProc,hwnd,msg,wParam,lParam);//先让游戏画,再在游戏上画if(g_bShowBombs)DrawLabel();return0;caseWM_TIMER:// 如果停止计时就直接跳过WM_TIMER消息if(g_bFreeze){return0;}elsebreak;caseWM_LBUTTONUP:bUnplayed=pOpenedGridNumLoc[0]==0;CallWindowProc(g_oldWndProc,hwnd,msg,wParam,lParam);//先让游戏处理ProcessClick(bUnplayed);//找到点击的网格,并刷新return0;caseWM_COMMAND:if(!HIWORD(wParam&&!lParam))//处理自己的菜单消息,将自己的菜单IDProcessMenu(LOWORD(wParam));break;default:break;}returnCallWindowProc(g_oldWndProc,hwnd,msg,wParam,lParam);}

宏及重要的地址:

define FIRST_GRID_X 0xCdefine FIRST_GRID_Y 0x37define GRID_WIDTH 0x10define GRID_HEIGHT 0x10char*pGridLoc=(char*)0x01005360;char*pMatWidthLoc=(char*)0x010056AC;char*pMatHeightLoc=(char*)0x010056A8;int*pOpenedGridNumLoc=(int*)0x010057A4;int*pClickXLoc=(int*)0x01005118;int*pClickYLoc=(int*)0x0100511C;

最后重要的DrawLabel()函数,绘制炸弹位置:

//读取炸弹数据,在棋盘格上标注voidDrawLabel(){HDChdc;RECTrect;intx,y;GetClientRect(g_hMainWnd,&rect);hdc=GetDC(g_hMainWnd);HBRUSHhBrush=CreateSolidBrush(RGB(255,0,0));HGDIOBJhOldObject=SelectObject(hdc,hBrush);intiMatWidth=pMatWidthLoc[0];intiMatHeight=pMatHeightLoc[0];if(!iMatWidth||!iMatHeight)return;intiGridNum=iMatWidth*iMatHeight;for(inti=0;i<iMatHeight;i++){for(intj=0;j<iMatWidth;j++){switch((unsignedchar)pGridLoc[i*32+1+j]){case0x8F://炸弹x=FIRST_GRID_X+j*GRID_WIDTH;y=FIRST_GRID_Y+i*GRID_HEIGHT;Rectangle(hdc,x+2,y+2,x+GRID_WIDTH-2,y+GRID_HEIGHT-2);break;default:break;}}}SelectObject(hdc,hOldObject);DeleteObject(hBrush);ReleaseDC(g_hMainWnd,hdc);}

一个细节,如果游戏点击的第一个方格为炸弹,则游戏会把炸弹移动到别处。因此,拦截WM_LBUTTONUP(而非WM_LBUTTONDOWN)消息,如果开局就点击炸弹,需要刷新标记的位置。ProcessClick函数:

voidProcessClick(boolbUnplayed){intclickX=*pClickXLoc;intclickY=*pClickYLoc;//判断用户点击的X和Y坐标,(1,1)为第一个网格。此逻辑与游戏相同,参考.text:010037E1处的代码if(bUnplayed&&clickX>0&&clickX<=pMatWidthLoc[0]&&clickY>0&&clickY<=pMatHeightLoc[0]){InvalidateRect(g_hMainWnd,NULL,TRUE);UpdateWindow(g_hMainWnd);}}
... 
上一篇 : 红包群手把手教你写扫雷外挂扫雷红包群群规图片
下一篇 : QQ扫雷群怎么才能发现微信群里抢红包用隐身挂的?支付宝红包
猜你喜欢的微信抢红包群,支付宝红包群,红包群,红包扫雷群