利用远程线程注入DLL

今天接着上次说的远程线程注入来说下利用远程线程进行dll注入。
远程线程注入需要目标进程地址空间的某个函数作为线程的thread_func, 这样我们只能用目标进程中自定义的函数,那我们怎么样使用自定义的函数呢,这就需要使用DLL注入技术。

DLL注入原理很简单:exe文件都会链接kernel32.dll,利用kernel32.dll中的LoadLibrary可以把自己写的dll加载到目标进程(Windows核心编程原话: 对CreateRomoteThread的调用假定在本地进程和远程进程中,kernel32.dll被映射到地址空间中的同一内存地址)。DLL中有一系列的“”钩子“”, 可以在DLL被加载/卸载执行,这样我们自己写的代码就会被目标进程执行。

先自己写一个简单的DLL:

// base/external_dll.cc
#include <windows.h>

#ifndef BASE_EXTERNAL_API
#define BASE_EXTERNAL_API extern "C" __declspec(dllimport)

BOOL WINAPI DllMain(HINSTANCE hinstDLL, // handle to DLL module
                    DWORD fdwReason,    // reason for calling function
                    LPVOID lpvReserved) // reserved
{
  // Perform actions based on the reason for calling.
  switch (fdwReason) {
  case DLL_PROCESS_ATTACH:
    // Initialize once for each new process.
    // Return FALSE to fail DLL load.
    MessageBoxA(NULL, "Dll Main Notice", "Notice", MB_OK);
    break;

  case DLL_THREAD_ATTACH:
    // Do thread-specific initialization.
    break;

  case DLL_THREAD_DETACH:
    // Do thread-specific cleanup.
    break;

  case DLL_PROCESS_DETACH:

    if (lpvReserved != nullptr) {
      break; // do not do cleanup if process termination scenario
    }

    // Perform any necessary cleanup.
    break;
  }
  return TRUE; // Successful DLL_PROCESS_ATTACH.
}

#endif // BASE_EXTERNAL_API

DLL_PROCESS_ATTACH 会在进程通过LoadLibrary将DLL加载到进程空间的时候触发,这里我们简单弹出一个MessageBox提示DLL代码被执行。

使用控制台编译成DLL
g++ .\base\external_dll.cc -fPIC -shared -o external.dll

这里我们写一个client先在本进程加载下这个DLL验证下:

#include <windows.h>

constexpr char kDllFilePath[] =
    "C:\\Users\\chuzhang\\Desktop\\DummyProgram\\external.dll";
int main() {
  LoadLibraryA((LPCSTR)kDllFilePath);
  return 0;
}

在这里插入图片描述
本地编译执行下,发现message box弹出来了,说明咱们自己写在DLL里面的代码执行了,下面咱们把这个DLL执行到其他进程去。

我们还是使用我们之前用的dummy_process.exe 作为注入目标:

// dummy_process.cc
#include <iostream>
#include <string>
#include <windows.h>

int main() {
  int varInt = 123456;
  std::string varString = "DefaultString";
  char arrChar[] = "Long char array right there";
  int *ptr2int = &varInt;
  int **ptr2ptr = &ptr2int;
  int ***ptr2ptr2 = &ptr2ptr;

  while (true) {
    std::cout << "Process ID: " << GetCurrentProcessId() << std::endl;
    std::cout << std::endl;
    std::cout << "varInt          "
              << "(" << &varInt << ") = " << varInt << std::endl;
    std::cout << "varString       "
              << "(" << &varString << ") = " << varString << std::endl;
    std::cout << "arrChar         "
              << "(" << &arrChar << ") = " << arrChar << std::endl;
    std::cout << std::endl;
    std::cout << "ptr2int         "
              << "(" << &ptr2int << ") = " << ptr2int << std::endl;
    std::cout << "ptr2ptr         "
              << "(" << &ptr2ptr << ") = " << ptr2ptr << std::endl;
    std::cout << "ptr2ptr2        "
              << "(" << &ptr2ptr2 << ") = " << ptr2ptr2 << std::endl;
    std::cout << std::endl;
    std::cout << "Press ENTER to print again" << std::endl;
    std::cout << std::endl;
    std::cout << std::endl;
    std::cout << "----------------------------" << std::endl;

    getchar();
  }
}

在这里插入图片描述
注入DLL的代码:

// inject_dll.cc
#include <windows.h>

constexpr char kDllFilePath[] =
    "C:\\Users\\chuzhang\\Desktop\\DummyProgram\\external.dll";
constexpr int kProcessId = 20600;
int main() {
  HANDLE process = OpenProcess(PROCESS_ALL_ACCESS, false, kProcessId);
  FARPROC func = GetProcAddress(GetModuleHandleA("kernel32"), "LoadLibraryA");
  LPVOID remote_string = VirtualAllocEx(process, NULL, strlen(kDllFilePath) + 1,
                                        MEM_COMMIT, PAGE_EXECUTE_READWRITE);
  WriteProcessMemory(process, remote_string, kDllFilePath,
                     strlen(kDllFilePath) + 1, NULL);
  HANDLE thread = CreateRemoteThread(
      process, NULL, 0, LPTHREAD_START_ROUTINE(func), remote_string, 0, NULL);
  WaitForSingleObject(thread, INFINITE);
  CloseHandle(thread);
  VirtualFreeEx(process, remote_string, strlen(kDllFilePath) + 1, MEM_DECOMMIT);
  return 0;
}

我们要注意,CreateRemoteThread不能直接写成:

HANDLE thread = CreateRemoteThread(
      process, NULL, 0, LPTHREAD_START_ROUTINE(func), "C:\\Users\\chuzhang\\Desktop\\DummyProgram\\external.dll"", 0, NULL);

"C:\\Users\\chuzhang\\Desktop\\DummyProgram\\external.dll"在当前进程的地址会被传入到CreateRemoteThread,远程进程使用这个地址作为参数调用LoadLibraryA, 目标进程可能会发生内存访问违规。

解决方案是:在目标进程通过VirtualAllocEx在目标进程分配一块内存,这块内存大小为字符串大小加一(字符串末尾结束符),然后使用WriteProcessMemory把DLL路径写入到新分配的内存里,这样我们可以得到目标进程内指向DLL路径字符串的指针,使用这个指针调用CreateRemoteThread

运行注入程序,可以在目标cmd看到messagebox:

在这里插入图片描述
其实最好不要在DLL_PROCESS_ATTACH里面直接写代码因为DllMain和其他代码share了同步锁,在这里进行资源访问请求可能引发死锁,最好是创建一个线程,然后干自己想干的事情:

#include <iostream>
#include <windows.h>

#ifndef BASE_EXTERNAL_API
#define BASE_EXTERNAL_API extern "C" __declspec(dllimport)

DWORD DoWork() {
  std::cout << "hijack from dll";
  return 0;
}

BOOL WINAPI DllMain(HINSTANCE hinstDLL, // handle to DLL module
                    DWORD fdwReason,    // reason for calling function
                    LPVOID lpvReserved) // reserved
{
  // Perform actions based on the reason for calling.
  switch (fdwReason) {
  case DLL_PROCESS_ATTACH: {
    // Initialize once for each new process.
    // Return FALSE to fail DLL load.
    HANDLE thread =
        CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&DoWork, NULL, 0, NULL);
    CloseHandle(thread);
    break;
  }

  case DLL_THREAD_ATTACH:
    // Do thread-specific initialization.
    break;

  case DLL_THREAD_DETACH:
    // Do thread-specific cleanup.
    break;

  case DLL_PROCESS_DETACH:

    if (lpvReserved != nullptr) {
      break; // do not do cleanup if process termination scenario
    }

    // Perform any necessary cleanup.
    break;
  }
  return TRUE; // Successful DLL_PROCESS_ATTACH.
}

#endif // BASE_EXTERNAL_API
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值