# DiceGang - Highest Power
by @defund, @hgarrereyn and @Aplet123
## Conventions
`binop` pops two, pushes value
`binop c` pushes `c`, calls `binop`
`load` pops top (address on top), pushes value
`store` pops two (address on top), address on top
`jlt` pops two (greater on top)
`nz` pops one
`dup` replicates top of stack
`pick` replicates element below top of stack
## Base variables
```
0x00: uint32_t ip
0x04: char unk (used as a temp var in f39)
0x05: char shuffle_offset (initialized to 1)
0x06: char ctr (used to track newlines)
0x07: char unk (initialized to 0)
0x08: char[0x20] buffer (used by f6)
0x28: char unk28
0x29: fd
0x2d: char[0x100] buffer... (used by f39)
0x12d: request_key
0x12e: char cidx (used in f34)
0x12f: unk
0x130: return value of connect() in f5
```
## Assembly
```
f0_start: 16, 25, 11, 10, 1, 25, 2
base[0x29] = accept()
base[0] = ?
f16_check_req_path() ; "GET /gather_everyone_to_reveal_our_secret"
f25_cmp_0()
f25_cmp_0()
f11_wait_for_newlines(base[0x29])
f10_is_local()
and
dup
if nz:
f1_good_req()
f25_cmp_0()
if nz:
f2_bad_req()
```
```
f1_good_req: 19, 26, 8, 9, 5, 3
f19_ok() ; "HTTP/1.0 200 OK\r\n\r\n"
f26_init_things() ; initialize some variables
f8_format_ip()
ip = f9()
f5_talk_to_peer(ip)
drop
ip = f9()
f5_talk_to_peer(ip)
drop
f3()
close(base[0x29])
finish()
```
```
f2_bad_req: 18
f18_bad()
close(base[0x29])
```
```
f3: 4
push 0
f4()
drop
```
```
f4(v): 29
dup ; v v
load base[8 + (pop)] ; v base[8+v]
f29()
xor
write(base[0x29])
add 1
dup
push 0x20
lt
jnz
```
```
f5_talk_to_peer(ip):
; ------------
; target_fd @ 0x130
; ------------
if [base+0x12d] == 0: return
target_fd = connect(ip, 8000)
if target_fd < 0: return
f17_make_request()
f11_wait_for_newlines(target_fd)
f6_read_body()
close(target_fd)
_old_f5: 24, 17, 11, 6
push base
push 0x12d
add
load
push 0
if !eq: ;
dup ; ip ip
push 0x1f40 ; ip ip 8000
connect(8000, ip)
push base
push 0x130
add
set
; base[0x130] = connect(ip, 8000)
push base
push 0x130
add
load
f24_is_negative()
if eqz: <= 0x7fffffff
; make a request to another server
f17_make_request()
push base
push 0x130
add
load
f11_wait_for_newlines()
f6_read_body()
push base
push 0x130
add
load
close()
```
```
f6_read_body: 7
; reads 32 bytes from socket, xors with base[8], base[9], ..., base[8+32]
push 0
f7()
pop
```
```
f7(a):
dup ; [a, a]
push base ; [base, a, a]
add 8 ; [base+8, a, a]
add ; [base+8+a, a]
dup
load ; [v, base+8+a, a]
load base[0x130] ; [fd, v, base+8+a, a]
read() ; [char, v, base+8+a, a]
xor ; [char^v, base+8+a, a]
swap ; [base+8+a, char^v, a]
store ; [a]
add 1 ; [a+1]
dup ; [a+1, a+1]
push 0x20 ; [0x20, a+1, a+1]
jlt ; [a+1]
```
```
f8_format_ip: 27
load base[0] ; ip
dup ; ip ip
and 0xff ; ip ip[0]
swap ; ip[0] ip
shr 8 ; ip[0] (ip>>8)
dup ; ip[0] (ip>>8) (ip>>8)
and 0xff ; ip[0] (ip>>8) ip[1]
swap ; ip[0] ip[1] (ip>>8)
shr 8 ; ip[0] ip[1] (ip>>16)
dup
and 0xff
swap
shr 8 ; ip[0] ip[1] ip[2] ip[3]
f27()
f27()
f27()
f27()
```
```
f9: 29
push 0xa00
f29()
add
push 0x100
mul
f29()
add
push 0x100
mul
f29()
add
```
```
f10_is_local:
ret (base[0] >> 0x18) == 10
```
```
f11_wait_for_newlines(fd): 14, 12
f14_reset_ctr()
f12_inner_wait_for_newlines(fd)
drop
```
```
; this function waits for a newline followed by a return
f12_inner_wait_for_newlines(fd): 13, 25, 14, 24, 15
dup ; fd is on top of stack
read
dup
dup
push 10 ; '\n'
eq
dup
if nz: f13_inc_ctr()
f25_cmp_0()
swap
push 0xd ; '\r'
eq
f25_cmp_0()
and
if nz: f14_reset_ctr()
f24()
if nz: f15_ctr_set_2()
load base[6]
push 2
jlt
```
base[6] seems to act as some sort of counter?
```
f13_inc_ctr:
base[6] += 1
```
```
f14_reset_ctr:
base[6] = 0
```
```
f15_ctr_set_2:
base[6] = 2
```
```
f16_check_req_path: 25
read match "GET /gather_everyone_to_reveal_our_secret"
read(base[0x29])
dup ; v v
push 0x20 ; ' '
ensure eq ; v
push 0
swap ; not sure here ; 0 v
push '?'
xor
ensure eq ; 0 = v^?
read(base[0x29])
push 0x30
sub
push base
push 0x12d
add
store
; [base+0x12d] = read(fd) - 0x30
read(base[0x29])
push 0x20 ; ' '
xor
ensure eqz
push 2
push base
push 0x12d
add
load
if gt: ; this condition might be inverted
f25_cmp_0()
```
```
f17_make_request:
write "GET /gather_everyone_to_reveal_our_secret?"
push 0x30
push base
push 0x12d
add
load
add ; [base+0x12d]+0x30
push 1
sub ; [base+0x12d]+0x30-1
push base
push 0x130
add
load
write
write " HTTP/1.0\r\n\r\n"
```
```
f18_bad:
push "HTTP/1.0 403 Forbidden\r\n\r\n"
load base[0x29]
write
```
```
f19_ok:
push "HTTP/1.0 200 OK\r\n\r\n"
load base[0x29]
write
```
```
f20_init_buffer(buffer, len): 21
; initializes buffer to [0, 1, 2, ..., 254, 255]
pick ; [len, fd, len]
add ; [fd+len, len]
sub 1 ; [fd+len-1, len]
swap ; [len, fd+len-1]
f21()
pop
pop
```
```
f21(len, addr):
sub 1 ; [len-1, addr]
swap ; [addr, len-1]
pick ; [len-1, addr, len-1]
pick ; [addr, len-1, addr, len-1]
store ; [addr, len-1]
sub 1 ; [addr-1, len-1]
swap ; [len-1, addr-1]
dup ; [len-1, len-1, addr-1]
jnz ; [len-1, addr-1]
; returns 0, b-a
```
```
; unused
f22(addr, len): 23
pick ; [len, addr, len]
add ; [addr+len, len]
sub 1 ; [addr+len-1, len]
swap ; [len, addr+len-1]
f23()
pop
pop
```
```
; unused
f23(len, addr):
sub 1 ; [len-1, addr]
swap ; [addr, len-1]
pick ; [len-1, addr, len-1]
pick ; [addr, len-1, addr, len-1]
load ; [v, len-1, addr, len-1]
debug ; [v, len-1, addr, len-1] prints v
pop ; [len-1, addr, len-1]
pop ; [addr, len-1]
sub 1 ; [addr-1, len-1]
swap ; [len-1, addr-1]
dup ; [len-1, len-1, addr-1]
jnz ; [len-1, addr-1]
; returns 0, addr-l
```
```
f24_is_negative(x):
push 0x7fffffff
swap
lt
; returns whether x > 0x7fffffff
```
```
f25_cmp_0(x):
push 0
eq
; returns whether x is zero
```
```
f26_init_things: 20
base[0x12e] = 0
base[0x28] = 0
base[0x134] = 0
base[0x12f] = 0
base[7] = 0
base[5] = 1
f20_init_buffer(base[0x2d], 0x100)
```
```
f27(char v):
f28(v & 0xf)
f28(v >> 4)
```
```
f28(char v): 31, 39 ; takes a nibble
if base[7] == 0x80:
f31_shuffle_sort()
add 0x80
f39_swap_idx(base[7])
base[7] += 1
```
```
f29: 31, 34, 30
load base[7]
if nz:
f31_shuffle_sort()
f34_inner_shuffle()
f30_update_shuffle_keys()
```
```
; related to shuffling
f30_update_shuffle_keys():
; -------------
; cidx @ 0x12e
; -------------
v = ([base+0x134] + [base+0x12f]) & 0xff
v2 = (buffer[v] + [base+cidx]) & 0xff
v3 = (buffer[v2] + [base+28]) & 0xff
[base+0x12f] = buffer[v3]
_old_f30():
load base[0x134]
load base[0x12f]
add
and 0xff
load base[0x2d + (pop)]
load base[0x12e]
add
and 0xff
load base[0x2d + (pop)]
load base[0x28]
add
and 0xff
load base[0x2d + (pop)]
dup
store base[0x12f]
; returns the stored value
```
```
f31_shuffle_sort: 32, 35
f32_outer_shuffle(0x200)
f35_sort()
f32_outer_shuffle(0x200)
f35_sort()
f32_outer_shuffle(0x200)
base[7] = 0
```
```
f32_outer_shuffle(n): 33
; -------------
; shuffle_offset @ 0x5
; -------------
f33_shuffle(n)
pop
shuffle_offset += 2
```
```
; perform inner shuffle N times
f33_shuffle(n): 34
f34_inner_shuffle()
sub 1
dup
jnz
```
```
; seems like an inner shuffle thing
f34_inner_shuffle:
; -------------
; shuffle_offset @ 0x5
; unk28 @ 0x28
; cidx @ 0x12e
; -------------
cidx += shuffle_offset
v = (buffer[cidx] + unk28) & 0xff
unk28 = buffer[v] + [base+0x134]
[base+0x134] = buffer[unk28] + [base+0x134] + [base+cidx]
swap_idx(unk28, cidx)
_old_f34: 39
load base[0x12e] ; base[0x12e]
load base[5] ;
add ; (base[0x12e]+base[0x5])
store base[0x12e]
; [base+0x12e] += [base+0x5]
load base[0x12e]
load base[0x2d + (pop)] ; [base+0x2d+[base+0x12e]]
load base[0x28]
add
and 0xff
; ([base+0x2d+[base+0x12e]]+base[0x28]) & 0xff
load base[0x2d + (pop)] ; [base+0x2d+v]
load base[0x134]
add
store base[0x28]
load base[0x28]
load base[0x2d + (pop)]
load base[0x134]
add
load base[0x12e]
add
store base[0x134]
load base[0x12e]
load base[0x28]
f39_swap_idx()
```
```
; sorts the first 0x80 elements of the buffer at 0x2d
f35_sort: 36
f36_inner_sort(0x80)
pop
```
```
f36_inner_sort(v): 37
push 1 ; v 1
sub ; v-1
f37()
dup
jnz
```
```
f37(v): 38
dup ; v v
load base[0x2d + (pop)] ; v [base+0x2d+v]
pick ; v [base+0x2d+v] v
push 0xff ; v [base+0x2d+v] v 0xff
swap ; v [base+0x2d+v] 0xff v
sub ; v [base+0x2d+v] (0xff-v)
load base[0x2d + (pop)] ; v [base+0x2d+v] [base+0x2d+0xff-v]
swap ; v [base+0x2d+0xff-v] [base+0x2d+v]
lt
if nz: f38(v)
```
```
f38(v): 39
dup ; v v
dup ; v v v
push 0xff ; v v v 0xff
swap ; v v 0xff v
sub ; v v (0xff-v)
f39_swap_idx(0xff-v)
```
```
f39_swap_idx(v):
[base+4] = [base+0x2d+v]
[base+0x2d+v] = [base+0x2d]
[base+0x2d] = [base+4]
```
```
_asm_f39(v):
push base ; v base
add 0x2d
add ; v (base+0x2d)
swap ; (base+0x2d) v
push base
add 0x2d
add ; (base+0x2d) (base+0x2d+v)
dup ; (base+0x2d) (base+0x2d+v) (base+0x2d+v)
load ; (base+0x2d) (base+0x2d+v) [base+0x2d+v]
push base
add 4 ; (base+0x2d) (base+0x2d+v) [base+0x2d+v] (base+4)
store ; (base+0x2d) (base+0x2d+v)
; [base+4] = [base+0x2d+v]
pick ; (base+0x2d) (base+0x2d+v) (base+0x2d)
load ; (base+0x2d) (base+0x2d+v) [base+0x2d]
swap ; (base+0x2d) [base+0x2d] (base+0x2d+v)
store ; (base+0x2d)
; [base+0x2d+v] = [base+0x2d]
load base[4] ; (base+0x2d) [base+4]
swap ; [base+4] = (base+0x2d)
store
; [base+0x2d] = [base+4]
```