新手福利——x64逆向基础
一、x64程序的内存和通用寄存器
随着游戏行业的发展,x32位的程序已经很难满足一些新兴游戏的需求了,因为32位内存的最大值为0xFFFFFFFF,这个值看似足够,但是当游戏对资源需求非常大,那么真正可以分配的内存就显得捉襟见肘了,于是很多公司尝试并成功的开发了64位的游戏。并且很多32位的游戏也在向64位转型。
很多初学者在刚刚接触64位程序时会觉得很陌生,想象着这是一个新的领域,会比32位的分析难度高很多。其实当你对32位的逆向有一定的基础和理解的时候,再来看64位就不那么难了。
64位与32位最直观的区别就是他可分配的内存最大值是0xFFFFFFFFFFFFFFFF。有人可能会说这也就比32位的多了一倍,其实不然,他的大小是32位的0x100000000倍。这个大小就足够我们去使用了,甚至当你在分析64位的游戏时会发现,很多地址也仅仅是1XXXXXXXX,因为目前来说这些也就足够了。
64位与32位逆向的第二个区别就是他的通用寄存器,他的通用寄存器为16个而不是8个(如图)
在这16个寄存器中,前面8个的名字与32位的很像,只是前面的E改为了R。后面的8个则以R8-R15命名。当然我们所说的这16个是通用寄存器,而后面还有16个128位的XMM寄存器(如图)以及16个256位的YMM寄存器
在初学者的学习中,我们主要来学习通用寄存器的使用。
RAX与EAX的作用是类似的,他主要用来存放函数的返回值,他的数值也是经常会变化的(如图)
图中是一个随意截取的一断64位函数代码,函数后面的RAX传递给RDI,其实就是将返回值进行传递,这里了解一下即可,后面还会详细讲解。
RCX,RDX,R8,R9则常常会做为第1-4个参数(如图)
图中是一个程序调用send函数的代码,RCX-R9分别为函数的s,buf,len,flags,当然这只是前4个参数,详细的内容我们放到后面来讲。
RSP和32位中的ESP是类似的,同样作为堆栈指针(如图)
RBP虽然偶尔会用来作为帧指针,也就是所谓的栈底,但是显然没有32位用的频繁,下图则是RBP在函数头部被赋值的情况(如图)
当然RBP也常常会被用作普通的寄存器去进行传址。
R10和R11在syscall/sysret 指令中会被使用,暂时只需要了解一下即可。
而这些寄存器中,除了RAX,RCX,RDX,R8,R9,RSP之外的寄存器,如果在函数过程中被调用,则必须在调用前对其数值进行保留(如图)
以上就是初学者对x64通用寄存器需要掌握的内容,这只是寄存器最基本的分析方法和用法。
至于XMM和YMM寄存器,虽然在32位中也有应用,但是并没有x64应用的那么广泛,甚至在OllyIDE调试器中都没有显示XMM和YMM寄存器的数值。
由于这两种寄存器的指令比较复杂,所以我们在后面的实际应用中再进行学习。
二、64位数据扫描及工具介绍
x64位程序的分析,主要用到两款工具,而这两款工具同x32位程序的分析工具类似,一款是CE,另一款则是x64dbg。
CE与32位的用法大致相同,主要用来对数据的突破口及地址进行扫描(如图)
有人可能会说64位程序应该用8字节来扫描,其实大部分作为突破口的数据都是从4字节开始扫描的,因为64位地址的需求还不是那么大,有些程序数据中只有地址和一小部分数值是8字节的,其他大部分基础数据还是习惯用4字节来存放。比如某个存放血量值的数据,由于数值的范围并不需要太大,所以DWORD就足够了,此时一个8字节的地址就可能会在低32位和高32位分别存放当前血量和最大血量两个数值。此时,如果我们用8字节来扫描血量的话,可能就扫描不到了。
有时候,在x64的程序里,我们也会遇到只有8字节有效数值的地址,但这并不是代表这个地址只有8字节,因为所有的地址都是8字节的,就好比x32程序里的所有地址都是4字节的一样。
ce的其他功能和32位都大体相同,毕竟是同一款软件的不同版本,这里就不过多的讲解了。
下面我们来看一下x64dbg,xdbg也分为32和64版本,他的界面和功能都和OD很像。随着对OD的检测力度越来越大,xdbg也逐渐成为逆向调试器的主流。不过xdbg的插件和OD是有一些差异的,所以初学者用起来并不是特别习惯。
由于OD并没有更新比较实用的x64版本,而且还没有大量插件做辅助,所以在我们调试x64程序的时候只能实用x64dbg。当然有时候我们也会用ida做一些静态分析,来配合xdbg使用。
图中是一款xdbg64的界面,从左到右,从上到下,依次为反汇编窗口,寄存器窗口,参数窗口,数据窗口,以及堆栈窗口。这些都是xdbg64的常用显示窗口,除了参数窗口是为了让我们更加清晰和容易的分析x64程序的函数参数,其他的和OD都没有什么差别。这些调试器的用法在其他的文章里都做过详细的讲解,这里就不做过多的描述了。
三、x64函数约定
在默认情况下,x64程序使用fastcall函数约定,与大部分32位程序最大的区别就是他的参数并不是通过push来进行传递的,而是默认将前4个参数存放在rcx,rdx,r8,r9中。
图中我们传递是4个int型数值,所以传递的寄存器为低32位寄存器,不难看出,这个x64程序是符合我们上面所说的函数约定的。
但是并不是所有的函数都只会用到不超过4个参数,所以,我们还要考虑有更多参数的情况。
当参数多于4个时,x64程序会将多出来的参数传递给[rsp+0x20],[rsp+0x28]......[rsp+(n+1)*8]
图中的第5个参数传递给了[rsp+0x20]。
有人可能在翻阅资料的时候会看到,有的人说第5个参数是[rsp+28],这种说法也没错,因为这两种情况观察参数的位置是不同的
如果我们在函数调用处观察参数,第5个参数是[rsp+0x20],如果我们在函数内部去观察,由于步进call的过程中会push RIP,所以此时的rsp是要-8的,所以第五个参数自然就变成了[rsp+0x28]。
虽然在x64程序中,我们默认的前4个参数是rcx-r9,但是也有例外,如果我们传递的参数是浮点型的话,那么传入浮点数的参数则会使用xmm0-xmm3来代替。
图中的第3个参数,也就是原本的r8的位置,此时已经变成了xmm2,而r8并没有做为参数传递到函数里。也就是说,如果在前4个参数中存在浮点数的话,那么,它所对应的4个通用寄存器则会被xmm寄存器所替代。
现在参数我们已经有个大概的了解了,接下来则是函数的返回值。
之前我们说过,函数的返回值是存放在rax寄存器中的,这一点和32位程序是一样的。
图中的返回值是传递给rax,如果我们返回的是个int型数值的话,那么返回值还是会像32位程序一样传给eax的。
但是这个返回值也会有例外,比如我们要返回一个浮点型的话,那么此时的返回值就会传递给xmm0,在函数执行之后rax就没有用武之地了。
在返回 __m128、 __m128i、 __m128d、float、double时,返回值会传递给xmm0,其他情况则会传递给rax。
四、x64的堆栈
32位的堆栈可以说是初学者的噩梦,很多人在学习堆栈时耗费了大量的时间,这不仅仅是因为堆栈先进后出的抽象概念,同样也是因为32位的函数运行中常常使用push,pop来传递参数和维持堆栈平衡。
x64程序的函数约定可以说是初学者的福音,在汇编代码中没有了满窗口的push、pop、add esp,xxx、sub esp,xxx,这使得堆栈的运算变得格外的简单。
比如图中我们想要分析[rsp+F8]的来源,如果他是作为参数来源于上面的某个CALL中的话,那么我们只需要高亮F8,就可以轻松的找到他所在的CALL,并不需要担心rsp在这个过程中的变化,因为rsp基本上不会改变。很明显,他的来源就在上面的一个call里
这里他作为第三个参数传递到了call里,那么如果他不是来源于某个call里,而是来源于外层的呢?那也很简单,我们直接来到函数头部,计算一下他在函数头部是rsp+?,然后在返回接着去分析就可以了。
比如这里有一个[rsp+90],他并没有来源于本层调用的某个函数,那么我们只需要在头部进行计算,减去push rdi和sub rsp,60改变的偏移,变成[rsp+0x28],再减去push RIP的8个字节,就可以得出他来源于外层的[rsp+20],很明显这是第五个参数
执行到返回后我们会发现这个函数的确有第五个参数,他的来源是r12。
在一些程序中,我们还会发现如下代码
此时的寻址方式并不是以rsp为基地址来传递局部变量和参数,那么如果我们想知道一个rbp+xxxx是局部变量还是参数,就需要到头部去进行一个相对复杂的运算,比如图中的rcx来源rbp-59,虽然我们明知他是一个局部变量(因为前面是lea),但是我们也要到头部去算一算,-59-5F= -B8,在头部的地址是rsp-B8,也就是说他是一个局部变量。
这种方式看似复杂,其实很简单,以为他不需要去计算头部的push和sub rsp,事实上这些偏移都是相对于头部的RIP的。
类似的代码还有很多种,不过我们如果单纯的去逆向数据的话,不必考虑这些寻址方式,只要能正确的去进行计算就可以了。
相关文章:

新手福利——x64逆向基础
一、x64程序的内存和通用寄存器 随着游戏行业的发展,x32位的程序已经很难满足一些新兴游戏的需求了,因为32位内存的最大值为0xFFFFFFFF,这个值看似足够,但是当游戏对资源需求非常大,那么真正可以分配的内存就显得捉襟…...
虚幻c++中的细节之枚举类型(enum)
文章目录前言一、原生c的枚举类型关键字classint8 - 枚举的基础类型(underlying type)二、枚举类型的灵活运用位运算枚举循环遍历三、虚幻风格的枚举类型UENUMUMETATEnumAsByte总结前言 虚幻引擎中的代码部分实现了一套反射机制,为c代码带了…...
判断某个字符串在另一个字符串中的个数
/** * 用于判断字符串中字符的个数 * * param str1 原字符串 * param str2 需要判断的字符 * return 返回有几个 */ private int getCount(String str1, String str2) { //获取两个字符串的长度 int oneLength str1.length(); int toLength str2.length(); //定义两个整数&am…...

测试人员如何运用好OKR
在软件测试工作中是不是还不知道OKR是什么?又或者每次都很害怕写OKR?或者总觉得很迷茫,不知道目标是什么? OKR 与 KPI 的区别 去年公司从KPI换OKR之后,我也有一段抓瞎的过程,然后自己找了两本书看,一本是《OKR工作法》…...

CentOS7 Hive2.3.9 安装部署(mysql 8.0)
一、CentOS7安装MySQL数据库 查询载mariadb rpm -qa | grep mariadb卸载mariadb rpm -e --nodeps [查询出来的内容]安装wget为下载mysql准备 yum -y install wget在tools目录下执行以下命令,下载MySQL的repo源: wget -P /tools/ https://dev.mysql.…...
【PTA Advanced】1142 Maximal Clique(C++)
目录 题目 Input Specification: Output Specification: Sample Input: Sample Output: 思路 代码 题目 A clique is a subset of vertices of an undirected graph such that every two distinct vertices in the clique are adjacent. A maximal clique is a clique …...
1. MySQL在金融互联网行业的企业级安装部署
这里写目录标题 1. 版本介绍示例2.安装MySQL规范(建议二进制)2.1 安装方式2.2 安装用户2.3 目录规范3.二进制安装3.1 操作系统配置3.2 MySQL 5.7.33 安装部署2.3 MySQL8.0.27安装2.4 源码安装(了解 )3.多实例部署及注意事项3.1 多实例概念3.2 多实例安装3.3 多实例第二种方式…...

【C++修炼之路】19.AVL树
每一个不曾起舞的日子都是对生命的辜负 AVL树前言:一.AVL树的概念二.AVL树的结构2.1 AVL树节点的定义2.2 AVL树的结构2.3 AVL树的插入2.4 AVL树的验证2.5 AVL树的删除(了解)三.AVL树的旋转(重要)3.1 左单旋3.2 右单旋3.3 左右双旋3.4 右左双旋…...

项目管理工具dhtmlxGantt甘特图入门教程(十):服务器端数据集成(下)
这篇文章给大家讲解如何利用dhtmlxGantt在服务器端集成数据。 dhtmlxGantt是用于跨浏览器和跨平台应用程序的功能齐全的Gantt图表,可满足应用程序的所有需求,是完善的甘特图图表库 DhtmlxGantt正版试用下载(qun 764149912)http…...
LeetCode 793. 阶乘函数后 K 个零
f(x) 是 x! 末尾是 0 的数量。回想一下 x! 1 * 2 * 3 * ... * x,且 0! 1 。 例如, f(3) 0 ,因为 3! 6 的末尾没有 0 ;而 f(11) 2 ,因为 11! 39916800 末端有 2 个 0 。 给定 k,找出返回能满足 f(x) …...

maven打包顺序与jvm类加载顺序
背景:一次dev测试过程中,发现代码中关于jsr303的校验失效,校验类如下,会报一个莫名其妙的运行时错误;遂进行排查。import javax.validation.constraints.NotBlank;Data Accessors(chain true) public class Demo {Not…...

④ 链表
24. 两两交换链表中的节点 题目链接:https://leetcode.cn/problems/swap-nodes-in-pairs/ 注意点: 遍历链表的时候什么时候截止(避免空指针异常或无限死循环的问题)? 节点数量为偶数或链表为空时,cur.ne…...

小孩扁桃体肿大3度能自愈吗?6岁小孩扁桃体肥大怎么治效果好?
12月7日,四川眉山市民唐先生说,他刚出生的儿子在妇产医院分娩中心住了20天后感染了败血症。据唐先生介绍,哈子出院时各项指标正常。他在分娩中心住了半个月左右,孩子喝牛奶很生气,第二天就开始发烧了。同一天ÿ…...

【C++提高编程】C++全栈体系(二十二)
C提高编程 第三章 STL - 常用容器 五、stack容器 1. stack 基本概念 概念:stack是一种先进后出(First In Last Out,FILO)的数据结构,它只有一个出口 栈中只有顶端的元素才可以被外界使用,因此栈不允许有遍历行为 栈中进入数据称为 — 入…...

linux系统编程2--网络编程socket知识
在linux系统编程中网络编程是使用socket(套接字),socket这个词可以表示很多概念:在TCP/IP协议中,“IP地址TCP或UDP端口号”唯一标识网络通讯中的一个进程,“IP地址端口号”就称为socket。在TCP协议中&#…...
Python-__repr__、__hash__和__eq__方法,split()、join()、yield()和append()函数
1.__repr__方法程序1class Python:passa Python() print(a) print(a.__repr__())结果<__main__.Python object at 0x0000023B82185FD0> <__main__.Python object at 0x0000023B82185FD0>默认情况下,我们得到的信息只会是“类名object at内存地址”程序…...

【安卓开发】安卓广播机制
读书笔记系列(第一行代码) 5.1 广播机制简介 标准广播:完全异步执行,广播发出后,所有广播接收器几乎都同一时刻收到这条广播(无法被截断)有序广播:同步执行,广播发出后…...

移动WEB开发四、rem布局
零、文章目录 文章地址 个人博客-CSDN地址:https://blog.csdn.net/liyou123456789个人博客-GiteePages:https://bluecusliyou.gitee.io/techlearn 代码仓库地址 Gitee:https://gitee.com/bluecusliyou/TechLearnGithub:https:…...
request.getURL()和request.getURI() 以及通过request获得路径相关大全
request.getURL()和request.getURI() 如果我的请求是:http://localhost:8080/ServletTest/servlet/Hello request.getRequestURI() 返回值类似:/ServletTest/servlet/Hello request.getRequestURL() 返回值类似:http://localhost:8080/Servle…...

java网络编程-nio学习:阻塞和非阻塞
一、阻塞 阻塞模式下,相关方法都会导致线程暂停 ServerSocketChannel.accept 会在没有连接建立时让线程暂停 SocketChannel.read 会在没有数据可读时让线程暂停 阻塞的表现其实就是线程暂停了,暂停期间不会占用 cpu,但线程相当于闲置 单线…...
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...

[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?
论文网址:pdf 英文是纯手打的!论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误,若有发现欢迎评论指正!文章偏向于笔记,谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...
OkHttp 中实现断点续传 demo
在 OkHttp 中实现断点续传主要通过以下步骤完成,核心是利用 HTTP 协议的 Range 请求头指定下载范围: 实现原理 Range 请求头:向服务器请求文件的特定字节范围(如 Range: bytes1024-) 本地文件记录:保存已…...

Android15默认授权浮窗权限
我们经常有那种需求,客户需要定制的apk集成在ROM中,并且默认授予其【显示在其他应用的上层】权限,也就是我们常说的浮窗权限,那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...

QT: `long long` 类型转换为 `QString` 2025.6.5
在 Qt 中,将 long long 类型转换为 QString 可以通过以下两种常用方法实现: 方法 1:使用 QString::number() 直接调用 QString 的静态方法 number(),将数值转换为字符串: long long value 1234567890123456789LL; …...
【Go语言基础【13】】函数、闭包、方法
文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数(函数作为参数、返回值) 三、匿名函数与闭包1. 匿名函数(Lambda函…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
Java毕业设计:WML信息查询与后端信息发布系统开发
JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发,实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构,服务器端使用Java Servlet处理请求,数据库采用MySQL存储信息࿰…...

Git 3天2K星标:Datawhale 的 Happy-LLM 项目介绍(附教程)
引言 在人工智能飞速发展的今天,大语言模型(Large Language Models, LLMs)已成为技术领域的焦点。从智能写作到代码生成,LLM 的应用场景不断扩展,深刻改变了我们的工作和生活方式。然而,理解这些模型的内部…...