目录

1、动态链接库

(1)静态链接库

(2)动态链接库

(3)隐式链接

2、注入

(1)远程线程

(2)远程线程注入

(3)进程间的通信

(4)模块隐藏

(5)代码注入


1、动态链接库

(1)静态链接库

1、编写静态链接库文件

<1> 在 vs2019 中创建新项目,项目类型:静态库

<2> 在项目中创建 xxxx.h 和 xxxx.cpp , 编写代码,然后生成即可

<3> 在项目目录中会生成 xxxx.lib 文件

2、静态链接库的使用

方法一:将生成的 xxxx.h xxxx.lib 文件复制到项目根目录,然后在代码中引用

 

方法二在VS的项目设置中指定 xxxx.lib 文件的位置。右键单击项目,选择 Properties(属性),然后选择左侧 VC++目录 选项卡,编辑右侧 库目录 选项,把  xxxx.lib 文件所在目录添加进来

添加完成后,右击项目中的 引用,选择 添加引用 ,把刚才的 xxxx.lib 文件添加到引用中

3、静态链接库的缺点

  • 使用静态链接生成的可执行文件体积较大( 静态库会合并到 exe 文件中)
  • 包含相同的公共代码(如果多个程序引用同一个静态库,每个程序都将有一个静态库的副本),造成资源浪费

 

(2)动态链接库

1、什么是动态链接库

  • 动态链接库 Dynamic Link Library ,缩写为 DLL )
  • 动态链接库 是微软公司在微软 Windows 操作系统中,实现共享函数库概念的一种方式
  • 这些库函数的扩展名是 dllocx ( 包含 ActiveX 控制的库 )

2、创建动态链接库,使用 _declspec(dllexport)   

  • 在 vs2019 中创建新项目,项目类型:动态库
  • 在项目中创建 xxxx.h 和 xxxx.cpp ,编写代码,然后生成即可

  • 导出表

 

3、extern "C" _declspec(dllexport) 

<1> _declspec(dllexport)

_declspec(dllexport):将一个函数声名为导出函数,就是说这个函数要被其他程序调用,即作为DLL的一个对外函数接口1. 通常与 extern "C" 合用,形式如下:extern "C" _declspec(dllexport) 返回类型 调用约定 函数名();    // 以 C语言编译2. 这是由于在制作DLL导出函数时由于C++存在函数重载,因此 _declspec(dllexport) fun(int,int) 在DLL中会被decorate3. 如被decorate成为:fun_int_int,而且不同编译器decorate的方法不同,造成使用GetProcAddress获取 fun地址时的不便4. 使用 extern "C" 时,上述的 decorate不会发生,因为C没有函数重载,如此一来被 extern"C" 修饰的函数,就不具备重载能力

<2> 以下内容摘自 MSDN

1. 在 32位编译器版本中,可以使用 _declspec(dllexport) 关键字从 DLL导出数据、函数、类或类成员函数2. _declspec(dllexport) 将导出指令添加到对象文件(obj文件)3. 若要导出函数, _declspec(dllexport) 关键字必须出现在调用约定关键字的左边(如果指定了关键字)例如:_declspec(dllexport) void _cdecl Fun(void);4. 若要导出类中的所有公共数据成员和成员函数,关键字必须出现在类名的左边,如下所示:class __declspec(dllexport) CExampleExport : public CObject{ ... class definition ... };5. 生成 DLL 时,通常创建一个包含正在导出的函数原型和头文件,并将 _declspec(dllexport) 添加到头文件中的声明6. 若要提高代码的可读性,请为 _declspec(dllexport) 定义一个宏并对正在导出的每个符号使用该宏:#define DllExport _declspec( dllexport )

<3> _declspec(dllexport) 与 .def

模块定义文件(.def)是包含一个或多个描述各种 DLL属性的 Module 语句的文本文件1. 二者的目的都是将公共符号导入到应用程序中或从 DLL 导出函数2. 添加 _declspec(dllexport) 是为了不使用 .def文件,从 .EXE 或 .DLL 导出函数3. 如果不使用 _declspec(dllimport) 或 _declspec(dllexport) 导出 DLL 函数,则 DLL 需要.def文件4. 并不是任何时候选择添加 _declspec(dllexport) 而放弃 .def 的方式都是好的5. 如果DLL是提供给VC++用户使用的,只需要把编译DLL时产生的.lib提供给用户,它可以很轻松地调用你的DLL6. 但是如果DLL是供VB、PB、Delphi用户使用,那么会产生一个小麻烦因为VC++对于 _declspec(dllexport) 声明的函数会进行名称转换如下面的函数:_declspec(dllexport) int _stdcall fun()  会转换为 fun@0 ,这样你在VB中必须这样声明:Declare Function fun Lib "my.dll" Alias "fun@0" () As Long@ 后面的数由于参数类型不同而可能不同,这显然不太方便,所以如果要想避免这种转换,就要使用.def文件方式

4、dllexe 的区别

  • dllexe 都是一个模块,dll 为其他模块提供函数和数据
  • 每个 模块 存在一张导出表,导出表记录了 模块包含的函数名,dll 一定有导出表,exe 不一定有导出表
  • dllexe 都遵循 PE文件结构,dll 与 exe 本质上没有区别,exe 也可以为别的模块提供 函数和数据

5、使用 .def 文件创建 dll

  • 新建 .def 文件,在 .def 文件中 指定需要导出的函数

  • 生成 dll

  • 查看导出表 ( 使用 def 文件,可以达到隐藏函数的目的 
  • 序号 12 对应十六进制的 C 13 对应十六进制的 D

6、使用动态链接库

  • dll 放到项目的根目录 (显示链接
#include <stdio.h>
#include <Windows.h>// 定义函数指针
typedef int(__stdcall* lpPlus)(int, int);
typedef int(__stdcall* lpSub)(int, int);// 声明函数指针变量			
lpPlus myPlus;
lpSub mySub;int main() {
// 动态加载dll到内存中					HINSTANCE hModule = LoadLibrary(TEXT("动态库.dll"));// 获取函数地址myPlus = (lpPlus)GetProcAddress(hModule, "plus");		// 传入 函数名mySub = (lpSub)GetProcAddress(hModule, (char*)0xD);		// 传入 序号// 调用函数int a = myPlus(10, 2);int b = mySub(10, 2);// 释放动态链接库(将 dll从进程空间移除)				FreeLibrary(hModule);return 0;
}

 

(3)隐式链接

1、隐式链接

  • 将  dll  lib 放到项目的根目录
  • 静态库的 lib 文件包含代码,动态库的 lib 文件不包含代码,只包含描述性的信息
  • #pragma comment(lib,"xxxx.lib")  添加到调用文件中 
  • 加入函数的声明 (只有 dll,没有 lib,则只能使用显示链接)
  • 好处:不用获取函数地址
// 隐式链接
#pragma comment(lib,"动态库.lib")
// 加入函数的声明
// DLL 如果使用 _declspec(dllexport) 导出函数,函数声明需要加上 extern "C"
// 使用 def 文件导出函数,则不需要
_declspec(dllimport) int _stdcall plus(int x, int y);
_declspec(dllimport) int _stdcall sub(int x, int y);int main() {int x = plus(1, 2);int y = sub(4, 2);return 0;
}
  • 注意
// 导出函数
extern "C" _declspec(dllexport) 返回类型 调用约定 函数名 (参数列表);// 导入函数
extern "C" _declspec(dllimport) 返回类型 调用约定 函数名 (参数列表);  

2、隐式链接的实现

  • dll 拥有导出表,表中记录了当前模块提供了哪些函数
  • 使用隐式链接生成的 exe 文件,一定拥有导入表,表中记录了当前模块需要使用 哪些 dll 和 dll 中的哪些函数
  • dll 也拥有导入表, exe文件不一定拥有导出表

3、dll 的优点

  1. dll 不会把自己代码合并到 exe 文件中
  2. 对 dll 文件进行修改,不会影响其他进程(写拷贝)

4DllMain 函数

  • dll 和 exe 的入口函数和执行时间不同
  • exe 从 main 函数开始执行,dll 从 DllMain 开始执行
  • DllMain 可能执行多次
BOOL APIENTRY DllMain(HMODULE hModule,               // 当前 dll 被加载到哪个模块DWORD   ul_reason_for_call,    // reason for calling functionLPVOID  lpReserved             // reserved
)/*
DllMain 被调用的四种情况DLL_PROCESS_ATTACH: 某个进程第一次执行 LoadLibrary加载 dll到内存,会调用 DllMain函数DLL_PROCESS_DETACH: 某个进程调用 FreeLibrary释放 dll时,会调用 DllMain函数DLL_THREAD_ATTACH : 当前进程的另一个线程执行 LoadLibrary又加载了一次 dll,会调用 DllMainDLL_THREAD_DETACH : 当前进程的另一个线程执行结束,会调用 DllMain
*/
  • 示例代码
// 定义 DLL 应用程序的入口点,模拟不同调用情况
BOOL APIENTRY DllMain( HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{switch (ul_reason_for_call){case DLL_PROCESS_ATTACH:OutputDebugString(TEXT("1. DLL_PROCESS_ATTACH\n"));break;case DLL_THREAD_ATTACH:OutputDebugString(TEXT("2. DLL_THREAD_ATTACH\n"));break;case DLL_THREAD_DETACH:OutputDebugString(TEXT("3. DLL_THREAD_DETACH\n"));break;case DLL_PROCESS_DETACH:OutputDebugString(TEXT("4. DLL_PROCESS_DETACH\n"));break;}return TRUE;
}// main.cpp
DWORD WINAPI ThreadProc(LPVOID lpThreadParameter) {HINSTANCE hModule = LoadLibrary(TEXT("动态库.dll"));return 0;
}int main() {// 动态加载 dll到内存中					HINSTANCE hModule = LoadLibrary(TEXT("动态库.dll"));// 获取函数地址// 调用函数// 创建新线程,加载 dllCreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);getchar();                      // 阻塞 main线程,让新线程执行// 释放动态链接库		FreeLibrary(hModule);return 0;
}

 

2、注入

(1)远程线程

1、线程

  • 线程是附属在进程上的执行实体,是 代码的执行流程
  • 代码必须通过线程才能执行

2、创建远程线程

  • 函数原型
// 在别的进程中,创建新线程
HANDLE CreateRemoteThread(HANDLE hProcess,                                // 进程句柄LPSECURITY_ATTRIBUTES lpThreadAttributes,       // SDSIZE_T dwStackSize,                             // initial stack sizeLPTHREAD_START_ROUTINE lpStartAddress,          // thread functionLPVOID  lpParameter,                            // thread argumentDWORD   dwCreationFlags,                        // creation optionLPDWORD lpThreadId                              // thread identifier
);HANDLE OpenProcess(DWORD dwDesiredAccess,        // 访问权限BOOL  bInheritHandle,         // 是否继承DWORD dwProcessId             // 进程 id
);
  • 代码示例

(1) 空项目.cpp

DWORD WINAPI ThreadProc(LPVOID lpThreadParameter) {for (int i = 0; i < 10; i++) {Sleep(1000);printf("fun-------------\n");}return 0;
}int main() {
// 创建 A线程,执行 ThreadProcHANDLE hThread = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);CloseHandle(hThread);getchar();      // 阻塞 main线程return 0;
}

(2)远程线程.cpp

// 在 空项目.exe 中创建 B线程,执行 ThreadProc
#include <stdio.h>
#include <Windows.h>// dwProcessId:进程 id,要在哪个进程中创建线程
// dwProcAddr:线程需要执行的函数
BOOL MyCreateRemoteThread(DWORD dwProcessId, DWORD dwProcAddr) {
// 1.获取进程句柄HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);if (hProcess == NULL) {OutputDebugString(TEXT("获取进程句柄失败\n"));return FALSE;}// 2.创建远程线程DWORD dwThreadId = 0;HANDLE hThread = CreateRemoteThread(hProcess,NULL,0, (LPTHREAD_START_ROUTINE)dwProcAddr,NULL,0, &dwThreadId);if (hThread == NULL) {CloseHandle(hProcess);OutputDebugString(TEXT("创建远程线程失败\n"));return FALSE;}// 3.释放资源CloseHandle(hThread);CloseHandle(hProcess);return true;
}int main() {
/*1. 第一个参数:进程 id,通过任务管理器获取2. 第二个参数:需要提供 空项目.exe 中存在的线程函数的地址在 ThreadProc函数入口处下断点,通过反汇编代码查看函数的地址
*/MyCreateRemoteThread(39808, 0x891740);return 0;
}

3、总结

  • 通过 CreateRemoteThread 函数,我们可以在其他进程中创建一个新线程,并调用该进程中包含的函数

 

(2)远程线程注入

1、什么是注入?

  • 所谓注入就是在第三方进程不知道或者不允许的情况下将 模块 或者 代码 写入对方进程空间,并设法执行的技术
  • 已知的注入方式:远程线程注入APC注入、消息钩子注入、注册表注入、导入表注入、输入法注入等等

2、远程线程注入的流程

/*线程函数和 Dll 装载函数具有相同的形式:参数 4字节,返回值 4字节两者都可以作为线程函数,被线程执行
*/
DWORD WINAPI ThreadProc(LPVOID lpThreadParameter
)HMODULE LoadLibraryA(LPCSTR lpLibFileName
);

3、注入并执行代码

  • 动态库.dll DllMain 函数 (注入 dll 后,通过 DllMain 函数执行代码)
DWORD WINAPI ThreadProc(LPVOID lpThreadParameter) {while (true) {Sleep(1000);printf("动态库.dll 代码执行-------------\n");}return 0;
}// 当进程首次加载 dll,循环打印输出
// 执行 LoadLibrary 会调用 DllMain 函数
BOOL APIENTRY DllMain( HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{switch (ul_reason_for_call){case DLL_PROCESS_ATTACH:CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);break;case DLL_THREAD_ATTACH:  break;case DLL_THREAD_DETACH:  break;case DLL_PROCESS_DETACH: break;}return TRUE;
}
  • 空项目.exe 代码参考:( 空项目.cpp
  • 远程线程注入代码
// 参数:进程 id、 dll的完整路径名
BOOL LoadDll(DWORD dwProcessId, const char* szDllPathName) {BOOL bRet;HANDLE hProcess, hThread;DWORD dwLength, dwLoadAddr;LPVOID lpAllocAddr, dwThreadId;HMODULE hModule;// 1.获取进程句柄hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);if (hProcess == NULL) {OutputDebugString(TEXT("获取进程句柄失败\n"));return FALSE;}// 2.计算 DLL路径名字长度,并且要加上 0结尾的长度dwLength = strlen(szDllPathName) + 1;// 3.在目标进程分配内存// 1. VirtualAlloc   只能在自己进程中申请内存// 2. VirtualAllocEx 可以在别的进程中申请分配内存lpAllocAddr = VirtualAllocEx(hProcess, NULL, dwLength, MEM_COMMIT, PAGE_READWRITE);if (lpAllocAddr == NULL) {CloseHandle(hProcess);OutputDebugString(TEXT("内存分配失败\n"));return FALSE;}// 4.拷贝 Dll到目标进程的内存空间bRet = WriteProcessMemory(hProcess, lpAllocAddr, szDllPathName, dwLength, NULL);if (!bRet) {CloseHandle(hProcess);OutputDebugString(TEXT("写入进程失败\n"));return FALSE;}// 5.获取模块地址hModule = GetModuleHandle(TEXT("kernel32.dll"));if (!hModule) {CloseHandle(hProcess);OutputDebugString(TEXT("获取模块地址失败\n"));return FALSE;}// 6.获取 LoadLibraryA 函数地址dwLoadAddr = (DWORD)GetProcAddress(hModule, "LoadLibraryA");if (!dwLoadAddr) {CloseHandle(hModule);CloseHandle(hProcess);OutputDebugString(TEXT("获取函数地址失败\n"));return FALSE;}// 7.创建远程线程,加载 dllhThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)dwLoadAddr, lpAllocAddr, 0, NULL);if (!hThread) {CloseHandle(hModule);CloseHandle(hProcess);OutputDebugString(TEXT("创建远程线程失败\n"));return FALSE;}// 8.关闭进程句柄CloseHandle(hProcess);return TRUE;
}int main() {LoadDll(9300,"D:\\VS2019\\动态库\\Debug\\动态库.dll");return 0;
}
  • 使用 OD 查找 LoadLibraryA 函数的地址
  1. LoadLibraryA 位于 kernel32.dll 中,任意一个 exe 的执行都需要包含这个 dll
  2. 所以我们用OD打开 扫雷.exe,选择 E(Executable Modules),双击 kernel32.dll,使用 ctrl + N ,查看此 dll 包含的函数

 

(3)进程间的通信

1、通信方式

  • 同一台电脑 两个进程的通信方式:管道、消息队列、信号量、共享内存 (本质上都是共享内存)
  • 不同的电脑 两个进程的通信方式:套接字

2、共享内存的通信方式

  • 模拟游戏.cpp
void Q() {printf("----- 斩钢闪 -------\n"); return;
}
void W() {printf("----- 风之障壁 -----\n"); return;
}
void E() {printf("----- 踏前斩 -------\n"); return;
}
void R() {printf("----- 狂风绝息斩 ---\n"); return;
}int main() {printf("----- 游戏开始 -----\n");while (true) {char c = getchar();switch (c) {case 'Q': Q(); break;case 'W': W(); break;case 'E': E(); break;case 'R': R(); break;}}return 0;
}
  • 控制游戏.dll
#define _MAP_  "共享内存"
#define _Q_    0x6417A0
#define _W_    0x641860
#define _E_    0x641740
#define _R_    0x641800HANDLE g_hModule, g_hMapFile;
LPTSTR lpBuff;
DWORD dwType;DWORD WINAPI ThreadProc(LPVOID lpParameter) {g_hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, TEXT(_MAP_));if (g_hMapFile == NULL) {printf("打开映射文件失败:%d\n", GetLastError());return 0;}// 映射内存lpBuff = (LPTSTR)MapViewOfFile(g_hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, BUFSIZ);while (true) {if (lpBuff != NULL) {// 读取数据CopyMemory(&dwType, lpBuff, 4);}if (dwType == 1) {_asm {mov eax,_Q_call eax}dwType = 0;  CopyMemory(lpBuff, &dwType, 4);}if (dwType == 2) {_asm {mov eax, _W_call eax}dwType = 0;  CopyMemory(lpBuff, &dwType, 4);}if (dwType == 3) {_asm {mov eax, _E_call eax}dwType = 0;  CopyMemory(lpBuff, &dwType, 4);}if (dwType == 4) {_asm {mov eax, _R_call eax}dwType = 0;  CopyMemory(lpBuff, &dwType, 4);}if (dwType == 5) {// 卸载自己并退出FreeLibraryAndExitThread((HMODULE)g_hModule, 0);}Sleep(500);}return 0;
}BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{g_hModule = hModule;switch (ul_reason_for_call){case DLL_PROCESS_ATTACH:CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);break;case DLL_THREAD_ATTACH:  break;case DLL_THREAD_DETACH:  break;case DLL_PROCESS_DETACH: break;}return TRUE;
}
  • 注入dll.cpp
#include <stdio.h>
#include <Windows.h>
#include <TlHelp32.h>
#define _MAP_ "共享内存"HANDLE g_hMapFile;
LPTSTR lpBuff;// 参数:进程 id、 dll的完整路径名
BOOL LoadDll(DWORD dwProcessId, const char* szDllPathName) {// 代码参考:远程线程注入
}BOOL init() {// 创建事件、创建共享内存g_hMapFile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 0x1000, TEXT(_MAP_));if (g_hMapFile == NULL) {printf("创建映射文件失败\n");return FALSE;}// 映射内存lpBuff = (LPTSTR)MapViewOfFile(g_hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, BUFSIZ);if (lpBuff == NULL) {printf("关联文件失败\n");return FALSE;}return TRUE;
}DWORD GetPid(CONST WCHAR* szName) {HANDLE hProcessSnap = NULL;PROCESSENTRY32 pe32 = { 0 };hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);if (hProcessSnap == (HANDLE)-1) {return 0;}pe32.dwSize = sizeof(PROCESSENTRY32);if(Process32First(hProcessSnap,&pe32)) {do {if (!wcscmp(szName, pe32.szExeFile)) {return (int)pe32.th32ProcessID;}} while (Process32Next(hProcessSnap, &pe32));}elseCloseHandle(hProcessSnap);return 0;
}int main() {DWORD dwCtrlCode, dwOrdeList[10];// 1.初始化 2.注入 DLLif(init())LoadDll(GetPid(L"模拟游戏.exe"), "D:\\VS2019\\游戏控制\\Debug\\游戏控制.dll");// 3.命令队列dwOrdeList[0] = 1;  dwOrdeList[1] = 1;  dwOrdeList[2] = 2;dwOrdeList[3] = 2;  dwOrdeList[4] = 3;  dwOrdeList[5] = 3;dwOrdeList[6] = 4;  dwOrdeList[7] = 4;  dwOrdeList[8] = 4;  dwOrdeList[9] = 5;for (int i = 0; i < 10; i++) {dwCtrlCode = dwOrdeList[i];CopyMemory(lpBuff, &dwCtrlCode, 4);Sleep(1000);}return 0;
}
  • FreeLibrary                                     卸载某个某块,不能卸载自己
  • FreeLibraryAndExitThread            卸载模块,可以卸载自己

 

(4)模块隐藏

1、TEB 和 PEB

  • TEB(Thread Environment Block ),它记录的相关线程的信息,每一个线程都有自己的TEB,FS:[0] 即是当前线程的TEB
  • PEB(Process Environment Block,进程环境块)存放进程信息,每个进程都有自己的PEB,TEB偏移 0x30 即当前进程的PEB
  • TEB 与 PEB 都在用户空间(用户层结构体)

2、获取 TEB 结构体的步骤

(1)用 OD 打开 扫雷.exe,打开后会在 winmine.exe 模块 处发生中断,此时 TEB的地址存储在 FS 寄存器

(2)使用 dd 命令跳转到对应的内存地址,该地址存储着当前线程的 TEB 对象

(3)TEB 结构体图解

续:

(4)在OD中解析 TEB 结构体:双击入口地址,查看内存的相对偏移量

(4)使用代码获取 TEB 首地址

// 使用汇编代码,将首地址存入 eax中mov eax,fs:[0]

 

3、获取 PEB 结构体的步骤

(1)TEB 结构体首地址偏移 0x30 的内存地址,存放着 PEB 的首地址

(2)在 OD 中右键此地址,Fllow in Dump 找到 PEB 的首地址(和 dd 命令效果相同)

(3)win32API 可以遍历当前进程所有的模块,实际上这些 API查询的是 PEB的 Ldr 成员

(4)在 PEB 结构体首地址偏移 0x0C 的内存地址,Fllow in Dump,找到 _PEB_LDR_DATA 结构体

(5)在 _PEB_LDR_DATA 结构体的 0x0C 偏移处,Fllow in Dump,找到 _LDR_DATA_TABLE_ENTRY 结构体

(6)结构体图解

  • PEB 和 _PEB_LDR_DATA

  • PEB续

  • _LDR_DATA_TABLE_ENTRY

(7)使用代码获取 PEB

mov eax,fs:[0x30]mov PEB,eax

4、代码示例

// 通过断链的方式,可以使通过 Win32API 查询模块的方式失效
typedef struct _UNICODE_STRING {USHORT Length;USHORT MaximumLength;PWSTR  Buffer;
} UNICODE_STRING,*PUNICODE_STRING;typedef struct _PEB_LDR_DATA {ULONG       Length;BOOLEAN     Initialized;PVOID       SsHandle;LIST_ENTRY  InLoadOrderModuleList;LIST_ENTRY  InMemoryOrderModuleList;LIST_ENTRY  InInitializationOrderModuleList;
} PEB_LDR_DATA, *PPEB_LDR_DATA;typedef struct _LDR_DATA_TABLE_ENTRY {LIST_ENTRY		InLoadOrderModuleList;LIST_ENTRY		InMemoryOrderModuleList;LIST_ENTRY		InInitializationOrderModuleList;void*			BaseAddress;				// 模块的句柄void*		    EntryPoint;ULONG           SizeOfImage;UNICODE_STRING  FullDllName;UNICODE_STRING  BaseDllName;ULONG           Flags;SHORT           LoadCount;SHORT           TlsIndex;HANDLE          SectionHandle;ULONG           CheckSum;ULONG           TimeBaseStamp;
} LDR_MODULE, *PLDR_MODULE;void HideModule(CONST WCHAR* szModuleName) {HMODULE hMod = ::GetModuleHandle(szModuleName);PLIST_ENTRY Head, Cur;		// 双链表PPEB_LDR_DATA ldr;PLDR_MODULE ldm;_asm {mov eax, fs:[0x30]mov ecx, [eax+0x0c]mov ldr, ecx}Head = &(ldr->InLoadOrderModuleList);Cur = Head->Flink;do {// 宏 CONTAINING_RECORD 根据结构体中的某成员的地址来推算处该结构体整体的地址ldm = CONTAINING_RECORD(Cur, LDR_MODULE, InLoadOrderModuleList);if (hMod == ldm->BaseAddress) {// 双向链表断链ldm->InLoadOrderModuleList.Blink->Flink = ldm->InLoadOrderModuleList.Flink;ldm->InLoadOrderModuleList.Flink->Blink = ldm->InLoadOrderModuleList.Blink;ldm->InInitializationOrderModuleList.Blink->Flink = ldm->InInitializationOrderModuleList.Flink;ldm->InInitializationOrderModuleList.Flink->Blink = ldm->InInitializationOrderModuleList.Blink;ldm->InMemoryOrderModuleList.Blink->Flink = ldm->InMemoryOrderModuleList.Flink;ldm->InMemoryOrderModuleList.Flink->Blink = ldm->InMemoryOrderModuleList.Blink;break;}Cur = Cur->Flink;} while (Head != Cur);
}int main() {printf("按任意键隐藏模块\n");getchar();HideModule(L"kernel32.dll");printf("隐藏已模块\n");getchar();return 0;
}

5、内核层 —— VAD树

  • 遍历 VAD树(是一棵搜索二叉树)可以查询当前进程虚拟内存占用情况
  • VAD树 每个成员都是一个结构体,其中包含指针成员指向 dll 的名称
  • 把指针置空,VAD树 遍历也无法找到对应的 dll

6、模块隐藏之 PE指纹

  • 任何模块都有 PE 指纹

  1. 先找前2个字节,对应的值是 MZ
  2. 在找第 64个字节,对应的值为 D8
  3. 再找第 0xD8 个字节,对应的值为 PE,这就是一个 PE指纹,说明该内存地址中存放着一个模块
  • 通过 PE指纹找模块
  1. 遍历程序内存,如果找到 MZ 字符,则加上第64字节存放的偏移量
  2. 在对应偏移处存放的是 PE 字符,则说明该处存放着一个模块
  3. 将 PE指纹 置0,可监控 LoadLibrary 函数的调用,仍能发现模块的载入

7、最好的隐藏:代码注入

 

(5)代码注入

1、代码注入的思路

  • 将自己定义的函数复制到进程内存空间

  • 复制到目标进程的内容

将想要执行函数的 机器码 复制到目标进程的内存空间

  • 复制代码的编写原则
// 不能有全局变量int g;int Fun(int x.int y){g = 1;C7 05 38 A1 46 00 01       mov  dword ptr [g (046A138h)],1return x+y;}// 不能使用常量字符串int Fun(int x.int y){char* c = (char*)"china";C7 45 F8 D0 7B E9 00       mov  dword ptr [c],offset string "china" (0E97BD0h)return x+y;}// 不能使用系统调用( Win32API )// 导入表 会告诉编译器 MessageBox 的地址,在目标进程的导入表中 MessageBox 可能不存在int Fun(int x.int y){MessageBox(0,0,0,0);8B F4                mov       esi,esp  6A 00                push      0  6A 00                push      0  6A 00                push      0  6A 00                push      0  FF 15 98 B0 34 00    call      dword ptr [__imp__MessageBoxW@16 (034B098h)]  3B F4                cmp       esi,esp  E8 D8 FA FF FF       call      __RTC_CheckEsp (0341217h)return x+y;}// 不能嵌套调用其他函数int Fun(int x, int y) {Test();// E8 52 FC FF FF       call      Test (042137Fh)return x + y;}

2、向目标进程复制函数,并传递参数

3、代码示例

#include <stdio.h>
#include <Windows.h>typedef struct {// CreateFile 函数的地址DWORD   dwCreateAPIAddr;// CreateFile 函数的参数LPCSTR  lpFileName;DWORD   dwDesireAccess;DWORD   daShareMode;LPSECURITY_ATTRIBUTES lpSecurityAttributes;DWORD   dwCreationDispositon;DWORD   dwFlagsAndAttributes;HANDLE  hTemplateFile;
} CREATEFILE_PARAM;// CreateFile的函数指针
typedef HANDLE(WINAPI* PFN_CreateFile)(LPCSTR  lpFileName,DWORD   dwDesireAccess,DWORD   daShareMode,LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD   dwCreationDispositon,DWORD   dwFlagsAndAttributes,HANDLE  hTemplateFile
);// 要复制到目标进程的函数,参数:结构体指针
DWORD _stdcall CreateFileThreadProc(LPVOID lParam) {CREATEFILE_PARAM* Gcreate = (CREATEFILE_PARAM*)lParam;// 获取 CreateFile函数地址PFN_CreateFile pfnCreateFile= (PFN_CreateFile)Gcreate->dwCreateAPIAddr;pfnCreateFile(Gcreate->lpFileName,Gcreate->dwDesireAccess,Gcreate->daShareMode,Gcreate->lpSecurityAttributes,Gcreate->dwCreationDispositon,Gcreate->dwFlagsAndAttributes,Gcreate->hTemplateFile);return 0;
}// 远程创建文件
BOOL RemotCreateFile(DWORD dwProcessID, char* szFilePathName) {BOOL     bRet = 0;DWORD    dwThread;HANDLE   hProcess = 0;HANDLE   hThread;DWORD    dwThreadFunSize = 0x400;CREATEFILE_PARAM GCreateFile;LPVOID   lpFilePathName;LPVOID   lpRemotThreadAddr;LPVOID   lpFileParamAddr;DWORD    dwFunAddr;HMODULE  hModule;// 1.获取进程句柄hProcess = OpenProcess(PROCESS_AFFINITY_ENABLE_AUTO_UPDATE, FALSE, dwProcessID);if (hProcess == NULL)    return FALSE;// 2.分配3段内存:存储参数、线程函数、文件// 2.1用来存储文件名lpFilePathName = VirtualAllocEx(hProcess, NULL, strlen(szFilePathName) + 1, MEM_COMMIT, PAGE_READWRITE);// 2.2用来存储线程函数lpRemotThreadAddr = VirtualAllocEx(hProcess, NULL, dwThreadFunSize, MEM_COMMIT, PAGE_READWRITE);// 2.3用来存储参数lpFileParamAddr = VirtualAllocEx(hProcess, NULL, sizeof(CREATEFILE_PARAM), MEM_COMMIT, PAGE_READWRITE);// 3.初始化 CreateFile 参数GCreateFile.dwDesireAccess = GENERIC_READ | GENERIC_WRITE;GCreateFile.daShareMode = 0;GCreateFile.lpSecurityAttributes = NULL;GCreateFile.dwCreationDispositon = OPEN_ALWAYS;GCreateFile.dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;GCreateFile.hTemplateFile = NULL;// 4.获取 CreateFile 函数地址hModule = LoadLibrary(TEXT("kernel32.dll"));GCreateFile.dwCreateAPIAddr = (DWORD)GetProcAddress(hModule, "CreaeteFileA");FreeLibrary(hModule);// 5.初始化 CreateFile 文件名,文件名存储在目标进程的内存空间GCreateFile.lpFileName = (LPSTR)lpFilePathName;// 6.修正线程函数起始地址// 6.1在 main中调用的函数地址,与真正的函数地址有一个 jmp 指令dwFunAddr = (DWORD)CreateFileThreadProc;if (*(BYTE*)dwFunAddr == 0xE9) {dwFunAddr = dwFunAddr + 5 + *(DWORD*)(dwFunAddr + 1);}// 7.开始复制// 7.1拷贝文件名WriteProcessMemory(hProcess, lpFilePathName, szFilePathName, strlen(szFilePathName) + 1, 0);// 7.2拷贝线程函数WriteProcessMemory(hProcess, lpRemotThreadAddr, (LPVOID)dwFunAddr, dwThreadFunSize, 0);// 7.3拷贝线程参数WriteProcessMemory(hProcess, lpFileParamAddr, &GCreateFile, sizeof(CREATEFILE_PARAM), 0);// 8.创建远程线程hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)lpRemotThreadAddr,lpFileParamAddr, 0, &dwThread);// 9.关闭进程句柄CloseHandle(hProcess);return TRUE;
}int main() {// 目标进程创建文件后,要等待目标进程关闭,创建的文件才能删除RemotCreateFile(160, (char*)"D:\\a.txt");return 0;
}

4、修正线程函数起始地址

void Test(){
// 此处才是真实的函数地址,所以要进行修正000A1700   55                   push        ebp  000A1701   8B EC                mov         ebp,esp  000A1703   81 EC C0 00 00 00    sub         esp,0C0h  000A1709   53                   push        ebx  000A170A   56                   push        esi  000A170B   57                   push        edi  000A170C   8D BD 40 FF FF FF    lea         edi,[ebp-0C0h]  000A1712   B9 30 00 00 00       mov         ecx,30h  000A1717   B8 CC CC CC CC       mov         eax,0CCCCCCCCh  000A171C   F3 AB                rep stos    dword ptr es:[edi]  000A171E   B9 15 C0 0A 00       mov         ecx,offset _43B7F706_源@cpp (0AC015h)  000A1723   E8 E0 FA FF FF       call        @__CheckForDebuggerJustMyCode@4 (0A1208h)return;  000A1728   5F                   pop         edi  000A1729   5E                   pop         esi  000A172A   5B                   pop         ebx  000A172B   81 C4 C0 00 00 00    add         esp,0C0h  000A1731   3B EC                cmp         ebp,esp  000A1733   E8 DF FA FF FF       call        __RTC_CheckEsp (0A1217h)  000A1738   8B E5                mov         esp,ebp  000A173A   5D                   pop         ebp  000A173B   C3                   ret  
}int main() {Test();000A1768    E8 12 FC FF FF       call   Fun (0A137Fh)    
/*call 与真实的函数地址之间还有一个 jmp指令,E9是 jmp,7C是相对偏移000A137F    E9 7C 03 00 00       jmp    Test (0A1700h)000A1384 + 037C = 000A1700    
*/return 0;
}

 

 

 

查看全文
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

相关文章

  1. 十个帮助你解决CSS问题的网站

    下面是十个可以使得你的CSS更加有趣,简单并且也许可以解决多数你所遇到的CSS问题的网站。1. 像素的艺术你可能也喜欢使用像素艺术来制作你的网页。我可以说你们90%都是把像素艺术加入到png文件,但是如果怎么把它转变成CSS呢?这就是Pixel Art to CSS这个网站存在的意义了,他…...

    2024/4/10 12:34:12
  2. 问题汇总

    catkin_make指令出错:ImportError: "from catkin_pkg.topological_order import topological_order" failed: No module named catkin_pkg Make sure that you have installed "catkin_pkg", it is up to date and on the PYTHONPATH.原因时python的默认指…...

    2024/4/26 14:44:38
  3. H3C防火墙基础配置操作

    之前部署了一个虚拟防火墙,后面预计会出一个V7防火墙配置的系列专题。我一直在跟设备打交道,操作变更后都是要写入到配置文件的,简单操作也会花样出现问题,在此先介绍一下设备配置相关的基本操作。本文中所用测试设备:F1060(R9313P11)、F1070(R9313P18)、HCL F1060(A…...

    2024/4/10 12:34:10
  4. KMP 与字典树

    KMP 算法 概述 KMP 算法全称是 Knuth-Morris-Pratt 字符串查找算法,是用于在一个字符串(匹配串)中查找另一个字符串(模式串)的快速算法 KMP算法会在匹配前预处理模式串 PPP 得到 fail 数组, 借助 fail 数组,可以在匹配过程中减少很多冗余的操作,时间复杂度 : O(n+m)\ma…...

    2024/4/26 5:33:59
  5. 主存与CPU的连接

    主存与CPU的连接 1.存储器芯片的基本结构2.主存容量扩展-位扩展3.主容量扩展-字扩展4.主存容量扩展-译码器5.线选法和译码片选法对比6.字位同时扩展7.总结...

    2024/4/10 12:34:08
  6. 微擎模块开发-微擎小程序商城分类页面分类跳转至商品分类列表页详解(后端篇)

    相对于上节课的内容这节课想就行简单的不少,不过设计思路都是一样的,不过这个把这4次循环都写在了不同接口里,思路更明确。商城分类页面分类数据展示category.wxml <view class="rec-cate"><block wx:for="{{ categorySonId }}" wx:key=id>…...

    2024/4/10 12:34:09
  7. Spring Boot 2.x基础教程:使用Spring Data JPA访问MySQL

    在数据访问这章的第一篇文章《Spring中使用JdbcTemplate访问数据库》 中,我们已经介绍了如何使用Spring Boot中最基本的jdbc模块来实现关系型数据库的数据读写操作。那么结合Web开发一章的内容,我们就可以利用JDBC模块与Web模块的功能,综合着使用来完成一个适用于很多简单应…...

    2024/4/12 21:14:18
  8. 理论+实验·正则表达式与文本处理器===>grep,egrep,sed,awk,sort,uniq,tr

    理论+实验正则表达式与文本处理器 文章目录理论+实验正则表达式与文本处理器正则表达式概述正则表达式的定义正则表达式用途基础正则表达式---grep查找特定字符利用中括号“[]”来查找集合字符查找行首“^”与行尾字符“$”查找任意一个字符“.”与重复字符“*”查找连续字符范…...

    2024/4/10 12:41:23
  9. Django_CBV

    ...

    2024/4/10 12:41:22
  10. leetcode【每日一题】329. 矩阵中的最长递增路径 Java

    题干 给定一个整数矩阵,找出最长递增路径的长度。 对于每个单元格,你可以往上,下,左,右四个方向移动。 你不能在对角线方向上移动或移动到边界外(即不允许环绕)。 示例 1: 输入: nums = [[9,9,4],[6,6,8],[2,1,1] ] 输出: 4 解释: 最长递增路径为 [1, 2, 6, 9]。示例…...

    2024/4/24 12:27:31
  11. UG编程入门实战详解,带你快速了解UG编程的实现

    这里的编程并不是软件开发的编程,而是指数控机床的加工程序编制。将产品设计及加工过程实现数字化作业,利用UG等三维设计软轻松实现各种复杂实体及造型的建构、分析、制造、装配和检测工作,极大地提高了设计效率和准确性,缩短产品开发周期、提高产品质量、降低生产成本的同…...

    2024/4/25 4:15:22
  12. 虚幻4.25新建C++项目时编译失败

    问题:UE4.25新建C++项目时编译失败,显示???文件。 原因:无法识别中文项目名称。 解决:将项目名称改为英文数字等字母。...

    2024/4/10 12:41:19
  13. leetcode79. 单词搜索

    1、题目 https://leetcode-cn.com/problems/word-search/ 2、题意 题解1:递归回溯 ps:将走过的点标记为’.’ 进行特判 以免其重复走 class Solution { public:int dx[4] = {0,0,1,-1},dy[4] = {1,-1,0,0};bool dfs(vector<vector<char>>& board, string&…...

    2024/4/10 12:41:19
  14. 对公平锁、非公平锁、可重入锁、递归锁、自旋锁的理解

    本篇文章主要是记录自己的学习笔记,主要内容是:公平锁、非公平锁、可重入锁、递归锁、自旋锁的理解,并实现一个自旋锁。 一、公平和非公平锁 (1)公平锁和非公平锁是什么? 公平锁:是指多个线程按照申请锁的顺序来获取锁,类似排队打饭,先来后到。 非公平锁:是指多个线程…...

    2024/4/21 4:51:28
  15. Spring Cloud构建微服务架构(一)服务注册与发现

    Spring Cloud简介 Spring Cloud是一个基于Spring Boot实现的云应用开发工具,它为基于JVM的云应用开发中的配置管理、服务发现、断路器、智能路由、微代理、控制总线、全局锁、决策竞选、分布式会话和集群状态管理等操作提供了一种简单的开发方式。 Spring Cloud包含了多个子项…...

    2024/4/10 12:41:16
  16. Windows AD域用户属性对照表(综合整理)

    “常规”标签 姓 Sn 名 Givename 英文缩写 Initials 显示名称 displayName 描述 Description 办公室 physicalDeliveryOfficeName 电话号码 telephoneNumber 电话号码:其它 otherTelephone 多个以英文分号分隔 电子邮件 Mail 网页 wWWHomePage 网页:其它 url 多个…...

    2024/4/26 23:33:48
  17. 招贤纳士

    简介 前不久,我在Github上新建了一个团队 筑梦者 ,专注于Python开发与交流。但是由于是新团队,项目和成员都不多,我们期待你的加入! 优势 在这里,你可以学到更多,我们的氛围和谐平等,所有软件均为开源的,你所做的一切,也是为开源事业做出贡献! 目标 我们当下的目标是…...

    2024/4/25 12:15:41
  18. Springboot2入门阶段一

    Springboot2 1.使用maven构建项目 IDEA新建一个maven项目,创建好在pom.xml中添加依赖: <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLS…...

    2024/4/27 6:27:29
  19. 解决-冀时办(河北健康码)有一天忘记打卡

    (1)修改手机时间,哪天忘记打卡就把手机时间调到哪天 (2)打开支付宝搜索“河北健康码”,选择国家政务服务平台 (3)选择防疫健康信息码服务 (4)选择您已领取立即查看你 (5)每日健康打卡,今日未打卡点开 (6)打卡提交 (7)手机调回正常时间登录微信冀时办查看...

    2024/4/10 12:41:12
  20. 全网最全的Qt下载途径(多种下载通道+所有版本)

    本文转载自:http://c.biancheng.net/view/3851.htmlQt 体积很大,有 1GB~3GB,官方下载通道非常慢,相信很多读者会崩溃,所以建议大家使用国内的镜像网站(较快),或者使用迅雷下载(很快)。作为 Qt 下载教程,本文会同时讲解以上三种下载方式。 Qt 官方下载(非常慢) Qt …...

    2024/4/27 13:38:17

最新文章

  1. 【Java EE】Spring核心思想(一)——IOC

    文章目录 &#x1f38d;Spring 是什么&#xff1f;&#x1f384;什么是IoC呢&#xff1f;&#x1f338;传统程序开发&#x1f338;传统程序开发的缺陷&#x1f338;如何解决传统程序的缺陷&#xff1f;&#x1f338;控制反转式程序开发&#x1f338;对比总结 &#x1f332;理解…...

    2024/4/27 21:20:33
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/3/20 10:50:27
  3. 网络驱动器设备:ISCSI服务器

    文章目录 使用ISCSI服务部署网络存储ISCSI技术介绍创建RAID磁盘整列配置ISCSI服务端配置Windows端配置Linux客户端iSCSI服务器CHAP单向认证配置Linux端具体步骤Windows端具体步骤 使用ISCSI服务部署网络存储 主机名IPISCSI服务端192.168.200.10ISCSI客户端192.168.200.20Windo…...

    2024/4/27 9:20:19
  4. 汽车疲劳测试试验平台技术要求(北重厂家)

    汽车疲劳测试试验平台技术要求通常包括以下几个方面&#xff1a; 车辆加载能力&#xff1a;测试平台需要具备足够的承载能力&#xff0c;能够同时测试多种车型和不同重量的车辆。 动力系统&#xff1a;测试平台需要具备稳定可靠的动力系统&#xff0c;能够提供足够的力和速度来…...

    2024/4/27 20:00:22
  5. CTK插件框架学习-事件监听(04)

    CTK插件框架学习-插件注册调用(03)https://mp.csdn.net/mp_blog/creation/editor/136989802 一、主要流程 发送者注册消息事件接收者订阅消息事件接收者相应消息事件 事件监听比插件接口调用耦合性更弱&#xff0c;事件由框架维护&#xff0c;不需要指定发送方和接收方 二、…...

    2024/4/25 1:44:38
  6. 416. 分割等和子集问题(动态规划)

    题目 题解 class Solution:def canPartition(self, nums: List[int]) -> bool:# badcaseif not nums:return True# 不能被2整除if sum(nums) % 2 ! 0:return False# 状态定义&#xff1a;dp[i][j]表示当背包容量为j&#xff0c;用前i个物品是否正好可以将背包填满&#xff…...

    2024/4/27 1:53:53
  7. 【Java】ExcelWriter自适应宽度工具类(支持中文)

    工具类 import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellType; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet;/*** Excel工具类** author xiaoming* date 2023/11/17 10:40*/ public class ExcelUti…...

    2024/4/27 3:39:11
  8. Spring cloud负载均衡@LoadBalanced LoadBalancerClient

    LoadBalance vs Ribbon 由于Spring cloud2020之后移除了Ribbon&#xff0c;直接使用Spring Cloud LoadBalancer作为客户端负载均衡组件&#xff0c;我们讨论Spring负载均衡以Spring Cloud2020之后版本为主&#xff0c;学习Spring Cloud LoadBalance&#xff0c;暂不讨论Ribbon…...

    2024/4/27 12:24:35
  9. TSINGSEE青犀AI智能分析+视频监控工业园区周界安全防范方案

    一、背景需求分析 在工业产业园、化工园或生产制造园区中&#xff0c;周界防范意义重大&#xff0c;对园区的安全起到重要的作用。常规的安防方式是采用人员巡查&#xff0c;人力投入成本大而且效率低。周界一旦被破坏或入侵&#xff0c;会影响园区人员和资产安全&#xff0c;…...

    2024/4/27 12:24:46
  10. VB.net WebBrowser网页元素抓取分析方法

    在用WebBrowser编程实现网页操作自动化时&#xff0c;常要分析网页Html&#xff0c;例如网页在加载数据时&#xff0c;常会显示“系统处理中&#xff0c;请稍候..”&#xff0c;我们需要在数据加载完成后才能继续下一步操作&#xff0c;如何抓取这个信息的网页html元素变化&…...

    2024/4/27 3:39:08
  11. 【Objective-C】Objective-C汇总

    方法定义 参考&#xff1a;https://www.yiibai.com/objective_c/objective_c_functions.html Objective-C编程语言中方法定义的一般形式如下 - (return_type) method_name:( argumentType1 )argumentName1 joiningArgument2:( argumentType2 )argumentName2 ... joiningArgu…...

    2024/4/27 3:39:07
  12. 【洛谷算法题】P5713-洛谷团队系统【入门2分支结构】

    &#x1f468;‍&#x1f4bb;博客主页&#xff1a;花无缺 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 花无缺 原创 收录于专栏 【洛谷算法题】 文章目录 【洛谷算法题】P5713-洛谷团队系统【入门2分支结构】&#x1f30f;题目描述&#x1f30f;输入格…...

    2024/4/27 3:39:07
  13. 【ES6.0】- 扩展运算符(...)

    【ES6.0】- 扩展运算符... 文章目录 【ES6.0】- 扩展运算符...一、概述二、拷贝数组对象三、合并操作四、参数传递五、数组去重六、字符串转字符数组七、NodeList转数组八、解构变量九、打印日志十、总结 一、概述 **扩展运算符(...)**允许一个表达式在期望多个参数&#xff0…...

    2024/4/27 12:44:49
  14. 摩根看好的前智能硬件头部品牌双11交易数据极度异常!——是模式创新还是饮鸩止渴?

    文 | 螳螂观察 作者 | 李燃 双11狂欢已落下帷幕&#xff0c;各大品牌纷纷晒出优异的成绩单&#xff0c;摩根士丹利投资的智能硬件头部品牌凯迪仕也不例外。然而有爆料称&#xff0c;在自媒体平台发布霸榜各大榜单喜讯的凯迪仕智能锁&#xff0c;多个平台数据都表现出极度异常…...

    2024/4/27 21:08:20
  15. Go语言常用命令详解(二)

    文章目录 前言常用命令go bug示例参数说明 go doc示例参数说明 go env示例 go fix示例 go fmt示例 go generate示例 总结写在最后 前言 接着上一篇继续介绍Go语言的常用命令 常用命令 以下是一些常用的Go命令&#xff0c;这些命令可以帮助您在Go开发中进行编译、测试、运行和…...

    2024/4/26 22:35:59
  16. 用欧拉路径判断图同构推出reverse合法性:1116T4

    http://cplusoj.com/d/senior/p/SS231116D 假设我们要把 a a a 变成 b b b&#xff0c;我们在 a i a_i ai​ 和 a i 1 a_{i1} ai1​ 之间连边&#xff0c; b b b 同理&#xff0c;则 a a a 能变成 b b b 的充要条件是两图 A , B A,B A,B 同构。 必要性显然&#xff0…...

    2024/4/27 18:40:35
  17. 【NGINX--1】基础知识

    1、在 Debian/Ubuntu 上安装 NGINX 在 Debian 或 Ubuntu 机器上安装 NGINX 开源版。 更新已配置源的软件包信息&#xff0c;并安装一些有助于配置官方 NGINX 软件包仓库的软件包&#xff1a; apt-get update apt install -y curl gnupg2 ca-certificates lsb-release debian-…...

    2024/4/27 3:39:03
  18. Hive默认分割符、存储格式与数据压缩

    目录 1、Hive默认分割符2、Hive存储格式3、Hive数据压缩 1、Hive默认分割符 Hive创建表时指定的行受限&#xff08;ROW FORMAT&#xff09;配置标准HQL为&#xff1a; ... ROW FORMAT DELIMITED FIELDS TERMINATED BY \u0001 COLLECTION ITEMS TERMINATED BY , MAP KEYS TERMI…...

    2024/4/27 13:52:15
  19. 【论文阅读】MAG:一种用于航天器遥测数据中有效异常检测的新方法

    文章目录 摘要1 引言2 问题描述3 拟议框架4 所提出方法的细节A.数据预处理B.变量相关分析C.MAG模型D.异常分数 5 实验A.数据集和性能指标B.实验设置与平台C.结果和比较 6 结论 摘要 异常检测是保证航天器稳定性的关键。在航天器运行过程中&#xff0c;传感器和控制器产生大量周…...

    2024/4/27 13:38:13
  20. --max-old-space-size=8192报错

    vue项目运行时&#xff0c;如果经常运行慢&#xff0c;崩溃停止服务&#xff0c;报如下错误 FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory 因为在 Node 中&#xff0c;通过JavaScript使用内存时只能使用部分内存&#xff08;64位系统&…...

    2024/4/27 1:03:20
  21. 基于深度学习的恶意软件检测

    恶意软件是指恶意软件犯罪者用来感染个人计算机或整个组织的网络的软件。 它利用目标系统漏洞&#xff0c;例如可以被劫持的合法软件&#xff08;例如浏览器或 Web 应用程序插件&#xff09;中的错误。 恶意软件渗透可能会造成灾难性的后果&#xff0c;包括数据被盗、勒索或网…...

    2024/4/27 3:22:12
  22. JS原型对象prototype

    让我简单的为大家介绍一下原型对象prototype吧&#xff01; 使用原型实现方法共享 1.构造函数通过原型分配的函数是所有对象所 共享的。 2.JavaScript 规定&#xff0c;每一个构造函数都有一个 prototype 属性&#xff0c;指向另一个对象&#xff0c;所以我们也称为原型对象…...

    2024/4/26 21:29:56
  23. C++中只能有一个实例的单例类

    C中只能有一个实例的单例类 前面讨论的 President 类很不错&#xff0c;但存在一个缺陷&#xff1a;无法禁止通过实例化多个对象来创建多名总统&#xff1a; President One, Two, Three; 由于复制构造函数是私有的&#xff0c;其中每个对象都是不可复制的&#xff0c;但您的目…...

    2024/4/27 3:39:00
  24. python django 小程序图书借阅源码

    开发工具&#xff1a; PyCharm&#xff0c;mysql5.7&#xff0c;微信开发者工具 技术说明&#xff1a; python django html 小程序 功能介绍&#xff1a; 用户端&#xff1a; 登录注册&#xff08;含授权登录&#xff09; 首页显示搜索图书&#xff0c;轮播图&#xff0…...

    2024/4/26 23:53:24
  25. 电子学会C/C++编程等级考试2022年03月(一级)真题解析

    C/C++等级考试(1~8级)全部真题・点这里 第1题:双精度浮点数的输入输出 输入一个双精度浮点数,保留8位小数,输出这个浮点数。 时间限制:1000 内存限制:65536输入 只有一行,一个双精度浮点数。输出 一行,保留8位小数的浮点数。样例输入 3.1415926535798932样例输出 3.1…...

    2024/4/27 20:28:35
  26. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  27. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  28. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  29. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  30. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  31. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  32. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  33. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  34. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  35. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  36. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  37. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  38. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  39. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  40. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  41. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  42. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  43. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  44. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  45. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57