This is a in-depth explanation on how to identify the locations of firmware image partitions in Puma5/Puma6 MTD based modems.
Before we go into this, first I should explain why this is even necessary.
In modems that use direct flash based storage like SPI, they do not have a partition table because it would be dangerous to store the partition table directly.
This makes it potentially difficult to read/write to the images, since you need to know exactly where data is separated out in the image, or you risk overwriting things that you aren't supposed to.
The partitions are calculated at boot based on variables set in the UBoot environment, specifically they use data offsets.
In this tutorial, we're interested in copying the Image 1 partition from one dump to another dump of a different modem.
These images are also known as UBFI images.
In order to do this, we're going to need the starting position and size of the image.
Locating the UBFI image
A useful bit of information to know about these images is that they almost always have a boot script, kernel, and then the filesystem.
If we are able to locate any one of these pieces, we can determine the starting position of the boot script - or at least, we can determine it's general location.
Searching for the boot script
To locate the boot script, open your image in a hex editor and try searching for these terms:
"Boot Script File", "mtdparts="
Searching for "Boot Script File" usually always works, since they generally name the uImage section this, but this is not always the case.
"mtdparts=" is just a kernel boot parameter, which is one of the pieces of information they are required to specify in the boot script.
I was able to quickly find the boot script with the term "Boot Script File".
![[Image: peemgfz.png]]()
Now, it's notable to mention that before offset 138000, there is a bunch of empty data (those FFs). This suggests that our image offset address is 138000.
If we run this search again, we find another boot script and a similar pattern:
![[Image: tOJtXGY.png]]()
We've located a second image at offset 250000.
If we run this again, we actually find yet another image!
![[Image: nxElMYd.png]]()
So far we've located 3 UBFI images at 138000, 250000, and 900000.
3 images? What gives?
This modem is a Puma6 modem.
In Puma6, there is actually two cores: the ARM core, and the X86 core. Even in modems which do not actively use the Atom core, it still requires a filesystem for it!
Luckily, on this modem there is only 1 UBFI for the Atom core - since this modem does not support upgrading the Atom core's firmware, they decided to save space and only store one of them.
In this tutorial, we do not really care about the Atom core's filesystem, as this modem does not use it so it is mostly empty. Additionally, you will not find 3 UBFIs on Puma5, but on some Puma6 modems you may even find 4 UBFIs (for gateway modems that actually utilize the Atom core).
For reference, the image at 138000 is for the Atom core. 250000 and 900000 are what we're looking for!
Doing this faster with UBoot
Remember how I mentioned these are stored as UBoot environment variables? Well, we can print those variables from a UBoot shell.
![[Image: vrsYGzi.png]]()
And what do you know? We found the same addresses!
By the way, even if you do not have access to a live UBoot shell, these variables are still stored in your dump and you can find them by searching for them in your hex editor.
Doing this faster with binwalk
Sometimes, you don't have access to UBoot or don't know what the variables are called....luckily there is another handy tool we can use: Binwalk.
![[Image: rpd1DxB.png]]()
Figuring out image size
Spoiler alert: We can see it from UBoot variables: it's 6B0000.
However, this is not always gauranteed! Usually, the UBFIs are directly next to eachother, so if we subtract the first offset from the second offset, we get the size.
If this is not the case, it's probably defined in the script, which you can refer to - but that is outside the scope of this tutorial.
![[Image: R7N7nUu.gif]]()
Copying the UBFI out
Find your hex editor's Select Block function, then simply set the start to your image offset, and the length to your image length.
![[Image: 4wAdzl1.png]]()
Once it's selected, copy it with CTRL+C and now you can make a new file, and paste it in. You've successfully extracted the UBFI image from your firmware dump!
![[Image: ebBK9xl.png]]()
Replacing the existing UBFI with a new one
To replace one of the existing UBFIs, simply use your hex editor's Goto function to jump to the offset that your image is located at.
![[Image: 0IZ6DyG.png]]()
Now, you can simply paste the new UBFI in.
i![[Image: jt7B2TQ.png]]()
Pay attention to what offset your hex editor says you are at. If you are not on the exact offset, you will overwrite data that you aren't supposed to overwrite.
Now, save it and re-flash your modem with your edited dump, and you will have successfully replaced the UBFI image!
Before we go into this, first I should explain why this is even necessary.
In modems that use direct flash based storage like SPI, they do not have a partition table because it would be dangerous to store the partition table directly.
This makes it potentially difficult to read/write to the images, since you need to know exactly where data is separated out in the image, or you risk overwriting things that you aren't supposed to.
The partitions are calculated at boot based on variables set in the UBoot environment, specifically they use data offsets.
In this tutorial, we're interested in copying the Image 1 partition from one dump to another dump of a different modem.
These images are also known as UBFI images.
In order to do this, we're going to need the starting position and size of the image.
Locating the UBFI image
A useful bit of information to know about these images is that they almost always have a boot script, kernel, and then the filesystem.
If we are able to locate any one of these pieces, we can determine the starting position of the boot script - or at least, we can determine it's general location.
Searching for the boot script
To locate the boot script, open your image in a hex editor and try searching for these terms:
"Boot Script File", "mtdparts="
Searching for "Boot Script File" usually always works, since they generally name the uImage section this, but this is not always the case.
"mtdparts=" is just a kernel boot parameter, which is one of the pieces of information they are required to specify in the boot script.
I was able to quickly find the boot script with the term "Boot Script File".
![[Image: peemgfz.png]](http://i.imgur.com/peemgfz.png)
Now, it's notable to mention that before offset 138000, there is a bunch of empty data (those FFs). This suggests that our image offset address is 138000.
If we run this search again, we find another boot script and a similar pattern:
![[Image: tOJtXGY.png]](http://i.imgur.com/tOJtXGY.png)
We've located a second image at offset 250000.
If we run this again, we actually find yet another image!
![[Image: nxElMYd.png]](http://i.imgur.com/nxElMYd.png)
So far we've located 3 UBFI images at 138000, 250000, and 900000.
3 images? What gives?
This modem is a Puma6 modem.
In Puma6, there is actually two cores: the ARM core, and the X86 core. Even in modems which do not actively use the Atom core, it still requires a filesystem for it!
Luckily, on this modem there is only 1 UBFI for the Atom core - since this modem does not support upgrading the Atom core's firmware, they decided to save space and only store one of them.
In this tutorial, we do not really care about the Atom core's filesystem, as this modem does not use it so it is mostly empty. Additionally, you will not find 3 UBFIs on Puma5, but on some Puma6 modems you may even find 4 UBFIs (for gateway modems that actually utilize the Atom core).
For reference, the image at 138000 is for the Atom core. 250000 and 900000 are what we're looking for!
Doing this faster with UBoot
Remember how I mentioned these are stored as UBoot environment variables? Well, we can print those variables from a UBoot shell.
![[Image: vrsYGzi.png]](http://i.imgur.com/vrsYGzi.png)
And what do you know? We found the same addresses!
By the way, even if you do not have access to a live UBoot shell, these variables are still stored in your dump and you can find them by searching for them in your hex editor.
Doing this faster with binwalk
Sometimes, you don't have access to UBoot or don't know what the variables are called....luckily there is another handy tool we can use: Binwalk.
![[Image: rpd1DxB.png]](http://i.imgur.com/rpd1DxB.png)
Figuring out image size
Spoiler alert: We can see it from UBoot variables: it's 6B0000.
However, this is not always gauranteed! Usually, the UBFIs are directly next to eachother, so if we subtract the first offset from the second offset, we get the size.
If this is not the case, it's probably defined in the script, which you can refer to - but that is outside the scope of this tutorial.
![[Image: R7N7nUu.gif]](http://i.imgur.com/R7N7nUu.gif)
Copying the UBFI out
Find your hex editor's Select Block function, then simply set the start to your image offset, and the length to your image length.
![[Image: 4wAdzl1.png]](http://i.imgur.com/4wAdzl1.png)
Once it's selected, copy it with CTRL+C and now you can make a new file, and paste it in. You've successfully extracted the UBFI image from your firmware dump!
![[Image: ebBK9xl.png]](http://i.imgur.com/ebBK9xl.png)
Replacing the existing UBFI with a new one
To replace one of the existing UBFIs, simply use your hex editor's Goto function to jump to the offset that your image is located at.
![[Image: 0IZ6DyG.png]](http://i.imgur.com/0IZ6DyG.png)
Now, you can simply paste the new UBFI in.
i
![[Image: jt7B2TQ.png]](http://i.imgur.com/jt7B2TQ.png)
Pay attention to what offset your hex editor says you are at. If you are not on the exact offset, you will overwrite data that you aren't supposed to overwrite.
Now, save it and re-flash your modem with your edited dump, and you will have successfully replaced the UBFI image!