Changeset 108712 in vbox for trunk/src/VBox/HostDrivers/Support/posix/SUPR3HardenedMain-posix.cpp
- Timestamp:
- Mar 24, 2025 11:02:34 AM (4 weeks ago)
- svn:sync-xref-src-repo-rev:
- 168129
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/HostDrivers/Support/posix/SUPR3HardenedMain-posix.cpp
r108711 r108712 510 510 511 511 #else /* !RT_ARCH_AMD64 */ 512 # error "Port me" 512 /* 513 * Patch 32-bit hosts. 514 */ 515 /* Just use the disassembler to skip 5 bytes or more. */ 516 while (offJmpBack < 5) 517 { 518 cbInstr = 1; 519 int rc = DISInstr(pbTarget + offJmpBack, DISCPUMODE_32BIT, &Dis, &cbInstr); 520 if ( RT_FAILURE(rc) 521 || ( (Dis.pCurInstr->fOpType & DISOPTYPE_CONTROLFLOW) 522 && Dis.pCurInstr->uOpcode != OP_CALL)) 523 return VERR_SUPLIB_UNEXPECTED_INSTRUCTION; 524 525 if ( Dis.pCurInstr->uOpcode == OP_CALL 526 && (Dis.pCurInstr->fOpType & DISOPTYPE_RELATIVE_CONTROLFLOW)) 527 cbPatchMem += 10; /* push imm32 + jmp rel32 */ 528 else 529 cbPatchMem += cbInstr; 530 531 offJmpBack += cbInstr; 532 } 533 534 /* Allocate suitable exectuable memory available. */ 535 uint8_t *pbPatchMem = supR3HardenedMainPosixExecMemAlloc(cbPatchMem, pbTarget, false /* fRipRelAddr */); 536 if (!pbPatchMem) 537 return VERR_NO_MEMORY; 538 539 /* Assemble the code for resuming the call.*/ 540 *ppfnReal = (uintptr_t)pbPatchMem; 541 542 /* Go through the instructions to patch and fixup any relative call instructions. */ 543 uint32_t offInsn = 0; 544 while (offInsn < offJmpBack) 545 { 546 cbInstr = 1; 547 int rc = DISInstr(pbTarget + offInsn, DISCPUMODE_32BIT, &Dis, &cbInstr); 548 if ( RT_FAILURE(rc) 549 || ( (Dis.pCurInstr->fOpType & DISOPTYPE_CONTROLFLOW) 550 && Dis.pCurInstr->uOpcode != OP_CALL)) 551 return VERR_SUPLIB_UNEXPECTED_INSTRUCTION; 552 553 if ( Dis.pCurInstr->uOpcode == OP_CALL 554 && (Dis.pCurInstr->fOpType & DISOPTYPE_RELATIVE_CONTROLFLOW)) 555 { 556 /* 557 * Don't use a call instruction directly but push the original return address 558 * onto the stack and use a relative jump to the call target. 559 * The reason here is that on Linux the called method saves the return 560 * address from the stack which will be different from the original because 561 * the code is executed from our patch memory. 562 * 563 * Luckily the call instruction is 5 bytes long which means it is always the 564 * last instruction to patch and we don't need to return from the call 565 * to patch memory anyway but can use this method to resume the original call. 566 */ 567 AssertReturn(offInsn + cbInstr >= offJmpBack, VERR_SUPLIB_UNEXPECTED_INSTRUCTION); /* Must be last instruction! */ 568 569 /* push return address */ 570 uint32_t const uAddrReturn = (uintptr_t)&pbTarget[offInsn + cbInstr]; /* The return address to push to the stack. */ 571 572 *pbPatchMem++ = 0x68; /* push dword */ 573 *(uint32_t *)pbPatchMem = uAddrReturn; 574 pbPatchMem += sizeof(uint32_t); 575 576 /* jmp rel32 to the call target */ 577 uintptr_t const uAddr = uAddrReturn + (int32_t)Dis.aParams[0].uValue; 578 int32_t const i32DispNew = uAddr - (uintptr_t)&pbPatchMem[5]; 579 580 *pbPatchMem++ = 0xe9; /* jmp rel32 */ 581 *(int32_t *)pbPatchMem = i32DispNew; 582 pbPatchMem += sizeof(int32_t); 583 } 584 else 585 { 586 memcpy(pbPatchMem, pbTarget + offInsn, cbInstr); 587 pbPatchMem += cbInstr; 588 } 589 590 offInsn += cbInstr; 591 } 592 593 *pbPatchMem++ = 0xe9; /* jmp rel32 */ 594 *(uint32_t *)pbPatchMem = (uintptr_t)&pbTarget[offJmpBack] - ((uintptr_t)pbPatchMem + 4); 595 596 /* Assemble the patch. */ 597 Assert(offJmpBack >= 5); 598 pbTarget[0] = 0xe9; 599 *(uint32_t *)&pbTarget[1] = (uintptr_t)pfnHook - (uintptr_t)&pbTarget[1+4]; 513 600 #endif /* !RT_ARCH_AMD64 */ 514 601
Note:
See TracChangeset
for help on using the changeset viewer.