Skip to content

Commit

Permalink
feat: Support Go1.20+
Browse files Browse the repository at this point in the history
  • Loading branch information
0xjiayu committed Jun 14, 2023
1 parent 865359c commit 1da38a2
Show file tree
Hide file tree
Showing 3 changed files with 272 additions and 30 deletions.
1 change: 1 addition & 0 deletions common.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
MAGIC_112 = 0xFFFFFFFB # Magic Number from version 1.12
MAGIC_116 = 0xFFFFFFFA # Magic Number from version 1.16
MAGIC_118 = 0xFFFFFFF0 # Magic Number from version 1.18
MAGIC_120 = 0xFFFFFFF1 # Magic Number from version 1.20


if finfo.is_64bit():
Expand Down
191 changes: 178 additions & 13 deletions moduledata.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def test_firstmoduledata(possible_addr, magic_number):
return True
else:
common._debug(f"Not firstmoduledata addr: @ {possible_addr:#x}")
elif magic_number == common.MAGIC_118:
elif magic_number == common.MAGIC_118 or magic_number == common.MAGIC_120:
funcnametab_off = read_mem(mod_data.pcheader_addr + 8 + 3*ADDR_SZ, read_only=True)
filetab_off = read_mem(mod_data.pcheader_addr + 8 + 5*ADDR_SZ, read_only=True)
pctab_off = read_mem(mod_data.pcheader_addr + 8 + 6*ADDR_SZ, read_only=True)
Expand Down Expand Up @@ -112,9 +112,9 @@ def find_first_moduledata_addr_by_brute(magic_number):
curr_seg = ida_segment.getnseg(idx)
if curr_seg.type == 3: # Pure Data segment
curr_addr = curr_seg.start_ea
#common._info(f"Search seg [{curr_seg.name}], start: {curr_seg.start_ea:#x}, end: {curr_seg.end_ea:#x}, type: {curr_seg.type}")
common._info(f"Search seg [{curr_seg.name}], start: {curr_seg.start_ea:#x}, end: {curr_seg.end_ea:#x}, type: {curr_seg.type}")
while curr_addr <= curr_seg.end_ea:
#common._debug(f"Test firstmoduledata @ {curr_addr:#x} for magic_number {magic_number:#x}")
common._debug(f"Test firstmoduledata @ {curr_addr:#x} for magic_number {magic_number:#x}")
if idc.get_wide_dword(read_mem(curr_addr, read_only=True)) & 0xFFFFFFFF == magic_number: # possible firstmoduledata
if test_firstmoduledata(curr_addr, magic_number):
break
Expand All @@ -140,7 +140,7 @@ def find_first_moduledata_addr():
break
else: # is stripped, find firstmodule data by bruteforce searching
common._debug("Binary file is stripped")
magic_numbers = [common.MAGIC_116, common.MAGIC_112, common.MAGIC_118]
magic_numbers = [common.MAGIC_116, common.MAGIC_112, common.MAGIC_118, common.MAGIC_120]
# firstmoduledata is often contained in segment [.noptrdata]
mdata_seg_addr = get_mdata_seg_addr()
common._info("Finding firstmoduledata object...")
Expand All @@ -164,7 +164,7 @@ def find_first_moduledata_addr():
first_moduledata_addr = curr_addr
break

if first_moduledata_addr == idc.BADADDR and mdata_seg_addr == 0:
if first_moduledata_addr == idc.BADADDR:# and mdata_seg_addr == 0:
common._info("Now find firstmoduledata object by bruteforcing...")
for tmp_magic_number in magic_numbers:
common._info(f"Finding firstmoduledata with magic number {tmp_magic_number:#x} by bruteforcing...")
Expand Down Expand Up @@ -269,6 +269,51 @@ class ModuleData():
next *moduledata
}
type moduledata struct { // Go version 1.20+
pcHeader *pcHeader
funcnametab []byte
cutab []uint32
filetab []byte
pctab []byte
pclntable []byte
ftab []functab
findfunctab uintptr
minpc, maxpc uintptr
text, etext uintptr
noptrdata, enoptrdata uintptr
data, edata uintptr
bss, ebss uintptr
noptrbss, enoptrbss uintptr
covctrs, ecovctrs uintptr // Starts from 1.20
end, gcdata, gcbss uintptr
types, etypes uintptr
rodata uintptr // Starts from 1.18
gofunc uintptr // go.func.* // Starts from 1.18
textsectmap []textsect
typelinks []int32 // offsets from types
itablinks []*itab
ptab []ptabEntry
pluginpath string
pkghashes []modulehash
modulename string
modulehashes []modulehash
hasmain uint8 // 1 if module contains the main function, 0 otherwise
gcdatamask, gcbssmask bitvector
typemap map[typeOff]*_type // offset to *_rtype in previous module
bad bool // module failed to load and should be ignored
next *moduledata
}
type pcHeader struct { // Go version 1.16+
magic uint32 // 0xFFFFFFFA
pad1, pad2 uint8 // 0, 0
Expand Down Expand Up @@ -442,11 +487,13 @@ def parse(self, is_test=False):

pluginpath_addr = read_mem(self.start_addr + 39*ADDR_SZ, read_only=is_test)
pluginpath_len = read_mem(self.start_addr + 40*ADDR_SZ, read_only=is_test)
self.pluginpath = "" if (pluginpath_len==0x0 or pluginpath_addr ==0x0) else idc.get_bytes(pluginpath_addr, pluginpath_len).decode()
self.pluginpath = "" if (pluginpath_len==0x0 or pluginpath_addr ==0x0) else \
idc.get_bytes(pluginpath_addr, pluginpath_len).decode()

modulename_addr = read_mem(self.start_addr+44*ADDR_SZ, read_only=is_test)
modulename_len = read_mem(self.start_addr+45*ADDR_SZ, read_only=is_test)
self.modulename ="" if modulename_addr == 0x0 or modulename_len == 0 else idc.get_bytes(modulename_addr, modulename_len).decode()
self.modulename ="" if modulename_addr == 0x0 or modulename_len == 0 else \
idc.get_bytes(modulename_addr, modulename_len).decode()

self.hasmain = idc.get_wide_byte(self.start_addr + 49*ADDR_SZ)
self.next = read_mem(self.start_addr + 54*ADDR_SZ+1, read_only=is_test)
Expand Down Expand Up @@ -502,9 +549,10 @@ def parse(self, is_test=False):

idc.create_strlit(modulename_addr, modulename_addr+modulename_len)
idaapi.auto_wait()

idc.create_strlit(pluginpath_addr, pluginpath_addr+pluginpath_len)
idaapi.auto_wait()
else: # Go 1.16+
elif self.magic_number == common.MAGIC_116 or self.magic_number == common.MAGIC_118:
self.noptrdata_addr = read_mem(self.start_addr + 24*ADDR_SZ, read_only=is_test)
self.enoptrdata_addr = read_mem(self.start_addr + 25*ADDR_SZ, read_only=is_test)
self.data_addr = read_mem(self.start_addr + 26*ADDR_SZ, read_only=is_test)
Expand Down Expand Up @@ -535,11 +583,13 @@ def parse(self, is_test=False):

pluginpath_addr = read_mem(self.start_addr+49*ADDR_SZ, read_only=is_test)
pluginpath_len = read_mem(self.start_addr+50*ADDR_SZ, read_only=is_test)
self.pluginpath = "" if (pluginpath_len==0x0 or pluginpath_addr ==0x0) else idc.get_bytes(pluginpath_addr, pluginpath_len).decode()
self.pluginpath = "" if (pluginpath_len==0x0 or pluginpath_addr ==0x0) else \
idc.get_bytes(pluginpath_addr, pluginpath_len).decode()

modulename_addr = read_mem(self.start_addr+54*ADDR_SZ, read_only=is_test)
modulename_len = read_mem(self.start_addr+55*ADDR_SZ, read_only=is_test)
self.modulename = "" if modulename_addr ==0x0 or modulename_len ==0 else idc.get_bytes(modulename_addr, modulename_len).decode()
self.modulename = "" if modulename_addr ==0x0 or modulename_len ==0 else \
idc.get_bytes(modulename_addr, modulename_len).decode()

self.hasmain = idc.get_wide_byte(self.start_addr+59*ADDR_SZ)
self.next = read_mem(self.start_addr+64*ADDR_SZ+1, read_only=is_test)
Expand All @@ -562,11 +612,13 @@ def parse(self, is_test=False):

pluginpath_addr = read_mem(self.start_addr + 51*ADDR_SZ, read_only=is_test)
pluginpath_len = read_mem(self.start_addr + 52*ADDR_SZ, read_only=is_test)
self.pluginpath = "" if (pluginpath_len == 0x0 or pluginpath_addr == 0x0) else idc.get_bytes(pluginpath_addr, pluginpath_len).decode()
self.pluginpath = "" if (pluginpath_len == 0x0 or pluginpath_addr == 0x0) else \
idc.get_bytes(pluginpath_addr, pluginpath_len).decode()

modulename_addr = read_mem(self.start_addr + 56*ADDR_SZ, read_only=is_test)
modulename_len = read_mem(self.start_addr + 57*ADDR_SZ, read_only=is_test)
self.modulename ="" if modulename_addr == 0x0 or modulename_len == 0x0 else idc.get_bytes(modulename_addr, modulename_len).decode()
self.modulename ="" if modulename_addr == 0x0 or modulename_len == 0x0 else \
idc.get_bytes(modulename_addr, modulename_len).decode()

self.hasmain = idc.get_wide_byte(self.start_addr + 61*ADDR_SZ)
self.next = read_mem(self.start_addr + 66*ADDR_SZ+1, read_only=is_test)
Expand Down Expand Up @@ -654,5 +706,118 @@ def parse(self, is_test=False):

idc.create_strlit(modulename_addr, modulename_addr+modulename_len)
idaapi.auto_wait()

idc.create_strlit(pluginpath_addr, pluginpath_addr+pluginpath_len)
idaapi.auto_wait()
else: # MAGIC_120
self.noptrdata_addr = read_mem(self.start_addr + 24*ADDR_SZ, read_only=is_test)
self.enoptrdata_addr = read_mem(self.start_addr + 25*ADDR_SZ, read_only=is_test)
self.data_addr = read_mem(self.start_addr + 26*ADDR_SZ, read_only=is_test)
self.edata_addr = read_mem(self.start_addr + 27*ADDR_SZ, read_only=is_test)
self.bss_addr = read_mem(self.start_addr + 28*ADDR_SZ, read_only=is_test)
self.ebss_addr = read_mem(self.start_addr + 29*ADDR_SZ, read_only=is_test)
self.noptrbss_addr = read_mem(self.start_addr + 30*ADDR_SZ, read_only=is_test)
self.enoptrbss_addr = read_mem(self.start_addr + 31*ADDR_SZ, read_only=is_test)
self.covctrs_addr = read_mem(self.start_addr + 32*ADDR_SZ, read_only=is_test)
self.ecovctrs_addr = read_mem(self.start_addr + 33*ADDR_SZ, read_only=is_test)
self.end_addr = read_mem(self.start_addr + 34*ADDR_SZ, read_only=is_test)
self.gcdata_addr = read_mem(self.start_addr + 35*ADDR_SZ, read_only=is_test)
self.gcbss_addr = read_mem(self.start_addr + 36*ADDR_SZ, read_only=is_test)
self.types_addr = read_mem(self.start_addr + 37*ADDR_SZ, read_only=is_test)
self.etypes_addr = read_mem(self.start_addr + 38*ADDR_SZ, read_only=is_test)
self.rodata_addr = read_mem(self.start_addr + 39*ADDR_SZ, read_only=is_test)
self.gofunc_addr = read_mem(self.start_addr + 40*ADDR_SZ, read_only=is_test)
self.textsecmap_addr = read_mem(self.start_addr + 41*ADDR_SZ, read_only=is_test)
self.textsecmap_len = read_mem(self.start_addr + 42*ADDR_SZ, read_only=is_test)
self.textsecmap_cap = read_mem(self.start_addr + 43*ADDR_SZ, read_only=is_test)
self.typelink_addr = read_mem(self.start_addr + 44*ADDR_SZ, read_only=is_test)
self.type_cnt = read_mem(self.start_addr + 45*ADDR_SZ, read_only=is_test)
self.type_cap = read_mem(self.start_addr + 46*ADDR_SZ, read_only=is_test)
self.itablink_addr = read_mem(self.start_addr + 47*ADDR_SZ, read_only=is_test)
self.itab_cnt = read_mem(self.start_addr + 48*ADDR_SZ, read_only=is_test)
self.itab_cap = read_mem(self.start_addr + 49*ADDR_SZ, read_only=is_test)
self.ptab_addr = read_mem(self.start_addr + 50*ADDR_SZ, read_only=is_test)
self.ptab_sz = read_mem(self.start_addr + 51*ADDR_SZ, read_only=is_test)
self.ptab_cap = read_mem(self.start_addr + 52*ADDR_SZ, read_only=is_test)

pluginpath_addr = read_mem(self.start_addr + 53*ADDR_SZ, read_only=is_test)
pluginpath_len = read_mem(self.start_addr + 54*ADDR_SZ, read_only=is_test)
self.pluginpath = "" if (pluginpath_len == 0x0 or pluginpath_addr == 0x0) else \
idc.get_bytes(pluginpath_addr, pluginpath_len).decode()

modulename_addr = read_mem(self.start_addr + 58*ADDR_SZ, read_only=is_test)
modulename_len = read_mem(self.start_addr + 59*ADDR_SZ, read_only=is_test)
self.modulename ="" if modulename_addr == 0x0 or modulename_len == 0x0 else \
idc.get_bytes(modulename_addr, modulename_len).decode()

self.hasmain = idc.get_wide_byte(self.start_addr + 63*ADDR_SZ)
self.next = read_mem(self.start_addr + 69*ADDR_SZ+1, read_only=is_test)

# Set comment for each field
idc.set_cmt(self.start_addr, "pcHeader", 0)
idc.set_cmt(self.start_addr + ADDR_SZ, "funcnametab addr", 0)
idc.set_cmt(self.start_addr + 2*ADDR_SZ, "funcnametab size", 0)
idc.set_cmt(self.start_addr + 3*ADDR_SZ, "funcnametab capacity", 0)
idc.set_cmt(self.start_addr + 4*ADDR_SZ, "cutab addr", 0)
idc.set_cmt(self.start_addr + 5*ADDR_SZ, "cutab count", 0)
idc.set_cmt(self.start_addr + 6*ADDR_SZ, "cutab capacity", 0)
idc.set_cmt(self.start_addr + 7*ADDR_SZ, "source files table addr",0)
idc.set_cmt(self.start_addr + 8*ADDR_SZ, "source files count",0)
idc.set_cmt(self.start_addr + 9*ADDR_SZ, "source files table capacity",0)
idc.set_cmt(self.start_addr + 10*ADDR_SZ, "pc table addr", 0)
idc.set_cmt(self.start_addr + 11*ADDR_SZ, "pc table size", 0)
idc.set_cmt(self.start_addr + 12*ADDR_SZ, "pc table capacity", 0)
idc.set_cmt(self.start_addr + 13*ADDR_SZ, "pclntbl addr",0)
idc.set_cmt(self.start_addr + 14*ADDR_SZ, "pclntbl size",0)
idc.set_cmt(self.start_addr + 15*ADDR_SZ, "pclntbl capacity",0)
idc.set_cmt(self.start_addr + 16*ADDR_SZ, "funcs table addr",0)
idc.set_cmt(self.start_addr + 17*ADDR_SZ, "funcs count",0)
idc.set_cmt(self.start_addr + 18*ADDR_SZ, "funcs table capacity",0)
idc.set_cmt(self.start_addr + 19*ADDR_SZ, "findfunctable addr",0)
idc.set_cmt(self.start_addr + 20*ADDR_SZ, "min pc",0)
idc.set_cmt(self.start_addr + 21*ADDR_SZ, "max pc",0)
idc.set_cmt(self.start_addr + 22*ADDR_SZ, "text start addr",0)
idc.set_cmt(self.start_addr + 23*ADDR_SZ, "text end addr",0)
idc.set_cmt(self.start_addr + 24*ADDR_SZ, "noptrdata start addr",0)
idc.set_cmt(self.start_addr + 25*ADDR_SZ, "noptrdata end addr",0)
idc.set_cmt(self.start_addr + 26*ADDR_SZ, "data section start addr",0)
idc.set_cmt(self.start_addr + 27*ADDR_SZ, "data section end addr",0)
idc.set_cmt(self.start_addr + 28*ADDR_SZ, "bss start addr",0)
idc.set_cmt(self.start_addr + 29*ADDR_SZ, "bss end addr",0)
idc.set_cmt(self.start_addr + 30*ADDR_SZ, "noptrbss start addr",0)
idc.set_cmt(self.start_addr + 31*ADDR_SZ, "noptrbss end addr",0)
idc.set_cmt(self.start_addr + 32*ADDR_SZ, "code coverage counters start addr",0)
idc.set_cmt(self.start_addr + 33*ADDR_SZ, "code coverage counters end addr",0)
idc.set_cmt(self.start_addr + 34*ADDR_SZ, "end addr of whole image",0)
idc.set_cmt(self.start_addr + 35*ADDR_SZ, "gcdata addr",0)
idc.set_cmt(self.start_addr + 36*ADDR_SZ, "gcbss addr",0)
idc.set_cmt(self.start_addr + 37*ADDR_SZ, "types start addr",0)
idc.set_cmt(self.start_addr + 38*ADDR_SZ, "types end addr",0)
idc.set_cmt(self.start_addr + 39*ADDR_SZ, "rodata addr",0)
idc.set_cmt(self.start_addr + 40*ADDR_SZ, "go func pointer addr",0)
idc.set_cmt(self.start_addr + 41*ADDR_SZ, "text section map addr",0)
idc.set_cmt(self.start_addr + 42*ADDR_SZ, "text section map length",0)
idc.set_cmt(self.start_addr + 43*ADDR_SZ, "text section map capacity",0)
idc.set_cmt(self.start_addr + 44*ADDR_SZ, "typelink addr",0)
idc.set_cmt(self.start_addr + 45*ADDR_SZ, "types count",0)
idc.set_cmt(self.start_addr + 46*ADDR_SZ, "types table capacity",0)
idc.set_cmt(self.start_addr + 47*ADDR_SZ, "itabslink addr",0)
idc.set_cmt(self.start_addr + 48*ADDR_SZ, "itabs count",0)
idc.set_cmt(self.start_addr + 49*ADDR_SZ, "itabs caapacity",0)
idc.set_cmt(self.start_addr + 50*ADDR_SZ, "ptab addr",0)
idc.set_cmt(self.start_addr + 51*ADDR_SZ, "ptab count",0)
idc.set_cmt(self.start_addr + 52*ADDR_SZ, "ptab capacity",0)
idc.set_cmt(self.start_addr + 53*ADDR_SZ, "plugin path addr",0)
idc.set_cmt(self.start_addr + 54*ADDR_SZ, "plugin path length",0)
idc.set_cmt(self.start_addr + 55*ADDR_SZ, "module name addr",0)
idc.set_cmt(self.start_addr + 56*ADDR_SZ, "module name length",0)
idc.set_cmt(self.start_addr + 63*ADDR_SZ, "hasmain flag",0)
idc.set_cmt(self.start_addr + 69*ADDR_SZ+1, "next moduledata addr",0)

idaapi.auto_wait()

idc.create_strlit(modulename_addr, modulename_addr+modulename_len)
idaapi.auto_wait()

idc.create_strlit(pluginpath_addr, pluginpath_addr+pluginpath_len)
idaapi.auto_wait()
idaapi.auto_wait()
Loading

0 comments on commit 1da38a2

Please sign in to comment.