MacOS LLDB |线程 1:EXC_BAD_ACCESS(代码=1 & 2,地址=0x123456789)

MacOS LLDB | Thread 1: EXC_BAD_ACCESS (code=1 & 2, address=0x123456789)

所以首先,我对 C++ 不太了解,我从前一段时间 class 那里知道的很少。到目前为止,我所拥有的几乎所有东西都来自这个非常慷慨且知识渊博的社区。

我必须使用一个古怪的自定义软件才能在 MacOS 上工作,它没有任何形式的自动保存功能,而且偶尔会崩溃。虽然我经常保存,但它很烦人因为它崩溃而失去任何工作量。

我想做的是使用保存功能地址来保存并每5分钟左右重复一次。到目前为止,我有进程ID,进程的运行时间基内存地址,保存函数地址的偏移量(我已经从调试和反汇编找到的地址中减去反汇编程序基地址),以及它需要的参数。当我尝试 运行 保存功能时,我收到 lldb 错误 Thread 1: EXC_BAD_ACCESS (code=1, address=0x10a106ecf) 有时它会更改为 Thread 1: EXC_BAD_ACCESS (code= 2、地址=0x10a106ecf)。我在这个网站上发现了关于这个错误的其他问题,但它要么不适用于我的情况,要么由于我的知识有限,我只是不明白如何解决我的情况。如果有人能详细解释我做错了什么以及解决方案,将不胜感激,因为我想得到理解和学习。

该项目是 Xcode 中的命令行实用程序。我不确定它是否需要是一个 .dylib 并添加到进程中,但如果它可以是一个外部命令行实用程序,那对我来说会更理想。

问题代码如下:

mach_vm_address_t runtimeBase = 0; // Base process memory address. Set in the getProc() function
mach_vm_address_t funcBase = 0x973ECF; // Function Address from disassembling. (0x100973ECF - 0x100000000 = 0x973ECF)

int main()
{
    if (!getProc()) throw std::logic_error("Failed to get Process.");
    
    typedef mach_vm_address_t(__cdecl* autoSave)(int saveType, const char* saveMessage);
    autoSave save = (autoSave)(runtimeBase + funcBase);
    for(;;)
    {
        save(0, "AutoSave");//    <-- Error Here: Thread 1: EXC_BAD_ACCESS (code=1/2, address=0x10a106ecf)
        //sleep(5); //add sleep after I get save to work.
    }
}

/*
 saveType:
    0 = Save local.
    1 = Save server.
 
 saveMessage: Message for history/save log.
 */

我从 c​​ode=1 错误中得到的更多细节是:

error: memory read failed for 0x10a106e00  <-- Thread 1: EXC_BAD_ACCESS (code=1, address=0x10a106ecf)

代码=2 是:

0x10a106ecf: addb   %al, (%rax)            <-- Thread 1: EXC_BAD_ACCESS (code=2, address=0x10a106ecf)
0x10a106ed1: addb   %al, (%rax)
0x10a106ed3: addb   %al, (%rax)
0x10a106ed5: addb   %al, (%rax)
0x10a106ed7: addb   %al, (%rax)
0x10a106ed9: addb   %al, (%rax)
0x10a106edb: addb   %al, (%rax)
0x10a106edd: addb   %al, (%rax)
0x10a106edf: addb   %al, (%rax)
0x10a106ee1: addb   %al, (%rax)
0x10a106ee3: addb   %al, (%rax)
0x10a106ee5: addb   %al, (%rax)
0x10a106ee7: addb   %al, (%rax)
0x10a106ee9: addb   %al, (%rax)
0x10a106eeb: addb   %al, (%rax)
0x10a106eed: addb   %al, (%rax)

根据 @Peter Cordes 的汇编解释,我设法解决了我的问题。

@Peter Cordes: addb %al, (%rax) is how 00 00 decodes. Crashing there indicates that execution jumped to some memory that's all zeros, perhaps due to overwriting a return address or function pointer. Or if you have any hand-written asm, due to getting something wrong with the stack.

@Peter Cordes: The EXC_BAD_ACCESS (code=2, address=0x10a106ecf) is from trying to deref whatever garbage is in RAX, for read+write. The 00 00 garbage machine code decodes as instructions that try to access that "bad pointer". I haven't used LLDB much, or MacOS for development at all, but I'm guessing code=1 vs 2 might be read vs. write. (And I haven't really looked at the details of your question, just wanted to help out by explaining that seeing execution in a whole block of addb %al, (%rax) instructions means you jumped to a region full of zeros; any mem access it attempts is already bogus.)


因此,正如 @Peter Cordes 所说 addb %al, (%rax)00 00 解码的方式。在那里崩溃表明执行跳转到了一些全为零的内存。

由此我们可以推断,当Thread 1: EXC_BAD_ACCESS (code=2, address=0x10a106ecf)发生时,是因为我们跳转到了内存中的一个全为零的地方。但是为什么我们要跳到内存中全为零的地方呢?我认为这是因为 MacOS 处理内存的方式。每个进程都有自己的内存space,我试图跳转到我自己的进程内存中的地址0x10a106e00,它不存在。有大量资源解释进程内存如何在现代 OS 上工作,如果您想了解更多信息,只需快速 google 搜索。

所以我们现在知道的是:

  • Thread 1: EXC_BAD_ACCESS (code=1, address=0x10a106ecf)是因为我的程序无法读取指定地址的内存。
  • Thread 1: EXC_BAD_ACCESS (code=2, address=0x10a106ecf) 发生是因为我们在内存中跳转了一个无效的地方,而且是针对错误的进程。

代码也有一些问题,我使用的代码更适合 Windows,根据我所做的内存地址创建一个函数,

typedef mach_vm_address_t(__cdecl* autoSave)(int saveType, const char* saveMessage);
    autoSave save = (autoSave)(runtimeBase + funcBase);

这就是我的想法 better/correct 基于内存地址创建函数的方法是:

int (*autoSave)(int saveType, const char* saveMessage) = (int (*)(int , const char *))(runtimeBase + funcBase);

我做的最后一件事是创建 Dylib 而不是命令行实用程序。我这样做是因为访问目标进程的内存要容易得多。虽然我试图实现的目标可能通过命令行实用程序 (CLU) 并附加到目标进程,就好像 CLU 是调试器或其他方法一样,但对我来说,创建 dylib 更简单、更容易。

如果阅读本文的任何人对我的解释有任何疑问,或者想要更详细的 explanation/example 我的解决方案。欢迎给我留言或评论。

再次感谢@Peter Cordes的解说。他们提供了帮助,尽管他们说“我根本没有使用 LLDB 或 MacOS 进行开发”。这些解释仍然非常有帮助,并且以易于理解的方式进行了解释。