The most common hacking method applied on the calculators is return-oriented programming.

What are "set lr" commands used for?

Usually, it is desirable for the destination (popped value from the stack used as new PC value) to be one of the following:

  • Some commands, and pop pc. In this case, it is possible to execute those commands, then jump to another chosen location.
  • Right after the push lr command of a function. Similar to the above, the calculator will execute the specified function, then jump to another chosen location.
  • Some commands, and rt. After executing those commands, the code at the address of lcsr:lr will be executed, therefore it is necessary to make lcsr:lr have a "good" value (usually at a pop pc command) before having this destination in the ROP chain.
  • Some commands, push lr, the main function and pop pc. This may happen for functions doing very simple task then return/call another function. This also require good LR value similar to the case above

In the last 2 cases, it's necessary for the LR to have correct value (preferably right before a POP PC command). To achieve that it's possible to jump to an address like this (often called set lr:

a:
    call b
    pop pc

....

b:
    (some trivial task, or nothing)
    rt

Why/when is it necessary to restore the stack?

Most functions, except the extremely simple ones, use the stack to store temporary variables.
Because the stack is used to store the ROP chain, it will get corrupted.

In that case, if it's necessary to execute that part again, the program must restore itself with a copy.