在递归调用中保留寄存器%rbx的前一个值,可以通过将前一个值保存在堆栈中来实现。堆栈是一种后进先出(LIFO)的数据结构,可以用于保存函数调用的上下文信息。
具体步骤如下:
这样,在递归调用过程中,每次进入递归函数时都会将%rbx的值保存在堆栈中,然后在递归函数返回时再将之前保存的值恢复到%rbx中,从而实现了保留前一个值的目的。
同时还保留了与旧代码的向后兼容性。各种竞争对手(如AMD)生产的兼容芯片也实现了相同的指令集。...前8个浮点型参数依次存储在寄存器%xmm0-%xmm7。 超过这些寄存器个数的参数才被压栈。 如果函数接受可变数量的参数(如printf),则必须将%rax寄存器设置为浮动参数的数量。...事实证明,这个函数不需要使用寄存器%rbx和%r15,所以不需要保存和恢复他们。同样的,我们也可以把参数就保留在寄存器中而不必把它们压栈。...(使用LDP/STP,在加载和存储成对的寄存器时更有效率)。 调用习惯 当调用函数的时候,前8个参数被存储到寄存器x0-x7中,其余的参数压栈。...调用者必须保留寄存器x9-x15和x30,而被调用者必须保留x19-x29。返回值的标量部分存储到x0中,而返回值的扩展部分存储到x8中。
每个炸弹阶段考察了机器级语言程序的一个不同方面,难度逐级递增: * 阶段1:字符串比较 * 阶段2:循环 * 阶段3:条件/分支 * 阶段4:递归调用和栈 * 阶段5:指针 * 阶段6:链表.../phase_2 分析反汇编代码的phase_2部分内容如下: 1.push %rbp: 将寄存器%rbp的值压入栈中。 2.push %rbx: 将寄存器%rbx的值压入栈中。...: 将数据压入栈中; 减少栈指针40,为局部变量提供空间; 将栈指针存入%rsi寄存器中; 调用两个explode_bomb函数; 调用read_six_numbers函数读取6个数字。...1.这段代码是一个循环操作,它对一组数进行比较,并且判断其中是否存在某个数是前一个数的2倍。这组数存储在栈中,栈顶元素即为第一个数。...可以看到sub指令,它将%rbx的值减去4,并将其对应的内存地址中的值(即前一个数)存储到%eax寄存器中。接着,将%eax的值乘以2,并将其与%rbx对应的内存地址中的值(即当前数)进行比较。
用来实现控制或数据流中的条件变化 一组向量寄存器可以存放一个或多个整数或者浮点数值 程序内存包含:程序的可执行机器代码,操作系统需要一些信息,用来管理过程调用和返回的运行时栈,以及用户分配的内存块 先看一个代码编译实例...标号从%rax到%rbp,除此之外还增加了8个新的寄存器,标号从%r8到%r15 操作数指示符 大多数指令有一个或多个操作数,指示出执行一个操作中要使用的源数据值,以及放置结果的目的位置。...源操作数指定的值是一个立即数,存储在寄存器中或者内存中,目的操作数指定一个位置,要么是一个内存地址。而在x86-64中增加一个限制,传送指令的两个操作数不能都指向内存位置。 ?...稍后用寄存器%rax 从这个函数返回一个值,因而返回值就是x movq %rsi, (%rdi):这个指令将y写入到寄存器%rdi 中的xp指向的内存位置,直接实现了代码中*xp=y 关于这段汇编代码有两个地方需要注意...栈是一种数据结构,可以添加和删除值,不过要遵循后进先出的原则,通过push操作将数据压入栈中,通过pop删除数据。 它具有一个属性:弹出的值永远是最近被压入而且仍然在栈中的值。
# 汇编寄存器的规则 在本章中,您将了解到 CPU 使用的寄存器,并研究和修改传入函数的参数。您还将了解常见的苹果计算机架构,以及如何在函数中使用它们的寄存器。这就是所谓的架构调用约定。...在上面的示例中,有几个寄存器,显示为 rbx 、 rsp 、 rdi 和 rbp 。前面的 % 告诉您这是一个寄存器。 此外,您还可以找到一个十六进制的数字常量,如 0x228。...RDI,RSI,RDX,RCX,R8 和 R9 保留您的前六个参数。 注意:关于 LLDB,我一直没有告诉您的是,LLDB 可以以argX形式来引用寄存器,其中X是参数号。...# RAX,用于返回的寄存器 等等 -- 还有呢!到这里,你已经了解了函数中六个寄存器是如何调用的,但是返回值呢? 幸运的是,只有一个指定的寄存器用于返回值:RAX。...了解 RAX 中的返回值非常重要,因为它将构成您将在后面的部分中编写的调试脚本的基础。 # 改变寄存器值 为了巩固您对寄存器的理解,您将在一个已编译的应用程序中修改寄存器。
r8d(r8的32位)、rcx(在64位类似fastcall,它的前四个参数分别是rcx、rdx、r8、r9)喊话CALL是会带一个发送的文本,有文本参数,所以先找一下参数。...rcx、rdx、r8、r9参数复制下来,可以确定r8是字符串地址10.找rdx参数10.1 Ctrl+G返回到这里,确定10.2测试rdx,在当前多喊几次话,发现寄存器没有值,所以认为rdx是写死的值-...13.1在寄存器里发现rbx和rcx一样,就以rbx为突破点,找到了rbx对rcx的赋值13.2怀疑没有通过src对rcx赋值,而是通过rbx对rcx赋值之后,通过跳转到参数传递,直接调用喊话CALL13.3...若是上述情况,需要先找rbx的值13.3.1发现是变量Var EB0给rbx赋值13.3.2再寻找变量Var EB0,发现是rax赋值给变量Var EB013.3.3 rax值来源于上面的call,call...的返回值是rax13.4 Rcx=那个call的返回值13.4.1进一层,Rax就是call的返回值+48,然后取值13.4.2再进去一层,发现一个基址放在rax里13.4.3 Rcx=[0x基址+0x48
leaq 来传递指针 最后栈顶回退16个字节-释放栈空间 ret始终会把栈指针指向的地址作为返回地址 所以%rsp在ret前执行 回到该回到的地方 —- 我们会把那些可能被用到的寄存器存在栈帧里面。...managing local data illustration of recursion 一个神奇方法去计算一个数字有多少1: 巧妙利用返回的 rax 成对出现的push pop rbx 是用来保存...弹出rbx临时值的 可以看出 在return里面 先计算两个表达式的值保存在寄存器然后再去call,我们要知道 call完以后他肯定rax保存了返回值 与此同时在call的时候我明白,在call之前rbx...设置为右移后的值,当返回时,我们知道rbx存储了x的最低有效位, 所以我们可以把二者相加 最后的返回值rax就是最后的结果 疑问️如果最后一轮popq rbx 会执行 L6 rep吗 总之rbp不管如何修改...,在返回的时候都会是被恢复前面的值 保护现场机制 这就是ABI标准制定的意义 所有被调用函数都有恢复寄存器环境的责任 栈正好可以达到这个效果 被调用者 callee有责任把那些寄存器值保存到自己的栈帧里面
0x4: 64位的特点: 在64位程序中,函数的前6个参数是通过寄存器传递的,但是大多数时候,我们很难找到每一个寄存器对应的gadgets。...这时候,我们可以利用x64下的__libc_scu_init中的gadgets。这个函数是用来对libc进行初始化操作的,而一般的程序都会调用libc函数,所以这个函数一定会存在。...0x0000000000400600到0x0000000000400609,我们可以将r13赋给rdx,将r14赋给rsi,将r15d赋给edi(需要注意的是,虽然这里赋给的是edi,但其实此时rdi的高32位寄存器值为...0,所以其实我们可以控制rdi寄存器的值,只不过只能控制低32位),而这三个寄存器,也是x64函数调用中传递的前三个寄存器。...此外,如果我们可以合理地控制r12与rbx,那么我们就可以调用我们想要调用的函数。比如说我们可以控制rbx为0,r12为存储我们想要调用的函数的地址。
例如32位通过栈传递参数, 通过eax寄存器传递返回值. 64位windows通过rcx, rdx, r8, r9传递前4个参数, 通过栈传递第5个开始的参数, 通过eax寄存器传递返回值. 64位linux..., unix通过rdi, rsi, rdx, rcx, r8, r9传递前6个参数, 通过栈传递第7个开始的参数, 通过eax寄存器传递返回值. go并不使用这些调用规范(除非涉及到与原生代码交互),...栈扩张 因为go中的协程是stackful coroutine, 每一个goroutine都需要有自己的栈空间, 栈空间的内容在goroutine休眠时需要保留, 待休眠完成后恢复(这时整个调用树都是完整的...传递闭包给其他函数时会传递指向"闭包的内容"的指针 调用闭包时会把指向"闭包的内容"的指针放到寄存器rdx(在go内部这个指针称为"上下文") 闭包会从寄存器rdx取出参数 如果闭包修改了变量, 闭包中的参数会是指针而不是值...: 设置g.sched.pc等于当前的返回地址 设置g.sched.sp等于寄存器rsp的值 设置g.sched.g等于当前的g 设置g.sched.bp等于寄存器rbp的值 切换TLS中当前的g等于m.g0
分析到这里可以得出三个重要的结论:1.第一个数是1。2. 6个数字的关系为:后一个数是前一个数的两倍。3.结束的条件存放在%rsp+0x18。...4010f3: c3 retq #%rbp %rbx %r12~%15 被调用者保存寄存器 # %r10 %r11 调用者保存寄存器 %rdi %rsi...第15行 ~ 23行为一个循环。输入的字符串存储在%rbx中,第15行表示把输入字符串的第%eax个字符的ASCII码值给%ecx,%cl为%ecx的低8位,所以第16行为取%ecx的低八位。 ...0x00000000004011e5 : cmp %eax,(%rbx) 比较链表节点中第一个字段值的大小,如果前一个节点值大于后一个节点值...%rbp %rbx %r12~%15 被调用者保存寄存器 %r10 %r11 调用者保存寄存器 %rdi %rsi %rdx %rcx %r8 %r9 依次保存输入数1~6 假设输入数据为4 3 2
/phase_2 分析反汇编代码的phase_2部分内容如下: 1.push %rbp: 将寄存器%rbp的值压入栈中。 2.push %rbx: 将寄存器%rbx的值压入栈中。...可以看到sub指令,它将%rbx的值减去4,并将其对应的内存地址中的值(即前一个数)存储到%eax寄存器中。接着,将%eax的值乘以2,并将其与%rbx对应的内存地址中的值(即当前数)进行比较。...,并将%edi里存储的输入的第一个数与%ecx寄存器中的值进行比较。...如果%edi的值小于7,程序会进入400fe9处并再次调用func4函数,形成递归调用。虽然看起来很复杂,但我们可以通过代入寄存器中的值并记录它们的变化来推导出最终的结果。...cmp %eax, (%rbx) //比较链表结点中第一个字段值的大小,如果前一个节点值大于后一个节点值,跳转 4011e7: 7d 05 jge 4011ee <
程序要有向栈内写入数据的行为,利用函数,如gets,writes 2....并且将程序的控制权交给该指令(system/shellcode),攻击指令可以是自定义的指令片段,也可以利用系统内已有的函数和指令 保护机制: 一、Canary保护机制 简单来说,就是在ebp的前面放一个值...->eax 调用参数依次->ebx,ecx,edx,esi,edi Hijack GOT --修改某个被调用函数的地址,让其指向另一个函数 程序对外部函数的调用需要在生成可执行文件时将外部函数链接到程序中...,PLT表内存储的入口点就是GOT表中对应条目的地址 ret2__libc_csu_init 原理:在64位程序中,函数的前六个参数是通过寄存器传递的,但是大多时候,我们很难找到每一个寄存器对应的gadgets...X64中的前六个参数依次保存在rdi,rsi,rdx,rcx,r8,r9中 r13=rdx=arg3 r14=rsi=arg2 r15d=edi=arg1 r12= call address 这段gadgets
最后 TinyInst 将目标程序的 RIP 寄存器指向二进制重写的代码的开始位置(工作内存空间),目标程序真正开始运行,并在运行过程中完成覆盖率的记录。...我们回到全局跳转表 InitGlobalJumptable() 初始化函数,其首先在二进制重写的内存空间前 0x2000 项中循环写入一个跳转地址,该跳转地址为 内存起始地址 + 指针大小(8) * 0x2000...rbx 以上二进制重写的代码主要操作为:保存 eflags/rax/rbx 到栈中,将要调用的函数地址 function_address 保存在 rax 中,随后将其与全局跳转表长度 0x0FFF8...计算 hash 并保存在 rbx 中,从 rbx 继续运行。...碰撞检测),随后从栈中还原 rbx/rax/eflags,最终调用目标函数执行,完成整个外部函数调用流程。
C2会递归式地移除死节点的输入边,这一步又可能产生新的死节点。...while(_worklist.size()) { // 从worklist中获取一个元素 Node* n = _worklist.pop(); ...// 特殊情况,这一步的迭代次数超过C2限制 //...整个图的最外部虚线方框表示在分析过程中我们关心的四个程序点:调用方法L()前,方法L()入口,方法L()返回,调用方法L()后。虚线圆圈表示每个程序点的连接图状态。...图9-12 逃逸分析Java示例对应的连接图 逃逸分析在调用NewListElement.T()前建立连接图,然后进入方法入口。...不过调用者(方法L)不能直接使用被调用者(方法T)的逃逸分析结果,需要经过一个映射过程,即将被调用者的分析结果中的节点和边映射到调用者的连接图上,如将ArgEscape的a1映射到图9-12f的a1。
就像PC寄存器一样,可以专门设立一个“程序调用寄存器”,存储接下来要跳转回来执行的指令地址 等到函数调用结束,从这个寄存器里取出地址,再跳转到这个记录的地址,继续执行就好了。...34行的call指令时,会把当前的PC寄存器里的下一条指令的地址压栈,保留函数调用结束后要执行的指令地址 而add函数的第0行,push rbp指令,就是在压栈 这里的rbp又叫栈帧指针(Frame...,更新到PC寄存器中,将程序的控制权返回到出栈后的栈顶。...2 构造Stack Overflow 通过引入栈,我们可以看到,无论有多少层的函数调用,或者在函数A里调用函数B,再在函数B里调用A 这样的递归调用,我们都只需要通过维持rbp和rsp,这两个维护栈顶所在地址的寄存器...Mirror Effect的方式,让函数A调用自己,并且不设任何终止条件 这样一个无限递归的程序,在不断地压栈过程中,将整个栈空间填满,并最终遇上stack overflow。
第一行是通过and指令,使rsp寄存器里的值满足16字节对齐。 第二行看注释可知,是保存efi_pe_entry传过来的boot_params参数到rbx寄存器里。...我们再来看下efi_pe_entry中调用efi_stub_entry的地方: ? 该调用传递了三个指针类型的参数,所以它们使用的寄存器分别是 rdi, rsi, rdx。...我们继续看efi_stub_entry中的第三行代码,它是通过call指令,调用efi_main函数,执行efi_main里的逻辑。...看上面介绍calling convention时的第一个截图,当被调用函数要使用rbx时,它必须在返回之前,恢复rbx原来的值,所以rbx一定是不会被修改的。...首先,efi_stub_entry在调用该方法时,寄存器rdi, rsi, rdx里的值都没有改变,还是efi_pe_entry调用efi_stub_entry时传递的那些值,所以根据上述calling
,前两个整数参数是通过 RDI 和 RS 寄存器传递的。...jmp rax 以上代码中,rdi 为 CallAdd 函数的第一个参数,也就是函数的地址,后来赋值给 rbx 寄存器,后续的调用都是通过 rbx 寄存器进行的,第二次调用时甚至优化掉了调用,直接跳转到了函数的地址...,前两个整数参数分别通过 AX,BX 传递,返回值也是通过同样的寄存器序列。...在 Go 的版本中,真正的函数地址是从 AX 寄存器指向的地址读取到后放到 CX 寄存器中,然后还要把函数值的地址设置到 DX 寄存器中。...嵌套函数实际上也是一个真正的函数,但是比起普通的函数,多了个从 DX 寄存器读取的值操作: main.MakeAddN.func1 STEXT nosplit size=8 args=0x10 locals
就像PC寄存器一样,可以专门设立一个“程序调用寄存器”,存储接下来要跳转回来执行的指令地址 等到函数调用结束,从这个寄存器里取出地址,再跳转到这个记录的地址,继续执行就好了。...12~13行 在调用第34行的call指令时,会把当前的PC寄存器里的下一条指令的地址压栈,保留函数调用结束后要执行的指令地址 而add函数的第0行,push rbp指令,就是在压栈 这里的rbp又叫栈帧指针...,更新到PC寄存器中,将程序的控制权返回到出栈后的栈顶。...2 构造Stack Overflow 通过引入栈,我们可以看到,无论有多少层的函数调用,或者在函数A里调用函数B,再在函数B里调用A 这样的递归调用,我们都只需要通过维持rbp和rsp,这两个维护栈顶所在地址的寄存器...Mirror Effect的方式,让函数A调用自己,并且不设任何终止条件 这样一个无限递归的程序,在不断地压栈过程中,将整个栈空间填满,并最终遇上stack overflow。
在程序结束前,把栈指针加32,释放这个栈帧。 寄存器中的局部存储 寄存器组是唯一被所有过程共享的资源。因此,在某些调用过程中,我们要不同过程调用的寄存器不能相互影响。 ...根据惯例,寄存器%rbx、%rbp和%r12~%r15被划分为被调用者保存寄存器。当过程P调用过程Q时,Q必须保存这些寄存器的值,保证它们的值在Q返回到P时与Q被调用时是一样的。...可以看到GCC生成的代码使用了两个被调用者保存寄存器:%rbp保存x和%rbx保存计算出来的Q(y)的值。在函数的开头,把这两个寄存器的值保存到栈中(第2~3行)。...上图给出了递归的阶乘函数的C代码和生成的汇编代码。可以看到汇编代码使用寄存器%rbx来保存参数n,先把已有的值保存在栈上(第2行),随后在返回前恢复该值(第11行)。...根据栈的使用特性和寄存器保存规则,可以保证当递归调用 refact(n-1)返回时(第9行),(1)该次调用的结果会保存在寄存器号%rax中,(2)参数n的值仍然在寄存器各%rbx中。
该POC首先利用“sudo cat /proc/kallsyms | grep “linux_proc_banner””获取linux_proc_banner在内核中的地址,再读取该地址上的值。...lea %[target], %%rbx: 把全局变量target_array的地址放到RBX寄存器中,这里的target_ array正是上一章节中的探测数组probe_array, target_array...movzx (%[addr]), %%eax: 对应上一章节指令序列的第三条指令,将攻击者的目标内核地址所指向的数据放入eax寄存器中,该操作会触发处理器异常 shl $12, %%rax: 对应上一章节指令序列第四条指令..., %%rax, 1)指令之后,处理器开始处理异常,攻击者则注册一个信号处理器,直接修改程序指针寄存器,将执行位置跳转到stopspeculate指令继续执行即nop指令。...- 隐藏技术:平均化侧信道信息,降低数据的可区分度 - 混淆技术:降低信噪比(有效侧信道信息)如使用随机时钟等,增加侧信道分析难度。
领取专属 10元无门槛券
手把手带您无忧上云