И такс, ну чтож, приступим, посмотрев список опкодов необработанных в лизисе от квики, пришел к выводу что можно немного запротектить плагин несколькими способами, от ключей до вызова опкодов.
И так, имеем:
AmxModX
StrafeHack Detector
и руки, или нет?
Буду использовать стрейф детектор для примера.
Компилируем плагин (без ключей).
Пробуй декомпилировать
В этот раз будем использовать именно вызов опкода который не обрабатывается.
Всеми любимый lctrl)
(можно заюзать shl_c_pri он тоже не обработан на сколько я помню)
Создаем глобальную переменную
Добавляем вызовы опкодов в начало каждой функции.
Получаем что то вроде:
Компилируем и пробуем декомпилировать Lisys'ом:
Эт самый простейший способ. Можно вообще не заморачиватся и воспользоватся ключами(я не о d0).
Работа с памятью в статье лишь для примера, для корректной работы плагина нужно немного дописать.
На вопросы отвечать тож не буду, т.к над иметь немного познаний асамблера, или нет?
Пример со вторым не обработанным опкодом
И так, имеем:
AmxModX
StrafeHack Detector
и руки, или нет?
Буду использовать стрейф детектор для примера.
Компилируем плагин (без ключей).
Пробуй декомпилировать
Код:
#pragma semicolon 1
#pragma ctrlchar '\'
new m_pPlayer = 41;
new XO_CBASEPLAYERWEAPON = 4;
new g_ePlayerInfo[33][5];
new g_ePlayerLog[33][12];
new g_ePlayerButtons[4][2] =
{
{
8, 0
},
{
16, 1
}
Error on write global g_ePlayerButtons: Index was outside the bounds of the array.
new g_szKeyName[4][] =
{
"[W]",
"",
"[A]",
"[D]"
};
new g_iKeyFrames[33][4];
new g_iOldKeyFrames[33][4];
new g_iKeyWarning[33][4];
new Float:g_fOldAngles[33][3];
new g_iOldTurning[33];
new Float:g_fOldStrafeAngles[33][3];
new Float:g_fOldAnglesDiff[33];
bool:operator==(Float:,Float:)(Float:oper1, Float:oper2)
{
return floatcmp(oper1, oper2) == 0;
}
bool:operator!=(Float:,Float:)(Float:oper1, Float:oper2)
{
return floatcmp(oper1, oper2) != 0;
}
bool:operator>(Float:,Float:)(Float:oper1, Float:oper2)
{
return 0 < floatcmp(oper1, oper2);
}
bool:operator>=(Float:,Float:)(Float:oper1, Float:oper2)
{
return 0 <= floatcmp(oper1, oper2);
}
bool:operator>=(Float:,_:)(Float:oper1, oper2)
{
return 0 <= floatcmp(oper1, float(oper2));
}
bool:operator<(Float:,Float:)(Float:oper1, Float:oper2)
{
return 0 > floatcmp(oper1, oper2);
}
bool:operator<(Float:,_:)(Float:oper1, oper2)
{
return 0 > floatcmp(oper1, float(oper2));
}
bool:operator<=(Float:,Float:)(Float:oper1, Float:oper2)
{
return 0 >= floatcmp(oper1, oper2);
}
public __fatal_ham_error(Ham:id, HamError:err, String:reason[])
{
!!! Removed Phi
if (func != -1 && callfunc_begin_i(func, -1) == 1)
{
callfunc_push_int(id);
callfunc_push_int(err);
callfunc_push_str(reason, false);
if (callfunc_end() == 1)
{
fail = 0;
}
}
if (fail)
{
set_fail_state(reason);
}
return 0;
}
public plugin_init()
{
register_plugin("StrafeHack Detector", "0.1", "Mistrick");
register_forward(FM_CmdStart, "FM_CmdStart_Pre", 0);
register_forward(FM_PlayerPreThink, "FM_PlayerPreThink_Pre", 0);
new iId = 1;
new szWeaponName[32];
while (iId <= 30)
{
if (get_weaponname(iId, szWeaponName, 31))
{
RegisterHam(Ham_Item_Deploy, szWeaponName, "Ham_Item_Deploy_Pre", 0);
iId++;
}
iId++;
}
return 0;
}
public Ham_Item_Deploy_Pre(weapon)
{
new id = get_pdata_cbase(weapon, m_pPlayer, XO_CBASEPLAYERWEAPON, "");
g_ePlayerInfo[id][0][0][4] = get_gametime();
return 0;
}
public FM_PlayerPreThink_Pre(id)
{
!!! Removed Phi
if (!is_user_alive(id))
{
return 1;
}
new bBlockSpeed = 0;
new bButtons = pev(id, pev_button);
new bOldButton = pev(id, pev_oldbuttons);
new i = 0;
while (i < 4)
{
new CheckButton = g_ePlayerButtons[0][0][0];
new CheckKey = g_ePlayerButtons[0][0][1];
if (CheckButton & bButtons)
{
g_iKeyFrames[id][0][0][CheckKey]++;
}
if (CheckButton & ~bButtons && CheckButton & bOldButton)
{
if (g_iOldKeyFrames[id][0][0][CheckKey] == g_iKeyFrames[id][0][0][CheckKey])
{
if (g_iKeyFrames[id][0][0][CheckKey] == 1)
{
g_iKeyWarning[id][0][0][CheckKey]++;
}
new var2 = g_iKeyWarning[id][0][0][CheckKey];
var2++;
if (5 <= var2)
{
bBlockSpeed = 1;
g_iKeyWarning[id][0][0][CheckKey] = 0;
new Float:fTime = get_gametime();
if (fTime >= g_ePlayerLog[id][0][0][3])
{
g_ePlayerLog[id][0][0][3] = fTime + 3.00;
UTIL_LogUser(id, "CheatKeys: [%d] keyframe agreement[%d], key %s", g_ePlayerLog[id][0][0][9], g_iKeyFrames[id][0][0][CheckKey], g_szKeyName[CheckKey][0][0]);
g_ePlayerLog[id][0][0][9] = 0;
}
g_ePlayerLog[id][0][0][9]++;
}
}
else
{
if (g_iKeyWarning[id][0][0][CheckKey])
{
g_iKeyWarning[id][0][0][CheckKey]--;
}
}
g_iOldKeyFrames[id][0][0][CheckKey] = g_iKeyFrames[id][0][0][CheckKey];
g_iKeyFrames[id][0][0][CheckKey] = 0;
i++;
}
i++;
}
if (bBlockSpeed)
{
new Float:fVelocity[3];
pev(id, pev_velocity, fVelocity);
fVelocity[0] = fVelocity[0] * 0.20;
fVelocity[1] *= 0.20;
set_pev(id, pev_velocity, fVelocity);
}
return 1;
}
StrafeForward(id, Float:angles[3])
{
!!! Removed Phi
new Float:fAnglesDiff[3];
vec_diff(fAnglesDiff, angles, g_fOldStrafeAngles[id][0][0]);
if (fAnglesDiff[1] >= 0.00)
{
fAnglesDiff[1] -= 360.00;
}
if (fAnglesDiff[1] < NaN)
{
fAnglesDiff[1] += 360.00;
}
fAnglesDiff[1] = floatabs(fAnglesDiff[1]);
if (fAnglesDiff[1] < 90.00)
{
new Float:fDiff = floatabs(fAnglesDiff[1] - g_fOldAnglesDiff[id][0][0]);
new iOldWarn = g_ePlayerInfo[id][0][0][2];
if (fDiff < 0.10)
{
g_ePlayerInfo[id][0][0][2] += 5;
}
else
{
if (fDiff < 1.00)
{
g_ePlayerInfo[id][0][0][2]++;
}
if (g_ePlayerInfo[id][0][0][2])
{
g_ePlayerInfo[id][0][0][2]--;
}
}
new Float:fTime = get_gametime();
if (iOldWarn < g_ePlayerInfo[id][0][0][2])
{
if (fTime <= g_ePlayerLog[id][0][0][4] + 3.00)
{
new var1 = g_ePlayerLog[id][0][0][10];
var1++;
if (5 <= var1)
{
UTIL_LogUser(id, "CheatStrafes: diff %f, cur angle %f, old angle %f", fDiff, fAnglesDiff[1], g_fOldAnglesDiff[id]);
}
}
else
{
g_ePlayerLog[id][0][0][10] = 0;
}
g_ePlayerLog[id][0][0][4] = fTime;
}
if (15 <= g_ePlayerInfo[id][0][0][2])
{
if (fTime >= g_ePlayerLog[id][0][0][5])
{
g_ePlayerLog[id][0][0][5] = fTime + 3.00;
PunishPlayer(id, "StrafeMacros");
UTIL_LogUser(id, "CheatStrafes: [%d] using macros", g_ePlayerLog[id][0][0][11]);
g_ePlayerLog[id][0][0][11] = 0;
}
g_ePlayerLog[id][0][0][11]++;
g_ePlayerInfo[id][0][0][2] = 0;
}
}
g_fOldAnglesDiff[id] = fAnglesDiff[1];
new var2 = g_fOldStrafeAngles[id][0][0];
new var3 = angles;
var2[0] = var3;
return 0;
}
vec_diff(Float:vec[3], Float:new_vec[3], Float:old_vec[3])
{
vec[0] = new_vec[0] - old_vec[0];
vec[1] = new_vec[1] - old_vec[1];
vec[2] = new_vec[2] - old_vec[2];
return 0;
}
equal_null(Float:vec[3])
{
new var4 = 0.00;
new var1;
new var2;
if (var4 == vec[0])
{
new var5 = 0.00;
if (var5 == vec[1])
{
var2 = var5;
new var3;
if (ERROR: Phi)
{
var3 = 1;
}
else
{
var3 = 0;
}
/ * ERROR! Unable to cast object of type 'Lysis.DSentinel' to type 'Lysis.DReturn'. * /
function "equal_null"
equal_null(Float:vec[3])
PunishPlayer(id, String:reason[])
{
new szName[32];
get_user_name(id, szName, 31);
client_print(0, print_chat, "[SHD] %s using %s.", szName, reason);
return 0;
}
UTIL_LogUser(id, String:szCvar[])
{
static szLogFile[128];
if (!szLogFile[0][0])
{
get_localinfo("amxx_logs", szLogFile, 127);
format(szLogFile, 127, "/%s/%s", szLogFile, "strafehack_detector.log");
}
new iFile = 0;
new var1 = fopen("", "a");
iFile = var1;
if (var1)
{
new szName[32];
new szAuthid[32];
new szIp[32];
new szTime[22];
new message[128];
vformat(message, 127, szCvar, 3);
get_user_name(id, szName, 31);
get_user_authid(id, szAuthid, 31);
get_user_ip(id, szIp, 31, 1);
get_time("%m/%d/%Y - %H:%M:%S", szTime, 21);
fprintf(iFile, "L %s: <%s><%s><%s> %s\n", szTime, szName, szAuthid, szIp, message);
fclose(iFile);
}
return 0;
}
В этот раз будем использовать именно вызов опкода который не обрабатывается.
Всеми любимый lctrl)
(можно заюзать shl_c_pri он тоже не обработан на сколько я помню)
Создаем глобальную переменную
Код:
new abcd;
Добавляем вызовы опкодов в начало каждой функции.
Код:
#emit LCTRL 6
#emit STOR.pri abcd
Получаем что то вроде:
C++:
#include <amxmodx>
#include <engine>
#include <fakemeta>
#include <fun>
#include <hamsandwich>
new abcd;
#define PLUGIN "StrafeHack Detector"
#define VERSION "0.1"
#define AUTHOR "Mistrick"
C++:
#pragma semicolon 1
const PITCH = 0;
const YAW = 1;
const LEFT = 1;
const RIGHT = 2;
stock const m_afButtonPressed = 246;
stock const m_afButtonReleased = 247;
stock const m_pPlayer = 41;
stock const XO_CBASEPLAYER = 5;
stock const XO_CBASEPLAYERWEAPON = 4;
#define LOGFILE "strafehack_detector.log"
#define MIN_LOG_TIME 3.0
#define MAX_BADFRAMES 5
#define MAX_KEYWARNING 5
#define MAX_STRAFES 16
#define STRAFE_CHECK_TIME 0.2
#define MAX_ANGLE_CHECK 90.0
#define MIN_STRAFE_ANGLE_DIFF 1.0
#define MAX_STRAFE_ANGLE_WARNINGS 15
#define MIN_STRAFE_ANGLE_WARNINGS_TO_LOG 5
#define IGNORE_TIME 0.5
enum _:PLAYER_DATA
{
m_BadFrame,
m_Strafes,
m_WarningStrafeAngle,
Float:m_fLastStrafeCheck,
Float:m_fLastWeaponDeploy
};
new g_ePlayerInfo[33][PLAYER_DATA];
enum _:LOG_DATA
{
Float:m_LastForwardMoveLog,
Float:m_LastSideMoveLog,
Float:m_LastValueLog,
Float:m_LastKeyLog,
Float:m_LastStrafeAngleLog,
Float:m_LastChatLog,
m_CountForwardMoveLog,
m_CountSideMoveLog,
m_CountValueLog,
m_CountKeyLog,
m_CountStrafeAngleLog,
m_CountChatLog
};
new g_ePlayerLog[33][LOG_DATA];
enum _:KEYS
{
KEY_W, KEY_S, KEY_A, KEY_D
}
enum _:BUTTONS_DATA
{
BUTTON, KEY
}
new g_ePlayerButtons[][BUTTONS_DATA] =
{
{IN_FORWARD, KEY_W}, {IN_BACK, KEY_S}, {IN_MOVELEFT, KEY_A}, {IN_MOVERIGHT, KEY_D}
};
new g_szKeyName[KEYS][] =
{
"[W]", "", "[A]", "[D]"
};
new g_iKeyFrames[33][KEYS], g_iOldKeyFrames[33][KEYS], g_iKeyWarning[33][KEYS];
new Float:g_fOldAngles[33][3];
new g_iOldTurning[33];
new Float:g_fOldStrafeAngles[33][3];
new Float:g_fOldAnglesDiff[33];
public plugin_init()
{
#emit LCTRL 6
#emit STOR.pri abcd
register_plugin(PLUGIN, VERSION, AUTHOR);
register_forward(FM_CmdStart, "FM_CmdStart_Pre", false);
register_forward(FM_PlayerPreThink, "FM_PlayerPreThink_Pre", false);
for(new iId = CSW_P228, szWeaponName[32]; iId <= CSW_P90; iId++)
{
if(get_weaponname(iId, szWeaponName, charsmax(szWeaponName)))
{
RegisterHam(Ham_Item_Deploy, szWeaponName, "Ham_Item_Deploy_Pre", false);
}
}
}
public Ham_Item_Deploy_Pre(weapon)
{
#emit LCTRL 6
#emit STOR.pri abcd
new id = get_pdata_cbase(weapon, m_pPlayer, XO_CBASEPLAYERWEAPON);
g_ePlayerInfo[id][m_fLastWeaponDeploy] = _:get_gametime();
}
public FM_CmdStart_Pre(id, uc_handle, seed)
{
#emit LCTRL 6
#emit STOR.pri abcd
if(!is_user_alive(id)) return FMRES_IGNORED;
new Float:fForwardMove; get_uc(uc_handle, UC_ForwardMove, fForwardMove);
new Float:fSideMove; get_uc(uc_handle, UC_SideMove, fSideMove);
if(fForwardMove == 0.0 && fSideMove == 0.0) return FMRES_IGNORED;
new Float:fTime = get_gametime();
if(fTime < g_ePlayerInfo[id][m_fLastWeaponDeploy] + IGNORE_TIME) return FMRES_IGNORED;
new bBlockSpeed = false;
new bButtons = get_uc(uc_handle, UC_Buttons);
new Float:fAngles[3]; pev(id, pev_angles, fAngles);
new Float:fAnglesDiff[3]; vec_diff(fAnglesDiff, fAngles, g_fOldAngles[id]);
new Float:fValue = floatsqroot(fForwardMove * fForwardMove + fSideMove * fSideMove);
if(!(equal_null(fAnglesDiff) && fValue > 115.0))
{
// forwardmove without button
if((fForwardMove > 0.0 && ~bButtons & IN_FORWARD || fForwardMove < 0.0 && ~bButtons & IN_BACK) && fAnglesDiff[PITCH] != 0.0)
{
bBlockSpeed = true;
if(fTime >= g_ePlayerLog[id][m_LastForwardMoveLog])
{
g_ePlayerLog[id][m_LastForwardMoveLog] = _:(fTime + MIN_LOG_TIME);
UTIL_LogUser(id, "CheatMoves: [%d] forward move without button[%.1f]", g_ePlayerLog[id][m_CountForwardMoveLog], fForwardMove);
g_ePlayerLog[id][m_CountForwardMoveLog] = 0;
}
g_ePlayerLog[id][m_CountForwardMoveLog]++;
}
// sidemove without button
if(fSideMove > 0.0 && ~bButtons & IN_MOVERIGHT || fSideMove < 0.0 && ~bButtons & IN_MOVELEFT)
{
bBlockSpeed = true;
if(fTime >= g_ePlayerLog[id][m_LastSideMoveLog])
{
g_ePlayerLog[id][m_LastSideMoveLog] = _:(fTime + MIN_LOG_TIME);
UTIL_LogUser(id, "CheatMoves: [%d] side move without button[%.1f]", g_ePlayerLog[id][m_CountSideMoveLog], fSideMove);
g_ePlayerLog[id][m_CountSideMoveLog] = 0;
}
g_ePlayerLog[id][m_CountSideMoveLog]++;
}
}
new Float:fMaxSpeed = get_user_maxspeed(id);
// value can't be more maxspeed
if(fValue > fMaxSpeed && fMaxSpeed > 100.0)
{
bBlockSpeed = true;
if(fTime >= g_ePlayerLog[id][m_LastValueLog])
{
g_ePlayerLog[id][m_LastValueLog] = _:(fTime + MIN_LOG_TIME);
UTIL_LogUser(id, "CheatMoves: [%d] value[%.1f], fw[%.1f], sd[%.1f], maxspeed[%.1f]", g_ePlayerLog[id][m_CountValueLog], fValue, fForwardMove, fSideMove, fMaxSpeed);
g_ePlayerLog[id][m_CountValueLog] = 0;
}
g_ePlayerLog[id][m_CountValueLog]++;
}
// block scripts with +right, +left
if(bButtons & (IN_LEFT | IN_RIGHT))
{
bBlockSpeed = true;
}
fForwardMove = floatabs(fForwardMove);
fSideMove = floatabs(fSideMove);
// cl_forwardspeed != cl_sidespeed
if(fForwardMove && fSideMove && fForwardMove != fSideMove)
{
if(++g_ePlayerInfo[id][m_BadFrame] >= MAX_BADFRAMES)
{
bBlockSpeed = true;
g_ePlayerInfo[id][m_BadFrame] = 0;
}
}
else
{
g_ePlayerInfo[id][m_BadFrame] = 0;
}
new iTurning = 0;
new Float:fDiff = fAngles[YAW] - g_fOldAngles[id][YAW];
if(fDiff >= 180.0) fDiff -= 360.0;
if(fDiff < -180.0) fDiff += 360.0;
if(fDiff < 0.0)
{
iTurning = RIGHT;
if(g_iOldTurning[id] == LEFT)
{
g_ePlayerInfo[id][m_Strafes]++;
StrafeForward(id, fAngles);
}
}
else if(fDiff > 0.0)
{
iTurning = LEFT;
if(g_iOldTurning[id] == RIGHT)
{
g_ePlayerInfo[id][m_Strafes]++;
StrafeForward(id, fAngles);
}
}
if(fTime >= g_ePlayerInfo[id][m_fLastStrafeCheck])
{
if(g_ePlayerInfo[id][m_Strafes] >= MAX_STRAFES)
{
bBlockSpeed = true;
UTIL_LogUser(id, "CheatStrafes: %d strafes in %.1f sec", g_ePlayerInfo[id][m_Strafes], STRAFE_CHECK_TIME);
}
g_ePlayerInfo[id][m_Strafes] = 0;
g_ePlayerInfo[id][m_fLastStrafeCheck] = _:(fTime + STRAFE_CHECK_TIME);
}
g_iOldTurning[id] = iTurning;
if(bBlockSpeed)
{
new Float:fVelocity[3]; pev(id, pev_velocity, fVelocity);
fVelocity[0] *= 0.2; fVelocity[1] *= 0.2;
set_pev(id, pev_velocity, fVelocity);
}
g_fOldAngles[id] = fAngles;
return FMRES_IGNORED;
}
public FM_PlayerPreThink_Pre(id)
{
#emit LCTRL 6
#emit STOR.pri abcd
if(!is_user_alive(id)) return FMRES_IGNORED;
new bBlockSpeed = false;
new bButtons = pev(id, pev_button);
new bOldButton = pev(id, pev_oldbuttons);
for(new i; i < sizeof(g_ePlayerButtons); i++)
{
new CheckButton = g_ePlayerButtons[BUTTON];
new CheckKey = g_ePlayerButtons[KEY];
if(bButtons & CheckButton)
{
g_iKeyFrames[id][CheckKey]++;
}
if(~bButtons & CheckButton && bOldButton & CheckButton)
{
if(g_iKeyFrames[id][CheckKey] == g_iOldKeyFrames[id][CheckKey])
{
if(g_iKeyFrames[id][CheckKey] == 1) g_iKeyWarning[id][CheckKey]++;
if(++g_iKeyWarning[id][CheckKey] >= MAX_KEYWARNING)
{
bBlockSpeed = true;
g_iKeyWarning[id][CheckKey] = 0;
new Float:fTime = get_gametime();
if(fTime >= g_ePlayerLog[id][m_LastKeyLog])
{
g_ePlayerLog[id][m_LastKeyLog] = _:(fTime + MIN_LOG_TIME);
UTIL_LogUser(id, "CheatKeys: [%d] keyframe agreement[%d], key %s", g_ePlayerLog[id][m_CountKeyLog], g_iKeyFrames[id][CheckKey], g_szKeyName[CheckKey]);
g_ePlayerLog[id][m_CountKeyLog] = 0;
}
g_ePlayerLog[id][m_CountKeyLog]++;
}
}
else if(g_iKeyWarning[id][CheckKey])
{
g_iKeyWarning[id][CheckKey]--;
}
//console_print(id, "key frame %s is %d, warn [%d]", g_szKeyName[CheckKey], g_iKeyFrames[id][CheckKey], g_iKeyWarning[id][CheckKey]);
g_iOldKeyFrames[id][CheckKey] = g_iKeyFrames[id][CheckKey];
g_iKeyFrames[id][CheckKey] = 0;
}
}
if(bBlockSpeed)
{
new Float:fVelocity[3]; pev(id, pev_velocity, fVelocity);
fVelocity[0] *= 0.2; fVelocity[1] *= 0.2;
set_pev(id, pev_velocity, fVelocity);
}
return FMRES_IGNORED;
}
StrafeForward(id, Float:angles[3])
{
#emit LCTRL 6
#emit STOR.pri abcd
new Float:fAnglesDiff[3]; vec_diff(fAnglesDiff, angles, g_fOldStrafeAngles[id]);
if(fAnglesDiff[YAW] >= 180) fAnglesDiff[YAW] -= 360.0;
if(fAnglesDiff[YAW] < -180) fAnglesDiff[YAW] += 360.0;
fAnglesDiff[YAW] = floatabs(fAnglesDiff[YAW]);
//console_print(id, "strafe angle diff %f, old angle diff %f, turning [%d]", fAnglesDiff[YAW], g_fOldAnglesDiff[id], turning);
if(fAnglesDiff[YAW] < MAX_ANGLE_CHECK)
{
new Float:fDiff = floatabs(fAnglesDiff[YAW] - g_fOldAnglesDiff[id]);
new iOldWarn = g_ePlayerInfo[id][m_WarningStrafeAngle];
if( fDiff < 0.1 )
{
g_ePlayerInfo[id][m_WarningStrafeAngle] += 5;
}
else if( fDiff < MIN_STRAFE_ANGLE_DIFF )
{
g_ePlayerInfo[id][m_WarningStrafeAngle]++;
}
else if(g_ePlayerInfo[id][m_WarningStrafeAngle])
{
g_ePlayerInfo[id][m_WarningStrafeAngle]--;
}
new Float:fTime = get_gametime();
if(g_ePlayerInfo[id][m_WarningStrafeAngle] > iOldWarn)
{
//console_print(id, " time %f, last time %f, count %d", fTime, g_ePlayerLog[id][m_LastStrafeAngleLog], g_ePlayerLog[id][m_CountStrafeAngleLog]);
if( fTime <= g_ePlayerLog[id][m_LastStrafeAngleLog] + MIN_LOG_TIME)
{
if(++g_ePlayerLog[id][m_CountStrafeAngleLog] >= MIN_STRAFE_ANGLE_WARNINGS_TO_LOG)
{
UTIL_LogUser(id, "CheatStrafes: diff %f, cur angle %f, old angle %f", fDiff, fAnglesDiff[YAW], g_fOldAnglesDiff[id]);
}
}
else
{
g_ePlayerLog[id][m_CountStrafeAngleLog] = 0;
}
g_ePlayerLog[id][m_LastStrafeAngleLog] = _:fTime;
}
if(g_ePlayerInfo[id][m_WarningStrafeAngle] >= MAX_STRAFE_ANGLE_WARNINGS)
{
if(fTime >= g_ePlayerLog[id][m_LastChatLog])
{
g_ePlayerLog[id][m_LastChatLog] = _:(fTime + MIN_LOG_TIME);
PunishPlayer(id, "StrafeMacros");
UTIL_LogUser(id, "CheatStrafes: [%d] using macros", g_ePlayerLog[id][m_CountChatLog]);
g_ePlayerLog[id][m_CountChatLog] = 0;
}
g_ePlayerLog[id][m_CountChatLog]++;
g_ePlayerInfo[id][m_WarningStrafeAngle] = 0;
}
}
g_fOldAnglesDiff[id] = fAnglesDiff[YAW];
g_fOldStrafeAngles[id] = angles;
}
vec_diff(Float:vec[3], Float:new_vec[3], Float:old_vec[3])
{
#emit LCTRL 6
#emit STOR.pri abcd
vec[0] = new_vec[0] - old_vec[0];
vec[1] = new_vec[1] - old_vec[1];
vec[2] = new_vec[2] - old_vec[2];
}
equal_null(Float:vec[3])
{
#emit LCTRL 6
#emit STOR.pri abcd
return (vec[0] == 0.0 && vec[1] == 0.0) ? true : false;
}
stock PunishPlayer(id, reason[])
{
#emit LCTRL 6
#emit STOR.pri abcd
new szName[32]; get_user_name(id, szName, charsmax(szName));
client_print(0, print_chat, "[SHD] %s using %s.", szName, reason);
}
stock UTIL_LogUser(const id, const szCvar[], any:...)
{
#emit LCTRL 6
#emit STOR.pri abcd
static szLogFile[128];
if(!szLogFile[0])
{
get_localinfo("amxx_logs", szLogFile, charsmax(szLogFile));
format(szLogFile, charsmax(szLogFile), "/%s/%s", szLogFile, LOGFILE);
}
new iFile;
if( (iFile = fopen(szLogFile, "a")) )
{
new szName[32], szAuthid[32], szIp[32], szTime[22];
new message[128]; vformat(message, charsmax(message), szCvar, 3);
get_user_name(id, szName, charsmax(szName));
get_user_authid(id, szAuthid, charsmax(szAuthid));
get_user_ip(id, szIp, charsmax(szIp), 1);
get_time("%m/%d/%Y - %H:%M:%S", szTime, charsmax(szTime));
fprintf(iFile, "L %s: <%s><%s><%s> %s^n", szTime, szName, szAuthid, szIp, message);
fclose(iFile);
}
}
Компилируем и пробуем декомпилировать Lisys'ом:
Код:
#pragma semicolon 1
#pragma ctrlchar '\'
Код:
new abcd;
new m_pPlayer = 41;
new XO_CBASEPLAYERWEAPON = 4;
new g_ePlayerInfo[33][5];
new g_ePlayerLog[33][12];
new g_ePlayerButtons[4][2] =
{
{
8, 0
},
{
16, 1
}
Error on write global g_ePlayerButtons: Index was outside the bounds of the array.
new g_szKeyName[4][] =
{
"[W]",
"",
"[A]",
"[D]"
};
new g_iKeyFrames[33][4];
new g_iOldKeyFrames[33][4];
new g_iKeyWarning[33][4];
new Float:g_fOldAngles[33][3];
new g_iOldTurning[33];
new Float:g_fOldStrafeAngles[33][3];
new Float:g_fOldAnglesDiff[33];
bool:operator==(Float:,Float:)(Float:oper1, Float:oper2)
{
return floatcmp(oper1, oper2) == 0;
}
bool:operator!=(Float:,Float:)(Float:oper1, Float:oper2)
{
return floatcmp(oper1, oper2) != 0;
}
bool:operator>(Float:,Float:)(Float:oper1, Float:oper2)
{
return 0 < floatcmp(oper1, oper2);
}
bool:operator>=(Float:,Float:)(Float:oper1, Float:oper2)
{
return 0 <= floatcmp(oper1, oper2);
}
bool:operator>=(Float:,_:)(Float:oper1, oper2)
{
return 0 <= floatcmp(oper1, float(oper2));
}
bool:operator<(Float:,Float:)(Float:oper1, Float:oper2)
{
return 0 > floatcmp(oper1, oper2);
}
bool:operator<(Float:,_:)(Float:oper1, oper2)
{
return 0 > floatcmp(oper1, float(oper2));
}
bool:operator<=(Float:,Float:)(Float:oper1, Float:oper2)
{
return 0 >= floatcmp(oper1, oper2);
}
public __fatal_ham_error(Ham:id, HamError:err, String:reason[])
{
!!! Removed Phi
if (func != -1 && callfunc_begin_i(func, -1) == 1)
{
callfunc_push_int(id);
callfunc_push_int(err);
callfunc_push_str(reason, false);
if (callfunc_end() == 1)
{
fail = 0;
}
}
if (fail)
{
set_fail_state(reason);
}
return 0;
}
/ * ERROR! Unrecognized opcode: lctrl * /
function "plugin_init"
public plugin_init()
/ * ERROR! Unrecognized opcode: lctrl * /
function "Ham_Item_Deploy_Pre"
public Ham_Item_Deploy_Pre(weapon)
/ * ERROR! Unrecognized opcode: lctrl * /
function "FM_CmdStart_Pre"
public FM_CmdStart_Pre(id, uc_handle, seed)
/ * ERROR! Unrecognized opcode: lctrl * /
function "FM_PlayerPreThink_Pre"
public FM_PlayerPreThink_Pre(id)
/ * ERROR! Unrecognized opcode: lctrl * /
function "StrafeForward"
StrafeForward(id, Float:angles[3])
/ * ERROR! Unrecognized opcode: lctrl * /
function "vec_diff"
vec_diff(Float:vec[3], Float:new_vec[3], Float:old_vec[3])
/ * ERROR! Unrecognized opcode: lctrl * /
function "equal_null"
equal_null(Float:vec[3])
/ * ERROR! Unrecognized opcode: lctrl * /
function "PunishPlayer"
PunishPlayer(id, String:reason[])
/ * ERROR! Unrecognized opcode: lctrl * /
function "UTIL_LogUser"
UTIL_LogUser(id, String:szCvar[])
Эт самый простейший способ. Можно вообще не заморачиватся и воспользоватся ключами(я не о d0).
Работа с памятью в статье лишь для примера, для корректной работы плагина нужно немного дописать.
На вопросы отвечать тож не буду, т.к над иметь немного познаний асамблера, или нет?
10 Апр 2017
Код:
#include <amxmodx>
#include <engine>
#include <fakemeta>
#include <fun>
#include <hamsandwich>
new abcd;
#define PLUGIN "StrafeHack Detector"
#define VERSION "0.1"
#define AUTHOR "Mistrick"
Код:
#pragma semicolon 1
const PITCH = 0;
const YAW = 1;
const LEFT = 1;
const RIGHT = 2;
stock const m_afButtonPressed = 246;
stock const m_afButtonReleased = 247;
stock const m_pPlayer = 41;
stock const XO_CBASEPLAYER = 5;
stock const XO_CBASEPLAYERWEAPON = 4;
#define LOGFILE "strafehack_detector.log"
#define MIN_LOG_TIME 3.0
#define MAX_BADFRAMES 5
#define MAX_KEYWARNING 5
#define MAX_STRAFES 16
#define STRAFE_CHECK_TIME 0.2
#define MAX_ANGLE_CHECK 90.0
#define MIN_STRAFE_ANGLE_DIFF 1.0
#define MAX_STRAFE_ANGLE_WARNINGS 15
#define MIN_STRAFE_ANGLE_WARNINGS_TO_LOG 5
#define IGNORE_TIME 0.5
enum _:PLAYER_DATA
{
m_BadFrame,
m_Strafes,
m_WarningStrafeAngle,
Float:m_fLastStrafeCheck,
Float:m_fLastWeaponDeploy
};
new g_ePlayerInfo[33][PLAYER_DATA];
enum _:LOG_DATA
{
Float:m_LastForwardMoveLog,
Float:m_LastSideMoveLog,
Float:m_LastValueLog,
Float:m_LastKeyLog,
Float:m_LastStrafeAngleLog,
Float:m_LastChatLog,
m_CountForwardMoveLog,
m_CountSideMoveLog,
m_CountValueLog,
m_CountKeyLog,
m_CountStrafeAngleLog,
m_CountChatLog
};
new g_ePlayerLog[33][LOG_DATA];
enum _:KEYS
{
KEY_W, KEY_S, KEY_A, KEY_D
}
enum _:BUTTONS_DATA
{
BUTTON, KEY
}
new g_ePlayerButtons[][BUTTONS_DATA] =
{
{IN_FORWARD, KEY_W}, {IN_BACK, KEY_S}, {IN_MOVELEFT, KEY_A}, {IN_MOVERIGHT, KEY_D}
};
new g_szKeyName[KEYS][] =
{
"[W]", "", "[A]", "[D]"
};
new g_iKeyFrames[33][KEYS], g_iOldKeyFrames[33][KEYS], g_iKeyWarning[33][KEYS];
new Float:g_fOldAngles[33][3];
new g_iOldTurning[33];
new Float:g_fOldStrafeAngles[33][3];
new Float:g_fOldAnglesDiff[33];
public plugin_init()
{
register_plugin(PLUGIN, VERSION, AUTHOR);
register_forward(FM_CmdStart, "FM_CmdStart_Pre", false);
register_forward(FM_PlayerPreThink, "FM_PlayerPreThink_Pre", false);
for(new iId = CSW_P228, szWeaponName[32]; iId <= CSW_P90; iId++){
if(get_weaponname(iId, szWeaponName, charsmax(szWeaponName)))
{
RegisterHam(Ham_Item_Deploy, szWeaponName, "Ham_Item_Deploy_Pre", false);
}
}
#emit LOAD.S.pri abcd
#emit SHL.C.pri 5
#emit STOR.S.pri abcd
}
public Ham_Item_Deploy_Pre(weapon)
{
new id = get_pdata_cbase(weapon, m_pPlayer, XO_CBASEPLAYERWEAPON);
g_ePlayerInfo[id][m_fLastWeaponDeploy] = _:get_gametime();
#emit LOAD.S.pri abcd
#emit SHL.C.pri 5
#emit STOR.S.pri abcd
}
public FM_CmdStart_Pre(id, uc_handle, seed)
{
#emit LOAD.S.pri abcd
#emit SHL.C.pri 5
#emit STOR.S.pri abcd
if(!is_user_alive(id)) return FMRES_IGNORED;
new Float:fForwardMove; get_uc(uc_handle, UC_ForwardMove, fForwardMove);
new Float:fSideMove; get_uc(uc_handle, UC_SideMove, fSideMove);
if(fForwardMove == 0.0 && fSideMove == 0.0) return FMRES_IGNORED;
new Float:fTime = get_gametime();
if(fTime < g_ePlayerInfo[id][m_fLastWeaponDeploy] + IGNORE_TIME) return FMRES_IGNORED;
new bBlockSpeed = false;
new bButtons = get_uc(uc_handle, UC_Buttons);
new Float:fAngles[3]; pev(id, pev_angles, fAngles);
new Float:fAnglesDiff[3]; vec_diff(fAnglesDiff, fAngles, g_fOldAngles[id]);
new Float:fValue = floatsqroot(fForwardMove * fForwardMove + fSideMove * fSideMove);
if(!(equal_null(fAnglesDiff) && fValue > 115.0))
{
// forwardmove without button
if((fForwardMove > 0.0 && ~bButtons & IN_FORWARD || fForwardMove < 0.0 && ~bButtons & IN_BACK) && fAnglesDiff[PITCH] != 0.0)
{
bBlockSpeed = true;
if(fTime >= g_ePlayerLog[id][m_LastForwardMoveLog])
{
g_ePlayerLog[id][m_LastForwardMoveLog] = _:(fTime + MIN_LOG_TIME);
UTIL_LogUser(id, "CheatMoves: [%d] forward move without button[%.1f]", g_ePlayerLog[id][m_CountForwardMoveLog], fForwardMove);
g_ePlayerLog[id][m_CountForwardMoveLog] = 0;
}
g_ePlayerLog[id][m_CountForwardMoveLog]++;
}
// sidemove without button
if(fSideMove > 0.0 && ~bButtons & IN_MOVERIGHT || fSideMove < 0.0 && ~bButtons & IN_MOVELEFT)
{
bBlockSpeed = true;
if(fTime >= g_ePlayerLog[id][m_LastSideMoveLog])
{
g_ePlayerLog[id][m_LastSideMoveLog] = _:(fTime + MIN_LOG_TIME);
UTIL_LogUser(id, "CheatMoves: [%d] side move without button[%.1f]", g_ePlayerLog[id][m_CountSideMoveLog], fSideMove);
g_ePlayerLog[id][m_CountSideMoveLog] = 0;
}
g_ePlayerLog[id][m_CountSideMoveLog]++;
}
}
new Float:fMaxSpeed = get_user_maxspeed(id);
// value can't be more maxspeed
if(fValue > fMaxSpeed && fMaxSpeed > 100.0)
{
bBlockSpeed = true;
if(fTime >= g_ePlayerLog[id][m_LastValueLog])
{
g_ePlayerLog[id][m_LastValueLog] = _:(fTime + MIN_LOG_TIME);
UTIL_LogUser(id, "CheatMoves: [%d] value[%.1f], fw[%.1f], sd[%.1f], maxspeed[%.1f]", g_ePlayerLog[id][m_CountValueLog], fValue, fForwardMove, fSideMove, fMaxSpeed);
g_ePlayerLog[id][m_CountValueLog] = 0;
}
g_ePlayerLog[id][m_CountValueLog]++;
}
// block scripts with +right, +left
if(bButtons & (IN_LEFT | IN_RIGHT))
{
bBlockSpeed = true;
}
fForwardMove = floatabs(fForwardMove);
fSideMove = floatabs(fSideMove);
// cl_forwardspeed != cl_sidespeed
if(fForwardMove && fSideMove && fForwardMove != fSideMove)
{
if(++g_ePlayerInfo[id][m_BadFrame] >= MAX_BADFRAMES)
{
bBlockSpeed = true;
g_ePlayerInfo[id][m_BadFrame] = 0;
}
}
else
{
g_ePlayerInfo[id][m_BadFrame] = 0;
}
new iTurning = 0;
new Float:fDiff = fAngles[YAW] - g_fOldAngles[id][YAW];
if(fDiff >= 180.0) fDiff -= 360.0;
if(fDiff < -180.0) fDiff += 360.0;
if(fDiff < 0.0)
{
iTurning = RIGHT;
if(g_iOldTurning[id] == LEFT)
{
g_ePlayerInfo[id][m_Strafes]++;
StrafeForward(id, fAngles);
}
}
else if(fDiff > 0.0)
{
iTurning = LEFT;
if(g_iOldTurning[id] == RIGHT)
{
g_ePlayerInfo[id][m_Strafes]++;
StrafeForward(id, fAngles);
}
}
if(fTime >= g_ePlayerInfo[id][m_fLastStrafeCheck])
{
if(g_ePlayerInfo[id][m_Strafes] >= MAX_STRAFES)
{
bBlockSpeed = true;
UTIL_LogUser(id, "CheatStrafes: %d strafes in %.1f sec", g_ePlayerInfo[id][m_Strafes], STRAFE_CHECK_TIME);
}
g_ePlayerInfo[id][m_Strafes] = 0;
g_ePlayerInfo[id][m_fLastStrafeCheck] = _:(fTime + STRAFE_CHECK_TIME);
}
g_iOldTurning[id] = iTurning;
if(bBlockSpeed)
{
new Float:fVelocity[3]; pev(id, pev_velocity, fVelocity);
fVelocity[0] *= 0.2; fVelocity[1] *= 0.2;
set_pev(id, pev_velocity, fVelocity);
}
g_fOldAngles[id] = fAngles;
return FMRES_IGNORED;
}
public FM_PlayerPreThink_Pre(id)
{
#emit LOAD.S.pri abcd
#emit SHL.C.pri 5
#emit STOR.S.pri abcd
if(!is_user_alive(id)) return FMRES_IGNORED;
new bBlockSpeed = false;
new bButtons = pev(id, pev_button);
new bOldButton = pev(id, pev_oldbuttons);
for(new i; i < sizeof(g_ePlayerButtons); i++)
{
new CheckButton = g_ePlayerButtons[BUTTON];
new CheckKey = g_ePlayerButtons[KEY];
if(bButtons & CheckButton)
{
g_iKeyFrames[id][CheckKey]++;
}
if(~bButtons & CheckButton && bOldButton & CheckButton)
{
if(g_iKeyFrames[id][CheckKey] == g_iOldKeyFrames[id][CheckKey])
{
if(g_iKeyFrames[id][CheckKey] == 1) g_iKeyWarning[id][CheckKey]++;
if(++g_iKeyWarning[id][CheckKey] >= MAX_KEYWARNING)
{
bBlockSpeed = true;
g_iKeyWarning[id][CheckKey] = 0;
new Float:fTime = get_gametime();
if(fTime >= g_ePlayerLog[id][m_LastKeyLog])
{
g_ePlayerLog[id][m_LastKeyLog] = _:(fTime + MIN_LOG_TIME);
UTIL_LogUser(id, "CheatKeys: [%d] keyframe agreement[%d], key %s", g_ePlayerLog[id][m_CountKeyLog], g_iKeyFrames[id][CheckKey], g_szKeyName[CheckKey]);
g_ePlayerLog[id][m_CountKeyLog] = 0;
}
g_ePlayerLog[id][m_CountKeyLog]++;
}
}
else if(g_iKeyWarning[id][CheckKey])
{
g_iKeyWarning[id][CheckKey]--;
}
//console_print(id, "key frame %s is %d, warn [%d]", g_szKeyName[CheckKey], g_iKeyFrames[id][CheckKey], g_iKeyWarning[id][CheckKey]);
g_iOldKeyFrames[id][CheckKey] = g_iKeyFrames[id][CheckKey];
g_iKeyFrames[id][CheckKey] = 0;
}
}
if(bBlockSpeed)
{
new Float:fVelocity[3]; pev(id, pev_velocity, fVelocity);
fVelocity[0] *= 0.2; fVelocity[1] *= 0.2;
set_pev(id, pev_velocity, fVelocity);
}
return FMRES_IGNORED;
}
StrafeForward(id, Float:angles[3])
{
#emit LOAD.S.pri abcd
#emit SHL.C.pri 5
#emit STOR.S.pri abcd
new Float:fAnglesDiff[3]; vec_diff(fAnglesDiff, angles, g_fOldStrafeAngles[id]);
if(fAnglesDiff[YAW] >= 180) fAnglesDiff[YAW] -= 360.0;
if(fAnglesDiff[YAW] < -180) fAnglesDiff[YAW] += 360.0;
fAnglesDiff[YAW] = floatabs(fAnglesDiff[YAW]);
//console_print(id, "strafe angle diff %f, old angle diff %f, turning [%d]", fAnglesDiff[YAW], g_fOldAnglesDiff[id], turning);
if(fAnglesDiff[YAW] < MAX_ANGLE_CHECK)
{
new Float:fDiff = floatabs(fAnglesDiff[YAW] - g_fOldAnglesDiff[id]);
new iOldWarn = g_ePlayerInfo[id][m_WarningStrafeAngle];
if( fDiff < 0.1 )
{
g_ePlayerInfo[id][m_WarningStrafeAngle] += 5;
}
else if( fDiff < MIN_STRAFE_ANGLE_DIFF )
{
g_ePlayerInfo[id][m_WarningStrafeAngle]++;
}
else if(g_ePlayerInfo[id][m_WarningStrafeAngle])
{
g_ePlayerInfo[id][m_WarningStrafeAngle]--;
}
new Float:fTime = get_gametime();
if(g_ePlayerInfo[id][m_WarningStrafeAngle] > iOldWarn)
{
//console_print(id, " time %f, last time %f, count %d", fTime, g_ePlayerLog[id][m_LastStrafeAngleLog], g_ePlayerLog[id][m_CountStrafeAngleLog]);
if( fTime <= g_ePlayerLog[id][m_LastStrafeAngleLog] + MIN_LOG_TIME)
{
if(++g_ePlayerLog[id][m_CountStrafeAngleLog] >= MIN_STRAFE_ANGLE_WARNINGS_TO_LOG)
{
UTIL_LogUser(id, "CheatStrafes: diff %f, cur angle %f, old angle %f", fDiff, fAnglesDiff[YAW], g_fOldAnglesDiff[id]);
}
}
else
{
g_ePlayerLog[id][m_CountStrafeAngleLog] = 0;
}
g_ePlayerLog[id][m_LastStrafeAngleLog] = _:fTime;
}
if(g_ePlayerInfo[id][m_WarningStrafeAngle] >= MAX_STRAFE_ANGLE_WARNINGS)
{
if(fTime >= g_ePlayerLog[id][m_LastChatLog])
{
g_ePlayerLog[id][m_LastChatLog] = _:(fTime + MIN_LOG_TIME);
PunishPlayer(id, "StrafeMacros");
UTIL_LogUser(id, "CheatStrafes: [%d] using macros", g_ePlayerLog[id][m_CountChatLog]);
g_ePlayerLog[id][m_CountChatLog] = 0;
}
g_ePlayerLog[id][m_CountChatLog]++;
g_ePlayerInfo[id][m_WarningStrafeAngle] = 0;
}
}
g_fOldAnglesDiff[id] = fAnglesDiff[YAW];
g_fOldStrafeAngles[id] = angles;
}
vec_diff(Float:vec[3], Float:new_vec[3], Float:old_vec[3])
{
#emit LOAD.S.pri abcd
#emit SHL.C.pri 5
#emit STOR.S.pri abcd
vec[0] = new_vec[0] - old_vec[0];
vec[1] = new_vec[1] - old_vec[1];
vec[2] = new_vec[2] - old_vec[2];
}
equal_null(Float:vec[3])
{
#emit LOAD.S.pri abcd
#emit SHL.C.pri 5
#emit STOR.S.pri abcd
return (vec[0] == 0.0 && vec[1] == 0.0) ? true : false;
}
stock PunishPlayer(id, reason[])
{
#emit LOAD.S.pri abcd
#emit SHL.C.pri 5
#emit STOR.S.pri abcd
new szName[32]; get_user_name(id, szName, charsmax(szName));
client_print(0, print_chat, "[SHD] %s using %s.", szName, reason);
}
stock UTIL_LogUser(const id, const szCvar[], any:...)
{
#emit LOAD.S.pri abcd
#emit SHL.C.pri 5
#emit STOR.S.pri abcd
static szLogFile[128];
if(!szLogFile[0])
{
get_localinfo("amxx_logs", szLogFile, charsmax(szLogFile));
format(szLogFile, charsmax(szLogFile), "/%s/%s", szLogFile, LOGFILE);
}
new iFile;
if( (iFile = fopen(szLogFile, "a")) )
{
new szName[32], szAuthid[32], szIp[32], szTime[22];
new message[128]; vformat(message, charsmax(message), szCvar, 3);
get_user_name(id, szName, charsmax(szName));
get_user_authid(id, szAuthid, charsmax(szAuthid));
get_user_ip(id, szIp, charsmax(szIp), 1);
get_time("%m/%d/%Y - %H:%M:%S", szTime, charsmax(szTime));
fprintf(iFile, "L %s: <%s><%s><%s> %s^n", szTime, szName, szAuthid, szIp, message);
fclose(iFile);
}
}
Последнее редактирование модератором: