aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--haunt/data/blogroll.scm72
-rw-r--r--haunt/data/bookmarks.scm72
-rw-r--r--haunt/haunt.scm2
-rw-r--r--haunt/jakob/builder/blog.scm6
-rw-r--r--haunt/jakob/builder/blogroll.scm58
-rw-r--r--haunt/jakob/builder/htaccess.scm25
-rw-r--r--haunt/jakob/utils/pagination.scm4
-rw-r--r--haunt/pages/404.sxml19
-rw-r--r--haunt/pages/about.sxml114
-rw-r--r--haunt/static/css/style.css94
-rw-r--r--haunt/static/gpg.txt190
-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
20 files changed, 2751 insertions, 325 deletions
diff --git a/haunt/data/blogroll.scm b/haunt/data/blogroll.scm
index a88974c..672b959 100644
--- a/haunt/data/blogroll.scm
+++ b/haunt/data/blogroll.scm
@@ -720,4 +720,74 @@
("linux" "nixos" "programming" "rust"))
("Fred's notes"
"https://ramblings.fred.moe/"
- ("c" "programming")))
+ ("c" "programming"))
+ ("nurpax"
+ "https://nurpax.github.io/"
+ ("6502"
+ "c64"
+ "emacs"
+ "functional-programming"
+ "haskell"
+ "linux"
+ "programming"
+ "retro-tech"))
+ ("absorptions"
+ "https://www.windytan.com/"
+ ("ham" "hardware" "sdr"))
+ ("see shy jo"
+ "https://joeyh.name/blog/"
+ ("functional-programming"
+ "ham"
+ "hardware"
+ "haskell"
+ "linux"
+ "off-grid"
+ "programming"))
+ ("TMZ Lair - Underground Coding"
+ "https://www.guitmz.com/"
+ ("linux" "programming" "security" "windows"))
+ ("Barracuda Blues"
+ "https://bendersteed.gitlab.io/index.xml"
+ ("common-lisp" "emacs" "guix" "linux" "lisp" "programming"))
+ ("../../../../overused_linux_joke/../../../../"
+ "https://korcankaraokcu.github.io"
+ ("binary-exploitation" "ctf" "reversing" "security"))
+ ("Hell Oh Entropy!"
+ "https://siddhesh.in/"
+ ("c" "compilers" "programming"))
+ ("Inside Rust"
+ "https://blog.rust-lang.org/inside-rust/"
+ ("compilers" "programming" "rust"))
+ ("An Index of Verisimilitudes"
+ "http://verisimilitudes.net/"
+ ("common-lisp" "lisp" "programming"))
+ ("byuu"
+ "https://byuu.net/"
+ ("6502" "hardware" "programming" "retro-tech"))
+ ("erkin's Blog"
+ "https://erkin.party/blog/"
+ ("functional-programming" "lisp" "programming" "scheme"))
+ ("Juraj's Blog"
+ "https://jborza.github.io/"
+ ("programming" "retro-tech"))
+ ("The cr.yp.to blog"
+ "https://blog.cr.yp.to/index.html"
+ ("crypto" "math"))
+ ("programming in the twenty-first century"
+ "https://prog21.dadgum.com/"
+ ("functional-programing" "game-development" "programming" "retro-tech"))
+ ("Shell is coming..."
+ "https://www.shelliscoming.com/"
+ ("binary-exploitation" "reversing" "security" "windows" "x86"))
+ ("(pixel)desu.blog"
+ "https://desu.blog/"
+ ("reversing" "video-games"))
+ ("Mildly entertainingᵝ"
+ "https://beepb00p.xyz/"
+ ("emacs" "programming"))
+ ("Thomas' place in cyberspace"
+ "https://www.härdin.se/category/blog.html"
+ ("hardware" "linux" "programming" "security"))
+ ("acloudtree"
+ "https://www.acloudtree.com/post/"
+ ("programming" "security")))
diff --git a/haunt/data/bookmarks.scm b/haunt/data/bookmarks.scm
index 13df748..cb0b4b6 100644
--- a/haunt/data/bookmarks.scm
+++ b/haunt/data/bookmarks.scm
@@ -1,4 +1,4 @@
-'(("Finding and Exploiting Hidden Features of Animal Crossings NES Emulator"
+`(("Finding and Exploiting Hidden Features of Animal Crossings NES Emulator"
"https://jamchamb.github.io/2018/07/11/animal-crossing-nes-emulator-hacks.html"
("binary-exploitation"
"c"
@@ -9,6 +9,15 @@
"retro-tech"
"reversing"
"video-games"))
+ ("Arbitrary Code Execution in Ocarina of Time"
+ "https://www.youtube.com/watch?v=RoEmGCNsbno"
+ ("binary-exploitation"
+ "game-hacking"
+ "mips"
+ "n64"
+ "security"
+ "video"
+ "video-games"))
("Disassembling Jak & Daxter"
"http://www.codersnotes.com/notes/disassembling-jak/"
("lisp"
@@ -31,15 +40,36 @@
("Zelda Screen Transitions are Undefined Behavior"
"https://gridbugs.org/zelda-screen-transitions-are-undefined-behaviour/"
("6502" "nes" "retro-tech" "reversing" "video-games"))
+ ("Sonic Battle (GBA) Renderer Series"
+ "https://fouramgames.com/blog/sonic-battle-renderer"
+ ("graphics" "hardware" "reversing" "retro-tech"))
+ ("How Much of a Genius-Level Move Was Using Binary Space Partitioning in Doom?"
+ "https://twobithistory.org/2019/11/06/doom-bsp.html"
+ ("graphics" "math" "programming" "video-games"))
("Investigating a recent ebook DRM system (c. 2018)"
"https://yingtongli.me/blog/2019/03/28/drm2.html"
("android" "arm" "reversing"))
("Looking inside the box"
"https://anvilventures.com/blog/looking-inside-the-box.html"
("python" "reversing"))
+ ("Analysis of the 2015 ESET Crackme challenge"
+ "https://lyxica.github.io/ESET.pdf"
+ ("ctf" "reversing" "x86"))
("Adventures in reverse engineering Broadcom NIC firmware"
"https://www.devever.net/~hl/ortega"
("arm" "hardware" "reversing" "x86"))
+ ("GPS, Galileo & More: How do they work & what happened during the big outage?"
+ "https://ds9a.nl/articles/posts/gps-gnss-how-do-they-work/"
+ ("ham"))
+ ("[DSCTF 2019] CPU Adventure – Unknown CPU Reversing"
+ "https://www.robertxiao.ca/hacking/dsctf-2019-cpu-adventure-unknown-cpu-reversing/"
+ ("ctf" "reversing" "writeup"))
+ ("You Won't Believe This One Weird CPU Instruction!"
+ "https://vaibhavsagar.com/blog/2019/09/08/popcount/"
+ ("hardware" "historical" "optimization" "x86"))
+ ("Glitching a $20k Piece of History"
+ "https://yifan.lu/2019/08/16/glitching-a-20k-piece-of-history/"
+ ("arm" "hardware" "reversing"))
("A Great Old-Timey Game-Programming Hack"
"http://blog.moertel.com/posts/2013-12-14-great-old-timey-game-programming-hack.html"
("6502"
@@ -64,6 +94,9 @@
("Code Conversion Language"
"http://emacsninja.com/posts/code-conversion-language.html"
("c" "emacs" "emacs-lisp" "lisp" "optimization" "programming" "reversing"))
+ ("The General Problem"
+ "https://generalproblem.net/"
+ ("compilers" "functional-programming" "guile" "lisp" "programming" "scheme" "x86"))
("What the Hero Sees: Field-of-View for Roguelikes "
"http://journal.stuffwithstuff.com/2015/09/07/what-the-hero-sees/"
("programming"
@@ -96,6 +129,9 @@
("A Road to Common Lisp"
"http://stevelosh.com/blog/2018/08/a-road-to-common-lisp/"
("common-lisp" "lisp" "programming"))
+ ("MOST-POSITIVE-BIGNUM"
+ "https://www.jwz.org/blog/2008/03/most-positive-bignum/"
+ ("historical" "lisp"))
("Meta-Circular Adventures in Functional Abstraction"
"https://web.archive.org/web/20160609222905/https://chriskohlhepp.wordpress.com/metacircular-adventures-in-functional-abstraction-challenging-clojure-in-common-lisp/"
("common-lisp"
@@ -113,6 +149,9 @@
("Models of Generics and Metaprogramming: Go, Rust, Swift, D and More"
"http://thume.ca/2019/07/14/a-tour-of-metaprogramming-models-for-generics/"
("c" "c++" "go" "optimization" "programming" "programming-languages" "rust"))
+ ("John Carmack on Inlined Code"
+ "http://number-none.com/blow/john_carmack_on_inlined_code.html"
+ ("c++" "optimization" "programming"))
("Notes on a smaller Rust"
"https://boats.gitlab.io/blog/post/notes-on-a-smaller-rust/"
("programming" "rust"))
@@ -126,9 +165,37 @@
"programming"
"rust"
"video-games"))
+ ("Creating a Rootkit to Learn C"
+ "https://h0mbre.github.io/Learn-C-By-Creating-A-Rootkit/#"
+ ("c" "security" "linux"))
("Building a Homebrew Video Game Console"
"https://internalregister.github.io/2019/03/14/Homebrew-Console.html"
("c" "hardware" "programming" "z80"))
+ ("Approximating the Sine Function"
+ "http://datagenetics.com/blog/july12019/index.html"
+ ("math" "optimization"))
+ ("Looping Music Seamlessly"
+ "http://nolannicholson.com/looper.html"
+ ("math"))
+ ("The PGP Problem"
+ "https://latacora.micro.blog/2019/07/16/the-pgp-problem.html"
+ ("crypto" "math" "pgp" "security")
+ ((p "While I feel the author's suggestion to \"[u]se Signal. Or Wire, or
+WhatsApp, or some other Signal-protocol-based secure messenger\" is
+well-intentioned, I strongly dislike advocating for nonfree software and network
+services that are run unethically. I am a proponent of OMEMO/XMPP.")
+ (p "I may start using signify for my own software. Of course, I won't
+entirely give up on PGP, but I think that signing with both would be enough to
+signal my endorsement of the former.")
+ (p "The lack of a suggested alternative for email is particularly depressing
+to me. Why haven't we come up with a better system yet?")
+ (p "And the author does well to admit that PGP is still a fair choice for
+encrypting files. I see myself continuing to use "
+ ,(hyperlink "https://www.passwordstore.org/" "pass")
+ " for years to come.")))
+ ("Infectious Executable Stacks"
+ "https://nullprogram.com/blog/2019/11/15/"
+ ("binary-exploitation" "c" "security"))
("In Noisy Digital Era, Elegant Internet Still Thrives"
"https://www.npr.org/2012/04/17/150817325/in-noisy-digital-era-elegant-internet-still-thrives"
("culture"))
@@ -138,6 +205,9 @@
("Graying Out"
"https://www.tbray.org/ongoing/When/201x/2019/03/11/Lights-Going-Out"
("culture" "jabber"))
+ ("What's Wrong With XMPP?"
+ "https://blog.samwhited.com/2019/02/whats-wrong-with-xmpp/"
+ ("culture" "jabber"))
("Does Visual Studio Rot the Mind?"
"http://www.charlespetzold.com/etc/DoesVisualStudioRotTheMind.html"
("practices" "programming"))
diff --git a/haunt/haunt.scm b/haunt/haunt.scm
index 8a975ec..e47090c 100644
--- a/haunt/haunt.scm
+++ b/haunt/haunt.scm
@@ -47,7 +47,7 @@
(list (atom-feed)
(blog)
(blogroll)
- (htaccess #:handler-404 "pages/404.html")
+ (htaccess #:error-documents '((404 . "pages/404.html")))
(outbox)
(static-pages)
(static-directory "static")))
diff --git a/haunt/jakob/builder/blog.scm b/haunt/jakob/builder/blog.scm
index 93eb519..0eda775 100644
--- a/haunt/jakob/builder/blog.scm
+++ b/haunt/jakob/builder/blog.scm
@@ -90,7 +90,7 @@
(p ,@(maybe-cons*
(date->string (post-date post) "~B ~d, ~Y")
(when crosspost-uri
- (list " ⮀ " (hyperlink local-uri "Crosspost")))
+ (list " ↻ " (hyperlink local-uri "Crosspost")))
" ❖ Tags: "
(intersperse
(map (lambda (tag)
@@ -98,7 +98,7 @@
(post-ref post 'tags))
", ")))
(p ,(first-paragraph post))
- ,(hyperlink (or crosspost-uri local-uri) "read more 🢩"))))
+ ,(hyperlink (or crosspost-uri local-uri) "read more →"))))
;;;
@@ -139,7 +139,7 @@ only the posts tagged with that tag."
(flat-map (match-lambda
((tag . posts)
(items->pages render-preview posts
- (format #f "Posts tagged as \"~a\"" tag)
+ (format #f "Posts tagged with \"~a\"" tag)
(tag-uri %tag-prefix tag ""))))
(group-by-tag posts (cut post-ref <> 'tags))))
diff --git a/haunt/jakob/builder/blogroll.scm b/haunt/jakob/builder/blogroll.scm
index 70ab1f9..9d75c1e 100644
--- a/haunt/jakob/builder/blogroll.scm
+++ b/haunt/jakob/builder/blogroll.scm
@@ -24,6 +24,7 @@
#:use-module (jakob utils sxml)
#:use-module (jakob utils tags)
#:use-module (srfi srfi-1)
+ #:use-module (srfi srfi-9)
#:use-module (srfi srfi-26)
#:export (blogroll))
@@ -36,19 +37,39 @@
;;;
-;;; Page creation.
+;;; Type for entries.
;;;
-(define (render-preview name uri tags tag-prefix)
+(define-record-type <entry>
+ (make-entry name uri tags comments)
+ entry?
+ (name entry-name)
+ (uri entry-uri)
+ (tags entry-tags)
+ (comments entry-comments))
+
+(define entry
+ (match-lambda
+ ((name uri tags) (make-entry name uri tags #f))
+ ((name uri tags comments) (make-entry name uri tags comments))))
+
+
+;;;
+;;; Rendering.
+;;;
+
+(define* (render-preview name uri tags tag-prefix #:optional comments)
"Return an SHTML preview of an entry with the given parameters."
`(section
- (h2 ,(hyperlink uri name))
- (p
- ,(intersperse
- (map (lambda (tag)
- (hyperlink (tag-uri tag-prefix tag) tag))
- tags)
- ", "))))
+ ,@(cons*
+ `(h2 ,(hyperlink uri name))
+ `(p
+ ,(intersperse
+ (map (lambda (tag)
+ (hyperlink (tag-uri tag-prefix tag) tag))
+ tags)
+ ", "))
+ (or comments '()))))
(define (render-tag-cloud prefix entries)
"Return SHTML listing the tags of ENTRIES in PREFIX with the number of times
@@ -58,22 +79,25 @@ each tag is used."
((tag count)
(hyperlink (tag-uri prefix tag)
`(li ,(format #f "~a (~a)" tag count)))))
- (count-tags entries third))))
+ (count-tags entries entry-tags))))
(define* (render-entries title prefix entries #:optional tag)
"Return an SHTML document listing ENTRIES in PREFIX, with a header of TITLE."
`(main
,@(maybe-cons*
`(h1 ,(if tag
- (format #f "~a - Tagged as ~a" title tag)
+ (format #f "~a - Tagged with \"~a\"" title tag)
title))
(unless tag
(render-tag-cloud prefix entries))
(unless tag
`(hr))
- (map (match-lambda
- ((name uri tags)
- (render-preview name uri tags prefix)))
+ (map (lambda (entry)
+ (render-preview (entry-name entry)
+ (entry-uri entry)
+ (entry-tags entry)
+ prefix
+ (entry-comments entry)))
entries))))
(define (entries->pages title prefix entries)
@@ -90,7 +114,7 @@ pages for each of the tags used in ENTRIES."
(theme #:title title
#:content (render-entries title prefix entries tag))
sxml->html)))
- (group-by-tag entries third))))
+ (group-by-tag entries entry-tags))))
@@ -101,12 +125,12 @@ pages for each of the tags used in ENTRIES."
(define %blogroll
(list "Blogroll"
"/blogroll"
- (primitive-load "data/blogroll.scm")))
+ (map entry (primitive-load "data/blogroll.scm"))))
(define %bookmarks
(list "Bookmarks"
"/bookmark"
- (primitive-load "data/bookmarks.scm")))
+ (map entry (primitive-load "data/bookmarks.scm"))))
(define (blogroll)
(lambda (site posts)
diff --git a/haunt/jakob/builder/htaccess.scm b/haunt/jakob/builder/htaccess.scm
index fd20eca..e0068d1 100644
--- a/haunt/jakob/builder/htaccess.scm
+++ b/haunt/jakob/builder/htaccess.scm
@@ -16,20 +16,35 @@
(define-module (jakob builder htaccess)
#:use-module (haunt page)
+ #:use-module (ice-9 match)
#:export (htaccess))
+;; Good resource:
+;; <https://perishablepress.com/stupid-htaccess-tricks/#ess4>
+
(define* (htaccess-writer contents #:optional (port (current-output-port)))
(display (string-join contents "\n") port)
(newline port))
-;; TODO: https://help.dreamhost.com/hc/en-us/articles/215747748-How-can-I-redirect-and-rewrite-my-URLs-with-an-htaccess-file-
-(define* (htaccess #:key handler-404)
+(define* (htaccess #:key
+ (error-documents '())
+ (redirects '()))
"Create an .htaccess file at the site's root.
-HANDLER-404 specifies the file name of the page to display for a 404 not found."
+ERROR-DOCUMENTS specifies the file name of the page to display for a specific
+HTTP error code: a list of (error-code . file-name) pairs.
+
+REDIRECTS specifies file names to show for certain requests: a list of (pattern
+. file-name) pairs."
(define contents
- `(,(if handler-404
- (format #f "ErrorDocument 404 ~a" handler-404))))
+ `(,@(map (match-lambda
+ ((code . file-name)
+ (format #f "ErrorDocument ~a ~a" code file-name)))
+ error-documents)
+ ,@(map (match-lambda
+ ((pattern . file-name)
+ (format #f "RewriteRule ~a ~a" pattern file-name)))
+ redirects)))
(lambda (site posts)
(make-page ".htaccess" contents htaccess-writer)))
diff --git a/haunt/jakob/utils/pagination.scm b/haunt/jakob/utils/pagination.scm
index a012dd4..2cda3c7 100644
--- a/haunt/jakob/utils/pagination.scm
+++ b/haunt/jakob/utils/pagination.scm
@@ -68,9 +68,9 @@ PREVIOUS-PAGE and NEXT-PAGE."
(@ (id "pagination"))
,@(maybe-list
(when previous-page
- (hyperlink previous-page "🢨 Previous Page"))
+ (hyperlink previous-page "← Previous Page"))
(when next-page
- (hyperlink next-page "Next Page 🢩"))))))
+ (hyperlink next-page "Next Page →"))))))
(define* (items->pages render-item items base-title base-file-name
#:key (items-per-page %items-per-page))
diff --git a/haunt/pages/404.sxml b/haunt/pages/404.sxml
new file mode 100644
index 0000000..450a612
--- /dev/null
+++ b/haunt/pages/404.sxml
@@ -0,0 +1,19 @@
+;;; -*- scheme -*-
+
+;;; Copyright © 2019 Jakob L. Kreuze <zerodaysfordays@sdf.lonestar.org>
+;;;
+;;; This program is free software; you can redistribute it and/or
+;;; modify it under the terms of the GNU General Public License as
+;;; published by the Free Software Foundation; either version 3 of the
+;;; License, or (at your option) any later version.
+;;;
+;;; This program is distributed in the hope that it will be useful,
+;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;;; General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with this program. If not, see
+;;; <http://www.gnu.org/licenses/>.
+
+`(p "Test")
diff --git a/haunt/pages/about.sxml b/haunt/pages/about.sxml
index 603d3e8..911bf8c 100644
--- a/haunt/pages/about.sxml
+++ b/haunt/pages/about.sxml
@@ -16,17 +16,115 @@
;;; along with this program. If not, see
;;; <http://www.gnu.org/licenses/>.
-(use-modules (jakob theme)
+(use-modules (ice-9 match)
+ (jakob theme)
(jakob utils sxml))
+(define %software-projects
+ '(("Mines" "Dormant"
+ "https://git.sr.ht/~jakob/mines"
+ ("Android implementation of the classic video game \"Minesweeper\"."))
+ ("Rebuild" "Dormant"
+ "https://git.sr.ht/~jakob/rebuild"
+ ("An attempt at reimplementing Ken Silverman's Build engine, with the goal of being modular enough to host a modern Blood source port."))
+ ("wildmidi" "Dormant"
+ "https://git.sr.ht/~jakob/wildmidi"
+ ("A simple [Rust] wrapper around the WildMIDI software synthesizer library."))
+ ("Slime the World" "Finished"
+ "https://git.sr.ht/~jakob/slime-the-world"
+ ("My entry for the 2018 Autumn Lisp Game Jam; a game about covering everything in slime."))
+ ("Nekopack" "Finished"
+ "https://git.sr.ht/~jakob/nekopack"
+ ("Tool for extracting game data from Nekopara's XP3 archives."))
+ ("skullfuck" "Finished"
+ "https://git.sr.ht/~jakob/skullfuck"
+ ("Optimizing compiler for Brainfuck, contained in a single C source file."))
+ ("Brisket" "Abandoned"
+ "https://git.sr.ht/~jakob/brisket"
+ ("Primitive newsreader script for interacting with NNTP servers."))
+ ("Hypodermic" "Abandoned"
+ "https://git.sr.ht/~jakob/hypodermic"
+ ("Proof-of-concept shared object injector that will eventually be integrated with PINCE."))
+ ("Duke on FluidSynth" "Abandoned"
+ "https://git.sr.ht/~jakob/duke-on-fluidsynth"
+ ("Experimental FluidSynth MIDI driver for EDuke32."))))
+
+(define %emacs-projects
+ '(("dired-rmjunk" "Active"
+ "https://melpa.org/#/dired-rmjunk"
+ ("A port of Jakub Klinkovský's rmshit.py to Dired."))
+ ("ox-haunt" "Active"
+ "https://melpa.org/#/dired-rmjunk"
+ ("Haunt-flavored HTML backend for the Org export engine."))))
+
+(define %software-contributions
+ `(("GNU Guix" "Active"
+ "https://guix.gnu.org"
+ ("Functional package manager."))
+ ("Radare2" "Finished"
+ "https://www.radare.org/r/"
+ ("UNIX-like reverse engineering framework and command-line tools."))
+ ("Haiku" "Finished"
+ "https://www.haiku-os.org/"
+ ("The Haiku operating system."))))
+
+(define %packaging-projects
+ '(("zerodaysfordays" "Dormant"
+ "https://git.sr.ht/~jakob/zerodaysfordays"
+ ("My personal Gentoo ebuild overlay."))))
+
+(define (project name status url description)
+ (let ((status-class (match status
+ ("Active" "good")
+ ("Finished" "info")
+ ("Dormant" "okay")
+ ("Abandoned" "bad")
+ (_ "info"))))
+ `(tr (td ,(hyperlink url name))
+ (td (button (@ (class ,(format #f "label-~a" status-class)))
+ ,status))
+ (td (p ,@description)))))
+
+(define (project-section name projects)
+ `(section
+ (h4 ,name)
+ (table
+ (tbody
+ ,@(map (lambda (args) (apply project args)) projects)))))
+
(theme
#:title "About"
#:content
`((h2 "Hey.")
- (p "I'm still in the process of putting things together, so this page is a bit empty.")
- (p "For those interested in contacting me, here's my info.")
- (ul
- (li "Email: zerodaysfordays at ‌​‌‌‌​‌‌‍‌​‌‌​​​​‍‌​‌‌​​​‌‍‌‌​‌‌​​​‍‌​‌​‌​‌‌‍‌‌​‌‌‌‌‌‍‌​‌‌‌​​‌‍‌​‌​‌​‌​‍‌​‌‌‌‌​​‍‌​‌‌​‌​​‍‌​‌‌​‌‌​‍‌​‌‌​​​‌‍‌​‌‌‌​​​‍‌‌​‌‌‌‌‌‍‌​‌​‌‌​​‍‌​‌​‌‌‌‌‍‌​‌‌‌‌‌​‍‌​‌‌​​‌​‍‌‌​‌‌‌‌‌‍‌​‌‌​​‌​‍‌​‌‌‌​‌​sdf.lonestar.org")
- (li "GPG: " ,(hyperlink "5A7B 8C4C 70D5 FC3F 5E35 4625 3FE7 8039 D0E5 C118" "/gpg.txt"))
- (li "XMPP: jakob at ‌​‌‌‌​‌‌‍‌​‌‌​​​​‍‌​‌‌​​​‌‍‌‌​‌‌​​​‍‌​‌​‌​‌‌‍‌‌​‌‌‌‌‌‍‌​‌‌‌​​‌‍‌​‌​‌​‌​‍‌​‌‌‌‌​​‍‌​‌‌​‌​​‍‌​‌‌​‌‌​‍‌​‌‌​​​‌‍‌​‌‌‌​​​‍‌‌​‌‌‌‌‌‍‌​‌​‌‌​​‍‌​‌​‌‌‌‌‍‌​‌‌‌‌‌​‍‌​‌‌​​‌​‍‌‌​‌‌‌‌‌‍‌​‌‌​​‌​‍‌​‌‌‌​‌​xmpp.is")
- (li "IRC: tsarfox on freenode.net, and jakob everywhere else. I frequent #lobsters and the #tildetown on the tilde.town internal IRC."))))
+ (ul (@ (class "horizontal-list"))
+ (li "Email: " (strong "zerodaysfordays at ‌​‌‌‌​‌‌‍‌​‌‌​​​​‍‌​‌‌​​​‌‍‌‌​‌‌​​​‍‌​‌​‌​‌‌‍‌‌​‌‌‌‌‌‍‌​‌‌‌​​‌‍‌​‌​‌​‌​‍‌​‌‌‌‌​​‍‌​‌‌​‌​​‍‌​‌‌​‌‌​‍‌​‌‌​​​‌‍‌​‌‌‌​​​‍‌‌​‌‌‌‌‌‍‌​‌​‌‌​​‍‌​‌​‌‌‌‌‍‌​‌‌‌‌‌​‍‌​‌‌​​‌​‍‌‌​‌‌‌‌‌‍‌​‌‌​​‌​‍‌​‌‌‌​‌​sdf.lonestar.org"))
+ (li "XMPP: " (strong "jakob at ‌​‌‌‌​‌‌‍‌​‌‌​​​​‍‌​‌‌​​​‌‍‌‌​‌‌​​​‍‌​‌​‌​‌‌‍‌‌​‌‌‌‌‌‍‌​‌‌‌​​‌‍‌​‌​‌​‌​‍‌​‌‌‌‌​​‍‌​‌‌​‌​​‍‌​‌‌​‌‌​‍‌​‌‌​​​‌‍‌​‌‌‌​​​‍‌‌​‌‌‌‌‌‍‌​‌​‌‌​​‍‌​‌​‌‌‌‌‍‌​‌‌‌‌‌​‍‌​‌‌​​‌​‍‌‌​‌‌‌‌‌‍‌​‌‌​​‌​‍‌​‌‌‌​‌​xmpp.is"))
+ (li "IRC: " (strong "tsarfox on freenode.net.")))
+ (ul (@ (class "horizontal-list"))
+ (li "GPG: " ,(hyperlink "/static/gpg.txt" "5A7B 8C4C 70D5 FC3F 5E35 4625 3FE7 8039 D0E5 C118")))
+ (ul (@ (class "horizontal-list"))
+ (li ,(hyperlink "https://git.sr.ht/~jakob" "git"))
+ (li ,(hyperlink "https://mastodon.sdf.org/@jakob" "fedi"))
+ (li ,(hyperlink "https://en.wikipedia.org/wiki/User:ZeroDaysForDays" "wiki"))
+ (li ,(hyperlink "http://tilde.town/~jakob" "tilde"))
+ (li ,(hyperlink "http://zerodaysfordays.sdf.org/" "sdf"))
+ (li ,(hyperlink "https://lobste.rs/u/jakob" "lobste.rs")))
+ (main (@ (class "overline"))
+ (p "My name's Jakob. I'm a self-taught free software hacker currently
+studying computer science and mathematics at the University of Massachusetts
+Amherst. I'm into functional programming, computer security, permaculture,
+cooking, punk rock, and lifting weights.")
+ (p "I'm still in the process of putting things together, so this page is a bit empty."))
+ (h3 "Site Map")
+ (nav (@ (id "site-map"))
+ (section (h4 ,(hyperlink "/blogroll" "Blogroll"))
+ (p "A noncomprehensive list of the blogs I follow."))
+ (section (h4 ,(hyperlink "/bookmark" "Bookmarks"))
+ (p "Collection of some things that I especially enjoyed reading."))
+ (section (h4 ,(hyperlink "/outbox" "Webmention Outbox"))
+ (p "List of all the Webmention replies I've sent. Probably uninteresting to most.")))
+ (h3 "Projects")
+ ,(project-section "Software" %software-projects)
+ ,(project-section "Emacs" %emacs-projects)
+ ,(project-section "Packaging" %packaging-projects)
+ ,(project-section "Other Contributions" %software-contributions)))
diff --git a/haunt/static/css/style.css b/haunt/static/css/style.css
index 02001ec..6cd9656 100644
--- a/haunt/static/css/style.css
+++ b/haunt/static/css/style.css
@@ -73,6 +73,20 @@ body > header > nav > ul {
}
}
+/* Horizontal lists. */
+
+.horizontal-list {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: space-around;
+
+ list-style-type: none;
+ text-align: center;
+
+ margin: 0;
+ padding: 8px 0;
+}
+
/* Pagination. */
#pagination {
@@ -209,3 +223,83 @@ body > footer > div > p {
margin: 0;
padding-right: 1rem;
}
+
+/* About page. */
+
+#site-map {
+ display: grid;
+ grid-template-columns: repeat(2, 1fr);
+ grid-gap: 1rem;
+
+ padding: 0 1rem;
+}
+
+#site-map > section {
+ text-align: center;
+}
+
+.overline {
+ border-top: 2px solid #d2d6dd;
+ margin-top: 0.5rem;
+}
+
+/* Tables. */
+
+table {
+ text-align: center;
+ width: 100%;
+}
+
+td {
+ padding: 0 1rem;
+}
+
+tr:nth-child(even) {
+ background-color: #f2f2f2;
+}
+
+
+td:nth-child(1) {
+ width: 20%;
+}
+
+td:nth-child(2) {
+ width: 10%;
+}
+
+td:nth-child(3) {
+ width: 70%;
+}
+
+/* Buttons. */
+
+button {
+ display: inline;
+ padding: .3em .6em .3em;
+ font-size: 75%;
+ font-weight: 700;
+ line-height: 1;
+ color: #fff;
+ text-align: center;
+ white-space: nowrap;
+ vertical-align: baseline;
+ border-radius: .25em;
+}
+
+.label-info {
+ background-color: #5bc0de;
+}
+
+.label-good {
+ background-color: #5cb85c;
+ border-color: #4cae4c;
+}
+
+.label-okay {
+ background-color: #ec971f;
+ border-color: #d58512;
+}
+
+.label-bad {
+ background-color: #dc3545;
+}
diff --git a/haunt/static/gpg.txt b/haunt/static/gpg.txt
new file mode 100644
index 0000000..aaa2630
--- /dev/null
+++ b/haunt/static/gpg.txt
@@ -0,0 +1,190 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mQINBFyL0CEBEACrmHInpe3ZUJ5f0lhgYbvVobjBaSgu6XKt1Lm640XR/d5RmCsh
+RS2oJ0zghzRQMx+BBTxr62OmuI8FU9MfU+ySHNJWcyobmGaPH0VG3n6xlkBY9g7l
+zm+lccrxpXTd8QH5KRQNUYcL7/aYRNgtqYrYWmkxPSTM2ydFHc+W9wEAZTHLOQsc
+aQJold5KJHM7DTwOq21oltLwWKCOL+MfMejjYoYRMT0UE9DduyR1H/cKsF9VvNjV
+AHFaxCcibtYK0s5jyq/fVIq8ZqU9AEnwUtspqVzWINaDCbVPL/NzFkjDlzu5Y9Bi
+ff9B/Ncd5TmstnsJ9cj6IgYjtwEPLw+aSJNsuzLlQROPDqDM6gaq8v+q8cjk2EH0
+ft0uFlWENf3kfql/WMMn8iVtYon0h9LLI480dQix4+OjNQFVrryPstuA2wTvGqIH
+ECYJeI5hLT5EdShHEXGQEE5JAqXhd19lrWfoV0HI7IKnxE2UI+riaUNSJE8VCmIm
+Y/e2YU/YFIzbrGOh/q0M2te+4ATrexwyBAxrlzl8gFiM3vTQGwJSIeIIlcVoUbti
+/UcywO9pKQlga7AN0oQ0GnmWkGmdLj44wFFuIQSDdkGDyxurh+RPspnSW4HAz3fC
+IbC5h9ACGcLWYT3p7JZGiR9SRbAHBDTgBF5F3hV9ORJpZ8ykN1V9iMq9pwARAQAB
+tEdKYWtvYiBMLiBLcmV1emUgKGh0dHA6Ly9qYWtvYi5zcGFjZSkgPHplcm9kYXlz
+Zm9yZGF5c0BzZGYubG9uZXN0YXIub3JnPokCUwQTAQgAPQIbAwUJAeEzgAIeAQIX
+gBYhBMr8F0Od9PwacViMZSdn1f7sIYnvBQJci9d+BQsJCAcCBhUKCQgLAgMWAgEA
+CgkQJ2fV/uwhie9HqA//SY9dIX46hjNIQpvWWLq8yKKMPZeC1B81JwyK3vimPrNz
+MWeMTJcnmzupNfHXtSaYGh3GlBj6sRONLEGQVS25qBOLgo5TOtPD4V/F4rbqmwRN
+scIMmHPN7s/n60if7dF2bOmrasCpkhROj8CCTsaImbFCYQW5kOywkvxP3tPM6sJd
+6yIqMeb/LR+7VOYYZuCGx3VTXmLdB4eMtY7fHE3K9iZp4yNYsxib+mgeIFPhsdQ2
+uGC7aGm9XusKVLMx4zGrm0ddZdsQyGosp6Ynd4t+5Xb3PM6UyvTNVwTxh6vEBIMb
+yIdz/6tC53xw0RlA86FUH+IY3CQLECjbZDPsjmKkD7KNcckUk11eQkhgMDHxgZAl
+v3Qe4qiDb89UdVpkBJJvxjJztgVyjfHwJdsErzktgOZpnBP/TxNlKwmvKaffMe35
+kIzl0RHrQffQlLhWaw6nndsWzD33jqyd6LzVxhLP+s5QKFIC7KN63d0BeUqEQirD
+Z6t1oKSaRWbK67MRRdTQ/hPb2wthw1TQ0ANXWMcpOHyyyZj2F64PLT6sWXvaE9Ky
+PAUZP2StHWztz6sGyshmCWQot2gROUxbVqyRLxKu158BSbqKbjf2DuwTju8Vtpcn
+qXJDE7L9LvuJo79CmGR/4cGN8SVY/yEfXPQh8+tqHJ0asXQ/iJ2pVZk5up9Wnr7R
+0DbQNAEQAAEBAAAAAAAAAAAAAAAA/9j/4AAQSkZJRgABAQEASABIAAD//gATQ3Jl
+YXRlZCB3aXRoIEdJTVD/2wEEEAA1ADUANQA1ADkANQA8AEMAQwA8AFMAWgBQAFoA
+UwB7AHEAZwBnAHEAewC6AIUAjwCFAI8AhQC6ARsAsADOALAAsADOALABGwD6AS8A
+9gDmAPYBLwD6AcIBYQE5ATkBYQHCAgcBtAGdAbQCBwJ1AjMCMwJ1AxkC8QMZBAwE
+DAVwEQA1ADUANQA1ADkANQA8AEMAQwA8AFMAWgBQAFoAUwB7AHEAZwBnAHEAewC6
+AIUAjwCFAI8AhQC6ARsAsADOALAAsADOALABGwD6AS8A9gDmAPYBLwD6AcIBYQE5
+ATkBYQHCAgcBtAGdAbQCBwJ1AjMCMwJ1AxkC8QMZBAwEDAVw/8IAEQgBIADwAwEi
+AAIRAQMRAf/EABoAAAIDAQEAAAAAAAAAAAAAAAAEAgMFAQb/2gAIAQEAAAAA0CYA
+AcVbAyuMq0t2dDgJnHXgAELWgyS9K1kAAI3ClWvMCvB3rDK5eg3aAABRfZSJ6LHF
+kObpmVsJM2gAAEOMKFiseswacz12V+NAAABXW5VUdhB1LZWzm4o6IAAAC0C+htS/
+i+vZiuxVtnYAAACN0Zyu5SvrXU5jUUY6EwAAAz5aE6Vhp3pTmNVZ12iRkAAAx3L2
+OgAV5DlC97NfLSidgAU2r6F4ABhPRRemm1Kii1kAL4UWuAAGI5zO0u52jXS9mvAB
+nxnptAAGM1FDSM3Rz3OoaYBzPvT9DOFdMSdyE+5+kZ17rgotU2cV0cxdzhbcEIUw
+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
+BC2J8VM1ySLIhdpwOpBmfBui8bkX1s2dedJ+XQ==
+=c2uQ
+-----END PGP PUBLIC KEY BLOCK-----
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)

© 2015 - 2026 Jakob L. Kreuze