Update Injector
This commit is contained in:
parent
ab93568598
commit
19f83f3c0c
695
SDK/injector.cpp
695
SDK/injector.cpp
@ -1,653 +1,70 @@
|
||||
#ifndef _CRT_SECURE_NO_WARNINGS
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
#include "injector.h"
|
||||
|
||||
#include "injector.h"
|
||||
#include <malloc.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
typedef BOOL(WINAPI *IsWow64Process2_t)(HANDLE hProcess, USHORT *pProcessMachine, USHORT *pNativeMachine);
|
||||
|
||||
static DWORD page_size = 0;
|
||||
static size_t func_LoadLibraryW;
|
||||
static size_t func_FreeLibrary;
|
||||
static size_t func_GetLastError;
|
||||
static char errmsg[512];
|
||||
static injector_t *g_injector;
|
||||
|
||||
#ifdef _M_AMD64
|
||||
static const char x64_code_template[] =
|
||||
// ---------- call LoadLibraryW ----------
|
||||
/* 0000: */ "\x48\x83\xEC\x28" // sub rsp,28h
|
||||
/* 0004: */ "\xFF\x15\x3E\x00\x00\x00" // call LoadLibraryW
|
||||
// 0x0000003e = X64_ADDR_LoadLibraryW - (0x0004 + 6)
|
||||
/* 000A: */ "\x48\x85\xC0" // test rax,rax
|
||||
/* 000D: */ "\x74\x0B" // je L1
|
||||
/* 000F: */ "\x48\x89\x05\xEA\x0F\x00\x00" // mov [load_address], rax
|
||||
// 0x00000fea = 0x1000 - (0x000F + 7)
|
||||
/* 0016: */ "\x33\xC0" // xor eax,eax
|
||||
/* 0018: */ "\xEB\x06" // jmp L2
|
||||
/* 001A: L1: */ "\xFF\x15\x38\x00\x00\x00" // call GetLastError
|
||||
// 0x00000038 = X64_ADDR_GetLastError - (0x001A + 6)
|
||||
/* 0020: L2: */ "\x48\x83\xC4\x28" // add rsp,28h
|
||||
/* 0024: */ "\xC3" // ret
|
||||
|
||||
// ---------- call FreeLibrary ----------
|
||||
#define X64_UNINJECTION_CODE_OFFSET 0x25
|
||||
/* 0025: */ "\x48\x83\xEC\x28" // sub rsp,28h
|
||||
/* 0029: */ "\xFF\x15\x21\x00\x00\x00" // call FreeLibrary
|
||||
// 0x00000021 = X64_ADDR_FreeLibrary - (0x0029 + 6)
|
||||
/* 002F: */ "\x85\xC0" // test eax,eax
|
||||
/* 0031: */ "\x74\x04" // je L1
|
||||
/* 0033: */ "\x33\xC0" // xor eax,eax
|
||||
/* 0035: */ "\xEB\x06" // jmp L2
|
||||
/* 0037: L1: */ "\xFF\x15\x1B\x00\x00\x00" // call GetLastError
|
||||
// 0x0000001B = X64_ADDR_GetLastError - (0x0037 + 6)
|
||||
/* 003D: L2: */ "\x48\x83\xC4\x28" // add rsp,28h
|
||||
/* 0041: */ "\xC3" // ret
|
||||
|
||||
// padding
|
||||
/* 0042: */ "\x90\x90\x90\x90\x90\x90"
|
||||
|
||||
// ---------- literal pool ----------
|
||||
#define X64_ADDR_LoadLibraryW 0x0048
|
||||
/* 0048: */ "\x90\x90\x90\x90\x90\x90\x90\x90"
|
||||
#define X64_ADDR_FreeLibrary 0x0050
|
||||
/* 0050: */ "\x90\x90\x90\x90\x90\x90\x90\x90"
|
||||
#define X64_ADDR_GetLastError 0x0058
|
||||
/* 0058: */ "\x90\x90\x90\x90\x90\x90\x90\x90";
|
||||
|
||||
#define X64_CODE_SIZE 0x0060
|
||||
#endif
|
||||
|
||||
#if defined(_M_AMD64) || defined(_M_IX86)
|
||||
static const char x86_code_template[] =
|
||||
// ---------- call LoadLibraryW ----------
|
||||
/* 0000: */ "\xFF\x74\x24\x04" // push dword ptr [esp+4]
|
||||
#define X86_CALL_LoadLibraryW 0x0004
|
||||
/* 0004: */ "\xE8\x00\x00\x00\x00" // call LoadLibraryW@4
|
||||
/* 0009: */ "\x85\xC0" // test eax,eax
|
||||
/* 000B: */ "\x74\x09" // je L1
|
||||
#define X86_MOV_EAX 0x000D
|
||||
/* 000D: */ "\xA3\x00\x00\x00\x00" // mov dword ptr [load_address], eax
|
||||
/* 0012: */ "\x33\xC0" // xor eax,eax
|
||||
/* 0014: */ "\xEB\x05" // jmp L2
|
||||
#define X86_CALL_GetLastError1 0x0016
|
||||
/* 0016: L1: */ "\xE8\x00\x00\x00\x00" // call GetLastError@0
|
||||
/* 001B: L2: */ "\xC2\x04\x00" // ret 4
|
||||
|
||||
// ---------- call FreeLibrary ----------
|
||||
#define X86_UNINJECTION_CODE_OFFSET 0x001E
|
||||
/* 001E: */ "\xFF\x74\x24\x04" // push dword ptr [esp+4]
|
||||
#define X86_CALL_FreeLibrary 0x0022
|
||||
/* 0022: */ "\xE8\x00\x00\x00\x00" // call FreeLibrary@4
|
||||
/* 0027: */ "\x85\xC0" // test eax,eax
|
||||
/* 0029: */ "\x74\x04" // je L1
|
||||
/* 002B: */ "\x33\xC0" // xor eax,eax
|
||||
/* 002D: */ "\xEB\x05" // jmp L2
|
||||
#define X86_CALL_GetLastError2 0x002F
|
||||
/* 002F: L1: */ "\xE8\x00\x00\x00\x00" // call GetLastError@0
|
||||
/* 0034: L2: */ "\xC2\x04\x00" // ret 4
|
||||
;
|
||||
|
||||
#define X86_CODE_SIZE 0x0037
|
||||
#endif
|
||||
|
||||
#ifdef _M_AMD64
|
||||
#define CURRENT_ARCH "x64"
|
||||
#define CODE_SIZE X64_CODE_SIZE
|
||||
#endif
|
||||
|
||||
#ifdef _M_IX86
|
||||
#define CURRENT_ARCH "x86"
|
||||
#define CODE_SIZE X86_CODE_SIZE
|
||||
#endif
|
||||
|
||||
static void set_errmsg(const char *format, ...);
|
||||
static const char *w32strerr(DWORD err);
|
||||
static USHORT process_arch(HANDLE hProcess);
|
||||
static const char *arch_name(USHORT arch);
|
||||
|
||||
struct injector {
|
||||
HANDLE hProcess;
|
||||
char *remote_mem;
|
||||
char *injection_code;
|
||||
char *uninjection_code;
|
||||
};
|
||||
|
||||
static BOOL init(void)
|
||||
{
|
||||
SYSTEM_INFO si;
|
||||
HANDLE hToken;
|
||||
LUID luid;
|
||||
TOKEN_PRIVILEGES tp;
|
||||
HMODULE kernel32 = GetModuleHandleA("kernel32");
|
||||
if (kernel32 == 0) {
|
||||
return FALSE;
|
||||
}
|
||||
GetSystemInfo(&si);
|
||||
page_size = si.dwPageSize;
|
||||
func_LoadLibraryW = (size_t)GetProcAddress(kernel32, "LoadLibraryW");
|
||||
func_FreeLibrary = (size_t)GetProcAddress(kernel32, "FreeLibrary");
|
||||
func_GetLastError = (size_t)GetProcAddress(kernel32, "GetLastError");
|
||||
|
||||
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) {
|
||||
return FALSE;
|
||||
}
|
||||
if (!LookupPrivilegeValue(0, SE_DEBUG_NAME, &luid)) {
|
||||
CloseHandle(hToken);
|
||||
return FALSE;
|
||||
}
|
||||
tp.PrivilegeCount = 1;
|
||||
tp.Privileges[0].Luid = luid;
|
||||
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
||||
if (!AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL)) {
|
||||
CloseHandle(hToken);
|
||||
return FALSE;
|
||||
}
|
||||
CloseHandle(hToken);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#if defined(_M_AMD64)
|
||||
static int cmp_func(const void *context, const void *key, const void *datum)
|
||||
{
|
||||
ptrdiff_t rva_to_va = (ptrdiff_t)context;
|
||||
const char *k = (const char *)key;
|
||||
const char *d = (const char *)(rva_to_va + *(const DWORD *)datum);
|
||||
return strcmp(k, d);
|
||||
}
|
||||
|
||||
static int funcaddr(DWORD pid, size_t *load_library, size_t *free_library, size_t *get_last_error)
|
||||
{
|
||||
HANDLE hSnapshot;
|
||||
MODULEENTRY32W me;
|
||||
BOOL ok;
|
||||
HANDLE hFile = INVALID_HANDLE_VALUE;
|
||||
HANDLE hFileMapping = NULL;
|
||||
void *base = NULL;
|
||||
IMAGE_NT_HEADERS *nt_hdrs;
|
||||
ULONG exp_size;
|
||||
const IMAGE_EXPORT_DIRECTORY *exp;
|
||||
const DWORD *names, *name, *funcs;
|
||||
const WORD *ordinals;
|
||||
ptrdiff_t rva_to_va;
|
||||
int rv = INJERR_OTHER;
|
||||
|
||||
/* Get the full path of kernel32.dll. */
|
||||
retry:
|
||||
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, pid);
|
||||
if (hSnapshot == INVALID_HANDLE_VALUE) {
|
||||
DWORD err = GetLastError();
|
||||
switch (err) {
|
||||
case ERROR_BAD_LENGTH:
|
||||
goto retry;
|
||||
case ERROR_ACCESS_DENIED:
|
||||
rv = INJERR_PERMISSION;
|
||||
break;
|
||||
case ERROR_INVALID_PARAMETER:
|
||||
rv = INJERR_NO_PROCESS;
|
||||
break;
|
||||
default:
|
||||
rv = INJERR_OTHER;
|
||||
}
|
||||
set_errmsg("CreateToolhelp32Snapshot error: %s", w32strerr(err));
|
||||
return rv;
|
||||
}
|
||||
me.dwSize = sizeof(me);
|
||||
for (ok = Module32FirstW(hSnapshot, &me); ok; ok = Module32NextW(hSnapshot, &me)) {
|
||||
if (wcsicmp(me.szModule, L"kernel32.dll") == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
CloseHandle(hSnapshot);
|
||||
if (!ok) {
|
||||
set_errmsg("kernel32.dll could not be found.");
|
||||
return INJERR_OTHER;
|
||||
}
|
||||
|
||||
/* Get the export directory in the kernel32.dll. */
|
||||
hFile = CreateFileW(me.szExePath, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE) {
|
||||
set_errmsg("failed to open file %s: %s", me.szExePath, w32strerr(GetLastError()));
|
||||
goto exit;
|
||||
}
|
||||
hFileMapping = CreateFileMappingA(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
|
||||
if (hFileMapping == NULL) {
|
||||
set_errmsg("failed to create file mapping of %s: %s", me.szExePath, w32strerr(GetLastError()));
|
||||
goto exit;
|
||||
}
|
||||
base = MapViewOfFile(hFileMapping, FILE_MAP_READ, 0, 0, 0);
|
||||
if (base == NULL) {
|
||||
set_errmsg("failed to map file %s to memory: %s", me.szExePath, w32strerr(GetLastError()));
|
||||
goto exit;
|
||||
}
|
||||
nt_hdrs = ImageNtHeader(base);
|
||||
if (nt_hdrs == NULL) {
|
||||
set_errmsg("ImageNtHeader error: %s", w32strerr(GetLastError()));
|
||||
goto exit;
|
||||
}
|
||||
exp = (const IMAGE_EXPORT_DIRECTORY *)ImageDirectoryEntryToDataEx(base, FALSE, IMAGE_DIRECTORY_ENTRY_EXPORT,
|
||||
&exp_size, NULL);
|
||||
if (exp == NULL) {
|
||||
set_errmsg("ImageDirectoryEntryToDataEx error: %s", w32strerr(GetLastError()));
|
||||
goto exit;
|
||||
}
|
||||
if (exp->NumberOfNames == 0) {
|
||||
set_errmsg("No export entires are not found.");
|
||||
goto exit;
|
||||
}
|
||||
names = (const DWORD *)ImageRvaToVa(nt_hdrs, base, exp->AddressOfNames, NULL);
|
||||
if (names == NULL) {
|
||||
set_errmsg("ImageRvaToVa error: %s", w32strerr(GetLastError()));
|
||||
goto exit;
|
||||
}
|
||||
ordinals = (const WORD *)ImageRvaToVa(nt_hdrs, base, exp->AddressOfNameOrdinals, NULL);
|
||||
if (ordinals == NULL) {
|
||||
set_errmsg("ImageRvaToVa error: %s", w32strerr(GetLastError()));
|
||||
goto exit;
|
||||
}
|
||||
funcs = (const DWORD *)ImageRvaToVa(nt_hdrs, base, exp->AddressOfFunctions, NULL);
|
||||
if (funcs == NULL) {
|
||||
set_errmsg("ImageRvaToVa error: %s", w32strerr(GetLastError()));
|
||||
goto exit;
|
||||
}
|
||||
rva_to_va = (size_t)ImageRvaToVa(nt_hdrs, base, names[0], NULL) - (size_t)names[0];
|
||||
|
||||
/* Find the address of LoadLibraryW */
|
||||
name = bsearch_s((void *)"LoadLibraryW", names, exp->NumberOfNames, sizeof(DWORD), cmp_func, (void *)rva_to_va);
|
||||
if (name == NULL) {
|
||||
set_errmsg("Could not find the address of LoadLibraryW");
|
||||
goto exit;
|
||||
}
|
||||
*load_library = (size_t)me.modBaseAddr + funcs[ordinals[name - names]];
|
||||
|
||||
/* Find the address of FreeLibrary */
|
||||
name = bsearch_s((void *)"FreeLibrary", names, exp->NumberOfNames, sizeof(DWORD), cmp_func, (void *)rva_to_va);
|
||||
if (name == NULL) {
|
||||
set_errmsg("Could not find the address of FreeLibrary");
|
||||
goto exit;
|
||||
}
|
||||
*free_library = (size_t)me.modBaseAddr + funcs[ordinals[name - names]];
|
||||
|
||||
/* Find the address of GetLastError */
|
||||
name = bsearch_s((void *)"GetLastError", names, exp->NumberOfNames, sizeof(DWORD), cmp_func, (void *)rva_to_va);
|
||||
if (name == NULL) {
|
||||
set_errmsg("Could not find the address of GetLastError");
|
||||
goto exit;
|
||||
}
|
||||
*get_last_error = (size_t)me.modBaseAddr + funcs[ordinals[name - names]];
|
||||
rv = 0;
|
||||
exit:
|
||||
if (base != NULL) {
|
||||
UnmapViewOfFile(base);
|
||||
}
|
||||
if (hFileMapping != NULL) {
|
||||
CloseHandle(hFileMapping);
|
||||
}
|
||||
if (hFile != INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(hFile);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
#endif
|
||||
|
||||
int cki_attach(injector_t **injector_out, DWORD pid)
|
||||
{
|
||||
injector_t *injector;
|
||||
DWORD dwDesiredAccess = PROCESS_QUERY_LIMITED_INFORMATION | /* for IsWow64Process() */
|
||||
PROCESS_CREATE_THREAD | /* for CreateRemoteThread() */
|
||||
PROCESS_VM_OPERATION | /* for VirtualAllocEx() */
|
||||
PROCESS_VM_READ | /* for ReadProcessMemory() */
|
||||
PROCESS_VM_WRITE; /* for WriteProcessMemory() */
|
||||
USHORT arch;
|
||||
DWORD old_protect;
|
||||
SIZE_T written;
|
||||
int rv;
|
||||
char code[CODE_SIZE];
|
||||
size_t code_size;
|
||||
size_t load_library, free_library, get_last_error;
|
||||
|
||||
if (page_size == 0) {
|
||||
init();
|
||||
}
|
||||
|
||||
load_library = func_LoadLibraryW;
|
||||
free_library = func_FreeLibrary;
|
||||
get_last_error = func_GetLastError;
|
||||
|
||||
injector = (injector_t *)calloc(1, sizeof(injector_t));
|
||||
if (injector == NULL) {
|
||||
set_errmsg("malloc error: %s", strerror(errno));
|
||||
return INJERR_NO_MEMORY;
|
||||
}
|
||||
injector->hProcess = OpenProcess(dwDesiredAccess, FALSE, pid);
|
||||
if (injector->hProcess == NULL) {
|
||||
DWORD err = GetLastError();
|
||||
set_errmsg("OpenProcess error: %s", w32strerr(err));
|
||||
switch (err) {
|
||||
case ERROR_ACCESS_DENIED:
|
||||
rv = INJERR_PERMISSION;
|
||||
break;
|
||||
case ERROR_INVALID_PARAMETER:
|
||||
rv = INJERR_NO_PROCESS;
|
||||
break;
|
||||
default:
|
||||
rv = INJERR_OTHER;
|
||||
}
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
arch = process_arch(injector->hProcess);
|
||||
switch (arch) {
|
||||
#ifdef _M_AMD64
|
||||
case IMAGE_FILE_MACHINE_AMD64:
|
||||
break;
|
||||
case IMAGE_FILE_MACHINE_I386:
|
||||
rv = funcaddr(pid, &load_library, &free_library, &get_last_error);
|
||||
if (rv != 0) {
|
||||
goto error_exit;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef _M_IX86
|
||||
case IMAGE_FILE_MACHINE_I386:
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
set_errmsg("%s target process isn't supported by %s process.", arch_name(arch), CURRENT_ARCH);
|
||||
rv = INJERR_UNSUPPORTED_TARGET;
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
injector->remote_mem
|
||||
= (char *)VirtualAllocEx(injector->hProcess, NULL, 2 * page_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
||||
if (injector->remote_mem == NULL) {
|
||||
set_errmsg("VirtualAllocEx error: %s", w32strerr(GetLastError()));
|
||||
rv = INJERR_OTHER;
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
injector->injection_code = injector->remote_mem;
|
||||
switch (arch) {
|
||||
#ifdef _M_AMD64
|
||||
case IMAGE_FILE_MACHINE_AMD64: /* x64 */
|
||||
memcpy(code, x64_code_template, X64_CODE_SIZE);
|
||||
code_size = X64_CODE_SIZE;
|
||||
*(size_t *)(code + X64_ADDR_LoadLibraryW) = load_library;
|
||||
*(size_t *)(code + X64_ADDR_FreeLibrary) = free_library;
|
||||
*(size_t *)(code + X64_ADDR_GetLastError) = get_last_error;
|
||||
injector->uninjection_code = injector->remote_mem + X64_UNINJECTION_CODE_OFFSET;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(_M_AMD64) || defined(_M_IX86)
|
||||
case IMAGE_FILE_MACHINE_I386: /* x86 */
|
||||
memcpy(code, x86_code_template, X86_CODE_SIZE);
|
||||
code_size = X86_CODE_SIZE;
|
||||
#define FIX_CALL_RELATIVE(addr, offset) \
|
||||
*(uint32_t *)(code + offset + 1) = addr - ((uint32_t)(size_t)injector->remote_mem + offset + 5)
|
||||
FIX_CALL_RELATIVE(load_library, X86_CALL_LoadLibraryW);
|
||||
FIX_CALL_RELATIVE(free_library, X86_CALL_FreeLibrary);
|
||||
FIX_CALL_RELATIVE(get_last_error, X86_CALL_GetLastError1);
|
||||
FIX_CALL_RELATIVE(get_last_error, X86_CALL_GetLastError2);
|
||||
*(uint32_t *)(code + X86_MOV_EAX + 1) = (uint32_t)(size_t)injector->remote_mem + page_size;
|
||||
injector->uninjection_code = injector->remote_mem + X86_UNINJECTION_CODE_OFFSET;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
set_errmsg("Never reach here: arch=0x%x", arch);
|
||||
rv = INJERR_OTHER;
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
if (!WriteProcessMemory(injector->hProcess, injector->remote_mem, code, code_size, &written)) {
|
||||
set_errmsg("WriteProcessMemory error: %s", w32strerr(GetLastError()));
|
||||
rv = INJERR_OTHER;
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
if (!VirtualProtectEx(injector->hProcess, injector->remote_mem, page_size, PAGE_EXECUTE_READ, &old_protect)) {
|
||||
set_errmsg("VirtualProtectEx error: %s", w32strerr(GetLastError()));
|
||||
rv = INJERR_OTHER;
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
*injector_out = injector;
|
||||
return 0;
|
||||
|
||||
error_exit:
|
||||
cki_detach(injector);
|
||||
return rv;
|
||||
}
|
||||
|
||||
int cki_inject(injector_t *injector, const char *path, void **handle)
|
||||
{
|
||||
DWORD pathlen = (DWORD)strlen(path);
|
||||
wchar_t *wpath;
|
||||
DWORD wpathlen;
|
||||
|
||||
if (pathlen == 0) {
|
||||
set_errmsg("The specified path is empty.");
|
||||
return INJERR_FILE_NOT_FOUND;
|
||||
}
|
||||
if (pathlen > MAX_PATH) {
|
||||
set_errmsg("too long file path: %s", path);
|
||||
return INJERR_FILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
wpath = (wchar_t *)_alloca((pathlen + 1) * sizeof(wchar_t));
|
||||
wpathlen = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, path, pathlen, wpath, pathlen + 1);
|
||||
wpath[wpathlen] = L'\0';
|
||||
return cki_inject_w(injector, wpath, handle);
|
||||
}
|
||||
|
||||
int cki_inject_w(injector_t *injector, const wchar_t *path, void **handle)
|
||||
{
|
||||
struct {
|
||||
void *load_address;
|
||||
wchar_t fullpath[MAX_PATH];
|
||||
} data = {
|
||||
NULL,
|
||||
};
|
||||
DWORD pathlen;
|
||||
SIZE_T written;
|
||||
HANDLE hThread;
|
||||
DWORD err;
|
||||
|
||||
pathlen = GetFullPathNameW(path, MAX_PATH, data.fullpath, NULL);
|
||||
if (pathlen > MAX_PATH) {
|
||||
set_errmsg("too long file path: %S", path);
|
||||
return INJERR_FILE_NOT_FOUND;
|
||||
}
|
||||
if (pathlen == 0) {
|
||||
set_errmsg("failed to get the full path: %S", path);
|
||||
return INJERR_FILE_NOT_FOUND;
|
||||
}
|
||||
if (!WriteProcessMemory(injector->hProcess, injector->remote_mem + page_size, &data, sizeof(data), &written)) {
|
||||
set_errmsg("WriteProcessMemory error: %s", w32strerr(GetLastError()));
|
||||
return INJERR_OTHER;
|
||||
}
|
||||
hThread = CreateRemoteThread(injector->hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)injector->injection_code,
|
||||
injector->remote_mem + page_size + sizeof(void *), 0, NULL);
|
||||
if (hThread == NULL) {
|
||||
set_errmsg("CreateRemoteThread error: %s", w32strerr(GetLastError()));
|
||||
return INJERR_OTHER;
|
||||
}
|
||||
WaitForSingleObject(hThread, INFINITE);
|
||||
GetExitCodeThread(hThread, &err);
|
||||
CloseHandle(hThread);
|
||||
if (err != 0) {
|
||||
set_errmsg("LoadLibrary in the target process failed: %s", w32strerr(err));
|
||||
return INJERR_ERROR_IN_TARGET;
|
||||
}
|
||||
if (!ReadProcessMemory(injector->hProcess, injector->remote_mem + page_size, &data, sizeof(void *), &written)) {
|
||||
set_errmsg("ReadProcessMemory error: %s", w32strerr(GetLastError()));
|
||||
return INJERR_OTHER;
|
||||
}
|
||||
if (handle != NULL) {
|
||||
*handle = data.load_address;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cki_uninject(injector_t *injector, void *handle)
|
||||
int InjectDll(DWORD pid, const WCHAR *dllPath)
|
||||
{
|
||||
HANDLE hThread;
|
||||
DWORD err;
|
||||
DWORD dwWriteSize = 0;
|
||||
// 1. 获取目标进程,并在目标进程的内存里开辟空间
|
||||
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
|
||||
LPVOID pRemoteAddress = VirtualAllocEx(hProcess, NULL, 1, MEM_COMMIT, PAGE_READWRITE);
|
||||
|
||||
hThread = CreateRemoteThread(injector->hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)injector->uninjection_code,
|
||||
handle, 0, NULL);
|
||||
if (hThread == NULL) {
|
||||
set_errmsg("CreateRemoteThread error: %s", w32strerr(GetLastError()));
|
||||
return INJERR_OTHER;
|
||||
// 2. 把 dll 的路径写入到目标进程的内存空间中
|
||||
if (pRemoteAddress) {
|
||||
WriteProcessMemory(hProcess, pRemoteAddress, dllPath, wcslen(dllPath) * 2 + 2, &dwWriteSize);
|
||||
} else {
|
||||
MessageBox(NULL, L"DLL 路径写入失败", L"InjectDll", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 3. 创建一个远程线程,让目标进程调用 LoadLibrary
|
||||
hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)LoadLibrary, pRemoteAddress, NULL, NULL);
|
||||
if (hThread) {
|
||||
WaitForSingleObject(hThread, -1);
|
||||
} else {
|
||||
MessageBox(NULL, L"LoadLibrary 调用失败", L"InjectDll", 0);
|
||||
return -2;
|
||||
}
|
||||
WaitForSingleObject(hThread, INFINITE);
|
||||
GetExitCodeThread(hThread, &err);
|
||||
CloseHandle(hThread);
|
||||
if (err != 0) {
|
||||
set_errmsg("FreeLibrary in the target process failed: %s", w32strerr(err));
|
||||
return INJERR_ERROR_IN_TARGET;
|
||||
}
|
||||
VirtualFreeEx(hProcess, pRemoteAddress, 0, MEM_RELEASE);
|
||||
CloseHandle(hProcess);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cki_detach(injector_t *injector)
|
||||
int EjectDll(DWORD pid, const WCHAR *dllPath)
|
||||
{
|
||||
if (injector->remote_mem != NULL) {
|
||||
VirtualFreeEx(injector->hProcess, injector->remote_mem, 0, MEM_RELEASE);
|
||||
DWORD dwHandle, dwID;
|
||||
HANDLE hThread = NULL;
|
||||
DWORD dwWriteSize = 0;
|
||||
|
||||
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
|
||||
LPVOID pRemoteAddress = VirtualAllocEx(hProcess, NULL, 1, MEM_COMMIT, PAGE_READWRITE);
|
||||
|
||||
if (pRemoteAddress)
|
||||
WriteProcessMemory(hProcess, pRemoteAddress, dllPath, wcslen(dllPath) * 2 + 2, &dwWriteSize);
|
||||
else {
|
||||
MessageBox(NULL, L"DLL 路径写入失败", L"EjectDll", 0);
|
||||
return -1;
|
||||
}
|
||||
if (injector->hProcess != NULL) {
|
||||
CloseHandle(injector->hProcess);
|
||||
hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)GetModuleHandleW, pRemoteAddress, 0, &dwID);
|
||||
if (hThread) {
|
||||
WaitForSingleObject(hThread, INFINITE);
|
||||
GetExitCodeThread(hThread, &dwHandle);
|
||||
} else {
|
||||
MessageBox(NULL, L"GetModuleHandleW 调用失败!", L"EjectDll", 0);
|
||||
return -2;
|
||||
}
|
||||
free(injector);
|
||||
CloseHandle(hThread);
|
||||
|
||||
// 使目标进程调用 FreeLibrary,卸载 DLL
|
||||
hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)FreeLibrary, (LPVOID)dwHandle, 0, &dwID);
|
||||
if (hThread) {
|
||||
WaitForSingleObject(hThread, INFINITE);
|
||||
} else {
|
||||
MessageBox(NULL, L"FreeLibrary 调用失败!", L"EjectDll", 0);
|
||||
return -3;
|
||||
}
|
||||
CloseHandle(hThread);
|
||||
VirtualFreeEx(hProcess, pRemoteAddress, 0, MEM_RELEASE);
|
||||
CloseHandle(hProcess);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *cki_error(void) { return errmsg; }
|
||||
|
||||
static void set_errmsg(const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int rv;
|
||||
|
||||
va_start(ap, format);
|
||||
rv = vsnprintf(errmsg, sizeof(errmsg), format, ap);
|
||||
va_end(ap);
|
||||
if (rv == -1 || rv >= sizeof(errmsg)) {
|
||||
errmsg[sizeof(errmsg) - 1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
static const char *w32strerr(DWORD err)
|
||||
{
|
||||
static char errmsg[512];
|
||||
DWORD len;
|
||||
|
||||
len = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err,
|
||||
MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), errmsg, sizeof(errmsg), NULL);
|
||||
if (len > 0) {
|
||||
while (len > 0) {
|
||||
char c = errmsg[len - 1];
|
||||
if (c == ' ' || c == '\n' || c == '\r') {
|
||||
len--;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
errmsg[len] = '\0';
|
||||
} else if ((int)err >= 0) {
|
||||
sprintf(errmsg, "win32 error code %d", err);
|
||||
} else {
|
||||
sprintf(errmsg, "win32 error code 0x%x", err);
|
||||
}
|
||||
return errmsg;
|
||||
}
|
||||
|
||||
static USHORT process_arch(HANDLE hProcess)
|
||||
{
|
||||
static IsWow64Process2_t IsWow64Process2_func = (IsWow64Process2_t)-1;
|
||||
if (IsWow64Process2_func == (IsWow64Process2_t)-1) {
|
||||
IsWow64Process2_func = (IsWow64Process2_t)GetProcAddress(GetModuleHandleA("kernel32"), "IsWow64Process2");
|
||||
}
|
||||
if (IsWow64Process2_func != NULL) {
|
||||
/* Windows 10 */
|
||||
USHORT process_machine;
|
||||
USHORT native_machine;
|
||||
if (IsWow64Process2_func(hProcess, &process_machine, &native_machine)) {
|
||||
if (process_machine != IMAGE_FILE_MACHINE_UNKNOWN) {
|
||||
return process_machine;
|
||||
} else {
|
||||
return native_machine;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Windows 8.1 or earlier */
|
||||
/* arch will be either x86 or x64. */
|
||||
#ifdef _M_AMD64
|
||||
BOOL is_wow64_proc;
|
||||
if (IsWow64Process(hProcess, &is_wow64_proc)) {
|
||||
if (is_wow64_proc) {
|
||||
return IMAGE_FILE_MACHINE_I386;
|
||||
} else {
|
||||
return IMAGE_FILE_MACHINE_AMD64;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef _M_IX86
|
||||
BOOL is_wow64_proc;
|
||||
if (IsWow64Process(GetCurrentProcess(), &is_wow64_proc)) {
|
||||
if (!is_wow64_proc) {
|
||||
/* Run on 32-bit Windows */
|
||||
return IMAGE_FILE_MACHINE_I386;
|
||||
}
|
||||
/* Run on Windows x64 */
|
||||
if (IsWow64Process(hProcess, &is_wow64_proc)) {
|
||||
if (is_wow64_proc) {
|
||||
return IMAGE_FILE_MACHINE_I386;
|
||||
} else {
|
||||
return IMAGE_FILE_MACHINE_AMD64;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return IMAGE_FILE_MACHINE_UNKNOWN;
|
||||
}
|
||||
|
||||
static const char *arch_name(USHORT arch)
|
||||
{
|
||||
switch (arch) {
|
||||
case IMAGE_FILE_MACHINE_AMD64:
|
||||
return "x64";
|
||||
case IMAGE_FILE_MACHINE_I386:
|
||||
return "x86";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
BOOL InjectDll(DWORD pid, const WCHAR *dllpath)
|
||||
{
|
||||
if (cki_attach(&g_injector, pid) != 0) {
|
||||
printf("%s\n", cki_error());
|
||||
return FALSE;
|
||||
}
|
||||
if (cki_inject_w(g_injector, dllpath, NULL) == 0) {
|
||||
return TRUE;
|
||||
} else {
|
||||
fprintf(stderr, " %s\n", cki_error());
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL EnjectDll(DWORD pid, const WCHAR *dllname)
|
||||
{
|
||||
if (cki_detach(g_injector) == 0) {
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
@ -1,40 +1,6 @@
|
||||
#ifndef __INJECTOR_H__
|
||||
#define __INJECTOR_H__
|
||||
#pragma once
|
||||
|
||||
#include "framework.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define INJERR_SUCCESS 0
|
||||
#define INJERR_OTHER -1
|
||||
#define INJERR_NO_MEMORY -2
|
||||
#define INJERR_NO_PROCESS -3
|
||||
#define INJERR_NO_LIBRARY -4
|
||||
#define INJERR_NO_FUNCTION -4
|
||||
#define INJERR_ERROR_IN_TARGET -5
|
||||
#define INJERR_FILE_NOT_FOUND -6
|
||||
#define INJERR_INVALID_MEMORY_AREA -7
|
||||
#define INJERR_PERMISSION -8
|
||||
#define INJERR_UNSUPPORTED_TARGET -9
|
||||
#define INJERR_INVALID_ELF_FORMAT -10
|
||||
#define INJERR_WAIT_TRACEE -11
|
||||
|
||||
typedef struct injector injector_t;
|
||||
|
||||
int cki_attach(injector_t **injector, DWORD pid);
|
||||
int cki_inject(injector_t *injector, const char *path, void **handle);
|
||||
int cki_inject_w(injector_t *injector, const wchar_t *path, void **handle);
|
||||
int cki_uninject(injector_t *injector, void *handle);
|
||||
int cki_detach(injector_t *injector);
|
||||
const char *cki_error(void);
|
||||
|
||||
BOOL InjectDll(DWORD pid, const WCHAR *dllpath);
|
||||
BOOL EnjectDll(DWORD pid, const WCHAR *dllname);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}; /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif
|
||||
int InjectDll(DWORD pid, const WCHAR* dllPath);
|
||||
int EjectDll(DWORD pid, const WCHAR* dllPath);
|
||||
|
@ -35,7 +35,7 @@ int WxInitSDK()
|
||||
return status;
|
||||
}
|
||||
Sleep(2000); // 等待微信打开
|
||||
if (!InjectDll(WeChatPID, SpyDllPath)) {
|
||||
if (InjectDll(WeChatPID, SpyDllPath)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -51,7 +51,7 @@ int WxInitSDK()
|
||||
int WxDestroySDK()
|
||||
{
|
||||
RpcDisconnectServer();
|
||||
EnjectDll(WeChatPID, SpyDllPath);
|
||||
EjectDll(WeChatPID, SpyDllPath);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user