✝️ 1 John 2:15-17 Do not love the world or anything in the world. If anyone loves the world, love for the Father is not in them. For everything in the world—the lust of the flesh, the lust of the eyes, and the pride of life—comes not from the Father but from the world. The world and its desires pass away, but whoever does the will of God lives forever. Ill be honest, I gotta lock in when it comes to learning abt anti reversing techniques, so let us practice together! I wanted to pick out some VM crackme to practice so I picked [this](https://crackmes.one/crackme/6a6b5bdd59d4a7b04de30a28). The name of the author is [mintcocs](https://crackmes.one/user/mintcocs). I started by opening the challenge in ida pro and saw the following: ``` Function name Segment Start Length Locals Arguments R F L M O S B T = X _main __text 0000000100000978 000000C8 00000040 R . . . . . B T . . -[VM initWithProgram:] __text 0000000100000A40 00000110 00000050 R . . . . . B T . . -[VM fetchByte] __text 0000000100000B50 00000034 00000010 R . . . . . . T . . -[VM fetchWord] __text 0000000100000B84 0000006C 00000030 R . . . . . B T . . -[VM updateZeroFlagWithValue:] __text 0000000100000BF0 0000004C 00000020 R . . . . . . T . . -[VM run] __text 0000000100000C3C 000010EC 00000210 R . . . . . B T . . ___memset_chk __stubs 0000000100001D28 0000000C R . . . . . . . . . ___stack_chk_fail __stubs 0000000100001D34 0000000C . . . . . . . . . . _fflush __stubs 0000000100001D40 0000000C R . . . . . . T . . _fgets __stubs 0000000100001D4C 0000000C R . . . . . . T . . _objc_alloc __stubs 0000000100001D58 0000000C R . . . . . . T . . _objc_autoreleasePoolPop __stubs 0000000100001D64 0000000C R . . . . . . T . . _objc_autoreleasePoolPush __stubs 0000000100001D70 0000000C R . . . . . . T . . _objc_msgSendSuper2 __stubs 0000000100001D7C 0000000C R . . . . . . T . . _printf __stubs 0000000100001D88 0000000C R . . . . . . T . . _putchar __stubs 0000000100001D94 0000000C R . . . . . . T . . ``` So, lets look at main first! ![[ida_vm_01.jpg]] So first of all, 0x64 bytes at \_PROGRAM are copied into a buffer and \-\[VM initWithProgram:\] is called with the buffer that 0x64 bytes of \_PROGRAM were copied to. The text "give me the code:" is printed and stdout is flushed and then \-\[VM run\] is called with the result of \-\[VM initWithProgram:\] and some cleanup happens and \_main returns. Now, lets look at \-\[VM initWithProgram:\]! ![[ida_vm_02.png]]After some setup, the address of the buffer is stored at SELF + 0x110, two zero bytes are stored at SELF + 0x10C and a zero byte at SELF + 0x10E. The function \_memset\_chk is called with SELF + 8, 0 also four zero bytes are stored at \[SP + 4\], 4, and -1, also -1 as 8 bytes is stored at \[SP + 8\]. \_memset\_chk is called again with SELF + 0xC, 4 bytes at \[SP + 4\], 0x100, 8 bytes at \[SP + 8\]. The length of the argument given to \-\[VM initWithProgram:\] is stored as 8 bytes in \[SP + 0x10\]. That same length is checked if it is less than 0x100 and if it is then we jump to loc\_100000B18 else we store 8 bytes equal to 0x100 at \[SP + 0x10\] and then we branch to loc\_100000B18. At loc\_100000B18, a new buffer is made from whatever the 8 bytes starting at \[SP + 0x10\] are as the length and SELF + 0xC as the start of the buffer and the argument given to \-\[VM initWithProgram:\] is what is used to copy from. SELF is returned. The next function to look at is \-\[VM fetchByte\]! ![[ida_vm_03.png]]So, the value of 2 bytes at SELF + 0x10C is increased by 1 and SELF + 0xC is returned. The next function to look at is \-\[VM fetchWord\]! ![[ida_vm_04.jpg]]So, \-\[VM fetchByte\] is called and the result as a byte is stored in \[SP + 0xF\], and \-\[VM fetchByte\] is called again and the result as a byte is stored in \[SP + 0xE\]. The result of the bitwise or operation between byte at \[SP + 0xF\] and the byte at \[SP + 0xE\] that is shifted to the left by 8 bits, has the bitwise and operation on it and 0xFFFF and is returned. The next function to look at is \-\[VM updateZeroFlagWithValue:\], so lets do this! ![[ida_vm_05.png]]If the argument given to \-\[VM updateZeroFlagWithValue:\] is not zero then we modify SELF + 0x10E by the bitwise and operation with 0xFE and we return. If the argument is zero then we modify SELF + 0x10E by the bitwise or operation with 1 and we return. NOW! The moment I have personally been waiting for... WE GET TO REVERSE \-\[VM run\]! It starts off like this! ![[ida_vm_06.png]]SELF is stored at \[SP + 0xE0\] and we jump to loc\_100000C68 and there \-\[VM fetchByte\] is called and the result as a byte is stored in \[SP + 0xD7\] and is also stored at \[SP + 0x80\] and that value is subtracted by 0xFF and if the carry flag was set and the zero flag was cleared then we branch to def\_100000CB4 else PC is set to 0x100000C9C. Now, let us look at def\_100000CB4 first! ![[ida_vm_07.png]]Sooo, lol it is just prints "Unknown opcode: %02x\n", where %02x will be the byte at \[SP + 0xD7\] and then the function returns. Now, lets look at 0x100000C9C. ![[ida_vm_08.png]]So, X11 is set to 8 bytes at \[SP + 0x80\] and the pseudo instruction ADRL is used to load the address of a jump table into X10. We jump to 0x100000CA8 + the value of 4 bytes at (X10 + (X11 shifted to the left by 2)). Now, let's go to the first option! ![[ida_vm_09.png]]It simply branches to loc\_100001CF4! So let's call loc\_100000CB8 VM\_NOP\_00. Anyways, loc\_100001CF4 just branches to loc\_100000C68 as you can see below! ![[ida_vm_10.png]] And you can see loc\_100000C68 in one of the images above! Anyways, the next place we branch to is def\_100000CB4. I already showed that image above, it is the unknown opcode branch, let us give it a fun name! hmmm... VM\_UNKNOWN\_OPCODE\_00 is boring but it works! Now, lets keep going! Up next we have... ![[ida_vm_11.png]]Now, this just prints a newline and then the function returns! Let us call this VM\_PRINT\_NEWLINE\_00. Next, up is... ![[ida_vm_12.png]]\-\[VM fetchByte\] is called on SELF twice, the first call's byte is stored in \[SP + 0xD6\], the second call's byte is stored in \[SP + 0xD5\]. If the byte at \[SP + 0xD6] is greater than or equal to 4 we jump to loc\_100000D4C, else the byte at \[SP + 0xD5] is stored at \[SELF + 8 + (the byte at \[SP + 0xD6])\ and then -\[VM updateZeroFlagWithValue:\] is called with SELF and the byte at \[SELF + 8 + (the byte at \[SP + 0xD6])\, then we branch to loc\_100000D4C and there we just branch to loc\_100001CF4. Also I renamed The code block we looked at (the first one) to VM\_MOV\_IMM\_00, anyways the next basic block we will look at is... (drum roll please... I SAID DRUMROLL PLEASE!) loc\_100000D50: ![[ida_vm_13.png]] \-\[VM fetchByte\] is called on SELF ![[ida_vm_14.png]] Next image below! ![[ida_vm_15.png]] Next image below! ![[ida_vm_16.png]] So, as you can see the 4 images show what happens for loc\_100000D50. (TODO)