Hack Yourself: Reversing the Program That Came Without a Manual
An interactive essay on reading the world, and myself, the way I read a malware sample: a program with no manual, a malware report on that program with six findings (Fun included), a triage window, a trace log, a breakpoint and a git history. The skills I thought were obsolete still transfer, once I learn to export them.

Short on time?
The one-minute version
This post takes about 20 minutes to read, so here is the whole idea in about one minute. You are welcome to stop after this card.
- 0x01The AI wave has made many people anxious, and the data is calmer than the online threads, with one real exception: a 19% employment gap for 22- to 25-year-olds in the most AI-exposed jobs. In 2025, AI was the stated reason for only about 4.5% of announced US job cuts.
- 0x04Instead of feeding that anxiety, I got curious and reverse engineered myself. I treated myself as a program with no manual and wrote a malware report on it, with six findings: Inner critic, Learning, Health, Tinkering, Friends and Fun.
- 0x06Then watch the program run: log your inputs and outputs for a day, and look at which ones move your energy, mood, focus, connection and joy.
- 0x07Before you react to something, set a breakpoint: one breath, or one sentence about how you feel, and only then decide what to do.
- 0x08Treat each change like a commit by keeping it small and explaining why you made it. If the change does not work, revert it, because a failed experiment is nothing to hide.
- 0x09The skills I thought AI had made obsolete were the ones I ended up using on myself. They travel best when you name the principle behind them and apply it somewhere new. The part you can show is smaller and easier to check than the part you can claim: a write-up, a detection rule, a small tool someone still uses.
If you have two more minutes, try one of these:
Open the triage window Trace a day
That is the whole idea. If this is where you stop, thank you for reading, take care of yourself, and go play something tonight.
My job is taking apart things that were built to stay hidden. For years I have opened malicious programs, the kind that steal passwords or hide inside other software, and worked out what they do with no manual and no help from whoever wrote them. It remains the most enjoyable work I know, because it takes all of my attention and all of my curiosity at once, a bit like a hard Rubik's cube, where you hold the whole puzzle in your head, turn one piece and watch what moves.
The same method works far away from any computer. The YouTuber LabCoatz spent a year rebuilding Coca-Cola from taste tests and a mass spectrometer. People who drink it regularly could not reliably taste the difference.

The targets are different every time, and the method never changes.
- Observe.
- Form a hypothesis.
- Test it.
- Write down what you learn.
For years I only used it on programs. I took malware apart every day and never thought to point the method at anything else, even though everyone uses it when nobody has explained how something works. A child takes a toy car apart to see what makes the wheels turn, someone presses every button on a new washing machine until the right programme starts, and a traveller works out a foreign metro map without reading a word of the language.
The cook is, in my mind, the easiest case to explain, because the evidence is in the dish. A sauce tastes flat, so they add salt and pepper, and taste again. Still flat, so they add acid, a squeeze of lemon, and taste again. Now it is too sharp, so they add a little fat or sugar, and taste again. If it needs heat, chilli and other spices go in near the end, because heat changes what the earlier adjustments taste like. They are tasting forward until the dish matches the one they had in mind. The recipe is what they write down afterwards.
A doctor narrows a different kind of search, and if you have watched House, you have seen it on the whiteboard. House and his team take the patient's full history first: when the pain started, where it moves, what makes it worse, what else is going on. The answers become a differential, the working list of causes that could explain the symptoms. Each test is chosen to strike out the likeliest entries rather than to confirm the first idea, and each result narrows the list until one explanation is left standing.
We run the same loop with people, and it shows most when you are not good at it. I am not, or at least I believe I am not, and I try to get a little better at it every day. Without much experience there is no instinct to fall back on, so you work from the outside. You say something and watch what comes back: a shorter answer, a pause, a laugh, or a laugh that arrives a second too late. A sentence that sounded neutral in your head comes out blunt. A question asked too quickly sounds like an interrogation. So you change the words, the tone or the pace, and you try again on the next exchange.
Some people do this without thinking and read a room the way a good cook tastes a sauce. The rest of us do it on purpose, one reaction at a time.
None of this looks like reverse engineering, which is why I missed the connection for so long. A cook, a doctor and someone nervous at a dinner table are all reading a system from the outside and working back to the part that explains the behaviour.
So I pointed the method at myself. The only way forward I could see was to study myself with the patience I give to a malware sample.
In the end, I was both the program and the person writing its manual.
The words of my job optional glossary, open it if a word trips you up
This post borrows vocabulary from programming and malware analysis. You do not need to learn it first. Skim the list, and come back whenever a word later in the text feels unfamiliar.
What a program is made of
One familiar example runs through this part: the alarm clock app on a phone.
- program
- A list of instructions that a computer follows exactly, one step at a time. The alarm clock app is one: it is a few thousand instructions that decide what the phone does at 07:00.
- function
- One named job inside the program. The alarm app has a job called "ring", another called "snooze" and another called "save the time you typed". Each can be read and changed on its own.
- call
- When one job asks another to do its part. At 07:00 the alarm job calls "ring", and "ring" calls the speaker job. Calls are how small jobs combine into a big result.
- public, private
- Public functions are the ones the outside world may use, like the snooze button. Private functions are for internal use, like the way the clock counts seconds. Nobody outside can call a private function, although everything inside may depend on it.
- import
- Something the program borrows instead of building. The alarm app does not make its own clock or speaker, it asks the phone for them.
- export
- The opposite: a job the program offers to others. When your calendar app can start an alarm for you, it is using something the alarm app exports.
- input, output
- What goes in and what comes out. The time you type is an input, and the sound at 07:00 is an output.
- bug
- A step that produces the wrong result, such as an alarm that rings at 06:00 when you set 07:00. It is a fault in the instructions and not a verdict on the person who set it.
- log
- A plain list of what happened and when, written as it happens, such as "07:00 alarm rang, 07:01 snoozed".
- patch
- A fix to one step, with the rest of the program left alone.
What I do with one
- malware
- A program made to harm or spy on whoever runs it, for example one that quietly copies saved passwords. It is what I study for a living.
- sample
- One copy of a program kept for study, the way a lab keeps a specimen. In this post, "the sample" also means me.
- source code, binary
- Source code is the readable version a programmer writes, with names and notes. The binary is the finished version that the computer actually runs, which is only numbers. When you install the alarm app you get the binary and never the notes.
- reverse engineering
- Working out how something was built by taking it apart and watching what it does, without the author's notes. A mechanic listening to an engine does a version of it.
- read it, run it
- Two ways to study a program. You can read the file without starting it, which is safe and slow, or you can watch it run and see what it does, which is fast and shows more.
- debugger, breakpoint
- A debugger is a tool for running a program in slow motion. A breakpoint is a spot where you tell it to freeze, so you can look at everything at that exact moment before letting it continue.
- register
- A tiny slot inside the processor that holds the number it is working on right now. In this post I use the word as a gauge that goes up and down.
- detection rule
- A short written description of what a known bad file looks like, so that a scanner can spot the next copy. The tool for writing them is called YARA.
- git, commit, revert
- Git is the tool that keeps every version of a project's files. A commit is one saved change with a note on why, and a revert undoes one change by adding a new one, so the history stays.
- mod
- A change made to an existing game or program by someone outside the team that built it. Some well-known games started this way.
It has become the most interesting project I have started since the pandemic, and this post is the write-up. It runs in the order of a real analysis, and every part is introduced by a numbered divider of its own, so you always know where you are.
- Read the file without running it. That gives the report (0x03 and 0x04) and the detection rule (0x05).
- Watch it run, with a log (0x06) and a breakpoint (0x07).
- Change it, one small patch at a time (0x08), then check what survives the move (0x09).
- Write the release notes (0x0A) and leave something for the next version (0x0B).
Along the way there are a handful of interactive tools to try. Each one is optional, the data inside is an example, and anything you type stays in your browser. A word with a dotted underline explains itself when you hover over it.
Why I started
I wrote before about the daily flood of AI announcements, and it has not slowed since. Many people around me feel lost, as if everything they studied for years has quietly stopped counting. Some have left their jobs to try a different direction, and some have been let go.
Others are watching their companies rebuild themselves around AI one piece at a time, and they are wondering where they fit when the only role that still feels safe is the one directing the tools.
They are far from alone. Among US workers, 48% now think AI might make some or all of their duties obsolete, up from 38% in 2023 and the highest share the survey has recorded.
The internet does not make it easier. A lot of what circulates about AI and jobs is wrong, from misread studies and numbers a chatbot invented to stories pushed on purpose to unsettle people. Reacting to them is normal, but following them down the rabbit hole is the trap, because a feed rewards whatever keeps you scrolling, whether it is true or not.
The most careful evidence I have found comes from payroll records, which count who actually got paid each month, so a mood or a press release cannot move them. Across millions of US workers tracked through June 2026, there is no economy-wide displacement. There is, however, a gap at the entrance. Employment for workers aged 22 to 25 in the most AI-exposed jobs sits 19% below where it would be if it had kept pace with their less-exposed peers, while experienced workers show no comparable gap. The change is happening through hiring rather than firing, and a missing first job is hard to see, because it never appears in any count.
The wider picture is calmer than the mood, because market conditions, closures, restructuring and cost-cutting were each named more often than AI as the reason for 2025 cuts.
The noise vs the numbers Challenger · US announced job cuts · 2025
job.cuts / 1,206,374AI is the reason people remember, and the smallest of the five named reasons on the chart. Same year, same source, two framings.
Data view. AI is 4.5% of the 1.2M cuts. Market conditions, closures and restructuring are all bigger.
*Remainder after the five categories Challenger names above: many smaller reasons combined, not a single category. Challenger counts announced cuts and the reasons employers state, not net job losses.
Source Challenger, Gray & Christmas, Challenger Report, December 2025 (8 January 2026), Table 4.
Data table: 2025 cuts by reason
| Reason | Cuts | Share |
|---|---|---|
| Market / economic conditions | 253,206 | 21.0% |
| Store / unit closings | 191,480 | 15.9% |
| Restructuring | 133,611 | 11.1% |
| Cost-cutting | 81,392 | 6.7% |
| AI | 54,836 | 4.5% |
| All other reasons (remainder) | 491,849 | 40.8% |
| Total | 1,206,374 | 100% |
None of this helps much if you are the person who lost the job, because a number can be true and still have nothing to say to someone in a room with a manager who has practised the sentence.
What I keep noticing, though, is that the fear runs through people who look stable, people who post confidently and people whose job titles sound safe. If it is happening to all of them, it is not happening because of something you did wrong.
As far as I can see, AI is rarely the whole cause. It is the trigger most people share right now, and it works like fuel. It lands on whatever was already unstable, a job that never felt secure, a confidence that was always borrowed, a year that was already too heavy, and it makes all of it burn faster. That is why this post spends less time on the headlines and more on the program they land on.
In my eyes, we are entering a new technological revolution, and every earlier one changed work on a massive scale. The ground is moving, but it is not moving at random. It moves where a task can be handed to a tool, where a junior's work can be checked by a model, and where a company can delay a hire and still ship. Those are patterns, and a pattern can be studied, which is the only useful optimism I have found.
Underneath the headlines sit the questions most of us would rather not say out loud.
- Am I too late?
- Did I choose the wrong field?
- Is the thing I am good at still worth being good at?
- What do I learn next, and who will hire me for it?
The fear shrinks when it becomes specific. "AI will replace me" is not a problem anyone can solve, while "this part of my job is a lookup, this part is a judgement, this part is trust" is a list you can work through. So I did what I always do with something I do not understand yet. I got curious, and I started taking it apart.
Hack, the old meaning
Before opening anything, I had to settle what I meant by hack, because I wanted the curiosity and not the damage. "Hack yourself" can sound aggressive, but the word did not start that way. In the MIT model railroad club of the late 1950s, a hack was a clever piece of work on the club's layout, usually late at night and rarely necessary. The Jargon File still defines a hacker as someone who enjoys exploring the details of programmable systems and stretching their capabilities, and it keeps a separate word, cracker, for someone who breaks in.

That is the meaning I have in mind. You take a system apart because you are curious, and then you make it work a little better.
A program with no manual
With that in mind, I imagined myself as a program. This program has no manual, no comments and no changelog, and none of its parts carry a name (a programmer would say it has no symbols). It is a binary, the finished file a computer runs long after the readable version was thrown away, and it starts every morning and produces behaviour.
For a reverser, a binary without documentation is the normal starting point. I have spent years opening files that did not want to be opened: stealers, loaders, miners and the packers that hide them, and later games that were never meant to be taken apart. None of them came with a README. Every one started the same way, with something running and nobody to explain why. The first hours, when nothing makes sense yet, are still my favourite part of the job.
ME.exe, taken apart
no symbols · no manualAn interactive code window. Select a function to read its listing, then use Rename to give it a meaningful name. Run analysis names all of them at once.
Click a function to read it. Rename it when the behaviour makes sense. Nothing here leaves your browser.
No symbols is not the same as no meaning. It just means the names are still yours to write.
Without JavaScript, here is the fully renamed listing. Same bytes, friendlier labels.
main_loop:
004017F0 55 push ebp
004017F1 8B EC mov ebp, esp
004017F3 E8 08 F8 FF FF call wake_up
004017F8 E8 A3 F8 FF FF call self_compassion
004017FD E8 FE F9 FF FF call learn_something
00401802 E8 30 FB FF FF call build_for_fun
00401807 E8 94 FB FF FF call call_friend
0040180C E8 8F FB FF FF call move_body
00401811 E8 1A FF FF FF call play
00401816 E8 E5 FB FF FF call sleep
0040181B EB D6 jmp short main_loop
; still in development — there is always a next versionwake_up0x401000self_compassion0x4010A0learn_something0x401200build_for_fun0x401337call_friend0x4013A0sleep0x401400write_it_down0x401480read_the_room0x401510say_no0x4015A0ask_for_help0x401620move_body0x4016A0play0x401730main_loop0x4017F0
This may sound like a joke, and part of it is. The obvious objection is that a person is not a program, and that looking at yourself like one must feel cold. In practice it worked the other way round, because when you analyse a sample, you are never angry at it for behaving strangely, or almost never. VMProtect (a protector that rewrites code for an imaginary processor of its own) is the exception, and so is the .NET loader with a dozen stages, each one unpacking the next as if the author were paid by the layer. The rest of the time you are curious, and every unusual behaviour becomes a clue.
Take the thought "I am useless now". Read as a fact, it decides how the evening goes. Read as output, "the program is printing I am useless now again", it becomes a line you can look at without obeying it. Psychologists call this move cognitive defusion, and it comes from acceptance and commitment therapy (ACT), which teaches you to notice a thought as a thought instead of treating it as a fact. The usual advice is to argue with the thought, gather the evidence and write a fairer version, and that is a large part of cognitive behavioural therapy (CBT).
At two in the morning, arguing with your own head mostly starts a second argument. Defusion skips that debate, so the line stays in the log while you stop executing it.
The oldest exercise is simpler than it sounds. Over a century ago, the psychologist Edward Titchener noticed that a word said out loud fast enough, "milk, milk, milk", turns into a sound. In a study of eight people, doing this with a negative word about themselves reduced discomfort and believability more than distraction or trying to control the thought. Eight is small, but the trick costs almost nothing to try.
The method rests on two things, which are curiosity instead of a verdict and enough distance to read a sentence about yourself as output rather than as truth. It is also everything I needed before opening the file, because the first thing a program with no manual does is tell you what it thinks of you.
Report: ME.exe
What it thinks of you stays a mood until you take it apart, so I opened the file. When a new sample lands on my desk, I write the same report every time. What is the file? What does it borrow from outside? Which strings does it carry? What does each part do? How do I recognise it next time? This time the sample was me.
I wrote it in the third person. "I failed" sounds like a confession. "The sample failed" sounds like a bug, and a bug has a line number.
What the program needs from outside matters more than its code. A reverser calls this list the imports, and it is often the most revealing part of a file, because a program can only do what it is able to borrow. Sleep comes from the body, and replies come from other people. Every day, four drives (learn(), tinker(), friends() and fun()) compete for a fixed attention budget, and whatever asks first gets served. When an import like sleep is missing, the program keeps running instead of crashing with a clear error, and it fails later, somewhere else.
The sentences it keeps saying to itself are the embarrassing part. A reverser calls them strings, and they are usually the fastest way to understand a sample, because they are the one part of a file written in plain language.
You can run the same triage on your copy below. Tick the strings you have heard yourself say this week, and sort them by what needs attention first. The indicators tab turns your week into a short list of warning signs. The strings are examples, and nothing leaves your browser.
$ strings -n 8 ME.exe | head
0x0041A0 critic() this is wrong 0x0042C8 learn() save for later 0x0043F0 health() five hours is fine 0x004518 tinker() maybe next weekend 0x004640 friends() I will reply properly tomorrow 0x004768 fun() is this productive?
JavaScript is off, so this is a fixed sample of strings. With JavaScript you can tick the ones you recognise and the window builds the sections, imports, indicators and a YARA rule for your week.
Here are the six findings, in the order the report found them. Each one points at a part and ends with a patch line, and those six lines are what the rest of this post keeps coming back to.
critic() Inner critic
critic() is private, so nobody else ever reads it, but its output leaks into everything else. Every time something goes wrong, the sample calls the inner critic. A good error handler logs the fault and moves on. This one writes a verdict about the programmer.
// the inner critic, in sketch
int handle(task_t task)
{
for (attempt = 0; attempt < 3; attempt++) {
if (run(task) == OK)
return OK; // success: logged nowhere
verdict(self, "this is wrong"); // line 213
}
log(task, "failed"); // the fault, no line number
return FAIL; // and no fix() to go with it
}
// private, but called from everywhere
void verdict(person_t *who, const char *msg)
{
who->confidence -= 1; // per attempt, not per fault
schedule(replay, msg, "02:00"); // re-run at night, unprompted
}
The bug is on line 213. The verdict sits inside the retry loop, so one timeout that fails three attempts earns three sentences, and a small slip gets punished like a big one. Moving the line was quick, but finding it took much longer, because every time I looked back at a mistake, the only note I had left myself was "this is wrong", and that note never says which line to move.

A review that only hands out verdicts also makes the next review something to dread, so you stop looking and the fault stays in the file.
People who are as kind to themselves after a failed test as they would be to a friend are more willing to study for the retake, not less, and across 20 study samples they report less depression, anxiety and stress.
So now every review has to name one specific fix and say nothing about the person. If I cannot find a fix, the review is dropped and only the verdict goes, while the fault stays in the log.
patch verdict() deleted from the retry loop. One fault, one log line, one fix attached.
learn() Learning
learn() decides what gets in and what stays. It keeps a queue of things to read, watch and finish, and the queue grows faster than it empties. A long queue feels like progress.
// the reading list, as code
queue_t reading_list = { books, papers, talks, courses };
void learn(void)
{
while (queue_len(reading_list) > 0) {
item = peek(reading_list); // never pops
reread(item); // feels like progress
highlight(item, YELLOW); // feels like more progress
if (found_something_new())
push(reading_list, it); // grows faster than it empties
}
// no test here: nothing checks what stayed
}
// recall(): present, never called
bool recall(item_t item)
{
close(item);
return write_from_blank_page(item);
}
The loop above re-reads the top of the list forever and never checks what stayed. Language study is where this showed most clearly. In a learning app, every word arrives next to a picture and four possible answers, so after a few months I could pick the right one almost every time. A real menu, however, has no pictures and no answer choices, and the person waiting behind me does not care how long my streak is. The app had trained recognition (spotting the right answer when someone shows it to you), while the menu asked for recall (producing the answer from nothing).
The research on this gap is unusually clear. In a 2008 study, students learned forty Swahili words, and a week later the ones who kept studying a word but stopped testing themselves on it remembered about 36%, while the ones who kept testing themselves remembered about 80%. Re-reading makes a page feel familiar, and familiar is easy to mistake for knowing. Recall forces the brain to rebuild the answer, and that effort is what makes it stay.
The same trap hides in colour-coded notes made for a "visual learner", which have no good evidence behind them. What works is plainer and less pleasant. I read a chapter once, close it, and write down everything I remember on a blank page before I check what I missed. It feels slower than highlighting, but the gaps on that page are the only honest list of what I have not learned yet.
patch Input queue capped. recall() wired into the build as a test that runs after every chapter.
health() Health
health() is the private check that every drive depends on, because each drive needs a body that can think. It reads the body's fields and returns a score made of fuel minus the interest on sleep debt, tension and load. When it returns a bad value, nothing reports a health error. What shows up instead is a shorter temper, a rushed decision, a message sent a bit too fast. Each one blames itself, so the real cause stays hidden a level below. Reversers know this pattern well, because the crash is rarely where the fault is. You trace back to whoever supplied the value, and that is why this function is worth checking before blaming anything else.
// health(), what it needs
sleep() the nightly recharge
move() a body that gets used, not only carried
eat() fuel, ideally cooked rather than grabbed
listen() warnings the body sends before it fails
check() an outside reading: a doctor, a blood test
// and what it returns
int health(body_t *b)
{
int score = b->fuel;
score -= interest(b->sleep_debt); // compounds every short night
score -= b->tension + b->load;
return score; // a low value logs nothing
}
// sleep(), before the patch
void sleep(void)
{
hours(5); // five hours used to be enough
episode(1); // one more, it is only midnight
}
Sleep goes first, because every other function reads from it. Mine ran on habits that were easy to start and quietly expensive to keep: five-hour nights, because five hours used to be enough, one more episode at midnight, and a catch-up plan, "I will sleep at the weekend", which sounds sensible and tends to repeat.
Short nights feel free, and that is the trick. In a fourteen-day experiment with 48 healthy adults, people held to four or six hours in bed slowly lost sharpness on attention tasks, while their own sleepiness ratings barely moved after the first few days. They felt fine and performed worse. It works in the other direction too, because a steady, slightly longer night is one of the cheapest upgrades there is.
Movement is the import this file drops first when the week gets busy, which is a pity, because a 2024 review of 218 trials found that walking, jogging and strength training each improved mood by a moderate amount. Food works the same way, only more quietly: one meal a day that is cooked and eaten away from the keyboard tends to pull other things up with it.
Listening is where the body gets a say. It usually mentions things early and politely, through a tight jaw by mid-afternoon, a headache on the same weekday, or waking at 04:20 with nothing to blame. A single one means nothing, but the same one three weeks in a row is worth a note. While general health checks for people with no symptoms make little difference, a visit booked because a warning keeps repeating is the useful one. For mood, NICE lists talking therapies, guided self-help and group exercise among the first options, so asking for help does not have to mean medication on day one.

patch health() returns better values. The wake time stays put, the phone charges outside the bedroom, the body gets moved and fed on purpose, and a warning that repeats gets an outside reading.
tinker() Tinkering
tinker() builds things nobody asked for. It takes apart radios, writes scripts to rename files, and once spent three weekends teaching a kettle to play two notes.
kettle.log
run 1 6h00 £0.00 relay clicks, does not latch
run 2 4h00 £4.20 wrong pitch: the delay loop was timed for 60 Hz mains
run 3 5h40 second note lands 40 ms late
parts relay from a doorbell that never worked, a board,
speaker from a radio taken apart at fourteen
known relay sticks below 10 °C; second note slightly flat;
do_it_again(), which nobody should read
Run 3 still lands the second note 40 ms late, and it is still slightly flat, and I count that as shipped.
When this section stops, nothing breaks. It keeps reading and watching, and it stops making. What goes missing is the belief that it can still build things. Flow needs a clear next step, quick feedback and a task slightly too hard (Sweeny et al., 2026), and having a hobby with no deliverable attached is one of the simplest ways to get it back (Mak et al., 2023).

Open the smallest unfinished thing on your drive and make it one step less broken. No new project, no rewrite, no domain.
patch One unfinished thing opened, made one step less broken, and closed.
friends() Friends
friends() is the network code, which covers every connection to another person. Most of the traffic is tiny, a photo or a single line. Mine treats every reply like a report, so every reply feels expensive. Here is one thread, logged like network traffic, with arrows for which way each message went.
friends.log, one thread
03 Oct 09:04 <- photo: a greyhound in a plastic cone
"he's fine. just dramatic."
read, no reply
24 Oct 23:41 -> "alive. what has he eaten now."
24 Oct <-> call, 41 min, mostly about the dog
Twenty-one days without sending a reply, and the other side never complained and never gave up on the thread. One line costs nothing, and every day of waiting makes the next line harder to send.
People reliably expect a conversation to go worse than it does. The call I dreaded lasted 41 minutes, mostly about the dog, and I would take that trade again. Long-term studies like the Harvard Study of Adult Development and the Surgeon General's advisory say plenty about relationships and health, but the fifteen-cigarettes figure for loneliness never made me reply. A dog in a cone did.
patch One line sent today.
fun() Fun
Since what fun() produces cannot be read from the file, here is what it does when it runs.
Games are my main fuel, and Persona 5 Royal is the one I keep coming back to. It runs for more than a hundred hours, spread over months of evenings, and when the credits roll you sit there with an empty feeling, the kind you only get when something was good enough to miss. Expedition 33 did that to me again in 2025, just not quite as hard. That empty feeling is the opposite of the NOPs below, because it shows that every call was running.
Games are the biggest input, although not the only one. Anime and TV shows do the same thing in smaller doses, with a few characters to follow for weeks and an episode waiting at the end of a long day. Cooking is the taste-and-adjust loop from the cook above, with the bonus that you get to eat the result, and so does whoever is at the table.
Modding the Resident Evil games I keep replaying uses the skills from my job with none of its deadlines. The gym is the newest addition, and the strangest one, because it is where the head finally goes quiet. There is no room to think about anything else while you lift, and a weight that felt heavy last month slowly stops being heavy.
None of it is big, because the fun sits in the details, and when a month goes badly, the details are the first thing to disappear.
// an ordinary evening, during a bad month
void evening(void)
{
play(game); // still runs, the last call standing
nop(); // taste(dinner): eaten, not tasted
nop(); // watch(episode): playing, not watched
nop(); // cook(for_two)
nop(); // lift(); log(weight)
nop(); // notice(progress)
scroll(phone); // fills the gaps, returns nothing
} // nothing crashes, so nothing reports
Nobody decides this, because while something else takes all the attention, the brain patches those calls out on its own. The dinner still gets eaten and the episode still plays, but nothing registers, and because nothing crashes, you do not notice. From the outside the function looks intact. I only saw the NOPs when I sat down and read it the way I would read a sample.
Putting the bytes back is slower than taking them out, and it happens one call at a time, through a dish cooked properly instead of eaten over the keyboard, an episode watched without a phone in your hand, a note of what you lifted so next month has something to compare against.
patch Original bytes restored. Dinner, episodes and the gym are back in the call graph, the map of what calls what.
Detection
Every malware report ends the same way, with a rule to catch the sample the next time it turns up. In my world that is usually YARA, a few strings and a condition, and when a file matches, someone goes and looks. This report is about me, so I wrote one about me.
rule ME_exe_2026_10
{
meta:
description = "the analyst, on a bad week"
response = "stop and check the function the hit points to"
strings:
$critic = "this is wrong" // critic(), before the patch
$behind = "I am behind on everything" // health()
$wake = "woke at 04:20" // health()
$friends = "he's fine. just dramatic." // friends(), still unanswered
$taste = "food that tastes of nothing" // fun(), before the patch
condition:
2 of them
}
Read from the top, the rule lists five sentences and fires when any two of them turn up in the same week. Most of the rule is sentences from the head, but two lines come from the body, and the body usually speaks first: waking at four for no reason, a tight jaw at the desk, eyes burning by eleven, food that tastes of nothing, a short answer to someone who did not deserve it. All of them arrive long before the head is ready to admit that a function is running low.
Anyone who has snoozed the same phone alarm every morning knows what happens to an alert that fires every day and gets ignored. People stop reading it, and then they stop seeing it. A body trains you the same way. Ignore the signal long enough and it fades into the background, until it comes back louder: a cold that lasts three weeks, a hobby that stopped being fun, a friend you have not heard from in months.
So when the rule fires, I treat it like any other alert and go and look. The string says which function is short, and the fix is usually small and a bit boring, such as an early night, the one-line message, an evening handed back to a game. The triage window earlier builds the same list from your own week, if you want yours.
If you keep only one function, keep fun(). There will never be a week with spare time for it.
A rule only recognises patterns someone has already written down. It says nothing about behaviour nobody has named yet, and most of what matters is still unnamed. For that you stop reading the file and watch it run.
Watching it run
So far I had only read the file, which a reverser calls static analysis. The report says what each part is supposed to do, and the rule says what a bad week looks like, but neither shows the program actually running. For that, the standard approach is dynamic analysis, which means you provide inputs, log the outputs, and then work out how the two are connected.
I applied the same approach to myself. The inputs were sleep, news, social feeds, people, work and projects, while the outputs were my mood, my energy, my focus, the work I shipped and the way I spoke to the people I care about.

The loop is the same one behavioural activation uses. When a mood drops, the obvious response is to stop doing things, and stopping removes the small evidence that anything can change. A bad morning cancels the walk, the missing walk makes the afternoon flatter, and the flat afternoon cancels the evening plans. Behavioural activation reverses that order, so you plan one small action, run it, and let the result update the mood rather than waiting for the mood to permit the action. It is recommended for depression in UK clinical guidance, and in a large head-to-head trial it held up against cognitive therapy and medication. The cognitive model behind CBT keeps a similar record: what happened, what you assumed, what the evidence shows, and what you will try next.
Pick a day below, run it, and watch which inputs move the registers, the five counters the tracer keeps for energy, mood, focus, connection and joy.
Dynamic analysis of a day
api monitor · pid 1337 (you)Pick what today actually contained, then run the tracer. It does not judge. It just writes down which registers moved.
No inputs yet. Select a chip and run the tracer.
JavaScript is off, so here is a still example of the tracer instead of the controls. This is an example day, not mine.
- 07:02:11.418 [0x55c0a010] openat("sleep(8h)", O_RDONLY) = 3 E+14 M+8 F+10
- 07:41:52.207 [0x55c0a124] nanosleep(18000s) = -EINTR E−14 M−6 F−12
- 08:14:03.612 [0x55c0a2d0] connect(outside, {sun, air}) = 0 E+5 M+9 F+4
- 10:02:47.109 [0x55c0a3f8] write(stdout, "shipped", 7) = 7 E+6 M+11 F+7 C+2
- 11:26:19.884 [0x55c0a44c] read(feed, buf, 4096) = 4096 E−6 M−10 F−8 C−3
- 12:40:52.021 [0x55c0a5a0] sendmsg(friend, "how are you") = 11 E+3 M+10 F+2 C+13
- 14:11:33.731 [0x55c0a6c4] pread(book, buf, 1200) = 1200 E+1 M+5 F+7 J+1
- 16:31:08.452 [0x55c0a7e8] ioctl(joy, PLAY, {no_reason}) = 0 E+2 M+9 F+3 J+12
Made-up weights, tune them to your own logs. Each register starts at 50, adds the weights and clamps to 0–100. The numbers are a demo, not a measurement: the useful part is writing down what moved.
Show the made-up weights
| Input | E | M | F | C | J |
|---|---|---|---|---|---|
| Slept 8h | +14 | +8 | +10 | 0 | 0 |
| Slept 5h | −14 | −6 | −12 | 0 | 0 |
| Doomscrolled AI news | −6 | −10 | −8 | −3 | −3 |
| Walked outside | +5 | +9 | +4 | 0 | +2 |
| Shipped a small thing | +6 | +11 | +7 | +2 | +2 |
| Talked to a friend | +3 | +10 | +2 | +13 | +3 |
| Skipped lunch | −9 | −5 | −7 | 0 | 0 |
| Worked on a side project | +7 | +9 | +12 | +1 | +2 |
| Compared myself on LinkedIn | −4 | −13 | −5 | −4 | −3 |
| Learned something new | +2 | +7 | +9 | +1 | +1 |
| Helped someone | +1 | +8 | +2 | +9 | +2 |
| Worked late again | −8 | +2 | +6 | −4 | −2 |
| Read for 20 minutes | +1 | +5 | +7 | 0 | +1 |
| Played a game for no reason | +2 | +9 | +3 | 0 | +12 |
| Laughed until it hurt | +3 | +10 | 0 | +6 | +13 |
| Listened to an album start to finish | 0 | +7 | +2 | 0 | +9 |
| Did something silly with a friend | +2 | +8 | 0 | +7 | +11 |
Nothing leaves your browser. The chips only change numbers on this page.
What the log showed
What surprised me most was how much was working. In the example day above, most inputs push a register up. When you only listen to the noise, you only notice bugs. When I logged mine, I found features I had never documented. The Jargon File even has a joke for this, defining a feature as a bug that has been documented, and half of what I called flaws turned out to be behaviour I had never written down.
A log does not stop you sending the sharp reply at 09:30, though. Seeing where a function fails and catching it while it fails are two different jobs, and the second one needs a breakpoint.
The breakpoint
You already know what a breakpoint is, even if you have never opened a debugger. Pausing a game to check your health before the next room is a breakpoint, and so is a time-out in a match, or hovering over the send button to read a message one last time.
Programmers use the same idea on purpose. A debugger lets them run a program slowly and look inside it, and a breakpoint is a stop sign placed on one specific line. When the program reaches that line, it freezes with everything still in place, so you can read what it is holding, see what it is about to do, and then let it carry on from exactly where it stopped.
The moments I regret are reactions rather than decisions, such as the verdict on line 213, the sharp answer before ten or one more episode at midnight. Reactions run fast, because a message, a headline or a comment arrives and a reply is already on its way before you have decided anything. The useful part is the gap between the event and the response, however short, because that gap is where the breakpoint goes.
While the program is frozen, a debugger lets you read its variables, the values it is holding at that moment. A person in the middle of a reaction is holding four: the feeling (naming it in a word or two can take some of its intensity away), the story you are telling about what just happened, what you actually know, and the options you have. In a hurry they blur into one, but once they are separated they come apart quickly.
The widget below runs the same pause on six ordinary moments. Press Step to go one stage at a time, and compare it with the run that has no breakpoint.
Pause the moment
break · inspect · choose · continueAn email that stings
- What happens
- An email questions your work in front of the whole team, and the next line to run is
reply_all(). - Without a breakpoint
- You type a sharp answer within two minutes and send it. The thread grows, and you spend the afternoon replaying it.
- With a breakpoint
- You take one breath and write down four things. The feeling is irritated and a little embarrassed. The story is that they are doubting you in public. The fact is that the message only asks which version of a file is correct. The options are to answer with the file name, ask a question or reply after lunch.
- A possible result
- A two-line reply, and the thread ends.
JavaScript is off, so this is a single worked example. With JavaScript you can step through six everyday situations.
Pick a moment, then press Step to pause it.
Without a breakpoint
runs
With a breakpoint
paused at
- break
- inspect
- choose
- continue
These are example runs for ordinary situations, not measurements and not my day. Nothing here is saved or sent anywhere.
A breakpoint does not need to be dramatic. It can be one breath with your hands off the keyboard, a glass of water, or a sentence typed into a notes app instead of the reply box. You will forget on some days, and the program will run straight through the line you were worried about. Go back and read what happened afterwards, repair what needs repairing, and place the stop sign one line earlier next time. For me it turned out to be the most useful technique of all: one breath before the angry reply, the fourth thread of the evening or the yes I have no time for, and the evening goes differently.
A breakpoint buys one second in which the program is paused and nothing has happened yet. What you do with that second is a change, and a change has to be shipped.
Small patches, no rewrite
The six patch lines in the report were already commits. In git (the tool programmers use to track every version of their code), a commit is one saved change with a short message explaining why, and each of those patches changed one thing and could be undone without touching the others. I had been working that way at my desk for years, just never on myself.
"Get healthier" is a resolution. "When I close the laptop, I put on my shoes and walk for ten minutes" is a commit, because it is one change tied to one cue, with a reason you could write in the message. Psychologists call the second kind an implementation intention (Gollwitzer & Sheeran, 2006; 2024). It works because the decision is made in advance, so when the laptop closes there is nothing left to decide.
If a change does not work, I revert it. In git that adds a commit which undoes the old one, so the history stays, and a failed experiment becomes a line that says "tried this, learned that". The next commit is better for it.
git log --graph --me
example history · not my real logSmall changes, one commit at a time. Click a commit to open its diff, and revert it if it did not work. Add your own at the top of the log and watch it land on the graph.
Every commit is progress you can see in the log.
a1b0c1d
init: first boot
- f3a1d8edocs: write the method down so future me can read it Learning
- 4c9e0b1chore: tidy the week before the release Friends
- 8d2b6a5feat: ship the mod loader for my own habits Tinkering
- 1a7f9c3fix: charge the phone outside the bedroom Health
- 6b8e4f0revert: "feat: no feeds after 22:00" Health
- c50a3d7feat: no feeds after 22:00 Health
- 9f6c2e1fix: "I'm an idiot" → "that was a bug" in self_judge() Inner critic
- 5e1f0a2feat: play a game with no notes open Fun
- d40b7f2merge: experiment/morning-walks, it stays Tinkering
- 3e8a1c6chore: archive the old to-do app Friends
- b7d0f44fix: walk still happens when it rains Health
- e91c3aafeat: 10-minute walk before the phone Tinkering
- 7c2d5b8fix: bedtime alarm stops snoozing itself Health
- 2f4a9e2chore: log sleep and mood for one week Health
- a1b0c1dinit: first boot, no manual found Tinkering
JavaScript is off, so this is the readable version: the example graph and the full log. The clickable diffs, your own commits and the release notes need JavaScript.
git revert keeps the old commit and adds a new one; git reset would rewrite the log and lose the lesson.
Example history, not my real life. Your commits stay in this page; nothing leaves your browser. The checkbox saves them to this browser only (localStorage), and Clear removes them.
Plutarch records an old puzzle about the ship of Theseus. The Athenians kept replacing its rotten planks over the years, and people argued about whether it was still the same ship. Git, however, keeps the old planks.
The files change while the history stays whole, so you can replace a lot of planks and still read the ship you started with.
There were six commits, one per section, and nothing was rewritten.
Why a small patch feels like nothing
There is a catch, and it is the reason small patches are so easy to skip. When I am overwhelmed, the part of me that decides what counts as relief stops registering small things. Answering one message, cooking one real meal or walking for ten minutes does not feel like anything, because the threshold (the size a task must reach before it feels like a win) has crept upward until only a colossal task can pay out: fix the whole career, clear the whole backlog, become a different person. Those tasks are almost impossible to finish, so the relief never arrives, and the real tasks in front of me keep counting for zero.
The fix is to lower the threshold a little at a time by writing down each small finish when it happens, because the brain no longer does it for me.
You never get the source code of yourself, only the binary. For a long time that felt like a limitation, until I remembered how much of my favourite software came from people who did not have the source either. Counter-Strike started in 1999 as a Half-Life mod made by two people. Defense of the Ancients began as a Warcraft III custom map and was rebuilt by Valve as Dota 2, and PUBG began with a battle royale mod for ARMA 2. Modders patch a function here, replace a texture there and add an item without breaking the save, and some mods end up better than the original game. Every patch in this post was a mod of that kind: a small edit to a binary I did not write and could not rebuild.
The skills did not die
The patches worked, and the fear stayed. So I asked what I had used to build them. Before AI, the advice to newcomers in security was always the same. Learn to read code first, and only then learn to read code that does not want to be read.
Those skills did not disappear. No model has taken observing before judging, forming and testing a hypothesis, writing everything down, changing one thing at a time, or staying patient at 2 a.m. with something that does not want to be understood, and together they are the part of my work I use most. None of it was ever about malware either. A training log, a budget and a project diary all write things down for their owner, and the kettle log in the report is one hypothesis tested three times. I cannot promise that these skills protect a job. What they did for me was turn a mood into a list I could work through, and once there was a list, there was a next step.
Skills do not transfer automatically, though (Perkins & Salomon, 1992). They travel when you name the principle behind what you did and deliberately apply it somewhere new, and when you take the time to reflect and write down what worked.

The export table
The report started with the imports, everything the program needs from outside, and the export table is the other side. A DLL, a library other programs load, is useful to them through what it exports. The four drives are how the program runs, and none of them is in the export table. The exports are what another team can call. "What transfers" is the same question asked about a person.
the analyst, exports
exported
triage() rank by what changes the answer, not by what is easy to start
report() the finding, written so the next person can act on it
tool() the smallest script that answers one question
read() an unfamiliar system, from the outside, with no manual
commit() one change at a time, with the reason attached
revert() undo a change, history kept
private
tool_shortcuts tool-specific, rots with the licence
case_notes useful until the family is renamed
all_nighter the patience travels; the hours do not
job_title the artefacts travel, the title does not
The first list is a method. It still works at a new employer, in a new language, a decade later. The second is inventory, which is real, expensive to build, and worth little outside the job that produced it.
The catch is the 19%, because none of this shows on the surface. A CV says "reverse engineering" and leaves a hiring manager with nothing to look at. A write-up of a sample, a rule that fires on a real family, or a small tool someone still uses are things someone else can check. The gap is at the entrance, and the study cannot say why. My guess is that the people standing there have the least to show, because the work that leaves a record is the work they have not been hired to do yet.
So the fourth question splits in two. I cannot say who will hire me, and neither can a post. What I can show them does have an answer, and it is the export table, made public one artefact at a time.
The questions from the opening
Three are answerable, and the fourth is half answerable.
- Am I too late? No, because I was already doing this work before I had a name for it.
- Did I choose the wrong field? No, because the skills travel and the field was never the whole story.
- Is the thing I am good at still worth being good at? As a method, yes, even while the tools change every quarter.
- What do I learn next, and who will hire me for it? Only half of it has an answer. Learn the next method that travels instead of the next tool that expires. The hiring half stays open, and the showing half is the export table.
What I can do is make the next attempt less blind, by making one export visible.
Where the skills go
reverser → lifeA diagram of seven reverser skills on the left and seven life areas on the right. Each skill connects to several areas. Select a skill or an area to read an example.
Reverser skills
One skill can feed several life areas. That is the transfer.
Life areas
inbox — unread
Pick a skill on the left, or a life area on the right. The lines are the same map either way.
Calm on purpose. Panic becomes a list of things to look at.
An example map, not a diagnosis. Your map will differ. Nothing here leaves your browser.
Without JavaScript, the same map as a table. Every skill still feeds the areas listed next to it.
| Skill | Life areas | Example of the transfer |
|---|---|---|
| observe before judging | Inner critic, Friends, Fun, Career | In a sample I log behaviour before naming it. With people: what happened first, what I think it means second. It is also how I notice which games I actually enjoy. |
| form a hypothesis and test it | Tinkering, Learning, Fun, Career | One guess, one test, one variable. It finds the crash, it finds the real problem in a bad week, and it gets you past a puzzle you have stared at for an hour. |
| write everything down | Learning, Inner critic, Tinkering | Notes turn a mood into a pattern. The bug report I write for myself is kinder than the one in my head. |
| change one thing at a time | Tinkering, Health, Career | One patch per commit. If it breaks, I know exactly what to revert. |
| read what does not want to be read | Inner critic, Friends, Learning, Fun | Packed code hides what it does until you run it. People are not code, but a conversation can hide its real question. A good puzzle hides its answer the same way. |
| debug at 2 a.m. patience | Health, Tinkering, Fun, Career | Staring at a crash until it confesses. Also works when the crash is a Tuesday, or a boss you have not beaten yet. |
| version control | Tinkering, Learning, Career | Every change gets a message that says why. A bad week is a revert, not a rewrite. |
Release notes
A changelog is where change becomes visible. At the start of this post, the program had no changelog, and this section gives it one. Every line but the known bug is a patch mentioned earlier, collected the way you would collect a diff. One month is too short to claim results, so the notes only record what changed, and mine came out like this.

ME.exe v2026.10
Added tinker(): one unfinished thing opened, made one step less broken
Fixed verdict() deleted; one log line per fault, with a fix
Fixed five-hour habit retired; the wake time no longer moves
Fixed input queue capped; recall() runs after every chapter
Fixed fun() put back in the call graph
Changed one line sent to the thread open since October
Known still overthinks at 2 a.m.; workaround: write it down, sleep
Software makes this easy, because the diff (the list of exactly what changed between two versions) is right there. A person's diff is spread out, so you have to go and collect it. Most of the evidence already exists.
- Something you wrote a year ago, a message, a note or a post. If it makes you wince a little, the version that wrote it is no longer running.
- An old photo or video. The face is close to the same. The room, the posture and the people around you have moved.
- A book you read twice. The book did not change between readings, so whatever you noticed the second time is the diff.
- A project folder sorted by date: the first commit, the first thing that worked, the first person who used it.
Pick the window on purpose. A day is too short and the diff looks empty, which is why bad days feel permanent. A week shows habits, a month shows a direction, and a year is where most of the change hides.
Write the notes once a month and read the old ones once a year.
Next version
The fear from the opening was reasonable, and it will come back with the next headline. I look at it differently now. One month of reading myself like a sample gave me a forty-one-minute call about a dog, a kettle that plays two notes slightly flat, evenings that taste of something again, and a file I know how to read. When the rule fires again, I will find what fired it and set a breakpoint on send() before I reply to anything.

You do not need to be a reverse engineer to do any of this. You need one thing that is slightly broken, and the patience to keep looking at it.
A note before you go: this is a way of looking at yourself, not a treatment. If things feel heavier than a bad week, talk to someone you trust or to a professional. If you are in danger, helplines are free and confidential, and Find A Helpline lists services in more than 175 countries, including 988 in the US, Samaritans on 116 123 in the UK and Ireland, and 3114 in France.
NDLR · AI helped me turn my draft and ideas into the article you just read. The experience, the opinions and the mistakes are mine. Thanks for reading.
Sources
- Decrypt, LabCoatz and the Coca-Cola formula, January 2026
- APA, Work in America 2026; 2023
- Brynjolfsson, Chandar & Chen, Canaries in the Coal Mine?, Stanford Digital Economy Lab, rev. August 2026
- Challenger, Gray & Christmas, December 2025 report
- The Jargon File: hacker, feature
- Gloster et al., the empirical status of ACT, 2020
- Masuda, Hayes, Sackett & Twohig, cognitive defusion and self-relevant negative thoughts, Behaviour Research and Therapy 42 (2004)
- Breines & Chen, self-compassion increases self-improvement motivation, 2012
- Mak et al., hobby engagement in 16 countries, Nature Medicine, 2023
- Harvard Study of Adult Development
- US Surgeon General, Our Epidemic of Loneliness and Isolation, 2023
- Sweeny et al., flow and wellbeing, Emotion (2026)
- NICE NG222, depression in adults; Dimidjian et al., 2006
- Beck Institute, understanding CBT
- Gollwitzer & Sheeran, 2006; Sheeran, Listrom & Gollwitzer, 2024
- git revert and git reset manuals
- Perkins & Salomon, Transfer of Learning, International Encyclopedia of Education, 1992
- Di Stefano, Gino, Pisano & Staats, Learning by Thinking, working paper, 2014
- Torre & Lieberman, Putting Feelings Into Words: Affect Labeling as Implicit Emotion Regulation, Emotion Review, 2018
- Plutarch, Life of Theseus 23.1
- MacBeth & Gumley, Clinical Psychology Review 32 (2012)
- Karpicke & Roediger, Science 319 (2008)
- Pashler et al., PSPI 9 (2008)
- Van Dongen et al., chronic sleep restriction, Sleep 26 (2003)
- Epley & Schroeder, J Exp Psychol Gen 143 (2014)
- Noetel et al., exercise for depression, BMJ 384 (2024)
- Krogsbøll, Jørgensen & Gøtzsche, general health checks in adults, Cochrane Review (2019)
Image credits
- “Car mechanic worker repairing suspension of lifted automobile at auto repair garage shop” by Shixart1985, CC BY 2.0, via Wikimedia Commons. Resized.
- “PT-109 Logbook Entry April 1, 1943”, US Navy, public domain, via DPLA and Wikimedia Commons. Resized.
- “Errata2pl1793” by Rodak, public domain, via Wikimedia Commons. Resized.
- “Sony Dream Machine at 6:37am” by arvind grover, CC BY-SA 2.0, via Wikimedia Commons. Resized.
- Street Fighter (1994), dir. Steven E. de Souza.
- “Laughing Man” by Cddigi, CC BY-SA 4.0, via Wikimedia Commons. Logo from Ghost in the Shell: Stand Alone Complex (2002), dir. Kenji Kamiyama.
- “PS Main Control Room, 1974” by CERN PhotoLab, CC BY-SA 4.0, via Wikimedia Commons. Resized.
- “Chongqing Skyline At Night” by Maple Doctor, CC BY-SA 4.0, via Wikimedia Commons. Resized.
- “Coca-Cola bottles” by DeusXFlorida, CC BY 2.0, via Wikimedia Commons.
- “Electronics workbench” by James Bastow, CC BY-SA 2.0, via Wikimedia Commons. Resized.