- 将读出的值再加上偏移 x 作为地址,然后将地址向下取整做 4 字节对齐
- 从计算出的地址的值读入到 R0 寄存器中
条件和标志位响应
CPSR 寄存器
CPSR 寄存器结构如下图所示:
各标志位含义:
N,bit[31]
若运算结果为 0 或正数则该该标志位置 0,若运算结果为负数则该标志位置 1 。Z,bit[30]
运算结果为 0 则置 1,否则置 0 。C,bit[29]
无符号数溢出,加法溢出置 1,减法溢出置 0。V,bit[28]
有符号数溢出T,bit[5]
T = 0
表示 Arm 模式T = 1
表示 Thumb 模式。
注意:指令是否影响标志位取决于是否是否加 S 后缀(大多数情况,具体看指令硬编码第 20 位是否置 1),比如 MOV
不影响标志位但 MOVS
影响标志位。
执行条件
cond 标志的值及其对应含义如下表所示:
cond 标志位位于指令硬编码的高 4 比特,在执行时根据标志寄存器决定该指令是否执行。
MOV 指令
MOV 不访问内存,因此操作数只能是寄存器或立即数。
MOV 立即数
由于 ARM 汇编指令长度的影响,对立即数范围有严格的限制。允许 MOV 的立即数有如下几类:
- 立即数不超过 16 位
该指令在给寄存器低 16 比特赋值的同时会将寄存器高 16 比特清零。 - 立即数可以用 不超过8 比特的数循环右移不超过 32 的偶数得到
其中 imm12 中的低 8 比特是需要循环右移的数,高 4 比特乘 2 是需要循环右移的次数。 - (MOVT)立即数不超过 16 位且需要移动到寄存器高 16 位(通常与 MOV 配合使且应当先 MOV 后 MOVT)
该指令在给寄存器高 16 比特赋值的同时不会将寄存器低 16 比特清零。
MOV 寄存器, 寄存器
- 寄存器 + 立即数移位
例如MOV R0, R1,LSL#4
,该指令等同于LSL R0, R1,#4
。
移位类型由 stype 决定,移位的值为 imm5 。 - 寄存器 + 寄存器移位
例如MOV R0, R1,LSR R2
,该指令等同于LSR R0, R1,R2
。
基本整型运算
相关指令
ADD
:加
ADR
:PC 与操作数相加结果放入结果寄存器中ADRL
:伪指令,与ADR
相似,不过通过类似MOV + MOVT
的方式使得寻址范围更大CMN
:加,只影响标志寄存器
SUB
:减
CMP
:减,只影响标志寄存器
RSB
:反减AND
:与
TST
:与,只影响标志寄存器
BIC
:第二个操作数与第三个操作数的反码逻辑与结果放在第一个寄存器中ORR
:或EOR
:异或
TEQ
:异或,只影响标志寄存器
LSL
:逻辑左移LSR
:逻辑右移ASR
:算术右移
ADD 指令(举例)
- ADD 立即数
这里 12 比特长的立即数与前面 MOV 的机制一样,采用移位的方式将其扩展为 32 位范围。 - ADD 寄存器,立即数移位
与 MOV 机制相同,例如ADD R0, R1, R2,LSL #4
。 - ADD 寄存器,寄存器移位
- ADR
本质还是 ADD,不过被加数为 PC 寄存器。由于设计到读 PC 寄存器,因此根据当前所处的模式,读出来的 PC 寄存器的值会加上相应的偏移。
访存指令
数据流向
- LDR:
寄存器 ← 内存
,例:ldr r0, [pc, #8]
,ldr r3, [r5], #4
。 - STR:
寄存器 → 内存
,例:str r3, [r4]
。
操作的寄存器和内存地址
- 寄存器:
LDR R0, [R1]
- 寄存器 + 偏移(立即数):
LDR R0, [R1,#4]
- 12 位立即数即偏移,不存在移位扩展。
- U 为立即数的正负号。
- P = 0 则外偏移,W = 1 则内偏移,内外偏移不能同时存在。
- 寄存器 + 移位偏移(寄存器):
LDR R0, [R1,R2,LSL #4]
LDR R0, [R1,R2,LSL R3]
后续的附加行为
- 内偏移:
LDR R0, [R1,#4]!
该指令表示将[R1 + 4]
赋值给 R0 ,然后将 R1 的值设为R1 + 4
。 - 外偏移:
LDR R0, [R1],#4
该指令表示将[R1]
赋值给 R0 ,然后将 R1 的值设为R1 + 4
。
注意:外偏移和内偏移不能同时存在。
根据附加附加行为性质可知:
PUSH R0
相当于STR R0, [SP,#-4]!
POP R0
相当于LDR R0, [SP],#4
块访存指令
指令结构
LDM\STM+后缀 寄存器(!), {寄存器组}
- LDM 表示将寄存器指向的地址的数据依次存放在寄存器组中。
- STM 表示将寄存器组中的数据依次存放在寄存器指向的地址。
- 寄存器组可以写作范围,比如
{R0-R4}
;也可指定具体寄存器,比如{R0,R2,R3}
。但是读写操作是按照寄存器下标的顺序依次操作寄存器组中的寄存器(编号小的在低地址),因为指令对应硬编码无法体现出寄存器组的顺序。
以 LDM 为例:
后缀类型
- I 表示地址加;D 表示地址减。
- A 表示先读写内存,再改变指向;B 表示先改变指向,再读写内存。
- 带 ! 表示修改的指向写入寄存器;不带 ! 表示修改的指向不写入寄存器。
- 如果操作地址寄存器为 SP 时LDMFD 相当于 LDMIA ;STMFD 相当于 STMDB 。
根据不同后缀类型的性质可以确定如下用法:
- STMFD 相当于 PUSH
- LDMFD 相当于 POP
- STM\LDMIA 可以快速复制内存
分支和模式切换
B + imm
- 跳转目标:立即数
- 模式切换:不带模式切换
- 写入 LR 的值:不影响 LR 寄存器
指令编码的立即数为目标地址与 PC 寄存器的差值除 4 。由于涉及读 PC 寄存器,因此根据当前模式要加上相应的偏移。跳转范围为 PC 值加上正负 32M 的偏移。
BL + imm
- 跳转目标:立即数
- 模式切换:不带模式切换
- 写入 LR 的值:
下一条指令的地址 | T 标志位
BX + reg
- 跳转目标:寄存器中的值去掉最低一位
- 模式切换:跳转时将寄存器中存储的地址的最低一位写入 T 标志位
- 写入 LR 的值:不影响 LR 寄存器。
BLX + imm
- 跳转目标:立即数
- 模式切换:一定切换模式
- 写入 LR 的值:
下一条指令的地址 | T 标志位
BLX + reg
- 跳转目标:寄存器中的值去掉最低一位
- 模式切换:跳转时将寄存器中存储的地址的最低一位写入 T 标志位
- 写入 LR 的值:
下一条指令的地址 | T 标志位
拓展
BX reg
和MOV PC, reg
的区别:BX 可以切换模式,MOV 不能切换模式。LDR PC, [R0]
:可以做模式切换,常用于 PLT 表中调用 GOT 表中对应的函数地址(最低位表示模式)。LDMFD SP!, {R11,PC}
:同样可以做模式切换,常与STMFD SP!, {R11,PC}
一起用于函数调用时保存栈帧和返回地址。
Thumb 模式
特点
- 段指令一般不使用 R8-R12
- 一般没有条件码和标志响应位,指令默认影响标志位
- 运算指令优先对第一,第二操作数相同情况有短指令编码。对于 STMFD 和 LDMFD,如果以 SP 寄存器的值作为地址则简写为 PUSH 和 POP 。
IT 块
结构如下图:
IT 指令的 mask 编码为从高到低,T 为 0,E 为 1 ,最后填一个 1 表示结束。比如 ITTEE EQ
的 mask 的二进制形式为 0111
。
调用约定
- 前 4 个参数:R0-R3,其它参数栈传递
- 非异变寄存器:R4-R11,使用此类寄存器的函数负责恢复寄存器原来的值。
- R11/FP:栈帧指针,类似 EBP。
- R12:导入表寻址
函数示例:
0x00010570 push {fp, lr}; ; 保存 FP 和 LR 寄存器,其中 FP 寄存器在栈顶。
0x00010574 add fp, sp, #4; ; FP 寄存器指向保存返回地址的位置。
0x00010578 sub sp, sp, #0x20; ; 抬升栈顶,开辟栈空间。
0x0001057C sub r3, fp, #0x24; ; R3 寄存器指向局部变量 char s[0x24] 开头,也就是栈顶。
0x00010580 mov r2, #0x20; ; memset 参数3
0x00010584 mov r1, #0; ; memset 参数2
0x00010588 mov r0, r3; ; memset 参数1
0x0001058C bl #0x10410; ; 调用 memset@plt
0x00010590 ldr r0, [pc, #0x40]; ; 由于是 ARM 模式,因此是取 0x00010590 + 8 + 0x40 = 0x000105D8 地址处的值。考虑到 ARM 的访存能力,编译器会为每个函数创建一个地址表来记录全局变量的地址。
0x00010594 bl #0x103d4; ; 调用 puts@plt
0x00010598 ldr r0, [pc, #0x3c];
0x0001059C bl #0x103d4;
0x000105A0 ldr r0, [pc, #0x38];
0x000105A4 bl #0x103d4;
0x000105A8 ldr r0, [pc, #0x34];
0x000105AC bl #0x103bc;
0x000105B0 sub r3, fp, #0x24; ; R3 寄存器指向局部变量 char s[0x24] 开头。
0x000105B4 mov r2, #0x38; ; read 第 3 个参数
0x000105B8 mov r1, r3; ; read 第 2 个参数
0x000105BC mov r0, #0; ; read 第 1 个参数
0x000105C0 bl #0x103c8; ; 调用 read@plt
0x000105C4 ldr r0, [pc, #0x1c];
0x000105C8 bl #0x103d4;
0x000105CC mov r0, r0;
0x000105D0 sub sp, fp, #4; ; SP = FP - 4 ,即指向了栈上保存 FP 寄存器的值的位置。
0x000105D4 pop {fp, pc}; ; 恢复 FP 和 PC 寄存器。
.text:000105D8 B0 06 01 00 off_105D8 DCD aForMyFirstTric ; DATA XREF: pwnme+20↑r
.text:000105D8 ; “For my first trick, I will attempt to f”…
.text:000105DC 10 07 01 00 off_105DC DCD aWhatCouldPossi ; DATA XREF: pwnme+28↑r
.text:000105DC ; “What could possibly go wrong?”
.text:000105E0 30 07 01 00 off_105E0 DCD aYouThereMayIHa ; DATA XREF: pwnme+30↑r
.text:000105E0 ; “You there, may I have your input please”…
.text:000105E4 90 07 01 00 off_105E4 DCD format ; DATA XREF: pwnme+38↑r
.text:000105E4 ; "> "
.text:000105E8 94 07 01 00 off_105E8 DCD aThankYou ; DATA XREF: pwnme+54↑r
.text:000105E8 ; “Thank you!”
对应反编译代码如下:
int pwnme()
{
char s[36]; // [sp+0h] [bp-24h] BYREF
memset(s, 0, 0x20u);
puts(“For my first trick, I will attempt to fit 56 bytes of user input into 32 bytes of stack buffer!”);
puts(“What could possibly go wrong?”);
puts(“You there, may I have your input please? And don’t worry about null bytes, we’re using read()!\n”);
printf("> ");
read(0, s, 0x38u);
return puts(“Thank you!”);
}
MIPS32
寄存器
通用寄存器
MIPS 有 32 个通用寄存器 (General purpose registers),以美元符号 ($) 表示。可以表示为 $0~ 31 ,也可以用寄存器名称表示如, 31,也可以用寄存器名称表示如, 31,也可以用寄存器名称表示如,sp、 t 9 、 t9 、 t9、fp 等等。
寄存器 | 名称 | 用途 |
---|---|---|
$0 | $zero | 常量0 |
$1 | $at | 保留给汇编器 |
$2-$3 | v 0 − v0- v0−v1 | 函数调用返回值 |
$4-$7 | a 0 − a0- a0−a3 | 函数调用参数 |
$8-$15 | t 0 − t0- t0−t7 | 暂时使用,不需要保存恢复 |
$16-$23 | s 0 − s0- s0−s7 | 使用需要保存和恢复 |
$24-$25 | t 8 − t8- t8−t9 | 暂时使用,不需要保存和恢复,$t9 通常与调用函数有关 |
$28 | $gp | 全局指针,用来充当寄存器间接寻址时的基址寄存器 |
$29 | $sp | 堆栈指针 |
$30 | $fp | 栈帧指针 |
$31 | $ra | 返回地址 |
pwndbg 中的 S8
寄存器对应的是 $fp
,而 pwndbg 中的 FP
寄存器貌似是虚拟出来用来表示栈底的,大概就是始终指向每次进一个函数时的栈顶位置。
修改一下 pwndbg/lib/regs.py
中寄存器的定义,让 $ra
寄存器也能显示出来。
http://logos.cs.uic.edu/366/notes/mips%20quick%20tutorial.htm
r0 => zero
r1 => temporary
r2-r3 => values
r4-r7 => arguments
r8-r15 => temporary
r16-r23 => saved values
r24-r25 => temporary
r26-r27 => interrupt/trap handler
r28 => global pointer
r29 => stack pointer
r30 => frame pointer
r31 => return address
mips = RegisterSet(
frame=“fp”,
retaddr=(“ra”,),
gpr=(
“v0”,
“v1”,
“a0”,
“a1”,
“a2”,
“a3”,
“t0”,
“t1”,
“t2”,
“t3”,
“t4”,
“t5”,
“t6”,
“t7”,
“t8”,
“t9”,
“s0”,
“s1”,
“s2”,
“s3”,
“s4”,
“s5”,
“s6”,
“s7”,
“s8”,
“gp”,
“ra”,
),
args=(“a0”, “a1”, “a2”, “a3”),
retval=“v0”,
)
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数网络安全工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年网络安全全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上网络安全知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加VX:vip204888 (备注网络安全获取)
本人从事网路安全工作12年,曾在2个大厂工作过,安全服务、售后服务、售前、攻防比赛、安全讲师、销售经理等职位都做过,对这个行业了解比较全面。
最近遍览了各种网络安全类的文章,内容参差不齐,其中不伐有大佬倾力教学,也有各种不良机构浑水摸鱼,在收到几条私信,发现大家对一套完整的系统的网络安全从学习路线到学习资料,甚至是工具有着不小的需求。
最后,我将这部分内容融会贯通成了一套282G的网络安全资料包,所有类目条理清晰,知识点层层递进,需要的小伙伴可以点击下方小卡片领取哦!下面就开始进入正题,如何从一个萌新一步一步进入网络安全行业。
学习路线图
其中最为瞩目也是最为基础的就是网络安全学习路线图,这里我给大家分享一份打磨了3个月,已经更新到4.0版本的网络安全学习路线图。
相比起繁琐的文字,还是生动的视频教程更加适合零基础的同学们学习,这里也是整理了一份与上述学习路线一一对应的网络安全视频教程。
网络安全工具箱
当然,当你入门之后,仅仅是视频教程已经不能满足你的需求了,你肯定需要学习各种工具的使用以及大量的实战项目,这里也分享一份我自己整理的网络安全入门工具以及使用教程和实战。
项目实战
最后就是项目实战,这里带来的是SRC资料&HW资料,毕竟实战是检验真理的唯一标准嘛~
面试题
归根结底,我们的最终目的都是为了就业,所以这份结合了多位朋友的亲身经验打磨的面试题合集你绝对不能错过!
一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
定需要学习各种工具的使用以及大量的实战项目,这里也分享一份我自己整理的网络安全入门工具以及使用教程和实战。
项目实战
最后就是项目实战,这里带来的是SRC资料&HW资料,毕竟实战是检验真理的唯一标准嘛~
面试题
归根结底,我们的最终目的都是为了就业,所以这份结合了多位朋友的亲身经验打磨的面试题合集你绝对不能错过!
一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-NtxgRgZi-1712497044671)]