当前位置: 首页 > news >正文

湖北定制型网站建设微信公众平台网页版

湖北定制型网站建设,微信公众平台网页版,周口seo优化,专业招牌制作价格CSAPP - 反汇编 strings_not_equal CSAPP bomlab1 中涉及到的 strings_not_equal 函数, 虽然可以从函数名字猜出函数含义#xff0c;但我想根据汇编代码反推出对应的C代码#xff0c;而不是根据函数名字猜测。 相比于专门学习 CTF 的选手#xff0c; 本篇的废话很多#…CSAPP - 反汇编 strings_not_equal CSAPP bomlab1 中涉及到的 strings_not_equal 函数, 虽然可以从函数名字猜出函数含义但我想根据汇编代码反推出对应的C代码而不是根据函数名字猜测。 相比于专门学习 CTF 的选手 本篇的废话很多是完全不熟悉汇编的视角出发。 一点经验 逐句翻译汇编写出对应的C代码写出C代码的时候增加注释把寄存器 和 变量名字 绑定起来 好处是下次看到 callee-saved 寄存器时直接对应到C代码 文章目录 CSAPP - 反汇编 strings_not_equal概况 - 涉及的函数调用完整的反汇编代码偏移地址 0, 2, 3 和偏移地址 101, 102, 103 的汇编解读偏移地址 4, 7偏移地址 94, 99 - 函数返回值类型偏移地址 10, 15, 18, 21, 26, 31, 34, 99 - 调用 string_length偏移地址 36, 39, 41, 80, 85, 99偏移地址 43, 46, 58, 62偏移地址 66, 69, 71, 50, 53, 56, 94, 99偏移地址 69, 71, 73, 78, 9950, 53, 56, 58, 6243, 46, 48, 87, 92, 99整理代码 概况 - 涉及的函数调用 int main() {phase_1()- read_line()- strings_not_equal()- string_length() }完整的反汇编代码 前文已对 string_length() 做了反汇编汇编代码到C代码的人工翻译和整理 本篇对 strings_not_equal() 做反汇编 它的完整汇编代码是 (gdb) disassemble strings_not_equal Dump of assembler code for function strings_not_equal:0x0000000000401338 0: push r120x000000000040133a 2: push rbp0x000000000040133b 3: push rbx0x000000000040133c 4: mov rbx,rdi0x000000000040133f 7: mov rbp,rsi0x0000000000401342 10: call 0x40131b string_length0x0000000000401347 15: mov r12d,eax0x000000000040134a 18: mov rdi,rbp0x000000000040134d 21: call 0x40131b string_length0x0000000000401352 26: mov edx,0x10x0000000000401357 31: cmp r12d,eax0x000000000040135a 34: jne 0x40139b strings_not_equal990x000000000040135c 36: movzx eax,BYTE PTR [rbx]0x000000000040135f 39: test al,al0x0000000000401361 41: je 0x401388 strings_not_equal800x0000000000401363 43: cmp al,BYTE PTR [rbp0x0]0x0000000000401366 46: je 0x401372 strings_not_equal580x0000000000401368 48: jmp 0x40138f strings_not_equal870x000000000040136a 50: cmp al,BYTE PTR [rbp0x0]0x000000000040136d 53: nop DWORD PTR [rax]0x0000000000401370 56: jne 0x401396 strings_not_equal940x0000000000401372 58: add rbx,0x10x0000000000401376 62: add rbp,0x10x000000000040137a 66: movzx eax,BYTE PTR [rbx]0x000000000040137d 69: test al,al0x000000000040137f 71: jne 0x40136a strings_not_equal500x0000000000401381 73: mov edx,0x00x0000000000401386 78: jmp 0x40139b strings_not_equal990x0000000000401388 80: mov edx,0x00x000000000040138d 85: jmp 0x40139b strings_not_equal990x000000000040138f 87: mov edx,0x10x0000000000401394 92: jmp 0x40139b strings_not_equal990x0000000000401396 94: mov edx,0x10x000000000040139b 99: mov eax,edx0x000000000040139d 101: pop rbx0x000000000040139e 102: pop rbp0x000000000040139f 103: pop r120x00000000004013a1 105: ret End of assembler dump.由于汇编较长并且在执行时跳来跳去像是乱划线因此按照汇编代码相对于函数起始地址的偏移量例如 8) 作为序号进行解释。一共105个序号其中很多相邻行可以合并起来看。 偏移地址 0, 2, 3 和偏移地址 101, 102, 103 的汇编解读 0x0000000000401338 0: push r120x000000000040133a 2: push rbp0x000000000040133b 3: push rbx...0x000000000040139d 101: pop rbx0x000000000040139e 102: pop rbp0x000000000040139f 103: pop r120: push r12: 把 r12 寄存器内容压栈。对应的是 103 的 pop 103, 是从栈上恢复 r12 寄存器。 为啥要压栈和恢复因为 r12 寄存器要被当前函数 strings_not_equal 使用 而调用规约规定 callee 要在函数结束时恢复 r12 这样的话前面一个调用 r12 的函数frame能继续用 r12。 2: push rbp: 将基指针寄存器Base Pointerrbp的内容压入栈中。rbp 通常用于标记当前栈帧的开始它在函数调用过程中用于定位局部变量和函数参数。 显然 先压入 r12 再压入 rbp 是比较合理的。 对应的是 102 的 pop rbp, 弹出 rbp。 3 push rbx: 将 rbx 寄存器的内容压入栈中。rbx 是另一个被调用者保存寄存器它在函数执行过程中用于保存一个临时值或者作为一个指向数据的指针。 对应的是 101 的 pop rbx, 恢复 rbx 寄存器。 callee-saved寄存器 在 x86_64 架构中使用的是 System V AMD64 ABI 调用约定这是大多数 Unix-like 系统包括 Linux 和 macOS所采用的。根据这个调用约定以下是被调用者保存callee-saved寄存器的列表 RBX - 基址寄存器Base register RBP - 基指针寄存器Base pointer register R12 - 第12个通用寄存器 R13 - 第13个通用寄存器 R14 - 第14个通用寄存器 R15 - 第15个通用寄存器 RSP - 栈指针寄存器Stack pointer register虽然通常不直接保存和恢复但必须在函数调用结束时保持一致。 被调用者保存的寄存器是指在函数调用过程中如果一个函数需要修改这些寄存器它必须在函数返回前将它们恢复到原始值。这意味着调用者可以期望这些寄存器在函数调用后保持不变。 caller-saved寄存器 除此之外还有一些寄存器是调用者保存caller-saved的也被称作易失性volatile寄存器包括: RAX - 累加器寄存器Accumulator用于整数运算和返回值。RCX - 计数寄存器Counter用于字符串操作和循环计数。RDX - 数据寄存器Data register用于整数运算和输入/输出操作。RSI - 源索引寄存器Source Index在字符串和数组操作中用作源地址指针。RDI - 目的索引寄存器Destination Index在字符串和数组操作中用作目的地址指针。R8 - 第8个通用寄存器用于整数运算和传递函数参数。R9 - 第9个通用寄存器同样用于整数运算和传递函数参数。R10 - 第10个通用寄存器通常用于整数运算。R11 - 第11个通用寄存器通常用于整数运算。XMM0-XMM15浮点寄存器用于浮点数和 SIMD 运算 XMM0-XMM7 - 用于浮点运算和 SIMD 运算的寄存器同时也用于传递函数参数和返回值。XMM8-XMM15 - 在某些系统上这些额外的寄存器用于相同的目的但主要是在函数调用中作为易失性寄存器使用。 这些寄存器可以在函数调用中被自由修改不需要保存和恢复它们的原始值。如果调用者希望在函数调用后使用这些寄存器的值它必须在调用之前自己保存它们。 偏移地址 4, 7 0x000000000040133c 4: mov rbx,rdi0x000000000040133f 7: mov rbp,rsi前面提到 rbx 和 rbp 都是 callee-saved 寄存器 已经在使用前保存原有值、 在函数结束时恢复原有值。 现在开始使用 rbx 和 rbp: mov rbx, rdi: rdi 寄存器存放了函数 strings_not_equal() 第一个参数。这句汇编是意思是把第一个参数放到 rbx 寄存器里。 mov rbp, rsi: 类似上面这句 是把第二个参数放到 rbp 寄存器里。 尝试写一下对应的 C 代码: return_type strings_not_equal(const char* s1, const char* s2) {const char* p1 s1;const char* p2 s2; }偏移地址 94, 99 - 函数返回值类型 0x0000000000401396 94: mov edx,0x10x000000000040139b 99: mov eax,edx在汇编代码 ret 之前紧邻的代码中 如果是往 eax 寄存器里写东西 那说明函数返回值类型是 int。 eax 是用于 int 类型返回值的函数的寄存器。 mov edx, 0x1: 把数字1写入到 rdx 寄存器。前面提到过 rdx 是数据寄存器Data register用于整数运算和输入/输出操作。 mov eax, edx: 把 edx 寄存器内容写入到 eax 寄存器。 通过 edx 寄存器传递感觉是多余的但由于不知道 CSAPP bomb 可执行文件的编译参数中是否开启过优化选项 因此不能确定能否直接干掉。 对应的 C 代码更新为 int strings_not_equal(const char* s1, const char* s2) {const char* p1 s1;const char* p2 s2;return 1; }偏移地址 10, 15, 18, 21, 26, 31, 34, 99 - 调用 string_length 0x0000000000401342 10: call 0x40131b string_length0x0000000000401347 15: mov r12d,eax0x000000000040134a 18: mov rdi,rbp0x000000000040134d 21: call 0x40131b string_length0x0000000000401352 26: mov edx,0x10x0000000000401357 31: cmp r12d,eax0x000000000040135a 34: jne 0x40139b strings_not_equal990x000000000040139b 99: mov eax,edxcall 0x40131b string_length: 调用 C 语言函数 string_length. 前文分析过它 返回值类型是 int 也就是说返回值放在 eax 寄存器中。 mov r12d,eax: 前面提到过 r12 是 callee-saved register 用来存放数据。这里是说把调用 string_length(s1) 的结果存放到 r12d。 此时 C 代码大概这样 int strings_not_equal(const char* s1, const char* s2) {const char* p1 s1; // p1: rbxconst char* p2 s2; // p2: rbpint len1 string_length(p1); // len1: r12dreturn 1; }mov rdi, rbp: 把 rbp 寄存器里的内容放到 rdi 寄存器 也就是说接下来调用 string_length() 函数时传入的第一个参数是 rbp 里的内容。 rbp 里现在是啥 0x000000000040133f 7: mov rbp,rsi 没错在偏移地址7处 是把 strings_not_equal() 第二个参数放到了 rbp 里 现在作为 string_length 的第一个参数。紧接着的汇编代码是 call 0x40131b string_length. 于是 C 代码更新为 int strings_not_equal(const char* s1, const char* s2) {const char* p1 s1; // p1: rbxconst char* p2 s2; // p2: rbpint len1 string_length(p1); // len1: r12dint len2 string_length(p2); // len2: eaxreturn 1; }mov edx,0x1: 往寄存器 edx 里写入1。 cmp r12d,eax: 比较 r12d 和 eax 两个寄存器的值。其中 eax 寄存器存放的是最近一次函数调用返回值是整数的结果也就是 string_length(s2)的结果 r12d 存放的是是调用 string_length(s1) 的结果 是在偏移地址15 时存入的。 因此现在这句汇编执行的是s1 和 s2 两个字符串长度的比较。 jne 0x40139b strings_not_equal99: 如果比较的 s1 和 s2 的长度不相等 那么跳转到偏移地址为99的汇编代码继续执行。 偏移地址99处的代码有分析过 是把 edx 寄存器的值放入 eax, 然后函数返回。而现在 edx 里存放的是1偏移地址26时写入的。因此C代码更新为 int strings_not_equal(const char* s1, const char* s2) {const char* p1 s1; // p1: rbxconst char* p2 s2; // p2: rbpint len1 string_length(p1); // len1: r12dint len2 string_length(p2); // len2: eaxif (len1 ! len2){return 1;} }偏移地址 36, 39, 41, 80, 85, 99 0x000000000040135c 36: movzx eax,BYTE PTR [rbx]0x000000000040135f 39: test al,al0x0000000000401361 41: je 0x401388 strings_not_equal800x0000000000401388 80: mov edx,0x00x000000000040138d 85: jmp 0x40139b strings_not_equal990x000000000040139b 99: mov eax,edxmovzx eax,BYTE PTR [rbx]: 把寄存器 rbx 里存放的值对应的内存地址处的值 放到 eax 寄存器里 并且注意 movzx 和 mov 有区别 movzx 是 move with zero extending 的意思高位填充0。也就是说被放到 eax 的 [rbx], 是一个宽度小于 int 的内容. 对应的C代码 char c1 *(rbx); // 也就是: char c1 *s1;完整的 C 代码更新为 int strings_not_equal(const char* s1, const char* s2) {const char* p1 s1; // p1: rbxconst char* p2 s2; // p2: rbpint len1 string_length(p1); // len1: r12dint len2 string_length(p2); //if (len1 ! len2){return 1;}char c1 *p1; // c1: eax }test al,al: test 指令执行的是 AND 操作。 test al, al 意思是 al 和自己做 AND 操作。 test 指令不存储结果 只修改 ZF, SF, PF。显然如果 al 本身是0那么 ZF 将等于1. je 0x401388 strings_not_equal80: 如果 ZF 为1 则跳转到偏移地址80的地方继续执行。 也就是说 如果 al(eax的低8位也就是刚刚C代码中的 c1)为0那么就跳转到偏移地址80地方执行。 对应的 C 代码: char c1 *p1; if (c1 0) {goto offset80; }地址偏移8085, 99处的汇编 mov edx, 0x0: 往 edx 寄存器写入0。 jmp 0x40139b strings_not_equal99: 无条件跳转到 offset99。 mov eax, edx: 把 edx 寄存器的值拷贝到 eax也就是说 edx 里刚刚写入的0是函数的返回值。 完整的C代码更新为 int strings_not_equal(const char* s1, const char* s2) {const char* p1 s1; // p1: rbxconst char* p2 s2; // p2: rbpint len1 string_length(p1); // len1: r12dint len2 string_length(p2);if (len1 ! len2){return 1;}char c1 *p1; // c1: eaxif (c1 \0) // s1[0] 为 \0, 而 s1, s2 长度相等 说明 s2[0] 也是 \0{return 0;} }偏移地址 43, 46, 58, 62 是在偏移地址41的地方 ZF 不为0的情况下继续执行的代码。也就是 char c1 *s1 后 c1 ! \0 情况下继续执行的代码。 0x0000000000401363 43: cmp al,BYTE PTR [rbp0x0]0x0000000000401366 46: je 0x401372 strings_not_equal580x0000000000401372 58: add rbx,0x10x0000000000401376 62: add rbp,0x1cmp al, BYTE PTR [rbp0x0]: 比较两个值第一个值是 al 寄存器 也就是 C 代码中我们自行定义的 c1 变量 第二个是 BYTE PTR [rbp0x0], 也就是 rbp 寄存器中存储的值对应的内存地址处存放的值。 cmp 指令可以理解为两个操作数做减法如果结果等于0那么ZF就更新为1否则ZF更新为0. je 0x401372 strings_not_equal58: 如果 ZF 为1也就是cmp比较的两个操作数相等那么跳转到偏移地址为58的地方。对应的C代码: if (al *rbp) {goto label58 }也就是 if (c1 *p2) {goto label58 }偏移地址为58的地方 add rbx, 0x1: rbx 寄存器加1. 也就是 rbx 更新为 rbx 1。 对应的C代码: p1;偏移地址为62的地方 add rbp, 0x1: 同上 rbp: p2;完整的C代码更新为 int strings_not_equal(const char* s1, const char* s2) {const char* p1 s1; // p1: rbxconst char* p2 s2; // p2: rbpint len1 string_length(p1); // len1: r12dint len2 string_length(p2);if (len1 ! len2){return 1;}char c1 *p1; // c1: eaxif (c1 \0) // s1[0] 为 \0, 而 s1, s2 长度相等 说明 s2[0] 也是 \0{return 0;}if (c1 *p2){p1;p2;} }偏移地址 66, 69, 71, 50, 53, 56, 94, 99 0x000000000040137a 66: movzx eax,BYTE PTR [rbx]0x000000000040137d 69: test al,al0x000000000040137f 71: jne 0x40136a strings_not_equal500x000000000040136a 50: cmp al,BYTE PTR [rbp0x0]0x000000000040136d 53: nop DWORD PTR [rax]0x0000000000401370 56: jne 0x401396 strings_not_equal940x0000000000401396 94: mov edx,0x10x000000000040139b 99: mov eax,edxmovzx eax, BYTE PTR [rbx]: 把 rbx 寄存器里存放的值对应的内存地址处 存放到 eax 寄存器。感觉这里是把 eax 寄存器当作临时变量用了。实际上偏移地址36和66的汇编代码一样 0x000000000040135c 36: movzx eax,BYTE PTR [rbx]0x000000000040137a 66: movzx eax,BYTE PTR [rbx]含义自然也是一样的char c1 *s1. 只不过此时的 s1 已经是原始输入的 s1 再加 1 了。 test al, al: 让 AL 和 AL 做 AND 操作 如果结果为1 则ZF为0. 如果 AND 结果为0 则 ZF 为1. jne 0x40136a strings_not_equal50: 检查 ZF 如果ZF为1也就是AL为0, 对应到C代码就是 c1 为 0则跳转到偏移地址为50的地方继续执行。 对应的 C 代码 int strings_not_equal(const char* s1, const char* s2) {const char* p1 s1; // p1: rbxconst char* p2 s2; // p2: rbpint len1 string_length(p1); // len1: r12dint len2 string_length(p2);if (len1 ! len2){return 1;}char c1 *p1; // c1: eaxif (c1 \0) // s1[0] 为 \0, 而 s1, s2 长度相等 说明 s2[0] 也是 \0{return 0;}if (c1 *p2){p1;p2;}c1 *p1;if (c1 ! \0){if (c1 ! *p2){return 1;}} }偏移地址 69, 71, 73, 78, 99 0x000000000040137d 69: test al,al0x000000000040137f 71: jne 0x40136a strings_not_equal500x0000000000401381 73: mov edx,0x00x0000000000401386 78: jmp 0x40139b strings_not_equal990x000000000040139b 99: mov eax,edxif (c1 \0) {return 0; }完整代码更新为 int strings_not_equal(const char* s1, const char* s2) {const char* p1 s1; // p1: rbxconst char* p2 s2; // p2: rbpint len1 string_length(p1); // len1: r12dint len2 string_length(p2);if (len1 ! len2){return 1;}char c1 *p1; // c1: eaxif (c1 \0) // s1[0] 为 \0, 而 s1, s2 长度相等 说明 s2[0] 也是 \0{return 0;}if (c1 *p2){p1;p2;}c1 *p1;if (c1 ! \0){if (c1 ! *p2){return 1;}}else{return 0;} }50, 53, 56, 58, 62 0x000000000040136a 50: cmp al,BYTE PTR [rbp0x0]0x000000000040136d 53: nop DWORD PTR [rax]0x0000000000401370 56: jne 0x401396 strings_not_equal940x0000000000401372 58: add rbx,0x10x0000000000401376 62: add rbp,0x1int strings_not_equal(const char* s1, const char* s2) {const char* p1 s1; // p1: rbxconst char* p2 s2; // p2: rbpint len1 string_length(p1); // len1: r12dint len2 string_length(p2);if (len1 ! len2){return 1;}char c1 *p1; // c1: eaxif (c1 \0) // s1[0] 为 \0, 而 s1, s2 长度相等 说明 s2[0] 也是 \0{return 0;}if (c1 *p2){ goto label58;} label58:p1;p2;c1 *p1;if (c1 ! \0){if (c1 ! *p2){return 1;}else{goto label58;}}else{return 0;} }43, 46, 48, 87, 92, 99 0x0000000000401363 43: cmp al,BYTE PTR [rbp0x0]0x0000000000401366 46: je 0x401372 strings_not_equal580x0000000000401368 48: jmp 0x40138f strings_not_equal870x000000000040138f 87: mov edx,0x10x0000000000401394 92: jmp 0x40139b strings_not_equal990x000000000040139b 99: mov eax,edxif (c1 ! *p2) {return 1; }完整的C代码更新为: int strings_not_equal(const char* s1, const char* s2) {const char* p1 s1; // p1: rbxconst char* p2 s2; // p2: rbpint len1 string_length(p1); // len1: r12dint len2 string_length(p2);if (len1 ! len2){return 1;}char c1 *p1; // c1: eaxif (c1 \0) // s1[0] 为 \0, 而 s1, s2 长度相等 说明 s2[0] 也是 \0{return 0;}if (c1 *p2){ goto label58;}else{return 1;} label58:p1;p2;c1 *p1;if (c1 ! \0){if (c1 ! *p2){return 1;}else{goto label58;}}else{return 0;} }整理代码 int strings_not_equal(const char* s1, const char* s2) {const char* p1 s1; // p1: rbxconst char* p2 s2; // p2: rbpint len1 string_length(p1); // len1: r12dint len2 string_length(p2);if (len1 ! len2){return 1;}char c1 *p1; // c1: eaxif (c1 \0) // s1[0] 为 \0, 而 s1, s2 长度相等 说明 s2[0] 也是 \0{return 0;}if (c1 ! *p2){return 1;} label58:p1;p2;c1 *p1;if (c1 \0){return 0;}if (c1 ! \0){if (c1 ! *p2){return 1;}else{goto label58;}} }int strings_not_equal(const char* s1, const char* s2) {const char* p1 s1; // p1: rbxconst char* p2 s2; // p2: rbpint len1 string_length(p1); // len1: r12dint len2 string_length(p2);if (len1 ! len2){return 1;}int ret 0;for (; ;){char c1 *p1; // c1: eaxif (c1 \0) // s1[0] 为 \0, 而 s1, s2 长度相等 说明 s2[0] 也是 \0{ret 0;break;}if (c1 ! *p2){ret 1;break;}p1;p2;}return ret; }
http://www.pierceye.com/news/618774/

相关文章:

  • 需要做网站的公司有哪些免费网页模板之家
  • 淘客网站怎么备案合肥在线官网
  • 马上飞做的一些网站免费自助建站系统有哪些
  • 建网站投放广告赚钱wordpress全屏弹窗插件
  • 电子商务公司网站模版通辽网站建设公司
  • 国外社交网站建设苏州seo门户网
  • 小程序建站公司唐山网页搜索排名提升
  • 网站后台模板北京网络营销方案
  • 网站如何不被百度搜到浙江网站怎么做推广
  • 网站建设主机类型怎么选diy电子商城网站
  • 中文域名 怎么做网站门户网站建站系统
  • 网站上的个人词条怎么做的做网站推广有用吗
  • 定兴县住房和城乡建设局网站河南省新闻奖
  • 江西省建设工程协会网站查询郑州网站建设一汉狮网络
  • 网站是否含有seo收录功能素材下载平台网站源码
  • 西宁个人网站建设不错的网站建设
  • 海南综合网站两学一做电视夜校做网店网站
  • wordpress分类页面空白网站建设优化哪家好
  • 宁波模板建站哪家服务专业wordpress 神箭手
  • 一张图片网站代码视频生成链接在线工具
  • 网站品牌推广浙江手机版建站系统开发
  • 网站后台密码在哪个文件建站报价表
  • 昌乐营销型网站建设个人管理系统
  • 手机网站开发位置定位天津和平做网站公司
  • 搜搜提交网站入口国外wordpress空间
  • python 做网站 数据库做企业官网还有必要吗
  • 数据录入网站开发安阳县实验中学
  • 网站 风格镜子厂家东莞网站建设
  • 做网站策划需要用什么软件网站建设 好发信息网
  • wordpress网站优化pc建站 手机网站