FORUMS

[R&D] Unlock Bootloaders

5,224 posts
Thanks Meter: 9,893
 
By AdamOutler, Retired Senior Recognized Developer on 13th July 2012, 03:50 AM
Thread Closed Email Thread
20th July 2012, 09:26 PM |#101  
For a "cheat engine" thing you guys want the "viewmem" binary. This will allow you to dump any memory location... Havn't tested it, but it should install the proper binaries into /system/bin.



Download CASUAL BHT Installer
This Cross-platform Adb Scripting Universal Android Loader package works on Windows, Linux and Mac.


I will be packing up my stuff and moving around the corner this weekend. I just want you guys to know I will be watching this thread and posting any relevant information. The best way to notify me of anything is a mention of +Adam Outler on G+ (please no questions). Obviously I will not have my computer or workbench set up this weekend and it might be a little bit until I'm able to get back into the swing.

Also, newswriters, any further articles on this topic MUST include names other than myself. I'm the recognizable face on this project and I'll take the blame if blame is needed.. But Ralekdev's post of a disassembled bootloader seriously trumps anything I've done and so far I've yet to see an article mention him and that offends me.



Samsung is running a campaign to fight rumors that they locked the bootloaders. They are telling customers that they send the devices to Verizon and Verizon locks the bootloaders. This is simply not true. That would be a redundant and inefficient step which would not make sense for business. These boards are specially made PER CARRIER. There is a different board for Sprint, Verizon and AT&T. Until one of these so-called "pre-Verizon" bootloaders shows up in Odin3 format, don't take it seriously, don't believe it, and dont repeat it. Rumors like that are designed to make people sit around and wait.




You can get your phone into Odin mode by using "adb reboot download" or "adb reboot bootloader" however there is another option. Using a 301kohm jig puts the device into Factory mode. I'm not sure on the differences.






When searching ABOOT partition for information, please inspect the difference between FACTORY MODE and ODIN MODE.
The Following 31 Users Say Thank You to AdamOutler For This Useful Post: [ View ] Gift AdamOutler Ad-Free
21st July 2012, 12:43 AM |#102  
Retired Senior Recognized Developer
Thanks Meter: 385
 
Donate to Me
More
All I can see that putting it into factory mode does is allow the odin command handler to reset the ddi info (flash counter, binary type, etc). Normally odin is still blocked from doing that.

EDIT:
More specifically, if factory mode is on it automatically clears the ddi info when the odin packet type 0x67 (kControlTypeEndSession in heimdall) is sent with the next int 0 (kRequestEndSession)
The Following 15 Users Say Thank You to Ralekdev For This Useful Post: [ View ] Gift Ralekdev Ad-Free
21st July 2012, 01:47 PM |#103  
N00BY0815's Avatar
Senior Member
Thanks Meter: 1,901
 
Donate to Me
More
Did anyone check, if during USB flash process, or other processes maybe a checksum like MD5 is being transfered onto the phone, which is being check right after the flash. If those two checksums are identical --> normal boot, if not --> error message... Just a thought, if this is useless, delete the post.
The Following 2 Users Say Thank You to N00BY0815 For This Useful Post: [ View ] Gift N00BY0815 Ad-Free
21st July 2012, 08:04 PM |#104  
stiltzkin's Avatar
Senior Member
Thanks Meter: 59
 
More
Quote:
Originally Posted by WildZontar

Normally, the OS puts a stop to you trying to use RAM you don't own (dereferencing unallocated RAM leads to a segmentation fault), but without RAM protection, you can theoretically dereference whatever you want whether or not it's been allocated to you. At this point, you'd be able to dump everything in RAM and analyze it. This wouldn't be of much use because 1) the kernel is the one thing we can't change to begin with, and 2) I'm not sure if the linux kernel even has such an option.

If I'm not mistaken, the Linux kernel has something like this in the form of ptrace scope, which controls whether or not processes are able to examine the memory of other processes. I've encountered this recently because most Blizzard games have an active memory monitor designed to prevent the kind of side-channel cheating attacks you guys are talking about, and without first temporarily setting "sysctl kernel.yama.ptrace_scope=0" on my Linux box, those games crash WINE with a segfault. Also I believe ptrace was used to take control of the init thread to accomplish 2nd-init on phones like the Droid X as well, so I think there has been some past work on this.

If this is incorrect, trivial knowledge, or not helpful, please feel free to remove this. Thanks.
The Following 2 Users Say Thank You to stiltzkin For This Useful Post: [ View ] Gift stiltzkin Ad-Free
22nd July 2012, 05:26 AM |#105  
Root owns all the memory and can access it through /dev/mem. I have never had a problem dumping memory with viewmem. The real question is where do we look for bootloaders
The Following 8 Users Say Thank You to AdamOutler For This Useful Post: [ View ] Gift AdamOutler Ad-Free
23rd July 2012, 04:28 PM |#106  
Senior Recognized Developer
Flag Owego, NY
Thanks Meter: 25,477
 
Donate to Me
More
Quote:
Originally Posted by N00BY0815

Did anyone check, if during USB flash process, or other processes maybe a checksum like MD5 is being transfered onto the phone, which is being check right after the flash. If those two checksums are identical --> normal boot, if not --> error message... Just a thought, if this is useless, delete the post.

It's about 50/50 whether it is HMAC or whether they are using some sort of asymmetric signature algorithm.

HMAC is closely related to hashes like MD5 and SHA (MD5 is very weak though.)

If HMAC is used, the signature is something like:
Code:
sig = SHA512(message | secret);
Where | stands for "append"

Then, for distribution, the "signed image" is
Code:
message | sig
Note that you can't generate a matching sig for a given message without that secret value. The good news is that HMAC is symmetric so that secret must be stored somewhere on the destination device. The bad news is that usually this secret is burned into protected eFuse memory of the CPU and can't be retrieved without sophisticated IC reverse engineering techniques (decap the chip and probe the die).

If it's an asymmetric algorithm - then the secret used to generate a signature is not the same one that verifies it.
The Following 11 Users Say Thank You to Entropy512 For This Useful Post: [ View ]
24th July 2012, 02:58 AM |#107  
Retired Senior Recognized Developer
Thanks Meter: 385
 
Donate to Me
More
It's been a few days so I wanted to give an update on the signature check on boot.img

As has been previously guessed, everything important in boot.img is included in the signature check

page_size is always 0x800 since we're using emmc boot

hash_size = 0x800 (read the first page with the boot_img_header)
hash_size += page_size * ((page_size + ramdisk_size - 1) / page_size)
hash_size += page_size * ((page_size + kernel_size - 1) / page_size)
hash_size += page_size * ((page_size + second_size - 1) / page_size)

For the stock boot.img, this should come out to be 0x573000, so the first 0x573000 bytes in boot.img are checked.

These bytes are then SHA1 hashed and passed to the verification function

After hash_size bytes is a series of 0x100 byte blocks that will be passed to the verification function (img_sig_data parameter below)

The verification function uses the following structure

Code:
struct sig_ctx_t {
	int count;
	int seed[65];
	int subcheck_seed[64]; // possibly a modulus
}
This sig_ctx is located in aboot.img at file offset 0x12642C in VRALF2 and VRALG1 (It'll start with bytes 0x40, 0x00, 0x00, 0x00)

I've cleaned up the first function a bit from what IDA/Hex-Rays spit out, but the second function I haven't simplified as much

Code:
int signature_check_data(sig_ctx_t *sig_ctx, char *img_sig_data, signed int signature_len, char *sha1_of_contents) {

	int* img_ofs_0x100 = (int*)(img_sig_data + 0x100);
	int* img_ofs_0x200 = (int*)(img_sig_data + 0x200);
	int* img_ofs_0x300 = (int*)(img_sig_data + 0x300);
	int* img_ofs_0x400 = (int*)(img_sig_data + 0x400); // Temporary storage

	// Copy 0x0 block to 0x100
	memcpy(img_ofs_0x100, &img_sig_data[0], signature_len);

	// ofs_0x200 is filled with byte-swapped ints from img_ofs_0x100
	for (int i = 0; i < sig_ctx->count; i++) {
		img_ofs_0x200[i] =  htonl(img_ofs_0x100[sig_ctx->count - 1 - i]);
	}

	// subcheck(sig_block *block, int *output, int *input1, int *input2)
	// multiplication maybe?
	signature_subcheck(sig_ctx, img_ofs_0x300, img_ofs_0x200, sig_ctx->subcheck_seed);
	signature_subcheck(sig_ctx, img_ofs_0x400, img_ofs_0x300, img_ofs_0x300);
	signature_subcheck(sig_ctx, img_ofs_0x300, img_ofs_0x400, img_ofs_0x200);

	if ( sig_ctx->count )
	{
		count_minus_1 = sig_ctx->count - 1;
		v18 = img_ofs_0x300[sig_ctx->count - 1];
		v19 = sig_ctx->seed[sig_ctx->count]; // seed[64]
		// v19 = *(&sig_ctx->count + sig_ctx->count + 1);
		if ( v18 >= v19 )
		{
			if ( v18 == v19 )
			{
				for (int i = 0; i < sig_ctx->count; i++) {
					int v22 = img_ofs_0x300[sig_ctx->count - 1 - i];
					int v23 = sig_ctx->seed[sig_ctx->count - 1 - i];
					if (v22 < v23) {
						goto LABEL_18
					}
				}
			}
			if ( sig_ctx->count > 0 )
			{
				int carry = 0;
				for (int i = 0; i < sig_ctx->count; i++) {
					uint64 temp = img_ofs_0x300[i] - (uint64)sig_ctx->seed[i + 1];
					img_ofs_0x300[i] = img_ofs_0x300[i] - sig_ctx->seed[i + 1] + carry;
					carry = (int)(temp >> 32); // get high 32 bits
				}
			}
		}

		LABEL_18:
		// Store the calculation back into img_ofs_0x100
		for (int i = 0; i < sig_ctx->count; i++) {
			int val = img_ofs_0x300[sig_ctx->count - 1 - i];
			char* dest = &img_ofs_0x100[i];

			dest[0] = (val & 0xFF000000) >> 24;
			dest[1] = ((val & 0x00FF0000) >> 16) & 0xFF;
			dest[2] = ((val & 0x0000FF00) >> 8) & 0xFF;
			dest[3] = (val & 0xFF);
		}

		if (memcmp(img_ofs_0x100, sig_check_compare_result, 236)) // sig_check_compare_result is a char[236] with the first 2 bytes 0x00, 0x01, and the rest 0xFF
			return 0;

		if (signature_len > 236) {
			if (memcmp(&img_ofs_0x100[236], sha1_of_contents, signature_len - 236)) // 256-236 = 20
				return 0;

			// Signature passed
			return 1;
		}
	}
	return 0;
}

Here's the subcheck function, it looks like arbitrary-precision math, possibly mulmod

Code:
void __fastcall signature_subcheck(sig_ctx_t *sig_data, int *output, int *input1, int *input2)
{
  int v5; // [email protected]
  int count; // [email protected]
  unsigned __int64 v7; // [email protected]
  unsigned __int64 v8; // [email protected]
  int inner_index; // [email protected]
  int block1_pos; // [email protected]
  int v11; // [email protected]
  __int64 v12; // [email protected]
  int v13; // [email protected]
  unsigned __int64 v14; // [email protected]
  int v15; // [email protected]
  int v16; // [sp+18h] [bp-48h]@6
  unsigned int v17; // [sp+1Ch] [bp-44h]@6
  int outer_index; // [sp+2Ch] [bp-34h]@5

  if ( sig_data->count > 0 )
  {
    v5 = 0;
    do
    {
      output[v5++] = 0;                         // this do while is just memset(output, 0, 4 * sig_data->count)
      count = sig_data->count;
    }
    while ( sig_data->count > v5 );
    if ( count > 0 )
    {
      outer_index = 0;
      do
      {
        v16 = input1[outer_index];
        v7 = (unsigned int)v16 * (unsigned __int64)(unsigned int)*input2 + (unsigned int)*output;// v7 = input1[outer_index] * (uint64)input2[0] + output[0]
        v17 = sig_data->seed[0] * v7;
        v8 = sig_data->seed[1] * (unsigned __int64)v17 + (unsigned int)v7;
        if ( count <= 1 )
        {
          block1_pos = 1;
        }
        else
        {
          inner_index = 0;
          block1_pos = 1;
          do
          {
            v7 = (unsigned int)v16 * (unsigned __int64)(unsigned int)input2[block1_pos]
               + (unsigned int)output[block1_pos]
               + HIDWORD(v7);
            v8 = sig_data->seed[inner_index + 2] * (unsigned __int64)v17 + HIDWORD(v8) + (unsigned int)v7;
            ++block1_pos;
            output[inner_index] = v8;
            ++inner_index;
          }
          while ( block1_pos < sig_data->count );
        }
        output[block1_pos - 1] = HIDWORD(v8) + HIDWORD(v7);
        if ( (HIDWORD(v8) + (unsigned __int64)HIDWORD(v7)) >> 32 )
        {
          if ( sig_data->count <= 0 )
            return;
          v11 = 0;
          v12 = 0LL;
          v13 = 0;
          do
          {
            v14 = (unsigned int)output[v11] - (unsigned __int64)sig_data->seed[v11 + 1];
            v15 = output[v11] - sig_data->seed[v11 + 1];
            output[v11] = output[v11] - sig_data->seed[v11 + 1] + v12;
            count = sig_data->count;
            ++v13;
            ++v11;
            v12 = (signed int)((__PAIR__(HIDWORD(v14), v15) + v12) >> 32);
          }
          while ( v13 < sig_data->count );
        }
        else
        {
          count = sig_data->count;
        }
        ++outer_index;
      }
      while ( outer_index < count );
    }
  }
}

The goal is to make it so that after all the calculations the 256 byte block located at img_sig_data+0x100 has the contents 0x00, 0x01, 0xFF * 236, and then the sha1 of our boot.img

I'm in the middle of moving at the moment, so I don't have as much time as I would like to look at this right now, but that should clear up in a few days.

Also, if there's any interest I can post a guide on how to get the bootloader files loaded into IDA for analysis. Some knowledge of ARM assembly would be required though.

EDIT:

In other news, I found what keeps resetting the 16 byte encrypted romtype in param.img. It's libcordon.so, which is from /system/app/SysScope.apk (it'll also be copied to /system/lib/libcordon.so). It's using quite a few checks to see if you've modified your system.

There's an adb scanner, checking to see if you've changed the ro.secure or ro.debuggable props.

The root process scanner checks running processes and returns true if any are found running as root that are not one of:
"debuggerd", "init", "installd", "servicemanager", "vold", "zygote", "netd", "ueventd", "dock_kbd_attach", "pppd", "pppd_runner", "mpdecision", "thermald", "hdmid", "sec_keyboard", "seccmmond", "mfsc", "mfdp"

There's also a partition check, kernel checker, su scanner, and a file scanning mechanism using data from a sqlite db

So to completely remove the Samsung custom screen on bootup and 5 second delay you'd need to disable the SysScope.apk, then encrypt and write the 16 bytes yourself using 0xFF000000 as the first int to mark yourself as official
The Following 85 Users Say Thank You to Ralekdev For This Useful Post: [ View ] Gift Ralekdev Ad-Free
24th July 2012, 08:08 AM |#108  
mybook4's Avatar
Senior Member
Thanks Meter: 269
 
Donate to Me
More
Great work! Thanks to Lee and everyone for all the hard work!

Still looking at the code to try to get a better understanding of the algorithm but here's some food for thought:

1) The recovery partition is signed, but the signature is not enforced. Perhaps there is a link 'n' (i.e. partition) in the chain of trust whose signature is also not enforced (not very likely, or secure).

In this case, we could modify 'n' such that it does not enforce signature of latter links in the chain of trust (e.g. overwrite the signature checking function with a series of noops or trivial assembly instructions leading to a properly placed return value of 1 or "true" ).

We could then perform similar modifications to the latter links including aboot. Note: it is very likely that this isn't testable in a practical way. It was stated previously (in the 1st post) that aboot contains the daemon for odin. If we broke the boot chain earlier than aboot, we wouldn't be able to Odin over a mistake.

2) From the C, my understanding is that the contents of the signature are loaded into RAM prior to running the signature checking. Is it possible for us (with JTAG equipment to modify the contents of the memory utilized for the memcmp call (pointed to by img_ofs_0x100)? This would be more of a proof of concept as carrying around JTAG equipment to reboot the phone is a little impractical.



Sent from my SCH-I535 using xda premium
The Following User Says Thank You to mybook4 For This Useful Post: [ View ] Gift mybook4 Ad-Free
24th July 2012, 12:53 PM |#109  
Junior Member
Thanks Meter: 102
 
More
Quote:
Originally Posted by Ralekdev

So to completely remove the Samsung custom screen on bootup and 5 second delay you'd need to disable the SysScope.apk, then encrypt and write the 16 bytes yourself using 0xFF000000 as the first int to mark yourself as official

Confirmed. I renamed the SysScope.apk file and wrote the encrypted block to signify a Samsung rom. Through multiple reboots, the pad lock icon was gone as well as the 5 second delay.

Thanks,
Enderblue
The Following 14 Users Say Thank You to enderblue For This Useful Post: [ View ] Gift enderblue Ad-Free
24th July 2012, 01:15 PM |#110  
Senior Member
Thanks Meter: 158
 
More
This doesn't really get us anywhere though right? Just removing a nag screen? Good work anyway - i'm just trying to understand.
The Following User Says Thank You to NegativeOne For This Useful Post: [ View ] Gift NegativeOne Ad-Free
24th July 2012, 04:13 PM |#111  
Junior Member
Thanks Meter: 102
 
More
Quote:
Originally Posted by NegativeOne

This doesn't really get us anywhere though right? Just removing a nag screen? Good work anyway - i'm just trying to understand.

You are correct. It doesn't get us much further with unlocking the bootlodaer, but it will make the standard bootup faster. I plan to work on a way to process the information and allow the user to implement this on their phone. Maybe through a standard application.

I'll go back to being quiet and learning from RalekDev.

Thanks,
Enderblue
The Following 14 Users Say Thank You to enderblue For This Useful Post: [ View ] Gift enderblue Ad-Free
Thread Closed Subscribe to Thread

Tags
d2vzw, locked bootloader
Previous Thread Next Thread
Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes