import os import zipfile import requests import UnityPy import re import shutil def cetak_header(judul): print("\n" + "="*80) print(f" šŸ” OTOPSI FORENSIK: {judul} ".center(80, "=")) print("="*80) def download_dan_ekstrak(url, folder_tujuan): nama_file = url.split('/')[-1] path_zip = os.path.join(folder_tujuan, nama_file) if not os.path.exists(folder_tujuan): os.makedirs(folder_tujuan) print(f"[*] Mendownload {nama_file} dari {url}...") try: response = requests.get(url, stream=True) response.raise_for_status() with open(path_zip, 'wb') as f: for chunk in response.iter_content(chunk_size=8192): f.write(chunk) except Exception as e: print(f"[!] Gagal mendownload {url}: {e}") return None folder_ekstrak = os.path.join(folder_tujuan, nama_file + "_ext") if os.path.exists(folder_ekstrak): shutil.rmtree(folder_ekstrak) os.makedirs(folder_ekstrak) print(f"[*] Mengekstrak {nama_file}...") try: with zipfile.ZipFile(path_zip, 'r') as zip_ref: zip_ref.extractall(folder_ekstrak) except Exception as e: print(f"[!] Gagal mengekstrak {path_zip}: {e}") return None return folder_ekstrak def cari_file(folder_dasar, ekstensi): hasil = [] for root, dirs, files in os.walk(folder_dasar): for file in files: if file.endswith(ekstensi): hasil.append(os.path.join(root, file)) return hasil def analisis_meta_dan_prefab(folder_ekstrak): print("\n--- [ ANALISIS KTP & BLUEPRINT (.meta & .prefab) ] ---") file_meta = cari_file(folder_ekstrak, ".prefab.meta") file_prefab = cari_file(folder_ekstrak, ".prefab") guid_meta = "TIDAK DITEMUKAN" nama_meta = "TIDAK DITEMUKAN" if file_meta: nama_meta = os.path.basename(file_meta[0]) with open(file_meta[0], 'r', encoding='utf-8') as f: konten = f.read() cocok = re.search(r'guid:\s*([a-f0-9]+)', konten) if cocok: guid_meta = cocok.group(1) print(f"šŸ“„ File Meta Ditemukan : {nama_meta}") print(f"šŸ”‘ GUID Meta (Luar) : {guid_meta}") else: print("āŒ File .meta tidak ditemukan!") if file_prefab: nama_prefab = os.path.basename(file_prefab[0]) print(f"\nšŸ“„ File Prefab Ditemukan: {nama_prefab}") with open(file_prefab[0], 'r', encoding='utf-8') as f: konten = f.read() # Mencari semua baris yang mengandung GUID meta di dalam prefab jumlah_guid = konten.count(guid_meta) if guid_meta != "TIDAK DITEMUKAN" else 0 print(f"šŸ”— Kecocokan GUID Luar di dalam Blueprint: Ditemukan {jumlah_guid} kali") # Mencari KTP CAB (jika ada) di dalam m_RenderDataKey cocok_render = re.search(r'm_RenderDataKey:\s*([a-f0-9]+)', konten) if cocok_render: print(f"šŸŽ­ Internal m_RenderDataKey (KTP Dalam): {cocok_render.group(1)}") # Mencari Root Bone cocok_bone = re.search(r'm_Name:\s*(jBone|foot_R|hips|head)', konten, re.IGNORECASE) if cocok_bone: print(f"🦓 Deteksi Root Bone Blueprint: {cocok_bone.group(1)}") else: print("āŒ File .prefab tidak ditemukan!") def analisis_assetbundles(folder_ekstrak): print("\n--- [ ANALISIS BINER ASSETBUNDLES (Deep Scan) ] ---") folder_ab = None for root, dirs, files in os.walk(folder_ekstrak): if 'assetbundles' in [d.lower() for d in dirs]: idx = [d.lower() for d in dirs].index('assetbundles') folder_ab = os.path.join(root, dirs[idx]) break if not folder_ab: print("āŒ Folder assetbundles tidak ditemukan! (Koper kosong)") return file_biner = [os.path.join(folder_ab, f) for f in os.listdir(folder_ab) if os.path.isfile(os.path.join(folder_ab, f))] print(f"šŸ“¦ Ditemukan {len(file_biner)} file biner platform.") for biner in file_biner: platform_name = os.path.basename(biner) print(f"\n šŸ”¬ Membedah Platform: {platform_name}") ukuran = os.path.getsize(biner) print(f" Ukuran Fisik: {ukuran} bytes") try: # Menggunakan UnityPy untuk membongkar jeroan env = UnityPy.load(biner) # 1. Identifikasi CAB cab_asli = list(env.cabs.keys())[0] if env.cabs else "TIDAK ADA CAB" print(f" šŸ·ļø ID CAB Terdaftar: {cab_asli}") # 2. Hitung Objek (Mendeteksi Gambar Melebur/Hilang) jumlah_mesh = 0 jumlah_texture = 0 jumlah_material = 0 for obj in env.objects: if obj.type.name == "Mesh": jumlah_mesh += 1 elif obj.type.name in ["Texture2D", "Sprite"]: jumlah_texture += 1 elif obj.type.name == "Material": jumlah_material += 1 print(f" 🧩 Integritas 3D: {jumlah_mesh} Mesh | {jumlah_texture} Texture | {jumlah_material} Material") if jumlah_mesh == 0 or jumlah_texture == 0: print(" āš ļø [WARNING] Mesh atau Texture HILANG! Gambar dipastikan hancur/melebur!") else: print(" āœ… [AMAN] Objek 3D lengkap. Gambar tidak korup.") # 3. Analisis Raw Bytes (Mendeteksi Patching Paksa) with open(biner, 'rb') as f: raw_data = f.read() # Mencari signature kompresi if raw_data.startswith(b'UnityFS'): print(" šŸ“¦ Jenis Kompresi: UnityFS (Bawaan Unity Sehat)") else: print(" āš ļø Jenis Kompresi: TIDAK DIKENAL (Mungkin Korup)") except Exception as e: print(f" āŒ [CRASH] UnityPy gagal membaca file! Kompresi LZ4 hancur total: {e}") def main(): target_analisis = { "1_BAHAN_MENTAH": "https://repo.pasdigi.com/DG_1.zepeto", "2_ICU_LOLOS_SEMPURNA": "https://repo.paspulsa.com/lolosfix.zip", "3_SURGERY_LOLOS_TAPI_HANCUR": "https://repo.paspulsa.com/res.zepeto", "4_GAGAL_WRONG_REQUEST": "https://repo.paspulsa.com/gagal.zepeto" } folder_kerja = "ruang_otopsi" if not os.path.exists(folder_kerja): os.makedirs(folder_kerja) for nama, url in target_analisis.items(): cetak_header(nama) folder_hasil = download_dan_ekstrak(url, folder_kerja) if folder_hasil: analisis_meta_dan_prefab(folder_hasil) analisis_assetbundles(folder_hasil) print("\n" + "="*80) print(" šŸ OTOPSI SELESAI. SILAKAN BACA LAPORAN DI ATAS ".center(80, "=")) print("="*80) if __name__ == "__main__": main()