三星Shannon基带固件解压方法
最近把很早以前购买的三星平板拿出来继续使用,其SoC是三星半导体自制的Exynos 9611,由于我买的是WIFI+LTE版本,其存在基带。很久以前用搭载Exynos4210的三星S2的时候,就对三星的奇怪的香农基带感到好奇。
历经快十年的对于逆向的爱好,最近再阅读了一些大牛写的代码和他们提供的Loader,成功的对目前最新的Exynos Shannon基带固件做到了解包,解压后可直接使用ShannonRE项目之中的Loader和静态分析工具进行分析。
当然如果你只是对三星的调试模式比较好奇的话,在我的解压工具中,其将自动从main区块中搜索AT指令,可通过终端模拟器连接到Samsung DM端口发送AT指令进行调试。
# siu.py v2
import struct
import re
import argparse
from contextlib import closing
class TOC:
def __init__(self, fstream, fpos=None):
try:
if fpos is not None:
fstream.seek(fpos)
self.buf = fstream.read(32)
except Exception as e:
print(f"[!]ERROR Reading TOC Header: {e}")
self.buf = bytearray(32)
def unpack(self):
try:
self.name = self.buf[:12].rstrip(b"\x00").decode("utf-8")
self.start = struct.unpack("i", self.buf[12:16])[0]
self.size = struct.unpack("i", self.buf[20:24])[0]
self.secdata = struct.unpack("i", self.buf[24:28])[0]
self.queue = struct.unpack("i", self.buf[28:32])[0]
except struct.error as e:
print(f"[!]ERROR Unpacking TOC: {e}")
raise
def print_info(self):
print(f"Block Name: {self.name}")
print(f"Start Offset: 0x{self.start:08x}")
print(f"Size: 0x{self.size:08x}")
print(f"Sec Data: 0x{self.secdata:08x}")
print(f"Queue: {self.queue}")
class IMG:
def __init__(self, fstream, header):
fstream.seek(header.start)
self.buf = fstream.read(header.size)
def unpack(self):
pass
def write(self, dst):
with open(f"{dst}.bin", "wb") as f:
f.write(self.buf)
class BOOT(IMG):
def unpack(self):
print('Done')
def unpack_toc(file_stream, name):
header = TOC(file_stream)
header.unpack()
header.print_info()
if header.name != name:
raise ValueError(f"Unexpected TOC name. Expected {name}, got {header.name}")
return header
def unpack_img(file_stream, header, img_type):
img = img_type(file_stream, header)
img.unpack()
return img
def find_in_img(img, pattern, filename):
strings = re.findall(rb'%s[^\x00]*' % pattern.encode(), img.buf)
with open(f'{filename}.TXT', 'wb') as f:
for s in strings:
f.write(s + b'\n')
print(f"Found {len(strings)} strings")
return strings
def main():
parser = argparse.ArgumentParser(description="SHANNON Image Unpacker v1.2 by Yuu/Idea from ShannonRE by grant-h")
parser.add_argument('file', help='Path to the binary file')
parser.add_argument('--at', action='store_true', help='Find AT strings')
parser.add_argument('--ver', help='Find version strings for a given model')
args = parser.parse_args()
with closing(open(args.file, "rb")) as file_stream:
toc_header = unpack_toc(file_stream, "TOC")
boot_header = unpack_toc(file_stream, "BOOT")
main_header = unpack_toc(file_stream, "MAIN")
vss_header = unpack_toc(file_stream, "VSS")
nv_header = unpack_toc(file_stream, "NV")
offset_header = unpack_toc(file_stream, "OFFSET")
boot_img = unpack_img(file_stream, boot_header, BOOT)
boot_img.write("boot")
main_img = unpack_img(file_stream, main_header, IMG)
main_img.write("main")
vss_img = unpack_img(file_stream, vss_header, IMG)
vss_img.write("vss")
nv_img = unpack_img(file_stream, nv_header, IMG)
nv_img.write("nv")
if args.at:
find_in_img(main_img, 'AT+', 'AT')
if args.ver:
ver_strings = find_in_img(main_img, args.ver, 'VER')
if ver_strings:
print(f"Possible Version: {ver_strings[0].decode()}")
if __name__ == "__main__":
main()