Last active
May 17, 2018 02:55
-
-
Save dkw72n/ec8cfe2a54f48b22f8465b92945bd3c6 to your computer and use it in GitHub Desktop.
UE4 string dumper
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import struct | |
| def logi(*args): | |
| if args: | |
| fmt, args = args[0], args[1:] | |
| if args: | |
| fmt = fmt % tuple(args) | |
| print '[-] %s' % fmt | |
| def loge(*args): | |
| if args: | |
| fmt, args = args[0], args[1:] | |
| if args: | |
| fmt = fmt % tuple(args) | |
| print '[!] %s' % fmt | |
| for i in traceback.format_exc().split('\n'): | |
| print " ", i | |
| def get_module_base(process, module): | |
| for mo in p.list_modules(): | |
| if mo.szModule.lower() == module.lower(): | |
| return mo.modBaseAddr | |
| return None | |
| def read_pointer(process, addr): | |
| bytes = process.read_bytes(addr, bytes = 8) | |
| # print "reading pointer: %08x -> %r" % (addr, bytes) | |
| if bytes and len(bytes) == 8: | |
| return struct.unpack('Q', bytes)[0] | |
| return None | |
| def read_float(process, addr): | |
| bytes = process.read_bytes(addr, bytes = 4) | |
| # print "reading pointer: %08x -> %r" % (addr, bytes) | |
| if bytes and len(bytes) == 4: | |
| return struct.unpack('f', bytes)[0] | |
| return None | |
| def read_int32(process, addr): | |
| bytes = process.read_bytes(addr, bytes = 4) | |
| # print "reading pointer: %08x -> %r" % (addr, bytes) | |
| if bytes and len(bytes) == 4: | |
| return struct.unpack('i', bytes)[0] | |
| return None | |
| def read_uint32(process, addr): | |
| bytes = process.read_bytes(addr, bytes = 4) | |
| # print "reading pointer: %08x -> %r" % (addr, bytes) | |
| if bytes and len(bytes) == 4: | |
| return struct.unpack('I', bytes)[0] | |
| return None | |
| def read_cstring(process, addr): | |
| STEP = 32 | |
| ret = '' | |
| off = 0 | |
| while True: | |
| part = process.read_bytes(addr + off, bytes = STEP) | |
| if not part: | |
| break | |
| end = part.find('\x00') | |
| if end != -1: | |
| ret += part[:end] | |
| break | |
| ret += part | |
| off += STEP | |
| return ret | |
| def dump_range(proc, base, left, right): | |
| print "%016x" % base | |
| for off in range(left, right, 8): | |
| print " %08x %016x %10.5g %10.5g %16d %16d" % ( | |
| off, | |
| read_pointer(proc, base + off), | |
| read_float(proc, base + off), | |
| read_float(proc, base + off + 4), | |
| read_int32(proc, base + off), | |
| read_int32(proc, base + off + 4), | |
| ) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #coding: utf8 | |
| from memorpy import * | |
| from shrutils import * | |
| import struct | |
| """ | |
| 在内存中搜索 UE4 的全局字符串表入口. | |
| 全局表结构: | |
| { | |
| FNameEntry** Buckets[128]; // 0x000 | |
| int32_t nEntries; // 0x400 | |
| int32_t nBuckets; // 0x404 | |
| } | |
| Buckets[i] 指向一个 FNameEntry* Names[0x4000] | |
| FNameEntry 结构 | |
| { | |
| int32_t Index; //0x00 | |
| int32_t dummy; //0x04 | |
| FNameEntry* Next; //0x08 | |
| TCHAR data[0]; //0x10 | |
| } | |
| Index = (iBucket * 0x4000 + iName) * 2 + (1 if wchar else 0) | |
| """ | |
| IMAGE_NAME = 'VehicleDemo.exe' | |
| def get_hex_of(bytes): | |
| return ' '.join(map(lambda x: "%02x" % ord(x), bytes)) | |
| Candidates = dict() | |
| def try_get_names_addr_from_str(mw, addr): | |
| p_addr_entry = addr - 0x10 | |
| idx = read_uint32(mw.process, p_addr_entry) | |
| print "trying", hex(int(p_addr_entry)) | |
| print "idx = ", idx | |
| y = idx / 2 % 0x4000 | |
| x = idx / 2 / 0x4000 | |
| print "searching for ", get_hex_of(struct.pack('Q', int(p_addr_entry))) | |
| p_entry_array_addrs = mw.mem_search(struct.pack('Q', int(p_addr_entry))) | |
| for entry_item in p_entry_array_addrs: | |
| guess_addr = entry_item - (y * 8) | |
| p_name_array_addrs = mw.mem_search(struct.pack('Q', int(guess_addr))) | |
| for name_item in p_name_array_addrs: | |
| guess = name_item - x * 8 | |
| print "guessing:", hex(int(guess)), read_int32(mw.process, guess + 0x400), read_int32(mw.process, guess + 0x404) | |
| Candidates[int(guess)] = Candidates.get(int(guess), 0) + 1 | |
| pass | |
| def guess_forward(mw, guess, addr): | |
| print "guess_forward:", hex(guess), "->", hex(int(addr)) | |
| p_addr_entry = addr - 0x10 | |
| idx = read_uint32(mw.process, p_addr_entry) | |
| y = idx / 2 % 0x4000 | |
| x = idx / 2 / 0x4000 | |
| bucket = read_pointer(mw.process, guess + x * 8) | |
| entry = read_pointer(mw.process, bucket + y * 8) | |
| return entry == int(p_addr_entry) | |
| def dump_all_string(mw, addr): | |
| T = read_int32(mw.process, addr + 0x400) | |
| for i in range(T): | |
| x = i / 0x4000 | |
| y = i % 0x4000 | |
| bucket = read_pointer(mw.process, addr + x * 8) | |
| entry = read_pointer(mw.process, bucket + y * 8) | |
| idx = read_int32(mw.process, entry) | |
| if idx is None: | |
| continue | |
| print "%08x %08x %r" % (idx, i, read_cstring(mw.process, entry + 0x10)) | |
| if __name__ == '__main__': | |
| PID = int(sys.argv[1]) | |
| #with MemWorker(name=IMAGE_NAME) as mw: | |
| with MemWorker(pid = int() as mw: | |
| print "process:", mw.process | |
| i = 0 | |
| #for addr in mw.mem_search("Default__ShooterPlayer"): | |
| for addr in mw.mem_search("Default__ActorComponent"): | |
| if i > 5: break | |
| if int(addr) % 8 != 0: continue | |
| i += 1 | |
| good_candidate = None | |
| for candidate in Candidates: | |
| if guess_forward(mw, candidate, addr): | |
| print "guess forward successfully" | |
| good_candidate = candidate | |
| break | |
| if good_candidate: | |
| Candidates[good_candidate] += 1 | |
| else: | |
| try_get_names_addr_from_str(mw, addr) | |
| if Candidates: | |
| print Candidates | |
| best = max(Candidates, key=lambda x:Candidates[x]) | |
| dump_all_string(mw, best) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment