From dc3be8f0d0eaa62700eeeb04a08b18bf2a3e6d1c Mon Sep 17 00:00:00 2001 From: lifegpc Date: Sun, 20 Apr 2025 22:15:25 +0800 Subject: [PATCH] Add support to patch bp --- patch_bp.py | 163 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 patch_bp.py diff --git a/patch_bp.py b/patch_bp.py new file mode 100644 index 0000000..9ad38e2 --- /dev/null +++ b/patch_bp.py @@ -0,0 +1,163 @@ +import struct +import sys +import json + + +class BPScript: + def __init__(self, path: str): + self.path = path + with open(path, 'rb') as f: + self.data = bytearray(f.read()) + self.len = len(self.data) + self.read_header() + self.iPos = self.header_size + + def read_header(self): + self.header_size = struct.unpack('= self.len or ((start_pos > self.last_pos + 1) and self.data[start_pos-1] != 0): + self.iPos -= 2 + return None + pos = start_pos + while True: + if self.data[pos] == 0x00: + break + pos += 1 + data = self.data[start_pos:pos] + try: + data = data.decode('cp932') + except UnicodeDecodeError: + data = data.decode('utf-8') + data = "utf8:" + data + if not data: + return None + return start_pos, self.iPos - 2 + + def extract_values(self): + str_pos = {} + self.iPos = self.header_size + while self.iPos < self.last_pos: + ins = self.data[self.iPos] + self.iPos += 1 + if ins == 0x5: + try: + t = self.extract_string() + if t is not None: + if t[0] not in str_pos: + str_pos[t[0]] = [t[1]] + else: + str_pos[t[0]].append(t[1]) + except UnicodeDecodeError: + self.iPos -= 2 + return str_pos + + def extract_strings(self): + self.iPos = self.last_pos + 1 + while self.data[self.iPos] == 0: + self.iPos += 1 + strings = [] + start_pos = self.iPos + while self.iPos < self.len: + if self.data[self.iPos] == 0: + data = self.data[start_pos:self.iPos] + data_len = len(data) + try: + data = data.decode('cp932') + except UnicodeDecodeError: + data = data.decode('utf-8') + data = "utf8:" + data + if data: + strings.append((start_pos, data_len)) + start_pos = self.iPos + 1 + self.iPos += 1 + return dict(strings) + + def setup_values(self, values: dict): + data = bytearray(self.data) + goffsets = self.extract_values() + offsets = self.extract_strings() + print(offsets) + self.iPos = self.header_size + all_keys = list(int(i) for i in values.keys()) + all_keys.sort() + new_offsets = {} + for key in all_keys: + new_offsets[key] = key + last_len = 0 + last_key = all_keys[-1] + for i in range(len(all_keys)): + key = all_keys[i] + ori_len = offsets[key] + 1 + v = values[f"{key}"] + if v.startswith("utf8:"): + v = v[5:] + v = v.encode("utf-8") + else: + v = v.encode("cp932") + v += b'\0' + new_len = len(v) + last_len = new_len + if new_len == ori_len: + continue + for j in range(i + 1, len(all_keys)): + off = all_keys[j] + new_offsets[off] += new_len - ori_len + print(new_offsets) + old_len = last_key + last_len + new_len = new_offsets[last_key] + last_len + # 对齐到16字节 + new_len = new_len + (16 - new_len % 16) + data = bytearray(data[:all_keys[0]] + b'\0' * (new_len - old_len) + data[all_keys[0] + last_len:]) + self.len = new_len + data[4:8] = struct.pack('= 3: + json_f = sys.argv[2] +output = f"../patched/{base}" +if len(sys.argv) >= 4: + output = sys.argv[3] +scr = BPScript(base) +print(scr.header_size) +print(scr.iPos) +print(scr.last_pos) +with open(json_f, "r", encoding="utf-8") as f: + data = json.load(f) +scr.setup_values(data) +scr.save_as(output)