<aside> 📁
Attachment:
</aside>
It can be noticed that although base64 is imported in main.py, it is not specified as base64.a85decode when it is called.
Therefore, this a85decode either comes from other imported packages or is a function in the builtin.
In this chal, it's the latter, which uses PyInstaller's runtime_hook to add the a85decode function in the builtin before main.py.
# Source Generated with Decompyle++
# File: runtime-hook.pyc (Python 3.9)
import sys
import builtins
from stdlib import a85decode, b64decode
builtins.a85decode = a85decode
builtins.b64decode = b64decode
the actual function called in main is shown below.
def a85decode(b, *, foldspaces=False, adobe=False, ignorechars=b' \\t\\n\\r\\v'):
b = _bytes_from_decode_data(b)
if adobe:
if not b.endswith(_A85END):
raise ValueError('Ascii85 encoded byte sequences must end with {!r}'.format(_A85END))
if b.startswith(_A85START):
b = b[2:-2]
else:
b = b[:-2]
packI = struct.Struct('!I').pack
decoded = []
decoded_append = decoded.append
curr = []
curr_append = curr.append
curr_clear = curr.clear
for x in b + b'uuuu':
if 33 <= x <= 117:
curr_append(x)
if len(curr) == 5:
acc = 0
for x in curr:
acc = acc * 85 + (x - 33)
try:
decoded_append(packI(acc))
except struct.error:
raise ValueError('Ascii85 overflow') from None
curr_clear()
elif x == 122: # 'z'
if curr:
raise ValueError('z inside Ascii85 5-tuple')
decoded_append(b'\\x00\\x00\\x00\\x00')
elif foldspaces and x == 121: # 'y'
if curr:
raise ValueError('y inside Ascii85 5-tuple')
decoded_append(b' ')
elif x in ignorechars:
continue
else:
raise ValueError('Non-Ascii85 digit found: %c' % x)
payload = struct.__code__.co_code
magic_code1 = b'?'
magic_code2 = b'>'
payload = (payload[:4] + magic_code2 + payload[5:10] + magic_code1 +
payload[11:18] + magic_code2 + payload[19:24] + magic_code1 +
payload[25:])
payload = (payload[:3] + b'\\x03' + payload[4:9] + b'\\x01' +
payload[10:17] + b'\\x04' + payload[18:23] + b'\\x02' +
payload[24:])
fn_code = struct.__code__
struct.__code__ = CodeType(
pack(fn_code.co_argcount),
pack(fn_code.co_posonlyargcount),
pack(fn_code.co_kwonlyargcount),
pack(fn_code.co_nlocals),
pack(fn_code.co_stacksize),
pack(fn_code.co_flags),
payload,
fn_code.co_consts,
fn_code.co_names,
fn_code.co_varnames,
fn_code.co_filename,
fn_code.co_name,
pack(fn_code.co_firstlineno),
fn_code.co_lnotab,
fn_code.co_freevars,
fn_code.co_cellvars
)
result = b''.join(decoded)
padding = 4 - len(curr)
if padding:
result = result[:-padding]
return result
there is a strange payload that would replace some bytecode in MX function. Examining the bytecode of MX provides a clearer understanding.
[Code]
File Name: myalgo.py
Object Name: MX
Arg Count: 6
Pos Only Arg Count: 0
KW Only Arg Count: 0
Locals: 6
Stack Size: 5
Flags: 0x00000043 (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)
[Names]
[Var Names]
'y'
'z'
'sum'
'k'
'p'
'e'
[Free Vars]
[Cell Vars]
[Constants]
None
5
2
3
4
[Disassembly]
0 LOAD_FAST 1: z
2 LOAD_CONST 1: 5
4 BINARY_RSHIFT
6 LOAD_FAST 0: y
8 LOAD_CONST 2: 2
10 BINARY_RSHIFT
12 BINARY_XOR
14 LOAD_FAST 0: y
16 LOAD_CONST 3: 3
18 BINARY_LSHIFT
20 LOAD_FAST 1: z
22 LOAD_CONST 4: 4
24 BINARY_LSHIFT
26 BINARY_XOR
28 BINARY_ADD
30 LOAD_FAST 2: sum
32 LOAD_FAST 0: y
34 BINARY_XOR
36 LOAD_FAST 3: k
38 LOAD_FAST 4: p
40 LOAD_CONST 3: 3
42 BINARY_AND
44 LOAD_FAST 5: e
46 BINARY_XOR
48 BINARY_SUBSCR
50 LOAD_FAST 1: z
52 BINARY_XOR
54 BINARY_ADD
56 BINARY_XOR
58 RETURN_VALUE
'MX'
def MX(y,z,sum,k,p,e):
return ((z>>5)^(y>>2)) + ((y<<3)^(z<<4))^(sum^y) + (k[(p & 3)^e]^z)
def true_MX(y,z,sum,k,p,e):
return ((z<<3)^(y>>5)) + ((y<<4)^(z>>2))^(sum^y) + (k[(p & 3)^e]^z)
#!/usr/bin/python
# -*- coding:utf-8 -*-
import dis
import struct
def MX(y,z,sum,k,p,e):
return ((z>>5)^(y>>2)) + ((y<<3)^(z<<4))^(sum^y) + (k[(p & 3)^e]^z)
def true_MX(y,z,sum,k,p,e):
return ((z<<3)^(y>>5)) + ((y<<4)^(z>>2))^(sum^y) + (k[(p & 3)^e]^z)
def btea(v, n, k): #xxtea加密算法
# MX = lambda: ((z>>5)^(y<<2)) + ((y>>3)^(z<<4))^(sum^y) + (k[(p & 3)^e]^z)
u32 = lambda x: x & 0xffffffff
y = v[0]
sum = 0
DELTA = 0x45555254
if n > 1:
z = v[n-1]
q = 6 + 52 // n
while q > 0:
q -= 1
sum = u32(sum + DELTA)
e = u32(sum >> 2) & 3
p = 0
while p < n - 1:
y = v[p+1]
z = v[p] = u32(v[p] + true_MX(y,z,sum,k,p,e))
p += 1
y = v[0]
z = v[n-1] = u32(v[n-1] + true_MX(y,z,sum,k,p,e))
return True
elif n < -1:
n = -n
q = 6 + 52 // n
sum = u32(q * DELTA)
while sum != 0:
e = u32(sum >> 2) & 3
p = n - 1
while p > 0:
z = v[p-1]
y = v[p] = u32(v[p] - true_MX(y,z,sum,k,p,e))
p -= 1
z = v[n-1]
y = v[0] = u32(v[0] - true_MX(y,z,sum,k,p,e))
sum = u32(sum - DELTA)
return True
return False
# dis.dis(MX2)
res = [761104570, 1033127419, 3729026053, 795718415]
key = struct.unpack("<IIII", b"1111222233334444")
flag = btea(res, -4, key)
flag = struct.pack("<IIII", res[0], res[1], res[2], res[3])
print(flag)
<aside> 📁
Attachment && Source:
</aside>
// Views/LockScreen/LockViewModel.swift
// Views/LockScreen/LockViewModel.swift
import SwiftUI
class LockViewModel: ObservableObject {
@Published var nodePositions: [CGPoint] = []
@Published var selectedNodes: [Int] = []
@Published var currentPosition: CGPoint?
@Published var message = "Please draw an unlock pattern"
@Published var isAuthenticated = false
var connectedNodes: [CGPoint] {
selectedNodes.map { nodePositions[$0] }
}
var current_key: UInt64 = 0
var current_idx = 0
var current_flag = ""
var weight_idx = 0
var key_all: [UInt64] = []
let weight: [UInt64] = [10564859903, 880404991, 67723460, 4837390, 322492, 20155, 1185, 65, 3]
let target_all: [UInt64] = [14599243207, 60002986363, 14560544087, 22317571743, 68376508563, 25193127450, 12705425144, 26108707849, 33544207307, 81606770389, 22317571743, 77570576608, 86640094905, 81606770389, 14560544087, 12705425144, 14560544087, 22317571743, 68376508563, 81606770389, 14587757950, 12705425144, 48799590969, 24155668525, 81606770389, 22505151037, 26108707849, 48760891849, 81606770389, 14248371181, 60362888175, 48995988997, 15440949078]
let map_list: [Character: String] = [
"L": "1478",
"i": "582",
"l": "147",
"a": "2147859",
"c": "6589",
"{": "248",
"1": "125879",
"0": "2587413",
"S": "321456987",
"_": "789",
"/": "27",
"\\\\": "18",
"N": "7415963",
"d": "825479",
"w": "1475963",
"n": "4758",
"3": "23598",
"f": "21745",
"r": "475",
"y": "14257",
"o": "58746",
"u": "47869",
"}": "157",
"2": "125478",
"4": "14528",
"5": "214587",
"6": "458712",
"7": "1238",
"9": "893256",
"A": "74269",
"G": "32478965",
"V": "183",
"T": "13258",
"P": "45217",
"M": "7418369",
"W": "1472963",
"Q": "42689",
"H": "1745639",
"K": "24718"
]
// private let correctPassword = "1478"
private let nodeSize: CGFloat = 60
private let gridSize: CGFloat = 300
init() {
calculateNodePositions()
}
private func calculateNodePositions() {
let padding = (gridSize - nodeSize * 3) / 4
for row in 0..<3 {
for col in 0..<3 {
let x = padding * CGFloat(col + 1) + nodeSize * CGFloat(col) + nodeSize/2
let y = padding * CGFloat(row + 1) + nodeSize * CGFloat(row) + nodeSize/2
nodePositions.append(CGPoint(x: x, y: y))
}
}
}
func handleDragChange(_ position: CGPoint) {
currentPosition = position
for (index, node) in nodePositions.enumerated() {
let distance = hypot(position.x - node.x, position.y - node.y)
if distance < nodeSize && !selectedNodes.contains(index) {
selectedNodes.append(index)
// Editing
current_key += (weight[weight_idx] * UInt64(index + 1))
weight_idx += 1
break
}
}
}
func handleDragEnd() {
var password = selectedNodes.map { String($0 + 1) }.joined()
key_all.append(current_key)
print(current_idx)
print(current_key)
message = "Keep Going! You Just Need " + String(target_all.count-index) + " times"
// TODO
current_idx += 1
current_key = 0
weight_idx = 0
for (key,val) in map_list{
if val == password{
current_flag += String(key)
}
}
print(current_flag)
if current_idx == target_all.count {
print("start_check")
var check = 1
for index in key_all.indices{
if target_all[index] != key_all[index]{
check = 0
}
}
if check == 0 {
message = "Wrong..LetGoAndMovOn!"
}
else{
message = "Right! flag is :" + current_flag
}
current_idx += 1
current_key = 0
weight_idx = 0
current_flag = ""
}
resetNodes()
}
private func resetNodes() {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
withAnimation {
self.selectedNodes.removeAll()
self.currentPosition = nil
// if !self.isAuthenticated {
// self.message = "Please draw an unlock pattern"
// }
}
}
}
private func provideHapticFeedback() {
let generator = UINotificationFeedbackGenerator()
generator.notificationOccurred(.error)
}
}

Yes it worked