ASM16

花指令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
MyStack segment stack
db 256 dup(?)
MyStack ends

MyData segment
MY_MSG db "Hello World!",0dh,0ah,'$'
MyData ends

MyCode segment
MAIN:
mov ax,MyData
mov ds,ax
mov es,ax
jmp LABEL1
db 0b8h ;花指令

LABEL1:
mov dx,offset MY_MSG
mov ah,09h
int 21h

mov ax,4c00h
int 21h
MyCode ends

end MAIN

image-20240915205902100

从B8开始下面全部的代码都会出错 但是运行的结果是不变的 只不过反汇编代码分析时会被干扰(实现代码加密)

image-20240915210152335

找到花指令 写入一条机器码 从正确的地方开始分析 即可获得正确的代码

image-20240916152531096

子程序

重复利用代码段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
MyStack segment stack
db 256 dup(?)
MyStack ends

MyData segment
MY_MSG db "Hello World!",0dh,0ah,'$'
MyData ends

MyCode segment
MAIN:
mov ax,MyData
mov ds,ax
mov es,ax
mov bx,offset RETURN1
jmp SHOW_HELLO
RETURN1:
mov bx,offset RETURN2
jmp SHOW_HELLO
RETURN2:

;LABEL1:
mov ax,4c00h
int 21h ;退出程序
SHOW_HELLO:
mov dx,offset MY_MSG
mov ah,09h
int 21h
jmp ax


MyCode ends

end MAIN

但是按照这种做法会有局限性jmp ax跳转回去时若ax的值发生改变则不能使用

修改后(效率太低):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
MyStack segment stack
db 256 dup(?)
MyStack ends

MyData segment
MY_MSG db "Hello World!",0dh,0ah,'$'
MyData ends

MyCode segment
MAIN:
mov ax,MyData
mov ds,ax
mov es,ax

mov ax,offset RETURN1
push ax
jmp SHOW_HELLO
RETURN1: ;子程序
mov bx,offset RETURN2
push ax
jmp SHOW_HELLO
RETURN2:


;LABEL1:
mov ax,4c00h
int 21h ;退出程序
SHOW_HELLO:
mov dx,offset MY_MSG
mov ah,09h
int 21h
pop ax
jmp ax


MyCode ends

end MAIN

用子程序改一下:

1
2
3
4
5
mov ax,offset RETURN1
push ax
jmp SHOW_HELLO
RETURN1: ;子程序
等同于 call SHOW_HELLO
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
MyStack segment stack
db 256 dup(?)
MyStack ends

MyData segment
MY_MSG db "Hello World!",0dh,0ah,'$'
MyData ends

MyCode segment
MAIN:
mov ax,MyData
mov ds,ax
mov es,ax

;mov ax,offset RETURN1
;push ax
;jmp SHOW_HELLO ;子程序 call ret
;RETURN1:
call SHOW_HELLO


mov ax,4c00h
int 21h ;退出程序
SHOW_HELLO:
push ax ;保存环境
mov dx,offset MY_MSG
mov ah,09h
int 21h

pop ax;恢复环境
;pop ax
;jmp ax 等价于 ret
ret


MyCode ends

end MAIN

恢复环境

1
2
3
4
pop dx: 从堆栈中恢复 dx 寄存器的值。
pop cx: 从堆栈中恢复 cx 寄存器的值。
pop ax: 从堆栈中恢复 ax 寄存器的值。
retn 4: 返回调用者,并清理堆栈中的4个字节(两个参数)。(平衡堆栈)

函数调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
MyStack segment stack
db 256 dup(?)
MyStack ends

MyData segment
MY_MSG1 db "Hello World1!",0dh,0ah,'$'
MY_MSG2 db "Hello World2!",0dh,0ah,'$'
MyData ends

MyCode segment
MAIN:
mov ax,MyData
mov ds,ax
mov es,ax

mov ax,09h ;参数2
push ax
mov ax,offset MY_MSG1 ;参数1 从右往左边入栈
push ax
call SHOW_HELLO
; add sp 4 ;stdcall调用约定

mov ax,09h
push ax
mov ax,offset MY_MSG2
push ax
call SHOW_HELLO
; add sp 4

mov ax,4c00h
int 21h

SHOW_HELLO:
push ax ;保存环境
push cx
push dx

mov bp,sp
mov cx,0
mov dx,word ptr [bp+8] ;访问参数1 ;[bp+8]由于前面存在三行push
mov ah,byte ptr [bp+10] ;访问参数2
int 21h

pop dx
pop cx
pop ax ;恢复环境
; pop ax
; jmp ax ==> pop ip

; pop ax
; add sp,4
; push ax
; ret
retn 4 ;mov ip,[sp] add sp,4 c调用约定

MyCode ends

end MAIN

运行结果:

image-20240916162425868

调试

运行完call指令后,IP的地址改为call后面的地址,堆栈中存放了call指令接下来的指令的地址,还有前面压入栈的两个参数

image-20240807193111067

image-20240807193327561

axcxdx的值被保存到堆栈

image-20240807193615477

从堆栈中取出参数,运行函数得出结果

image-20240807194018812

然后堆栈被平衡,axcxdx的值被还原,程序回到函数调用后要执行的指令的地方

image-20240807194519138