DLL隐藏和逆向

本文探讨了DLL(动态链接库)的作用,为何隐藏DLL及其在恶意软件中的应用,包括木马和游戏外挂。还介绍了DLL隐藏的手法,如手动载入和痕迹消除,以及如何编写和注入DLL进行测试。最后强调了LoadLibrary在DLL注入中的关键作用。
摘要由CSDN通过智能技术生成

DLL隐藏和逆向

1.何为DLL?

动态链接库英文为DLL,是Dynamic Link Library的缩写。DLL是一个包含可由多个程序,同时使用的代码和数据的库。例如,在 Windows 操作系统中,Comdlg32.dll 执行与对话框有关的常见函数。因此,每个程序都可以使用该 DLL 中包含的功能来实现“打开”对话框。这有助于避免代码重用和促进内存的有效使用。
通过使用 DLL,程序可以实现模块化,由相对独立的组件组成。例如,一个计帐程序可以按模块来销售。可以在运行时将各个模块加载到主程序中(如果安装了相应模块)。因为模块是彼此独立的,所以程序的加载速度更快,而且模块只在相应的功能被请求时才加载。

​ 总而言之就是DLL这种技术可以使得程序模块化,同时让程序加载速度更快。

详细解释见下面的链接:

DLL详解

2.为啥要隐藏DLL?

​ 一句话总结:没做啥坏事,干嘛隐藏自己呢?所以隐藏了自己,那有很大的可能性是要做坏事:

​ 1.木马以DLL形式注入进正常进程并隐藏自己,导致无法追踪溯源,如键盘记录木马,感染型木马

​ 2.游戏外挂通过该种方式躲避游戏自身的“模块检测”,如DXF的第三方木马检测

​ 除了坏事儿之外,在一些常见的攻防对抗中,如若用到windows木马,不仅要注意免杀工作,有时也需要通过该技术实现持久性隐藏攻击。

3.DLL隐藏常见手法

​ 一.手动载入

​ 所谓手动载入就是自己去实现LoadLibrary函数,从理论上讲,这种方法隐藏效果是最棒的,但是实现一个基本的PEloader并不是一件容易的事情,如果还要考虑兼容性完美,就必须还得妥善处理TLS,资源,线程等问题。(不太易上手)

​ 二.痕迹消除

​ 这个就比较好说了,我们在注入DLL的时候,通常要选择去调用 LoadLibrary函数,然后再擦除痕迹,这样不用去处理那些TLS,资源,线程等为了解决兼容性产生的问题。但是Windows大家都清楚,表面风平浪静,背地里风起云涌,说不准现在你电脑的XXX安全卫士正在对你的电脑做些什么呢,这些都是你不通过技术手段看不到的东西,实际上没有什么好的方法把痕迹真正的消除。

​ 以DLL擦除痕迹为例,网上大多数的方法都是通过PEB双向断链,需要很多的硬编码,麻烦不说,通过内存暴力搜索还是会露出尾巴来

​ 攻防无绝对,攻防本身就是一个提升本身技术的过程,只要能够通过一个比较合适的方法,实现相应的功能,便具有可行性。

4.DLL编写与注入测试

​ 一.DLL编写:

​ ①.于vs中创建一个空的项目。

​ ②.添加C语言代码如下:

#include <Windows.h>
 
BOOL WINAPI DllMain(HMODULE hDll, DWORD dwReason, LPVOID lpReserved)
{
    DisableThreadLibraryCalls(hDll);
 
    if (dwReason == DLL_PROCESS_ATTACH)
    {
        //================================== OPTIONAL =========================================
        MessageBoxA(0, "Message Test","Message Title", 0); 
    }
    return 1;
}

​ ③.同时在项目属性中设置:在这里插入图片描述
在这里插入图片描述

​ ④.而后对文件进行编译生成即可。

​ 二.DLL注入测试:

​ 见演示。
在这里插入图片描述

由图可见进程中已经注入进入了我们的DLL,且内存地址为0x78EB0000

​ 三.手写代码实现注入

​ 谈完DLL编写和利用工具注入测试,我们来大致了解一下代码实现注入,方法有很多,但原理大致相同,我在这里以线程注入dll为例:

​ 代码编写:

#include <Windows.h>

void Inject(int pID, char* Path)
{
    //获取进程句柄
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pID);

    //申请一块内存给DLL路径
    LPVOID pReturnAddress = VirtualAllocEx(hProcess, NULL, strlen(Path) + 1, MEM_COMMIT, PAGE_READWRITE);

    //写入路径到上一行代码申请的内存中
    WriteProcessMemory(hProcess, pReturnAddress, Path, strlen(Path) + 1, NULL);


    //获取LoadLibraryA函数的地址
    HMODULE hModule = LoadLibrary("KERNEL32.DLL");
    LPTHREAD_START_ROUTINE lpStartAddress = (LPTHREAD_START_ROUTINE)GetProcAddress(hModule, "LoadLibraryA");


    //创建远程线程-并获取线程的句柄
    HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, lpStartAddress, pReturnAddress, 0, NULL);

    //等待线程事件
    WaitForSingleObject(hThread, 2000);


    //防止内存泄露
    CloseHandle(hThread);
    CloseHandle(hProcess);

}

int main()
{
    //传dll路径
    const char* a = "(传入dll所在路径)";

    //传入进程ID
    Inject(传入进程id, (char*)a);

    return 0;
}

代码解析:

​ 首先,通过调用OpenProcess函数获取目标进程的句柄(hProcess)。OpenProcess函数使用了PROCESS_ALL_ACCESS参数,表示打开进程时拥有最高权限。然后,通过VirtualAllocEx函数在目标进程中申请一块内存(pReturnAddress),用于存储DLL文件路径。接着,使用WriteProcessMemory函数将DLL文件路径写入到刚才申请的内存空间中。

之后,通过调用LoadLibrary函数加载KERNEL32.DLL库,并使用GetProcAddress函数获取LoadLibraryA函数的地址(lpStartAddress)。

接下来,使用CreateRemoteThread函数在目标进程中创建一个远程线程,该线程将在目标进程的上下文中执行lpStartAddress函数,并将pReturnAddress作为参数传递给它。这样,目标进程就会执行LoadLibraryA函数,将DLL文件路径作为参数加载到自己的地址空间中。

最后,通过调用WaitForSingleObject函数等待远程线程事件的发生,直到线程执行完毕或超时。

整个过程完成后,关闭线程和进程句柄,释放相关资源,避免内存泄漏。

根据传入参数,记录我们要传入的数据

进程ID:xxxx

路径:xxxxxx

在这里插入图片描述

​ 而后将两个参数写入到程序对应的位置当中去,生成exe后丢到虚拟机中即可实现dll注入(此步还未复现)

成功注入之后,应该会弹出信息框,通过分析源代码,我们总结了一下注入流程:

1.在别人的程序里开辟内存空间A

2.将 LoadLibrary 函数参数写入A

3.获取LoadLibrary函数地址

4.在别人的程序里远程执行 LoadLibrary实现加载外部DLL

虚拟机中即可实现dll注入(此步还未复现)

成功注入之后,应该会弹出信息框,通过分析源代码,我们总结了一下注入流程:

1.在别人的程序里开辟内存空间A

2.将 LoadLibrary 函数参数写入A

3.获取LoadLibrary函数地址

4.在别人的程序里远程执行 LoadLibrary实现加载外部DLL

由此可见 LoadLibrary很重要,这个玩意竟然实现了注入!

下期详解逆向隐藏部分

参考看雪社区文章完成(https://bbs.kanxue.com/thread-257081.html)

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值