There are two problems:
Util.exe is actually not called in the context of the cmd instance you initiate, but I guess you want that; to resolve this, either escape the ampersand or quote the command line:
cmd /C MainApp.exe ^& Util.exe
or:
cmd /C "MainApp.exe & Util.exe"
Since you are trying to write and read a variable in the same command line/block, you need to enable and apply delayed expansion, which can be achieved by cmd /V, like this:
cmd /V /C MainApp.exe ^& set /A ERR=!ErrorLevel! ^& Util.exe ^& exit !ERR!
or:
cmd /V /C "MainApp.exe & set /A ERR=!ErrorLevel! & Util.exe & exit !ERR!"
This works only given that MainApp.exe also sets the ErrorLevel, which is not always the same as the exit code. If it does not, you could try this (the || operator forces ErrorLevel to equal the current exit code):
cmd /V /C MainApp.exe ^|^| rem/ ^& set /A ERR=!ErrorLevel! ^& Util.exe ^& exit !ERR!
or:
cmd /V /C "MainApp.exe || rem/ & set /A ERR=!ErrorLevel! & Util.exe & exit !ERR!"
In case Util.exe does not need to be executed in case MainApp.exe returns a non-zero exit code, do this (so the exit code of MainApp.exe survives):
cmd /C MainApp.exe ^&^& Util.exe
or:
cmd /C "MainApp.exe && Util.exe"
If MainApp.exe really does not set ErrorLevel, you could try the following:
cmd /C MainApp.exe ^&^& Util.exe || rem/
or:
cmd /C "MainApp.exe && Util.exe || rem/"