看网上有许多通过进程寻找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. centos7 nginx端口转发出现502的其中一种原因

    在排查了一系列可能的原因后仍无法解决,经资料查阅可能是SELinux造成,SELinux很强大但若配置不当也会造成很多组件无法正常使用,这里直接将其关闭: //打开配置文件 vi /etc/selin ...

  2. P2845 [USACO15DEC]Switching on the Lights 开关灯

    题目背景 来源:usaco-2015-dec Farm John 最近新建了一批巨大的牛棚.这些牛棚构成了一个N*N的矩形网络.(1<n<100) 然而bessie十分怕黑,他想计算可以把 ...

  3. [HAOI2007]分割矩阵 DP+推式子

    发现最近好少写博客啊(其实是各种摆去了) 更一点吧 这道题要求最小化均方差,其实凭直觉来说就是要使每个块分的比较均匀一点,但是单单想到想到这些还是不够的, 首先f[i][j][k][l][t]表示以( ...

  4. IT英语累积

    JPA: Java Persistence API   一种持久化规范 Spring Data:一种用于简化数据库访问,支持云服务的开源框架 Spring Data JPA:是Spring Data的 ...

  5. SRM13绵津见-终(扫描线+线段树/BIT)

    题目大意:求对于每个i求有多少个合法的j以及j对于几个i是合法的,合法的定义:l[i]<=x[j]<=r[i],T[i]-y[i]<=t[j]<=T[i]+y[i]. 设a[i ...

  6. 【线段树】【P3372】模板-线段树

    百度百科 Definition&Solution 线段树是一种log级别的树形结构,可以处理区间修改以及区间查询问题.期望情况下,复杂度为O(nlogn). 核心思想见百度百科,线段树即将每个 ...

  7. poco普通线程

    #include "Poco/Thread.h" #include "Poco/RunnableAdapter.h" #include <iostream ...

  8. Linux之SSL安全套接字20160704

    使用SSL前,先有 基本的TCP套接字连接.见demo代码 SSL_library_init();//在使用OpenSSL 之前,必须进行相应的协议初始化工作 OpenSSL_add_all_algo ...

  9. mybatis Mapper 中resultType使用方法及返回值为Map的写法

    mybatis学习(七)——resultType解析 resultType是sql映射文件中定义返回值类型,返回值有基本类型,对象类型,List类型,Map类型等.现总结一下再解释 总结: resul ...

  10. 获取 exception 对象的字符串形式(接口服务返回给调用者)

    工具类: package com.taotao.common.utils; import java.io.PrintWriter; import java.io.StringWriter; publi ...