summaryrefslogtreecommitdiff
path: root/org
diff options
context:
space:
mode:
authorJakob L. Kreuze <zerodaysfordays@sdf.lonestar.org>2019-12-28 20:34:37 -0500
committerJakob L. Kreuze <zerodaysfordays@sdf.lonestar.org>2019-12-28 20:34:37 -0500
commit7b2e58eafb5562ca425075e112746b0ab33a0869 (patch)
treef5b17b5b58d1d578a27bcca5ab1fc0a533eb93b2 /org
parent216ca5aa5a3b5f82908414fdab591a0e6a6ca9d9 (diff)
Let's try this again...
Diffstat (limited to 'org')
-rw-r--r--org/A Reflection on New Ambitions for a New Year/new-ambitions-for-a-new-year.org279
-rw-r--r--org/First Impressions of the Kotlin Programming Language/first-impressions-of-the-kotlin-programming-language.org2
-rw-r--r--org/First Impressions of the Myrddin Programming Language/first-impressions-of-the-myrddin-programming-language.org196
-rw-r--r--org/Gaming Hacking on Linux - scanmem Basics/game-hacking-on-linux-scanmem.org8
-rw-r--r--org/Installing GuixSD: One Month Later/installing-guixsd-one-month-later.org100
-rw-r--r--org/Towards Guix for DevOps/towards-guix-for-devops.org8
-rw-r--r--org/Writeups for Dennis Yurichev's Reverse Engineering Challenges (#2-#11)/challenges-re-writeups-1.org14
-rw-r--r--org/Writeups for Dennis Yurichev's Reverse Engineering Challenges (#23-#35)/challenges-re-writeups-3.org817
-rw-r--r--org/Writeups for Dennis Yurichev's Reverse Engineering Challenges (#36-)/challenges-re-writeups-4.org996
9 files changed, 2133 insertions, 287 deletions
diff --git a/org/A Reflection on New Ambitions for a New Year/new-ambitions-for-a-new-year.org b/org/A Reflection on New Ambitions for a New Year/new-ambitions-for-a-new-year.org
deleted file mode 100644
index efa5015..0000000
--- a/org/A Reflection on New Ambitions for a New Year/new-ambitions-for-a-new-year.org
+++ /dev/null
@@ -1,279 +0,0 @@
-#+TITLE: A Reflection on "New Ambitions for a New Year"
-#+DATE: <2019-03-03 Sun>
-#+TAGS: writeup, practices
-
-On the night of December 31st of last year, I wrote "New Ambitions for a New
-Year," a blog post outlining a number of self-imposed goals for 2019. The words
-I ended on were: "[t]oo ambitious? Well, I guess we'll find out in 365 days when
-I write another post like this." Indeed, what you're reading right now is
-something I expected to author much later, but enough has changed in the past
-three months that I feel it's appropriate to put out an addendum now. The post's
-original text follows.
-
----
-
-As we draw on the final hours of 2018, the only words I feel appropriate are:
-"wait, it's really January tomorrow?" The past twelve months have felt
-deceivingly short despite everything that's happened in that span of time. I had
-a number of rough job interviews, met Richard Stallman in person, installed
-Gentoo, became a legal adult, graduated high school, and finished my first
-semester of university, all in what seemed to me like just a few weeks.
-
-"Productive" is how I'd characterize the year, but I'm having a hard time
-rationalizing why it is that I feel that way. Yes, I reached two major
-milestones in my education, but I still don't know what to make of everything
-else I did. I'd probably feel better about my accomplishments if I had a goal
-and a means of assessing whether or not I achieved it, but alas, I didn't set
-any out of the same cynicism that drives me to point out resolutioners
-contributing to the January gympocalypse. I'd like to mend that cynicism for
-2019, though. One year really isn't a bad span of time for setting goals -- it's
-long enough that you can be ambitious in your planning, but short enough that
-there's pressure to continue making progress throughout the year.
-
-So, I've come up with some goals for myself, and I've decided to write about
-them to impose some level of accountability.
-
-* Doing
-
-** Writing
-
-This year, I managed to put out seven articles. Last year saw four, and the year
-before saw one. A linear regression suggests that I'll be putting out ten this
-year.
-
-I kid. As tempting as it is to make "write more frequently" one of my goals, my
-focus will be on quality over quantity. In 2019, I plan to:
-
-- Read through /all/ of my past posts, drafts, and [[http://jakob.space/links/][favorite articles]], taking
- notes on how they're written, and synthesizing a writing style that can be
- thoroughly described on paper. If you've read my earlier writing, I anticipate
- that you've noticed significant variance in the presentation of each piece.
- It's time for me to identify the aspects of style that work, and find a way to
- consistently incorporate those aspects into my future writing.
-- In a similar fashion, develop a consistent method for doing research and
- managing sources throughout the writing process. I believe my technical
- writing will benefit if I make a habit of perusing the existing corpus of
- research prior to putting words down on paper.
-- Expand my writing endeavors to Wikipedia. I've collected a number of sources
- for expanding Wikipedia stubs, and my goal is to turn every entry on that list
- into a series of edits. Ideally, I'll go beyond that, but given the preceding
- goals, I think that it makes sense to start small. Writing for Wikipedia will
- expose me to critique from more experienced writers, and give me experience
- writing in an encyclopedic style.
-
-No hard article count goals this year, because again, quality over quantity. If
-I'm forcing myself to write to fill a quota, my heart won't be in it.
-
-** Contributing to Free Software
-
-I'd like to migrate all of the projects I maintain to [[https://git.sr.ht/~jakob/][sr.ht]], but I'll be keeping
-my GitHub account for sending pull requests to projects that live on there.
-
-Originally, I had a list of projects that I wanted to contribute to in the new
-year, but I haven't read a single line of code from any of the entries on that
-list and there's a good chance that I'll have second thoughts about contributing
-following the first perusals, so I've decided that a more reasonable goal is to
-become a regular contributor to at least one project. By "regular contributor,"
-I mean gaining enough of a presence that people are coming to me to ask
-questions about the code.
-
-* Learning
-
-** Computer Science
-
-I have tried, and failed, numerous times to get through Hal Abelson and Gerald
-Sussman's /Structure and Interpretation of Computer Programs/. Now that I'm more
-mature in terms of rigor, I've decided to finally buckle down to make my way
-through the text and all of its exercises. It's a fat 657 page book, but I'm
-more than capable, and I have an entire year to do it.
-
-My more lighthearted goal is to put out at least one demo on either the Super
-Nintendo or the Nintendo DS. I've always wanted to program for a platform where
-I'm constrained by the limitations of the hardware.
-
-** Computer Security
-
-Capture-the-flag used to be a more significant hobby of mine; I mostly dropped
-off the scene when I graduated high school, but I'd like to get back into it. In
-a similar vein to my SICP goal, I'm aiming to finally get through a book that
-I've failed to finish in the past, [[https://beginners.re/][Reverse Engineering for Beginners]], and
-complete _at least_ 50 of its exercises. 50 is a about one per week, which I
-think is reasonable.
-
-** Electronics
-
-I've tried several times in the past to learn "electronics", and never
-progressed beyond the laws of Ohm and Joule. I think the issue was that I didn't
-know what I wanted to learn; I set out to study "electronics," which wasn't
-specific enough. This time, I'll be more diligent in finding curriculum that's
-relevant to me. I want to learn to read boards and gain the knowledge necessary
-to repair my Commodore 64, so my focus will be on the design of electronic
-circuits. I'll achieve this is by going through the coursework for MIT's 6.002:
-"Circuits and Electronics". It's a course I wanted to go through when I was a
-sophomore in high school, but at the time, I was discouraged by the list of
-prerequisites in the syllabus.
-
-Another goal of mine is to join an amateur radio club. I've already got two in
-mind: [[http://sdfarc.org/][SDFARC]] and the one that runs the local 2-meter repeater I frequent. My
-thought is that joining one will give me an opportunity to find an Elmer whose
-brain I can pick about RF electronics.
-
-** Mandarin Chinese
-
-One of my favorite courses in high school was Mandarin Chinese. I took it for
-four years, and while I wanted to continue studying it at university, I sadly
-couldn't fit any classes into my schedule. The four years of study left me with
-a grasp of the language's fundamentals, however, and I think that I could
-reasonably continue to learn the language on my own accords. Throughout the
-year, I plan to:
-
-- Learn the vocabulary on [[https://en.wiktionary.org/wiki/Appendix:Mandarin_Frequency_lists/1-1000][Wiktionary's list]] of the 1000 most frequently used
- words in Mandarin. I already know a number of words on the list from my four
- years of study, and learning the rest should give me a good base for reading
- from newspaper articles and books. I plan to learn the words' definitions and
- pronunciations through spaced repetition, and I'll handwrite the character
- every time I review the card for it. Although the ability to handwrite
- characters isn't a specific goal of mine, I've found that it helps me in
- learning to recognize the characters.
-- Read /C程序设计语言/. I have a translated copy of Kernighan and Ritchie from
- when I went to 王府井, so that should be reading that's both engaging and full
- of the kind of vocabulary that I'm interested in learning.
-- Make friends with at least one of the international student in my dorm. I'd
- feel bad conscripting someone solely for the purpose of helping me learn
- Mandarin, but I figure that if I befriend someone whose native tongue is
- Mandarin and spit a bunch of broken Chinese at them, they'll be inclined to
- correct me (through laughter, perhaps).
-
-To recap, my goals this year are:
-
-- Move my software projects to [[https://sr.ht/][sr.ht]].
-- Join an amateur radio club.
-- Make friends with at least one of the international students in my dorm.
-- Synthesize a consistent writing style and document it.
-- Synthesize a method for performing research and document it.
-- Turn my list of articles into a series of edits to Wikipedia stubs.
-- Learn the 1000 most frequently used words in Mandarin Chinese.
-- Read /C程序设计语言/.
-- Read /SICP/ and complete all of its exercises.
-- Read /RE4B/ and compete at least 50 of its exercises.
-- Complete the coursework for 6.002.
-- Put out at least one demo on either the Super Nintendo or the Nintendo DS.
-- Become a regular contributor to at least one free software project.
-
-Too ambitious? Well, I guess we'll find out in 365 days when I write another
-post like this.
-
----
-
-As alluded to in the introduction, I've come to understand that achieving every
-goal on that list within the span of a year is impossible. Well, at least for a
-full-time university student. Balancing a course load of 19 credits with
-undergraduate research and a social life leaves me with little more than a few
-hours on the weekends to dedicate to those tasks. As such, I'm reevaluating and
-redefining my goals for 2019.
-
-What's more, some of the things on that list no longer even interest me. Why
-invest significant time into something I know I won't find fulfilling? Take the
-plan for continuing my study of Mandarin Chinese as an example: bilingualism
-seems like it might be useful, but I have no realistic use for the skill, and I
-was really dreading the daily practice I was putting in for the first few weeks
-of the year.
-
-The other issue that's come up is a loss of motivation for some of the tasks
-that, unlike continuing my study of Mandarin, I /would/ find fulfilling. To remedy
-this, I've decided to associate small integrative projects with each of the
-goals I intend on keeping. This move is inspired by the points made in Norvig's
-[[http://norvig.com/21-days.html][Teach Yourself Programming in Ten Years]], which I had read several years ago but
-was reminded of after a recent perusal of the introduction to [[http://www.cs.cornell.edu/courses/cs3110/2019sp/textbook/][Functional
-Programming in OCaml]]. I'd specifically like to quote a few things he lists in
-his "recipe for programming success":
-
-- Get *interested* in programming, and do some because it is fun. Make sure that
- it keeps being enough fun so that you will be willing to put in your ten
- years/10,000 hours.
-- *Program*. The best kind of learning is learning by doing. To put it more
- technically, "the maximal level of performance for individuals in a given
- domain is not attained automatically as a function of extended experience, but
- the level of performance can be increased even by highly experienced
- individuals as a result of deliberate efforts to improve." (p. 366) and "the
- most effective learning requires a well-defined task with an appropriate
- difficulty level for the particular individual, informative feedback, and
- opportunities for repetition and corrections of errors." (p. 20-21) The book
- Cognition in Practice: Mind, Mathematics, and Culture in Everyday Life is an
- interesting reference for this viewpoint.
-- *Talk with* other programmers; read other programs. This is more important than
- any book or training course.
-- Work on *projects with* other programmers. Be the best programmer on some
- projects; be the worst on some others. When you're the best, you get to test
- your abilities to lead a project, and to inspire others with your vision. When
- you're the worst, you learn what the masters do, and you learn what they don't
- like to do (because they make you do it for them).
-- Work on *projects after* other programmers. Understand a program written by
- someone else. See what it takes to understand and fix it when the original
- programmers are not around. Think about how to design your programs to make it
- easier for those who will maintain them after you.
-
-Working towards a project is largely conducive of these. It will ensure that I'm
-having fun, that I'm learning by doing, and that I'm speaking with those who
-have expertise. So, here's my updated list of goals for 2019, paired with the
-projects I've come up with:
-
-- Complete the coursework for MIT's 6.002.
- - Troubleshoot my Commodore 64 and restore it to a working state.
-- Read chapters 1-4 of Structure and Interpretation of Computer Programs and
- complete all of their exercises.
- - Implement a ray-tracer in Scheme.
-- Compete 50 of the exercises in Reverse Engineering for Beginners.
- - Write another game hacking post.
-- Synthesize a consistent writing style and document it.
- - Write another game hacking post.
-- Synthesize a method for performing research and document it.
- - Adopt the "Heap feng shui" and "JIT spraying" pages on Wikipedia.
-
-Although this is still an ambitious list, I think I can reasonably achieve all
-of these by 2020. I think the more important point, however, is that I've
-effectively reduced my original ragtag list of last-minute New Year's Eve
-thoughts into a clear plan for personal growth. Completing the coursework for
-6.002 will enable me to design and reverse engineer circuits. Completing
-Structure and Interpretation of Computer Programs will teach me to approach
-problems with a functional programming mindset. Working through the exercises
-from Reverse Engineering for Beginners will give me a repertoire of patterns for
-going forward in capture-the-flag and any projects I take on in the future that
-may involve reverse engineering. Developing a consistent writing style will
-strengthen my ability to communicate knowledge, and developing a consistent
-method for performing research will encourage me to exercise that skill of
-communicating knowledge.
-
-During my initial reflection, I thought that troubleshooting the C64 would make
-for a poor choice of project, as there's the possibility that I'd start
-troubleshooting and soon realize that it's borked beyond repair. One thought was
-to instead follow the instructions outlined in Steve Ciarcia's Build Your Own
-Z80 Computer, but after looking through the book, I realized that it would be
-both expensive and probably very difficult to complete due to the age of the
-components used.[fn:1] I also thought to follow Ben Eater's instructions for
-[[https://eater.net/8bit/kits][building an 8-bit computer from scratch]], but that also has the issue of price.
-Ultimately, I decided to go with my original plan to fix the C64. Even if I
-can't repair the C64, I have a broken VIC-20 I can fall back on, and I think I'd
-learn more in the domain of reverse engineering circuits than I would following
-the instructions that come with some homebrew computer kit.
-
-My definition of success for the goal of reading Structure and Interpretation of
-Computer Programs changed slightly to omit the fifth chapter. I still plan to
-read it, just not this year. My reasoning comes mainly from skimming ahead to
-get an idea for an integrative project and seeing exercise 5.51. It'd just be...
-well, a lot. Why a ray-tracer? It's short, sweet, utilitarian, and would
-probably be both pleasant and eye-opening to implement in a functional style.
-
-I'll still be working through the exercises in Reverse Engineering for
-Beginners, but I will not be reading the book in it's entirety. After going
-through the first few chapters, I've developed the opinion that the book makes
-for incredible reference material, but that a page-by-page reading wouldn't be
-valuable for someone with prior experience in reverse engineering. I'll still be
-skimming a subset of the book[fn:2], but I don't want promise to myself that
-I'll finish those chapters by the end of this year.
-
-One last thing to note -- I've omitted the goal about moving all my software
-projects to sr.ht, as I've succeeded in doing that.
-
-[fn:1] How the hell am I going to get my hands on a CRT terminal in 2019?
-[fn:2] Chapters 30-63, 68, 76, and 88.
diff --git a/org/First Impressions of the Kotlin Programming Language/first-impressions-of-the-kotlin-programming-language.org b/org/First Impressions of the Kotlin Programming Language/first-impressions-of-the-kotlin-programming-language.org
index 75b7438..742103b 100644
--- a/org/First Impressions of the Kotlin Programming Language/first-impressions-of-the-kotlin-programming-language.org
+++ b/org/First Impressions of the Kotlin Programming Language/first-impressions-of-the-kotlin-programming-language.org
@@ -2,7 +2,7 @@
#+DATE: <2018-12-17 Mon>
#+TAGS: opinion, programming, java, kotlin, android
-In the introduction of the previous post I wrote for this series, [[http://jakob.space/posts/first-impressions-of-the-rust-programming-language/][First
+In the introduction of the previous post I wrote for this series, [[http://jakob.space/blog/first-impressions-of-the-rust-programming-language.html][First
Impressions of the Rust Programming Language]], I alluded to the presence of
arguments that programming language safety should be achieved by moving to
languages such as Java which run on a virtual machine. While "safety" may no
diff --git a/org/First Impressions of the Myrddin Programming Language/first-impressions-of-the-myrddin-programming-language.org b/org/First Impressions of the Myrddin Programming Language/first-impressions-of-the-myrddin-programming-language.org
new file mode 100644
index 0000000..fec4a31
--- /dev/null
+++ b/org/First Impressions of the Myrddin Programming Language/first-impressions-of-the-myrddin-programming-language.org
@@ -0,0 +1,196 @@
+#+TITLE: First Impressions of the Myrddin Programming Language
+#+TAGS: opinion, programming, myrddin
+
+# Man the memory management model of this lang is so wierd I'm constantly
+# dealing with things being freed from under my feet.
+
+# Also, no shadowing, which sucks.
+
+# It's been a long time since I've made a post like this.
+
+I'm not sure there are many applications writen in Myrddin. The [[https://eigenstate.org/software/ircmyr][irc.myr]] IRC
+client comes to mind, but not much else. It seems most of the work has gone
+towards developing libraries.
+
+It took a restless night for me to come up with a good project to use Myrddin
+for. The limited architecture support restricted my choices somewhat. I had
+considered writing a very lightweight [[https://en.wikipedia.org/wiki/Imageboard#Danbooru-style_boards][Booru]] engine to use as a self-hosted,
+tagged image gallery, but my "server" [fn:1] is ARMv6, so I wouldn't be getting
+much use out of it. Ah, well. The next language I plan to write about is built
+upon LLVM, so I'll be able to target my server then. I also toyed with the idea
+of a text editor and a Lisp interpreter, but settled on a CHIP-8 emulator.
+First, it would be a good opportunity to demonstrate the C binding support as
+I'll be using SDL. There's plenty of room to go above the bare-minimum for
+features, such as additionally implementing an assembler, debugger, or JIT.
+Furthermore, it would be (to my knowledge) the first graphical application
+writen in Myrddin.
+
+# Also, I figure having a CHIP-8 emulator of my own would be good, since it
+# would be a fun target for a "toy" compiler if I decide to make one.
+
+# Mention the [[https://myrlang.org/wishlist][wishlist]]
+
+* Tooling
+
+# There's a syntax highlighting implementation for vim, but I don't use vim
+
+So I've written a [[https://git.sr.ht/~jakob/myrddin-mode][major mode]] for GNU Emacs.
+
+# It's packaged in melpa!
+
+* Build System
+
+The build system for Myrddin is interesting, and very reminiscent of
+
+- =mbld=
+- =6m= is the actual compiler.
+- =muse=???
+
+# Error messages are AWFUL
+
+#+BEGIN_SRC prog
+jakob@Epsilon ~/Code/chip $ mbld -b asm asm.myr && ./asm
+ 6m asm.myr
+asm.myr:52: type "char" incompatible with "byte" near Otup:(union
+ `std.None
+ `std.Some byte[:]
+;;,byte[:][:])
+ char from asm.myr:24
+ byte from asm.myr:8
+FAIL: 6m asm.myr
+#+END_SRC
+
+# This one was in response to trying to do .len on an array rather than a slice
+
+#+BEGIN_SRC prog
+jakob@Epsilon ~/Code/chip $ mbld -b asm asm.myr
+ 6m asm.myr
+6m: typeinfo.c:363: tyoffset: Assertion `ty->type == Tystruct' failed.
+CRASH: 6m asm.myr
+#+END_SRC
+
+One interesting difference between Myrddin and Rust is that Myrddin does not
+require that arguments have a type specifier.
+
+#+BEGIN_SRC myrddin
+use std
+
+const factorial = {n
+ if n < 1
+ -> 1
+ ;;
+ -> n * factorial(n - 1)
+}
+
+const main = {
+ std.put("Hello, world!\n")
+}
+#+END_SRC
+
+But as soon as you have more complicaed functions that aren't used...
+
+[fn:1] At the moment, a Raspberry Pi B+. It does the job, but I'm afraid of blowing the 512MB RAM trying to run a full MediaGoblin instance on it.
+
+# ---
+
+- Entry point is the function named =main=.
+- Simpler, but similar to Rust's format specifies for output (=std.put("{} + {} = {}\n", 2, 2, 5)=)
+- Function prototypes not necessary (!)
+ - Drew Devault's recent mockup requires function prototypes.
+- Lines aren't terminated with semicolons (feels a bit like Go?)
+
+- Declarations begin with =var=, =const=, or =generic=.
+ - Specify type like in rust (=var acc: int=)
+ - There's type inference (cool!)
+
+- There's no special syntax for function declarations; functions are declared by
+ assigning a function literal to a constant.
+ - A bit like Scheme, I guess?
+ - Function literal syntax is a bit weird, though.
+
+#+BEGIN_SRC myrddin
+{arg, list
+ function
+ body
+}
+#+END_SRC
+
+- Argument types aren't actually needed (unlike in Rust).
+- Fixed-width integer types (unlike C, more like Rust, which I really appreciate)
+
+- Multiple exit points for a function, i.e.
+
+#+BEGIN_SRC myrddin
+const factorial = {n
+ if n < 1
+ -> 1
+ ;;
+ -> n * factorial(n - 1)
+}
+#+END_SRC
+
+ - Minor point, but returning early from a function in Common Lisp is a pain in
+ the rear. (Of course =if= being an expression makes =factorial= trivial to
+ implement without it).
+
+- Only control flow is =if/elif/else=, =while=, =for=.
+ - I like =elif=, like Python.
+
+- Pattern matching!!!
+ - "Pattern matches can descend into the structure of almost any type.
+ Structures, arrays, strings, unions, and even values on the other end of
+ pointers are fair game."
+ - There's also algebraic data types, which I'm diggin'.
+ - The backtick syntax is nice for readability imo.
+ - =std.result=
+
+- Generics. Dunno how to feel about that, yet.
+ - There are traits, which I'm not comfortable enough with in Rust to make a
+ comparison.
+ - Lends itself to allowing for iterators to be implemented.
+
+- Libraries are so simple. Just a =pkg= declaration.
+- Array literals are pretty cool.
+ - =x = [0: 1, 73: 2]=.
+- Structs are literals, assigned to a =type= declaration.
+
+- Operators are pretty much the same as C, which makes the learning curve quite nice.
+ - Only meaningful addition is =->=.
+
+- Tuples!
+
+- I especially enjoy the section on "Style" in the tutorial.
+ - snake_case is "acceptable", constants are Initialuppercase.
+ - 60 characters to line is a big opinion.
+
+* Building
+
+** On a Simple Level
+
+- =mbld -b [binary-name] [source.myr ...]=
+
+** Build System
+
+I love this. =[name].proj= looks like
+
+#+BEGIN_SRC myrddin
+lib stack =
+ stk.myr
+;;
+#+END_SRC
+
+then you just run =mbld=. For binaries, replace =lib= with =bin=.
+
+* Standard Library
+
+- std.optparse
+
+* CFFI
+
+Horribly documented. See [[https://eigenstate.org/archive/myrddin-dev/2015-Oct/0000002.html]].
+
+# ---
+
+- https://github.com/glouw/c8c
+- https://github.com/dmatlack/chip8/tree/master/roms
+- http://www.multigesture.net/articles/how-to-write-an-emulator-chip-8-interpreter/
diff --git a/org/Gaming Hacking on Linux - scanmem Basics/game-hacking-on-linux-scanmem.org b/org/Gaming Hacking on Linux - scanmem Basics/game-hacking-on-linux-scanmem.org
new file mode 100644
index 0000000..6e7cf1f
--- /dev/null
+++ b/org/Gaming Hacking on Linux - scanmem Basics/game-hacking-on-linux-scanmem.org
@@ -0,0 +1,8 @@
+#+TITLE: Game Hacking on Linux - scanmem Basics
+#+DATE: <2017-06-18 Sun 11:51>
+#+TAGS: tutorial, reverse-engineering, linux, video-games, game-hacking
+#+CROSSPOST: https://0x00sec.org/t/game-hacking-on-linux-scanmem-basics/2458
+
+Hey, this is a very brief tutorial on scanmem, a memory manipulation tool for
+Linux that’s well suited to game hacking. I’ll be using GZDoom as an example,
+but you should be able to follow along with any game you want.
diff --git a/org/Installing GuixSD: One Month Later/installing-guixsd-one-month-later.org b/org/Installing GuixSD: One Month Later/installing-guixsd-one-month-later.org
new file mode 100644
index 0000000..32b6685
--- /dev/null
+++ b/org/Installing GuixSD: One Month Later/installing-guixsd-one-month-later.org
@@ -0,0 +1,100 @@
+#+TITLE: Installing GuixSD: One Month Later
++DATE:
+#+TAGS: opinion, linux, gentoo
+
+# https://zge.us.to/guix.html
+
+# https://octodon.social/@cwebber/101816791252611754
+# https://mastodon.sdf.org/@jakob/101857455853919355
+# Stability with v1.0.0
+# https://octodon.social/@cwebber/102089556606069384
+
+# It's actually been three months since I began running GuixSD as a daily driver,
+# but I wanted to reference a [[/blog/installing-gentoo-one-month-later.html][similar post]] I wrote last year.
+
+Several months ago, I came across one of Pierre Neidhardt's [[https://ambrevar.xyz/guix-advance/index.html][articles]] regarding
+the Guix System Distribution. NixOS was little more than a name to me back then,
+so this was my first exposure to the concepts of purely functional package
+management. I was pretty stoked about the ideas behind it.
+
+The article introduces GuixSD as the "fully-programmable OS," explaining that
+the init system and package manager are both written in [[https://www.gnu.org/software/guile/][GNU Guile]]. As someone
+who often longed for a Lisp interface to [[https://en.wikipedia.org/wiki/Portage_(software)][Portage]], this immediately caught my
+attention. Among the other favorite features that Neidhardt lists, I was
+particularly enticed by the promises of system roll-backs, support for multiple
+simultaneously-installed package versions, a "self-reproducing live USB", and a
+GNU Emacs package for working with the package manager.
+
+#+BEGIN_EXPORT html
+<div class="mastodon">
+ <iframe height="180" src="https://mastodon.sdf.org/@jakob/101415693778707984/embed"></iframe>
+</div>
+#+END_EXPORT
+
+My setup was working just fine, though, and I needed a working computer for
+university, so I didn't have much of a compelling reason to distro hop. That is,
+until I got word that my GSoC [[https://summerofcode.withgoogle.com/projects/#5232565294727168][proposal]] this year was accepted. I'll say this
+much: If a virtual machine is a significant part of your development workflow,
+you're gonna have a bad time.
+
+* Installation
+
+When I'm not at university, I have two machines that I like to use: a desktop
+computer, and a laptop. The desktop computer was my first victim as I'd still be
+able to get things done if it were in an unusable state (the laptop was another
+story). As it turns out, I picked the harder of the two machines to install
+GuixSD to first. The installer would show some messages from Shepherd, and then
+continue to boot to a blank screen. I was able to get to a console if I passed
+in 'nomodeset' from Grub, so the issue was immediately obvious to me: the
+default kernel for GuixSD is [[https://en.wikipedia.org/wiki/Linux-libre][Linux-libre]], an offshoot of Linux that removes any
+and all non-free components. Put another way, any firmware blobs that the
+tower's graphics card might have need weren't being loaded
+
+As comforting as the VESA framebuffer console is, I wanted to run an X server.
+I'd have to load non-free firmware. Sigh. Please don't blob-shame me.
+
+This actually isn't too hard to do, and is [[https://ambrevar.xyz/guix-advance/index.html#org1a64edd][covered]] in Pierre's article. What I
+did, essentially, was create a Guix configuration with a custom kernel and use
+'guix system disk-image' to produce something that I could use on my tower, and
+install GuixSD from there. I began with the kernel config I was using for
+Gentoo, but that would panic, claiming that Linux couldn't find the root
+filesystem. So I copied over GuixSD's config. That seemed to work. This all took
+a pretty long time because I was compiling the kernel in a /virtual machine/, and
+every time I changed something, Guix would calculate a new derivation for the
+kernel, and it would be rebuilt without any of the object files from the
+previous compilation.
+
+When I had a good development environment on the tower, I felt it was time to
+install to the laptop. This was far easier as I didn't have to worry about
+firmware for the machine to be _usable_. The internal WNIC didn't work, but that
+was alright since I had a USB WNIC that didn't require non-free firmware.
+
+--
+
+Being able to configure my machines from a single Scheme source file has
+provided me great peace of mind; trying to document the changes I make to the
+various configuration files in ~/etc/~ is hopeless.
+
+There are a number of features that Gentoo brought that I'll miss, but I also
+think my missing them is a matter of preference.
+
+I never really understood slots in Gentoo. I think they allow multiple versions
+of a package to be installed at the same time. Regardless, I have no plans to
+learn about them now. The use of symbolic links in Guix is a solution to the
+multiple-versions problem that's much easier to wrap my head around.
+
+I always hated the way that Gentoo dealt with configuration files of upgraded
+packages.
+
+"For example, alice installs GCC 4.7.2. As a result,
+/home/alice/.guix-profile/bin/gcc points to /gnu/store/…-gcc-4.7.2/bin/gcc. Now,
+on the same machine, bob had already installed GCC 4.8.0. The profile of bob
+simply continues to point to /gnu/store/…-gcc-4.8.0/bin/gcc—i.e., both versions
+of GCC coexist on the same system without any interference."
+
+- Package "categories" (i.e. app-admin, net-im). This is something that the
+ BSD's do, and Debian-likes do not.
+
+The straw that broke the camel's back was this [[https://forum.zdoom.org/viewtopic.php?f=50&t=65552][unusual stuttering]] in anything
+running OpenGL. I concluded that this was an issue with SDL or Mesa and
+proceeded to nuke everything and reinstall Gentoo.
diff --git a/org/Towards Guix for DevOps/towards-guix-for-devops.org b/org/Towards Guix for DevOps/towards-guix-for-devops.org
new file mode 100644
index 0000000..afbaea4
--- /dev/null
+++ b/org/Towards Guix for DevOps/towards-guix-for-devops.org
@@ -0,0 +1,8 @@
+#+TITLE: Towards Guix for DevOps
+#+DATE: <2019-07-13 Sat 16:11>
+#+TAGS: writeup, programming, functional-programming, linux, guix, lisp, scheme, guile
+#+CROSSPOST: https://www.gnu.org/software/guix/blog/2019/towards-guix-for-devops/
+
+Hey, there! I'm Jakob, a Google Summer of Code intern and new contributor to
+Guix. Since May, I've been working on a DevOps automation tool for the Guix
+System, which we've been calling guix deploy.
diff --git a/org/Writeups for Dennis Yurichev's Reverse Engineering Challenges (#2-#11)/challenges-re-writeups-1.org b/org/Writeups for Dennis Yurichev's Reverse Engineering Challenges (#2-#11)/challenges-re-writeups-1.org
index 6ea207c..5450a4a 100644
--- a/org/Writeups for Dennis Yurichev's Reverse Engineering Challenges (#2-#11)/challenges-re-writeups-1.org
+++ b/org/Writeups for Dennis Yurichev's Reverse Engineering Challenges (#2-#11)/challenges-re-writeups-1.org
@@ -2,12 +2,12 @@
#+DATE: <2019-03-10 Sun>
#+TAGS: writeup, reverse-engineering, arm, x86
-As mentioned in the post I wrote [[http://jakob.space/posts/new-ambitions-for-a-new-year/][describing my plans for 2019]], one of my goals
-this year is to get through at least 50 of the exercises on Dennis Yurichev's
-[[https://challenges.re/][challenges.re]]. I've decided to document my progress in the form of writeups for
-the challenges I complete, batched in sets of ten exercises. For each challenge,
-I'll try to explain the intuitions that brought me closer to answering the
-recurring question from Yurichev, "[w]hat does this code do?"
+As mentioned in the (now deleted) post I wrote describing my plans for 2019, one
+of my goals this year is to get through at least 50 of the exercises on Dennis
+Yurichev's [[https://challenges.re/][challenges.re]]. I've decided to document my progress in the form of
+writeups for the challenges I complete, batched in sets of ten exercises. For
+each challenge, I'll try to explain the intuitions that brought me closer to
+answering the recurring question from Yurichev, "[w]hat does this code do?"
* Challenge #2
@@ -30,7 +30,7 @@ listing to AT&T syntax for once.
#+END_EXPORT
Below is a rough translation of the disassembly listing to C. My process is
-relatively unchanged from the workflow I described in an [[http://jakob.space/posts/decompilation-by-hand/][older post]].
+relatively unchanged from the workflow I described in an [[http://jakob.space/blog/decompilation-by-hand.html][older post]].
#+BEGIN_SRC c :hl_lines 0
unsigned f(unsigned a)
diff --git a/org/Writeups for Dennis Yurichev's Reverse Engineering Challenges (#23-#35)/challenges-re-writeups-3.org b/org/Writeups for Dennis Yurichev's Reverse Engineering Challenges (#23-#35)/challenges-re-writeups-3.org
new file mode 100644
index 0000000..44b3021
--- /dev/null
+++ b/org/Writeups for Dennis Yurichev's Reverse Engineering Challenges (#23-#35)/challenges-re-writeups-3.org
@@ -0,0 +1,817 @@
+#+TITLE: Writeups for Dennis Yurichev's Reverse Engineering Challenges (#23-#35)
+#+DATE: <2019-08-18 Sun 10:42>
+#+TAGS: writeup, reverse-engineering, x86
+
+This is the third set of solutions for my self-imposed challenge of completing
+at least fifty of the exercises on Dennis Yurichev's [[https://challenges.re][challenges.re]] by the end of
+the year. The previous set is available [[http:///jakob.space/challenges-re-writeups-2.html][here]].
+
+* Challenge #23
+
+The problem is prefaced with, "[t]his is another implementation of a well-known
+library function, works only in a 64-bit environment." Translating the
+disassembly directly to C reveals unrolled loops, but the intent isn't too
+difficult to figure out.
+
+#+BEGIN_SRC c
+int f(char *a)
+{
+ int i;
+
+ if (a[0] == '\0') {
+ return 0;
+ }
+
+ if (a[1] == (char) 0xff) {
+ return 1;
+ }
+
+ if (a[2] == (char) 0xff) {
+ return 2;
+ }
+
+ if (a[3] == (char) 0xff) {
+ return 3;
+ }
+
+ if (a[4] == (char) 0xff) {
+ return 4;
+ }
+
+ if (a[5] == (char) 0xff) {
+ return 5;
+ }
+
+ i = 0;
+
+ while (a[6] != (char) 0xff) {
+ if (a[7] == (char) 0xff) {
+ return i + 7;
+ }
+
+ i += 8;
+ a += 8;
+
+ if (a[1] == (char) 0xff) {
+ return i;
+ }
+
+ if (a[1] == (char) 0xff) {
+ return i + 1;
+ }
+
+ if (a[2] == (char) 0xff) {
+ return i + 2;
+ }
+
+ if (a[3] == (char) 0xff) {
+ return i + 3;
+ }
+
+ if (a[4] == (char) 0xff) {
+ return i + 4;
+ }
+
+ if (a[5] == (char) 0xff) {
+ return i + 5;
+ }
+ }
+
+ return i + 6;
+}
+#+END_SRC
+
+=f= returns the index of the first occurrence of =0xff= in =a=. In addition to asking
+for the purpose of the code, the challenge poses a few additional questions.
+
+First: "The code may crash under some specific circumstances. Which are...?" =f=
+will crash in the case that there isn't a 0xff character in the string.
+
+Second: "The code can be easily optimized using SSEx. How?" =movq= can be used to
+dereference the characters of =a=, and the location of the =0xff= character can be
+found using =pcmpeqb=. Actually implementing this is left as an exercise to the
+reader. And I'm not saying that just because writing SIMD by hand makes me want
+to break down and cry... or anything like that...
+
+Finally: "The code will not work correctly on big-endian architectures. How to
+fix it?" In the disassembly, the LSB of =rdx= (=dl=) is treated as the _first_
+character in the sliding window. On a big-endian system, dereferencing the
+window as an integer would mean that the LSB would correspond with the _last_
+character in the window. To fix this, you would need to change which parts of
+the register are being looked at. I realize that's a rather anemic answer, but
+the alternative would be going all-in and implementing =f= on a big-endian
+platform, which I don't really want to do right now.
+
+* Challenge #26
+
+I decided to skip challenges #24 and #25 as they were listed as "Level 2" and
+"Level 3" respectively in terms of difficulty. Challenge #25 in particular
+seemed particularly demanding. Challenge #26, on the other hand, was a
+relatively straightforward bytecode reverse engineering task. Like Challenge
+#14, disassemblies for both .NET and the JVM are given, and as I'm more familiar
+with Java than C# (unfortunately), that's the disassembly I chose to work with.
+
+#+BEGIN_SRC java
+public static byte f(byte a) {
+ return (byte) ((((long) a * 8623620610L) & 1136090292240L) % 1023L);
+}
+#+END_SRC
+
+Again, I'm not familiar with JVM bytecode, so I broke out [[https://en.wikipedia.org/wiki/Java_bytecode_instruction_listings][my favorite JVM
+reference]]. Here are the instructions we're concerned with:
+
+#+BEGIN_SRC java
+iload_0 // load an int value from local 0
+i2l // convert an int to a long
+l2i // convert a long to an int
+i2b // convert an int to a byte
+ldc2_w // push a constant onto the stack
+lmul // multiply two longs
+land // perform a bitwise and on two longs
+lrem // perform remainder division on two longs
+#+END_SRC
+
+Even if you don't know how the JVM works, I think the purpose of =f= is fairly
+clear as soon as you know what those few instructions do.
+
+I've typically been using Matt Godbolt's amazing [[https://godbolt.org/][Compiler Explorer]] to check my
+solutions, but this time around I used [[http://javabytes.io/][Javabytes]]. The disassembly of my
+translation for =f= matches what was given for the challenge, so I'm quite
+confident in my answer. As for what it does: I began my analysis as I typically
+do, giving the function some test values and observing the output.
+
+#+BEGIN_SRC java
+public static void main(String[] args) {
+ for (int i = 0; i < 256; i++) {
+ System.out.printf("%3i: b\n", i, f((byte) i));
+ }
+}
+
+// 0: 0
+// 1: -128
+// 2: 64
+// 3: -64
+// 4: 32
+// ...
+// 253: 63
+// 254: -65
+// 255: 127
+#+END_SRC
+
+That isn't very telling, but the oscillating sign gives me an idea.
+
+#+BEGIN_SRC java
+public static String toPaddedBinary(byte a) {
+ String s = String.format("%8s", Integer.toBinaryString(a));
+ s = s.replace(' ', '0');
+ return s.substring(s.length() - 8, s.length());
+}
+
+public static void main(String[] args) {
+ for (int i = 0; i < 256; i++) {
+ System.out.printf("%s: %s\n", toPaddedBinary((byte) i), toPaddedBinary(f((byte) i)));
+ }
+}
+
+// 00000000: 00000000
+// 00000001: 10000000
+// 00000010: 01000000
+// ...
+// 11111101: 10111111
+// 11111110: 01111111
+// 11111111: 11111111
+#+END_SRC
+
+So =f= reverses the bits of =a=.
+
+* Challenge #27
+
+This challenge threw me for a bit of a loop, as it didn't give the usual amd64
+output from GCC 4.9. Rather an i386 disassembly from MSVC 2010 was given,
+alongside an arm64 disassembly from GCC 4.9. I tried both, but had some
+significant trouble with the MSVC disassembly as it seemed to be dealing with
+64-bit integers on a 32-bit architecture.
+
+After quickly reviewing CDOT's [[https://wiki.cdot.senecacollege.ca/wiki/Aarch64_Register_and_Instruction_Quick_Start#General-Purpose_Registers][AArch64 reference]] to get an idea of register
+widths, this is the translation came up with:
+
+#+BEGIN_SRC c
+int f(int a)
+{
+ return (((int) (((long) a * 0xc64b2279) >> 32)) + a) >> 9 - (a >> 31);
+}
+#+END_SRC
+
+I'm not particularly confident in this, however, as the behavior of =f= is to
+return \(floor(a / 289)\). I suspect my poor understanding of the [[http://infocenter.arm.com/help/topic/com.arm.doc.dui0068b/CIHBEAGE.html][flexible
+second operand]] (i.e. in =sub w0, w1, w0, asr 31=) is what gave me me the most
+trouble. Perhaps this is a challenge I should return to when I properly learn
+ARM.
+
+I tried a more direct translation to Python,
+
+#+BEGIN_SRC python
+def test_f(a):
+ result = a * 0xc64b2279
+ upper = result & 0xffffffff00000000
+ lower = result & 0xffffffff
+ return ((upper + lower) >> 9) + \
+ (((upper + lower) >> 9) >> 31)
+
+fmt = lambda n: bin(n)[2:].rjust(32, '0')
+
+for i in range(256):
+ print("{}\n{}\n".format(fmt(i), fmt(test_f(i))))
+#+END_SRC
+
+which didn't yield any recognizable patterns.
+
+Actually, before implementing it in Python, I implemented it in Emacs Lisp (I
+might have been waiting on Python to compile? I don't remember).
+
+#+BEGIN_SRC elisp
+(defun test-f (a)
+ (let* ((result (* a #xc64b2279))
+ (upper (logand result #xffffffff00000000))
+ (lower (logand result #xffffffff)))
+ (+ (ash (+ upper lower) 9)
+ (ash (ash (+ upper lower) 9) 31))))
+#+END_SRC
+
+Either way, this challenge wasn't fruitful.
+
+* Challenge #28
+
+I suspect that this challenge was made a bit easier by GCC's optimizations. The
+amd64 disassembly includes two unused functions, =f2= and =my_memdup= -- they're
+used in some of the other disassemblies, but I chose to ignore them.
+
+#+BEGIN_SRC c
+#include <string.h>
+#include <stdlib.h>
+
+int f1(int *a, int *b)
+{
+ return *a > *b ? 0 : -1;
+}
+
+int f_main(void *src, int n)
+{
+ int tmp;
+ char *dst;
+
+ dst = malloc(n * sizeof(int));
+ memcpy(dst, src, n * sizeof(int));
+ qsort(dst, n, sizeof(int), f1);
+
+ if (n > 1) {
+ tmp = dst[n >> 1] + \
+ dst[n >> 1 - 1];
+ return (tmp + (tmp >> 31)) >> 1;
+ }
+
+ return dst[0];
+}
+#+END_SRC
+
+I've started to see this =(tmp + (tmp >> 31)) >> 1= idiom rather frequently, so I
+decided to finally look it up, coming across [[https://stackoverflow.com/questions/40638335/why-does-the-compiler-generate-a-right-shift-by-31-bits-when-dividing-by-2][this]] Stack Overflow answer. I'm
+glad I did, because realizing that it carries out signed integer division by two
+makes this exercise far more clear.
+
+#+BEGIN_SRC c
+#include <string.h>
+#include <stdlib.h>
+
+int f1(int *a, int *b)
+{
+ return *a > *b ? 0 : -1;
+}
+
+int f_main(void *src, int n)
+{
+ char *dst;
+
+ dst = malloc(n * sizeof(int));
+ memcpy(dst, src, n * sizeof(int));
+ qsort(dst, n, sizeof(int), f1);
+
+ if (n > 1) {
+ return (dst[n / 2] + dst[n / 2 - 1]) / 2;
+ }
+
+ return dst[0];
+}
+#+END_SRC
+
+=f_main= returns the [[https://en.wikipedia.org/wiki/Median][median]] of a set of values.
+
+* Challenge #30
+
+I have, once again, skipped another challenge that was being listed as "level
+2," which brings us to the thirtieth challenge. This one is strikingly different
+from the other challenges I've covered here; rather than being asked to describe
+what a program does, the instruction read:
+
+"This program requires a password. Try to find it.
+
+As an additional exercise, try to change the password by patching the executable
+file. Also try using one with a different length. What is the shortest possible
+password here?
+
+Also try to crash the program using only string input."
+
+We're given several links to downloads. Binaries are provided for 32-bit
+Microsoft Windows, Mac OS X, and i386/mips Linux. I went with i386 Linux, as I'd
+be able to run the challenge natively.q
+
+#+BEGIN_SRC
+jakob@Epsilon /tmp $ sha256sum password1
+96b8110208d61c7ac586910ebad22ef2e4bbeb867e6d6429967846698b9d02fc password1
+#+END_SRC
+
+Being faced with a binary, I was tempted to use this as an opportunity to try
+out [[https://ghidra-sre.org/][Ghidra]], but while I waited for OpenJDK 11 to download, I peered inside with
+radare2 and decided that it wasn't worth the trouble. Here's the disassembly,
+according to radare:
+
+#+BEGIN_SRC
+[0x080484ed]> pdf
+ ;-- eip:
+┌ (fcn) main 149
+│ main ();
+│ ; var int local_4h @ esp+0x4
+│ ; var int local_1ch @ esp+0x1c
+│ ; var int local_9ch @ esp+0x9c
+│ ; DATA XREF from 0x08048407 (entry0)
+│ 0x080484ed 55 pushl %ebp
+│ 0x080484ee 89e5 movl %esp, %ebp
+│ 0x080484f0 83e4f0 andl $0xfffffff0, %esp
+│ 0x080484f3 81eca0000000 subl $0xa0, %esp
+│ 0x080484f9 65a114000000 movl %gs:0x14, %eax ; [0x14:4]=-1 ; 20
+│ 0x080484ff 8984249c0000. movl %eax, local_9ch
+│ 0x08048506 31c0 xorl %eax, %eax
+│ 0x08048508 c70424208604. movl $str.enter_password:, 0(%esp) ; [0x8048620:4]=0x65746e65 ; "enter password:"
+│ 0x0804850f e89cfeffff calll sym.imp.puts ; int puts(const char *s)
+│ 0x08048514 8d44241c leal local_1ch, %eax ; 0x1c ; 28
+│ 0x08048518 89442404 movl %eax, local_4h
+│ 0x0804851c c70424308604. movl $0x8048630, 0(%esp) ; [0x8048630:4]=0x6e007325
+│ 0x08048523 e8b8feffff calll sym.imp.__isoc99_scanf
+│ 0x08048528 83f801 cmpl $1, %eax ; 1
+│ ┌─< 0x0804852b 740c je 0x8048539
+│ │ 0x0804852d c70424338604. movl $str.no_password_supplied, 0(%esp) ; [0x8048633:4]=0x70206f6e ; "no password supplied"
+│ │ 0x08048534 e877feffff calll sym.imp.puts ; int puts(const char *s)
+│ │ ; JMP XREF from 0x0804852b (main)
+│ └─> 0x08048539 c74424044886. movl $str.metallica, local_4h ; [0x8048648:4]=0x6174656d ; "metallica"
+│ 0x08048541 8d44241c leal local_1ch, %eax ; 0x1c ; 28
+│ 0x08048545 890424 movl %eax, 0(%esp)
+│ 0x08048548 e843feffff calll sym.imp.strcmp ; int strcmp(const char *s1, const char *s2)
+│ 0x0804854d 85c0 testl %eax, %eax
+│ ┌─< 0x0804854f 750e jne 0x804855f
+│ │ 0x08048551 c70424528604. movl $str.password_is_correct, 0(%esp) ; [0x8048652:4]=0x73736170 ; "password is correct"
+│ │ 0x08048558 e853feffff calll sym.imp.puts ; int puts(const char *s)
+│ ┌──< 0x0804855d eb0c jmp 0x804856b
+│ ││ ; JMP XREF from 0x0804854f (main)
+│ │└─> 0x0804855f c70424668604. movl $str.password_is_not_correct, 0(%esp) ; [0x8048666:4]=0x73736170 ; "password is not correct"
+│ │ 0x08048566 e845feffff calll sym.imp.puts ; int puts(const char *s)
+│ │ ; JMP XREF from 0x0804855d (main)
+│ └──> 0x0804856b 8b94249c0000. movl local_9ch, %edx ; [0x9c:4]=-1 ; 156
+│ 0x08048572 653315140000. xorl %gs:0x14, %edx
+│ ┌─< 0x08048579 7405 je 0x8048580
+│ │ 0x0804857b e820feffff calll sym.imp.__stack_chk_fail ; void __stack_chk_fail(void)
+│ │ ; JMP XREF from 0x08048579 (main)
+│ └─> 0x08048580 c9 leave
+└ 0x08048581 c3 retl
+#+END_SRC
+
+As you can see, this is just like any other "easy crackme." A simple string
+comparison. radare2 doesn't automatically decode 0x8048630 as a string, but it's
+trivial to obtain its value.
+
+#+BEGIN_SRC
+:> psz @ 0x8048630
+%s
+#+END_SRC
+
+Translating it into C is similarly trivial.
+
+#+BEGIN_SRC c
+#include <stdio.h>
+#include <string.h>
+
+int main(void)
+{
+ char buf[128];
+ puts("enter password:");
+ if (scanf("%s", buf) != 1) {
+ puts("no password supplied");
+ }
+ if (strcmp(buf, "metallica") == 0) {
+ puts("password is correct");
+ } else {
+ puts("password is not correct");
+ }
+}
+#+END_SRC
+
+I do have to complement Yurichev's choice of strong passwords. \m/
+
+One may wonder where I pulled =128= from. Our stack layout looks something like
+this:
+
+#+BEGIN_SRC prog
++-------------------------------------+
+|%esp |
+|Scratch space for function arguments.|
++-------------------------------------+
+|%esp + 0x1c |
+|Buffer starts here |
+|... |
+|Buffer ends here |
++-------------------------------------+
+|%esp + 0x9c |
+|Stack canary, perhaps? |
++-------------------------------------+
+|%esp + I DON'T CARE ANYMORE |
+|Here be dragons. |
++-------------------------------------+
+#+END_SRC
+
+radare2 is kind enough to automatically name local variables according to their
+position in the stack layout, so I was able to derive this from the names
+=local_1ch= and =local_9ch=. =local_4h= isn't really a local variable -- it looks like
+one, but that's just how the compiler decided to set up arguments for the
+various function calls (dereferencing the stack pointer, as opposed to using
+=push=). Anyway, subtracting =0x9c= from =0x1c= gets you 128 -- hence, the buffer size
+in my translation.
+
+It's pretty easy to patch the password, since =strcmp= operates on C strings. Just
+patch the characters. No sort of length needs to be adjusted since they're
+null-terminated. The shortest possible password would be zero characters long,
+which would be achieved by patching in a null byte at the 'm' in "metallica".
+This can be done however you like, though radare makes it easy if you've opened
+the file in "write mode": just seek to the location of the 'm' and =wx 00=.
+Crashing the program is similarly easy, since there are no bounds checks on the
+call to =scanf=.
+
+#+BEGIN_SRC
+jakob@Epsilon /tmp $ python -c "print('a' * 256)" | ./test
+enter password:
+password is not correct
+Segmentation fault
+#+END_SRC
+
+* Challenge #31
+
+Yowch. We're only given disassemblies from MSVC this time.
+
+#+BEGIN_SRC c
+double f(double a, int b)
+{
+ double cur;
+ cur = 1.0;
+ while (((double) (((int) (cur - a)) - b)) <= 0.001)
+ cur = (a + 1.0) * 0.5;
+ return cur;
+}
+#+END_SRC
+
+Once again, I deferred to [[https://float.exposed/][float.exposed]] to decode the floating-point constant
+values. =__real@3ff0000000000000= is =1.0=, =__real@3f50624dd2f1a9fc= is approximately
+=0.001=, and =__real@3fe0000000000000= is =0.5=. I also needed to look up most of the
+SIMD instructions. =cvttsd2si= converts a double to an int, =cdq= converts an int
+into a long, =cvtdq2pd= converts an int to a double, and =comisd= is comparable to
+=cmp=.
+
+This converges for very few values. Which is a pain, since this translation
+gives me some very promising output in [[https://godbolt.org/][Compiler Explorer]]. But considering the
+value that the loop gets stuck on, I suspect that =f= averages =a= and =b=.
+
+* Challenge #32
+
+We're given a hint that, "[t]his is a standard C library function. The source
+code is taken from MSVC 2010."
+
+#+BEGIN_SRC c
+#include <stddef.h>
+
+char *f(char *a, char *b)
+{
+ char *cur;
+ char *a_cur;
+ char *b_cur;
+
+ cur = a;
+
+ if (*b == '\0') {
+ return a;
+ }
+
+ while (*cur != '\0') {
+ a_cur = cur;
+ b_cur = b;
+
+ while (*a_cur != '\0' && *b_cur != '\0' && *a_cur == *b_cur) {
+ a_cur++;
+ b_cur++;
+ }
+
+ if (*b_cur == '\0') {
+ return cur;
+ }
+
+ cur++;
+ }
+
+ return NULL;
+}
+#+END_SRC
+
+I think the translation makes the purpose of this function reasonably clear, but
+the hint means I can verify my work against C's tiny standard library. =f= is
+obviously one of the library's [[https://en.wikipedia.org/wiki/C_string_handling][string functions]]. Can you guess which one?
+
+(My answer is that =f= is an implementation of =strstr=.)
+
+* Challenge #33
+
+What gave it away for me this time was the "crypto" tag. I stopped in my
+translation efforts about here,
+
+#+BEGIN_SRC c
+void f(void *a, void *b, void *c)
+{
+ int mushroom; // _k0
+ int bean; // _k1
+ int tomato; // _k2
+ int corn; // _k3
+
+ // eax = a[0]
+ // ecx = a[1]
+
+ mushroom = b[0];
+ bean = b[1];
+
+ // esi = b[3];
+ // edx = 0;
+
+ tomato = b[2];
+ corn = b[3];
+
+ // edi = 32;
+
+ // LL8
+ esi = ecx >> 5 + bean;
+ ebx = ecx << 4 + mushroom;
+ edx -= 0x61c88647;
+
+ esi ^= ebx;
+ ebx = ecx + edx;
+ esi ^= ebx;
+
+ eax += esi;
+
+ esi = eax >> 5 + corn;
+ ebx = eax << 4 + tomato;
+
+ esi ^= ebx;
+ ebx = eax + edx;
+ esi ^= ebx;
+
+ ecx += esi;
+ edi--;
+
+ // When edi == 0: c[0] = eax, c[1] = ecx
+}
+#+END_SRC
+
+and decided to do a search for '0x61c88647 hash'. This yields a few interesting
+results, such as [[https://stackoverflow.com/questions/38994306/what-is-the-meaning-of-0x61c88647-constant-in-threadlocal-java][one]] describing the constant used in ThreadLocal.java's
+implementation Fibonacci hashing and [[https://softwareengineering.stackexchange.com/questions/63595/tea-algorithm-constant-0x9e3779b9-said-to-be-derived-from-golden-ratio-but-the][another]] describing the constants used in
+the Tiny Encryption Algorithm.
+
+This immediately set off bells for me. I read Bruce Schneier's /Applied
+Cryptography/ some years back and was instantly reminded that TEA uses [[https://en.wikipedia.org/wiki/Block_cipher#Operations][ARX]] with
+shifts of =5= and =4=. If you pull up Wikipedia's reference code for TEA encryption,
+you'll be greeted with the following:
+
+#+BEGIN_SRC c
+void encrypt (uint32_t v[2], uint32_t k[4]) {
+ uint32_t v0=v[0], v1=v[1], sum=0, i; /* set up */
+ uint32_t delta=0x9E3779B9; /* a key schedule constant */
+ uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3]; /* cache key */
+ for (i=0; i<32; i++) { /* basic cycle start */
+ sum += delta;
+ v0 += ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
+ v1 += ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
+ } /* end cycle */
+ v[0]=v0; v[1]=v1;
+}
+#+END_SRC
+
+Armed with this, I can confidently say that =f= is an implementation of TEA
+encryption with a schedule constant of =0x61c88647=.
+
+* Challenge #34
+
+Another crypto challenge. This time, we're told that "[t]his is a well-known
+cryptographic algorithm from the past." The disassembly was simple enough that I
+thought to translate it into standard mathematical notation rather than C, but
+it turned out to be far less helpful than the equivalent C.
+
+#+BEGIN_SRC c
+uint16_t f(uint16_t a)
+{
+ uint16_t tmp;
+
+ tmp = a << 2;
+ tmp ^= a;
+ tmp <<= 1;
+ tmp ^= a;
+ tmp <<= 2;
+ tmp ^= a;
+
+ return ((tmp & 32) << 10) | (a >> 1);
+}
+#+END_SRC
+
+That said, I'm not familiar with the particular algorithm. There's a clear
+pattern, but I'm not sure where to start looking. Is it a hash function? Some
+kind of bastardized XOR encryption? Who knows.
+
+* Challenge #35
+
+This was a tough one. I'll give my initial translation to C and explain where I
+went wrong:
+
+#+BEGIN_SRC c
+#include <strings.h>
+#include <stdio.h>
+
+int f(int x, int y)
+{
+ int a, b;
+
+ if (x == 0) {
+ return y;
+ }
+
+ if (y == 0) {
+ return x;
+ }
+
+ a = x >> ffs(x);
+ b = y >> ffs(y);
+
+ while (a != b) {
+ if (a < b) {
+ SWAP(a, b);
+ }
+
+ if (a == 1) {
+ break;
+ }
+
+ b = (b - a) >> ffs(b - a);
+ }
+
+ return a << ffs(x | y);
+}
+#+END_SRC
+
+One thing worth remarking on in the disassembly is this:
+
+#+BEGIN_SRC asm
+ xor esi, edx
+ xor edx, esi
+ xor esi, edx
+#+END_SRC
+
+This is the [[https://en.wikipedia.org/wiki/XOR_swap_algorithm][XOR swap algorithm]]. In an attempt to make the translation more
+clear, I replaced it with a (non-existent) =SWAP= macro. =ffs= is also a POSIX
+extension that [[https://stackoverflow.com/questions/757059/position-of-least-significant-bit-that-is-set][corresponds nicely]] to the =bsf= instruction.
+
+The issue? I've been reading these MSVC disassemblies wrong the whole time. Take
+this instruction, for example: =mov edx, DWORD PTR _y$[esp+4]=. I'd never actually
+done out the calculations. As it turns out, =_rt$2[esp+8]= aliases with =y=. I
+thought that =_rt$2= was a distinct variable and that the compiler was storing to
+some local variable but never using it. This isn't the case, hence why the
+translation doesn't work as intended.
+
+What I need to start doing for these MSVC disassemblies is translating them into
+something I can assemble.
+
+#+BEGIN_SRC asm
+global f
+f:
+ push ecx
+ push esi
+ mov esi, DWORD [esp+12]
+ test esi, esi
+ jne init
+ mov eax, DWORD [esp+16]
+ pop esi
+ pop ecx
+ ret
+init:
+ mov edx, DWORD [esp+16]
+ mov eax, esi
+ test edx, edx
+ je exit
+ or eax, edx
+ push edi
+ bsf edi, eax
+ bsf eax, esi
+ mov ecx, eax
+ mov DWORD [esp+8], eax
+ bsf eax, edx
+ shr esi, cl
+ mov ecx, eax
+ shr edx, cl
+ mov DWORD [esp+16], eax
+ cmp esi, edx
+ je return
+lp:
+ jbe skip
+ xor esi, edx
+ xor edx, esi
+ xor esi, edx
+skip:
+ cmp esi, 1
+ je return
+ sub edx, esi
+ bsf eax, edx
+ mov ecx, eax
+ shr edx, cl
+ mov DWORD [esp+16], eax
+ cmp esi, edx
+ jne lp
+return:
+ mov ecx, edi
+ shl esi, cl
+ pop edi
+ mov eax, esi
+exit:
+ pop esi
+ pop ecx
+ ret 0
+#+END_SRC
+
+Actually, I should be doing this for all of the challenges... Anyway, observing
+a few test values for =f=:
+
+#+BEGIN_SRC prog
+f(1, 1) = 1
+f(1, 2) = 1
+f(1, 3) = 1
+f(1, 4) = 1
+f(1, 5) = 1
+f(1, 6) = 1
+f(1, 7) = 1
+f(1, 8) = 1
+f(1, 9) = 1
+...
+f(1, 252) = 1
+f(1, 253) = 1
+f(1, 254) = 1
+f(1, 255) = 1
+f(2, 1) = 1
+f(2, 2) = 2
+f(2, 3) = 1
+f(2, 4) = 2
+f(2, 5) = 1
+f(2, 6) = 2
+f(2, 7) = 1
+f(2, 8) = 2
+f(2, 9) = 1
+f(2, 10) = 2
+f(2, 11) = 1
+f(2, 12) = 2
+...
+f(9, 1) = 1
+f(9, 2) = 1
+f(9, 3) = 3
+f(9, 4) = 1
+f(9, 5) = 1
+f(9, 6) = 3
+f(9, 7) = 1
+f(9, 8) = 1
+f(9, 9) = 9
+...
+f(10, 1) = 1
+f(10, 2) = 2
+f(10, 3) = 1
+f(10, 4) = 2
+f(10, 5) = 5
+f(10, 6) = 2
+f(10, 7) = 1
+f(10, 8) = 2
+f(10, 9) = 1
+f(10, 10) = 10
+f(10, 11) = 1
+f(10, 12) = 2
+...
+#+END_SRC
+
+It took me a while, but I eventually noticed the pattern. =f= is the [[https://en.wikipedia.org/wiki/Greatest_common_divisor][greatest
+common divisor]] function.
diff --git a/org/Writeups for Dennis Yurichev's Reverse Engineering Challenges (#36-)/challenges-re-writeups-4.org b/org/Writeups for Dennis Yurichev's Reverse Engineering Challenges (#36-)/challenges-re-writeups-4.org
new file mode 100644
index 0000000..a3a1990
--- /dev/null
+++ b/org/Writeups for Dennis Yurichev's Reverse Engineering Challenges (#36-)/challenges-re-writeups-4.org
@@ -0,0 +1,996 @@
+#+TITLE: Writeups for Dennis Yurichev's Reverse Engineering Challenges (#36-)
+#+TAGS: writeup, reverse-engineering, x86
+
+* Challenge #36
+
+The description this time describes that this is "[a] well-known algorithm
+again. What does it do? Also, take notice that the code for x86 uses FPU, but
+SIMD instructions are used instead in the x64 code. That's OK."
+
+#+BEGIN_SRC c
+long state = 0x12345678;
+
+float f1(void)
+{
+ state = state * 0x19660d + 0x3c6ef35f;
+ return ((float) ((state & 0x7fffff) | 0x40000000)) - 3.0f;
+}
+
+void f(void)
+{
+ int i;
+ int count;
+ float a;
+ float b;
+
+ for (i = 0, count = 0; i < 1000000; i++) {
+ a = f1();
+ b = f1();
+
+ if (a * a + b * b > 1.0f) {
+ count++
+ }
+ }
+
+ ((float) (((double) count) * 2.25) / 10.9073486328125);
+}
+#+END_SRC
+
+I thought this was a lame challenge. The floating point operations of =f1= have
+been optimized to the point that it's unrecognizable, so if you aren't familiar
+with the standard bit-twiddling tricks that GCC uses to speed up floating-point
+operations, you aren't going to be able to come up with anything meaningful --
+especially since neither function take parameters. My response? =f= returns the
+constant value =206282.937500=.
+
+I thought this might be the [[https://en.wikipedia.org/wiki/Fast_inverse_square_root][fast inverse square root]], but I don't believe it is.
+
+* Challenge #37
+
+Ah, another challenge for which the description is that it is a "[w]ell-known
+function" and only x86 disassembly given is from MSVC. Fortunately, this one is
+not too difficult.
+
+#+BEGIN_SRC c
+int f(int a, int b)
+{
+ int i;
+ int n;
+
+ if (a == 0) {
+ return b + 1;
+ }
+
+ n = b;
+ i = a;
+
+ do {
+ if (n == 0) {
+ n = 1;
+ } else {
+ n = f(i, n - 1);
+ }
+ } while (--i != 0);
+
+ return n + 1;
+}
+#+END_SRC
+
+This is the Ackermann function, albeit using a loop rather than a direct
+translation of the Ackermann–Péter function to code.
+
+To answer Yurichev's additional questions, a stack overflow occurs if 4 and 2
+are supplied as input because those are [[https://www.wolframalpha.com/input/?i=Ackermann(4,2)][absurd parameters for this function]], and
+this function bears the error of not enforcing the constraints given in the
+definition of the Ackermann–Péter function.
+
+* Challenge #38
+
+Ah, fun. Another challenge provided as a binary.
+
+#+BEGIN_SRC prog
+jakob@Upsilon ~ $ sha256sum 17
+8f73f329e0988968a9fa40f61da906e83b46817bcb5c0e93f7e95aa74c30e8e0 17
+jakob@Upsilon ~ $ file 17
+17: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.18, BuildID[sha1]=bdeac54f2d98db38d7a63a43f1c41857432686c4, stripped
+#+END_SRC
+
+I stopped a bit early because, for once, the question wasn't "[w]hat does this
+code do?", but was instead, "[t]his program prints some information to stdout,
+each time different. What is that?"
+
+#+BEGIN_SRC c
+#include <stdlib.h>
+#include <time.h>
+
+static time_t current_time;
+
+int fcn.004006c4(void)
+{
+ return current_time = current_time * 0x19660d * 0x3c6ef35f;
+}
+
+int main(int argc, char **argv)
+{
+ char *s2;
+ void **s1;
+ int var_1ch;
+ int var_18h;
+ int var_11h;
+
+ s2 = malloc(230);
+ s1 = malloc(80);
+ var_1ch = 0;
+
+ while (var_1ch <= 9) {
+ s1[var_1ch++] = calloc(230, 1);
+ }
+
+ current_time = time(NULL);
+
+ var_1ch = 0;
+ while (var_1ch <= 230) {
+ var_11h = fcn.00400b60(fcn.004006c4());
+ s2[var_1ch++] = var_11h & 1;
+ }
+
+ var_1ch = 0;
+ while (1) {
+ fcn.00400970(s2, 230);
+ fcn.0040072a(s2, 230, 110);
+
+ var_18h = 0;
+ while (var_18h <= 8) {
+ if (!memcmp(s1[var_18h++], s2, 230)) {
+ exit(0);
+ }
+ }
+
+ var_18h = 0;
+ while (var_18h <= 8) {
+ memcpy(s1[var_18h], s1[++var_18h], 230);
+ }
+
+ memcpy(s1[9], s2, 230);
+ var_1ch++;
+ }
+}
+#+END_SRC
+
+The only nondeterminism I saw in the disassembly was from =time=. The actual
+output of the program is incomprehensible -- appearing to be some sort of
+ASCII-art fractal. For this reason, I'm concluding that the information printed
+to =stdout= is the current time.
+
+* Challenge #39
+
+The description for this challenge had me quite excited. "This program requires
+a password. Find it." Yes, I love crackmes!
+
+#+BEGIN_SRC prog
+jakob@Upsilon ~ $ sha256sum password2
+8c8365f316de896c453511c5f484755600208b87ad0f1595a2900cbf5a36db24 password2
+#+END_SRC
+
+=main= is simple enough that I feel I can omit the: it reads in a password with
+=scanf=, and then checks it with the following snippet.
+
+#+BEGIN_SRC prog
+│ 0x0804853e e87affffff calll fcn.080484bd
+│ 0x08048543 3df8010000 cmpl $0x1f8, %eax ; 504
+#+END_SRC
+
+We want to find some =password= such that =fcn.080484bd(password) = 0x1f8=.
+Peeking into =fcn.080484bd=, I was a little disappointed.
+
+#+BEGIN_SRC prog
+┌ (fcn) fcn.080484bd 46
+│ fcn.080484bd (int32_t arg_8h);
+│ ; var int32_t var_4h @ ebp-0x4
+│ ; arg int32_t arg_8h @ ebp+0x8
+│ ; CALL XREF from main @ 0x804853e
+│ 0x080484bd 55 pushl %ebp
+│ 0x080484be 89e5 movl %esp, %ebp
+│ 0x080484c0 83ec10 subl $0x10, %esp
+│ 0x080484c3 c745fc000000. movl $0, var_4h
+│ ┌─< 0x080484ca eb10 jmp 0x80484dc
+│ │ ; CODE XREF from fcn.080484bd @ 0x80484e4
+│ ┌──> 0x080484cc 8b4508 movl arg_8h, %eax ; [0x8:4]=-1 ; 8 ; edx
+│ ╎│ 0x080484cf 0fb600 movzbl 0(%eax), %eax
+│ ╎│ 0x080484d2 0fbec0 movsbl %al, %eax
+│ ╎│ 0x080484d5 0145fc addl %eax, var_4h
+│ ╎│ 0x080484d8 83450801 addl $1, arg_8h ; [0x8:4]=-1 ; 1
+│ ╎│ ; CODE XREF from fcn.080484bd @ 0x80484ca
+│ ╎└─> 0x080484dc 8b4508 movl arg_8h, %eax ; [0x8:4]=-1 ; 8 ; edx
+│ ╎ 0x080484df 0fb600 movzbl 0(%eax), %eax
+│ ╎ 0x080484e2 84c0 testb %al, %al
+│ └──< 0x080484e4 75e6 jne 0x80484cc ; likely
+│ 0x080484e6 8b45fc movl var_4h, %eax ; edx
+│ 0x080484e9 c9 leave ; edx
+└ 0x080484ea c3 retl ; edx
+#+END_SRC
+
+Do I even need to provide a C translation? The disassembly should be glaringly
+obvious: this "check" function just returns the sum of the string argument's
+individual bytes. Coming up with a valid password is trivial.
+
+#+BEGIN_SRC prog
+jakob@Upsilon ~ $ ./password2
+enter password:
+AAAAAAA1
+password is correct
+#+END_SRC
+
+The problem also suggests that I "try to change the password by patching the
+executable file," but this doesn't invokve anything more than changing the word
+at =0x08048544=.
+
+* Challenge #41
+
+The question this time is: "[t]his program prints some numbers to stdout. What
+is it?"
+
+#+BEGIN_SRC prog
+jakob@Upsilon ~ $ file problem
+problem: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.24, BuildID[sha1]=a89ecf1ae2f2474548d09ca3ebccd7db4162fa1e, stripped
+jakob@Upsilon ~ $ sha256sum problem
+ab3864e8fceeffe4b166cb7481332e88a1fe90b6a406e635c6921119c91a00fd problem
+#+END_SRC
+
+I wrote a C translation without running the program. In retrospect, this wasn't
+a bad idea. The calculation is a function of some integer, but the binary spits
+out subsequent numbers with no sort of delimitation. Having the C translation
+means that I could add a =printf("\n");= after the call to =fcn_00400536(var_4h++);=
+and get output similar to the following:
+
+#+BEGIN_SRC prog
+jakob@Upsilon ~ $ /tmp/test
+1
+
+2
+1
+
+3
+10
+5
+16
+8
+4
+2
+1
+
+4
+2
+1
+
+5
+16
+8
+4
+2
+1
+#+END_SRC
+
+Here's the C translation.
+
+#+BEGIN_SRC c
+void fcn_00400536(int a)
+{
+ printf("%d\n", a);
+ while (a != 1) {
+ if (a & 1 != 0) {
+ a = a * 3 + 1;
+ } else {
+ a >>= 1;
+ }
+ printf("%d\n", a);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ int var_4h;
+ var_4h = 1;
+ while (var_4h <= 15) {
+ fcn_00400536(var_4h++);
+ }
+ return var_4h;
+}
+#+END_SRC
+
+We can pick any interesting sequence and plug it into [[https://oeis.org/search?q=3%2C10%2C5%2C16%2C8%2C4%2C2%2C1&language=english&go=Search][OEIS]], which identifies
+=fcn_00400536= as "A070165: Irregular triangle read by rows giving trajectory of n
+in Collatz problem." Ah, yes. This is looking familiar now. This is the famously
+unsolved problem in mathematics, the [[https://en.wikipedia.org/wiki/Collatz_conjecture][Collatz conjecture]].
+
+* Challenge #43
+
+#+BEGIN_SRC prog
+jakob@Upsilon ~ $ file unknown_utility_2_3
+unknown_utility_2_3: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.24, BuildID[sha1]=cb74037dd37694879f6250bfb5623c273ef68ca6, stripped
+jakob@Upsilon ~ $ sha256sum unknown_utility_2_3
+9d3df3be78f21971059ba2d9973a1358865ccbe2f47f78fc5800779d6f6083fe unknown_utility_2_3
+#+END_SRC
+
+I really wasn't feeling it today, so I took the easy way out and just ran the
+binary provided on a test file. It spits out a floating point number, which
+seems to decrease as the file becomes less interesting. Just a hunch, but maybe
+it's binary entropy?
+
+#+BEGIN_SRC prog
+jakob@Upsilon ~ $ python -c "print('a' * 256)" > test.txt
+jakob@Upsilon ~ $ ./unknown_utility_2_3 test.txt
+0.036753
+jakob@Upsilon ~ $ rahash2 -a entropy test.txt
+test.txt: 0x00000000-0x00000100 entropy: 0.03675295
+jakob@Upsilon ~ $ dd bs=256 count=1 if=/dev/urandom > test.txt
+1+0 records in
+1+0 records out
+256 bytes copied, 7.0438e-05 s, 3.6 MB/s
+jakob@Upsilon ~ $ ./unknown_utility_2_3 test.txt
+7.069718
+jakob@Upsilon ~ $ rahash2 -a entropy test.txt
+test.txt: 0x00000000-0x000000ff entropy: 7.06971784
+#+END_SRC
+
+Well, that's an answer I'm certainly happy with.
+
+* Challenge #48
+
+It looks like we're starting to get into the realm of =win32=. The question for
+this challenge is, "[w]hat does this win32-function do?"
+
+#+BEGIN_SRC asm
+main:
+ push 0xFFFFFFFF
+ call MessageBeep
+ xor eax,eax
+ retn
+#+END_SRC
+
+This is pretty simple. It's a wrapper for =MessageBeep=. According to [[https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-messagebeep][MSDN]], the
+=0xFFFFFFFF= parameter produces "[a] simple beep. If the sound card is not
+available, the sound is generated using the speaker."
+
+* Challenge #49
+
+Another rather simple one. The disassembly for this challenge is given in AT&T
+syntax, which is my preferred way of reading x86 assembly.
+
+#+BEGIN_SRC asm
+main:
+ pushq %rbp
+ movq %rsp, %rbp
+ movl $2, %edi
+ call sleep
+ popq %rbp
+ ret
+#+END_SRC
+
+A wrapper around =sleep=, presumably the only provided by =unistd.h=, calling it
+with an argument of two seconds.
+
+* Challenge #52
+
+Another simple disassembly:
+
+#+BEGIN_SRC asm
+$SG3103 DB '%d', 0aH, 00H
+
+_main PROC
+ push 0
+ call DWORD PTR __imp___time64
+ push edx
+ push eax
+ push OFFSET $SG3103 ; '%d'
+ call DWORD PTR __imp__printf
+ add esp, 16
+ xor eax, eax
+ ret 0
+_main ENDP
+#+END_SRC
+
+To copy straight from [[https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/time-time32-time64?view=vs-2019][MSDN]], this prints the number of "seconds elapsed since
+midnight (00:00:00), January 1, 1970, Coordinated Universal Time (UTC)."
+
+MSDN also answers the follow-up question: "=time= is a wrapper for =_time64= and
+=time_t= is, by default, equivalent to =__time64_t=. If you need to force the
+compiler to interpret =time_t= as the old 32-bit =time_t=, you can define
+=_USE_32BIT_TIME_T=. This is not recommended because your application may fail
+after January 18, 2038; the use of this macro is not allowed on 64-bit
+platforms."
+
+* Challenge #53
+
+I thought this was an interesting challenge. "This code, compiled in Linux
+x86-64 using GCC is crashing while execution (segmentation fault). It's also
+crashed if compiled by MinGW for win32. However, it works in Windows environment
+if compiled by MSVC 2010 x86. Why?"
+
+#+BEGIN_SRC c
+#include <string.h>
+#include <stdio.h>
+
+void alter_string(char *s)
+{
+ strcpy (s, "Goodbye!");
+ printf ("Result: %s\n", s);
+};
+
+int main()
+{
+ alter_string ("Hello, world!\n");
+};
+#+END_SRC
+
+The code is modifying a string constant, which GCC tends to put in a read-only
+memory segment (=.rodata=) in the resultant executable. Writing to a read-only
+memory segment will cause a segmentation fault. I haven't tested it, but the
+question statement makes me think that MSVC puts string constants in a writable
+segment, so this would work just fine.
+
+* Challenge #54
+
+No disassembly is given for this challenge. The only thing on the page is "[w]hy
+isn't the x86 LOOP instruction used by modern compilers anymore?" Some searching
+yields [[https://stackoverflow.com/questions/35742570/why-is-the-loop-instruction-slow-couldnt-intel-have-implemented-it-efficiently/35743699#35743699][this Stack Overflow answer]]. Basically, =loop= is from the time before x86
+became horribly complex, and so on modern processors, it's slow.
+
+* Challenge #56
+
+I decided to skip challenge #55, as it would really just be a walkthrough of
+which r2 commands I used. Challenge #56 is not particularly difficult. I went
+along with the disassembly from MSVC.
+
+#+BEGIN_SRC c
+#include <stdio.h>
+
+int main(void)
+{
+ int n;
+ n = 100;
+ do {
+ printf("%d", n);
+ } while (n-- != 0);
+ return 0;
+}
+#+END_SRC
+
+The code prints the integers from 100 to 0.
+
+* Challenge #57
+
+This is almost the same disassembly as last time.
+
+#+BEGIN_SRC c
+#include <stdio.h>
+
+int main(void)
+{
+ int n;
+ n = 1;
+ do {
+ printf("%d", n);
+ n += 3;
+ } while (n < 100);
+ return 0;
+}
+#+END_SRC
+
+* Challenge #58
+
+This time, we're fortunate enough to be given a disassembly from GCC 4.8.1,
+albeit with =-O3=.
+
+#+BEGIN_SRC c
+int f(char *a)
+{
+ int count;
+ count = 0;
+ while (*a != '\0') {
+ if (*a++ == ' ') {
+ count++;
+ }
+ }
+ return count;
+}
+#+END_SRC
+
+=f= counts the number of spaces in a given string. As an aside, when I was first
+learning to read assembly, I recall someone describing =-O3= as "unintelligible to
+humans." The more reverse engineering I've done, the more I've realized that the
+optimizations at that level tend to not be as absurd as people make them out to
+be. I considered this to be an easy challenge.
+
+* Challenge #59
+
+This one was /really/ easy.
+
+#+BEGIN_SRC asm
+_a$ = 8
+_f PROC
+ mov ecx, DWORD PTR _a$[esp-4]
+ lea eax, DWORD PTR [ecx*8]
+ sub eax, ecx
+ ret 0
+_f ENDP
+#+END_SRC
+
+The function just returns =a * 7=. I suspect the multiplication followed by
+subtraction was an optimization, since multiplication by a power of two can be
+implemented as a left shift.
+
+* Challenge #61
+
+Perhaps the most difficult part of this challenge was going out my way to [[https://float.exposed/0x4014000000000000][ensure
+that the constant really was 5.0]].
+
+#+BEGIN_SRC c
+double f(double a, double b, double c, double d, double e)
+{
+ return (a + b + c + d + e) / 5;
+}
+#+END_SRC
+
+=f= simply averages five numbers.
+
+* Challenge #62
+
+The challenge notes that the compiler was optimizing for space, which may
+explain the pointless nested loop.
+
+#+BEGIN_SRC c
+void f(float *a, float *b, float *c)
+{
+ int i;
+ int j;
+
+ long coffee;
+ long cake;
+
+ coffee = a - b;
+ cake = c - b;
+
+ for (i = 200; i > 0; i--) {
+ for (j = 100; j > 0; j--) {
+ b[cake] = b[0] + b[coffee];
+ b += 8;
+ }
+ }
+}
+#+END_SRC
+
+=f= adds 20000 elements from =a= and =b=, storing their sums in =c=.
+
+* Challenge #64
+
+I was swamped with preparing for finals this weekend, so I decided to skip
+challenge #64 in favor of something a bit more manageable. The question for this
+one is, "[a]n array of array[x][y] form is accessed here. Try to determine the
+dimensions of the array, at least partially, by finding y."
+
+#+BEGIN_SRC c
+double f(double *array, int x, int y)
+{
+ return array[y + x * 15];
+}
+#+END_SRC
+
+The array has some number of rows each containing 15 elements.
+
+* Challenge #65
+
+#+BEGIN_SRC c
+int f(int *array, int x, int y, int z)
+{
+ return array[z + 5 * 16 * (y + 4 * 15 * x)];
+}
+#+END_SRC
+
+Assuming an array of integers, the dimensions of the array are 15 x 20 x ...
+
+* Challenge #74
+
+#+BEGIN_SRC prog
+jakob@Epsilon ~ $ sha256sum challenge74
+6d2ac11d1e6200d6a2cca988189764b6acdb7811d24619e8e66f1796c8c27394 challenge74
+jakob@Epsilon ~ $ file challenge74
+challenge74: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.24, BuildID[sha1]=7fa3bd4aa738bced5aaccb161090818646e07704, stripped
+#+END_SRC
+
+#+BEGIN_SRC prog
+2Z7A7-EK270-TMHR4-BHC71-CEB52-HELL0-HELL0-EONP9
+2Z7A7-6I7R9-MZGO9-FDQJ3-JN0Q6-HELL0-HELL0-72KJ9
+#+END_SRC
+
+#+BEGIN_SRC c
+// WARNING: Could not reconcile some variable overlaps
+// WARNING: [r2ghidra] Detected overlap for variable var_20h// WARNING: [r2ghidra] Failed to match type signed int64_t for variable var_10h to Decompiler type: Unknown type
+// identifier signed
+// WARNING: [r2ghidra] Detected overlap for variable var_ch
+// WARNING: [r2ghidra] Failed to match type signed int64_t for variable var_8h to Decompiler type: Unknown type
+// identifier signed
+// WARNING: [r2ghidra] Detected overlap for variable var_8h
+// WARNING: [r2ghidra] Failed to match type signed int for variable var_4h to Decompiler type: Unknown type identifier
+// signed
+// WARNING: [r2ghidra] Detected overlap for variable var_4h
+// WARNING: [r2ghidra] Detected overlap for variable var_bh
+
+undefined8 main(uint32_t argc, char **argv)
+{
+ int64_t iVar1;
+ char cVar2;
+ int32_t iVar3;
+ int64_t in_FS_OFFSET;
+ int64_t var_30h;
+ int64_t var_24h;
+ int64_t var_8h;
+
+ iVar1 = *(int64_t *)(in_FS_OFFSET + 0x28);
+ var_24h._0_4_ = argc;
+ sym.imp.puts("Crackme/keygenme by Dennis Yurichev, http://challenges.re/74");
+ sym.imp.putchar(10);
+ if ((uint32_t)var_24h == 1) {
+ sym.imp.puts("Command line: <serial number>");
+ // WARNING: Subroutine does not return
+ sym.imp.exit(0);
+ }
+ iVar3 = sym.imp.memcmp(argv[1] + 0x1e, "HELL0-HELL0", 0xb);
+ if (iVar3 != 0) {
+ sym.imp.puts("SN format is incorrect");
+ // WARNING: Subroutine does not return
+ sym.imp.exit(0);
+ }
+ iVar3 = fcn.00400bb5((int64_t)argv[1], (int64_t)&var_24h + 4);
+ if (iVar3 == -1) {
+ sym.imp.puts("SN format is incorrect");
+ // WARNING: Subroutine does not return
+ sym.imp.exit(0);
+ }
+ cVar2 = fcn.0040085e((void *)((int64_t)&var_24h + 4));
+ if (cVar2 == '\0') {
+ sym.imp.puts("SN is not valid");
+ } else {
+ sym.imp.puts("SN valid");
+ }
+ if (iVar1 != *(int64_t *)(in_FS_OFFSET + 0x28)) {
+ // WARNING: Subroutine does not return
+ sym.imp.__stack_chk_fail();
+ }
+ return 0;
+}
+#+END_SRC
+
+#+BEGIN_SRC c
+#include <stdint.h>
+
+int main(int argc, char **argv)
+{
+ char buf[24];
+
+ printf("Crackme/keygenme by Dennis Yurichev, http://challenges.re/74\n\n");
+
+ if (argc == 1) {
+ puts("Command line: <serial number>");
+ exit(0);
+ }
+
+ if (memcmp(argv[1] + 0x1e, "HELL0-HELL0", 0xb)) {
+ puts("SN format is incorrect");
+ exit(0);
+ }
+
+ if (fcn_00400bb5(argv[1], buf) == -1) {
+ puts("SN format is incorrect");
+ exit(0);
+ }
+
+ if (fcn_0040085e(buf) == '\0') {
+ puts("SN is not valid");
+ } else {
+ puts("SN valid");
+ }
+
+ return 0;
+}
+#+END_SRC
+
+- Removed iVar1, since that's just the stack canary.
+
+# For var_24h:
+#
+# pushq %rbp
+# movq %rsp, %rbp
+# subq $0x30, %rsp
+# movl %edi, var_24h ; argc
+# movq %rsi, var_30h ; argv
+#
+# Ended up removing it anyway. Using 'argc' is clearer.
+
+# leaq var_20h, %rdx
+# movq %rdx, %rsi
+# movq %rax, %rdi
+# callq fcn.00400bb5
+
+# leaq var_20h, %rax
+# movq %rax, %rdi
+# callq fcn.0040085e
+
+We can tell already that the sixth and seventh components must be "HELL0-HELL0".
+
+# From fcn_00400bb5
+#+BEGIN_SRC c
+var_10h._0_4_ = 0;
+while ((int32_t)var_10h < 7) {
+ if (*(char *)(arg1 + (int64_t)((int32_t)var_10h * 6) + 5) != '-') {
+ return 0xffffffff;
+ }
+ var_10h._0_4_ = (int32_t)var_10h + 1;
+}
+#+END_SRC
+
+# ---
+
+- =fcn_00400bb5= parses the key into a buffer (I renamed to =parse_key=)
+ - =charcode= function maps numerals to their numeric values ('0' becomes 0) and letters 'A' through 'Z' to 10-35
+ - buffer is written with 3 bytes per component
+ - I thought this was a decompiler mistake at first, but I checked the disassembly and it's legit.
+- =fcn_0040085e= enables features based on the parsed key (I renamed to =enable_features=)
+ - parsed buffer needs to start with 0xdeadbabe
+ - bytes 4 and 5 give a numerical year, 6 gives a numerical month, and 7 gives a numerical day.
+ - Sanity checks to ensure that day is between 1 and 31, that month is between 1 and 12, and that year is between 2016 and 2101.
+ - 7th bit of byte 8 enables feature A
+ - 1st bit of byte 9 enables feature B
+ - 2nd bit of byte 10 enables feature C
+ - 4th bit of byte 11 enables feature D
+ - 1st bit of byte 12 enables feature E
+ - One final check of the last 8 bytes against a checksum function
+checksum(0, parsed, 0x18)
+
+#+BEGIN_SRC c
+#include <stdint.h>
+
+uint64_t checksum(int64_t init, char *parsed, int64_t length)
+{
+ uint64_t ret;
+ char *cur;
+ int i;
+ int j;
+
+ cur = parsed;
+ ret = ~init;
+ i = length;
+
+ while (i != 0) {
+ ret = ret ^ (uint64_t) *cur;
+ j = 0;
+ while (i--, cur++, j < 8) {
+ if ((ret & 1) == 0) {
+ ret = ret >> 1;
+ } else {
+ ret = ret >> 1 ^ 0x42f0e1eb0badbad0;
+ }
+ j++;
+ }
+ }
+
+ return ~ret;
+}
+#+END_SRC
+
+# ---
+
+From this, we can hack together a quick key verifier.
+
+#+BEGIN_SRC common-lisp
+(use-package :cl-utilities)
+
+(defun charcode (c)
+ (let ((value (char-code c)))
+ (cond ((<= (char-code #\0) value (char-code #\9)) (- value #x30))
+ ((<= (char-code #\A) value (char-code #\Z)) (- value #x37)))))
+
+(defun hash-component (component)
+ (let* ((characters (coerce component 'list))
+ (values (mapcar #'charcode characters)))
+ (unless (or (/= 5 (length values)) (find nil values))
+ (+ (* #x000001 (nth 0 values))
+ (* #x000024 (nth 1 values))
+ (* #x000510 (nth 2 values))
+ (* #x00b640 (nth 3 values))
+ (* #x19a100 (nth 4 values))))))
+
+(defun parse-key (key)
+ (reduce #'append
+ (mapcar #'(lambda (component)
+ (let ((hash (hash-component component)))
+ (list (logand hash #xff)
+ (logand (ash hash -8) #xff)
+ (logand (ash hash -16) #xff))))
+ (split-sequence #\- key))))
+
+(defun key-valid-p (key)
+ ;; Must begin with 0xdeadbabe, and have HELL0 for components 6 and 7.
+ (and (equal (subseq key 0 4) '(222 173 186 190))
+ (equal (subseq key 15 21) '(153 95 15 153 95 15))))
+
+(defun key-attributes (key)
+ (let ((parsed (parse-key key)))
+ (list :valid (key-valid-p parsed)
+ :expiry-year (logior (ash (nth 4 parsed) 8)
+ (nth 5 parsed))
+ :expiry-month (nth 6 parsed)
+ :expiry-day (nth 7 parsed)
+ :feature-a (plusp (logand (nth 8 parsed) (ash 1 6)))
+ :feature-b (plusp (logand (nth 9 parsed) (ash 1 0)))
+ :feature-c (plusp (logand (nth 10 parsed) (ash 1 1)))
+ :feature-d (plusp (logand (nth 11 parsed) (ash 1 2)))
+ :feature-e (plusp (logand (nth 12 parsed) (ash 1 0))))))
+
+(key-attributes "2Z7A7-EK270-TMHR4-BHC71-CEB52-HELL0-HELL0-EONP9")
+;; (:VALID T :EXPIRY-YEAR 2053 :EXPIRY-MONTH 5 :EXPIRY-DAY 22 :FEATURE-A T
+;; :FEATURE-B T :FEATURE-C T :FEATURE-D T :FEATURE-E NIL)
+
+(key-attributes "2Z7A7-6I7R9-MZGO9-FDQJ3-JN0Q6-HELL0-HELL0-72KJ9")
+;; (:VALID T :EXPIRY-YEAR 2042 :EXPIRY-MONTH 2 :EXPIRY-DAY 21 :FEATURE-A T
+;; :FEATURE-B T :FEATURE-C T :FEATURE-D T :FEATURE-E T)
+#+END_SRC
+
+And verify our results.
+
+#+BEGIN_SRC prog
+jakob@Epsilon ~ $ ./challenge74 "2Z7A7-EK270-TMHR4-BHC71-CEB52-HELL0-HELL0-EONP9"
+Crackme/keygenme by Dennis Yurichev, http://challenges.re/74
+
+Expiration date: 2053-05-22
+Feature A: ON
+Feature B: ON
+Feature C: ON
+Feature D: ON
+Feature E: OFF
+SN valid
+jakob@Epsilon ~ $ ./challenge74 "2Z7A7-6I7R9-MZGO9-FDQJ3-JN0Q6-HELL0-HELL0-72KJ9"
+Crackme/keygenme by Dennis Yurichev, http://challenges.re/74
+
+Expiration date: 2042-02-21
+Feature A: ON
+Feature B: ON
+Feature C: ON
+Feature D: ON
+Feature E: ON
+SN valid
+#+END_SRC
+
+# ---
+
+Tried to brute force overnight, which brought me back to playing CTF, but it was
+sadly unfruitful.
+
+# ---
+
+GDB's call functionality is godsend.
+
+(gdb) p (unsigned long long) $checksum(0, &{'\xff', '\xff', '\xff'}, 3)
+$14 = 18446742974197923840
+
+# ---
+
+Z3 https://jomo.tv/security/mrmcd-ctf-writeup-flag-checker
+https://ericpony.github.io/z3py-tutorial/guide-examples.htm
+https://stackoverflow.com/questions/53726998/using-z3-where-constraint-depends-on-output-of-function
+
+Right shift was giving me a hard time (not prepending with zeroes) which you can
+see from the & 0x7fffffffffffffff.
+
+#+BEGIN_SRC prog
+jakob@Epsilon ~ $ python solver.py
+[bv22 = 196,
+ bv13 = 18,
+ bv21 = 216,
+ bv23 = 130,
+ bv14 = 209,
+ bv8 = 130,
+ bv10 = 108,
+ bv9 = 170,
+ bv11 = 208,
+ bv12 = 240,
+ bv20 = 15,
+ bv19 = 95,
+ bv18 = 153,
+ bv17 = 15,
+ bv16 = 95,
+ bv15 = 153,
+ bv7 = 24,
+ bv6 = 12,
+ bv5 = 227,
+ bv4 = 0,
+ bv3 = 190,
+ bv2 = 186,
+ bv1 = 173,
+ bv0 = 222]
+#+END_SRC
+
+#+BEGIN_SRC common-lisp
+(string-join (mapcar #'ahash-component-inverse (mapcar #'triplet-to-number '((222 173 186) (190 0 27) (12 24 13) (170 108 208) (240 18 20) (153 95 15) (153 95 15) (216 196 130)))) "-")
+#+END_SRC
+
+#+BEGIN_SRC prog
+CL-USER> (key-attributes "2Z7A7-AHX11-S4EI0-6LR48-K37S0-HELL0-HELL0-KPO35")
+(:VALID NIL :EXPIRY-YEAR 27 :EXPIRY-MONTH 12 :EXPIRY-DAY 24 :FEATURE-A NIL
+ :FEATURE-B NIL :FEATURE-C NIL :FEATURE-D NIL :FEATURE-E NIL)
+#+END_SRC
+
+OH MY GOD
+
+#+BEGIN_SRC python
+...
+s.add(key[4] == 2019 & 0xff00)
+...
+#+END_SRC
+
+That should've been =s.add(key[4] == ((2019 & 0xff00) >> 8))=...
+
+;-;
+
+Let's try this again...
+
+#+BEGIN_SRC prog
+jakob@Epsilon ~ $ python solver.py
+[bv22 = 80,
+ bv13 = 39,
+ bv21 = 204,
+ bv23 = 133,
+ bv14 = 124,
+ bv8 = 140,
+ bv10 = 12,
+ bv9 = 168,
+ bv11 = 183,
+ bv12 = 184,
+ bv20 = 15,
+ bv19 = 95,
+ bv18 = 153,
+ bv17 = 15,
+ bv16 = 95,
+ bv15 = 153,
+ bv7 = 25,
+ bv6 = 12,
+ bv5 = 227,
+ bv4 = 7,
+ bv3 = 190,
+ bv2 = 186,
+ bv1 = 173,
+ bv0 = 222]
+#+END_SRC
+
+#+BEGIN_SRC prog
+CL-USER> (mapcar #'hash-component-inverse (mapcar #'triplet-to-number '((222 173 186) (190 7 227) (12 25 140) (168 12 183) (184 39 124) (153 95 15) (153 95 15) (204 80 133))))
+("2Z7A7" "YFWU8" "CGSG5" "CF457" "K9EU4" "HELL0" "HELL0" "OH975")
+CL-USER> (key-attributes "2Z7A7-YFWU8-CGSG5-CF457-K9EU4-HELL0-HELL0-OH975")
+(:VALID T :EXPIRY-YEAR 2019 :EXPIRY-MONTH 12 :EXPIRY-DAY 25 :FEATURE-A NIL
+ :FEATURE-B NIL :FEATURE-C NIL :FEATURE-D NIL :FEATURE-E NIL)
+#+END_SRC
+
+#+BEGIN_SRC prog
+jakob@Epsilon ~ $ ./challenge74 "2Z7A7-YFWU8-CGSG5-CF457-K9EU4-HELL0-HELL0-OH975"
+Crackme/keygenme by Dennis Yurichev, http://challenges.re/74
+
+Expiration date: 2019-12-25
+Feature A: OFF
+Feature B: OFF
+Feature C: OFF
+Feature D: OFF
+Feature E: OFF
+SN valid
+#+END_SRC
+
+# ---
+
+I have to say, r2ghidra is really fucking good. =pdg= takes a while, but if you
+rename some variables with =afvn= and run it again, it spits out the updated
+version instantly (probably doing some sort of caching/quick substitution).
+
+# ---
+
+# End-of-year reflection: Context is super important for making sense of assembly code.
+# Case in point: crypto challenges like #33
+# Idea to toy with: A monthly crackme, hints given out every week and solutions posted (also, the challenges won't be painfully abstract)