chore: initial commit
This commit is contained in:
commit
b0e6851eee
|
@ -0,0 +1,115 @@
|
|||
# This IDA script will find all the signatures in your code and
|
||||
# make sure they're in the FFXIV binary.
|
||||
|
||||
# these directories will be checked recursively
|
||||
SOURCE_DIRS = [
|
||||
'D:\\code\\BetterPartyFinder',
|
||||
'D:\\code\\Burnt Toast',
|
||||
'D:\\code\\ChatTwo',
|
||||
'D:\\code\\DalamudPython',
|
||||
'D:\\code\\ExpandedSearchInfo',
|
||||
'D:\\code\\Glamaholic',
|
||||
'D:\\code\\Globetrotter',
|
||||
'D:\\code\\GoodMemory',
|
||||
'D:\\code\\HUD Manager',
|
||||
'D:\\code\\Macrology',
|
||||
'D:\\code\\Namingway',
|
||||
'D:\\code\\NominaOcculta',
|
||||
'D:\\code\\NoSoliciting',
|
||||
'D:\\code\\PeepingTom',
|
||||
'D:\\code\\Quest Map',
|
||||
'D:\\code\\remote-party-finder',
|
||||
'D:\\code\\SoundFilter',
|
||||
'D:\\code\\TextBoxStyler',
|
||||
'D:\\code\\TheGreatSeparator',
|
||||
'D:\\code\\Tourist',
|
||||
'D:\\code\\XIVChat',
|
||||
'D:\\code\\XivCommon',
|
||||
]
|
||||
|
||||
# file extension to check for signatures in
|
||||
FILE_EXT = 'cs'
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import re
|
||||
import io
|
||||
import idaapi
|
||||
import ida_segment
|
||||
import ida_bytes
|
||||
|
||||
SIG_REGEX = re.compile(r'"([A-Fa-f0-9\? ]+)"')
|
||||
|
||||
def is_valid_sig(sig):
|
||||
sig = sig.strip()
|
||||
|
||||
if len(sig) == 0:
|
||||
return False
|
||||
|
||||
if len(sig) % 2 != 0:
|
||||
return False
|
||||
|
||||
# gonna say 5 bytes min
|
||||
if len(sig) < 10:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def find_all_signatures():
|
||||
all_sigs = {}
|
||||
|
||||
for source_dir in SOURCE_DIRS:
|
||||
for root, dirs, files in os.walk(source_dir):
|
||||
for file_name in files:
|
||||
path = os.path.join(root, file_name)
|
||||
if not path.endswith('.' + FILE_EXT):
|
||||
continue
|
||||
|
||||
with io.open(path, encoding='utf8') as f:
|
||||
data = f.read()
|
||||
sigs = [x for x in SIG_REGEX.findall(data) if is_valid_sig(x)]
|
||||
all_sigs[path] = sigs
|
||||
|
||||
return all_sigs
|
||||
|
||||
def validate():
|
||||
text = ida_segment.segment_t = ida_segment.get_segm_by_name('.text')
|
||||
sigs = find_all_signatures()
|
||||
for path, sigs in sigs.items():
|
||||
for sig in sigs:
|
||||
result_count = 0
|
||||
sig_addr = text.start_ea
|
||||
|
||||
while True:
|
||||
# Expects a byte array
|
||||
fmt_sig = [int(s, 16).to_bytes(1, 'little') if s != '??' else b'\0' for s in sig.split(' ')]
|
||||
fmt_sig = b''.join(fmt_sig)
|
||||
|
||||
# Another byte array, 0 = "??" wildcard
|
||||
sig_mask = [int(b != '??').to_bytes(1, 'little') for b in sig.split(' ')]
|
||||
sig_mask = b''.join(sig_mask)
|
||||
|
||||
sig_addr = idaapi.bin_search(
|
||||
sig_addr,
|
||||
text.end_ea,
|
||||
fmt_sig,
|
||||
sig_mask,
|
||||
ida_bytes.BIN_SEARCH_FORWARD,
|
||||
ida_bytes.BIN_SEARCH_NOCASE
|
||||
)
|
||||
|
||||
if sig_addr == idaapi.BADADDR:
|
||||
break
|
||||
|
||||
result_count += 1
|
||||
sig_addr += 1
|
||||
|
||||
if result_count == 0:
|
||||
print('[E] ' + path + ': Missing ' + sig)
|
||||
|
||||
if result_count > 1:
|
||||
print('[W] ' + path + ': Multiple matches for ' + sig)
|
||||
|
||||
if __name__ == '__main__':
|
||||
validate()
|
||||
print('Done')
|
Loading…
Reference in New Issue