分析连连看

1. 样本概况

1.1 应用程序信息

应用程序名称:连连看单机版
MD5值:
SHA1值:
简单功能介绍:
说明:如果是分析网页则记录网页的相关信息即可

1.2 分析环境及工具

Win7 32位操作系统,使用工具:OD,CE,Visual Studio 2019

2. 具体分析过程

2.1 找到程序本身的EXE

  先打开游戏,会先进入广告界面,需要跳过这个界面。在任务管理器中关闭游戏进程,可以发现关闭kyodai.exe后游戏关闭,所以程序本身的exe应该是 kyodai.exe。
  在文件夹中找到kyodai.exe,双击打开,发现不能打开,可以知道游戏的打开被广告程序限制了,我们需要分析广告程序找到打开游戏的部分。

2.2 去除程序的广告

  由于不能直接打开程序本身的exe,程序是通过另一个广告程序打开的,所以我们可以分析一下广告程序是怎么打开游戏的,然后我们直接利用这个功能打开游戏。
  来到广告程序中打开游戏的界面,发现点击继续之后会弹出游戏界面。
在这里插入图片描述
  猜测这个程序使用了创建窗口或者创建进程的 API,所以我们用OD打开广告程序,然后在这些API中下断点,然后点击继续,看程序在OD中有没有断下来。
  经过尝试发现程序在CreateProcess处断了下来。
在这里插入图片描述
在这里插入图片描述
  查看堆栈,发现创建进程的地址为0x43817A,跟随地址,观察函数调用之后,将01修改成了00。
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
  用LoadPE找到偏移地址,然后在010Ediotr中将对应的EXE中的值修改成00
在这里插入图片描述
  修改之后保存,然后双击修改后的程序,进入了游戏,并且跳过了广告。

2.3 编写DLL完成外挂

  我们要完成的外挂功能是可以自动匹配相同的方块,在游戏中有自动匹配方块的道具,我们的思路是利用游戏自带的道具,完成外挂功能。
  首先我们要找到游戏中调用道具的地方。
  找出道具的思路是,先在内存中找到存储方块的数组,然在这里下内存访问断点,再使用道具,因为道具会根据数组判断方块是否可以消,所以在断点处查看堆栈,里面就会有道具函数的调用。
  要找出存储数组,我们考虑在可能调用的API处下断点,然后去查看哪个地方存储了数组。
因为地图的初始化是没有规律的,所以猜测可能调用了RAND函数来生成随机数。
  我们在Rand函数处下一个断点,让程序运行起来,点击练习,会生成新的地图,并且程序也断了下来,我们按F8向下查看。
在这里插入图片描述
  我们来到第二个CALL时,进入函数,发现只传入了一个参数,我们查看ECX,在数据窗口跟随。
在这里插入图片描述在这里插入图片描述
  再跟随第二个地址,找到数组。
在这里插入图片描述
  在数组里下一个内存访问断点,然后使用指南针道具,当程序断下来时查看堆栈。
在这里插入图片描述
  从里面可以找出调用指南针的函数。
在这里插入图片描述
  给栈里可能的函数下断点,然后使用指南针道具看程序在哪里断下来。
在这里插入图片描述
  找到之后我们创建一个MFC DLL来调用这个函数,来验证这个函数的功能。
  首先创建一个MFC DLL项目,在初始化部分获取连连看窗口句柄,然后设置窗口回调函数,并且还需要弹出有一个对话框,在对话框里添加按钮,通过按按钮实现外挂功能。
在这里插入图片描述  通过调试之后写出相应部分的代码
①处的代码为:

CWinApp::InitInstance();
//1.查找扫雷窗口,获得句柄
g_Wnd = ::FindWindow(NULL, L"QQ连连看");
if (g_Wnd == NULL)
{
	OutputDebugString(L"获取窗口句柄失败");
	return FALSE;
}
//2.设置窗口回调函数
g_OldProc = (WNDPROC)SetWindowLong(g_Wnd, GWL_WNDPROC, (LONG)WindowProc);
if (g_OldProc == NULL)
{
	OutputDebugString(L"设置窗口回调函数失败");
	return FALSE;
}

②处的代码为:

//创建线程
_beginthreadex(0, 0, (_beginthreadex_proc_type)ThreadProc, 0, 0, 0);

③处的代码为:

//线程回调函数 
unsigned __stdcall ThreadProc()
{
	CMyDlg dlg;
	dlg.DoModal();
	return 0;
}

④处的窗口按钮:处的窗口按钮:
在这里插入图片描述
⑤处的代码为:

//使用指南针
void CMyDlg::OnBnClickedButton1()
{
	// TODO: 在此添加控件通知处理程序代码
	CLianLianKanPlugApp* pApp = (CLianLianKanPlugApp*)AfxGetApp();
	::SendMessage(pApp->g_Wnd, WM_DATA1, 0, 0);
}

⑥处的代码为:

//窗口回调函数
LRESULT CALLBACK WindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
	if (Msg == WM_DATA1)
	{
		//调用指南针道具
		_asm 
		{
			mov ECX, 0x45DEBC
			mov ECX, [ECX]
			LEA ECX, DWORD PTR DS : [ECX + 0x494] 
			push 0xF0
			push 0
			push 0
			mov EAX,0x0041E691
			call EAX
		} 
		return DefWindowProc(hWnd, Msg, wParam, lParam);
	}
}

  写好程序后生成DLL,将DLL注入练练看进程,点击使用指南针按钮。
在这里插入图片描述
  接下来再实现消除功能。
  先找到消除两个相同块的函数,采用之前找指南针函数的方法,先找到内存数组,然后下内存访问断点,手动消除两个相同方块,直到程序断下来,程序断下来后按F8继续走,直到内存中对应的区域的方块被消除,然后点击K查看堆栈,
  经过排除和观察参数,找到一个很有可能是消除的CALL
在这里插入图片描述
  我们通过分析参数,再VS中模拟参数的传递来调用这个CALL,来验证它的功能
  DLL的代码如下:

POINT P1 = {0};
	POINT P2 = {0};
	//获得坐标
	_asm
	{
		mov ecx, 0x045DEBC
		mov ecx, [ecx]
		lea ecx,DWORD PTR DS:[ecx+0x494]
		mov ecx, DWORD PTR DS : [ecx + 0x19F0]
		lea eax, P1.x;
		push eax
		lea eax, P2.x;
		push eax 
		mov eax,0x0042923F
		call eax
	}
	if (P1.x == 0 && P1.x == P1.y)
	{
		return -1;
	}
	//调用消除函数
	_asm
	{
		mov ecx, 0x45DEBC
		mov ecx, [ecx]
		push 0x4
		lea eax, DWORD PTR DS : [ecx + 0x494]
		mov eax, DWORD PTR DS : [eax + 0x19F0]
		add eax, 0x40
		push eax

		lea eax, P1.x;
		push eax
		lea eax, P2.x;
		push eax

		lea eax,DWORD PTR DS:[ecx+0x494]
		mov eax,DWORD PTR DS:[eax+0x19F0]
		mov eax,DWORD PTR DS:[eax+0x4]
		push eax
		push 0
		mov eax,0x0041C68E
		call eax
	}
		return DefWindowProc(hWnd, Msg, wParam, lParam);

  生成DLL,然后注入到游戏中。
在这里插入图片描述
  经过测试,消除功能可以使用
  再实现一个一键秒杀功能
  我们只需要循环发送消息,让程序不断使用消除功能直道消除所有方块为止。
  实现的代码如下:

//一键秒杀
void CMyDlg::OnBnClickedButton2()
{
	// TODO: 在此添加控件通知处理程序代码
	CLianLianKanPlugApp* pApp = (CLianLianKanPlugApp*)AfxGetApp();
	for (int i = 0; i < 100; i++)
	{
		::SendMessage(pApp->g_Wnd, WM_DATA2, 0, 0);
		if (i == -1)
		{
			break;
		}
	}
}

  生成之后再注入连连看测试一下。
在这里插入图片描述
经过测试,一键秒杀功能也实现了。

3. 总结

  经过几天的学习,终于实现了练练看的外挂,在完成练练看项目的过程中,我学到了新的逆向思路和方法。
  可以通过搜索函数或API对它们下断点,然后在它们附近找需要的部分,并且通过堆栈查看在断点前都调用了哪些函数,然后在这些函数处下断点来找出需要分析的函数。
  如果在内存中找到了要分析的数据,可以对这个数据下内存访问断点,看哪些地方对它进行了访问。
  这些方法都是帮助我们快速定位到需要分析的函数或者数据,通过下断点和栈回溯的结合,定位函数非常方便。
  另外还学习了在DLL中使用汇编来调用程序的函数,以及通过自定义消息的回调函数来使用这些函数。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值