debugger(一):打断点的实现以及案例分析

〇、前言

最近在学习 debugger 的实现原理,并按照博客实现,是一个很不错的小项目,这是地址。由于 macOS 的问题,系统调用并不完全相同,因此实现了两个版本分支,一个是 main 版本分支(macOS M1 silicon),另一个是 linux 版本分支(Ubuntu 20.04 x86),这是仓库地址。以下以及后都用 linux 版本代码阐述其原理。

一、断点创建

这很简单,主要是由 ptrace() 实现(debug工具都依赖于 ptrace() ):

#ifndef BREAKPOINT_HPP_
#define BREAKPOINT_HPP_
#include <stdint.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
class BreakPoint {pid_t m_pid;intptr_t m_addr;bool m_enabled;uint8_t m_saved_data; // 最低位的旧数据(1 字节),之后需要恢复public:BreakPoint() {}BreakPoint(pid_t pid, intptr_t addr): m_pid(pid), m_addr(addr), m_enabled(false), m_saved_data{} {}auto is_enabled() const -> bool { return m_enabled; }auto get_address() const -> intptr_t { return m_addr; }void enable() {auto data = ptrace(PTRACE_PEEKDATA, m_pid, m_addr, nullptr);m_saved_data = static_cast<uint8_t>(data & 0xff); // save bottom byteuint64_t int3 = 0xcc;uint64_t data_with_int3 = ((data & ~0xff) | int3); // set bottom byte to// 0xccptrace(PTRACE_POKEDATA, m_pid, m_addr, data_with_int3);m_enabled = true;}void disable() {auto data = ptrace(PTRACE_PEEKDATA, m_pid, m_addr, nullptr);auto restored_data = ((data & ~0xff) | m_saved_data);ptrace(PTRACE_POKEDATA, m_pid, m_addr, restored_data);m_enabled = false;}
};
#endif

以上是 BreakPoint 类的定义。重点是关注 enable()disable() 两个方法,在这两个方法中,这段代码及其关键:

	auto data = ptrace(PTRACE_PEEKDATA, m_pid, m_addr, nullptr);m_saved_data = static_cast<uint8_t>(data & 0xff); // save bottom byteuint64_t int3 = 0xcc;uint64_t data_with_int3 = ((data & ~0xff) | int3); // set bottom byte to// 0xccptrace(PTRACE_POKEDATA, m_pid, m_addr, data_with_int3);

这里先说明一下,int3x86 中的一个中断指令,只要我们把某个指令修改为 int3,那么它运行到这里就会停下来。另外,我们只是打个断点,又不想真正得越过这个指令(这个指令被越过不执行,谁都不知道会发生什么),所以后面得恢复这个执行,并重新执行它,这就是 disable(),我们先讨论 enable()

因为 int3 指令的代码为 0xcc,这很明显是一个 1 字节指令,只要我们在我们想打断的指令处,将操作码改为 0xcc,这个指令就会停下来(这里牵扯到字节序,因为指令第一个字节是低地址,因为我们需要将 int3 放在一个指令的最低处)。然后再将这个被篡改的指令放回到原处,就成功的打了一个断点。

至于 disable(),其实做的也是这样的事情,将原来的被替换的一个字节再恢复放回去:

	auto data = ptrace(PTRACE_PEEKDATA, m_pid, m_addr, nullptr);auto restored_data = ((data & ~0xff) | m_saved_data);ptrace(PTRACE_POKEDATA, m_pid, m_addr, restored_data);m_enabled = false;

以上都是很简单的东西,我们现在就可以检验这个事情了,对了以下是 debugger 类的定义:

#ifndef DEBUGGER_HPP_
#define DEBUGGER_HPP_#include "../ext/linenoise/linenoise.h"
#include "breakpoint.hpp"
#include "helpers.hpp"
#include <cstddef>
#include <iostream>
#include <string>
#include <unordered_map>class debugger {std::string m_prog_name;pid_t m_pid;std::unordered_map<std::intptr_t, BreakPoint> m_breakPoints; // 存储断点public:// 这里不应该给默认参数,断言:传了正确的 prog_name,piddebugger(std::string prog_name, pid_t pid): m_prog_name(prog_name), m_pid(pid) {}void run() {int wait_status;auto options = 0;waitpid(m_pid, &wait_status, options);char *line = nullptr;while ((line = linenoise("minidbg> ")) != nullptr) {handl_command(line);linenoiseHistoryAdd(line);linenoiseFree(line);}}// handlersvoid handl_command(const std::string &line) {auto args = split(line, ' ');auto command = args[0];if (is_prefix(command, "continue")) {continue_execution();} else if (is_prefix(command, "break")) { // break 地址std::string addr{args[1], 2};set_breakPoint(std::stol(addr, 0, 16));} else {std::cerr << "Unkown command\n";}}void continue_execution() {ptrace(PTRACE_CONT, m_pid, nullptr, nullptr);int wait_status;auto options = 0;waitpid(m_pid, &wait_status, options);}void set_breakPoint(std::intptr_t addr) {std::cout << "Set breakpoint at address 0x" << std::hex << addr<< std::endl;BreakPoint bp{m_pid, addr};bp.enable();m_breakPoints[addr] = bp;}~debugger() {}
};#endif

二、检测

main() 就是 debuggermain() 了:

#include "../include/debugger.hpp"
#include <cstddef>
#include <iostream>
#include <unistd.h>
#include <sys/personality.h>
int main(int argc, char *argv[]) {if (argc < 2) {std::cerr << "Program paras are not right.";return -1;}auto proj = argv[1];auto pid = fork();if (pid == 0) {personality(ADDR_NO_RANDOMIZE); // 取消随机内存// child progress// debugged progressptrace(PTRACE_TRACEME, 0, nullptr, nullptr);execl(proj, proj, nullptr);} else if (pid >= 1) {// parent progress// debugger progressstd::cout << "Start debugging the progress: " << proj << ", pid = " << pid<< ":\n";debugger dbg(proj, pid);dbg.run();}return 0;
}

被 debug 的进程放在子进程中,然后由父进程,也就是我们的 debugger process,由它进行调试。

我们先写一个被 debug 的程序,这个程序输出 hello,world.

#include <iostream>
int main() {std::cerr << "hello,world.\n";return 0;
}

编译后,我们要打断点进行测试,可以看到目前只能传入一个地址,这个地址还是 0x 开头的 16 进制地址,我们对于这个地址丝毫没有头绪,因为我们不知道 std::cerr << "hello,world.\n";这个语句对应的汇编代码的指令地址是什么。这个程序首先有一个程序结构,对这个不清楚的话,可以看看我之前写的文章,是关于 elf 的,可以参考 c++ 内存模型或者 c++内存管理的那几篇博客。

现在看看这个被调试的程序的文件结构:

objdump -d hw        hw:     file format elf64-x86-64Disassembly of section .init:0000000000001000 <_init>:1000:       f3 0f 1e fa             endbr64 1004:       48 83 ec 08             sub    $0x8,%rsp1008:       48 8b 05 d9 2f 00 00    mov    0x2fd9(%rip),%rax        # 3fe8 <__gmon_start__>100f:       48 85 c0                test   %rax,%rax1012:       74 02                   je     1016 <_init+0x16>1014:       ff d0                   callq  *%rax1016:       48 83 c4 08             add    $0x8,%rsp101a:       c3                      retq   Disassembly of section .plt:0000000000001020 <.plt>:1020:       ff 35 82 2f 00 00       pushq  0x2f82(%rip)        # 3fa8 <_GLOBAL_OFFSET_TABLE_+0x8>1026:       f2 ff 25 83 2f 00 00    bnd jmpq *0x2f83(%rip)        # 3fb0 <_GLOBAL_OFFSET_TABLE_+0x10>102d:       0f 1f 00                nopl   (%rax)1030:       f3 0f 1e fa             endbr64 1034:       68 00 00 00 00          pushq  $0x01039:       f2 e9 e1 ff ff ff       bnd jmpq 1020 <.plt>103f:       90                      nop1040:       f3 0f 1e fa             endbr64 1044:       68 01 00 00 00          pushq  $0x11049:       f2 e9 d1 ff ff ff       bnd jmpq 1020 <.plt>104f:       90                      nop1050:       f3 0f 1e fa             endbr64 1054:       68 02 00 00 00          pushq  $0x21059:       f2 e9 c1 ff ff ff       bnd jmpq 1020 <.plt>105f:       90                      nopDisassembly of section .plt.got:0000000000001060 <__cxa_finalize@plt>:1060:       f3 0f 1e fa             endbr64 1064:       f2 ff 25 65 2f 00 00    bnd jmpq *0x2f65(%rip)        # 3fd0 <__cxa_finalize@GLIBC_2.2.5>106b:       0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)Disassembly of section .plt.sec:0000000000001070 <__cxa_atexit@plt>:1070:       f3 0f 1e fa             endbr64 1074:       f2 ff 25 3d 2f 00 00    bnd jmpq *0x2f3d(%rip)        # 3fb8 <__cxa_atexit@GLIBC_2.2.5>107b:       0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)0000000000001080 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>:1080:       f3 0f 1e fa             endbr64 1084:       f2 ff 25 35 2f 00 00    bnd jmpq *0x2f35(%rip)        # 3fc0 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@GLIBCXX_3.4>108b:       0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)0000000000001090 <_ZNSt8ios_base4InitC1Ev@plt>:1090:       f3 0f 1e fa             endbr64 1094:       f2 ff 25 2d 2f 00 00    bnd jmpq *0x2f2d(%rip)        # 3fc8 <_ZNSt8ios_base4InitC1Ev@GLIBCXX_3.4>109b:       0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)Disassembly of section .text:00000000000010a0 <_start>:10a0:       f3 0f 1e fa             endbr64 10a4:       31 ed                   xor    %ebp,%ebp10a6:       49 89 d1                mov    %rdx,%r910a9:       5e                      pop    %rsi10aa:       48 89 e2                mov    %rsp,%rdx10ad:       48 83 e4 f0             and    $0xfffffffffffffff0,%rsp10b1:       50                      push   %rax10b2:       54                      push   %rsp10b3:       4c 8d 05 d6 01 00 00    lea    0x1d6(%rip),%r8        # 1290 <__libc_csu_fini>10ba:       48 8d 0d 5f 01 00 00    lea    0x15f(%rip),%rcx        # 1220 <__libc_csu_init>10c1:       48 8d 3d c1 00 00 00    lea    0xc1(%rip),%rdi        # 1189 <main>10c8:       ff 15 12 2f 00 00       callq  *0x2f12(%rip)        # 3fe0 <__libc_start_main@GLIBC_2.2.5>10ce:       f4                      hlt    10cf:       90                      nop00000000000010d0 <deregister_tm_clones>:10d0:       48 8d 3d 39 2f 00 00    lea    0x2f39(%rip),%rdi        # 4010 <__TMC_END__>10d7:       48 8d 05 32 2f 00 00    lea    0x2f32(%rip),%rax        # 4010 <__TMC_END__>10de:       48 39 f8                cmp    %rdi,%rax10e1:       74 15                   je     10f8 <deregister_tm_clones+0x28>10e3:       48 8b 05 ee 2e 00 00    mov    0x2eee(%rip),%rax        # 3fd8 <_ITM_deregisterTMCloneTable>10ea:       48 85 c0                test   %rax,%rax10ed:       74 09                   je     10f8 <deregister_tm_clones+0x28>10ef:       ff e0                   jmpq   *%rax10f1:       0f 1f 80 00 00 00 00    nopl   0x0(%rax)10f8:       c3                      retq   10f9:       0f 1f 80 00 00 00 00    nopl   0x0(%rax)0000000000001100 <register_tm_clones>:1100:       48 8d 3d 09 2f 00 00    lea    0x2f09(%rip),%rdi        # 4010 <__TMC_END__>1107:       48 8d 35 02 2f 00 00    lea    0x2f02(%rip),%rsi        # 4010 <__TMC_END__>110e:       48 29 fe                sub    %rdi,%rsi1111:       48 89 f0                mov    %rsi,%rax1114:       48 c1 ee 3f             shr    $0x3f,%rsi1118:       48 c1 f8 03             sar    $0x3,%rax111c:       48 01 c6                add    %rax,%rsi111f:       48 d1 fe                sar    %rsi1122:       74 14                   je     1138 <register_tm_clones+0x38>1124:       48 8b 05 c5 2e 00 00    mov    0x2ec5(%rip),%rax        # 3ff0 <_ITM_registerTMCloneTable>112b:       48 85 c0                test   %rax,%rax112e:       74 08                   je     1138 <register_tm_clones+0x38>1130:       ff e0                   jmpq   *%rax1132:       66 0f 1f 44 00 00       nopw   0x0(%rax,%rax,1)1138:       c3                      retq   1139:       0f 1f 80 00 00 00 00    nopl   0x0(%rax)0000000000001140 <__do_global_dtors_aux>:1140:       f3 0f 1e fa             endbr64 1144:       80 3d e5 2f 00 00 00    cmpb   $0x0,0x2fe5(%rip)        # 4130 <completed.0>114b:       75 2b                   jne    1178 <__do_global_dtors_aux+0x38>114d:       55                      push   %rbp114e:       48 83 3d 7a 2e 00 00    cmpq   $0x0,0x2e7a(%rip)        # 3fd0 <__cxa_finalize@GLIBC_2.2.5>1155:       00 1156:       48 89 e5                mov    %rsp,%rbp1159:       74 0c                   je     1167 <__do_global_dtors_aux+0x27>115b:       48 8b 3d a6 2e 00 00    mov    0x2ea6(%rip),%rdi        # 4008 <__dso_handle>1162:       e8 f9 fe ff ff          callq  1060 <__cxa_finalize@plt>1167:       e8 64 ff ff ff          callq  10d0 <deregister_tm_clones>116c:       c6 05 bd 2f 00 00 01    movb   $0x1,0x2fbd(%rip)        # 4130 <completed.0>1173:       5d                      pop    %rbp1174:       c3                      retq   1175:       0f 1f 00                nopl   (%rax)1178:       c3                      retq   1179:       0f 1f 80 00 00 00 00    nopl   0x0(%rax)0000000000001180 <frame_dummy>:1180:       f3 0f 1e fa             endbr64 1184:       e9 77 ff ff ff          jmpq   1100 <register_tm_clones>0000000000001189 <main>:1189:       f3 0f 1e fa             endbr64 118d:       55                      push   %rbp118e:       48 89 e5                mov    %rsp,%rbp1191:       48 8d 35 6d 0e 00 00    lea    0xe6d(%rip),%rsi        # 2005 <_ZStL19piecewise_construct+0x1>1198:       48 8d 3d 81 2e 00 00    lea    0x2e81(%rip),%rdi        # 4020 <_ZSt4cerr@@GLIBCXX_3.4>119f:       e8 dc fe ff ff          callq  1080 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>11a4:       b8 00 00 00 00          mov    $0x0,%eax11a9:       5d                      pop    %rbp11aa:       c3                      retq   00000000000011ab <_Z41__static_initialization_and_destruction_0ii>:11ab:       f3 0f 1e fa             endbr64 11af:       55                      push   %rbp11b0:       48 89 e5                mov    %rsp,%rbp11b3:       48 83 ec 10             sub    $0x10,%rsp11b7:       89 7d fc                mov    %edi,-0x4(%rbp)11ba:       89 75 f8                mov    %esi,-0x8(%rbp)11bd:       83 7d fc 01             cmpl   $0x1,-0x4(%rbp)11c1:       75 32                   jne    11f5 <_Z41__static_initialization_and_destruction_0ii+0x4a>11c3:       81 7d f8 ff ff 00 00    cmpl   $0xffff,-0x8(%rbp)11ca:       75 29                   jne    11f5 <_Z41__static_initialization_and_destruction_0ii+0x4a>11cc:       48 8d 3d 5e 2f 00 00    lea    0x2f5e(%rip),%rdi        # 4131 <_ZStL8__ioinit>11d3:       e8 b8 fe ff ff          callq  1090 <_ZNSt8ios_base4InitC1Ev@plt>11d8:       48 8d 15 29 2e 00 00    lea    0x2e29(%rip),%rdx        # 4008 <__dso_handle>11df:       48 8d 35 4b 2f 00 00    lea    0x2f4b(%rip),%rsi        # 4131 <_ZStL8__ioinit>11e6:       48 8b 05 0b 2e 00 00    mov    0x2e0b(%rip),%rax        # 3ff8 <_ZNSt8ios_base4InitD1Ev@GLIBCXX_3.4>11ed:       48 89 c7                mov    %rax,%rdi11f0:       e8 7b fe ff ff          callq  1070 <__cxa_atexit@plt>11f5:       90                      nop11f6:       c9                      leaveq 11f7:       c3                      retq   00000000000011f8 <_GLOBAL__sub_I_main>:11f8:       f3 0f 1e fa             endbr64 11fc:       55                      push   %rbp11fd:       48 89 e5                mov    %rsp,%rbp1200:       be ff ff 00 00          mov    $0xffff,%esi1205:       bf 01 00 00 00          mov    $0x1,%edi120a:       e8 9c ff ff ff          callq  11ab <_Z41__static_initialization_and_destruction_0ii>120f:       5d                      pop    %rbp1210:       c3                      retq   1211:       66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%rax,%rax,1)1218:       00 00 00 121b:       0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)0000000000001220 <__libc_csu_init>:1220:       f3 0f 1e fa             endbr64 1224:       41 57                   push   %r151226:       4c 8d 3d 5b 2b 00 00    lea    0x2b5b(%rip),%r15        # 3d88 <__frame_dummy_init_array_entry>122d:       41 56                   push   %r14122f:       49 89 d6                mov    %rdx,%r141232:       41 55                   push   %r131234:       49 89 f5                mov    %rsi,%r131237:       41 54                   push   %r121239:       41 89 fc                mov    %edi,%r12d123c:       55                      push   %rbp123d:       48 8d 2d 54 2b 00 00    lea    0x2b54(%rip),%rbp        # 3d98 <__do_global_dtors_aux_fini_array_entry>1244:       53                      push   %rbx1245:       4c 29 fd                sub    %r15,%rbp1248:       48 83 ec 08             sub    $0x8,%rsp124c:       e8 af fd ff ff          callq  1000 <_init>1251:       48 c1 fd 03             sar    $0x3,%rbp1255:       74 1f                   je     1276 <__libc_csu_init+0x56>1257:       31 db                   xor    %ebx,%ebx1259:       0f 1f 80 00 00 00 00    nopl   0x0(%rax)1260:       4c 89 f2                mov    %r14,%rdx1263:       4c 89 ee                mov    %r13,%rsi1266:       44 89 e7                mov    %r12d,%edi1269:       41 ff 14 df             callq  *(%r15,%rbx,8)126d:       48 83 c3 01             add    $0x1,%rbx1271:       48 39 dd                cmp    %rbx,%rbp1274:       75 ea                   jne    1260 <__libc_csu_init+0x40>1276:       48 83 c4 08             add    $0x8,%rsp127a:       5b                      pop    %rbx127b:       5d                      pop    %rbp127c:       41 5c                   pop    %r12127e:       41 5d                   pop    %r131280:       41 5e                   pop    %r141282:       41 5f                   pop    %r151284:       c3                      retq   1285:       66 66 2e 0f 1f 84 00    data16 nopw %cs:0x0(%rax,%rax,1)128c:       00 00 00 00 0000000000001290 <__libc_csu_fini>:1290:       f3 0f 1e fa             endbr64 1294:       c3                      retq   Disassembly of section .fini:0000000000001298 <_fini>:1298:       f3 0f 1e fa             endbr64 129c:       48 83 ec 08             sub    $0x8,%rsp12a0:       48 83 c4 08             add    $0x8,%rsp12a4:       c3                      retq   

可以看到,这个程序虽然只是输出 hello,world.,但依然很复杂,因为它要包含其它很多的基础资源或者子程序,我们只需要重点关注 main

0000000000001189 <main>:1189:       f3 0f 1e fa             endbr64 118d:       55                      push   %rbp118e:       48 89 e5                mov    %rsp,%rbp1191:       48 8d 35 6d 0e 00 00    lea    0xe6d(%rip),%rsi        # 2005 <_ZStL19piecewise_construct+0x1>1198:       48 8d 3d 81 2e 00 00    lea    0x2e81(%rip),%rdi        # 4020 <_ZSt4cerr@@GLIBCXX_3.4>119f:       e8 dc fe ff ff          callq  1080 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>11a4:       b8 00 00 00 00          mov    $0x0,%eax11a9:       5d                      pop    %rbp11aa:       c3                      retq   

可以看到,这个段是从0000000000001189开始的,需要关注的输出语句为:

    119f:       e8 dc fe ff ff          callq  1080 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>

这个地址 119f 就是我们需要打断点的地方,被我们找出来了,这个地址是定死的,它在运行的时候,需要加载到内存中。问题是,加载到哪里?

我们并不知道加载到哪里,换句话说,我们不知道段地址是什么,它不固定,这主要是为了程序数据安全考虑,采用了内存分布随机化,我们可以关掉内存分布随机化

if (pid == 0) {personality(ADDR_NO_RANDOMIZE); // 取消随机内存// child progress// debugged progressptrace(PTRACE_TRACEME, 0, nullptr, nullptr);execl(proj, proj, nullptr);...

这样它就固定了,我们可以这样查看它在运行的时候的 map,首先用我们程序进行调试:

./main hw
Start debugging the progress: hw, pid = 260915:
minidbg> 

可以看到,pid260915,另开一个 zsh,直接查看:

cat /proc/260915/maps
555555554000-555555555000 r--p 00000000 fc:01 698165                     /root/mydebugger/src/hw
555555555000-555555556000 r-xp 00001000 fc:01 698165                     /root/mydebugger/src/hw
555555556000-555555557000 r--p 00002000 fc:01 698165                     /root/mydebugger/src/hw
555555557000-555555559000 rw-p 00002000 fc:01 698165                     /root/mydebugger/src/hw
7ffff7fcb000-7ffff7fce000 r--p 00000000 00:00 0                          [vvar]
7ffff7fce000-7ffff7fcf000 r-xp 00000000 00:00 0                          [vdso]
7ffff7fcf000-7ffff7fd0000 r--p 00000000 fc:01 1185709                    /usr/lib/x86_64-linux-gnu/ld-2.31.so
7ffff7fd0000-7ffff7ff3000 r-xp 00001000 fc:01 1185709                    /usr/lib/x86_64-linux-gnu/ld-2.31.so
7ffff7ff3000-7ffff7ffb000 r--p 00024000 fc:01 1185709                    /usr/lib/x86_64-linux-gnu/ld-2.31.so
7ffff7ffc000-7ffff7ffe000 rw-p 0002c000 fc:01 1185709                    /usr/lib/x86_64-linux-gnu/ld-2.31.so
7ffff7ffe000-7ffff7fff000 rw-p 00000000 00:00 0 
7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0                          [stack]
ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0

可以看到我们的可执行代码也就是 main 段在这里:

555555555000-555555556000 r-xp 00001000 fc:01 698165                     /root/mydebugger/src/hw

这以后都是固定的,虽然不安全,但是仅仅是为了演示,就没关系了。段的偏移地址为555555554000,因为我们需要打断点的地址为119f,因此:

基址 + 指令相对地址
= 555555554000 + 119f
= 55555555519f

可以预见的是,如果 break 0x55555555519f,之后执行,并不会打印出 hello,world,但是我们如果打到了下一条地址:0x5555555551a4,运行之后,就会理解打印出 hello,world。以下进行检测:

./main hw
Start debugging the progress: hw, pid = 261169:
minidbg> break 0x55555555519f
Set breakpoint at address 0x55555555519f
minidbg> continue
minidbg> 

我们换一个地址:

./main hw
Start debugging the progress: hw, pid = 261407:
minidbg> break 0x0x5555555551a4
Set breakpoint at address 0x5555555551a4
minidbg> continue
hello,world.
minidbg> 

可以看到,以下就打印出了hello,world。以上符合我们的预期,因此实验是成功的,另外不需要担心 pid 不一样,由于我们关闭了地址空间布局随机化(ASLR, Address Space Layout Randomization),段地址不会变,因此地址也是固定的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/15745.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【一站式学会Kotlin】第八节:kotlin== 和 === 的差别和含义

作者介绍&#xff1a; 百度资深Android工程师T6&#xff0c;在百度任职7年半。 目前&#xff1a;成立赵小灰代码工作室&#xff0c;欢迎大家找我交流Android、微信小程序、鸿蒙项目。 一&#xff1a;通俗易懂的人工智能教程&#xff1a;https://www.captainbed.cn/nefu/ 点一下…

Altium Designer 中键拖动,滚轮缩放,并修改缩放速度

我的版本是AD19&#xff0c;其他版本应该都一样。 滚轮缩放 首先&#xff0c;要用滚轮缩放&#xff0c;先要调整一下AD 设置&#xff0c;打开Preferences&#xff0c;在Mouse Wheel Configuration 里&#xff0c;把Zoom Main Window 后面Ctrl 上的对勾取消掉&#xff0c;再把…

C++中的悬挂指针和野指针

悬挂指针&#xff08;dangling pointer&#xff09;和野指针&#xff08;wild pointer&#xff09;是两种常见的指针错误&#xff0c;虽然它们都可能导致未定义行为&#xff0c;但它们产生的原因和表现有所不同。 1.悬挂指针&#xff08;Dangling Pointer&#xff09; 悬挂指…

2024 ISCC pwn wp

iscc 练武pwn 总结第一周chaosISCC_easyFlagshopping 第二周ISCC_easyISCC_Uheapheap 第三周miaoYour_programeazy_heap 总结 总体感觉iscc考察的题目都挺基础的&#xff0c;在目前这种比赛的大环境下&#xff0c;仍然出这种&#xff0c;比较基础的题目&#xff0c;实在是难得…

智驭未来:探究AIGC行业的战略入局时机与前景展望

当前时点涉足人工智能生成内容&#xff08;AIGC&#xff09;行业&#xff0c;是一个策略性抉择&#xff0c;基于对该行业现状的深度剖析及对未来趋势的前瞻性预判&#xff0c;其可行性与吸引力显著。 行业发展阶段分析&#xff1a; 技术迭代加速&#xff1a;近年来&#xff0c…

力扣刷题---2283. 判断一个数的数字计数是否等于数位的值【简单】

题目描述 给你一个下标从 0 开始长度为 n 的字符串 num &#xff0c;它只包含数字。 如果对于 每个 0 < i < n 的下标 i &#xff0c;都满足数位 i 在 num 中出现了 num[i]次&#xff0c;那么请你返回 true &#xff0c;否则返回 false 。 示例 1&#xff1a; 输入&a…

SpringCloud系列(31)--使用Hystrix进行服务降级

前言&#xff1a;在上一章节中我们创建了服务消费者模块&#xff0c;而本节内容则是使用Hystrix对服务进行服务降级处理。 1、首先我们先对服务提供者的服务进行服务降级处理 (1)修改cloud-provider-hystrix-payment8001子模块的PaymentServiceImpl类 注&#xff1a;HystrixP…

学习elixir(1)

突然发现elixir很有趣&#xff0c;所以想记录以下学习内容 # .ex .exs file elixir simple.exs # mix new <app_name> # mix deps.get; mix deps.update; mix deps.compile # 怎么使用mix escript.build # eg. 在mix.exs添加escript: [main_module: IntentionCLI, name:…

Window在VScode运行C/C++程序

首先说明&#xff1a;不同运行环境&#xff08;Linux/Window&#xff09;下的头文件会有差异&#xff0c;要注意变换&#xff01;生成可执行文件 Window默认生成a.exe&#xff0c;Linux默认生成a.out # C源代码 g test.cpp # C语言源代码 g test.c 或 gcc test.c直接输入a.ex…

从零开始学逆向,js逆向启蒙:有道翻译

语言&#xff1a;js、python 工具&#xff1a;pycharm、chrome浏览器F12调试、chatgpt&#xff08;补充js第三方库&#xff0c;转python&#xff09;、node.js(js运行)&#xff08;必须&#xff09; 目标&#xff1a;学习掌握基本js逆向知识。 对象&#xff1a; 有道翻译 &a…

怎么判断同步时序逻辑电路和异步时序逻辑电路?

&#x1f3c6;本文收录于「Bug调优」专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收藏&&…

力扣刷题---2418. 按身高排序【简单】

题目描述 给你一个字符串 数组 names &#xff0c;和一个由 互不相同 的正整数组成的数组 heights 。两个数组的长度均为 n 。 对于每个下标 i&#xff0c;names[i] 和 heights[i] 表示第 i 个人的名字和身高。 请按身高 降序 顺序返回对应的名字数组 names 。 示例 1&…

僵尸进程,孤儿进程,守护进程

【一】僵尸进程 1.僵尸进程是指完成自己的任务之后&#xff0c;没有被父进程回收资源,占用系统资源,对计算机有害&#xff0c;应该避免 """ 所有的子进程在运行结束之后都会变成僵尸进程(死了没死透)还保留着pid和一些运行过程的中的记录便于主进程查看(短时间…

嵌入式作业5

在函数main.c中初始化三种颜色的灯&#xff1a; gpio_init(LIGHT_BLUE, GPIO_OUTPUT, LIGHT_OFF); //蓝灯 gpio_init(LIGHT_GREEN, GPIO_OUTPUT, LIGHT_OFF); //绿灯 gpio_init(LIGHT_RED, GPIO_OUTPUT, LIGHT_OFF); //红灯 同时为了响应以上修改&#xff0c;进入isr。c…

STM32 CubeMX使用记录

取消DMA中断默认使能 DMA中断默认使能勾选无法取消选中 取消勾选Force DMA channels interrupts

cadence23---PCB Editer 学习笔记

1.交互式布局 在Orcad中点击图标N生成第一网表&#xff1a; 在PCB Editer中导入第一网表&#xff0c; 之后点击移动命令并在右侧属性框中勾选Symbol选项卡&#xff1a; 设置--应用模式--点击常规编辑&#xff1a; 之后就可以进行交互式选择了。 绿色图标为打开全部飞线&#…

web前端学习笔记11

11. CSS3高级特效 11.1 CSS3变形 CSS3变形是一些效果的集合, 如平移、旋转、缩放、倾斜效果 每个效果都可以称为变形(transform),它们可以分别操控元素发生平移、旋转、缩放、倾斜等变化 语法 transform:[transform-function] ; /* 设置变形函数,可以是一个,也可以是多…

2024年【N1叉车司机】考试题及N1叉车司机找解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 N1叉车司机考试题参考答案及N1叉车司机考试试题解析是安全生产模拟考试一点通题库老师及N1叉车司机操作证已考过的学员汇总&#xff0c;相对有效帮助N1叉车司机找解析学员顺利通过考试。 1、【多选题】《特种设备使用…

git使用介绍

一、为什么做版本控制&#xff08;git是版本控制工具&#xff09; 为了保留之前所以的版本&#xff0c;以便回滚和修改 二、点击安装 三、基础操作 1、初步认识 想要让git对一个目录进行版本控制需要以下步骤&#xff1a; 进入要管理的文件夹进行初始化命令 git init管理…

Amesim基础篇-元件详解-H型膨胀阀四象限解析

一 膨胀阀简介 膨胀阀的主要功能是节流和调节过热度,库内膨胀阀包含节流管、H型膨胀阀、T型膨胀阀三种: 节流管:一根内径较小的管路,当制冷剂通过他时发生等等焓降压降温,具有成本低,内径不可变的特点,因此普遍在家用空调中使用,在汽车空调上使用较少。当我们建模过程…