# Fast Calculator - rev
One binary file is given. 64bit ELF file, compiled with golang.
```c=
while ( 1 )
{
do
{
while ( 1 )
{
printf("Enter your operation: ", v8, v28, v29, v30, v31, v63, v64, v65, v66);
while ( 1 )
{
v8 = &v74;
if ( _isoc99_scanf(" %lf %c %lf", &v74, &v67, v75, v32, v33, v63) == 3 )
break;
while ( getchar() != 10 )
;
printf("Enter your operation: ", &v74, v34, v35, v36, v37);
}
if ( v67 == '+' || v67 == '-' || v67 == '*' || v67 == '/' || v67 == '%' || v67 == '^' )
break;
puts("Invalid operation!", &v74, v38, v39);
}
LODWORD(v79) = v67;
v80 = v74;
v81 = v75[0];
v76 = calculate(" %lf %c %lf", &v74, v38, v39, v40, v41, *v75, v3, v4, v5, v42, v43, v6, v7, v67, v74, *v75);
printf("Result: %lf\n", &v74, v44, v45, v46, v47, v76);
v48 = v76;
}
while ( v76 != 8573.8567 );
```
Throwing binary into ida and checking the pseudo code, you can see that the calculation formula is input first, calculated with the `calculate` function, and then repeated until the result is `8573.8567`.
```c=
enc_data = &v63;
j_memcpy(&v63, v83, v70);
flip_count = 0;
for ( i = 0; i < operations_length; ++i )
{
v48 = calculate(...v82[3 * i],*&v82[3 * i + 1],*&v82[3 * i + 2]);
if ( gauntlet(v48) )
{
i_div = i / 8;
v52 = (1 << (7 - i % 8)) ^ enc_data[i / 8];
enc_data[i_div] ^= 1 << (7 - i % 8);
++flip_count;
}
}
v8 = operations_length;
printf("I calculated %d operations, tested each result in the gauntlet, and flipped %d bits in the encrypted flag!\n",operations_length,flip_count);
puts("Here is your decrypted flag:\n", v8, v57, v58);
printf("%s\n\n", enc_data, v59, v60, v61, v62);
```
enc_data -> `encrypted flag`
v82 -> `0x00000000004B8240`
If the result is 8573.8567, the loop is end, and an operator symbol and two double-type numbers are taken from v82 and called as arguments of the `calculate` function. `gauntlet` function just checks if the number is negative.
so, each bit of encrypted flag is xored with 1 when the return value of calculate is negative.
That's all. But the final decrypted data is `uiuctf{This is a fake flag. You are too fast!}`. User input has no effect on the decryption.
With some guessing, I checked somethings
+ init_array -> just call `set_fast_math`
+ another array -> nop
+ swap the positions of each numbers -> nop
So I started debugging and I have encountered some peculiar operations in the calculate function.
In one specific calculation, when `-218.05xx` is divided by `218.05xx` using ``%``, the result is -0.0 (`0x8000000000000000`). However, the gauntlet function does not interpret this value as negative.
Similarly, in certain square operations, the result is -nan (`0xfff8000000000000`), but the gauntlet function does not consider it negative.
As far as I know, the result of the modulo operation is always negative if the dividend is negative. The same is true for squares.
I implemented the operation back in Python to handle these exceptions.
`solve script`
```python=
import struct
ops = open("./ops", "rb").read()
enc = open("./calc_out", "rb").read()
enc = list(enc)
c = 0
for i in range(0, len(ops), 24):
op = chr(ops[i])
n1, n2 = struct.unpack("<dd", ops[i + 8:i + 24])
if op in ["+", "-", "*", "/"]:
res = eval(f"n1 {op} n2")
elif op == "%":
res = -1 if n1 < 0.0 else 1
elif op == "^":
res = -1 if n1 < 0.0 else 1
if res < 0.0:
enc[c // 8] ^= 1 << (7 - c % 8)
c += 1
print(bytes(enc))
```
ops -> dumped 0x00000000004B8240 ~ 0x00000000004B8240+0x170 * 0x24
enc -> dumped v83 ~ v83+0x40
> uiuctf{n0t_So_f45t_w1th_0bscur3_b1ts_of_MaThs}
second blood 🩸🩸