看网上有许多通过进程寻找QQ号的例子,看了一下,里面涉及的知识点还是比较多,但网上的兼容性不太好,而且没有给出匹配字符的来源,所以自己动手写了一下,顺便给出一些我调试的结果。

#include "stdafx.h"
#include <windows.h>
#include <TlHelp32.h> DWORD FindByPID(WCHAR* ProcessName);
int ReadMemory(DWORD PID);
int SearchStr(char* MemoryString, int StrLength, char* Special); int main()
{ WCHAR MyQQ[] = L"QQ.exe";
DWORD QQID = FindByPID(MyQQ);
return 0;
} DWORD FindByPID(WCHAR* ProcessName)
{
DWORD ProcessID = 0;
HANDLE ProcessSnapHANDLE;
PROCESSENTRY32 pe32; ProcessSnapHANDLE = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (ProcessSnapHANDLE == INVALID_HANDLE_VALUE)
{
return 0;
}
pe32.dwSize = sizeof(PROCESSENTRY32);
if (!Process32First(ProcessSnapHANDLE, &pe32))
{
CloseHandle(ProcessSnapHANDLE);
return 0;
}
do
{
//找到QQ进程
if (wcscmp(ProcessName, pe32.szExeFile) == 0)
{
ProcessID = pe32.th32ProcessID;
printf("ProcessID = %d \r\n", ProcessID);
//开始内存搜索
ReadMemory(ProcessID); }
}while (Process32Next(ProcessSnapHANDLE, &pe32));//继续找下一个进程
CloseHandle(ProcessSnapHANDLE);
return ProcessID;
} int ReadMemory(DWORD PID)
{
//要搜索的特征码
char Special[] = "User uin=";
//特征码出现的位置
int Pos = 0;
HANDLE ProcessHandle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, 0, PID);
if (ProcessHandle == NULL)
{
return 0;
}
SYSTEM_INFO si;
GetSystemInfo(&si); MEMORY_BASIC_INFORMATION mbi;
DWORD Address = (DWORD)si.lpMinimumApplicationAddress; //可申请的最小值
while (Address < (DWORD)si.lpMaximumApplicationAddress)
{
if (VirtualQueryEx(ProcessHandle, (LPVOID)Address, &mbi, sizeof(mbi)) != sizeof(mbi))
{
return 0;
} if ((mbi.State == MEM_COMMIT) && (mbi.Protect == PAGE_READWRITE)) //限制条件,缩小范围
{
DWORD BaseAddress = Address;
int ReadSize = mbi.RegionSize; if (ReadSize >= 1024)
{
DWORD Bytes = 0;
char* MemBuffer = (char *)malloc(ReadSize * sizeof(char)); if (ReadProcessMemory(ProcessHandle, (LPCVOID)BaseAddress, MemBuffer, ReadSize, &Bytes))
{
//开始搜索特征码
Pos = SearchStr(MemBuffer, Bytes, Special);
if (Pos)
{
printf("Address: 0x%08X\n", BaseAddress + Pos * sizeof(char));
//指向QQ号码的第一个字符
char *ptsQQ = &MemBuffer[Pos + strlen(Special)];
printf("QQ: ");
//利用指针来打印出当前QQ进程的QQ号码,
//QQ号码之后的字符是'"'
for (*ptsQQ++; *ptsQQ != '"'; *ptsQQ++)
{
//注意这里是循环打印出QQ号码的每个字符,而不是整个字符串
printf("%c", *ptsQQ);
}
printf("\r\n");
//找到1个就OK了,去除break可继续找
break;
}
}
free(MemBuffer);
}
}
//从下一块内存块继续找
Address = (DWORD)mbi.BaseAddress + mbi.RegionSize;
}
return Pos;
} int SearchStr(char* MemoryString, int StrLength, char* Special)
{
int i = 0;
int SpecialLength = strlen(Special); while ((i + SpecialLength) <= StrLength)
{
int n = 0;
//先匹配两个字串的第一个字符
if (Special[0] == MemoryString[i])
{
//若相等,则开始逐字符匹配
for (int j = 0; j < SpecialLength; j++)
{
//相同位置字符匹配
if (Special[j] == MemoryString[i + j])
{
//若相同位置字符匹配成功,则计数器加1
n++;
}
else //相同位置字符匹配失败
{
//源字符串位置跳过匹配相同的n个字符
i = i + n;
//跳出当前匹配循环,开始新位置的匹配
break;
}
}
//若匹配成功,计数和目标字符串长度相等,则找到目标
if (SpecialLength == n)
{
//i为找到的目标字符串在源字符串中的起点位置, return i;
}
}
else //若两字符串的第一个字符不同
{
//开始反向找源字符串相对目标字符串的后一个字符是否在目标字符串内
for (int j = SpecialLength - 1; j >= 0; j--)
{
//找到存在紧跟其后的那个字符
if (Special[j] == MemoryString[i + SpecialLength])
{
//该字符出现在目标字符串中的位置
n = j;
//只需知道排在倒数第一那个位置,跳出循环开始移动位置
break;
}
}
i = i + SpecialLength - n;
}
}
return 0;
}

  

代码虽然比较简单,但是其中还是有一些需要注意的地方。

首先,为了方便从内存中粘出来内存数据,我都是用ASCII的单字符,而不是宽字符,因为宽字符的内存中会在每个字节后加上一个 00 ,看到的就是一个黑点。但是在进程查找匹配过程中,发现怎么也匹配不到 "QQ.exe",好像strcmp中用了强制类型转换就不行了,无奈只好把这个地方换成宽字节,但对于最后的结果没有影响。

还有就是由于操作系统不同,特征码"index?uin="我在运行时没有找到,我就换了一种思路,将我QQ号的前5位作为特征码来匹配,此时要注意代码中的结束字符,可能是&或者",自己多尝试一下。

我就找到了第一个符合条件的

/*
"1.0" encoding="utf-8"?>.<NewsFeed>.???<User uin="2294
800094"><minifeed appid="1" apptitle="title" showarea=

*/

可以看出我们要匹配的字符是  User uin=" ,但是两个双引号连在一起就视为空,又不会处理了,也没法用单引号代替,只能少一个引号,而在for循环的时候,用

*ptsQQ++   来跳过第一个字符。

下面是我找到的第二个:

/*
...........down?..€.)'PE?'P).*[???wp??w?8?v?].w?].w_ER
ROR_CODE_OK, status-code=200, url=http://s.url.cn/qqwe
b/qunactivity/img/icon_qq_2014.png.1546250318/15462503
18-3167137263-CEE4381B4D81CC2812670D031D808E69/0?vuin=
2294800094&term=1&srvver=26650&rf=naio.i.p.....???L???
L???L???L???L???L???L?R?L?M?L?s?L?n?L?.?L?.?L?.?L?:?L?
*/

可以看出 uin= 在两个里面都出现了,应该是兼容性较好的一个特征码了,如果使用 uin= ,那么刚刚for循环一定改成这样:

for (; *ptsQQ != '&'; *ptsQQ++)

就可以找到QQ号码了。

FindQQByProcess的更多相关文章

随机推荐

  1. 【bzoj1616】[Usaco2008 Mar]Cow Travelling游荡的奶牛 bfs

    题目描述 奶牛们在被划分成N行M列(2 <= N <= 100; 2 <= M <= 100)的草地上游走,试图找到整块草地中最美味的牧草.Farmer John在某个时刻看见 ...

  2. CentOS 普通用户提升root权限

    1.sudo命令可以使普通用户具备root用户的权限,使用前,需要先配置/etc/sudoers文件. #sudoers文件是只读,一般情况下都是用visudo来修改,visudo也一定程度上可以保证 ...

  3. 【题解】SDOI2017树点涂色

    LCT强强!以前总是觉得LCT非常的难懂(当然现在也是的),但实际上它真的是很厉害的一种东西.它是一种动态的链剖分结构,其实就是对于剖分出来的重链使用LCT去进行维护.cut 与 link 两个操作让 ...

  4. 【刷题】BZOJ 1717 [Usaco2006 Dec]Milk Patterns 产奶的模式

    Description 农夫John发现他的奶牛产奶的质量一直在变动.经过细致的调查,他发现:虽然他不能预见明天产奶的质量,但连续的若干天的质量有很多重叠.我们称之为一个"模式". ...

  5. jsp电子商务购物车之五 数据库存储篇2

    业务逻辑图,简单版要写各个Servlet //ChangeCartCountServlet 使用ajax实现数量,增加或减少; package com.cart.web; import java.io ...

  6. 关于wesocket大文件通讯的切片实现方法

    关于websocket的实现网上很多资料这里就不详说,这里大概讲我在websocket传输大文件的时的方法,websocket传输单个文件最大不能超过7kg,否则前段自动断掉,当我们用来语音通讯时,通 ...

  7. java 在centos6.5+eclipse环境下调用opencv实现sift算法

    java 在centos6.5+eclipse环境下调用opencv实现sift算法,代码如下: import org.opencv.core.Core; import org.opencv.core ...

  8. iOS更改项目名称的详细步骤

    http://www.cocoachina.com/ios/20150104/10824.html

  9. POJ1679:The Unique MST(最小生成树)

    The Unique MST Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 38430   Accepted: 14045 ...

  10. 【转载】Innodb共享表空间VS独立表空间

    http://www.mysqlsupport.cn/innodb%E5%85%B1%E4%BA%AB%E8%A1%A8%E7%A9%BA%E9%97%B4vs%E7%8B%AC%E7%AB%8B%E ...