0

OK, I am very new to x64dbg. I used to use OllyDbg a lot and I'm having some problems with this. I just made a customized version of MS-PAINT for practice by changing a few things like the default palette, etc.

I want to add a MessageBoxW to the help button in the corner. I successfully located the method. In ollydbg, I could simply type push, push, push and then call MessageBoxW, but it doesn't work with this. Maybe it's not imported? But I searched for references and found a MessageBoxW, but it looks like this: call qword ptr ds:[0x00000000FF467880] and that ptr is automatically evaluated to MessageBoxW. However, when I copy that code myself it's not working. Why can't I simply type call MessageBoxW????

I know this might seem amateurish, but I am doing this to try to learn how to use this debugger better. I hope you understand I don't have much experience. Thanks!

1
  • 1
    "However, when I copy that code myself it's not working" and this not working has any manifestation? No crashes? Or anything? If you debug this, do you see this code being executed? Nov 25 '20 at 20:40
1

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
Call cs:MessageBoxW 

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

NEAR CALLS

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 displacement.

CALL rel32off ( E8 id ) Near call with the target specified by a 32-bit relative displacement.

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.

FAR CALLS

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 mode. • 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 stack. 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 in memory.

CALL FAR mem16:32 (FF /3) Far call indirect, with the target specified by a far pointer in memory

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.