【Windows系统编程】04.动态库与静态库(详解远线程注入dll)-笔记

都符合PE结构

静态库(lib)

引用lib:

需要头文件和lib文件在当前项目文件夹中

#include "StaticLib1.h"

项目属性-链接器-输入:附加依赖项:加入lib文件

#pragma comment(lib,"路径")

然后直接调用静态库中的函数了.

动态库(dll)

创建动态链接库:

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;
}

附加到进程的时候,会先弹出对话框(不用导出,只要加载,就会执行)

  • 被动加载:

远线程注入DLL

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是如何实现的:

    1. 首先,我们打开了指定的进程(也就是我们要注入的进程)
    2. 然后,在打开的进程中,使用VirtualAllocEx API,申请一段内存,注意这里的内存属性为PAGE_READWRITE(可读可写)这里的内存用于保存我们要注入的dll文件路径
    3. 我们使用WriteProcessMemory API,将我们要注入的文件路径写入进程内存,参数(我们打开的进程句柄,写入我们刚申请的内存,要注入的dll文件路径,要写入的字符串长度,返回实际写入的长度)
    4. 之后,我们创建远程线程(也就是跨进程创建线程)参数(我们刚打开的(也就是要注入的进程)句柄,NULL,NULL,强转为LPTHREAD_START_ROUTINE的LoadLibraryW API,lpAddr,NULL,NULL);
    5. 等待线程执行结束
    6. 关闭无关句柄
  • 重点:

    为什么我们能够使用这种方式注入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)){
    //这里添加操作
  }
}

MFC动态链接库

只有一个入口点

优势:创建界面非常快

你可能感兴趣的:(Windows系统编程,windows,笔记,安全)