gpt4 book ai didi

c++ - 在 Windows 上发送 Ctrl+C 到 QProcess

转载 作者:行者123 更新时间:2023-12-03 07:00:19 60 4
gpt4 key购买 nike

捕获你的马鞍,这是一个很长的马鞍!如果您不想阅读所有内容,请跳至“MCVE”部分。

我试图让一个以 QProcess 开始的进程优雅地退出。我不控制有问题的进程如何退出,它只接受 Ctrl+C 信号。令我感到困惑的是,在 QProcess 的 API 中,这听起来非常简单明了。然而,我在这里 :D

这是我到目前为止得到的:

正如我所说,QProcess 并不真正支持这一点。所以我必须深入 Windows 生态系统并尝试在本地实现它。我在 Microsoft Docs 中找到了 GenerateConsoleCtrlEvent .它似乎完全符合我的需要,所以我尝试使用它。在努力处理 Windows API 中的错误消息之后,这就是我得到的:

QProcess myprocess = new QProcess(this);
myprocess->setReadChannel(QProcess::StandardOutput);

// I'm sorry that I have to be vague here. I can't really share this part.
myprocess->start("myexec", {"arg1", "arg2"});

//...

auto success = GenerateConsoleCtrlEvent(CTRL_C_EVENT, myprocess->pid()->dwProcessId);
if (!success) {
LPVOID lpMsgBuf;
auto err = GetLastError();

FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr,
err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPTSTR>(&lpMsgBuf),
0, nullptr );

// probably could have used wcerr, but after making this work I was happy enough with it :D
auto error_string = QString::fromWCharArray((reinterpret_cast<LPTSTR>(lpMsgBuf)));
std::cerr << error_string.toStdString();
LocalFree(lpMsgBuf);
}

这只是打印 the handle is invalid. 到标准错误。我有点期待它,因为 GenerateConsoleCtrlEvent 的文档说:

dwProcessGroupId [in]
The identifier of the process group to receive the signal. A process group is created when the CREATE_NEW_PROCESS_GROUP flag is specified in a call to the CreateProcess function. The process identifier of the new process is also the process group identifier of a new process group.

...我支持 Qt 已经传递了那个标志。这让我卡住了一段时间,而且它似乎是关于这个的大多数问题的地方(是的,我已经看到他们都——我想)似乎也死了。然后我找到了 QProcess::setCreateProcessArgumentsModifier(有一个很好的用法示例 here),它允许我将参数注入(inject)到 CreateProcess 调用中。然后我更新了我的代码来执行此操作:

QProcess myprocess = new QProcess(this);
myprocess->setCreateProcessArgumentsModifier([this] (QProcess::CreateProcessArguments *args) {
args->flags |= CREATE_NEW_PROCESS_GROUP;
});
myprocess->setReadChannel(QProcess::StandardOutput);

myprocess->start("myexec", {"arg1", "arg2"});

//...

auto success = GenerateConsoleCtrlEvent(CTRL_C_EVENT, myprocess->pid()->dwProcessId);
if (!success) {
LPVOID lpMsgBuf;
auto err = GetLastError();

FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr,
err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPTSTR>(&lpMsgBuf),
0, nullptr );

auto error_string = QString::fromWCharArray((reinterpret_cast<LPTSTR>(lpMsgBuf)));
std::cerr << error_string.toStdString();
LocalFree(lpMsgBuf);
}

然而,这给了我同样的错误(句柄无效)。从那里,我尝试了其他事情,比如注入(inject)我自己的 PROCESS_INFORMATION 结构以确保我有正确的进程标识符,或者甚至将 CREATE_NEW_PROCESS_GROUP 添加到 lpStartupInfo 相反 - 我现在知道这是错误的地方,因为这导致了 some strange behavior (此链接中的提问者不是我 :D)

有什么想法吗?我可以采取不同的做法吗?

我正在使用 Qt 5.14.2,使用 MSVC 2017(64 位)编译。


MCVE

为此制作一个“最小”MCVE 并不容易 :)

我创建了一个简单的 Windows 应用程序,它通过简单地打印一条消息来处理 Ctrl+C。目标是让 QProcess 触发这个处理程序,没有副作用。这是子进程的源代码:

#include <atomic>
#include <chrono>
#include <iostream>
#include <thread>

#include "windows.h"

std::atomic<bool> should_stop = false;

BOOL WINAPI consoleHandler(DWORD signal) {
if (signal == CTRL_C_EVENT) {
std::cout << "\nThank you for your Ctrl+C event!\n";
should_stop.store(true);
}

return TRUE;
}

int main() {

if (!SetConsoleCtrlHandler(consoleHandler, TRUE)) {
std::cout << "Failed to set console handler\n";
return 1;
}

while (!should_stop) {
std::cout << "I'll keep printing this message until you stop me." << std::endl; // Yes, I want to flush every time.
std::this_thread::sleep_for(std::chrono::seconds(1));
}

return 0;
}

我的父应用程序的“MVCE”有一个普通的 main.cpp,以及一个带有 header 和源文件的 ProcessHolder 类。这是必需的,以便我可以有一个事件循环,并且 Qt 能够正确地 moc 类(用于所述事件循环)。

main.cpp

#include <QCoreApplication>
#include <QTimer>

#include <memory>

#include "processholder.h"

int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);

std::unique_ptr<ProcessHolder> ph(new ProcessHolder());

// Just so I can get the event loop running
QTimer::singleShot(0, ph.get(), &ProcessHolder::waitForInput);

return a.exec();
}

进程持有者.h

#ifndef PROCESSHOLDER_H
#define PROCESSHOLDER_H

#include <QObject>
#include <QProcess>

class ProcessHolder : public QObject
{
Q_OBJECT
public:
explicit ProcessHolder(QObject *parent = nullptr);

signals:

public slots:
void waitForInput();
private:
QProcess* p;
};

#endif // PROCESSHOLDER_H

进程持有者.cpp

#include "processholder.h"

#include <iostream>

#include <QTimer>

#include "Windows.h"

void tryFinishProcess(QProcess* p) {
auto success = GenerateConsoleCtrlEvent(CTRL_C_EVENT, p->pid()->dwProcessId);
if (!success) {
LPVOID lpMsgBuf;
auto err = GetLastError();

FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr,
err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPTSTR>(&lpMsgBuf),
0, nullptr );

// probably could have used wcerr, but after making this work I was happy enough with it :D
auto error_string = QString::fromWCharArray((reinterpret_cast<LPTSTR>(lpMsgBuf)));
std::cerr << error_string.toStdString();
LocalFree(lpMsgBuf);
}
}

ProcessHolder::ProcessHolder(QObject *parent) : QObject(parent), p(new QProcess(this))
{
connect(p, &QProcess::readyReadStandardOutput, [this]() {
auto lines = p->readAllStandardOutput();
std::cout << lines.toStdString();
});

// Doing this for this example makes things fail miserably when trying to close the parent program.
// An when not doing it, the CtrlC event that is generated on tryFinishProcess actually ends the
// parent program, rather than the child one.
/*p->setCreateProcessArgumentsModifier([this] (QProcess::CreateProcessArguments *args) {
args->flags |= CREATE_NEW_PROCESS_GROUP;
});*/

std::cout << "starting process...\n";

p->start(R"(path\to\TrivialConsoleApp.exe)");
}

void ProcessHolder::waitForInput(){
char c;
bool quit = false;
// Print a small prompt just so we can differentiate input from output
std::cout << "> ";
if (std::cin >> c) {
switch(c) {
case 'k':
p->kill();
break;
case 't':
p->terminate();
break;
case 'c':
p->close();
break;
case 'g':
tryFinishProcess(p);
}
// any other character will just reliquinsh the hold on standard io for a small time, enough for the
// messages that were sent via cout to show up.

if (!quit) {
QTimer::singleShot(0, this, &ProcessHolder::waitForInput);
}
}
}

一些示例运行:

使用 QProcess::kill()。子进程终止,但没有 CtrlC 消息。

console example using kill

使用 tryFinishProcess(见上面的实现)实际上使父进程退出:

console example using try finish process

再次使用 tryFinishProcess,但这次添加了 CREATE_NEW_PROCESS_GROUP(请参阅对 ProcessHolder 的构造函数的评论)。这里要注意的是,最后按终端要求的 RETURN 不再起作用(它什么都不做),所以那里出了点问题:

console example using try finish process with create new process group

我对以上三个示例(或至少最后两个示例)的期望是看到 “感谢您的 Ctrl+C 事件!” 消息(查看 consoleHandler 在子进程上)在请求进程完成后的某个地方。如果我在控制台上运行它,然后按 Ctrl+C,就会发生这种情况:

expected behavior

最佳答案

CTRL+C 被输入到控制台进程时,系统会在该进程中创建具有入口点的线程

EXTERN_C
WINBASEAPI
ULONG
WINAPI
CtrlRoutine(_In_ DWORD dwCtrlEvent);

此函数由 kernel32.dll 导出(可以正向导出到另一个 dll,比如 kernelbase.dll)

CtrlRoutine 接下来执行:如果正在调试进程 - 提高 DBG_CONTROL_C异常(exception),那么调用由 SetConsoleCtrlHandler 回调注册。如果没有注册回调或所有回调都返回 false - DefaultHandler 被调用,它只是调用 ExitProcess(STATUS_CONTROL_C_EXIT)(按 CTRL+C 退出应用程序)

但可以通过自己直接调用目标进程中的 CreateRemoteThread,入口点位于 CtrlRoutineCTRL_C_EVENT 作为参数。如果目标进程与我们的进程具有相同的数字容量 - 32 位或 64 位 - 完全没有任何问题 - 我们可以在链接时导入 CtrlRoutine(它在 kernel32.lib ) 或通过 GetProcAddress 获取地址。但是如果我们的进程是 64 位 native 进程并且目标进程是 32 位 (WoW64) - 这里的问题 - 我们需要在 32 位 中获取 CtrlRoutine 的地址kernel32.dll - 但我们不能直接将其加载到自身 64 位进程中并调用 GetProcAddress。需要自行映射此 dll,并自行获取它的基础并解析导出。这个任务已经不简单了。如果我们在 wow64 进程(64 位 Windows 上的 32 位进程)中运行并且目标进程是 64 位( native ) - 任务已经变得非常困难(尽管解决方案也存在,无需创建额外的进程)。但我假设控制进程是本地的(64 位 Windows 上的 64 位)

#pragma warning( disable : 4201)

#include <Windows.h>
#include <malloc.h>
#define LDR_DATA_TABLE_ENTRY _LDR_DATA_TABLE_ENTRY_
#define PLDR_DATA_TABLE_ENTRY _PLDR_DATA_TABLE_ENTRY_
#include <winternl.h>
#undef PLDR_DATA_TABLE_ENTRY
#undef LDR_DATA_TABLE_ENTRY

#define MAXUSHORT 0xffff
#define MAXULONG 0xffffffff

#define RtlOffsetToPointer(B,O) ((PCHAR)( ((PCHAR)(B)) + ((ULONG_PTR)(O)) ))
#define RtlPointerToOffset(B,P) ((ULONG)( ((PCHAR)(P)) - ((PCHAR)(B)) ))

#define RTL_CONSTANT_STRING(s) { sizeof( s ) - sizeof( (s)[0] ), sizeof( s ), const_cast<PWSTR>(s) }

#define NtCurrentProcess() ( (HANDLE)(LONG_PTR) -1 )

typedef enum _SECTION_INHERIT {
ViewShare = 1,
ViewUnmap = 2
} SECTION_INHERIT;

typedef enum _SECTION_INFORMATION_CLASS
{
SectionBasicInformation, // q; SECTION_BASIC_INFORMATION
SectionImageInformation, // q; SECTION_IMAGE_INFORMATION
SectionRelocationInformation, // name:wow64:whNtQuerySection_SectionRelocationInformation
SectionOriginalBaseInformation, // PVOID BaseAddress
SectionInternalImageInformation, // SECTION_INTERNAL_IMAGE_INFORMATION // since REDSTONE2
MaxSectionInfoClass
} SECTION_INFORMATION_CLASS;

typedef struct SECTION_IMAGE_INFORMATION
{
PVOID TransferAddress;
ULONG ZeroBits;
SIZE_T MaximumStackSize;
SIZE_T CommittedStackSize;
ULONG SubSystemType;
union
{
struct
{
USHORT SubSystemMinorVersion;
USHORT SubSystemMajorVersion;
};
ULONG SubSystemVersion;
};
union
{
struct
{
USHORT MajorOperatingSystemVersion;
USHORT MinorOperatingSystemVersion;
};
ULONG OperatingSystemVersion;
};
USHORT ImageCharacteristics;
USHORT DllCharacteristics;
USHORT Machine;
BOOLEAN ImageContainsCode;
union
{
UCHAR ImageFlags;
struct
{
UCHAR ComPlusNativeReady : 1;
UCHAR ComPlusILOnly : 1;
UCHAR ImageDynamicallyRelocated : 1;
UCHAR ImageMappedFlat : 1;
UCHAR BaseBelow4gb : 1;
UCHAR ComPlusPrefer32bit : 1;
UCHAR Reserved : 2;
};
};
ULONG LoaderFlags;
ULONG ImageFileSize;
ULONG CheckSum;
} *PSECTION_IMAGE_INFORMATION;

typedef struct LDR_DATA_TABLE_ENTRY
{
LIST_ENTRY InLoadOrderLinks;
LIST_ENTRY InMemoryOrderLinks;
LIST_ENTRY InInitializationOrderLinks;
void *DllBase;
void *EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
// .. more members. trucated
} *PLDR_DATA_TABLE_ENTRY;

EXTERN_C_START

NTSYSAPI
NTSTATUS
NTAPI
LdrFindEntryForAddress(
_In_ PVOID DllHandle,
_Out_ PLDR_DATA_TABLE_ENTRY *Entry
);


NTSYSAPI
PIMAGE_NT_HEADERS
NTAPI
RtlImageNtHeader(
_In_ PVOID Base
);

EXTERN_C
NTSYSAPI
PVOID
NTAPI
RtlImageDirectoryEntryToData(
_In_ PVOID Base,
_In_ BOOLEAN MappedAsImage,
_In_ USHORT DirectoryEntry,
_Out_ PULONG Size
);

NTSYSAPI
NTSTATUS
NTAPI
RtlMultiByteToUnicodeSize(
_Out_ PULONG BytesInUnicodeString,
_In_reads_bytes_(BytesInMultiByteString) const CHAR *MultiByteString,
_In_ ULONG BytesInMultiByteString
);

NTSYSAPI
NTSTATUS
NTAPI
RtlMultiByteToUnicodeSize(
_Out_ PULONG BytesInUnicodeString,
_In_reads_bytes_(BytesInMultiByteString) const CHAR *MultiByteString,
_In_ ULONG BytesInMultiByteString
);

NTSYSAPI
NTSTATUS
NTAPI
RtlMultiByteToUnicodeN(
_Out_writes_bytes_to_(MaxBytesInUnicodeString, *BytesInUnicodeString) PWCH UnicodeString,
_In_ ULONG MaxBytesInUnicodeString,
_Out_opt_ PULONG BytesInUnicodeString,
_In_reads_bytes_(BytesInMultiByteString) const CHAR *MultiByteString,
_In_ ULONG BytesInMultiByteString
);

NTSYSAPI
NTSTATUS
NTAPI
RtlAppendUnicodeToString (
_Inout_ PUNICODE_STRING Destination,
_In_opt_z_ PCWSTR Source
);

NTSYSAPI
NTSTATUS
NTAPI
RtlAppendUnicodeStringToString (
_Inout_ PUNICODE_STRING Destination,
_In_ PCUNICODE_STRING Source
);

NTSYSAPI
BOOLEAN
NTAPI
RtlPrefixUnicodeString(
_In_ PCUNICODE_STRING String1,
_In_ PCUNICODE_STRING String2,
_In_ BOOLEAN CaseInSensitive
);

NTSYSAPI
NTSTATUS
NTAPI
ZwUnmapViewOfSection(
_In_ HANDLE ProcessHandle,
_In_opt_ PVOID BaseAddress
);

NTSYSAPI
NTSTATUS
NTAPI
ZwMapViewOfSection(
_In_ HANDLE SectionHandle,
_In_ HANDLE ProcessHandle,
_Outptr_result_bytebuffer_(*ViewSize) PVOID *BaseAddress,
_In_ ULONG_PTR ZeroBits,
_In_ SIZE_T CommitSize,
_Inout_opt_ PLARGE_INTEGER SectionOffset,
_Inout_ PSIZE_T ViewSize,
_In_ SECTION_INHERIT InheritDisposition,
_In_ ULONG AllocationType,
_In_ ULONG Win32Protect
);

NTSYSAPI
NTSTATUS
NTAPI
ZwOpenSection(
_Out_ PHANDLE SectionHandle,
_In_ ACCESS_MASK DesiredAccess,
_In_ POBJECT_ATTRIBUTES ObjectAttributes
);

NTSYSAPI
NTSTATUS
NTAPI
ZwQuerySection(
_In_ HANDLE SectionHandle,
_In_ ULONG SectionInformationClass,
_Out_ PVOID SectionInformation,
_In_ ULONG SectionInformationLength,
_Out_ PSIZE_T ResultLength OPTIONAL
);

NTSYSAPI
NTSTATUS
NTAPI
LdrLoadDll(
_In_opt_ PWSTR DllPath,
_In_opt_ PULONG DllCharacteristics,
_In_ PUNICODE_STRING DllName,
_Out_ HMODULE *DllHandle
);

NTSYSAPI
NTSTATUS
NTAPI
LdrUnloadDll(
_In_ PVOID DllHandle
);

NTSYSAPI
NTSTATUS
NTAPI
LdrGetProcedureAddress(
_In_ PVOID DllHandle,
_In_opt_ PANSI_STRING ProcedureName,
_In_opt_ ULONG ProcedureNumber,
_Out_ PVOID *ProcedureAddress
);

EXTERN_C_END

ULONG GetNameOrdinal(PVOID Base, PDWORD AddressOfNames, DWORD NumberOfNames, PCSTR Name)
{
if (NumberOfNames)
{
DWORD a = 0, o;

do
{
o = (a + NumberOfNames) >> 1;

int i = strcmp(RtlOffsetToPointer(Base, AddressOfNames[o]), Name);

if (!i)
{
return o;
}

0 > i ? a = o + 1 : NumberOfNames = o;

} while (a < NumberOfNames);
}

return MAXULONG;
}

PVOID getWowProcs(PCUNICODE_STRING DllName, PCSTR Name);

PVOID getWowProcs(PVOID ImageBase, PVOID BaseAddress, PCSTR Name)
{
ULONG exportSize, exportRVA;

PIMAGE_EXPORT_DIRECTORY pied = (PIMAGE_EXPORT_DIRECTORY)
RtlImageDirectoryEntryToData(BaseAddress, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &exportSize);

if (!pied) return 0;

exportRVA = RtlPointerToOffset(BaseAddress, pied);

ULONG NumberOfFunctions = pied->NumberOfFunctions;

if (!NumberOfFunctions) return 0;

ULONG NumberOfNames = pied->NumberOfNames;
ULONG OrdinalBase = pied->Base;

PULONG AddressOfFunctions = (PULONG)RtlOffsetToPointer(BaseAddress, pied->AddressOfFunctions);
PULONG AddressOfNames = (PULONG)RtlOffsetToPointer(BaseAddress, pied->AddressOfNames);
PWORD AddressOfNameOrdinals = (PWORD)RtlOffsetToPointer(BaseAddress, pied->AddressOfNameOrdinals);

ULONG o;

if (*Name == '#')
{
if ((o = strtoul(Name + 1, const_cast<char**>(&Name), 10)) < OrdinalBase || *Name)
{
return 0;
}
o -= OrdinalBase;
}
else
{
o = GetNameOrdinal(BaseAddress, AddressOfNames, NumberOfNames, Name);
if (o < NumberOfNames)
{
o = AddressOfNameOrdinals[o];
}
}

if (o >= NumberOfFunctions)
{
return 0;
}

DWORD Rva = AddressOfFunctions[o];

if ((ULONG_PTR)Rva - (ULONG_PTR)exportRVA >= exportSize)
{
return RtlOffsetToPointer(ImageBase, Rva);
}

// forward export
PCSTR pfn = RtlOffsetToPointer(BaseAddress, Rva);

if (!(Name = strrchr(pfn, '.')))
{
return 0;
}

static const WCHAR DLL[] = L"DLL";

ULONG BytesInUnicodeString, BytesInMultiByteString = RtlPointerToOffset(pfn, ++Name);

if (0 > RtlMultiByteToUnicodeSize(&BytesInUnicodeString, pfn, BytesInMultiByteString) ||
(BytesInUnicodeString += sizeof(DLL)) >= MAXUSHORT )
{
return 0;
}

UNICODE_STRING DllName = {
0, (USHORT)BytesInUnicodeString, (PWSTR)alloca(BytesInUnicodeString)
};

if (0 > RtlMultiByteToUnicodeN(DllName.Buffer, DllName.MaximumLength,
&BytesInUnicodeString, pfn, BytesInMultiByteString))
{
return 0;
}

DllName.Length = (USHORT)BytesInUnicodeString;

if (0 > RtlAppendUnicodeToString(&DllName, DLL))
{
return 0;
}

static const UNICODE_STRING API_ = RTL_CONSTANT_STRING(L"API-");
static const UNICODE_STRING EXT_ = RTL_CONSTANT_STRING(L"EXT-");

if (!RtlPrefixUnicodeString(&API_, &DllName, TRUE) &&
!RtlPrefixUnicodeString(&EXT_, &DllName, TRUE))
{
return getWowProcs(&DllName, Name);
}

HMODULE hmod;

if (0 <= LdrLoadDll(0, 0, &DllName, &hmod))
{
ANSI_STRING as, *pas;

if (*Name == '#')
{
pas = 0;
o = strtoul(Name + 1, const_cast<char**>(&Name), 10);
if (*Name)
{
o = 0;
}
}
else
{
o = 0;
RtlInitAnsiString(pas = &as, Name);
}

PVOID pv, pvfn = 0;
if (0 <= LdrGetProcedureAddress(hmod, pas, o, &pv))
{
PLDR_DATA_TABLE_ENTRY ldte;
if (0 <= LdrFindEntryForAddress(pv, &ldte))
{
pvfn = getWowProcs(&ldte->BaseDllName, Name);
}
}
LdrUnloadDll(hmod);

return pvfn;
}

return 0;
}

PVOID getWowProcs(PCUNICODE_STRING DllName, PCSTR Name)
{
static const WCHAR KnownDlls32[] = L"\\KnownDlls32\\";

UNICODE_STRING ObjectName = {
0,
(USHORT)(sizeof(KnownDlls32) + DllName->Length),
(PWSTR)alloca(ObjectName.MaximumLength)
};

if (0 > RtlAppendUnicodeToString(&ObjectName, KnownDlls32) ||
0 > RtlAppendUnicodeStringToString(&ObjectName, DllName))
{
return 0;
}

OBJECT_ATTRIBUTES oa = { sizeof(oa), 0, &ObjectName, OBJ_CASE_INSENSITIVE };

HANDLE hSection;

PVOID pv = 0;

if (0 <= ZwOpenSection(&hSection, SECTION_QUERY|SECTION_MAP_READ, &oa))
{
SECTION_IMAGE_INFORMATION sii;
if (0 <= ZwQuerySection(hSection, SectionImageInformation, &sii, sizeof(sii), 0))
{
PVOID BaseAddress = 0;
SIZE_T ViewSize = 0;

if (0 <= ZwMapViewOfSection(hSection, NtCurrentProcess(), &BaseAddress, 0, 0, 0, &ViewSize, ViewUnmap, 0, PAGE_READONLY))
{
__try
{
if (PIMAGE_NT_HEADERS32 pinth = (PIMAGE_NT_HEADERS32)RtlImageNtHeader(BaseAddress))
{
pv = getWowProcs((PBYTE)sii.TransferAddress - pinth->OptionalHeader.AddressOfEntryPoint, BaseAddress, Name);
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
}

ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
}
}
NtClose(hSection);
}

return pv;
}

PVOID GetCtrlRoutine(HANDLE hProcess)
{
BOOL bWow;
if (IsWow64Process(hProcess, &bWow))
{
static const UNICODE_STRING kernel32 = RTL_CONSTANT_STRING(L"kernel32.dll");

if (bWow)
{
static PVOID pvCtrlRoutine = 0;
if (!pvCtrlRoutine)
{
// GetOverlappedResultEx
// just for some extreme case, for better understand code in getWowProcs
// it not need here
// pvCtrlRoutine = getWowProcs(&kernel32, "GetOverlappedResultEx");
pvCtrlRoutine = getWowProcs(&kernel32, "CtrlRoutine");
}
return pvCtrlRoutine;
}

static PVOID pvCtrlRoutine = 0;
if (!pvCtrlRoutine)
{
if (HMODULE hmod = GetModuleHandle(kernel32.Buffer))
{
pvCtrlRoutine = GetProcAddress(hmod, "CtrlRoutine");
}
}
return pvCtrlRoutine;
}

return 0;
}

void SendCtrlEvent(HANDLE hProcess)
{
if (PVOID pv = GetCtrlRoutine(hProcess))
{
if (HANDLE hThread = CreateRemoteThread(hProcess, 0, 0, (PTHREAD_START_ROUTINE)pv, CTRL_C_EVENT, 0, 0))
{
CloseHandle(hThread);
return ;
}
}

TerminateProcess(hProcess, STATUS_CONTROL_C_EXIT);
}

void DemoUseCtrlC()
{
WCHAR AppName[MAX_PATH];

if (ExpandEnvironmentStringsW(L"%SystemRoot%\\syswow64\\ping.exe", AppName, _countof(AppName)))
{
STARTUPINFO si = { sizeof(si)};
PROCESS_INFORMATION pi;
if (CreateProcessW(AppName, const_cast<PWSTR>(L"* -n 999 8.8.8.8"), 0, 0, 0, 0, 0, 0, &si, &pi))
{
CloseHandle(pi.hThread);
MessageBoxW(HWND_DESKTOP, L"Break..", L"CTRL+C", MB_ICONINFORMATION);
SendCtrlEvent(pi.hProcess);
CloseHandle(pi.hProcess);
}
}
}

关于c++ - 在 Windows 上发送 Ctrl+C 到 QProcess,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64760376/

60 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com