爆款云主机2核4G限时秒杀,88元/年起!
查看详情

活动

天翼云最新优惠活动,涵盖免费试用,产品折扣等,助您降本增效!
热门活动
  • 618智算钜惠季 爆款云主机2核4G限时秒杀,88元/年起!
  • 免费体验DeepSeek,上天翼云息壤 NEW 新老用户均可免费体验2500万Tokens,限时两周
  • 云上钜惠 HOT 爆款云主机全场特惠,更有万元锦鲤券等你来领!
  • 算力套餐 HOT 让算力触手可及
  • 天翼云脑AOne NEW 连接、保护、办公,All-in-One!
  • 中小企业应用上云专场 产品组合下单即享折上9折起,助力企业快速上云
  • 息壤高校钜惠活动 NEW 天翼云息壤杯高校AI大赛,数款产品享受线上订购超值特惠
  • 天翼云电脑专场 HOT 移动办公新选择,爆款4核8G畅享1年3.5折起,快来抢购!
  • 天翼云奖励推广计划 加入成为云推官,推荐新用户注册下单得现金奖励
免费活动
  • 免费试用中心 HOT 多款云产品免费试用,快来开启云上之旅
  • 天翼云用户体验官 NEW 您的洞察,重塑科技边界

智算服务

打造统一的产品能力,实现算网调度、训练推理、技术架构、资源管理一体化智算服务
智算云(DeepSeek专区)
科研助手
  • 算力商城
  • 应用商城
  • 开发机
  • 并行计算
算力互联调度平台
  • 应用市场
  • 算力市场
  • 算力调度推荐
一站式智算服务平台
  • 模型广场
  • 体验中心
  • 服务接入
智算一体机
  • 智算一体机
大模型
  • DeepSeek-R1-昇腾版(671B)
  • DeepSeek-R1-英伟达版(671B)
  • DeepSeek-V3-昇腾版(671B)
  • DeepSeek-R1-Distill-Llama-70B
  • DeepSeek-R1-Distill-Qwen-32B
  • Qwen2-72B-Instruct
  • StableDiffusion-V2.1
  • TeleChat-12B

应用商城

天翼云精选行业优秀合作伙伴及千余款商品,提供一站式云上应用服务
进入甄选商城进入云市场创新解决方案
办公协同
  • WPS云文档
  • 安全邮箱
  • EMM手机管家
  • 智能商业平台
财务管理
  • 工资条
  • 税务风控云
企业应用
  • 翼信息化运维服务
  • 翼视频云归档解决方案
工业能源
  • 智慧工厂_生产流程管理解决方案
  • 智慧工地
建站工具
  • SSL证书
  • 新域名服务
网络工具
  • 翼云加速
灾备迁移
  • 云管家2.0
  • 翼备份
资源管理
  • 全栈混合云敏捷版(软件)
  • 全栈混合云敏捷版(一体机)
行业应用
  • 翼电子教室
  • 翼智慧显示一体化解决方案

合作伙伴

天翼云携手合作伙伴,共创云上生态,合作共赢
天翼云生态合作中心
  • 天翼云生态合作中心
天翼云渠道合作伙伴
  • 天翼云代理渠道合作伙伴
天翼云服务合作伙伴
  • 天翼云集成商交付能力认证
天翼云应用合作伙伴
  • 天翼云云市场合作伙伴
  • 天翼云甄选商城合作伙伴
天翼云技术合作伙伴
  • 天翼云OpenAPI中心
  • 天翼云EasyCoding平台
天翼云培训认证
  • 天翼云学堂
  • 天翼云市场商学院
天翼云合作计划
  • 云汇计划
天翼云东升计划
  • 适配中心
  • 东升计划
  • 适配互认证

开发者

开发者相关功能入口汇聚
技术社区
  • 专栏文章
  • 互动问答
  • 技术视频
资源与工具
  • OpenAPI中心
开放能力
  • EasyCoding敏捷开发平台
培训与认证
  • 天翼云学堂
  • 天翼云认证
魔乐社区
  • 魔乐社区

支持与服务

为您提供全方位支持与服务,全流程技术保障,助您轻松上云,安全无忧
文档与工具
  • 文档中心
  • 新手上云
  • 自助服务
  • OpenAPI中心
定价
  • 价格计算器
  • 定价策略
基础服务
  • 售前咨询
  • 在线支持
  • 在线支持
  • 工单服务
  • 建议与反馈
  • 用户体验官
  • 服务保障
  • 客户公告
  • 会员中心
增值服务
  • 红心服务
  • 首保服务
  • 客户支持计划
  • 专家技术服务
  • 备案管家

了解天翼云

天翼云秉承央企使命,致力于成为数字经济主力军,投身科技强国伟大事业,为用户提供安全、普惠云服务
品牌介绍
  • 关于天翼云
  • 智算云
  • 天翼云4.0
  • 新闻资讯
  • 天翼云APP
基础设施
  • 全球基础设施
  • 信任中心
最佳实践
  • 精选案例
  • 超级探访
  • 云杂志
  • 分析师和白皮书
  • 天翼云·创新直播间
市场活动
  • 2025智能云生态大会
  • 2024智算云生态大会
  • 2023云生态大会
  • 2022云生态大会
  • 天翼云中国行
天翼云
  • 活动
  • 智算服务
  • 产品
  • 解决方案
  • 应用商城
  • 合作伙伴
  • 开发者
  • 支持与服务
  • 了解天翼云
      • 文档
      • 控制中心
      • 备案
      • 管理中心

      C/C++ 实现常用的线程注入

      首页 知识中心 软件开发 文章详情页

      C/C++ 实现常用的线程注入

      2023-07-20 06:03:30 阅读次数:427

      C++,DLL,线程

      各种API远程线程注入的方法,分别是 远程线程注入,普通消息钩子注入,全局消息钩子注入,APC应用层异步注入,ZwCreateThreadEx强力注入,纯汇编实现的线程注入等。

      简单编写DLL文件:

      #include <Windows.h>
      
      extern "C" __declspec(dllexport) void MsgBox(LPCWSTR szMsg, LPCWSTR Title)
      {
      	MessageBox(NULL, szMsg, Title, MB_OK);
      }
      
      BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
      {
      	switch (ul_reason_for_call)
      	{
      	case DLL_PROCESS_ATTACH:
      		// 进程被加载后执行
      		break;
      	case DLL_THREAD_ATTACH:
      		// 线程被创建后加载
      		break;
      	case DLL_THREAD_DETACH:
      		// 正常退出执行的代码
      		break;
      	case DLL_PROCESS_DETACH:
      		// 进程卸载本Dll后执行的代码
      		break;
      	}
      	return TRUE;
      }
      
      #include <Windows.h>
      #include <iostream>
      
      typedef VOID(*PFUNMSG)(LPCWSTR szMsg, LPCWSTR Title);
      
      int main(int argc, char *argv[])
      {
      
      	HMODULE hModule = LoadLibrary("./hook.dll");
      
      	if (hModule != NULL)
      	{
      		PFUNMSG pMsgBox = (PFUNMSG)GetProcAddress(hModule, "MsgBox");
      		pMsgBox(L"hello lyshark", L"msgbox");
      	}
      
      	system("pause");
      	return 0;
      }
      

      x86 实现远程线程注入: 注入原理是利用了Windows系统中提供的CreateRemoteThread()这个API函数,该函数第四个参数是准备运行的线程,我们将LoadLibrary()函数填入其中,这样就可以执行远程进程中的LoadLibrary()函数,进而将我们自己准备的DLL加载到远程进程空间中执行,DLL在被装载后则会自动执行初始化部分,X86注入代码如下.

      #include <windows.h>
      #include <stdio.h>
      
      // 使用 CreateRemoteThread 实现远线程注入
      BOOL CreateRemoteThreadInjectDll(DWORD Pid, char *DllName)
      {
      	HANDLE hProcess = NULL;
      	SIZE_T dwSize = 0;
      	LPVOID pDllAddr = NULL;
      	FARPROC pFuncProcAddr = NULL;
      
      	// 打开注入进程,获取进程句柄
      	hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, Pid);
      	if (NULL == hProcess)
      	{
      		return FALSE;
      	}
      	// 计算欲注入 DLL 文件完整路径的长度
      	dwSize = sizeof(char)+lstrlen(DllName);
      
      	//  在目标进程申请一块长度为 nDllLen 大小的内存空间
      	pDllAddr = VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);
      	if (NULL == pDllAddr)
      	{
      		return FALSE;
      	}
      	//  将欲注入 DLL 文件的完整路径写入在目标进程中申请的空间内
      	if (FALSE == WriteProcessMemory(hProcess, pDllAddr, DllName, dwSize, NULL))
      	{
      		return FALSE;
      	}
      	// 获得 LoadLibraryA()函数的地址
      	pFuncProcAddr = GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
      	if (NULL == pFuncProcAddr)
      	{
      		return FALSE;
      	}
      	// 使用 CreateRemoteThread 创建远线程, 实现 DLL 注入
      	HANDLE hRemoteThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pFuncProcAddr, pDllAddr, 0, NULL);
      	if (NULL == hRemoteThread)
      	{
      		return FALSE;
      	}
      	// 关闭句柄
      	CloseHandle(hProcess);
      	return TRUE;
      }
      
      int main(int argc, char *argv[])
      {
      	CreateRemoteThreadInjectDll(4668, "./x86.dll");
      	system("pause");
      	return 0;
      }
      

      x64 实现远程线程注入: 如果想要注入X64程序,则需要在编译时指定为64位编译模式,并且使用LoadLibraryW()来加载动态链接库,我们只需要在上面代码的基础上稍加改进就可以实现64位进程的注入了.

      #include <windows.h>
      #include <stdio.h>
      
      // 使用 CreateRemoteThread 实现远线程注入
      BOOL CreateRemoteThreadInjectDll(DWORD Pid, PCWSTR DllName)
      {
      	BOOL ret = FALSE;
      	HANDLE hProcess, hThread = NULL;
      	FARPROC pfnThreadRtn = NULL;
      	PWSTR pwszPara = NULL;
      
      	// 打开注入进程,获取进程句柄
      	hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, Pid);
      	if (NULL == hProcess)
      	{
      		return FALSE;
      	}
      
      	// 计算欲注入 DLL 文件完整路径的长度
      	size_t iProxyFileLen = wcslen(DllName) * sizeof(WCHAR);
      
      	//  在目标进程申请一块长度为 nDllLen 大小的内存空间
      	pwszPara = (PWSTR)VirtualAllocEx(hProcess, NULL, iProxyFileLen, MEM_COMMIT, PAGE_READWRITE);
      	if (NULL == pwszPara)
      	{
      		return FALSE;
      	}
      
      	//  将欲注入 DLL 文件的完整路径写入在目标进程中申请的空间内
      	if (FALSE == WriteProcessMemory(hProcess, pwszPara, (PVOID)DllName, iProxyFileLen, NULL))
      	{
      		return FALSE;
      	}
      
      	// 获得 LoadLibraryW()函数的地址
      	pfnThreadRtn = GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryW");
      	if (NULL == pfnThreadRtn)
      	{
      		return FALSE;
      	}
      
      	// 使用 CreateRemoteThread 创建远线程, 实现 DLL 注入
      	hThread = CreateRemoteThread(hProcess, NULL, 1024, (LPTHREAD_START_ROUTINE)pfnThreadRtn, pwszPara, 0, NULL);
      	WaitForSingleObject(hThread, INFINITE);
      	if (NULL != hThread)
      	{
      		CloseHandle(hThread);
      		CloseHandle(hProcess);
      		VirtualFreeEx(hProcess, pwszPara, 0, MEM_RELEASE);
      		return TRUE;
      	}
      	return FALSE;
      }
      
      int main(int argc, char *argv[])
      {
      	CreateRemoteThreadInjectDll(8224, L"./x64.dll");
      	system("pause");
      	return 0;
      }
      

      实现普通消息钩子注入: Windows提供的钩子类型非常多,其中一种类型的钩子非常实用,那就是WH_GETME SSAGE钩子,它可以很方便地将DLL文件注入到所有的基于消息机制的目标程序中,代码非常简单,这里直接给出DLL文件的代码,具体如下:

      #include <windows.h>
      
      extern "C" __declspec(dllexport) VOID SetHookOn();
      extern "C" __declspec(dllexport) VOID SetHookOff();
      
      HHOOK g_HHook = NULL;
      HINSTANCE g_hInst = NULL;
      
      VOID DoSomeThing()
      {
      	MessageBoxA(0, "hello lyshark", 0, 0);
      }
      
      BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)
      {
      	switch (fdwReason)
      	{
      		case DLL_PROCESS_ATTACH:
      		{
      			g_hInst = hinstDLL;
      			DoSomeThing();
      			break;
      		}
      	}
      	return TRUE;
      }
      
      LRESULT CALLBACK GetMsgProc(int code,WPARAM wParam,LPARAM lParam)
      {
      	return CallNextHookEx(g_HHook, code, wParam, lParam);
      }
      
      VOID SetHookOn()
      {
      	g_HHook = SetWindowsHookEx(WH_GETMESSAGE, GetMsgProc, g_hInst, 0);
      }
      
      VOID SetHookOff()
      {
      	UnhookWindowsHookEx(g_HHook);
      }
      

      实现全局消息钩子注入: 该注入的原理是利用系统中的SetWindowHookEx()这个API函数,该函数可以拦截目标进程的消息到指定DLL中的导出函数上,利用这个特性,我们可以将DLL注入到全局进程中,但是在使用SetWindowsHookEx()之前首先需要将HOOK的DLL加载到本身的进程中,以此得到DLL的模块句柄,再使用GetProcAddress()得到DLL中公开的函数地址,最后遍历出待注入进程的线程ID,这样SetWindowHookEx()就可以利用这些参数进行HOOK了.

      我们先来编写DLL文件,创建Dll工程hook.cpp然后将SetHook()函数导出,由于该注入方式是全局注入,所以如果我们想要注入到指定进程中,则需要在DllMain()也就是动态链接库开头位置进行判断,如果是我们需要Hook的进程,则加载Dll到指定进程中,如果不是则不执行任何操作,这样一来即可实现指定进程注入.

      #include <windows.h>
      HHOOK Global_Hook;
      
      // 设置全局消息回调函数
      LRESULT CALLBACK MyProc(int nCode, WPARAM wParam, LPARAM lParam)
      {
      	return CallNextHookEx(Global_Hook, nCode, wParam, lParam);
      }
      // 安装全局钩子,此处的hook.dll可以是外部其他的dll
      extern "C" __declspec(dllexport) void SetHook()
      {
      	Global_Hook = SetWindowsHookEx(WH_CBT, MyProc, GetModuleHandle(TEXT("hook.dll")), 0);
      }
      // 卸载全局钩子
      extern "C" __declspec(dllexport) void UnHook()
      {
      	if(Global_Hook)
      		UnhookWindowsHookEx(Global_Hook);
      }
      
      bool APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
      {
      	HWND hwnd = FindWindowW(L"valve001",NULL);
      	DWORD pid;
      	GetWindowThreadProcessId(hwnd, &pid);
      	if (GetCurrentProcessId() == pid)
      	{
      		MessageBox(hwnd, TEXT("hello lyshark"), 0, 0);
      	}
      	return true;
      }
      

      调用代码:注意必须将上方编译好的hook.dll与下方工程放到同一个目录下,通过LoadLibrary()函数获取到模块句柄,然后通过GetProcAddress()获取到导出函数地址,并通过函数指针调用,由于全局注入依赖于父进程,所以下面的代码必须一直运行.

      #include <windows.h>
      
      int main(int argc, char *argv[])
      {
      	HMODULE hMod = LoadLibrary(TEXT("hook.dll"));
      
      	typedef void(*pSetHook)(void);
      	pSetHook SetHook = (pSetHook)GetProcAddress(hMod, "SetHook");
      	SetHook();
      	while (1)
      	{
      		Sleep(1000);
      	}
      	return 0;
      }
      

      APC应用层异步注入: APC 是异步过程调用,在Windows下每个线程在可被唤醒时在其APC链中的函数将有机会执行被执行,每一个线程都具有一个APC链,那么只要在可以在APC链中添加一个APC,就可以完成我们所需要的DLL注入的功能.

      1.将需要加载的DLL的完整路径写入目标进程空间.
      2.获得LoadLibraryA()函数的地址,当然也可以是LoadLibraryW()函数的地址.
      3.枚举目标进程中的所有线程,为每个线程添加一个APC函数,这样增加了注入成功的机会.

      该注入的原理是利用当线程被唤醒时APC中的注册函数会被执行的机制,并以此去执行我们的DLL加载代码,进而完成DLL注入的目的,通过APC注入的流程步骤大致如下

      1.当EXE里某个线程执行到SleepEx()或者WaitForSingleObjectEx()时,系统就会产生一个软中断.
      2.当线程再次被唤醒时,此线程会首先执行APC队列中的被注册的函数.
      3.利用QueueUserAPC()这个API可以在软中断时向线程的APC队列插入一个函数指针,如果我们插入的是Loadlibrary()执行函数的话,就能达到注入DLL的目的,不论如何目标程序必须有执行SleepEx()或者WaitForSingleObjectEx()否则DLL不会加载.

      #include <windows.h>
      #include <tlhelp32.h>
      #include <stdio.h>
      
      // APC注入
      BOOL ApcInjectDll(DWORD dwPid, char * szDllName)
      {
      	// 计算欲注入 DLL 文件完整路径的长度
      	int nDllLen = lstrlen(szDllName) + sizeof(char);
      
      	// 打开目标进程
      	HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE, dwPid);
      	if (hProcess == NULL)
      	{
      		return FALSE;
      	}
      	// 在目标进程申请一块长度为 nDllLen 大小的内存空间
      	PVOID pDllAddr = VirtualAllocEx(hProcess,NULL, nDllLen,MEM_COMMIT,PAGE_READWRITE);
      	if (pDllAddr == NULL)
      	{
      		CloseHandle(hProcess);
      		return FALSE;
      	}
      	DWORD dwWriteNum = 0;
      	// 将欲注入 DLL 文件的完整路径写入在目标进程中申请的空间内
      	WriteProcessMemory(hProcess, pDllAddr, szDllName,nDllLen, &dwWriteNum);
      	CloseHandle(hProcess);
      
      	THREADENTRY32 te = { 0 };
      	te.dwSize = sizeof(THREADENTRY32);
      	//得到线程快照
      	HANDLE handleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
      	if (INVALID_HANDLE_VALUE == handleSnap)
      	{
      		CloseHandle(hProcess);
      		return FALSE;
      	}
      	// 获得 LoadLibraryA()函数的地址
      	FARPROC pFunAddr = GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
      	DWORD dwRet = 0;
      	//得到第一个线程
      	if (Thread32First(handleSnap, &te))
      	{
      		do
      		{
      			//进行进程 ID 对比
      			if (te.th32OwnerProcessID == dwPid)
      			{
      				//得到线程句柄
      				HANDLE hThread = OpenThread(THREAD_ALL_ACCESS,FALSE,te.th32ThreadID);
      				if (hThread)
      				{
      					//向线程插入 APC
      					dwRet = QueueUserAPC((PAPCFUNC)pFunAddr,hThread,(ULONG_PTR)pDllAddr);
      					//关闭句柄
      					CloseHandle(hThread);
      				}
      			}
      			//循环下一个线程
      		} while (Thread32Next(handleSnap, &te));
      	}
      	CloseHandle(handleSnap);
      	return TRUE;
      }
      
      int main(int argc, char *argv[])
      {
      	ApcInjectDll(9608, "c:/x86.dll");
      	system("pause");
      	return 0;
      }
      

      ZwCreateThreadEx强力注入: 在前面的注入方式中,我们使用了CreateRemoteThread()这个函数来完成线程注入,此方式可以注入普通的进程,但却无法注入到系统进程中,因为系统进程是处在SESSION0高权限级别的会话层.

      由于CreateRemoteThread()底层会调用ZwCreateThreadEx()这个未公开的内核函数,所以我们必须手动调用ZwCreateThread()这一内核函数,将第七个参数设置为0即可,ZwCreateThreadEx函数在ntdll.dll中并未声明,所以必须手动使用GetProcAddress函数将其地址导出.

      #include <windows.h>
      #include <stdio.h>
      
      // 使用 ZwCreateThreadEx 实现远线程注入
      BOOL ZwCreateThreadExInjectDll(DWORD dwProcessId, char * pDllName)
      {
      	HANDLE hProcess = NULL;
      	SIZE_T dwSize = 0;
      	LPVOID pDllAddr = NULL;
      	FARPROC pFuncProcAddr = NULL;
      	HANDLE hRemoteThread = NULL;
      	DWORD dwStatus = 0;
      
      	// 打开注入进程,获取进程句柄
      	hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
      	if (NULL == hProcess)
      	{
      		return FALSE;
      	}
      	// 在注入进程中申请内存
      	dwSize = sizeof(char)+lstrlen(pDllName);
      	pDllAddr = ::VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);
      	if (NULL == pDllAddr)
      	{
      		return FALSE;
      	}
      	// 向申请的内存中写入数据
      	if (FALSE == ::WriteProcessMemory(hProcess, pDllAddr, pDllName, dwSize, NULL))
      	{
      		return FALSE;
      	}
      	// 加载 ntdll.dll
      	HMODULE hNtdllDll = ::LoadLibrary("ntdll.dll");
      	if (NULL == hNtdllDll)
      	{
      		return FALSE;
      	}
      	// 获取LoadLibraryA函数地址
      	pFuncProcAddr = ::GetProcAddress(::GetModuleHandle("Kernel32.dll"), "LoadLibraryA");
      	if (NULL == pFuncProcAddr)
      	{
      		return FALSE;
      	}
      	// 获取ZwCreateThread函数地址
      #ifdef _WIN64
      	typedef DWORD(WINAPI *typedef_ZwCreateThreadEx)(
      		PHANDLE ThreadHandle,
      		ACCESS_MASK DesiredAccess,
      		LPVOID ObjectAttributes,
      		HANDLE ProcessHandle,
      		LPTHREAD_START_ROUTINE lpStartAddress,
      		LPVOID lpParameter,
      		ULONG CreateThreadFlags,
      		SIZE_T ZeroBits,
      		SIZE_T StackSize,
      		SIZE_T MaximumStackSize,
      		LPVOID pUnkown);
      #else
      	typedef DWORD(WINAPI *typedef_ZwCreateThreadEx)(
      		PHANDLE ThreadHandle,
      		ACCESS_MASK DesiredAccess,
      		LPVOID ObjectAttributes,
      		HANDLE ProcessHandle,
      		LPTHREAD_START_ROUTINE lpStartAddress,
      		LPVOID lpParameter,
      		BOOL CreateSuspended,
      		DWORD dwStackSize,
      		DWORD dw1,
      		DWORD dw2,
      		LPVOID pUnkown);
      #endif
      	typedef_ZwCreateThreadEx ZwCreateThreadEx = (typedef_ZwCreateThreadEx)::GetProcAddress(hNtdllDll, "ZwCreateThreadEx");
      	if (NULL == ZwCreateThreadEx)
      	{
      		return FALSE;
      	}
      	// 使用 ZwCreateThreadEx 创建远线程, 实现 DLL 注入
      	dwStatus = ZwCreateThreadEx(&hRemoteThread, PROCESS_ALL_ACCESS, NULL, hProcess, 
      		(LPTHREAD_START_ROUTINE)pFuncProcAddr, pDllAddr, 0, 0, 0, 0, NULL);
      	if (NULL == hRemoteThread)
      	{
      		return FALSE;
      	}
      	// 关闭句柄
      	::CloseHandle(hProcess);
      	::FreeLibrary(hNtdllDll);
      	return TRUE;
      }
      
      int main(int argc, char *argv[])
      {
      	BOOL bRet = ZwCreateThreadExInjectDll(2940, "hook.dll");
      
      	system("pause");
      	return 0;
      }
      

      强制卸载进程中的DLL:

      #include <Windows.h>
      #include <stdio.h>
      #include <TlHelp32.h>
      
      BOOL UnLoad_Module(DWORD dwPID, LPCTSTR szDllName)
      {
      	BOOL bMore = FALSE, bFound = FALSE;
      	HANDLE hSnapshot, hProcess, hThread;
      	HMODULE hModule = NULL;
      	MODULEENTRY32 me = { sizeof(me) };
      	LPTHREAD_START_ROUTINE pThreadProc;
      
      	hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwPID);
      	bMore = Module32First(hSnapshot, &me);
      	for (; bMore; bMore = Module32Next(hSnapshot, &me))
      	{
      		if (!_tcsicmp((LPCTSTR)me.szModule, szDllName) || !_tcsicmp((LPCTSTR)me.szExePath, szDllName))
      		{
      			bFound = TRUE;
      			break;
      		}
      	}
      	if (!(hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID)))
      		return FALSE;
      
      	hModule = GetModuleHandle(L"kernel32.dll");
      	pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(hModule, "FreeLibrary");
      	hThread = CreateRemoteThread(hProcess, NULL, 0, pThreadProc, me.modBaseAddr, 0, NULL);
      	WaitForSingleObject(hThread, INFINITE);
      	if (hThread != 0)
      	{
      		CloseHandle(hThread);
      		CloseHandle(hProcess);
      		CloseHandle(hSnapshot);
      		return TRUE;
      	}
      	return FALSE;
      }
      
      int main(int argc, char *argv[])
      {
      	UnLoad_Module(2012, "lyshark.dll");
      
      	system("pause");
      	return 0;
      }
      

      纯汇编实现远程Dll注入:

      .data
      	szMyDll        db "\lyshark.dll",0h       ; 要注入的DLL
      	szDllKernel    db "Kernel32.dll",0h
      	szLoadLibrary  db "LoadLibraryA",0h
      	lpFileName     db "Tutorial-i386",0h      ; 指定要注入进程
      	lpDllName      dd ?
      .data?
      	szMyDllFull    db MAX_PATH dup (?)
      	lpLoadLibrary  dd ?
      	dwProcessID    dd ?     
      	dwThreadID     dd ?
      	hProcess       dd ?
      .code
      	main PROC
      ; 准备工作:获取dll的全路径文件名、获取LoadLibrary函数地址等
      		invoke GetCurrentDirectory,MAX_PATH,addr szMyDllFull
      		invoke lstrcat,addr szMyDllFull,addr szMyDll
      		invoke GetModuleHandle,addr szDllKernel
      		invoke GetProcAddress,eax,offset szLoadLibrary
      		mov lpLoadLibrary,eax
      
      ; 查找文件管理器窗口并获取进程ID,然后打开进程
      		invoke FindWindow,NULL,addr lpFileName
      		invoke GetWindowThreadProcessId,eax,offset dwProcessID
        		mov dwThreadID,eax
        		invoke OpenProcess,PROCESS_ALL_ACCESS,FALSE,dwProcessID
      		mov hProcess,eax
      
      ; 在进程中分配空间并将DLL文件名拷贝过去,然后创建一个LoadLibrary线程
      		invoke VirtualAllocEx,hProcess,NULL,MAX_PATH,MEM_COMMIT,PAGE_READWRITE
      		mov lpDllName,eax
      		invoke WriteProcessMemory,hProcess,eax,offset szMyDllFull,MAX_PATH,NULL
      		invoke CreateRemoteThread,hProcess,NULL,0,lpLoadLibrary,lpDllName,0,NULL
      		ret
      	main endp
      end main
      

      纯汇编实现远程代码注入:

      1.首先使用汇编编写一个代码注入器,其命名为main.asm

      .data
      	lpLoadLibrary      dd ?
      	lpGetProcAddress   dd ?
      	lpGetModuleHandle  dd ?
      	dwProcessID        dd ?
      	dwThreadID         dd ?
      	hProcess           dd ?
      	lpRemoteCode       dd ?
      .const
      	ProcHandle        db "lyshark.exe",0h
      	KernelBase        db "Kernel32.dll",0h
      	szLoadLibrary     db "LoadLibraryA",0h
      	szGetProcAddress  db "GetProcAddress",0h
      	szGetModuleHandle db "GetModuleHandleA",0h
      .code
      include Macro.inc
      include ShellCode.asm
      	main proc
      		invoke GetModuleHandle,addr KernelBase
      		mov ebx,eax
      		invoke GetProcAddress,ebx,offset szLoadLibrary
      		mov lpLoadLibrary,eax
      		invoke GetProcAddress,ebx,offset szGetProcAddress
      		mov lpGetProcAddress,eax
      		invoke GetProcAddress,ebx,offset szGetModuleHandle
      		mov lpGetModuleHandle,eax
      
      		invoke FindWindow,NULL,addr ProcHandle
      		invoke GetWindowThreadProcessId,eax,offset dwProcessID
      		mov dwThreadID,eax
      		invoke OpenProcess,PROCESS_ALL_ACCESS,FALSE,dwProcessID
      		mov hProcess,eax
      
      		invoke VirtualAllocEx,hProcess,NULL,2048,MEM_COMMIT,PAGE_EXECUTE_READWRITE
      			.if eax
      				mov lpRemoteCode,eax
      				invoke WriteProcessMemory,hProcess,lpRemoteCode,offset REMOTE_CODE_START,1024,NULL
      				invoke WriteProcessMemory,hProcess,lpRemoteCode,offset lpLoadLibrary,sizeof dword * 3,NULL
      				mov eax,lpRemoteCode
      				add eax,offset _RemoteThread - offset REMOTE_CODE_START
      				invoke CreateRemoteThread,hProcess,NULL,0,eax,0,0,NULL
      				invoke CloseHandle,eax
      			.endif
      			invoke CloseHandle,hProcess	
      	invoke ExitProcess,NULL
      	ret
      	main endp
      end main
      

      为了后期编程方便,编写一个反转宏Macro.inc用来翻转参数,使用定义_invoke调用更方便

      ; --------------------------------------------
      ; 翻转参数字节序
      reverseArgs macro arglist:VARARG
      	LOCAL txt,count
      	txt TEXTEQU <>
      	count=0
      	for i,<arglist>
      		count = count+1
      		txt TEXTEQU @CatStr(i,<!,>,<%txt>)
      	endm
      	if count GT 0
      		txt SUBSTR txt,1,@SizeStr(%txt)-1
      	endif
      	exitm txt
      endm
      ; --------------------------------------------
      ; 创建类似于INVOKE的宏代码
      _invoke macro _Proc,args:VARARG
      	LOCAL count
      	count = 0
      %	for i,< reverseArgs( args ) >
      		count = count+1
      		push i
      	endm
      	call dword ptr _Proc    
      endm
      

      最后编写注入代码,此处命名为shellcode.asm该代码包括了子定位功能.

      REMOTE_CODE_START equ this byte
      _lpLoadLibrary      dd ?
      _lpGetProcAddress   dd ?
      _lpGetModuleHandle  dd ?
      
      ; --------------------------------------------
      ; 存放静态资源,比如常量,字符串等.
      _hInstance          dd ?
      _szShowTitle        db "hello lyshark",0h
      
      ; --------------------------------------------
      ; 存放获取到的指针
      _lpDllUser          dd ?
      _lpMessageBox       dd ?
      ; --------------------------------------------
      ; 放入导入函数的字符串
      _szDllUser		db	"user32.dll",0h
      _szMessageBox           db      "MessageBoxA",0h,0
      ; --------------------------------------------
      _RemoteThread proc uses ebx esi edi
      		LOCAL @hModule
      ; --------------------------------------------
      ; 计算指令的偏移地址,用ebx作为基址指针
      		call @F
      		@@:
      		pop ebx
      		sub ebx,offset @B
      ; --------------------------------------------
      		_invoke [ebx + _lpGetModuleHandle],NULL         ; 取当前模块句柄
      		mov [ebx + _hInstance],eax
      		lea eax,[ebx + offset _szDllUser]           
      		_invoke [ebx + _lpGetModuleHandle],eax          ; 取user32.dll模块句柄
      		mov @hModule,eax
      ; --------------------------------------------
      ; 循环获取每个导入函数的地址,并放入指针变量保存
      		lea esi,[ebx + offset _szMessageBox]            ; 循环获取,从该函数起始地址处
      		lea edi,[ebx + offset _lpMessageBox]
      		.while TRUE
      			_invoke	[ebx + _lpGetProcAddress],@hModule,esi
      			mov [edi],eax       ; 获取到函数地址后,放入导入函数字符串中
      			add edi,4           ; 每次递增4字节,指向下一个函数,遇到0则停止
      			@@:
      			lodsb
      			or al,al
      			jnz @B
      			.break .if !byte ptr [esi]
      		.endw
      ; --------------------------------------------
      		;lea esi,[ebx+ offset _szMessageBox]            ; 取msgbox模块地址
      		;_invoke [ebx+_lpGetProcAddress],@hModule,esi   ; 获取地址
      		;mov [ebx+_lpMessageBox],eax                    ; 存入变量中
      		lea esi,[ebx + offset _szShowTitle]             ; 获取弹窗资源
      		_invoke [ebx + _lpMessageBox],0,esi,eax,0       ; 调用信息框
      		ret
      _RemoteThread endp
      
      版权声明:本文内容来自第三方投稿或授权转载,原文地址:https://my.oschina.net/lyshark/blog/5550789,作者:LyShark,版权归原作者所有。本网站转在其作品的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如因作品内容、版权等问题需要同本网站联系,请发邮件至ctyunbbs@chinatelecom.cn沟通。

      上一篇:CE修改器入门:查找共享代码

      下一篇:X86逆向7:特殊窗体的破解思路

      相关文章

      2025-05-16 09:15:17

      Linux系统基础-多线程超详细讲解(5)_单例模式与线程池

      Linux系统基础-多线程超详细讲解(5)_单例模式与线程池

      2025-05-16 09:15:17
      单例 , 线程 , 队列
      2025-05-14 10:07:38

      超级好用的C++实用库之互斥锁

      互斥锁是一种用于多线程编程的同步机制,其主要目的是确保在并发执行环境中,同一时间内只有一个线程能够访问和修改共享资源。

      2025-05-14 10:07:38
      CHP , Lock , 互斥 , 线程 , 释放 , 锁定
      2025-05-14 10:03:13

      超级好用的C++实用库之线程基类

      在C++中,线程是操作系统能够进行运算调度的最小单位。一个进程可以包含多个线程,这些线程共享进程的资源,比如:内存空间和系统资源,但它们有自己的指令指针、堆栈和局部变量等。

      2025-05-14 10:03:13
      Linux , void , Windows , 函数 , 操作系统 , 线程
      2025-05-14 10:02:48

      互斥锁解决redis缓存击穿

      在高并发系统中,Redis 缓存是一种常见的性能优化方式。然而,缓存击穿问题也伴随着高并发访问而来。

      2025-05-14 10:02:48
      Redis , 互斥 , 数据库 , 线程 , 缓存 , 请求
      2025-05-14 09:51:15

      java怎么对线程池做监控

      对Java线程池进行监控是确保系统性能和稳定性的重要部分。监控线程池可以帮助我们了解线程池的状态,如当前活跃线程数、任务队列长度、已完成任务数等。

      2025-05-14 09:51:15
      Java , 方法 , 监控 , 示例 , 线程 , 队列
      2025-05-12 08:40:18

      如何向线程传递参数

      如何向线程传递参数

      2025-05-12 08:40:18
      传递 , 参数 , 封装 , 开启 , 线程
      2025-05-09 08:51:21

      notify和notifyall的区别

      notify和notifyall的区别

      2025-05-09 08:51:21
      notify , synchronized , 方法 , 线程 , 调用 , 释放
      2025-05-09 08:51:09

      Java之线程同步(同步方法、同步代码块)(关键字synchronized)(案例分析)

      多线程的并发执行可以提高程序的效率。但是多个线程访问共享资源时,会引发一些安全问题。

      2025-05-09 08:51:09
      代码 , 同步 , 执行 , 方法 , 线程
      2025-05-07 09:08:42

      C++Lambda表达式

      C++Lambda表达式

      2025-05-07 09:08:42
      C++ , 形参 , 捕获 , 类型 , 闭包
      2025-05-07 09:08:23

      Qt中线程的使用

      在qt中线程的使用有两种方式,第一种就是创建一个类继承QObject类,之后使用moveToThread函数将线程添加到类中。另一种就是创建一个类继承QThread类,在类中实现run函数。

      2025-05-07 09:08:23
      run , 使用 , 函数 , 线程
      查看更多
      推荐标签

      作者介绍

      天翼云小翼
      天翼云用户

      文章

      33561

      阅读量

      5234953

      查看更多

      最新文章

      Linux系统基础-多线程超详细讲解(5)_单例模式与线程池

      2025-05-16 09:15:17

      超级好用的C++实用库之互斥锁

      2025-05-14 10:07:38

      超级好用的C++实用库之线程基类

      2025-05-14 10:03:13

      互斥锁解决redis缓存击穿

      2025-05-14 10:02:48

      java怎么对线程池做监控

      2025-05-14 09:51:15

      如何向线程传递参数

      2025-05-12 08:40:18

      查看更多

      热门文章

      Java线程同步synchronized wait notifyAll

      2023-04-18 14:15:05

      C++最普通的定时器功能实现

      2023-03-08 10:27:24

      C/C++泛型编程实现数据结构之栈

      2023-05-15 10:00:33

      C++生成指定范围内随机数封装

      2023-02-07 10:34:04

      C++中substr函数的用法

      2023-04-18 14:14:13

      C++拷贝构造函数(深拷贝,浅拷贝)详解

      2023-03-30 09:59:46

      查看更多

      热门标签

      java Java python 编程开发 代码 开发语言 算法 线程 Python html 数组 C++ 元素 javascript c++
      查看更多

      相关产品

      弹性云主机

      随时自助获取、弹性伸缩的云服务器资源

      天翼云电脑(公众版)

      便捷、安全、高效的云电脑服务

      对象存储

      高品质、低成本的云上存储服务

      云硬盘

      为云上计算资源提供持久性块存储

      查看更多

      随机文章

      java中垃圾回收器让工作线程停顿下来是怎么做的?

      java基础-线程间通信方式

      【Java】线程插队

      C++ 非泛型,自定义类str_的迭代。

      C/C++ 常用排序算法整理

      C++从入门到精通——存储类

      • 7*24小时售后
      • 无忧退款
      • 免费备案
      • 专家服务
      售前咨询热线
      400-810-9889转1
      关注天翼云
      • 旗舰店
      • 天翼云APP
      • 天翼云微信公众号
      服务与支持
      • 备案中心
      • 售前咨询
      • 智能客服
      • 自助服务
      • 工单管理
      • 客户公告
      • 涉诈举报
      账户管理
      • 管理中心
      • 订单管理
      • 余额管理
      • 发票管理
      • 充值汇款
      • 续费管理
      快速入口
      • 天翼云旗舰店
      • 文档中心
      • 最新活动
      • 免费试用
      • 信任中心
      • 天翼云学堂
      云网生态
      • 甄选商城
      • 渠道合作
      • 云市场合作
      了解天翼云
      • 关于天翼云
      • 天翼云APP
      • 服务案例
      • 新闻资讯
      • 联系我们
      热门产品
      • 云电脑
      • 弹性云主机
      • 云电脑政企版
      • 天翼云手机
      • 云数据库
      • 对象存储
      • 云硬盘
      • Web应用防火墙
      • 服务器安全卫士
      • CDN加速
      热门推荐
      • 云服务备份
      • 边缘安全加速平台
      • 全站加速
      • 安全加速
      • 云服务器
      • 云主机
      • 智能边缘云
      • 应用编排服务
      • 微服务引擎
      • 共享流量包
      更多推荐
      • web应用防火墙
      • 密钥管理
      • 等保咨询
      • 安全专区
      • 应用运维管理
      • 云日志服务
      • 文档数据库服务
      • 云搜索服务
      • 数据湖探索
      • 数据仓库服务
      友情链接
      • 中国电信集团
      • 189邮箱
      • 天翼企业云盘
      • 天翼云盘
      ©2025 天翼云科技有限公司版权所有 增值电信业务经营许可证A2.B1.B2-20090001
      公司地址:北京市东城区青龙胡同甲1号、3号2幢2层205-32室
      • 用户协议
      • 隐私政策
      • 个人信息保护
      • 法律声明
      备案 京公网安备11010802043424号 京ICP备 2021034386号