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