• [Windows编程]释放DLL资源


    作用:将dll作为资源添加到程序中,程序运行时将dll释放到指定位置。

    整体流程为:添加资源 -> 资源释放 -> 写入文件

    添加资源

    下面以Visual Studio 2015举例

    选择要导入的dll文件

    资源类型填写"DLL"

    添加完成后会生成resource.h头文件和Project4.rc资源文件

    打开resource.h头文件,可以看到定义了IDR_DLL1,这个常量后面会用到

    资源释放

    资源释放要用到4个Windows API

    // 确定模块中指定类型和名称的资源所在位置。
    HRSRC FindResourceW(
      HMODULE hModule,  // 处理包含资源的可执行文件模块,NULL表示系统从当前进程的模块中装载资源。
      LPCWSTR lpName,  // 指定资源名称,MAKEINTRESOURCE类型,这里是MAKEINTRESOURCE(IDR_DLL1)或MAKEINTRESOURCE(101),IDR_DLL1是resource.h中定义的常量。
      LPCWSTR lpType  // 指定资源类型,这里是"DLL"。
    );
    // 获取指定资源的字节数。
    DWORD SizeofResource(
      HMODULE hModule,  // 包含资源的可执行文件模块的句柄。NULL表示系统从当前进程的模块中装载资源。
      HRSRC   hResInfo  // 资源句柄。此句柄必须由函数FindResource或FindResourceEx来创建。
    );
    // 装载指定资源到全局存储器。
    HGLOBAL LoadResource(
      HMODULE hModule,  // 处理资源可执行文件的模块句柄。NULL表示系统从当前进程的模块中装载资源。
      HRSRC   hResInfo  // 资源句柄。此句柄必须由函数FindResource或FindResourceEx来创建。
    );
    // 锁定资源并得到资源在内存中第一个字节的指针。
    LPVOID LockResource(
      HGLOBAL hResData  // 装载资源的句柄。函数LoadResource可以返回这个句柄。
    );

    写入文件

    写入文件也要用到4个Windows API:

    // 从堆中分配指定数量的字节。
    DECLSPEC_ALLOCATOR HGLOBAL GlobalAlloc(
      UINT   uFlags,  // 内存分配属性。GPTR表示分配固定内存。返回值是一个指针,并将内存内容初始化为零。
      SIZE_T dwBytes  // 要分配的字节数。
    );
    // 将一块内存从一个位置复制到另一个位置。
    void CopyMemory(
      _In_       PVOID  Destination,  // 指向复制块目标起始地址的指针。
      _In_ const VOID   *Source,  // 指向要复制的内存块起始地址的指针。
      _In_       SIZE_T Length  // 要复制的内存块的大小,以字节为单位。
    );
    // 此函数创建、打开或截断文件、COM 端口、设备、服务或控制台。它返回一个句柄来访问对象。
    HANDLE CreateFile(
      LPCTSTR lpFileName,  // 要创建文件的路径。
      DWORD dwDesiredAccess,  // 访问对象的类型。GENERIC_WRITE表示对对象的写访问。数据可以写入文件,文件指针可以移动。
      DWORD dwShareMode,  // 对象的共享模式。如果此参数设置为零,则无法共享对象。对对象的后续打开操作将失败,直到句柄关闭。
      LPSECURITY_ATTRIBUTES lpSecurityAttributes,  // 未使用。
      DWORD dwCreationDisposition,  // 对存在的文件采取的行动,以及在文件不存在时采取的行动。CREATE_ALWAYS表示创建一个新文件。如果文件存在,该函数将覆盖该文件并清除现有属性。
      DWORD dwFlagsAndAttributes,  // 文件的文件属性和标志。
      HANDLE hTemplateFile  // 忽略
    );
    // 将数据写入指定的文件或输入/输出 (I/O) 设备。
    BOOL WriteFile(
      HANDLE       hFile,  //文件的句柄,该文件必须已创建且有写权限。
      LPCVOID      lpBuffer,  // 指向包含要写入文件或设备的数据的缓冲区的指针。该缓冲区必须在写操作期间保持有效。在写操作完成之前,调用者不得使用此缓冲区。
      DWORD        nNumberOfBytesToWrite,  // 要写入文件或设备的字节数。
      LPDWORD      lpNumberOfBytesWritten,  // 一个指向接收使用同步hFile参数时写入的字节数的变量的指针。
      LPOVERLAPPED lpOverlapped  // 这里是NULL。
    );

    编程实现

    可与远线程注入配合,实现只执行一个exe,不需要外部dll的dll注入。

    #include <stdio.h>
    #include <Windows.h>
    #include "resource4.h"void ShowError(char *pszText)
    {
        char szErr[MAX_PATH] = { 0 };
        ::wsprintf(szErr, "%s Error[%d]
    ", pszText, ::GetLastError());
        ::MessageBox(NULL, szErr, "ERROR", MB_OK);
    }
    ​
    bool CreateMyFile(char* strFilePath, LPBYTE lpBuffer, DWORD dwSize)
    {
        DWORD dwWritten;
    ​
        HANDLE hFile = CreateFile(strFilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
        if (hFile != NULL)
        {
            WriteFile(hFile, (LPCVOID)lpBuffer, dwSize, &dwWritten, NULL);
        }
        else
        {
            return false;
        }
        CloseHandle(hFile);
        return true;
    }
    ​
    bool CreateEXE(char* strFilePath, int nResourceID, char* strResourceName)
    {
        HRSRC hResInfo;
        HGLOBAL hResData;
        DWORD dwSize;
        LPBYTE p;
        // 查找所需的资源
        hResInfo = FindResource(NULL, MAKEINTRESOURCE(nResourceID), strResourceName);
        if (hResInfo == NULL)
        {
            MessageBox(NULL, "查找资源失败!", "错误", MB_OK | MB_ICONINFORMATION);
            return false;
        }
        // 获得资源尺寸
        dwSize = SizeofResource(NULL, hResInfo);
        // 装载资源
        hResData = LoadResource(NULL, hResInfo);
        if (hResData == NULL)
        {
            MessageBox(NULL, "装载资源失败!", "错误", MB_OK | MB_ICONINFORMATION);
            return false;
        }
        // 为数据分配空间
        p = (LPBYTE)GlobalAlloc(GPTR, dwSize);
        if (p == NULL)
        {
            MessageBox(NULL, "分配内存失败!", "错误", MB_OK | MB_ICONINFORMATION);
            return false;
        }
        // 复制资源数据
        CopyMemory((LPVOID)p, (LPCVOID)LockResource(hResData), dwSize);
    ​
        bool bRet = CreateMyFile(strFilePath, p, dwSize);
        if (!bRet)
        {
            GlobalFree((HGLOBAL)p);
            return false;
        }
    ​
        GlobalFree((HGLOBAL)p);
    ​
        return true;
    }
    ​
    BOOL CreateRemoteThreadInjectDll(DWORD dwProcessId, char *pszDllFileName)
    {
        HANDLE hProcess = NULL;
        SIZE_T dwSize = 0;
        LPVOID pDllAddr = NULL;
        FARPROC pFuncProcAddr = NULL;
    ​
        // 打开注入进程,获取进程句柄
        hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
        if (NULL == hProcess)
        {
            ShowError("OpenProcess");
            return FALSE;
        }
        // 在注入进程中申请内存
        dwSize = 1 + ::lstrlen(pszDllFileName);
        pDllAddr = ::VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);
        if (NULL == pDllAddr)
        {
            ShowError("VirtualAllocEx");
            return FALSE;
        }
        // 向申请的内存中写入数据
        if (FALSE == ::WriteProcessMemory(hProcess, pDllAddr, pszDllFileName, dwSize, NULL))
        {
            ShowError("WriteProcessMemory");
            return FALSE;
        }
        // 获取LoadLibraryA函数地址
        pFuncProcAddr = ::GetProcAddress(::GetModuleHandle("kernel32.dll"), "LoadLibraryA");
        if (NULL == pFuncProcAddr)
        {
            ShowError("GetProcAddress_LoadLibraryA");
            return FALSE;
        }
        // 使用 CreateRemoteThread 创建远线程, 实现 DLL 注入
        HANDLE hRemoteThread = ::CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pFuncProcAddr, pDllAddr, 0, NULL);
        if (NULL == hRemoteThread)
        {
            ShowError("CreateRemoteThread");
    return FALSE;
        }
    // 关闭句柄
        ::CloseHandle(hProcess);
    ​
    return TRUE;
    }
    ​
    int main()
    {
    CreateEXE("C:\Windows\System32\0409\a.dll", IDR_DLL1, "DLL");
    ​
    // 远线程注入 DLL
    BOOL bRet = CreateRemoteThreadInjectDll(9120, "C:\Windows\System32\0409\a.dll");
    ​
    if (FALSE == bRet)
        {
    printf("Inject Dll Error.
    ");
        }
    printf("Inject Dll OK.
    ");
    system("pause");
    return 0;
    }

     参考:《Windows黑客编程技术详解》

    https://blog.csdn.net/sunjikui1255326447/article/details/90520970

     

  • 相关阅读:
    STM32学习笔记之__attribute__ ((at())绝对定位分析
    CRC 自动判断大端 小端
    AT命令控制上网 PDP
    PPP PDP 及GPRS
    Renesas CAT CONFIG
    AT指令(二)
    字节对齐问题
    IntelliJ Idea 常用快捷键列表
    solr6.6 导入 文本(txt/json/xml/csv)文件
    solr6.6 导入 pdf/doc/txt/json/csv/xml文件
  • 原文地址:https://www.cnblogs.com/rnss/p/15319696.html
Copyright © 2020-2023  润新知