- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
LyScript 插件提供的反汇编系列函数虽然能够实现基本的反汇编功能,但在实际使用中,可能会遇到一些更为复杂的需求,此时就需要根据自身需要进行二次开发,以实现更加高级的功能。本章将继续深入探索反汇编功能,并将介绍如何实现反汇编代码的检索、获取上下一条代码等功能。这些功能对于分析和调试代码都非常有用,因此是书中重要的内容之一。在本章的学习过程中,读者不仅可以掌握反汇编的基础知识和技巧,还能够了解如何进行插件的开发和调试,这对于提高读者的技能和能力也非常有帮助.
首先我们来实现第一种需求,通过 LyScript 插件实现搜索内存中的特定机器码,此功能当然可通过 scan_memory_all() 系列函数实现,但读者希望你能通过自己的理解调用原生API接口实现这个需求,要实现该功能第一步则是需要封装一个 GetCode() 函数,该函数的作用是读取进程数据到内存中.
其中 dbg.get_local_base() 用于获取当前进程内的首地址,而通过 start_address + dbg.get_local_size() 的方式则可获取到该程序的结束地址,当确定了读取范围后再通过 dbg.read_memory_byte(index) 循环即可将程序的内存数据读入,而 ReadHexCode() 仅仅只是一个格式化函数,这段程序的核心代码可以总结为如下样子; 。
# 将可执行文件中的单数转换为 0x00 格式
def ReadHexCode(code):
hex_code = []
for index in code:
if index >= 0 and index <= 15:
#print("0" + str(hex(index).replace("0x","")))
hex_code.append("0" + str(hex(index).replace("0x","")))
else:
hex_code.append(hex(index).replace("0x",""))
#print(hex(index).replace("0x",""))
return hex_code
# 获取到内存中的机器码
def GetCode():
try:
ref_code = []
dbg = MyDebug()
connect_flag = dbg.connect()
if connect_flag != 1:
return None
start_address = dbg.get_local_base()
end_address = start_address + dbg.get_local_size()
# 循环得到机器码
for index in range(start_address,end_address):
read_bytes = dbg.read_memory_byte(index)
ref_code.append(read_bytes)
dbg.close()
return ref_code
except Exception:
return False
接着则需要读者封装实现一个 SearchHexCode() 搜索函数,如下这段代码实现了在给定的字节数组中搜索特定的十六进制特征码的功能.
具体而言,函数接受三个参数:Code表示要搜索的字节数组,SearchCode表示要匹配的特征码,ReadByte表示要搜索的字节数.
函数首先获取特征码的长度,并通过一个for循环遍历给定字节数组中的所有可能匹配的位置。对于每个位置,函数获取该位置及其后面 SearchCount 个字节的十六进制表示形式,并将其与给定的特征码进行比较。如果有一位不匹配,则计数器重置为0,否则计数器加1。如果计数器最终等于特征码长度,则说明已找到完全匹配的特征码,函数返回True。如果遍历完整个数组都没有找到匹配的特征码,则函数返回False.
# 在字节数组中匹配是否与特征码一致
def SearchHexCode(Code,SearchCode,ReadByte):
SearchCount = len(SearchCode)
#print("特征码总长度: {}".format(SearchCount))
for item in range(0,ReadByte):
count = 0
# 对十六进制数切片,每次向后遍历SearchCount
OpCode = Code[ 0+item :SearchCount+item ]
#print("切割数组: {} --> 对比: {}".format(OpCode,SearchCode))
try:
for x in range(0,SearchCount):
if OpCode[x] == SearchCode[x]:
count = count + 1
#print("寻找特征码计数: {} {} {}".format(count,OpCode[x],SearchCode[x]))
if count == SearchCount:
# 如果找到了,就返回True,否则返回False
return True
exit(0)
except Exception:
pass
return False
有了这两段程序的实现流程,那么完成特征码搜索功能将变得很容易实现,如下主函数中运行后则可搜索进程内 search 中所涉及到的机器码,当搜索到后则返回一个状态.
if __name__ == "__main__":
# 读取到内存机器码
ref_code = GetCode()
if ref_code != False:
# 转为十六进制
hex_code = ReadHexCode(ref_code)
code_size = len(hex_code)
# 指定要搜索的特征码序列
search = ['c0', '74', '0d', '66', '3b', 'c6', '77', '08']
# 搜索特征: hex_code = exe的字节码,search=搜索特征码,code_size = 搜索大小
ret = SearchHexCode(hex_code, search, code_size)
if ret == True:
print("特征码 {} 存在".format(search))
else:
print("特征码 {} 不存在".format(search))
else:
print("读入失败")
由于此类搜索属于枚举类,所以搜索效率会明显变低,搜索结束后则会返回该特征值是否存在的一个标志; 。
而与之对应的,当读者搜索反汇编代码时则无需自行实现内存读入功能,LyScript插件内提供了 dbg.get_disasm_code(eip,1000) 函数,可以让我们很容易的实现读取内存的功能,如下案例中,搜索特定反汇编指令集,当找到后返回其内存地址; 。
from LyScript32 import MyDebug
# 检索指定序列中是否存在一段特定的指令集
def SearchOpCode(OpCodeList,SearchCode,ReadByte):
SearchCount = len(SearchCode)
for item in range(0,ReadByte):
count = 0
OpCode_Dic = OpCodeList[ 0 + item : SearchCount + item ]
# print("切割字典: {}".format(OpCode_Dic))
try:
for x in range(0,SearchCount):
if OpCode_Dic[x].get("opcode") == SearchCode[x]:
#print(OpCode_Dic[x].get("addr"),OpCode_Dic[x].get("opcode"))
count = count + 1
if count == SearchCount:
#print(OpCode_Dic[0].get("addr"))
return OpCode_Dic[0].get("addr")
exit(0)
except Exception:
pass
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
print("连接状态: {}".format(connect_flag))
# 得到EIP位置
eip = dbg.get_register("eip")
# 反汇编前1000行
disasm_dict = dbg.get_disasm_code(eip,1000)
# 搜索一个指令序列,用于快速查找构建漏洞利用代码
SearchCode = [
["ret", "push ebp", "mov ebp,esp"],
["push ecx", "push ebx"]
]
# 检索内存指令集
for item in range(0,len(SearchCode)):
Search = SearchCode[item]
# disasm_dict = 返回汇编指令 Search = 寻找指令集 1000 = 向下检索长度
ret = SearchOpCode(disasm_dict,Search,1000)
if ret != None:
print("指令集: {} --> 首次出现地址: {}".format(SearchCode[item],hex(ret)))
dbg.close()
如上代码当搜寻到 SearchCode 内的指令序列时则自动输出内存地址,输出效果图如下所示; 。
LyScript 插件默认并没有提供上一条与下一条汇编指令的获取功能,笔者认为通过亲自动手封装实现功能能够让读者更好的理解内存断点的工作原理,则本次我们将亲自动手实现这两个功能.
在x64dbg中,软件断点的实现原理与通用的软件断点实现原理类似。具体来说,x64dbg会在程序的指令地址处插入一个中断指令,一般是int3指令。这个指令会触发一个软件中断,从而让程序停止执行,等待调试器处理。在插入中断指令之前,x64dbg会先将这个地址处的原始指令保存下来。这样,当程序被调试器停止时,调试器就可以将中断指令替换成原始指令,让程序恢复执行.
为了实现软件断点,x64dbg需要修改程序的可执行代码。具体来说,它会将指令的第一个字节替换成中断指令的操作码,这样当程序执行到这个指令时就会触发中断。如果指令长度不足一个字节,x64dbg会将这个指令转换成跳转指令,跳转到另一个地址,然后在这个地址处插入中断指令.
此外在调试器中设置软件断点时,x64dbg会根据指令地址的特性来判断是否可以设置断点。如果指令地址不可执行,x64dbg就无法在这个地址处设置断点。另外,由于软件断点会修改程序的可执行代码,因此在某些情况下,设置过多的软件断点可能会影响程序的性能.
读者注意:实现获取下一条汇编指令的获取,需要注意如果是被命中的指令,则此处应该是 CC断点 占用一个字节,如果不是则正常获取到当前指令即可.
CC
断点,也就是汇编中的 init
停机指令,该指令占用1个字节,需要 eip+1
得到。而如果是系统断点,EIP所停留的位置,则我们需要正常获取当前指令地址,此处调试器没有改动汇编指令,仅仅只下了异常断点。
from LyScript32 import MyDebug
# 获取当前EIP指令的下一条指令
def get_disasm_next(dbg,eip):
next = 0
# 检查当前内存地址是否被下了绊子
check_breakpoint = dbg.check_breakpoint(eip)
# 说明存在断点,如果存在则这里就是一个字节了
if check_breakpoint == True:
# 接着判断当前是否是EIP,如果是EIP则需要使用原来的字节
local_eip = dbg.get_register("eip")
# 说明是EIP并且命中了断点
if local_eip == eip:
dis_size = dbg.get_disasm_operand_size(eip)
next = eip + dis_size
next_asm = dbg.get_disasm_one_code(next)
return next_asm
else:
next = eip + 1
next_asm = dbg.get_disasm_one_code(next)
return next_asm
return None
# 不是则需要获取到原始汇编代码的长度
elif check_breakpoint == False:
# 得到当前指令长度
dis_size = dbg.get_disasm_operand_size(eip)
next = eip + dis_size
next_asm = dbg.get_disasm_one_code(next)
return next_asm
else:
return None
if __name__ == "__main__":
dbg = MyDebug()
dbg.connect()
eip = dbg.get_register("eip")
next = get_disasm_next(dbg,eip)
print("下一条指令: {}".format(next))
prev = get_disasm_next(dbg,4584103)
print("下一条指令: {}".format(prev))
dbg.close()
如上代码则是显现设置断点的核心指令集,读者可自行测试是否可读取到当前指令的下一条指令,其输出效果如下图所示; 。
读者注意:获取上一条汇编指令时,由于上一条指令的获取难点就在于,我们无法确定当前指令的上一条指令到底有多长,所以只能用笨办法,逐行扫描对比汇编指令,如果找到则取出其上一条指令即可.
from LyScript32 import MyDebug
# 获取当前EIP指令的上一条指令
def get_disasm_prev(dbg,eip):
prev_dasm = None
# 得到当前汇编指令
local_disasm = dbg.get_disasm_one_code(eip)
# 只能向上扫描10行
eip = eip - 10
disasm = dbg.get_disasm_code(eip,10)
# 循环扫描汇编代码
for index in range(0,len(disasm)):
# 如果找到了,就取出他的上一个汇编代码
if disasm[index].get("opcode") == local_disasm:
prev_dasm = disasm[index-1].get("opcode")
break
return prev_dasm
if __name__ == "__main__":
dbg = MyDebug()
dbg.connect()
eip = dbg.get_register("eip")
next = get_disasm_prev(dbg,eip)
print("上一条指令: {}".format(next))
dbg.close()
运行后即可读入当前EIP的上一条指令位置处的反汇编指令,输出效果如下图所示; 。
https://www.lyshark.com/post/b62cec0e.html 。
最后此篇关于4.10x64dbg反汇编功能的封装的文章就讲到这里了,如果你想了解更多关于4.10x64dbg反汇编功能的封装的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
问题故障解决记录 -- Java RMI Connection refused to host: x.x.x.x .... 在学习JavaRMI时,我遇到了以下情况 问题原因:可
我正在玩 Rank-N-type 并尝试输入 x x .但我发现这两个函数可以以相同的方式输入,这很不直观。 f :: (forall a b. a -> b) -> c f x = x x g ::
这个问题已经有答案了: How do you compare two version Strings in Java? (31 个回答) 已关闭 8 年前。 有谁知道如何在Java中比较两个版本字符串
这个问题已经有答案了: How do the post increment (i++) and pre increment (++i) operators work in Java? (14 个回答)
下面是带有 -n 和 -r 选项的 netstat 命令的输出,其中目标字段显示压缩地址 (127.1/16)。我想知道 netstat 命令是否有任何方法或选项可以显示整个目标 IP (127.1.
我知道要证明 : (¬ ∀ x, p x) → (∃ x, ¬ p x) 证明是: theorem : (¬ ∀ x, p x) → (∃ x, ¬ p x) := begin intro n
x * x 如何通过将其存储在“auto 变量”中来更改?我认为它应该仍然是相同的,并且我的测试表明类型、大小和值显然都是相同的。 但即使 x * x == (xx = x * x) 也是错误的。什么
假设,我们这样表达: someIQueryable.Where(x => x.SomeBoolProperty) someIQueryable.Where(x => !x.SomeBoolProper
我有一个字符串 1234X5678 我使用这个正则表达式来匹配模式 .X|..X|X. 我得到了 34X 问题是为什么我没有得到 4X 或 X5? 为什么正则表达式选择执行第二种模式? 最佳答案 这里
我的一个 friend 在面试时遇到了这个问题 找到使该函数返回真值的 x 值 function f(x) { return (x++ !== x) && (x++ === x); } 面试官
这个问题在这里已经有了答案: 10年前关闭。 Possible Duplicate: Isn't it easier to work with foo when it is represented b
我是 android 的新手,我一直在练习开发一个针对 2.2 版本的应用程序,我需要帮助了解如何将我的应用程序扩展到其他版本,即 1.x、2.3.x、3 .x 和 4.x.x,以及一些针对屏幕分辨率
为什么案例 1 给我们 :error: TypeError: x is undefined on line... //case 1 var x; x.push(x); console.log(x);
代码优先: # CASE 01 def test1(x): x += x print x l = [100] test1(l) print l CASE01 输出: [100, 100
我正在努力温习我的大计算。如果我有将所有项目移至 'i' 2 个空格右侧的函数,我有一个如下所示的公式: (n -1) + (n - 2) + (n - 3) ... (n - n) 第一次迭代我必须
给定 IP 字符串(如 x.x.x.x/x),我如何或将如何计算 IP 的范围最常见的情况可能是 198.162.1.1/24但可以是任何东西,因为法律允许的任何东西。 我要带198.162.1.1/
在我作为初学者努力编写干净的 Javascript 代码时,我最近阅读了 this article当我偶然发现这一段时,关于 JavaScript 中的命名空间: The code at the ve
我正在编写一个脚本,我希望避免污染 DOM 的其余部分,它将是一个用于收集一些基本访问者分析数据的第 3 方脚本。 我通常使用以下内容创建一个伪“命名空间”: var x = x || {}; 我正在
我尝试运行我的test_container_services.py套件,但遇到了以下问题: docker.errors.APIError:500服务器错误:内部服务器错误(“ b'{” message
是否存在这两个 if 语句会产生不同结果的情况? if(x as X != null) { // Do something } if(x is X) { // Do something } 编
我是一名优秀的程序员,十分优秀!