[+] Include Kotlin source code

This commit is contained in:
Hykilpikonna
2020-11-07 21:46:05 -05:00
parent 28df4a61f5
commit 932b99b91b
11 changed files with 1024 additions and 0 deletions
+1
View File
@@ -1,3 +1,4 @@
.DS_Store .DS_Store
.idea/ .idea/
*.iml *.iml
.gradle/
+59
View File
@@ -0,0 +1,59 @@
plugins {
id 'java'
id 'org.jetbrains.kotlin.jvm' version '1.3.72'
id 'org.jetbrains.kotlin.plugin.serialization' version '1.3.70'
}
group 'org.hydev.experiment'
version '0.0.0.1'
repositories {
mavenCentral()
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.20.0"
// https://mvnrepository.com/artifact/org.apache.commons/httpclient
compile group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.5.9'
// https://mvnrepository.com/artifact/com.googlecode.aviator/aviator
compile group: 'com.googlecode.aviator', name: 'aviator', version: '5.1.4'
// https://mvnrepository.com/artifact/com.google.zxing/core
compile group: 'com.google.zxing', name: 'core', version: '3.4.1'
// https://mvnrepository.com/artifact/com.google.zxing/javase
compile group: 'com.google.zxing', name: 'javase', version: '3.4.1'
// https://mvnrepository.com/artifact/com.beust/jcommander
compile group: 'com.beust', name: 'jcommander', version: '1.78'
// https://mvnrepository.com/artifact/commons-io/commons-io
compile group: 'commons-io', name: 'commons-io', version: '2.8.0'
// https://mvnrepository.com/artifact/com.google.guava/guava
compile group: 'com.google.guava', name: 'guava', version: '30.0-jre'
// https://mvnrepository.com/artifact/org.hydev/HyLogger
compile group: 'org.hydev', name: 'HyLogger', version: '2.1.0.378'
testCompile group: 'junit', name: 'junit', version: '4.12'
}
compileKotlin {
kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
kotlinOptions.jvmTarget = "1.8"
}
jar {
manifest {
attributes "Main-Class": "org.hydev.experiment.MainKt"
}
from { configurations.compileClasspath.collect { it.isDirectory() ? it : zipTree(it) } }
}
+1
View File
@@ -0,0 +1 @@
kotlin.code.style=official
+2
View File
@@ -0,0 +1,2 @@
rootProject.name = 'Hackergame2020'
@@ -0,0 +1,289 @@
package org.hydev.experiment
import org.hydev.logger.HyLogger
import org.hydev.logger.HyLoggerConfig
import org.hydev.logger.appenders.FileAppender
import javax.script.ScriptEngine
import javax.script.ScriptEngineManager
import kotlin.math.abs
import kotlin.math.roundToInt
val symbols = "+-*/%^&| ".toCharArray()
val scriptEngineManager = ScriptEngineManager()
val engine: ScriptEngine = scriptEngineManager.getEngineByName("AviatorScript")
// Combination presets for the prime method
fun getCombs(vararg strs: String) = strs.map { str -> str.split(" ").map { it.toInt() } }
val comb1 = getCombs("114514")
val comb2 = getCombs("1 14514", "11 4514", "114 514", "1145 14", "11451 4")
val comb3 = getCombs("1 1 4514", "1 14 514", "1 145 14", "1 1451 4", "11 4 514", "11 45 14", "11 451 4", "114 5 14", "114 51 4", "1145 1 4")
val comb4 = getCombs("1 1 4 514", "1 1 45 14", "1 1 451 4", "1 14 5 14", "1 14 51 4", "11 4 5 14", "11 4 51 4", "11 45 1 4", "114 5 1 4")
val comb5 = getCombs("1 1 4 5 14", "1 1 4 51 4", "1 1 45 1 4", "1 14 5 1 4", "11 4 5 1 4")
val comb6 = getCombs("1 1 4 5 1 4")
val combs = listOf(getCombs(), comb1, comb2, comb3, comb4, comb5, comb6)
val clipboard = ClipboardTools()
/**
* TODO: Write a description for this class!
*
* @author HyDEV Team (https://github.com/HyDevelop)
* @author Hykilpikonna (https://github.com/hykilpikonna)
* @author Vanilla (https://github.com/VergeDX)
* @since 2020-11-03 21:44
*/
fun main(args: Array<String>)
{
// HyLogger
HyLoggerConfig.appenders.add(FileAppender("./logs", "ctf-mini-miner.log"))
//HyLoggerConfig.installSysOut()
// Actual program starts
val lastClip = clipboard.clipboardContents
while (true)
{
print("\n")
println("Waiting for clipboard...")
// Wait for clipboard
while (clipboard.clipboardContents == lastClip || clipboard.getInt() == null) { Thread.sleep(200) }
println("Clipboard received!")
val target = clipboard.getInt()!!
findEquation(target)
}
}
fun findEquation(target: Int)
{
for (offsetIndex in 2..220)
{
val primeTotalOffset = if (offsetIndex % 2 == 0) offsetIndex / 2 else -offsetIndex / 2
var expr = findEquationHelper(target - primeTotalOffset)
// Apply total offset
expr = if (primeTotalOffset >= 0) "${"-~".repeat(primeTotalOffset)}($expr)"
else "${"~-".repeat(-primeTotalOffset)}($expr)"
// Check expression length
if (expr.length < 255)
{
println("Found! $expr")
clipboard.clipboardContents = expr
// Check correct
if (engine.eval(expr).toString().toInt() == target) println("Checked, correct!")
else error("Equation does not match :(")
return
}
else continue
}
error("Failed to find expression :(")
//
// // If a short enough expression is not found, use the prime number method
// var originalPrimes = target.getPrimeFactors()
// var primeTotalOffset = 0
//
// // Reduce prime targets to the least "prime" number around it (Eg. 3347 -> 3346)
// for (offset in -searchRange..searchRange)
// {
// if (target + offset < 0) continue
//
// val primes = (target - offset).getPrimeFactors()
//
// // New least "prime" number found!
// if (primes.size > originalPrimes.size)
// {
// originalPrimes = primes
// primeTotalOffset = offset
// }
// }
}
fun findEquationHelper(target: Int): String
{
val originalPrimes = target.getPrimeFactors()
var closestPrimeComb = listOf<Int>()
var closestPrimePerm = listOf<Int>()
var closestPrimeOffset = Int.MAX_VALUE
// Loop through all possible separations for combinations
for (n in 1..6)
{
// Loop through all combinations
for (combination in combs[n])
{
// Loop through all permutations of prime numbers
for (primePerm in organizePrimes(originalPrimes, n).permute())
{
if (primePerm.size != n || combination.size != n)
{
print("EERRRORRR")
}
// Count the total offset
var offset = 0
for (i in 0 until n)
{
offset += abs(primePerm[i] - combination[i])
}
// New closest found
if (offset < closestPrimeOffset)
{
closestPrimeComb = combination
closestPrimePerm = primePerm
closestPrimeOffset = offset
}
}
}
}
// Found, construct expression
var expr = ""
for (i in closestPrimeComb.indices)
{
val value = closestPrimePerm[i]
val actual = closestPrimeComb[i]
expr += when
{
actual == value -> actual
actual < value -> "${"~-".repeat(value - actual - 1)}~$actual"
else -> "${"~-".repeat(actual - value)}$actual"
}
// Add multiplication symbol
if (i != closestPrimeComb.size - 1) expr += "*"
}
// Fail
if (expr.length > 255) return expr
// Evaluate expression and add neg sign if necessary
val eval = engine.eval(expr).toString().toInt()
if (eval < 0) expr = "-$expr"
return expr
}
fun findEquationFallback(target: Int)
{
// The symbol brute force method
var closest = ""
var closestValue = Int.MIN_VALUE
var closestOffset = Int.MAX_VALUE
outer@for (one in symbols)
{
for (two in symbols)
{
for (three in symbols)
{
for (four in symbols)
{
for (five in symbols)
{
val text = "1${one}1${two}4${three}5${four}1${five}4".replace(" ", "")
val evalString = engine.eval(text).toString()
if (evalString.contains("E")) continue
val eval = evalString.toDouble().roundToInt()
// New closest found
val offset = abs(eval - target)
if (offset < closestOffset)
{
closest = text
closestValue = eval
closestOffset = offset
if (closestOffset < 50) break@outer
}
}
}
}
}
}
HyLogger.general.timing.time().reset()
// Create expression
val expr = if (closestValue <= target) "${"-~".repeat(target - closestValue)}($closest)"
else "-(${"-~".repeat(closestValue - target)}-($closest))"
// Check expression length
if (expr.length < 255) println("Found! $expr")
else findEquation(target)
}
/**
* Organize a list of primes so that it contains ${count} numbers
*
* @param primes
* @param count
* @return
*/
fun organizePrimes(primes: List<Int>, count: Int): MutableList<Int>
{
val new = ArrayList<Int>(primes)
// Eg. [2, 2, 2].size < 6 -> [1, 1, 1, 2, 2, 2]
if (primes.size < count)
{
for (i in 1..count - primes.size) new.add(0, 1)
return new
}
// Eg. [2, 2, 2, 3, 3, 3, 5, 5, 5].size > 6 -> [2, 3, 3, 3, 4, 5, 5, 5] -> [3, 3, 4, 5, 5, 5, 6] -> [4, 5, 5, 5, 6, 9]
while (new.size > count) new.apply { add(removeAt(0) * removeAt(0)); sort() }
return new
}
fun Int.getPrimeFactors(): List<Int>
{
// It is a prime
if (this <= 2) return listOf(this)
// Find prime numbers
var temp = this
val primes = ArrayList<Int>()
for (i in 2 until temp)
{
while (temp % i == 0)
{
primes.add(i)
temp /= i
}
}
if(temp > 2) primes.add(temp)
return primes
}
fun <T> List<T>.permute() = permuteHelper().distinct()
// https://code.sololearn.com/c24EP02YuQx3/#kt
private fun <T> List<T>.permuteHelper(): List<List<T>>
{
if (size == 1) return listOf(this)
val perms = mutableListOf<List<T>>()
val sub = this[0]
for(perm in drop(1).permuteHelper())
{
for (i in 0..perm.size)
{
val newPerm = perm.toMutableList()
newPerm.add(i, sub)
perms.add(newPerm)
}
}
return perms
}
@@ -0,0 +1,218 @@
package org.hydev.experiment
import kotlinx.serialization.ImplicitReflectionSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.UnstableDefault
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonConfiguration
import org.apache.http.client.methods.HttpGet
import org.apache.http.client.methods.HttpPost
import org.apache.http.client.protocol.HttpClientContext
import org.apache.http.entity.StringEntity
import org.apache.http.impl.client.BasicCookieStore
import org.apache.http.impl.client.HttpClients
import org.apache.http.impl.cookie.BasicClientCookie
import org.apache.http.util.EntityUtils
import org.hydev.logger.HyLoggerConfig
import org.hydev.logger.appenders.FileAppender
import java.io.File
import kotlin.math.roundToInt
import kotlin.system.exitProcess
/**
* TODO: Write a description for this class!
*
* @author HyDEV Team (https://github.com/HyDevelop)
* @author Hykilpikonna (https://github.com/hykilpikonna)
* @author Vanilla (https://github.com/VergeDX)
* @since 2020-11-02 15:51
*/
@OptIn(UnstableDefault::class)
@ImplicitReflectionSerializer
fun main(args: Array<String>)
{
// Json
val json = Json(JsonConfiguration(isLenient = true))
// HyLogger
HyLoggerConfig.appenders.add(FileAppender("./logs", "ctf-doggy.log"))
HyLoggerConfig.installSysOut()
// Create http client
val builder = HttpClients.custom()
val context = HttpClientContext.create()
val cookies = BasicCookieStore()
context.cookieStore = cookies
builder.setDefaultCookieStore(cookies)
val client = builder.build()
// CTF session
val sessionFile = File("doggy-session.txt")
cookies.addCookie(BasicClientCookie("session", sessionFile.readText().replace("\n", ""))
.apply { domain = "202.38.93.111" })
val auth = File("doggy-auth.txt").readText()
val host = "http://202.38.93.111:10102/api/"
// Function to access api
fun get(api: String, body: String): String
{
val get = if (body == "") HttpGet(host + api)
else HttpPost(host + api).apply { entity = StringEntity(body) }
get.addHeader("authorization", auth)
get.addHeader("accept", "application/json, text/plain, */*")
get.addHeader("content-type", "application/json;charset=UTF-8")
val response = client.execute(get)
if (response.statusLine.statusCode != 200)
{
println("Error $api - Body: $body ; Status code: ${response.statusLine.statusCode}")
}
val responseBody = EntityUtils.toString(response.entity, "UTF-8")
response.close()
return responseBody
}
fun getUser() = json.parse(User.serializer(), get("user", ""))
fun transfer(src: Int, dst: Int, amount: Int)
{
get("transfer", "{\"src\":$src,\"dst\":$dst,\"amount\":$amount}")
println("→ Transfer from $src to $dst, $amount")
}
fun create(credit: Boolean)
{
get("create", "{\"type\":\"${if (credit) "credit" else "debit"}\"}")
println("+ Created ${if (credit) "credit" else "debit"} card.")
}
fun eat(card: Int, log: Boolean = true)
{
get("eat", "{\"account\":$card}")
if (log) println("================ DAY ENDS ================")
}
// Each problem
while (true)
{
// Backup session
val session = cookies.cookies.filter { it.name == "session" }[0].value
println("==============SESSION===============")
println(session)
println("================END=================")
sessionFile.writeText(session)
// Get today
val user = getUser()
// 后期可以不用四舍五入 bug 赚钱了
if (user.printSummary())
{
// 把所有储蓄卡转到卡 1
user.debits().forEach {
if (it.balance != 0) transfer(it.id, 1, it.balance)
}
// 把所有债还了
user.credits().forEach {
if (it.balance != 0) transfer(1, it.id, it.balance)
}
break
}
// 初始化: 每 1 张信用卡添加 12 张储蓄卡
if (user.date == 1 && user.credits().isEmpty())
{
var idStart = 2 // 这一组的信用卡 ID
for (credit in 0..19)
{
create(true)
for (debit in 1..12)
{
create(false)
// 从信用卡给储蓄卡付款 167
transfer(idStart, idStart + debit, 167)
}
idStart += 13
}
}
val debitThreshold = 10 + user.date / 10
val creditThreshold = 100
// 检查每张储蓄卡都差不多 167, 多赚的转到卡 1
user.debits().forEach {
if (it.balance > 167 + debitThreshold && it.id != 1)
{
Thread { transfer(it.id, 1, it.balance - 167) }.start()
Thread.sleep(100)
}
}
// 让信用卡都小于 -2098,多欠的的用卡 1 付
user.credits().forEach {
val transfer = it.balance - 2098 + creditThreshold
if (it.balance > 2098 && user.swap().balance > transfer) transfer(1, it.id, transfer)
}
// 吃!
eat(1)
}
// 后期模式, 开 15 个线程一起吃w
for (i in 0..14)
{
Thread { while (true) eat(1, false) }.start()
}
println("Rounding mode ended.")
while (true)
{
when (readLine()!!.toLowerCase())
{
"stop" -> exitProcess(0)
"summary" -> getUser().printSummary()
}
}
}
@Serializable
data class Account(
val balance: Int,
val id: Int,
val type: String
)
@Serializable
data class User(
val accounts: List<Account>,
val date: Int,
val flag: String?
)
{
fun credits() = accounts.filter { it.type == "credit" }
fun debits() = accounts.filter { it.type == "debit" }
fun swap() = debits().find { it.id == 1 }!!
/**
* Print summary and check if it's ready to leave the rounding profit system.
*/
fun printSummary(): Boolean
{
val dSum = debits().map { it.balance }.sum()
val cSum = credits().map { it.balance }.sum()
val dd = debits().map { (it.balance * 0.003).roundToInt() }.sum()
val dc = -credits().map { (it.balance * 0.005).roundToInt() }.sum()
val de = -10
val sum = dd + dc + de
println("Summary - Total Balance: ${dSum - cSum} - DD: +$dd, DC: $dc, DE: $de, Sum: $sum")
// Check if it's ready to leave the rounding profit system
return ((dSum - cSum) * 0.003).roundToInt() > 20
}
}
@@ -0,0 +1,200 @@
package org.hydev.experiment
import org.apache.http.client.entity.UrlEncodedFormEntity
import org.apache.http.client.methods.HttpGet
import org.apache.http.client.methods.HttpPost
import org.apache.http.client.protocol.HttpClientContext
import org.apache.http.impl.client.BasicCookieStore
import org.apache.http.impl.client.HttpClients
import org.apache.http.impl.cookie.BasicClientCookie
import org.apache.http.message.BasicNameValuePair
import org.apache.http.util.EntityUtils
import org.hydev.logger.HyLoggerConfig
import org.hydev.logger.appenders.FileAppender
import java.awt.Robot
import java.awt.event.KeyEvent.*
import java.io.File
/**
* TODO: Write a description for this class!
*
* @author HyDEV Team (https://github.com/HyDevelop)
* @author Hykilpikonna (https://github.com/hykilpikonna)
* @author Vanilla (https://github.com/VergeDX)
* @since 2020-11-02 15:51
*/
fun main(args: Array<String>)
{
// HyLogger
HyLoggerConfig.appenders.add(FileAppender("./logs", "ctf.log"))
HyLoggerConfig.installSysOut()
// Create http client
val builder = HttpClients.custom()
val context = HttpClientContext.create()
val cookies = BasicCookieStore()
context.cookieStore = cookies
builder.setDefaultCookieStore(cookies)
val client = builder.build()
// Constants
val regex = """(?<=<p> \$).*(?=\$)""".toRegex()
val numberRegex = """(?<= )[0-9]*(?= 题)""".toRegex()
// CTF session
val sessionFile = File("session")
cookies.addCookie(BasicClientCookie("session", sessionFile.readText().replace("\n", ""))
.apply { domain = "202.38.93.111" })
// Clipboard
val clipboard = ClipboardTools()
// Robot: Keyboard control
val robot = Robot()
fun press(vararg events: Int)
{
events.forEach { robot.keyPress(it) }
robot.delay(100)
events.forEach { robot.keyRelease(it) }
}
// Each problem
while (true)
{
// Backup session
val session = cookies.cookies.filter { it.name == "session" }[0].value
println("==============SESSION===============")
println(session)
println("================END=================")
sessionFile.writeText(session)
// Get request
val get = HttpGet("http://202.38.93.111:10190/")
val response = client.execute(get)
val html = EntityUtils.toString(response.entity, "UTF-8")
val questionsRemaining = numberRegex.find(html)!!.value.toInt()
println("Questions remaining: $questionsRemaining")
val tex = regex.find(html)!!.value
response.close()
// Do the last one on the website by yourself
if (questionsRemaining == 1)
{
println("===============FINISH================")
println("Now copy the session and override your browser cookie, " +
"then complete the last question in your browser to get the flag.")
return
}
// Tex to function, copy
val eq = toEquation(tex)
println(eq)
clipboard.clipboardContents = eq
// Robot: Auto paste and enter (META is the macOS command key. IF you're on Windows, change this to CONTROL)
press(VK_META, VK_V)
robot.delay(100)
press(VK_ENTER)
Thread.sleep(1000)
// Robot: Auto copy result
press(VK_UP)
robot.delay(100)
press(VK_META, VK_C) // META: same here :)
robot.delay(100)
press(VK_DOWN)
// Wait for clipboard
while (clipboard.getDouble() == null) { Thread.sleep(200) }
println("Clipboard received!")
val ans = clipboard.getDouble()
// Send response
val post = HttpPost("http://202.38.93.111:10190/submit")
post.addHeader("content-type", "application/x-www-form-urlencoded")
post.entity = UrlEncodedFormEntity(listOf(BasicNameValuePair("ans", String.format("%.6f", ans))), "UTF-8")
val result = client.execute(post)
result.close()
}
}
fun toEquation(originalTex: String): String
{
val tex = originalTex
.replace("\\left(", "(").replace("\\right)", ")").replace("\\,", " ")
.replace("{", "(").replace("}", ")")
.replace("\\", "")
.shortenSpaces()
return toEquationHelper(tex)
.replace("x (", "x * (").replace("x(", "x * (") // Fix implied multiplication error
}
fun toEquationHelper(originalTex: String): String
{
var tex = originalTex
if (tex.startsWith("int_("))
{
tex = tex.substring(5, tex.length - 6)
val upper = tex.substring(0, tex.findBracket())
tex = tex.substring(upper.length + 3)
val lower = tex.substring(0, tex.findBracket())
tex = tex.substring(lower.length + 2)
return "integral(${toEquation(tex)},x,${toEquation(upper)},${toEquation(lower)})"
}
// Change fractions
while (tex.contains("frac("))
{
// frac(1)(2) -> (1)/(2)
val loc = tex.indexOf("frac(")
val endBrack = tex.findBracket(start = loc + 5)
tex = tex.substring(0, loc) + tex.substring(loc + 4, endBrack + 1) + "/" + tex.substring(endBrack + 1)
}
return tex
}
/**
* Find the index of the end bracket
*
* @param bracket { or (
* @param start Start index
* @return
*/
fun String.findBracket(bracket: Boolean = false, start: Int = 0): Int
{
val open = if (bracket) '{' else '('
val close = if (bracket) '}' else ')'
var level = 0
var i = start
while (i < length)
{
val c = this[i]
if (c == close)
{
if (level == 0) return i
else level--
}
if (c == open) level++;
i++
}
return -1
}
/**
* Reduce double spaces to single spaces
*
* @return Shortened string
*/
fun String.shortenSpaces(): String
{
var s = this
while (s.contains(" ")) s = s.replace(" ", " ")
return s
}
@@ -0,0 +1,132 @@
package org.hydev.experiment
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonConfiguration
import org.apache.http.client.methods.HttpPost
import org.apache.http.client.protocol.HttpClientContext
import org.apache.http.impl.client.BasicCookieStore
import org.apache.http.impl.client.HttpClients
import org.apache.http.util.EntityUtils
import org.hydev.logger.HyLoggerConfig
import org.hydev.logger.appenders.FileAppender
import java.io.File
import java.net.URLEncoder
/**
* TODO: Write a description for this class!
*
* @author HyDEV Team (https://github.com/HyDevelop)
* @author Hykilpikonna (https://github.com/hykilpikonna)
* @author Vanilla (https://github.com/VergeDX)
* @since 2020-11-03 16:19
*/
fun main(args: Array<String>)
{
// Json
val json = Json(JsonConfiguration(isLenient = true))
// HyLogger
HyLoggerConfig.appenders.add(FileAppender("./logs", "ctf-mini-miner.log"))
HyLoggerConfig.installSysOut()
// Create http client
val builder = HttpClients.custom()
val context = HttpClientContext.create()
val cookies = BasicCookieStore()
context.cookieStore = cookies
builder.setDefaultCookieStore(cookies)
val client = builder.build()
// API stuff
val baseUrl = "http://localhost:8088/api/"
val token = File("mini-miner-token.txt").readText().replace("\n", "")
fun post(api: String, params: String): String
{
// Create post
val url = "$baseUrl$api?token=${token.urlEncode()}$params"
val post = HttpPost(url).apply {
addHeader("accept", "*/*")
addHeader("content-type", "application/json;charset=UTF-8")
}
// Execute
val response = client.execute(post)
val responseBody = EntityUtils.toString(response.entity, "UTF-8")
response.close()
// Error
if (response.statusLine.statusCode != 200)
{
println("Error $api - Params: $params ; Status code: ${response.statusLine.statusCode} ; Response body: $responseBody")
}
// Return body
return responseBody
}
fun state() = json.parse(StateReturn.serializer(), post("state", "&x=0&y=0"))
fun reset() = json.parse(ResetReturn.serializer(), post("reset", ""))
fun damage(x: Int, y: Int) = json.parse(DamageReturn.serializer(), post("damage", "&x=$x&y=$y&material=OBSIDIAN"))
// Actual code begins
while (true)
{
// Reset and get current state
println(reset())
val state = state()
// Find flag
var flagX = 0
var flagY = 0
for (x in 0..state.materials.size)
{
if (state.materials[x].contains("FLAG"))
{
flagX = x
flagY = state.materials[x].indexOf("FLAG")
break
}
}
println("$flagX,$flagY")
// Destroy block, wait for it to complete (long = 5s)
damage(flagX, flagY)
Thread.sleep(5500)
// Destroy air, have roughly 3s until it checks the flag again
Thread {
val result = damage(flagX, flagY)
println(result)
}.start()
Thread.sleep(500)
reset() // Reset the flag block
}
}
@Serializable
data class ResetReturn(
val expiration: String,
val user: String
)
@Serializable
data class StateReturn(
val materials: List<List<String>>,
val min: List<Int>
)
@Serializable
data class DamageReturn(
val dropped: String,
val flag: String
)
fun String.urlEncode(): String = URLEncoder.encode(this, "UTF-8")
@@ -0,0 +1,64 @@
package org.hydev.experiment
import com.google.zxing.BarcodeFormat.QR_CODE
import com.google.zxing.BinaryBitmap
import com.google.zxing.DecodeHintType.*
import com.google.zxing.client.j2se.BufferedImageLuminanceSource
import com.google.zxing.common.BitSource
import com.google.zxing.common.GlobalHistogramBinarizer
import com.google.zxing.multi.GenericMultipleBarcodeReader
import com.google.zxing.qrcode.QRCodeReader
import org.apache.commons.io.FileUtils
import java.io.File
import java.lang.System.err
import java.nio.charset.Charset
import javax.imageio.ImageIO
// 这个是要改 ZXing 源码才会把解析的 byte[] 加进来啦w
var parsedBytes = byteArrayOf();
/**
* TODO: Write a description for this class!
*
* @author HyDEV Team (https://github.com/HyDevelop)
* @author Hykilpikonna (https://github.com/hykilpikonna)
* @author Vanilla (https://github.com/VergeDX)
* @since 2020-11-05 18:27
*/
fun main(args: Array<String>)
{
var rawBytes = byteArrayOf()
var utfBytes = byteArrayOf()
var iso8859Bytes = byteArrayOf()
File("/Users/hykilpikonna/Downloads/CTF/qr-frames").listFiles()!!.sorted().forEach {
try
{
val source = BufferedImageLuminanceSource(ImageIO.read(it))
val bitmap = BinaryBitmap(GlobalHistogramBinarizer(source))
val reader = GenericMultipleBarcodeReader(QRCodeReader())
val hints = mapOf(TRY_HARDER to true, POSSIBLE_FORMATS to QR_CODE, PURE_BARCODE to true)
val result = reader.decodeMultiple(bitmap, hints)[0]
rawBytes += result.rawBytes
utfBytes += result.text.toByteArray(Charset.forName("UTF-16"))
iso8859Bytes += result.text.toByteArray(Charset.forName("ISO-8859-1"))
}
catch (e: Exception)
{
err.println(it)
e.printStackTrace()
}
}
val bits = BitSource(rawBytes)
val readBytes = ByteArray(rawBytes.size)
for (i in rawBytes.indices)
{
readBytes[i] = bits.readBits(8).toByte()
}
FileUtils.writeByteArrayToFile(File("./qr_bytes_raw_processed"), parsedBytes)
}
@@ -0,0 +1,48 @@
package org.hydev.experiment
import java.awt.Toolkit
import java.awt.datatransfer.*
/**
* http://www.javapractices.com/topic/TopicAction.do?Id=82
*/
class ClipboardTools : ClipboardOwner
{
/**
* Empty implementation of the ClipboardOwner interface.
*/
override fun lostOwnership(clipboard: Clipboard, contents: Transferable) {}
fun getDouble() = clipboardContents!!.replace("", "-").toDoubleOrNull();
fun getInt() = clipboardContents!!.replace("", "-").toIntOrNull();
/**
* Get and set the clipboard contents
*/
var clipboardContents: String?
get()
{
var result = ""
val clipboard = Toolkit.getDefaultToolkit().systemClipboard
val contents = clipboard.getContents(null)
val hasTransferableText = contents != null && contents.isDataFlavorSupported(DataFlavor.stringFlavor)
if (hasTransferableText)
{
try
{
result = contents!!.getTransferData(DataFlavor.stringFlavor) as String
}
catch (ex: Exception)
{
ex.printStackTrace()
}
}
return result
}
set(string)
{
val stringSelection = StringSelection(string)
val clipboard = Toolkit.getDefaultToolkit().systemClipboard
clipboard.setContents(stringSelection, this)
}
}
+10
View File
@@ -15,6 +15,8 @@
## 14: 来自未来的 ~~D-Mail~~ ## 14: 来自未来的 ~~D-Mail~~
[Kotlin 源码](./KotlinProject/src/main/kotlin/org/hydev/experiment/CTFQR.kt)
(会有 3020 的考古队看到这个嘛w:thinking: (会有 3020 的考古队看到这个嘛w:thinking:
1. 把 QR **解析**成 `byte[]` 然后写到文件里(和 rawBytes 不一样哦! 1. 把 QR **解析**成 `byte[]` 然后写到文件里(和 rawBytes 不一样哦!
@@ -51,6 +53,8 @@ Python 的库试过的: zbar 装不上,qrtools 不能用来解析,pyzbar 很
## 15. 狗狗银行 🐶🏦 ## 15. 狗狗银行 🐶🏦
[Kotlin 源码](./KotlinProject/src/main/kotlin/org/hydev/experiment/CTFDoggyBank.kt)
### 数学方面的 ### 数学方面的
1. 信用卡欠 2099 的话每天的利息是 10.4910),实际利率是 4.99% 1. 信用卡欠 2099 的话每天的利息是 10.4910),实际利率是 4.99%
@@ -83,6 +87,8 @@ Python 的库试过的: zbar 装不上,qrtools 不能用来解析,pyzbar 很
## 16. ∫(超基础的数理模拟器)dx ## 16. ∫(超基础的数理模拟器)dx
[Kotlin 源码](./KotlinProject/src/main/kotlin/org/hydev/experiment/CTFIntegrals.kt)
虽然不是最高效的解但是视觉效果超厉害的!! 虽然不是最高效的解但是视觉效果超厉害的!!
**视频链接:** [ビリビリ](https://www.bilibili.com/video/BV16a411c7jN/) | [YouTube](https://youtu.be/8L2TkLmXngQ) **视频链接:** [ビリビリ](https://www.bilibili.com/video/BV16a411c7jN/) | [YouTube](https://youtu.be/8L2TkLmXngQ)
@@ -107,6 +113,8 @@ Sage 看了下但是不知道怎样在程序里面控制w
## 19. 超恶臭的数字论证器 (确信) ## 19. 超恶臭的数字论证器 (确信)
[Kotlin 源码 (是最乱的一个 ;-;)](./KotlinProject/src/main/kotlin/org/hydev/experiment/CTF114514.kt)
原来官方解法那么简单哇w 原来官方解法那么简单哇w
代码短 20 倍了!!!(╯‵□′)╯︵┻━┻ 代码短 20 倍了!!!(╯‵□′)╯︵┻━┻
@@ -140,6 +148,8 @@ Sage 看了下但是不知道怎样在程序里面控制w
## 31. 超迷你的挖矿模拟器 ⛏️ ## 31. 超迷你的挖矿模拟器 ⛏️
[Kotlin 源码](./KotlinProject/src/main/kotlin/org/hydev/experiment/CTFMiniMiner.kt)
1. 挖掉 Flag 位置(1,1)的方块w5s 1. 挖掉 Flag 位置(1,1)的方块w5s
2. 开始挖 Flag 位置的空气, 2. 开始挖 Flag 位置的空气,
这个时候服务器检测到空气所以就执行可以掉落物品的代码w 这个时候服务器检测到空气所以就执行可以掉落物品的代码w