Hijacks the Abort function from MSVCRT.DLL or UCRTBASE.DLL, gets information on loaded modules, and sets up an unhandled exception filter.
| 439 | // gets information on loaded modules, and sets up an unhandled |
| 440 | // exception filter. |
| 441 | void SetupCrashDebugging() |
| 442 | { |
| 443 | #ifdef ALLOW_ABORT_HIJACKING |
| 444 | #ifdef FILE_DEBUG_HIJACKER |
| 445 | FILE* something = fopen("something.txt", "w"); |
| 446 | #endif |
| 447 | |
| 448 | // Step 1. Hijack abort() |
| 449 | if (sizeof(uintptr_t) > 4) |
| 450 | { |
| 451 | HijackDbgPrint("Abort hijack disabled. The target is 64-bit."); |
| 452 | return; |
| 453 | } |
| 454 | |
| 455 | void* patchAt = (void*) &abort; |
| 456 | |
| 457 | // We need to find the actual address of abort() from within the loaded libraries. |
| 458 | // This means that just "&abort" does not do as it links to our thunk which jumps |
| 459 | // indirectly to the actual loaded abort(). |
| 460 | // |
| 461 | // Now, import thunks are typically encoded in FF 25 XX XX XX XX. So, check for |
| 462 | // those bytes' presence. |
| 463 | uint8_t* abortPtr = (uint8_t*) &abort; |
| 464 | if (abortPtr[0] != 0xFF || abortPtr[1] != 0x25) |
| 465 | { |
| 466 | // Wow! It looks like this ain't an import thunk of a known kind. |
| 467 | auto x = abortPtr; |
| 468 | HijackDbgPrint("Abort hijack may be ineffective. The import thunk looks weird. Here is a dump:"); |
| 469 | HijackDbgPrint("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", |
| 470 | x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], |
| 471 | x[8], x[9], x[10], x[11], x[12], x[13], x[14], x[15]); |
| 472 | } |
| 473 | else |
| 474 | { |
| 475 | // It is. This means that the address we're looking for is after the FF 25 bytes. |
| 476 | void*** ptr = (void***)(abortPtr + 2); |
| 477 | |
| 478 | // ptr - The address of the offset of the FF 25 XX XX XX XX instruction |
| 479 | // *ptr - The address where the JMP loads the address to jump to |
| 480 | // **ptr = The address to jump to |
| 481 | |
| 482 | HijackDbgPrint("Found import thunk at %p, jumping to indirection via %p", ptr, *ptr); |
| 483 | HijackDbgPrint("The indirection leads to %p", **ptr); |
| 484 | |
| 485 | patchAt = **ptr; |
| 486 | } |
| 487 | |
| 488 | uintptr_t Patch[2]; |
| 489 | Patch[0] = 0x25FF9090; // NOP; NOP; JMP [modrm] |
| 490 | Patch[1] = (uintptr_t) &HijackedAbortPtr; // [absolute indirect 32-bit address] |
| 491 | |
| 492 | if (!PatchMemory((void*) patchAt, Patch, sizeof Patch)) |
| 493 | { |
| 494 | HijackDbgPrint("Abort hijack disabled. Could not write 8 bytes to %p.", &abort); |
| 495 | return; |
| 496 | } |
| 497 | |
| 498 | HijackDbgPrint("Abort hijack engaged. abort() = %p, patched at %p, hijacked to %p", &abort, patchAt, &HijackedAbort); |
no test coverage detected