逆向学习笔记
逆向学习笔记
汇编了解部分
一 通用寄存器
通用寄存器是一种用于存储和操作数据的硬件组件【一个典型CPU一般由运算器,控制器,寄存器等器件组成】。它们是计算机体系结构中的一部分,用于临时存储和处理数据。通用寄存器通常具有固定的位数大小,在一台计算机中可能会有多个通用寄存器。(例如AX,BX,CX,DX四个寄存器通常存放一般性数据,因此被称为通用寄存器。)
通用寄存器的主要功能包括:
- 存储数据:通用寄存器可以用来存储指令中的操作数、临时结果和其他需要在计算过程中保存的数据。
- 数据操作:通过通用寄存器,可以对存储在其中的数据执行各种数学和逻辑操作,如加法、减法、乘法、移位和逻辑运算等。
- 数据传输:通用寄存器可以用来传输数据,比如从内存中读取数据到寄存器,或将寄存器中的数据写回到内存中。
通用寄存器在计算机体系结构中起着重要的作用,因为它们提供了一个快速访问和操作数据的方式。不同的体系结构可能会有不同数量和命名方式的通用寄存器。
二 标志寄存器
标志寄存器是计算机中的一种特殊寄存器,用于存储特定的标志位或状态信息。它通常用于记录程序运行过程中的条件和结果,以便进行条件分支、循环等控制操作。
常见的标志寄存器包括:
- 零标志位(ZF):用于表示运算结果是否为零。
- 进位标志位(CF):用于表示无符号数运算过程中是否发生进位或借位。
- 溢出标志位(OF):用于表示有符号数运算过程中是否发生溢出。
- 符号标志位(SF):用于表示运算结果的符号。
- 奇偶标志位(PF):用于表示运算结果中 1 的个数的奇偶性。
三 基础汇编指令
基础汇编指令是用于编写汇编语言程序的基本指令集。这些指令用于执行各种操作,例如数据传输、运算、控制流程等。下面是一些常见的基础汇编指令:
1.数据传送指令:
指令 | 名称 | 示例 | 备注 |
---|---|---|---|
MOV | 传送指令 | MOV dest, src | 将数据从src移动到dest |
PUSH | 进栈指令 | PUSH src | 把源操作数src压入堆栈 |
POP | 出栈指令 | POP desc | 从栈顶弹出字数据到dest |
相关补充:movb传送字节;movw传送字(2Byte):movl传送双字;movq传送四字。
2.算术运算指令:
指令 | 名称 | 示例 | 备注 |
---|---|---|---|
ADD | 加法指令 | ADD dest, src | 在dest基础上加src |
SUB | 减法指令 | SUB dest, src | 在dest基础上减src |
3.逻辑运算指令:
指令 名称 示例 备注
NOT 取反运算指令 NOT dest 把操作数dest按位取反
AND 与运算指令 AND dest, src 把dest和src进行与运算之后送回dest
OR 或运算指令 OR dest, src 把dest和src进行或运算之后送回dest
XOR 异或运算 XOR dest, src 把dest和src进行异或运算之后送回dest
4.转移指令:
指令 名称 示例 备注
JMP 无条件转移指令 JMP lable 无条件地转移到标号为label的位置
CALL 过程调用指令 CALL labal 直接调用label
JE 条件转移指令 JE lable zf =1 时跳转到标号为label的位置
JNE 条件转移指令 JNE lable zf=0 时跳转到标号为label的位置
5.其他:
RET指令则是将栈顶的返回地址弹出到EIP,然后按照EIP此时指示的指令地址继续执行程序。
JZ跳转 ZF=1,运算结果为0 跳转
JNZ跳转 ZF≠1,运算结果不为0时 跳转
四 栈
百度百科解释:栈(stack)又名堆栈,它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。
栈是一种数据结构,它按照后进先出(LIFO)的原则存储和访问数据。这意味着最后进入栈的元素首先被访问和移除。栈有两个主要操作:推入(push)将元素放入栈的顶部,弹出(pop)将顶部元素移除。
五 内存分区
在没有运行程序前,也就是说程序没有加载到内存前,可执行程序内部已经分好3段信息,分别为代码区(text)、数据区(data) 和 未初始化数据区(bss) 3 个部分(有人直接把data和bss合起来叫做静态区或全局区)
代码区
存放 CPU 执行的机器指令。
通常代码区是可共享的(即另外的执行程序可以调用它),使其可共享的目的是对于频繁被执行的程序,只需要在内存中有一份代码即可。代码区通常是只读的,使其只读的原因是防止程序意外地修改了它的指t令。另外,代码区还规划了局部变量的相关信息。
全局初始化数据区/静态数据区(data段)
该区包含了在程序中明确被初始化的全局变量、已经初始化的静态变量(包括全局静态变量和t)和常量数据(如字符串常量)。
未初始化数据区(又叫 bss 区)
存入的是全局未初始化变量和未初始化静态变量。未初始化数据区的数据在程序开始执行之前被内核初始化为 0 或者空(NULL)。
总体来讲说,程序源代码被编译之后主要分成两种段:程序指令(代码区)和程序数据(数据区)。代码段属于程序指令,而数据域段和.bss段属于程序数据。
题目部分
六 base64
基础内容链接已经十分清晰,一言蔽之就是3 * 8=4 * 6.下面的代码就是base64的核心,移位和保留位数。
1 | for(i=0,j=0;i<len1;i+=3,j+=4) |
七 Task思路分析
T1和T2都是base64基础题,难点在于读懂加密代码和确认解码表是否是标准形式,所以第一步便是查找字符串,找到解码表,如Task1中shift+F12发现“WERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm7894561230+/”字符串,对比标准解码表发现少一位字符对应,所以在字符串上下找隐藏的解码字符,发现上方51h,对其R转化位字符“Q“,将其与解码字符串拼接得到完整解码表,再用python编写脚本,将题目给我们要解码字符串’KRWfD4zPB7bcrdCyVVsxM9Kiw78itVs0’放入即可解出flag。
1 | import base64 |
脚本运行结果(Task1):
1 | bytearray(b'D0g3{I_Love_YingdaoMayi}') |
如法炮制,Task2更为简单,解码过程与Task1相同并且解码表就是原表,同样相关数据代入脚本
1 | import base64 |
脚本运行结果(Task2):
1 | bytearray(b'D0g3{I_Love_YingdaoMayi}') |
Task3没有解出来,主要原因是IDA的调试,尤其是动态调试熟练度不够,导致开启IDA调试模式后很迷茫,不知道要一步一步做什么,去找flag,所以希望学长师傅们能分享一点相关知识,如果能在线上会议讲一讲就更好了(萌新瑟瑟发抖.jpg)
八 学习感悟
re的学习我个人感觉主要靠刷题,看博客,学大佬们怎么写高效好用的脚本和最重要的解题思路,尤其是解题思路这块,这决定我能否把每一份功都用在找flag上,除此之外,不懂就问也很重要,因为自己想要的知识,答案网络上不一定合适,完整,且通俗易懂,所以及时向学长问问题能节约很多不必要的时间。(在此十分感谢学长的细致教导)