EDL mode and test point of the Moto G 5G Plus?

Search This thread

SomeRandomGuy

Senior Member
Mar 17, 2008
119
22
Chicago
LG G4
LG G6
Hmm... so blankflash fails, too? Wouldn't that have all the needed signatures? I mean, you may need to redo with stock firmware post-blank-flash, then let it activate the OEM unlock switch, then unlock it, then start the game all over again, but it saves the hardware? Not saying you are wrong or anything, I've never gotten even this far with EDL (acknowledging there is a functioning EDL mode) on a Moto before. No one else in the moto communities I've looked at ever discuss it; the OnePlus folks are well aware and routinely use it to unbrick stupidities (myself included, many times).

I may be entirely wrong, but I thought if you had a signed programmer (e.g. the ELF file) the actual firehose contents (e.g. what you flash) weren't signed or otherwise verified, and you could overwrite any of the partitions (including where the 'Allow OEM unlock' is stored)? I figure the worst was that verified boot would limit you to a properly signed bootloader until the OEM unlocking is completed- but we have the signed stock image, right? Just as a fastboot-mode flash vs EDL/Sahara mode image (I do, if you don't... just DM me).
 

Arealhooman

Senior Member
So I tried the programmer I found in the singleimage.bin file, it's indeed capable of programming through QFIL! (Do note I needed to get QFIL through QPST to get it to work.) However now I'm faced with this as I'm trying to flash recovery.img to get to recovery and get recovery to reinstall a working system:

Code:
INFO: TARGET SAID: 'ERROR: range restricted: lun=5, start_sector=142688, num_sectors=25600'

I guess the programmer checks for the flash being in a locked state, so it's time to try to patch the programmer to force the flash, if at all possible...

Edit: guessed right. The programmer has a routine that does various checks. It isn't encrypted, but I found data that could indicate the file is signed. I didn't see either the PEEK or POKE strings in there, meaning these primitives weren't included in the programmer, so there's no way to manually poke any image by hand, or just enable that blasted "Allow OEM unlock" bit (the fact I don't know where it is not withstanding.)

I think that's the end of the line for my device. At this point the only way it will ever work again will be either getting a patched and signed firehose (unlikely), or getting Motorola to reflash a stock image internally (even more unlikely) or just changing the motherboard (which defeats the purpose of searching how to get the device back in working order after messing up!)
Oo, I don’t have this device, but I was reading this discussion and was really hoping for a happy ending :( you can always hope for a patched+signed firehouse but I doubt it.
 

Awilen

Member
Aug 17, 2022
10
1
Hmm... so blankflash fails, too? Wouldn't that have all the needed signatures?
Yes, the signatures are valid. Some parts do flash alright, including the bootloader (I tried flashing a Motorola "Racer" bootloader which has the same SoC and it worked, giving me a different-looking error message that read the same thing about not finding a valid OS). For some reason, the signed recovery.img isn't written through the protection, and I just find it dumb that it's not. Considering my recovery right now is a custom /e_project/ one that won't boot either...

The "range restricted" I quoted in my previous message is the recovery partition, measuring 25600 sectors of 4kB for a grand total of 100MB, just the size of the recovery.img file. That img file I got from a up-to-date stock firmware zip file... It's just... dumb or actively evil at this point. Flashing recovery with a stock recovery.img, how innovative and safe of an idea, amirite?

Oo, I don’t have this device, but I was reading this discussion and was really hoping for a happy ending :( you can always hope for a patched+signed firehouse but I doubt it.
This is my first time venturing in the Android flashing scene, and I think I did everything I could to get it back in working condition. Thanks for the support ^^ I'll contact Motorola, see if I can get anything done through them. Doubt it even more though...
 

SomeRandomGuy

Senior Member
Mar 17, 2008
119
22
Chicago
LG G4
LG G6
The sport of this gave me a Shower Thought last night: do we know what it is actually restricting? If it is hardcoded to not write to part of flash by position, is it restricting the partition table, too? If not, could it be repartitioned to put the images down in a pattern that skips the protected section?

I've never reversed a Moto .bin file, but the OP images (happy to share if you don't want to dig) have the UFS provisioning files and firehose programming that lay it out, hinting that it is possible. But they do come with this neat note, though:

<!-- WARNING: PROVISIONING UFS IS A ONE TIME OPERATION IN FACTORY -->
<!-- SO CARE MUST BE TAKEN TO ENSURE THE PARAMETERS -->
<!-- IN THIS CONFIGURATION FILE MEETS THE END PRODUCT -->
<!-- REQUIREMENTS. PLEASE REFER TO THE QUALCOMM FLASH IMAGE -->
<!-- LOADER (QFIL) USER GUIDE (80-NN120-1) FOR MORE DETAILS -->
<!-- ON THE PROVISIONING -->
<!-- -->
<!-- THIS FILE IS FOR UFS 3.1 DEVICES WITH -->
<!-- JEDEC COMPLIANT WRITE BOOSTER FEATURE -->

I think it's over my head at this point, but I'm sure there is a way somehow; something they didn't think of.
 

Renate

Recognized Contributor / Inactive Recognized Dev
I ran into this "range restricted" too on my Moto G 2021 XT2117-4.
I ran into this before on a MotoE5 or E6, I forget, and gave up.

In any case, I can read any (512 byte) block from 0 to 255.
That means I can dump the GPT and see what/where the partitions are.
It also means that I can't read anything useful.
Code:
C:>edl /lmotog.bin
Found EDL 9008
HWID: 0014d0e102e80000, QC: 0014d0e1, OEM: 02e8, Model: 0000
Hash: abbcc86fe393b13d-59e2a2ec944af26d-a3fa3d4b2a1ccd2f-b383c73e0fffc30d
Sending motog.bin 100% Ok
Waiting for Firehose... Ok

C:\>edl /g
Found EDL 9008
Configuring... Ok
Requesting GPT 0 header... Ok, receiving... Ok, requesting entries... Ok, receiving... Ok

 #  Name                   Start       Count  Type
--  ----------------  ----------  ----------  --------------------
 1  xbl_a                 131072       10240  Inactive
<big list of partitions>
77  userdata            24266752    97875935  User data

C:\>edl /r /c256 foo
Found EDL 9008
Configuring... Ok
Requesting read foo... Ok, receiving 100% Ok

C:>edl /r /c257 foo
Found EDL 9008
Configuring... Ok
Requesting read foo...
<log value="ERROR: range restricted: lun=0, start_sector=0, num_sectors=257" />
Nope
 

HemanthJabalpuri

Senior Member
Edit: I have, out of boredom, decomposed the singleimage.bin into its various files. Here is the file format:
Code:
* SINGLE_N_LONELY Header [256 bytes]
* FILE:
    Header:
        * file name: 248 bytes (name + "\0" padding)
        * file size: 8 bytes, little-endian
    Data:
        * data: file size in bytes
        * 0xA0 padding if (file size % 4096) != 0 : file size + 4096 - (file size % 4096) bytes
[* FILE...]
* LONELY_N_SINGLE Footer [256 bytes]

Do note the 4096 magic number is the flash sector size, thus is device-dependant. In singleimage.bin, there was gpt.bin which also follows the same format. Among the files is programmer.elf, a strong candidate to be a firehose, I'll try to use with QFIL tomorrow. I do take note of Motorola's attempt at psychological warfare.
Off-topic but thanks for the stucture explanation. I can't able find any reference to extract this file and searching "SINGLE_N_LONELY" in Google pointed to your post. Here is a quick LUA program to extract my Moto G52 SINGLE_N_LONELY files
Code:
#!/usr/bin/env lua5.3
-- parse files with magic SINGLE_N_LONELY
-- Tested only files of Moto G52(bootloader.img, radio.img, gpt.bin, singleimage.bin)

function abort(msg)
  io.stderr:write(msg .. "\n")
  os.exit()
end

function getString(n)
  local dat = f:read(n)
  return dat:gsub("\x00", "")
end

function getLong()
  local long = { string.unpack("I8", f:read(8), 1) }
  return long[1]
end

function extract(name, offset, length)
  of = io.open(name, "wb")
  f:seek("set", offset)
  of:write(f:read(length))
  of:close()
end

if #arg < 1 then
  abort("Usage: parsegpt.lua gpt.bin")
end

f = io.open(arg[1], "rb")

magic = getString(256)
if magic ~= "SINGLE_N_LONELY" then
  abort("Unsupported")
end

fsize = f:seek("end")
f:seek("set", 256)

for i = 1,64 do
  name = getString(248)
  size = getLong()
  if name == "LONELY_N_SINGLE" then
    break -- no more files
  end
  io.write(string.format("Name: %s, Offset: %d, Size: %d", name, f:seek(), size))
  extract(name, f:seek(), size)
  pad = 0
  if size % 4096 ~= 0 then
    pad = 4096 - (size % 4096)
    f:read(pad)
  end
  print(", Padding: " .. pad)
end

f:close()
 

Attachments

  • parse.zip
    7.4 KB · Views: 5
  • Like
Reactions: Awilen

meetact

Member
Dec 26, 2015
7
0
Yes, the signatures are valid. Some parts do flash alright, including the bootloader (I tried flashing a Motorola "Racer" bootloader which has the same SoC and it worked, giving me a different-looking error message that read the same thing about not finding a valid OS). For some reason, the signed recovery.img isn't written through the protection, and I just find it dumb that it's not. Considering my recovery right now is a custom /e_project/ one that won't boot either...

The "range restricted" I quoted in my previous message is the recovery partition, measuring 25600 sectors of 4kB for a grand total of 100MB, just the size of the recovery.img file. That img file I got from a up-to-date stock firmware zip file... It's just... dumb or actively evil at this point. Flashing recovery with a stock recovery.img, how innovative and safe of an idea, amirite?


This is my first time venturing in the Android flashing scene, and I think I did everything I could to get it back in working condition. Thanks for the support ^^ I'll contact Motorola, see if I can get anything done through them. Doubt it even more though...
Hi Awilen,
I read your posts and realize the hard work you are putting up for your device, really impressive, was wondering if you did get and success in this ? Hope to hear from you soon.
 

Renate

Recognized Contributor / Inactive Recognized Dev
Do we know what it is actually restricting?
Yes, we do.
There are tables in the Firehose loader that tells you what you are allowed to access.
I've added extraction of these tables to my QcomView.exe utility.
Code:
C:\>qcomview motog.bin /r
 Addr   LUN     Start     Count
------  ---  --------  --------
008220   0          0        32
008238   0         -5         5
008250   1          0        32
008268   1         -5         5
008280   2          0        32
008298   2         -5         5
0082b0   3          0        32
0082c8   3         -5         5
0082e0   4          0        32
0082f8   4         -5         5
008310   5          0        32
008328   5         -5         5
008340   1          0      2048
008358   2          0      2048
008370   3          0      2356
008388   5          0      2356
0083a0   0       2080       512

0083b8   0          0       256
0083d0   0        -33        33
0083e8   0     131072    284992
008400   0     416064      2048
008418   1          1         1
The top part is for UFS, the bottom part for eMMC.
So, for my eMMC that says that I can read the GPT, the GPT backup, xbl_a - storsec_b and ddr.
Note that I can dump (if I want) the whole xbl_a - storesec in one chunk, but I have to dump ddr separately.
The allowed contiguous chunks can not be merged.
 

SomeRandomGuy

Senior Member
Mar 17, 2008
119
22
Chicago
LG G4
LG G6
I've added extraction of these tables to my QcomView.exe utility.
Wow, that's really cool. Your page has lots of great stuff... wish I ran Windows to play with it natively. Any thoughts on open sourcing it or building a *nix compile?

Using your /r mode, is it only concerned with reading, or does a presence in the entries suggest RW capabilities?

Was this (printed above) the loader from blankflash?
 

Renate

Recognized Contributor / Inactive Recognized Dev
Using your /r mode, is it only concerned with reading, or does a presence in the entries suggest RW capabilities?
The /r is for restriction.
It certainly applies to reading, you might be allowed to write.
I haven't even tried writing.

Do you have an actual Lenovo/Motorola Firehose loader that you want to check?
What are you using? Just give me the md5sum, I might already have a copy.
I can print the range restrictions for you.
 

SomeRandomGuy

Senior Member
Mar 17, 2008
119
22
Chicago
LG G4
LG G6
I appreciate the offer, but my Moto work is stymied by no easy access to EDL. I had a bad experience with Pixels (locking myself out of my phone, and realizing how much I appreciate EDL to unf#$k what I did) and now am pretty much OnePlus only. I can run a VM to check, no bother... just happy to see the tools offered, and a gentle reminder that if you are willing to roll your own phone firmware from (mostly) source, you might be the kind of person who wants their PC OS open, too... ;)

Again... still cool, and thanks for sharing!
 

Top Liked Posts

  • There are no posts matching your filters.
  • 1
    Hey @Awilen please keep us posted. I too want to play with this phone, but am frustrated by lack of easy access to EDL mode (to unbrick). (I want to try to roll my own GSI/AOSP build + Moto proprietary drivers, which will likely not boot the first thirty or so times I try it.)

    FWIW, I tried this method and a pre-bought cable that allegedly does the same thing- no dice either. :(

    The fact that there ARE EDL IMAGES out there gives me hope.
    1
    Edit: I made a thread on the e.foundation forums listing everything I tried: https://community.e.foundation/t/bo...and-wont-boot-am-i-out-of-luck/43362?u=awilen
    TIL “fastboot oem qcom-on” and “fastboot oem qcom-off” are a thing.
    1
    For my part, to this day I cannot find a way to access this mode, I still have my theories, since on one page I found "official" diagrams of this motorola and the phrase "EDL" is indicated at various points, but I don't really know how to interpret them on the motherboard, I'll leave the link in case someone wants to review it, it's from a Brazilian page:


    In that one there are several files, with more technical specifications, in case someone wants to review it and see what they find useful out there, to see if it is possible to reach EDL mode on this model.
    1
    so you activated the qcom, but it is not responding to the blankflash? at least it's an advance, maybe it's a blankflash problem or do you think it's some kind of board protection?

    Later I will try on my own on my board
    I am confident EDL mode flashing worked. I used a different phone's blankflash that had the same SoC and it worked, giving me a visually different "No OS found" error screen. I posted the log of the blanking process. The "Allow OEM Unlock" bit is still set to "disabled" after blanking, such that I still can't use "fastboot oem unlock" successfully.

    There's this line that makes me think the system is still intact: "Skipping UFS provsioning as target is secure", meaning the UFS filesystem might have not been actually blanked. Since singleimage.bin is a signed binary, there's no way to force UFS provisioning or modify it in any other way. I think the only way in will be with a firehose and QFIL... Except I haven't found one for this SoC. The programmer.elf is the firehose, but again that needs to be signed to be useful after getting extracted.
    Congrats on your quest. Were you literally shorting them, or did you use a resistor? You had to touch all three together?

    I guess I still am confused how there is a blankflash out there for this phone, but no way to trigger EDL without a hardware kit. I just ran through all the key combinations (V+,V-, PWR) and USB in/out just to make sure I didn't miss something... no dice to EDL.
    I marked two pads of the missing connector with a green rectangle (I reused the photo I posted earlier on which I had already marked the test points' voltages, disregard the test points). I shorted them with only one voltmeter probe.

    The idea is that the EDL pads I marked in green are connected to a 1.8V supply and a pin on the SoC with "infinite resistance", so there's no need for an additional resistor. You are not at risk of shorting anything and cause a major disaster on pins on the row of the green rectangle. The connector is very small, so stab confidently in the middle of the row of pads!

    The (V+, PWR) combination may be available in development units, and be disabled in production units at the hardware level (missing components).

    (Keep in mind I'm talking in hypotheticals at times to keep up plausible deniability regarding the files posted earlier by supermafari2.0... Those are surely under copyright.)

    Layers of security upon layers of security just to get a stock firmware on an empty filesystem on my own device... This is getting old...

    Edit: I have, out of boredom, decomposed the singleimage.bin into its various files. Here is the file format:
    Code:
    * SINGLE_N_LONELY Header [256 bytes]
    * FILE:
        Header:
            * file name: 248 bytes (name + "\0" padding)
            * file size: 8 bytes, little-endian
        Data:
            * data: file size in bytes
            * 0xA0 padding if (file size % 4096) != 0 : file size + 4096 - (file size % 4096) bytes
    [* FILE...]
    * LONELY_N_SINGLE Footer [256 bytes]

    Do note the 4096 magic number is the flash sector size, thus is device-dependant. In singleimage.bin, there was gpt.bin which also follows the same format. Among the files is programmer.elf, a strong candidate to be a firehose, I'll try to use with QFIL tomorrow. I do take note of Motorola's attempt at psychological warfare.
    1
    Edit: I have, out of boredom, decomposed the singleimage.bin into its various files. Here is the file format:
    Code:
    * SINGLE_N_LONELY Header [256 bytes]
    * FILE:
        Header:
            * file name: 248 bytes (name + "\0" padding)
            * file size: 8 bytes, little-endian
        Data:
            * data: file size in bytes
            * 0xA0 padding if (file size % 4096) != 0 : file size + 4096 - (file size % 4096) bytes
    [* FILE...]
    * LONELY_N_SINGLE Footer [256 bytes]

    Do note the 4096 magic number is the flash sector size, thus is device-dependant. In singleimage.bin, there was gpt.bin which also follows the same format. Among the files is programmer.elf, a strong candidate to be a firehose, I'll try to use with QFIL tomorrow. I do take note of Motorola's attempt at psychological warfare.
    Off-topic but thanks for the stucture explanation. I can't able find any reference to extract this file and searching "SINGLE_N_LONELY" in Google pointed to your post. Here is a quick LUA program to extract my Moto G52 SINGLE_N_LONELY files
    Code:
    #!/usr/bin/env lua5.3
    -- parse files with magic SINGLE_N_LONELY
    -- Tested only files of Moto G52(bootloader.img, radio.img, gpt.bin, singleimage.bin)
    
    function abort(msg)
      io.stderr:write(msg .. "\n")
      os.exit()
    end
    
    function getString(n)
      local dat = f:read(n)
      return dat:gsub("\x00", "")
    end
    
    function getLong()
      local long = { string.unpack("I8", f:read(8), 1) }
      return long[1]
    end
    
    function extract(name, offset, length)
      of = io.open(name, "wb")
      f:seek("set", offset)
      of:write(f:read(length))
      of:close()
    end
    
    if #arg < 1 then
      abort("Usage: parsegpt.lua gpt.bin")
    end
    
    f = io.open(arg[1], "rb")
    
    magic = getString(256)
    if magic ~= "SINGLE_N_LONELY" then
      abort("Unsupported")
    end
    
    fsize = f:seek("end")
    f:seek("set", 256)
    
    for i = 1,64 do
      name = getString(248)
      size = getLong()
      if name == "LONELY_N_SINGLE" then
        break -- no more files
      end
      io.write(string.format("Name: %s, Offset: %d, Size: %d", name, f:seek(), size))
      extract(name, f:seek(), size)
      pad = 0
      if size % 4096 ~= 0 then
        pad = 4096 - (size % 4096)
        f:read(pad)
      end
      print(", Padding: " .. pad)
    end
    
    f:close()