滴水逆向--01-16 内存地址_堆栈
内存地址
反汇编窗口和寄存器窗口数据存储都是从高位到低位,数据区则是由低位到高位

寻址公式一:[立即数]
-
读取内存的值:
1
2MOV EAX, DWORD PTR DS:[0x13FFC4]
MOV EAX, DWORD PTR DS:[0x13FFC8] -
向内存中写入数据:
1
2MOV DWORD PTR DS:[0x13FFC4], eax
MOV DWORD PTR DS:[0x13FFC8], ebx -
获取内存编号:
1
2LEA EAX, DWORD PTR DS:[0x13FFC4]
LEA EAX, DWORD PTR DS:[ESP+8]LEA 拿的是内存的编号
寻址公式二:[reg] reg代表寄存器,可以是 8 个通用寄存器中的任意一个
-
读取内存的值:
1
2MOV EAX, 0x13FFD0
MOV EAX, DWORD PTR DS:[ECX] -
向内存中写入数据:
1
2MOV EDX, 0x13FFD8
MOV DWORD PTR DS:[EDX], 0x87654321 -
获取内存编号:
1
2MOV EAX, DWORD PTR DS:[EDX]
LEA EAX, DWORD PTR DS:[EDX]LEA 执行过后 EAX = EDX
寻址公式三:[reg+立即数]
-
读取内存的值:
1
2MOV ECX, 0x13FFD0
MOV EAX, DWORD OTR DS:[ECX+4] -
向内存中写入数据:
1
2MOV EDX, 0x13FFD8
MOV DWORD PTR DS:[EDX+0xC], 0x87654321 -
获取内存编号:
1
2MOV EAX, DWORD PTR DS:[EDX+4]
LEA EAX, DWORD PTR DS:[EDX+4]
寻址公式四:[reg+reg*{1,2,4,8}]
-
读取内存的值:
1
2
3MOV EAX, 0x13FFC4
MOV ECX, 2
MOV EDX, DWORD PTR DS:[EAX+ECX*4] -
向内存中写入数据:
1
2
3MOV EAX, 0x13FFC4
MOV ECX, 2
MOV DWORD PTR DS:[EAX+ECX*4], 0x87654321 -
获取内存编号:
1
LEA EAX, DWORD PTR DS:[EAX+ECX*4]
寻址公式五:[reg+reg*{1,2,4,8}+立即数]
-
读取内存的值:
1
2
3MOV EAX, 0x13FFC4
MOV ECX, 2
MOV EDX, DWORD PTR DS:[EAX+ECX*4+4] -
向内存中写入数据:
1
2
3MOV EAX, 0x13FFC4
MOV ECX, 2
MOV DWORD PTR DS:[EAX+ECX*4+4], 0x87654321 -
获取内存编号:
1
LEA EAX, DWORD PTR DS:[EAX+ECX*4+2]
堆栈
堆栈的优点:临时存储大量的数据,便于查找
1 | MOV EBX, 0x13FFDC BASE |
-
压入数据
-
方式一:
1
2MOV DWORD PTR DS:[EDX-4], 0xAAAAAAAA
SUB EDX, 4 -
方式二:
1
2SUB EDX, 4
MOV DWORD PTR DS:[EDX], 0xBBBBBBBB -
方式三:
1
2MOV DWORD PTR DS:[EDX-4], 0xDDDDDDDD
LEA EDX, DWORD PTR DS:[EDX-4] -
方式四:
1
2LEA EDX, DWORD PTR DS:[EDX-4]
MOV DWORD PTR DS:[EDX], 0xEEEEEEEE
-
-
读取第 N 个数
-
方式一:通过 BASE 加偏移来读取
1
2
3
4读第一个压入的数据:
MOV ESI, DWORD PTR DS:[EBX-4]
读第四个压入的数据:
MOV ESI, DWORD PTR DS:[EBX-0x10] -
方式二:通过 TOP 加偏移来读取
1
2
3
4读第二个压入的数据:
MOV EDI, DWORD PTR DS:[EDX+8]
读第三个压入的数据:
MOV EDI, DWORD PTR DS:[EDX+4]
-
-
弹出数据
-
方式一:
1
2MOV ECX, DWORD PTR DS:[EDX]
LEA EDX, DWORD PTR DS:[EDX+4] -
方式二:
1
2MOV ESI, DWORD PTR DS:[EDX]
ADD EDX, 4 -
方式三:
1
2LEA EDX, DWORD PTR DS:[EDX+4]
MOV EDI, DWORD PTR DS:[EDX-4]
-
PUSH 指令:
1 | PUSH r32 执行后栈顶指针+4 |
POP 指令:
1 | POP r32 |
PUSH/POP 一个立即数,永远都是esp ± 4;16 位 r/m – esp ± 2; 32 位 ± 4
PUSH 与 POP 操作没有跟 8 位寄存器的可能
PUSHAD 指令:把所有通用寄存器压入堆栈
POPAD 指令:恢复现场,把所有寄存器的值恢复
保护现场用,在 pushad 后可以随便动寄存器,调试后用 popad 恢复现场
课后作业
-
使用 EBX 存储栈底地址,EDX 存储栈顶地址,连续存储 5 个不同的数

运行后:

-
分别使用栈底加偏移、栈顶加偏移的方式读取这 5 个数,并存储到寄存器

两个方式各取一个数,运行后:

-
弹出这 5 个数,恢复栈顶到原来的位置

运行后:

-
使用 2 种方式实现:push ecx
1
2MOV DWORD PTR DS:[ESP-4], ECX
SUB ESP, 41
2MOV DWORD PTR DS:[ESP-4], ECX
LEA ESP, DWORD PTR DS:[ESP-4] -
使用 2 种方式实现:pop ecx
1
2MOV ECX, DWORD PTR DS:[ESP]
ADD ESP, 41
2MOV ECX, DWORD PTR DS:[ESP]
LEA ESP, DWORD PTR DA:[ESP+4] -
使用 2 种方式实现:push esp
1
2MOV DWORD PTR DS:[ESP-4], ESP
SUB ESP, 41
2MOV DWORD PTR DS:[ESP-4], ESP
LEA ESP, DWORD PTR DS:[ESP-4] -
使用 2 种方式实现:pop esp
1
MOV ESP, DWORD PTR DS:[ESP]
1
2LEA ESP, DWORD PTR DS:[ESP+4]
MOV ESP, DWORD PTR DS:[ESP-4]