反插件工程

 #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的更多相关文章

随机推荐

  1. AcWing 241. 楼兰图腾 (树状数组)打卡

    题目:https://www.acwing.com/problem/content/description/243/ 题意:给你n个点,问你 V 和  ^的图腾有多少个 思路:比如V 其实就是找当前点 ...

  2. http中请求协议 GET和POST两种基本请求方法的区别

    GET和POST是什么?HTTP协议中的两种发送请求的方法. HTTP是什么?HTTP是基于TCP/IP的关于数据如何在万维网中如何通信的协议. HTTP的底层是TCP/IP.所以GET和POST的底 ...

  3. (转)Android Studio解决unspecified on project app resolves to an APK archive which is not supported

    出现该问题unspecified on project app resolves to an APK archive which is not supported as a compilation d ...

  4. Mac Office2016 安装及破解

    一.安装包下载地址 http://officecdn.microsoft.com/sg/C1297A47-86C4-4C1F-97FA-950631F94777/OfficeMac/Microsoft ...

  5. javscript 实现iframe加载内容页出现LOADING效果

    <div id="load" align="center"> <img src="http://sc.cnwebshow.com/u ...

  6. StaticInjectorError[Http]:

    报错:AppComponent.html:28 ERROR Error: StaticInjectorError[Http]: StaticInjectorError[Http]: 解决方法:

  7. 【足迹C++primer】47、Moving Objects(2)

    版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/cutter_point/article/details/37954805 Moving Object ...

  8. Python之向函数传递元组和字典

    也可以在函数定义时加上这两个参数用以接收多余的参数哦~

  9. Go 语言变量、常量

    变量 第一种,指定变量类型,声明后若不赋值,使用默认值. var v_name v_type v_name = value 第二种,根据值自行判定变量类型. var v_name = value 第三 ...

  10. 每天一个Linux常用命令 cat命令

    在Linux系统中,cat命令是一个文本输出命令,通常用来查看某个文档的内容.它有如下三个功能: 1.一次性显示整个文件 如:查看/etc/initab文件,可以使用命令:cat/etc/initta ...