都符合PE结构
引用lib:
需要头文件和lib文件在当前项目文件夹中
#include "StaticLib1.h"
项目属性-链接器-输入:附加依赖项:加入lib文件
#pragma comment(lib,"路径")
然后直接调用静态库中的函数了.
创建动态链接库:
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH: //附加到进程的时候触发事件
break;
case DLL_THREAD_ATTACH: //附加到线程的时候触发事件
break;
case DLL_THREAD_DETACH: //进程剥离的时候触发事件
break;
case DLL_PROCESS_DETACH: //线程剥离的时候触发事件
break;
}
return TRUE;
}
添加头文件,声明函数;
#include
void show(const char* szBuffer);
导出:
_declspec(dllexport)void show(const char* szBuffer);
这种方式导出函数,会触发名称粉碎机制
extern"C"或EXTERN_C _declspec(dllexport)void show(const char* szBuffer);
这种方式导出函数,不会触发名称粉碎机制
添加模块定义文件
LIBRARY
EXPORTS
show
这种方式导出函数,不会触发名称粉碎机制
名称粉碎机制
C++独有
调用动态链接库:
把头文件粘贴到项目文件夹中(不粘贴也可以)
#include
typedef void(*MyShow)(const char* szBuffer);
int main()
{
HMODULE hDll = LoadLibrary(L"Dll1.dll");
//在某个动态链接库中找到函数地址
MyShow func = (MyShow)GetProcAddress(hDll,"Show");
func("WdIg");
FreeLibrary(hDll);
return 0;
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH: //附加到进程的时候触发事件
MessageBox(NULL,L"加载模块","rkvir",MB_OK);
break;
case DLL_THREAD_ATTACH: //附加到线程的时候触发事件
break;
case DLL_THREAD_DETACH: //进程剥离的时候触发事件
break;
case DLL_PROCESS_DETACH: //线程剥离的时候触发事件
break;
}
return TRUE;
}
附加到进程的时候,会先弹出对话框(不用导出,只要加载,就会执行)
void Inject(DWORD PID, const WCHAR * szBuffer)
{
//打开进程
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, PID);
//在进程内存中申请一段内存
LPVOID lpAddr = VirtualAllocEx(hProcess, NULL, MAX_PATH, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
//向内存中写入要注入的dll文件路径
SIZE_T dwWrittenSize = 0;
WriteProcessMemory(hProcess, lpAddr, szBuffer, (wcslen(szBuffer) + 1) * 2, &dwWrittenSize);
//创建远程线程
HANDLE hThread = CreateRemoteThread(hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibraryW, lpAddr, NULL, NULL);
WaitForSingleObject(hThread, -1);
VirtualFreeEx(hProcess, lpAddr, 0, MEM_RELEASE);
CloseHandle(hProcess);
CloseHandle(hThread);
}
我们来分析一下这里的注入dll是如何实现的:
重点:
为什么我们能够使用这种方式注入dll呢?创建远程现成的时候,不是要提供线程回调函数吗?我们来深究一下:
我们先来看看CreateRemoteThread API原型:
CreateRemoteThread(
_In_ HANDLE hProcess,
_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
_In_ SIZE_T dwStackSize,
_In_ LPTHREAD_START_ROUTINE lpStartAddress,
_In_opt_ LPVOID lpParameter,
_In_ DWORD dwCreationFlags,
_Out_opt_ LPDWORD lpThreadId
);
其他参数都正常传递,我们来看看第四个参数,也就是线程回调函数
这个参数是LPTHREAD_START_ROUTINE类型的,我们跟进去:
线程回调函数的原型实际上是这样:
typedef DWORD (WINAPI *PTHREAD_START_ROUTINE)(
LPVOID lpThreadParameter
);
typedef PTHREAD_START_ROUTINE LPTHREAD_START_ROUTINE;
接下来我们再看看LoadLibraryW API:
HMODULE
WINAPI
LoadLibraryA(
_In_ LPCSTR lpLibFileName
);
我们来分析一下这俩函数:
首先,返回值,一个是DWORD,一个是HMODULE,在x86环境下,都是一个四字节整数,没有什么区别
然后,调用约定,都是WINAPI(__stdcall),也没有什么区别
最后,参数,都是需要指向一段内存,所以也没有什么区别
所以,这里的远线程注入dll,本质上就是跨进程创建一个线程,然后将LoadLibrary API当作线程回调使用了,所以就完成了注入。
#include
void ShowModule(DWORD PID){
//创建快照:
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE|TH32CS_SNAPMODULE32,PID);
MODULEENTRY32 me32 ={size0f(MODULEENTRY32)};
while(MOdule32Next(hSnap,&me32)){
//这里添加操作
}
}
只有一个入口点
优势:创建界面非常快