免杀基础– 自删除之重命名文件流

0x00 介绍

当我还是一个电脑小白的时候,遇到过不止一次点击一个exe文件(如 server.exe),然后这个文件立马消失了。以当时浅薄的知识认为自己是不能删除自己的,这是怎么回事?实现自删除的方法有很多,本文介绍一种重命名文件流的方法。

0x01 利用思路

删除当前运行的可执行文件的方法。关键点在于将主文件流:$DATA重命名为:wtfbbq。简略过程如下

  1. 打开当前运行进程的HANDLE,使用DELETE访问。
  2. 使用SetFileInformationByHandle将主文件流:$DATA重命名为:wtfbbq。
  3. 关闭HANDLE
  4. 打开当前进程的HANDLE,将FileDispositionInfo类的DeleteFile设置为TRUE。
  5. 关闭HANDLE以触发文件处置

0x02 代码实现分析

参考开源代码:https://github.com/LloydLabs/delete-self-poc


#include <Windows.h>
#include <shlwapi.h>
#include <stdio.h>
#include <stdlib.h>

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

#define DS_STREAM_RENAME L":wtfbbq"
#define DS_DEBUG_LOG(msg) wprintf(L"[LOG] - %s\n", msg)static
HANDLE
ds_open_handle(
    PWCHAR pwPath
)
{
    return CreateFileW(pwPath, DELETE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
}

static
BOOL
ds_rename_handle(
    HANDLE hHandle
)
{
    FILE_RENAME_INFO fRename;
    RtlSecureZeroMemory(&fRename, sizeof(fRename));

    // set our FileNameLength and FileName to DS_STREAM_RENAME
    LPWSTR lpwStream = DS_STREAM_RENAME;
    fRename.FileNameLength = sizeof(lpwStream);
    RtlCopyMemory(fRename.FileName, lpwStream, sizeof(lpwStream));

    return SetFileInformationByHandle(hHandle, FileRenameInfo, &fRename, sizeof(fRename) + sizeof(lpwStream));
}

static
BOOL 
ds_deposite_handle(
    HANDLE hHandle
)
{
    // set FILE_DISPOSITION_INFO::DeleteFile to TRUE
    FILE_DISPOSITION_INFO fDelete;
    RtlSecureZeroMemory(&fDelete, sizeof(fDelete));

    fDelete.DeleteFile = TRUE;
    // 将主文件流:$DATA重命名为:wtfbbq
    return SetFileInformationByHandle(hHandle, FileDispositionInfo, &fDelete, sizeof(fDelete));
}

int
main(
    int argc,
    char** argv
)
{
    WCHAR wcPath[MAX_PATH + 1];
    RtlSecureZeroMemory(wcPath, sizeof(wcPath));

    // get the path to the current running process ctx
    if (GetModuleFileNameW(NULL, wcPath, MAX_PATH) == 0)
    {
        DS_DEBUG_LOG(L"failed to get the current module handle");
        return 0;
    }

    HANDLE hCurrent = ds_open_handle(wcPath);
    if (hCurrent == INVALID_HANDLE_VALUE)
    {
        DS_DEBUG_LOG(L"failed to acquire handle to current running process");
        return 0;
    }

    // rename the associated HANDLE's file name
    DS_DEBUG_LOG(L"attempting to rename file name");
    if (!ds_rename_handle(hCurrent))
    {
        DS_DEBUG_LOG(L"failed to rename to stream");
        return 0;
    }

    DS_DEBUG_LOG(L"successfully renamed file primary :$DATA ADS to specified stream, closing initial handle");
    CloseHandle(hCurrent);

    // open another handle, trigger deletion on close
    hCurrent = ds_open_handle(wcPath);
    if (hCurrent == INVALID_HANDLE_VALUE)
    {
        DS_DEBUG_LOG(L"failed to reopen current module");
        return 0;
    }

    if (!ds_deposite_handle(hCurrent))
    {
        DS_DEBUG_LOG(L"failed to set delete deposition");
        return 0;
    }

    // trigger the deletion deposition on hCurrent
    DS_DEBUG_LOG(L"closing handle to trigger deletion deposition");
    CloseHandle(hCurrent);

    // verify we've been deleted
    if (PathFileExistsW(wcPath))
    {
        DS_DEBUG_LOG(L"failed to delete copy, file still exists");
        return 0;
    }

    DS_DEBUG_LOG(L"successfully deleted self from disk");
    return 1;
}

0x03 生成演示