From bf73d847bb8724d8d3488087e2422dcef1c723fc Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Mon, 18 May 2026 11:46:24 -0600 Subject: [PATCH] JsHunter/JsUnpacker: use Kotlin-native regex --- .../lagradost/cloudstream3/utils/JsHunter.kt | 28 ++-- .../cloudstream3/utils/JsUnpacker.kt | 140 +++++------------- 2 files changed, 48 insertions(+), 120 deletions(-) diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/JsHunter.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/JsHunter.kt index 1ec442d7bcc..8aabeb1f17c 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/JsHunter.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/JsHunter.kt @@ -1,11 +1,9 @@ package com.lagradost.cloudstream3.utils import com.lagradost.cloudstream3.mvvm.logError -import java.util.regex.Matcher -import java.util.regex.Pattern import kotlin.math.pow -//author: https://github.com/daarkdemon +// author: https://github.com/daarkdemon class JsHunter(private val hunterJS: String) { /** @@ -14,9 +12,8 @@ class JsHunter(private val hunterJS: String) { * @return true if it's H.U.N.T.E.R coded. */ fun detect(): Boolean { - val p = Pattern.compile("eval\\(function\\(h,u,n,t,e,r\\)") - val searchResults = p.matcher(hunterJS) - return searchResults.find() + val regex = Regex("eval\\(function\\(h,u,n,t,e,r\\)") + return regex.containsMatchIn(hunterJS) } /** @@ -24,20 +21,15 @@ class JsHunter(private val hunterJS: String) { * * @return the javascript unhunt or null. */ - fun dehunt(): String? { try { - val p: Pattern = - Pattern.compile( - """\}\("([^"]+)",[^,]+,\s*"([^"]+)",\s*(\d+),\s*(\d+)""", - Pattern.DOTALL - ) - val searchResults: Matcher = p.matcher(hunterJS) - if (searchResults.find() && searchResults.groupCount() == 4) { - val h = searchResults.group(1)!! - val n = searchResults.group(2)!! - val t = searchResults.group(3)!!.toInt() - val e = searchResults.group(4)!!.toInt() + val regex = Regex("""\}\("([^"]+)",[^,]+,\s*"([^"]+)",\s*(\d+),\s*(\d+)""", RegexOption.DOT_MATCHES_ALL) + val match = regex.find(hunterJS) + if (match != null && match.groupValues.size == 5) { + val h = match.groupValues[1] + val n = match.groupValues[2] + val t = match.groupValues[3].toInt() + val e = match.groupValues[4].toInt() return hunter(h, n, t, e) } } catch (e: Exception) { diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/JsUnpacker.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/JsUnpacker.kt index 7ed2e9be2c2..2dbbfddb0d8 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/JsUnpacker.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/JsUnpacker.kt @@ -1,7 +1,6 @@ package com.lagradost.cloudstream3.utils import com.lagradost.cloudstream3.mvvm.logError -import java.util.regex.Pattern import kotlin.math.pow // https://github.com/cylonu87/JsUnpacker @@ -15,9 +14,7 @@ class JsUnpacker(packedJS: String?) { */ fun detect(): Boolean { val js = packedJS!!.replace(" ", "") - val p = Pattern.compile("eval\\(function\\(p,a,c,k,e,[rd]") - val m = p.matcher(js) - return m.find() + return Regex("eval\\(function\\(p,a,c,k,e,[rd]").containsMatchIn(js) } /** @@ -28,41 +25,42 @@ class JsUnpacker(packedJS: String?) { fun unpack(): String? { val js = packedJS ?: return null try { - var p = - Pattern.compile("""\}\s*\('(.*)',\s*(.*?),\s*(\d+),\s*'(.*?)'\.split\('\|'\)""", Pattern.DOTALL) - var m = p.matcher(js) - if (m.find() && m.groupCount() == 4) { - val payload = m.group(1)?.replace("\\'", "'") ?: "" - val radixStr = m.group(2) - val countStr = m.group(3) - val symtab = (m.group(4)?.split("\\|".toRegex()) ?: emptyList()).toTypedArray() + val match = Regex( + """\}\s*\('(.*)',\s*(.*?),\s*(\d+),\s*'(.*?)'\.split\('\|'\)""", + RegexOption.DOT_MATCHES_ALL + ).find(js) + if (match != null && match.groupValues.size == 5) { + val payload = match.groupValues[1].replace("\\'", "'") + val radixStr = match.groupValues[2] + val countStr = match.groupValues[3] + val symtab = match.groupValues[4].split("|").toTypedArray() var radix = 36 var count = 0 try { - radix = radixStr?.toIntOrNull() ?: radix + radix = radixStr.toIntOrNull() ?: radix } catch (_: Exception) { } try { - count = countStr?.toIntOrNull() ?: 0 + count = countStr.toIntOrNull() ?: 0 } catch (_: Exception) { } if (symtab.size != count) { throw Exception("Unknown p.a.c.k.e.r. encoding") } val unbase = Unbase(radix) - p = Pattern.compile("""\b[a-zA-Z0-9_]+\b""") - m = p.matcher(payload) + val wordRegex = Regex("""\b[a-zA-Z0-9_]+\b""") val decoded = StringBuilder(payload) var replaceOffset = 0 - while (m.find()) { - val word = m.group(0) - val x = if (word == null) 0 else unbase.unbase(word) - var value: String? = null - if (x < symtab.size && x >= 0) { - value = symtab[x] - } - if (!value.isNullOrEmpty() && !word.isNullOrEmpty()) { - decoded.replace(m.start() + replaceOffset, m.end() + replaceOffset, value) + wordRegex.findAll(payload).forEach { wordMatch -> + val word = wordMatch.value + val x = unbase.unbase(word) + val value = if (x in symtab.indices) symtab[x] else null + if (!value.isNullOrEmpty()) { + decoded.replace( + wordMatch.range.first + replaceOffset, + wordMatch.range.last + 1 + replaceOffset, + value + ) replaceOffset += value.length - word.length } } @@ -80,6 +78,7 @@ class JsUnpacker(packedJS: String?) { " !\"#$%&\\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" private var alphabet: String? = null private var dictionary: HashMap? = null + fun unbase(str: String): Int { var ret = 0 if (alphabet == null) { @@ -96,18 +95,10 @@ class JsUnpacker(packedJS: String?) { init { if (radix > 36) { when { - radix < 62 -> { - alphabet = ALPHABET_62.substring(0, radix) - } - radix in 63..94 -> { - alphabet = ALPHABET_95.substring(0, radix) - } - radix == 62 -> { - alphabet = ALPHABET_62 - } - radix == 95 -> { - alphabet = ALPHABET_95 - } + radix < 62 -> alphabet = ALPHABET_62.substring(0, radix) + radix in 63..94 -> alphabet = ALPHABET_95.substring(0, radix) + radix == 62 -> alphabet = ALPHABET_62 + radix == 95 -> alphabet = ALPHABET_95 } dictionary = HashMap(95) for (i in 0 until alphabet!!.length) { @@ -124,74 +115,20 @@ class JsUnpacker(packedJS: String?) { this.packedJS = packedJS } - companion object { - val c = - listOf( - 0x63, - 0x6f, - 0x6d, - 0x2e, - 0x67, - 0x6f, - 0x6f, - 0x67, - 0x6c, - 0x65, - 0x2e, - 0x61, - 0x6e, - 0x64, - 0x72, - 0x6f, - 0x69, - 0x64, - 0x2e, - 0x67, - 0x6d, - 0x73, - 0x2e, - 0x61, - 0x64, - 0x73, - 0x2e, - 0x4d, - 0x6f, - 0x62, - 0x69, - 0x6c, - 0x65, - 0x41, - 0x64, - 0x73 - ) - val z = - listOf( - 0x63, - 0x6f, - 0x6d, - 0x2e, - 0x66, - 0x61, - 0x63, - 0x65, - 0x62, - 0x6f, - 0x6f, - 0x6b, - 0x2e, - 0x61, - 0x64, - 0x73, - 0x2e, - 0x41, - 0x64 - ) + val c = listOf( + 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x6e, 0x64, + 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x67, 0x6d, 0x73, 0x2e, 0x61, 0x64, 0x73, 0x2e, 0x4d, + 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x41, 0x64, 0x73 + ) + val z = listOf( + 0x63, 0x6f, 0x6d, 0x2e, 0x66, 0x61, 0x63, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x2e, 0x61, + 0x64, 0x73, 0x2e, 0x41, 0x64 + ) fun String.load(): String? { return try { var load = this - for (q in c.indices) { if (c[q % 4] > 270) { load += c[q % 3] @@ -199,7 +136,6 @@ class JsUnpacker(packedJS: String?) { load += c[q].toChar() } } - Class.forName(load.substring(load.length - c.size, load.length)).name } catch (_: Exception) { try { @@ -207,7 +143,7 @@ class JsUnpacker(packedJS: String?) { for (w in z.indices) { f += z[w].toChar() } - return Class.forName(f.substring(0b001, f.length)).name + Class.forName(f.substring(0b001, f.length)).name } catch (_: Exception) { null }