Challenge Description

Challenge Design Notes
I had the pleasure to author a challenge for L3AK CTF 26 for forensics. While making this challenge, i thought of making a standard DFIR investigate qsn via qsn based on a memory dump and maybe a packet capture analysis, tbh nothing out of the blue, and the malware was actually originally a c++ VM based obsfuscator, and thats pretty much it. After that all the news started to come out of how AI agents are getting 0 days buy just propmpting etcetc and i thought of something to make the challenge clanker proof and genuinly fun for humans. And so it began ...
The first issues and thoughts were was on trying to make the c++ VM hard, i wanted to use some mordern c++ features and something leaning into property based heavily compiled type encryption. This repo https://github.com/JustasMasiulis/xorstr was basically what i was looking for and my thoughts here were to use NTTP string literals to adapt this repo into my own funny fork if any Agent managed to understand that is was based on that .[https://blog.ganets.ky/StaticString/] (C++20) to kill the macro. The literal becomes an NTTP value, it enters the mangled name of the instantiation and as per Itanium ABI[https://itanium-cxx-abi.github.io/cxx-abi/abi.html] class-type NTTP values encode their bytes something so that the AI cannot see that it uses xorstr's model to encrypt directly and would have to think a bit
This worked out quite well before testing, but i wasn't satisfied since AI could just write a dissassembler with miasm or lift it with remill and mcsema and defeat the obsfucation. My main issue here was figuring out writing an symbolic execution script with angr or miasm could be trivial for ai so there's that as well [https://miasm.re/blog/2016/09/03/zeusvm_analysis.html] something like this could be made up for this challenge trivially by a smart harness, last thing i wanted was to throw the binary into ida pro and let it manage all the reversing, after all there were many good ida plugins made by smarter people than me to figure and resolve all these techniques : https://github.com/kweatherman/ida_missinglink etc etc which would be easy to identify ...
Then while talking with my friends valium and cortexauth about reversing a VM, valium sent a binary to reverse while we were arguing about dynamic debugging frameworks to devirtualise a VM based crackme and he said something which caught my interest

and this part especially

Ive had heard about path explosion but had no idea how does that work internally so i read the paper he sent
https://www.sciopen.com/article/10.32604/cmc.2025.062743
Think about what a symbolic enginedoes- it explores all paths through a program, building path constraints at each branch which we can narrow down to find the constrainsts to reach the path we need, which can be a flag or some basic block wtv.
Now write Collatz as a loop;
while (n != 1) {
if (n % 2 == 0) n = n / 2;
else n = 3 * n + 1;
}
Now u can use any symbolic engine of your wish to symbolically execute this with n as an unconstrained symbolic integer. At every iteration you fork on n % 2 == 0. The path tree branches infinitely, to determine whether a path terminates (reaches n == 1), you'd need to prove the Collatz conjecture for that class of inputs
This is what is called as an path explosion since collatz has no mergeable structure because the even/odd paths feed back into each other nonlinearly
Now how could i do this to twarth all the sloppers?? Enter liquidhaskell and n ranked polymorphics.
https://ucsd-progsys.github.io/liquidhaskell/
This was as close i could emulate the avoidance of being solved by symbolic solvers because of how haskell is built, these decompilers today are very alien to haskells decompilation, read this for more info - https://www.reddit.com/r/haskell/comments/iqz0l/reverse_engineering_of_compiled_haskell/
GHC compiles to Spineless Tagless G-machine, and the ret and jumps are evaluated to into heap-allocated closures via an info pointer and the best part is the stack is owned by the GHC and "returning" is entering a continuation closure so this will get resolved into a blob of indirect jumps which we will see in the writeup.
Now the best ways to form logic about reversing is to xref the data blocks and see how the call with the arguments etc and for this haskell can help, an unevaluated expression is a thunk which is a heap object whose info pointer initially points to the evaluation code. First entry evaluates it, then overwrites the info pointer to point at the value. So the same indirect jump target mutates at runtime
Terminating the basic blocks were intresting, for ida this jmp [rax+offset] with no recoverable jump table will not be correct. case on an algebraic type enters the scrutinee, which then jumps to the correct case alternative via a return vector or tagged pointer (if im not mistaken)
And the best part for the last no C ABI frames.
Now the malware was done and i was still thinking about the later parts of the DFIR challenge, i mainly tend to avoid DFIR challenge's with only the answer as the flag because it dosent built an intuition for the player to how to see and look at things. Some time ago I played r3kaCTF and the theme was about a game dev loosing their files, I have some experince is modding fromsoftware games and loves darksouls remastered and maybe it was time to bring those together to make a CTF challenge.
Since the modding utils and tools dont have an MCP's and people can't just vibe it but need to actually look up a youtube guide or read some reddit comments , join a the community discord for these stuff and read and find out like how CTF's are meant to be , seemed like a good way ahead to make a challenge than a PCAP sorta way . These are the main tools needed
Smithbox: a multi-purpose GUI tool with support for most FromSoftware games. Primarily for editing maps, parameters and text.
WitchyBND: a unpacking/packing tool used to unpack encrypted or compressed files inside BNDs, the generic archive format for game files.
Soulstruct: a multi-purpose GUI tool with a focus on Dark Souls, Dark Souls: Remastered and Bloodborne. Edits maps, events, parameters, text, and ESD.
DarkScript: a GUI tool for editing EMEVD files, Fromsoft's event script format.
And there are a lot of video guides which are helpful on what to do - https://www.youtube.com/watch?v=V76X6tDEK7Q, this one specifically is a really nice video using the OP's own tool called soulstruct.
During the CTF bloopers
1) One of the players came close till the 6th qsn out of 7, and was having trouble parsing everything by hand or AI(this team got banned for slopping on another challenge), the encrypted files were not parsed properly it seems, maybe they should have gooled how to parse havoc engine file formats and these is an entire repo based on what to do exactly for each files...
https://github.com/soulsmods/Paramdex for the info if they wanted to give it to the clanker or maybe a whole entire library for https://github.com/soulsmods/SoulsFormatsNEXT ..

2) We had a team who got till the 7th qsn and was trying to parse the files again but they actually were right, i didnt ask them for any solve scripts because this was the first time someone was this close to doing it, so i helped them by givng the link for https://github.com/soulsmods/SoulsFormatsNEXT and asked them to see what they were doing wrong for the files and they could have gotten the first blood for the challenge so i hyped them up.
But he said we wont submit the flag? and uhm and didnt bother to reply for the next minutes, and it should go to people who were hardworking ... And he said he spent around 88 million output tokens on GPT 5.6 sol high combined with a army of agents who were talking to each other and trying to figure it out, the exact agent setup used to cross talk were
But credit where credit is due , 100 points for honesty
agentic setup used to reverse the malware
3) This one team did actually use their agents to rebuilt the repos mentioned above when they could have just googled and made a sort of python library to interact with the files,and they got all the parts except the coordinates correct which was so close bc no one made it till far. Since they were using python to interact it had miscl they forgot about the endiness or their library was trying to extract the files but not keeping the refernce model valid for the attackers placed model, it's hard to know if you're writing your own library with AI, but 20 minutues of googling was all it needs.
Eventually this team also got banned for slopping.
https://github.com/katalash/DSLuaDecompiler - Lua/HavokScript decompiler for Dark Souls/Bloodborne/Sekiro AI lua files and Havok behavior scripts (hks)
https://github.com/soulsmods/DSMapStudio - A standalone map/level editor for Demon's Souls, Dark Souls 1/2/3, Bloodborne, Sekiro, and Elden Ring
Writeup :)
We are given 3 things in the handout, eml a zipped protected folder called evidence and a memory dump.
Q1: What is the password of Natsume's Windows account?
windows stores passwords ans NTLM and lets use volatility for extracting the hash.

nastume's hash is: natsume 1001 aad3b435b51404eeaad3b435b51404ee afe5244a02f5443c41893a5dd8593ef1
we can now crack this with crackstation.

the password is sukii.
Q2: What is the name of the malicious executable found on Natsume's machine?
First instinct is pslist, see what's running.

Only notepad.exe stands out as user-launched.
Luckily there's another forensic artifact that can help us called shimcahce. The Shimcache (AppCompatCache) is a kernel-maintained list in the registry that tracks files accessed by the OS loader. It persists across reboots and process exits.
Vol3's windows.shimcachemem plugin reads the in-memory shimcache (more complete than the on-disk registry hive since unflushed entries are still in kernel memory):

Order 7 shows C:\Users\natsume\Desktop\ModCollabTool.exe with Last Modified 2026-07-11 17:23:36 UTC. That's our malware.
Answer: ModCollabTool.exe
Shimcache lives at SYSTEM\CurrentControlSet\Control\SessionManager\AppCompatCache\AppCompatCache. Windows writes it to the registry only on shutdown, so if you parse the on-disk hive from a live machine you'll miss everything from the current session. The memory dump catches what hasn't been flushed yet, which is why windows.shimcachemem finds ModCollabTool even though it ran and exited.
Note: on Windows 10, shimcache records a file the moment it's visible to the OS loader, not necessarily when it actually ran. Browsing to the Desktop in Explorer can shim an exe you never double-clicked. So shimcache proves the file existed on disk and was seen by the system, not that it executed. For execution proof we need BAM or prefetch.
Q3: What password did Natsume use to extract the tool sent by the attacker?
This qsn was based on this amazing paper written by Abdelrhman Mohamed and Azr43lKn1ght.
Notepad is open in the pslist, Natsume wrote the password down there.
We'll use MemProcFS, it mounts a memory dump as a virtual filesystem, exposing processes, threads, and memory regions as browsable files and directories. It needs Dokany (a Windows kernel filesystem driver) installed as a dependency grab it from https://github.com/dokan-dev/dokany/releases.
But without the system's DTB (Directory Table Base / CR3 register), MemProcFS can't locate the Windows kernel and fails:

DTB is the physical address of the page directory (how the CPU translates virtual addresses. MemProcFS needs it to walk the page tables and reconstruct process memory.) Get it from Vol3's windows.info:

DTB = 0x1ad000. Pass it explicitly:
MemProcFS.exe -device memdump.raw -mount M: -dtb 0x1ad000

Mounted at M:\. MemProcFS synthesizes a full kernel dump at M:\memory.dmp. Open that in WinDbg - gives us a real kernel debugging session with full cross-process memory access:

Find notepad and switch into its virtual address space:
!process 0 0 notepad.exe
.process /p /r ffff9b0e630c3080

Now enumerate notepad's heap to understand the memory layout. !heap -a walks every heap chunk and prints its address, size, and flags:

u can see that busy extra user_flag chunks stand out, Windows sets user_flag on heap blocks that carry application-defined metadata, like text buffer allocations. These are where Notepad stores its content:


Navigate the Memory pane to the address of that chunk and the password is there in UTF-16LE:

There is another approach - Volatility 2 has a vadtree plugin that can render the VAD tree as a dot graph. Sadly it did not work on this dump. Windows on build 19041 encrypts the KDBG structure, so Vol2's profile-based symbol resolution fails completely - it cannot locate EPROCESS or walk the VAD tree. Vol3 avoids this by using type layers instead of KDBG, which is why we went with windows.vadinfo above.
A VAD (Virtual Address Descriptor) is Windows' per-process map of virtual memory ranges. It is the higher-level tree Windows keeps so it knows which address ranges belong to mapped images, private heaps, stacks, memory-mapped files, and so on. In a VAD tree, lower virtual address ranges sit on the left, higher ranges sit on the right, and every node describes a range plus metadata like protection and backing file.
So the workflow is: use vadinfo/vadtree to understand the process ranges, then use MemProcFS/WinDbg to step into the specific private region and read the user data from memory. The tree gives structure; the heap chunk gives the password.
To help visualise what the VAD tree actually looks like and how this forensic process works, here is a short animation:
This isnt entirely accurate at all, but the focus is on VAD as a whole and how the vad plugin works.
Answer: vX#82mK$pL@3nR!qZ9wT
Alternate solution (credit houssem0x1) - instead of reading heap content via WinDbg, dump the process memory and run strings on it directly, keeping the UTF-16LE encoding Windows uses in mind:
But in a real DFIR scenario , you shouldnt verify just by strings , as it's not a definite proof that the password is and was used by the uses , then you should only use the windbg method mentioned in the paper , string can help with maybe get context around the stack or registers lead you to look where's next . That's all .
Q4: What is the master encryption key used by ModCollabTool?
So lets analyse the file now, we have the zip password from solving qsn 3
scaning on virustotal shows that it's packed by upx so unpack it.

Now lets open up ida and try to understand how it encrypts the files.

we can see there are strings for a key, rounds, accumulator state and a module called crypto which is not a standard library
lets look at what crypto state and grep for more functions related to it
upon more investigating we can see this is a haskell binary, so the non standard ABI means ida cannot restructure it properly

after searching for where the crypto modules is used we can find an xor which is using 0xAB as immediate
seeing it more in deapth is a bytecode.

0x140004348: mov dil, [rax+rsi]
0x14000434c: movzx edi, dil
0x140004350: xor rdi, 0ABh
0x140004357: mov [rbx+rsi], dil
0x14000435b: inc rsi
0x14000435e: cmp rsi, rcx
0x140004361: jl 0x140004348
So This is a byte-by-byte XOR deobfuscation loop. Mask = 0xAB.
The source buffer (rax) contains encoded key bytes and the destination (rbx) receives the decoded master key
We need to investigate the surrounding adresses for more crypto module loads

0x140001570: mov rdi, 9E3779B97F4A7C15h
0x14000157E: imul r8, rdi
0x140001582: add r8, rsi
0x140001591: shr rsi, 38h
0x1400015A5: xor r9, r10
0x1400015B8: shl r9, 3
0x1400015B0: shr r11, 5
0x1400015BC: or r9, r11
0x1400015C6: xor r9, r10
that is certainly huge constant lol

there is also another mov rdx, 0DEADBEEFCAFEBABEh + rotateL
we can now look into the xref of the data before this
this is the 0x140A07110: dq offset loc_140858080, GHC W8# info table
the reason why ida cannot decompile it properly here for instance if i press c on the area it will pop out

its bc IDA struggles heavily with GHC-compiled binaries. GHC uses the STG (Spineless Tagless G-machine) runtime instead of standard calling conventions, it uses rbp as a stack pointer, r13 as heap pointer, and jumps between code blocks via jmp [rbp+0] (continuation passing). but IDA expects standard prologues (push rbp; mov rbp, rsp) to identify functions and well GHC has none, so most code stays as raw data blobsd and string xrefs are broken because strings are accessed through CAF closures at runtime, not direct lea references
In memory, a thunk is just a pointer to a closure: a code pointer (info table) + captured variables, when you dereference it, GHC overwrites it with the result (this is called black-holing the thunk gets replaced so it's only evaluated once) bc every value is a thunk (a suspended computation) until forced
we need to move onto dynamic analysis for recovering the VM state
come all the way up here till the bp that the buffer reads in.Step into any of the VM transition states between the accumulator and Vm.crypto and bp on the state , and go onto running and reading the data from the dump and if you do it correctly you will see the master key plaintext xored

then in the dump view check for the bytes

XOR each byte with 0xAB to get the master key:
xK9#mP2$vL7@nQ4&wR1!zT5*bY8^cU3@
Notes
you can also do this via static as well
GHC stores[Word8]literals as flat static closures in.data. Each byte is a qword value interleaved with a repeating info table pointer (0x140858080= GHCW8#constructor) every 16 bytes. Search.dataforAB 00 00 00 00 00 00 00which is tthe XOR mask stored as a boxed Word8. The 32 encoded key bytes should follow immediately after in the same pattern. So we will need to read every 16 bytes, skip the info pointers, XOR with 0xAB.Note GHC CAF evaluation issues
If you set the breakpoint and run, it hits multiple times before any file is even touche bc GHC evaluates Constant Applicative Forms (CAFs) which is top-level values like the key, lazily at program startup, not at the call site which would have been the case if this was a c++ or rust. The XOR deobfuscation runs once during GHC's runtime init to force the CAF, then the result is cached (black-holed) forever. So the "hit we want " is the first one the key is decoded beforemaineven starts. Later hits (there is ) are other ByteStrings going through the same loop.
Q5: What MITRE ATT&CK techniques does ModCollabTool use?
so 2 things happened here, obsfucation of files and encrypted data, the answer can be either of the one's
MITRE ATT&CK:
- T1027 - Obfuscated Files or Information (XOR-encoded key in .data)
- T1486 - Data Encrypted for Impact (encrypts .msb files, appends .l3ak)
Q6: What map contains the attacker's planted artifact?
the question gives us the evidence archive password: s0und_0f_a_s0ul
extract evidence.7z with it. we now have a folder of .l3ak files with hex-obfuscated names

the eml attachment zip also contains filelist.txt - 2073 known Dark Souls map folder filenames. this is our brute-force dictionary to pass the solver to.
how filename obfuscation works:
From reversing ModCollabTool derives a per-file subkey from the master key + original filename + file index (alphabetical DFS order), then XORs the filename bytes against the subkey and hex-encodes:
obfuscated_name = hex(xor(filename_bytes, subkey[:len(filename)])) + ".l3ak"
to recover we need to try every candidate in filelist.txt which the fromsoft modder sent for the skelton, derive its subkey, XOR + hex, check if it matches the .l3ak stem on disk
the logic, as a diagram:
$$ \begin{array}{c} \text{masterKey} \\[4pt] \big\downarrow\ \scriptstyle \text{mixByte over each byte of filename} \\[4pt] (k_1, a_1) \\[4pt] \downarrow\ \scriptstyle \text{mixWord32}(idx) \\[4pt] (k_2, a_2) \\[4pt] \downarrow\ \scriptstyle \text{doRound} \times 16\ \text{(roundConsts, rotl8, xor)} \\[4pt] \text{subkey} \\[4pt] \downarrow \\[4pt] \text{hexName}(fname, subkey)\ \overset{?}{=}\ \text{stem} \\[4pt] \downarrow\ \scriptstyle \text{match} \\[4pt] \text{decryptL3ak}(data, subkey)\ \longrightarrow\ \text{plaintext} \end{array} $$
this is just the pure logic - the solver still needs to walk
enc_dir, read each.l3akfile, and write the plaintext back. implementation is left as an exercise.
after decrypting the files we can see they have the structured location back.
Going back to the email, the attacker mentioned Natsume was working on 2 areas - kiln of the first flame and blighttown. These correspond to m18 and m15.
After recovering the map files, unpack them with UXM Selective Unpack and load them into DSMapStudio to see the assets and how they're related.
Some notes about unpacking and loading the game files;
Inside a map's MSB, many objects - enemies, certain assets, regions - have an entity ID field. It's a number that functions as a stable handle. The event system (EMEVD) is a separate layer of scripts that runs the map's logic: spawning enemies, opening doors, triggering cutscenes, awarding items. Those scripts don't know positions or models - they know entity IDs. An object's entity ID is the name events use to talk about it.
Two consequences: an object no script needs to reference doesn't strictly need an entity ID (decorative scenery, say); and any object you do want a script to react to - a boss whose death unlocks something, a trigger region - must carry a unique entity ID the script targets.
DS map studio expects unpacked files, UXM-unpacked is needed so we need it back, Darksouls predates UXM and unpacks with UDSFM instead; Each level is one MSB file (Map Studio Binary). Open a map and you're editing its MSB, shown as a tree of categories:
Parts - the physical contents: map pieces (geometry), objects/assets, enemies and characters, player spawn points, collision, and navmesh. Most placement work happens here.
Regions - invisible volumes and points: trigger areas, spawn points, warp targets, markers that events reference.
Events - map-level event data and groupings that tie into the game's event scripting.
Every object has a position, rotation, and properties - and many carry an entity ID that the game's event scripts use to address them. Editing a map means selecting objects in the tree or viewport and changing where they are and what they reference.
with that out of the way lets load the map onto studio editor's param index mode.
The qsn asks for the map id, and the ids referencing the two regions are m18_00_00_00 for kiln and m15_00_00_00 for blighttown
so we can try both since the attacker was targeting either based on the eml. m18 is the correct answer.
Q7: The attacker planted something in Gwyn's boss room. Find the collision mesh ID, boss room BGM region event, XYZ coordinates of the model, and the map piece ID.
okies, lets load it up in and see the area,

Load m18 into DSMapStudio and navigate to the main boss area. The boss is Gwyn, Lord of Cinder. When you try to select that model, map studio complains it cannot load the navmesh for the entity - a red highlight shows up on the paramview window bar. So the attacker did something to mess with the boss AI.

Now we need to find where the model is actually trying to load from. In Dark Souls, bosses with cutscenes have 2 models - one animated inside the cutscene, one for the actual fight. Export that model onto the model viewer window and see where the duplicate of that boss AI is located - coordinates pos:383.891,-103.660,202.784. The Y axis is out of range for the ID, so the game can't load it - that's the error.

Open the entity ID for the rest of the values:

mesh is the navmesh the model was actually meant to load, ThinkParamID is the boss AI behavior, then position and map.
if you want to sanity-check a ThinkParamID or param edit like this without repacking the map and relaunching the game every time, DS1RParamReloader does this by hooking the running DSR process (finds it by window title via PropertyHook), then for whatever param you click it builds a small assembly stub, patches in the target address and param name at fixed offsets, allocates RWX memory inside the game process, writes the stub there, and executes it directly - basically manual code-caving to trigger the game's own internal param-reload routine.
Answer: {mesh:h0006B0|ThinkParamID:537000|pos:383.891,-103.660,202.784|map:m18_00_00_00}
There are also multiple ways to do this but i found this one straightforward, but you can google a data sheet of the SFX model which Gwyn uses and refer from it to finish it in a few minutes if navigating map studio is a bit messy.
SFX are the special visual effects that use models and textures to "simulate" glowing, fire, flames and magic. They are located in the sfx folder of the game (you can just download them from the web):
- There is the
FRPG_SfxBnd_CommonEffects.ffxbnd(.dcx)that contains SFX that can appear everywhere which also includes magic. - There are e.g.
FRPG_SfxBnd_m10.ffxbnd(.dcx)which are the map SFX. - There are e.g.
FRPG_SfxBnd_c3471.ffxbnd(.dcx)which are the SFX for special enemies.
FINAL FLAG
L3AK{fr0ms0ftm0dd3r_w4s_h3r3_h0p3_y0u_3nj0y3d_7h3_k1ln_0f_7h3_f1rs7_fl4m3_:3}
Shoutouts
Shoutout and thanks to houssem0x1, suvoni, Andyrew, aresinheaven, 0x1622 and the l3ak forensics department for helping me out and playtesting the challenge <3


References
- JustasMasiulis/xorstr - compile-time string obfuscation library using C++17 constexpr.
- Static Strings as Template Parameters (ganets.ky) - explains using C++20 non-type template parameter (NTTP) string literals so encrypted strings get baked into mangled symbol names instead of macros, making them harder to spot statically.
- Itanium C++ ABI - the name-mangling spec referenced for how class-type NTTP values get encoded byte-for-byte into a symbol name, which is what let the key bytes hide inside the mangled name.
- kweatherman/ida_missinglink - an IDA Pro plugin that helps resolve indirect/virtual calls.
- CMC paper on path explosion (sciopen.com) - background reading on why symbolic execution engines blow up on loops like Collatz, which motivated using a Haskell/GHC-compiled core to resist symbolic solvers.
- LiquidHaskell - refinement-type checker for Haskell; used here less for its verification features and more for leaning into GHC's STG-machine compilation model to defeat standard decompilers.
- LiquidHaskell Tutorial - the hands-on tutorial for learning refinement types in LiquidHaskell, useful for actually getting comfortable with the tooling used to shape the crypto core.
- Reverse Engineering of Compiled Haskell (r/haskell) - discussion on how alien GHC-compiled binaries look to disassemblers/decompilers, which is exactly the problem solvers hit reversing ModCollabTool's crypto routine.
- Soulstruct video guide (YouTube) - walkthrough of using Soulstruct to edit Dark Souls maps/params/events, the tool ecosystem the second half of the challenge (map artifact hunting) is built around.
- soulsmods/Paramdex - reference definitions for FromSoftware's param file formats, needed to correctly parse the game's parameter data rather than guessing field layouts by hand.
- soulsmods/SoulsFormatsNEXT - a library implementing FromSoftware's proprietary file formats (MSB, BND, param, etc); the correct way to parse the game files instead of hand-rolling a broken parser.
- katalash/DSLuaDecompiler - Lua/HavokScript decompiler for Dark Souls/Bloodborne/Sekiro AI and behavior scripts; relevant to teams trying to fully unpack the game's scripting layer.
- soulsmods/DSMapStudio - standalone map/level editor for the Souls games, an alternative to Smithbox for viewing and editing the planted map artifact.
- dokan-dev/dokany - the Windows kernel filesystem driver MemProcFS depends on to mount a memory dump as a browsable virtual filesystem; required before MemProcFS can expose process memory for the WinDbg-based heap analysis in Q3.
- DSMapStudio - MSB map editor with param and text editors; the map-loading tool referenced for opening the decrypted Dark Souls map files in Q6/Q7.
- Smithbox - a fork of DSMapStudio, multi-purpose GUI for editing maps, params, and text across most FromSoftware games.
- Soulstruct - Python-based editor for Params, Text, AI, TalkESD, Maps, and Events; the tool behind the video guide linked above.
- GParamStudio - map lighting (GPARAM) file editor, useful if the planted artifact's surroundings needed lighting inspection.
- NPCParam-SpEffect-Reorganizer - reconfigures NPCParam csv exports for mass-editing without overriding IDs.
- EasySoulsAI - KVP system for easy creation and modification of enemy behaviors, relevant to the Elden Ring AI/event layer tooling ecosystem.
- ER OBJ2HKX - converts OBJ to HKX Elden Ring collision meshes with materials.
- Soulstruct for Blender - Blender plugin to export/import FLVER map pieces and HKX collisions/navmeshes, useful for visually inspecting the planted model geometry.
- SoulsCollisionExport - collision converter to OBJ format (drag-and-drop HKX onto the exe), an alternative path for inspecting the boss-room collision mesh in Q7.
- MapBuddy - helper tool to quickly apply entity/map IDs, relevant to the entity ID concepts explained before Q6.
- cea-sec/miasm - a reverse engineering framework with its own disassembler and IR.
- lifting-bits/remill - a library for lifting machine code to LLVM bitcode, the kind of tool that could be used to lift the obfuscated binary into something more analyzable.
- lifting-bits/mcsema - builds on remill to translate binaries into LLVM bitcode for further analysis, another potential path around the obfuscation the challenge was designed to resist.