Перейти к содержанию

Внедрение C/C++ функций в чужой процесс.


Рекомендуемые сообщения

Спойлер

/*
	Внедрение C/C++ функций в чужой процесс.

	Компилятор MinGW.

	Делаем так: Помещяем функции и переменные в отдельные секции, потом эти секции копируем в чужой процесс.
	Перед копированием функций - нужно изменять статические адреса на новые, reloc укажет в каких местах изменять.


	Добавляем параметры для линкера.
	Добавим reloc [-Wl,-pie], но после этого параметра - точка входа указывает неправильно.
	Восстанавливаем точку входа [-Wl,--entry,_mainCRTStartup] или [-Wl,--entry,mainCRTStartup].
*/


#include <stdio.h>
#include <windows.h>
#include <tlhelp32.h>

typedef DWORD_PTR ADDRESS;


//Можно поменять название на свои, максимум 8 символов.
#define name_section_text "._text"
#define name_section_data "._data"


#define __text __attribute__ ((section (name_section_text), used))
#define __data __attribute__ ((section (name_section_data), used))



struct Sections
{
	struct section_region
	{
		ADDRESS begin;
		DWORD size;
	} text, data, reloc;
};

static void sections_clear(struct Sections *s)
{
	s->text.begin = s->text.size = 0;
	s->data.begin = s->data.size = 0;
	s->reloc.begin = s->reloc.size = 0;
}



typedef HMODULE (*WINAPI _GetModuleHandleA) (LPCSTR);
typedef FARPROC (*WINAPI _GetProcAddress) (HMODULE, LPCSTR);
typedef int (*WINAPI _MessageBoxA) (HWND, LPCSTR, LPCSTR, UINT);


//Ставим атрибуты __data для переменных и __text для функций.
//const не ставим - работать не будет.

__data static _GetModuleHandleA pGetModuleHandleA;
__data static _GetProcAddress pGetProcAddress;
__data static _MessageBoxA pMessageBoxA;



//////////////////////////////////////////////////////////////////////
__data static char str_user32_dll[] = "USER32.dll";
__data static char str_messageboxa[] = "MessageBoxA";

//Выполняем инициализацию в чужом процессе.
__text static void process_function_init()
{
	HMODULE kernel32 = pGetModuleHandleA(str_user32_dll);
	pMessageBoxA = (_MessageBoxA)pGetProcAddress(kernel32, str_messageboxa);
}
//////////////////////////////////////////////////////////////////////



//////////////////////////////////////////////////////////////////////
__data static char str_hello[] = "Hello";
__data static char str_message[] = "message";

//Вызываем MessageBox в чужом процессе.
static void process_function_message() asm("process_function_message"); //label for asm
__text static void process_function_message()
{
	pMessageBoxA(NULL, str_hello, str_message, MB_OK);
}
//////////////////////////////////////////////////////////////////////



//////////////////////////////////////////////////////////////////////
__data static int process_variable_test asm("process_variable_test") = 0;

__text static void ASM()
{
#ifdef WIN64
	__asm__
	(
	".intel_syntax noprefix\n\t"
	"process_function_asm:"
	"sub rsp, 0x28\n\t"
	"mov rax, 1\n\t"
	"mov process_variable_test, rax\n\t"
	"call process_function_message\n\t"
	"add rsp, 0x28\n\t"
	"ret\n\t"
	".att_syntax noprefix"
	);
#else
	__asm__
	(
	".intel_syntax noprefix\n\t"
	"process_function_asm:"
	"mov eax, 1\n\t"
	"mov process_variable_test, eax\n\t"
	"call process_function_message\n\t"
	"ret\n\t"
	".att_syntax noprefix"
	);
#endif
}
//////////////////////////////////////////////////////////////////////







//Функция правит статические адреса.
static void displace_addresses(const ADDRESS base,
							   const struct Sections *sections,
							   ADDRESS buffer,
							   const DWORD value)
{
	PIMAGE_BASE_RELOCATION reloc = (PIMAGE_BASE_RELOCATION)sections->reloc.begin;
	DWORD offset = 0;
	const ADDRESS text_begin = sections->text.begin;
	const ADDRESS text_end = sections->text.begin + sections->text.size;
	while (offset != sections->reloc.size) {
		DWORD offset_buf_size = (reloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD);
		WORD *type_and_offset = (WORD*)((ADDRESS)reloc + sizeof(IMAGE_BASE_RELOCATION));
		for (DWORD i = 0; i != offset_buf_size; i++) {
			if (type_and_offset[i] >> 12) {
				ADDRESS address = (base + reloc->VirtualAddress + (type_and_offset[i] & 0x0FFF));
				if (text_begin <= address && text_end > address) {
					const DWORD offset = (address - sections->text.begin);
					//printf("changed %08lX\n", offset);
					*(DWORD*)(buffer + offset) += value;
				}
			}
		}
		offset += reloc->SizeOfBlock;
		reloc = (PIMAGE_BASE_RELOCATION)((ADDRESS)reloc + reloc->SizeOfBlock);
	}
}



static void init_sections(ADDRESS base_address, struct Sections *sections)
{
	sections_clear(sections);
	const PIMAGE_DOS_HEADER image_dos_header = (PIMAGE_DOS_HEADER)base_address;
	const PIMAGE_NT_HEADERS image_nt_header = (PIMAGE_NT_HEADERS)(base_address + image_dos_header->e_lfanew);
	const ADDRESS section = image_dos_header->e_lfanew + image_nt_header->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + sizeof(DWORD);
	PIMAGE_SECTION_HEADER image_section_header = (PIMAGE_SECTION_HEADER)(base_address + section);

	for (WORD i = 0; i < image_nt_header->FileHeader.NumberOfSections; i++, image_section_header++) {
		const char *name = (const char*)image_section_header->Name;
		const ADDRESS begin = base_address + image_section_header->VirtualAddress;
		const DWORD size = image_section_header->Misc.VirtualSize;
		if (!strcmp(name, name_section_text)) {
			sections->text.begin = begin;
			sections->text.size = size;
		} else if (!strcmp(name, name_section_data)) {
			sections->data.begin = begin;
			sections->data.size = size;
		}
	}

	const PIMAGE_DATA_DIRECTORY dir = &image_nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
	sections->reloc.begin = base_address + dir->VirtualAddress;
	sections->reloc.size = dir->Size;
}


static void init_start_functions()
{
	HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
	pGetModuleHandleA = (_GetModuleHandleA)GetProcAddress(kernel32, "GetModuleHandleA");
	pGetProcAddress = (_GetProcAddress)GetProcAddress(kernel32, "GetProcAddress");
}

struct ProcessMemory
{
	ADDRESS base;
	DWORD size;
	ADDRESS text, data;
};


//0x500 -> 0x1000, 0x2001 -> 0x3000
static DWORD align_size(DWORD size)
{
	union { struct { unsigned a:12; unsigned b:20; }; DWORD c;} u;
	u.c = size;
	if (u.a == 0) {
		return size;
	} else {
		u.a = 0;
		u.b++;
	}
	return u.c;
}


static BOOL injection(const ADDRESS base_address,
					  const struct Sections *sections,
					  const HANDLE hProcess,
					  struct ProcessMemory *memory)
{
	const DWORD text_size = align_size(sections->text.size);
	const DWORD data_size = align_size(sections->data.size);

#ifndef WIN64
	//for x86
	memory->size = text_size + data_size;
	memory->base = (ADDRESS)VirtualAllocEx(hProcess, 0, memory->size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	if (memory->base == 0)
		return FALSE;
	memory->text = memory->base;
	memory->data = memory->text + text_size;
#else
	//for x64
	const DWORD intermediate = sections->data.begin - sections->text.begin;
	memory->size = text_size + intermediate + data_size;
	memory->base = (ADDRESS)VirtualAllocEx(hProcess, 0, memory->size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	if (memory->base == 0)
		return FALSE;
	memory->text = memory->base;
	memory->data = memory->text + intermediate;
#endif

	DWORD oldProtect;

	//text
	PVOID buffer = malloc(sections->text.size);
	memcpy(buffer, (PVOID)sections->text.begin, sections->text.size); //Копируем исполняемый код в буфер.
	displace_addresses(base_address, sections, (ADDRESS)buffer, memory->data -  sections->data.begin); //Изменим адреса переменных с помощью reloc.
	WriteProcessMemory(hProcess, (PVOID)memory->text, buffer, sections->text.size, NULL); //Запишем в процесс.
	free(buffer);
	VirtualProtectEx(hProcess, (PVOID)memory->text, sections->text.size, PAGE_EXECUTE_READ, &oldProtect); //Изменим защиту на выполнение.

	//data
	WriteProcessMemory(hProcess, (PVOID)memory->data, (PBYTE)sections->data.begin, sections->data.size, NULL); //Записываем данные в процесс.
	VirtualProtectEx(hProcess, (PVOID)memory->data, sections->data.size, PAGE_READWRITE, &oldProtect); //Изменим защиту на чтение/запись.

	return TRUE;
}


//Создаёт поток в чужом процессе.
static void createRemoteThread(const HANDLE hProcess, const ADDRESS address)
{
	const HANDLE handle = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)address, NULL, 0, NULL);
	WaitForSingleObject(handle, INFINITE);
	CloseHandle(handle);
}

//Поиск процесса по названию.
static DWORD findProcess(const wchar_t *name)
{
	DWORD PID = 0;

	const HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
	if (hSnap == NULL)
		return PID;

	PROCESSENTRY32W proc;
	proc.dwSize = sizeof(PROCESSENTRY32W);
	if (Process32FirstW(hSnap, &proc)) {
		do {
			if (!wcscmp(proc.szExeFile, name)) {
				PID = proc.th32ProcessID;
				break;
			}
		} while (Process32NextW(hSnap, &proc));
	}

	CloseHandle(hSnap);
	return PID;
}




static ADDRESS getProcessAddressText(void *address, const struct Sections *sections, const struct ProcessMemory *memory)
{
	return ((ADDRESS)address - sections->text.begin) + memory->text;
}

static ADDRESS getProcessAddressData(void *address, const struct Sections *sections, const struct ProcessMemory *memory)
{
	return ((ADDRESS)address - sections->data.begin) + memory->data;
}


int main()
{
	const ADDRESS base_address = (ADDRESS)GetModuleHandleA(NULL); //Получим базовый адрес (0x00400000)


	struct Sections sections;
	init_sections(base_address, &sections); //Находим ._text, ._data и .reloc

	if (sections.reloc.size == 0) {
		printf("no section reloc\n");
		return -1;
	}

	printf("section text.size %08lX\n", sections.text.size);
	printf("section data.size %08lX\n", sections.data.size);


	init_start_functions(); //Получим адреса GetModuleHandleA и GetProcAddress.


	const DWORD pid = findProcess(L"calc.exe");
	if (pid == 0) {
		printf("not found process\n");
		return -1;
	}

	const HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
	if (hProcess == NULL) {
		printf("error open process\n");
		return -1;
	}



	//Внедряем
	struct ProcessMemory memory;
	if (!injection(base_address, &sections, hProcess, &memory)) {
		printf("error injection\n");
		return -1;
	}

	printf("process address %08lX size %08lX\n", (DWORD)memory.base, memory.size);
	printf("text %08lX\n", (DWORD)memory.text);
	printf("data %08lX\n", (DWORD)memory.data);


	void *process_function_asm;
	asm("lea process_function_asm, %0" : "=r" (process_function_asm)); //Получим адрес метки асм.


	//Получим адреса наших функций и переменных.
	const ADDRESS address_init = getProcessAddressText((void*)&process_function_init, &sections, &memory);
	const ADDRESS address_message = getProcessAddressText((void*)&process_function_message, &sections, &memory);
	const ADDRESS address_asm = getProcessAddressText(process_function_asm, &sections, &memory);
	const ADDRESS address_variable_test = getProcessAddressData(&process_variable_test, &sections, &memory);

	printf("address init %08lX\n", (DWORD)address_init);
	printf("address message %08lX\n", (DWORD)address_message);
	printf("address asm %08lX\n", (DWORD)address_asm);
	printf("address variable_test %08lX\n", (DWORD)address_variable_test);

	fflush(stdout); //for printf

	//Выполняем функции в чужом процессе.
	createRemoteThread(hProcess, address_init); //Инициализируем.
	createRemoteThread(hProcess, address_message); //Покажем сообщение.
	createRemoteThread(hProcess, address_message); //Покажем сообщение.
	createRemoteThread(hProcess, address_asm); //Покажем сообщение через асм.


	//VirtualFreeEx(hProcess, (PVOID)m.base, 0, MEM_RELEASE);

	CloseHandle(hProcess);

	return 0;
}

 

 

Изменено пользователем Hack
Ссылка на комментарий
Поделиться на другие сайты

В 25.10.2019 в 21:07, Hack сказал:

HMODULE kernel32 = GetModuleHandleA("kernel32.dll");

pGetModuleHandleA = (_GetModuleHandleA)GetProcAddress(kernel32, "GetModuleHandleA");

pGetProcAddress = (_GetProcAddress)GetProcAddress(kernel32, "GetProcAddress");

это и похоже - что бы было больше текста? :D

(LPTHREAD_START_ROUTINE)GetModuleHandleA
(LPTHREAD_START_ROUTINE)GetProcAddress

 

Ссылка на комментарий
Поделиться на другие сайты

×
×
  • Создать...

Важная информация

Находясь на нашем сайте, Вы автоматически соглашаетесь соблюдать наши Условия использования.