Question

Could anyone provide some insight into the following assembly code:

More Information:

The bootloader is in fact a small 16bit bootloader that decipher using Xor decryption, a bigger one, a linux bootloader located in sectors 3 to 34. ( 1 sector is 512 byte in that disk )

The whole thing is a protection system for an exec running on embedded Linux.

the version where the protection was removed has the linux bootloader already deciphered ( we were able to reverse it using IDA ) so we assume that the xor key must be made only with zero's in the version without the protection.

if we look at offset 0x800 to 0x8FF in the version with protection removed it is not filled with zero's so this cannot be the key otherwise this version couldn't be loaded, it would xor plain data and load nothing but garbage.

the sectors 3->34 are ciphered in original version and in clear in our version ( protection removed ) but the MBR code ( small prebootloader ) is identical in both version.

So could it be that there is a small detail in the assembly code of the MBR that changes slightly the place of the xor key?

This is simply an exercise I am doing to understand assembly code loaders better and I found this one quite a challenge to go through. I thank you for your input so far!

Was it helpful?

Solution

Well, reading assembly code is a lot of work. I'll just stick to answering where does the "key" come from.

  • The BIOS loads the MBR at 0000:7C00 and sets DL to the drive from which it was loaded.
  • First, your MBR sets up a stack growing down from 0000:7C00.
  • Then, it copies itself to 0000:0600-0000:07ff and does the far jump which I assume is to the next instruction, however on the copied version, 0000:061D. (EDIT: this copy is a pretty standard thing for an MBR to do, typically to this address, it leaves the address space above free) (EDIT: it copies itself fully, I misread).
  • Then, it tries 5 times to read sector 2 into 0000:0700-0000:08ff, and halts with an error message if it fails (loc_78).
  • Then, it tries 5 times to read 32 sectors starting from sector 3 into 2000:0-2000:3FFF (absolute address 20000-23FFF, that's 16kB starting at 128kB).
  • If all goes well we are at loc_60 and we know what we have in memory.
  • The loop on loc_68 will use as destination the buffer holding those 32 sectors.
  • It will use as source the buffer starting at 0000:0800 (which is the second 256 bytes of the buffer we read into 0:0700-0:08ff, the second 256 bytes of sector 2 of the disk).
  • On each iteration, LODSW adds 2 to SI.
  • When SI reaches 840, it is set back to 800 by the AND. Therefore, the "key" buffer goes from 800 to 83F, which is to say the 64 bytes starting at byte 256 of sector 2 of the disk.
  • I have the impression that the XORing falls one byte short... that CX should have been set to 4000h, not 3FFF. I think this is a bug in the code.
  • After the 16kB buffer at physical address 20000 has been circularly XORed with that "key" buffer, we jump into it with a far jump to 2000:0.

Right? Does it fit? It the key there?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top