Без проблем.
LIBRARY HookDamage;
{!INFO
MODULENAME = 'Damage'
VERSION = '1.0'
AUTHOR = 'Sav'
}
USES Win, Utils, SysUtils, VPUtils;
CONST (* HookCode constants *) C_HOOKTYPE_JUMP = FALSE; C_HOOKTYPE_CALL = TRUE; C_OPCODE_JUMP = $E9; C_OPCODE_CALL = $E8; C_UNIHOOK_SIZE = 5;
TYPE
THookRec = RECORD Opcode: BYTE; Ofs: INTEGER;
END;
VAR
Temp: INTEGER;
PROCEDURE WriteAtCode(P: POINTER; Buf: POINTER; Count: INTEGER);
BEGIN Win.VirtualProtect(P, Count, PAGE_READWRITE, @Temp); Win.CopyMemory(P, Buf, Count); Win.VirtualProtect(P, Count, Temp, NIL);
END;
PROCEDURE HookCode(P: POINTER; NewAddr: POINTER; UseCall: BOOLEAN);
VAR HookRec: THookRec;
BEGIN IF UseCall THEN BEGIN HookRec.Opcode:=C_OPCODE_CALL; END // .if ELSE BEGIN HookRec.Opcode:=C_OPCODE_JUMP; END; // .else HookRec.Ofs:=INTEGER(NewAddr)-INTEGER(P)-C_UNIHOOK_SIZE; WriteAtCode(P, @HookRec, 5);
END;
//Модификация удара с флагом бить всех вокруг.
//Вместо вычисления 8-ми атакованных позиций, проверяется каждый из 42 стеков на необходимость атаки по нему (записанную в v-переменных).
//$890AD8 - v9501 - номера целевых стеков атакующего (побитно), $890ADC - v9502 - номера целевых стеков защищающегося (побитно).
//Модификация условия выполнения прохода цикла (в функции $440030).
//Запись 0 (что значит - все позиции вокруг могут быть атакованы).
//Без модификации значение - начение - смежные позиций побитно от правой нижней против часовой стрелки (0 - доступна).
PROCEDURE Damage_ability; ASSEMBLER; {$FRAME-}
ASM //Если 32-й бит в v9501 = 1, модифицируем. PUSH EAX MOV EAX, DWORD PTR DS:[$890AD8] SHR EAX, 31 TEST EAX, EAX POP EAX JNZ @@Modify //Восстановление изначального кода: получение всех позиций рядом, на которых кто-то стоит побитно (Запись в ECX). MOV ECX, [EBP+8] JMP @@Exit //Модифицирование кода: запись 0 (будто на всех клетках рядом кто-то стоит) в возвращаемый результат. @@Modify: MOV ECX, 0 @@Exit: TEST ECX, EAX//Восстанавливаем испорченную команду. PUSH $440057
END;
//Модификация вызова функции, вычисляющей позицию текущего атакованного (в функции $440030).
//Автоматическое возвращение 1 (легальной позиции) (в EAX), т. к. позиция может быть вычислена неправильно, если будет больше 8 атакованных.
PROCEDURE Damage_position; ASSEMBLER; {$FRAME-}
ASM //Если 32-й бит в v9501 = 1, модифицируем. MOV EAX, DWORD PTR DS:[$890AD8] SHR EAX, 31 TEST EAX, EAX JNZ @@Modify //Восстановление изначального кода: вызов функции, вычисляющей позицию текущего атакованного (Запись в EAX). MOV EAX, $5242E0 CALL EAX//Внутри функции используется ESP - нельзя использовать PUSH перед ней. JMP @@Exit //Модифицирование кода: запись 1 (легальной позиции) в возвращаемый результат. @@Modify: MOV EAX, 1 @@Exit: PUSH $440069
END;
//Модификация вызова функции вычисления адреса конструкций для атакованного на определённой позиции (в функции $440030).
//Вместо вычисления стека по позиции, смотрим в бите v-переменной, надо ли атаковать текущий проверяемый стек.
//Если надо, возвращаем (в EAX) $699420 + 1352*номер стека + 21708, иначе 0.
PROCEDURE Damage_stack; ASSEMBLER; {$FRAME-}
ASM //Если 32-й бит в v9501 = 1, модифицируем. MOV EAX, DWORD PTR DS:[$890AD8] SHR EAX, 31 TEST EAX, EAX JNZ @@Modify //Восстановление изначального кода: вызов функции, вычисляющей адрес конструкций для атакованного на определённой позиции (запись в EAX). MOV EAX, $4E7230 CALL EAX JMP @@Exit //Модифицирование кода: проверка, надо ли атаковать текущий стек и запись адреса его конструкций или 0 в EAX. @@Modify: //Проверяем, какой стороне принадлежит проверяемый стек. CMP EBX, 21 JAE @@Def_st //Если стек принадлежит атакующей стороне, помещаем в EAX соответствующий стеку бит из v9501. MOV EAX, DWORD PTR DS:[$890AD8] MOV CL, BL SHR EAX, CL JMP @@All_st //Если стек принадлежит защищающейся стороне, помещаем в EAX соответствующий стеку бит из v9502. @@Def_st: MOV EAX, DWORD PTR DS:[$890ADC] SUB EBX, 21 MOV CL, BL SHR EAX, CL ADD EBX, 21
//Оставляем в EAX 0 или помещаем в него адрес конструкций стека (в зависимости от начального значкния EAX, т. е. бита v-переменной). @@All_st: AND EAX, 1 JZ @@Exit //EAX = $699420 + 1352*EBX + 21708. LEA ECX, DS:0[EBX*8] SUB ECX, EBX LEA EDX, [ECX+ECX*2] MOV ECX, DWORD PTR DS:[$699420] LEA EAX, [EBX+EDX*8] LEA EAX, [ECX+EAX*8+21708] @@Exit: PUSH $44009A
END;
//Модификация условия выхода из цикла (в функции $440030).
//42 прохода (для каждого стека) вместо стандартных 8 (для каждой возможной позиции около атакующего).
PROCEDURE Damage_target; ASSEMBLER; {$FRAME-}
ASM PUSH EAX //Если 32-й бит в v9501 = 1, модифицируем. MOV EAX, DWORD PTR DS:[$890AD8] SHR EAX, 31 TEST EAX, EAX JNZ @@Modify //Восстановление изначального кода: сравнивание номера текущего атакованного с 8. CMP EBX, 8 JMP @@Exit //Модифицирование кода: сравнивание номера текущего атакованного с 42. @@Modify: CMP EBX, 42 @@Exit: POP EAX MOV [EBP-12], EBX//Восстанавливаем испорченную команду. PUSH $44019A
END;
BEGIN HookCode(POINTER($440052), @Damage_ability, C_HOOKTYPE_JUMP); HookCode(POINTER($440064), @Damage_position, C_HOOKTYPE_JUMP); HookCode(POINTER($440095), @Damage_stack, C_HOOKTYPE_JUMP); HookCode(POINTER($440194), @Damage_target, C_HOOKTYPE_JUMP);
END.
Ошибка по адресу 0x004417A4 (MOV EAX, [ESI+34h]) - попытка прочесть память по адресу 34h.
Ещё - отклонение, вызвавшее, скорее всего, эту ошибку - неправильная работа функции sub_5242E0, вызванной по адресу 0x00440064. Там идёт работа со стеком напрямую и извлекается неверное значение (по адресу 0x0052430F (MOV EBX, [EBP+arg_0]; arg_0 = 8])).
Но фишка-то в том, что всё это только при отладке. Просто в игре ничего такого нет.
P.S. Без включенного режима немодифицируемости (отключить - 32-й бит переменной v9501 = 1) ошибка будет в любом случае (правда, разная в игре и отладчике), но с этим я как-нибудь сам разберусь.
(This post was last modified: 14.11.2010 23:33 by Sav.)
|