精华内容
下载资源
问答
  • 保护机制

    千次阅读 2020-05-04 09:30:57
    一、CANNARY(栈溢出保护) ​ 栈溢出保护是一种用缓冲区溢出攻击环节手段,当函数存在缓冲区溢出漏洞时,攻击者可以覆盖栈上的返回地址来让shellcode能够得到执行。当启用栈保护后,函数开始执行的时候就会向往栈里...

    一、CANNARY(栈溢出保护)

    ​ 栈溢出保护是一种用缓冲区溢出攻击环节手段,当函数存在缓冲区溢出漏洞时,攻击者可以覆盖栈上的返回地址来让shellcode能够得到执行。当启用栈保护后,函数开始执行的时候就会向往栈里插入cookie信息,当函数真正返回的时候回验证cookie信息是否合法,若果不合法就会停止程序运行。攻击者在覆盖返回地址的时候往往也会将cookie信息给覆盖掉,导致栈保护检查失败,而阻止shellcode的执行,在Linux中将cookie信息称为canary。

    当开启栈溢出时不可以覆盖最后的canary内容,但是可以对canary前面进行溢出

    GCC用法:

    gcc -o test test.c // 默认情况下,不开启Canary保护
    gcc -fno-stack-protector -o test test.c //禁用栈保护
    gcc -fstack-protector -o test test.c //启用堆栈保护,不过只为局部变量中含有 char 数组的函数插入保护代码
    gcc -fstack-protector-all -o test test.c //启用堆栈保护,为所有函数插入保护代码
    -fno-stack-protector /-fstack-protector / -fstack-protector-all (关闭 / 开启 / 全开启)
    

    二、FORTIFY

    ​ fortify是轻微的检查,用于检查是否存在缓冲区溢出的错误。适用于程序采用大量的字符串或者内存操作函数,如:

    >>> memcpy():
    	描述:void *memcpy(void *str1, const void *str2, size_t n)
        	 从存储区str2复制n个字符到存储区str1
      参数:str1 -- 指向用于存储复制内容的目标数组,类型强制转换为 void* 指针
        	 str2 -- 指向要复制的数据源,类型强制转换为 void* 指针
        	 n -- 要被复制的字节数
      返回值:该函数返回一个指向目标存储区 str1 的指针
    ---------------------------------------------------------------------------------------
    >>> memset():
      描述:void *memset(void *str, int c, size_t n)
        	 复制字符 c(一个无符号字符)到参数 str 所指向的字符串的前 n 个字符
      参数:str -- 指向要填充的内存块
        	 c -- 要被设置的值。该值以 int 形式传递,但是函数在填充内存块时是使用该值的无符号字符形式
        	 n -- 要被设置为该值的字节数
      返回值:该值返回一个指向存储区 str 的指针
    ---------------------------------------------------------------------------------------
    >>> strcpy():
      描述:char *strcpy(char *dest, const char *src)
        	 把 src 所指向的字符串复制到 dest,容易出现溢出
      参数:dest -- 指向用于存储复制内容的目标数组
        	 src -- 要复制的字符串
      返回值:该函数返回一个指向最终的目标字符串 dest 的指针
    -------------------------------------------------------------------------------------->>> stpcpy():
      描述:extern char *stpcpy(char *dest,char *src)
        	 把src所指由NULL借宿的字符串复制到dest所指的数组中
      说明:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串返回指向dest结尾处字符(NULL)的指针	 
      返回值:
    ---------------------------------------------------------------------------------------    >>> strncpy():
      描述:char *strncpy(char *dest, const char *src, size_t n)
        	 把 src 所指向的字符串复制到 dest,最多复制 n 个字符。当 src 的长度小于 n 时,dest 的剩余部分将用空字节填充
      参数:dest -- 指向用于存储复制内容的目标数组
        	 src -- 要复制的字符串
        	 n -- 要从源中复制的字符数
      返回值:该函数返回最终复制的字符串
    --------------------------------------------------------------------------------------->>> strcat():
      描述:char *strcat(char *dest, const char *src)
        	 把 src 所指向的字符串追加到 dest 所指向的字符串的结尾
      参数:dest -- 指向目标数组,该数组包含了一个 C 字符串,且足够容纳追加后的字符串
        	 src -- 指向要追加的字符串,该字符串不会覆盖目标字符串
      返回值:
    --------------------------------------------------------------------------------------->>> strncat():
      描述:char *strncat(char *dest, const char *src, size_t n)
        	 把 src 所指向的字符串追加到 dest 所指向的字符串的结尾,直到 n 字符长度为止
      参数:dest -- 指向目标数组,该数组包含了一个 C 字符串,且足够容纳追加后的字符串,包括额外的空字符
        	 src -- 要追加的字符串
        	 n -- 要追加的最大字符数
      返回值:该函数返回一个指向最终的目标字符串 dest 的指针
    --------------------------------------------------------------------------------------->>> sprintf():PHP
      描述:sprintf(format,arg1,arg2,arg++)
        	 arg1、arg2、++ 参数将被插入到主字符串中的百分号(%)符号处。该函数是逐步执行的。在第一个 % 符号处,插入 arg1,在第二个 % 符号处,插入 arg2,依此类推
      参数:format -- 必需。规定字符串以及如何格式化其中的变量
        	 arg1 -- 必需。规定插到 format 字符串中第一个 % 符号处的参
        	 arg2 -- 可选。规定插到 format 字符串中第二个 % 符号处的参数
        	 arg++ -- 可选。规定插到 format 字符串中第三、四等等 % 符号处的参数
      返回值:返回已格式化的字符串
    --------------------------------------------------------------------------------------->>> snprintf():
      描述:int snprintf ( char * str, size_t size, const char * format, ... )
        	 设将可变参数(...)按照 format 格式化成字符串,并将字符串复制到 str 中,size 为要写入的字符的最大数目,超过 size 会被截断
      参数:str -- 目标字符串
        	 size -- 拷贝字节数(Bytes)如果格式化后的字符串长度大于 size
        	 format -- 格式化成字符串
      返回值:如果格式化后的字符串长度小于等于 size,则会把字符串全部复制到 str 中,并给其后添加一个字符串结束符 \0。 如果格式化后的字符串长度大于 size,超过 size 的部分会被截断,只将其中的 (size-1) 个字符复制到 str 中,并给其后添加一个字符串结束符 \0,返回值为欲写入的字符串长度
    --------------------------------------------------------------------------------------->>> vsprintf():PHP
      描述:vsprintf(format,argarray)sprintf() 不同,vsprintf() 中的参数位于数组中。数组元素将被插入到主字符串中的百分号(%)符号处。该函数是逐步执行的
      参数:format -- 必需。规定字符串以及如何格式化其中的变量
        	 argarray -- 必需。带有参数的一个数组,这些参数会被插到 format 字符串中的 % 符号处
      返回值:以格式化字符串的形式返回数组值
    --------------------------------------------------------------------------------------->>> vsnprintf():
      描述:int vsnprintf (char * s, size_t n, const char * format, va_list arg )
        	 将格式化数据从可变参数列表写入大小缓冲区
    如果在printf上使用格式,则使用相同的文本组成字符串,但使用由arg标识的变量参数列表中的元素而不是附加的函数参数,并将结果内容作为C字符串存储在s指向的缓冲区中 (以n为最大缓冲区容量来填充)。如果结果字符串的长度超过了n-1个字符,则剩余的字符将被丢弃并且不被存储,而是被计算为函数返回的值。在内部,函数从arg标识的列表中检索参数,就好像va_arg被使用了一样,因此arg的状态很可能被调用所改变。在任何情况下,arg都应该在调用之前的某个时刻由va_start初始化,并且在调用之后的某个时刻,预计会由va_end释放
      参数:s -- 指向存储结果C字符串的缓冲区的指针,缓冲区应至少有n个字符的大小
        	 n -- 在缓冲区中使用的最大字节数,生成的字符串的长度至多为n-1,为额外的终止空字符留下空,size_t是一个无符号整数类型
        	 format -- 包含格式字符串的C字符串,其格式字符串与printf中的格式相同
         	 arg -- 标识使用va_start初始化的变量参数列表的值
      返回值:如果n足够大,则会写入的字符数,不包括终止空字符。如果发生编码错误,则返回负数。注意,只有当这个返回值是非负值且小于n时,字符串才被完全写入
    --------------------------------------------------------------------------------------->>> gets():
      描述:char *gets(char *str)
        	 从标准输入 stdin 读取一行,并把它存储在 str 所指向的字符串中。当读取到换行符时,或者到达文件末尾时,它会停止,具体视情况而定
      参数:str -- 这是指向一个字符数组的指针,该数组存储了 C 字符串
      返回值:如果成功,该函数返回 str。如果发生错误或者到达文件末尾时还未读取任何字符,则返回 NULL 	
    

    GCC用法:

    gcc -D_FORTIFY_SOURCE=1  仅仅只在编译时进行检查(尤其是#include <string.h>这种文件头)
    gcc -D_FORTIFY_SOURCE=2  程序执行时也会进行检查(如果检查到缓冲区溢出,就会终止程序)
    

    在-D_FORTIFY_SOURCE=2时,通过对数组大小来判断替换strcpy、memcpy、memset等函数名,从而达到防止缓冲区溢出的作用

    三、NX(DEP)

    ​ NX即No-eXecute(不可执行)的意思,NX(DEP)的基本原理是将数据所在内存表示为不可执行,当程序溢出成功转入shellcode时,程序会尝试在数据页面上执行命令,此时CPU就会抛出异常,而不去执行恶意代码,主要防止在数据区溢出

    ​ 正常在栈溢出时通过跳转指令跳转至shellcode,但是NX开启后CPU会对数据区域进行检查,当发现正常程序不执行,并跳转至其他地址后会抛出异常,接下来不会继续执行shellcode,而是去转入异常处理,处理后会禁止shellcode继续执行

    GCC 用法:

    gcc -o test test.c // 默认情况下,开启NX保护
    gcc -z execstack -o test test.c // 禁用NX保护
    gcc -z noexecstack -o test test.c // 开启NX保护
    -z execstack / -z noexecstack (关闭 / 开启)
    

    四、PIE(ASLR)

    ​ 一般情况下NX(Windows平台上称为DEP)和地址空间分布随机化(ASLR)会同时工作。内存地址随机化机制有三种情况

    0 - 表示关闭进程地址随机化
    1 - 表示将mmap的基地址,栈基地址和.so地址随机化
    2 - 表示在1的基础上增加heap的地址随机化
    

    可以防止Ret2libc方式针对DEP的攻击。ASLR和DEP配合使用,能有效阻止攻击者在堆栈上运行恶意代码

    Linux下关闭PIE的命令:

    sudo -s echo 0 > /proc/sys/kernel/randomize_va_space
    

    GCC用法:

    gcc -o test test.c // 默认情况下,不开启PIE
    gcc -fpie -pie -o test test.c // 开启PIE,此时强度为1
    gcc -fPIE -pie -o test test.c // 开启PIE,此时为最高强度2
    gcc -fpic -o test test.c // 开启PIC,此时强度为1,不会开启PIE
    gcc -fPIC -o test test.c // 开启PIC,此时为最高强度2,不会开启PIE
    -no-pie / -pie (关闭 / 开启)
    

    gcc中的-fPIC选项是针对某些特殊机型做了特殊处理,比如适合动态链接并能避免超出GOT大小限制之类的错误

    五、RELRO

    ​ 在Linux系统安全领域数据可以写的存储区就会是攻击的目标,尤其是存储函数指针的区域。所以在安全防护的角度应尽量减少可写的存储区域

    RELRO会设置符号重定向表格为只读或者程序启动时就解析并绑定所有动态符号,从而减少对GOT表的攻击。如果RELRO为Partial RELRO,就说明对GOT表具有写权限

    GCC用法:

    gcc -o test test.c // 默认情况下,是Partial RELRO
    gcc -z norelro -o test test.c // 关闭,即No RELRO
    gcc -z lazy -o test test.c // 部分开启,即Partial RELRO
    gcc -z now -o test test.c // 全部开启
    -z norelro / -z lazy / -z now (关闭 / 部分开启 / 完全开启)
    
    展开全文
  • c变量的压栈操作

    2019-09-26 20:20:42
    int main() { long t = 10; int x = 10; short y = 20; char c = 'a'; return 0; } 生成的汇编如下 1、long t = 10 ⇒ movq $10, -16(%rbp) 也就是 10 存储在下面8字节中。... %rb...
    int main()
    {
       long t = 10;
       int x = 10;
       short y = 20;
       char c = 'a';
        return 0;
    }
    生成的汇编如下
    1long t = 10 
    ⇒
    movq    $10, -16(%rbp)   
    也就是 10 存储在下面8字节中。
     %rbp - 16 
     %rbp - 15
     %rbp - 14
     %rbp - 13
     %rbp - 12
     %rbp - 11
     %rbp - 10
     %rbp - 9
    
    int x = 10;
     ⇒
    movl    $10, -8(%rbp)
    
    也就是 10 存储在下面4字节中。
     %rbp - 8
     %rbp - 7
     %rbp - 6
     %rbp - 5
    
    short y = 20;
     ⇒
    movw    $20, -4(%rbp)
    
    也就是 10 存储在下面2字节中。
    
       %rbp - 4
    
     %rbp - 3
    
    char c = 'a';
    
     ⇒
    movb    $97, -1(%rbp)
    
    也就是 a存储在下面1字节中。
     %rbp - 1

    从上面的例子可以看出,变量值从低地址到高地址存放。

    转载于:https://www.cnblogs.com/snail88/p/7474388.html

    展开全文
  • 如何对程序栈进行保护,当要控制程序执行过程,需要先保护栈。然后执行要执行的代码,最后恢复栈 保护基本方法为: pushq %rsp pushq (%rsp) andq $-0x10, %rsp 执行要执行的代码 movl 8(%rsp), %rsp

    如何对程序栈进行保护,当要控制程序执行过程,需要先保护栈。然后执行要执行的代码,最后恢复栈


    保护基本方法为:

    pushq %rsp
    pushq (%rsp)
    andq $-0x10, %rsp

    执行要执行的代码

    movl 8(%rsp), %rsp



    展开全文
  • 好了,我们的压栈过程就到此讲完了,下面我们来了解一下,中断程序返回即出栈的过程,假设此时ESP已经跳过错误码指向eip_old 当处理器执行到 iret指令时,它首先需要从栈中返回CS_old 及EIP_old,由于处理器在中断...

    我们知道,中断在发生时,处理器根据收到的中断向量号在中断描述符表中找到相应的中断门描述符。

    处理器从该描述符中加载目标代码段选择子到代码段寄存器 cs 及偏移量到指令指针寄存器 EIP。

    注意,由于 cs 加载了新的目标代码段选择子,处理器只要发现段寄存器被加载,段描述符缓冲寄存器就会被刷新,因为处理器认为是换了一个段,属于段间转移,也就是远转移。

    所以,当前进程被中断打断后,为了从中断返回后能继续运行该进程,处理器自动把 cs 和 EIP 的当前值保存到中断处理程序使用的栈中。

    除了要保存 cs、 EIP 外,还需要保存标志寄存器 EFLAGS,

    因为中断是可以在任何特权级别下发生的,不同特权级别下处理器使用不同的栈,如果涉及到特权级变化,还要压入 SS 和 ESP 寄存器。

    那么我们就来看看到底中断的时候是如何来压栈的吧~

    1。当中断发生时,低特权级向高特权级转化时的压栈现象


    当处理器根据中断向量号找到中断描述符后,根据中断描述符中的段描述符选择子+GDTR的值,我们可以找到目标段描述符。

    我们是否能访问这个目标段描述符,要做的就是将找到中断描述符时当前的CPL与目标段描述符的DPL进行对比。

    这里我们讨论的是CPL特权级比DPL低的情况,即数值上CPL > DPL.
    这表示我们要往高特权级栈上转移,也意味着我们最后需要恢复旧栈,所以

    (1) 处理器先临时保存一下旧栈的SS和ESP(SS是堆栈段寄存器,因为换了一个栈,所以其也要变,ESP相当于在栈上的索引),然后加载新的特权级和DPL相同的段,将其加载到SS和ESP中,然后将之前保存的旧栈的SS和ESP压到新栈中

    由于SS堆段寄存器是16位寄存器,所以为了对齐,将其0拓展后压栈。
    然后在新栈中压入EFLAGS标志寄存器,得到图如下:

    2.因为是要切换栈,属于段间转移,所以我们还要将旧栈SS和EIP备份,以便中断程序执行后还可以恢复到被中断的进程。因为CS代码段寄存器也是16位寄存器,所以也要在压入栈前进行0扩展,此时如下图

    3.某些异常会有错误码,此错误码用于报告异常是在哪个段上发生的,也就是异常发生的位置,所以错误码中包含选择子等信息。错误码会紧跟在 EIP 之后入栈,记作 ERROR CODE

    2。当中断发生时,无特权级转化时的压栈现象

    此时由于不会切换栈,就不用保存SS和ESP,但是由于在处理完中断程序后还是要返回源程序中继续执行的,所以,我们的CS EIP寄存器还是要保存的。

    这种中断返 回是用 iret 指令实现的。 Iret,即 interrupt ret。注意在返回的时候,其错误码不会自动跳过,所以需要我们手动跳过。

    ????????????????????????

    好了,我们的压栈过程就到此讲完了,下面我们来了解一下,中断程序返回即出栈的过程,假设此时ESP已经跳过错误码指向eip_old

    当处理器执行到 iret指令时,它首先需要从栈中返回CS_old 及EIP_old,由于处理器在中断返回的时候,并不记得自己来的时候也曾经做过特权级检查,所以这时候它还要再进行特权级检查。

    特权级检查如下:

    (1)将cs_old对应的代码段的DPL及cs_old中的RPL做特权级检查, 如果检查通过,随即需要更新寄存器cs和EIP

    由于cs_old在入栈时已经将高16位扩充为 0,现在是 32 位数据,段寄存器 cs 是 16 位,故处理器丢弃 cs_old 高 16 位,将低16 位加载到 cs.
    将 EIP_old加载到 EIP 寄存器,之后栈指针指向 EFLAGS。

    如果进入中断时未涉及特权级转移,此时栈指针是 ESP_old (说明在之前进入中断后,是继续使用旧栈)。否则栈指针是 ESP_new (说明在之前进入中断后用的是 TSS 中记录的新栈)。

    (2)将栈中保存的EFLAGS 弹出到标志寄存器 EFLAGS。如果在第 1 步中判断返回后要改变特权级, 此时栈指针是 ESP_new,它指向栈中的 ESP_old。否则进入中断时属于平级转移,用的是旧栈,此时栈指针是 ESP_old,栈中已无因此次中断发生而入栈的数据,栈指针指向中断发生前的栈顶。

    (3)如果在第 1 步中判断出返回时需要改变特权级,也就是说需要恢复旧栈,此时便需要将 ESP_old 和 SS_old 分别加载到寄存器 ESP 及 SS,丢弃寄存器 SS 和 ESP 中原有的 SS_new 和 ESP_new,同时进行特权级检查。

    由于 SS_old 在入栈时已经由处理器将高 16 位填充为 0,现在是 32 位数据,所以在 重新加载到栈段寄存器 SS 之前,需要将 SS_old 高 16 位剥离丢弃,只用其低 16 位加载 SS。

    至此,处理器回到了被中断的那个进程。

    参考书籍:《操作系统真相还原》第七章7.4.2

    展开全文
  • 3.4 ARM堆栈保护/恢复现场分析 3.4.1 堆栈的分类 根据堆栈的生成方式,又可以分为递增堆栈(Ascending Stack)和递减堆栈(DecendingStack),当堆栈由低地址向高地址生成时,称为递增堆栈,当堆栈由高地址向...
  • 汇编 压栈出栈

    千次阅读 2016-03-20 20:54:47
    每一次发生函数的调用(主函数调用子函数)时,在被调用函数初始时,都会把当前函数(主函数)的EBP压栈,以便从子函数返回到主函数时可以获取EBP。 下面是按调用约定__stdcall 调用函数test(int p1,int p2)的...
  • 所以, 压栈出栈保护的是 ESP. 但因 ESP 是动态的, 所以一般先 mov ebp, esp, 然后 push ebp ... 像这样: mov ebp , esp push ebp ;...函数或子过程 pop ebp mov esp , ebp ;leave ;可以...
  • 中断发生时的压栈 特权级发生转移时:用户进程正在执行时候发生了中断 1,当前进程被中断打断后,处理器根据中断向量号找到对应的中断描述符,拿CPL和中断门描述符中选择子对应的目标代码段的DPL对比,若CPL...
  • 汇编

    千次阅读 2016-12-24 15:42:33
    汇编
  • 子程序调用和中断的几个概念

    千次阅读 2015-10-10 15:54:01
    主程序在执行过程中执行子程序,我们称之为子程序调用。  完成子程序调用/中断需要几个概念: ...保护现场和恢复现场。如果主程序中断时,有些寄存器还存放着中间结果,而子程序很有可能要占用这些寄存器,那么就要将
  • 压栈也称进栈,例如一个正在执行程序被中断函数打断,需要从 A 函数跳到中断服务函数,此时为了保持A函数执行进度,需要进行保护现场(进栈),出栈对应就是恢复现场; 压栈和进栈遵循:先入后出,后入先出,从高...
  • 在进入汇编程序之后,需要保护现场,退出汇编程序的时候,需要恢复现场。 压栈:只能对Rx进行压栈,其它寄存器需要先赋值给Rx,然后再压栈 puts = R1 或者 R1 = Ix;puts = R1; 出栈: 同样的,只能对Rx...
  • 因为内层循环也要用CX控制循环次数,所以压栈保护 mov dl, 0 ;从 0 列开始 mov cx, 16 ;循环 16 次,从 0 列到 15 列 put_0_F: ;------------内层循环 push cx ;因为循环体中要用到CX,所以压栈保护 mov cx...
  • 汇编语言Assembly(二)

    千次阅读 2017-01-02 11:59:04
    若是近调用,CALL指令将产生一个近调用,它把该指令之后地址的偏移量(用一个字来表示的)压栈,把被调用子程序入口地址的偏移量送给指令指针寄存器IP即可实现执行程序的转移。若是远调用,调用指令不仅要把该指令之后...
  • 调用约定明确了栈的恢复责任。嗯,是恢复责任,不是压栈……
  • 在写汇编函数时,总感觉在哪些寄存器该保护哪些不需要保护的问题上比较模糊,要是保护所有使用到的寄存器感觉比较死板也不符合规则,所以就去网上搜了搜。找到了一些规则,我觉得这是一个规则问题,大家都遵守的话就...
  • 段界限可以理解为栈向下扩展的一个红线,不能碰, 所以压栈时ESP - 操作数的长度后的值必须大于这个边界值.(这里这么理解与书中ESP - 操作数的长度>=(实际使用的段界限+1)是一个意思) 例2 , 基地址为0x7c00 , 段...
  • 其二,主要体现在利用保护和分页、特权级、中断等技术依托CPU提供的硬件机制,对进程调度、内存管理、文件系统等方面进行保护。其三,为了更好的管理资源并保护系统不受侵害,操作系统利用先机,以时间换取特权,先...
  • 软件保护技术 - 基础

    2021-03-09 16:03:17
    一、什么是软件保护技术 软件保护技术主要分两大类 法律 技术 二、水印技术 1、什么是水印技术 2、水印技术的方法 2.1 静态水印 定义常量 不过使用定义常量的方法来实现水印的话,容易在编译的...
  • 编译器具有会非常多方便的功能,优化等级这些可能大家都知道,但像一些性能加速如for循环编译展开,这样CPU流水线就不会被打断加快速度,还有堆栈保护等功能大家很少注意,这样有点可惜,一个工匠还是要尽可能的对...
  • 【ARM】Load Store指令

    千次阅读 2020-06-19 10:36:45
    寄存器压栈保护 … BL DELAY ;调用 DELAY 子程序 … LDMFD SP!,{R0~R7,PC} ;恢复寄存器,并返回 04. 单数据交换指令 交换指令是 Load/Store 指令的一种特例,它把一个寄存器单元的内容与寄存器内容交换。交换指令是...
  • Cortex-M系列:中断的内在机理

    千次阅读 2020-01-21 13:54:48
    文中用一个例子解释了惰性压栈的原理。在发生中断嵌套时,Cortex-M处理器将使用出栈抢占、末端连锁、延迟到达等机制来优化响应速度,同时降低了功耗[6]。理解这部分原理,一方面有利于处理在中断中出现的BUG,另一...
  • 首先进入主函数,系统为主函数开辟一个...后的指令地址也进行入栈,称为现场保护。然后将a+b的值30赋值给c,将c=30入栈。子函数此时执行到return c; 系统将30这个值寄存到eax寄存器中,然后将eax寄存器的值30赋值给主.
  • 硬件压栈R0-R3、R12寄存器,在中断服务函数结束后,硬件出栈,这样就保护了现场,C函数调用标准约定详见https://blog.csdn.net/itismine/article/details/4752489 入栈顺序以及入栈后堆栈中的内容 取向量 当数据...
  • GCC 中的编译器堆栈保护技术

    万次阅读 2016-06-28 19:42:33
    地址为 0x0804834b 的指令将 ecx-4 所指向的内存压栈,由于之前已将 esp+4 存入 ecx,所以该指令执行后原先 esp 指向的内容将被压栈,即返回地址被再次压栈。0x08048348 处的 and 指令使堆顶以 16 字节对齐。从 0x...
  • 基于虚拟机的软件保护技术不确定是否首先由vmprotect提出,但vmprotect毫无疑问是将这项技术大力推广至人所周知。现在基于虚拟机的软件保护技术已经成为现代软件安全防护的必备功能之一。 本文并不打算对...
  • STM32函数现场保护

    2019-09-12 21:52:44
    STM32函数现场保护 STM32函数调用时的压栈顺序: PC LR IP FP R0 R1 R2 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 11,233
精华内容 4,493
关键字:

压栈保护