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