import{_ as e}from"./dll-hkWT0ShJ.js";import{_ as a,o as L,c as i,h as r,a as l,b as n,e as d}from"./app-xDBkFjzT.js";const o={},t=l("h2",{id:"动态库基础",tabindex:"-1"},[l("a",{class:"header-anchor",href:"#动态库基础","aria-hidden":"true"},"#"),n(" 动态库基础")],-1),h=l("p",null,"很多程序,基本都不是仅仅程序本身就可以直接运行,经常会依赖到其他的动态库(Dynamic Link Library)。比如最基本的ntdll.dll、kernel32.dll。",-1),p=l("p",null,"程序对动态库的依赖分为两种:",-1),s=l("ul",null,[l("li",null,[l("p",null,"静态依赖"),l("p",null,"一般程序在编译的时候会依赖一个lib,编译后在程序的导入表就会生成相应的依赖信息")]),l("li",null,[l("p",null,"动态加载"),l("p",null,"指通过LoadLibrary、LdrLoadDll的方式进行手动加载动态库的方式")])],-1),D=d('<p>在一个DLL的加载过程,默认会通过以下的目录进行查找:</p><ul><li>程序所在目录</li><li>程序设置的加载目录(SetCurrentDirectory)</li><li>系统目录 <ul><li>System32目录</li><li>Windows目录</li></ul></li><li>PATH环境变量的目录</li></ul><p>更多的可以参考LoadLibrary的API说明。</p><h2 id="dll挟持的原理" tabindex="-1"><a class="header-anchor" href="#dll挟持的原理" aria-hidden="true">#</a> DLL挟持的原理</h2><p>为什么会造成DLL挟持,正是因为DLL的加载过程会搜索不同的路径导致。比如搜索的路径依次A、B、C,而需要的DLL在C位置,如果有恶意的软件把相同名字的DLL放在了A目录,就会导致优先加载A目录的DLL,从而导致DLL挟持的发生。几乎所有的程序都会存在DLL挟持的风险。比如古老的LPK病毒就是利用了这个原理。</p><h3 id="knowndlls" tabindex="-1"><a class="header-anchor" href="#knowndlls" aria-hidden="true">#</a> KnownDLLs</h3><p>系统为了解决这个问题,同时加快系统动态库的加载效率,会建立一份信任列表KnownDLLs,在这份列表的DLL,会直接从已经加载的镜像里面映射一份,不需要重新经过查找、加载的过程。</p><p>KnownDLLs注册表项的路径为 HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session<br> Manager\\KnownDLLs。</p><p>(针对KnownDlls的攻击本文不介绍,有兴趣的可以自行了解)</p><p>但是仍然有很多其他的DLL没有在这个列表里面,从而还是会存在挟持的风险。</p><h3 id="dll挟持可能带来的风险" tabindex="-1"><a class="header-anchor" href="#dll挟持可能带来的风险" aria-hidden="true">#</a> DLL挟持可能带来的风险</h3><ul><li><p>程序的完整性会被破坏</p></li><li><p>程序的逻辑会被篡改</p></li><li><p>程序信任关系被盗用</p><p>比如利用白 + 黑的病毒、绕过某些安全软件的信任逻辑、强制结束带自保护的软件</p></li></ul><p>而且DLL挟持是没法简单通过数字签名来得到解决的。</p><h2 id="dll挟持分析" tabindex="-1"><a class="header-anchor" href="#dll挟持分析" aria-hidden="true">#</a> DLL挟持分析</h2><p>使用iMonitor(冰镜)的最新版本,可以直接分析出哪些程序存在DLL挟持(包括静态依赖、动态加载)的风险。</p><figure><img src="'+e+'" alt="" tabindex="0" loading="lazy"><figcaption></figcaption></figure><h2 id="dll挟持应用" tabindex="-1"><a class="header-anchor" href="#dll挟持应用" aria-hidden="true">#</a> DLL挟持应用</h2><p>如果已经知道一个程序存在DLL挟持,一般是怎么应用的呢?这个具体得挟持的目的是什么,常见的有下面的几种方式。</p><h3 id="拷贝dll到程序目录的方式" tabindex="-1"><a class="header-anchor" href="#拷贝dll到程序目录的方式" aria-hidden="true">#</a> 拷贝DLL到程序目录的方式</h3><p>比如,基本的程序都会依赖version.dll(其他的DLL都可以),而version.dll是系统的DLL,但是加载搜索的过程,优先级最高是程序的当前目录,那么就可以自己制作一个假的version.dll(为了功能可以,需要同时把调用映射回真实的version.dll,如果不会操作,后续可以提供对应的工具),然后放到程序的目录下面,这样程序启动就会自动加载这个假的DLL。</p><p>在这个DLL里面可以做一些Hook操作,这样就可以篡改程序的逻辑,比如修改日期绕过试用期达到破解的目的。</p><blockquote><p>之前还有一些奇葩的安全厂商,提交了针对某会议、某聊天工具的所谓漏洞,竟然是利用DLL挟持来实现。DLL挟持是几乎无法避免的,这样说的话所有软件都会存在漏洞了。</p></blockquote><p>这种方式的DLL挟持,其实比较容易添加一些保护。比如在程序的目录添加自保护(如果需要自保护功能,可以接入iMonitorSDK快速实现),防止其他人拷贝恶意DLL进来,同时可以添加一个对当前目录DLL的扫描,删除不是自己的其他DLL。</p><h3 id="白-黑的方式" tabindex="-1"><a class="header-anchor" href="#白-黑的方式" aria-hidden="true">#</a> 白 + 黑的方式</h3><p>拷贝一个存在DLL挟持的存在信任签名的程序,然后制作一个可以被他加载的DLL放到一起,这样启动这个程序的时候,就会自动加载这个DLL了。因为这个程序存在信任签名,这样就可以绕过一些安全软件的检测,从而提高权限、或者执行恶意逻辑。</p><p>比如:某知名安全软件的自保护控制,只允许自己的固定一个进程来操作,驱动会校验通信的进程名,进程的签名是否有效,这样只要把这个信任的进程拷贝出来,然后跟关闭自保护的恶意DLL放一起,就可以轻松关闭自保护。</p><h3 id="拷贝dll到path目录的方式" tabindex="-1"><a class="header-anchor" href="#拷贝dll到path目录的方式" aria-hidden="true">#</a> 拷贝DLL到PATH目录的方式</h3><p>上面的方式都是主动发起挟持注入DLL的,达到利用条件的前提是具备程序目录的文件拷贝权限、或者执行的时候已经不是完整的程序了。</p><p>另外一种挟持方式是程序依赖的DLL在程序的目录根本没有,而且不是系统DLL。这种在搜索DLL的过程,就会找到PATH目录,但是因为很多软件可能会修改PATH目录,导致里面的条目非常多,这样就会从很多位置尝试去加载DLL。如果存在一个低权限的PATH目录,那么拷贝一个DLL过去,会到导致程序启动的时候自动加载这个DLL,恶意DLL就有可能达到提权的目的,从而做出更多恶意行为。</p><p>建议在软件发布前,都分析程序中是否存在DLL丢失的情况,只要存在DLL丢失,就会潜在一个很大的挟持风险。红蓝对抗中,很多是通过这样的方式来达到提权的目的的。如果因为某一款软件的漏洞引发系统被入侵,这款软件可能会被抛弃的,特别是对等保要求比较高的企业。</p>',30);function c(u,_){return L(),i("div",null,[t,h,p,s,r(" more "),D])}const m=a(o,[["render",c],["__file","DllHijack.html.vue"]]);export{m as default};