首页
社区
课程
招聘
[求助]64位 call qword ptr [********] 的疑问
发表于: 2015-2-27 20:46 21046

[求助]64位 call qword ptr [********] 的疑问

2015-2-27 20:46
21046

64位 call qword ptr [********]
的流程是怎样的
push rip
jmp qword ptr [********]
像上面这样?? 好像不对

对应的返回指令是什么

ret ?  retf ?
好像都不对


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 3
支持
分享
最新回复 (19)
雪    币: 19
活跃值: (1086)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
返回指令就是ret
返回之前会平衡堆栈的 返回的地址就是你CALL之前压入的地址了
2015-2-27 22:05
0
雪    币: 581
活跃值: (215)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
3
[QUOTE=h辉;1355674]64位 call qword ptr [********]
的流程是怎样的
push rip
jmp call qword ptr [********]
像上面这样?? 好像不对

对应的返回指令是什么

ret ?  retf ?
好像都不对[/QUOTE]

rip?是打错了么?EIP?
jmp 和call 还能一起用?

你的意思是call 的含义么?
2015-2-27 23:04
0
雪    币: 376
活跃值: (92)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
楼主的意思应该是
call可以理解为
先 push eip
再 jmp qword ptr
2015-2-27 23:37
0
雪    币: 101
活跃值: (29)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
32位汇编区分近跳转和远跳转... 64位下取消了吗
call 指令

CPU 执行call指令时,进行两步操作:

(1)当前的IP或CS和IP压入栈中;

(2)转移

call 指令不能实现短转移

3.依据位移进行转移的call指令

call 标号(将当前的IP压栈后 , 转到标号处执行指令)

CPU执行此种格式的call指令时,进行如下操作:

(1)(sp)= (sp)- 2

           ((ss)* 16 + (sp))= (IP)

(2)(IP)=(IP)+16位位移

4.前面的 call 指令,其对应的机器指令并没有转移的目的地址,而是相对于当前IP的转移位移。

“ call far ptr ”实现的是段间转移

5.转移地址在寄存器中的call指令

指令格式:call 16位reg

功能:

(sp) = (sp) + 2

((ss)*16+(sp))=(IP)

(IP)=(16位reg)
2015-2-28 09:00
0
雪    币: 23
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
64用syscall试试,如果成功了,麻烦说一下,一直没空试这个
2015-2-28 15:39
0
雪    币: 8
活跃值: (120)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
其实 你用OD随便载入一个稍微大点的软件,一会儿就明白 近距离和远距离的调用区别。主要是二进制指令不一样。授人与鱼,不如与渔。
2015-2-28 21:03
0
雪    币: 101
活跃值: (29)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
当初我也是满怀期待打开 OD 的....:结果. 64 位你懂的
我还是拿 CE 调试看看 就是不如 OD 方便
2015-2-28 22:27
0
雪    币: 1604
活跃值: (640)
能力值: ( LV13,RANK:460 )
在线值:
发帖
回帖
粉丝
9
[QUOTE=h辉;1355674]64位 call qword ptr [********]
的流程是怎样的
push rip
jmp qword ptr [********]
像上面这样?? 好像不对

对应的返回指令是什么

ret ?  retf ?
好像都不对[/QUOTE]

rip 是 x64 体系结构下的扩展指令指针寄存器(eip)
用户汇编代码不能直接读写EIP的内容,除非使用运行在ring0 级别的调试器或内核调试器
但是在执行 call指令前,它会隐式地将EIP中的值(call指令所在地址的下一条指令的地址)作为返回地址压到栈内存上.
通常位于[ebp+4] 处就是返回地址,你可以尝试读取这个栈地址中的内容来提取返回地址
x64 体系结构下的返回指令即ret,(有些编译器生成 retn)它与call成对出现,通常情况下,被调函数在返回主调函数前的最后一条指令就是ret,
ret的内幕是从当前栈顶提取返回地址,保存到EIP中,CPU执行EIP中指向的地址处的指令,如此就实现了将控制权转交主调函数.
2015-2-28 23:44
0
雪    币: 19
活跃值: (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
inter 下 IP 好像是不可以直接修改的吧
另 64位 调用函数类似于 FastCall
64位下 长跳的实现为
JUMP
FF 25 (4Byte Offset)

jmp offset 0
:address   ; qword

CALL
FF 15 (4Byte Offset)

CALL offset 0
:address   ; qword

详细见 64位 shadowSSDT  360驱动HOOK win32k 实现方式
2015-3-3 10:57
0
雪    币: 19
活跃值: (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
64位下调用协议只有一种,具体名字想不起来了 名字不是 FASTCALL
协议如下:
    前四个整型或指针类型参数由RCX,RDX,R8,R9依次传递,前四个浮点类型参数由XMM0,XMM1,XMM2,XMM3依次传递。
    调用函数为前四个参数在调用栈上保留相应的空间,称作shadow space或spill slot。即使被调用方没有或小于4个参数,调用函数仍然保留那么多的栈空间,这有助于在某些特殊情况下简化调用约定。
    除前四个参数以外的任何其他参数通过栈来传递,从右至左依次入栈。
    由调用函数负责清理调用栈。
    小于等于64位的整型或指针类型返回值由RAX传递。
    浮点返回值由XMM0传递。
    更大的返回值(比如结构体),由调用方在栈上分配空间,并有RCX持有该空间的指针并传递给被调用函数,因此整型参数使用的寄存器依次右移一格,实际只可以利用3个寄存器,其余参数入栈。函数调用结束后,RAX返回该空间的指针。
    除RCX,RDX,R8,R9以外,RAX、R10、R11、XMM4 和 XMM5也是易变化的(volatile)寄存器。
    RBX, RBP, RDI, RSI, R12, R14, R14, and R15寄存器则必须在使用时进行保护。
    在寄存器中,所有参数都是右对齐的。小于64位的参数并不进行高位零扩展,也就是高位是无法预测的垃圾数据。
2015-3-3 11:03
0
雪    币: 101
活跃值: (29)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
没搜索到..求链接
2015-3-3 14:08
0
雪    币: 101
活跃值: (29)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
64 位 syscall 和32位差不多吧...
我在学64位的驱动.. 好像用不到这个
2015-3-3 14:11
0
雪    币: 19
活跃值: (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
调用协议类似 __fastcall 但好像不叫__fastcall,具体叫什么忘记了,好早以前看过,你看看微软官方介绍
和inter x64 指令集 相关 助记符 说明
打开 PCHunter->内核钩子->ShadowSSDT 下,如果安装360
就会发现被Hook函数查看被挂钩函数字节码,跟几步,可以看到如何实现的.
FF 25 00 00 00 00(4Byte Offset)  8 byte (8Byte MemAddr)

{具体过程 建议你自己从代码里面跟一下就明白了}

调用协议参考
    前四个整型或指针类型参数由RCX,RDX,R8,R9依次传递,前四个浮点类型参数由XMM0,XMM1,XMM2,XMM3依次传递。
    调用函数为前四个参数在调用栈上保留相应的空间,称作shadow space或spill slot。即使被调用方没有或小于4个参数,调用函数仍然保留那么多的栈空间,这有助于在某些特殊情况下简化调用约定。
    除前四个参数以外的任何其他参数通过栈来传递,从右至左依次入栈。
    由调用函数负责清理调用栈。
    小于等于64位的整型或指针类型返回值由RAX传递。
    浮点返回值由XMM0传递。
    更大的返回值(比如结构体),由调用方在栈上分配空间,并有RCX持有该空间的指针并传递给被调用函数,因此整型参数使用的寄存器依次右移一格,实际只可以利用3个寄存器,其余参数入栈。函数调用结束后,RAX返回该空间的指针。
    除RCX,RDX,R8,R9以外,RAX、R10、R11、XMM4 和 XMM5也是易变化的(volatile)寄存器。
    RBX, RBP, RDI, RSI, R12, R14, R14, and R15寄存器则必须在使用时进行保护。
    在寄存器中,所有参数都是右对齐的。小于64位的参数并不进行高位零扩展,也就是高位是无法预测的垃圾数据。

64位程序调用,所有的函数地址都在一段表里面,Offset指向表地址
2015-3-3 16:05
0
雪    币: 101
活跃值: (29)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
FF 25 00 00 00 00(4Byte Offset)  8 byte (8Byte MemAddr)
这种 HOOK 方式已经实现了。。

现在就是纠结
FF 15 00 00 00 00(4Byte Offset)  8 byte (8Byte MemAddr)
call qword ptr [********]
这是 HOOK NtOpenProcess 之后 代理函数中
        asm volatile(
                "add qword ptr [rbp+8], 0xE;" // 跳过hook处被覆盖的代码
                "leave;" // 平衡代理函数头中的 enter 指令
                "sub rsp, 0x38;"
                "mov rax, gs:0x188;"
                "mov r10b, [rax+0x1F6];"
                "ret;" // 返回继续执行
        );
用ret 方式跳转回去就蓝屏 改成retf 也是蓝屏...

图中是用 FF 25 00 00 00 00(4Byte Offset)  8 byte (8Byte MemAddr) 方式 hook 并 jmp 回去跳过hook处被覆盖的代码 代理函数 可以正常hook
上传的附件:
2015-3-3 16:29
0
雪    币: 19
活跃值: (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
定义个一样的函数接口就行啊,找到函数头

NTSTATUS MyZwOpenProcess(
  _Out_     PHANDLE ProcessHandle,
  _In_      ACCESS_MASK DesiredAccess,
  _In_      POBJECT_ATTRIBUTES ObjectAttributes,
  _In_opt_  PCLIENT_ID ClientId
)
{
     return pfZwOpenProcess(ProcessHandle,DesiredAccess, ObjectAttributes,ClientId);
}

save (2 + 4 + 8) + 破坏的字节
jmp 到 address + Offset

NtOpenProcess 的头部修改为 MyZwOpenProcess
pfZwOpenProcess = save 的地址

和32位下 jmp inline hook 没什么区别啊
你看看 360是如何hook 的
2015-3-5 15:32
0
雪    币: 22
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
64位下为了减少指令长度,call用的是相对地址。
2015-3-7 10:57
0
雪    币: 2155
活跃值: (29)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
18
RIP 是64位下的IP寄存器名字

EIP->RIP
EAX->RAX
EBX->RBX
以此类推。。。
2015-3-7 11:47
0
雪    币: 581
活跃值: (215)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
19
谢谢。平时不怎么整x64的。
2015-3-8 00:34
0
雪    币: 3523
活跃值: (837)
能力值: ( LV9,RANK:140 )
在线值:
发帖
回帖
粉丝
20
x64  下  的call  far  字节码是怎样的
2017-9-8 16:01
0
游客
登录 | 注册 方可回帖
返回
//