正如标题所示,我试图从C++中的另一个进程读取内存,以检查来自另一个进程的值是否达到某个级别。因为我对此一无所知,所以我决定向GitHub副驾驶寻求帮助。在正常的基础上,我会搜索这些文档,但在不同意看来是这样的。由于我可以访问GitHub副驾驶,而且由于头版广告显然鼓励用户信任Copilot的编程能力,所以我选择让Copilot做这个功能。
因此,我以评论的形式给了它一个提示://A function that can grab an address from the memory of another process and store it as a double value
它给了我很好的感觉,但是我永远不会接受副驾驶所做的函数,并且盲目地使用它,除非我确信它会起作用(因为我不相信副驾驶做的每件事都不会引起问题,特别是在处理指针之类的问题时)。我想看看在C++中有过内存经验的人是否能告诉我这个函数是否能工作,以及为什么它会或不会工作,因为我对从另一个进程获取内存一无所知。
除了GitHub的声明之外,我不只是搜索文档有三个主要原因:
以下是Copilot为我生成的代码:
DWORD GetAddress(DWORD dwProcessId, LPCWSTR szModuleName, const char* szProcName)
{
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
if (hProcess == NULL)
return 0;
MODULEINFO modinfo;
GetModuleInformation(hProcess, GetModuleHandle(szModuleName), &modinfo, sizeof(MODULEINFO));
DWORD dwAddress = (DWORD)modinfo.lpBaseOfDll;
DWORD dwSize = (DWORD)modinfo.SizeOfImage;
MEMORY_BASIC_INFORMATION mbi;
while (dwSize > 0)
{
VirtualQueryEx(hProcess, (LPVOID)dwAddress, &mbi, sizeof(mbi));
if (mbi.State == MEM_COMMIT && !(mbi.Protect & PAGE_GUARD) && mbi.Protect & PAGE_EXECUTE_READWRITE)
{
DWORD dwOldProtect;
VirtualProtectEx(hProcess, (LPVOID)dwAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE, &dwOldProtect);
char* szBuffer = new char[mbi.RegionSize];
ReadProcessMemory(hProcess, (LPVOID)dwAddress, szBuffer, mbi.RegionSize, NULL);
for (DWORD dwIndex = 0; dwIndex < mbi.RegionSize - 4; dwIndex++)
{
if (szBuffer[dwIndex] == '\x55' && szBuffer[dwIndex + 1] == '\x8B' && szBuffer[dwIndex + 2] == 'E' && szBuffer[dwIndex + 3] == 'A')
{
DWORD dwAddress2 = dwAddress + dwIndex + 7;
DWORD dwAddress3 = dwAddress2 + *(DWORD*)(dwAddress2);
if (strcmp((char*)dwAddress3, szProcName) == 0)
{
delete[] szBuffer;
CloseHandle(hProcess);
return dwAddress2 + 4;
}
}
}
delete[] szBuffer;
VirtualProtectEx(hProcess, (LPVOID)dwAddress, mbi.RegionSize, dwOldProtect, &dwOldProtect);
}
dwAddress += mbi.RegionSize;
dwSize -= mbi.RegionSize;
}
CloseHandle(hProcess);
return 0;
}您可能会立即指出一个明显的错误:函数返回DWORD而不是double,这正是我要求Copilot返回的。我看到了这个错误,但是从我看到的例子来看(是的,我至少做了一些搜索),返回DWORD也是一样的。我本可以看到这些例子是错误的,如果我是正确的。
发布于 2022-02-17 04:53:10
函数返回double,但它只返回存储在内存中的值,而实际上不是双类型数据。如果对double进行转换,就会得到原始数据。
除了64位系统上的字节指针之外,您不能在内存中进行搜索:http://msdn.microsoft.com/en-us/library/aa746449%28v=vs.85%29.aspx。
在内存中搜索字符串有不同的方法,具体取决于您要寻找的内容:http://www.catatonicsoft.com/blog/need-to-read-and-write-strings-and-data-in-a-processs-memory/
(在这里阅读更多:https://github.com/MicrosoftArchiveOrgMember/copilot)
记忆刮板
该程序在运行时使用几种技术从进程和内存中获取信息,以便在Cofactor终止目标进程(默认情况下)或手动终止程序时(使用CTRL+C)时可以将其添加到证据文件中。
这段代码主要是从http://www.codeproject.com和https://forums.hak5.org的各种示例中拼凑而成的,并进行了一些重大修改,以获得有用的格式的输出。
不断检查进程内存使用情况,并在日志文件更改时将其添加到日志文件中。这是通过获取指向进程内存区域的指针来完成的,然后在引用过程中检查其所有页面。当它们被更改时,该页的内容将被读取并作为证据添加到日志文件中。如果进程进入或退出休眠模式,或由于其他原因而停止,此程序将检测到该模式,并相应地将其添加到日志文件中。
由进程加载的当前DLL每5秒记录一次,以便如果DLL在Cofactor终止其目标后加载,它仍将作为证据包含在日志文件中。还每5秒检查一次进程是否生成新线程,以便子进程也包含在我们的证据文件中。
我们可以通过检查两个模块来扩展这个程序:
1) A module containing functions that correspond to debug breakpoints (which would detect whether a debugger was attached).
2) A module containing crash signatures - integers that would trigger an alert if they were found written to memory in any of our processes (like stack smashing protections might provide).为了做到这一点而不使事情变得过于复杂,我可能会使用每个模块中带有地址的CreateRemoteThread继续从该线程执行到您自己的代码中,在这里您可以检查断点或崩溃签名并相应地执行。
结论
如果您需要调试一个进程,并且由于任何原因无法使它停止,这个程序仍然能够在任何时候抓取进程内存,以便您可以搜索所需的任何东西。
为了使用创建的日志文件,您需要做一些额外的工作,比如使用您选择的解析器解析它并搜索它(使用regexes或其他什么),我认为它超出了Copilot设计的范围。
如果你最终使用了这个程序,请告诉我!我很想知道有多少人认为这个程序有用。
我从其他程序中学到了有趣的技巧
查找进程加载的DLL
下面的C++代码使用Windows ()获取加载DLL的完整路径,并将其解析为split(),只提取文件名,而不是整个路径。该代码的其余部分只是尽量避免重复,同时又足够简单,这样就不会在不同进程和文件系统用例之间产生太大的混淆(希望如此)。
// Code Example: Finding DLLs Loaded by a Process
#include <stdio.h>
#include <string.h>
#include <tchar.h>
#define BUFF_SIZE 200
// Find the full path to a loaded DLL by process ID (PID) and its filename (first 8 characters)
void GetModuleFileNameEx(int pid, const char* szName, char* buff, int buffSize)
{
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
if (hProcess == NULL) { return; }
HMODULE hMods[1024];
DWORD cbNeeded;
if (!EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded)) { return; }
for (int i = 0; i < (int)(cbNeeded / sizeof(HMODULE)); i++) {
TCHAR szModName[MAX_PATH];
if (!GetModuleFileNameEx(hProcess, hMods[i], szModName, sizeof(szModName))) { continue; }
strcat_s((char*)buff, buffSize - 1 , (char*)szModName);
// Check if the first 8 characters of the filename in the process matches
// with what we are looking for and avoid adding duplicates
char* chPtr = strchr((char*)buff, '\\');
if (chPtr != NULL) {
*chPtr = 0;
strcat_s((char*)buff, buffSize - 1 , "\\");
strcat_s((char*)buff, buffSize - 1 , szName);
HANDLE hFile = CreateFileA((LPCSTR)buff, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (hFile != INVALID_HANDLE_VALUE) { CloseHandle(hFile); return; }
} else { break; }
}
}
int main() {
char szDllName[8]; // Maximum length of a module name is MAXPATH - 1 bytes including the NULL terminator. However we only need 8 characters to store the DLL name so use this limit to save memory.
int pid; scanf("%d", &pid);
if (pid == 0) { return 0; }
char buff[BUFF_SIZE];
GetModuleFileNameEx(pid, szDllName, buff, BUFF_SIZE);
char* chPtr = strchr(buff, '\\');
// Change the path separator character to a null terminator so we can split it
if (chPtr != NULL) { *chPtr = 0; }
chPtr = strtok(buff, "\\");
while (chPtr != NULL) {
printf("%s\n", chPtr);
chPtr = strtok(NULL, "\\");
}
return 0;
}https://stackoverflow.com/questions/71152461
复制相似问题