Что нового

Прочитать значение в регистре

blacklis

Новичок
Сообщения
64
Репутация
1
Всем привет!
Есть ассемблерная инструкция типа такой
name.exe+1213A3 - mov eax,[edi+78]
Как прочитать значение регистра edi в момент её исполнения? Есть библиотеки для работы с ассемблером?
 

firex

AutoIT Гуру
Сообщения
943
Репутация
208
blacklis
Вполне вероятно, что регистр edi задается прежде явно, если же нет, то с помощью AutoIt можно поступить следующим образом:

https://msdn.microsoft.com/en-us/library/windows/desktop/ms679304(v=vs.85).aspx

Нас интересует установка breakpoint'а (INT3). Собственно подключаемся к целевому процессу, пишем на нужный адрес INT3, далее ловим его с помощью: https://msdn.microsoft.com/en-us/library/windows/desktop/ms681423(v=vs.85).aspx

Теперь нас интересуют регистры, для этого воспользуйтесь следующей функцией:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms679362(v=vs.85).aspx

Регистры будут записаны в структуру CONTEXT: http://www.nirsoft.net/kernel_struct/vista/CONTEXT.html
 
Автор
B

blacklis

Новичок
Сообщения
64
Репутация
1
firex сказал(а):
blacklis
Нас интересует установка breakpoint'а (INT3). Собственно подключаемся к целевому процессу, пишем на нужный адрес INT3, далее ловим его с помощью: https://msdn.microsoft.com/en-us/library/windows/desktop/ms681423(v=vs.85).aspx
Благодарю за ответ, саму концепцию понял. Не поделитесь примером установки брейкпоинта на нужный адрес(на с+)?
 

firex

AutoIT Гуру
Сообщения
943
Репутация
208
blacklis
Просто запишите на начало целевой инструкции 0xCC, это создаст исключение EXCEPTION_BREAKPOINT. Прочитаете регистры, восстановите инструкцию и продолжите выполнение кода.
 
Автор
B

blacklis

Новичок
Сообщения
64
Репутация
1
firex сказал(а):
blacklis
Просто запишите на начало целевой инструкции 0xCC, это создаст исключение EXCEPTION_BREAKPOINT. Прочитаете регистры, восстановите инструкцию и продолжите выполнение кода.
Спасибо за ответ!
Вот что у меня вышло:
Код:
#include "MemReader.h"
int n = 0;
DWORD FindAdr;

int main(int argc, char* argv[])
{
	MemReader* mem = new MemReader("name.exe");
	mem->Open();
	HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, false, mem->getPID());
	MODULEENTRY32 game = { 0 };
	mem->GetModuleInfo("name.exe", &game, true);

	printf("base = 0x%X\n", (DWORD)game.modBaseAddr);
	printf("debug = %X\n", DebugActiveProcess(mem->getPID()));
	printf("Pid = %X\n", mem->getPID());


	DWORD x = (DWORD)game.modBaseAddr + 0x120CF3; // адрес искомой инструкции
	printf("adr = 0x%X\n", x);
	
	DWORD oldOp = mem->Read(x, 1).toDWORD(); //оригинальный байт
	printf("oldOp = 0x%X\n", oldOp);

	DWORD opInt3 = 0xCC; // int 3
	mem->Write(&opInt3, x, 1);
	FlushInstructionCache(hProc, &opInt3, 1);
	printf("realdOp = 0x%X\n", mem->Read(x, 1).toDWORD());


	DEBUG_EVENT debug_event = { 0 };
	CONTEXT thread_context;
	thread_context.ContextFlags = CONTEXT_FULL;
	for (;;)
	{
		if (!WaitForDebugEvent(&debug_event, INFINITE))
			return 0; 
		
		if (EXCEPTION_BREAKPOINT == debug_event.u.Exception.ExceptionRecord.ExceptionCode)
		{
			HANDLE hBadThread = OpenThread(THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME, 0, debug_event.dwThreadId);
			GetThreadContext(hBadThread, &thread_context);
			printf("edi  = 0x%X\n", thread_context.Edi);
		//	thread_context.Eip--; // Move back one byte
			//SetThreadContext(hBadThread, &thread_context);
			//CloseHandle(hBadThread);
			n++;
		}

		if (n == 2)
		{
			FindAdr = thread_context.Edi;
			printf("FindArd  = 0x%X\n", FindAdr);
			mem->Write(&oldOp, x, 1);
			FlushInstructionCache(hProc, &opInt3, 1);
			printf("realdOp = 0x%X\n", mem->Read(x, 1).toDWORD());

			ContinueDebugEvent(debug_event.dwProcessId,
				debug_event.dwThreadId,
				DBG_CONTINUE);
			break;
		}


		ContinueDebugEvent(debug_event.dwProcessId,
			debug_event.dwThreadId,
			DBG_EXCEPTION_NOT_HANDLED);
		
	}

	mem->Write(&oldOp, x, 1); //если не словили нужное исключение(в цикле for i<90)
	DebugActiveProcessStop(mem->getPID());
	system("PAUSE")
};
Код отрабатывает, выдаёт нужное значение из регистра, но после завершения крашит процесс с исключением с000096. Если ловить исключения до второго EXCEPTION_BREAKPOINT(которое и нужно), то отлаживаемый процесс не падает. Вероятнее всего я неправильно обрабатываю исключение или передаю его обратно. А понять что не так знаний не хватает :(
 

firex

AutoIT Гуру
Сообщения
943
Репутация
208
blacklis
Ерунду вы наворотили. Ждете первого события и устанавливаете dwContinueStatus в DBG_EXCEPTION_NOT_HANDLED, зачем? Подойдите ответственно и без спешки к построению алгоритма.

P.S. После получения нужного адреса отладку стоит прервать. Предотвратить отключение отлаживаемого процесса можно так:
Код:
DllCall( 'kernel32.dll', 'bool', 'DebugSetProcessKillOnExit', 'bool', 0 )
 
Автор
B

blacklis

Новичок
Сообщения
64
Репутация
1
firex сказал(а):
blacklis
Ерунду вы наворотили. Ждете первого события и устанавливаете dwContinueStatus в DBG_EXCEPTION_NOT_HANDLED, зачем? Подойдите ответственно и без спешки к построению алгоритма.

P.S. После получения нужного адреса отладку стоит прервать. Предотвратить отключение отлаживаемого процесса можно так:
Код:
DllCall( 'kernel32.dll', 'bool', 'DebugSetProcessKillOnExit', 'bool', 0 )

Код:
DEBUG_EVENT debug_event = { 0 };
	CONTEXT thread_context;
	thread_context.ContextFlags = CONTEXT_FULL;
	for (int i = 0;i<1;)
	{
		if (!WaitForDebugEvent(&debug_event, INFINITE))
			return 0; 

		switch (debug_event.u.Exception.ExceptionRecord.ExceptionCode)
		{

		case EXCEPTION_BREAKPOINT:
			if (OnceHit)
			{
				mem->Write(&oldOp, x, 1);
				FlushInstructionCache(hProc, &opInt3, 1);

				HANDLE hBadThread = OpenThread(THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME, 0, debug_event.dwThreadId);
				GetThreadContext(hBadThread, &thread_context);
				FindAdr = thread_context.Edi;
				printf("FindArd  = 0x%X\n", FindAdr);
				printf("realdOp = 0x%X\n", mem->Read(x, 1).toDWORD());
				i = 1;
				
			}
			else
			{
				OnceHit = true;
				
			}
				
			break;

		}

		ContinueDebugEvent(debug_event.dwProcessId,
			debug_event.dwThreadId,
			DBG_CONTINUE);
			
		
	}

	DebugSetProcessKillOnExit(false);
	DebugActiveProcessStop(mem->getPID());
	system("PAUSE");
Немного переделал, практически ничего не изменилось, отлаживаемый процесс по прежнему крашится, причину я так и не понял :(
Если восстановить инструкцию на первом исключении, то завершается нормально и не крашится, только второго исключения естественно не будет. Но после второго - крах. ЧЯДНТ?
OffTopic:
Только не говорите, что всё ;D

DebugActiveProcessStop выходил, не закрывая процесс, для чего DebugSetProcessKillOnExit(false)?

устанавливаете dwContinueStatus в DBG_EXCEPTION_NOT_HANDLED, зачем?
Смотрел на результат его работы, изначально там был DBG_CONTINUE.


Набрёл на книжку Дж. Роббинса, он делает так:
Код:
 case EXCEPTION_DEBUG_EVENT : 

{

switch ( stDE.u.Exception.ExceptionRecord.ExceptionCode)

{

case EXCEPTION_BREAKPOINT :

{

// Если возникает исключение точки прерывания

//и оно замечается впервые, то продолжаем;

// иначе, передаем исключение подчиненному

// отладчику

if ( FALSE == bSeenlnitialBP)

{

bSeenlnitialBP = TRUE;

 dwContinueStatus = DBG_CONTINUE; 

}

else {

// Хьюстон, у нас проблема! 

dwContinueStatus =

DBG_EXCEPTION_NOT_HANDLED; 

} 

} 

break;

// Просто передать любые другие исключения

 // подчиненному отладчику, 

default :

 {

dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED;

 }

break; 

}

 }

break;

// Для любых других событий просто продолжить,

 default :

 {

dwContinueStatus = DBG_CONTINUE;

 }

break; 

}

// Перейти к операционной системе. 

ContinueDebugEvent ( stDE.dwProcessId, 

stDE.dwThreadld , 

dwContinueStatus );

 }

ииии... А где и как обрабатывать исключение? :stars:



Код:
for (int i = 0;i<2;)
	{
		
		if (!WaitForDebugEvent(&debug_event, INFINITE))
			return 0; 

		if (i == 1)
		{
			HANDLE hBadThread = OpenThread(THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME, 0, debug_event.dwThreadId);
			GetThreadContext(hBadThread, &thread_context);

			WriteProcessMemory(hProc, (void*)x, &oldOp, 1, NULL);
			FlushInstructionCache(hProc, &opInt3, 1);

			FindAdr = thread_context.Edi;
			printf("FindArd  = 0x%X\n", FindAdr);
			printf("realdOp = 0x%X\n", mem->Read(x, 1).toDWORD());
			dwContinueStatus = DBG_CONTINUE;
				ContinueDebugEvent(debug_event.dwProcessId,
				debug_event.dwThreadId,
				dwContinueStatus);
			i = 2;
			printf("i = 2\n");
			DebugSetProcessKillOnExit(false);
			DebugActiveProcessStop(mem->getPID());
			break;
		}

		switch (debug_event.u.Exception.ExceptionRecord.ExceptionCode)
		{

		case EXCEPTION_BREAKPOINT:
			if (OnceHit)
			{
				//mem->Write(&oldOp, x, 1);
				i = 1;
				dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED;
				
			}
			else
			{
				OnceHit = true;
				
			}
				
			break;

		default:

		{

				   dwContinueStatus = DBG_CONTINUE;

		}

			break;

		}

		ContinueDebugEvent(debug_event.dwProcessId,
			debug_event.dwThreadId,
			dwContinueStatus);	
			
		
	}
Вот так всё работает и не вылетает :blink:
И ещё, в регистр поочерёдно записываются 3 разных значения, меняются они очень быстро(~5мс), как прочитать все 3?
 
Автор
B

blacklis

Новичок
Сообщения
64
Репутация
1
Вопрос решён, огромное спасибо firex за помощь
 
Верх