将dll从进程模块列表中移除并保持正常运行

/*

URL: http://hi.baidu.com/zxhouse
Email: LZX*QQ.COM

将dll从进程模块列表中移除并保持正常运行,这玩意想想是挺简单,n久前byshell就用了,
简单的思路就是给当前的dll内存映像做份拷贝,然后跳到那份拷贝的地址空间的代码,回头free掉原来的dll,
然后马上用VirtualAlloc在原基址上申请块同样大小的空间,并将那份拷贝还原回去,再跳回去执行。完。

代码写完后再实际程序中应用后发现问题,一旦调用到malloc或new的话就会崩溃,
于是去看了下byshell的代码,发现他申请内存是用VirtualAlloc,但是我大量的代码都是用new来分配,而且类对象不好用VirtualAlloc来分配吧~

经调式才清楚,原来每个dll,windows都会给其分配一个heap,
在freelibrary时系统会将其完全destroy掉,不怕你内存泄露。
调试时在FreeLibrary后HeapDestroy断点正好触发一次,就是这一次那个heap给销毁了。
解决办法就是在FreeLibrary前修改HeapDestroy的第一条指令为return,FreeLibrary后再修复。
实践证明,稳定......
*/

#include <windows.h>
#include <stdio.h>
#include <tlhelp32.h>
#include <psapi.h>

#pragma comment(lib, "Psapi.lib")
#define __printf printf
void HideLibrary(HMODULE hModule, LPVOID pCallBackAddr, LPVOID lParam);

typedef struct
{
      HMODULE lpDllBase;
      LPVOID lpNewDllBase;
      PTHREAD_START_ROUTINE pAddress;
      LPVOID lParam;
}UNLOADLIB_CALLBACK, *PUNLOADLIB_CALLBACK;

typedef
LPVOID WINAPI VIRTUALALLOC(
    LPVOID lpAddress,
    SIZE_T dwSize,
    DWORD flAllocationType,
    DWORD flProtect
);

typedef
BOOL WINAPI VIRTUALFREE(
    LPVOID lpAddress,
    SIZE_T dwSize,
    DWORD dwFreeType
);


typedef
BOOL WINAPI HEAPDESTROY(
    HANDLE hHeap
);

typedef
HMODULE WINAPI LOADLIBRARY(
    LPCTSTR lpFileName
);

typedef
HANDLE WINAPI CREATETHREAD(
    LPSECURITY_ATTRIBUTES lpThreadAttributes,
    SIZE_T dwStackSize,
    LPTHREAD_START_ROUTINE lpStartAddress,
    LPVOID lpParameter,
    DWORD dwCreationFlags,
    LPDWORD lpThreadId
);

typedef void *    __cdecl MEMCPY(void *, const void *, size_t);

BOOL incLibraryCount(HMODULE hMe)
{
      //FreeLibrary后很多系统dll也会free掉,所以将所有已加载的再load一次以增加计数
    
      HANDLE hModsSnap =    CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, 0);

      if(INVALID_HANDLE_VALUE == hModsSnap)
      {
          return FALSE;
      }

      MODULEENTRY32 meModuleEntry;
      meModuleEntry.dwSize = sizeof(MODULEENTRY32);

      if(!Module32First(hModsSnap, &meModuleEntry))
      {
          CloseHandle(hModsSnap);
          return FALSE;
      }
      do
      {
          if(LoadLibrary(meModuleEntry.szModule) == hMe)
              FreeLibrary(hMe);

      } while(Module32Next(hModsSnap, &meModuleEntry));

      CloseHandle(hModsSnap);
      return TRUE;
}

//枚举指定进程的所有线程
DWORD WINAPI EnumAndSetThreadState(LPVOID lParam)
{
      HANDLE hThreadSnap = NULL;
      THREADENTRY32 te32;
      memset(&te32,0,sizeof(te32));
      te32.dwSize = sizeof(THREADENTRY32);
      hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD,0);

      DWORD myThreadId = GetCurrentThreadId();
      DWORD pid = GetCurrentProcessId();

      if (Thread32First(hThreadSnap, &te32))
      {
          do
          {
               if (pid == te32.th32OwnerProcessID)
               {
                   if(myThreadId != te32.th32ThreadID)
                   {
                       HANDLE hThread = OpenThread(
                           THREAD_SUSPEND_RESUME,
                           FALSE,
                           te32.th32ThreadID);

                       if(hThread != NULL)
                       {
                           if((int)lParam)
                               ResumeThread(hThread);
                           else
                               SuspendThread(hThread);

                           CloseHandle(hThread);
                       }
                   }
               }
          }
          while (Thread32Next(hThreadSnap,&te32));
      }
      CloseHandle( hThreadSnap );

      return 0;
}

DWORD WINAPI GotoCallBackAddr(LPVOID lParam)
{
      PUNLOADLIB_CALLBACK cbFunc = (PUNLOADLIB_CALLBACK)lParam;

      DWORD dwThreadId;
      HANDLE hThread;

      if(cbFunc->pAddress)
      {
          hThread = CreateThread(
              NULL,
              0,
              cbFunc->pAddress,
              cbFunc->lParam,
              0,
              &dwThreadId);

          if(hThread)
              CloseHandle(hThread);
      }

      //那份dll的拷贝不需要了,释放~
      VirtualFree(cbFunc->lpNewDllBase, 0, MEM_DECOMMIT);
      delete cbFunc;
      return 0;
}

DWORD WINAPI UnLoadLibrary(LPVOID lParam)
{
      //__asm INT 3
      __printf("UnLoadLibrary Entry.\r\n");

      BYTE HeapDestroy_HookCode_bak[4];
      BYTE HeapDestroy_HookCode[4] = "\xC2\x04\x00";//RETN 0004
      MODULEINFO modinfo;
      DWORD oldProtect;

      PUNLOADLIB_CALLBACK cbFunc = (PUNLOADLIB_CALLBACK)lParam;

      HMODULE hDllInstance = cbFunc->lpDllBase;
      char dllpath_bak[MAX_PATH];

      GetModuleFileName(hDllInstance, dllpath_bak, sizeof(dllpath_bak));
      GetModuleInformation(GetCurrentProcess(), hDllInstance, &modinfo, sizeof(MODULEINFO));

      //给所有dll(除了自己)增加计数,防止FreeLibrary的时候那些dll给系统卸载掉
      incLibraryCount(hDllInstance);

      //保险起见,挂起其他线程,搞定后再恢复
      EnumAndSetThreadState((LPVOID)FALSE);

      //FreeLibrary之后原来存放api地址的内存也会被释放,
      //但是FreeLibrary之后还有些动作,趁现在还没free,关键API记下来
      VIRTUALALLOC *_VirtualAlloc = (VIRTUALALLOC*)
          GetProcAddress(GetModuleHandle("kernel32.dll"), "VirtualAlloc");
      LOADLIBRARY    *_LoadLibrary    = (LOADLIBRARY*)
          GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
      CREATETHREAD *_CreateThread = (CREATETHREAD*)
          GetProcAddress(GetModuleHandle("kernel32.dll"), "CreateThread");
      MEMCPY         *_memcpy         = (MEMCPY*)
          GetProcAddress(GetModuleHandle("ntdll.dll"), "memcpy");

      //这个很关键,并不是我要调用,是 FreeLibrary 时系统会调用,我要hook它,
      //不能给系统破坏这个heap,否则之后的dll貌似能工作,
      //但却不能用new或malloc申请内存, VirtualAlloc可以代替之,
      //但如果改写好多代码是划不来的,况且一些代码不好改,如list<T>的push内部的new

      HEAPDESTROY *_HeapDestroy    = (HEAPDESTROY*)
          GetProcAddress(GetModuleHandle("kernel32.dll"), "HeapDestroy");

      VirtualProtect(_HeapDestroy, 3, PAGE_EXECUTE_READWRITE, &oldProtect);

      //修改第一条指令为直接返回
      _memcpy(HeapDestroy_HookCode_bak, _HeapDestroy, 3);
      _memcpy(_HeapDestroy, HeapDestroy_HookCode, 3);


      //Sleep(100);
      //终于到这里了~~~^_^!
      FreeLibrary(hDllInstance);//释放

      //修复刚hook的函数
      _memcpy(_HeapDestroy, HeapDestroy_HookCode_bak, 3);
      //_memcpy(_RtlFreeHeap, RtlFreeHeap_HookCode_bak, 3);

      //在原来的dll基址申请同样大小的内存,并把之前的那份dll拷贝还原回去
      if(_VirtualAlloc(hDllInstance,
          modinfo.SizeOfImage,
          MEM_COMMIT|MEM_RESERVE,
          PAGE_EXECUTE_READWRITE) == NULL
          )
      {
          //失败,加载原来dll, 以正常方式工作
          //注意,不宜在dllmain中调用HideLibrary,LoadLibrary将导致dllmain再次被调用,导致死循环啦
          HMODULE hDll = _LoadLibrary(dllpath_bak);

          //重新计算回调函数在hDll地址空间的地址
          cbFunc->pAddress = (LPTHREAD_START_ROUTINE)
              ((DWORD)cbFunc->pAddress - (DWORD)hDllInstance + (DWORD)hDll);

          LPTHREAD_START_ROUTINE pFunc1 = (LPTHREAD_START_ROUTINE)
              ((DWORD)EnumAndSetThreadState - (DWORD)hDllInstance + (DWORD)hDll);

          //恢复被挂起的线程
          _CreateThread(0, 0, pFunc1, (LPVOID)TRUE, 0, 0);

          //调用回调函数
          if(cbFunc->pAddress)
              _CreateThread(0, 0, cbFunc->pAddress, cbFunc->lParam, 0, 0);
          return 0;
      }

      _memcpy(hDllInstance, cbFunc->lpNewDllBase, modinfo.SizeOfImage);

      //恢复被挂起的线程
      EnumAndSetThreadState((LPVOID)TRUE);
      //跳回原dll地址空间的GotoCallBackAddr,由它来释放这边VirtualAlloc申请的指针
      _CreateThread(0, 0, GotoCallBackAddr, cbFunc, 0, 0);
      return 0;
}

DWORD WINAPI HideLibrary02(LPVOID lParam)
{
      //__asm INT 3
      __printf("HideLibrary02 Entry.\r\n");

      PUNLOADLIB_CALLBACK cbFunc = (PUNLOADLIB_CALLBACK)lParam;
      MODULEINFO modinfo;
      GetModuleInformation(GetCurrentProcess(), cbFunc->lpDllBase, &modinfo, sizeof(MODULEINFO));

      //申请一块和当前dll同样大小的内存
      cbFunc->lpNewDllBase = VirtualAlloc(NULL, modinfo.SizeOfImage, MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE);
      if(cbFunc->lpNewDllBase == NULL)
          return FALSE;

      //给当前dll做份拷贝,复制所有数据到刚申请的内存,
      memcpy(cbFunc->lpNewDllBase, modinfo.lpBaseOfDll, modinfo.SizeOfImage);

      //计算在copy中UnLoadLibrary的地址,并另起线程到该地址执行
      void *pNewUnLoadLibrary = LPVOID((DWORD)cbFunc->lpNewDllBase + (DWORD)UnLoadLibrary - (DWORD)modinfo.lpBaseOfDll);

      DWORD ThreadId;
      HANDLE hThread = CreateThread(0,0,
          (LPTHREAD_START_ROUTINE)pNewUnLoadLibrary, (LPVOID)cbFunc, CREATE_SUSPENDED, &ThreadId);

      if(hThread == NULL)
      {
          VirtualFree(cbFunc->lpNewDllBase, 0, MEM_DECOMMIT);
          delete cbFunc;
          return FALSE;
      }

      ResumeThread(hThread);
      CloseHandle(hThread);
      return TRUE;
}


void HideLibrary(HMODULE hModule, LPVOID pCallBackAddr, LPVOID lParam)
{
      __printf("HideLibrary Entry.\r\n");

      PUNLOADLIB_CALLBACK lparam = new UNLOADLIB_CALLBACK;

      lparam->lpDllBase      = hModule;
      lparam->lpNewDllBase = NULL;
      lparam->pAddress       = (PTHREAD_START_ROUTINE)pCallBackAddr;
      lparam->lParam         = lParam;

      HANDLE hThread = CreateThread(0,0,
          HideLibrary02, (LPVOID)lparam, 0, NULL);

      if(hThread == NULL)
      {
          __printf("CreateThread HideLibrary02 Failed.\r\n");
          delete lparam;
          return;
      }

      CloseHandle(hThread);
      return;
}

///
//example
//rundll32 UnloadLibrary.dll,Test
DWORD WINAPI testThread(LPVOID lParam)
{
      char *ptest = new char[512];
      sprintf(ptest, "My Pid: %d\r\n 用一些软件查看下,找不到这个dll吧?", GetCurrentProcessId());
      MessageBox(0, ptest, (char*)lParam, 0);
      delete ptest;
      return 0;
}

DWORD WINAPI testThread02(LPVOID lParam)
{
      HMODULE hModule = (HMODULE)lParam;
      char *ptest = new char[512];
      sprintf(ptest, "testThread02\r\n");
      Sleep(500);
      MessageBox(0, ptest, "start", 0);
      //不设置回调函数,成功还好,一旦失败则gameover
      HideLibrary(hModule, 0, 0);

      sprintf(ptest, "My Pid: %d\r\n 用一些软件查看下,找不到这个dll吧?", GetCurrentProcessId());
      MessageBox(0, ptest, "ok", 0);
      delete ptest;
      return 0;
}

HMODULE hDll;
extern "C"
{
__declspec(dllexport) int Test();
}

int Test()
{
      //1
      //主要线程开始工作后再HideLibrary不是很安全
      //CreateThread(0, 0, testThread02, hDll, 0, 0);

      //2
      //free掉dll后再开启主要工作线程妥当些
      char *p = strdup("hello");
      HideLibrary(hDll, testThread, p);
      Sleep(60000);
      return 0;
}

BOOL APIENTRY DllMain( HANDLE hModule, 
                         DWORD    ul_reason_for_call, 
                         LPVOID lpReserved
                       )
{
      switch (ul_reason_for_call)
      {
      case DLL_PROCESS_ATTACH:
          {
              hDll = (HMODULE)hModule;
          }
          break;
      }

      return TRUE;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
将.dll文件放入资源可以实现在运行时自动加载的效果。将.dll文件放入资源可以将其作为一个资源文件进行管理,这样可以方便地与应用程序进行打包、分发和使用。 首先,将.dll文件添加到项目的资源文件夹。可以通过在Visual Studio右键点击项目,选择“属性”,然后点击“资源”选项卡,再点击“添加资源”按钮,将.dll文件添加到资源。 接下来,在应用程序编写代码以从资源加载和使用.dll文件。可以通过使用System.Reflection命名空间下的Assembly类的Load方法来加载.dll文件。首先,使用Assembly类的GetManifestResourceStream方法获取.dll文件的流对象,然后通过Load方法加载这个流对象,并返回一个Assembly对象。最后,通过Assembly对象可以实现对.dll文件的类型和方法的访问和调用。 在运行时,当需要使用.dll的类型和方法时,可以直接使用上述获取到的Assembly对象来访问和调用它们,而不需要额外的加载操作。只需在代码使用命名空间,通过Assembly对象直接引用其的类型和方法即可。 通过将.dll文件放入资源,并使用反射技术在运行时进行加载和使用,可以避免了运行时丢失.dll文件的问题,提高了应用程序的可靠性和稳定性。同时,还可以加强对.dll文件的版本管理和分发控制,方便进行升级和维护。 这样可以简化应用程序的部署和配置,提高了开发和维护的效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值