dll劫持从0到1 - 篇1(基础)

  • A+
所属分类:CTF专场


STATEMENT

声明

由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,雷神众测及文章作者不为此承担任何责任。

雷神众测拥有对此文章的修改和解释权。如欲转载或传播此文章,必须保证此文章的完整性,包括版权声明等全部内容。未经雷神众测允许,不得任意修改或者增减此文章内容,不得以任何方式将其用于商业目的。



NO.1 基础知识

DLL(Dynamic Link Library)文件为动态链接库文件,又称“应用程序拓展”,是软件文件类型。 在Windows中,许多应用程序并不是一个完整的可执行文件,它们被分割成一些相对独立的动态链接库,即DLL文件。


在windows平台下,很多应用程序的很多功能是相似的,抛去ui等等来说,大致的功能都差不多,比如都得调用窗口,都得调用内存管理的模块来分配内存,都得调用io模块去进行文件操作,读写文件等等,这些模块的具体表现就是DLL文件。


那么问题来了,比如应用程序要调用这个模块的时候,他如何在茫茫文件中找到正确的dll去调用他呢? 肯定不是ai 肯定不是机器学习hhh。


Windows操作系统通过“DLL路径搜索目录顺序”和“Know DLLs注册表项”的机制来确定应用程序所要调用的DLL的路径,之后,应用程序就将DLL载入了自己的内存空间,执行相应的函数功能。


那么具体的DLL路径搜索目录顺序 和 Know DLLs注册表项 是什么呢?


· DLL路径搜索目录顺序

    1.程序所在目录

    2.程序加载目录(SetCurrentDirectory)

    3.系统目录即 SYSTEM32 目录

    4.16位系统目录即 SYSTEM 目录

    5.Windows目录

    6.PATH环境变量中列出的目录

· Know DLLs注册表项


Know DLLs注册表项里的DLL列表在应用程序运行后就已经加入到了内核空间中,多个进程公用这些模块,必须具有非常高的权限才能修改。


Know DLLs注册表项的路径

HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlSession ManagerKnownDLLs
dll劫持从0到1 - 篇1(基础)

那么dll劫持想必大家也就知道了,应用程序在寻找正常dll去执行功能的之前,我们创建一个恶意的dll在他找的路上放好,让他以为找到正常的dll了实际上加载的是我们恶意构造的dll。


还有一些前置的知识需要去了解,例如C++去调用dll的两种方式等等,当然有条件的更可以去看看windows核心编程第五版中第19章和第20章的内容,会让你后面的学习更加清楚。


https://blog.csdn.net/sj2050/article/details/81700183
https://blog.csdn.net/qq_29542611/article/details/86618902



NO.2 dll模板代码

生成一个简单的dll

这里用的是vs2019

dll劫持从0到1 - 篇1(基础)
dll劫持从0到1 - 篇1(基础)

vs2019会给你生成一个dll的模板,在此基础上我对各个参数进行了详细的解释

dll劫持从0到1 - 篇1(基础)
// dllmain.cpp : 定义 DLL 应用程序的入口点。
// 预编译头,提高编译速度# include "pch.h"
BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved )
/* 指向自身的句柄 HINSTANCE hinstDLL,
指明了DLL被调用的原因 DWORD ul_reason_for_call,
加载方式(隐式、显式) LPVOID lpvReserved*/{ switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: //DLL进程装载 case DLL_THREAD_ATTACH: //DLL线程装载 case DLL_THREAD_DETACH: //DLL线程卸载 case DLL_PROCESS_DETACH: //DLL进程卸载 break; } return TRUE;}

DLL_PROCESS_ATTACH :当系统第一次将一个DLL映射到进程的地址空间中时候,会调用Dllmain函数,并在ul_reason_for_call参数中传入DLL_PROCESS_ATTACH,只有在当DLL的文件映像第一次被映射的时候,才会这样。之后的线程如果再去调用loadlibrary来载入一个已经被映射到进程的地址空间的dll,那么操作系统只会去递增DLL的使用计数,不会再次调用Dllmain。


DLL_PROCESS_DETACH:当系统将一个 DLL从进程的地址空间中 撤销映射时,会调用DLL的Dllmain函数,并在ul_reason_for_call参数中传入DLL_PROCESS_DETACH
当DLL处理这个通知的时候,应该执行与进程相关的清理工作。


DLL_THREAD_ATTACH:当进程创建个线程的时候, 系统会检查当前映射到该进程的地址空间中的所有DLL文件映像,并用DLL_THREAD_ATTACH来调用每个DLL的DIMain函数。这告诉DLL需要执行与线程相关的初始化。新创建的线程负责执行所有DLL的Dllmain函数中的代码。只有当所有DLL都完成了对该通知的处理之后,系统才会让新线程开始执行它的线程函数。


DLL_THREAD_DETACH:让线程终止的首选方式是让它的线程函数返回。这会使得系统调用ExitThread 来终止线程。ExitThread 告诉系统该线程想要终止,但系统不会立即终止该线程,而会让这个即将终止的线程用DLL_THREAD_DETACH来调用所有已映射DLL的DIMain函数。这个通知告诉DLL执行与线程相关的清理。



NO.3 简单做一个dll劫持

dll劫持-劫持没有的dll

这里我们选用了notepad++ 7之前的版本,因为之前的版本是可以dll劫持的,(本文是6.66版本)可以说当个靶场。


当然这里还需要用到 ProcessMonitor
ProcessMonitor下载地址:

https://docs.microsoft.com/en-us/sysinternals/downloads/procmon

我们打开ProcessMonitor 再打开notepad++
之后设置几个过滤条例,比如下面这张图就是设置了过滤notepad++.exe 的进程名

dll劫持从0到1 - 篇1(基础)

以此类推,整三个

dll劫持从0到1 - 篇1(基础)

这样出来的结果就很清楚

dll劫持从0到1 - 篇1(基础)

我们需要找到一个有loadlibrary相关的API的dll
比如我们选 Msimg32.DLL

dll劫持从0到1 - 篇1(基础)

那么为什么要找一个有loadlibrary相关的API的dll呢?


是因为如果该dll的调用栈中存在有 LoadLibrary(Ex),说明这个DLL是被进程所动态加载的。在这种利用场景下,伪造的DLL文件不需要存在任何导出函数即可被成功加载,即使加载后进程内部出错,也是在DLL被成功加载之后的事情。

加载dll动态库时LoadLibrary与LoadLibraryEx的区别

若DLL不在调用方的同一目录下,可以用LoadLibrary(L"DLL绝对路径")加载。


但若被调DLL内部又调用另外一个DLL,此时调用仍会失败。解决办法是用LoadLibraryEx:


LoadLibraryEx(“DLL绝对路径”, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);


通过指定LOAD_WITH_ALTERED_SEARCH_PATH,让系统DLL搜索顺序从DLL所在目录开始。

看来这个Msimg32.DLL 很符合我们的条件,于是我们通过dll模板去写一个dll 将他命名成Msimg32.DLL

# include "pch.h"# include <stdlib.h>
BOOL APIENTRY DllMain( HMODULE hModule,                       DWORD  ul_reason_for_call,                       LPVOID lpReserved                     ){    switch (ul_reason_for_call)    {    case DLL_PROCESS_ATTACH:   //DLL进程装载        system("calc");    case DLL_THREAD_ATTACH:    //DLL线程装载        case DLL_THREAD_DETACH:    //DLL线程卸载    case DLL_PROCESS_DETACH:   //DLL进程卸载        break;    }    return TRUE;}
dll劫持从0到1 - 篇1(基础)
dll劫持从0到1 - 篇1(基础)

运行notepad++,可以发现直接程序在运行的时候加载了Msimg32.DLL 然后直接执行了里面的恶意命令

dll劫持从0到1 - 篇1(基础)

我们可以看看,把这个过滤条件改掉

dll劫持从0到1 - 篇1(基础)
dll劫持从0到1 - 篇1(基础)

有点需要注意的就是比如此notepad++是32位的,那么你去编译dll的时候也需要用x86去编译

dll劫持-劫持存在的dll

既然是劫持存在的dll,最简单的 我们去看看notepad++安装目录下已经存在的dll,就比如下图的SciLexer.dll

dll劫持从0到1 - 篇1(基础)

打开Process Monitor 再打开notepad++
过滤器设置成

dll劫持从0到1 - 篇1(基础)
dll劫持从0到1 - 篇1(基础)

双击SciLexer.dll 然后看下stack,可以发现同样存在loadlibrary。那就说明这个dll是动态加载的,并且不需要什么导出函数就可以成功被加载。并且是在程序在运行过程中完成的

dll劫持从0到1 - 篇1(基础)

这里要用到apimonitor这工具

http://www.rohitab.com/apimonitor

apimonitor 可让您监控和控制应用程序和服务发出的 API 调用。它是查看应用程序和服务如何工作或跟踪您自己的应用程序中存在的问题的强大工具。

首先我们打开api monitor 32位版本 然后,我们的目的要很明确,我们需要知道这个dll在实际运行中调用的哪个导出函数,因为有些dll的导出函数很多,有些很少,这就得去用apimonitor监控。


那么为什么要用寻找导出函数呢?,是因为导出函数中的方法是可以被外部访问的。

.DLL 文件的布局与 .exe 文件非常相似,但有一个重要的差异:DLL 文件包含导出表。导出表包含 DLL 导出到其他可执行文件的每个函数的名称。这些函数是 DLL 中的入口点;只有导出表中的导出函数可由其他可执行文件访问。DLL 中的任何其他函数都是 DLL 私有的。

在动态调用的时候,一般代码通过loadlibrary去加载dll 并作为参数传到到导出函数,所以我们使用apimonitor去监控那几个常用的loadlibrary,然后看他最后走到哪个导出函数中去了, 这样就可以知道导出函数了。然后我们写些恶意代码在导出函数里。让程序在显式载入的时候,LoadLibrary载入dll、使用GetProcAddress获取某函数地址,然后调用。

dll劫持从0到1 - 篇1(基础)
dll劫持从0到1 - 篇1(基础)
dll劫持从0到1 - 篇1(基础)
dll劫持从0到1 - 篇1(基础)

把上面五个勾上

dll劫持从0到1 - 篇1(基础)

再去打开notepad++.exe

dll劫持从0到1 - 篇1(基础)
dll劫持从0到1 - 篇1(基础)

到这一步,就已经拿到了dll的导出函数

dll劫持从0到1 - 篇1(基础)

之后我们开始编写dll


编写dll时,有个重要的问题需要解决,那就是函数重命名——Name-Mangling。C++的编译器通常会对函数名和变量名进行改编,这在链接的时候会出现一个严重的问题,假如dll是C++写的,可执行文件是C写的。在构建dll的时候,编译器会对函数名进行改编,但是在构建可执行文件的时候,编译器不会对函数名进行改。这个时候当链接器试图链接可执行文件的时候,会发现可执行文件引用了一个不存在的符号并报错,那么如何解决这个问题呢?有几种方法。


第一种是用extern "C"、来告诉编译器不要对变量名和函数名进行改编,这样用C,C++或者任何语言编写可执行模块都可以访问该变量或者该函数。


第二种是给项目创建一个.def文件,.def文件会包含一下类似下面的EXPORTS段
EXPORTS
Myfunc
当链接器解析这个.def文件的时候,会发现被改编后的函数名比如[email protected]和没被改编的函数名Myfunc都被导出,这俩函数名是匹配的(不考虑改编),然后链接器就会用.def文件中定义的名称也就是Myfunc来导出函数,而不是用[email protected]


第三种是还可以在源文件中添加# pragma comment(linker, "/export:[Exports Name]=[Mangling Name]")
比如 # pragma comment(linker, "/export:Myfunc=[email protected]")


还需要知道
导出:__declspec(dllexport)
导入:__declspec(dllimport)

dll劫持从0到1 - 篇1(基础)
dll劫持从0到1 - 篇1(基础)

目的很清楚 让notepad++程序运行的时候,程序本身的loadlibrary 去加载这个存在的dll,然后执行导出函数。这个过程我们之前用apimonitor监控过了。


之后我们看看实验是否成功,将生成的dll改名为SciLexer.dll。

dll劫持从0到1 - 篇1(基础)

实验失败,因为程序的代码对我们来说是完全黑盒的,于是我们尝试另一种dll转发的方式。


dll转发

保留原dll,恶意的dll的原因是要做两件事,一件事就是执行恶意代码,第二件事情就是转到正常的dll,来维持程序的正常运行。

// dllmain.cpp : 定义 DLL 应用程序的入口点。# include "pch.h"# include <stdlib.h>
extern "C" __declspec(dllexport) void Scintilla_DirectFunction();
BOOL APIENTRY DllMain( HMODULE hModule,                       DWORD  ul_reason_for_call,                       LPVOID lpReserved                     ){    switch (ul_reason_for_call)    {    case DLL_PROCESS_ATTACH:        system("calc");    case DLL_THREAD_ATTACH:    case DLL_THREAD_DETACH:    case DLL_PROCESS_DETACH:        break;    }    return TRUE;}
void Scintilla_DirectFunction(){    HINSTANCE hDll = LoadLibrary(L"SciLexer_org.dll");        if (hDll)
       {            //typedef 是定义了一个新的类型            //DWORD是双字类型 4个字节,API函数中有很多参数和返回值是DWORD            //定义了类型EXPFUNC,并且返回类型是DWORD的函数的指针            typedef DWORD(WINAPI *EXPFUNC)();            EXPFUNC expFunc = NULL;            expFunc = (EXPFUNC)GetProcAddress(hDll, "Scintilla_DirectFunction");            if (expFunc)            {                expFunc();            }                    }        return;}
dll劫持从0到1 - 篇1(基础)
dll劫持从0到1 - 篇1(基础)

后来询问了倾旋大佬才知道,转发对主程序的依赖非常的高,报错是CreateWindowsEx()返回值为空报错,
当使用转发,让程序先走恶意的dll(SciLexer.dll),再走正常的dll的时候(SciLexer_org.dll),我们不清楚主程序的需求是什么可能是一个返回值,也可能参数不正确,这个时候都会导致主程序运行出错。不过好在loadlibrary 还是去载入了恶意dll执行了恶意代码,可以看到计算器弹出。


参考链接
https://www.cnblogs.com/cswuyg/archive/2011/09/30/dll.html
https://cloud.tencent.com/developer/article/1005669
https://www.cnblogs.com/punished/p/14715771.html

参考书籍
《windows核心编程(第五版)》




RECRUITMENT

招聘启事

安恒雷神众测SRC运营(实习生)
————————
【职责描述】
1.  负责SRC的微博、微信公众号等线上新媒体的运营工作,保持用户活跃度,提高站点访问量;
2.  负责白帽子提交漏洞的漏洞审核、Rank评级、漏洞修复处理等相关沟通工作,促进审核人员与白帽子之间友好协作沟通;
3.  参与策划、组织和落实针对白帽子的线下活动,如沙龙、发布会、技术交流论坛等;
4.  积极参与雷神众测的品牌推广工作,协助技术人员输出优质的技术文章;
5.  积极参与公司媒体、行业内相关媒体及其他市场资源的工作沟通工作。

【任职要求】 
 1.  责任心强,性格活泼,具备良好的人际交往能力;
 2.  对网络安全感兴趣,对行业有基本了解;
 3.  良好的文案写作能力和活动组织协调能力。


简历投递至 

[email protected]

设计师(实习生)

————————

【职位描述】
负责设计公司日常宣传图片、软文等与设计相关工作,负责产品品牌设计。

【职位要求】
1、从事平面设计相关工作1年以上,熟悉印刷工艺;具有敏锐的观察力及审美能力,及优异的创意设计能力;有 VI 设计、广告设计、画册设计等专长;
2、有良好的美术功底,审美能力和创意,色彩感强;

3、精通photoshop/illustrator/coreldrew/等设计制作软件;
4、有品牌传播、产品设计或新媒体视觉工作经历;

【关于岗位的其他信息】
企业名称:杭州安恒信息技术股份有限公司
办公地点:杭州市滨江区安恒大厦19楼
学历要求:本科及以上
工作年限:1年及以上,条件优秀者可放宽


简历投递至 

[email protected]

安全招聘

————————

公司:安恒信息
岗位:Web安全 安全研究员
部门:战略支援部
薪资:13-30K
工作年限:1年+
工作地点:杭州(总部)、广州、成都、上海、北京

工作环境:一座大厦,健身场所,医师,帅哥,美女,高级食堂…

【岗位职责】
1.定期面向部门、全公司技术分享;
2.前沿攻防技术研究、跟踪国内外安全领域的安全动态、漏洞披露并落地沉淀;
3.负责完成部门渗透测试、红蓝对抗业务;
4.负责自动化平台建设
5.负责针对常见WAF产品规则进行测试并落地bypass方案

【岗位要求】
1.至少1年安全领域工作经验;
2.熟悉HTTP协议相关技术
3.拥有大型产品、CMS、厂商漏洞挖掘案例;
4.熟练掌握php、java、asp.net代码审计基础(一种或多种)
5.精通Web Fuzz模糊测试漏洞挖掘技术
6.精通OWASP TOP 10安全漏洞原理并熟悉漏洞利用方法
7.有过独立分析漏洞的经验,熟悉各种Web调试技巧
8.熟悉常见编程语言中的至少一种(Asp.net、Python、php、java)

【加分项】
1.具备良好的英语文档阅读能力;
2.曾参加过技术沙龙担任嘉宾进行技术分享;
3.具有CISSP、CISA、CSSLP、ISO27001、ITIL、PMP、COBIT、Security+、CISP、OSCP等安全相关资质者;
4.具有大型SRC漏洞提交经验、获得年度表彰、大型CTF夺得名次者;
5.开发过安全相关的开源项目;
6.具备良好的人际沟通、协调能力、分析和解决问题的能力者优先;
7.个人技术博客;
8.在优质社区投稿过文章;


岗位:安全红队武器自动化工程师
薪资:13-30K
工作年限:2年+
工作地点:杭州(总部)

【岗位职责】
1.负责红蓝对抗中的武器化落地与研究;
2.平台化建设;
3.安全研究落地。

【岗位要求】
1.熟练使用Python、java、c/c++等至少一门语言作为主要开发语言;
2.熟练使用Django、flask 等常用web开发框架、以及熟练使用mysql、mongoDB、redis等数据存储方案;
3:熟悉域安全以及内网横向渗透、常见web等漏洞原理;
4.对安全技术有浓厚的兴趣及热情,有主观研究和学习的动力;
5.具备正向价值观、良好的团队协作能力和较强的问题解决能力,善于沟通、乐于分享。

【加分项】
1.有高并发tcp服务、分布式等相关经验者优先;
2.在github上有开源安全产品优先;
3:有过安全开发经验、独自分析过相关开源安全工具、以及参与开发过相关后渗透框架等优先;
4.在freebuf、安全客、先知等安全平台分享过相关技术文章优先;
5.具备良好的英语文档阅读能力。


简历投递至

[email protected]

岗位:红队武器化Golang开发工程师

薪资:13-30K
工作年限:2年+
工作地点:杭州(总部)

【岗位职责】
1.负责红蓝对抗中的武器化落地与研究;
2.平台化建设;
3.安全研究落地。

【岗位要求】
1.掌握C/C++/Java/Go/Python/JavaScript等至少一门语言作为主要开发语言;
2.熟练使用Gin、Beego、Echo等常用web开发框架、熟悉MySQL、Redis、MongoDB等主流数据库结构的设计,有独立部署调优经验;
3.了解docker,能进行简单的项目部署;
3.熟悉常见web漏洞原理,并能写出对应的利用工具;
4.熟悉TCP/IP协议的基本运作原理;
5.对安全技术与开发技术有浓厚的兴趣及热情,有主观研究和学习的动力,具备正向价值观、良好的团队协作能力和较强的问题解决能力,善于沟通、乐于分享。

【加分项】
1.有高并发tcp服务、分布式、消息队列等相关经验者优先;
2.在github上有开源安全产品优先;
3:有过安全开发经验、独自分析过相关开源安全工具、以及参与开发过相关后渗透框架等优先;
4.在freebuf、安全客、先知等安全平台分享过相关技术文章优先;
5.具备良好的英语文档阅读能力。

简历投递至

[email protected]



END

dll劫持从0到1 - 篇1(基础)
dll劫持从0到1 - 篇1(基础)
dll劫持从0到1 - 篇1(基础)

长按识别二维码关注我们


本文始发于微信公众号(雷神众测):dll劫持从0到1 - 篇1(基础)

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: