-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathasp_loader.py
More file actions
182 lines (145 loc) · 6.6 KB
/
asp_loader.py
File metadata and controls
182 lines (145 loc) · 6.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
'''
IDA AMD PSP/ASP binary loader
@SpecterDev
'''
import binascii
import ida_idp
import idaapi
import idc
import struct
PSP_MAGIC_GENERIC = 0x24505331 # $PS1
PSP_MAGIC_ABL_VARIANT_A = 0x00424157 # [N]BAW
PSP_MAGIC_ABL_VARIANT_A_MASK = 0xFF000000
PSP_MAGIC_ABL_VARIANT_A_SHIFT = 24
PSP_MAGIC_ABL_VARIANT_B = 0x41570042 # AW[N]B
PSP_MAGIC_ABL_VARIANT_B_MASK = 0x0000FF00
PSP_MAGIC_ABL_VARIANT_B_SHIFT = 8
def swap32(i):
return struct.unpack("<I", struct.pack(">I", i))[0]
class PSPFile:
def __init__(self, f):
self.offset = f.tell()
# 0x00-0x10
f.seek(0x00)
self.pad1 = struct.unpack("<16s", f.read(0x10))
# 0x10-0x20
f.seek(0x10)
(self.magic, self.body_size, self.is_encrypted, self.pad2) = struct.unpack("<III4s", f.read(0x10))
self.magic = swap32(self.magic)
# 0x20-0x50
f.seek(0x20)
(self.iv, self.is_signed, self.pad3, self.signature_footprint, self.is_compressed, self.pad4) = struct.unpack("<16sI4s16sI4s", f.read(0x30))
# 0x50-0x60
f.seek(0x50)
(self.uncompressed_size, self.zlib_size, self.pad5) = struct.unpack("<II8s", f.read(0x10))
# 0x60-0x80
f.seek(0x60)
(self.version, self.pad6, self.load_addr, self.rom_size, self.pad7) = struct.unpack("<I4sII16s", f.read(0x20))
# 0x80-0xA0
f.seek(0x80)
(self.wrapped_key, self.pad8) = struct.unpack("<16s16s", f.read(0x20))
# 0xA0-0xA4
f.seek(0xA0)
self.abl_id = struct.unpack("<I", f.read(0x04))[0]
self.abl_id = swap32(self.abl_id)
def get_abl_num(self):
if (self.magic == PSP_MAGIC_GENERIC):
return (self.abl_id & PSP_MAGIC_ABL_VARIANT_B_MASK) >> PSP_MAGIC_ABL_VARIANT_B_SHIFT
if (self.magic & ~PSP_MAGIC_ABL_VARIANT_A_MASK) == PSP_MAGIC_ABL_VARIANT_A:
return (self.magic & PSP_MAGIC_ABL_VARIANT_A_MASK) >> PSP_MAGIC_ABL_VARIANT_A_SHIFT
if (self.magic & ~PSP_MAGIC_ABL_VARIANT_B_MASK) == PSP_MAGIC_ABL_VARIANT_B:
return (self.magic & PSP_MAGIC_ABL_VARIANT_B_MASK) >> PSP_MAGIC_ABL_VARIANT_B_SHIFT
def is_abl0(self):
abl_num = self.get_abl_num()
if abl_num == 0x30:
return True
return False
def is_abln(self):
abl_num = self.get_abl_num()
if abl_num >= 0x31 and abl_num <= 0x37:
return True
return False
def create_header_struct(address):
pspStructId = idc.add_struc(-1, "PSPFileHeader", 0)
idc.add_struc_member(pspStructId, "pad1", 0x00, idc.FF_BYTE, -1, 0x10)
idc.add_struc_member(pspStructId, "magic", 0x10, idc.FF_STRLIT, -1, 0x04)
idc.add_struc_member(pspStructId, "body_size", 0x14, idc.FF_DWORD, -1, 0x04)
idc.add_struc_member(pspStructId, "is_encrypted", 0x18, idc.FF_DWORD, -1, 0x04)
idc.add_struc_member(pspStructId, "pad2", 0x1C, idc.FF_BYTE, -1, 0x4)
idc.add_struc_member(pspStructId, "iv", 0x20, idc.FF_BYTE, -1, 0x10)
idc.add_struc_member(pspStructId, "is_signed", 0x30, idc.FF_DWORD, -1, 0x04)
idc.add_struc_member(pspStructId, "pad3", 0x34, idc.FF_BYTE, -1, 0x04)
idc.add_struc_member(pspStructId, "signature_footprint", 0x38, idc.FF_BYTE, -1, 0x10)
idc.add_struc_member(pspStructId, "is_compressed", 0x48, idc.FF_DWORD, -1, 0x04)
idc.add_struc_member(pspStructId, "pad4", 0x4C, idc.FF_BYTE, -1, 0x04)
idc.add_struc_member(pspStructId, "uncompressed_size", 0x50, idc.FF_DWORD, -1, 0x04)
idc.add_struc_member(pspStructId, "zlib_size", 0x54, idc.FF_DWORD, -1, 0x04)
idc.add_struc_member(pspStructId, "pad5", 0x58, idc.FF_BYTE, -1, 0x08)
idc.add_struc_member(pspStructId, "version", 0x60, idc.FF_DWORD, -1, 0x04)
idc.add_struc_member(pspStructId, "pad6", 0x64, idc.FF_BYTE, -1, 0x04)
idc.add_struc_member(pspStructId, "load_addr", 0x68, idc.FF_DWORD, -1, 0x04)
idc.add_struc_member(pspStructId, "rom_size", 0x6C, idc.FF_DWORD, -1, 0x04)
idc.add_struc_member(pspStructId, "pad7", 0x70, idc.FF_BYTE, -1, 0x10)
idc.add_struc_member(pspStructId, "wrapped_key", 0x80, idc.FF_BYTE, -1, 0x10)
idc.add_struc_member(pspStructId, "pad8", 0x90, idc.FF_BYTE, -1, 0x10)
idc.add_struc_member(pspStructId, "abl_id", 0xA0, idc.FF_BYTE, -1, 0x04)
idaapi.create_struct(address, 0x90, pspStructId)
def load_file(f, neflags, format):
print('# ASP Loader')
pspFile = PSPFile(f)
idaapi.set_processor_type("arm", ida_idp.SETPROC_LOADER)
idaapi.get_inf_structure().lflags |= idaapi.LFLG_PC_FLAT
# Default addr of 0 (used for PSP_FW_BOOT_LOADER)
address = 0x0
# ABL0 standard addr is 0x15000, which seems to be the case when load addr is 0x100
if pspFile.is_abl0():
if pspFile.load_addr == 0x100:
address = 0x15100
else:
# Exceptions, currently all we have is 4700s
address = 0x54000
# ABLN standard addr is 0x16200, which seems to be the case when load addr is 0x100
if pspFile.is_abln():
if pspFile.load_addr == 0x100:
address = 0x16200
else:
# Exceptions, currently all we have is 4700s
address = 0x57000 # for c09+
end = address + 0x100
print('# Creating header segment')
idaapi.add_segm(0x0, address, end, 'HEADER', 'CONST', 0x0)
f.seek(0x0)
f.file2base(0x0, address, end, 0)
create_header_struct(address)
print('# Creating ROM Segment...')
address += 0x100
end = address + f.size() - 0x100
idaapi.add_segm(0x0, address, end, 'ROM', 'CODE', 0x0)
f.seek(0x100)
f.file2base(0x100, address, end, 0)
idaapi.add_entry(address, address, "start", 1)
return 1
def accept_file(f, n):
retval = 0
print('# Checking for ASP')
f.seek(0)
pspFile = PSPFile(f)
if pspFile.magic == PSP_MAGIC_GENERIC or (pspFile.magic & ~PSP_MAGIC_ABL_VARIANT_A_MASK) == PSP_MAGIC_ABL_VARIANT_A or (pspFile.magic & ~PSP_MAGIC_ABL_VARIANT_B_MASK) == PSP_MAGIC_ABL_VARIANT_B:
retval = "AMD-SP Firmware Blob"
magicStr = bytearray.fromhex('{:x}'.format(pspFile.magic)).decode()
print('# PSP File found!')
print('# Magic: {:s}'.format(magicStr))
print('# Version: {:02x}'.format(pspFile.version))
print('# Is encrypted: {}'.format(pspFile.is_encrypted))
print('# Is signed: {}'.format(pspFile.is_signed))
print('# Is compressed: {}'.format(pspFile.is_compressed))
print('# Load Address: 0x{:02x}'.format(pspFile.load_addr))
print('# ROM size: 0x{:02x}'.format(pspFile.rom_size))
print('# Body size: 0x{:02x}'.format(pspFile.body_size))
print('# Zlib size: 0x{:02x}'.format(pspFile.zlib_size))
print('# Uncompressed size: 0x{:02x}'.format(pspFile.uncompressed_size))
print('# Wrapped key: {}'.format(binascii.hexlify(pspFile.wrapped_key, ' ').decode()))
print('# IV: {}'.format(binascii.hexlify(pspFile.iv, ' ').decode()))
print('# Signature footprint: {}'.format(binascii.hexlify(pspFile.signature_footprint, ' ').decode()))
print('# ABL ID: {}'.format(pspFile.abl_id))
return retval