0x00
开设日常学习和笔记分享的篇章,帮助大家来学习汇编语言。为什么要学习汇编语言呢?是由于在红蓝对抗中,常常因为一些AV/EDR的存在导致我们的工具被查杀。所以才需要我们来对抗AV也就是免杀技术。所以要学习免杀技术就要从基础开始。后续可能还会分享一些C++、PE文件结构等等笔记。另外也可能会推出逆向相关的知识。
0x01
作业一:
assume cs:code
code segment
mov ax,0
mov cx,236
s:
add ax,123
loop s
mov ax,4c00h
int 21h
code ends
end
作业二:
assume cs:codesg
codesg segment
mov ax,200h
mov ds,ax
mov bx,0
mov cx,64
s:
mov ds:[cx],cx
inc bx
loop s
mov ax,4c00h
int 21h
codesg ends
end
五、包含多个段得程序
前面的程序只有一个代码段,如果程序需要用其他空间来存放数据,使用前面的安全空间0:200~02ff 只有256字节,不一定够使用
操作系统的环境中,合法的通过操作系统取得的空间都是安全的,一种是加载程序的时候为程序分配,凌一种是执行的过程中向系统申请,我们学习不讨论第二种方法
我们若要一个程序在被加载的时候取得所需的空间,则必须要在源程序中说明,通过在源程序中顶一段来进行内存空间的获取
在代码段中使用数据
考虑一个问题:编程计算 0123h、 0456h、0789h、0abch、0defh、0fedh、0cbah、0987h 八个数的和,结果存在ax中。
前面的课程里我们都是累加内存单元中的数据,并不关心数据本身,而要累计的就是已经给定了数值的数据,希望用循环的方式累加,所以累加钱要将数据存储在一组地址连续的内存单元中。
要做到这点,可以用指令一个一个将他们送入地址连续的内存单元中,那从哪里找这段内存单元?我们不能自己决定,应让操作系统为我们分配
我们可以在程序中定义希望处理的数据,这些数据被编译、链接程序作为程序的一部分写道可执行文件中,可执行文件中的程序加载入内存时,这些数据同时被加载入内存,要处理的数据自然获得了存储空间。
assume cs:code
code segment
dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h
mov bx,0
mov ax,0
mov cx,8
s:
add ax,cs:[bx]
add bx,2
loop s
mov ax,4c00h
int 21h
code ends
end
程序第一行dw含义时定义字型数据,即define word,,使用dw定义了8个字型数据,所占的内存空间的大小为16个字节。
程序中的指令就要对这8个数据进行累加,由于他们在代码段中,程序运行时cs中存放代码段的段地址,所以可以从cs中得到他们的段地址,由于dw定义的数据位于代码段开始,所以偏移地址分别位于偏移0、2、4、6、8、A、C、E处
程序中,用bx存放加2递增的偏移地址,用循环来累加,循环开始前设置(bx)=0,cs:bx指向第一个数据所在的字单元,每次循环中(bx)=(bx)+2,cs:bx指向下一个数据所在的字单元
但是程序的入口处不是我们希望执行的命令,我们可以在源程序中指明入口所在
assume cs:code
code segment
dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h
start:
mov bx,0
mov ax,0
mov cx,8
s:
add ax,cs:[bx]
add bx,2
loop s
mov ax,4c00h
int 21h
code ends
end start
我们在程序的第一条指令前面加上标号start,这个标号在伪指令end后面出现,也就是说enbd除了指明程序结束,还通知编译器入口位于start处
在单任务系统中,可执行文件中的程序执行过程如下:
- 由于其他的程序将可执行文件加载入内存
- 设置CS:IP执行程序的入口
- 程序运行结束后返回到加载者
由此我们可以安排程序的框架:
assume cs:code
code segment
数据
start:
代码
code ends
end start
在代码段中使用段
完成下面的程序,利用栈,将程序中定义的数据逆序存放
assume cs:codesg
codesg segment
dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h
?
codesg ends
end
大致思路如下:
程序运行时,定义的数据存放在 CS:0~CS:F 单元中,依次将这8个字单元中的数据入栈,然后再一次出栈到这8个字单元中,从而实现数据的逆序存放问题是,我们首先要有一段可当作栈空间的内存空间,应该由操作系统分配,可以在程序汇总通过定义数据来取得一段空间,然后当作栈空间使用
assume cs:codesg
codesg segment
dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //用dw定义16个字型数据,程序加载后将得到16个字的内存空间
start:
mov ax,cs
mov ss,ax
mov sp,30h //设置栈顶ss:sp指向cs:30
mov bx,0
mov cx,8
s:
push cs:[bx]
add bx,2
loop s
mov bx,0
mov cx,8
s0:
pop cs:[bx]
add bx,2
loop s0
mov ax,4c00h
int 21h
codesg ends
end start
将数据、代码、栈放入不同的段
代码和数据放到一个段中显得混乱,如果栈和代码、数据需要的空间超过64KB,就不能存放在一个段中,所以就像定义代码段一样定义多个段,在这些段里面定义需要的数据,或者定义数据来取得栈空间
assume cs:code,ds:data,ss:stack
data segment
dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h
data ends
stack segment
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
stack ends
code segment
start:mov ax,stack
mov ss,ax
mov sp,20h
mov ax,data
mov ds,ax
mov bx,0
mov cx,8
s: push [bx]
add bx,2
loop s
mov bx,0
mov cx,8
s0:pop [bx]
add bx,2
loop s0
mov ax,4c00h
int 21h
code ends
end start
对段地址的引用
现在程序有多个段,段名相当于一个标号,代表了段地址,所以mov ax,data 就是把数据段的段地址送入ax,程序中数据段中的0abch 的地址时data:6,将它送入bx中,就需要
mov ax,data
mov ds,ax
mov bx,ds:[6]
代码段、数据段、栈段都是我们自己的安排,CPU并不认识,而assume是伪指令,cs、ds、ss也不会分别和code、data、stack段相连,如果改成一下形式,计算机处理结果相同
assume cs:b,ds:a,ss:c
a segment
dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h
a ends
c segment
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
c ends
b segment
d:mov ax,c
mov ss,ax
mov sp,20h
mov ax,a
mov ds,ax
mov bx,0
mov cx,8
s: push [bx]
add bx,2
loop s
mov bx,0
mov cx,8
s0:pop [bx]
add bx,2
loop s0
mov ax,4c00h
int 21h
b ends
end d
0x02
往期笔记:
往期实战:
红队视角下的域森林突破:一场由Shiro反序列化引发的跨域控攻防对抗
域控接管后的“核爆效应”:基于DCSync与黄金票据的1600台主机权限收割
原文始发于微信公众号(伍六七安全):汇编语言Day05
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论