Skip to content

Instantly share code, notes, and snippets.

@ess7
Last active November 14, 2021 04:25
Show Gist options
  • Save ess7/1ae08640ea22b92764acd1ad84516156 to your computer and use it in GitHub Desktop.
Save ess7/1ae08640ea22b92764acd1ad84516156 to your computer and use it in GitHub Desktop.
Dump NSEEL functions in jsfx.dll
from ctypes import *
import struct
import re
assert RPR_GetAppVersion()[-4:] == '/x64'
def console(s):
RPR_ShowConsoleMsg(str(s) + '\n')
class MODULEINFO(Structure):
_fields_ = [
('lpBaseOfDll', c_void_p),
('SizeOfImage', c_ulong),
('EntryPoint', c_void_p)
]
kernel32 = windll.kernel32
kernel32.GetCurrentProcess.restype = c_void_p
kernel32.GetModuleHandleA.argtypes = [c_char_p]
kernel32.GetModuleHandleA.restype = c_void_p
kernel32.K32GetModuleInformation.argtypes = [c_void_p, c_void_p, c_void_p, c_ulong]
kernel32.K32GetModuleInformation.restype = c_long
MIN_MATCH = 7
MAX_MATCH = 32
def longest_match(haystack, needle):
longest = None
where = None
for length in range(MIN_MATCH, len(needle)):
i = haystack.find(needle[:length])
if i >= 0:
where = i
longest = length
else:
break
if where is not None and \
haystack.find(needle[:longest], where+longest) == -1: # no other match
return where, longest
else:
return None, None
RPR_ShowConsoleMsg('')
reaper = kernel32.GetModuleHandleA(None)
jsfx = kernel32.GetModuleHandleA(b'jsfx.dll')
jsfx_modinfo = MODULEINFO()
reaper_modinfo = MODULEINFO()
kernel32.K32GetModuleInformation(kernel32.GetCurrentProcess(), reaper, addressof(reaper_modinfo), sizeof(reaper_modinfo))
kernel32.K32GetModuleInformation(kernel32.GetCurrentProcess(), jsfx, addressof(jsfx_modinfo), sizeof(jsfx_modinfo))
reaper_bin = string_at(reaper_modinfo.lpBaseOfDll, reaper_modinfo.SizeOfImage)
jsfx_bin = string_at( jsfx_modinfo.lpBaseOfDll, jsfx_modinfo.SizeOfImage)
# find function table in reaper.exe
'''
from 6.40
140573ec5 48 8d 15 14 aa 5b 00 LEA RDX,[function_table]
140573ecc 41 b8 e9 00 00 00 MOV R8D,0x.... (table size)
140573ed2 41 b9 10 00 00 00 MOV R9D,0x10
140573ed8 e8 e3 b2 3a 00 CALL ...
'''
for match in re.finditer(
b'\x48\x8d\x15(?P<rip_ofs>....)'
b'\x41\xb8(?P<table_size>..)\x00\x00'
b'\x41\xb9\x10\x00\x00\x00'
b'\xe8',
reaper_bin, re.DOTALL):
function_table_addr = reaper_modinfo.lpBaseOfDll + \
match.start('rip_ofs') + 4 + \
struct.unpack('<l', match.group('rip_ofs'))[0]
table_size = struct.unpack('<H', match.group('table_size'))[0]
break
console('function table 0x%x\n' % function_table_addr)
functions = []
for i in range(table_size):
table_entry = string_at(function_table_addr + 16*i, 16)
name_addr, func_addr = struct.unpack('<QQ', table_entry)
functions.append((str(string_at(name_addr), 'ascii'), func_addr))
# dump all undocumented functions
#for name, addr in functions:
# console('{:40} 0x{:05x}'.format(name, addr))
console('{:29} {} {}'.format('function name', 'jsfx RVA', 'length'))
for name, addr in functions:
pattern = string_at(addr, MAX_MATCH)
jsfx_addr, length = longest_match(jsfx_bin, pattern)
if jsfx_addr is not None and 'nseel' in name.lower():
console('{:29} 0x{:05x} {:2d}'.format(name, jsfx_addr, length))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment