How to dump the bootloader from UA65ES8000

Here is information about customize your E series firmware..:!:This forum is NOT FOR USER questions or problems but DEVELOPER.

xorloser
Posts: 43
Joined: Sun Oct 28, 2012 2:49 pm

How to dump the bootloader from UA65ES8000

Post by xorloser »

Note that the following was done on my UA65ES8000 TV, but I would assume that the method would be much the same for any TV that uses a similar emmc flash.



:: Why Would I Want to Dump the Bootloader?

While researching the security model of my UA65ES8000 TV, I found I needed to dump the bootloader since it is the root of trust for it. Since I wasn't able to find any info on how to do this I thought I'd post my method and the process I followed to help others who may want to dump their own. All reverse engineering was done in the interest of interoperability. And be warned that attempting what I describe could brick your TV.

ONLY TRY THIS IF YOU KNOW WHAT YOU ARE DOING!



:: Why Can't I Dump the Bootloader?

The "bootloader area" is different to "user area" in the emmc flash present in the TV. A different mode is used to access each area, so "bootloader mode" lets you access the bootloader, and "user mode" lets you access the user area. While this can limit access to the bootloader, I imagine the main reason this is done is to stop accidental bootloader corruption. At power on time the flash is in bootloader mode so it can execute the bootloader. It then gets switched to user mode and stays in this mode to load the rest of the system. So when we run the linux "dd" command, we can dump all partitions in the user area because we are currently in user mode. However we cannot access and dump the bootloader until the mode gets changed to bootloader mode. (This is my understand of how the flash works anyway, I could be wrong ;)).



:: So How Do I Get Access to the Bootloader?

juuso pointed out that there is a user mode program present on the TV called "mmc.restore" which is able to write to the bootloader area. I assumed that since this program would need to access the bootloader area in order to write to it, it would be a good place to start looking. So I reversed mmc.restore and found that it uses ioctls write to the bootloader area. This suggests that either the kernel or a kernel module would handle these ioctls. After reversing a bit of the kernel I found that it contained the handlers for these ioctls. Then I looked in the sourcecode provided by samsung and found that the ioctl handlers were in there, albeit a bit different to what was in my kernel binary.

The ioctl handler sourcecode is in "VDLinux_2.6.35.11\linux-2.6.35.11\drivers\mmc\card\block.c" from the "UNxxES8xxx.zip" sourcecode pack from samsung.
The function mmc_ioctl() is the main handler code, and the ioctl values are:
#define RESTORE_BOOT_PARTITION 0x5628
#define RESTORE_PARTITION 0x5629

The code makes use of the mmc_restore_partition() function to write the bootloader, and a closer look at the source for that function shows that they nicely included a flag to select whether to read or write the bootloader. So it looks like there is support for reading in the code, just no ioctl handler pointing to it. However looking back into the real kernel binary from my TV I found that this flag did not exist and the mmc_restore_partition() function had no read support.

So now I knew that I needed to add read support to the kernel and add an ioctl to execute that read functionality. Thankfully after reading the provided sourcecode I knew what was required to do so.



:: Ok, Dump it Already!

So wrote a (linux) user mode app that will mmap() kernel space and patch it while it's running. It will alter the mmc_restore_partition() function to only read (instead of only write) and alter the ioctl handlers to handle reading instead of writing of data. The user mode app would then call the altered ioctls to perform the reading out of the bootloader.

I double checked everything, crossed my fingers and ran it. Thankfully it worked correctly and dumped my bootloader to a file. :D



:: How Do I Repeat Your Success?

Download my mmctools source and build them for your system. This pack contains:
* mmcdump - to patch the kernel and dump the bootloader
* mmcrestore - source code of mmc.restore program (reversed for interoperability)
* mmcsmart - an app to dump smart data from your emmc flash

Unless you are running the same firmware as my TV you *will* have to edit mmcdump to dump your bootloader. The editing requires being able to disassemble your TVs kernel and make whatever changes are required to the ARM assembly code patches to support your tv.

These tools do not come prebuilt because if you don't know how to build them, then you shouldn't be running them.

Once built, dump it by doing:
mmcdump /dev/mmcblk0p0 /tmp/bootloader.bin
You do not have the required permissions to view the files attached to this post.
E3V3A
Posts: 247
Joined: Wed Oct 31, 2012 2:31 am
Location: /dev/zero

Re: How to dump the bootloader from UA65ES8000

Post by E3V3A »

This is indeed nice and inspiring work, but I still don't see (or understand) why you didn't just use the "standard" linux mmc-utils or viewmem?
(Or am I missing something?)

Linaro (linux-mmc)
MMC development tree: linux/kernel/git/cjb/mmc.git
https://kernel.googlesource.com/pub/scm ... mmc-utils/

Viewmem:
SpoilerShow

Code: Select all

/* ==========================================================================
 * Original by Maurus Cuelenaere: 
 * http://blog.maurus.be/index.php/2011/01/samsung-i9000-irom-dump/
 * ========================================================================*/
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/mman.h>
#define INFO(fmt, ...) fprintf(stderr, "[INFO] " fmt, ##__VA_ARGS__)
#define ERR(fmt, ...) fprintf(stderr, "[ERR]  " fmt, ##__VA_ARGS__)
#define MAX(x, y) ((x) > (y) ? (x) : (y))

int main(int argc, char* argv[]) {
    int fd;
    unsigned long addr = 0, size = sizeof(unsigned long), i, newaddr;
    void *buf;

    if (argc < 2 || sscanf(argv[1], "0x%lx", &addr) != 1) {
        ERR("Wrong arguments!\n");
		//EVA: "Use with: ...\n"
        INFO("%s <0xABCDEF> [0x10] [/dev/kmem]\n", argv[0]);
        return -1;
    }

    if (argc >= 3 && sscanf(argv[2], "0x%lx", &size) != 1) {
        ERR("Wrong size format!\n");
		//EVA: "Use HEX, i.e. 0x10" 
        return -1;
    }

    INFO("Reading %ld bytes at 0x%lx...\n", size, addr);

    fd = open(argc >= 4 && argv[3] ? argv[3] : "/dev/mem", O_RDONLY);
    if (!fd) {
        ERR("Couldn't open /dev/mem! (%s)\n", strerror(errno));
		// EVA: "Try using /dev/kmem."
		return -1;
    }

    newaddr = addr & ~(getpagesize()-1);
    buf = mmap(NULL, MAX(getpagesize(), size & ~(getpagesize()-1)), PROT_READ, MAP_SHARED, fd, newaddr);
    if (buf == MAP_FAILED) {
        ERR("Couldn't map 0x%lx (%d %s)!\n", addr, errno, strerror(errno));
        close(fd);
        return -1;
    }

    for (i = 0; i < size; i += sizeof(unsigned long)) {
        char temp[4];
        *(unsigned long*)temp = *(unsigned long*)(buf + (addr-newaddr) + i);
        fwrite(temp, sizeof(temp), 1, stdout);
    }

    munmap(buf, size);
    close(fd);
    return 0;
}
HW: UE40ES5700SXXH
FW: T-MST10PDEUC-1029.0 Onboot: 1003
xorloser
Posts: 43
Joined: Sun Oct 28, 2012 2:49 pm

Re: How to dump the bootloader from UA65ES8000

Post by xorloser »

I am a linux n00b, I have only used linux once before on the PS3 when I was hacking it, so I don't really know what is out there for it. I have however had lots of experience programming and reversing many different cpus, so the method I chose is a more generic approach that involves modifying the existing system as little as possible to accomplish my goal.

Btw in my above post I used the terminology "boot area" and "user area" whereas emmc specs refer to them as "boot partition" and "user partition". I did this so they would not be confused with the logical partitions used by linux such as p1, p2, p3 etc.

That viewmem source appears to be very basic readonly usage of mmap(). That isn't of any use in dumping the bootloader. I *did* use mmap to perform the kernel patches at runtime, but that required write access as well as flushing of data & instruction caches. This is outside of the scope of that viewmem source.

As for the standard mmc-utils, I had not seen them before you pointed them out. I took a quick look and it appears they have a "boot partition enable" command, which seems to be what we would need to gain access to the bootloader. However in order to send commands such as "boot partition enable" it makes use of an "MMC_IOC_CMD" ioctl. I did a quick search over the kernel source provided by samsung and it did not appear to support that ioctl, which would mean it cannot be used. Perhaps I missed it while searching, but even if it did exist it would mean that only one command could be sent per ioctl call. This would mean that after the "boot partition enable" command was sent the system would continue running with it enabled. This *may* be an issue if it the system then cannot access the user area or if it accesses the boot area in a way it should not. The way my method accesses the boot area makes use of mostly existing code that will enable boot partition access, read out data and then disable boot partition access again before returning from each ioctl call. So the system stays in its expected state. Possibly this doesn't matter, but I'd rather choose the safest method to not brick my expensive TV :)
sbav1
Official SamyGO Developer
Posts: 374
Joined: Fri Jan 15, 2010 10:20 am

Re: How to dump the bootloader from UA65ES8000

Post by sbav1 »

Hey - good stuff, quite impressing! Thanks for sharing.

Just a couple of questions:
1) Boot partition[s] size: unless I'm very much mistaken, in mmcdump.cpp, while dumping #1 eMMC boot partition, you are doing lseek(..., SEEK_END) on /dev/mmcblk0p1 - i.e., getting 1st primary partition size in user area (which happens to be 512kB empty u-boot partition in Echo-P TVs). That's probably not very important, as Samsung Echo-P onboot is only fetching first 128kB anyway from boot partition, and initially just 2kB (or 8kB ???) in eMMC boot mode.. Still, it would be nice to know what exactly boot partition size is in this particular eMMC chip (we can use extra eMMC boot blocks for storing custom/secondary bootloader code etc.). Actual boot partition size can be established by checking EXT_CSD register byte 226 (cat /sys/kernel/debug/mmc0/mmc0\:0001/ext_csd, ...).

2) bootloader_p1.bin: this is 1st primary partition from user area (i.e, empty u-boot partition), and not the #2 eMMC boot partition, right? I expect #2 eMMC boot partition to also be empty/not used by Samsung, but who knows - there is a slight chance it may be something interesting in there..

3) Looks like your current bootloader version (0053) doesn't match the publicly available onboot sources for Echo-P (0055) - if you are planning to replace/modify your onboot in any significant way, you should probably request v0053 version source release from Samsung (they are legally obliged to release it on request).
Denny
Official SamyGO Developer
Posts: 350
Joined: Thu Sep 30, 2010 12:18 pm
Location: Croatia

Re: How to dump the bootloader from UA65ES8000

Post by Denny »

add function in "VDLinux_2.6.35.11\linux-2.6.35.11\drivers\mmc\card\block.c" :

Code: Select all

static int mmc_read_partition(struct mmc_card *card, void *buf, unsigned int offset, unsigned int rw_cmd)
{
	struct mmc_request mrq;
	struct mmc_command cmd;
	struct mmc_command stop;
	struct mmc_data data;
	struct scatterlist sg;

	printk(KERN_ALERT" mmc_read_partition....\n");
	memset(&mrq, 0, sizeof(struct mmc_request));
	memset(&cmd, 0, sizeof(struct mmc_command));
	memset(&data, 0, sizeof(struct mmc_data));
	memset(&stop, 0, sizeof(struct mmc_command));
		
	mrq.cmd = &cmd;
	mrq.stop = &stop;
	mrq.data = &data;
	
	cmd.arg = offset;
	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
	data.blksz = 1 << 9;
	stop.opcode = MMC_STOP_TRANSMISSION;
	stop.arg = 0;
	stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
	data.blocks = 8;
	data.flags |= MMC_DATA_READ;
	if (data.blocks > 1)
	{
	   cmd.opcode = MMC_READ_MULTIPLE_BLOCK;
	}
	else
	{
	   cmd.opcode = MMC_READ_SINGLE_BLOCK;
	}
	mmc_set_data_timeout(&data, card);
	data.sg = &sg;
	data.sg_len = 1;
	sg_init_one(&sg, buf, PAGE_SIZE);
	mmc_wait_for_req(card->host, &mrq);
	if (cmd.error) {
		printk(KERN_ERR "error %d sending read/write command\n", cmd.error);
	}
	if (data.error) {
		printk(KERN_ERR "error %d transferring data\n",
				 data.error);
	}
	if (stop.error) {
		printk(KERN_ERR "error %d sending stop command\n",stop.error);
	}
	mmc_wait_busy(card);
	return 0;
}

ioctl modify (add) :

Code: Select all

		case READ_BOOT_PARTITION:
		{
			_mmc_arg *mmc_arg;
			unsigned int m_offset;
			printk(KERN_ALERT"mmc-ioctl READ_BOOT_PARTITION ....\n");   
			if(!(mmc_arg = kmalloc(sizeof(_mmc_arg), GFP_KERNEL))) {
					return -ENOMEM;
			}
			if(copy_from_user(mmc_arg, (void *) arg,sizeof(_mmc_arg) )) {
				kfree(mmc_arg);
				return -EFAULT;
			}
			if(high_capacity)
			{
    			m_offset = (mmc_arg->offset)/SECTOR_SIZE;

			}else{
    			m_offset =  mmc_arg->offset;
			}            
			mmc_claim_host(ioctl_card->host);
			mmc_boot_part_enable(ioctl_card);
			
			mmc_read_partition(ioctl_card,mmc_arg->buf,m_offset, READ);
			copy_to_user((void *) arg,mmc_arg, sizeof(_mmc_arg));
			mmc_boot_part_disable(ioctl_card);
			mmc_release_host(ioctl_card->host);
			kfree(mmc_arg);   
			break;
		}
		case READ_PARTITION:
		{
			_mmc_arg *mmc_arg;
			unsigned int m_offset;
			void *buf;

        	printk(KERN_ALERT"mmc-ioctl READ_PARTITION ....\n"); 

			if(!(buf = kmalloc(PAGE_SIZE,GFP_KERNEL))) {
					return -ENOMEM;
			}
			if(!(mmc_arg = kmalloc(sizeof(_mmc_arg), GFP_KERNEL))) {
					return -ENOMEM;
			}
			if(copy_from_user(mmc_arg, (void *) arg,sizeof(_mmc_arg) )) {
				kfree(mmc_arg);
				return -EFAULT;
			}
         if(high_capacity)
         {
    			m_offset = (mmc_arg->offset)/SECTOR_SIZE;

         }else{
    			m_offset =  mmc_arg->offset;
         }            
			mmc_claim_host(ioctl_card->host);
			//mmc_boot_part_enable(ioctl_card);
			mmc_read_partition(ioctl_card,mmc_arg->buf,m_offset, READ);
			
			copy_to_user((void *) arg,mmc_arg, sizeof(_mmc_arg));
			//mmc_boot_part_disable(ioctl_card);
			mmc_release_host(ioctl_card->host);
			kfree(mmc_arg);   
			break;
		}
with removed patch functions from mmcdump, work to , just as sbav1 told, size is 1MB not 512k, mmcblk0boot1 is blank.
Denny - 데니 - 丹尼 (card2000)
UE55C8000 UE55D8000 UE32D6510 BD-C9600 3xDM8000
Reversing HW Demux Drivers and API from Samsung´s TV
xorloser
Posts: 43
Joined: Sun Oct 28, 2012 2:49 pm

Re: How to dump the bootloader from UA65ES8000

Post by xorloser »

Hi sbav1

1) "mmc.restore" does the same thing where if you specify it uses "/dev/mmcblk0p1", it internally changes it to "/dev/mmcblk0p0". So from this behaviour I assumed they were the same size. Really the official bootloader is only 128kb bytes anyway. So 512kb is plenty enough to dump it :)

It seems that initially the first 8kb (0x2000 bytes) of the bootloader is loaded to address 0 and executed there. This code does some secureboot authentication of itself (ie over the first 0x2000 bytes of bootloader), and then if it passes it will load 128kb (0x20000 bytes) of bootloader to 0x47000000. It will then do a second secureboot authentication over this 0x20000 bytes of data, and if that passes it will execute the Main function of the bootloader in the 0x47000000 address range.

So it is the bootloader itself that does the secureboot checks, as well as determining the size of data to load. This means that a customised bootloader could have the secureboot checks removed and be of any custom size, as long as that size fits into the bootarea of the flash. (So up to 1MB maybe?)

2) It seems to be zeroed.

3) I have already fully reversed my bootloader to C source code, so I will probably just look into building this. It would be cool if I could make it build to a 100% the same binary file :)


Hi Denny

The sourcecode changes you list are essentially what my patches do at runtime. In my case I had to perform the patches at runtime rather than make changes to the kernel sourcecode, as I was not able to create a custom kernel that would pass authentication checks. Now that I have dumped my bootloader I could remove these checks from my bootloader or make a kernel that would pas the checks. But it was a chicken and egg situation where I couldn't run my own custom kernel without first dumping the bootloader to work out what checks were being done :)
E3V3A
Posts: 247
Joined: Wed Oct 31, 2012 2:31 am
Location: /dev/zero

Re: How to dump the bootloader from UA65ES8000

Post by E3V3A »

xorloser wrote:I am a linux n00b,
You don't speak like one, and you certainly seem to know what you're doing, so it seem to me that I'm the noob here! :D
That viewmem source appears to be very basic readonly usage of mmap(). That isn't of any use in dumping the bootloader.
That's right, but from my Samsung experience with other (mobile) processors, the boot loader is usually located in IROM (internal ROM) and then copied to IRAM before execution. The question lies in where IROM is located on these processors. AFAIK, it can be in one of two locations, either in an internal (OTP) EPROM like area on the processor itself, or a special read-only area on the eMMC. This depend on the eMMC/processor combo in use. In either case, there should always exists a window (in time) when you can read the bootloader from IRAM, using /dev/mem (viewmem) or /dev/kmem, hopefully before it gets overwritten by something else, and before the kernel kicks in some other kernel memory protection schemes (in which case you'd need to recompile or patch the kernel first.) That's how we dump bootloaders on Samsung Androids. In some cases it can't get overwritten as some (emergency) firmware download functionality need to remain...

However, in your (our) case the bootloader source code should be available upon request, AFAIK. I'm still waiting to see the bootloaders for the ES6100-class (Amber3) models...
HW: UE40ES5700SXXH
FW: T-MST10PDEUC-1029.0 Onboot: 1003
dajojo
Posts: 46
Joined: Thu Jun 21, 2012 12:43 am

Re: How to dump the bootloader from UA65ES8000

Post by dajojo »

nice job bro :)
it seems samsung uses this 3-fold structure with everything, bootloader and also the remote via network as well as the rs232. they all have this 3-stage system.
i doubt samsung gonna give the code without husle since it contains encryption methods and the actual security system, allthough they should nobody tells em when.

first stage check key sigs of itself
second stage check sig of other and make common key
third stage start exedsp with key

dualview/smarthub
first stage check itself
second stage check other key and get acces (accept on tv)
third remote with DRM key

my guess is that second stage is used to determine which mode should run i.e. hotel or normal or that its going to be used for the evolution kit upgrade.
bootloader is 512 + 512 and also split in part0 and part1
but since u have source now u can figure it out probably :)

processor is a echolon-p which dont have own mem and i found no eprom so it take it must be in emmc chip.
this can read out via the dataconnectorholes next to it. just have to figure out what language it speaks and u can dump whole chip.
offcourse we need recompiled kernel lol
we want to run the tv whithout the useless security so it response is faster and offcourse DRM free
maybe with the evolution kit we can intercept the data or even make our own modded evo-kit, i see possibilities here.
E3V3A
Posts: 247
Joined: Wed Oct 31, 2012 2:31 am
Location: /dev/zero

Re: How to dump the bootloader from UA65ES8000

Post by E3V3A »

@xorloser: Two questions:
1. The eMMC contains it's own firmware, in some (possibly "hidden") part of the eMMC NAND space. At this point, I don't know if the TV processor bootloader you extracted, is part of this same space. Have you seen any signs of this? Would your method be able to extract it? (If it does, it could be an important tool to resolve eMMC bugs in a whole range of Samsung NAND based devices.)
2. Since I'm not sure your mmcsmart program would work as a standalone on my platform (ES5700, Amber3), perhaps you could provide an example output of the Smart data.
Thanks again.
HW: UE40ES5700SXXH
FW: T-MST10PDEUC-1029.0 Onboot: 1003
xorloser
Posts: 43
Joined: Sun Oct 28, 2012 2:49 pm

Re: How to dump the bootloader from UA65ES8000

Post by xorloser »

E3V3A:
1) If that is the case I would assume it to be located in inaccessable parts of the flash, much like hdd firmwares have part of their content present on the hdd itself, but you cannot access that part of the hdd normally to dump the hdd firmware out.

2) It works standalone for my ES8000 with no modifications (except the ability to run it somehow). I have attached the output from mmcsmart from my tv.
You do not have the required permissions to view the files attached to this post.

Post Reply

Return to “[E] Firmware”