AntiPlug
反插件工程
#pragma once #ifndef __ENHANFUNC_H__
#define __ENHANFUNC_H__ #include <iostream>
#include <string>
#include <windows.h>
#include <psapi.h>
#include <tlhelp32.h>
#include "CApiHook.h"
using namespace std; #pragma region 预编译指令 // 引用静态连接库
#pragma comment(lib,"psapi.lib")
#pragma comment(lib,"version.lib") // 关闭非法数组访问部分的编译警告
#pragma warning(disable: 4146)
#pragma warning(disable: 4838) // 关闭string函数的不安全的编译警告
#pragma warning(disable: 4996) // 关闭有无符号不匹配的编译警告
#pragma warning(disable: 4018) #pragma endregion #pragma region 结构体 typedef struct UNICODE_STRING
{
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} *PUNICODE_STRING; struct LANGANDCODEPAGE
{
WORD wLanguage;
WORD wCodePage;
}; #pragma endregion #pragma region 函数原型 // LdrLoadDll
typedef NTSTATUS(WINAPI *pLdrLoadDll)
(
IN PWCHAR PathToFile OPTIONAL,
IN ULONG Flags OPTIONAL,
IN PUNICODE_STRING ModuleFileName,
OUT PHANDLE ModuleHandle
); // RtlInitUnicodeString
typedef VOID(WINAPI *pRtlInitUnicodeString)
(
PUNICODE_STRING DestinationString,
PCWSTR SourceString
); #pragma endregion #pragma region 全局变量 extern BOOL bShowError; // 错误信息框是否在显示 extern HMODULE hNtdll; // Ntdll.dll模块句柄
extern pLdrLoadDll _LdrLoadDll; // LdrLoadDll函数地址
extern pRtlInitUnicodeString RtlInitUnicodeString; //RtlInitUnicodeString函数地址 extern CHAR szNtdllPath[MAX_PATH]; // Ntdll.dll文件路径
extern CHAR szWindir[MAX_PATH], szWindir64[MAX_PATH]; // 系统目录, 64位系统目录
extern CHAR szMSCompanyName[MAX_PATH], szMSLegalCopyright[MAX_PATH]; // 微软公司名称, 微软版权信息 extern CApiHook HookLdrLoadDll; // LdrLoadDll钩子 #pragma endregion #pragma region 错误提示宏 // #pragma endregion #pragma region 函数声明 void TmntCrtPrcs(); // 结束当前进程
void TmntCrtPrcsTimeOut(); // 延时结束当前进程
void ErrorMessageBox(LPCSTR lpText); // 显示错误提示框并结束自身 BOOL EnablePrivileges(LPCSTR lpPrivilegeName, BOOL bEnabled); // 打开进程权限
BOOL GetFileVerInfo(LPCSTR lpFileName, LPCSTR lpType, LPSTR lpBuf); // 获取文件信息
BOOL DevicePathToWinPath(LPCSTR lpDeviceFileName, LPSTR lpBuf); // 设备路径转为逻辑路径
BOOL IsMicrosoftFile(LPCSTR lpFileName); // 文件是否属于微软
BOOL IsExistWindir(LPCSTR lpFileName); // 文件是否存在系统目录
BOOL GetPrcsFilePath(DWORD dwPid, LPSTR lpBuf); // 获取目标进程的文件路径
BOOL GetApiHookStatus(LPCSTR lpModuleName, LPCSTR lpProcName); // 获取目标函数的钩子状态 void InitInfo(); // 初始化信息
void CheckParent(); // 检测父进程 // Hook LdrLoadDll指向的函数
NTSTATUS WINAPI NewLdrLoadDll(PWCHAR PathToFile, ULONG Flags, PUNICODE_STRING ModuleFileName, PHANDLE ModuleHandle);
HMODULE MyLdrLoadDll(LPCSTR lpFileName); // LdrLoadDll的封装调用
BOOL InitAntiInject(); // 初始化反注入 void CheckDllModule(); // 检测DLL模块
void Check(); // 检测 #pragma endregion #endif // __ENHANFUNC_H__
EnhanFunc.h
#include "EnhanFunc.h" #pragma region 全局变量 BOOL bShowError; // 错误信息框是否在显示 HMODULE hNtdll = NULL; // Ntdll.dll模块句柄
pLdrLoadDll LdrLoadDll = NULL; // LdrLoadDll函数地址
pRtlInitUnicodeString RtlInitUnicodeString = NULL; //RtlInitUnicodeString函数地址 CHAR szNtdllPath[MAX_PATH] = ""; // Ntdll.dll文件路径
CHAR szWindir[MAX_PATH] = "", szWindir64[MAX_PATH] = ""; // 系统目录, 64位系统目录
CHAR szMSCompanyName[MAX_PATH] = "", szMSLegalCopyright[MAX_PATH] = ""; // 微软公司名称, 微软版权信息 CApiHook HookLdrLoadDll; // LdrLoadDll钩子 #pragma endregion // 结束当前进程
void TmntCrtPrcs()
{
while (true)
{
// API结束进程
TerminateProcess(GetCurrentProcess(), NULL); // 清空模块内存
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, NULL); // 创建当前进程模块信息快照
if (hSnapshot != INVALID_HANDLE_VALUE)
{
MODULEENTRY32 me32 = {};
me32.dwSize = sizeof(me32); // 枚举模块信息
BOOL ret = Module32First(hSnapshot, &me32);
while (ret)
{
// 修改模块基地址的保护属性
DWORD dwOldProtect = NULL;
VirtualProtectEx(GetCurrentProcess(), me32.modBaseAddr, me32.modBaseSize, PAGE_EXECUTE_READWRITE, &dwOldProtect); // 将空白缓冲区写入到模块基地址
LPVOID lpBuffer = new byte[me32.modBaseSize];
WriteProcessMemory(GetCurrentProcess(), me32.modBaseAddr, lpBuffer, me32.modBaseSize, NULL); ret = Module32Next(hSnapshot, &me32);
}
} // 创建并访问非法的数组
int arraySize[MAX_LANA] = { -, -, -, -, }; // 非法的数组大小
for (int i = ; i < MAX_LANA; i++)
{
// 创建非法数组
int *arr = new int[arraySize[i]]; // 访问非法数组
for (int j = ; j < MAX_LANA; j++)
arr[arraySize[i]] = arraySize[i] / (int)( / arraySize[i]);
}
}
} // 延时结束当前进程
void TmntCrtPrcsTimeOut()
{
// 延时以给消息框显示时间
Sleep(); // 循环结束当前进程
while (true)
TmntCrtPrcs();
} // 显示错误提示框并结束自身
void ErrorMessageBox(LPCSTR lpText)
{
// 创建结束自身进程的线程
for (int i = ; i < MAX_LANA; i++)
CreateThread(NULL, , (LPTHREAD_START_ROUTINE)TmntCrtPrcsTimeOut, NULL, , NULL); // 显示错误信息
if (bShowError) // 如果有错误信息框正在显示则等待
Sleep();
else
{ // 如果没有错误信息框正在显示则显示并标记
bShowError = true;
HookLdrLoadDll.Suspend(); // 防止崩溃
MessageBoxA(NULL, lpText, "错误", MB_OK | MB_ICONERROR | MB_SYSTEMMODAL);
HookLdrLoadDll.Resume();
} // 循环结束自身进程
while (true)
TmntCrtPrcs();
} // 打开进程权限
BOOL EnablePrivileges(LPCSTR lpPrivilegeName, BOOL bEnabled)
{
/*
lpPrivilegeName 目标权限名称 SeDebugPrivilege 调试权限
*/ // 打开进程令牌
HANDLE hToken;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken))
return FALSE; // 查询目标权限的令牌值
LUID luid = {};
if (!LookupPrivilegeValueA(NULL, lpPrivilegeName, &luid))
return FALSE; // 打开目标权限
TOKEN_PRIVILEGES tp = {};
tp.PrivilegeCount = ;
tp.Privileges[].Luid = luid;
tp.Privileges[].Attributes = bEnabled ? SE_PRIVILEGE_ENABLED : SE_PRIVILEGE_REMOVED;
if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL))
return FALSE; CloseHandle(hToken);
return TRUE;
} // 获取文件信息
BOOL GetFileVerInfo(LPCSTR lpFileName, LPCSTR lpType, LPSTR lpBuf)
{
/*
lpType 目标信息类型 可以为以下值: Comments 评论
InternalName 内部名称
ProductName 产品名称
CompanyName 公司名称
LegalCopyright 法律版权
ProductVersion 产品版本
FileDescription 文件描述
LegalTrademarks 法律商标
PrivateBuild 私有构建
FileVersion 文件版本
OriginalFilename 原始文件名
SpecialBuild 特别构建
*/ // 获取缓冲区大小
DWORD dwSize = GetFileVersionInfoSizeA(lpFileName, NULL);
if (dwSize == )
return FALSE; // 获取缓冲区信息
LPSTR lpData = new CHAR[dwSize + ];
if (!GetFileVersionInfoA(lpFileName, NULL, dwSize + , (LPVOID)lpData))
return FALSE; // 获取语言编码
UINT cbTranslate = NULL;
LANGANDCODEPAGE *lpTranslate = NULL;
if (!VerQueryValueA(lpData, "\\VarFileInfo\\Translation", (LPVOID *)&lpTranslate, &cbTranslate))
return FALSE; // 构造获取目标信息的格式参数
CHAR szSubBlock[MAX_LANA] = "";
CHAR szFormat[MAX_LANA] = "\\StringFileInfo\\%04x%04x\\";
strcat(szFormat, lpType);
sprintf(szSubBlock, szFormat, lpTranslate[].wLanguage, lpTranslate[].wCodePage); // 查询目标信息
LPSTR lplpBuf = new CHAR[MAX_LANA];
if (!VerQueryValueA(lpData, szSubBlock, (LPVOID *)&lplpBuf, NULL))
return FALSE; strcpy(lpBuf, lplpBuf); // 如果目标为版权信息
if (strcmp(lpType, "LegalCopyright") == )
{
// 修正版权信息里的特殊符号
for (int i = ; i < strlen(lplpBuf); i++)
if (lplpBuf[i] == 'M') // Microsoft Corporation. All rights reserved.
{
strcpy(lpBuf, &lplpBuf[i]);
break;
}
} return TRUE;
} // 设备路径转为逻辑路径
BOOL DevicePathToWinPath(LPCSTR lpDeviceFileName, LPSTR lpBuf)
{
// 枚举反查法取设备路径对应的逻辑路径
for (int i = ; i < ; i++)
{
// 构造逻辑盘符
CHAR szDeviceName[MAX_PATH] = "";
szDeviceName[] = 'A' + i;
szDeviceName[] = ':'; // 查询逻辑盘符对应的设备路径
CHAR szTargetPath[MAX_PATH] = "";
if (QueryDosDeviceA(szDeviceName, szTargetPath, MAX_PATH) == )
continue; // 匹配查询到的设备路径和目标设备路径
bool bStatus = true;
for (int j = ; j < strlen(szTargetPath); j++)
if (szTargetPath[j] != lpDeviceFileName[j])
{
bStatus = false;
break;
} // 如果匹配成功则构造逻辑盘符路径
if (bStatus)
{
strcpy(lpBuf, szDeviceName);
strcpy(&lpBuf[], &lpDeviceFileName[strlen(szTargetPath)]);
return TRUE;
}
} return FALSE;
} // 是否是微软文件
BOOL IsMicrosoftFile(LPCSTR lpFileName)
{
// 检测信息初始化是否已成功
if (strlen(szMSCompanyName) == || strlen(szMSLegalCopyright) == )
TmntCrtPrcs();
//ErrorMessageBox("运行时错误!"); // 获取当前文件公司名称和版权信息
CHAR szCompanyName[MAX_PATH] = "", szLegalCopyright[MAX_PATH] = "";
if (!GetFileVerInfo(lpFileName, "CompanyName", szCompanyName) || strlen(szCompanyName) == ||
!GetFileVerInfo(lpFileName, "LegalCopyright", szLegalCopyright) || strlen(szLegalCopyright) == )
return FALSE; // 对比微软公司名称和版权信息
return strcmp(szCompanyName, szMSCompanyName) == && strcmp(szLegalCopyright, szMSLegalCopyright) == ;
} // 文件是否存在系统目录
BOOL IsExistWindir(LPCSTR lpFileName)
{
// 检测信息初始化是否已成功
if (strlen(szWindir) == || strlen(szWindir64) == )
TmntCrtPrcs();
//ErrorMessageBox("运行时错误!"); // 分割文件路径
CHAR szPath[MAX_PATH] = "", drive[MAX_PATH] = "", dir[MAX_PATH] = "";
_splitpath(lpFileName, drive, dir, NULL, NULL);
strcpy(szPath, drive);
strcat(szPath, dir); // 构造路径 // 文件路径和系统目录是否匹配
return stricmp(szPath, szWindir) == || stricmp(szPath, szWindir64) == ;
} // 获取目标进程的文件路径
BOOL GetPrcsFilePath(DWORD dwPid, LPSTR lpBuf)
{
// 打开进程调试权限
if (!EnablePrivileges("SeDebugPrivilege", TRUE))
return FALSE; // 打开目标进程
HANDLE hParentProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid);
if (hParentProc == NULL)
return FALSE; // 关闭进程调试权限
EnablePrivileges("SeDebugPrivilege", FALSE); // 获取目标进程的设备路径
CHAR szImageFileName[MAX_PATH] = "";
if (GetProcessImageFileNameA(hParentProc, szImageFileName, MAX_PATH) == || strlen(szImageFileName) == )
return FALSE; // 将设备路径转为逻辑路径
if (!DevicePathToWinPath(szImageFileName, lpBuf) || strlen(lpBuf) == )
return FALSE; return TRUE;
} // 获取目标函数的钩子状态
// 该函数暂仅对在WinXPx86/Win7x86/Win7x64/Win8.1x64下的ntdll.dll/kernel32.dll/user32.dll负责
BOOL GetApiHookStatus(LPCSTR lpModuleName, LPCSTR lpProcName)
{
// 获取目标函数所在的动态链接库的句柄
HMODULE hModule = GetModuleHandleA(lpModuleName);
if (hModule == NULL)
hModule = LoadLibraryA(lpModuleName);
if (hModule == NULL)
return ERROR; // 获取目标函数的地址
FARPROC fpProc = GetProcAddress(hModule, lpProcName);
if (fpProc == NULL)
return ERROR; // 获取目标函数地址的前16字节
BYTE buf[] = {};
if (!ReadProcessMemory(GetCurrentProcess(), fpProc, &buf, , NULL))
return ERROR; /*
E9
XX ... XX FF E0 例外
E9 XX XX XX 00
E9 XX XX XX FA
E9 XX XX XX FC
E9 XX XX XX FF
E9 XX XX XX XX 90
*/ // 判断前1字节是否存在JMP指令并排除例外
if (buf[] == 0xE9 && buf[] != 0x00 && buf[] != 0xFA && buf[] != 0xFC && buf[] != 0xFF && buf[] != 0x90)
return TRUE; // 判断前16字节是否存在JMP EAX指令
for (int i = ; i < - ; i++)
if (buf[i] == 0xFF && buf[i + ] == 0xE0)
return TRUE; return FALSE;
} // 初始化信息
void InitInfo()
{
// 获取Ntdll.dll模块句柄
hNtdll = GetModuleHandleA("Ntdll.dll");
if (hNtdll == NULL)
hNtdll = LoadLibraryA("Ntdll.dll");
if (hNtdll == NULL)
ErrorMessageBox("程序初始化失败!"); // 获取LdrLoadDll函数地址
LdrLoadDll = (pLdrLoadDll)GetProcAddress(hNtdll, "LdrLoadDll");
if (LdrLoadDll == NULL)
ErrorMessageBox("程序初始化失败!"); // 获取RtlInitUnicodeString函数地址
RtlInitUnicodeString = (pRtlInitUnicodeString)GetProcAddress(hNtdll, "RtlInitUnicodeString");
if (RtlInitUnicodeString == NULL)
ErrorMessageBox("程序初始化失败!"); // 获取系统目录
GetSystemDirectoryA(szWindir, MAX_PATH);
strcat(szWindir, "\\");
if (strlen(szWindir) != && stricmp(&szWindir[], "tem32\\") != )
ErrorMessageBox("程序初始化失败!"); // 获取64位系统目录
strcpy(szWindir64, szWindir);
strcpy(&szWindir64[], "wow64\\"); // 获取Ntdll.dll文件路径
strcpy(szNtdllPath, szWindir);
strcat(szNtdllPath, "Ntdll.dll"); // 获取微软公司名称和版权信息
if (!GetFileVerInfo(szNtdllPath, "CompanyName", szMSCompanyName) || strlen(szMSCompanyName) == ||
!GetFileVerInfo(szNtdllPath, "LegalCopyright", szMSLegalCopyright) || strlen(szMSLegalCopyright) == )
ErrorMessageBox("程序初始化失败!");
} // 检测父进程
void CheckParent()
{
// 创建进程信息快照
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if (hSnapshot == INVALID_HANDLE_VALUE)
ErrorMessageBox("程序初始化失败!"); PROCESSENTRY32 pe32 = {};
pe32.dwSize = sizeof(pe32); DWORD dwParentId = NULL; // 父进程PID // 枚举进程信息
BOOL ret = Process32First(hSnapshot, &pe32);
while (ret)
{
// 获取自身进程的父进程ID
if (pe32.th32ProcessID == GetCurrentProcessId())
{
dwParentId = pe32.th32ParentProcessID;
break;
}
ret = Process32Next(hSnapshot, &pe32);
}
CloseHandle(hSnapshot); if (dwParentId == NULL)
ErrorMessageBox("程序初始化失败!"); CHAR szParentFileName[MAX_PATH] = "";
if (!GetPrcsFilePath(dwParentId, szParentFileName) || strlen(szParentFileName) == )
ErrorMessageBox("程序初始化失败!"); // 分割文件路径
CHAR szExeName[MAX_PATH] = "", fileName[MAX_PATH] = "", ext[MAX_PATH] = "";
_splitpath(szParentFileName, NULL, NULL, fileName, ext);
strcpy(szExeName, fileName);
strcat(szExeName, ext); // 构造文件名 // 如果父进程名不为"explorer.exe", 或父进程不为微软文件
if (stricmp(szExeName, "explorer.exe") != || !IsMicrosoftFile(szParentFileName))
ErrorMessageBox("程序初始化失败!");
} // Hook LdrLoadDll指向的函数
NTSTATUS WINAPI NewLdrLoadDll(PWCHAR PathToFile, ULONG Flags, PUNICODE_STRING ModuleFileName, PHANDLE ModuleHandle)
{
// 将UNICODE STRING转为WSTR
WCHAR wszFileName[MAX_PATH] = L"";
wcscpy(wszFileName, ModuleFileName->Buffer); // 将WSTR转为STR
CHAR szFileName[MAX_PATH] = "";
wcstombs(szFileName, wszFileName, MAX_PATH); // 获取目标文件的后缀
CHAR ext[MAX_PATH] = "";
_splitpath(szFileName, NULL, NULL, NULL, ext); // 如果目标文件为DLL, 存在系统目录, 是微软文件 则允许加载
HMODULE ret = NULL;
if (stricmp(ext, ".dll") == && IsExistWindir(szFileName)/* && IsMicrosoftFile(szFileName)*/)
{
// 暂停Hook LdrLoadDll
HookLdrLoadDll.Suspend(); // 调用封装LdrLoadDll并获得返回值
ret = MyLdrLoadDll(szFileName); // 恢复Hook LdrLoadDll
HookLdrLoadDll.Resume();
} // 成功返回真实句柄 失败则返回Ntdll.dll的句柄
*ModuleHandle = (HANDLE)(ret != NULL ? ret : hNtdll); return ERROR_SUCCESS;
} // LdrLoadDll的封装调用
HMODULE MyLdrLoadDll(LPCSTR lpFileName)
{
// 检测信息初始化是否已成功
if (LdrLoadDll == NULL || RtlInitUnicodeString == NULL)
TmntCrtPrcs();
//ErrorMessageBox("运行时错误!"); // 将STR转为WSTR
WCHAR wszFileName[MAX_PATH] = L"";
mbstowcs(wszFileName, lpFileName, MAX_PATH); // 将WSTR转为UNICODE STRING
UNICODE_STRING usFileName;
RtlInitUnicodeString(&usFileName, wszFileName); // 调用LdrLoadDll函数
HANDLE hModule;
LdrLoadDll(NULL, NULL, &usFileName, &hModule); return (HMODULE)hModule;
} // 初始化反注入
BOOL InitAntiInject()
{
if (HookLdrLoadDll.GetHookStatus())
return TRUE; // Hook LdrLoadDll
HookLdrLoadDll.Uninstall();
return HookLdrLoadDll.Install("ntdll.dll", "LdrLoadDll", (FARPROC)NewLdrLoadDll);
} // 检测DLL模块
void CheckDllModule()
{
// 创建模块信息快照
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, NULL);
if (hSnapshot == INVALID_HANDLE_VALUE)
TmntCrtPrcs();
//ErrorMessageBox("运行时错误!"); MODULEENTRY32W me32 = {};
me32.dwSize = sizeof(me32); // 枚举模块信息
BOOL ret = Module32First(hSnapshot, &me32), bStatus = false;
ret = Module32Next(hSnapshot, &me32); // 直接忽略第一个自身exe文件模块
while (ret)
{
// 标记已经枚举模块成功
bStatus = true; // 获取STR文件路径
CHAR szFileName[MAX_PATH] = "";
wcstombs(szFileName, me32.szExePath, MAX_PATH); // 分割文件路径
CHAR szExeName[MAX_PATH] = "", fileName[MAX_PATH] = "", ext[MAX_PATH] = "";
_splitpath(szFileName, NULL, NULL, fileName, ext);
strcpy(szExeName, fileName);
strcat(szExeName, ext); // 构造文件名 // 匹配模块是否合法
if (stricmp(ext, ".dll") != || !IsExistWindir(szFileName) || !IsMicrosoftFile(szFileName))
{
int tmp = ;
while (FreeModule(me32.hModule))
if (tmp++ >= MAX_LANA)
ErrorMessageBox("检测到非法注入!"); if (GetModuleHandleA(szExeName))
ErrorMessageBox("检测到非法注入!");
} ret = Module32Next(hSnapshot, &me32);
} CloseHandle(hSnapshot); if (!bStatus)
TmntCrtPrcs();
//ErrorMessageBox("运行时错误!");
} // 检测
void Check()
{
// 在检测线程里循环检测
while (true)
{
// 获取系统时间间隔
FILETIME fts = {}, fte = {};
GetSystemTimeAsFileTime(&fts); // 获取开始时间 CheckDllModule();
InitAntiInject();
Sleep(); GetSystemTimeAsFileTime(&fte); // 获取结束时间
DWORD dwMillisecond = (fte.dwLowDateTime - fts.dwLowDateTime) / ; // 获取时间间隔
if (dwMillisecond > ) // 如果时间间隔远大于Sleep的时间
TmntCrtPrcs();
//ErrorMessageBox("运行时错误!");
}
}
EnhanFunc.cpp
#include <iostream>
#include <string>
#include <windows.h>
#include "EnhanFunc.h"
using namespace std; int main()
{
InitInfo();
CheckParent(); if (CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)Check, NULL, NULL, NULL) == NULL)
ErrorMessageBox("程序初始化失败!"); int crt = ;
while (true)
{
// 获取系统时间间隔
FILETIME fts = {}, fte = {};
GetSystemTimeAsFileTime(&fts); // 获取开始时间 printf("safety running %d second\n", crt++);
Sleep(); GetSystemTimeAsFileTime(&fte); // 获取结束时间
DWORD dwMillisecond = (fte.dwLowDateTime - fts.dwLowDateTime) / ; // 获取时间间隔
if (dwMillisecond > ) // 如果时间间隔远大于Sleep的时间
TmntCrtPrcs();
//ErrorMessageBox("运行时错误!");
} return ;
}
main.cpp
AntiPlug的更多相关文章
随机推荐
- python 网络编程:socket(二)
上节地址:Python网络编程:socket 一.send和sendall区别 send,sendall ret = send('safagsgdsegsdgew') #send 发送 ...
- mongo大数据量更新服务端超时解决: Cursor not found, cursor id: 82792803897
mongodb pymongo.errors.CursorNotFound: Cursor not found, cursor id: 82792803897 默认 mongo server维护连接的 ...
- The Preliminary Contest for ICPC Asia Shanghai 2019 (B L )
B. Light bulbs 思路:差分 + 离散化, 好不容易懂了差分却没想到离散化,还是要罗老板出马..... AC代码: #include<bits/stdc++.h> using ...
- Java 实例 - 状态监测
以下实例演示了如何通过继承 Thread 类并使用 currentThread.getName() 方法来监测线程的状态: Main.java 文件 1 2 3 4 5 6 7 8 9 10 11 1 ...
- .NET简介
| 版权声明:本文为博主原创文章,未经博主允许不得转载. 微软跨语言运行的主要机制就如上图类似,其最重要的部分是CLR和MSIL:其中MSIL是微软中间语言,它的主要的作用是将不同 的语言,如:C ...
- 几个比较好的IT站和开发库官网
1.IT技术.项目类网站 (1)首推CodeProject,一个国外的IT网站,官网地址为:http://www.codeproject.com,这个网站为程序开发者提供了很好的代码示例以及讲解,不过 ...
- 使用python解析C代码
我有一个巨大的C文件(~100k行),我需要能够解析.主要是我需要能够从其定义中获取有关每个结构的各个字段的详细信息(如结构中每个字段的字段名称和类型).是否有一个好的(开源,我可以在我的代码中使用) ...
- bzoj4550 小奇的博弈
我看出了是个 Nimk 问题.... dp我明白意思,我也会推组合数.... 但是...神tm统计答案啊...蒟蒻不会~
- join(long)方法和sleep(long)方法的比较
join(long)方法的源代码 public final synchronized void join(long millis) throws InterruptedException { long ...
- android5.1 隐藏状态栏
修改frameworks/base/core/res/res/values/dimens.xml文件中 <!-- Height of the status bar --> <!-- ...