当前位置: 首页 > article >正文

DLL注入

Dll注入

关键API

CreateRemoteThread

HANDLE CreateRemoteThread(
HANDLE hProcess,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
SIZE_T dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId
);

在DLL注入的时候,起的是远程的线程

在上面的参数中,lpStartAddress就是线程的函数,使用LoadLibrary的地址作为线程函数的地址,这样我们就可以用LoadLibrary来起lpParameter中装载的dll路径

VirtualAllocEx

这个函数是在指定进程的虚拟空间中保留或者提交内存区域,除非指定MEM_RESET参数,否则将该内存区域置0

LPVOID VirtualAllocEx(
HANDLE hProcess,
LPVOID lpAddress,
SIZE_T dwSize,
DWORD flAllocationType,
DWORD flProtect
);

WriteProcessMemory

此函数能够写入后一个进程的内存区域(但是直接写入会存在Access Violation错误),故需要此函数入口必修可以访问,否则操作将失败。

BOOL WriteProcessMemory(
HANDLE hProcess, //进程句柄
LPVOID lpBaseAddress, //写入的内存首地址
LPCVOID lpBuffer, //要写数据的指针
SIZE_T nSize, //x
SIZE_T *lpNumberOfBytesWritten
);

思路

1.在进程中开辟一段空间
2.存入dll绝对路径地址的字符串
3.使用RemoteCreateThread函数带起LoadLibrary函数带起dll

实现

获取句柄

DWORD GetProcessPID(LPCTSTR lpProcessName){

DWORD Ret = 0;
PROCESSENTRY32 p32;

HANDLE lpSnapshot = ::CreateToolhelp32Snampshot(TH32CS_SNAPPROCESS,0);

if (lpSnashot == INVALID_HANDLE_VALUE){
	printf("GetSnapshotError:%d",::GetLastError());
	return Ret;
  }
  //获取进程快照成功之后,将快照存储到PROCESSENTRY32的结构里面
  p32.dwSize = sizeof(PROCESSENTRY32);
  ::Process32First(lpSnapshot,&p32);
  //遍历快照,找到指定进程名的进程号
  do{
  if (!lstrcmp(p32.szExeFile,lpProcessName)){
		  Ret = p32.th32ProcessID;
		  break;
   }
  }while(::Process32Next(lpSnapshot,&p32));
  
  ::CloseHandle(lpSnapshot);
  return Ret;
}

完整demo

#include<iostream>
#include<tchar.h>
#include<windows.h>
#include<TlHelp32.h>

DWORD GetProcessPID(LPCTSTR lpProcessName)
{
DWORD Ret = 0;
PROCESSENTRY32 p32;
HANDLE lpSnapshot = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (lpSnapshot == INVALID_HANDLE_VALUE)
{
printf("GetSnapshotError:%d",::GetLastError());
return Ret;
}
p32.dwSize = sizeof(PROCESSENTRY32);
::Process32First(lpSnapshot, &p32);
do {
if (!lstrcmp(p32.szExeFile, lpProcessName))
{
Ret = p32.th32ProcessID;
break;
}
} while (::Process32Next(lpSnapshot, &p32));
::CloseHandle(lpSnapshot);
return Ret;
}
	DWORD RemoteThreadInject(DWORD Pid,LPCWSTR DllName){
	
	DWORD size = 0;
	DWORD DllAddr = 0;
	//1.打开进程
	HANDLE hprocess = OpenProcess(PROCESS_ALL_ACCESS,FALSE,Pid);
	if (hprocess == NULL){
			printf("OpenProcessError:%d",GetLastError());
			return FALSE;
		}
		size = (wcslen(DllName)+1)*sizeof(TCHAR);
		//2.申请空间
		LPVOID pAllocMemory = VirtualAllocEx(hprocess,NULL,size,MEM_COMMIT,PAGE_READWRITE);
		if (pAllocMemory == NULL){
				printf("VirtualAllocExError:%d",GetLastError());
				return FALSE;
		}		
		//3.写入内存
		BOOL write = WriteProcessMemory(hprocess,pAllocMemory,DllName,size,NULL);
		if (pAllocMemory == 0){
				printf("WriteProcessMemoryError:%d",GetLastError());
				return FALSE;
		}		
		//4.获取LoadLibrary-kenrnel32.dll
		FARPROC pThread = GetProcAddress(GetModuleHandle(L"kernel32.dll"),"LoadLibraryW");
		LPTHREAD_START_ROUTINE addr = (LPTHREAD_START_ROUINE)pThread;
		//5.创建线程
		HANDLE hThread = CreateRemoteThread(hprocess, NULL, 0, addr, pAllocMemory,0, NULL);
		if (hThread == NULL){
				printf("CreateRemoteThreadError:%d",GetLastError());
				return FALSE;
		}		
		//6.等待线程函数结束
		WaitForSingleObject(hThread,-1);
		//7.释放DLL空间
		VirtualFreeEx(hprocess,pAllocMemory,size,MEM_DECOMMIT);
		//8.关闭句柄
		CloseHandle(hprocess);
		return TRUE;	
	}
	
	int main(){
	    //根据进程名获得PID
			DWORD PID  = GetProcessPID(L"notepad.exe");
			//根据进程名和DLL的路径名来加载,这里主要是因为我们自己写的dll是不存在system32里面的所以要给绝对路径)
			RemoteThreadInject(PID, L"C:\\Users\\test\\Desktop\\x64.dll");
			
	}

可能要注意的问题

编码问题

VS2022中可以指定我们自己的编码方式

在这里插入图片描述

现在VS生成的项目一般统一使用Unicode,但是统一成Unicode之后,虽然解决了乱码问题,但是在文本上编码需要比ascii多一倍的空间

所以,如果是文本上纯英文,那么使用ascii就行了

VS里面有两种API,一种是A系,一种是W系。这两种的区别就是其基本的编码方式,在项目中会帮助你自动扩展到指定的系中

在这里插入图片描述

如果想写的通用一点,可以使用__T,在使用之前要声明tchar.h

#include <tchar.h>
MessageBox(0,_T("1"),_T("1"),MB_OK);
Visual C++里边定义字符串的时候,用T来保证兼容性,VC支持ascii和unicode两种字符类型,用T
可以保证从ascii编码类型转换到unicode编码类型的时候,程序不需要修改
int _tmain(int argc, TCHAR* argv[])
//这种用于unicode条件下
BOOL bRet = ZwCreateThreadExInject((DWORD)_tstol(argv[1]), argv[2]);
//可以使用_tstol转换参数

运行库问题

在本地跑没有问题的程序,在虚拟机或者其他环境跑有问题,比如报错缺少vcruntime140d.dll

这是因为目标环境可能没有装vs,这时候就需要我们把dll包在我们编译的环境里面

在这里插入图片描述

多线程模式下会包裹更加全面的dll文件,而默认的多线程调试模式下则不会,为了确保我们的程序能够正确的在其他人的电脑上面生成


http://www.kler.cn/a/398148.html

相关文章:

  • 基于大语言模型意图识别和实体提取功能;具体ZK数值例子:加密货币交易验证;
  • 软件测试 —— 自动化基础
  • 动手学深度学习73 课程总结和进阶学习
  • Ubuntu 24.04 安装 JDK 21
  • 车载诊断架构 --- 关于DTC的开始检测条件
  • React Hooks 深度解析与实战
  • 鸿蒙next版开发:音频并发策略扩展(ArkTS)
  • GoogleCloud服务器的SSH连接配置
  • [含文档+PPT+源码等]精品基于springboot实现的原生Andriod手机使用管理软件
  • VMware Tools工具安装脚本(CentOS Ubuntu)
  • 【微信小程序】用户房屋管理
  • 软硬互联——革新机器人非标产线智能制造
  • CSS Float(浮动)
  • 快速搭建Android开发环境:Docker部署docker-android并实现远程连接
  • 【大数据学习 | HBASE高级】hive操作hbase
  • pytorch中的ImageFolder 用法
  • ASUS/华硕灵耀14 2024款 UX3405MA 原厂Win11-23H2系统 工厂文件 带ASUS Recovery恢复
  • 【Java Web】Ajax 介绍及 jQuery 实现
  • ranger-kms安装
  • 串口DMA接收不定长数据
  • AndroidStudio-Activity的生命周期
  • 权限系统:权限应用服务设计
  • LeetCode 18. 四数之和 Java题解
  • JVM双亲委派机制详解
  • GPT-5 要来了:抢先了解其创新突破
  • web与网络编程