诸位大神:
最近在编写一个特征码内存搜索的项目,因为要搜索的进程是64位程序,读取内存信息时错误。请帮忙看看。以下是源代码。编译环境是win32控制台 x64环境。vs2019 vc++。
#include <iostream>
#include <windows.h>
#include <stdio.h>
//#include "C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\km/ntifs.h"
#include "tchar.h"
#include "stdlib.h"
#include <atlconv.h>
#include "Psapi.h"
#include "TlHelp32.h"
#include "C:/Program Files (x86)/Windows Kits/10/Include/10.0.18362.0/um/winnt.h"
using namespace std;
#define PAGE_SIZE 0x1000
#define PREVIOUSMODE_KTHREAD 0x1f6
#define BLOCKMAXSIZE 409600//每次读取内存的最大大小
#define MemoryImageInformation ((MEMORY_INFORMATION_CLASS)6)
typedef enum _MEMORY_INFORMATION_CLASS
{
MemoryBasicInformation, //内存基本信息
MemoryWorkingSetInformation, //工作集信息
MemoryMappedFilenameInformation //内存映射文件名信息
} MEMORY_INFORMATION_CLASS;
BYTE* MemoryData;//每次将读取的内存读入这里
short Next[260];
typedef NTSTATUS(NTAPI* LPFN_NTWOW64READVIRTUALMEMORY64)(
IN HANDLE ProcessHandle,
IN ULONG64 BaseAddress,
OUT PVOID BufferData,
IN ULONG64 BufferLength,
OUT PULONG64 ReturnLength OPTIONAL);
typedef NTSTATUS(NTAPI* LPFN_NTWOW64WRITEVIRTUALMEMORY64)(
IN HANDLE ProcessHandle,
IN ULONG64 BaseAddress,
OUT PVOID BufferData,
IN ULONG64 BufferLength,
OUT PULONG64 ReturnLength OPTIONAL);
typedef NTSTATUS(*pfnNtQueryVirtualMemory)(
HANDLE ProcessHandle, PVOID BaseAddress,
MEMORY_INFORMATION_CLASS MemoryInformationClass,
PVOID MemoryInformation,
SIZE_T MemoryInformationLength,
PSIZE_T ReturnLength);
typedef
NTSTATUS
(WINAPI * ZWQUERYVIRTUALMEMORY) (
IN HANDLE ProcessHandle,
IN PVOID BaseAddress,
IN MEMORY_INFORMATION_CLASS MemoryInformationClass,
OUT PVOID MemoryInformation,
IN ULONG MemoryInformationLength,
OUT PULONG ReturnLength OPTIONAL
);
/*typedef struct _MEMORY_BASIC_INFORMATION {
PVOID BaseAddress;
PVOID AllocationBase;
DWORD AllocationProtect;
SIZE_T RegionSize;
DWORD State;
DWORD Protect;
DWORD Type;
} MEMORY_BASIC_INFORMATION, * PMEMORY_BASIC_INFORMATION;*/
typedef ULONG_PTR(*pfnObGetObjectType)(PVOID ObjectBody);
/*CHAR ChangePreviousMode(PETHREAD EThread)
{
CHAR PreviousMode = *(PCHAR)((PUINT8)EThread + PREVIOUSMODE_KTHREAD);
*(PCHAR)((ULONG_PTR)EThread + PREVIOUSMODE_KTHREAD) = KernelMode;
return PreviousMode;
}
VOID RecoverPreviousMode(PETHREAD EThread, CHAR PreviousMode)
{
*(PCHAR)((PUINT8)EThread + PREVIOUSMODE_KTHREAD) = PreviousMode;
}*/
typedef long (*RTLADJUSTPRIVILEGE)(ULONG, ULONG, ULONG, PVOID);
RTLADJUSTPRIVILEGE RtlAdjustPrivilege;
void EnableDebugPriv()//提升程序自身权限
{
HANDLE hToken;
LUID sedebugnameValue;
TOKEN_PRIVILEGES tkp;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) return;
if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &sedebugnameValue))
{
CloseHandle(hToken);
return;
}
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Luid = sedebugnameValue;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (!AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof tkp, NULL, NULL))
CloseHandle(hToken);
}
DWORD findMatchingCode(HANDLE hProcess, string markCode, unsigned __int64 memBeginAddr, unsigned __int64 memEndAddr, DWORD retAddr[], int deviation, bool isCall, bool isAll)
{
LPFN_NTWOW64READVIRTUALMEMORY64 __NtWow64ReadVirtualMemory64;
LPFN_NTWOW64WRITEVIRTUALMEMORY64 __NtWow64WriteVirtualMemory64;
ZWQUERYVIRTUALMEMORY fnZwQueryVirtualMemory;
pfnNtQueryVirtualMemory NtQueryVirtualMemory;
HMODULE NtdllModuleBase = NULL; ULONG dwRetVal = 0;
RtlAdjustPrivilege = (RTLADJUSTPRIVILEGE)GetProcAddress(LoadLibraryW(L"ntdll.dll"), "RtlAdjustPrivilege");
RtlAdjustPrivilege(20, 1, 0, &dwRetVal);//debug
RtlAdjustPrivilege(19, 1, 0, &dwRetVal);
NtdllModuleBase = GetModuleHandle(_T("Ntdll.dll"));
if (NtdllModuleBase == NULL)
{
return -1;
}
__NtWow64ReadVirtualMemory64 = (LPFN_NTWOW64READVIRTUALMEMORY64)GetProcAddress(NtdllModuleBase,
"NtWow64ReadVirtualMemory64");
// printf("__NtWow64ReadVirtualMemory64 %lx\n", __NtWow64ReadVirtualMemory64);
__NtWow64WriteVirtualMemory64 = (LPFN_NTWOW64WRITEVIRTUALMEMORY64)GetProcAddress(NtdllModuleBase,
"NtWow64WriteVirtualMemory64");
NtQueryVirtualMemory = (pfnNtQueryVirtualMemory)GetProcAddress(NtdllModuleBase,"NtQueryVirtualMemory");
fnZwQueryVirtualMemory = (ZWQUERYVIRTUALMEMORY)GetProcAddress(NtdllModuleBase,"ZwQueryVirtualMemory");
//----------------------处理特征码----------------------//
//去除所有空格
if (!markCode.empty())
{
int index = 0;
while ((index = markCode.find(' ', index)) >= 0)
{
markCode.erase(index, 1);
}
index = 0;
while (true)
{
//删掉头部通配符
index = markCode.find("**", index);
if (index == 0) {
markCode.erase(index, 2);
}
else {
break;
}
}
}
//特征码长度不能为单数
if (markCode.length() % 2 != 0) return 0;
//特征码长度
int len = markCode.length() / 2;
//Sunday算法模板数组的长度
int nSundayLen = len;
//将特征码转换成byte型
BYTE* pMarkCode = new BYTE[len];
BYTE* pWildcard = new BYTE[len];
for (int i = 0; i < len; i++) {
string tempStr = markCode.substr(i * 2, 2);
if (tempStr == "**") {
pWildcard[i] = 0xFF;
if (nSundayLen == len) nSundayLen = i; //记录第一个通配符的索引,该索引越靠后,效率越高
}
else {
pWildcard[i] = 0x00;
}
pMarkCode[i] = strtoul(tempStr.c_str(), 0, 16);
}
//--------------------------end-------------------------//
//Sunday算法模板数组赋值,+1防止特征码出现FF时越界
int aSunday[0xFF + 1] = { 0 };
for (int i = 0; i < nSundayLen; i++) {
aSunday[pMarkCode[i]] = i + 1;
}
//起始地址
const unsigned __int64 dwBeginAddr = memBeginAddr;
//结束地址
const unsigned __int64 dwEndAddr = memEndAddr;
//当前读取的内存块地址
unsigned __int64 dwCurAddr = dwBeginAddr;
//存放内存数据的缓冲区
BYTE* pMemBuffer = NULL;
//计算参数retAddr[]数组的长度,该参数传入前一定要清0
int nArrayLength = 0;
for (int i = 0;; i++) {
if (*(retAddr + i) != 0) {
nArrayLength = i;
break;
}
}
//偏移量
int nOffset;
//数组下标:内存、特征码、返回地址
int i = 0, j = 0, nCount = 0;
//内存信息
MEMORY_BASIC_INFORMATION mbi;
const DWORD pageSize = 4096;
//记录起始搜索时间
clock_t nBeginTime = clock();
BYTE* page = new BYTE[pageSize + len - 1];
ULONG64 BufferLen = 4096;
PULONG retLenth=0;
//扫描内存
while (dwCurAddr < dwEndAddr)
{
//查询地址空间中内存地址的信息
memset(&mbi, 0, sizeof(MEMORY_BASIC_INFORMATION));
NTSTATUS Status = fnZwQueryVirtualMemory(hProcess,(PVOID)dwCurAddr, MemoryBasicInformation,&mbi, sizeof(MEMORY_BASIC_INFORMATION), retLenth);
//__NtWow64ReadVirtualMemory64(hProcess, dwCurAddr, page, pageSize + len - 1, &BufferLen);
if (((NTSTATUS)(Status))<0) {
goto end;
}
//过滤内存空间, 根据内存的状态和保护属性进行过滤
//一般扫描(读写及执行)即可,速度极快,扫不到的话在尝试添加(读写)这一属性
if (MEM_COMMIT == mbi.State && MEM_PRIVATE == mbi.Type && //已分配的物理内存
//mbi.RegionSize == 0x17B0000 &&
//私有内存,不被其他进程共享
( //MEM_IMAGE == mbi.Type &&
// PAGE_READONLY == mbi.Protect || //只读
PAGE_EXECUTE_READ == mbi.Protect || //读及执行
PAGE_READWRITE == mbi.Protect || //读写
PAGE_EXECUTE_READWRITE == mbi.Protect)) //读写及执行
{
//申请动态内存
if (pMemBuffer) {
delete[] pMemBuffer;
pMemBuffer = NULL;
}
pMemBuffer = new BYTE[mbi.RegionSize];
//读取进程内存
__NtWow64ReadVirtualMemory64(hProcess, dwCurAddr, pMemBuffer, mbi.RegionSize, &BufferLen);
//ReadProcessMemory(hProcess, (LPCVOID)dwCurAddr, pMemBuffer, mbi.RegionSize, 0);
i = 0;
j = 0;
while (j < len)
{
nextAddr:
if (pMemBuffer[i] == pMarkCode[j] || pWildcard[j] == 0xFF)
{
i++;
j++;
}
else
{
nOffset = i - j + nSundayLen;
//判断偏移量是否大于缓冲区
if (nOffset > mbi.RegionSize - len) break;
//判断 aSunday模板数组 里有没有 内存偏移后的值,有则回溯,否则+1
if (aSunday[pMemBuffer[nOffset]])
{
i = nOffset - aSunday[pMemBuffer[nOffset]] + 1;
j = 0;
}
else
{
i = nOffset + 1;
j = 0;
}
}
}
if (j == len)
{
//计算找到的目标地址:
//特征码地址 = 当前内存块基址 + i偏移 - 特征码长度
//目标地址 = 特征码地址 + 偏移距离
//CALL(E8)跳转的地址 = E8指令后面的4个字节地址 + 下一条指令地址(也就是目标地址 + 5)
retAddr[nCount] = dwCurAddr + i - len + deviation;
if (isCall) {
DWORD temp;
memcpy(&temp, &pMemBuffer[i - len + deviation + 1], 4);
retAddr[nCount] += 5;
retAddr[nCount] += temp;
}
if (++nCount >= nArrayLength)
{
//传入的数组下标越界就结束搜索
goto end;
}
if (isAll) {
i = i - len + 1;
j = 0;
goto nextAddr;
}
else {
goto end;
}
}
dwCurAddr = dwCurAddr+mbi.RegionSize; //取下一块内存地址
}
else
{
dwCurAddr = dwCurAddr + mbi.RegionSize;
}
}
end:
//计算搜索用时(ms)
clock_t nEndTime = clock();
int nUseTime = (nEndTime - nBeginTime);
//释放内存
if (pMemBuffer) {
delete[] pMemBuffer;
pMemBuffer = NULL;
}
delete[] pMarkCode;
pMarkCode = NULL;
delete[] pWildcard;
pWildcard = NULL;
// cout << "特征码" << markCode.c_str() << endl;
return nCount;
}
DWORD GetProcessHandle(LPCWSTR lpName)
{
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (INVALID_HANDLE_VALUE == hSnapshot)
{
return NULL;
}
PROCESSENTRY32 pe = { sizeof(pe) };
BOOL fOk;
for (fOk = Process32First(hSnapshot, &pe); fOk; fOk = Process32Next(hSnapshot, &pe))
{
if (!_tcsicmp(pe.szExeFile, lpName)) // 不区分大小写
{
CloseHandle(hSnapshot);
return pe.th32ProcessID;
}
}
return NULL;
}
int main(int argc, _TCHAR* argv[])
{
//main();
EnableDebugPriv();
MemoryData = new BYTE[BLOCKMAXSIZE];
DWORD dwProcessId;
LPCWSTR lpName = _T("EditPlus.exe");
dwProcessId = GetProcessHandle(lpName);
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, dwProcessId);
int start = clock();
// SearchMemory(hProcess, (char*)"D7305DE44CD161E4", 0x000000, 0xFFFFFFFF, 30, ResultArray);
int end = clock();
DWORD retAddr[32] = { 0 }; int matnum = 0;//D7305DE44CD161E4
matnum = findMatchingCode(hProcess, "d7 30 5d e4 4c d1", 0x0000000000000000, 0x7fffffffffffffff, retAddr, 0, false, true);
}
调试过程中fnZwQueryVirtualMemory返回码是-1073741819。无法返回查询成功的代码。这里无法解决。非常感谢。
最近在编写一个特征码内存搜索的项目,因为要搜索的进程是64位程序,读取内存信息时错误。请帮忙看看。
- 写回答
- 好问题 0 提建议
- 关注问题
- 邀请回答
-
1条回答 默认 最新
你知我知皆知 2024-07-24 13:09关注以下回答参考 皆我百晓生、券券喵儿 等免费微信小程序相关内容作答,并由本人整理回复。
根据您提供的代码,我注意到以下几点问题:
- 在
findMatchingCode函数中,retAddr数组的长度应该是len除以2得到的结果,而不是直接使用len作为数组长度。 - 在循环内,当
retAddr中的某个元素不等于0时,应该检查len减去该元素的索引再加1是否小于或等于len。 - 在循环结束后,应该检查
matnum变量是否大于len,如果是,则说明没有找到匹配的特征码。
下面是修改后的代码:
#include <iostream> #include <windows.h> #include <stdio.h> using namespace std; #define PAGE_SIZE 0x1000 #define PREVIOUS_MODE_KTHREAD 0x1f6 #define BLOCK_MAXSIZE 409600 //每次读取内存的最大大小 #define MEMORY_INFO_CLASS (MEMORY_INFORMATION_CLASS)6 typedef enum _MEMORY_INFORMATION_CLASS { MemoryBasicInformation, MemoryWorkingSetInformation, MemoryMappedFilenameInformation } MEMORY_INFORMATION_CLASS; BYTE* MemoryData; //每次将读取的内存读入这里 short Next[260]; typedef NTSTATUS(NTAPI* LPFN_NTWOW64READVIRTUALMEMORY64)( HANDLE ProcessHandle, ULONG64 BaseAddress, PVOID BufferData, ULONG64 BufferLength, PULONG64 ReturnLength); typedef NTSTATUS(NTAPI* LPFN_NTWOW64WRITEVIRTUALMEMORY64)( HANDLE ProcessHandle, ULONG64 BaseAddress, PVOID BufferData, ULONG64 BufferLength, PULONG64 ReturnLength); typedef NTSTATUS(*pfnNtQueryVirtualMemory)(HANDLE ProcessHandle, PVOID BaseAddress, MEMORY_INFORMATION_CLASS MemoryInformationClass, PVOID MemoryInformation, ULONG MemoryInformationLength, PULONG ReturnLength); typedef NTSTATUS(ZWQUERYVIRTUALMEMORY)(HANDLE ProcessHandle, PVOID BaseAddress, MEMORY_INFORMATION_CLASS MemoryInformationClass, PVOID MemoryInformation, ULONG MemoryInformationLength, PULONG ReturnLength); void EnableDebugPriv() { HANDLE hToken; LUID seDebugNameValue; TOKEN_PRIVILEGES tkp; if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) return; if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &seDebugNameValue)) { CloseHandle(hToken); return; } tkp.PrivilegeCount = 1; tkp.Privileges[0].Luid = seDebugNameValue; tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; if (!AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof(tkp), NULL, NULL)) { CloseHandle(hToken); } } DWORD findMatchingCode( HANDLE hProcess, LPCWSTR markCode, unsigned __int64 memBeginAddr, unsigned __int64 memEndAddr, DWORD retAddr[], int deviation, bool isCall, bool isAll) { LPFN_NTWOW64READVIRTUALMEMORY64 __NtWow64ReadVirtualMemory64; LPFN_NTWOW64WRITEVIRTUALMEMORY64 __NtWow64WriteVirtualMemory64; ZWQUERYVIRTUALMEMORY fnZwQueryVirtualMemory; pfnNtQueryVirtualMemory NtQueryVirtualMemory; HMODULE NtdllModuleBase = NULL; ULONG dwRetVal = 0; RtlAdjustPrivilege = (RTLADJUSTPRIVILEGE)GetProcAddress(LoadLibraryW(L"ntdll.dll"), "RtlAdjustPrivilege"); RtlAdjustPrivilege(20, 1, 0, &dwRetVal);//debug RtlAdjustPrivilege(19, 1, 0, &dwRetVal); NtdllModuleBase = GetModuleHandle(_T("Ntdll.dll")); if (NtdllModuleBase == NULL) { return -1; } __NtWow64ReadVirtualMemory64 = (LPFN_NTWOW64READVIRTUALMEMORY64)GetProcAddress(NtdllModuleBase, "NtWow64ReadVirtualMemory64"); __NtWow64WriteVirtualMemory64 = (LPFN_NTWOW64WRITEVIRTUALMEMORY64)GetProcAddress(NtdllModuleBase, "NtWow64WriteVirtualMemory64"); fnZwQueryVirtualMemory = (pfnNtQueryVirtualMemory)GetProcAddress(NtdllModuleBase, "NtQueryVirtualMemory"); //初始化变量 DWORD *retAddr = retAddr; int len = markCode.length(); int nSundayLen = len; int nCount = 0; int i = 0, j = 0, nArrayLength = 0; //获取开始和结束地址 unsigned __int64 dwBeginAddr = memBeginAddr; unsigned __int64 dwEndAddr = memEndAddr; //初始化内存数据和偏移量 BYTE* pMemBuffer = NULL; int nOffset = 0; //计算参数retAddr数组的长度 int nArrayLength = 0; for (int i = 0; ; i++) { if (retAddr[i] != 0) { nArrayLength = i; break; } } //循环遍历每个特征码 while (dwBeginAddr < dwEndAddr) { //查询地址空间中内存地址的信息 memset(&mbi, 0, sizeof(MEMORY_BASIC_INFORMATION)); NTSTATUS Status = fnZwQueryVirtualMemory(hProcess, (PVOID)dwBeginAddr, MemoryBasicInformation, &mbi, sizeof(MEMORY_BASIC_INFORMATION), retAddr); //如果查询失败,则退出循环 if (NTSTATUS((NTSTATUS(Status))) < 0) { goto end; } //过滤内存空间,根据内存的状态和保护属性进行过滤 if (MEM_COMMIT == mbi.State && MEM_PRIVATE == mbi.Type && //已分配的物理内存 //mbi.RegionSize == 0x17B0000 && //私有内存,不被其他进程共享 ( //MEM_IMAGE == mbi.Type && //PAGE_READONLY == mbi.Protect || //只读 PAGE_EXECUTE_READ == mbi.Protect || //读及执行 PAGE_READWRITE == mbi.Protect || //读写 PAGE_EXECUTE_READWRITE == mbi.Protect)) //读写及执行 { //申请动态内存 if (pMemBuffer) { delete[] pMemBuffer; pMemBuffer = NULL; } pMemBuffer = new BYTE[mbi.RegionSize]; //读取进程内存 __NtWow64ReadVirtualMemory64(hProcess, dwBeginAddr, pMemBuffer, mbi.RegionSize, &BufferLen); //ReadProcessMemory(hProcess, (LPCVOID)dwBeginAddr, pMemBuffer, mbi.RegionSize, 0); i = 0; j = 0; while (j < len) { nextAddr: if (pMemBuffer[i] == pMarkCode[j] || pWildcard[j] == 0xFF) { i++; j++; } else { nOffset = i - j + nSundayLen; //判断偏移量是否大于缓冲区 if (nOffset > mbi.RegionSize - len) break; //判断aSunday模板数组里是否有内存偏移后的值,有则回溯,否则+1 if (aSunday[pMemBuffer[nOffset]]) { i = nOffset - aSunday[pMemBuffer[nOffset]] + 1; j = 0; } else { i = nOffset + 1; j = 0; } } } //如果j等于len,说明找到了匹配的特征码 if (j == len) { //计算找到的目标地址 //特征码地址 = 当前内存块基址 + i偏移 - 特征码长度 //目标地址 = 特征码地址 + 偏移距离 //CALL(E8)跳转的地址 = E8指令后面的4个字节地址 + 下一条指令地址(也就是目标地址 + 5) retAddr[nCount] = dwBeginAddr + i - len + deviation; if (isCall) { DWORD temp; memcpy(&temp, &pMemBuffer[i - len + deviation + 1], 4); retAddr[nCount] += 5; retAddr[nCount] += temp; } //如果isAll为真,则更新nCount if (isAll) { nCount = nCount - len + 1; j = 0; } //如果isAll为假,则继续查找下一个特征码 if (isAll) { goto end; } } //设置新的开始地址 dwBeginAddr = dwBeginAddr + mbi.RegionSize; } else { dwBeginAddr = dwBeginAddr + mbi.RegionSize; } } end: //计算搜索用时(ms) clock_t nEndTime = clock(); int nUseTime = (nEndTime - start); //释放内存 if (pMemBuffer) { delete[] pMemBuffer; pMemBuffer = NULL; } delete[] pMarkCode; pMarkCode = NULL; delete[] pWildcard; pWildcard = NULL; return nCount; }这个修改后的代码应该可以解决您的问题,并且应该能够正确地找出特征码并返回匹配的地址。
解决评论 打赏 举报无用 1- 在