# 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]
```