import frida
import pymem
import time
import math
from typing import List, Tuple
PLAYER_BASE_PTR = 0x01A4E104
PLAYER_BASE_OFF = 0x14
PLAYER_X_OFF = 0x69C
PLAYER_Y_OFF = 0x6A0
MOB_BASE_PTR = 0x1A4E378
MOB_VID_OFF = 0x79C
MOB_X_OFF = 0x69C
MOB_Y_OFF = 0x6A0
ATTACK_RANGE = 1000
ATTACK_DELAY = 0.1 #Milisaniye
class WaitDamage:
def __init__(self):
self.pm = pymem.Pymem("metin2client.bin")
self.base_address = pymem.process.module_from_name(self.pm.process_handle, "metin2client.bin").lpBaseOfDll
print(f"[+] Base address: {hex(self.base_address)}")
self.session = frida.attach("metin2client.bin")
self.script = None
self.running = True
def read_player_position(self) -> Tuple[float, float]:
try:
player_base = self.pm.read_int(self.base_address + PLAYER_BASE_PTR)
if player_base == 0:
return 0, 0
player_ptr = self.pm.read_int(player_base + PLAYER_BASE_OFF)
if player_ptr == 0:
return 0, 0
player_x = self.pm.read_float(player_ptr + PLAYER_X_OFF)
player_y = self.pm.read_float(player_ptr + PLAYER_Y_OFF)
return player_x, player_y
except Exception as e:
print(f"Player konum alınamıyor: {e}")
return 0, 0
def get_mob_list(self) -> List[Tuple[int, float, float]]:
mobs = []
try:
mob_base = self.pm.read_int(self.base_address + MOB_BASE_PTR)
if mob_base == 0:
return mobs
offset = 0
for i in range(300):
try:
mob_ptr = self.pm.read_int(mob_base + offset)
if mob_ptr == 0:
break
mob_vid = self.pm.read_int(mob_ptr + MOB_VID_OFF)
if mob_vid <= 0:
offset += 4
continue
mob_x = self.pm.read_float(mob_ptr + MOB_X_OFF)
mob_y = self.pm.read_float(mob_ptr + MOB_Y_OFF)
mobs.append((mob_vid, mob_x, mob_y))
except Exception:
offset += 4
continue
offset += 4
except Exception as e:
print(f"Moblar alınamıyor: {e}")
return mobs
def is_in_range(self, x1: float, y1: float, x2: float, y2: float) -> bool:
distance = math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
return distance <= ATTACK_RANGE
def setup_frida_script(self):
script_code = """
const BATTLE_CALL_ADDRESS = ptr(0x004BD660); //Send battle attack MOV
const NET_POINTER_ADDRESS = ptr(0x01E4E114); //Send battle attack CALL
function sendBattleAttack(targetId) {
if (targetId <= 0) return false;
try {
var codeSize = 64;
var codePtr = Memory.alloc(codeSize);
var netPointer = Memory.readPointer(NET_POINTER_ADDRESS);
if (netPointer.isNull()) return false;
Memory.patchCode(codePtr, codeSize, function(code) {
var writer = new X86Writer(code);
writer.putMovRegAddress('ecx', netPointer);
writer.putPushU32(targetId);
writer.putPushU32(0);
writer.putCallAddress(BATTLE_CALL_ADDRESS);
writer.putRet();
writer.flush();
});
var execFunc = new NativeFunction(codePtr, 'void', []);
execFunc();
return true;
} catch (e) {
return false;
}
}
rpc.exports = {
attack: function(targetId) {
return sendBattleAttack(targetId);
}
};
"""
self.script = self.session.create_script(script_code)
self.script.load()
def run(self):
self.setup_frida_script()
print("[+] Wait damage başladı")
try:
while self.running:
player_x, player_y = self.read_player_position()
if player_x == 0 and player_y == 0:
print("[!] Player konumu alınamıyor")
time.sleep(1)
continue
mobs = self.get_mob_list()
if not mobs:
time.sleep(0.1)
continue
in_range_mobs = [
mob for mob in mobs
if self.is_in_range(player_x, player_y, mob[1], mob[2])
]
for mob_vid, _, _ in in_range_mobs:
try:
self.script.exports.attack(mob_vid)
except Exception as e:
print(f"Hata: {mob_vid}: {e}")
time.sleep(ATTACK_DELAY)
except KeyboardInterrupt:
print("\n[*] Program durduruluyor")
finally:
self.cleanup()
def cleanup(self):
if self.script:
self.script.unload()
if self.session:
self.session.detach()
print("[+] Bağlantı koparıldı")
if __name__ == "__main__":
attacker = WaitDamage()
attacker.run()