自学内容网 自学内容网

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文件,而默认的多线程调试模式下则不会,为了确保我们的程序能够正确的在其他人的电脑上面生成


原文地址:https://blog.csdn.net/m0_68259687/article/details/143810421

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!