【发布时间】:2018-06-28 15:35:00
【问题描述】:
我的服务从某些进程接收数据,对其进行解析,然后将 HTTP 帖子发送到我的 PHP 服务器。
当我开始编写代码时,它是一个普通的 64 位程序。完成后,我将其转换为服务,但是当服务尝试发送数据时发生了一些崩溃。
原因不清楚,因为我在服务的其他地方使用libcurl没有问题。
我的接收器是这样的:
while (true)
{
memset(pipe_buffer, 0, 10000);
cres = ReadFile(pipe, pipe_buffer, 10000, &read, 0);
ofile << "[*] got a packet with length : " << read << endl;
if (read > 0 && cres) {
ofile << "[*] " << pipe_buffer << endl;
// send the request
string payload;
payload += "data=";
payload += pipe_buffer;
ofile << "[*] sending post : " << url << "?" << payload<< endl;
CURL *curl;
curl = curl_easy_init();
if (!curl) {
ofile << "[!] curl failed to init" << endl;
return 0;
}
curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); // crashes start here
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, payload.c_str());
curl_easy_perform(curl);
curl_easy_cleanup(curl);
}
else {
// the client may dissconnect , wait for it to connect again
DisconnectNamedPipe(pipe); ConnectNamedPipe(pipe, 0);
}
}
我每次都会遇到非常不同和奇怪的错误。
其中大部分来自 libcurl 调用的RtlFreeHeap(),以及来自curl_easy_perform() 使用的某些 WSA 函数除以零的整数。
从curl_easy_setopt()开始的任何libcurl函数都可能发生崩溃。
相同的代码在普通程序中运行没有问题。
编辑:挖掘后这是导致损坏的函数 以前的 curl 使用没有发生崩溃的原因是我不使用这个函数,除非在这个之后,然后我创建一个接收器线程,它与使用这个函数的线程并行工作,普通程序也没有t 崩溃,因为此功能仅适用于服务(不在本地系统中运行的程序可以使用 EnumWindows) 我认为 Poco 网络没有崩溃,因为它基于 c++ 而不是 c 并使用 new/delete 来分配和释放内存,但是来自 curl 和其他函数的崩溃从 _malloc_base 和类似的 c 分配函数开始
功能代码:
wstring GetCommandLineRemote(DWORD id) {
PROCESS_BASIC_INFORMATION pbInfo = { 0 };
HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, 0, id);
if (!hProc || hProc == INVALID_HANDLE_VALUE) return wstring(L"");
auto status = fNtQueryInformationProcess(hProc, ProcessBasicInformation, &pbInfo, sizeof(pbInfo), NULL);
if (!NT_SUCCESS(status)) { CloseHandle(hProc); return wstring(L""); }
BPEB bbeb = { 0 };
BOOL result;
result = ReadProcessMemory(hProc, (void*)pbInfo.PebBaseAddress, &bbeb, sizeof(BPEB), 0);
if (!result) { CloseHandle(hProc); return wstring(L""); }
BRTL_USER_PROCESS_PARAMETERS parameters = { 0 };
result = ReadProcessMemory(hProc, (void*)((uintptr_t)bbeb.ProcessParameters), ¶meters, sizeof(BRTL_USER_PROCESS_PARAMETERS), 0);
if (!result) { CloseHandle(hProc); return wstring(L""); }
UNICODE_STRING CommandLine = { 0 };
CommandLine.Length = parameters.CommandLine.Length;
CommandLine.MaximumLength = parameters.CommandLine.MaximumLength;
CommandLine.Buffer = new WCHAR[CommandLine.MaximumLength];
result = ReadProcessMemory(hProc, (void*)parameters.CommandLine.Buffer, CommandLine.Buffer, parameters.MaximumLength, 0);
if (!result) { CloseHandle(hProc); return wstring(L""); }
CloseHandle(hProc);
wstring wCommandLine = CommandLine.Buffer;
delete CommandLine.Buffer;
return wCommandLine;
}
我正在使用此函数通过进程启动的命令行来区分我的辅助进程的实例
所以查找实例的机制如下所示:
vector<DWORD> enum_ids(wstring proc_name) {
HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
vector<DWORD> ids;
PROCESSENTRY32W entry = { 0 };
entry.dwSize = sizeof(entry);
if (!Process32FirstW(snap, &entry)) return ids;
do {
wstring p_name = entry.szExeFile;
auto check_pos = p_name.find(proc_name);
if (check_pos != wstring::npos) {
ofile << "[*] found process instance with id : " << entry.th32ProcessID << endl;
ids.push_back(entry.th32ProcessID);
}
} while (Process32NextW(snap, &entry));
return ids;
}
DWORD find_process(wstring proc_name,wstring unique) {
DWORD process_id = 0;
auto ids = enum_ids(proc_name);
for (auto id : ids) {
wstring wCommandLine = GetCommandLineRemote(id);
auto check_pos = wCommandLine.find(unique);
if (check_pos != wstring::npos) {
process_id = id;
break;
}
//if (id == 83004) { process_id = id; break; } 83004 is example , if I used this instead of the above comparison code no errors occur so I assumed the errors come from GetCommandLineRemote
}
return process_id;
}
然后在服务主线程中:
CreateThread(0, 0, recieve, 0, 0, 0);
CreateThread(0, 0, FindParticularInstance, (char*)"ch", 0, 0);
现在在找到错误源之后,这个函数如何处理所有这些错误以及如何防止它发生?
结构的定义(来自 NiroSoft 和进程黑客):
typedef struct _CURDIR
{
UNICODE_STRING DosPath;
PVOID Handle;
} CURDIR, *PCURDIR;
typedef struct _RTL_DRIVE_LETTER_CURDIR
{
WORD Flags;
WORD Length;
ULONG TimeStamp;
STRING DosPath;
} RTL_DRIVE_LETTER_CURDIR, *PRTL_DRIVE_LETTER_CURDIR;
typedef struct _BRTL_USER_PROCESS_PARAMETERS
{
ULONG MaximumLength;
ULONG Length;
ULONG Flags;
ULONG DebugFlags;
PVOID ConsoleHandle;
ULONG ConsoleFlags;
PVOID StandardInput;
PVOID StandardOutput;
PVOID StandardError;
CURDIR CurrentDirectory;
UNICODE_STRING DllPath;
UNICODE_STRING ImagePathName;
UNICODE_STRING CommandLine;
PVOID Environment;
ULONG StartingX;
ULONG StartingY;
ULONG CountX;
ULONG CountY;
ULONG CountCharsX;
ULONG CountCharsY;
ULONG FillAttribute;
ULONG WindowFlags;
ULONG ShowWindowFlags;
UNICODE_STRING WindowTitle;
UNICODE_STRING DesktopInfo;
UNICODE_STRING ShellInfo;
UNICODE_STRING RuntimeData;
RTL_DRIVE_LETTER_CURDIR CurrentDirectores[32];
ULONG EnvironmentSize;
} BRTL_USER_PROCESS_PARAMETERS, *PBRTL_USER_PROCESS_PARAMETERS;
typedef struct _BPEB
{
UCHAR InheritedAddressSpace;
UCHAR ReadImageFileExecOptions;
UCHAR BeingDebugged;
UCHAR BitField;
ULONG ImageUsesLargePages : 1;
ULONG IsProtectedProcess : 1;
ULONG IsLegacyProcess : 1;
ULONG IsImageDynamicallyRelocated : 1;
ULONG SpareBits : 4;
PVOID Mutant;
PVOID ImageBaseAddress;
PPEB_LDR_DATA Ldr;
PBRTL_USER_PROCESS_PARAMETERS ProcessParameters;
PVOID SubSystemData;
PVOID ProcessHeap;
PRTL_CRITICAL_SECTION FastPebLock;
PVOID AtlThunkSListPtr;
PVOID IFEOKey;
ULONG CrossProcessFlags;
ULONG ProcessInJob : 1;
ULONG ProcessInitializing : 1;
ULONG ReservedBits0 : 30;
union
{
PVOID KernelCallbackTable;
PVOID UserSharedInfoPtr;
};
ULONG SystemReserved[1];
ULONG SpareUlong;
} BPEB, *PBPEB;
【问题讨论】:
-
是时候启动调试器了。
-
我调试了很多,所以我知道崩溃发生在哪里,但不知道为什么?正如我所说,相同的代码在服务中不使用时也可以工作
-
你在
url上做什么操作?也许您以某种方式破坏了变量?也许它是无效的? -
@dev65 你能发布更多关于崩溃的信息吗?
-
@dev65 崩溃发生在你所说的那一行。有一件事是
url。到目前为止,我们还没有看到这个变量是在哪里初始化的,它是如何获得它的值的,等等。而且仅仅因为你可以打印并不意味着没有内存损坏。
标签: c++ curl winapi windows-services libcurl