- How to extract the bytecode without a lots of manual work
As per https://github.com/kfl/mosml/blob/master/src/runtime/main.c#L62, the last 20 bytes of the EXE make up an
static int read_trailer(int fd, struct exec_trailer * trail)
unsigned char buffer[TRAILER_SIZE];
lseek(fd, (long) -TRAILER_SIZE, 2);
if (read(fd, (char*)buffer, TRAILER_SIZE) < TRAILER_SIZE)
trail->code_size = read_size(buffer);
trail->data_size = read_size(buffer+4);
trail->symbol_size = read_size(buffer+8);
trail->debug_size = read_size(buffer+12);
trail->magic = read_size(buffer+16);
if (trail->magic == EXEC_MAGIC) return 0; else return BAD_MAGIC_NUM;
And as per https://github.com/kfl/mosml/blob/master/src/runtime/main.c#L229, the bytecode begins at
(20 + trail.code_size + trail.data_size + trail.symbol_size + trail.debug_size) bytes before the end of the file.
- How to decompile the Moscow ML bytecode?
The bytecode interpreter is defined here: https://github.com/kfl/mosml/blob/master/src/runtime/interp.c#L87
However, even if you were to leverage the parser in that interpreter, the best you'd get is an intermediate representation of the code (consisting of the instructions in https://github.com/kfl/mosml/blob/master/src/runtime/instruct.h), not the decompiled ML code itself.
If you want to convert the intermediate instructions to an actual decompilation, that question would probably be better asked at https://stackoverflow.com/.