m0_46216186 2021-02-02 22:27
浏览 416

最近在编写一个特征码内存搜索的项目,因为要搜索的进程是64位程序,读取内存信息时错误。请帮忙看看。

诸位大神:
       最近在编写一个特征码内存搜索的项目,因为要搜索的进程是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。无法返回查询成功的代码。这里无法解决。非常感谢。

  • 写回答

0条回答 默认 最新

    报告相同问题?

    悬赏问题

    • ¥15 Arcgis相交分析无法绘制一个或多个图形
    • ¥15 seatunnel-web使用SQL组件时候后台报错,无法找到表格
    • ¥15 fpga自动售货机数码管(相关搜索:数字时钟)
    • ¥15 用前端向数据库插入数据,通过debug发现数据能走到后端,但是放行之后就会提示错误
    • ¥30 3天&7天&&15天&销量如何统计同一行
    • ¥30 帮我写一段可以读取LD2450数据并计算距离的Arduino代码
    • ¥15 飞机曲面部件如机翼,壁板等具体的孔位模型
    • ¥15 vs2019中数据导出问题
    • ¥20 云服务Linux系统TCP-MSS值修改?
    • ¥20 关于#单片机#的问题:项目:使用模拟iic与ov2640通讯环境:F407问题:读取的ID号总是0xff,自己调了调发现在读从机数据时,SDA线上并未有信号变化(语言-c语言)