When reading code that's hard to understand, I like to gradually remove annoyances. First, I'll reformat the code, so that it follows the style guide of the rest of the project. Second, I'll rename functions and variables to better explain their purpose. Third, I'll go through weird constructs and try to simplify them. If I still don't understand the code, I'll try to use a debugger or draw diagrams to better explain the program flow to myself. Throughout this process, I'll ask colleagues, if needed, especially the author of the code.
A dilemma appears when I probably should replace the code with something better, but I'm not entirely sure yet. Do I really have to work on code that's about to disappear?