HackIM 2019 0bfusc8 much

Disclaimer
I failed to solve this during CTF. I got good looking flag, but it was wrong. The following day woke up, fixed one character, and it was correct. I am also n00b on RE, so there probably is a better solution.

Overview
In short, we are given a binary that asks flag string, runs a lot of obfuscated code, and prints out 0 for the wrong flag and 1 for the correct one. There is the only main function
but it has 1.8MB of assembly code and 152kB of stack variables, so reversing this traditionally would take a long time.

Approach
Out of ideas, I had to try something. So I wrote Frida script to dump stack memory after execution to see some changes when trying different flag strings. But looking at that huge dump of numbers with WinMerge was pain. The last idea that came to mind was to calculate a count of zero bytes in that dump. I thought that if the program advanced in the right direction, it would generate more non-zero bytes.

Solution
So I had a Frida script to dump stack after execution. I modified it to append count of zeros and flag string to file. Next, I wrote C# code to enumerate the last character of my flag string and call Frida script with that. After guessing all possible characters at the end of the string, C# takes the output file, sorts results by count of zeros, and takes the character with the least zeros on the stack. With that I got result like this: hackim19{Get_Hard____Dynamic_Reeersing_AAAP_braceeee_e_e__y_u_traceeee}. So clearly, this is working, but there are some errors. Code gives a probability of characters in case of wrong characters, so it is possible to guess the right one. Like here:

TheString:hackim19{Get_Hard_In_Dynamic_Reversing_A
:139184:hackim19{Get_Hard_In_Dynamic_Reversing_AA
:139185:hackim19{Get_Hard_In_Dynamic_Reversing_AS
:139225:hackim19{Get_Hard_In_Dynamic_Reversing_A_
:139260:hackim19{Get_Hard_In_Dynamic_Reversing_AP
:139283:hackim19{Get_Hard_In_Dynamic_Reversing_A-

Here the correct character would be S, but the code gets A. This is because stack zero counts differ only by one. But we can guess that AAAP is ASAP.

The failure
After all coding and guessing finally got flag: hackim19{Get_Hard_In_Dynamic_Reversing_ASAP_brace_me_then_you_trace_me} but it was WRONG!
Wrote code to iterate each character and tried all possible characters in the ASCII table to replace it. No flag.
The next morning realized I had accidentally fed the wrong string to code. There were now two wrong characters. With correct string, finally got:
hackim19{Get_Hard_In_Dynamic_Reversing_ASAP_brace_me_when_you_trace_me}
But it was a few hours too late. On no.

Resources

Here is Frida script. Download here. Edit: there may be some mistakes in pointer addition operations. Please use ptr(somever).add(123) form. ptr(somevar+123) may cause surprises if somevar is string.

IDA view at beginning of main.

C# code to run things. Download here.