wkbk, [Оффтопик]
Часть 1 - Поиск и удаление "таймера" Запустив Garena.exe в пропатченной и "проплагиненной" Ольке (по урокам Рикардо Нарвахи) у меня почему то не запускается Garena - виснет на загрузке Chenyx.dll из папки pluginsUI. Кто может объяснить или высказать свои мнения по этому поводу, пожалуста пишите. Поэтому я поставил чистую Ольку, на которой все прекрасно грузится =). Итак, после повторного входа в комнату, появляется окошко с надписью "Sorry, you can only try join a room every 5 seconds". Можно попробовать поставить бряки на MessageBox, но это не поможет: 1). Это не "великое сообщение" =) 2). видимо, гарена ставит VirtualProtect, поэтому ставить обычные бряки не получится, ну и пусть, воспользуемся аппаратными.
Лично я нашёл такой способ: до начала появления первого пятисекундного предупреждения, ищем в памяти юникод-строку, она находится в секции .rsrc модуля Garena.
Далее ставим на неё Hardware Breakpoint on access на первый байт и пытаемся повторно зайти в комнату, останавливаемся тут:
7E369E0B . 66:F3:A5 REP MOVS WORD PTR ES:[EDI],WORD PTR DS:[>
7E369E0E . 8B7D 10 MOV EDI,DWORD PTR SS:[EBP+10]
7E369E11 > FF75 08 PUSH DWORD PTR SS:[EBP+8]
Если посмотреть в стек, то можно понять, что мы находимся где то в USER32.LoadStringW, о чем свидетельствует адрес возврата и коммент Ольки
0012B09C |00F6411D RETURN to Language.00F6411D from USER32.LoadStringW
Выходим по этому адресу возврата: Right_Click -> Follow in Disassembler (Enter) и оказываемся здесь
00F64117 FF15 64E1F800 CALL DWORD PTR DS:[<&USER32.LoadStringW>>; USER32.LoadStringW
00F6411D 8D4424 20 LEA EAX,DWORD PTR SS:[ESP+20]
00F64121 8D50 02 LEA EDX,DWORD PTR DS:[EAX+2]
00F64124 66:8B08 MOV CX,WORD PTR DS:[EAX]
00F64127 83C0 02 ADD EAX,2
Мы находимся в модуле Language - чисто по названию можно предположить, что это модуль "общение с юзером", или что то в этом роде, но врядли тут окажется проверка на конец таймера. Кстати, таймер организован не через функцию вроде SetTimer, а других я пока не знал =) Так же и не дал каких то результатов и поиск в коде "PUSH 1388" (5000 в dec).
Так как мы предположили, что этот модуль нам не нужен, идем дальше до "RETN 8" (если идти по F7F8 то прога опять у меня виснет, так что я поставил hr на эту инструкцию). После выхода из Language, оказываемся тут:
004E0B7D |. FFD0 CALL EAX
004E0B7F |. 8B4424 14 MOV EAX,DWORD PTR SS:[ESP+14]
004E0B83 |. 3BC7 CMP EAX,EDI
004E0B85 |. 75 1A JNZ SHORT Garena.004E0BA1
004E0B87 |. 8B7424 30 MOV ESI,DWORD PTR SS:[ESP+30]
Ок, теперь мы в основном модуле, его мы и будем копать. Мы находимся в функции, о чем свидетельствует жирная дуга слева от опкода. Видим, что кроме CALL'a, из которого мы вышли, в этой функции больше ничего сверху нету (код выполняется линейно), а поэтому поставим hr на на PUSH -1 и посмотрим в стеке, откуда вызывается сиё чудо (не забывайте удалять ненужные hr бряки, ибо их всего четыре) :
004E0B30 /$ 6A FF PUSH -1
004E0B32 |. 68 386E5900 PUSH Garena.00596E38
004E0B37 |. 64:A1 0000000>MOV EAX,DWORD PTR FS:[0]
004E0B3D |. 50 PUSH EAX
004E0B3E |. 83EC 10 SUB ESP,10
004E0B41 |. 53 PUSH EBX
004E0B42 |. 56 PUSH ESI
004E0B43 |. 57 PUSH EDI
004E0B44 |. A1 50596100 MOV EAX,DWORD PTR DS:[615950]
004E0B49 |. 33C4 XOR EAX,ESP
004E0B4B |. 50 PUSH EAX
004E0B4C |. 8D4424 20 LEA EAX,DWORD PTR SS:[ESP+20]
004E0B50 |. 64:A3 0000000>MOV DWORD PTR FS:[0],EAX
004E0B56 |. 33FF XOR EDI,EDI
004E0B58 |. 897C24 10 MOV DWORD PTR SS:[ESP+10],EDI
004E0B5C |. 897C24 1C MOV DWORD PTR SS:[ESP+1C],EDI
004E0B60 |. 897C24 18 MOV DWORD PTR SS:[ESP+18],EDI
004E0B64 |. 897C24 14 MOV DWORD PTR SS:[ESP+14],EDI
004E0B68 |. 8B09 MOV ECX,DWORD PTR DS:[ECX]
004E0B6A |. 8B01 MOV EAX,DWORD PTR DS:[ECX]
004E0B6C |. 8B40 0C MOV EAX,DWORD PTR DS:[EAX+C]
004E0B6F |. 8D5424 14 LEA EDX,DWORD PTR SS:[ESP+14]
004E0B73 |. 52 PUSH EDX
004E0B74 |. 8B5424 38 MOV EDX,DWORD PTR SS:[ESP+38]
004E0B78 |. 52 PUSH EDX
004E0B79 |. 897C24 30 MOV DWORD PTR SS:[ESP+30],EDI
004E0B7D |. FFD0 CALL EAX
Пытаемся зайти в руму, отладчик незамедлительно всплывает, а esp указывает на адрес возврата:
0012E358 00499227 RETURN to Garena.00499227 from Garena.004E0B30
Запоминаем его, теперь надо выполнить следующую вещь: пытаемся зайти в комнату, и когда всплывает отладчик быстро жмем F9 и снова заходим в руму, тем самым спровоцировав появление окошка. Отладчик всплывает и в этом случае, но сейчас адрес возврата уже другой:
0012D91C 00540954 RETURN to Garena.00540954 from Garena.004E0B30
Так так,немного поразмыслив, можно предположить, что есть некая функция и в зависимости от каких то действий происходит её вызов с различными параметрами (так как функция вызывается в обоих случаях).
Дальше всё очевидно: ставим курсор на esp (строка выше) и давим на Enter, оказываемся тут (попадаем в место вызова процедуры с плохими параметрами):
0054092B > 8B35 CC135A00 MOV ESI,DWORD PTR DS:[<&KERNEL32.GetTick>; kernel32.GetTickCount
00540931 . FFD6 CALL ESI ; [GetTickCount
00540933 . 2B05 109E6100 SUB EAX,DWORD PTR DS:[619E10]
00540939 . 3D 88130000 CMP EAX,1388
0054093E . 73 60 JNB SHORT Garena.005409A0 ;
00540940 . 68 AE010000 PUSH 1AE ; /Arg2 = 000001AE
00540945 . 8D4C24 58 LEA ECX,DWORD PTR SS:[ESP+58] ; |
00540949 . 51 PUSH ECX ; |Arg1
0054094A . B9 40F86000 MOV ECX,Garena.0060F840 ; |
0054094F . E8 DC01FAFF CALL Garena.004E0B30 ; Garena.004E0B30
Ок, кажется, мы нашли то, что нужно: вызывается функция GetTickCount, затем высчитывается какая то разность и сравнивается с ... 1388!!! (для тех, что не помнит, это 5000 в dec). И как я мог забыть поискать кроме пуша ещё и сравнение
По адресу 0054093E находится переход, который ведет на 005409A0, в Ольке очень хорошо видно, что этот переход как раз и пропускает вызов функции с "плохими параметрами" =).
Пробуем, ставим hr бряк по адресу 0054093E, ломимся в комнату, отладчик всплывает и сейчас всё TRUE (мы пролетаем через функцию). Теперь быстренько (надо успеть за пять секунд) жмакаем F9 и опять ломимся -> отладчик всплывает, но теперь уже не True, меняем флаг C и, отпустив прогу на волю, видим, что мы пытаемся зайти второй раз!! Ура товарищи, у нас всё получилось!!! Если вы подумали, что это всё, то ошиблись, хехе.
Давайте сделаем патч: очевидно надо заменить JNB переход на JMP, но когда прога уже загружена, сделать это не удастся, поэтому запоминаем адрес перехода - 0054093E, нажимаем Ctrl+F2, переходим по адресу (Ctrl+G -> 0054093E -> Enter) и меняем переходик. После чего жмакаем правой кнопкой по листингу -> Copy to Executable -> All modifications -> Copy All. Сохраняем под новым именем, и... нет, ещё не закрываем статью, потому что дальше будет поинтереснее =).
Часть 2 - Убираем проверку на "вшивость" патченного EXE
Те, кто уже обрадовались, что всё закончено, ошибались, ибо после запуска Garena.exe появляется окошко с надписью "You are using a cracked version of Garena. Garena will close shortly ...". Эх, а я то уж обрадовался...
Снова загружаем Garen'у в Ольгу, и ставим hr на USER32.CreateDialogParamW (для этого нажимаем Ctrk+N, набираем "cre", оказываемся на функции, далее правай кнопка-> Follow import in disassembler и мы в первой строке кода данной API). Запускаем прогу и пропускаем все ненужные срабатывания бряка. Как только прога запустилась, сидим и ждем всплытие отладчика .
Ок, отладчик всплыл, вот стек:
0012E630 04E793F7 /CALL to CreateDialogParamW from AvoidCra.04E793F1
0012E634 04E70000 |hInst = 04E70000
0012E638 00000065 |pTemplate = 65
0012E63C 00000000 |hOwner = NULL
0012E640 04E79640 |pDlgProc = AvoidCra.04E79640
0012E644 00000000 lParam = 0
0012E648 04E94A88 AvoidCra.04E94A88
0012E64C 04E7918E RETURN to AvoidCra.04E7918E from AvoidCra.04E79360
Итак, вся соль в AvoidCrackPlugin.dll, которая находится в папке с плагинами(пусть можно узнать, нажав Alt+E в Ольке). Её название говорит само за себя, чтоб постараемся устранить проверку на вшивость ЕХЕ-шника. Выходим к тому месту, где была вызвана брякнутай апишка:
0012E630 04E793F7 /CALL to CreateDialogParamW from AvoidCra.04E793F1Left click -> Enter. Теперь мы тут
04E7935F CC INT3
04E79360 837F 14 00 CMP DWORD PTR DS:[EDI+14],0
04E79364 75 10 JNZ SHORT AvoidCra.04E79376
04E79366 E8 A1140000 CALL AvoidCra.04E7A80C
04E7936B 85C0 TEST EAX,EAX
04E7936D 8947 14 MOV DWORD PTR DS:[EDI+14],EAX
04E79370 0F84 83000000 JE AvoidCra.04E793F9
04E79376 8B47 14 MOV EAX,DWORD PTR DS:[EDI+14]
...
04E793F0 50 PUSH EAX
04E793F1 FF15 B0C1E804 CALL DWORD PTR DS:[<&USER32.CreateDialog>; USER32.CreateDialogParamW
04E793F7 5E POP ESI
04E793F8 C3 RETN
04E793F9 6A 0E PUSH 0E
04E793FB FF15 4CC0E804 CALL DWORD PTR DS:[<&KERNEL32.SetLastErr>; ntdll.RtlSetLastWin32Error
04E79401 33C0 XOR EAX,EAX
04E79403 C3 RETN
04E79404 6A 00 PUSH 0
04E79406 6A 00 PUSH 0
04E79408 6A 01 PUSH 1
04E7940A 68 050000C0 PUSH C0000005
04E7940F FF15 50C0E804 CALL DWORD PTR DS:[<&KERNEL32.RaiseExcep>; kernel32.RaiseException
Дальше по логике вещей надо посмотреть выше вызова USER32.CreateDialogParamW на переходы, которые перескакивают через этот самый вызов =)
Здесь их три штуки, и все они прыгают на один и тот же код, следовательно, проверка проверяется по трем критериям, и если первое правильное, то проверяем второй и т.д. Кароче нам надо заменить самый старший (читай стоящий выше) условный переход на безусловный. Чтобы убедится, что нам нужно менять именно этот переход, можно поставить hr бряк на него : 04E79370 /0F84 83000000 JE AvoidCra.04E793F9Рестартуем Garena -> Ctrl+F2, и запускаем -> F9. Останавливаемся на бряке, и видим, что он сейчас не сработает, меняем флаг Z и никакого окошка не появляется! Ура, товарищи!
Теперь есть один момент по поводу того, как сделать так, чтобы был jmp а не je. Как вы знаете, править то нам сейчас нельзя, а при рестарте прога ещё не загрузила DLL. Есть, конечно всевозможные методы инлайна, но мы воспользуемся более простым - замена опкода команды в файле. Как вы уже поняли, менять будем не опкод команды jmp на je, а "xor eax, eax" на "test eax,eax", стоящий выше перехода. Почему? Да потому что у test и xor всегда одинаковый опкод, независимо от из расположения по какому либо смещению, потому что они не работают со смещениями (не пользуются ими), а у je и jmp опкод высчитывается исходя из того, на каком месте стоит команда и куда она прыгает (для проверки сами попробуйте расположить эти команды по разным местам и увидите различия в опкоде).
Итак, меняем "test eax, eax" на "xor eax,eax" (85С0 меняем на 33С0). Я буду юзать HIEW32. Открываем файл в HIEW32, жмем F4, выбираем HEX и нажимаем F7 для поиска, теперь пишем опкоды команд (желательно брать побольше, чтобы нашлось только одно уникальное совпадение, в данном случае достаточно ввести опкоды test'a и следующего mov'a - 85 C0 89 47 14). Ок, теперь нажимаем F3, вводим 33 и нажимаем F9, а затем и F10 для выхода. "Теперь можно спокойно играть? ", - нет нет, есть ещё одна проверочка, хехе.
Часть 3 - Убираем проверку в EXE на вшивость DLL'ок
Теперь если мы попытаемся запустить ЕХЕ, то выдается ошибка "Check File (...AvoidCrackPlugin.dll)Error". Хехе, наблюдаем мат Garen'ы, которая обнаружила вторжение во владение DLL. Давайте исправлять... Попытаемся найти проверку в EXE на валидность DLL'ок. Грузим в Ольку наш ранее патченный EXE.
Существует несколько способов снятия защиты проверки DLL, я напишу тот, который попроще:
Можно предположить, что сначала происходит проверка, а потом, если DLL в норме, то она загружается. Ок, ставим hr бряк на функцию LoadLibraryW вышеописанным способом, и запускаем прогу.
Видим, что сразу происходит остановка, и если чуть придавить F9 кирпичом, то можно заметить, что все DLL, лежащие в папке plugins грузятся из одного места (смотрим на адрес возврата):
0012E710 004FC673 /CALL to LoadLibraryW from Garena1.004FC66D
0012E714 001F5178 FileName = "CrogramsGarenapluginsUI/ViwawaPlugin.dll"Выходим по адресу возврата и оказываемся тут: 004FC66A . /74 5D JE SHORT Garena1.004FC6C9 ; !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
004FC66C > |57 PUSH EDI ; /FileName
004FC66D . |FF15 F8125A00 CALL DWORD PTR DS:[<&KERNEL32.LoadLibrar>; LoadLibraryW
Выше есть переход, который я и попробовал первым делом: ставим бряк (хардварный, конечно) и смотрим, что же происходит: АГА, прыжка не происходит никогда, кроме... хехе, догадайтесь сами)
Инвертируем флаг Z и... УРА! Garena успешно стартовала!!! Остается дело за малым: запоминаем адрес перехода, давим на Ctrl+F2, затем переходим по адресу и забиваем переход командами nop.
Чтож, теперь всё работает и таймер убран) Можно играть в доту и не пытаться войти в топовые комнаты по полчаса, теперь шанс значительно выше.