First make sure you are using correct calling convention, in 64-bit Windows most APIs expect parameters via registers not push.
An example of calling convention for 64-bit Windows:
lea r9d, uType ; uType
lea r8, Caption ; Caption
lea rdx, Text ; Text
mov rcx, hWnd ; hWnd
This is covered in more detailed in x64 Calling Convention
If the call instruction uses relative addresses you will need to adjust when relocating the code.
As an example (These addresses will vary in MS Paint)
At 00007FF72599A000 import table starts
At 00007FF72599AFA0 entry for MessageBox:
; int __stdcall MessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType)
extrn MessageBoxW:qword ;
At 00007FF7258CA6A2 message box is called:
Call cs:MessageBoxW ( bytes FF 15 F8 08 0D 00 )
AT 00007FF7258CA6A2 message box is called:
Call cs:MessageBoxW ( bytes FF 15 09 5F 0A 00 )
You can see from these bytes changes that the in this case the address is relative, so will need to be adjusted if relocating the code. Reading the processor documentation can explain the different call options, for example from amd64 Architecture Programming Manual
Pushes the offset of the next instruction onto the stack and branches to the target address, which
contains the first instruction of the called procedure. The target operand can specify a register, a
memory location, or a label. A procedure accessed by a near CALL is located in the same code
segment as the CALL instruction.
If the CALL target is specified by a register or memory location, then a 16-, 32-, or 64-bit rIP is read
from the operand, depending on the operand size. A 16- or 32-bit rIP is zero-extended to 64 bits.
If the CALL target is specified by a displacement, the signed displacement is added to the rIP (of the
following instruction), and the result is truncated to 16, 32, or 64 bits, depending on the operand size.
The signed displacement is 16 or 32 bits, depending on the operand size.
In all cases, the rIP of the instruction after the CALL is pushed on the stack, and the size of the stack
push (16, 32, or 64 bits) depends on the operand size of the CALL instruction.
For near calls in 64-bit mode, the operand size defaults to 64 bits. The E8 opcode results in
RIP = RIP + 32-bit signed displacement and the FF /2 opcode results in RIP = 64-bit offset from
register or memory. No prefix is available to encode a 32-bit operand size in 64-bit mode.
At the end of the called procedure, RET is used to return control to the instruction following the
original CALL. When RET is executed, the rIP is popped off the stack, which returns control to the
instruction after the CALL.
CALL rel16off ( E8 iw ) Near call with the target specified by a 16-bit relative
CALL rel32off ( E8 id ) Near call with the target specified by a 32-bit relative
CALL reg/mem16 ( FF /2 ) Near call with the target specified by reg/mem16.
CALL reg/mem32 ( FF /2 ) Near call with the target specified by reg/mem32. (There
is no prefix for encoding this in 64-bit mode.)
CALL reg/mem64 (FF /2) Near call with the target specified by reg/mem64.
Pushes procedure linking information onto the stack and branches to the target address, which contains
the first instruction of the called procedure. The operand specifies a target selector and offset.
The instruction can specify the target directly, by including the far pointer in the immediate and
displacement fields of the instruction, or indirectly, by referencing a far pointer in memory. In 64-bit
mode, only indirect far calls are allowed; executing a direct far call (opcode 9A) generates an
undefined opcode exception. For both direct and indirect far calls, if the CALL (Far) operand-size is
16 bits, the instruction's operand is a 16-bit offset followed by a 16-bit selector. If the operand-size is
32 or 64 bits, the operand is a 32-bit offset followed by a 16-bit selector.
The target selector used by the instruction can be a code selector in all modes. Additionally, the target
selector can reference a call gate in protected mode, or a task gate or TSS selector in legacy protected
• Target is a code selector—The CS:rIP of the next instruction is pushed to the stack, using operandsize stack pushes. Then code is executed from the target CS:rIP. In this case, the target offset can
only be a 16- or 32-bit value, depending on operand-size, and is zero-extended to 64 bits. No CPL
change is allowed.
• Target is a call gate—The call gate specifies the actual target code segment and offset. Call gates
allow calls to the same or more privileged code. If the target segment is at the same CPL as the
current code segment, the CS:rIP of the next instruction is pushed to the stack.
If the CALL (Far) changes privilege level, then a stack-switch occurs, using an inner-level stack
pointer from the TSS. The CS:rIP of the next instruction is pushed to the new stack. If the mode is
legacy mode and the param-count field in the call gate is non-zero, then up to 31 operands are
copied from the caller's stack to the new stack. Finally, the caller's SS:rSP is pushed to the new
When calling through a call gate, the stack pushes are 16-, 32-, or 64-bits, depending on the size of
the call gate. The size of the target rIP is also 16, 32, or 64 bits, depending on the size of the call
gate. If the target rIP is less than 64 bits, it is zero-extended to 64 bits. Long mode only allows 64-
bit call gates that must point to 64-bit code segments.
• Target is a task gate or a TSS—If the mode is legacy protected mode, then a task switch occurs.
See “Hardware Task-Management in Legacy Mode” in volume 2 for details about task switches.
Hardware task switches are not supported in long mode.
CALL FAR pntr16:16 (9A cd) Far call direct, with the target specified by a far pointer
contained in the instruction. (Invalid in 64-bit mode.)
CALL FAR pntr16:32 ( 9A cp ) Far call direct, with the target specified by a far pointer
contained in the instruction. (Invalid in 64-bit mode.)
CALL FAR mem16:16 ( FF /3 ) Far call indirect, with the target specified by a far pointer
CALL FAR mem16:32 (FF /3) Far call indirect, with the target specified by a far pointer
Further info can be found in Intel® 64 and IA-32 Architectures Software Developer’s Manual Combined Volumes: 1, 2A, 2B, 2C, 2D, 3A, 3B, 3C, 3D, and 4