# Programming News Paper Puzzle

This puzzle appeared in my local paper, while I am unable to solve it - maybe you guys can take a crack at it.

Page 1

Page 2

They were scanned at pretty high resolution, so you should be able to see better when you zoom in.

Feel free to suggest any tags.

UPDATE: Had a small absence, this is the underlined bold characters from the page:

MzJoYWnrZXI1NTdbambaSvbm1vqo

Date Published: Friday 3rd March 2017

Update:

BMP File of page thanks @MikeThammer

Update 12/03/2017: According to this reddit post This is from the Danish Cyber Defence (although there is no source).

• I am not sure if this will be ever solved here without the text version. Especially, the second picture. – Techidiot Mar 3 '17 at 18:37
• Well, the first page, of this this appears to be a copy, seems to be part of a little byte-code interpreter. The second page looks as if it's base64-encoded or something of the kind, but I personally don't feel like typing it in to see whether it turns out to be a program for that virtual machine :-). – Gareth McCaughan Mar 3 '17 at 18:38
• I have a PDF document of the scan, if somebody has a program that can rip the text from it that would be awesome – Memhave Mar 3 '17 at 18:45
• "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA." Clearly there's someone trapped in a computer. – Ian MacDonald Mar 3 '17 at 19:23
• Please find the original .bmp file here, it's much better than the one scanned off the newspaper: fe-ddis.dk/SiteCollectionImages/FE/grafik_og_billeder/… – MikeThammer Mar 8 '17 at 20:10

This is a community wiki non-answer for transcribing all that stuff.

# Transcription of the program

Language: Intel 80x86 Assembly Language

%define REG(r) [REGS + r * 4]
%define PTR(p) [MEM + p]

U5_LE:
mov ecx, 0x200
mov edi, MEM
mov esi, DISK                   ; DISK = page 2 text?
rep movsb                       ; copy 1st 512 bytes from DISK to MEM
SPIN:
mov edx, REG(63)                ; fetch instruction  ( REG(63) = program counter )
mov edx, PTR(edx)               ; edx = 32-bit instruction
mov WORD REG(0), 0

mov ebp, edx
shr ebp, 21
and ebp, 77o                    ; ebp = bits 26-21 of inst'n = destination register #
mov esi, edx
shr esi, 15
and esi, 77o                    ; esi = bits 20-15 of instruction
mov edi, edx
shr edi, 9
and edi, 77o                    ; edi = bits 14-9 of instruction

mov eax, edx
shr eax, 27                     ; eax = bits 31-27 of instruction = op code
mov eax, [OP_TABLE + eax * 4]
jmp eax                         ; execute instruction

OP_TABLE:
0, OP_ADD, OP_MUL, OP_DIV, OP_NOR, 0, 0, 0, 0, OP_MOVI, 0, OP_CMOV, 0, 0,  \
0, 0, 0, OP_IN, OP_OUT, OP_READ, OP_WRITE, 0, 0, 0, OP_HALT

mov eax, REG(esi)
mov eax, PTR(eax)
mov REG(ebp), eax
jmp SPIN

OP_MUL:
mov eax, REG(esi)
mul DWORD REG(edi)
mov REG(ebp), eax
jmp SPIN

OP_MOVI:                 ; -- MOVe Immediate (constant) value to register # ebp
mov eax, edx         ; (edx = 32-bit instruction)
mov ecx, edx
shr eax, 5
and eax, 0xffff      ;  eax =  bits 20-5  of instruction
and ecx, 37o         ;  ecs =  bits  4-0  of instruction
shl eax, cl          ;  eax = (bits 20-5) * 2^(bits 4-0)
mov REG(ebp), eax    ; (ebp =  bits 26-21 of instruction)
jmp SPIN

OP_CMOV:                 ; -- Conditional MOVe
mov eax, REG(edi)    ;                      (edi = bits 14-9 of instruction)
test eax, eax        ; IF  register # edi is not 0
jz .F
mov eax, REG(esi)    ;                     (esi = bits 20-15 of instruction)
mov REG(ebp), eax    ; THEN move value from register # esi to register # ebp
.F:
jmp SPIN

OP_OUT:
push DWORD REG(ebp)
call putchar
jmp SPIN

mov ecx, 0x200
mov esi, REG(esi)    ; (esi = bits 20-15 of instruction)
shl esi, 9
lea esi, [DISK + esi]
mov edi, REG(ebp)
lea edi, PTR(edi)
rep movsb            ; read 512-byte DISK block whose number is in register # esi
jmp SPIN


This program seems to be an assembly language emulator, but it looks like to be incomplete, since many entries of the table are not valid jump targets. I guess that completing the program is part of the challenge.

# Transcription of the text

To make it easier to coordinate efforts and doublecheck the transcription, please transcribe the text in blocks, adding both the image blocks and the textual transcription below. Preserve the new lines and the hyphens, since we don't know if they are important or not. Use <pre></pre> blocks instead of standard four spaces identation for two reasons:

1. Save some space (there is a 30K limit in answers, I am afraid to hit it).

2. Use <kbd></kbd> for underscore text.

Also, be careful about characters that are too easy to confuse:

• l and 1. You can distinguish them because 1 has a tail, and l don't.

• o, O and 0. 0 is rectangular, O is diamond-shaped. o is smaller and round.

• q and g. g has a a small turn in the descent line. Be careful specially to a q that is directly above another letter that has a transversal ascent line that could be confused with the g descent line.

• 6 and b. The 6 is very square. b is rounded.

• 8 and B. The B is straight in its left, the 8 isn't.

Also, it is important that each part to be reviewed by at least one person other than the transcriber to ensure that there are no typos in the transcription. Two or more reviewers are better.

## First part

[Transcribed by Victor Stafusa, reviewed by humn, second review welcome]

h+ABgKIA4IfCjYkhh+ACo4micpng-
CiCHAAAgzyEHIIcAACDP4A0ghwAA-
IM/hBICHAAAgz+AMIIcA-
ACDPJQAghwAAIM+gDCCHAAAg-
z+EGIIcAACDPIgMghwAAIM8gD-
SCHAAAgzyAMIIcAACDP4QYghwAA
IM/hBiCHAAAgz6AMIIcAACD-
PYA4ghwAAIM9gDiCHAAAgzyAEII-
ZoKgCmKCwAvhIAsAANAAAABH6oAA-
hyACIs8gAACHIA0gzyAAAIcgDmD-
PIAAAhyANYM8gAACHIAAl-
zyAAAIcgByHPIAAAhyAMoM8gAA-
CHIAwgzyAAAIcgAyLPIAAAhyAAJc-
8gAACHIAygzyAAAIcgByHP-
IAAAhyAHIc8gAACHIA3gzyAAAIcg-
ByHPIAAAhyAEIM8gAACHIA-
ChzyAAAPgAAABHv4AAhyAAIl88-
8gBHvvIAhyAAIEe+8gCHwAA0g-
sAAYYKAACCCoAApXyooAELrcgC-
HIAAgQuvyAIcgAGJHP/IAl/yu-
AIcgDaJH/IAA0qoAAIcgACBCinIA-
hyAAKUKq8gCHIAuiR/yAAFqA-
hyAUYkf8gACHIAggzyAAAIcgAm-
LPIAAAhyAKoM8gAACHIAAlzyAAA-
IANizyAAAIcgBmHPIAAAhy-
AOoM8gAACHIAbhzyAAAIcgDGD-
DeDPIAAAhyAG4c8gAA-
CHIAAlzyAAAIcgAKPPIAAAhyACIs-
8gAACHIAkgzyAAAIcgBWHPIAAAhy-
AF-


## ...

Add a lot of parts here...

## Last part

[Transcribed by Silenus, reviewed by Victor Stafusa, second review welcome]

NWdNu+qgtKoyqoHspnuURTOjUVw-
Gy75nE7fcM0doZWLOI-
u50d+mbS46Z1+AqfXaA6/-
rT9AqdvNt4-
iA0yYRQwidXoRtqSzankRtG71Nn-
6vikbXTKSvk8ZrbdjYCxVoCDVpx-
pXRxT2hGC8OPhLk9537gU4-
rUoirNDzkuytvIQF+sH-
belshtabXTuWap0g2V+ZhA2w-
g1vZi78Fld/uP9VsDPNzgkD-
3jtXPPe0Xi-
l1AzDJN/7VWSKI9AfUXKrEx2Rl-
R3IR+18B7wsoRwCn9qbExo3meD-
vCER2NVcM81GNXcZV5JORUnE-
rVEtQJqwU4Rr1doiibD/JWu8n-
zLiYMG25C0QDQCGAx1FuhXGmqEA-
3Dy6fbgr6D+aUc2bUCviBv69-
UiHl+l7N7kkkdWKl5vwok8suTh/-
zgYXJNvQuFf19WtE6VIdabzOBc-
c1PwR3u0k/0eoglxqYqcD5L-
INh2iTzrMbW0SMGm5lhYoPXelf-
wsFbLQFBmR8Oz8Fwe0h/UbAw1w-
9JddVlDmHr0NDd+fbPL/N6Qe-
DPMxp3W2x-
FnKOPagBnmpxjOyeECNor/-
UhfbC5HCS0ojdS+ShclM/-
Y9rPb0bUC7zj7wdSG3BusbNa-
chJorOjDP9RBnGmBmPr9kxFKQqg-
dQfSvlGu+Z3H5HO/5OEKbDJps-
lPQzB5cWbFacYkKqNrvyCZQi-
LsM+omRCI3gM


Also,

Certain of the characters from page 2 are underlined (see here). The underlined characters are (at least) MzJYWNrZXI1NT6amt6a5vbm1vqo. Perhaps these are the only characters that are important and the rest of the string can be ignored.

• I think this is a good lead, I will see if I cant find something to output the 2nd page in text while leaving the question open for a (hopeful) solution. – Memhave Mar 4 '17 at 0:43
• I will take a closer look tomorrow and list all the underlined and bold chars – Memhave Mar 4 '17 at 1:06
• @Memhave Are the underlining just photocopying bleed-through from the next page? – Lawrence Mar 4 '17 at 13:30
• @Lawrence Looking at the scanned photocopy, no. The underlines are clearly in the text and clearly not part of what was on the next page. Also, the underlined letters seems to be in boldtext for me. – Victor Stafusa Mar 4 '17 at 13:32
• @VictorStafusa You're right. My mistake. – Lawrence Mar 4 '17 at 13:35

When I looked at the underlined characters in the base64 encoded part, I got the sequence: MzJoYWNrZXI1NTd6amt6aS5vbmlvbgo.

Which decodes to a webpage.

The assembly code and the whole base64 string are on that site. The assembly code is in a file named u5emu.asm and the string is in a file named disk.img.b64.

So maybe the emulator/vm is some sort of Ultra 5 or SPARC thingy - which can mount the .img file?

• What is that site? – humn Mar 7 '17 at 18:06
• I guess it is a part of the puzzle :) – johndon Mar 7 '17 at 20:34
• This is the site (its a .onion so you'll need TOR or something similar afaik) 32hacker557zjkzi.onion – Memhave Mar 7 '17 at 21:49
• Definitely not SPARC. The opcode's in the wrong part of the word, for one thing. – Gareth McCaughan Mar 8 '17 at 0:12
• Can anyone confirm that the link is down now? Or am I missing some part of the link? – identity Mar 9 '17 at 18:16

I started reversing the VM; might as well post what I have so far. :)

• The VM is little-endian.
• The VM uses 32-bit fixed-length instructions. The opcode is stored in the high 5 bits (loadw, mul, movi, etc.). The remaining 27 bits vary depending on the opcode.
• There are 64 registers. The last register (reg[63]) is a 16-bit program counter, which increments by 4 after executing an instruction.
• Although instructions are always 4 bytes, they don't need to be 4-byte aligned.

Let us now document each instruction. In our notation, r6 means a register (identified by a 6-bit code) and immX means an X-bit immediate constant.

As Victor Stafusa has already mentioned, the x86 code provided in Image 1 is incomplete, and only provides 6 instructions: loadw, mul, movi, cmov, out, and read. The rest need to be figured out from the base64-encoded program in Image 2.

Encoding:

• Bits [31:27]: Opcode (00010)
• Bits [26:21]: Dest (r6)
• Bits [20:15]: X (r6)
• Bits [14:9]: Y (r6)
• Bits [8:0]: Unused

Operation:

Dest = mem[X + Y];


### OP_MUL

Encoding:

• Bits [31:27]: Opcode (01001)
• Bits [26:21]: Dest (r6)
• Bits [20:15]: X (r6)
• Bits [14:9]: Y (r6)
• Bits [8:0]: Unused

Operation:

Dest = X * Y; // Unsigned multiplication.


### OP_MOVI

Encoding:

• Bits [31:27]: Opcode (10000)
• Bits [26:21]: Dest (r6)
• Bits [20:5]: X (imm16)
• Bits [4:0]: Y (imm5)

Operation:

Dest = X << Y;


### OP_CMOV

Encoding:

• Bits [31:27]: Opcode (10010)
• Bits [26:21]: Dest (r6)
• Bits [20:15]: Src (r6)
• Bits [14:9]: X (r6)
• Bits [8:0]: Unused

Operation:

if (X != 0) {
Dest = Src;
}


### OP_OUT

Encoding:

• Bits [31:27]: Opcode (11001)
• Bits [26:21]: Char (r6)
• Bits [20:0]: Unused

Operation:

putchar(Char);


Encoding:

• Bits [31:27]: Opcode (11010)
• Bits [26:21]: Dest (r6)
• Bits [20:15]: Sector (r6)
• Bits [14:0]: Unused

Operation:

for (i = 0; i < 512; i++) {
mem[Dest + i] = disk[(Sector*512) + i];
}

• Maybe the [disk] referenced in the OP_READ is the same disk from @johndon s answer – Memhave Mar 7 '17 at 21:51