Bonk Deobfuscator

Partially deobfuscate the code

安装此脚本
作者推荐脚本

您可能也喜欢Bonk Panel

安装此脚本
  1. // ==UserScript==
  2. // @name Bonk Deobfuscator
  3. // @version 0.2
  4. // @description Partially deobfuscate the code
  5. // @author KOOKY WARRIOR
  6. // @license MIT
  7. // @match https://bonk.io/gameframe-release.html
  8. // @require https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.7/beautify.min.js
  9. // @grant none
  10. // @run-at document-end
  11. // @namespace https://greasyfork.org/users/999838
  12. // ==/UserScript==
  13.  
  14. /*
  15. This code can only **PARTIALLY** deobfuscate the alpha2.js and save as a .js file
  16.  
  17. **TIPS: Disable this userscript once you have obtained the deobfuscated code**
  18. */
  19.  
  20. function log(text) {
  21. console.log(`[Bonk Deobfuscator] ${text}`)
  22. }
  23.  
  24. const url = "https://bonk.io/js/alpha2s.js"
  25. log("Fetching " + url)
  26.  
  27. fetch(url)
  28. .then((response) => response.text())
  29. .then((response) => {
  30. log("Deobfuscation started")
  31.  
  32. function noDuplicate(array) {
  33. return [...new Set(array)]
  34. }
  35. function escapeRegExp(string) {
  36. return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
  37. }
  38.  
  39. let tmp
  40.  
  41. log("Unminifing the code")
  42. const splitedText = js_beautify(response, { e4x: true }).split("requirejs")
  43.  
  44. log("Setting up main variables")
  45. const MAINFUNCTION = splitedText[0].match(/[^\[]+/)[0]
  46. const MAINARRAY = splitedText[0].match(/^var ([^=^\s]+);/m)[1]
  47.  
  48. log(`eval ${MAINFUNCTION} function`)
  49. eval(`var ${MAINFUNCTION};${response.split("requestjs")[0]}`)
  50. let returncode = `requirejs${splitedText[1]}`
  51.  
  52. log(`Replacing "var a = ${MAINFUNCTION}; a.bcd(123)" to "${MAINFUNCTION}.bcd(123)"`)
  53. tmp = returncode.match(new RegExp(`var (\\S+) = ${escapeRegExp(MAINFUNCTION)};`, ""))[1]
  54. returncode = returncode.replaceAll(`${tmp}.`, `${MAINFUNCTION}.`)
  55.  
  56. log(`Replacing all duplicate functions`)
  57. tmp = [...splitedText[0].matchAll(new RegExp(`(?<v>${escapeRegExp(MAINFUNCTION)}\\.[\\S]+) = (?<f>function\\(\\) \\{.+?};)`, "gs"))]
  58. let VARIABLES = tmp.map((m) => m.groups.v)
  59. let FUNCTIONS = tmp.map((m) => m.groups.f)
  60. let indices = {}
  61. for (let i = 0; i < FUNCTIONS.length; i++) {
  62. if (!indices[FUNCTIONS[i]]) {
  63. indices[FUNCTIONS[i]] = []
  64. }
  65. indices[FUNCTIONS[i]].push(i)
  66. }
  67. for (const key in indices) {
  68. const element = indices[key]
  69. for (let i = 0; i < element.length; i++) {
  70. splitedText[0] = splitedText[0].replaceAll(VARIABLES[element[i]], VARIABLES[element[0]])
  71. returncode = returncode.replaceAll(VARIABLES[element[i]], VARIABLES[element[0]])
  72. }
  73. }
  74.  
  75. log(`Replacing math operation`)
  76. const OPERATIONEQUALVARIABLE = /case 0:\n\s+(\S+) = .+\n.+break;/gm.exec(splitedText[0])[1]
  77. tmp = new RegExp(
  78. `return {\\s+(\\S+): function\\(\\) {\\s+var ${escapeRegExp(OPERATIONEQUALVARIABLE)}, (.+) = arguments;\\s+switch \\((.+)\\)`,
  79. "gm"
  80. ).exec(splitedText[0])
  81. const OPERATIONFUNCTION = new RegExp(`(${escapeRegExp(MAINFUNCTION)}\\....) = function\\(\\) {\\s+return.+${tmp[1]}`, "gm").exec(splitedText[0])[1]
  82. const OPERATIONFUNCTIONSETTER = new RegExp(
  83. `(${escapeRegExp(MAINFUNCTION)}\\....) = function\\(\\) {\\s+return.+${escapeRegExp(
  84. new RegExp(`,\\s+(\\S+): function.+\\s+${escapeRegExp(tmp[3])} =`, "gm").exec(splitedText[0])[1]
  85. )}`,
  86. "gm"
  87. ).exec(splitedText[0])[1]
  88. const OPERATIONARGUMENTVARIABLE = escapeRegExp(tmp[2])
  89. tmp = returncode.match(
  90. new RegExp(
  91. `${escapeRegExp(OPERATIONFUNCTION)}\\((?:[^)(]|\\((?:[^)(]|\\((?:[^)(]|\\([^)(]*\\))*\\))*\\))*\\)|${escapeRegExp(
  92. OPERATIONFUNCTIONSETTER
  93. )}\\(\\d+\\)`,
  94. "g"
  95. )
  96. )
  97. // FUNCTION\((?:[^)(]|\((?:[^)(]|\((?:[^)(]|\([^)(]*\))*\))*\))*\)
  98. var OPERATIONFUNCTIONSETTERVALUE = 0
  99. for (let i = 0; i < tmp.length; i++) {
  100. const element = tmp[i]
  101. if (element.includes(OPERATIONFUNCTION)) {
  102. const args = element.replace(`${OPERATIONFUNCTION}(`, "").replace(/.$/, "").replace(/\s/g, "").split(",")
  103. if (args[args.length - 1].includes(OPERATIONFUNCTIONSETTER)) {
  104. OPERATIONFUNCTIONSETTERVALUE = parseInt(new RegExp(`${escapeRegExp(OPERATIONFUNCTIONSETTER)}\\((\\d+)\\)`).exec(args[args.length - 1])[1])
  105. args.pop()
  106. }
  107. var value = new RegExp(`case ${OPERATIONFUNCTIONSETTERVALUE}:\\n\\s+${escapeRegExp(OPERATIONEQUALVARIABLE)} = (.+);\\n.+break;`, "gm").exec(
  108. splitedText[0]
  109. )[1]
  110. for (let j = 0; j < args.length; j++) {
  111. value = value.replaceAll(`${OPERATIONARGUMENTVARIABLE}[${j}]`, args[j])
  112. }
  113. try {
  114. value = eval(value)
  115. } catch (error) {
  116. } finally {
  117. returncode = returncode.replace(element, value)
  118. }
  119. } else {
  120. OPERATIONFUNCTIONSETTERVALUE = parseInt(new RegExp(`${escapeRegExp(OPERATIONFUNCTIONSETTER)}\\((\\d+)\\)`).exec(element)[1])
  121. }
  122. }
  123.  
  124. const ARRAYFUNCTION = new RegExp(`${escapeRegExp(MAINARRAY)} = .+?(${escapeRegExp(MAINFUNCTION)}\\....)`, "").exec(splitedText[0])[1]
  125. log(`Replacing "${ARRAYFUNCTION}(123)" to "real data"`)
  126. tmp = noDuplicate(returncode.match(new RegExp(`${escapeRegExp(ARRAYFUNCTION)}\\((?:[^)(]|\\((?:[^)(]|\\((?:[^)(]|\\([^)(]*\\))*\\))*\\))*\\)`, "g")))
  127. for (let i = 0; i < tmp.length; i++) {
  128. const element = tmp[i]
  129. try {
  130. returncode = returncode.replaceAll(element, `"${eval(element).replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/"/g, '\\"')}"`)
  131. } catch (error) {
  132. const args = element.replace(`${ARRAYFUNCTION}(`, "").replace(/.$/, "")
  133. const value = parseInt(new RegExp(`${escapeRegExp(args)} = (\\d+)`).exec(returncode)[1])
  134. returncode = returncode.replaceAll(
  135. element,
  136. `"${eval(`${ARRAYFUNCTION}(${value})`).replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/"/g, '\\"')}"`
  137. )
  138. }
  139. }
  140.  
  141. log(`Replacing "var a = ${MAINARRAY}; a[123]" to "${MAINARRAY}[123]"`)
  142. tmp = [...returncode.matchAll(new RegExp(`\\s+(?<v>\\S+) = ${escapeRegExp(MAINARRAY)}.*$`, "gm"))].map((m) => m.groups.v)
  143. for (let i = 0; i < tmp.length; i++) {
  144. returncode = returncode.replaceAll(tmp[i], MAINARRAY)
  145. }
  146.  
  147. log(`Replacing "${MAINARRAY}[123]" to "real data"`)
  148. tmp = noDuplicate(
  149. returncode.match(new RegExp(`${escapeRegExp(MAINARRAY)}\\[(?:[^\\]\\[]|\\[(?:[^\\]\\[]|\\[(?:[^\\]\\[]|\\[[^\\]\\[]*\\])*\\])*\\])*\\]`, "g"))
  150. )
  151. // ARRAY\[(?:[^\]\[]|\[(?:[^\]\[]|\[(?:[^\]\[]|\[[^\]\[]*\])*\])*\])*\]
  152. for (let i = 0; i < tmp.length; i++) {
  153. const element = tmp[i]
  154. try {
  155. returncode = returncode.replaceAll(element, `"${eval(element).replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/"/g, '\\"')}"`)
  156. } catch (error) {
  157. try {
  158. const args = element.replace(`${MAINARRAY}[`, "").replace(/.$/, "")
  159. const value = parseInt(new RegExp(`${escapeRegExp(args)} = (\\d+)`).exec(returncode)[1])
  160. returncode = returncode.replaceAll(element, `"${eval(`${MAINARRAY}[${value}]`).replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/"/g, '\\"')}"`)
  161. } catch (err) {}
  162. }
  163. }
  164.  
  165. log("Saving deobfuscated code")
  166. const filename = `BonkDeobfuscated_${Date.now()}`
  167. const blob = new Blob([splitedText[0] + returncode], { type: "text/javascript;charset=utf-8;" })
  168. if (window.navigator.msSaveOrOpenBlob) {
  169. window.navigator.msSaveBlob(blob, filename)
  170. } else {
  171. const elem = window.document.createElement("a")
  172. elem.href = window.URL.createObjectURL(blob)
  173. elem.download = filename
  174. document.body.appendChild(elem)
  175. elem.click()
  176. document.body.removeChild(elem)
  177. }
  178. })
  179. .catch((err) => console.log(err))