看网上有许多通过进程寻找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. java数组相等

    java中数组相等判断: 1.最常规的是遍历 public static boolean arrayEquals(String[] a,String[] b){ boolean flag = fals ...

  2. java zip 压缩与解压

    java zip 压缩与解压 import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java. ...

  3. 【bzoj2100】[Usaco2010 Dec]Apple Delivery 最短路

    题目描述 Bessie has two crisp red apples to deliver to two of her friends in the herd. Of course, she tr ...

  4. hdu 2962 Trucking (最短路径)

    Trucking Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  5. CentOS 文件及目录等

    1.在linux中一切皆是文件,只是类型不同,通过ls -l看到的一个字母表示文件的类型 -:普通文件. d:目录文件. l:链接文件. b:块设备文件. c:字符设备文件. p:管道文件. 2.文件 ...

  6. [HAOI2010]计数 数位DP+组合数

    题面: 你有一组非零数字(不一定唯一),你可以在其中插入任意个0,这样就可以产生无限个数.比如说给定{1,2},那么可以生成数字12,21,102,120,201,210,1002,1020,等等. ...

  7. POJ3057:Evacuation——题解

    http://poj.org/problem?id=3057 题目大意: .为人,D为门,X为障碍,门每秒只能出去一个人,问多少秒出光. 如果无法出光输出impossible. ——————————— ...

  8. XXE漏洞攻击与防御整理

    一.漏洞原理 1.DTD 文档类型定义(DTD)可定义合法的XML文档构建模块.它使用一系列合法的元素来定义文档的结构.DTD 可被成行地声明于 XML 文档中,也可作为一个外部引用. 内部的 DOC ...

  9. 四道JavaScript面试题检测你的js基本功

    下面有四道简短的JavaScript小脚本,如果你能顺利预测脚本的运行结果,那么你的JavaScript基本功还是可以的.如果答错了,可以相应地去补一下缺漏的知识.反正也很简单,答错了只是说明你没了解 ...

  10. Spring源码解析-autowiring自动装配的实现

    IoC容器提供了自动依赖装配的方式,为应用IoC容器提供很大的方便.在自动配置中,不需要显式的去指定Bean属性,只需要配置autowiring属性,IoC容器会根据这个属性配置,使用反射的方式查找属 ...