Try   HackMD

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]