The goal of this blag post is to get a legacy software used by teachers to run under Linux. The software is used to put grades of pupils into a database.
<img fetchpriority="high" decoding="async" src="https://blag.nullteilerfrei.de/wp-content/uploads/2026/03/Schild-Notenmodul-1024x652.png" alt="Screenshot of running application" width="1024" height="652" class="aligncenter size-large" />
<a href="https://blag.nullteilerfrei.de/2026/03/15/helping-move-the-german-educational-system-to-linux/#more-6172" class="more-link">Would you like to know more?</a>
In this blob post, I will describe how I wrote a config extractor for obfuscated JavaScript-based GootLoader component. The hard part of automating the config extraction is the obfuscation: the C2 servers are just plain text in the last stage. All <a href="https://github.com/larsborn/gootloader-babel-deobfuscator">code is on Github</a> if you are just interested in that.
# Intro
A fellow Cyberian struppigel recently released <a href="https://samplepedia.cc/">Samplepedia</a>, a platform were people can drop SHA256 hashes of files with a description and an analysis goal and some other metadata. My understanding is that the goal is to finally have a place to find interesting malware to analyze, a question I get asked a lot when teaching reverse engineering.
Naturally I picked a task myself and decided to do one involve JavaScript, something I don't have a lot of expose to as a reverse engineer (I do have some exposure to it as a forward engineer, but that's a different story). The sample in question is ``1bc77b013c83b5b075c3d3c403da330178477843fc2d8326d90e495a61fbb01f`` and the task is:
> Create a static C2 extractor that uses abstract syntax tree transformations with Babel. You can use astexplorer.net as helper tool.
I was particularly intrigued because I've recently seen other people be extremely successful leveraging "normal dev tooling" in the JavaScript ecosystem to tackle challenges with JavaScript-based malware.
<a href="https://blag.nullteilerfrei.de/2026/01/18/use-babel-to-deobfuscate-javascript-malware/#more-6162" class="more-link">Would you like to know more?</a>
# Summary
Malware uses InnoSetup and hides the installer password in obfuscated, compiled PascalScript, but this article is not about this malware.
I abandoned all sanity and wrote an emulator for this arcane language to recover them.
This article is about the process of reverse engineering the runtime:
While IFPS has an open-source interpreter, I found it easier to recover the logic from existing code by assuming that it works.
If you found this because you are interested in Inno Setup stuff and IFPS: The emulator and archive parsing is open source and [implemented in BinaryRefinery](https://binref.github.io/lib/inno/index.html).
Feel free to file issues on GitHub for issues, questions, or feature requests.
<a href="https://blag.nullteilerfrei.de/2025/03/30/complete-first-correct-later-writing-a-pascal-script-emulator/#more-6030" class="more-link">Do you want to know more?</a>
I've tried upgrading a laptop to Windows 11, with an existing VeraCrypt system encryption. I decrypted the partition and removed the system encryption first, then tried the update. It always failed with error 0xc190012e. I couldn't find any details about that error code, or helpful advice. I've tried a bunch of generic stuff (upgrading via either Windows Update or Windows Update Assistant, `chkdsk`, `sfc /scannow`, safe mode with networking, and probably some more), but none of these resolved the issue.
tldr: Delete or rename `C:\Users\Default\AppData\Local\Microsoft\Windows\WSUS\SetupConfig.ini` after removing the system encryption.
A few more words about this:
There's a file `C:\Users\Default\AppData\Local\Microsoft\Windows\WSUS\SetupConfig.ini` (<a href="https://learn.microsoft.com/en-us/windows-hardware/manufacture/desktop/windows-setup-automation-overview?view=windows-11">documentation</a>) which VeraCrypt creates when encrypting the system partition, with the following content (for me at least):
```
[SetupConfig]
ReflectDrivers="C:\Program Files\VeraCrypt"
PostOOBE=C:\ProgramData\VeraCrypt\SetupComplete.cmd
```
After removing system encryption, the file only contains
```
[SetupConfig]
```
but still exists.
Removing or renaming this file allowed me to upgrade and re-enable system encryption without further problems. I've tried it on another (desktop) machine to verify - ran into the exact same problem, which went away after removing that file.
<em>Edit: I've opened a <a href="https://github.com/veracrypt/VeraCrypt/issues/1483">bug report at VeraCrypt's repo</a>.</em>
I've been using a Co2 sensor for a long time now to remind myself to regularly open the window and vent the used up air. With my recently newly acquired hobby of home automation, I wanted to get its data into HomeAssistant to _automatically_ switch on the ventilation. This blag post documents my journey with a couple of detours and a bit of hacking.
<a href="https://blag.nullteilerfrei.de/2025/01/17/my-quest-for-a-reliable-co2-sensor-in-home-assistant/#more-5989" class="more-link">Do you want to know more?</a>
I've recently fallen into the rabbit hole of using home-automation. The obvious choice is Home Assistant and I've enjoyed the journey a lot so far. This blag post documents my process of automating all those crappy remote controlled gadget that accumulated in the house: that cheap light bulb, those cheap fairy lights, or that cheap LED strip … you might know what I mean. The remotes come in all forms and sizes and are often quite thin, powered by a button cell, and work occasionally. I have a literal box full of them.
<a href="https://blag.nullteilerfrei.de/2024/12/22/broadlink-rm4-pro-in-home-assistant-without-the-app/#more-5954" class="more-link">Do you want to know more?</a>
I have a Windows VM that can has an internet connection that acts as a tunnel into a VPN, and this VM is supposed to share this internet connection with the host. This works perfectly in principle: On that Windows VM, I have a network interface named `Outbound` which represents the VPN connection, and an interface named `Gateway` which represents the connection that is shared with the host. I use Windows Internet Connection Sharing (ICS) to provide routing to the `Gateway` interface via `Outbound`. For reasons unknown to me, however, this sometimes just breaks and the only way to get it running again is to simply disable ICS on the `Outbound` interface and re-enable it. Doing this through the UI every time became annoying, so I researched how to do it programmatically. There is [a great superuser answer](https://superuser.com/a/649183/222330) which provides _almost_ all the details you need, but not quite.
<a href="https://blag.nullteilerfrei.de/2024/06/26/programmatic-internet-connection-sharing/#more-5917" class="more-link">Do you want to know more?</a>
When you write a lot of Python that is intended to mimic arithmetic that was taken from C or assembly code, one giant advantage of Python sometimes becomes a burden: The integers are arbitrary precision, and the "built-in" wrapping of fixed-width integer types is something that has to be added manually, sometimes a truly arduous process. I recently had a thought about how this can be done in a slightly less agonizing way. This is a prototype and might require some more extension in the future, but I am pretty happy with it already. The idea is to implement a decorator that will use Python's `ast` module to add a bitmask to each arithmetic operation that occurs in the code of a decorated function. Here's the code:
```python
import ast
import functools
import inspect
def masked(mask: int):
'''
Convert arithmetic operations that occur within the decorated function body in such a way that
the result is reduced using the given bitmask. All additions, subtractions, multiplications,
left shifts, and taking powers is augmented by introducing a bitwise and with the given mask.
'''
def decorator(function):
code = inspect.getsource(function)
tree = ast.parse(code, mode='exec')
class Postprocessor(ast.NodeTransformer):
name = None
def visit_BinOp(self, node: ast.BinOp):
node = self.generic_visit(node)
if not isinstance(node.op, (ast.Add, ast.Mult, ast.Sub, ast.LShift, ast.Pow)):
return node
return ast.BinOp(node, ast.BitAnd(), ast.Constant(mask))
def visit_FunctionDef(self, node: ast.FunctionDef):
node = self.generic_visit(node)
if self.name is None:
node.name = self.name = F'__wrapped_{node.name}'
for k in range(len(node.decorator_list)):
if node.decorator_list[k].func.id == masked.__name__:
del node.decorator_list[:k + 1]
break
return node
pp = Postprocessor()
fixed = ast.fix_missing_locations(pp.visit(tree))
eval(compile(fixed, function.__code__.co_filename, 'exec'))
return functools.wraps(function)(eval(pp.name))
return decorator
```
With this decorator, you can now write:
```
@masked(0xFFFF)
def test(x: int) -> int:
return x * 0xBAAD
```
This will leave all code exactly as it is except for the binary operations involving addition, multiplication, subtraction, left shift, and computing powers - all of these are converted to having one additional bitwise and operation on top.
I'm known for my Ghidra stand-up comedy routines. In order to make them enjoyable for everyone in the room, the font size better be not as tiny as it normally is when you do your day-to-day reverse engineering. There are two places to consider:
1. menus, dialogs, etc.
2. specialized components like the assembly listing view and the decompiler
# Font Size Override
The first can be adjusted by editing the `launch.properties` file, which is normally located in the `support` directory within your Ghidra directory (`C:\Users\born\Programs\ghidra_11.0.1_PUBLIC\support\launch.properties` on my machine). Just add the following somewhere in the file to adjust the font size to 23:
```
VMARGS=-Dfont.size.override=23
```
# Components
In order to adjust the font size in dialogs, I recommend searching the settings dialog ("Edit" -> "Tool Options") for "font". By the time of writing this involved the following entries (I use 12 for small and 18 for presentations):
* Byte Viewer
* Console
* Decompiler -> Display
* Graph -> Program Graph Display Options -> Miscellaneous
* Listing Display
This blag post covers scanning the Ghidra virtual memory with YARA.
<a href="https://blag.nullteilerfrei.de/2023/10/21/ghidra-yara-scanning/#more-5903" class="more-link">Do you want to know more?</a>
This is a quick one: If you are living in Germany but enjoy using a US keyboard layout — for one reason or another — I recommend using the EU keyboard layout instead.
<a href="https://blag.nullteilerfrei.de/2023/10/19/advertisement-for-the-eu-keyboard-layout/#more-5901" class="more-link">Do you want to know more?</a>
NSQ is an awesome and extremely simple distributed message queue. You can simply use it by publishing messages — that is arbitrary text, I often use JSON — on a so called "topic". A second process can than attach to a topic to consume messages on a so called "channel". Each messages is forwarded into each channel (at least once). This blag post covers deployment of NSQ in the simplest scenario: one box running everything.
<a href="https://blag.nullteilerfrei.de/2023/10/13/install-nsq-on-debian-with-init-d-and-nginx/#more-5889" class="more-link">Do you want to know more?</a>
Assume you did all the proper and mature building steps for your Symfony application. You have a build environment independent of your development environment. You really made sure all the environment variables like `COMPOSER_NO_DEV` and `NODE_ENV` are set correctly without getting the double negatives confused. And you execute `composer`, `yarn`, and whatnot with all the good switches like `--no-dev`, `--frozen-lockfile`, and `--production`. But you still get the following error message:
```text
Attempted to load class "WebProfilerBundle" from namespace "Symfony\Bundle\WebProfilerBundle".
Did you forget a "use" statement for another namespace?
```
Then you _might_ have forgotten to set `APP_ENV="prod"` on the **production system**. It of course makes sense when you think about it. But it always does, once you figured out. Anyway: I hope this helps a fellow traveler at some point in the future! ❤️