shchetinin > А как на счет того что в момент патчей либа выгрузилась? При патче jmp short -> jmp far выгрузиться ничего не может?
deLight Я имею ввиду что потоки должны быть остановлены ... А не какой джамб выбрать... Не говоря уже от том что не для каждого же патча проверять а не выгрузили ли либу?
хм ну а допустим такая ситуация если запускается софт который устраивает цепочки хуков тоесть есть например плагин в opera.exe который всегда сплайсит ws2_32.dll но в это время запускается другая программа которая аттачится к opera.exe и тоже ставит хуки на ws2_32.dll то в случае с push ret в прологе я просто копировал push ret предыдущего перехватчика в трамплин в итоге сначало вызывалсЯ мой перезхватчик я вызывал трамлин попадал в старый перехватчик из него вызывалась настоящая апи в итоге софт друг другу не мешал сплайсить одни и теже функции софт разный например плагин всегда модифицирует пакеты opera.exe во время работы но если надо подцепить некую программу сниффер то нет проблем цепочка хуков прекрасно работает а как быть в случае с хот патчиногм ? получится ли так же делать ?
Почему система будет деградировать? Просто код будет в памяти висеть, это конечно не по фен шую, зато просто. Не совсем врубился что имелось ввиду под "расщепленными страницами"? Помоему вы сильно усложнили все. Тормозим все потоки, смотрим какие из них выполняются в нашем обработчике либо трамплине. Ставим флаг unhook и (любым удобным способом, например в TEB) и отпускаем этот поток. MainUnhookLoop() { SuspendAllThreadsWithoutMe(); //тормозим все кроме нас =)) HOOKED_FUNCTOINS hf[NumberOfFunction]; for(int i=0; i<RTL_NUMBER_OF(hf); i++) { if(!IsEipInTramp(Thread.eip) && !IsEipInDispatcher(Thread.eip)) //проверяем не находится ли поток в данный момент в нашем коде { RestoreOriginalBytes(); } else { //если нам не повезло)) SetThreadUnhookFlag(Thread.TEB) // устанавливаем флаг любым удобным способом WaitForEvent(Unhook_Event); } } UnloadHookDll(); } В конце каждого обработчика должна быть вставка типа if(CheckUnhookFlag()) // проверяем надо ли анхукать { CloseHandle(CreateThread(UnhookThread,PARAMS{FuncBegin,OriginalBytes})); //создаем поток который просто восстановит байты а этот усыпляем, проснется он уже на точке входа ф-ции которую анхукаем. передаем ему все необходимое для этого while(TRUE) {nop;} // подвешиваем чтобы никуда не убежал)) } UnhookThread() { RestoreOriginalBytes(); SuspendThread; SetThreadContext(eip=FuncBegin); SignalizeToUnhookLoop(); CloseThread(); } Вроде бы должно работать, если что предупреждаю: писал засыпая, возможно где-то глупые ошибки, но мне кажется вполне рабочий вариант, не нравится только создание потока для каждой ф-ции.
вот как обычно программы накатывали патчи друг на друга и работали в цепочке придумать бы еще как замарозить процесс перед патчингом что бы ни один поток не был замарожен в DllMain тогда создать новый поток и можно проверять в нем что Eip != ws2_32.dll!for_each_func_entry + diasm(min(6)) и патчить Код (Text): #include <windows.h> // SLESH #define _SALC 0xD6 #define _AAM 0xD4 #define NRM_TAB_LEN 53 #define DB __asm _emit __declspec(naked) int _cdecl MDAL_GetOpcodeLen(BYTE* opcode) { _asm { mov esi, [esp + 4] pushad push 000001510h push 0100101FFh push 0FFFFFF55h push 0FFFFFFF8h push 0F8FF7FA0h push 00F0EC40Dh push 007551004h push 001D005FFh push 0550D5D55h push 0555F0F88h push 0F3F3FFFFh push 00A0C1154h mov edx, esi mov esi, esp push 11001b push 10110000101011000000101110000000b push 10111111101100011111001100111110b push 00000000000100011110101001011000b mov ebx, esp sub esp, 110 mov edi, esp cld push 100 pop ecx xa_nxtIndx: bt [ebx], ecx DB _SALC jnc xa_is0 lodsb xa_is0: stosb loop xa_nxtIndx mov esi, edx push 2 pop ebx mov edx, ebx xa_NxtByte: lodsb push eax push eax cmp al, 66h cmove ebx, ecx cmp al, 67h cmove edx, ecx cmp al, 0EAh je xa_jmp cmp al, 09Ah jne xa_nocall inc esi xa_jmp: lea esi, [esi+ebx+3] xa_nocall: cmp al, 0C8h je xa_i16 and al, 0F7h cmp al, 0C2h jne xa_no16 xa_i16: inc esi inc esi xa_no16: and al, 0E7h cmp al, 26h pop eax je xa_PopNxt cmp al, 0F1h je xa_F1 and al, 0FCh cmp al, 0A0h jne xa_noMOV lea esi, [esi+edx+2] xa_noMOV: cmp al, 0F0h je xa_PopNxt xa_F1: cmp al, 64h xa_PopNxt: pop eax je xa_NxtByte mov edi, esp push edx push eax cmp al, 0Fh jne xa_Nrm lodsb xa_Nrm: pushfd DB _AAM DB 10h xchg cl, ah cwde cdq xor ebp, ebp popfd jne xa_NrmGroup add edi, NRM_TAB_LEN jecxz xa_3 xa_1: bt [edi], ebp jnc xa_2 inc edx xa_2: inc ebp loop xa_1 jc xa_3 DB _SALC cdq xa_3: shl edx, 1 jmp xa_ProcOpcode xa_NrmGroup: sub cl, 4 jns xa_4 mov cl, 0Ch and al, 7 xa_4: jecxz xa_4x xa_5: adc dl, 1 inc ebp bt [edi], ebp loop xa_5 jc xa_ProcOpcode xa_4x: shr al, 1 xa_ProcOpcode: xchg cl, al lea edx, [edx*8+ecx] pop ecx pop ebp bt [edi+2], edx jnc xa_noModRM lodsb DB _AAM DB 8 shl ah, 4 jnc xa_isModRM js xa_enModRM xa_isModRM: pushfd test ebp, ebp jnz xa_addr32 sub al, 6 jnz xa_noSIB mov al, 5 xa_addr32: cmp al, 4 jne xa_noSIB lodsb and al, 7 xa_noSIB: popfd jc xa_iWD js xa_i8 cmp al, 5 jne xa_enModRM xa_iWD: add esi, ebp inc esi xa_i8: inc esi xa_enModRM: test ah, 60h jnz xa_noModRM xchg eax, ecx cmp al, 0F6h je xa_ti8 cmp al, 0F7h jne xa_noModRM add esi, ebx inc esi xa_ti8: inc esi xa_noModRM: shl edx, 1 bt [edi+2+17], edx jnc xa_Exit inc edx bt [edi+2+17], edx jnc xa_im8 adc esi, ebx xa_im8: inc esi xa_Exit: add esp, 110+64 sub esi, [esp+4] mov [esp+7*4], esi popad ret } } int MDAL_GetOpcodesLenByNeedLen(BYTE* opcode, int NeedLen) { int FullLen = 0; int len; do { __asm push esi len = MDAL_GetOpcodeLen(opcode + FullLen); __asm pop esi if (!len) { return 0; } FullLen += len; } while (FullLen < NeedLen); return FullLen; } typedef struct TRAMPOLINE { BYTE CodeBuf[0x1A]; DWORD cbSaved; }*PTRAMPOLINE; VOID SpliceUp(PVOID WinApi, PTRAMPOLINE Jmp, PVOID HookSub) { /* * \x68\xFF\xFF\xFF\xFF\xC3 */ DWORD cb = MDAL_GetOpcodesLenByNeedLen((PBYTE)WinApi, 6); memcpy(Jmp->CodeBuf, WinApi, cb); /* * jmp rel32 */ #include <pshpack1.h> struct { BYTE jmp; DWORD rel32; } sub; #include <poppack.h> sub.jmp = 0xE9; sub.rel32 = ((PBYTE)WinApi + cb) - ((PBYTE)Jmp->CodeBuf + cb + 5); memcpy(Jmp->CodeBuf + cb, &sub, sizeof(sub)); Jmp->cbSaved = cb; /* * push imm32 * ret */ #include <pshpack1.h> struct { BYTE push; PVOID imm32; BYTE ret; } obj; #include <poppack.h> obj.push = 0x68; obj.imm32 = HookSub; obj.ret = 0xC3; WriteProcessMemory(GetCurrentProcess(), WinApi, &obj, sizeof(obj), 0); } VOID SpliceDown(PVOID WinApi, PTRAMPOLINE Jmp) { WriteProcessMemory(GetCurrentProcess(), WinApi, Jmp, Jmp->cbSaved, 0); } #pragma data_seg(push, r1, ".text") BYTE xxx[16]; #pragma data_seg(pop, r1) #define pk1 __asm{__emit 0xCC} #define pk4 pk1 pk1 pk1 pk1 #define pk16 pk4 pk4 pk4 pk4 #define pk64 pk16 pk16 pk16 pk16 #define pk256 pk64 pk64 pk64 pk64 TRAMPOLINE jmp1, jmp2; #include <boost/typeof/typeof.hpp> static int WINAPI hook1( __in_opt HWND hWnd, __in_opt LPCSTR lpText, __in_opt LPCSTR lpCaption, __in UINT uType) { return ((BOOST_TYPEOF(hook1)*)&jmp1)(hWnd,lpText,lpCaption,uType); } static int WINAPI hook2( __in_opt HWND hWnd, __in_opt LPCSTR lpText, __in_opt LPCSTR lpCaption, __in UINT uType) { return ((BOOST_TYPEOF(hook2)*)&jmp2)(hWnd,lpText,lpCaption,uType); } int main() { MessageBox(0, 0, 0, 0); SpliceUp(&MessageBoxA, &jmp1, &hook1); MessageBox(0, 0, 0, 0); SpliceUp(&MessageBoxA, &jmp2, &hook2); MessageBox(0, 0, 0, 0); SpliceDown(&MessageBoxA, &jmp2); MessageBox(0, 0, 0, 0); SpliceDown(&MessageBoxA, &jmp1); MessageBox(0, 0, 0, 0); }
63F45EF45RB65R6VR Саспенд после захвата кс загрузчика. Но не спеши открывать папку "Counter-Strike" (ровно как и пдфник с последним ксакепом), речь о критической секции. Смесь asm-листенгов, буста и тотального винегрета в голове - это конечно ахтунг. Надо фиксить. Еще пару таких постов и делайт необратимо о*уеет. Ставь хоть запятые иногда.
onSide Рассщипление страницы - это случай когда либо грузится в не сколько процессов. Физичиская память будет одна, но после того как её модифицируют , то происходит расщепления страницы дабы избежать изменения во всех процессах(Это когда мы ставим патч). После того как мы сделаем анпатч кто это страницы вернет в норлмаьное состояние то и есть в изначальное? Очень не проще, а точнее намного: 1) Менее прозрачно + Версии а архитектура. 2) Нельзя стартовать потоки. 3) Не чего нельзя вгрузить(У меня например случай на некоторые патчи вгружалась специльная либа так сказать база данных )
deLight Я согласен это давно специфичные пункты, но все таки решение с локом инвалидно, особенно подумав о факте если туды поподет человек без знания локов загрузчика( А такие есть, например у меня сейчас в проекте ).
вот например по адресу 0x0000000F есть такой код 0x0000000F 8B FF mov edi,edi теперь представим что поток был вытеснен со значением eip == 0x0000000F теперь другой поток хочет пропатчить эти два байта и записать туда 0x0000000F EB F9 jmp short $ - 5 и например выполняет для этого такой код mov eax, 0x0000000F mov word ptr [eax], 0xF9EB возможно ли расщепление записи т.е запись только 1 байта EB потом переключение контекста и второй поток увидит в итоге 0x0000000F EB FF ?? или запись будет гарантированно атомарной и любой поток никак не прочтет разрезанные опкоды ? вообще во всех этих случаях атомарность гарантируется mov byte ptr[eax], AA mov word ptr[eax], AABB mov dword ptr[eax], AABBCCDD ?
63F45EF45RB65R6VR Не такого не будет, если его что то вытеснит то это прирывание, в этом случае не будет работать другой поток.
63F45EF45RB65R6VR Такого, как Вы описали, быть не может, потому что процессор исполняет инструкции целиком, и не может прерваться на середине инструкции (полслова записал, полслова — нет). Но это не означает, что запись будет атомарной. Если адрес записываемого слова попадает на границу линейки кэша, то в многопроцессорной системе теоретически может запись одним процессором может быть разбита на две транзакции, между которыми может влезть читающий другой процессор. Хотя в случае, когда под чтением понимается выборка инструкций (кроссмодифицируемый код), тут всё может быть немного сложнее.
l_inc Я немного запутался, кто на что и кому отвечает, но вот это хочется уточнить: Только ли при пересечении границы кэша? Как я себе представлял, чтение/запись объекта по некратному ему размеру адресу может быть разбито на несколько транзакций. Т.е. например при proc0: mov eax, [0x1] proc1: mov [0x1], eax может произойти перемешивание. Я в таких случаях использую простое правило: записывающая инструкция должна использовать префикс LOCK. С другой стороны, проверить такую ситуацию довольно сложно, может это и не совсем правильно. В общем, где лучше почитать насчет "дробления" операций?
клерк ты классный специалист и многие из за этого к тебе относятся с уважением например я но своим поведением ты нивелируеш себя прежде всего как человека вот посмотри со стороны это похоже на поведение школьника и это только портит твою репутацию P.S я совершенно беспристрастный человек так что моим словам можеш доверять насчет Mika0x65 помоему классный специалист в моих темах не троллил да и вообще замечен не был зачем его оскорблятъ ?
Mika0x65 Нет никаких транзакций, если доступ к памяти целиком попадает в подгруженную линейку кэша. Если же попадает целиком в неподгруженную линейку, то под транзакциями понимается сброс/подгрузка всей линейки целиком. Ну правило-то может и простое, но по lock mov будет #UD, что указано в документации. Более подробно мне известен только один надёжный источник: leo.