Open mbirth opened 4 years ago
That's one of the things that pushed me to buy it, just because I was curious about It but i never managed to properly load fw_all.bin in IDA pro.
There might be a slightly difference between the 601 and the 701 hardware :
Some websites claims the Foretrex 701 is shipped with a ELR Core
ELR stands for Extreme Long Range
I have no idea what to put in RAM/ROM Section and where is the entry point.
Also fw_all.bin is clearly not encrypted as we can find plain strings in the file.
I found the forum GpsPassion where they tried to load several Garmin firmwares in IDA but the forum is inactive and the garmin-ida-loader isn't working with this firmware.
I suspect the ELR Core to be some marketing bullshit
Yeah, I guess, ELR is the marketing term for the ballistic stuff - it sounds like a software feature.
The header of the fw_all doesn't match any of the ones from https://www.memotech.franken.de/FileFormats/Garmin_BIN_Format.pdf .
You could try to dump the NV area and see if there's some sort of identifier: https://www.gpspower.net/garmin-receivers-firmwares/277248-how-backup-nuvi-nv-region41-sd.html .
While the dump itself didn't work ... it still dumped it here
G:\GARMIN\DEBUG\ERR_LOG.TXT
2769 (Foretrex) SW ver: 350
Build Type: RELEASE
Commit:c376795e6f82f336fe49a3e492b982eb444dade0
ESN: 3964412548
03/07/20 18:55:38
AP
PWR RST CTRL: 0x00400028
POR
dump: <BASE64 DUMP>
Using base64 --decode dsqd.txt > out.out
I turned it back into a binary file and then I uploaded the dump here : https://extrem-team.com/dump.out
(file will be destroyed in few weeks as it contains well .. data from my GPS)
trid returns this :
trid .\out.out
TrID/32 - File Identifier v2.24 - (C) 2003-16 By M.Pontello
Definitions found: 12464
Analyzing...
Collecting data from file: .\out.out
50.7% (.BIN/MACBIN) MacBinary 1 (1033/5)
49.2% (.ABR) Adobe PhotoShop Brush (1002/3)
Inside there is some string and string in French as my Foretrex was in french, so it seems to be a memory dump.
Interesting string found in it :
MT3333 Software Version 2.50
It may not be our entry point but at least that's a big function
Located at 0x0000F350
I'm just going monkey mode in the text section to find the entrypoint
Data (not code but data) seems to be stored from around 0007F486 to 000FDA40 but after 000CA238 it's only 0xFF bytes, they're probably saving space for future ballistic DB updates
Base offset of the firmware is 0x00002000
Bootloader is probably 0x20000400
Internally it calls this :
Now I need to find how to repack the whole thing and force the update
It seems there is 3 version of the foretrex, not just the 601 and the 701, because the flag type can be 0 1 or 2
Strings in the firmware only show "Foretrex 601" and "Foretrex 701", so maybe a value of "2" is some developer mode or something like that.
Once you got the binary blob, I could make a GCD file from it. That should be the easiest part.
I used your tool to repack the whole thing as a GCD file (with incremented fw version), the bootloader can be modded as much as we want, but the firmware refuses to be updated as the update get stuck on 100%.
The Fenixes have a SHA1 checksum in the binary blob. There's an ending marker ff ff 5a a5 ff ff ff ff
which is followed by the SHA1 of everything from the beginning up to - and including - the marker. Doesn't seem to apply to the Foretrex fw, though.
Also, the sum of all bytes in the binary blob must be 00. (see my gcksum.py)
And then, check if you can find the PREBOOT mode - usually, by turning the watch off, then holding one or two keys while plugging it into the PC. Then you can flash anything using the WebUpdater (drag&drop gcd file onto WebUpdater.exe).
After few investigations :
Didn't manage to get the 601 to boot in pre-boot mode, however the webupdated allowed me to restore an old official firmware.
In the GCD file :
For the older Foretrex it was holding the UP key (probably as long as you want the mode to stay active) while connecting to the PC (and keeping holding the button). If nothing happens, keep holding UP and press POWER once to turn it on. Display will probably stay empty, but the PC should recognise a new device. (IF it works, that is.)
You could try changing the strings to 666, then fix the very last byte using the gcksum.py. It will show the expected value of the last byte, but you'll have to hexedit the file yourself. I don't know where the real "fix" byte (i.e. the byte that fixes the sum) appears in that firmware. There's gcksum_search.py to find possible locations, but that shows a looooooong list since it's only 1 Byte that has to match.
Yeah i just decided to patch the byte into one of the string used for debug, i managed to get this far :
But the menu is locked for some reasons
Menu unlock function is at
Menu unlock is reading a byte at address 0x2003F84C
patched the following bytes 03 4B 18 78 A0 F1 01 00 B0 FA 80 F0 40 09 70 47
to -> 03 4B 18 78 A0 F1 01 01 B0 FA 80 F0 40 09 70 47
to unlock the menu
701 byte is at 1
at this address, 601 is at 0
There is few other checks in the firmware at address 0x2003F84B
Value goes from 0 to 4
Did you try installing an unmodified firmware now to see if it still thinks its a 701?
If that doesn't work, install the patched firmware, then do a factory reset. It probably needs the database initialised or so.
well fuck, the gps just ran out of batteries and my local supermaket has no batteries left
i guess progress will have to wait
I'd suggest using Eneloop rechargeable batteries. Does Amazon Prime Now work in your area? Or take batteries from a TV remote or so. ;)
Folks I am really interested in this but a complete idiot and beginner with the Hex modifications, for a simpleton like me would it be possible to teach a step by step process?
Garmin released an update for the foretrex 601/701 two days ago anyway, i might do it after i fixed this last issue
Appreciate the quick response, So I take it the modification is only temporary? that after each OEM update you have to redo your work? or does modifying the brain of the device (sorry for the terrible terminology) trick the system to upgrading as 701? Also thank you for this thread.
There are probably multiple method but with the low skills I have I am only able to modify the firmware, which mean, yes i have to redo it on each firmware update
Also, to force the device to accept the update i have to edit the firmware version to make it think the one i'm giving to it is newer, so i have a very limited number of attempts at flashing the firmware.
What you classify as a low skill I class as wizardry!
So I've started playing around with Ghidra, the NSA tool. It gives me this for the internal check function:
uint checkIf701(void)
{
uint uVar1;
uVar1 = count_leading_zeroes((uint)*DAT_00032d14 - 1);
return uVar1 >> 5;
}
And if that returns "0", it's a 601, otherwise a 701.
DAT_00032d14 points to the memory address 0x2003F84c as you already found out above. From the value there, "1" is subtracted (so if the value was "0", it's now 0xffffffff = all 1s in binary) and then the leading zeroes from the 32bit value are counted. Then the value is bit-shifted 5 positions to the right, i.e. the 5 right-most bits are ignored. So to have something NOT 0, we have to have at least a binary 100000, or decimal 32 (or larger) in that address.
But we can also just move some value into the r0 register and nop the rest. This would ALWAYS return our (non-0) value. Basically MOV r0,#0x1
which is 01 20
in hex. The rest can be replaced with NOPs (00 bf
).
I never managed to get it to work with Ghidra.
Instead of attacking the part where it checks in the memory if the gps is a 701, I decided to attack the part on boot where it saves to ram the fact it's a 701 or a 601. As compiler may be inlining this check at other places.
The function checking saving this to ram is sub_32D90
(at position 0x32D90
, with loading address added)
int sub_32D90()
{
int result; // r0
unsigned int v1; // r2
char v2; // r3
signed int v3; // r2
char v4; // r2
int v5; // [sp+0h] [bp-20h]
int v6; // [sp+8h] [bp-18h]
sub_4D020(0x200141D8);
MEMORY[0x200141E8] = "&adc_mngr_smphr";
sub_4D2CC(0x200141D8);
sub_32D38(1);
sub_29BD8(10000);
if ( obscure_hardware_check(1, &v5) && (v3 = (unsigned __int16)(1000 * v6 / 1000), v3 != 0xFFFF) )
{
if ( (unsigned int)v3 > 0x31 )
{
if ( v3 <= 149 )
{
v4 = 1;
}
else if ( v3 <= 249 )
{
v4 = 2;
}
else if ( v3 < 350 )
{
v4 = 3;
}
else
{
v4 = 4;
}
}
else
{
v4 = 0;
}
MEMORY[0x2003F84B] = v4;
}
else
{
MEMORY[0x2003F84B] = 5;
}
if ( obscure_hardware_check(0, &v5) && (v1 = (unsigned __int16)(1000 * v6 / 1000), v1 != 0xFFFF) )
{
if ( v1 < 0x1C2 )
{
v2 = 0;
}
else if ( (signed int)(unsigned __int16)(1000 * v6 / 1000) <= 749 )
{
v2 = 1;
}
else
{
v2 = 2;
}
MEMORY[0x2003F84C] = v2;
}
else
{
MEMORY[0x2003F84C] = 2;
}
sub_32D38(0);
result = sub_4D0DC(0x200141D8);
MEMORY[0x20026C28] = 0;
return result;
}
You can see 0x2003F84C
is being wrote in this function, and another variable aswell :
0x2003F84B
The issue is it doesn't fix the "CANNOT UNLOCK APPLIED BALLISTICS" issue shown here
There is two calls to obscure_hardware_check, I don't know what the first checks sets, but the second one 100% sets 701 or 601 mode.
Patching tutorial :
Original code at ROM:00032E64
: 00 23 DA E7 01 22 EE E7 02 22 EC E7 D8 41 01 20
changed to : 01 23 DA E7 01 22 EE E7 02 22 EC E7 D8 41 01 20
Only the first byte changed
Which mean you now end up with this
And it now boots in 701 mode
However it doesn't fix the CANNOT UNLOCK APPLIED BALLISTICS
The idea would be to get deeper and reverse the function I renamed obscure_hardware_check
(original name is sub_2F174
), but Ida 7.0 Hex ray decompiler isn't reliable enough to do so.
There is two patched bytes as we need to have the whole sum%16 to 0
As the sum calculator from gcd-parser crashes on my computer i did my own in Lua
local file = io.open("../dump1/outDump_02bd_11056.bin", "rb")
local data = file:read("*all")
local len = data:len()
local bytes = {}
local i = 1
while (i <= len) do
bytes[i] = string.byte(data, i, i)
i = i + 1
end
local sum = 0
for k, v in ipairs(bytes) do
sum = sum + v
end
print(sum%16 == 0)
Have you tried doing a factory reset after applying the patch? I wonder if it needs to write some databases to the memory before it can "unlock"? Also does your GarminDevice.xml show up as a 701? Compare it to a version from before and see if there's a new <UpdateFile>
record - maybe it's the AB database?
Yes it shows as a 701 in GarminDevice.xml
<Model>
<PartNumber>006-B2769-00</PartNumber>
<SoftwareVersion>360</SoftwareVersion>
<Description>Foretrex 701</Description>
</Model>
There is nothing I found related to factory reset beside this
However i discovered this :
Power+Enter boot mode, will start the test mode
https://www.youtube.com/watch?v=ueDyEm0VGME
I obviously tried the 3 others buttons and it doesn't do anything (or at least it doesn't unlocks it)
Edit : the garmin wiki pages says
PAGE, ENTER and POWER
It doesn't fixes it
Does Garmin Express say anything about some update? Can you use get_updates.py with your GarminDevice.xml and see if there's some download about applied ballistics?
The applied ballistics DB is part of the firmware, this is why they release updates so much.
I still tried what you told me to try and here is the result, nothing about applied ballistics DB
[
[Express] 006-B2769-00 Foretrex 601/701 3.60,
[Express] 006-D1074-00 Time Zone Map 24.00,
[Express] 006-B2957-00 GPS Software 2.50,
[Express] 006-D7024-00 Foretrex 601/701, Text, Danish 2.20,
[Express] 006-D7024-01 Foretrex 601/701, Text, Dutch 2.20,
[Express] 006-D7024-02 Foretrex 601/701, Text, Finnish 2.20,
[Express] 006-D7024-03 Foretrex 601/701, Text, French 2.20,
[Express] 006-D7024-04 Foretrex 601/701, Text, German 2.20,
[Express] 006-D7024-05 Foretrex 601/701, Text, Italian 2.20,
[Express] 006-D7024-06 Foretrex 601/701, Text, Norwegian 2.20,
[Express] 006-D7024-08 Foretrex 601/701, Text, Spanish 2.20,
[Express] 006-D7024-09 Foretrex 601/701, Text, Swedish 2.20,
[Express] 006-D7024-10 Foretrex 601/701, Text, Croatian 2.20,
[Express] 006-D7024-11 Foretrex 601/701, Text, Czech 2.20,
[Express] 006-D7024-13 Foretrex 601/701, Text, Polish 2.20,
[Express] 006-D7024-14 Foretrex 601/701, Text, Slovakian 2.20,
[Express] 006-D7024-15 Foretrex 601/701, Text, Slovenian 2.20,
[Express] 006-D7024-16 Foretrex 601/701, Text, Russian 2.20,
[Express] 006-D7024-17 Foretrex 601/701, Text, Greek 2.20,
[Express] 006-D7024-18 Foretrex 601/701, Text, Brazilian 2.20,
[Express] 006-D7024-23 Foretrex 601/701, Text, Arabic 2.20,
[Express] 006-D7024-27 Foretrex 601/701, Text, Turkish 2.20
]
Also in the link you sent, I don't see anything inside that could help, beside the key theory.
Beside, like any text that is displayed to the screen on the foretrex, there is no xref to this string
We can go "up" and find a xref at the start at the string list but it doesn't really help
There's a translation function in the code that first looks up if the desired language is installed and then locates the array of strings and selects PTR_sLanguage + stringId. You'll notice that this function is referenced like 40 times in the code. That's where I'd poke around next.
Cool! I wish to hack my 301 to enable backlight level change ability for night vision. It have it internally as I can see in service mode (yes, it's power+enter on boot), I can switch levels there but not in setup.
There's a translation function in the code that first looks up if the desired language is installed and then locates the array of strings and selects PTR_sLanguage + stringId. You'll notice that this function is referenced like 40 times in the code. That's where I'd poke around next.
Yes indeed! Same in 301/401. Language translate function with word number.
I actually gave on fixing the issue where it says it can't be unlocked as I didn't manage to get the memory address of the translated string.
So has this fully been stopped as in no longer being worked?
Hello,
I don't have the freetime to work on it anymore
The firmware is for both, the 601 and the 701. (The 701 adds a few gun-related features.) So there probably is a way to detect which model the firmware is running on. It might be a flag in the NV (non-volatile) area, might be something else.
Would be interesting to find out.