各位老师,网上找了个C++用特征码读取内存地址的代码,咋改才能达到如下的效果呢?
本帖最后由 jtwc 于 2022-4-18 11:23 编辑各位老师,网上找了个C++用特征码读取内存地址的代码,咋改才能达到如下的效果呢?谢谢了 代码如下:
#include <windows.h>
#include <time.h>
#include <iostream>
using namespace std;
//2020.8.9代码更新,修复通配符的小BUG,该BUG会有极低几率搜索错误,现已修复
//2022.4.4代码更新,添加一句代码,修复起始地址的小BUG,该BUG会有小概率搜不到想要的内存
/*
findMatchingCode() 参数说明:
1) hProcess 要打开的进程句柄
2) markCode 特征码,支持通配符(**),如: 55 8b ec ** 56 83 ec 20 ** ** 08 d9 ee
3) memBeginAddr 起始搜索地址
4) memEndAddr 结束搜索地址
5) retAddr[] 记录找到的地址,传入这个参数前一定要清0,如 DWORD retAddr = {0};或者 DWORD *retAddr = new DWORD();
6) deviation 特征码地址离目标地址的偏移距离,上负下正
7) isCall 是否为找CALL的跳转地址,true 则 retAddr[] 返回的是CALL跳转的地址
8) isAll 是否查找所有符合的地址,false找到第一个符合的地址后就结束搜索,true继续搜索,直到搜索地址大于结束地址(memEndAddr)
return返回值 找到的地址总数
搜不到内存可能是保护属性没有选对
*/
DWORD retAddr = { 0 }; //记录特征码对应的地址
//DWORD *retAddr = new DWORD();
int nCount;
DWORD findMatchingCode(HANDLE hProcess, string markCode, DWORD memBeginAddr, DWORD memEndAddr, DWORD retAddr[], int deviation, bool isCall, bool isAll = false);
DWORD findMatchingCode(HANDLE hProcess, string markCode, DWORD memBeginAddr, DWORD memEndAddr, DWORD retAddr[], int deviation, bool isCall, bool isAll)
//DWORD findMatchingCode(HANDLE hProcess, string markCode, DWORD memBeginAddr, DWORD memEndAddr, DWORD retAddr[], int deviation, bool isAll)
{
//----------------------处理特征码----------------------//
//去除所有空格
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;
BYTE *pWildcard = new BYTE;
for (int i = 0; i < len; i++) {
string tempStr = markCode.substr(i * 2, 2);
if (tempStr == "**") {
pWildcard = 0xFF;
if (nSundayLen == len) nSundayLen = i; //记录第一个通配符的索引,该索引越靠后,效率越高
}
else {
pWildcard = 0x00;
}
pMarkCode = strtoul(tempStr.c_str(), 0, 16);
}
//--------------------------end-------------------------//
//Sunday算法模板数组赋值,+1防止特征码出现FF时越界
int aSunday = { 0 };
for (int i = 0; i < nSundayLen; i++) {
aSunday] = i + 1;
}
//起始地址
const DWORD dwBeginAddr = memBeginAddr;
//结束地址
const DWORD dwEndAddr = memEndAddr;
//当前读取的内存块地址
DWORD 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;
//记录起始搜索时间
clock_t nBeginTime = clock();
//扫描内存
while (dwCurAddr < dwEndAddr)
{
//查询地址空间中内存地址的信息
memset(&mbi, 0, sizeof(MEMORY_BASIC_INFORMATION));
if (::VirtualQueryEx(hProcess, (LPCVOID)dwCurAddr, &mbi, sizeof(mbi)) == 0) {
goto end;
}
//添加一句代码,修改当前地址到这块内存页的起始地址,编辑于2022.4.4,没有这句会有概率搜不到想要的内存
dwCurAddr = (DWORD_PTR)mbi.BaseAddress;
//-----------------------------------------------------//
//过滤内存空间, 根据内存的状态和保护属性进行过滤
//一般扫描(读写及执行)即可,速度极快,扫不到的话在尝试添加(读写)这一属性
if (MEM_COMMIT == mbi.State && //已分配的物理内存
//MEM_PRIVATE == mbi.Type || //私有内存,不被其他进程共享
//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;
//读取进程内存
ReadProcessMemory(hProcess, (LPCVOID)dwCurAddr, pMemBuffer, mbi.RegionSize, 0);
i = 0;
j = 0;
while (j < len)
{
nextAddr:
if (pMemBuffer == pMarkCode || pWildcard == 0xFF)
{
i++;
j++;
}
else
{
nOffset = i - j + nSundayLen;
//判断偏移量是否大于缓冲区
if (nOffset > mbi.RegionSize - len) break;
//判断 aSunday模板数组 里有没有 内存偏移后的值,有则回溯,否则+1
if (aSunday])
{
i = nOffset - aSunday] + 1;
j = 0;
}
else
{
i = nOffset + 1;
j = 0;
}
}
}
if (j == len)
{
//计算找到的目标地址:
//特征码地址 = 当前内存块基址 + i偏移 - 特征码长度
//目标地址 = 特征码地址 + 偏移距离
//CALL(E8)跳转的地址 = E8指令后面的4个字节地址 + 下一条指令地址(也就是目标地址 + 5)
retAddr = dwCurAddr + i - len + deviation;
if (isCall) {
DWORD temp;
memcpy(&temp, &pMemBuffer, 4);
retAddr += 5;
retAddr += temp;
}
if (++nCount >= nArrayLength)
{
//传入的数组下标越界就结束搜索
goto end;
}
if (isAll) {
i = i - len + 1;
j = 0;
goto nextAddr;
}
else {
goto end;
}
}
dwCurAddr += mbi.RegionSize; //取下一块内存地址
}
else
{
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;
return nCount;
}
int main()
{
HWND hWnd;
hWnd = FindWindow(NULL, "Plants vs. Zombies GOTY ");
DWORD PID;
GetWindowThreadProcessId(hWnd, &PID);
HANDLE lsProcess;
lsProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, PID);
cout << findMatchingCode(lsProcess, " 96 00 00 00 14 00 00 00 D4 3B ", 0x400000, 0x7FFFFFFF, retAddr, 0, 0, true) << endl;
cout << retAddr << endl;//内存地址
system("pause");
return 0;
}
#include <string>
#include <algorithm>
#include <array>
#include <immintrin.h>
static constexpr char charhexset[] = "0123456789ABCDEFabcdef";
typedef unsigned int u32;
#if defined(__LP64__) || defined(_WIN64) || defined(__x86_64__) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)
typedef long long s96;
typedef unsigned long long u96;
#else
typedef int s96;
typedef unsigned int u96;
#endif
static bool StringReplace(std::string& source, const std::string& delimiters, const std::string& dispose = "", const std::size_t offset = 1)
{
if (source.empty())
{
return false;
}
if (delimiters.empty())
{
return true;
}
for (std::string::size_type pos = source.find(delimiters); pos != std::string::npos; pos = source.find(delimiters))
{
if (source.replace(pos, offset, dispose).size())
{
continue;
}
return false;
}
return true;
}
static bool Hexadec2xdigit(const std::string& data, std::string& buffer, std::size_t offset)
{
if (data.empty())
{
return false;
}
for (std::size_t i = 0; i < data.size(); i += offset)
{
if (std::isxdigit(data))
{
buffer += static_cast<char>(std::stoul(data.substr(i, offset), nullptr, 16));
}
else
{
buffer += 'X';
}
}
return true;
}
static bool Hexadec2xdigitEx(const std::string& data, std::string& buffer, u32 checkxdigit = 0, u32 transform = 1)
{
if (data.empty())
{
return false;
}
std::string masks(data);
{
// 去掉 0x 去掉 空格
if (StringReplace(masks, "0x") && StringReplace(masks, " "))
{
// 大小写转换
if (masks.end() == (1 == transform ? std::transform(masks.begin(), masks.end(), masks.begin(), [] (unsigned char ch) { return toupper(ch); }) : std::transform(masks.begin(), masks.end(), masks.begin(), [] (unsigned char ch) { return tolower(ch); })))
{
// 检查是否是完整的十六进制数
if (checkxdigit)
{
if (std::string::npos != masks.find_first_not_of(charhexset))
{
return false;
}
}
return Hexadec2xdigit(static_cast<const std::string&>(masks), buffer, 2);
}
}
}
return false;
}
static bool SearchPattern(const unsigned char* pos, const std::string& chars)
{
for (std::string::const_iterator xdigit = chars.cbegin(); xdigit != chars.cend(); ++xdigit, ++pos)
{
if (*pos != static_cast<const unsigned char>(*xdigit) && // no match
'X' != static_cast<const unsigned char>(*xdigit)) // filter out arbitrary characters
{
return false;
}
else
{
// hit character
continue;
}
}
return true;
}
static bool SearchPattern(const void* start, // start address
const void* end, // end address
const std::string& keyword, // characteristic code
std::size_t index, // take out the serial number
void*& address) // return to address
{
if (keyword.empty())
{
return false;
}
if (start != end && static_cast<const unsigned char*>(end) > static_cast<const unsigned char*>(start) && static_cast<std::size_t>(static_cast<const unsigned char*>(end) - static_cast<const unsigned char*>(start)) > keyword.size())
{
std::string chars;
{
if (Hexadec2xdigitEx(keyword, chars, 0))
{
for (auto = std::make_tuple(static_cast<const unsigned char*>(start), static_cast<std::size_t>(0)); pos <= end; ++pos)
{
if (SearchPattern(pos, chars))
{
if (++i != index)
{
continue;
}
else
{
address = const_cast<void*>(reinterpret_cast<const void*>(pos));
}
return true;
}
}
}
}
}
return false;
}
static bool SearchPattern(const u96 start, const u96 end, const std::string& keyword, std::size_t index, void*& address)
{
return SearchPattern(reinterpret_cast<const void*>(start), reinterpret_cast<const void*>(end), keyword, index, address);
}
static bool SearchPatternEx(const void* start, const void* end, const std::string& chars, std::size_t index, std::size_t count, void*& address)
{
for (auto = std::make_tuple(std::array<std::size_t, 32>{}, static_cast<std::size_t>(0), static_cast<std::size_t>(0), static_cast<const unsigned char*>(start)); i < count; ++i)
{
for (std::size_t j = 0; j < 16 && n < chars.size(); ++j, ++n)
{
if ('X' != static_cast<const char*>(chars.c_str() + i * 16))
{
masks |= static_cast<std::size_t>(1) << j;
}
}
for (auto = std::make_tuple(_mm_loadu_si128(reinterpret_cast<const __m128i *>(chars.c_str() + i * 16)), static_cast<std::size_t>(0)); pos <= end; _mm_prefetch(reinterpret_cast<const char*>(++pos + 64), _MM_HINT_NTA))
{
if (static_cast<std::size_t>(static_cast<std::size_t>(_mm_movemask_epi8(_mm_cmpeq_epi8(_mm_loadu_si128(reinterpret_cast<const __m128i *>(pos + i * 16)), store))) & masks) == masks)
{
if (n < chars.size())
{
break;
}
if (++j != index)
{
continue;
}
else
{
address = const_cast<void*>(reinterpret_cast<const void*>(pos));
}
return true;
}
}
}
return false;
}
static bool SearchPatternEx(const void* start, const void* end, const std::string& keyword, std::size_t index, void*& address)
{
if (keyword.empty())
{
return false;
}
if (start != end && static_cast<const unsigned char*>(end) > static_cast<const unsigned char*>(start) && static_cast<std::size_t>(static_cast<const unsigned char*>(end) - static_cast<const unsigned char*>(start)) > keyword.size())
{
std::string chars;
{
if (Hexadec2xdigitEx(keyword, chars, 0))
{
return SearchPatternEx(start, end, chars, index, static_cast<std::size_t>((((chars.size()) + (16 - 1)) & ~(16 - 1)) >> 4), address);
}
}
}
return false;
}
static bool SearchPatternEx(const u96 start, const u96 end, const std::string& keyword, std::size_t index, void*& address)
{
return SearchPatternEx(reinterpret_cast<const void*>(start), reinterpret_cast<const void*>(end), keyword, index, address);
} 小小随 发表于 2022-4-18 10:25
#include
#include
#include
老师,谢谢了,这个特征码,支持通配符(**)吗? laodan 发表于 2022-4-18 10:30
你看下这个:https://www.52pojie.cn/thread-1180359-1-1.html
老师,谢谢了,这个支持“??”,不支持(**),而且程序容易崩溃 特征码是地址? metoo2 发表于 2022-4-18 10:50
特征码是地址?
老师,不是 jtwc 发表于 2022-4-18 10:29
老师,谢谢了,这个特征码,支持通配符(**)吗?
支持 格式为 AA BB ?? DD ?? FF
页:
[1]