solved lake ctf
This commit is contained in:
@@ -9,8 +9,18 @@
|
||||
"anothapk.apk"
|
||||
],
|
||||
[
|
||||
"android",
|
||||
"Source code",
|
||||
"Resources",
|
||||
"anothapk.apk"
|
||||
],
|
||||
[
|
||||
"lib",
|
||||
"Resources",
|
||||
"anothapk.apk"
|
||||
],
|
||||
[
|
||||
"x86_64",
|
||||
"lib",
|
||||
"Resources",
|
||||
"anothapk.apk"
|
||||
],
|
||||
[
|
||||
@@ -34,9 +44,14 @@
|
||||
"anothapk.apk"
|
||||
],
|
||||
[
|
||||
"com.lake.ctf.MainActivity",
|
||||
"com.lake.ctf",
|
||||
"Source code",
|
||||
"lib",
|
||||
"Resources",
|
||||
"anothapk.apk"
|
||||
],
|
||||
[
|
||||
"x86_64",
|
||||
"lib",
|
||||
"Resources",
|
||||
"anothapk.apk"
|
||||
]
|
||||
],
|
||||
@@ -49,12 +64,12 @@
|
||||
"type": "class",
|
||||
"tabPath": "com.lake.ctf.MainActivity",
|
||||
"subPath": "java",
|
||||
"caret": 4782,
|
||||
"caret": 442,
|
||||
"view": {
|
||||
"x": 0,
|
||||
"y": 1365
|
||||
"y": 0
|
||||
},
|
||||
"active": true,
|
||||
"active": false,
|
||||
"pinned": false,
|
||||
"bookmarked": false,
|
||||
"hidden": false
|
||||
@@ -136,7 +151,7 @@
|
||||
"caret": 6022,
|
||||
"view": {
|
||||
"x": 0,
|
||||
"y": 4155
|
||||
"y": 1874
|
||||
},
|
||||
"active": false,
|
||||
"pinned": false,
|
||||
@@ -156,6 +171,20 @@
|
||||
"pinned": false,
|
||||
"bookmarked": false,
|
||||
"hidden": false
|
||||
},
|
||||
{
|
||||
"type": "class",
|
||||
"tabPath": "com.lake.ctf.Check4ec9599fc203d176a301536c2e091a19bc852759b255bd6818810a42c5fed14a",
|
||||
"subPath": "java",
|
||||
"caret": 252,
|
||||
"view": {
|
||||
"x": 0,
|
||||
"y": 4968
|
||||
},
|
||||
"active": true,
|
||||
"pinned": false,
|
||||
"bookmarked": false,
|
||||
"hidden": false
|
||||
}
|
||||
],
|
||||
"cacheDir": "/home/cato/.cache/jadx/projects/anothapk-a709dee63602e12ef9bab1f45e2a8b42",
|
||||
|
||||
Binary file not shown.
@@ -1,6 +0,0 @@
|
||||
def main():
|
||||
print("Hello from android!")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -96,27 +96,21 @@ def extract_logic(class_hash, method_hash, files_map):
|
||||
|
||||
def solve():
|
||||
files_map = load_files()
|
||||
if not files_map: return
|
||||
if not files_map:
|
||||
return
|
||||
|
||||
curr_class = START_CLASS_HASH
|
||||
curr_method = START_METHOD_HASH
|
||||
|
||||
step_count = 0
|
||||
visited = set()
|
||||
|
||||
print(f"[*] Starting traversal for exactly {MAX_STEPS} steps...")
|
||||
|
||||
# UPDATED: Loop exactly MAX_STEPS times
|
||||
for i in range(MAX_STEPS):
|
||||
if not curr_class:
|
||||
print("[!] Chain ended prematurely!")
|
||||
break
|
||||
|
||||
# Loop detection (just in case, though duplicates are mathematically fine)
|
||||
if (curr_class, curr_method) in visited:
|
||||
print(f"[i] Loop detected at step {i+1}. This is fine, just adding redundant constraints.")
|
||||
visited.add((curr_class, curr_method))
|
||||
|
||||
|
||||
step_count += 1
|
||||
|
||||
eq_str, next_class, next_method = extract_logic(curr_class, curr_method, files_map)
|
||||
@@ -126,6 +120,7 @@ def solve():
|
||||
|
||||
try:
|
||||
if "==" in eq_str:
|
||||
print(f"[*] Adding constraint {eq_str}")
|
||||
lhs, rhs = eq_str.split("==")
|
||||
ctx = {'str': MockString()}
|
||||
lhs_expr = eval(lhs.strip(), {}, ctx)
|
||||
@@ -133,7 +128,7 @@ def solve():
|
||||
solver.add(lhs_expr == rhs_val)
|
||||
else:
|
||||
print(f"[!] Warning: Equation format unknown: {eq_str}")
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
print(f"[!] Error parsing equation: {eq_str}")
|
||||
break
|
||||
|
||||
|
||||
Binary file not shown.
193
2025/lake/rev/real_ctf/a_real_ctf_linux/parse_replay.py
Normal file
193
2025/lake/rev/real_ctf/a_real_ctf_linux/parse_replay.py
Normal file
@@ -0,0 +1,193 @@
|
||||
import struct
|
||||
import enum
|
||||
import os
|
||||
|
||||
# --- 1. Enumeration Equivalent ---
|
||||
# Defines the PlayerActions flags from the C# code for easy interpretation.
|
||||
@enum.unique
|
||||
class PlayerActions(enum.Flag):
|
||||
"""
|
||||
Represents the bit flags for player actions/states in a frame.
|
||||
"""
|
||||
None_ = 0
|
||||
Jump = 1
|
||||
Forward = 2
|
||||
Backward = 4
|
||||
Left = 8
|
||||
Right = 0x10
|
||||
TakeFlag = 0x20
|
||||
Collision = 0x80
|
||||
|
||||
# --- 2. Constants and Struct Formats ---
|
||||
|
||||
# The magic number used to identify the file format (72848253210177uL)
|
||||
EXPECTED_MAGIC_NUMBER = 72848253210177
|
||||
|
||||
# Structure of the file header (16 bytes):
|
||||
# < : Little-endian
|
||||
# Q : unsigned long long (8 bytes, for Magic Number)
|
||||
# H : unsigned short (2 bytes, for Version)
|
||||
# I : unsigned int (4 bytes, for Level ID)
|
||||
# H : unsigned short (2 bytes, for Frame Count)
|
||||
HEADER_FORMAT = "<Q H I H"
|
||||
HEADER_SIZE = struct.calcsize(HEADER_FORMAT) # Should be 16 bytes
|
||||
|
||||
# Structure of a single frame record (29 bytes):
|
||||
# < : Little-endian
|
||||
# 3 x f: 3 floats (Vector3 position: x, y, z) - 12 bytes
|
||||
# 4 x f: 4 floats (Quaternion rotation: x, y, z, w) - 16 bytes
|
||||
# B : unsigned char (1 byte, for PlayerActions enum)
|
||||
# Total size: 29 bytes
|
||||
FRAME_FORMAT = "<f f f f f f f B"
|
||||
FRAME_SIZE = struct.calcsize(FRAME_FORMAT) # Should be 29 bytes
|
||||
|
||||
# --- 3. Parsing Functions ---
|
||||
|
||||
def parse_replay_file(file_path):
|
||||
"""
|
||||
Reads a binary replay file, parses the header and all frame data,
|
||||
and returns the structured data.
|
||||
"""
|
||||
print(f"Attempting to parse file: {file_path}")
|
||||
|
||||
if not os.path.exists(file_path):
|
||||
print(f"Error: File not found at {file_path}")
|
||||
return None
|
||||
|
||||
with open(file_path, "rb") as f:
|
||||
# --- A. Read and Parse Header (16 bytes) ---
|
||||
header_data = f.read(HEADER_SIZE)
|
||||
if len(header_data) < HEADER_SIZE:
|
||||
print("Error: File is too short to contain a valid header.")
|
||||
return None
|
||||
|
||||
# Unpack the header data
|
||||
magic_number, version, level_id, frame_count = struct.unpack(
|
||||
HEADER_FORMAT, header_data
|
||||
)
|
||||
|
||||
# Validate Magic Number
|
||||
if magic_number != EXPECTED_MAGIC_NUMBER:
|
||||
# Note: Python interprets 72848253210177uL as a standard integer.
|
||||
# If the C# ulong was a large negative number, the interpretation might differ,
|
||||
# but for this positive constant, it should match.
|
||||
print(f"Error: Invalid magic number. Expected {EXPECTED_MAGIC_NUMBER}, got {magic_number}.")
|
||||
return None
|
||||
|
||||
# Store header information
|
||||
replay_data = {
|
||||
"magic_number": magic_number,
|
||||
"version": version,
|
||||
"level_id": level_id,
|
||||
"frame_count": frame_count,
|
||||
"frames": []
|
||||
}
|
||||
|
||||
print(f"Header successfully parsed. Version: {version}, Level ID: {level_id}, Frames: {frame_count}")
|
||||
|
||||
# --- B. Read and Parse Frames ---
|
||||
for i in range(frame_count):
|
||||
frame_bytes = f.read(FRAME_SIZE)
|
||||
|
||||
if len(frame_bytes) < FRAME_SIZE:
|
||||
print(f"Warning: Expected {frame_count} frames, but file ended after {i} frames.")
|
||||
break
|
||||
|
||||
# Unpack the frame data
|
||||
(
|
||||
pos_x, pos_y, pos_z,
|
||||
rot_x, rot_y, rot_z, rot_w,
|
||||
actions_byte
|
||||
) = struct.unpack(FRAME_FORMAT, frame_bytes)
|
||||
|
||||
# Convert the action byte into readable flag enumeration
|
||||
actions = PlayerActions(actions_byte)
|
||||
|
||||
frame_record = {
|
||||
"frame_index": i,
|
||||
"position": {"x": pos_x, "y": pos_y, "z": pos_z},
|
||||
"rotation": {"x": rot_x, "y": rot_y, "z": rot_z, "w": rot_w},
|
||||
"actions_byte": actions_byte,
|
||||
"actions": [action.name for action in actions if action is not PlayerActions.None_]
|
||||
}
|
||||
replay_data["frames"].append(frame_record)
|
||||
|
||||
print(f"Successfully parsed {len(replay_data['frames'])}/{frame_count} frames.")
|
||||
return replay_data
|
||||
|
||||
# --- 4. Example Usage and Data Simulation ---
|
||||
|
||||
def create_mock_replay_bytes(level_id, frames_to_generate):
|
||||
"""
|
||||
Simulates the C# replayToBytes function to generate a mock byte array
|
||||
for testing the parser without an actual .bin file.
|
||||
"""
|
||||
# 1. Header (Magic, Version=1, LevelID, FrameCount)
|
||||
header_data = struct.pack(
|
||||
HEADER_FORMAT,
|
||||
EXPECTED_MAGIC_NUMBER,
|
||||
1, # Version
|
||||
level_id,
|
||||
len(frames_to_generate) # Frame Count
|
||||
)
|
||||
|
||||
# 2. Frames
|
||||
frame_data = b''
|
||||
for i, frame in enumerate(frames_to_generate):
|
||||
pos = frame.get("position", (0.0, 0.0, 0.0))
|
||||
rot = frame.get("rotation", (0.0, 0.0, 0.0, 1.0))
|
||||
|
||||
# Retrieve the action value, which is a PlayerActions enum object
|
||||
actions_value = frame.get("actions_byte", 0)
|
||||
|
||||
# FIX: Explicitly convert the enum object (or the default integer 0)
|
||||
# to a standard integer, as required by struct.pack for the 'B' format.
|
||||
actions_byte = int(actions_value)
|
||||
|
||||
frame_data += struct.pack(
|
||||
FRAME_FORMAT,
|
||||
pos[0], pos[1], pos[2],
|
||||
rot[0], rot[1], rot[2], rot[3],
|
||||
actions_byte # Now guaranteed to be an integer
|
||||
)
|
||||
|
||||
return header_data + frame_data
|
||||
|
||||
if __name__ == "__main__":
|
||||
# --- Generate Mock Data ---
|
||||
MOCK_LEVEL_ID = 42
|
||||
|
||||
# Define a list of frame data (position, rotation, actions_byte)
|
||||
mock_frames = [
|
||||
# Frame 0: Start position, Idle
|
||||
{"position": (0.0, 1.0, 0.0), "actions_byte": PlayerActions.None_},
|
||||
# Frame 1: Moving Forward and Jumping
|
||||
{"position": (0.5, 1.0, 0.0), "actions_byte": PlayerActions.Forward | PlayerActions.Jump},
|
||||
# Frame 2: Moving Right
|
||||
{"position": (1.0, 1.0, 0.5), "actions_byte": PlayerActions.Right},
|
||||
# Frame 3: Collision and Taking Flag
|
||||
{"position": (10.0, 5.0, 10.0), "actions_byte": PlayerActions.Collision | PlayerActions.TakeFlag},
|
||||
]
|
||||
|
||||
#mock_binary_content = create_mock_replay_bytes(MOCK_LEVEL_ID, mock_frames)
|
||||
#MOCK_FILE_PATH = "mock_replay.bin"
|
||||
|
||||
# Write mock data to a file for the parser to read
|
||||
#print(f"Generating mock binary file: {MOCK_FILE_PATH}")
|
||||
#with open(MOCK_FILE_PATH, "wb") as f:
|
||||
#f.write(mock_binary_content)
|
||||
|
||||
# --- Run Parser on Mock File ---
|
||||
parsed_replay = parse_replay_file("./good_run_patched")
|
||||
|
||||
if parsed_replay:
|
||||
print("\n--- PARSED REPLAY DATA (SUMMARY) ---")
|
||||
print(f"File Version: {parsed_replay['version']}")
|
||||
print(f"Level ID: {parsed_replay['level_id']}")
|
||||
print(f"Total Frames: {len(parsed_replay['frames'])}")
|
||||
|
||||
print("\n--- SAMPLE FRAMES ---")
|
||||
for i in range(min(5, len(parsed_replay['frames']))):
|
||||
frame = parsed_replay['frames'][i]
|
||||
print(f"Frame {frame['frame_index']:<2} | Pos: ({frame['position']['x']:.2f}, {frame['position']['y']:.2f}, {frame['position']['z']:.2f}) | Actions: {frame['actions']}")
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user