So to start, I am not too knowledageble in C , I know very little from a class I took a while back. Almost everything I have so far is from this very generous and knowledgable community.
I have to use a wack piece of custom software for work on MacOS and it doesn't have any form autosave and it occasionally likes to crash. Though I regularly save, its annoying loosing any amount of work because it crashes.
What I am trying to do is use the save function address to save and repeat every 5 or so minutes. So far I have the process id, the runtime base memory address for the process, the offset of the save function address(I have subtracted the disassembler base address from the address I found with debugging and disassembling), and the arguments it requires. When I try to run the save function I get the lldb error Thread 1: EXC_BAD_ACCESS (code=1, address=0x10a106ecf) and sometimes it changes to Thread 1: EXC_BAD_ACCESS (code=2, address=0x10a106ecf). I have found other questions about this error on this website, but it either doesn't apply to my situation, or due to my limited knowledge I just don't understand how to solve it for my case. If anyone could explain in detail what I am doing wrong in detail along with a solution, it would be much appreciated because I would like to get an understanding and learn.
The project is a Command Line Utility in Xcode. I'm not sure if it would need to be a .dylib and added into the process, but if it could be an external command line utility, that would be more optimal for me.
Here is the problem code:
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.
*/
More detail I get from code=1 error is:
error: memory read failed for 0x10a106e00 <-- Thread 1: EXC_BAD_ACCESS (code=1, address=0x10a106ecf)
And for code=2 is:
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)
CodePudding user response:
With assembly explanations from @Peter Cordes I managed to solve my issue.
@Peter Cordes:
addb %al, (%rax)
is how00 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. The00 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 ofaddb %al, (%rax)
instructions means you jumped to a region full of zeros; any mem access it attempts is already bogus.)
So, as @Peter Cordes said addb %al, (%rax)
is how 00 00
decodes. Crashing there indicates that execution jumped to some memory that's all zeros.
From this we can infer that when Thread 1: EXC_BAD_ACCESS (code=2, address=0x10a106ecf)
happens it is because we jumped to a place in memory that is all zeros. But why are we jumping to a place in memory with all zeros? I am thinking it's because of how MacOS handles memory. Each process has its own memory space, and I was trying to jump to the address 0x10a106e00
in MY OWN process' memory, which does not exist. There are a multitude of resources explain how process memory works on modern OS's, just do a quick google search if you want to learn more.
So what we know now is:
Thread 1: EXC_BAD_ACCESS (code=1, address=0x10a106ecf)
happens because my program fails to read the memory for the specified address.Thread 1: EXC_BAD_ACCESS (code=2, address=0x10a106ecf)
happens because we are jumping an invalid place in memory, and for the wrong process.
There was also some issues with the code, I was using code better suited for Windows, To create a function based on the memory address I did,
typedef mach_vm_address_t(__cdecl* autoSave)(int saveType, const char* saveMessage);
autoSave save = (autoSave)(runtimeBase funcBase);
And this is what I'm thinking a better/correct way of creating a function based on the memory address is:
int (*autoSave)(int saveType, const char* saveMessage) = (int (*)(int , const char *))(runtimeBase funcBase);
The last thing I did was create a Dylib instead of a Command Line Utility. I did this because it is MUCH easier to access the target process' memory. Though what I am trying to achieve is probably possible through a Command Line Utility(CLU) and attaching to the target process as if the CLU was a debugger or some other method, for me it was much simpler and easier to just create a dylib.
If anyone reading this has any questions about my explanation, or want more detailed explanation/example of my solution. Feel free to send me a message or comment.
I once again want to thank @Peter Cordes for his explanations. They helped even though they said `I haven't used LLDB much, or MacOS for development at all'. The explanations were still extremely helpful and were explained in an easy to understand way.