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的更多相关文章
随机推荐
- 极限IO优化
namespace IO{ #define BUF_SIZE 100000 #define OUT_SIZE 100000 #define ll long long //fread->read ...
- python join函数
join()函数 语法: 'sep'.join(seq) 参数说明sep:分隔符.可以为空seq:要连接的元素序列.字符串.元组.字典上面的语法即:以sep作为分隔符,将seq所有的元素合并成一个新 ...
- C# Winform版批量压缩图片程序
需求 上周,领导给我分配了一个需求:服务器上的图片文件非常大,每天要用掉两个G的大小的空间,要做一个自动压缩图片的工具处理这些大图片.领导的思路是这样的: 1)打开一个图片,看它的属性里面象素是多少, ...
- oracle服务端导出/导入方式expdp/impdp
1. expdp导出步骤 1.1 用sys管理员登录sqlplus [root@hxjk_test_mysql_redis_file oracle]# sqlplus SQL*Plus: Releas ...
- windows下Mysql5.7表名不区分大小写问题
前言 Windwos文件系统本身是不区分大小写的,但是Linux文件系统是支持大小写的.于是安装在Linux下的Mysql导出到windows下可能因为大小写问题导致错误,因此要开启window下My ...
- 个人笔记 - C++相关收藏
一.文件操作 1.C++从txt文件中读取二维的数组
- STL中六大组件
1)容器(Container),是一种数据结构,如list,vector,和deques ,以模板类的方法提供.为了访问容器中的数据,可以使用由容器类输出的迭代器: 容器(container)用于存放 ...
- Python List reverse() 与list[::-1]
reverse() https://www.runoob.com/python/att-list-reverse.html list[::-1] https://blog.csdn.net/usern ...
- vue中nextTick的使用
最近使用vue的vm.$nextTick的用法比较多,现在整理一下它的用法. 推荐阅读:http://www.ruanyifeng.com/blog/2014/10/event-loop.html ...
- JSON工具类的构建(后端版本)
前言 在前后端交互的选择上,之前一直采用的是模板引擎(因为我只负责后端). 而这次的一个算是作业吧,前后端都是我,所以就研究了一下JSON交互在java web的应用(主要是前端). 优缺点 前后端耦 ...