Exemplo n.º 1
0
    def native_to_win32_pathname(name):
        """
        @type  name: str
        @param name: Native (NT) absolute pathname.

        @rtype:  str
        @return: Win32 absolute pathname.
        """
        # XXX TODO
        # There are probably some native paths that
        # won't be converted by this naive approach.
        if name.startswith(compat.b("\\")):
            if name.startswith(compat.b("\\??\\")):
                name = name[4:]
            elif name.startswith(compat.b("\\SystemRoot\\")):
                system_root_path = os.environ['SYSTEMROOT']
                if system_root_path.endswith('\\'):
                    system_root_path = system_root_path[:-1]
                name = system_root_path + name[11:]
            else:
                for drive_number in compat.xrange(ord('A'), ord('Z') + 1):
                    drive_letter = '%c:' % drive_number
                    try:
                        device_native_path = win32.QueryDosDevice(drive_letter)
                    except WindowsError:
                        e = sys.exc_info()[1]
                        if e.winerror in (win32.ERROR_FILE_NOT_FOUND, \
                                                 win32.ERROR_PATH_NOT_FOUND):
                            continue
                        raise
                    if not device_native_path.endswith(compat.b('\\')):
                        device_native_path += compat.b('\\')
                    if name.startswith(device_native_path):
                        name = drive_letter + compat.b('\\') + \
                                              name[ len(device_native_path) : ]
                        break
        return name
Exemplo n.º 2
0
    def native_to_win32_pathname(name):
        """
        @type  name: str
        @param name: Native (NT) absolute pathname.

        @rtype:  str
        @return: Win32 absolute pathname.
        """
        # XXX TODO
        # There are probably some native paths that
        # won't be converted by this naive approach.
        if name.startswith(compat.b("\\")):
            if name.startswith(compat.b("\\??\\")):
                name = name[4:]
            elif name.startswith(compat.b("\\SystemRoot\\")):
                system_root_path = os.environ['SYSTEMROOT']
                if system_root_path.endswith('\\'):
                    system_root_path = system_root_path[:-1]
                name = system_root_path + name[11:]
            else:
                for drive_number in compat.xrange(ord('A'), ord('Z') + 1):
                    drive_letter = '%c:' % drive_number
                    try:
                        device_native_path = win32.QueryDosDevice(drive_letter)
                    except WindowsError:
                        e = sys.exc_info()[1]
                        if e.winerror in (win32.ERROR_FILE_NOT_FOUND, \
                                                 win32.ERROR_PATH_NOT_FOUND):
                            continue
                        raise
                    if not device_native_path.endswith(compat.b('\\')):
                        device_native_path += compat.b('\\')
                    if name.startswith(device_native_path):
                        name = drive_letter + compat.b('\\') + \
                                              name[ len(device_native_path) : ]
                        break
        return name
 def __init__(self, is_64):
     from winappdbg import compat
     self.is_64 = is_64
     self._code = []
     if not is_64:
         self._translations = {
             'push esi': compat.b('\x56'),
             'push eax': compat.b('\x50'),
             'push ebp': compat.b('\x55'),
             'push ebx': compat.b('\x53'),
             'pop esi': compat.b('\x5E'),
             'pop eax': compat.b('\x58'),
             'pop ebp': compat.b('\x5D'),
             'pop ebx': compat.b('\x5B'),
             'mov esi': compat.b('\xBE'),
             'mov eax': compat.b('\xB8'),
             'mov ebp': compat.b('\xBD'),
             'mov ebx': compat.b('\xBB'),
             'call ebp': compat.b('\xFF\xD5'),
             'call eax': compat.b('\xFF\xD0'),
             'call ebx': compat.b('\xFF\xD3'),
             'mov ebx,eax': compat.b('\x89\xC3'),
             'mov eax,ebx': compat.b('\x89\xD8'),
             'mov ebp,esp': compat.b('\x89\xE5'),
             'mov esp,ebp': compat.b('\x89\xEC'),
             'push dword': compat.b('\x68'),
             'mov ebp,eax': compat.b('\x89\xC5'),
             'mov eax,ebp': compat.b('\x89\xE8'),
             'ret': compat.b('\xc3'),
         }
     else:
         # Translate 64 bits
         self._translations = {
             'push rsi': compat.b('\x56'),
             'push rax': compat.b('\x50'),
             'push rbp': compat.b('\x55'),
             'push rbx': compat.b('\x53'),
             'push rsp': compat.b('\x54'),
             'push rdi': compat.b('\x57'),
             'pop rsi': compat.b('\x5E'),
             'pop rax': compat.b('\x58'),
             'pop rbp': compat.b('\x5D'),
             'pop rbx': compat.b('\x5B'),
             'pop rsp': compat.b('\x5C'),
             'pop rdi': compat.b('\x5F'),
             'mov rsi': compat.b('\x48\xBE'),
             'mov rax': compat.b('\x48\xB8'),
             'mov rbp': compat.b('\x48\xBD'),
             'mov rbx': compat.b('\x48\xBB'),
             'mov rdi': compat.b('\x48\xBF'),
             'mov rcx': compat.b('\x48\xB9'),
             'mov rdx': compat.b('\x48\xBA'),
             'call rbp': compat.b('\xFF\xD5'),
             'call rax': compat.b('\xFF\xD0'),
             'call rbx': compat.b('\xFF\xD3'),
             'mov rbx,rax': compat.b('\x48\x89\xC3'),
             'mov rax,rbx': compat.b('\x48\x89\xD8'),
             'mov rbp,rsp': compat.b('\x48\x89\xE5'),
             'mov rsp,rbp': compat.b('\x48\x89\xEC'),
             'mov rcx,rbp': compat.b('\x48\x89\xE9'),
             'mov rbp,rax': compat.b('\x48\x89\xC5'),
             'mov rax,rbp': compat.b('\x48\x89\xE8'),
             'mov rdi,rbp': compat.b('\x48\x89\xEF'),
             'ret': compat.b('\xc3'),
         }
def run_python_code_windows(pid,
                            python_code,
                            connect_debugger_tracing=False,
                            show_debug_info=0):
    assert '\'' not in python_code, 'Having a single quote messes with our command.'
    from winappdbg import compat
    from winappdbg.process import Process
    if not isinstance(python_code, compat.bytes):
        python_code = compat.b(python_code)

    process = Process(pid)
    bits = process.get_bits()
    is_64 = bits == 64

    if is_64 != is_python_64bit():
        raise RuntimeError(
            "The architecture of the Python used to connect doesn't match the architecture of the target.\n"
            "Target 64 bits: %s\n"
            "Current Python 64 bits: %s" % (is_64, is_python_64bit()))

    print('Connecting to %s bits target' % (bits, ))
    assert resolve_label(process, compat.b('PyGILState_Ensure'))

    filedir = os.path.dirname(__file__)
    if is_64:
        suffix = 'amd64'
    else:
        suffix = 'x86'
    target_dll = os.path.join(filedir, 'attach_%s.dll' % suffix)
    if not os.path.exists(target_dll):
        raise RuntimeError('Could not find dll file to inject: %s' %
                           target_dll)
    print('Injecting dll')
    process.inject_dll(target_dll.encode('mbcs'))
    print('Dll injected')

    process.scan_modules()
    attach_func = resolve_label(process, compat.b('AttachAndRunPythonCode'))
    assert attach_func

    print('Allocating code in target process')
    code_address = process.malloc(len(python_code))
    assert code_address
    print('Writing code in target process')
    process.write(code_address, python_code)

    print('Allocating return value memory in target process')
    return_code_address = process.malloc(ctypes.sizeof(ctypes.c_int))
    assert return_code_address

    CONNECT_DEBUGGER = 2

    startup_info = 0
    if show_debug_info:
        SHOW_DEBUG_INFO = 1
        startup_info |= SHOW_DEBUG_INFO  # Uncomment to show debug info

    if connect_debugger_tracing:
        startup_info |= CONNECT_DEBUGGER

    process.write_int(return_code_address, startup_info)

    helper = GenShellCodeHelper(is_64)
    if is_64:
        # Interesting read: http://msdn.microsoft.com/en-us/library/ms235286.aspx
        # Overview of x64 Calling Conventions (for windows: Linux is different!)
        # Register Usage: http://msdn.microsoft.com/en-us/library/9z1stfyw.aspx
        # The registers RAX, RCX, RDX, R8, R9, R10, R11 are considered volatile and must be considered destroyed on function calls (unless otherwise safety-provable by analysis such as whole program optimization).
        #
        # The registers RBX, RBP, RDI, RSI, RSP, R12, R13, R14, and R15 are considered nonvolatile and must be saved and restored by a function that uses them.
        #
        # Important: RCX: first int argument

        with helper.push('rdi'):  # This one REALLY must be pushed/poped
            with helper.push('rsp'):
                with helper.push('rbp'):
                    with helper.push('rbx'):

                        with helper.push('rdi'):  # Note: pop is automatic.
                            helper.mov_to_register_addr(
                                'rcx', helper.pack_address(code_address))
                            helper.mov_to_register_addr(
                                'rdx',
                                helper.pack_address(return_code_address))
                            helper.mov_to_register_addr(
                                'rbx', helper.pack_address(attach_func))
                            helper.call('rbx')

    else:
        with helper.push('eax'):  # Note: pop is automatic.
            with helper.push('ebp'):
                with helper.push('ebx'):

                    with helper.preserve_stack():
                        # Put our code as a parameter in the stack (on x86, we push parameters to
                        # the stack)
                        helper.push_addr(
                            helper.pack_address(return_code_address))
                        helper.push_addr(helper.pack_address(code_address))
                        helper.mov_to_register_addr(
                            'ebx', helper.pack_address(attach_func))
                        helper.call('ebx')

    helper.ret()

    code = helper.get_code()

    # Uncomment to see the disassembled version of what we just did...
    #     with open('f.asm', 'wb') as stream:
    #         stream.write(code)
    #
    #     exe = r'x:\nasm\nasm-2.07-win32\nasm-2.07\ndisasm.exe'
    #     if is_64:
    #         arch = '64'
    #     else:
    #         arch = '32'
    #
    #     subprocess.call((exe + ' -b %s f.asm' % arch).split())

    print('Injecting code to target process')
    thread, _thread_address = process.inject_code(code, 0)

    timeout = None  # Could receive timeout in millis.
    print('Waiting for code to complete')
    thread.wait(timeout)

    return_code = process.read_int(return_code_address)
    if return_code == 0:
        print('Attach finished successfully.')
    else:
        print(
            'Error when injecting code in target process. Error code: %s (on windows)'
            % (return_code, ))

    process.free(thread.pInjectedMemory)
    process.free(code_address)
    process.free(return_code_address)
    return return_code
 def get_code(self):
     from winappdbg import compat
     return compat.b('').join(self._code)
def run_python_code_windows(pid, python_code, connect_debugger_tracing=False, show_debug_info=0):
    assert '\'' not in python_code, 'Having a single quote messes with our command.'
    from winappdbg import compat
    from winappdbg.process import Process
    if not isinstance(python_code, compat.bytes):
        python_code = compat.b(python_code)

    process = Process(pid)
    bits = process.get_bits()
    is_64 = bits == 64

    if is_64 != is_python_64bit():
        raise RuntimeError("The architecture of the Python used to connect doesn't match the architecture of the target.\n"
        "Target 64 bits: %s\n"
        "Current Python 64 bits: %s" % (is_64, is_python_64bit()))

    debug('Connecting to %s bits target' % (bits,))
    assert resolve_label(process, compat.b('PyGILState_Ensure'))


    filedir = os.path.dirname(__file__)
    if is_64:
        suffix = 'amd64'
    else:
        suffix = 'x86'
    target_dll = os.path.join(filedir, 'attach_%s.dll' % suffix)
    if not os.path.exists(target_dll):
        raise RuntimeError('Could not find dll file to inject: %s' % target_dll)
    debug('Injecting dll')
    process.inject_dll(target_dll.encode('mbcs'))
    debug('Dll injected')

    process.scan_modules()
    attach_func = resolve_label(process, compat.b('AttachAndRunPythonCode'))
    assert attach_func

    debug('Allocating code in target process')
    code_address = process.malloc(len(python_code))
    assert code_address
    debug('Writing code in target process')
    process.write(code_address, python_code)

    debug('Allocating return value memory in target process')
    return_code_address = process.malloc(ctypes.sizeof(ctypes.c_int))
    assert return_code_address

    CONNECT_DEBUGGER = 2

    startup_info = 0
    if show_debug_info:
        SHOW_DEBUG_INFO = 1
        startup_info |= SHOW_DEBUG_INFO # Uncomment to show debug info

    if connect_debugger_tracing:
        startup_info |= CONNECT_DEBUGGER

    process.write_int(return_code_address, startup_info)

    helper = GenShellCodeHelper(is_64)
    if is_64:
        # Interesting read: http://msdn.microsoft.com/en-us/library/ms235286.aspx
        # Overview of x64 Calling Conventions (for windows: Linux is different!)
        # Register Usage: http://msdn.microsoft.com/en-us/library/9z1stfyw.aspx
        # The registers RAX, RCX, RDX, R8, R9, R10, R11 are considered volatile and must be considered destroyed on function calls (unless otherwise safety-provable by analysis such as whole program optimization).
        #
        # The registers RBX, RBP, RDI, RSI, RSP, R12, R13, R14, and R15 are considered nonvolatile and must be saved and restored by a function that uses them.
        #
        # Important: RCX: first int argument

        with helper.push('rdi'):  # This one REALLY must be pushed/poped
            with helper.push('rsp'):
                with helper.push('rbp'):
                    with helper.push('rbx'):

                        with helper.push('rdi'):  # Note: pop is automatic.
                            helper.mov_to_register_addr('rcx', helper.pack_address(code_address))
                            helper.mov_to_register_addr('rdx', helper.pack_address(return_code_address))
                            helper.mov_to_register_addr('rbx', helper.pack_address(attach_func))
                            helper.call('rbx')

    else:
        with helper.push('eax'):  # Note: pop is automatic.
            with helper.push('ebp'):
                with helper.push('ebx'):

                    with helper.preserve_stack():
                        # Put our code as a parameter in the stack (on x86, we push parameters to
                        # the stack)
                        helper.push_addr(helper.pack_address(return_code_address))
                        helper.push_addr(helper.pack_address(code_address))
                        helper.mov_to_register_addr('ebx', helper.pack_address(attach_func))
                        helper.call('ebx')

    helper.ret()

    code = helper.get_code()


    # Uncomment to see the disassembled version of what we just did...
#     with open('f.asm', 'wb') as stream:
#         stream.write(code)
#
#     exe = r'x:\nasm\nasm-2.07-win32\nasm-2.07\ndisasm.exe'
#     if is_64:
#         arch = '64'
#     else:
#         arch = '32'
#
#     subprocess.call((exe + ' -b %s f.asm' % arch).split())

    debug('Injecting code to target process')
    thread, _thread_address = process.inject_code(code, 0)

    timeout = None  # Could receive timeout in millis.
    debug('Waiting for code to complete')
    thread.wait(timeout)

    return_code = process.read_int(return_code_address)
    if return_code == 0:
        print('Attach finished successfully.')
    else:
        print('Error when injecting code in target process. Error code: %s (on windows)' % (return_code,))

    process.free(thread.pInjectedMemory)
    process.free(code_address)
    process.free(return_code_address)
    return return_code
 def get_code(self):
     from winappdbg import compat
     return compat.b('').join(self._code)
    def __init__(self, is_64):
        from winappdbg import compat
        self.is_64 = is_64
        self._code = []
        if not is_64:
            self._translations = {
                'push esi': compat.b('\x56'),
                'push eax': compat.b('\x50'),
                'push ebp': compat.b('\x55'),
                'push ebx': compat.b('\x53'),

                'pop esi': compat.b('\x5E'),
                'pop eax': compat.b('\x58'),
                'pop ebp': compat.b('\x5D'),
                'pop ebx': compat.b('\x5B'),

                'mov esi': compat.b('\xBE'),
                'mov eax': compat.b('\xB8'),
                'mov ebp': compat.b('\xBD'),
                'mov ebx': compat.b('\xBB'),

                'call ebp': compat.b('\xFF\xD5'),
                'call eax': compat.b('\xFF\xD0'),
                'call ebx': compat.b('\xFF\xD3'),

                'mov ebx,eax': compat.b('\x89\xC3'),
                'mov eax,ebx': compat.b('\x89\xD8'),
                'mov ebp,esp': compat.b('\x89\xE5'),
                'mov esp,ebp': compat.b('\x89\xEC'),
                'push dword': compat.b('\x68'),

                'mov ebp,eax': compat.b('\x89\xC5'),
                'mov eax,ebp': compat.b('\x89\xE8'),

                'ret': compat.b('\xc3'),
            }
        else:
            # Translate 64 bits
            self._translations = {
                'push rsi': compat.b('\x56'),
                'push rax': compat.b('\x50'),
                'push rbp': compat.b('\x55'),
                'push rbx': compat.b('\x53'),
                'push rsp': compat.b('\x54'),
                'push rdi': compat.b('\x57'),

                'pop rsi': compat.b('\x5E'),
                'pop rax': compat.b('\x58'),
                'pop rbp': compat.b('\x5D'),
                'pop rbx': compat.b('\x5B'),
                'pop rsp': compat.b('\x5C'),
                'pop rdi': compat.b('\x5F'),

                'mov rsi': compat.b('\x48\xBE'),
                'mov rax': compat.b('\x48\xB8'),
                'mov rbp': compat.b('\x48\xBD'),
                'mov rbx': compat.b('\x48\xBB'),
                'mov rdi': compat.b('\x48\xBF'),
                'mov rcx': compat.b('\x48\xB9'),
                'mov rdx': compat.b('\x48\xBA'),

                'call rbp': compat.b('\xFF\xD5'),
                'call rax': compat.b('\xFF\xD0'),
                'call rbx': compat.b('\xFF\xD3'),

                'mov rbx,rax': compat.b('\x48\x89\xC3'),
                'mov rax,rbx': compat.b('\x48\x89\xD8'),
                'mov rbp,rsp': compat.b('\x48\x89\xE5'),
                'mov rsp,rbp': compat.b('\x48\x89\xEC'),
                'mov rcx,rbp': compat.b('\x48\x89\xE9'),

                'mov rbp,rax': compat.b('\x48\x89\xC5'),
                'mov rax,rbp': compat.b('\x48\x89\xE8'),

                'mov rdi,rbp': compat.b('\x48\x89\xEF'),

                'ret': compat.b('\xc3'),
            }
    def __init__(self, is_64):
        from winappdbg import compat

        self.is_64 = is_64
        self._code = []
        if not is_64:
            self._translations = {
                "push esi": compat.b("\x56"),
                "push eax": compat.b("\x50"),
                "push ebp": compat.b("\x55"),
                "push ebx": compat.b("\x53"),
                "pop esi": compat.b("\x5E"),
                "pop eax": compat.b("\x58"),
                "pop ebp": compat.b("\x5D"),
                "pop ebx": compat.b("\x5B"),
                "mov esi": compat.b("\xBE"),
                "mov eax": compat.b("\xB8"),
                "mov ebp": compat.b("\xBD"),
                "mov ebx": compat.b("\xBB"),
                "call ebp": compat.b("\xFF\xD5"),
                "call eax": compat.b("\xFF\xD0"),
                "call ebx": compat.b("\xFF\xD3"),
                "mov ebx,eax": compat.b("\x89\xC3"),
                "mov eax,ebx": compat.b("\x89\xD8"),
                "mov ebp,esp": compat.b("\x89\xE5"),
                "mov esp,ebp": compat.b("\x89\xEC"),
                "push dword": compat.b("\x68"),
                "mov ebp,eax": compat.b("\x89\xC5"),
                "mov eax,ebp": compat.b("\x89\xE8"),
                "ret": compat.b("\xc3"),
            }
        else:
            # Translate 64 bits
            self._translations = {
                "push rsi": compat.b("\x56"),
                "push rax": compat.b("\x50"),
                "push rbp": compat.b("\x55"),
                "push rbx": compat.b("\x53"),
                "push rsp": compat.b("\x54"),
                "push rdi": compat.b("\x57"),
                "pop rsi": compat.b("\x5E"),
                "pop rax": compat.b("\x58"),
                "pop rbp": compat.b("\x5D"),
                "pop rbx": compat.b("\x5B"),
                "pop rsp": compat.b("\x5C"),
                "pop rdi": compat.b("\x5F"),
                "mov rsi": compat.b("\x48\xBE"),
                "mov rax": compat.b("\x48\xB8"),
                "mov rbp": compat.b("\x48\xBD"),
                "mov rbx": compat.b("\x48\xBB"),
                "mov rdi": compat.b("\x48\xBF"),
                "mov rcx": compat.b("\x48\xB9"),
                "mov rdx": compat.b("\x48\xBA"),
                "call rbp": compat.b("\xFF\xD5"),
                "call rax": compat.b("\xFF\xD0"),
                "call rbx": compat.b("\xFF\xD3"),
                "mov rbx,rax": compat.b("\x48\x89\xC3"),
                "mov rax,rbx": compat.b("\x48\x89\xD8"),
                "mov rbp,rsp": compat.b("\x48\x89\xE5"),
                "mov rsp,rbp": compat.b("\x48\x89\xEC"),
                "mov rcx,rbp": compat.b("\x48\x89\xE9"),
                "mov rbp,rax": compat.b("\x48\x89\xC5"),
                "mov rax,rbp": compat.b("\x48\x89\xE8"),
                "mov rdi,rbp": compat.b("\x48\x89\xEF"),
                "ret": compat.b("\xc3"),
            }
Exemplo n.º 10
0
def run_python_code_windows(pid,
                            python_code,
                            connect_debugger_tracing=False,
                            show_debug_info=0):
    assert '\'' not in python_code, 'Having a single quote messes with our command.'
    from winappdbg import compat
    from winappdbg.process import Process
    if not isinstance(python_code, compat.bytes):
        python_code = compat.b(python_code)

    process = Process(pid)
    bits = process.get_bits()
    is_64 = bits == 64

    if is_64 != is_python_64bit():
        raise RuntimeError(
            "The architecture of the Python used to connect doesn't match the architecture of the target.\n"
            "Target 64 bits: %s\n"
            "Current Python 64 bits: %s" % (is_64, is_python_64bit()))

    print('Connecting to %s bits target' % (bits, ))
    assert resolve_label(process, compat.b('PyGILState_Ensure'))

    filedir = os.path.dirname(__file__)
    if is_64:
        suffix = 'amd64'
    else:
        suffix = 'x86'
    target_dll = os.path.join(filedir, 'attach_%s.dll' % suffix)
    if not os.path.exists(target_dll):
        raise RuntimeError('Could not find dll file to inject: %s' %
                           target_dll)
    print('Injecting dll')
    process.inject_dll(target_dll.encode('mbcs'))
    print('Dll injected')

    process.scan_modules()
    attach_func = resolve_label(process, compat.b('AttachAndRunPythonCode'))
    assert attach_func

    print('Allocating code in target process')
    code_address = process.malloc(len(python_code))
    assert code_address
    print('Writing code in target process')
    process.write(code_address, python_code)

    print('Allocating return value memory in target process')
    attach_info_address = process.malloc(ctypes.sizeof(ctypes.c_int))
    assert attach_info_address

    CONNECT_DEBUGGER = 2

    attach_info = 0
    if show_debug_info:
        SHOW_DEBUG_INFO = 1
        attach_info |= SHOW_DEBUG_INFO  # Uncomment to show debug info

    if connect_debugger_tracing:
        attach_info |= CONNECT_DEBUGGER

    # Note: previously the attach_info address was treated as read/write to have the return
    # value, but it seems that sometimes when the program wrote back the memory became
    # unreadable with the stack trace below when trying to read, so, we just write and
    # no longer inspect the return value.
    # i.e.:
    # Traceback (most recent call last):
    #   File "X:\pydev\plugins\org.python.pydev.core\pysrc\pydevd_attach_to_process\attach_pydevd.py", line 72, in <module>
    #     main(process_command_line(sys.argv[1:]))
    #   File "X:\pydev\plugins\org.python.pydev.core\pysrc\pydevd_attach_to_process\attach_pydevd.py", line 68, in main
    #     setup['pid'], python_code, connect_debugger_tracing=True, show_debug_info=show_debug_info_on_target_process)
    #   File "X:\pydev\plugins\org.python.pydev.core\pysrc\pydevd_attach_to_process\add_code_to_python_process.py", line 392, in run_python_code_windows
    #     return_code = process.read_int(return_code_address)
    #   File "X:\pydev\plugins\org.python.pydev.core\pysrc\pydevd_attach_to_process\winappdbg\process.py", line 1673, in read_int
    #     return self.__read_c_type(lpBaseAddress, compat.b('@l'), ctypes.c_int)
    #   File "X:\pydev\plugins\org.python.pydev.core\pysrc\pydevd_attach_to_process\winappdbg\process.py", line 1568, in __read_c_type
    #     packed = self.read(address, size)
    #   File "X:\pydev\plugins\org.python.pydev.core\pysrc\pydevd_attach_to_process\winappdbg\process.py", line 1598, in read
    #     if not self.is_buffer(lpBaseAddress, nSize):
    #   File "X:\pydev\plugins\org.python.pydev.core\pysrc\pydevd_attach_to_process\winappdbg\process.py", line 2843, in is_buffer
    #     mbi = self.mquery(address)
    #   File "X:\pydev\plugins\org.python.pydev.core\pysrc\pydevd_attach_to_process\winappdbg\process.py", line 2533, in mquery
    #     return win32.VirtualQueryEx(hProcess, lpAddress)
    #   File "X:\pydev\plugins\org.python.pydev.core\pysrc\pydevd_attach_to_process\winappdbg\win32\kernel32.py", line 3742, in VirtualQueryEx
    #     raise ctypes.WinError()
    # PermissionError: [WinError 5] Access is denied.
    # Process finished with exitValue: 1

    process.write_int(attach_info_address, attach_info)

    helper = GenShellCodeHelper(is_64)
    if is_64:
        # Interesting read: http://msdn.microsoft.com/en-us/library/ms235286.aspx
        # Overview of x64 Calling Conventions (for windows: Linux is different!)
        # Register Usage: http://msdn.microsoft.com/en-us/library/9z1stfyw.aspx
        # The registers RAX, RCX, RDX, R8, R9, R10, R11 are considered volatile and must be considered destroyed on function calls (unless otherwise safety-provable by analysis such as whole program optimization).
        #
        # The registers RBX, RBP, RDI, RSI, RSP, R12, R13, R14, and R15 are considered nonvolatile and must be saved and restored by a function that uses them.
        #
        # Important: RCX: first int argument

        with helper.push('rdi'):  # This one REALLY must be pushed/poped
            with helper.push('rsp'):
                with helper.push('rbp'):
                    with helper.push('rbx'):

                        with helper.push('rdi'):  # Note: pop is automatic.
                            helper.mov_to_register_addr(
                                'rcx', helper.pack_address(code_address))
                            helper.mov_to_register_addr(
                                'rdx',
                                helper.pack_address(attach_info_address))
                            helper.mov_to_register_addr(
                                'rbx', helper.pack_address(attach_func))
                            helper.call('rbx')

    else:
        with helper.push('eax'):  # Note: pop is automatic.
            with helper.push('ebp'):
                with helper.push('ebx'):

                    with helper.preserve_stack():
                        # Put our code as a parameter in the stack (on x86, we push parameters to
                        # the stack)
                        helper.push_addr(
                            helper.pack_address(attach_info_address))
                        helper.push_addr(helper.pack_address(code_address))
                        helper.mov_to_register_addr(
                            'ebx', helper.pack_address(attach_func))
                        helper.call('ebx')

    helper.ret()

    code = helper.get_code()

    # Uncomment to see the disassembled version of what we just did...
    #     with open('f.asm', 'wb') as stream:
    #         stream.write(code)
    #
    #     exe = r'x:\nasm\nasm-2.07-win32\nasm-2.07\ndisasm.exe'
    #     if is_64:
    #         arch = '64'
    #     else:
    #         arch = '32'
    #
    #     subprocess.call((exe + ' -b %s f.asm' % arch).split())

    print('Injecting code to target process')
    thread, _thread_address = process.inject_code(code, 0)

    timeout = None  # Could receive timeout in millis.
    print('Waiting for code to complete')
    thread.wait(timeout)

    # return_code = process.read_int(attach_info_address)
    # if return_code == 0:
    #     print('Attach finished successfully.')
    # else:
    #     print('Error when injecting code in target process. Error code: %s (on windows)' % (return_code,))

    process.free(thread.pInjectedMemory)
    process.free(code_address)
    process.free(attach_info_address)
    return 0