├── dependency ├── __init__.py └── ordlookup │ ├── __init__.py │ ├── ws2_32.py │ └── oleaut32.py ├── example ├── hello.exe └── hello.py ├── .gitignore ├── core ├── __init__.py ├── util │ ├── __init__.py │ ├── windows.h │ ├── stdlib.h │ └── stdlib.c ├── log.py ├── compiler.py ├── assemble.py ├── patcher.py ├── linker.py └── binary.py ├── requirements.txt ├── README.md ├── LICENSE └── patch.py /dependency/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | from pefile import * 3 | -------------------------------------------------------------------------------- /example/hello.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marche147/pepatch/HEAD/example/hello.exe -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.pyo 3 | *.swp 4 | test.py 5 | .devenv/ 6 | test_binaries/ 7 | 8 | -------------------------------------------------------------------------------- /core/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | from binary import * 3 | from assemble import * 4 | from linker import * 5 | from patcher import * 6 | -------------------------------------------------------------------------------- /example/hello.py: -------------------------------------------------------------------------------- 1 | 2 | # hello.exe is compiled by vs2017 3 | # ../patch.py hello.exe hello.py 4 | 5 | def patch(pt): 6 | 7 | addr = pt.inject(asm=''' 8 | call getstr 9 | .byte 0x41 10 | .byte 0 11 | getstr: 12 | pop rcx 13 | call 0x140001030 14 | jmp 0x0000000140001010 15 | ''') 16 | pt.patch(0x014000100B, jmp=addr) 17 | return 18 | -------------------------------------------------------------------------------- /core/util/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | import os 3 | 4 | def readrelative(filename): 5 | directory = os.path.dirname(os.path.realpath(__file__)) 6 | return open(directory + os.sep + filename, 'r').read() 7 | 8 | def declare(linker): 9 | linker.addheader(readrelative('windows.h')) 10 | 11 | linker.decl(readrelative('stdlib.c'), readrelative('stdlib.h')) 12 | return 13 | -------------------------------------------------------------------------------- /core/util/windows.h: -------------------------------------------------------------------------------- 1 | 2 | typedef unsigned char BYTE; 3 | typedef unsigned short WORD; 4 | typedef unsigned int DWORD; 5 | 6 | typedef char CHAR; 7 | typedef unsigned char UCHAR; 8 | typedef short SHORT; 9 | typedef unsigned short USHORT; 10 | typedef long LONG; 11 | typedef unsigned long ULONG; 12 | typedef long long LONGLONG; 13 | typedef unsigned long long ULONGLONG; 14 | 15 | 16 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | appnope==0.1.0 2 | backports.shutil-get-terminal-size==1.0.0 3 | capstone==3.0.4 4 | colorama==0.3.9 5 | decorator==4.1.2 6 | enum34==1.1.6 7 | future==0.16.0 8 | ipython==5.5.0 9 | ipython-genutils==0.2.0 10 | keystone-engine==0.9.1.post3 11 | pathlib2==2.3.0 12 | pexpect==4.3.1 13 | pickleshare==0.7.4 14 | prompt-toolkit==1.0.15 15 | ptyprocess==0.5.2 16 | Pygments==2.2.0 17 | scandir==1.6 18 | simplegeneric==0.8.1 19 | six==1.11.0 20 | traitlets==4.3.2 21 | wcwidth==0.1.7 22 | -------------------------------------------------------------------------------- /core/util/stdlib.h: -------------------------------------------------------------------------------- 1 | // some basic type definitions 2 | typedef short int16_t; 3 | typedef unsigned short uint16_t; 4 | typedef int int32_t; 5 | typedef unsigned int uint32_t; 6 | typedef long long int64_t; 7 | typedef unsigned long long uint64_t; 8 | #ifdef __x86_64__ 9 | typedef unsigned long long uintptr_t; 10 | typedef long long intptr_t; 11 | #else 12 | typedef unsigned int uintptr_t; 13 | typedef int intptr_t; 14 | #endif 15 | typedef uintptr_t size_t; 16 | typedef intptr_t ssize_t; 17 | 18 | // function definitions 19 | int strlen(char* str); 20 | char* strcpy(char* dst, char* src); 21 | void* memcpy(void* dst, void* src, size_t size); 22 | void* memset(void* dst, int fill, size_t size); 23 | -------------------------------------------------------------------------------- /core/log.py: -------------------------------------------------------------------------------- 1 | 2 | from __future__ import print_function 3 | import colorama 4 | 5 | colorama.init() 6 | YELLOW = colorama.Fore.YELLOW 7 | RED = colorama.Fore.RED 8 | GREEN = colorama.Fore.GREEN 9 | BLUE = colorama.Fore.LIGHTBLUE_EX 10 | WHITE = colorama.Fore.WHITE 11 | 12 | def warn(msg): 13 | print("[" + YELLOW + 'WARN' + WHITE + '] ' + msg) 14 | return 15 | 16 | def info(msg): 17 | print("[" + BLUE + 'INFO' + WHITE + '] ' + msg) 18 | return 19 | 20 | def success(msg): 21 | print("[" + GREEN + 'GOOD' + WHITE + '] ' + msg) 22 | return 23 | 24 | def error(msg): 25 | print("[" + RED + 'FAIL' + WHITE + '] ' + msg) 26 | return 27 | 28 | __all__ = ['warn', 'info', 'success', 'error'] 29 | -------------------------------------------------------------------------------- /core/util/stdlib.c: -------------------------------------------------------------------------------- 1 | 2 | int strlen(char* str) 3 | { 4 | char* p; 5 | int result = 0; 6 | for(p = str; *p; p++) { 7 | result++; 8 | } 9 | return result; 10 | } 11 | 12 | char* strcpy(char* dest, char* src) 13 | { 14 | char* result = dest; 15 | while(*src) { 16 | *dest = *src; 17 | dest++, src++; 18 | } 19 | return result; 20 | } 21 | 22 | void* memcpy(void* dst, void* src, size_t size) 23 | { 24 | char* p1 = dst, *p2 = src; 25 | void* result = dst; 26 | while(size--) { 27 | *p1 = *p2; 28 | p1++, p2++; 29 | } 30 | return result; 31 | } 32 | 33 | void* memset(void* dst, int fill, size_t size) 34 | { 35 | char* p1 = dst; 36 | void* result = dst; 37 | while(size--) { 38 | *p1 = fill; 39 | p1++; 40 | } 41 | return result; 42 | } 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## pepatch 2 | 3 | A hacky tool for patching PE format binaries. 4 | 5 | ## Examples 6 | 7 | Please take a look at the files under example/ 8 | 9 | ## Dependencies 10 | 11 | * For pypi packages: See `requirements.txt`. Use this command to install all the dependencies: 12 | 13 | ``` 14 | pip install -r requirements.txt 15 | ``` 16 | * [pefile](https://github.com/erocarrera/pefile): This project contains a slightly modified version of `pefile` module for better usage. 17 | 18 | ## Few notes 19 | 20 | * The idea comes from [patchkit](https://github.com/lunixbochs/patchkit) after I found this fascinating small tool. 21 | * More features will be added in future. 22 | * This project is not thoroughly tested, and as you know, patching PE files can sometimes be clumsy and error-prone, so **ALWAYS** keep a copy of backup before applying any patch to the binary. 23 | 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 marche147 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /dependency/ordlookup/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | import sys 3 | from . import ws2_32 4 | from . import oleaut32 5 | 6 | ''' 7 | A small module for keeping a database of ordinal to symbol 8 | mappings for DLLs which frequently get linked without symbolic 9 | infoz. 10 | ''' 11 | 12 | ords = { 13 | b'ws2_32.dll': ws2_32.ord_names, 14 | b'wsock32.dll': ws2_32.ord_names, 15 | b'oleaut32.dll': oleaut32.ord_names, 16 | } 17 | 18 | PY3 = sys.version_info > (3,) 19 | 20 | if PY3: 21 | def formatOrdString(ord_val): 22 | return 'ord{}'.format(ord_val).encode() 23 | else: 24 | def formatOrdString(ord_val): 25 | return b'ord%d' % ord_val 26 | 27 | 28 | def ordLookup(libname, ord_val, make_name=False): 29 | ''' 30 | Lookup a name for the given ordinal if it's in our 31 | database. 32 | ''' 33 | names = ords.get(libname.lower()) 34 | if names is None: 35 | if make_name is True: 36 | return formatOrdString(ord_val) 37 | return None 38 | name = names.get(ord_val) 39 | if name is None: 40 | return formatOrdString(ord_val) 41 | return name 42 | -------------------------------------------------------------------------------- /patch.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | # -*- coding: utf-8 -*- 3 | 4 | from __future__ import print_function 5 | import sys 6 | import argparse 7 | from core.patcher import Patcher 8 | import os 9 | 10 | parser = argparse.ArgumentParser("A hacky tool for PE patching.") 11 | parser.add_argument('target', help="target file being patched") 12 | parser.add_argument('patchscript', help="patcher script") 13 | parser.add_argument("-o", nargs=1, help="output file path", action='store', dest='output', default=None, metavar=('output_file')) 14 | parser.add_argument("--cflags", nargs='+', help="cflags passed to the compiler", dest='cflags') 15 | 16 | def main(argv): 17 | args = parser.parse_args(argv[1:]) 18 | target = args.target 19 | dirname = os.path.dirname(args.patchscript) 20 | sys.path.insert(0, dirname) 21 | patchscript = os.path.basename(args.patchscript).rstrip('.py') 22 | output = args.output 23 | if not output: 24 | output = target + '.patched' 25 | cflags = args.cflags 26 | 27 | patcher = Patcher(target, cflags) 28 | # do it 29 | getattr(__import__(patchscript), 'patch')(patcher) 30 | 31 | patcher.save(output) 32 | return 0 33 | 34 | sys.exit(main(sys.argv)) 35 | -------------------------------------------------------------------------------- /core/compiler.py: -------------------------------------------------------------------------------- 1 | 2 | import log 3 | import subprocess 4 | import os 5 | 6 | compiler_version = '' 7 | DEVNULL = open(os.devnull, 'w') 8 | 9 | def clean(asm): 10 | strip = ( 11 | '.macosx_version_min', 12 | '.subsections_via_symbols', 13 | '.align', 14 | '.globl', 15 | '.weak_definition', 16 | '.p2align', 17 | '.cfi', 18 | '.file', 19 | '.section', 20 | '.intel_syntax', 21 | '#', 22 | ) 23 | asmcode = [] 24 | for line in asm.split('\n'): 25 | line = line.strip() 26 | if line.startswith(strip): 27 | continue 28 | asmcode.append(line) 29 | return '\n'.join(asmcode) 30 | 31 | def compile(code, arch='x86', extra_cflags=[]): 32 | global compiler_version 33 | cflags = ['-nostdlib', '-mno-sse', '-masm=intel', '-std=c99', '-fno-stack-protector', '-fno-jump-tables', '-fno-pic', '-fno-asynchronous-unwind-tables', '-Wno-incompatible-library-redeclaration'] 34 | 35 | if not compiler_version: 36 | p = subprocess.Popen(["gcc", "--version"], stdout=subprocess.PIPE, stderr=DEVNULL) 37 | compiler_version, _ = p.communicate() 38 | 39 | if 'gcc' in compiler_version and not 'clang' in compiler_version: 40 | cflags += ['-fleading-underscore', '-fno-toplevel-reorder'] 41 | 42 | if arch == 'x86': 43 | cflags.append('-m32') 44 | 45 | if extra_cflags: 46 | cflags += extra_cflags 47 | p = subprocess.Popen(['gcc', '-xc', '-S', '-o-', '-'] + cflags, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 48 | asm, err = p.communicate(code) 49 | if 'error:' in err.lower(): 50 | raise Exception(err) 51 | elif err: 52 | log.warn("Compiler warning: " + err) 53 | 54 | return clean(asm) 55 | 56 | 57 | -------------------------------------------------------------------------------- /core/assemble.py: -------------------------------------------------------------------------------- 1 | 2 | import capstone 3 | import keystone 4 | 5 | class Assembler(object): 6 | def __init__(self): 7 | self.cs = capstone.Cs(self.csmode[0], self.csmode[1]) 8 | self.ks = keystone.Ks(self.ksmode[0], self.ksmode[1]) 9 | return 10 | 11 | @staticmethod 12 | def _flatten(x): 13 | return ''.join(map(chr, x)) 14 | 15 | def asm(self, *args, **kwargs): 16 | return self._flatten(self.ks.asm(*args, **kwargs)[0]) 17 | 18 | def disasm(self, *args, **kwargs): 19 | return self.cs.disasm(*args, **kwargs) 20 | 21 | def jmp(self, target, *args, **kwargs): 22 | raise NotImplementedError("Abstract class") 23 | 24 | def call(self, target, *args, **kwargs): 25 | raise NotImplementedError("Abstract class") 26 | 27 | class X86Assembler(Assembler): 28 | csmode = (capstone.CS_ARCH_X86, capstone.CS_MODE_32) 29 | ksmode = (keystone.KS_ARCH_X86, keystone.KS_MODE_32) 30 | def jmp(self, target, *args, **kwargs): 31 | return self.asm("jmp {}".format(target), *args, **kwargs) 32 | 33 | def call(self, target, *args, **kwargs): 34 | return self.asm("call {}".format(target), *args, **kwargs) 35 | 36 | class X64Assembler(X86Assembler): 37 | csmode = (capstone.CS_ARCH_X86, capstone.CS_MODE_64) 38 | ksmode = (keystone.KS_ARCH_X86, keystone.KS_MODE_64) 39 | 40 | class ARMAssembler(Assembler): 41 | csmode = (capstone.CS_ARCH_ARM, capstone.CS_MODE_ARM) 42 | ksmode = (keystone.KS_ARCH_ARM, keystone.KS_MODE_ARM) 43 | 44 | def assembler(arch='x86'): 45 | asmdict = { 46 | 'x86': X86Assembler, 47 | 'amd64': X64Assembler, 48 | 'arm': ARMAssembler 49 | } 50 | if arch in asmdict: 51 | return asmdict[arch]() 52 | raise NotImplementedError("Support for arch {} is not implemented atm".format(arch)) 53 | 54 | __all__ = ["assembler"] 55 | -------------------------------------------------------------------------------- /core/patcher.py: -------------------------------------------------------------------------------- 1 | 2 | from binary import * 3 | from assemble import * 4 | from linker import * 5 | import util 6 | import compiler 7 | import log 8 | 9 | class Patcher(object): 10 | 11 | def __init__(self, filename, cflags=[]): 12 | self.binary = Binary(filename) 13 | self.linker = Linker(self.binary.arch, self, cflags) 14 | 15 | util.declare(self.linker) 16 | return 17 | 18 | def save(self, filename): 19 | return self.binary.save(filename) 20 | 21 | def _compile(self, *args, **kwargs): 22 | data = "" 23 | baseaddr = self.binary.next_alloc 24 | if kwargs.has_key("base"): 25 | baseaddr = kwargs["base"] 26 | 27 | if kwargs.has_key("asm"): 28 | code = self.linker.preasm(kwargs['asm']) 29 | if not kwargs.has_key("base"): baseaddr = self.binary.next_alloc # if we don't specify a base addr, we need to update baseaddr after linker preasm 30 | data = self.linker.assembler.asm(code, addr=baseaddr) 31 | elif kwargs.has_key("hex"): 32 | data = kwargs["hex"].decode('hex') 33 | elif kwargs.has_key("raw"): 34 | data = kwargs["raw"] 35 | elif kwargs.has_key("jmp"): 36 | data = self.linker.assembler.jmp(kwargs["jmp"], addr=baseaddr) 37 | elif kwargs.has_key("call"): 38 | data = self.linker.assembler.call(kwargs["call"], addr=baseaddr) 39 | elif kwargs.has_key("c"): 40 | code = kwargs["c"] 41 | asm = self.linker.compile(code) 42 | if not kwargs.has_key("base"): baseaddr = self.binary.next_alloc 43 | data = self.linker.assembler.asm(asm, addr=baseaddr) 44 | 45 | return bytes(data) 46 | 47 | def inject(self, *args, **kwargs): 48 | data = self._compile(*args, **kwargs) 49 | nextva = self.binary.alloc(len(data)) 50 | self.binary.writeva(nextva, data) 51 | log.success("Injected @ 0x%x"%(nextva)) 52 | return nextva 53 | 54 | def patch(self, va, *args, **kwargs): 55 | log.info("Patching @ 0x%x"%(va)) 56 | data = self._compile(base=va, *args, **kwargs) 57 | self.binary.writeva(va, data) 58 | return True 59 | 60 | def define(self, symbol, va): 61 | log.info("Defined %s @ 0x%x"%(symbol, va)) 62 | self.linker.addsym(symbol, va) 63 | return True 64 | 65 | def declare(self, ccodes, header): 66 | return self.linker.decl(ccodes, header) 67 | 68 | -------------------------------------------------------------------------------- /dependency/ordlookup/ws2_32.py: -------------------------------------------------------------------------------- 1 | 2 | ord_names = { 3 | 1: b'accept', 4 | 2: b'bind', 5 | 3: b'closesocket', 6 | 4: b'connect', 7 | 5: b'getpeername', 8 | 6: b'getsockname', 9 | 7: b'getsockopt', 10 | 8: b'htonl', 11 | 9: b'htons', 12 | 10: b'ioctlsocket', 13 | 11: b'inet_addr', 14 | 12: b'inet_ntoa', 15 | 13: b'listen', 16 | 14: b'ntohl', 17 | 15: b'ntohs', 18 | 16: b'recv', 19 | 17: b'recvfrom', 20 | 18: b'select', 21 | 19: b'send', 22 | 20: b'sendto', 23 | 21: b'setsockopt', 24 | 22: b'shutdown', 25 | 23: b'socket', 26 | 24: b'GetAddrInfoW', 27 | 25: b'GetNameInfoW', 28 | 26: b'WSApSetPostRoutine', 29 | 27: b'FreeAddrInfoW', 30 | 28: b'WPUCompleteOverlappedRequest', 31 | 29: b'WSAAccept', 32 | 30: b'WSAAddressToStringA', 33 | 31: b'WSAAddressToStringW', 34 | 32: b'WSACloseEvent', 35 | 33: b'WSAConnect', 36 | 34: b'WSACreateEvent', 37 | 35: b'WSADuplicateSocketA', 38 | 36: b'WSADuplicateSocketW', 39 | 37: b'WSAEnumNameSpaceProvidersA', 40 | 38: b'WSAEnumNameSpaceProvidersW', 41 | 39: b'WSAEnumNetworkEvents', 42 | 40: b'WSAEnumProtocolsA', 43 | 41: b'WSAEnumProtocolsW', 44 | 42: b'WSAEventSelect', 45 | 43: b'WSAGetOverlappedResult', 46 | 44: b'WSAGetQOSByName', 47 | 45: b'WSAGetServiceClassInfoA', 48 | 46: b'WSAGetServiceClassInfoW', 49 | 47: b'WSAGetServiceClassNameByClassIdA', 50 | 48: b'WSAGetServiceClassNameByClassIdW', 51 | 49: b'WSAHtonl', 52 | 50: b'WSAHtons', 53 | 51: b'gethostbyaddr', 54 | 52: b'gethostbyname', 55 | 53: b'getprotobyname', 56 | 54: b'getprotobynumber', 57 | 55: b'getservbyname', 58 | 56: b'getservbyport', 59 | 57: b'gethostname', 60 | 58: b'WSAInstallServiceClassA', 61 | 59: b'WSAInstallServiceClassW', 62 | 60: b'WSAIoctl', 63 | 61: b'WSAJoinLeaf', 64 | 62: b'WSALookupServiceBeginA', 65 | 63: b'WSALookupServiceBeginW', 66 | 64: b'WSALookupServiceEnd', 67 | 65: b'WSALookupServiceNextA', 68 | 66: b'WSALookupServiceNextW', 69 | 67: b'WSANSPIoctl', 70 | 68: b'WSANtohl', 71 | 69: b'WSANtohs', 72 | 70: b'WSAProviderConfigChange', 73 | 71: b'WSARecv', 74 | 72: b'WSARecvDisconnect', 75 | 73: b'WSARecvFrom', 76 | 74: b'WSARemoveServiceClass', 77 | 75: b'WSAResetEvent', 78 | 76: b'WSASend', 79 | 77: b'WSASendDisconnect', 80 | 78: b'WSASendTo', 81 | 79: b'WSASetEvent', 82 | 80: b'WSASetServiceA', 83 | 81: b'WSASetServiceW', 84 | 82: b'WSASocketA', 85 | 83: b'WSASocketW', 86 | 84: b'WSAStringToAddressA', 87 | 85: b'WSAStringToAddressW', 88 | 86: b'WSAWaitForMultipleEvents', 89 | 87: b'WSCDeinstallProvider', 90 | 88: b'WSCEnableNSProvider', 91 | 89: b'WSCEnumProtocols', 92 | 90: b'WSCGetProviderPath', 93 | 91: b'WSCInstallNameSpace', 94 | 92: b'WSCInstallProvider', 95 | 93: b'WSCUnInstallNameSpace', 96 | 94: b'WSCUpdateProvider', 97 | 95: b'WSCWriteNameSpaceOrder', 98 | 96: b'WSCWriteProviderOrder', 99 | 97: b'freeaddrinfo', 100 | 98: b'getaddrinfo', 101 | 99: b'getnameinfo', 102 | 101: b'WSAAsyncSelect', 103 | 102: b'WSAAsyncGetHostByAddr', 104 | 103: b'WSAAsyncGetHostByName', 105 | 104: b'WSAAsyncGetProtoByNumber', 106 | 105: b'WSAAsyncGetProtoByName', 107 | 106: b'WSAAsyncGetServByPort', 108 | 107: b'WSAAsyncGetServByName', 109 | 108: b'WSACancelAsyncRequest', 110 | 109: b'WSASetBlockingHook', 111 | 110: b'WSAUnhookBlockingHook', 112 | 111: b'WSAGetLastError', 113 | 112: b'WSASetLastError', 114 | 113: b'WSACancelBlockingCall', 115 | 114: b'WSAIsBlocking', 116 | 115: b'WSAStartup', 117 | 116: b'WSACleanup', 118 | 151: b'__WSAFDIsSet', 119 | 500: b'WEP', 120 | } 121 | -------------------------------------------------------------------------------- /core/linker.py: -------------------------------------------------------------------------------- 1 | 2 | import re 3 | import compiler 4 | import log 5 | from assemble import * 6 | 7 | funcdef_re = r'^(?P(?P[^\s].+?(?P%s)(?P\(.*?\)))\s*{(?P(.|\n)+?)^})$' 8 | 9 | class Linker(object): 10 | 11 | def __init__(self, arch, patcher, cflags=[]): 12 | self.symtable = {} # dict (key: function name, value: function address) 13 | self.header = [] 14 | self.declare = {} # declared c functions, [name] = code 15 | self.arch = arch 16 | self.assembler = assembler(arch) 17 | self.extra_cflags = cflags 18 | self.patcher = patcher 19 | return 20 | 21 | def addsym(self, sym, addr): 22 | self.symtable[sym] = addr 23 | return 24 | 25 | def resolve(self, sym): 26 | if sym in self.symtable: 27 | return self.symtable[sym] 28 | if sym in self.declare: 29 | return self.compile_dependecy(sym, self.declare[sym]) 30 | return None 31 | 32 | def preasm(self, asmcode): 33 | # search for direct jmp/call 34 | # e.g. jmp _exit -> (looks for symbol exit) 35 | refs = [] 36 | jmp_ref = re.compile(r'\b(j|J)[a-zA-Z]+\s+_(\w+)\b') 37 | call_ref = re.compile(r'\b(call|CALL)\s+_(\w+)\b') 38 | for line in asmcode.split('\n'): 39 | line = line.strip() 40 | match = jmp_ref.match(line) 41 | if match: 42 | refs.append(match.groups()[1]) 43 | else: 44 | match = call_ref.match(line) 45 | if match: 46 | refs.append(match.groups()[1]) 47 | 48 | for ref in refs: 49 | find_ref = r'\b_%s\b' % (re.escape(ref)) 50 | addr = self.resolve(ref) 51 | if not addr: 52 | raise Exception("Symbol %s not found!".format(ref)) 53 | 54 | if re.search(find_ref, asmcode): 55 | asmcode = re.sub(find_ref, '0x%x' % addr, asmcode) 56 | 57 | return asmcode 58 | 59 | def prec(self, ccode): 60 | result = [] 61 | for line in ccode.split('\n'): 62 | line = line.strip() 63 | result.append(line) 64 | return '\n'.join(result) 65 | 66 | def compile_dependecy(self, sym, code): 67 | code = self.prec(code) 68 | match = re.search(funcdef_re % sym, code, re.MULTILINE) 69 | if not match: 70 | raise Exception("Function definition not found!") 71 | 72 | result = match.groupdict() 73 | code = result["all"] 74 | ccode = "\n".join(self.header) + code 75 | asm = self.preasm(compiler.compile(ccode, self.arch, self.extra_cflags)) 76 | bincode = self.assembler.asm(asm, addr=self.patcher.binary.next_alloc) 77 | addr = self.patcher.inject(raw=bincode) 78 | self.addsym(sym, addr) 79 | log.success("Resolved %s @ 0x%x" % (sym, addr)) 80 | return addr 81 | 82 | def compile(self, code): 83 | code = self.prec(code) 84 | match = re.search(funcdef_re % '\w+', code, re.MULTILINE) 85 | if not match: 86 | raise Exception("Function definition not found!") 87 | 88 | result = match.groupdict() 89 | code = result["all"] 90 | ccode = '\n'.join(self.header) + code 91 | asm = self.preasm(compiler.compile(ccode, self.arch, self.extra_cflags)) 92 | return asm 93 | 94 | def decl(self, ccodes, header=''): 95 | if header: self.addheader(header) 96 | matches = re.findall(funcdef_re % '\w+', ccodes, re.MULTILINE) 97 | for match in matches: 98 | code = match[0] 99 | name = match[2] 100 | self.declare[name] = code 101 | return 102 | 103 | def addheader(self, header): 104 | return self.header.append(header) 105 | 106 | __all__ = ["Linker"] 107 | -------------------------------------------------------------------------------- /core/binary.py: -------------------------------------------------------------------------------- 1 | from ctypes import * 2 | from dependency import pefile 3 | 4 | class Binary(object): 5 | 6 | PAGE_SIZE = 0x1000 7 | DEFAULT_AMPLIFY_SIZE = 0x2000 8 | 9 | def __init__(self, filename): 10 | self.pefile = pefile.PE(filename) 11 | 12 | # HACK: there's currently certain ways to inject code into PE 13 | # 1. adding a section (requires gaps between section header and the first section) 14 | # 2. append code to the last section 15 | # ... 16 | # each method has it's own drawbacks 17 | result, section = self._valid() 18 | if not result: 19 | raise Exception("Malformed PE that's not valid for patching") 20 | 21 | # remap the pefile 22 | filesize = len(self.pefile) 23 | filedata = str(self.pefile.data) 24 | newsize = filesize + self.roundup(self.DEFAULT_AMPLIFY_SIZE, self.file_alignment) 25 | filedata = filedata.ljust(newsize, "\x00") 26 | self.pefile.close() 27 | self.pefile = pefile.PE(data=filedata) 28 | result, section = self._valid(second=True) 29 | if not result: 30 | raise Exception("????!!!!dafuq") 31 | 32 | # make the section rwx and expand it 33 | section.Characteristics |= (pefile.SECTION_CHARACTERISTICS['IMAGE_SCN_MEM_READ'] + pefile.SECTION_CHARACTERISTICS['IMAGE_SCN_MEM_WRITE'] + pefile.SECTION_CHARACTERISTICS['IMAGE_SCN_MEM_EXECUTE']) 34 | self.patch_foffset = section.SizeOfRawData + section.PointerToRawData 35 | section.SizeOfRawData += self.roundup(self.DEFAULT_AMPLIFY_SIZE, self.file_alignment) 36 | #section.Misc_VirtualSize = section.SizeOfRawData 37 | self.patch_alloc = self.patch_foffset 38 | 39 | return 40 | 41 | @property 42 | def file_alignment(self): 43 | return self.pefile.OPTIONAL_HEADER.FileAlignment 44 | 45 | @property 46 | def section_alignment(self): 47 | return self.pefile.OPTIONAL_HEADER.SectionAlignment 48 | 49 | @property 50 | def sections(self): 51 | return self.pefile.sections 52 | 53 | @property 54 | def base(self): 55 | return self.pefile.OPTIONAL_HEADER.ImageBase 56 | 57 | @staticmethod 58 | def roundup(x, align): 59 | return ((x + align - 1) // align) * align 60 | 61 | @staticmethod 62 | def rounddown(x, align): 63 | return (x // align) * align 64 | 65 | def save(self, filename): 66 | return self.pefile.write(filename) 67 | 68 | # return va 69 | def alloc(self, size): 70 | if self.patch_alloc - self.patch_foffset + size >= self.DEFAULT_AMPLIFY_SIZE: 71 | raise Exception("No more space for injection code") 72 | r = self.patch_alloc 73 | self.patch_alloc += size 74 | return self.offset2rva(r) + self.base 75 | 76 | def close(self): 77 | self.pefile.close() 78 | return 79 | 80 | @property 81 | def next_alloc(self): 82 | return self.offset2rva(self.patch_alloc) + self.base 83 | 84 | def _valid(self, second=False): 85 | """ 86 | Checks if the PE file is valid for patching 87 | Several situations not available for patching : 88 | 1. When appending data will cause section overlapping 89 | 90 | params: 91 | @second - if this is the second validate operation, where binary got amplified so that we dont need the last check 92 | """ 93 | 94 | last_section = None 95 | last_mem_section = None 96 | foffset = 0 97 | voffset = 0 98 | for section in self.sections: 99 | if section.PointerToRawData > foffset: 100 | last_section = section 101 | foffset = section.PointerToRawData 102 | if section.VirtualAddress > voffset: 103 | last_mem_section = section 104 | voffset = section.VirtualAddress 105 | 106 | # no overlapping! 107 | if last_mem_section != last_section: 108 | return False, None 109 | if not second and last_section.PointerToRawData + last_section.SizeOfRawData != len(self.pefile): 110 | return False, None 111 | 112 | return True, last_section 113 | 114 | @property 115 | def arch(self): 116 | machine_type = self.pefile.FILE_HEADER.Machine 117 | if machine_type == pefile.MACHINE_TYPE['IMAGE_FILE_MACHINE_I386']: 118 | return 'x86' 119 | elif machine_type == pefile.MACHINE_TYPE['IMAGE_FILE_MACHINE_AMD64']: 120 | return 'amd64' 121 | elif machine_type == pefile.MACHINE_TYPE['IMAGE_FILE_MACHINE_ARM'] or machine_type == pefile.MACHINE_TYPE['IMAGE_FILE_MACHINE_ARMNT']: 122 | return 'arm' 123 | raise Exception("Unknown or not supported architecture") 124 | 125 | def readva(self, va, nbytes): 126 | return self.readrva(va - self.base, nbytes) 127 | 128 | def writeva(self, va, data): 129 | return self.writerva(va - self.base, data) 130 | 131 | def readrva(self, rva, nbytes): 132 | return self.pefile.get_bytes_at_rva(rva, nbytes) 133 | 134 | def writerva(self, rva, data): 135 | return self.pefile.set_bytes_at_rva(rva, data) 136 | 137 | def offset2rva(self, offset): 138 | return self.pefile.get_rva_from_offset(offset) 139 | 140 | def rva2offset(self, offset): 141 | return self.pefile.get_offset_from_rva(offset) 142 | 143 | -------------------------------------------------------------------------------- /dependency/ordlookup/oleaut32.py: -------------------------------------------------------------------------------- 1 | ord_names = { 2 | 2: b'SysAllocString', 3 | 3: b'SysReAllocString', 4 | 4: b'SysAllocStringLen', 5 | 5: b'SysReAllocStringLen', 6 | 6: b'SysFreeString', 7 | 7: b'SysStringLen', 8 | 8: b'VariantInit', 9 | 9: b'VariantClear', 10 | 10: b'VariantCopy', 11 | 11: b'VariantCopyInd', 12 | 12: b'VariantChangeType', 13 | 13: b'VariantTimeToDosDateTime', 14 | 14: b'DosDateTimeToVariantTime', 15 | 15: b'SafeArrayCreate', 16 | 16: b'SafeArrayDestroy', 17 | 17: b'SafeArrayGetDim', 18 | 18: b'SafeArrayGetElemsize', 19 | 19: b'SafeArrayGetUBound', 20 | 20: b'SafeArrayGetLBound', 21 | 21: b'SafeArrayLock', 22 | 22: b'SafeArrayUnlock', 23 | 23: b'SafeArrayAccessData', 24 | 24: b'SafeArrayUnaccessData', 25 | 25: b'SafeArrayGetElement', 26 | 26: b'SafeArrayPutElement', 27 | 27: b'SafeArrayCopy', 28 | 28: b'DispGetParam', 29 | 29: b'DispGetIDsOfNames', 30 | 30: b'DispInvoke', 31 | 31: b'CreateDispTypeInfo', 32 | 32: b'CreateStdDispatch', 33 | 33: b'RegisterActiveObject', 34 | 34: b'RevokeActiveObject', 35 | 35: b'GetActiveObject', 36 | 36: b'SafeArrayAllocDescriptor', 37 | 37: b'SafeArrayAllocData', 38 | 38: b'SafeArrayDestroyDescriptor', 39 | 39: b'SafeArrayDestroyData', 40 | 40: b'SafeArrayRedim', 41 | 41: b'SafeArrayAllocDescriptorEx', 42 | 42: b'SafeArrayCreateEx', 43 | 43: b'SafeArrayCreateVectorEx', 44 | 44: b'SafeArraySetRecordInfo', 45 | 45: b'SafeArrayGetRecordInfo', 46 | 46: b'VarParseNumFromStr', 47 | 47: b'VarNumFromParseNum', 48 | 48: b'VarI2FromUI1', 49 | 49: b'VarI2FromI4', 50 | 50: b'VarI2FromR4', 51 | 51: b'VarI2FromR8', 52 | 52: b'VarI2FromCy', 53 | 53: b'VarI2FromDate', 54 | 54: b'VarI2FromStr', 55 | 55: b'VarI2FromDisp', 56 | 56: b'VarI2FromBool', 57 | 57: b'SafeArraySetIID', 58 | 58: b'VarI4FromUI1', 59 | 59: b'VarI4FromI2', 60 | 60: b'VarI4FromR4', 61 | 61: b'VarI4FromR8', 62 | 62: b'VarI4FromCy', 63 | 63: b'VarI4FromDate', 64 | 64: b'VarI4FromStr', 65 | 65: b'VarI4FromDisp', 66 | 66: b'VarI4FromBool', 67 | 67: b'SafeArrayGetIID', 68 | 68: b'VarR4FromUI1', 69 | 69: b'VarR4FromI2', 70 | 70: b'VarR4FromI4', 71 | 71: b'VarR4FromR8', 72 | 72: b'VarR4FromCy', 73 | 73: b'VarR4FromDate', 74 | 74: b'VarR4FromStr', 75 | 75: b'VarR4FromDisp', 76 | 76: b'VarR4FromBool', 77 | 77: b'SafeArrayGetVartype', 78 | 78: b'VarR8FromUI1', 79 | 79: b'VarR8FromI2', 80 | 80: b'VarR8FromI4', 81 | 81: b'VarR8FromR4', 82 | 82: b'VarR8FromCy', 83 | 83: b'VarR8FromDate', 84 | 84: b'VarR8FromStr', 85 | 85: b'VarR8FromDisp', 86 | 86: b'VarR8FromBool', 87 | 87: b'VarFormat', 88 | 88: b'VarDateFromUI1', 89 | 89: b'VarDateFromI2', 90 | 90: b'VarDateFromI4', 91 | 91: b'VarDateFromR4', 92 | 92: b'VarDateFromR8', 93 | 93: b'VarDateFromCy', 94 | 94: b'VarDateFromStr', 95 | 95: b'VarDateFromDisp', 96 | 96: b'VarDateFromBool', 97 | 97: b'VarFormatDateTime', 98 | 98: b'VarCyFromUI1', 99 | 99: b'VarCyFromI2', 100 | 100: b'VarCyFromI4', 101 | 101: b'VarCyFromR4', 102 | 102: b'VarCyFromR8', 103 | 103: b'VarCyFromDate', 104 | 104: b'VarCyFromStr', 105 | 105: b'VarCyFromDisp', 106 | 106: b'VarCyFromBool', 107 | 107: b'VarFormatNumber', 108 | 108: b'VarBstrFromUI1', 109 | 109: b'VarBstrFromI2', 110 | 110: b'VarBstrFromI4', 111 | 111: b'VarBstrFromR4', 112 | 112: b'VarBstrFromR8', 113 | 113: b'VarBstrFromCy', 114 | 114: b'VarBstrFromDate', 115 | 115: b'VarBstrFromDisp', 116 | 116: b'VarBstrFromBool', 117 | 117: b'VarFormatPercent', 118 | 118: b'VarBoolFromUI1', 119 | 119: b'VarBoolFromI2', 120 | 120: b'VarBoolFromI4', 121 | 121: b'VarBoolFromR4', 122 | 122: b'VarBoolFromR8', 123 | 123: b'VarBoolFromDate', 124 | 124: b'VarBoolFromCy', 125 | 125: b'VarBoolFromStr', 126 | 126: b'VarBoolFromDisp', 127 | 127: b'VarFormatCurrency', 128 | 128: b'VarWeekdayName', 129 | 129: b'VarMonthName', 130 | 130: b'VarUI1FromI2', 131 | 131: b'VarUI1FromI4', 132 | 132: b'VarUI1FromR4', 133 | 133: b'VarUI1FromR8', 134 | 134: b'VarUI1FromCy', 135 | 135: b'VarUI1FromDate', 136 | 136: b'VarUI1FromStr', 137 | 137: b'VarUI1FromDisp', 138 | 138: b'VarUI1FromBool', 139 | 139: b'VarFormatFromTokens', 140 | 140: b'VarTokenizeFormatString', 141 | 141: b'VarAdd', 142 | 142: b'VarAnd', 143 | 143: b'VarDiv', 144 | 144: b'DllCanUnloadNow', 145 | 145: b'DllGetClassObject', 146 | 146: b'DispCallFunc', 147 | 147: b'VariantChangeTypeEx', 148 | 148: b'SafeArrayPtrOfIndex', 149 | 149: b'SysStringByteLen', 150 | 150: b'SysAllocStringByteLen', 151 | 151: b'DllRegisterServer', 152 | 152: b'VarEqv', 153 | 153: b'VarIdiv', 154 | 154: b'VarImp', 155 | 155: b'VarMod', 156 | 156: b'VarMul', 157 | 157: b'VarOr', 158 | 158: b'VarPow', 159 | 159: b'VarSub', 160 | 160: b'CreateTypeLib', 161 | 161: b'LoadTypeLib', 162 | 162: b'LoadRegTypeLib', 163 | 163: b'RegisterTypeLib', 164 | 164: b'QueryPathOfRegTypeLib', 165 | 165: b'LHashValOfNameSys', 166 | 166: b'LHashValOfNameSysA', 167 | 167: b'VarXor', 168 | 168: b'VarAbs', 169 | 169: b'VarFix', 170 | 170: b'OaBuildVersion', 171 | 171: b'ClearCustData', 172 | 172: b'VarInt', 173 | 173: b'VarNeg', 174 | 174: b'VarNot', 175 | 175: b'VarRound', 176 | 176: b'VarCmp', 177 | 177: b'VarDecAdd', 178 | 178: b'VarDecDiv', 179 | 179: b'VarDecMul', 180 | 180: b'CreateTypeLib2', 181 | 181: b'VarDecSub', 182 | 182: b'VarDecAbs', 183 | 183: b'LoadTypeLibEx', 184 | 184: b'SystemTimeToVariantTime', 185 | 185: b'VariantTimeToSystemTime', 186 | 186: b'UnRegisterTypeLib', 187 | 187: b'VarDecFix', 188 | 188: b'VarDecInt', 189 | 189: b'VarDecNeg', 190 | 190: b'VarDecFromUI1', 191 | 191: b'VarDecFromI2', 192 | 192: b'VarDecFromI4', 193 | 193: b'VarDecFromR4', 194 | 194: b'VarDecFromR8', 195 | 195: b'VarDecFromDate', 196 | 196: b'VarDecFromCy', 197 | 197: b'VarDecFromStr', 198 | 198: b'VarDecFromDisp', 199 | 199: b'VarDecFromBool', 200 | 200: b'GetErrorInfo', 201 | 201: b'SetErrorInfo', 202 | 202: b'CreateErrorInfo', 203 | 203: b'VarDecRound', 204 | 204: b'VarDecCmp', 205 | 205: b'VarI2FromI1', 206 | 206: b'VarI2FromUI2', 207 | 207: b'VarI2FromUI4', 208 | 208: b'VarI2FromDec', 209 | 209: b'VarI4FromI1', 210 | 210: b'VarI4FromUI2', 211 | 211: b'VarI4FromUI4', 212 | 212: b'VarI4FromDec', 213 | 213: b'VarR4FromI1', 214 | 214: b'VarR4FromUI2', 215 | 215: b'VarR4FromUI4', 216 | 216: b'VarR4FromDec', 217 | 217: b'VarR8FromI1', 218 | 218: b'VarR8FromUI2', 219 | 219: b'VarR8FromUI4', 220 | 220: b'VarR8FromDec', 221 | 221: b'VarDateFromI1', 222 | 222: b'VarDateFromUI2', 223 | 223: b'VarDateFromUI4', 224 | 224: b'VarDateFromDec', 225 | 225: b'VarCyFromI1', 226 | 226: b'VarCyFromUI2', 227 | 227: b'VarCyFromUI4', 228 | 228: b'VarCyFromDec', 229 | 229: b'VarBstrFromI1', 230 | 230: b'VarBstrFromUI2', 231 | 231: b'VarBstrFromUI4', 232 | 232: b'VarBstrFromDec', 233 | 233: b'VarBoolFromI1', 234 | 234: b'VarBoolFromUI2', 235 | 235: b'VarBoolFromUI4', 236 | 236: b'VarBoolFromDec', 237 | 237: b'VarUI1FromI1', 238 | 238: b'VarUI1FromUI2', 239 | 239: b'VarUI1FromUI4', 240 | 240: b'VarUI1FromDec', 241 | 241: b'VarDecFromI1', 242 | 242: b'VarDecFromUI2', 243 | 243: b'VarDecFromUI4', 244 | 244: b'VarI1FromUI1', 245 | 245: b'VarI1FromI2', 246 | 246: b'VarI1FromI4', 247 | 247: b'VarI1FromR4', 248 | 248: b'VarI1FromR8', 249 | 249: b'VarI1FromDate', 250 | 250: b'VarI1FromCy', 251 | 251: b'VarI1FromStr', 252 | 252: b'VarI1FromDisp', 253 | 253: b'VarI1FromBool', 254 | 254: b'VarI1FromUI2', 255 | 255: b'VarI1FromUI4', 256 | 256: b'VarI1FromDec', 257 | 257: b'VarUI2FromUI1', 258 | 258: b'VarUI2FromI2', 259 | 259: b'VarUI2FromI4', 260 | 260: b'VarUI2FromR4', 261 | 261: b'VarUI2FromR8', 262 | 262: b'VarUI2FromDate', 263 | 263: b'VarUI2FromCy', 264 | 264: b'VarUI2FromStr', 265 | 265: b'VarUI2FromDisp', 266 | 266: b'VarUI2FromBool', 267 | 267: b'VarUI2FromI1', 268 | 268: b'VarUI2FromUI4', 269 | 269: b'VarUI2FromDec', 270 | 270: b'VarUI4FromUI1', 271 | 271: b'VarUI4FromI2', 272 | 272: b'VarUI4FromI4', 273 | 273: b'VarUI4FromR4', 274 | 274: b'VarUI4FromR8', 275 | 275: b'VarUI4FromDate', 276 | 276: b'VarUI4FromCy', 277 | 277: b'VarUI4FromStr', 278 | 278: b'VarUI4FromDisp', 279 | 279: b'VarUI4FromBool', 280 | 280: b'VarUI4FromI1', 281 | 281: b'VarUI4FromUI2', 282 | 282: b'VarUI4FromDec', 283 | 283: b'BSTR_UserSize', 284 | 284: b'BSTR_UserMarshal', 285 | 285: b'BSTR_UserUnmarshal', 286 | 286: b'BSTR_UserFree', 287 | 287: b'VARIANT_UserSize', 288 | 288: b'VARIANT_UserMarshal', 289 | 289: b'VARIANT_UserUnmarshal', 290 | 290: b'VARIANT_UserFree', 291 | 291: b'LPSAFEARRAY_UserSize', 292 | 292: b'LPSAFEARRAY_UserMarshal', 293 | 293: b'LPSAFEARRAY_UserUnmarshal', 294 | 294: b'LPSAFEARRAY_UserFree', 295 | 295: b'LPSAFEARRAY_Size', 296 | 296: b'LPSAFEARRAY_Marshal', 297 | 297: b'LPSAFEARRAY_Unmarshal', 298 | 298: b'VarDecCmpR8', 299 | 299: b'VarCyAdd', 300 | 300: b'DllUnregisterServer', 301 | 301: b'OACreateTypeLib2', 302 | 303: b'VarCyMul', 303 | 304: b'VarCyMulI4', 304 | 305: b'VarCySub', 305 | 306: b'VarCyAbs', 306 | 307: b'VarCyFix', 307 | 308: b'VarCyInt', 308 | 309: b'VarCyNeg', 309 | 310: b'VarCyRound', 310 | 311: b'VarCyCmp', 311 | 312: b'VarCyCmpR8', 312 | 313: b'VarBstrCat', 313 | 314: b'VarBstrCmp', 314 | 315: b'VarR8Pow', 315 | 316: b'VarR4CmpR8', 316 | 317: b'VarR8Round', 317 | 318: b'VarCat', 318 | 319: b'VarDateFromUdateEx', 319 | 322: b'GetRecordInfoFromGuids', 320 | 323: b'GetRecordInfoFromTypeInfo', 321 | 325: b'SetVarConversionLocaleSetting', 322 | 326: b'GetVarConversionLocaleSetting', 323 | 327: b'SetOaNoCache', 324 | 329: b'VarCyMulI8', 325 | 330: b'VarDateFromUdate', 326 | 331: b'VarUdateFromDate', 327 | 332: b'GetAltMonthNames', 328 | 333: b'VarI8FromUI1', 329 | 334: b'VarI8FromI2', 330 | 335: b'VarI8FromR4', 331 | 336: b'VarI8FromR8', 332 | 337: b'VarI8FromCy', 333 | 338: b'VarI8FromDate', 334 | 339: b'VarI8FromStr', 335 | 340: b'VarI8FromDisp', 336 | 341: b'VarI8FromBool', 337 | 342: b'VarI8FromI1', 338 | 343: b'VarI8FromUI2', 339 | 344: b'VarI8FromUI4', 340 | 345: b'VarI8FromDec', 341 | 346: b'VarI2FromI8', 342 | 347: b'VarI2FromUI8', 343 | 348: b'VarI4FromI8', 344 | 349: b'VarI4FromUI8', 345 | 360: b'VarR4FromI8', 346 | 361: b'VarR4FromUI8', 347 | 362: b'VarR8FromI8', 348 | 363: b'VarR8FromUI8', 349 | 364: b'VarDateFromI8', 350 | 365: b'VarDateFromUI8', 351 | 366: b'VarCyFromI8', 352 | 367: b'VarCyFromUI8', 353 | 368: b'VarBstrFromI8', 354 | 369: b'VarBstrFromUI8', 355 | 370: b'VarBoolFromI8', 356 | 371: b'VarBoolFromUI8', 357 | 372: b'VarUI1FromI8', 358 | 373: b'VarUI1FromUI8', 359 | 374: b'VarDecFromI8', 360 | 375: b'VarDecFromUI8', 361 | 376: b'VarI1FromI8', 362 | 377: b'VarI1FromUI8', 363 | 378: b'VarUI2FromI8', 364 | 379: b'VarUI2FromUI8', 365 | 401: b'OleLoadPictureEx', 366 | 402: b'OleLoadPictureFileEx', 367 | 411: b'SafeArrayCreateVector', 368 | 412: b'SafeArrayCopyData', 369 | 413: b'VectorFromBstr', 370 | 414: b'BstrFromVector', 371 | 415: b'OleIconToCursor', 372 | 416: b'OleCreatePropertyFrameIndirect', 373 | 417: b'OleCreatePropertyFrame', 374 | 418: b'OleLoadPicture', 375 | 419: b'OleCreatePictureIndirect', 376 | 420: b'OleCreateFontIndirect', 377 | 421: b'OleTranslateColor', 378 | 422: b'OleLoadPictureFile', 379 | 423: b'OleSavePictureFile', 380 | 424: b'OleLoadPicturePath', 381 | 425: b'VarUI4FromI8', 382 | 426: b'VarUI4FromUI8', 383 | 427: b'VarI8FromUI8', 384 | 428: b'VarUI8FromI8', 385 | 429: b'VarUI8FromUI1', 386 | 430: b'VarUI8FromI2', 387 | 431: b'VarUI8FromR4', 388 | 432: b'VarUI8FromR8', 389 | 433: b'VarUI8FromCy', 390 | 434: b'VarUI8FromDate', 391 | 435: b'VarUI8FromStr', 392 | 436: b'VarUI8FromDisp', 393 | 437: b'VarUI8FromBool', 394 | 438: b'VarUI8FromI1', 395 | 439: b'VarUI8FromUI2', 396 | 440: b'VarUI8FromUI4', 397 | 441: b'VarUI8FromDec', 398 | 442: b'RegisterTypeLibForUser', 399 | 443: b'UnRegisterTypeLibForUser', 400 | } 401 | --------------------------------------------------------------------------------