Перехват GetTickCount с помощью C++

Я не силен в C++, больше в C# и PHP. Мне был назначен проект, который требует от меня использования GetTickCount и подключения к приложению. Мне нужна помощь, так как по какой-то причине это не работает, как планировалось... Вот код для перехвата, я знаю, что он работает, потому что я использовал его в проектах раньше. Единственное, в чем я не уверен, так это в части GetTickCount. Я попробовал GetTickCount64, думая, что это решение моей проблемы (то, во что я его вводил, не вылетало), но обнаружил, что вместо этого оно просто не работает вообще, поэтому оно не вылетает.

bool APIENTRY DllMain(HINSTANCE hDll, DWORD dwReason, LPVOID lpReserved)
{
 switch(dwReason)
 {
 case DLL_PROCESS_ATTACH:

  DisableThreadLibraryCalls(hDll);
  CreateThread(0,0, (LPTHREAD_START_ROUTINE)KeyHooks, 0, 0, 0);
  GetTickCount_orig = (DWORD (__stdcall *)(void))DetourFunction((PBYTE)GetProcAddress(GetModuleHandle("kernel32.dll"), "GetTickCount"), (PBYTE)GetTickCount_hooked);

 case DLL_PROCESS_DETACH:
  DetourRemove((PBYTE)GetProcAddress(GetModuleHandle("kernel32.dll"), "GetTickCount"), (PBYTE)GetTickCount_hooked);

  break;
 }
 return true;
}

Вот остальная часть кода, который используется для GetTickCount

DWORD oldtick=0;
DWORD (WINAPI *GetTickCount_orig)(void);
DWORD WINAPI GetTickCount_hooked(void)
{ 
 if(oldtick==0)
 {
  oldtick=(*GetTickCount_orig)();
  return oldtick;
 }
 DWORD factor;
 DWORD ret;

 ret = (*GetTickCount_orig)();
 factor = 3.0;
 DWORD newret;

 newret = ret+((oldtick-ret)*(factor-1));

 oldtick=ret;
 return newret; 
}

Видите ли вы что-то неправильное или что следует изменить? Любая помощь приветствуется. Спасибо!


person E3pO    schedule 28.01.2011    source источник
comment
В чем здесь проблема?   -  person wj32    schedule 28.01.2011
comment
Вылетает приложение при попытке инжекта. Мой QueryPerformanceCounter вводит без проблем.   -  person E3pO    schedule 28.01.2011
comment
Как насчет того, чтобы поставить break; перед case DLL_PROCESS_DETACH? Потому что как сейчас написано - вы сразу удаляете свой хук после инициализации   -  person valdo    schedule 01.02.2011


Ответы (2)


Что за ветка "KeyHooks"? Если ожидается, что будут вызываться обходные API, вам следует выполнить обход перед созданием потока.

GetTickCount_orig вообще устанавливается?

GetTickCount, вероятно, является очень, очень коротким API, вызывающим проблемы для Detours (просто не хватает байтов для подключения).

Ваш DetourRemove удаляет для GetTickCount64, а не для GetTickCount.

Отдельно, если Detours не работает, есть библиотека mhook, у которой гораздо более простое лицензирование.

person Graham Perks    schedule 31.01.2011
comment
Все, что делает Keyhooks, — это видит, удерживает ли пользователь клавишу Shift. void KeyHooks(void){while(true){makemetrue = false;while(GetAsyncKeyState(0x14)){makemetrue = true;}Sleep(50);}} Также... Я не уверен, что GetTickCount_orig устанавливается. Когда у меня нет GetTickCount64, все, что я пытаюсь внедрить, вылетает. - person E3pO; 01.02.2011
comment
Выйдите из отладчика и посмотрите, установлен ли GetTickCount_orig. Также см. пункт Вальдо выше об отсутствующем операторе break (не могу поверить, что я этого не видел :) - person Graham Perks; 01.02.2011

Не изменяйте oldtick !

Вы должны сохранить его только один раз, а затем

// accelerating time by factor of "factor"
return oldtick + (realtick - oldtick) * factor;

РЕДАКТИРОВАТЬ:

Другая возможная проблема заключается в том, что GetTickCount (по крайней мере, на моем компьютере с 32-разрядной версией XP) не имеет стандартной преамбулы, которую можно перехватить:

8B FF     mov     edi, edi
55        push    ebp
8B EC     mov     ebp, esp

Без него его можно перехватить только из IAT, и это нужно сделать для каждого вызывающего его модуля. Я подозреваю, что DetourFunction работает для каждого процесса, поэтому он перехватывает API, используя преамбулу.

Чтобы решить эту проблему, вы можете либо попробовать подключить IAT каждого модуля, либо исправить его вручную, но тогда вы не сможете вызывать исходную версию, пока она подключена.

EDIT2: использование перехода является наиболее распространенным способом, но это означает, что мы должны перезаписать 5 байтов в начале функции. Основная проблема не в размере функции, а в коде при ее запуске. Конечно, перезаписать можно что угодно, но если вы хотите иметь возможность вызывать старую функцию при включенном хуке (как в этом вопросе), вам нужно знать, что вы перезаписываете.
Вы не хотите этого делать. перезапишите половину кода операции, и вам придется выполнить перезаписанную часть. Это означает, что в общем случае для этого вам понадобится полный дизассемблер.

Чтобы упростить это, большинство функций начинаются с дополнительного 2-байтового NOP: mov edi, edi, так что их преамбула имеет стандартные 5 байтов, которые легко перемещать.

person ruslik    schedule 28.01.2011
comment
Я не думаю, что Detours настолько глуп, чтобы не работать с произвольными инструкциями. Разве не они придумали батут для зацепления? - person wj32; 28.01.2011
comment
@ wj32: Тогда почему большинство API Win32 начинаются с этого mov edi, edi? - person ruslik; 28.01.2011
comment
Ну похоже проблема в oldtick=(*GetTickCount_orig)(); return oldtick; - person E3pO; 28.01.2011
comment
@E3pO: Так что я прав :) Он безоговорочно исправляется jmp, поэтому исходная функция не может быть вызвана, пока хук включен. Тогда вам придется делать это вручную. - person ruslik; 28.01.2011
comment
@ruslik: Это для облегчения установки исправлений. Это не означает, что исправление невозможно без заполнения в начале. @E3pO: я думаю, вам нужно использовать DetourFunctionWithTrampoline. - person wj32; 28.01.2011
comment
Он не падает, но я не думаю, что он что-то делает .. Я могу ошибаться. - person E3pO; 28.01.2011
comment
Возможно, кто-то был бы не против написать мне в личные сообщения со своим аимом или скайпом? Было бы неплохо разобраться в этом. Я готов заплатить. - person E3pO; 28.01.2011
comment
Не могли бы вы объяснить, в чем смысл преамбулы к крючку? Насколько я знаю, помимо перехвата через IAT существует способ перезаписать первую часть кода функции на jmp по другому адресу. Этот метод требует, чтобы функция была достаточно длинной (иначе другая память будет перезаписана). - person valdo; 01.02.2011