Skip to content
  1. use16: 16位寻址
  2. segment: 是段定义语法
assume cs:code, ds:data

告诉编译器,某个变量段地址为data:时要替换为ds:.

其中 assume 为伪指令

  1. .386为伪指令,表示使用哪个指令集。

  2. 命令行参数:

    C/C++ 中 main 函数的 argc 与 argv.

执行:

g++ .\main.cpp -o main
.\main.exe 123 456

输出文件位置, 123, 456.

#include<iostream>
#include<windows.h>
using namespace std;
const int N=2e5+10;
int main(int argc,char *argv[]) {
    if(argc==3){
        printf("%s %s %s",argv[0],argv[1],argv[2]);
    }
    system("pause");
    return 0;
}

汇编中psp:[80h]处存放了命令行参数的长度,psp:[81h]开始存放命令行参数。注意这里psp不是寄存器,前面写法是为了简便,想要访问psp需要用未赋初值的ds/es寄存器。

  1. ss:sp ss:sp指向堆栈顶端。 每次push操作, sp=sp-2, 按小端规则存入变量。

  2. es 初始指向psp,需要赋值后使用。

  3. 只有bx,bp,si,di可以放在[] 中。

  4. cli/sti:IF=0/1 禁止/启用硬件中断,Windows/linux中是特权指令,用户程序没有权限执行这两条指令,只有操作系统可以执行。(编写驱动程序)

  5. int8h:时钟中断,用于分时,运行多进程程序

  6. int9h:键盘中断,读取键盘按下对应编码

  7. TF:Trap Flag,陷阱标志,TF=1,CPU进入单步模式:执行完一条指令,插入一条int1h并执行,int1h称为单步中断,按下键盘后执行下一步。

  8. int1h可以用来反调试:调试器与程序抢夺int1h的绑定关系,程序抢到int1h调试器就不能运行,调试器抢到int1h程序就不能运行(可以在自己的int1h对指令机器码加减某个数做加密/解密)。
  9. 显卡控制:段地址B800h,通过更改里面内容,显示不同的字母/背景颜色
  10. 用方波发生器唱歌
  11. 32位寻址:eax,ecx,edx,esp,ebx,ebp,esi,edi都可以放在[]中。
  12. [寄存器+寄存器]对寄存器组合无限制(16位只能b_+_i而不能di+si,bx+bp);

    还有[eax+ebx*n+c],n=1,2,4,8;c常数

    当[]中有bp,默认段地址为ss 18. 发生Divide overflow时,cpu会在当前指令上方插入一条int00h并执行 19. int00h的函数地址保存在dword ptr 0:[0]中 20. softice:

    ldr //调试某个程序
    F6/ec entercode//进入代码窗
    d 0:0 跳转到地址0:[0]
    u 684:8 观察code段中的指令
    F2/BPX 断点
    x execute 执行相当于td的run全速执行
    F8 单步执行 
    F5 用户屏幕
    ec enter code-window进入代码窗
    ctrl+d 挂起softice
    bpmb //Break Point on Memory Byte
    //softice支持4个硬件断点,他会把断点地址写入调试寄存器dr0,dr1,dr2,dr3,再把断点类型信息(R,W,RW,X)写入dr7
    bpmb cs:104 x //在cs:104处设一个执行硬件断点
    bpmb ds:200 w (C=01)//在ds:200处被改写(1次)时断住
    bpmb ds:200 r//在ds:200处被读取时断住
    R32 //观察32位寄存器
    . //定位当前指令cs:[ip]
    
    21. 22. cbw,cwd:字节到字扩展,字到双字扩展 23. movzx,movsx:zero expansion,sign expansion 24. imul:
    imul eax,ebx ;eax*=ebx
    imul eax,ebx,3;eax=ebx*3
    
    25. xlat:(translate) 查表指令 26. repe cmpsb:如果相等,则继续比较 27. cmpsb会停在不等的位置的后一位,则需要-1获得不等的两个元素 28. 判断全等:如果zf=1,则最后一次比较也是相等的,则全等
    repe cmpsb
    je equal ;如果ZF=1,则全等
    repne cmpsb
    jne not_equal
    
    29. scasb 扫描
    cmp al, es:[di]
    
    可用来计算字符串长度/跳过前导重复字符
  13. stosb 赋值store

    mov es:[di], al
    
    相当于memset
  14. lodsb 加载load

    mov al, ds:[si]
    
    lodsb 加rep没有意义
  15. 几个特殊位置

0000:7C00 第一个扇区

B800

psp

0000:0000

  1. tasm /m2 jmp 扫描两次来解决不知道跳转是短跳还是近跳导致的nop的出现 然后使用tlink 来link
  2. byte ptr ; 1字节
    word ptr ; 2字节
    dword ptr; 4字节(32位整数或float类型小数)
    fword ptr; 6字节(4字节偏移地址+2字节段地址)
    qword ptr; 8字节(64位整数或double类型小数)
    tbyte ptr; 10字节(long double类型的80位小数)
    short     用来修饰一个短的标号
    near ptr 用来修饰一个近的标号
    far ptr  用来修饰一个远的标号
    
  3. call far ptr + retf 远跳调用函数

  4. __asm int 3在C语言中加入软件断点

  5. ret n , n是参数,表示将栈退回n个byte

  6. pragma comment(linker, '\SECTION:.text.RWX') 让windows代码段(code段)可写,可以改动printf等函数

  7. it's been a long day without you my friend and i'll tell you all about it when i see you again we've come a long way from where we began oh i'll tell you all abnout it when i see you again. when i see you again. damn who knew all the place we flew good things we been through that i'll be standing right there talking to you bout another path i know we love to hit the road and laugh

  8. #include<stdio.h>
    int *f(int i){
        int a[3]={10,20,30};
        return *a[i];
    }
    int main(){
        int *p;
        p=f(1);
        printf("%d\n",*p);
        return 0;
    }
    
    这段程序无法正确显示a[1],因为a[1]是动态变量,子程序结束后栈空间退回,动态变量死亡。 所以使用static.
    #include<stdio.h>
    int *f(int i){
        static int a[3]={10,20,30};
        return *a[i];
    }
    int main(){
        int *p;
        p=f(1);
        printf("%d\n",*p);
        return 0;
    }
    
  9. 事实上不被覆盖就可以正确显示,但是有[Warning] address of local variable 'a' returned [-Wreturn-local-addr]

  10. gcc内嵌asm:

    #include<stdio.h>
    int main(){
        int input=1, output=0,temp=-1;
        printf("%d\n",output);
        printf("%d\n",temp);
        __asm__ __volatile__
        ("movl $0, %%eax; movl  %%eax, %1;     movl  %2, %%eax; movl  %%eax, %0; "
        :"=m"(output),"=m"(temp)    /* output */
        :"r"(input)     /* input */
        :"eax");  /* 描述符 */
        printf("%d\n",output);
        printf("%d\n",temp);
        return 0;
    }
    
  11. __declspec(naked)?

  12. ip和fl时无法正常赋值的寄存器,使用ret,call,pushf,popf等进行更改/取出
  13. gbt 全局描述符
  14. lgbt 把gbt中的内容加载到gbtr中(48位向量)
  15. sgbt 把gbtr中内容复制到gbt中
  16. 指令+中断汇总

int 21h(ah=01h,02h,09h,0ah)
int 8h;时钟中断
int 0h;除法溢出
int 1h;单步执行
int 3h;软件断点
int 9h;键盘按下/释放
int 10h;图形模式
db,dw,dd,df,dq,dt

add
sub
mul
imul
div
idiv
xchg
xlat
pop 
push
popf
pushf
lgbt
sgbt;gbt,寄存器gbtr
mov 
movsb
cmpsb
scasb
stosb
lodsb
rep
call
ret
call far ptr
retf
int
iret
daa; 判断AF=1,AL的低4位向高4位进位/借位,或(AL & 0Fh)>9,此时AL=AL+6
cli
sti
cld
sti
stc
clc
movzx
movsx
cbw;al->ax
cwd;ax->dx:ax
cdq;eax->edx:eax
sbb/adc
dec/inc
neg;求相反数 
fadd/fsub/fmul/fdiv
fld ;入栈加载
fstp ;出栈保存
sal
sar
jcxz
48. shl,shr,sal,sar,rol,ror都会把移位溢出的位移入CF 48. TF要通过popf,pushf赋值 49. in al, 60h; 从端口60h读取一个字节并存放到AL中
  1. 以读取键盘为例, 以下为从高层到低层的编程方式排序:
    dos         高   mov ah, 1; int 21h 功能弱,但编程简单
    bios        中   mov ah, 0; int 16h
    in/out      低   in al, 60h; 功能强, 但编程麻烦
    
  2. push word ptr ds:[bx+2] 允许push后加内存
  3. 16位汇编中,远指针是指16位段地址:16位偏移地址; 32位汇编中,远指针是指16位段地址:32位偏移地址。 48位的远指针在汇编语言中有一个类型修饰词: fword ptr 近指针(near pointer):偏移地址就是近指针 16位汇编中,近指针是指16位的偏移地址; 32位汇编中,近指针是指32位的偏移地址;
  4. mul/imul第二种用法
    mul eax, ebx; eax = eax * ebx
    imul eax, ebx, 3; eax = ebx * 3