钩子劫持技术是计算机编程中的一种技术,它们可以让开发者拦截系统函数或应用程序函数的调用,并在函数调用前或调用后执行自定义代码,钩子劫持技术通常用于病毒和恶意软件,也可以让开发者扩展或修改系统函数的功能,从而提高软件的性能和增加新功能。

4.5.1 探索反汇编写出函数原理

钩子劫持技术的实现一般需要在对端内存中通过create_alloc()函数准备一块空间,并通过assemble_write_memory()函数,将一段汇编代码转为机器码,并循环写出自定义指令集到堆中,函数write_opcode_from_assemble()就是我们自己实现的,该函数传入一个汇编指令列表,自动转为机器码并写出到堆内,函数的核心代码如下所示。

  1. def write_opcode_from_assemble(dbg_ptr,asm_list):
  2. addr_count = 0
  3. addr = dbg_ptr.create_alloc(1024)
  4. if addr != 0:
  5. for index in asm_list:
  6. asm_size = dbg_ptr.assemble_code_size(index)
  7. if asm_size != 0:
  8. # print("长度: {}".format(asm_size))
  9. write = dbg_ptr.assemble_write_memory(addr + addr_count, index)
  10. if write == True:
  11. addr_count = addr_count + asm_size
  12. else:
  13. dbg_ptr.delete_alloc(addr)
  14. return 0
  15. else:
  16. dbg_ptr.delete_alloc(addr)
  17. return 0
  18. else:
  19. return 0
  20. return addr

我们以写出一段MessageBox弹窗代码为例,首先通过get_module_from_function函数获取到位于user32.dll模块内MessageBoxA的函数地址,该函数的栈传参数为五个,其中前四个为push压栈,最后一个则是调用call,为了构建这个指令集需要在asm_list写出所需参数列表及调用函数地址,并通过set_local_protect设置可执行属性,通过set_register将当前EIP设置到写出位置,并执行程序。

  1. from LyScript32 import MyDebug
  2. def write_opcode_from_assemble(dbg_ptr,asm_list):
  3. pass
  4. if __name__ == "__main__":
  5. dbg = MyDebug()
  6. dbg.connect()
  7. # 得到messagebox内存地址
  8. msg_ptr = dbg.get_module_from_function("user32.dll","MessageBoxA")
  9. call = "call {}".format(str(hex(msg_ptr)))
  10. print("函数地址: {}".format(call))
  11. # 写出指令集到内存
  12. asm_list = ['push 0','push 0','push 0','push 0',call]
  13. write_addr = write_opcode_from_assemble(dbg,asm_list)
  14. print("写出地址: {}".format(hex(write_addr)))
  15. # 设置执行属性
  16. dbg.set_local_protect(write_addr,32,1024)
  17. # 将EIP设置到指令集位置
  18. dbg.set_register("eip",write_addr)
  19. # 执行代码
  20. dbg.set_debug("Run")
  21. dbg.close()

运行上述代码片段,则首先会在0x3130000的位置处写出调用MessageBox的指令集。

当执行set_debug("Run")则会执行如下图所示代码,这些代码则是经过填充的,由于此处仅仅只是一个演示案例,所以不具备任何实战性,读者在该案例中学会指令的替换是如何实现的即可;

4.5.2 实现Hook改写MsgBox弹窗

在之前的内容中笔者通过封装write_opcode_from_assemble函数实现了自定义写出内存的功能,本章将继续探索Hook劫持技术的实现原理,如下案例中我们先来实现一个Hook通用模板,在代码中实现中转机制,代码中以MessageBoxA函数为案例实现修改汇编参数传递。

  1. from LyScript32 import MyDebug
  2. # 传入汇编列表,写出到内存
  3. def assemble(dbg, address=0, asm_list=[]):
  4. asm_len_count = 0
  5. for index in range(0,len(asm_list)):
  6. # 写出到内存
  7. dbg.assemble_at(address, asm_list[index])
  8. # print("地址: {} --> 长度计数器: {} --> 写出: {}".format(hex(address + asm_len_count), asm_len_count,asm_list[index]))
  9. # 得到asm长度
  10. asm_len_count = dbg.assemble_code_size(asm_list[index])
  11. # 地址每次递增
  12. address = address + asm_len_count
  13. if __name__ == "__main__":
  14. dbg = MyDebug()
  15. connect_flag = dbg.connect()
  16. print("连接状态: {}".format(connect_flag))
  17. # 找到MessageBoxA
  18. messagebox_address = dbg.get_module_from_function("user32.dll","MessageBoxA")
  19. print("MessageBoxA内存地址 = {}".format(hex(messagebox_address)))
  20. # 分配空间
  21. HookMem = dbg.create_alloc(1024)
  22. print("自定义内存空间: {}".format(hex(HookMem)))
  23. # 写出MessageBoxA内存地址,跳转地址
  24. asm = [
  25. f"push {hex(HookMem)}",
  26. "ret"
  27. ]
  28. # 将列表中的汇编指令写出到内存
  29. assemble(dbg,messagebox_address,asm)
  30. dbg.close()

如上代码中,通过找到user32.dll库中的MessageBoxA函数,并返回其内存地址。接着,程序会分配1024字节大小的自定义内存空间,获取刚刚写入的内存地址,并将其写入到MessageBoxA函数的内存地址中,代码运行后读者可看到如下图所示的提示信息;

提示:解释一下为什么需要增加asm列表中的指令集,此处的指令集作用只有一个那就是跳转,当原始MessageBoxA函数被调用时,则此处通过push;ret的组合跳转到我们自定义的HookMem内存空间中,而此内存空间中后期则需要填充我们自己的弹窗代码片段,所以需要提前通过HookMem = dbg.create_alloc(1024)构建出这段内存区域;

由于MessageBox弹窗需要使用两个变量这两个变量依次代表标题和内容,所以我们通过create_alloc函数在对端内存中分配两块堆空间,并依次将弹窗字符串通过write_memory_byte写出到内存中,至此弹窗内容也算填充好了,其中txt代表标题,而box则代表内容;

  1. # 定义两个变量,存放字符串
  2. MsgBoxAddr = dbg.create_alloc(512)
  3. MsgTextAddr = dbg.create_alloc(512)
  4. # 填充字符串内容
  5. # lyshark 标题
  6. txt = [0x6c, 0x79, 0x73, 0x68, 0x61, 0x72, 0x6b]
  7. # 内容 lyshark.com
  8. box = [0x6C, 0x79, 0x73, 0x68, 0x61, 0x72, 0x6B, 0x2E, 0x63, 0x6F, 0x6D]
  9. for txt_count in range(0,len(txt)):
  10. dbg.write_memory_byte(MsgBoxAddr + txt_count, txt[txt_count])
  11. for box_count in range(0,len(box)):
  12. dbg.write_memory_byte(MsgTextAddr + box_count, box[box_count])
  13. print("标题地址: {} 内容: {}".format(hex(MsgBoxAddr),hex(MsgTextAddr)))

紧接着,我们需要跳转到MessageBoxA函数所在内存中,并提取出该函数调用时的核心汇编指令集,如下图所示则是弹窗的具体实现流程;

而对于一个完整的弹窗来说,只需要提取出核心代码即可不必提取所有指令集,但需要注意的是图中的call 0x75B20E20地址需要进行替换,根据系统的不同此处的地址也不会相同,在提取时需要格外注意;

  1. # 此处是MessageBox替换后的片段
  2. PatchCode =\
  3. [
  4. "mov edi, edi",
  5. "push ebp",
  6. "mov ebp,esp",
  7. "push -1",
  8. "push 0",
  9. "push dword ptr ss:[ebp+0x14]",
  10. f"push {hex(MsgBoxAddr)}",
  11. f"push {hex(MsgTextAddr)}",
  12. "push dword ptr ss:[ebp+0x8]",
  13. "call 0x75B20E20",
  14. "pop ebp",
  15. "ret 0x10"
  16. ]
  17. # 写出到自定义内存
  18. assemble(dbg, HookMem, PatchCode)

如上则是替换弹窗的代码解释,将这段代码整合在一起,读者则可实现一段替换弹窗功能的代码,如下弹窗中的消息替换成我们自己的版权信息,此处完整代码实现如下所示;

  1. from LyScript32 import MyDebug
  2. # 传入汇编列表,写出到内存
  3. def assemble(dbg, address=0, asm_list=[]):
  4. asm_len_count = 0
  5. for index in range(0,len(asm_list)):
  6. # 写出到内存
  7. dbg.assemble_at(address, asm_list[index])
  8. # print("地址: {} --> 长度计数器: {} --> 写出: {}".format(hex(address + asm_len_count), asm_len_count,asm_list[index]))
  9. # 得到asm长度
  10. asm_len_count = dbg.assemble_code_size(asm_list[index])
  11. # 地址每次递增
  12. address = address + asm_len_count
  13. if __name__ == "__main__":
  14. dbg = MyDebug()
  15. connect_flag = dbg.connect()
  16. print("连接状态: {}".format(connect_flag))
  17. # 找到MessageBoxA
  18. messagebox_address = dbg.get_module_from_function("user32.dll","MessageBoxA")
  19. print("MessageBoxA内存地址 = {}".format(hex(messagebox_address)))
  20. # 分配空间
  21. HookMem = dbg.create_alloc(1024)
  22. print("自定义内存空间: {}".format(hex(HookMem)))
  23. # 写出FindWindowA内存地址,跳转地址
  24. asm = [
  25. f"push {hex(HookMem)}",
  26. "ret"
  27. ]
  28. # 将列表中的汇编指令写出到内存
  29. assemble(dbg,messagebox_address,asm)
  30. # 定义两个变量,存放字符串
  31. MsgBoxAddr = dbg.create_alloc(512)
  32. MsgTextAddr = dbg.create_alloc(512)
  33. # 填充字符串内容
  34. # lyshark 标题
  35. txt = [0x6c, 0x79, 0x73, 0x68, 0x61, 0x72, 0x6b]
  36. # 内容 lyshark.com
  37. box = [0x6C, 0x79, 0x73, 0x68, 0x61, 0x72, 0x6B, 0x2E, 0x63, 0x6F, 0x6D]
  38. for txt_count in range(0,len(txt)):
  39. dbg.write_memory_byte(MsgBoxAddr + txt_count, txt[txt_count])
  40. for box_count in range(0,len(box)):
  41. dbg.write_memory_byte(MsgTextAddr + box_count, box[box_count])
  42. print("标题地址: {} 内容: {}".format(hex(MsgBoxAddr),hex(MsgTextAddr)))
  43. # 此处是MessageBox替换后的片段
  44. PatchCode =\
  45. [
  46. "mov edi, edi",
  47. "push ebp",
  48. "mov ebp,esp",
  49. "push -1",
  50. "push 0",
  51. "push dword ptr ss:[ebp+0x14]",
  52. f"push {hex(MsgBoxAddr)}",
  53. f"push {hex(MsgTextAddr)}",
  54. "push dword ptr ss:[ebp+0x8]",
  55. "call 0x75B20E20",
  56. "pop ebp",
  57. "ret 0x10"
  58. ]
  59. # 写出到自定义内存
  60. assemble(dbg, HookMem, PatchCode)
  61. print("地址已被替换,可以运行了.")
  62. dbg.set_debug("Run")
  63. dbg.set_debug("Run")
  64. dbg.close()

当如上代码被运行后,则会替换进程内MessageBoxA函数为我们自己的地址,运行输出效果如下图所示;

读者可通过Ctrl+G并输入MessageBoxA跳转到原函数弹窗位置,此时输出的则是一个跳转地址0x6C0000该地址则代表我们自己的自定义内存区域,如下图所示;

继续跟进这内存区域,读者可看到我们自己构建的MessageBoxA弹窗的核心代码片段,当这段代码被执行结束后则通过ret会返回到程序领空,如下图所示;

至此,当用户再次打开弹窗按钮时,则不会提示原始内容,而是提示自定义弹窗,如下图所示;

原文地址

https://www.lyshark.com/post/6b7ca168.html

4.5 x64dbg 探索钩子劫持技术的更多相关文章

  1. dll劫持技术

    DLL劫持技术当一个可执行文件运行时,Windows加载器将可执行模块映射到进程的地址空间中,加载器分析可执行模块的输入表,并设法找出任何需要的DLL,并将它们映射到进程的地址空间中. DLL劫持原理 ...

  2. windows、linux劫持技术

    windows系统以下能够利用detours劫持 realse  模式劫持,调试的程序不能够 函数劫持能够实现的效果. 函数的劫持原理 我们怎样实现-detours detours是微软亚洲研究院出品 ...

  3. 探索云网络技术前沿,Sigcomm 2019 阿里云参会分享

    Sigcomm 2019简介 一年一度的网络顶级学术峰会Sigcomm于8月20日至22日在北京举行.作为ACM Special Interest Group on Data Communicatio ...

  4. 新型Web劫持技术

    该类新型Web劫持是利用script脚本实现的.在已知的案例中,黑客入侵了某地方门户网站,篡改了该网站的新闻页面,并向这些页面植入自己的广告.新闻及恶意代码.一旦用户从搜索结果页面点击进入被篡改过的新 ...

  5. session劫持技术

    目录: 0×00 应用程序认证设计背景0×01 常规攻击思路及缺陷0×02 利用应用程序设计缺陷进行Session劫持的攻击原理0×03 Session劫持的大致思路及意义0×04 如何防御这种攻击 ...

  6. 关于thrift的一些探索——thrift序列化技术

    thrift的IDL,相当于一个钥匙.而thrift传输过程,相当于从两个房间之间的传输数据. 图-1 (因为Thrift采用了C/S模型,不支持双向通信:client只能远程调用server端的RP ...

  7. 25.Detours劫持技术

    Detours可以用来实现劫持,他是微软亚洲研究院开发出来的工具,要实现它首先需要安装Detours. 安装地址链接:https://pan.baidu.com/s/1eTolVZs 密码:uy8x ...

  8. DLL劫持技术例子: HijackDll

    控制台程序:DllLoader Dll加载器,用于动态加载目标Dll,并动态调用目标函数 #include <cstdio> #include <windows.h> type ...

  9. openwrt-智能路由器hack技术(1)---"DNS劫持"

    openwrt-智能路由器hack技术(1)---"DNS劫持" 1   导读 PS:之前写的一个文章,现在发现结构内容排版不是太好,导致阅读体验太差,影响传播和SEO,所以现在整 ...

  10. Windows Dll Injection、Process Injection、API Hook、DLL后门/恶意程序入侵技术

    catalogue 1. 引言2. 使用注册表注入DLL3. 使用Windows挂钩来注入DLL4. 使用远程线程来注入DLL5. 使用木马DLL来注入DLL6. 把DLL作为调试器来注入7. 使用c ...

随机推荐

  1. Mybatis 框架下 SQL 注入攻击的方式

    前言 SQL注入漏洞作为WEB安全的最常见的漏洞之一,在java中随着预编译与各种ORM框架的使用,注入问题也越来越少. 新手代码审计者往往对Java Web应用的多个框架组合而心生畏惧,不知如何下手 ...

  2. JQuery日期选择控件-兼容手机端

    在项目中经常使用到日期时间控件. 用的时候总是临时去找,现在记录下,以备下次使用. 官网http://www.bootcss.com/p/bootstrap-datetimepicker/ 需要引用一 ...

  3. day05 运算符和流程控制

    Day05 逻辑运算符 成员运算符 身份运算符 流程控制(重点) if判断 while循环 标志位的使用 逻辑运算符 and  与 #可以用and链接多个条件,会按照从左到右的顺序依次判断,有一个为F ...

  4. Godot 4.0 文件系统特性的总结

    关于文件系统,官方文档犹抱琵琶半遮面,有一些很独特的特性并没有集中地摆出来,导致用的时候晕头转向. 这里总结了目前我发现的Godot文件系统的一些特性. 这是专门针对导出后的,因为一些操作在编辑器里面 ...

  5. STL------sort三种比较算子定义

    sort的三种比较算子的定义方式 例:一道细碎的细节模拟题: http://newoj.acmclub.cn/contests/1258/problem/3 1932: 2018蓝桥杯培训-STL应用 ...

  6. JavaScript 如何判断一个对象中是否有某个属性?

    今天讲讲,JavaScript 如何判断一个对象中是否有某个属性? 我总结了5个方法: 方法1: if(Obj[a]) {} 缺点:对于参数值为 undefined 和 0 的无效. 方法2: if( ...

  7. 2022-09-01:字符串的 波动 定义为子字符串中出现次数 最多 的字符次数与出现次数 最少 的字符次数之差。 给你一个字符串 s ,它只包含小写英文字母。请你返回 s 里所有 子字符串的 最大波

    2022-09-01:字符串的 波动 定义为子字符串中出现次数 最多 的字符次数与出现次数 最少 的字符次数之差. 给你一个字符串 s ,它只包含小写英文字母.请你返回 s 里所有 子字符串的 最大波 ...

  8. 2020-11-02:go中,s:=make([]string,10);s=append(s,“test“);fmt.Println(s[0]),打印什么?

    福哥答案2020-11-02: 打印空字符串.s:=make([]string,10),s中已经有10个元素,append元素,s就有11个元素了.前10个元素没初始化,就是10个空字符串,最后1个字 ...

  9. 2022-07-22:以下go语言代码输出什么?A:1;B:1.5;C:编译错误;D:1.49。 package main import “fmt“ func main() { var i

    2022-07-22:以下go语言代码输出什么?A:1:B:1.5:C:编译错误:D:1.49. package main import "fmt" func main() { v ...

  10. 2020-12-03:mysql中,Heap 表是什么?

    福哥答案2020-12-04:[答案来自此链接:](http://bbs.xiangxueketang.cn/question/605) Heap表,即使用MEMORY存储引擎的表,这种表的数据存储在 ...