mirror of
https://github.com/ApfelTeeSaft/IDA-DOL-Plugin-9.2.git
synced 2026-08-26 19:23:36 +00:00
init
This commit is contained in:
@@ -0,0 +1,243 @@
|
||||
import struct
|
||||
|
||||
import idaapi
|
||||
import ida_idp
|
||||
import ida_loader
|
||||
import ida_segment
|
||||
import ida_entry
|
||||
import ida_name
|
||||
import ida_ua
|
||||
import ida_bytes
|
||||
|
||||
DOL_FORMAT_NAME = "Nintendo GameCube/Wii DOL"
|
||||
PPC_PROCESSOR = "ppc"
|
||||
|
||||
TEXT_COUNT = 7
|
||||
DATA_COUNT = 11
|
||||
DOL_HEADER_SIZE = 0x100
|
||||
|
||||
|
||||
def read_u32be(li):
|
||||
b = li.read(4)
|
||||
if len(b) != 4:
|
||||
raise EOFError("Unexpected EOF")
|
||||
return struct.unpack(">I", b)[0]
|
||||
|
||||
|
||||
def get_file_size(li):
|
||||
cur = li.tell()
|
||||
li.seek(0, 2)
|
||||
size = li.tell()
|
||||
li.seek(cur, 0)
|
||||
return size
|
||||
|
||||
|
||||
def is_mem_addr(addr):
|
||||
# GameCube/Wii MEM1 + common Wii MEM2 range.
|
||||
return (
|
||||
0x80000000 <= addr < 0x81800000 or
|
||||
0x90000000 <= addr < 0x94000000
|
||||
)
|
||||
|
||||
|
||||
def parse_dol(li):
|
||||
li.seek(0)
|
||||
|
||||
text_offsets = [read_u32be(li) for _ in range(TEXT_COUNT)]
|
||||
data_offsets = [read_u32be(li) for _ in range(DATA_COUNT)]
|
||||
|
||||
text_addrs = [read_u32be(li) for _ in range(TEXT_COUNT)]
|
||||
data_addrs = [read_u32be(li) for _ in range(DATA_COUNT)]
|
||||
|
||||
text_sizes = [read_u32be(li) for _ in range(TEXT_COUNT)]
|
||||
data_sizes = [read_u32be(li) for _ in range(DATA_COUNT)]
|
||||
|
||||
bss_addr = read_u32be(li)
|
||||
bss_size = read_u32be(li)
|
||||
entry = read_u32be(li)
|
||||
|
||||
return {
|
||||
"text_offsets": text_offsets,
|
||||
"data_offsets": data_offsets,
|
||||
"text_addrs": text_addrs,
|
||||
"data_addrs": data_addrs,
|
||||
"text_sizes": text_sizes,
|
||||
"data_sizes": data_sizes,
|
||||
"bss_addr": bss_addr,
|
||||
"bss_size": bss_size,
|
||||
"entry": entry,
|
||||
}
|
||||
|
||||
|
||||
def validate_dol(li):
|
||||
size = get_file_size(li)
|
||||
|
||||
if size < DOL_HEADER_SIZE:
|
||||
return False
|
||||
|
||||
li.seek(0)
|
||||
magic = li.read(4)
|
||||
|
||||
# Reject obvious non-DOL containers/files.
|
||||
if magic == b"\x55\xAA\x38\x2D": # U8 archive
|
||||
return False
|
||||
if magic in (b"Yaz0", b"LZ77", b"RARC", b"RIFF", b"\x89PNG"):
|
||||
return False
|
||||
if magic[:2] in (b"PK", b"BM"):
|
||||
return False
|
||||
|
||||
try:
|
||||
h = parse_dol(li)
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
sections = []
|
||||
|
||||
for i in range(TEXT_COUNT):
|
||||
off = h["text_offsets"][i]
|
||||
addr = h["text_addrs"][i]
|
||||
sz = h["text_sizes"][i]
|
||||
|
||||
if sz == 0:
|
||||
continue
|
||||
|
||||
if off < DOL_HEADER_SIZE or off >= size:
|
||||
return False
|
||||
if off + sz > size:
|
||||
return False
|
||||
if off % 4 != 0:
|
||||
return False
|
||||
if not is_mem_addr(addr):
|
||||
return False
|
||||
if not is_mem_addr(addr + sz - 1):
|
||||
return False
|
||||
|
||||
sections.append(("text", i, off, addr, sz))
|
||||
|
||||
for i in range(DATA_COUNT):
|
||||
off = h["data_offsets"][i]
|
||||
addr = h["data_addrs"][i]
|
||||
sz = h["data_sizes"][i]
|
||||
|
||||
if sz == 0:
|
||||
continue
|
||||
|
||||
if off < DOL_HEADER_SIZE or off >= size:
|
||||
return False
|
||||
if off + sz > size:
|
||||
return False
|
||||
if off % 4 != 0:
|
||||
return False
|
||||
if not is_mem_addr(addr):
|
||||
return False
|
||||
if not is_mem_addr(addr + sz - 1):
|
||||
return False
|
||||
|
||||
sections.append(("data", i, off, addr, sz))
|
||||
|
||||
if len(sections) < 2:
|
||||
return False
|
||||
|
||||
# Entry must point into a text section.
|
||||
entry_ok = False
|
||||
for kind, _idx, _off, addr, sz in sections:
|
||||
if kind == "text" and addr <= h["entry"] < addr + sz:
|
||||
entry_ok = True
|
||||
break
|
||||
|
||||
if not entry_ok:
|
||||
return False
|
||||
|
||||
# File ranges should not overlap.
|
||||
ranges = sorted((off, off + sz) for _kind, _idx, off, _addr, sz in sections)
|
||||
for a, b in zip(ranges, ranges[1:]):
|
||||
if a[1] > b[0]:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def accept_file(li, filename):
|
||||
if validate_dol(li):
|
||||
return {
|
||||
"format": DOL_FORMAT_NAME,
|
||||
"processor": PPC_PROCESSOR,
|
||||
}
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
def add_segment(start, end, name, seg_class):
|
||||
ida_segment.add_segm(0, start, end, name, seg_class)
|
||||
|
||||
|
||||
def load_file(li, neflags, fmt):
|
||||
print("[DOL] Loading Nintendo GameCube/Wii DOL")
|
||||
|
||||
ida_idp.set_processor_type(PPC_PROCESSOR, ida_idp.SETPROC_LOADER)
|
||||
|
||||
h = parse_dol(li)
|
||||
|
||||
for i in range(TEXT_COUNT):
|
||||
off = h["text_offsets"][i]
|
||||
addr = h["text_addrs"][i]
|
||||
sz = h["text_sizes"][i]
|
||||
|
||||
if sz == 0:
|
||||
continue
|
||||
|
||||
end = addr + sz
|
||||
name = ".text%d" % i
|
||||
|
||||
print("[DOL] text%d file=0x%X addr=0x%X size=0x%X" % (i, off, addr, sz))
|
||||
|
||||
add_segment(addr, end, name, "CODE")
|
||||
li.file2base(off, addr, end, True)
|
||||
|
||||
seg = ida_segment.getseg(addr)
|
||||
if seg:
|
||||
seg.perm = ida_segment.SEGPERM_READ | ida_segment.SEGPERM_EXEC
|
||||
ida_segment.update_segm(seg)
|
||||
|
||||
ida_ua.create_insn(addr)
|
||||
|
||||
for i in range(DATA_COUNT):
|
||||
off = h["data_offsets"][i]
|
||||
addr = h["data_addrs"][i]
|
||||
sz = h["data_sizes"][i]
|
||||
|
||||
if sz == 0:
|
||||
continue
|
||||
|
||||
end = addr + sz
|
||||
name = ".data%d" % i
|
||||
|
||||
print("[DOL] data%d file=0x%X addr=0x%X size=0x%X" % (i, off, addr, sz))
|
||||
|
||||
add_segment(addr, end, name, "DATA")
|
||||
li.file2base(off, addr, end, True)
|
||||
|
||||
seg = ida_segment.getseg(addr)
|
||||
if seg:
|
||||
seg.perm = ida_segment.SEGPERM_READ | ida_segment.SEGPERM_WRITE
|
||||
ida_segment.update_segm(seg)
|
||||
|
||||
if h["bss_size"] != 0 and is_mem_addr(h["bss_addr"]):
|
||||
bss_start = h["bss_addr"]
|
||||
bss_end = h["bss_addr"] + h["bss_size"]
|
||||
|
||||
print("[DOL] bss addr=0x%X size=0x%X" % (bss_start, h["bss_size"]))
|
||||
|
||||
add_segment(bss_start, bss_end, ".bss", "BSS")
|
||||
|
||||
seg = ida_segment.getseg(bss_start)
|
||||
if seg:
|
||||
seg.perm = ida_segment.SEGPERM_READ | ida_segment.SEGPERM_WRITE
|
||||
ida_segment.update_segm(seg)
|
||||
|
||||
ida_entry.add_entry(h["entry"], h["entry"], "entry", True)
|
||||
ida_name.set_name(h["entry"], "entry", ida_name.SN_CHECK)
|
||||
|
||||
print("[DOL] Entry point: 0x%08X" % h["entry"])
|
||||
|
||||
return 1
|
||||
Reference in New Issue
Block a user