1

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!

Unity
  • 23
  • 4
  • 1
    If you clarify, maybe we can help you, I've written bootloaders, but I don't think we have enough data. You should explain that there are two buffers being XORed together. The destination buffer goes from ES:0000 to ES:3FFF. The source (maybe that's what you call key) goes from DS:0800 to ... maybe DS:08BF, used circularly... We don't know what sectors those come from, since we don't see the beginning of the MBR code. – migle Jun 07 '13 at 20:50
  • Since the post is called "understanding assembly...", you see SI is set to 800h, then incremented by LODSW by 2, then the AND SI, 0ffbfh does a "remainder of division" operation, which keeps the "key" buffer being scanned circularly. Wherease the destination buffer, say, the ciphertext, is the one which is at ES:0000-3FFF. – migle Jun 07 '13 at 20:54
  • Thank you, I have added the complete MBR above aswell now – Unity Jun 07 '13 at 20:58
  • I hope this will help to understand where the key comes from – Unity Jun 07 '13 at 21:14
  • Yes, but this is also a bit of work... Hold on, I think it comes from the MBR. – migle Jun 07 '13 at 21:17
  • This MBR code is not very well written, which is quite unusual of open source software. Why don't you read the source code of a bootloader (instead of a disassembly, which lacks a lot of things)? There's one from me on github, https://github.com/migle/BootDuet. It has lots of comments... – migle Jun 07 '13 at 22:51

1 Answers1

0

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?

migle
  • 881
  • 8
  • 11
  • About that bug... actually, this code does the XOR-thing for 32kB minus 2 bytes... instead of the 16kB we read from disk. I guess there's no harm in XORing garbage, taking twice the time, but it shows some sloppyness. Also, the copy of the MBR to 0600 was pretty useless, since we are loading the target program at address 20000, there was no need of doing it. Now, you satisfy our curiosity and tell us where is this from. – migle Jun 07 '13 at 21:52
  • Thanks, Ive added some more queries and information to the original post taking all the points you have made so far. – Unity Jun 07 '13 at 22:21
  • the 64 byte xor key is at byte 256 of second sector but this is offset 0x300-0x3FF on the disk – Unity Jun 07 '13 at 22:31
  • Of course... Each sector is 512 bytes, so byte 256 of second sector is byte 768 on disk, 0x300. But it's only 64 bytes from then on, so its from 0x300 to 0x33f, not 0x3ff. Or, say, each sector is 0x200, half a sector 0x100, and we could go on and on refering to the same address in different ways... – migle Jun 07 '13 at 22:44
  • Oh, I see, you misunderstood the 0x800 to 0x83F address, that's the address of the memory buffer, not the disk address. – migle Jun 07 '13 at 22:49
  • Yes, I understand now. Thank you for all the help youve given, its been very useful – Unity Jun 07 '13 at 22:57