首页
论坛
专栏
课程

[原创]利用数据结构知识撸一下微信好友列表

2019-7-16 17:17 2650

[原创]利用数据结构知识撸一下微信好友列表

2019-7-16 17:17
2650
看到网上满天飞微信数据都是HOOK,在这里给大家来点利用数据结构的知识获取微信好友列表。
HOOK要检测到其实相对容易,常用的 代码修改、内存(读写执行)处理、DRX利用。

一、利用微信ID做突破口,找到存放微信ID内存地址:


好友通讯录把微信ID转为UNICODE字节数组,不停切换搜索最后过滤出来几个。

二、我们找到读取微信ID和ID详细信息代码 :
 
先来个硬件访问断点。


断点下好后再去切换一下好友列表,这时我们看堆栈。
第一个明显是两个ID 交换写入,我们直接看第二个.


标注参数一为传入微信号,eax 是上面的[esi + 0x1C] 赋值, 我们先看看 esi 数据(数据窗口内             好像是一些详细信息)
这时我们需要找 esi 来源。




我们看到 esi 需要加 0x28.
我们对add esi,0x28下 F2 断点,然后在数据窗口里看到如图。
这时我们直接对 $-28 下硬件访问断点.


这里我们疑似看到了一段二叉树搜索代码。
如何证明这里是二叉树?

我们明显看到 中间指向上一个结点, 上一个第一或者第三指向下一个结点


这里我们继续返回找到二叉树的头


这里可以看到 ecx 来源ebx, ebx = esi + 68, 那么这时二叉树头应该是 dd [esi + 68] + 4


我们继续往上找可以看到 ecx, ebx, 继续找 ebx 来源。




这里我们好像发现了什么。
获取二叉树头 esi 的地方。

 
函数返回的eax,dd [eax + 68] + 4
好像拿到二叉树的头了。   

三、我们写点代码把好友列表读出来 :
学过一点数据结构应该知道,遍历二叉树常用 递归双栈

先找到图上函数地址:
DWORD CSearchMem::SearchFriendBase()
{
	DWORD dwRet = 0;

	try
	{
		if (m_sModuleName.empty())
		{
			return dwRet;
		}

		DWORD dwModuleBase = 0;
		int dwModuleSize = 0;

		if (!GetSearchInfo(m_sModuleName.c_str(), dwModuleBase, dwModuleSize))
		{
			return dwRet;
		}

		char chOpCode[] = "\x83\xC8\xFF\xFF\xFF\x8D\x8D\xFF\xFF\xFF\xFF\xE8";

		dwRet = SearchAddress(dwModuleBase, dwModuleSize, (const byte*)chOpCode, ::strlen(chOpCode), true, 0x1F);
	}
	catch (...)
	{
		dwRet = 0;
	}

	return dwRet;
}
int CSearchMem::SearchAddress(int inStartAddr, int inSize, const byte* pOpCode, int inOpSize, bool bDirection, int inOffset)
{
	int inRet = 0;

	try
	{
		if ((0 == inStartAddr) || (inSize <= 0) || (NULL == pOpCode) || (NULL == inOpSize))
		{
			return inRet;
		}

		DWORD dwOleProtect = 0;
		::VirtualProtect((LPVOID)inStartAddr, inSize, PAGE_EXECUTE_READ, &dwOleProtect);

		int inFindCount = 0;
		byte* pData = (byte*)inStartAddr;

		for (int i = 0; i < inSize; i++, pData++)
		{
			const byte* pOpData = pOpCode;

			for (int j = 0; j < inOpSize; j++, pOpData++)
			{
				while (0xFF == *pOpData)
				{
					inFindCount++;

					i++;
					pData++;

					j++;
					pOpData++;
				}

				if (*pData == *pOpData)
				{
					inFindCount++;

					i++;
					pData++;
				}
				else
				{
					inFindCount = 0;
					break;
				}
			}

			if (inFindCount == inOpSize)
			{
				break;
			}
		}

		if (inFindCount == inOpSize)
		{
			inRet = (int)pData - inFindCount;

			if (bDirection)
			{
				inRet = inRet + inOffset;
			}
			else
			{
				inRet = inRet - inOffset;
			}
		}

		::VirtualProtect((LPVOID)inStartAddr, inSize, dwOleProtect, &dwOleProtect);
	}
	catch (...)
	{
		inRet = 0;
	}

	return inRet;
}
获取二叉树头:
DWORD CFriendTable::GetFriendHeader()
{
	DWORD dwRet = 0;

	__try
	{
		DWORD dwBase = SearchFriendBase();

		if (0 == dwBase)
		{
			return dwRet;
		}

		DWORD dwCall = dwBase + *(PDWORD)(dwBase + 1) + 5;

		if ((0 == dwCall) || (::IsBadReadPtr((void*)dwCall, sizeof(int))))
		{
			return dwRet;
		}

		DWORD dwHeader = GetHeader(dwCall);

		if (0 != dwHeader)
		{
			__asm
			{
				pushad
				pushfd

				mov esi, dword ptr dwHeader
				lea ecx, dword ptr[esi + 0x68]
				mov ebx, dword ptr[ecx]
				mov esi, dword ptr[ebx + 0x4]
				mov dword ptr dwRet, esi

				popfd
				popad
			}
		}
	}
	__except (EXCEPTION_EXECUTE_HANDLER)
	{
		dwRet = 0;
	}

	return dwRet;
}

//二叉树结构
typedef struct _BinaryTree
{
	//左
	_BinaryTree* s_tree_pleft;
	//中
	_BinaryTree* s_tree_pcentre;
	//右
	_BinaryTree* s_tree_pright;
	//标志
	byte				s_by_flags;
	//结束标志
	byte				s_by_endflags;

	_BinaryTree()
	{
		s_tree_pleft = nullptr;
		s_tree_pcentre = nullptr;
		s_tree_pright = nullptr;
		s_by_flags = 0;
		s_by_endflags = 0;
	}

} BinaryTree, *pBinaryTree;

                DWORD dwHeader = GetFriendHeader();

		if (0 == dwHeader)
		{
			return bRet;
		}

		pBinaryTree pTree = reinterpret_cast<pBinaryTree>(dwHeader);

		stack<pBinaryTree> pStack1, pStack2;
		pStack1.push(pTree);

		while (!pStack1.empty())
		{
			pBinaryTree pTempTree = pStack1.top();

			pStack1.pop();

			if (pTempTree->s_by_endflags == 0)
			{
				pStack2.push(pTempTree);

				if ((pTempTree->s_tree_pleft) && (pTree != pTempTree->s_tree_pleft))
					pStack1.push(pTempTree->s_tree_pleft);

				if ((pTempTree->s_tree_pright) && (pTree != pTempTree->s_tree_pright))
					pStack1.push(pTempTree->s_tree_pright);
			}
		}

		while (!pStack2.empty())
		{
			pBinaryTree pTreeItem = pStack2.top();

			if (NULL != pTreeItem)
			{
				ItemInfo Info;
				Info.sObject = (DWORD)pTreeItem;

				GetWechatId(Info.sObject, Info.sWechatId);

				GetWechatNumber(Info.sObject, Info.sWechatNumber);

				GetName(Info.sObject, Info.sName);

				GetRemarks(Info.sObject, Info.sRemarks);

				GetSpellAc(Info.sObject, Info.sSpellAc);

				GetSpellFu(Info.sObject, Info.sSpellFu);

				if (::wcsstr(Info.sWechatId.c_str(), TEXT("@chatroom")))
				{
					IsRoomChat(Info.sObject, Info.sRoom);
				}

				pInfo->push_back(Info);
			}

			pStack2.pop();
		}

效果如图:




[公告]安全服务和外包项目请将项目需求发到看雪企服平台:https://qifu.kanxue.com

最新回复 (6)
#幼稚不 2019-7-16 17:52
2
0
这很6 值得学习
yimingqpa 1 2019-7-16 17:59
3
0
 看贴的人不要去加图中的微信号,因为是测试号或者机器人号。
cmputer 2019-7-16 19:37
4
0
 
最后于 2019-7-16 19:37 被cmputer编辑 ,原因:
pengqiang 2019-7-17 07:16
5
0
听朋友说 有啥能爆破微信好友这个人的他的通讯录.以为是这个。。
小白学C 2019-7-21 20:24
6
0
老乡是荆门的吗
易语言初学者 2019-9-10 12:47
7
0
老大 能不能说的稍微详细点呀,对于初学者来说 完全没看懂
游客
登录 | 注册 方可回帖
返回