逆向学习笔记

汇编了解部分

一 通用寄存器

通用寄存器是一种用于存储和操作数据的硬件组件【一个典型CPU一般由运算器,控制器,寄存器等器件组成】。它们是计算机体系结构中的一部分,用于临时存储和处理数据。通用寄存器通常具有固定的位数大小,在一台计算机中可能会有多个通用寄存器。(例如AX,BX,CX,DX四个寄存器通常存放一般性数据,因此被称为通用寄存器。)

通用寄存器的主要功能包括:

  1. 存储数据:通用寄存器可以用来存储指令中的操作数、临时结果和其他需要在计算过程中保存的数据。
  2. 数据操作:通过通用寄存器,可以对存储在其中的数据执行各种数学和逻辑操作,如加法、减法、乘法、移位和逻辑运算等。
  3. 数据传输:通用寄存器可以用来传输数据,比如从内存中读取数据到寄存器,或将寄存器中的数据写回到内存中。

通用寄存器在计算机体系结构中起着重要的作用,因为它们提供了一个快速访问和操作数据的方式。不同的体系结构可能会有不同数量和命名方式的通用寄存器。

二 标志寄存器

标志寄存器是计算机中的一种特殊寄存器,用于存储特定的标志位或状态信息。它通常用于记录程序运行过程中的条件和结果,以便进行条件分支、循环等控制操作。

常见的标志寄存器包括:

  1. 零标志位(ZF):用于表示运算结果是否为零。
  2. 进位标志位(CF):用于表示无符号数运算过程中是否发生进位或借位。
  3. 溢出标志位(OF):用于表示有符号数运算过程中是否发生溢出。
  4. 符号标志位(SF):用于表示运算结果的符号。
  5. 奇偶标志位(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
2
3
4
5
6
7
8
9
10
11
12
for(i=0,j=0;i<len1;i+=3,j+=4)
{
str2[j]=table[str1[i]>>2];
//将待加密的第一个字符(binary)右移2位(保留其前六位对应一个base64编码字符)
str2[j+1]=table[(((str1[i]&3)<<4)|(str1[i+1]>>4))];
//将待加密的第二个字符保留其二进制的后两位(&3),再左移4位,由此得到的六位对应一个base64编码字符
str2[j+2]=table[((str1[i+1]&15)<<2)|(str1[i+2]>>6)];
//此时第二个待加密的字符还剩下四个二进制位没有参与编码,所以&15保留第二个待加密字符的后4位,再左移两位使其变成六位中的高四位,再和第三个待加密字符右移六位后剩下的前两位合并,对应一个base64编码字符
str2[j+3]=table[str1[i+2]&63];
//保留最后一个待加密字符的后6位对应一个base64编码字符
}

七 Task思路分析

T1和T2都是base64基础题,难点在于读懂加密代码和确认解码表是否是标准形式,所以第一步便是查找字符串,找到解码表,如Task1中shift+F12发现“WERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm7894561230+/”字符串,对比标准解码表发现少一位字符对应,所以在字符串上下找隐藏的解码字符,发现上方51h,对其R转化位字符“Q“,将其与解码字符串拼接得到完整解码表,再用python编写脚本,将题目给我们要解码字符串’KRWfD4zPB7bcrdCyVVsxM9Kiw78itVs0’放入即可解出flag。

1
2
3
4
5
6
7
8
9
10
import base64  
data = 'KRWfD4zPB7bcrdCyVVsxM9Kiw78itVs0'
T1 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
T2 = 'QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm7894561230+/'
result = ''
for ch in data:
result += T1[T2.index(ch)]
result = bytearray(base64.b64decode(result))

print(result)

脚本运行结果(Task1):

1
bytearray(b'D0g3{I_Love_YingdaoMayi}')

如法炮制,Task2更为简单,解码过程与Task1相同并且解码表就是原表,同样相关数据代入脚本

1
2
3
4
5
6
7
8
9
10
import base64  
data = 'RDBnM3tJX0xvdmVfWWluZ2Rhb01heWl9'
T1 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
T2 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
result = ''
for ch in data:
result += T1[T2.index(ch)]
result = bytearray(base64.b64decode(result))

print(result)

脚本运行结果(Task2):

1
bytearray(b'D0g3{I_Love_YingdaoMayi}')

Task3没有解出来,主要原因是IDA的调试,尤其是动态调试熟练度不够,导致开启IDA调试模式后很迷茫,不知道要一步一步做什么,去找flag,所以希望学长师傅们能分享一点相关知识,如果能在线上会议讲一讲就更好了(萌新瑟瑟发抖.jpg)

八 学习感悟

re的学习我个人感觉主要靠刷题,看博客,学大佬们怎么写高效好用的脚本和最重要的解题思路,尤其是解题思路这块,这决定我能否把每一份功都用在找flag上,除此之外,不懂就问也很重要,因为自己想要的知识,答案网络上不一定合适,完整,且通俗易懂,所以及时向学长问问题能节约很多不必要的时间。(在此十分感谢学长的细致教导)