Spaces:
Sleeping
Sleeping
| 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() |