WarCraft 3: Вызов функций вк 3, через mix (dll)

» Раздел: Основы
» Автор оригинала: Snowww (я)

постараюсь объяснить максимально просто,без теории (совсем без теории).
Во первых нам понадобиться c++ (или аналог)
  1. Создаем новый проект, динамичная dll библиотека.
будет что-то на подобии этого:

#include "stdafx.h"

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
					 )
{
	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:
	case DLL_THREAD_ATTACH:
	case DLL_THREAD_DETACH:
	case DLL_PROCESS_DETACH:
		break;
	}
	return TRUE;
}
Чтобы работать с jass`вскими функциями варика, во первых нужно узнать, хендл либы game.dll
добавляем 2 строчки:
глобальную переменную DWORD GameDll; и получение аддрес game.dll в памяти: GameDll = (DWORD) GetModuleHandle("Game.dll");


#include "stdafx.h"

DWORD GameDll = 0;



BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
					 )
{
	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:
		{
			GameDll = (DWORD) GetModuleHandle("Game.dll");

			break;
		}

	case DLL_THREAD_ATTACH:
	case DLL_THREAD_DETACH:
	case DLL_PROCESS_DETACH:
		break;
	}
	return TRUE;
}
  1. Шаг - добавление функций.
к примеру, попытаемся изменить уровень максимального значения апгрейда. В файле, что кидал, ищем: SetPlayerTechMaxAllowed, находим следующую строчку:
SetPlayerTechMaxAllowed (Hplayer;II)V 0x3c9660
Где 0x3c9660 адресс этой функции. (Hplayer;II) - переменные Hplayer и 2 integer.
Пишем вызов функции, это будет выглядеть вот так:
__declspec(naked) void __cdecl SetPlayerTechMaxAllowed(Hplayer WhichPlayer, int TechId, int Maximum)
{
	_asm
	{
		mov eax, GameDll
		add eax, 0x3C9660
		jmp eax
	}
}
к регистру eax присваиваем адресс game.dll и добавляем адресс, тот который нашли ранее. Не забываем добавить тип "Hplayer"
typedef DWORD Hplayer;
Нам так-же понадобиться функция "Player(0)", делаем тоже самое, что и с SetPlayerTechMaxAllowed
declspec(naked) Hplayer cdecl Player(int number)
{
_asm
{
mov eax, GameDll
add eax, 0x3BBB30
jmp eax
}
}
  1. Вызов, к примеру по нажатие на клавишу end. ничего писать не буду, просто кину финальный код.
#include "stdafx.h"
#define IS_KD(lParam) ((lParam & ((DWORD)1<<30)) ==  0 && (lParam & ((DWORD)1<<31)) == 0)
DWORD GameDll = 0;
typedef DWORD Hplayer;
HHOOK KHook = NULL;


__declspec(naked) Hplayer __cdecl Player(int number)
{
	_asm
	{
		mov eax, GameDll
		add eax, 0x3BBB30
		jmp eax
	}
}

__declspec(naked) void __cdecl SetPlayerTechMaxAllowed(Hplayer WhichPlayer, int TechId, int Maximum)
{
	_asm
	{
		mov eax, GameDll
		add eax, 0x3C9660
		jmp eax
	}
}



LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{

	if (IS_KD(lParam) )
	{
	

		SetPlayerTechMaxAllowed(Player(15), 4,28); 

	}





	return CallNextHookEx(KHook, nCode, wParam, lParam);
}

BOOL APIENTRY DllMain(  HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
					 )

{
	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:
		{
			GameDll = (DWORD) GetModuleHandle("Game.dll");


			KHook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, hModule, GetCurrentThreadId());
			break;
		}
	case DLL_PROCESS_DETACH:
		{

			UnhookWindowsHookEx(KHook);
			break;
		}
		break;
	}
	return TRUE;
}
принципе пока все, в след статье расскажу про хуки, и как вызвать из под варика функции нашей библиотеки (но без теории не обойтись).

Просмотров: 1 749

» Лучшие комментарии


Alexander12 #1 - 1 год назад 0
Не забываем .dll переименовать в mix )
ENAleksey #2 - 1 год назад (отредактировано ) 0
Alexander12, в нирване используется тот же метод, только для отлова RenderState'а:
» раскрыть
#include "GameHook.h"

namespace HOOK {
	static DWORD next_line;
	volatile DWORD g_GameBase;
	volatile DWORD g_CurrentRenderTarget;
	volatile RENDER_TYPE g_CurrentRenderType;
	volatile DWORD currentRenderCall;
	DWORD address_render_state_sequence;
	DWORD address_render_target_switch;
	DWORD address_render_target_switch_default_case;
	DWORD address_render_mesh;
	DWORD address_render_mesh_real_func;
	DWORD address_render_particle;
	DWORD address_render_particle_real_func;

	//
	// Trampoline functions
	//
	#pragma warning(push)
	#pragma warning(disable : 4740)
	__declspec (naked) void render_state_sequence()
	{
		__asm
		{
			mov edx, [eax+0x30];
			mov ecx, edi;
			pushad;
			mov [currentRenderCall], edx;
		}

		next_line = address_render_state_sequence + 5;

		__asm
		{
			popad;
			jmp [next_line];
		}
	}
	__declspec (naked) void render_target_switch()
	{
		// Save all registers
		__asm 
		{
			pushad;
			mov [g_CurrentRenderTarget], eax;
		}

		next_line = address_render_target_switch + 9; // 9 bytes after the original address

		// Restore the original code
		__asm
		{
			popad;
			cmp eax, 0x15
			ja default_case;
			jmp [next_line];
		default_case:
			jmp [address_render_target_switch_default_case];
		}
	}
	__declspec (naked) void render_mesh()
	{
		__asm pushad;

		g_CurrentRenderType = D3D_MESH;
		next_line = address_render_mesh + 5;

		__asm
		{
			popad;
			call address_render_mesh_real_func;
			jmp next_line;
		}
	}
	__declspec (naked) void render_particle()
	{
		__asm pushad;

		g_CurrentRenderType = D3D_PARTICLE;
		next_line = address_render_particle + 5;

		__asm
		{
			popad;
			call [address_render_particle_real_func];
			jmp next_line;
		}
	}
	#pragma warning(pop)

	void deployHooks()
	{
		// Initialize offests
		g_GameBase = (DWORD)GetModuleHandle("Nirvana.dll");
		address_render_state_sequence = g_GameBase + RENDER_STATE_SEQUENCE;
		address_render_target_switch = g_GameBase + RENDER_TARGET_SWITCH;
		address_render_target_switch_default_case = g_GameBase + RENDER_TARGET_SWITCH_DEFAULT_CASE;
		address_render_mesh = g_GameBase + CALL_TO_RENDER_MESH;
		address_render_particle = g_GameBase + CALL_TO_RENDER_PARTICLE;

		// Hook
		address_render_mesh_real_func = getFuncPtr(address_render_mesh+1);
		address_render_particle_real_func = getFuncPtr(address_render_particle+1);

		JmpPatch(render_state_sequence, (void*)address_render_state_sequence);
		JmpPatch(render_target_switch, (void*)address_render_target_switch, 4);
		JmpPatch(render_mesh, (void*)address_render_mesh);
		JmpPatch(render_particle, (void*)address_render_particle);
	}

	RENDER_STATE getCurrentRenderState()
	{
		int offest = currentRenderCall - g_GameBase;
		switch (offest)
		{
		case RENDER_UNIT_AND_EFFECT_FUNC:
			return STATE_UNIT_AND_EFFECT;
			break;
		case RENDER_UNKNOWN_1_FUNC:
			return STATE_PORTRAIT;
			break;
		case RENDER_MAYJOR_UI_FUNC:
			return STATE_MAYJOR_UI;
			break;
		case RENDER_MINOR_UI_FUNC:
			return STATE_MINOR_UI;
			break;
		case RENDER_MINI_MAP_FUNC:
			return STATE_MINI_MAP;
			break;
		default:
			break;
		}
		return STATE_NULL;
	}
}
Так что вполне реально сделать то, что ты задумал - отрисовка дополнительного интерфейса поверх стандартного.
Ну, попробую поэкспериментировать.
Только напиши, как вызывать функции библиотеки из игры на jass (можешь пока в лс).
Alexander12 #3 - 1 год назад (отредактировано ) 2
Насчет вызова игровых функций (пользовательские).
Есть несколько способов.
  1. ExecuteFunc (для 1 игрока)
  2. Пересылка адресса нужной нашей функции.
  3. Цикл 0.01. на проверку данных со стороны игры, если в хештаблицы опр значение не равно 0, то вызываем функцию.
так насчет 2 способа, как передать адресс ?
без хука не обойтись. возьмем какую нибудь функцию, которая получает код, например StartThread , которая принимает code.
		*(BYTE*)	(GameDll + 0x2de2a0+ 0x0)	= 0xE8;	
		*(DWORD*)	(GameDll + 0x2de2a0+ 0x1)	= (DWORD)hookCHS - (dwGameBaseAddress + 0x2de2a0+ 0x5);
		*(BYTE*)	(GameDll + 0x2de2a0+ 0x5)	= 0xC3;		
И в итоге вызывается наша функция hookCHS, в ней же получаем код функции. по адресу вызываем сию функцию
JaBeN_Симфер #4 - 1 год назад 0
Можно ли сделать обмен данными с сервером?
Alexander12 #5 - 1 год назад 5
JaBeN_Симфер:
Можно ли сделать обмен данными с сервером?
Конечно, любую функцию в нашей длл, можно вызывать из под варика.
quq_CCCP #6 - 1 год назад 0
Нужно будет попробовать вызвать preloader...
alexprey #7 - 1 год назад 0
Хм.. интересно, можно как-нибудь прокрутить взаимодействие, чтобы из под плюсов вызывались методы .net библиотеки :D
мне даже захотелось побаловаться...
Alexander12 #8 - 1 год назад 0
ужно будет попробовать вызвать preloader...
quq_CCCP #9 - 1 год назад (отредактировано ) 0
Alexander12:
ужно будет попробовать вызвать preloader...
Во во, надо будет тоже поиздеваться над ракапом, чисто из спортивного интереса...
ENAleksey #10 - 1 год назад (отредактировано ) 6
Получилось!
Передаю строку текста, введённого в чат, в библиотеку, где её перехватываю, обрабатываю и вывожу на экран поверх игры с помощью d3d хука:
output << "GAME CHAT INPUT: " << HOOK::ConvertToChar(HOOK::LoadStr(HT, -3, 3)) << std::endl;
Jass код передачи данных в библиотеку:
function Test takes nothing returns nothing
    call SaveStr(HT, -3, 3, GetEventPlayerChatString())
endfunction

function InitTrig_Test takes nothing returns nothing
    local trigger trig = CreateTrigger()
    call TriggerRegisterPlayerChatEvent(trig, Player(0), "", false)
    call TriggerAddAction(trig, function Test)
endfunction
Уже можно выводить текст, изображения и создавать меши, вызывая нужные jass функции из игры, но пока только в RenderEdge.
Теперь я помогу Александру добавить хук Direct3D в его библиотеку и постараюсь сделать это так, чтобы не требовалось использовать дополнительный launcher, придерживаясь идеи использовать только один .mix файл.
прикреплены файлы
quq_CCCP #11 - 1 год назад 2
Мб либу сюда? Сделаем ICCUP WIN HACK - доступным народу!
Ну а если поделу интересен именно preloader и писать в кешь свои данные, подгружая параметры в через тхт файлик.
Alexander12 #12 - 10 месяцев назад 0
Вскоре покажу как вызвать mix или dll которая содержится в самой карте
Это сообщение удалено
Vitalik8 #14 - 3 месяца назад (отредактировано ) 0
А можеш зделать более подробно?