Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Низкоуровневое программирование > Win Api
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 07.05.2010, 15:41   #1
BOBAH13
Android Developer
Старожил Подтвердите свой е-майл
 
Аватар для BOBAH13
 
Регистрация: 19.02.2007
Сообщений: 3,708
По умолчанию Перехват API

Приветствую.
Ситуация такова: работаю на Windows 7 x64. Мое приложение (и .dll соответственно) являются x32. Прошу помощи в "тыкни носом", т.к. отлавливает события вроде нормально (сделал тестовое приложение), а вот если передать управление оригинальной функции, то все приложения крушатся.

Собственно ниже приведу как все делаю, прошу уделить некоторое время на обсуждение данной проблемы. Не упускаю возможность, что я сам виноват (а то, тогда кто?). Думаю мимо проходящим тоже будем интересно.

Intercept.h
Код:
#ifndef INTERCEPT_H
#define INTERCEPT_H

#include <windows.h>
#include <TlHelp32.h>

bool ThreadsState(bool suspend);

bool InterceptAPI(wchar_t *module, char *functionName, void *functionInterceptAddr, void **functionOldAddr);
bool InterceptAPIRestore(void *functionOldAddr);

#define INTERCEPT_DECLARE_INFO(a) void *oldAddr##a##;
#define INTERCEPT_API(a, b) InterceptAPI(a, #b, &ic##b, &oldAddr##b);
#define INTERCEPT_RESTORE(a) InterceptAPIRestore(oldAddr##a);
#define INTERCEPT_CALLREAL(a) oldAddr##a

#endif /* INTERCEPT_H */
Intercept.cpp
Код:
#include "intercept.h"

WORD OPCODES1[256] = {...}; // брал тут 
http://www.sql.ru/forum/actualthread.aspx?bid=20&tid=745040
WORD OPCODES2[256] = {...};
WORD OPCODES3[10][16] = {...};

DWORD InterceptAPISaveFunction(void *functionAddr, void *functionOldAddr)
{
	DWORD saveSize = 0;
	void *next = functionAddr;
	while(saveSize < 5)
	{
		DWORD size = SizeOfCode(next);
		next = (void*)((DWORD)next + size);
		saveSize += size;
	}
	memcpy(functionOldAddr, functionAddr, saveSize);
	(*((BYTE*)((DWORD)functionOldAddr + saveSize))) = 0xe9;
	(*((DWORD*)((DWORD)functionOldAddr + saveSize + 1))) = (DWORD)next - (DWORD)functionOldAddr - saveSize - 5;
	return saveSize;
}

bool InterceptAPI(wchar_t *module, char *functionName, void *functionInterceptAddr, void **functionOldAddr)
{
	void *functionAddr = GetProcAddress(GetModuleHandle(module), functionName);
	if(!functionAddr)
	{
		return false;
	}
	DWORD addr = (DWORD)functionInterceptAddr - (DWORD)functionAddr - 5;

	DWORD oldProtect;
	VirtualProtect(functionAddr, 5, PAGE_EXECUTE_READWRITE, &oldProtect);

	void *oldFunction = malloc(255);
	(*(DWORD*)oldFunction) = (DWORD)functionAddr;
	(*((BYTE*)((DWORD)oldFunction + 4))) = (BYTE)InterceptAPISaveFunction(functionAddr, (void*)((DWORD)oldFunction + 5));

	(*((BYTE*)functionAddr)) = 0xe9;
	(*((DWORD*)((DWORD)functionAddr + 1))) = addr;
	VirtualProtect(functionAddr, 5, oldProtect, &oldProtect);
	(*functionOldAddr) = (void*)((DWORD)oldFunction + 5);
	return true;
}

bool InterceptAPIRestore(void *functionOldAddr)
{
	void *proc = (void*)(*((DWORD*)((DWORD)functionOldAddr - 5)));
	DWORD saveSize = (*((BYTE*)((DWORD)functionOldAddr - 1)));
	DWORD oldProtect;
	VirtualProtect(proc, 5, PAGE_EXECUTE_READWRITE, &oldProtect);
	memcpy(proc, functionOldAddr, saveSize);
	VirtualProtect(proc, 5, oldProtect, &oldProtect);
	free((void*)((DWORD)functionOldAddr - 5));
	return true;
}
В коде идет все так:
Код:
INTERCEPT_DECLARE_INFO(SetFocus);
HWND WINAPI icSetFocus(HWND hWnd)
{
	return ((HWND(WINAPI*)(HWND))INTERCEPT_CALLREAL(SetFocus))(hWnd);
}

BOOL WINAPI DllMain(__in HINSTANCE hinstDLL, __in DWORD fdwReason, __in LPVOID lpvReserved)
{
	switch(fdwReason)
	{
	case DLL_PROCESS_ATTACH:
		{
			ThreadsState(true);
			INTERCEPT_API(L"User32.dll", SetFocus);
			ThreadsState(false);
		}
		break;

	case DLL_PROCESS_DETACH:
		{
			ThreadsState(true);
			INTERCEPT_RESTORE(SetFocus);
			ThreadsState(false);
		}
		break;
	}
	return TRUE;
}
В принципе все логично. Кто что подскажет? Спасибо.

Последний раз редактировалось BOBAH13; 07.05.2010 в 19:31.
BOBAH13 вне форума Ответить с цитированием
Старый 07.05.2010, 19:30   #2
BOBAH13
Android Developer
Старожил Подтвердите свой е-майл
 
Аватар для BOBAH13
 
Регистрация: 19.02.2007
Сообщений: 3,708
По умолчанию

А на счет SizeOfCode функции, я ее тоже брал там же где и константы OPCODES, вроде перевел корректно
Код:
DWORD SizeOfCode(void *code)
{
	DWORD last = (DWORD)code;
	bool addrOveride = false, fixed = false;
	DWORD operandOveride = 4, extend = 0, size;
	WORD flags, opcode, rm, modrm;
	if(last)
	{
		do
		{
			opcode = (*((BYTE*)code));
			code = (void*)((DWORD)code + 1);
			if(opcode == 0x66)
			{
				operandOveride = 2;
			}
			else
			if(opcode == 0x67)
			{
				addrOveride = true;
			}
			else
			if(((opcode & 0xe7) != 0x26) && (opcode < 0x64) || (opcode > 0x65))
			{
				fixed = true;
			}
		}
		while(!fixed);
		if(opcode == 0x0f)
		{
			opcode = (*((BYTE*)code));
			flags = OPCODES2[opcode];
			opcode += 0x0f00;
			code = (void*)((DWORD)code + 1);
		}
		else
		{
			flags = OPCODES1[opcode];
		}
		if(flags & 0x0038)
		{
			modrm = (*((BYTE*)code));
			rm = modrm & 0x7;
			code = (void*)((DWORD)code + 1);
			size = 0;
			switch(modrm & 0xc0)
			{
			case 0x40:
				{
					size = 1;
				}
				break;

			case 0x80:
				{
					size = addrOveride ? 2 : 4;
				}
				break;
			}
			if(!(((modrm & 0xc0) != 0xc0) && addrOveride))
			{
				if((rm == 4) && ((modrm & 0xc0) != 0xc0))
				{
					rm = (*((BYTE*)code)) & 0x7;
				}
				if(((modrm & 0xc0) == 0) && (rm == 5))
				{
					size = 4;
				}
				code = (void*)((DWORD)code + size);
			}
			if((flags & 0x0038) == 0x0008)
			{
				switch(opcode)
				{
				case 0xf6:
					extend = 0;
					break;

				case 0xf7: 
					extend = 1;
					break;

				case 0xd8: 
					extend = 2;
					break;

				case 0xd9: 
					extend = 3;
					break;

				case 0xda: 
					extend = 4;
					break;

				case 0xdb: 
					extend = 5;
					break;

				case 0xdc: 
					extend = 6;
					break;

				case 0xdd: 
					extend = 7;
					break;

				case 0xde: 
					extend = 8;
					break;

				case 0xdf: 
					extend = 9;
					break;
				}
				if((modrm & 0xc0) != 0xc0)
				{
					flags = OPCODES3[extend][(modrm >> 3) & 0x7];
				}
				else
				{
					flags = OPCODES3[extend][((modrm >> 3) & 0x7) + 8];
				}
			}
		}
		switch(flags & 0x0c00)
		{
		case 0x0400:
			code = (void*)((DWORD)code + 1);
			break;

		case 0x0800:
			code = (void*)((DWORD)code + 2);
			break;

		case 0x0c00:
			code = (void*)((DWORD)code + operandOveride);
			break;

		default:
			{
				switch(opcode)
				{
				case 0x9a:
				case 0xea:
					code = (void*)((DWORD)code + operandOveride + 2);
					break;

				case 0xc8:
					code = (void*)((DWORD)code + 3);
					break;

				case 0xa0:
				case 0xa1:
				case 0xa2:
				case 0xa3:
					code = (void*)((DWORD)code + addrOveride ? 2 : 4);
					break;
				}
			}
			break;
		}
	}
	return (DWORD)code - last;
}
BOBAH13 вне форума Ответить с цитированием
Старый 07.05.2010, 21:57   #3
BOBAH13
Android Developer
Старожил Подтвердите свой е-майл
 
Аватар для BOBAH13
 
Регистрация: 19.02.2007
Сообщений: 3,708
По умолчанию

Продолжаю беседу сам с собой, начал вываливать дампы памяти по адресам и сравнивать с дизассемблером (результатом). Оказалось что в функции InterceptAPISaveFunction, а именно (DWORD)next - (DWORD)functionOldAddr - saveSize - 5; формируется не корректный адрес, т.е. если по корректному адресу вывалить первые 5 байт, должен получить B9 03 00 00 00, а получаю совершенно другое.

Кто нибудь может подсказать, подправить формирование адреса?

Edit:
Оставил только (DWORD)next, дамп теперь правильный, полный код с моим jmp внутри. Но крашится всеравно.

Edit:
Осознал свою тупость, адреса формируется видимо верно, но почему крашится, не ясно. Т.н. краш происходит при попытке call на оригинальный адрес, там его ждет 5 байт (mov eax, какое то значение DWORD), потом jmp и этот адрес (DWORD)next.... а он шлет на оригинальный код (его продолжение). Т.е. где-то здесь, что-то не так.

Edit:
Всем спасибо! Разобрался.

Последний раз редактировалось BOBAH13; 08.05.2010 в 13:14.
BOBAH13 вне форума Ответить с цитированием
Старый 09.05.2010, 00:54   #4
liljon
Форумчанин
 
Регистрация: 03.01.2010
Сообщений: 229
По умолчанию

так скажите же, где была проблема?
подпись
liljon вне форума Ответить с цитированием
Старый 09.05.2010, 10:23   #5
BOBAH13
Android Developer
Старожил Подтвердите свой е-майл
 
Аватар для BOBAH13
 
Регистрация: 19.02.2007
Сообщений: 3,708
По умолчанию

Цитата:
Сообщение от liljon Посмотреть сообщение
так скажите же, где была проблема?
С какого перепуга я буду говорить ? :D

Меняйте malloc/free на VirtualAlloc/VirtualFree с аргументами MEM_COMMINT + PAGE_EXECUTE_READWRITE/MEM_RELEASE, соответственно.

А вообще... пост катит на статейку ))) 3 вечера убил, даже нашел еще один вариант перепрыгивания на реальный адрес, без расчета относительного, правда код больше на пару байт. Ну это не проблема вовсе.
BOBAH13 вне форума Ответить с цитированием
Старый 09.05.2010, 10:36   #6
liljon
Форумчанин
 
Регистрация: 03.01.2010
Сообщений: 229
По умолчанию

Цитата:
Меняйте malloc/free на VirtualAlloc/VirtualFree с аргументами MEM_COMMINT + PAGE_EXECUTE_READWRITE/MEM_RELEASE, соответственно.
Почему надо менять? Вы разобрались в этом?
подпись
liljon вне форума Ответить с цитированием
Старый 09.05.2010, 10:45   #7
BOBAH13
Android Developer
Старожил Подтвердите свой е-майл
 
Аватар для BOBAH13
 
Регистрация: 19.02.2007
Сообщений: 3,708
По умолчанию

А по атрибутам не видно ? Нет, я угадал. Разумеется разобрался как все работает. Нужен атрибут для этого куска памяти, чтобы код в нем мог исполнятся, читаться и писаться - PAGE_EXECUTE_READWRITE.
BOBAH13 вне форума Ответить с цитированием
Старый 09.05.2010, 19:16   #8
liljon
Форумчанин
 
Регистрация: 03.01.2010
Сообщений: 229
По умолчанию

какая то абра кадабра у вас получилась

Я делал так
Код:
typedef struct jmp_far
{
  BYTE instr_push;
  DWORD arg;
  BYTE  instr_ret;
}JMP;

BYTE old[30][6]; //область для хранения 6-ти затираемых байт начала функции
jmp_far jump[30];

void ToBuff(JMP jump, BYTE * &b)
{
  New(b,6);
  memcpy(b,&jump.instr_push,1);
  memcpy(b+1,&jump.arg,sizeof(DWORD));
  memcpy(b+sizeof(DWORD)+1,&jump.instr_ret,1);
}

bool Inject2(const char * module,const char * funcname,DWORD ourFunc,DWORD & realFunc,int i)
{
	DWORD op,written;
	realFunc = (DWORD)GetProcAddress(GetModuleHandle(module),funcname);
	if(realFunc == 0)
	{
		log->AddEventFtm("Injection error: can't locate real function '%s.%s'",module,funcname);
		return false;
	}
	
	jump[i].instr_push = 0x68;
	jump[i].arg = ourFunc;
	jump[i].instr_ret = 0xC3;
	
	BYTE * b; ToBuff(jump[i],b);
	ReadProcessMemory(GetCurrentProcess(),(void*) realFunc, (void*)old[i], 6, &written);
	WriteProcessMemory(GetCurrentProcess(), (void*)realFunc, (void*)b, 6, &written);

	log->AddEventFtm("Injected function '%s.%s' at new adress '0x%x'", module, funcname,ourFunc);
	Free(b);
              return true;
}
подпись
liljon вне форума Ответить с цитированием
Старый 09.05.2010, 19:27   #9
BOBAH13
Android Developer
Старожил Подтвердите свой е-майл
 
Аватар для BOBAH13
 
Регистрация: 19.02.2007
Сообщений: 3,708
По умолчанию

У вас тормозной вариант. Если вы не понимаете, то не зачем писать, что у меня получилась
Цитата:
какая то абра кадабра
1. Чтобы вызывать оригинал функцию, вам придется опять вызывать WriteProcessMemory, потом вызов оригинала, потом опять WriteProcessMemory
2. Мне всего то, ничего, просто указать адрес оригинала. Без лишних действий.

так что думайте, прежде чем писать так совет на будущее
BOBAH13 вне форума Ответить с цитированием
Старый 09.05.2010, 20:57   #10
liljon
Форумчанин
 
Регистрация: 03.01.2010
Сообщений: 229
По умолчанию

Цитата:
Если вы не понимаете, то не зачем писать, что у меня получилась
Это не у тебя получилось, а другого человека. Ты лишь содрал код и все. Сам почитаю и разберусь не хуже твоего. Я хотел, чтобы ты объяснил суть перехвата с технической стороны. А ты только умничал со своим быдло-кодом.
Мне не нужны твои советы
подпись

Последний раз редактировалось liljon; 09.05.2010 в 21:00.
liljon вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
перехват API функций ассемблер123 Assembler - Ассемблер (FASM, MASM, WASM, NASM, GoASM, Gas, RosAsm, HLA) и не рекомендуем TASM 16 29.04.2010 12:51
Внедрение DLL и перехват API-функций Doom_Rooster Win Api 4 01.04.2010 03:37
обновление в блоге - Перехват API функций. Основы Pblog Обсуждение статей 0 20.01.2009 10:40
API перехват Irat Помощь студентам 13 11.02.2008 12:04
Перехват API функций satana Win Api 4 21.08.2007 20:12