mirror of
https://github.com/0O0o0oOoO00/Alas.git
synced 2026-05-14 13:29:25 +08:00
572 lines
22 KiB
Python
572 lines
22 KiB
Python
import hashlib
|
|
import json
|
|
import os
|
|
from pathlib import Path
|
|
from typing import Union, List, Type
|
|
|
|
import requests
|
|
from pydantic import BaseModel
|
|
|
|
from module.config.config import AzurLaneConfig
|
|
from module.config.deep import deep_get
|
|
from module.device.device import Device
|
|
from module.luahook.exception import CrackerError
|
|
from module.logger import logger
|
|
|
|
from module.luahook.api import CrackApi
|
|
from module.luahook.op import CrackOp
|
|
|
|
ALL_ENABLE_OPS = [
|
|
CrackOp.EnableHookedLuaFunctionTrace,
|
|
CrackOp.EnableGlobalShipProperties,
|
|
CrackOp.EnableChapterFastMove,
|
|
CrackOp.EnableRemoveHardModeLimit,
|
|
CrackOp.EnableFakePlayer,
|
|
CrackOp.EnableNoBBAnimation,
|
|
CrackOp.EnableNoEmotionWarning,
|
|
CrackOp.EnableOpsiFastMove,
|
|
CrackOp.EnableRemoveHardModeShipTypeLimit,
|
|
CrackOp.EnableRemoveHardModeShipPropertiesLimit,
|
|
CrackOp.EnableGGFactor,
|
|
CrackOp.EnableGlobalSpeedup,
|
|
CrackOp.EnableBetterGlobalSpeedup,
|
|
CrackOp.EnableExerciseGodMod,
|
|
CrackOp.EnableExerciseMorePower,
|
|
CrackOp.EnableFastWave,
|
|
CrackOp.EnableMonsterKillSelf,
|
|
CrackOp.EnableSkipBattleCelebrate,
|
|
CrackOp.EnableNoDamage,
|
|
CrackOp.EnableOpsiForceAuto,
|
|
CrackOp.EnableOpsiNoMapFog,
|
|
CrackOp.EnableSkipShipGainShow,
|
|
CrackOp.EnableChapterForceEnableAutoFight,
|
|
CrackOp.EnableChapterSkipPrecombat,
|
|
]
|
|
|
|
REMOTE_PORT = 23897
|
|
|
|
|
|
class Cracker(CrackApi):
|
|
def __init__(self, config: AzurLaneConfig, device: Device):
|
|
self.config = config
|
|
self.device = device
|
|
super().__init__(f"http://127.0.0.1:{device.adb.forward_port(REMOTE_PORT)}")
|
|
|
|
|
|
def do_crack_op_on_func(
|
|
before_call: Union[Type[CrackOp.Op], List[Type[CrackOp.Op]]] = None,
|
|
after_call: Union[Type[CrackOp.Op], List[Type[CrackOp.Op]]] = None
|
|
):
|
|
def wrapper(func):
|
|
def inner(*args, **kwargs):
|
|
obj = args[0]
|
|
if before_call is not None:
|
|
do_crack_op(obj.config, obj.device, before_call)
|
|
try:
|
|
ret = func(*args, **kwargs)
|
|
except Exception as e:
|
|
if after_call is not None:
|
|
do_crack_op(obj.config, obj.device, after_call)
|
|
raise e
|
|
if after_call is not None:
|
|
do_crack_op(obj.config, obj.device, after_call)
|
|
return ret
|
|
|
|
return inner
|
|
|
|
return wrapper
|
|
|
|
|
|
def do_crack_op(config: AzurLaneConfig, device: Device, ops: Union[Type[CrackOp.Op], List[Type[CrackOp.Op]]]):
|
|
if not config.full_config.Hook_HookGeneral_Enable:
|
|
return
|
|
if not device.app_is_running():
|
|
logger.info("Game not running, do not crack")
|
|
return
|
|
if isinstance(ops, list):
|
|
l = ops
|
|
else:
|
|
if ops == CrackOp.EnableAll:
|
|
l = ALL_ENABLE_OPS
|
|
else:
|
|
l = [ops]
|
|
|
|
full_config = config.full_config
|
|
|
|
base_url = f"http://127.0.0.1:{device.adb.forward_port(REMOTE_PORT)}"
|
|
timeout = full_config.Hook_HookGeneral_RequestTimeLimit
|
|
api = CrackApi(base_url, timeout=timeout)
|
|
for op in l:
|
|
if op == CrackOp.DisableAll:
|
|
api.disable_all()
|
|
elif op == CrackOp.EnableHookedLuaFunctionTrace:
|
|
if full_config.Hook_HookGeneral_HookedLuaFunctionTrace:
|
|
api.enable_hooked_lua_function_trace()
|
|
elif op == CrackOp.DisableHookedLuaFunctionTrace:
|
|
api.disable_hooked_lua_function_trace()
|
|
elif op == CrackOp.EnableGlobalShipProperties:
|
|
if config.full_config.Hook_ShipProperty_Method != "final_properties":
|
|
continue
|
|
api.update_global_ship_properties(
|
|
CrackApi.ShipProperties(
|
|
armor=float(full_config.Hook_ShipProperty_Armor),
|
|
speed=float(full_config.Hook_ShipProperty_Speed),
|
|
antiaircraft=float(full_config.Hook_ShipProperty_AntiAircraft),
|
|
oxy_recovery_bench=float(full_config.Hook_ShipProperty_OxyRecoveryBench),
|
|
torpedo=float(full_config.Hook_ShipProperty_Torpedo),
|
|
hit=float(full_config.Hook_ShipProperty_Hit),
|
|
sonarRange=float(full_config.Hook_ShipProperty_SonarRange),
|
|
attack_duration=float(full_config.Hook_ShipProperty_AttackDuration),
|
|
raid_distance=float(full_config.Hook_ShipProperty_RaidDistance),
|
|
oxy_recovery_surface=float(full_config.Hook_ShipProperty_OxyRecoverySurface),
|
|
oxy_recovery=float(full_config.Hook_ShipProperty_OxyRecovery),
|
|
dodge=float(full_config.Hook_ShipProperty_Dodge),
|
|
luck=float(full_config.Hook_ShipProperty_Luck),
|
|
reload=float(full_config.Hook_ShipProperty_Reload),
|
|
oxy_cost=float(full_config.Hook_ShipProperty_OxyCost),
|
|
durability=float(full_config.Hook_ShipProperty_Durability),
|
|
air=float(full_config.Hook_ShipProperty_Air),
|
|
oxy_max=float(full_config.Hook_ShipProperty_OxyMax),
|
|
cannon=float(full_config.Hook_ShipProperty_Cannon),
|
|
antisub=float(full_config.Hook_ShipProperty_AntiSub),
|
|
)
|
|
)
|
|
api.enable_global_ship_properties_crack()
|
|
elif op == CrackOp.DisableGlobalShipProperties:
|
|
api.disable_global_ship_properties_crack()
|
|
elif op == CrackOp.EnableChapterFastMove:
|
|
if not full_config.Hook_Misc_ChapterMove:
|
|
continue
|
|
api.enable_fast_stage_move()
|
|
elif op == CrackOp.DisableChapterFastMove:
|
|
api.disable_fast_stage_move()
|
|
elif op == CrackOp.EnableRemoveHardModeShipPropertiesLimit:
|
|
if full_config.Hook_Misc_RemoveHardMapLimit != "remove_ship_properties_limit":
|
|
continue
|
|
api.enable_remove_hard_mode_ship_properties_limit()
|
|
elif op == CrackOp.DisableRemoveHardModeShipPropertiesLimit:
|
|
api.disable_remove_hard_mode_ship_properties_limit()
|
|
elif op == CrackOp.EnableRemoveHardModeShipTypeLimit:
|
|
if full_config.Hook_Misc_RemoveHardMapLimit != "remove_ship_type_limit":
|
|
continue
|
|
api.enable_remove_hard_mode_ship_type_limit()
|
|
elif op == CrackOp.DisableRemoveHardModeShipTypeLimit:
|
|
api.disable_remove_hard_mode_ship_type_limit()
|
|
elif op == CrackOp.EnableRemoveHardModeLimit:
|
|
if full_config.Hook_Misc_RemoveHardMapLimit != "remove_both":
|
|
continue
|
|
api.enable_remove_hard_mode_limit()
|
|
elif op == CrackOp.DisableRemoveHardModeLimit:
|
|
api.disable_remove_hard_mode_limit()
|
|
elif op == CrackOp.EnableFakePlayer:
|
|
if not full_config.Hook_FakePlayer_Enable:
|
|
continue
|
|
api.update_fake_player_info(
|
|
CrackApi.FakePlayerInfo(
|
|
name=str(full_config.Hook_FakePlayer_Name),
|
|
level=str(full_config.Hook_FakePlayer_Level),
|
|
id=str(full_config.Hook_FakePlayer_Id),
|
|
)
|
|
)
|
|
api.enable_fake_player()
|
|
elif op == CrackOp.DisableFakePlayer:
|
|
api.disable_fake_player()
|
|
elif op == CrackOp.EnableNoBBAnimation:
|
|
if not full_config.Hook_Misc_NoBBAnimation:
|
|
continue
|
|
api.enable_no_bb_animation()
|
|
elif op == CrackOp.DisableNoBBAnimation:
|
|
api.disable_no_bb_animation()
|
|
elif op == CrackOp.EnableNoEmotionWarning:
|
|
if not full_config.Hook_Misc_NoEmotionWarning:
|
|
continue
|
|
api.enable_no_emotion_warning()
|
|
elif op == CrackOp.DisableNoEmotionWarning:
|
|
api.disable_no_emotion_warning()
|
|
elif op == CrackOp.IsAlive:
|
|
api.is_alive()
|
|
elif op == CrackOp.EnableOpsiFastMove:
|
|
api.enable_opsi_fast_move()
|
|
elif op == CrackOp.DisableOpsiFastMove:
|
|
api.disable_opsi_fast_move()
|
|
elif op == CrackOp.EnableGGFactor:
|
|
if full_config.Hook_ShipProperty_Method != "gg_factor":
|
|
continue
|
|
api.update_gg_factor(float(full_config.Hook_ShipProperty_Factor))
|
|
api.enable_gg_factor()
|
|
elif op == CrackOp.DisableGGFactor:
|
|
api.disable_gg_factor()
|
|
elif op == CrackOp.EnableGlobalSpeedup:
|
|
rate = float(full_config.Hook_Misc_GlobalSpeedup)
|
|
if rate == 1.0:
|
|
continue
|
|
api.update_global_speedup_rate(CrackApi.GlobalSpeedupRate(rate=rate))
|
|
api.enable_global_speedup()
|
|
elif op == CrackOp.DisableGlobalSpeedup:
|
|
api.disable_global_speedup()
|
|
elif op == CrackOp.EnableBetterGlobalSpeedup:
|
|
rate = float(full_config.Hook_Misc_BetterGlobalSpeedup)
|
|
if rate == 1.0:
|
|
continue
|
|
api.update_better_global_speedup_rate(CrackApi.BetterGlobalSpeedupRate(rate=rate))
|
|
api.enable_better_global_speedup()
|
|
elif op == CrackOp.DisableBetterGlobalSpeedup:
|
|
api.disable_better_global_speedup()
|
|
elif op == CrackOp.EnableExerciseGodMod:
|
|
if full_config.Hook_Misc_ExerciseGodMod:
|
|
api.enable_exercise_god_mode()
|
|
elif op == CrackOp.DisableExerciseGodMod:
|
|
api.disable_exercise_god_mode()
|
|
elif op == CrackOp.EnableExerciseMorePower:
|
|
rate = float(full_config.Hook_Misc_ExerciseMorePower)
|
|
if rate == -1.0:
|
|
continue
|
|
api.update_exercise_more_power_rate(CrackApi.ExerciseMorePowerRate(rate=rate))
|
|
api.enable_exercise_more_power()
|
|
elif op == CrackOp.DisableExerciseMorePower:
|
|
api.disable_exercise_more_power()
|
|
elif op == CrackOp.EnableFastWave:
|
|
if full_config.Hook_Misc_FastWave:
|
|
api.enable_fast_wave()
|
|
elif op == CrackOp.DisableFastWave:
|
|
api.disable_fast_wave()
|
|
elif op == CrackOp.EnableMonsterKillSelf:
|
|
if full_config.Hook_Misc_MonsterKillSelf:
|
|
api.enable_monster_kill_self()
|
|
elif op == CrackOp.DisableMonsterKillSelf:
|
|
api.disable_monster_kill_self()
|
|
elif op == CrackOp.EnableSkipBattleCelebrate:
|
|
if full_config.Hook_Misc_SkipBattleCelebrate:
|
|
api.enable_skip_battle_celebrate()
|
|
elif op == CrackOp.DisableSkipBattleCelebrate:
|
|
api.disable_skip_battle_celebrate()
|
|
elif op == CrackOp.EnableNoDamage:
|
|
if full_config.Hook_Misc_NoDamage:
|
|
api.enable_no_damage()
|
|
elif op == CrackOp.DisableNoDamage:
|
|
api.disable_no_damage()
|
|
elif op == CrackOp.EnableOpsiForceAuto:
|
|
if full_config.Hook_Misc_OpsiForceAuto:
|
|
api.enable_opsi_force_auto()
|
|
elif op == CrackOp.DisableOpsiForceAuto:
|
|
api.disable_opsi_force_auto()
|
|
elif op == CrackOp.EnableOpsiNoMapFog:
|
|
if full_config.Hook_Misc_OpsiNoMapFog:
|
|
api.enable_opsi_no_map_fog()
|
|
elif op == CrackOp.DisableOpsiNoMapFog:
|
|
api.disable_opsi_no_map_fog()
|
|
elif op == CrackOp.EnableSkipShipGainShow:
|
|
if full_config.Hook_Misc_SkipShipGainShow:
|
|
api.enable_skip_ship_gain_show()
|
|
elif op == CrackOp.DisableSkipShipGainShow:
|
|
api.disable_skip_ship_gain_show()
|
|
elif op == CrackOp.EnableChapterForceEnableAutoFight:
|
|
if full_config.Hook_Misc_ChapterForceEnableAutoFight:
|
|
api.enable_chapter_force_enable_auto_fight()
|
|
elif op == CrackOp.DisableChapterForceEnableAutoFight:
|
|
api.disable_chapter_force_enable_auto_fight()
|
|
elif op == CrackOp.EnableChapterSkipPrecombat:
|
|
if full_config.Hook_Misc_ChapterForceEnableAutoFight:
|
|
api.enable_chapter_skip_precombat()
|
|
elif op == CrackOp.DisableChapterSkipPrecombat:
|
|
api.disable_chapter_skip_precombat()
|
|
else:
|
|
logger.error(f"Unsupported op: {op}")
|
|
|
|
|
|
crack_op = do_crack_op_on_func
|
|
|
|
|
|
def disable_all_crack(f):
|
|
def wrapper(*args, **kwargs):
|
|
obj = args[0]
|
|
logger.info("Disabe all luahook cracks")
|
|
do_crack_op(obj.config, obj.device, CrackOp.DisableAll)
|
|
return f(*args, **kwargs)
|
|
|
|
return wrapper
|
|
|
|
|
|
def enable_all_crack(f):
|
|
def wrapper(*args, **kwargs):
|
|
obj = args[0]
|
|
do_crack_op(obj.config, obj.device, CrackOp.EnableAll)
|
|
return f(*args, **kwargs)
|
|
|
|
return wrapper
|
|
|
|
|
|
def luahook_crack_all(config: AzurLaneConfig, device: Device):
|
|
logger.info("Crack all with luahook")
|
|
do_crack_op(config, device, CrackOp.EnableAll)
|
|
|
|
|
|
def luahook_disable_all(config: AzurLaneConfig, device: Device):
|
|
logger.info("Disable all luahook")
|
|
do_crack_op(config, device, CrackOp.DisableAll)
|
|
|
|
|
|
CHAPTER_CRACK_OPS = [
|
|
CrackOp.EnableHookedLuaFunctionTrace,
|
|
CrackOp.EnableChapterFastMove,
|
|
CrackOp.EnableNoBBAnimation,
|
|
CrackOp.EnableNoEmotionWarning,
|
|
CrackOp.EnableGlobalShipProperties,
|
|
CrackOp.EnableRemoveHardModeLimit,
|
|
CrackOp.EnableFakePlayer,
|
|
CrackOp.EnableGGFactor,
|
|
CrackOp.EnableGlobalSpeedup,
|
|
CrackOp.EnableBetterGlobalSpeedup,
|
|
CrackOp.EnableFastWave,
|
|
CrackOp.EnableMonsterKillSelf,
|
|
CrackOp.EnableSkipBattleCelebrate,
|
|
CrackOp.EnableNoDamage,
|
|
CrackOp.EnableSkipShipGainShow,
|
|
CrackOp.EnableChapterForceEnableAutoFight,
|
|
CrackOp.EnableChapterSkipPrecombat,
|
|
]
|
|
|
|
|
|
def chapter_task_crack(f):
|
|
def wrapper(*args, **kwargs):
|
|
obj = args[0]
|
|
do_crack_op(obj.config, obj.device, CHAPTER_CRACK_OPS)
|
|
return f(*args, **kwargs)
|
|
|
|
return wrapper
|
|
|
|
|
|
OPSI_CRACK_OPS = [
|
|
CrackOp.EnableHookedLuaFunctionTrace,
|
|
CrackOp.EnableNoBBAnimation,
|
|
CrackOp.EnableOpsiFastMove,
|
|
CrackOp.EnableGlobalShipProperties,
|
|
CrackOp.EnableFakePlayer,
|
|
CrackOp.EnableGGFactor,
|
|
CrackOp.EnableGlobalSpeedup,
|
|
CrackOp.EnableBetterGlobalSpeedup,
|
|
CrackOp.EnableFastWave,
|
|
CrackOp.EnableMonsterKillSelf,
|
|
CrackOp.EnableSkipBattleCelebrate,
|
|
CrackOp.EnableNoDamage,
|
|
CrackOp.EnableOpsiForceAuto,
|
|
CrackOp.EnableOpsiNoMapFog,
|
|
CrackOp.EnableSkipShipGainShow,
|
|
]
|
|
|
|
|
|
def opsi_task_crack(f):
|
|
def wrapper(*args, **kwargs):
|
|
obj = args[0]
|
|
do_crack_op(obj.config, obj.device, OPSI_CRACK_OPS)
|
|
return f(*args, **kwargs)
|
|
|
|
return wrapper
|
|
|
|
|
|
class UpdateServerApi:
|
|
class ResourceFile(BaseModel):
|
|
arch: str
|
|
file: str
|
|
|
|
def __init__(self, api_url: str = ""):
|
|
self.api_url = api_url
|
|
|
|
def post(self, path: str, data=None):
|
|
logger.info(f"UpdateServerApi post: {path}")
|
|
url = f'{self.api_url}/{path}'
|
|
try:
|
|
response = requests.post(url, data=data) # TODO: add timeout
|
|
except requests.exceptions.Timeout:
|
|
raise CrackerError('UpdateServerApi request timeout')
|
|
except Exception as e:
|
|
raise CrackerError(f'UpdateServerApi request error: {e}')
|
|
if response.status_code != 200:
|
|
raise CrackerError(f'UpdateServerApi response error: {response.status_code}')
|
|
return response
|
|
|
|
def download_file(self, arch: str, file_name: str) -> bytes:
|
|
res = self.post("files", UpdateServerApi.ResourceFile(arch=arch, file=file_name).json())
|
|
return res.content
|
|
|
|
def get_hash(self, arch: str, file_name: str) -> str:
|
|
res = self.post("get_hash", UpdateServerApi.ResourceFile(arch=arch, file=file_name).json())
|
|
return res.text
|
|
|
|
|
|
class CrackResource:
|
|
ARCH_MAP = {
|
|
"x86": "x86",
|
|
"x86_64": "x86",
|
|
"armv7": "armeabi-v7a",
|
|
"arm64": "arm64-v8a",
|
|
"aarch64": "arm64-v8a",
|
|
"aarch": "armeabi-v7a",
|
|
}
|
|
|
|
def __init__(self, config: AzurLaneConfig, device: Device):
|
|
self.config = config
|
|
self.device = device
|
|
|
|
arch_conf = config.full_config.Hook_HookGeneral_Architecture
|
|
|
|
if arch_conf == "auto":
|
|
arch_ret = device.adb_shell("uname -m").lower()
|
|
self.arch = self.ARCH_MAP.get(arch_ret, "")
|
|
if not self.arch:
|
|
raise CrackerError(f"Unsupported arch: {arch_ret}")
|
|
logger.info(f"Arch: {arch_ret} -> {self.arch}")
|
|
else:
|
|
self.arch = arch_conf
|
|
logger.info(f"Use arch: {self.arch}")
|
|
|
|
self.resource_root = f"./bin/hook"
|
|
self.resource_dir = f"{self.resource_root}/{self.arch}"
|
|
self.version_file = f"{self.resource_dir}/version.json"
|
|
|
|
self.first_init = False
|
|
self.has_new_version = False
|
|
|
|
self.update_server = self.__get_update_server()
|
|
|
|
self.upload_dir = f"/data/hook/{self.arch}"
|
|
|
|
self.game_lib_dir = Path(self.__format_str(config.full_config.Hook_HookGeneral_GameLibDir)).as_posix()
|
|
|
|
def __file_hash(self, file_name):
|
|
with open(file_name, "rb") as f:
|
|
return hashlib.md5(f.read()).hexdigest()
|
|
|
|
def __gen_version_file_from_local(self):
|
|
d = {}
|
|
for file_name in os.listdir(self.resource_dir):
|
|
f = f"{self.resource_dir}/{file_name}"
|
|
if not os.path.isfile(f):
|
|
continue
|
|
if file_name.endswith(".json"):
|
|
continue
|
|
|
|
hash_value = self.__file_hash(f).upper()
|
|
d[file_name] = hash_value
|
|
with open(self.version_file, "w") as f:
|
|
json.dump(d, f, indent=4)
|
|
|
|
def __ensure_local_resource(self):
|
|
if self.update_server is None:
|
|
logger.info("No update server, skip ensure local resource")
|
|
return
|
|
|
|
if not os.path.exists(f"{self.resource_dir}/libcracker.so"):
|
|
self.__download_resource("libcracker.so")
|
|
self.first_init = True
|
|
|
|
if not os.path.exists(f"{self.resource_dir}/patchelf"):
|
|
self.__download_resource("patchelf")
|
|
self.first_init = True
|
|
|
|
__update_local_version = __gen_version_file_from_local
|
|
|
|
def __ensure_crack_resource(self, ):
|
|
if not os.path.exists(self.resource_root):
|
|
os.makedirs(self.resource_root)
|
|
if not os.path.exists(self.resource_dir):
|
|
os.makedirs(self.resource_dir)
|
|
self.__ensure_local_resource()
|
|
if not os.path.exists(self.version_file):
|
|
self.__gen_version_file_from_local()
|
|
|
|
def __download_resource(self, file_name: str):
|
|
if self.update_server is None:
|
|
logger.info("No update server, skip download resource")
|
|
return
|
|
logger.info(f"Download resource: {self.arch}/{file_name}")
|
|
res = self.update_server.download_file(self.arch, file_name)
|
|
with open(f"{self.resource_dir}/{file_name}", "wb") as f:
|
|
f.write(res)
|
|
|
|
def __is_same_version(self, version_json: dict, file_name: str):
|
|
h = self.update_server.get_hash(self.arch, file_name)
|
|
return h == version_json.get(file_name, "")
|
|
|
|
def __check_update(self):
|
|
if self.update_server is None:
|
|
logger.info("No update server, skip update check, use local resource")
|
|
return
|
|
if not self.config.full_config.Hook_HookGeneral_UpdateEveryTime:
|
|
logger.info("Update skip, use local resource")
|
|
return
|
|
with open(self.version_file, "r") as f:
|
|
local_version = json.load(f)
|
|
|
|
if not self.__is_same_version(local_version, "libcracker.so"):
|
|
self.__download_resource("libcracker.so")
|
|
self.has_new_version = True
|
|
if not self.__is_same_version(local_version, "patchelf"):
|
|
self.__download_resource("patchelf")
|
|
self.has_new_version = True
|
|
|
|
if self.has_new_version:
|
|
self.__update_local_version()
|
|
|
|
def __format_str(self, s: str) -> str:
|
|
return ("".join([i for i in s if i.isprintable()])).replace(" ", "").replace("\n", "")
|
|
|
|
def __get_update_server(self) -> Union[UpdateServerApi, None]:
|
|
update_server_url: str = self.config.full_config.Hook_HookGeneral_UpdateServer
|
|
update_server_url = self.__format_str(update_server_url)
|
|
if not update_server_url:
|
|
return None
|
|
return UpdateServerApi(update_server_url)
|
|
|
|
def __push(self, file_name: str):
|
|
self.device.adb_shell(f"mkdir -p {self.upload_dir}")
|
|
self.device.adb_shell(f"rm {self.upload_dir}/{file_name}")
|
|
self.device.adb_push(f"{self.resource_dir}/{file_name}", f"{self.upload_dir}/{file_name}")
|
|
self.device.adb_shell(f"chmod 777 {self.upload_dir}/{file_name}")
|
|
|
|
def __push_resource(self):
|
|
logger.info("Push resource to device")
|
|
self.__push("libcracker.so")
|
|
self.__push("patchelf")
|
|
|
|
def __do_inject(self):
|
|
if not self.game_lib_dir:
|
|
raise CrackerError("GameLibDir not set")
|
|
|
|
logger.info(f"GameLibDir: {self.game_lib_dir}, do inject")
|
|
cmd = f"cd {self.upload_dir} && ./patchelf --local-patch --game-lib-dir '{self.game_lib_dir}'"
|
|
self.device.adb_shell(cmd)
|
|
|
|
def __is_exist(self, path):
|
|
cmd = f"if [ -f {path} ]; then echo 'exist'; else if [ -d {path} ]; then echo 'exist'; else echo 'not exist'; fi; fi"
|
|
return self.device.adb_shell(cmd) == "exist"
|
|
|
|
def __is_remote_file_exist(self) -> bool:
|
|
return self.__is_exist(self.upload_dir) and self.__is_exist(f"{self.upload_dir}/libcracker.so") and self.__is_exist(f"{self.upload_dir}/patchelf")
|
|
|
|
def __adb_su_do(self, cmd: str):
|
|
return self.device.adb_shell(f"su -c '{cmd}'")
|
|
|
|
def __adb_root(self):
|
|
self.device.adb_command(["root"])
|
|
|
|
def __check_game_lib_dir(self):
|
|
return self.__is_exist(f"{self.game_lib_dir}/libil2cpp.so") and self.__is_exist(f"{self.game_lib_dir}/libtolua.so")
|
|
|
|
def ensure(self):
|
|
if not self.config.full_config.Hook_HookGeneral_Enable:
|
|
return
|
|
|
|
if not self.__check_game_lib_dir():
|
|
raise CrackerError(f"GameLibDir '{self.game_lib_dir}' is invalid")
|
|
|
|
self.__adb_root()
|
|
self.__ensure_crack_resource()
|
|
if not self.first_init:
|
|
self.__check_update()
|
|
if self.has_new_version or not self.__is_remote_file_exist() or self.config.full_config.Hook_HookGeneral_PushEveryTime:
|
|
self.__push_resource()
|
|
self.device.app_stop()
|
|
self.config.task_call("Restart")
|
|
self.__do_inject()
|