Find Your Device:
Or Continue to Thread: [R&D] Unlock Bootloaders
18th July 2012, 03:02 PM |#67  
AdamOutler's Avatar
OP Recognized Developer
Flag Miami, Fl̨̞̲̟̦̀̈̃͛҃҅͟orida
Thanks Meter: 9,822
Donate to Me
A gentleman named Lee contacted me via email. He said he has 0 posts so he could not post in here. This post contains his email to me. I am not wrapping it in quotes because quotes are destroyed in future posts. This is literally the best development we've had in this thread.

------email from Lee------
I've been looking at the bootloader in aboot.img the past day or so and wanted to contribute what I know about the param.img partition and how it's used. I've been following the thread at xda, but since my account has 0 posts I can't actually post this in that thread.

Please note these are a little rough around the edges, just things I jotted down while reverse engineering.

param.img Structure

At offset 0 there's an 88 byte structure I've called the header

struct param_header {
int status; // need to investigate more. some relationships between this and boot modes. 4 == firmware error int unk_04; // haven't seen this used anywhere int unk_08; // haven't seen this used anywhere int emmc_checksum_attempted; int emmc_checksum_ok; int nvdata_backup; // says whether we have a backup of modemst1 in "fsg" partition and a backup of modemst2 in "backup" partition?
int unk_18[16]; // haven't seen this used anywhere };

status (NEEDS WORK):
1 = ?
2 = boot_mode 3?
3 = recovery?
4 = boot_mode 1 - fastboot. displays "firmware update issue" image
5 = boot_mode 4?

at offset 0x900000 there's a structure controlling some debug variables

struct param_debug {
int debug_level;
int unk_04; // 4 in dumps. haven't seen this used anywhere int unk_08; // 0 in dumps. haven't seen this used anywhere int emmc_checksum_attempted; // mirror of param_header.emmc_checksum_attempted
int emmc_checksum_ok; // mirror of param_header.emmc_checksum_ok };

About param_debug.debug_level:
It has 3 possible values, and it changes some flags are passed to the kernel.
DLOW is the default, but some features like ramdump mode only work on DMID or DHIG

1. 0x574F4C44 (DLOW) - Low debug setting strcat(boot_img_hdr->cmdline, " androidboot.debug_level=0x4f4c");// OL strcat(boot_img_hdr->cmdline, " sec_debug.enable=0"); strcat(boot_img_hdr->cmdline, " sec_debug.enable_user=0");

2. 0x44494D44 (DMID) - Mid-level debugging strcat(boot_img_hdr->cmdline, " androidboot.debug_level=0x494d");// IM strcat(boot_img_hdr->cmdline, " sec_debug.enable=1"); strcat(boot_img_hdr->cmdline, " sec_debug.enable_user=0");

3. 0x47494844 (DHIG) - Full debugging
strcat(boot_img_hdr->cmdline, " androidboot.debug_level=0x4948");// IH strcat(boot_img_hdr->cmdline, " sec_debug.enable=1"); strcat(boot_img_hdr->cmdline, " sec_debug.enable_user=1"); strcat(boot_img_hdr->cmdline, " slub_debug=FPUZ");

Check drivers/misc/sec_misc.c for what these values do for the kernel

At offset 0x9FFC00 (sizeof(param.img) - 0x400 is how the offset is calculated by the BL):
Here are 16 bytes unique to each device, and they are part of what determines whether or not you have a custom rom.

It's AES128 encrypted using a key made from the emmc's psn and some static data

Key generation:
First, the 4byte psn is expanded to 8 bytes

char first_half[14];
snprintf(first_half, 13, "%08x", mmc_get_psn()); memcpy(aes_initial_key, first_half, 8);

The second half is calculated based on all static data

char custom_check_index_shuf_table[] = { 1, 3, 2, 4, 5, 1, 0, 4, 4, 5, 4, 0 }; char custom_check_table[] = { 0x40, 0x74, 0x25, 0x61, 0x21, 0x74, 0x70, 0x62, 0x62, 0x24, 0x33, 0x5E }; char romtype_enc_key_buf[32];

char* custom_check_shuffle_calc(signed int always_199, int count) { int out_index; // r3@2 int last_index; // r2@2 int odd_index; // r4@3 int table_index; // r2@3 char table_value;

if ( count <= 0 )
out_index = 0;
out_index = 0;
last_index = 0;
odd_index = always_199 & 1;
always_199 >>= 1;
table_index = odd_index + 2 * last_index; table_value = custom_check_table[table_index]; last_index = custom_check_index_shuf_table[table_index];
romtype_enc_key_buf[out_index++] = table_value; } while ( out_index != count ); } romtype_enc_key_buf[out_index] = 0; return romtype_enc_key_buf; }

This function is used like this (the parameters are always 199 and 8 in the vzw aboot):
char* second_half = custom_check_shuffle_calc(199, 8); memcpy(&aes_initial_key[8], second_half, 8);

Now we have 16 bytes in aes_initial_key, but it's shuffled again with the following function

char custom_check_final_index_table[] = { 0, 4, 5, 0xD, 3, 8, 0xE, 9, 0xA, 2, 1, 7, 0xB, 6, 0xC, 0xF }; void custom_check_shuffle_final_key(char *iv, char *final) { int v2; // r3@1 int v5; // r3@3

v2 = 0;
final[custom_check_final_index_table[v2]] = iv[v2];
while ( v2 != 16 );
v5 = 0;
final[custom_check_final_index_table[v5]] = iv[v5] ^ final[v5];
while ( v5 != 16 );

char aes_final_key[16];
custom_check_shuffle_final_key(aes_initial_key, aes_final_key);

This final key should be able to decrypt the 16 bytes

The first 4 decrypted bytes cast to an int will be 0xFF000000 if you're running an official rom, or 0xEE000000 if you've flashed something custom If it's 0xEE000000 then you will be shown the "Custom" boot screen with the padlock on it, and it also causes a call to mdelay(5000) before actually booting the kernel.
I've also seen 0xCC000000 mentioned in debug prints, causing it to print the device status as "Scanning" instead of "Official" or "Custom"

Unfortunately this doesn't seem to help much with the boot.img check, but I've found where that is and am reversing it now.


DDI Data
Here's where the values like the flash count are stored (sometimes this might be called triangle state?) It's stored at 0x3FFE00 on the mmc

struct ddi_data {
int magic; // must be 0x12340012
int custom_flash_count;
int odin_count;
int binary_type; // 0 = samsung official, 1 = custom, 2 = "Unknown"
char model_name[16];
int rom_type; // this is the first 4 bytes of the decrypted 16 bytes in the param partition. 0xFF000000 = samsung, 0xEE000000 = custom }


Reboot Reason

Values and effects for the reboot reason stored at 0x2A03F65C

0x12345671 - ?
0x12345678 - Normal mode

0x77665500 - FASTBOOT_MODE. displays "downloading" boot image
0x77665501 - ? seen checked but haven't found it used anywhere
0x77665502 - RECOVERY_MODE. sets param_header.state to 3
0x77665503 - sets param_header.state to 4. haven't seen it actually used

0x77665507 - display the "not authorized" picture

if ((reason & ~0xF) == 0x77665510) then they're commands for manipulating the nvdata I wouldn't play around with these unless you really know what you're doing All of them reboot the device into the normal mode except 0x77665515

0x77665511 - copy modemst1 to fsg partition and copy modemst2 to backup partition. sets param_header.nvdata_backup to 1
0x77665512 - copy fsg to modemst1 and copy backup to modemst2. checks to ensure param_header.nvdata_backup=1 first
0x77665514 - erase fsg and backup partitions. clears param_header.nvdata_backup
0x77665515 - same as 0x77665511 but then reboots the device into RECOVERY_MODE

0x776655EE - RAMDUMP_MODE (only valid if param_debug.debug_level is DMID/DHIG)

0xABCD4F4C - set param_debug.debug_level to DLOW 0xABCD494D - set param_debug.debug_level to DMID
0xABCD4948 - set param_debug.debug_level to DHIG


boot_type INCOMPLETE
1 = fastboot
2 = ramdump mode
3 = recovery. resets param_debug
4 = ?



0xF00 - jig mask
0x100 - put the device into factory mode
0x400 - change "console" boot parameter to "console=ttyHSL0,115200,n8%s" where %s is replaced by whatever was originally after "console="



In addition to the ODIN/LOKE handshake sequence I saw in heimdall, there are 2 more in the S3.
Send "FPGM" and you should get a response of "OK". It functions exactly as the ODIN/LOKE sequence.
Send "ROOTING" and it responds with the current DDI data and terminates.

The Following 70 Users Say Thank You to AdamOutler For This Useful Post: [ View ]