It reads two arguments and copies arg2 to mem[arg1]. And here is the mistake: arg1 is checked, but if it’s too large, nothing bad happens – only a message is shown and the instruction is executed.

So, we can overwrite any writeable place in program with any data. I decided to put shellcode at the first virtual memory addresses. And then overwrite some callable pointer with our shellcode address. There is a nice one, at 0x080E4FF0 (it points to a some sort of terminating function). It’s has index of 396 ( (0x080E4FF0-0x080E49C0)/4 ):