mirror of
https://github.com/mytechnotalent/Embedded-Hacking.git
synced 2026-04-02 01:20:17 +02:00
220 lines
6.1 KiB
Python
220 lines
6.1 KiB
Python
#!/usr/bin/env python3
|
|
|
|
"""
|
|
FILE: hack-temp.py
|
|
|
|
DESCRIPTION:
|
|
Incremental firmware patcher with minimal, conservative steps to bias readings.
|
|
|
|
BRIEF:
|
|
Provides three modes:
|
|
- pool_only: change only the literal pool constant (scaling effect; least invasive)
|
|
- temp_only_vadd: convert temperature path to vadd.f32 and set a small negative pool
|
|
- both_vadd: convert both paths to vadd.f32 and set a small negative pool
|
|
|
|
Intended to let you test changes incrementally, keeping humidity stable while
|
|
you evaluate temperature bias first.
|
|
|
|
AUTHOR: Kevin Thomas
|
|
CREATION DATE: November 1, 2025
|
|
UPDATE DATE: November 1, 2025
|
|
"""
|
|
|
|
import sys
|
|
import os
|
|
import struct
|
|
|
|
BIN_PATH = "build/0x001a_operators.bin"
|
|
|
|
# Offsets
|
|
OFF_410 = 0x410
|
|
OFF_414 = 0x414
|
|
OFF_POOL = 0x42C
|
|
|
|
# Original encodings (for visibility only)
|
|
ORIG_410 = bytes.fromhex("a6ee257a") # vfma.f32 s14, s12, s11
|
|
ORIG_414 = bytes.fromhex("e6eea57a") # vfma.f32 s15, s13, s11
|
|
ORIG_POOL = bytes.fromhex("cccccc3d") # 0.1f
|
|
|
|
# Encodings for vadd.f32 s14, s14, s11 and vadd.f32 s15, s15, s11
|
|
VADD_S14_S11 = struct.pack("<I", 0xEEB47A06) # 06 7a b4 ee
|
|
VADD_S15_S11 = struct.pack("<I", 0xEEB47A86) # 86 7a b4 ee
|
|
|
|
|
|
def read_at(path, offset, n):
|
|
"""Read bytes from a binary file at a given offset.
|
|
|
|
Parameters
|
|
----------
|
|
path : str
|
|
Filesystem path to the binary file.
|
|
offset : int
|
|
Byte offset from the start of the file.
|
|
n : int
|
|
Number of bytes to read.
|
|
|
|
Returns
|
|
-------
|
|
bytes
|
|
The raw bytes read from the file.
|
|
|
|
Raises
|
|
------
|
|
IOError
|
|
If the file cannot be opened or read.
|
|
"""
|
|
with open(path, "rb") as f:
|
|
f.seek(offset)
|
|
return f.read(n)
|
|
|
|
|
|
def write_at(path, offset, data):
|
|
"""Write bytes into a binary file at a given offset.
|
|
|
|
Parameters
|
|
----------
|
|
path : str
|
|
Filesystem path to the binary file.
|
|
offset : int
|
|
Byte offset from the start of the file.
|
|
data : bytes
|
|
Bytes to write into the file.
|
|
|
|
Raises
|
|
------
|
|
IOError
|
|
If the file cannot be opened or written.
|
|
"""
|
|
with open(path, "rb+") as f:
|
|
f.seek(offset)
|
|
f.write(data)
|
|
|
|
|
|
def fmt_float(b):
|
|
"""Format a 4-byte sequence as hex and float if possible.
|
|
|
|
Parameters
|
|
----------
|
|
b : bytes
|
|
A 4-byte sequence.
|
|
|
|
Returns
|
|
-------
|
|
str
|
|
Hexadecimal string with float interpretation if valid.
|
|
"""
|
|
hx = b.hex()
|
|
try:
|
|
val = struct.unpack("<f", b)[0]
|
|
return f"{hx} (float {val:.6f})"
|
|
except Exception:
|
|
return hx
|
|
|
|
|
|
def patch_pool_only(new_pool_float=-1.0):
|
|
"""Patch only the pool constant to a new float value.
|
|
|
|
Parameters
|
|
----------
|
|
new_pool_float : float, optional
|
|
New float value to write into the pool constant (default -1.0).
|
|
|
|
Returns
|
|
-------
|
|
None
|
|
"""
|
|
print("[mode] pool_only")
|
|
curp = read_at(BIN_PATH, OFF_POOL, 4)
|
|
print(f"Current @0x1000042C: {fmt_float(curp)} (expected {ORIG_POOL.hex()} == 0.1f)")
|
|
newb = struct.pack("<f", new_pool_float)
|
|
write_at(BIN_PATH, OFF_POOL, newb)
|
|
chkp = read_at(BIN_PATH, OFF_POOL, 4)
|
|
print(f"Patched @0x1000042C: {fmt_float(chkp)} (target {newb.hex()} == {new_pool_float}f)")
|
|
|
|
|
|
def patch_temp_only_vadd(new_pool_float=-2.0):
|
|
"""Patch temperature path to vadd and set pool to a small negative.
|
|
|
|
Parameters
|
|
----------
|
|
new_pool_float : float, optional
|
|
New float value to write into the pool constant (default -2.0).
|
|
|
|
Returns
|
|
-------
|
|
None
|
|
"""
|
|
print("[mode] temp_only_vadd")
|
|
cur414 = read_at(BIN_PATH, OFF_414, 4)
|
|
curp = read_at(BIN_PATH, OFF_POOL, 4)
|
|
print(f"Current @0x10000414: {cur414.hex()} (expected {ORIG_414.hex()})")
|
|
print(f"Current @0x1000042C: {fmt_float(curp)}")
|
|
write_at(BIN_PATH, OFF_414, VADD_S15_S11)
|
|
write_at(BIN_PATH, OFF_POOL, struct.pack("<f", new_pool_float))
|
|
chk414 = read_at(BIN_PATH, OFF_414, 4)
|
|
chkp = read_at(BIN_PATH, OFF_POOL, 4)
|
|
print(f"Patched @0x10000414: {chk414.hex()} (should be {VADD_S15_S11.hex()})")
|
|
print(f"Patched @0x1000042C: {fmt_float(chkp)} (target {new_pool_float}f)")
|
|
|
|
|
|
def patch_both_vadd(new_pool_float=-2.0):
|
|
"""Patch both humidity and temperature paths to vadd and set pool.
|
|
|
|
Parameters
|
|
----------
|
|
new_pool_float : float, optional
|
|
New float value to write into the pool constant (default -2.0).
|
|
|
|
Returns
|
|
-------
|
|
None
|
|
"""
|
|
print("[mode] both_vadd")
|
|
cur410 = read_at(BIN_PATH, OFF_410, 4)
|
|
cur414 = read_at(BIN_PATH, OFF_414, 4)
|
|
curp = read_at(BIN_PATH, OFF_POOL, 4)
|
|
print(f"Current @0x10000410: {cur410.hex()} (expected {ORIG_410.hex()})")
|
|
print(f"Current @0x10000414: {cur414.hex()} (expected {ORIG_414.hex()})")
|
|
print(f"Current @0x1000042C: {fmt_float(curp)}")
|
|
write_at(BIN_PATH, OFF_410, VADD_S14_S11)
|
|
write_at(BIN_PATH, OFF_414, VADD_S15_S11)
|
|
write_at(BIN_PATH, OFF_POOL, struct.pack("<f", new_pool_float))
|
|
chk410 = read_at(BIN_PATH, OFF_410, 4)
|
|
chk414 = read_at(BIN_PATH, OFF_414, 4)
|
|
chkp = read_at(BIN_PATH, OFF_POOL, 4)
|
|
print(f"Patched @0x10000410: {chk410.hex()} (should be {VADD_S14_S11.hex()})")
|
|
print(f"Patched @0x10000414: {chk414.hex()} (should be {VADD_S15_S11.hex()})")
|
|
print(f"Patched @0x1000042C: {fmt_float(chkp)} (target {new_pool_float}f)")
|
|
|
|
|
|
def main():
|
|
"""Dispatch patch mode and perform incremental modifications.
|
|
|
|
Returns
|
|
-------
|
|
None
|
|
|
|
Raises
|
|
------
|
|
FileNotFoundError
|
|
If the binary file specified by BIN_PATH does not exist.
|
|
"""
|
|
if not os.path.exists(BIN_PATH):
|
|
raise FileNotFoundError(f"Binary not found: {BIN_PATH}")
|
|
mode = (sys.argv[1] if len(sys.argv) > 1 else "pool_only").strip().lower()
|
|
if mode == "pool_only":
|
|
patch_pool_only(new_pool_float=-1.0)
|
|
elif mode == "temp_only_vadd":
|
|
patch_temp_only_vadd(new_pool_float=-2.0)
|
|
elif mode == "both_vadd":
|
|
patch_both_vadd(new_pool_float=-2.0)
|
|
else:
|
|
print(f"Unknown mode: {mode}")
|
|
print("Use: pool_only | temp_only_vadd | both_vadd")
|
|
sys.exit(2)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|
|
print("Patch complete. Convert to UF2 and flash. Test each mode incrementally.")
|